/// <summary>
    /// Normale Suche nach vorne (von der Startstellung aus beginnend)
    /// </summary>
    /// <param name="limit">maximale Anzahl der Rechenschritte</param>
    /// <returns>true, wenn noch weitere Berechnungen anstehen</returns>
    bool SucheVorwärts(int limit)
    {
      if (limit == 0)
      {
        vorwärtsTiefeAktuell = vorwärtsTiefe;
        return true;
      }

      if (vorwärtsTiefe >= vorwärtsSucher.Length) return false;

      if (limit > 1111100000)
      {
        maxZüge = limit - 1111100000 + 1;
        for (int i = maxZüge; i < vorwärtsSucher.Length; i++)
        {
          vorwärtsSucher[i].Dispose();
          vorwärtsSucher[i] = null;
          vorwärtsSucherPunkte[i].Clear();
          vorwärtsSucherPunkte[i] = null;
        }
        Array.Resize(ref vorwärtsSucher, Math.Min(vorwärtsSucher.Length, maxZüge));
        Array.Resize(ref vorwärtsSucherPunkte, vorwärtsSucher.Length);
        MessageBox.Show("Maxzüge gesetzt auf: " + (maxZüge - 1));
        vorwärtsTiefeAktuell = vorwärtsTiefe;
        return true;
      }

      bool schnell = limit >= 100000;

      var liste = vorwärtsSucher[vorwärtsTiefeAktuell];
      var listePunkte = vorwärtsSucherPunkte[vorwärtsTiefeAktuell];

      //if (liste.SatzAnzahl * 2L > (long)limit)
      //{
      //  if (liste.SatzAnzahl < (long)limit * 10L)
      //  {
      //    limit = (int)(liste.SatzAnzahl / 2L);
      //  }
      //}

      limit = (int)Math.Min((long)limit, liste.SatzAnzahl);

      #region # // --- raumPool abfragen bzw. erstellen ---
      if (raumPool == null)
      {
        raumPool = Enumerable.Range(0, 256).Select(x => new SokowahnRaum(raumBasis, blocker, bekannteStellungen, zielStellungen)).ToArray();

        SokowahnRaum r = new SokowahnRaum(raumPool[0]);

        r.KistenAnzahl = 1;

        int[] kistePos = new int[1];
        int[] kisteIndex = new int[1];
        int raumAnzahl = r.RaumAnzahl;
        einzelKistenDauer = new int[raumAnzahl];

        char[] feldLeer = raumPool[0].FeldDataLeer;
        bool[] spielerRaum = SokowahnStaticTools.SpielfeldRaumScan(feldData, feldBreite);
        int[] raumZuFeld = Enumerable.Range(0, spielerRaum.Length).Where(i => spielerRaum[i]).ToArray();
        raumZiele = new bool[raumAnzahl];
        for (int i = 0; i < raumAnzahl; i++) raumZiele[i] = feldLeer[raumZuFeld[i]] == '.';

        for (int k = 0; k < raumAnzahl; k++)
        {
          kistePos[0] = k;
          r.LadeStellung(kisteIndex, kistePos);
          einzelKistenDauer[k] = RechneMinZügeKiste(r);
        }

        laufFelder = new ushort[raumAnzahl * raumAnzahl];

        ushort[] laufPosis = new ushort[raumAnzahl + 1];
        for (int y = 0; y < laufFelder.Length; y += raumAnzahl)
        {
          int pp = 0;
          laufPosis[pp++] = (ushort)(y / raumAnzahl);
          for (int x = 0; x < raumAnzahl; x++)
          {
            if (x > pp) throw new Exception("Fatal!");
            ushort p = laufPosis[x];
            laufFelder[y + x] = p;
            if ((laufPosis[pp] = (ushort)r.raumOben[p]) < raumAnzahl && !laufPosis.Take(pp).Any(i => i == laufPosis[pp])) pp++;
            if ((laufPosis[pp] = (ushort)r.raumRechts[p]) < raumAnzahl && !laufPosis.Take(pp).Any(i => i == laufPosis[pp])) pp++;
            if ((laufPosis[pp] = (ushort)r.raumUnten[p]) < raumAnzahl && !laufPosis.Take(pp).Any(i => i == laufPosis[pp])) pp++;
            if ((laufPosis[pp] = (ushort)r.raumLinks[p]) < raumAnzahl && !laufPosis.Take(pp).Any(i => i == laufPosis[pp])) pp++;
          }
        }

      }

      #endregion

      #region # // --- Teilliste mit den besten Stellungen erzeugen (falls notwendig) ---
      if (liste.SatzAnzahl > limit)
      {
        int punkteOk = 0;
        int findAnzahl = 0;
        int gutDazu = 0;
        foreach (var satz in listePunkte.OrderBy(x => x.Key))
        {
          punkteOk = satz.Key;
          findAnzahl += satz.Value;
          if (findAnzahl >= limit)
          {
            gutDazu = limit - (findAnzahl - satz.Value);
            break;
          }
        }

        var listeOk = new SokowahnLinearList2(raumBasis.KistenAnzahl + 1 + 2, TempOrdner);
        var listeAufheben = new SokowahnLinearList2(raumBasis.KistenAnzahl + 1 + 2, TempOrdner);

        long bis = liste.SatzAnzahl;
        for (long i = 0; i < bis; i++)
        {
          var stellung = liste.Pop();
          SokowahnPunkte punkte = new SokowahnPunkte(stellung);
          if (punkte.tiefeMax <= punkteOk)
          {
            if (punkte.tiefeMax == punkteOk)
            {
              if (gutDazu > 0)
              {
                gutDazu--;
              }
              else
              {
                listeAufheben.Add(stellung);
                continue;
              }
            }
            listeOk.Add(stellung);
            if (listeOk.SatzAnzahl == limit) break;
          }
          else
          {
            listeAufheben.Add(stellung);
          }
        }

        if (liste.SatzAnzahl < listeAufheben.SatzAnzahl)
        {
          bis = liste.SatzAnzahl;
          for (long i = 0; i < bis; i++) listeAufheben.Add(liste.Pop());
          vorwärtsSucher[vorwärtsTiefeAktuell] = listeAufheben;
          liste.Dispose();
        }
        else
        {
          bis = listeAufheben.SatzAnzahl;
          for (long i = 0; i < bis; i++) liste.Add(listeAufheben.Pop());
          listeAufheben.Dispose();
        }

        liste = listeOk;
      }

#if DEBUG
      if (limit != liste.SatzAnzahl) throw new Exception("aua?");
#endif
      #endregion

      SokowahnRaum raum = raumPool[Thread.CurrentThread.ManagedThreadId];

      int mx = maxZüge - rückwärtsTiefe;
      var ergebnisse = Enumerable.Range(0, limit).Select(i => liste.Pop()).SelectMany(stellung =>
      {
        raum.LadeStellung(stellung, vorwärtsTiefeAktuell);
        SokowahnPunkte punkte = new SokowahnPunkte(stellung);

        listePunkte[punkte.tiefeMax]--;
        if (bekannteStellungen.Get(raum.Crc) < vorwärtsTiefeAktuell) return Enumerable.Empty<SokowahnStellungRun>();

        return raum.GetVariantenRun().Where(v => v.zugTiefe <= mx && v.zugTiefe < bekannteStellungen.Get(v.crc64));
      }).ToArray();

#if !parallelDeaktivieren
      var punkteListe = new SokowahnPunkte[ergebnisse.Length];

      if (schnell)
      {
        ParallelEnumerable.Range(0, ergebnisse.Length).Select(v =>
        {
          SokowahnRaum r = raumPool[Thread.CurrentThread.ManagedThreadId];
          r.LadeStellung(ergebnisse[v]);
          punkteListe[v] = r.BerechnePunkte2(einzelKistenDauer, laufFelder);
          //punkteListe[v] = r.BerechnePunkteSchnell(einzelKistenDauer);
          return true;
        }).Count();
      }
      else
      {
        ParallelEnumerable.Range(0, ergebnisse.Length).Select(v =>
        {
          SokowahnRaum r = raumPool[Thread.CurrentThread.ManagedThreadId];
          r.LadeStellung(ergebnisse[v]);
          punkteListe[v] = r.BerechnePunkte(einzelKistenDauer);
          return true;
        }).Count();
      }
#endif

      for (int v = 0; v < ergebnisse.Length; v++)
      {
        var variante = ergebnisse[v];
        int findQuelle = bekannteStellungen.Get(variante.crc64);

#if parallelDeaktivieren
        raum.LadeStellung(variante);
        //        SokowahnPunkte punkte = raum.BerechnePunkte(einzelKistenDauer);
        SokowahnPunkte punkte = raum.BerechnePunkte2(einzelKistenDauer, laufFelder);
        //        SokowahnPunkte punkte = raum.BerechnePunkte3(einzelKistenDauer, laufFelder);
#else
        var punkte = punkteListe[v];
#endif

        if (variante.zugTiefe < findQuelle) // neue Stellung oder bessere Variante gefunden
        {
          int findZiel = zielStellungen.Get(variante.crc64);
          if (findZiel < 65535)
          {
            if (variante.zugTiefe + 60000 - findZiel < maxZüge)
            {
              #region // --- neue (bessere) Variante gefunden ---
              maxZüge = variante.zugTiefe + 60000 - findZiel;
              //gefundenCrc = variante.crc64;

              for (int i = maxZüge; i < vorwärtsSucher.Length; i++)
              {
                vorwärtsSucher[i].Dispose();
                vorwärtsSucher[i] = null;
                vorwärtsSucherPunkte[i].Clear();
                vorwärtsSucherPunkte[i] = null;
              }
              if (maxZüge < vorwärtsSucher.Length)
              {
                Array.Resize(ref vorwärtsSucher, maxZüge);
                Array.Resize(ref vorwärtsSucherPunkte, maxZüge);
              }
              #endregion
            }
            continue;
          }
          //if (punkte.tiefeMin + variante.zugTiefe < maxZüge)
          //if (variante.zugTiefe + rückwärtsTiefe < maxZüge)
          if (variante.zugTiefe + rückwärtsTiefe < maxZüge && punkte.tiefeMin + variante.zugTiefe < maxZüge)
          {
            if (findQuelle < 65535) bekannteStellungen.Update(variante.crc64, variante.zugTiefe); else bekannteStellungen.Add(variante.crc64, variante.zugTiefe);
            VorwärtsAdd(variante, punkte);
          }
        }
      }

      vorwärtsTiefeAktuell++;

      while (vorwärtsTiefe < vorwärtsSucher.Length && vorwärtsSucher[vorwärtsTiefe].SatzAnzahl == 0)
      {
        vorwärtsTiefe++;
        vorwärtsTiefeAktuell = vorwärtsTiefe;
      }

      if (vorwärtsTiefeAktuell == vorwärtsSucher.Length)
      {
        vorwärtsTiefeAktuell = vorwärtsTiefe;
      }

      return true;
    }
    /// <summary>
    /// reduziert den Speicherverbrauch (falls ein Multiplikator angegeben wurde) und lagert die Daten in eine Temp-Datei aus
    /// </summary>
    /// <returns>Anzahl der Bytes, welche frei geworden sind</returns>
    public long Refresh()
    {
      if (schreibBuffer == null || schreibBuffer.Length == BufferElemente) return 0; // wurde bereits Refreshed

#if byteModus
      var tmp = new SokowahnLinearList2Byte(satzGröße, tempOrdner);
#else
      var tmp = new SokowahnLinearList2(satzGröße, tempOrdner);
#endif
      long bis = this.SatzAnzahl;
      for (long i = 0; i < bis; i++)
      {
        tmp.Add(this.Pop());
      }

      this.Dispose();
      this.bufferMax = tmp.bufferMax;
      this.leseBuffer = tmp.leseBuffer;
      this.leseBufferGro = tmp.leseBufferGro;
      this.leseBufferPos = tmp.leseBufferPos;
      this.schreibBuffer = tmp.schreibBuffer;
      this.schreibBufferPos = tmp.schreibBufferPos;
      this.tempDatei = tmp.tempDatei;
      tmp.tempDatei = null;
      this.tmpBufferBelegt = tmp.tmpBufferBelegt;
      this.tmpBufferFrei = tmp.tmpBufferFrei;
      tmp.Dispose();

      GC.Collect();
      return SatzAnzahl * (long)sizeof(SatzTyp);
    }
示例#3
0
    /// <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)
    {
      int maxKisten = basisRaum.FeldData.Where(c => c == '$' || c == '*').Count();

      if (limit <= 0) // Marker für Abbruch
      {
        return false;
      }

      switch (status)
      {
        #region # case BlockerStatus.Init: // Start einer Blocker-Sucher (eine neue Kistenanzahl wird ausprobiert)
        case BlockerStatus.Init:
        {
          if (suchKistenAnzahl + 1 >= maxKisten)
          {
            Abbruch();
            return false; // Kisten-Limit erreicht
          }

          suchKistenAnzahl++;

          SammleKistenInit(false);

          status = BlockerStatus.SammleStartStellungen;
          return true;
        }
        #endregion
        #region # case BlockerStatus.SammleStartStellungen: // sammelt alle Start-Stellungen mit der entsprechenden Kistenanzahl (sind automatisch auch gleichzeitig Stellungen, mit denen das Ziel erreichbar ist)
        case BlockerStatus.SammleStartStellungen:
        {
          limit--;
          while (limit > 0 && SammleKistenNext()) limit--;

          if (SammleKistenNext())
          {
            return true;
          }
          else
          {
            SammleKistenInit(true);

            status = BlockerStatus.SammleZielStellungen;
            return true;
          }
        }
        #endregion
        #region # case BlockerStatus.SammleZielStellungen: // sammelt alle Ziel-Stellungen, wo jede Kiste auf ein Zielfeld steht
        case BlockerStatus.SammleZielStellungen:
        {
          limit--;
          while (limit > 0 && SammleKistenNext()) limit--;

          if (!SammleKistenNext()) status = BlockerStatus.SucheVarianten;

          return true;
        }
        #endregion
        #region # case BlockerStatus.SucheVarianten: // sucht vorwärts alle möglichen Varianten (eventuell bereits vorhandene Blocker werden beachten)
        case BlockerStatus.SucheVarianten:
        {
          if (prüfListe.SatzAnzahl == 0)
          {
            prüfListe.Dispose();
            prüfListe = prüfListeSammler;
            prüfListeSammler = new SokowahnLinearList2(suchKistenAnzahl + 1, Environment.CurrentDirectory + "\\temp\\", listeMax / 32768);
            if (prüfListe.SatzAnzahl == 0)
            {
              prüfListeSammler.Dispose();
              status = BlockerStatus.VerschmelzeZielStellungen;
              verschmelzenRest = prüfListeBöse.SatzAnzahl;
              return true;
            }
          }

          limit = (int)Math.Min((long)limit, prüfListe.SatzAnzahl);

          var ergebnisse = Enumerable.Range(0, limit).Select(i => prüfListe.Pop()).AsParallel().SelectMany(stellung =>
          {
            SokowahnRaum raum = threadRäume[Thread.CurrentThread.ManagedThreadId];
            raum.LadeStellung(stellung, 0, 0);
            return raum.GetVarianten(this);
          }).Where(x => bekannteStellungen.Get(x.crc64) == 65535).ToArray();

          foreach (var stellung in ergebnisse)
          {
            int find = bekannteStellungen.Get(stellung.crc64);
            if (find == 65535)
            {
              bekannteStellungen.Add(stellung.crc64, 12345);
              prüfListeSammler.Add(stellung.raumSpielerPos, stellung.kistenZuRaum);
              prüfListeBöse.Add(stellung.raumSpielerPos, stellung.kistenZuRaum);
            }
          }

          return true;
        }
        #endregion
        #region # case BlockerStatus.VerschmelzeZielStellungen: // ermittelt (anhand der Rückwärts-Suche) welche der ermittelten Stellungen zum Ziel führen können und markiert diese
        case BlockerStatus.VerschmelzeZielStellungen:
        {
          if (prüfListe.SatzAnzahl == 0)
          {
            prüfListe.Dispose();
            prüfListe = prüfListeGut;
            prüfListeGut = new SokowahnLinearList2(suchKistenAnzahl + 1, Environment.CurrentDirectory + "\\temp\\", listeMax / 32768);
            if (prüfListe.SatzAnzahl == 0)
            {
              prüfListe.Dispose();
              prüfListeGut.Dispose();
              prüfListe = null;
              prüfListeGut = null;
              status = BlockerStatus.ErstelleBlocker;
              tempBlocker = new BlockerFeld[raumAnzahl];
              for (int i = 0; i < tempBlocker.Length; i++)
              {
                tempBlocker[i].geprüfteStellungen = bekannteStellungen.HashAnzahl;
                tempBlocker[i].kistenNummerLeer = suchKistenAnzahl;
              }
              return true;
            }
          }

          limit = (int)Math.Min((long)limit, prüfListe.SatzAnzahl);
          verschmelzenRest -= (long)limit;

          var ergebnisse = Enumerable.Range(0, limit).Select(i => prüfListe.Pop()).AsParallel().SelectMany(stellung =>
          {
            SokowahnRaum raum = threadRäume[Thread.CurrentThread.ManagedThreadId];
            raum.LadeStellung(stellung, 0, 0);
            return raum.GetVariantenRückwärts();
          }).Where(x => bekannteStellungen.Get(x.crc64) < 65535).ToArray();

          foreach (var stellung in ergebnisse)
          {
            int find = bekannteStellungen.Get(stellung.crc64);
            if (find == 60000)
            {
              continue;
            }
            else
            {
              prüfListeGut.Add(stellung.raumSpielerPos, stellung.kistenZuRaum);
              bekannteStellungen.Update(stellung.crc64, 60000);
            }
          }

          return true;
        }
        #endregion
        #region # case BlockerStatus.ErstelleBlocker: // erstellt die Blocker anhand der restlichen Stellungen, welche nicht zum Ziel führten
        case BlockerStatus.ErstelleBlocker:
        {
          limit = (int)Math.Min((long)limit, prüfListeBöse.SatzAnzahl);

          var ergebnisse = Enumerable.Range(0, limit).Select(i => prüfListeBöse.Pop()).Select(x =>
          {
            tmpRaum.LadeStellung(x, 0, 0);
            return tmpRaum.GetStellung();
          }).Where(stellung => bekannteStellungen.Get(stellung.crc64) == 12345).ToArray();

          foreach (var stellung in ergebnisse)
          {
            tempBlocker[stellung.raumSpielerPos].Add(stellung.kistenZuRaum, suchKistenAnzahl);
          }

          if (prüfListeBöse.SatzAnzahl == 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].kistenNummerLeer = suchKistenAnzahl + 1;

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

            status = BlockerStatus.Init;
            bekannteStellungen = null;
          }

          return true;
        }
        #endregion
        #region # case BlockerStatus.Fertig: // Blockersuche wurde beendet, (nur noch der Check-Methode steht bereit)
        case BlockerStatus.Fertig: return false;
        #endregion

        default: throw new Exception("Status unbekant: " + status);
      }
    }