/// <summary>
    /// berechnet die nächsten Blocker
    /// </summary>
    /// <param name="limit">maximale Anzahl der Berechnungen, oder 0, wenn die Berechnung beendet werden soll</param>
    /// <returns>true, wenn noch weitere Berechnungen anstehen</returns>
    public bool Next(int limit)
    {
      switch (blockerStatus)
      {
        #region # case BlockerStatus.init:
        case BlockerStatus.init:
        {
          sammlerKistenAnzahl++;
          if (sammlerKistenAnzahl == basisRaum.KistenAnzahl)
          {
            Abbruch();
            return false;
          }

          sammlerAbfrage = SammlerBerechneZielStellungen().GetEnumerator();
          sammlerHash = new SokowahnHash_Index16Multi();
          sammlerStats = new long[60001];
          rückwärtsSucher = Enumerable.Range(0, maxVorschau).Select(x => new SokowahnLinearList2(sammlerKistenAnzahl + 1, Environment.CurrentDirectory + "\\temp\\", multi32k)).ToArray();
          rückwärtsTiefe = 0;

          alleStellungen = new SokowahnLinearList2(sammlerKistenAnzahl + 1, Environment.CurrentDirectory + "\\temp\\", multi32k * 4);
          alleBlockerHash = new HashSet<ulong>();

          char[] feldData = basisRaum.FeldData;
          int feldBreite = basisRaum.FeldBreite;

          bool[] spielerRaum = SokowahnStaticTools.SpielfeldRaumScan(feldData, feldBreite);
          raumAnzahl = spielerRaum.Count(x => x);

          tempBlocker = new SokowahnBlockerB.BlockerFeld[raumAnzahl];
          for (int i = 0; i < tempBlocker.Length; i++) tempBlocker[i].kistenNummerLeer = sammlerKistenAnzahl;

          blockerStatus = BlockerStatus.sammleZiele;
          return true;
        }
        #endregion

        #region # case BlockerStatus.sammleZiele:
        case BlockerStatus.sammleZiele:
        {
          while (limit-- > 0 && sammlerAbfrage.MoveNext())
          {
            var satz = sammlerAbfrage.Current;
            if (sammlerHash.Get(satz.crc64) == 65535)
            {
              sammlerHash.Add(satz.crc64, 60000);
              sammlerStats[60000]++;
              rückwärtsSucher[0].Add(satz.raumSpielerPos, satz.kistenZuRaum);
              alleStellungen.Add(satz.raumSpielerPos, satz.kistenZuRaum);
            }
          }

          if (limit >= 0)
          {
            tempRaum = new SokowahnRaum(basisRaum);
            tempRaum.KistenAnzahl = sammlerKistenAnzahl;
            threadRäume = Enumerable.Range(0, 256).Select(i => new SokowahnRaum(tempRaum)).ToArray();
            blockerStatus = BlockerStatus.suchModus;
          }

          return true;
        }
        #endregion

        #region # case BlockerStatus.suchModus:
        case BlockerStatus.suchModus:
        {
          if (SucheRückwärts(limit)) return true;

          Array.Resize(ref bekannteBlockerHashes, sammlerKistenAnzahl);
          bekannteBlockerHashes[sammlerKistenAnzahl - 1] = sammlerHash;
          Array.Resize(ref bekannteSammlerStats, sammlerKistenAnzahl);
          var tmp = sammlerStats.Reverse().ToList();
          while (tmp[tmp.Count - 1] == 0) tmp.RemoveAt(tmp.Count - 1);
          bekannteSammlerStats[sammlerKistenAnzahl - 1] = tmp.ToArray();
          for (int i = 0; i < rückwärtsSucher.Length; i++) rückwärtsSucher[i].Dispose();
          blockerStatus = BlockerStatus.blockerSuche;

          return true;
        }
        #endregion

        #region # case BlockerStatus.blockerSuche:
        case BlockerStatus.blockerSuche:
        {
          limit = (int)Math.Min((long)limit, alleStellungen.SatzAnzahl);

          if (limit == 0)
          {
            int startPos = bekannteBlocker.Length;
            Array.Resize(ref bekannteBlocker, startPos + raumAnzahl);
            for (int i = 0; i < raumAnzahl; i++) bekannteBlocker[startPos + i] = tempBlocker[i];

            for (int i = 0; i < bekannteBlocker.Length; i++)
            {
              bekannteBlocker[i].geprüfteStellungen = sammlerHash.HashAnzahl;
              bekannteBlocker[i].kistenNummerLeer = sammlerKistenAnzahl + 1;
            }

            long geprüfteStellungenGesamt = 0;
            for (int i = 0; i < bekannteBlocker.Length; i += raumAnzahl) geprüfteStellungenGesamt += bekannteBlocker[i].geprüfteStellungen;
            for (int i = 0; i < bekannteBlocker.Length; i++) bekannteBlocker[i].Sortieren();

            blockerStatus = BlockerStatus.init;
            return true;
          }

          var stellungen = alleStellungen.Pop(limit);
          int satzGröße = alleStellungen.SatzGröße;

          var ergebnisse = Enumerable.Range(0, limit)
#if !parallelDeaktivieren
.AsParallel()
#if parallelGeordnet
.AsOrdered()
#endif
#endif
.SelectMany(stellung =>
          {
            SokowahnRaum raum = threadRäume[Thread.CurrentThread.ManagedThreadId];
            raum.LadeStellung(stellungen, stellung * satzGröße, 0);
            //            return raum.GetVarianten(this).Where(x => sammlerHash.Get(x.crc64) == 65535);
            var ausgabe = raum.GetVarianten(this).Where(x =>
              {
                if (sammlerHash.Get(x.crc64) == 65535) return true;
                x.zugTiefe = 60000 - sammlerHash.Get(x.crc64);
                //string dbg = x.Debug(basisRaum);
                return false;
              }
              );
            return ausgabe;
          }).ToArray();

          foreach (var stellung in ergebnisse)
          {
            if (alleBlockerHash.Contains(stellung.crc64)) continue;
            alleBlockerHash.Add(stellung.crc64);
            tempBlocker[stellung.raumSpielerPos].Add(stellung.kistenZuRaum, sammlerKistenAnzahl);
          }

          return true;
        }
        #endregion

        #region # case BlockerStatus.bereit:
        case BlockerStatus.bereit:
        {
          return false;
        }
        #endregion

        default: throw new NotImplementedException();
      }
    }