/// <summary> /// Rekursive Suchmethode einer einzelnen Kiste /// </summary> /// <param name="raum">Raum mit der einzelnen Kiste und Spielerstellung</param> /// <returns>Mindestzahl der Schritte zum Ziel (oder 60000 = wenn kein Ziel möglich)</returns> int RechneMindestZüge(SokowahnRaum raum) { List<List<SokowahnStellung>> list = new List<List<SokowahnStellung>>(); list.Add(new List<SokowahnStellung>(raum.GetStellung().SelfEnumerable())); int listTiefe = 0; SokowahnHash_Index0 hash = new SokowahnHash_Index0(); while (listTiefe < list.Count) { foreach (var stellung in list[listTiefe]) { raum.LadeStellung(stellung); if (raumZiele[stellung.kistenZuRaum[0]]) return listTiefe; foreach (var variante in raum.GetVarianten()) { int find = hash.Get(variante.crc64); if (find < 65535) { if (find <= variante.zugTiefe) continue; hash.Update(variante.crc64, variante.zugTiefe); } else { hash.Add(variante.crc64, variante.zugTiefe); } while (list.Count <= variante.zugTiefe) { list.Add(new List<SokowahnStellung>()); } list[variante.zugTiefe].Add(variante); } } listTiefe++; } return 60000; }
/// <summary> /// initialisiert die ersten Blocker-Kisten für den SammlerStart /// </summary> /// <param name="zielVariante">gibt an, ob nur Varianten ermittelt werden sollen, wo alle Kisten bereits auf dem Zielfeld stehen</param> void SammleKistenInit(bool zielVariante) { sammlerCheckKisten = Enumerable.Range(0, suchKistenAnzahl).Select(i => i).ToArray(); sammlerCheckKisten[suchKistenAnzahl - 1]--; // letzte eins zurück setzen, damit beim ersten sammlerNext() auch die erste Variante gesetzt werden kann char[] feldData = basisRaum.FeldData; int feldBreite = basisRaum.FeldBreite; bool[] spielerRaum = SokowahnStaticTools.SpielfeldRaumScan(feldData, feldBreite); raumAnzahl = spielerRaum.Count(x => x); int[] raumZuFeld = Enumerable.Range(0, spielerRaum.Length).Where(i => spielerRaum[i]).ToArray(); int[] feldZuRaum = Enumerable.Range(0, feldData.Length).Select(i => spielerRaum[i] ? raumZuFeld.ToList().IndexOf(i) : -1).ToArray(); if (zielVariante) { sammlerCheckKistenRaum = raumZuFeld.Select(i => (feldData[i] == '.' || feldData[i] == '*' || feldData[i] == '+') ? feldZuRaum[i] : -1).Where(i => i >= 0).ToArray(); } else { sammlerCheckKistenRaum = raumZuFeld.Select(i => (feldData[i] == '$' || feldData[i] == '*') ? feldZuRaum[i] : -1).Where(i => i >= 0).ToArray(); } if (!zielVariante) // nur beim ersten mal Initialisieren { tmpRaum = new SokowahnRaum(feldData, feldBreite); tmpRaum.KistenAnzahl = suchKistenAnzahl; threadRäume = Enumerable.Range(0, 256).Select(i => new SokowahnRaum(tmpRaum)).ToArray(); bekannteStellungen = new SokowahnHash_Index24Multi(); prüfListe = new SokowahnLinearList2(suchKistenAnzahl + 1, Environment.CurrentDirectory + "\\temp\\", listeMax / 32768); prüfListeSammler = new SokowahnLinearList2(suchKistenAnzahl + 1, Environment.CurrentDirectory + "\\temp\\", listeMax / 32768); prüfListeGut = new SokowahnLinearList2(suchKistenAnzahl + 1, Environment.CurrentDirectory + "\\temp\\", listeMax / 32768); prüfListeBöse = new SokowahnLinearList2(suchKistenAnzahl + 1, Environment.CurrentDirectory + "\\temp\\", listeMax / 32768); } }
/// <summary> /// Konstruktor /// </summary> /// <param name="spielFeld">Spielfeld als Textzeilen</param> public SokoWahn_5th(string spielFeld) { SokowahnStaticTools.SpielfeldEinlesen(spielFeld, out feldBreite, out feldHöhe, out feldSpielerStartPos, out feldData, out feldDataLeer); raumBasis = new SokowahnRaum(feldData, feldBreite); Directory.CreateDirectory(TempOrdner); // --- Vorwärtssuche initialisieren --- bekannteStellungen = new SokowahnHash_Index24Multi(); bekannteStellungen.Add(raumBasis.Crc, 0); vorwärtsTiefe = 0; vorwärtsTiefeAktuell = 0; vorwärtsSucher = new SokowahnLinearList2[0]; vorwärtsSucherPunkte = new Dictionary<int, int>[0]; VorwärtsAdd(raumBasis.GetStellung(), new SokowahnPunkte()); // --- Zielstellungen und Rückwärtssuche initialisieren --- zielStellungen = new SokowahnHash_Index24Multi(); rückwärtsTiefe = 0; rückwärtsSucher = new SokowahnLinearList2[0]; foreach (SokowahnStellung stellung in SokowahnStaticTools.SucheZielStellungen(raumBasis)) { zielStellungen.Add(stellung.crc64, 60000); RückwärtsAdd(stellung); } ulong spielFeldCrc = Crc64.Start.Crc64Update(raumBasis.FeldBreite, raumBasis.FeldHöhe, raumBasis.FeldData); blocker = new SokowahnBlockerB2(Environment.CurrentDirectory + "\\temp\\blocker2_x" + spielFeldCrc.ToString("x").PadLeft(16, '0') + ".gz", raumBasis); }
/// <summary> /// fügt eine Stellung in die Liste ein /// </summary> /// <param name="raum">Raum mit den entsprechenden Daten</param> public void Add(SokowahnRaum raum) { if (leseModus) throw new Exception("Fehler beim hinzufügen, Liste befindet siche bereits im Lese-Modus!"); if (bufferPos == bufferGro) { if (bufferGro < bufferMax) { bufferGro = Math.Min(bufferGro * 2, bufferMax); Array.Resize(ref buffer, bufferGro * satzGröße); } else { TempSpeichern(); } } int off = bufferPos * satzGröße; buffer[off] = (byte)raum.raumSpielerPos; for (int i = 1; i < satzGröße; i++) buffer[off + i] = (byte)raum.kistenZuRaum[i - 1]; bufferPos++; }
/// <summary> /// Konstruktor /// </summary> /// <param name="blockerDatei">Pfad zur Datei, worin sich eventuell archivierte Blocker-Daten befinden</param> /// <param name="basisRaum">Raum mit dem originalen Spielfeld</param> public SokowahnBlocker(string blockerDatei, SokowahnRaum basisRaum) { this.basisRaum = basisRaum; bekannteBlocker = new BlockerFeld[0]; status = BlockerStatus.Init; suchKistenAnzahl = 0; this.blockerDatei = blockerDatei; if (File.Exists(blockerDatei)) { LadeAlleBlocker(); } }
/// <summary> /// gibt eine bestimmte Stellung direkt als sichtbaren String aus (ohne die eigene Stellung zu beeinflussen) /// </summary> /// <param name="data">Stellungsdaten, welche ausgelesen werden sollen</param> /// <param name="offset">Startposition im Array</param> /// <returns>lesbare Stellung</returns> public string Debug(ushort[] data, int offset, int zugTiefe) { SokowahnRaum tmp = new SokowahnRaum(this); tmp.LadeStellung(data, offset, zugTiefe); return tmp.ToString(); }
/// <summary> /// Konstruktor /// </summary> /// <param name="blockerDatei">Pfad zur Datei, worin sich eventuell archivierte Blocker-Daten befinden</param> /// <param name="basisRaum">Raum mit dem originalen Spielfeld</param> public SokowahnBlockerB2(string blockerDatei, SokowahnRaum basisRaum) { this.basisRaum = basisRaum; this.blockerDatei = blockerDatei; this.blockerStatus = BlockerStatus.init; //if (file.exists(blockerdatei)) //{ // ladealleblocker(); //} }
/// <summary> /// ermittelt alle möglichen Zielstellungen /// </summary> /// <param name="raumBasis">Raumsystem mit Basis-Stellung</param> /// <returns>Enumerable aller möglichen Zielstellungen</returns> public static IEnumerable<SokowahnStellung> SucheZielStellungen(SokowahnRaum raumBasis) { int feldBreite = raumBasis.FeldBreite; int feldHöhe = raumBasis.FeldHöhe; char[] feldData = raumBasis.FeldDataLeer.Select(c => c == '.' ? '*' : c).ToArray(); for (int spielerY = 1; spielerY < feldHöhe - 1; spielerY++) { for (int spielerX = 1; spielerX < feldBreite - 1; spielerX++) { int pos = spielerX + spielerY * feldBreite; if (feldData[pos] == ' ' && (feldData[pos - 1] == '*' || feldData[pos + 1] == '*' || feldData[pos - feldBreite] == '*' || feldData[pos + feldBreite] == '*')) { feldData[pos] = '@'; SokowahnRaum tmpRaum = new SokowahnRaum(feldData, feldBreite); tmpRaum.SpielerZugTiefe = 60000; var findStellungen = tmpRaum.GetVariantenRückwärts().ToArray(); if (findStellungen.Length > 0) { yield return tmpRaum.GetStellung(); // foreach (var findStellung in findStellungen) yield return findStellung; } feldData[pos] = ' '; } } } yield break; }
/// <summary> /// ermittelt alle Zielstellungen, welche mit der entsprechenden Anzahl der Kisten erreichbar sind /// </summary> /// <returns>Enumerable aller möglichen Zielstellungen</returns> IEnumerable<SokowahnStellung> SammlerBerechneZielStellungen() { SokowahnRaum raum = new SokowahnRaum(basisRaum); raum.KistenAnzahl = sammlerKistenAnzahl; char[] feldData = basisRaum.FeldData; int feldBreite = basisRaum.FeldBreite; bool[] spielerRaum = SokowahnStaticTools.SpielfeldRaumScan(feldData, feldBreite); int[] raumZuFeld = Enumerable.Range(0, spielerRaum.Length).Where(i => spielerRaum[i]).ToArray(); int[] feldZuRaum = Enumerable.Range(0, feldData.Length).Select(i => spielerRaum[i] ? raumZuFeld.ToList().IndexOf(i) : -1).ToArray(); var sammlerKistenRaum = raumZuFeld.Select(i => (feldData[i] == '.' || feldData[i] == '*' || feldData[i] == '+') ? feldZuRaum[i] : -1).Where(i => i >= 0).ToArray(); foreach (var variante in Tools.BerechneElementeVarianten(basisRaum.KistenAnzahl, sammlerKistenAnzahl, false)) { raum.LadeStellung(variante, sammlerKistenRaum); foreach (var stellung in raum.GetVariantenBlockerZiele()) { yield return stellung; } } yield break; }
/// <summary> /// gibt die eigene Stellung als lesbares Feld zurück /// </summary> /// <param name="tmpRaum">Sokowahn-Raum mit den jeweiligen Grunddaten</param> /// <returns>lesbares Spielfeld</returns> public string Debug(SokowahnRaum raum) { SokowahnRaum temp = new SokowahnRaum(raum); temp.KistenAnzahl = kistenZuRaum.Length; return temp.Debug(this); }
/// <summary> /// gibt die eigene Stellung als lesbares Feld zurück /// </summary> /// <param name="tmpRaum">Sokowahn-Raum mit den jeweiligen Grunddaten</param> /// <returns>lesbares Spielfeld</returns> public string ToString(SokowahnRaum raum) { return Debug(raum); }
/// <summary> /// gibt die eigene Stellung als lesbares Feld zurück /// </summary> /// <param name="tmpRaum">Sokowahn-Raum mit den jeweiligen Grunddaten</param> /// <returns>lesbares Spielfeld</returns> public string Debug(SokowahnRaum raum) { return raum.Debug(this); }
/// <summary> /// Konstruktor /// </summary> /// <param name="raum">Basisdaten anhand eines vorhanden Raumes nutzen</param> /// <param name="blocker">bekannte Blocker</param> /// <param name="startHash">bekannte Einträge in der Start-Hashtable</param> /// <param name="zielHash">bekannte Einträge in der Ziel-Hashtable</param> public SokowahnRaum(SokowahnRaum raum, ISokowahnBlocker blocker, ISokowahnHash startHash, ISokowahnHash zielHash) { this.feldData = raum.feldData; this.feldBreite = raum.feldBreite; this.raumAnzahl = raum.raumAnzahl; this.raumLinks = raum.raumLinks; this.raumRechts = raum.raumRechts; this.raumOben = raum.raumOben; this.raumUnten = raum.raumUnten; this.raumSpielerPos = raum.raumSpielerPos; this.spielerZugTiefe = raum.spielerZugTiefe; this.raumZuKisten = raum.raumZuKisten.ToArray(); // Kopie erstellen this.kistenAnzahl = raum.kistenAnzahl; this.kistenZuRaum = raum.kistenZuRaum.ToArray(); // Kopie erstellen this.tmpCheckRaumPosis = new int[raumAnzahl]; this.tmpCheckRaumTiefe = new int[raumAnzahl]; this.tmpRaumCheckFertig = new bool[raumAnzahl + 1]; this.tmpRaumCheckFertig[raumAnzahl] = true; // Ende-Feld schon auf fertig setzen this.merkBlocker = blocker; this.merkStartHash = startHash; this.merkZielHash = zielHash; }
/// <summary> /// Konstruktor /// </summary> /// <param name="raum">Basisdaten anhand eines vorhanden Raumes nutzen</param> public SokowahnRaum(SokowahnRaum raum) { this.feldData = raum.feldData; this.feldBreite = raum.feldBreite; this.raumAnzahl = raum.raumAnzahl; this.raumLinks = raum.raumLinks; this.raumRechts = raum.raumRechts; this.raumOben = raum.raumOben; this.raumUnten = raum.raumUnten; this.raumSpielerPos = raum.raumSpielerPos; this.spielerZugTiefe = raum.spielerZugTiefe; this.raumZuKisten = raum.raumZuKisten.ToArray(); // Kopie erstellen this.kistenAnzahl = raum.kistenAnzahl; this.kistenZuRaum = raum.kistenZuRaum.ToArray(); // Kopie erstellen this.tmpCheckRaumPosis = new int[raumAnzahl]; this.tmpCheckRaumTiefe = new int[raumAnzahl]; this.tmpRaumCheckFertig = new bool[raumAnzahl + 1]; this.tmpRaumCheckFertig[raumAnzahl] = true; // Ende-Feld schon auf fertig setzen }
/// <summary> /// berechnet die Anzahl der Schritte um eine einzelne Kiste zum Ziel zu bewegen /// </summary> /// <param name="raum">Raum mit der einzelnen Kiste</param> /// <returns>Mindestzahl der Schritte zum Ziel (oder 60000 = wenn kein Ziel möglich)</returns> int RechneMinZügeKiste(SokowahnRaum raum) { var varianten = raum.GetVariantenBlockerZiele().ToArray(); int mindest = 60000; foreach (var variante in varianten) { raum.LadeStellung(variante); raum.spielerZugTiefe = 0; int i = RechneMindestZüge(raum); if (i < mindest) mindest = i; } return mindest; }
/// <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(); } }
/// <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> /// gibt eine bestimmte Stellung direkt als sichtbaren String aus (ohne die eigene Stellung zu beeinflussen) /// </summary> /// <param name="data">Stellungsdaten, welche ausgelesen werden sollen</param> /// <param name="offset">Startposition im Array</param> /// <returns>lesbare Stellung</returns> public string Debug(byte[] data, int offset) { SokowahnRaum tmp = new SokowahnRaum(this); tmp.LadeStellung(data, offset, 0); return tmp.ToString(); }