/// <summary> /// ermittelt alle möglichen Zugvarianten und gibt deren Stellungen zurück /// </summary> /// <param name="blocker">Klasse mit bekannten Blockern</param> /// <returns>Enumerable der gefundenen Stellungen</returns> public IEnumerable<SokowahnStellung> GetVarianten(ISokowahnBlocker blocker) { int checkRaumVon = 0; int checkRaumBis = 0; Array.Clear(tmpRaumCheckFertig, 0, raumAnzahl); // erste Spielerposition hinzufügen tmpRaumCheckFertig[raumSpielerPos] = true; tmpCheckRaumPosis[checkRaumBis] = raumSpielerPos; tmpCheckRaumTiefe[checkRaumBis] = spielerZugTiefe; checkRaumBis++; // alle möglichen Spielerposition berechnen while (checkRaumVon < checkRaumBis) { raumSpielerPos = tmpCheckRaumPosis[checkRaumVon]; int pTiefe = tmpCheckRaumTiefe[checkRaumVon] + 1; int p, p2; #region # // --- links --- if (!tmpRaumCheckFertig[p = raumLinks[raumSpielerPos]]) { if (raumZuKisten[p] < kistenAnzahl) // steht eine Kiste auf den benachbarten Feld? { if (raumZuKisten[p2 = raumLinks[p]] == kistenAnzahl && p2 < raumAnzahl) // Feld hinter der Kiste frei? { kistenZuRaum[raumZuKisten[p2] = raumZuKisten[p]] = p2; raumZuKisten[p] = kistenAnzahl; // linke Kiste weiter nach links schieben raumSpielerPos = p; // Spieler nach links bewegen if (blocker.CheckErlaubt(raumSpielerPos, raumZuKisten)) { yield return new SokowahnStellung { raumSpielerPos = raumSpielerPos, kistenZuRaum = kistenZuRaum.TeilArray(kistenAnzahl), crc64 = Crc, zugTiefe = pTiefe }; } raumSpielerPos = tmpCheckRaumPosis[checkRaumVon]; // Spieler zurück nach rechts bewegen kistenZuRaum[raumZuKisten[p] = raumZuKisten[p2]] = p; raumZuKisten[p2] = kistenAnzahl; // linke Kiste eins zurück nach rechts schieben } } else { tmpRaumCheckFertig[p] = true; tmpCheckRaumPosis[checkRaumBis] = p; tmpCheckRaumTiefe[checkRaumBis] = pTiefe; checkRaumBis++; } } #endregion #region # // --- rechts --- if (!tmpRaumCheckFertig[p = raumRechts[raumSpielerPos]]) { if (raumZuKisten[p] < kistenAnzahl) // steht eine Kiste auf den benachbarten Feld? { if (raumZuKisten[p2 = raumRechts[p]] == kistenAnzahl && p2 < raumAnzahl) // Feld hinter der Kiste frei? { kistenZuRaum[raumZuKisten[p2] = raumZuKisten[p]] = p2; raumZuKisten[p] = kistenAnzahl; // rechte Kiste weiter nach rechts schieben raumSpielerPos = p; // Spieler nach rechts bewegen if (blocker.CheckErlaubt(raumSpielerPos, raumZuKisten)) { yield return new SokowahnStellung { raumSpielerPos = raumSpielerPos, kistenZuRaum = kistenZuRaum.TeilArray(kistenAnzahl), crc64 = Crc, zugTiefe = pTiefe }; } raumSpielerPos = tmpCheckRaumPosis[checkRaumVon]; // Spieler zurück nach links bewegen kistenZuRaum[raumZuKisten[p] = raumZuKisten[p2]] = p; raumZuKisten[p2] = kistenAnzahl; // rechte Kiste eins zurück nach links schieben } } else { tmpRaumCheckFertig[p] = true; tmpCheckRaumPosis[checkRaumBis] = p; tmpCheckRaumTiefe[checkRaumBis] = pTiefe; checkRaumBis++; } } #endregion #region # // --- oben --- if (!tmpRaumCheckFertig[p = raumOben[raumSpielerPos]]) { if (raumZuKisten[p] < kistenAnzahl) // steht eine Kiste auf den benachbarten Feld? { if (raumZuKisten[p2 = raumOben[p]] == kistenAnzahl && p2 < raumAnzahl) // Feld hinter der Kiste frei? { kistenZuRaum[raumZuKisten[p2] = raumZuKisten[p]] = p2; raumZuKisten[p] = kistenAnzahl; // obere Kiste weiter nach oben schieben raumSpielerPos = p; // Spieler nach oben bewegen #region # // Kisten sortieren (sofern notwendig) while (raumZuKisten[p2] > 0 && kistenZuRaum[raumZuKisten[p2] - 1] > p2 && raumZuKisten[p2] < kistenAnzahl) { int tmp = kistenZuRaum[raumZuKisten[p2] - 1]; kistenZuRaum[raumZuKisten[p2]--] = tmp; kistenZuRaum[raumZuKisten[tmp]++] = p2; } #endregion if (blocker.CheckErlaubt(raumSpielerPos, raumZuKisten)) { yield return new SokowahnStellung { raumSpielerPos = raumSpielerPos, kistenZuRaum = kistenZuRaum.TeilArray(kistenAnzahl), crc64 = Crc, zugTiefe = pTiefe }; } raumSpielerPos = tmpCheckRaumPosis[checkRaumVon]; // Spieler zurück nach unten bewegen kistenZuRaum[raumZuKisten[p] = raumZuKisten[p2]] = p; raumZuKisten[p2] = kistenAnzahl; // obere Kiste eins zurück nach unten schieben #region # // Kisten zurück sortieren (sofern notwendig) while (raumZuKisten[p] < kistenAnzahl - 1 && kistenZuRaum[raumZuKisten[p] + 1] < p) { int tmp = kistenZuRaum[raumZuKisten[p] + 1]; kistenZuRaum[raumZuKisten[p]++] = tmp; kistenZuRaum[raumZuKisten[tmp]--] = p; } #endregion } } else { tmpRaumCheckFertig[p] = true; tmpCheckRaumPosis[checkRaumBis] = p; tmpCheckRaumTiefe[checkRaumBis] = pTiefe; checkRaumBis++; } } #endregion #region # // --- unten --- if (!tmpRaumCheckFertig[p = raumUnten[raumSpielerPos]]) { if (raumZuKisten[p] < kistenAnzahl) // steht eine Kiste auf den benachbarten Feld? { if (raumZuKisten[p2 = raumUnten[p]] == kistenAnzahl && p2 < raumAnzahl) // Feld hinter der Kiste frei? { kistenZuRaum[raumZuKisten[p2] = raumZuKisten[p]] = p2; raumZuKisten[p] = kistenAnzahl; // untere Kiste weiter nach unten schieben raumSpielerPos = p; // Spieler nach unten bewegen #region # // Kisten sortieren (sofern notwendig) while (raumZuKisten[p2] < kistenAnzahl - 1 && kistenZuRaum[raumZuKisten[p2] + 1] < p2) { int tmp = kistenZuRaum[raumZuKisten[p2] + 1]; kistenZuRaum[raumZuKisten[p2]++] = tmp; kistenZuRaum[raumZuKisten[tmp]--] = p2; } #endregion if (blocker.CheckErlaubt(raumSpielerPos, raumZuKisten)) { yield return new SokowahnStellung { raumSpielerPos = raumSpielerPos, kistenZuRaum = kistenZuRaum.TeilArray(kistenAnzahl), crc64 = Crc, zugTiefe = pTiefe }; } raumSpielerPos = tmpCheckRaumPosis[checkRaumVon]; // Spieler zurück nach oben bewegen kistenZuRaum[raumZuKisten[p] = raumZuKisten[p2]] = p; raumZuKisten[p2] = kistenAnzahl; // untere Kiste eins zurück nach oben schieben #region # // Kisten zurück sortieren (sofern notwendig) while (raumZuKisten[p] > 0 && kistenZuRaum[raumZuKisten[p] - 1] > p && raumZuKisten[p] < kistenAnzahl) { int tmp = kistenZuRaum[raumZuKisten[p] - 1]; kistenZuRaum[raumZuKisten[p]--] = tmp; kistenZuRaum[raumZuKisten[tmp]++] = p; } #endregion } } else { tmpRaumCheckFertig[p] = true; tmpCheckRaumPosis[checkRaumBis] = p; tmpCheckRaumTiefe[checkRaumBis] = pTiefe; checkRaumBis++; } } #endregion checkRaumVon++; } raumSpielerPos = tmpCheckRaumPosis[0]; // alte Spielerposition wieder herstellen }
/// <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; }