/// <summary> /// System, welche die FehlerMapErstellen erstellt /// </summary> /// <param name="würfel">Anzahl der zu testenden Würfel (muss immer weniger sein als die Ziel-Anzahl)</param> void FehlerMapErstellen(int würfel) { int[] kannFelder = Enumerable.Range(0, feldAnzahl).Where(pos => erlaubteBoxFelder[pos]).ToArray(); var ofss = new[] { -1, +1, -feldBreite, +feldBreite }; switch (würfel) { #region # case 1: // --- einzelne unerlaubte Boxen ermitteln --- case 1: { Dictionary<int, bool> spielerFertig = kannFelder.ToDictionary(p => p, p => false); foreach (int boxPos in kannFelder) { List<int> spielerGut = new List<int>(); List<int> spielerSchlecht = new List<int>(); foreach (int p in kannFelder) spielerFertig[p] = false; MapReset(true); feldData[boxPos] ^= 2; spielerFertig[boxPos] = true; foreach (int spielerPos in kannFelder.Where(pos => !spielerFertig[pos])) { #region # // --- Spieler setzen und Hash resetten --- feldData[spielerPos] ^= 8; HashFeld hashFeld = new HashFeld(0, feldData, true); hashIndex.Clear(); hashGro = hashSatzGro; feldData[spielerPos] ^= 8; #endregion #region # // --- prüfen, ob Stellung gelöst werden kann --- bool find = false; for (int hashPos = 0; hashPos < hashGro; hashPos += hashSatzGro) { hashFeld = new HashFeld(hashPos); if (hashFeld.RestWürfel == 0) // machbare Lösung gefunden? { find = true; break; } if (hashGro > hashInfoMax * hashSatzGro) { hashInfoMax *= 2; Array.Resize(ref hashInfo, hashInfoMax + 65536); } if (hashFeld.KannLinks) { HashFeld neuHash = new HashFeld(hashGro); hashInfo[hashGro / hashSatzGro] = new HashInfo(hashPos, hashFeld.BewegeLinks(neuHash)); if (!HashBekannt(neuHash)) hashGro += hashSatzGro; } if (hashFeld.KannRechts) { HashFeld neuHash = new HashFeld(hashGro); hashInfo[hashGro / hashSatzGro] = new HashInfo(hashPos, hashFeld.BewegeRechts(neuHash)); if (!HashBekannt(neuHash)) hashGro += hashSatzGro; } if (hashFeld.KannOben) { HashFeld neuHash = new HashFeld(hashGro); hashInfo[hashGro / hashSatzGro] = new HashInfo(hashPos, hashFeld.BewegeOben(neuHash)); if (!HashBekannt(neuHash)) hashGro += hashSatzGro; } if (hashFeld.KannUnten) { HashFeld neuHash = new HashFeld(hashGro); hashInfo[hashGro / hashSatzGro] = new HashInfo(hashPos, hashFeld.BewegeUnten(neuHash)); if (!HashBekannt(neuHash)) hashGro += hashSatzGro; } } #endregion #region # // --- alle zusätzlich erreichbare Spielerpositionen ermitteln --- List<int> alleSpielerPos = new List<int>(); alleSpielerPos.Add(spielerPos); spielerFertig[spielerPos] = true; for (int i = 0; i < alleSpielerPos.Count; i++) { int checkPos = alleSpielerPos[i]; foreach (int ofs in ofss) { if ((feldData[checkPos + ofs] & 3) == 0 && !alleSpielerPos.Any(p => p == checkPos + ofs)) { alleSpielerPos.Add(checkPos + ofs); if (erlaubteBoxFelder[checkPos + ofs]) spielerFertig[checkPos + ofs] = true; } } } #endregion if (find) { spielerGut.AddRange(alleSpielerPos); } else { spielerSchlecht.AddRange(alleSpielerPos); hashGro = 0; hashIndex.Clear(); } } if (spielerGut.Count == 0) erlaubteBoxFelder[boxPos] = false; } FehlerDataInit(); } break; #endregion #region # case 2: // --- unerlaubte Zweier-Kombinationen der Boxen ermitteln --- case 2: { Dictionary<int, bool> spielerFertig = kannFelder.ToDictionary(p => p, p => false); MapReset(true); for (int p1 = 0; p1 < kannFelder.Length; p1++) { int boxPos1 = kannFelder[p1]; feldData[boxPos1] ^= 2; feldZeichner.Zeichne(pictureBox1, feldData); Application.DoEvents(); for (int p2 = p1 + 1; p2 < kannFelder.Length; p2++) { int boxPos2 = kannFelder[p2]; feldData[boxPos2] ^= 2; List<int> spielerGut = new List<int>(); List<int> spielerSchlecht = new List<int>(); foreach (int p in kannFelder) spielerFertig[p] = false; spielerFertig[boxPos1] = true; spielerFertig[boxPos2] = true; foreach (int spielerPos in kannFelder.Where(pos => !spielerFertig[pos])) { #region # // --- Spieler setzen und Hash resetten --- feldData[spielerPos] ^= 8; HashFeld hashFeld = new HashFeld(0, feldData, true); hashIndex.Clear(); hashGro = hashSatzGro; feldData[spielerPos] ^= 8; #endregion #region # // --- prüfen, ob Stellung gelöst werden kann --- bool find = false; for (int hashPos = 0; hashPos < hashGro; hashPos += hashSatzGro) { hashFeld = new HashFeld(hashPos); if (hashFeld.RestWürfel == 0) // machbare Lösung gefunden? { find = true; break; } if (hashGro > hashInfoMax * hashSatzGro) { hashInfoMax *= 2; Array.Resize(ref hashInfo, hashInfoMax + 65536); } if (hashFeld.KannLinks) { HashFeld neuHash = new HashFeld(hashGro); hashInfo[hashGro / hashSatzGro] = new HashInfo(hashPos, hashFeld.BewegeLinks(neuHash)); if (!HashBekannt(neuHash)) hashGro += hashSatzGro; } if (hashFeld.KannRechts) { HashFeld neuHash = new HashFeld(hashGro); hashInfo[hashGro / hashSatzGro] = new HashInfo(hashPos, hashFeld.BewegeRechts(neuHash)); if (!HashBekannt(neuHash)) hashGro += hashSatzGro; } if (hashFeld.KannOben) { HashFeld neuHash = new HashFeld(hashGro); hashInfo[hashGro / hashSatzGro] = new HashInfo(hashPos, hashFeld.BewegeOben(neuHash)); if (!HashBekannt(neuHash)) hashGro += hashSatzGro; } if (hashFeld.KannUnten) { HashFeld neuHash = new HashFeld(hashGro); hashInfo[hashGro / hashSatzGro] = new HashInfo(hashPos, hashFeld.BewegeUnten(neuHash)); if (!HashBekannt(neuHash)) hashGro += hashSatzGro; } } #endregion #region # // --- alle zusätzlich erreichbare Spielerpositionen ermitteln --- List<int> alleSpielerPos = new List<int>(); alleSpielerPos.Add(spielerPos); spielerFertig[spielerPos] = true; for (int i = 0; i < alleSpielerPos.Count; i++) { int checkPos = alleSpielerPos[i]; foreach (int ofs in ofss) { if ((feldData[checkPos + ofs] & 3) == 0 && !alleSpielerPos.Any(p => p == checkPos + ofs)) { alleSpielerPos.Add(checkPos + ofs); if (erlaubteBoxFelder[checkPos + ofs]) spielerFertig[checkPos + ofs] = true; } } } #endregion if (find) { spielerGut.AddRange(alleSpielerPos); } else { spielerSchlecht.AddRange(alleSpielerPos); } } if (spielerGut.Count == 0 || spielerSchlecht.Count > 0) { #region # // --- Box 1 -> Box 2 --- List<short> dazu = new List<short>(); dazu.Add((short)boxPos2); if (spielerGut.Count < spielerSchlecht.Count) // nur die guten Felder merken? { dazu.Add((short)spielerGut.Count); dazu.AddRange(spielerGut.Select(pos => (short)pos)); } else // nur die schlechten Felder merken (da weniger) { dazu.Add((short)-spielerSchlecht.Count); dazu.AddRange(spielerSchlecht.Select(pos => (short)pos)); } FehlerDataUpdate(ref fehlerBox2[boxPos1], dazu); fehlerVorhanden[boxPos1] |= 1; #endregion #region # // --- Box 2 -> Box 1 --- dazu.Clear(); dazu.Add((short)boxPos1); if (spielerGut.Count < spielerSchlecht.Count) // nur die guten Felder merken? { dazu.Add((short)spielerGut.Count); dazu.AddRange(spielerGut.Select(pos => (short)pos)); } else // nur die schlechten Felder merken (da weniger) { dazu.Add((short)-spielerSchlecht.Count); dazu.AddRange(spielerSchlecht.Select(pos => (short)pos)); } FehlerDataUpdate(ref fehlerBox2[boxPos2], dazu); fehlerVorhanden[boxPos2] |= 1; #endregion } feldData[boxPos2] ^= 2; } feldData[boxPos1] ^= 2; } } break; #endregion #region # case 3: // --- unerlaubte Dreier-Kombinationen der Boxen ermitteln --- case 3: { Dictionary<int, bool> spielerFertig = kannFelder.ToDictionary(p => p, p => false); MapReset(true); for (int p1 = 0; p1 < kannFelder.Length; p1++) { int boxPos1 = kannFelder[p1]; int boxPos1x = boxPos1 % feldBreite; int boxPos1y = boxPos1 / feldBreite; feldData[boxPos1] ^= 2; for (int p2 = p1 + 1; p2 < kannFelder.Length; p2++) { int boxPos2 = kannFelder[p2]; if (FehlerCheckDirekt(boxPos2)) continue; int boxPos2x = boxPos2 % feldBreite; int boxPos2y = boxPos2 / feldBreite; if (Math.Abs(boxPos2x - boxPos1x) > 2) continue; if (Math.Abs(boxPos2y - boxPos1y) > 2) continue; feldData[boxPos2] ^= 2; feldZeichner.Zeichne(pictureBox1, feldData); Application.DoEvents(); for (int p3 = p2 + 1; p3 < kannFelder.Length; p3++) { int boxPos3 = kannFelder[p3]; if (FehlerCheckDirekt(boxPos3)) continue; int boxPos3x = boxPos3 % feldBreite; int boxPos3y = boxPos3 / feldBreite; if (Math.Abs(boxPos3x - boxPos2x) > 2 && Math.Abs(boxPos3x - boxPos1x) > 2) continue; if (Math.Abs(boxPos3y - boxPos2y) > 2 && Math.Abs(boxPos3y - boxPos1y) > 2) continue; feldData[boxPos3] ^= 2; List<int> spielerGut = new List<int>(); List<int> spielerSchlecht = new List<int>(); foreach (int p in kannFelder) spielerFertig[p] = false; spielerFertig[boxPos1] = true; spielerFertig[boxPos2] = true; spielerFertig[boxPos3] = true; foreach (int spielerPos in kannFelder.Where(pos => !spielerFertig[pos])) { #region # // --- Spieler setzen und Hash resetten --- feldData[spielerPos] ^= 8; HashFeld hashFeld = new HashFeld(0, feldData, true); hashIndex.Clear(); hashGro = hashSatzGro; feldData[spielerPos] ^= 8; #endregion #region # // --- prüfen, ob Stellung gelöst werden kann --- bool find = false; for (int hashPos = 0; hashPos < hashGro; hashPos += hashSatzGro) { hashFeld = new HashFeld(hashPos); if (hashFeld.RestWürfel == 0) // machbare Lösung gefunden? { find = true; break; } if (hashGro > hashInfoMax * hashSatzGro) { hashInfoMax *= 2; Array.Resize(ref hashInfo, hashInfoMax + 65536); } if (hashFeld.KannLinks) { HashFeld neuHash = new HashFeld(hashGro); hashInfo[hashGro / hashSatzGro] = new HashInfo(hashPos, hashFeld.BewegeLinks(neuHash)); if (!HashBekannt(neuHash)) hashGro += hashSatzGro; } if (hashFeld.KannRechts) { HashFeld neuHash = new HashFeld(hashGro); hashInfo[hashGro / hashSatzGro] = new HashInfo(hashPos, hashFeld.BewegeRechts(neuHash)); if (!HashBekannt(neuHash)) hashGro += hashSatzGro; } if (hashFeld.KannOben) { HashFeld neuHash = new HashFeld(hashGro); hashInfo[hashGro / hashSatzGro] = new HashInfo(hashPos, hashFeld.BewegeOben(neuHash)); if (!HashBekannt(neuHash)) hashGro += hashSatzGro; } if (hashFeld.KannUnten) { HashFeld neuHash = new HashFeld(hashGro); hashInfo[hashGro / hashSatzGro] = new HashInfo(hashPos, hashFeld.BewegeUnten(neuHash)); if (!HashBekannt(neuHash)) hashGro += hashSatzGro; } } #endregion #region # // --- alle zusätzlich erreichbare Spielerpositionen ermitteln --- List<int> alleSpielerPos = new List<int>(); alleSpielerPos.Add(spielerPos); spielerFertig[spielerPos] = true; for (int i = 0; i < alleSpielerPos.Count; i++) { int checkPos = alleSpielerPos[i]; foreach (int ofs in ofss) { if ((feldData[checkPos + ofs] & 3) == 0 && !alleSpielerPos.Any(p => p == checkPos + ofs)) { alleSpielerPos.Add(checkPos + ofs); if (erlaubteBoxFelder[checkPos + ofs]) spielerFertig[checkPos + ofs] = true; } } } #endregion if (find) { spielerGut.AddRange(alleSpielerPos); } else { spielerSchlecht.AddRange(alleSpielerPos); } } if (spielerGut.Count == 0 || spielerSchlecht.Count > 0) { #region # // --- Box 1 -> Box 2 + 3 --- List<short> dazu = new List<short>(); dazu.Add((short)boxPos2); dazu.Add((short)boxPos3); if (spielerGut.Count < spielerSchlecht.Count) // nur die guten Felder merken? { dazu.Add((short)spielerGut.Count); dazu.AddRange(spielerGut.Select(pos => (short)pos)); } else // nur die schlechten Felder merken (da weniger) { dazu.Add((short)-spielerSchlecht.Count); dazu.AddRange(spielerSchlecht.Select(pos => (short)pos)); } FehlerDataUpdate(ref fehlerBox3[boxPos1], dazu); fehlerVorhanden[boxPos1] |= 1; #endregion #region # // --- Box 2 -> Box 1 + 3 --- dazu.Clear(); dazu.Add((short)boxPos1); dazu.Add((short)boxPos3); if (spielerGut.Count < spielerSchlecht.Count) // nur die guten Felder merken? { dazu.Add((short)spielerGut.Count); dazu.AddRange(spielerGut.Select(pos => (short)pos)); } else // nur die schlechten Felder merken (da weniger) { dazu.Add((short)-spielerSchlecht.Count); dazu.AddRange(spielerSchlecht.Select(pos => (short)pos)); } FehlerDataUpdate(ref fehlerBox3[boxPos2], dazu); fehlerVorhanden[boxPos2] |= 1; #endregion #region # // --- Box 3 -> Box 1 + 2 --- dazu.Clear(); dazu.Add((short)boxPos1); dazu.Add((short)boxPos2); if (spielerGut.Count < spielerSchlecht.Count) // nur die guten Felder merken? { dazu.Add((short)spielerGut.Count); dazu.AddRange(spielerGut.Select(pos => (short)pos)); } else // nur die schlechten Felder merken (da weniger) { dazu.Add((short)-spielerSchlecht.Count); dazu.AddRange(spielerSchlecht.Select(pos => (short)pos)); } FehlerDataUpdate(ref fehlerBox3[boxPos3], dazu); fehlerVorhanden[boxPos3] |= 1; #endregion } feldData[boxPos3] ^= 2; } feldData[boxPos2] ^= 2; } feldData[boxPos1] ^= 2; } } break; #endregion default: throw new NotSupportedException(); } }
/// <summary> /// berechnet einen oder mehrere Schritte /// </summary> /// <param name="limit">maximal zu berechnende Schritte</param> void Tick(int limit) { zurückButton.Enabled = false; vorButton.Enabled = false; for (int lim = 0; lim < limit; lim++) { do { if (merkHashPos == hashGro) { tickButton.Text = "keine weiteren Knoten bekannt"; return; } if (hashGro > hashInfoMax * hashSatzGro) { hashInfoMax *= 2; Array.Resize(ref hashInfo, hashInfoMax + 65536); } HashFeld h = new HashFeld(merkHashPos); if (h.RestWürfel == 0) { feldZeichner.Zeichne(pictureBox1, new HashFeld(merkHashPos)); tickButton.Text = "Ziel gefunden! (" + hashIndex.Count.ToString("#,##0") + " Knoten)"; int pos = merkHashPos; List<int> posListe = new List<int>(); posListe.Add(pos); while (pos > 0) { pos = hashInfo[pos / hashSatzGro].vorgänger; posListe.Add(pos); } posListe.Reverse(); viewListe = posListe.ToArray(); viewPos = 0; zurückButton.Enabled = false; vorButton.Enabled = true; return; } if (h.KannLinks) { HashFeld neuHash = new HashFeld(hashGro); hashInfo[hashGro / hashSatzGro] = new HashInfo(merkHashPos, h.BewegeLinks(neuHash)); if (!HashBekannt(neuHash)) hashGro += hashSatzGro; } if (h.KannRechts) { HashFeld neuHash = new HashFeld(hashGro); hashInfo[hashGro / hashSatzGro] = new HashInfo(merkHashPos, h.BewegeRechts(neuHash)); if (!HashBekannt(neuHash)) hashGro += hashSatzGro; } if (h.KannOben) { HashFeld neuHash = new HashFeld(hashGro); hashInfo[hashGro / hashSatzGro] = new HashInfo(merkHashPos, h.BewegeOben(neuHash)); if (!HashBekannt(neuHash)) hashGro += hashSatzGro; } if (h.KannUnten) { HashFeld neuHash = new HashFeld(hashGro); hashInfo[hashGro / hashSatzGro] = new HashInfo(merkHashPos, h.BewegeUnten(neuHash)); if (!HashBekannt(neuHash)) hashGro += hashSatzGro; } merkHashPos += hashSatzGro; } while (merkHashPos < hashGro && !hashInfo[merkHashPos / hashSatzGro].verschoben); if (merkHashPos < hashGro) { if (lim + 1 == limit) { feldZeichner.Zeichne(pictureBox1, new HashFeld(merkHashPos)); int schritte = OptiErmitteleTiefe(merkHashPos / hashSatzGro); tickButton.Text = (hashGro / hashSatzGro).ToString("#,##0") + " Felder (" + ((double)hashGro / 1048576.0).ToString("#,##0.0") + " MB) [" + schritte + "]"; tickButton.Update(); } } else { tickButton.Text = "keine weiteren Knoten bekannt"; return; } } }