コード例 #1
0
    /// <summary>
    /// sucht die oberste und am weitestende linke Position, welche vom Spieler noch erreichbar ist
    /// </summary>
    /// <param name="field">Spielfeld, welches gescannt werden soll</param>
    /// <returns>erreichbare Spielerposition</returns>
    public static int ScanTopLeftPos(SokowahnField field)
    {
      var data = field.fieldData;
      int bestPos = int.MaxValue;
      int width = field.width;

      var scanned = new bool[data.Length];

      var next = new Stack<int>();
      next.Push(field.PlayerPos);

      while (next.Count > 0)
      {
        int checkPos = next.Pop();
        if (checkPos < bestPos) bestPos = checkPos;

        scanned[checkPos] = true;

        checkPos--;
        if (!scanned[checkPos] && (data[checkPos] == ' ' || data[checkPos] == '.')) next.Push(checkPos);

        checkPos += 2;
        if (!scanned[checkPos] && (data[checkPos] == ' ' || data[checkPos] == '.')) next.Push(checkPos);

        checkPos -= width + 1;
        if (!scanned[checkPos] && (data[checkPos] == ' ' || data[checkPos] == '.')) next.Push(checkPos);

        checkPos += width * 2;
        if (!scanned[checkPos] && (data[checkPos] == ' ' || data[checkPos] == '.')) next.Push(checkPos);
      }

      return bestPos;
    }
コード例 #2
0
    /// <summary>
    /// Konstruktor
    /// </summary>
    /// <param name="field">Spielfeld, welches betroffen ist</param>
    public DeadlockBlocker(SokowahnField field)
    {
      this.field = new SokowahnField(field);

      wayMap = SokoTools.CreateWayMap(field.fieldData, field.width, field.PlayerPos);

      blockerSingle = wayMap.SelectArray(b => !b);

      ScanBlockerSingle();
    }
コード例 #3
0
    /// <summary>
    /// fügt den Code für das Spielfeld inkl. deren Basis-Werte hinzu
    /// </summary>
    /// <param name="csFile">Cs-Datei, wo der Code hinzugefügt werden soll</param>
    /// <param name="field">Spielfeld, welches dargestellt werden soll</param>
    public static void AddLevelBasics(CsFile csFile, SokowahnField field)
    {
      var fChars = new char[field.width * field.height];

      #region # // --- static readonly char[] FieldData = ... ---
      csFile.Write("const int FieldWidth = " + field.width + ";");
      csFile.Write("const int FieldHeight = " + field.height + ";");
      csFile.Write("const int FieldCount = FieldWidth * FieldHeight;");
      csFile.Write();
      csFile.Write("static readonly char[] FieldData =", f =>
      {
        var zeile = new StringBuilder();
        for (int y = 0; y < field.height; y++)
        {
          zeile.Clear();
          zeile.Append("/* " + (y * field.width).ToString("N0").PadLeft(((field.height - 1) * field.width).ToString("N0").Length) + " */ ");
          for (int x = 0; x < field.width; x++)
          {
            char c = field.fieldData[x + y * field.width];
            fChars[x + y * field.width] = c;
            if (c != '#') c = ' ';
            zeile.Append('\'').Append(c).Append("',");
          }
          if (y == field.height - 1) zeile.Remove(zeile.Length - 1, 1);
          f.Write(zeile.ToString());
        }
      });
      csFile.WriteV(";\r\n\r\n");
      #endregion

      #region # // --- static readonly ushort[] TargetPosis ---
      var targetFields = fChars.Select((c, i) => new { c, i }).Where(f => f.c == '.' || f.c == '*').Select(f => (ushort)f.i).ToArray();
      csFile.Write("static readonly ushort[] TargetPosis = { " + string.Join(", ", targetFields) + " };");
      csFile.Write();
      #endregion

      #region # // --- static readonly ushort[] BoxPosis ---
      csFile.Write("static readonly ushort[] BoxPosis = { " + string.Join(", ", targetFields.Select(x => fChars.Length - 1)) + " };");
      csFile.Write();
      #endregion

      #region # // --- TxtView ---
      csFile.Write("static string TxtViewP(int playerPos = -1) { return SokoTools.TxtView(FieldData, FieldWidth, TargetPosis, playerPos); }");
      csFile.Write("static string TxtView { get { return TxtViewP(); } }");
      csFile.Write();
      #endregion
    }
コード例 #4
0
ファイル: Program.cs プロジェクト: MaxKlaxxMiner/SokoWahn
    /// <summary>
    /// einfaches Tool zum finden irgendeiner Lösung eines Spielfeldes
    /// </summary>
    /// <param name="field">Spielfeld, welches gescannt werden soll</param>
    static void MiniSolver(SokowahnField field)
    {
      var scanner = new SokowahnField(field);

      int stateLen = scanner.posis.Length;
      var todoBuf = new ushort[16777216 * stateLen];
      int todoPos = 0;
      int todoLen = 0;
      foreach (var p in scanner.posis) todoBuf[todoLen++] = p;

      var nextBuf = new ushort[stateLen * (stateLen - 1) * 4];

      var hashCrcs = new HashSet<ulong>();

      while (todoPos < todoLen)
      {
        scanner.SetGameState(todoBuf, todoPos);
        todoPos += stateLen;

        if (todoLen - todoPos == 0 || (hashCrcs.Count & 0xfff) == 0)
        {
          Console.Clear();
          Console.WriteLine(scanner);
          Console.WriteLine();
          Console.WriteLine("Todo: " + ((todoLen - todoPos) / stateLen).ToString("N0") + " (" + (200.0 / todoBuf.Length * (todoLen - todoPos)).ToString("N1") + " %)");
          Console.WriteLine("Hash: " + hashCrcs.Count.ToString("N0") + " (" + (100.0 / 48000000 * hashCrcs.Count).ToString("N1") + " %)");
        }

        scanner.SetPlayerTopLeft();

        var crc = scanner.GetGameStateCrc();
        if (hashCrcs.Contains(crc)) continue;
        hashCrcs.Add(crc);

        int nextCount = scanner.ScanMoves(nextBuf);
        for (int i = 0; i < nextCount * stateLen; i++) todoBuf[todoLen++] = nextBuf[i];

        if (todoPos * 2 > todoBuf.Length)
        {
          for (int i = todoPos; i < todoLen; i++) todoBuf[i - todoPos] = todoBuf[i];
          todoLen -= todoPos;
          todoPos = 0;
        }
      }
      Console.ReadLine();
    }
コード例 #5
0
    /// <summary>
    /// fügt Informationen über das Spielfeld als Kommentare im Quellcode hinzu
    /// </summary>
    /// <param name="csFile">Cs-Datei, wo der Code hinzugefügt werden soll</param>
    /// <param name="field">Spielfeld, welches dargestellt werden soll</param>
    /// <param name="headLine">Überschrift, welche über dem Level verwendet werden soll</param>
    public static void AddLevelComments(CsFile csFile, SokowahnField field, string headLine)
    {
      int commentWidth = Math.Max(field.width + 2, 35);
      commentWidth = (commentWidth + 1) / 2 * 2 + field.width % 2;
      string levelId = field.GetLevelId();

      string emptyLine = " *" + new string(' ', commentWidth - 2) + "*";
      csFile.Write("/" + new string('*', commentWidth));
      csFile.Write(emptyLine);
      csFile.Write((" *  " + new string(' ', (commentWidth - 14 - headLine.Length) / 2) + "--- " + headLine + " ---").PadRight(commentWidth, ' ') + "*");
      csFile.Write(emptyLine);
      csFile.Write(" " + new string('*', commentWidth));
      csFile.Write(emptyLine);
      csFile.Write((" *  Level-Hash: " + levelId.Remove(0, levelId.LastIndexOf('_') + 1)).PadRight(commentWidth, ' ') + "*");
      csFile.Write(emptyLine);
      csFile.Write((" *  Size      : " + field.width + " x " + field.height + " (" + (field.width * field.height).ToString("N0") + ")").PadRight(commentWidth, ' ') + "*");
      csFile.Write((" *  Boxes     : " + field.boxesCount).PadRight(commentWidth, ' ') + "*");
      csFile.Write(emptyLine);
      string centerChars = new string(' ', (commentWidth - field.width - 2) / 2);
      csFile.Write(field.ToString().Replace("\r", "").Split('\n').Select(x => " *" + centerChars + x + centerChars + "*"));
      csFile.Write(emptyLine);
      csFile.Write(" " + new string('*', commentWidth) + "/");
    }
コード例 #6
0
    /// <summary>
    /// erstellt ein vollständiges Hashbuilder-Projekt und kompiliert dieses
    /// </summary>
    /// <param name="field">Spielfeld, welches als Grundlage dient</param>
    /// <param name="solutionPath">Pfad zum Ordner, wo die Projektmappe erstellt werden soll</param>
    public static void CreateProject(SokowahnField field, string solutionPath)
    {
      var scanner = new SokowahnField(field);
      Console.WriteLine(scanner.ToString());
      Console.WriteLine();

      string levelId = scanner.GetLevelId();

      var solutionGuid = CsProject.NewGuid("S" + levelId);
      var projectGuid = CsProject.NewGuid("P" + levelId);

      string projectName = "Sokowahn_HashBuilder_" + levelId;

      var csFile = new CsFile();

      csFile.Write();
      csFile.Write();
      GenLevelTools.AddLevelComments(csFile, scanner, "Hash Builder Alpha");
      csFile.Write();
      csFile.Write();

      #region # // --- using *.* ---
      csFile.Write("#region # using *.*");
      csFile.Write();
      csFile.Write("using System;");
      csFile.Write("using System.Linq;");
      csFile.Write("using System.Collections.Generic;");
      csFile.Write("using System.Diagnostics;");
      csFile.Write();
      csFile.Write("// ReSharper disable UnusedMember.Local");
      csFile.Write();
      csFile.Write("#endregion");
      csFile.Write();
      csFile.Write();
      #endregion

      #region # // --- Program.cs ---
      csFile.Write("namespace " + projectName, ns =>
      {
        ns.Write("static unsafe class Program", cl =>
        {
          GenLevelTools.AddLevelBasics(cl, scanner);

          GenLevelTools.AddBoxFunctions(cl);

          #region # // --- static int ScanTopLeftPos(int startPos) ---
          cl.Write("static readonly int[] PlayerDirections = { -1, +1, -FieldWidth, +FieldWidth };");
          cl.Write();
          cl.Write("static readonly int[] ScanTmp = new int[FieldCount];");
          cl.Write();
          cl.Write("static int ScanTopLeftPosIntern(int* next, bool* scanned, char* fd)", sc =>
          {
            sc.Write("int bestPos = int.MaxValue;");
            sc.Write("int nextPos = 1;");
            sc.Write("while (nextPos > 0)", wh =>
            {
              wh.Write("int checkPos = next[--nextPos];");
              wh.Write("if (checkPos < bestPos) bestPos = checkPos;");
              wh.Write("scanned[checkPos] = true;");
              wh.Write("if (!scanned[checkPos - 1] && fd[checkPos - 1] == ' ') next[nextPos++] = checkPos - 1;");
              wh.Write("if (!scanned[checkPos + 1] && fd[checkPos + 1] == ' ') next[nextPos++] = checkPos + 1;");
              wh.Write("if (!scanned[checkPos - FieldWidth] && fd[checkPos - FieldWidth] == ' ') next[nextPos++] = checkPos - FieldWidth;");
              wh.Write("if (!scanned[checkPos + FieldWidth] && fd[checkPos + FieldWidth] == ' ') next[nextPos++] = checkPos + FieldWidth;");
            });
            sc.Write("return bestPos;");
          });
          cl.Write();
          cl.Write("static int ScanTopLeftPos(int startPos)", sc =>
          {
            sc.Write("fixed (int* next = ScanTmp) fixed (char* fd = FieldData)", f =>
            {
              f.Write("bool* scanned = stackalloc bool[FieldCount];");
              f.Write("*next = startPos;");
              f.Write("return ScanTopLeftPosIntern(next, scanned, fd);");
            });
          });
          cl.Write();
          #endregion

          #region # // --- static int ScanReverseMoves(int startPlayerPos, ushort[] output) ---
          cl.Write("static int ScanReverseMoves(int startPlayerPos, ushort[] output, int boxesCount)", sc =>
          {
            sc.Write("int outputLen = 0;");
            sc.Write();
            sc.Write("bool* scannedFields = stackalloc bool[FieldCount];");
            sc.Write("ushort* scanTodo = stackalloc ushort[FieldCount];");
            sc.Write();
            sc.Write("int scanTodoPos = 0;");
            sc.Write("int scanTodoLen = 0;");
            sc.Write();
            sc.Write("scanTodo[scanTodoLen++] = (ushort)startPlayerPos;");
            sc.Write("scannedFields[startPlayerPos] = true;");
            sc.Write();
            sc.Write("while (scanTodoPos < scanTodoLen)", wh =>
            {
              wh.Write("ushort scan = scanTodo[scanTodoPos++];");
              wh.Write();

              wh.Write("#region # // --- links (zurück nach rechts) ---");
              wh.Write("switch (FieldData[scan - 1])", sw =>
              {
                sw.Write("case '#': break;");
                sw.Write("case ' ': if (!scannedFields[scan - 1]) { scannedFields[scan - 1] = true; scanTodo[scanTodoLen++] = (ushort)(scan - 1); } break;");
                sw.Write("default:", bx =>
                {
                  bx.Write("if (FieldData[scan + 1] != ' ') break;");
                  bx.Write();
                  bx.Write("MoveBox((ushort)(scan - 1), scan);");
                  bx.Write();
                  bx.Write("for (int i = 0; i < boxesCount; i++) output[outputLen + i] = BoxPosis[i];");
                  bx.Write("output[outputLen + boxesCount] = (ushort)(scan + 1);");
                  bx.Write("outputLen += boxesCount + 1;");
                  bx.Write();
                  bx.Write("MoveBox(scan, (ushort)(scan - 1));");
                });
                sw.Write("break;");
              });
              wh.Write("#endregion");
              wh.Write();

              wh.Write("#region # // --- rechts (zurück nach links) ---");
              wh.Write("switch (FieldData[scan + 1])", sw =>
              {
                sw.Write("case '#': break;");
                sw.Write("case ' ': if (!scannedFields[scan + 1]) { scannedFields[scan + 1] = true; scanTodo[scanTodoLen++] = (ushort)(scan + 1); } break;");
                sw.Write("default:", bx =>
                {
                  bx.Write("if (FieldData[scan - 1] != ' ') break;");
                  bx.Write();
                  bx.Write("MoveBox((ushort)(scan + 1), scan);");
                  bx.Write();
                  bx.Write("for (int i = 0; i < boxesCount; i++) output[outputLen + i] = BoxPosis[i];");
                  bx.Write("output[outputLen + boxesCount] = (ushort)(scan - 1);");
                  bx.Write("outputLen += boxesCount + 1;");
                  bx.Write();
                  bx.Write("MoveBox(scan, (ushort)(scan + 1));");
                });
                sw.Write("break;");
              });
              wh.Write("#endregion");
              wh.Write();

              wh.Write("#region # // --- oben (zurück nach unten) ---");
              wh.Write("switch (FieldData[scan - FieldWidth])", sw =>
              {
                sw.Write("case '#': break;");
                sw.Write("case ' ': if (!scannedFields[scan - FieldWidth]) { scannedFields[scan - FieldWidth] = true; scanTodo[scanTodoLen++] = (ushort)(scan - FieldWidth); } break;");
                sw.Write("default:", bx =>
                {
                  bx.Write("if (FieldData[scan + FieldWidth] != ' ') break;");
                  bx.Write();
                  bx.Write("MoveBox((ushort)(scan - FieldWidth), scan);");
                  bx.Write();
                  bx.Write("for (int i = 0; i < boxesCount; i++) output[outputLen + i] = BoxPosis[i];");
                  bx.Write("output[outputLen + boxesCount] = (ushort)(scan + FieldWidth);");
                  bx.Write("outputLen += boxesCount + 1;");
                  bx.Write();
                  bx.Write("MoveBox(scan, (ushort)(scan - FieldWidth));");
                });
                sw.Write("break;");
              });
              wh.Write("#endregion");
              wh.Write();

              wh.Write("#region # // --- unten (zurück nach oben) ---");
              wh.Write("switch (FieldData[scan + FieldWidth])", sw =>
              {
                sw.Write("case '#': break;");
                sw.Write("case ' ': if (!scannedFields[scan + FieldWidth]) { scannedFields[scan + FieldWidth] = true; scanTodo[scanTodoLen++] = (ushort)(scan + FieldWidth); } break;");
                sw.Write("default:", bx =>
                {
                  bx.Write("if (FieldData[scan - FieldWidth] != ' ') break;");
                  bx.Write();
                  bx.Write("MoveBox((ushort)(scan + FieldWidth), scan);");
                  bx.Write();
                  bx.Write("for (int i = 0; i < boxesCount; i++) output[outputLen + i] = BoxPosis[i];");
                  bx.Write("output[outputLen + boxesCount] = (ushort)(scan - FieldWidth);");
                  bx.Write("outputLen += boxesCount + 1;");
                  bx.Write();
                  bx.Write("MoveBox(scan, (ushort)(scan + FieldWidth));");
                });
                sw.Write("break;");
              });
              wh.Write("#endregion");
              wh.Write();
            });
            sc.Write();
            sc.Write("return outputLen;");
          });
          cl.Write();
          #endregion

          #region # // --- static void Main() ---
          cl.Write("static void Main()", main =>
          {
            main.Write("for (int boxesCount = 1; boxesCount <= TargetPosis.Length; boxesCount++)", bx =>
            {
              bx.Write("int stateLen = boxesCount + 1;");
              bx.Write("var todoBuf = new ushort[16777216 / (stateLen + 1) * (stateLen + 1)];");
              bx.Write("int todoLen = 0;");
              bx.Write("var stopWatch = Stopwatch.StartNew();");
              bx.Write();

              #region # // --- Suche End-Varianten ---
              bx.Write("#region # // --- search all finish-positions -> put into \"todoBuf\" ---", sc =>
              {
                sc.Write("var checkDuplicates = new HashSet<ulong>();");
                sc.Write();
                sc.Write("foreach (var boxesVariant in SokoTools.FieldBoxesVariants(TargetPosis.Length, boxesCount).Select(v => v.Select(f => TargetPosis[f]).ToArray()))", fe =>
                {
                  fe.Write("foreach (var box in boxesVariant) FieldData[box] = '$';");
                  fe.Write();
                  fe.Write("ulong boxCrc = SokoTools.CrcCompute(SokoTools.CrcStart, boxesVariant, 0, boxesVariant.Length);");
                  fe.Write();
                  fe.Write("foreach (var box in boxesVariant)", feb =>
                  {
                    feb.Write("foreach (int playerDir in PlayerDirections)", febs =>
                    {
                      febs.Write("int playerPos = box - playerDir;");
                      febs.Write("if (FieldData[playerPos] != ' ') continue;");
                      febs.Write("if (FieldData[playerPos - playerDir] != ' ') continue;");
                      febs.Write();
                      febs.Write("ulong crc = SokoTools.CrcCompute(boxCrc, playerPos);");
                      febs.Write("if (checkDuplicates.Contains(crc)) continue;");
                      febs.Write("checkDuplicates.Add(crc);");
                      febs.Write();
                      febs.Write("int topPlayerPos = ScanTopLeftPos(playerPos);");
                      febs.Write();
                      febs.Write("if (topPlayerPos != playerPos)", febst =>
                      {
                        febst.Write("crc = SokoTools.CrcCompute(boxCrc, topPlayerPos);");
                        febst.Write("if (checkDuplicates.Contains(crc)) continue;");
                        febst.Write("checkDuplicates.Add(crc);");
                      });
                      febs.Write();
                      febs.Write("todoBuf[todoLen++] = 0;");
                      febs.Write("for(int i = 0; i < boxesVariant.Length; i++) todoBuf[todoLen + i] = boxesVariant[i];");
                      febs.Write("todoBuf[todoLen + boxesVariant.Length] = (ushort)topPlayerPos;");
                      febs.Write("todoLen += stateLen;");
                    });
                  });
                  fe.Write();
                  fe.Write("foreach (var box in boxesVariant) FieldData[box] = ' ';");
                });
              });
              bx.Write("#endregion");
              bx.Write();
              #endregion

              #region # // --- Durchsuche Rückwärts alle Möglichkeiten ---
              bx.Write("#region # // --- search all possible positions (bruteforce-reverse) ---", sc =>
              {
                sc.Write("var hash = new DictionaryFastCrc<ushort>();");
                sc.Write("var nextBuf = new ushort[stateLen * boxesCount * 4];");
                sc.Write();
                sc.Write("int todoPos = 0;");
                sc.Write("while (todoPos < todoLen)", wh =>
                {
                  wh.Write("ushort depth = todoBuf[todoPos++];");
                  wh.Write("ulong crc = SetBoxes(todoBuf, todoPos, boxesCount);");
                  wh.Write("int playerPos = ScanTopLeftPos(todoBuf[todoPos + boxesCount]);");
                  wh.Write("crc = SokoTools.CrcCompute(crc, playerPos);");
                  wh.Write();
                  wh.Write("if (hash.ContainsKey(crc))", skip =>
                  {
                    skip.Write("todoPos += stateLen;");
                    skip.Write("continue;");
                  });
                  wh.Write();
                  wh.Write("hash.Add(crc, depth);");
                  wh.Write("if ((hash.Count & 0xffff) == 0) Console.WriteLine(\"[\" + boxesCount + \"] (\" + depth + \") \" + ((todoLen - todoPos) / (stateLen + 1)).ToString(\"N0\") + \" / \" + hash.Count.ToString(\"N0\"));");
                  wh.Write();
                  wh.Write("depth++;");
                  wh.Write("int nextLength = ScanReverseMoves(playerPos, nextBuf, boxesCount);");
                  wh.Write("for (int next = 0; next < nextLength; next += stateLen)", f =>
                  {
                    f.Write("todoBuf[todoLen++] = depth;");
                    f.Write("for (int i = 0; i < stateLen; i++) todoBuf[todoLen++] = nextBuf[next + i];");
                  });
                  wh.Write();
                  wh.Write("todoPos += stateLen;");
                  wh.Write("if (todoBuf.Length - todoLen < nextLength * 2)", arr =>
                  {
                    arr.Write("Array.Copy(todoBuf, todoPos, todoBuf, 0, todoLen - todoPos);");
                    arr.Write("todoLen -= todoPos;");
                    arr.Write("todoPos = 0;");
                  });
                });
                sc.Write("stopWatch.Stop();");
                sc.Write("Console.WriteLine();");
                sc.Write("Console.ForegroundColor = ConsoleColor.Yellow;");
                sc.Write("Console.WriteLine(\"[\" + boxesCount + \"] ok. Hash: \" + hash.Count.ToString(\"N0\") + \" (\" + stopWatch.ElapsedMilliseconds.ToString(\"N0\") + \" ms)\");");
                sc.Write("Console.ForegroundColor = ConsoleColor.Gray;");
                sc.Write("Console.WriteLine();");
              });
              bx.Write("#endregion");
              #endregion
            });
          });
          #endregion
        });
      });

      csFile.SaveToFile(solutionPath + "Program.cs");
      #endregion

      var csSokoTools = GenStaticTools.GenSokoTools(projectName);
      csSokoTools.SaveToFile(solutionPath + "SokoTools.cs");

      var csDictFast = GenStaticTools.GenDictionaryFastCrc(projectName);
      csDictFast.SaveToFile(solutionPath + "DictionaryFastCrc.cs");

      var projectFile = CsProject.CreateCsProjectFile(projectGuid, projectName, new[] { "System" }, new[] { "Program.cs", "SokoTools.cs", "DictionaryFastCrc.cs" });
      projectFile.SaveToFile(solutionPath + projectName + ".csproj");

      var solutionFile = CsProject.CreateSolutionFile(solutionGuid, projectGuid, "Sokowahn", projectName + ".csproj");
      solutionFile.SaveToFile(solutionPath + projectName + ".sln");

      CsCompiler.Compile(solutionPath + projectName + ".sln");
    }
コード例 #7
0
    /// <summary>
    /// Konstruktor
    /// </summary>
    /// <param name="sokowahnField">vorhandenes Sokowahn-Spielfeld, kopiert werden soll</param>
    /// <param name="gameState">optionaler Spielstatus, welcher stattdessen verwendet werden soll</param>
    public SokowahnField(SokowahnField sokowahnField, ushort[] gameState = null)
    {
      width = sokowahnField.width;
      height = sokowahnField.height;
      fieldData = sokowahnField.fieldData.ToArray();
      boxesCount = sokowahnField.boxesCount;

      boxesRemain = sokowahnField.boxesRemain;
      posis = sokowahnField.posis.ToArray();

      if (gameState != null) SetGameState(gameState);
    }
コード例 #8
0
ファイル: Form1.cs プロジェクト: MaxKlaxxMiner/SokoWahn
 void Form1_Load(object sender, EventArgs e)
 {
   var playField = new SokowahnField(TestData.Level3);
   drawSystem.DrawField(playField);
 }
コード例 #9
0
ファイル: Program.cs プロジェクト: MaxKlaxxMiner/SokoWahn
    /// <summary>
    /// analysiert alle möglichen Kistenstellungen mit einfachen (langsamen) Methoden
    /// </summary>
    /// <param name="field">Feld, welches durchsucht werden soll</param>
    /// <param name="minBoxes">minimale Anzahl der Kisten, welche berechnet werden sollen</param>
    /// <param name="maxBoxes">maximale Anzahl der Kisten, welche berechnet werden sollen</param>
    static List<Dictionary<ulong, ushort>> MiniSolverHashBuilder(SokowahnField field, int minBoxes = 1, int maxBoxes = int.MaxValue)
    {
      var scanner = new SokowahnField(field);

      var targetFields = scanner.fieldData.Select((c, i) => new { c, i }).Where(f => f.c == '.' || f.c == '*').Select(f => (ushort)f.i).ToArray();
      if (targetFields.Length < maxBoxes) maxBoxes = targetFields.Length;
      if (minBoxes < 1 || minBoxes > maxBoxes) throw new ArgumentException("minBoxes");

      var hashResults = new List<Dictionary<ulong, ushort>>();

      for (int boxesCount = minBoxes; boxesCount <= maxBoxes; boxesCount++)
      {

        // --- Variablen initialisieren ---
        var boxes = new ushort[boxesCount];
        int stateLen = 1 + boxes.Length;
        var todoBuf = new ushort[16777216 * 2 / (stateLen + 1) * (stateLen + 1)];
        int todoPos = 0, todoLen = 0;
        var stopWatch = Stopwatch.StartNew();

        // --- Startaufgaben scannen und setzen ---
        {
          int emptyPlayerPos = scanner.fieldData.ToList().IndexOf(' ');
          int[] playerDirections = { -1, +1, -scanner.width, +scanner.width };
          var checkDuplicates = new HashSet<ulong>();

          foreach (var boxesVariant in SokoTools.FieldBoxesVariantsStatic(targetFields.Length, boxesCount).Select(v => v.SelectArray(f => targetFields[f])))
          {
            scanner.SetPlayerPos(emptyPlayerPos);
            scanner.SetBoxes(boxesVariant);
            var fieldData = scanner.fieldData;
            foreach (ushort box in boxesVariant)
            {
              foreach (int playerDir in playerDirections)
              {
                int playerPos = box - playerDir;
                if (fieldData[playerPos] == '#' || fieldData[playerPos] == '$' || fieldData[playerPos] == '*') continue;
                int revPos = playerPos - playerDir;
                if (fieldData[revPos] == '#' || fieldData[revPos] == '$' || fieldData[revPos] == '*') continue;

                scanner.SetPlayerPos(playerPos);
                scanner.SetPlayerTopLeft();

                ulong crc = scanner.GetGameStateCrc();
                if (checkDuplicates.Contains(crc)) continue;
                checkDuplicates.Add(crc);

                todoBuf[todoLen++] = 0;
                todoLen += scanner.GetGameState(todoBuf, todoLen);
              }
            }
          }
        }

        Console.WriteLine(field.ToString());
        Console.WriteLine();

        // --- Aufgaben weiter rückwärts gerichtet abarbeiten ---
        {
          var hash = new Dictionary<ulong, ushort>();
          var nextBuf = new ushort[stateLen * boxesCount * 4];
          int limitTickCount = Environment.TickCount + 1000;

          while (todoPos < todoLen)
          {
            ushort depth = todoBuf[todoPos++];
            scanner.SetGameState(todoBuf, todoPos); todoPos += stateLen;
            scanner.SetPlayerTopLeft();

            ulong crc = scanner.GetGameStateCrc();
            if (hash.ContainsKey(crc)) continue;
            hash.Add(crc, depth);

            if ((hash.Count & 0xff) == 0 && Environment.TickCount > limitTickCount)
            {
              limitTickCount = Environment.TickCount + 1000;
              Console.WriteLine("[" + boxesCount + "] (" + depth + ") " + ((todoLen - todoPos) / (stateLen + 1)).ToString("N0") + " / " + hash.Count.ToString("N0"));
            }

            depth++;
            int nextLength = scanner.ScanReverseMoves(nextBuf) * stateLen;
            for (int next = 0; next < nextLength; next += stateLen)
            {
              todoBuf[todoLen++] = depth;
              for (int i = 0; i < stateLen; i++) todoBuf[todoLen++] = nextBuf[next + i];
            }
            if (todoBuf.Length - todoLen < nextLength * 2)
            {
              Array.Copy(todoBuf, todoPos, todoBuf, 0, todoLen - todoPos);
              todoLen -= todoPos;
              todoPos = 0;
            }
          }
          stopWatch.Stop();
          Console.WriteLine();
          Console.ForegroundColor = ConsoleColor.Yellow;
          Console.WriteLine("[" + boxesCount + "] ok. Hash: " + hash.Count.ToString("N0") + " (" + stopWatch.ElapsedMilliseconds.ToString("N0") + " ms)");
          Console.ForegroundColor = ConsoleColor.Gray;
          Console.WriteLine();

          hashResults.Add(hash);
        }
      }

      return hashResults;
    }
コード例 #10
0
ファイル: Program.cs プロジェクト: MaxKlaxxMiner/SokoWahn
    static void ScanBlocker(SokowahnField field)
    {
      Console.WriteLine(field.ToString());
      Console.WriteLine();

      var test = new DeadlockBlocker(field);

      int width = field.width;
      var allPossibleBoxPositions = test.blockerSingle.Select((b, i) => new { b, i }).Where(x => !x.b).SelectArray(x => x.i);
      int boxDistanceLimit = SokoTools.MaxBoxDistance(allPossibleBoxPositions, 0, allPossibleBoxPositions.Length, width);

      var areas = new int[field.fieldData.Length];
      int boxCount = 2;
      var nextBuf = new ushort[boxCount * 4 * (boxCount + 1)];

      for (int boxDistance = 1; boxDistance <= boxDistanceLimit; boxDistance++)
      {
        Func<int[], int, bool> validateMethod = (boxes, index) => !test.blockerSingle[boxes[index]] && SokoTools.MaxBoxDistance(boxes, 0, index + 1, width) <= boxDistance;

        foreach (var set in SokoTools.FieldBoxesVariantsExtended(field.fieldData.Length, boxCount, validateMethod))
        {
          if (test.blockerSingle[set[set.Length - 1]]) continue;
          if (SokoTools.MaxBoxDistance(set, 0, set.Length, width) != boxDistance) continue;

          test.ScanAreasWithBoxes(set, areas);

          field.SetGameState(areas[2], set.SelectArray(x => (ushort)x));

          if (field.boxesRemain == 0) continue;

          int nextCount = field.ScanMoves(nextBuf);
          if (nextCount == 0)
          {
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("--- DEAD ---\r\n");
            Console.ForegroundColor = ConsoleColor.Gray;
          }

          Console.WriteLine(field.ToString());
          if (nextCount == 0)
          {
            int stop = 0;
          }
        }
      }

    }
コード例 #11
0
ファイル: Program.cs プロジェクト: MaxKlaxxMiner/SokoWahn
    static void ScanTopLeftFields(SokowahnField field)
    {
      boxesHash = new Dictionary<int, HashSet<ulong>>();
      for (int b = 1; b <= field.boxesCount; b++)
      {
        Console.Clear();
        Console.WriteLine();
        for (int known = 1; known < b; known++)
        {
          Console.WriteLine(" known Boxes: " + known + " - Hash: " + boxesHash[known].Count.ToString("N0") + " Nodes");
        }
        Console.WriteLine();
        Console.WriteLine(" --- Calc Boxes: " + b + " ---");
        Console.WriteLine();
        int time = Environment.TickCount;
        var hash = MiniSolverHashBuilder(field, b, b);
        time = Environment.TickCount - time;
        boxesHash.Add(b, new HashSet<ulong>(hash.First().Keys));
        if (time > 10000) break;
        if (time > 250 && b == field.boxesCount - 1) break;
      }
      Console.Clear();

      var view = new SokowahnField(field);
      int maxBoxes = field.boxesCount;

      int width = field.width;
      var ways = FilterWays((ushort)field.PlayerPos, width, new HashSet<ushort>(Enumerable.Range(0, field.fieldData.Length).Select(f => (ushort)f)), new HashSet<ushort>(field.fieldData.Select((c, i) => new { c, i = (ushort)i }).Where(x => x.c == '#').Select(x => x.i)));

      #region # // --- ungültige Einzel-Box Positionen suchen ---
      invalidBoxes = new HashSet<ushort>();
      foreach (ushort box in ways)
      {
        var checkCrc = new List<ulong>();
        if (ways.Contains((ushort)(box - 1)))
        {
          view.SetGameState(new[] { (ushort)(box - 1), box });
          view.SetPlayerTopLeft();
          checkCrc.Add(view.GetGameStateCrc());
        }
        if (ways.Contains((ushort)(box + 1)))
        {
          view.SetGameState(new[] { (ushort)(box + 1), box });
          view.SetPlayerTopLeft();
          checkCrc.Add(view.GetGameStateCrc());
        }
        if (ways.Contains((ushort)(box - width)))
        {
          view.SetGameState(new[] { (ushort)(box - width), box });
          view.SetPlayerTopLeft();
          checkCrc.Add(view.GetGameStateCrc());
        }
        if (ways.Contains((ushort)(box + width)))
        {
          view.SetGameState(new[] { (ushort)(box + width), box });
          view.SetPlayerTopLeft();
          checkCrc.Add(view.GetGameStateCrc());
        }
        if (!checkCrc.Any(crc => boxesHash[1].Contains(crc)))
        {
          invalidBoxes.Add(box);
        }
      }
      #endregion

      var todo = new Queue<TopLeftTodo>();
      var map = new List<int> { ways.Count };

      foreach (var f in ways.OrderBy(x => x))
      {
        map.Add(0); // Index Platzhalter
        todo.Enqueue(new TopLeftTodo { mapIndex = map.Count - 1, state = new[] { f }, known = new ushort[0] });
      }

      int tick = 0;
      int nextTick = 0;
      while (todo.Count > 0)
      {
        bool dbg = false;

        if (map.Count > nextTick)
        {
          int t = Environment.TickCount;
          if (t > tick + 100)
          {
            Console.Title = "remain: " + todo.Count.ToString("N0") + " / " + map.Count.ToString("N0") + " (" + (Process.GetCurrentProcess().WorkingSet64 / 1048576.0).ToString("N1") + " MB)";
            tick = t;
            dbg = true;
          }
          nextTick += 1000;
        }

        var next = todo.Dequeue();
        var result = TestScan(width, next, ways, view, dbg);

        if (result != null)
        {
          if (result.Length <= 1)
          {
            map[next.mapIndex] = -result[0];
          }
          else
          {
            map[next.mapIndex] = map.Count;
            map.Add(result.Length - 1);
            var known = new HashSet<ushort>(next.known);
            for (int r = 1; r < result.Length; r++)
            {
              map.Add(result[r]);
              known.Add(result[r]);
              map.Add(0);  // Index Platzhalter
              if (next.state.Length <= maxBoxes)
              {
                var newState = AppendBoxesNewArray(next.state, result[r]);
                newState[0] = result[r - 1];
                todo.Enqueue(new TopLeftTodo { mapIndex = map.Count - 1, state = newState, lastBox = result[r], known = known.ToArray() });
              }
            }
          }
        }
        else
        {
          map[next.mapIndex] = -1; // ungültige Position
          if (dbg)
          {
            nextTick -= 1000;
            tick = 0;
          }
        }
      }

      Console.WriteLine();
      Console.WriteLine("Map-Size: " + map.Count.ToString("N0") + " (" + (map.Count / 262144.0).ToString("N1") + " MB)");
      Console.WriteLine();
    }
コード例 #12
0
ファイル: Program.cs プロジェクト: MaxKlaxxMiner/SokoWahn
    static bool CheckDeadlock(TopLeftTodo topLeftTodo, SokowahnField view, ushort playerTopLeft)
    {
      HashSet<ulong> bHash;
      int boxesCount = topLeftTodo.state.Length - 1;
      if (boxesHash.TryGetValue(boxesCount, out bHash))
      {
        ulong crc = Crc64.Start.Crc64Update(playerTopLeft).Crc64Update(topLeftTodo.state, 1, boxesCount);
        if (!bHash.Contains(crc))
        {
          return true;
        }
      }
      else
      {
        // --- schnelle Vorprüfung ---
        for (int b = 1; b < topLeftTodo.state.Length; b++)
        {
          if (invalidBoxes.Contains(topLeftTodo.state[b])) return true;
        }

        // --- bestmögliche Hashprüfung ---
        int boxesCountMin = boxesHash.Count;
        bHash = boxesHash[boxesCountMin];
        var checkBoxes = topLeftTodo.state.Skip(1).Where(b => b != topLeftTodo.lastBox).ToArray();
        var checkState = new ushort[1 + boxesCountMin];
        checkState[0] = playerTopLeft;
        foreach (var variant in SokoTools.FieldBoxesVariantsStatic(checkBoxes.Length, boxesCountMin - 1))
        {
          for (int v = 0; v < variant.Length; v++) checkState[v + 1] = checkBoxes[variant[v]];
          AppendBoxes(checkState, topLeftTodo.lastBox);
          view.SetGameState(checkState);
          view.SetPlayerTopLeft();
          ulong crc = view.GetGameStateCrc();
          if (!bHash.Contains(crc))
          {
            return true;
          }
        }
      }
      return false;
    }
コード例 #13
0
    /// <summary>
    /// scannt nach einzelnen Felder-Positionen, wo keine Kisten stehen dürfen
    /// </summary>
    void ScanBlockerSingle()
    {
      var targetFields = field.fieldData.Select((c, i) => new { c, i }).Where(f => wayMap[f.i] && (f.c == '.' || f.c == '*')).Select(f => (ushort)f.i).ToArray();
      var boxFields = field.fieldData.Select((c, i) => new { c, i }).Where(f => wayMap[f.i] && (f.c == '$' || f.c == '*')).Select(f => (ushort)f.i).ToArray();

      var scanner = new SokowahnField(field);
      var fieldData = scanner.fieldData;
      int emptyPlayerPos = scanner.fieldData.ToList().IndexOf(' ');
      int[] playerDirections = { -1, +1, -scanner.width, +scanner.width };
      var todoStates = new Queue<ushort[]>();
      const int StateLen = 2;

      #region # // --- Rückwärts-Suche vorbereiten ---
      foreach (ushort box in targetFields)
      {
        scanner.SetGameState(new[] { (ushort)emptyPlayerPos, box });
        foreach (int playerDir in playerDirections)
        {
          int playerPos = box - playerDir;
          if (fieldData[playerPos] == '#' || fieldData[playerPos] == '$' || fieldData[playerPos] == '*') continue;
          int revPos = playerPos - playerDir;
          if (fieldData[revPos] == '#' || fieldData[revPos] == '$' || fieldData[revPos] == '*') continue;

          scanner.SetPlayerPos(playerPos);
          scanner.SetPlayerTopLeft();

          todoStates.Enqueue(scanner.GetGameState());
        }
      }
      #endregion

      #region # // --- Rückwärts-Suche durchführen ---
      var reverseHash = new HashSet<ulong>(); // alle Stellungen, welche mit einer Kiste rückwärts erreichbar sind
      var nextBuf = new ushort[StateLen * (1) * 4];
      while (todoStates.Count > 0)
      {
        scanner.SetGameState(todoStates.Dequeue());
        scanner.SetPlayerTopLeft();

        ulong crc = scanner.GetGameStateCrc();
        if (reverseHash.Contains(crc)) continue;
        reverseHash.Add(crc);


        int nextLength = scanner.ScanReverseMoves(nextBuf) * StateLen;
        for (int next = 0; next < nextLength; next += StateLen)
        {
          todoStates.Enqueue(new[] { nextBuf[next], nextBuf[next + 1] });
        }
      }
      #endregion

      #region # // --- Vorwärts-Suche vorbereiten ---
      foreach (ushort box in boxFields)
      {
        todoStates.Enqueue(new[] { (ushort)field.PlayerPos, box });
      }
      #endregion

      #region # // --- Vorwärts-Suche durchführen ---
      var forwardHash = new HashSet<ulong>(); // alle Stellungen, welche mit einer Kiste vorwärts erreichbar sind
      var forwardBoxPosis = new HashSet<ushort>(); // alle Positionen, wo eine Kiste stehen könnte
      while (todoStates.Count > 0)
      {
        var gameState = todoStates.Dequeue();
        scanner.SetGameState(gameState);
        scanner.SetPlayerTopLeft();

        ulong crc = scanner.GetGameStateCrc();
        if (forwardHash.Contains(crc)) continue;
        forwardHash.Add(crc);
        if (!reverseHash.Contains(crc)) continue;

        forwardBoxPosis.Add(gameState[1]);

        int nextLength = scanner.ScanMoves(nextBuf) * StateLen;
        for (int next = 0; next < nextLength; next += StateLen)
        {
          todoStates.Enqueue(new[] { nextBuf[next], nextBuf[next + 1] });
        }
      }
      #endregion

      #region # // --- geblockte Felder markieren, wo niemals eine Kiste stehen darf ---
      for (ushort i = 0; i < blockerSingle.Length; i++)
      {
        if (!blockerSingle[i] && !forwardBoxPosis.Contains(i))
        {
          blockerSingle[i] = true;
        }
      }
      #endregion
    }
コード例 #14
0
    void UpdateScreen(SokowahnField field)
    {
      if (playField.width != drawField.width || playField.height != drawField.height)
      {
        throw new NotImplementedException("Resize Screen");
      }

      var drawData = drawField.fieldData;
      var f = field.fieldData;
      int w = field.width;

      var minField = new PointInt(int.MaxValue, int.MaxValue);
      var maxField = new PointInt(int.MinValue, int.MinValue);

      int tickLimit = Environment.TickCount + 1000;
      for (int y = 0; y < field.height; y++)
      {
        if (Environment.TickCount > tickLimit) return;
        for (int x = 0; x < w; x++)
        {
          char c = f[x + y * w];
          if (drawData[x + y * w] == c) continue;

          if (x < minField.x) minField.x = x;
          if (y < minField.y) minField.y = y;
          if (x > maxField.x) maxField.x = x;
          if (y > maxField.y) maxField.y = y;

          drawData[x + y * w] = c;
          switch (c)
          {
            case ' ': MaleTestbild(viewContext, skinContext, x, y, BildElement.Frei); break;
            case '.': MaleTestbild(viewContext, skinContext, x, y, BildElement.Frei); MaleTestbild(viewContext, skinContext, x, y, BildElement.FreiZiel); break;
            case '$': MaleTestbild(viewContext, skinContext, x, y, BildElement.Frei); MaleTestbild(viewContext, skinContext, x, y, BildElement.KisteOffen); break;
            case '*': MaleTestbild(viewContext, skinContext, x, y, BildElement.Frei); MaleTestbild(viewContext, skinContext, x, y, BildElement.KisteZiel); break;
            case '@': MaleTestbild(viewContext, skinContext, x, y, BildElement.Frei); MaleTestbild(viewContext, skinContext, x, y, BildElement.Spieler); break;
            case '+': MaleTestbild(viewContext, skinContext, x, y, BildElement.Frei); MaleTestbild(viewContext, skinContext, x, y, BildElement.FreiZiel); MaleTestbild(viewContext, skinContext, x, y, BildElement.Spieler); break;
            case '#':
            {
              MaleTestbild(viewContext, skinContext, x, y, BildElement.Frei);

              var lo = BildElement.WandVoll;
              var ro = BildElement.WandVoll;
              var lu = BildElement.WandVoll;
              var ru = BildElement.WandVoll;

              if (GetF(f, x - 1, y, w) && GetF(f, x, y - 1, w)) lo = BildElement.WandSpitzen;
              if (GetF(f, x - 1, y, w) && !GetF(f, x, y - 1, w)) lo = BildElement.WandSenkrecht;
              if (!GetF(f, x - 1, y, w) && GetF(f, x, y - 1, w)) lo = BildElement.WandWaagerecht;
              if (!GetF(f, x - 1, y, w) && !GetF(f, x, y - 1, w)) lo = GetF(f, x - 1, y - 1, w) ? BildElement.WandEcken : BildElement.WandVoll;

              if (GetF(f, x + 1, y, w) && GetF(f, x, y - 1, w)) ro = BildElement.WandSpitzen;
              if (GetF(f, x + 1, y, w) && !GetF(f, x, y - 1, w)) ro = BildElement.WandSenkrecht;
              if (!GetF(f, x + 1, y, w) && GetF(f, x, y - 1, w)) ro = BildElement.WandWaagerecht;
              if (!GetF(f, x + 1, y, w) && !GetF(f, x, y - 1, w)) ro = GetF(f, x + 1, y - 1, w) ? BildElement.WandEcken : BildElement.WandVoll;

              if (GetF(f, x - 1, y, w) && GetF(f, x, y + 1, w)) lu = BildElement.WandSpitzen;
              if (GetF(f, x - 1, y, w) && !GetF(f, x, y + 1, w)) lu = BildElement.WandSenkrecht;
              if (!GetF(f, x - 1, y, w) && GetF(f, x, y + 1, w)) lu = BildElement.WandWaagerecht;
              if (!GetF(f, x - 1, y, w) && !GetF(f, x, y + 1, w)) lu = GetF(f, x - 1, y + 1, w) ? BildElement.WandEcken : BildElement.WandVoll;

              if (GetF(f, x + 1, y, w) && GetF(f, x, y + 1, w)) ru = BildElement.WandSpitzen;
              if (GetF(f, x + 1, y, w) && !GetF(f, x, y + 1, w)) ru = BildElement.WandSenkrecht;
              if (!GetF(f, x + 1, y, w) && GetF(f, x, y + 1, w)) ru = BildElement.WandWaagerecht;
              if (!GetF(f, x + 1, y, w) && !GetF(f, x, y + 1, w)) ru = GetF(f, x + 1, y + 1, w) ? BildElement.WandEcken : BildElement.WandVoll;

              MaleTestbild(viewContext, skinContext, x, y, lo, BildTeile.LinksOben);
              MaleTestbild(viewContext, skinContext, x, y, ro, BildTeile.RechtsOben);
              MaleTestbild(viewContext, skinContext, x, y, lu, BildTeile.LinksUnten);
              MaleTestbild(viewContext, skinContext, x, y, ru, BildTeile.RechtsUnten);
            } break;
            default: throw new Exception("unknown Char: '" + c + "'");
          }
        }
      }

      if (minField.x != int.MaxValue)
      {
        maxField.x = maxField.x - minField.x + 1;
        maxField.y = maxField.y - minField.y + 1;
        viewContext.Present(minField.x * BoxPixelWidth, minField.y * BoxPixelHeight, maxField.x * BoxPixelWidth, maxField.y * BoxPixelHeight);
      }
    }
コード例 #15
0
ファイル: Program.cs プロジェクト: MaxKlaxxMiner/SokoWahn
 /// <summary>
 /// analysiert alle möglichen Kistenstellungen mit spezialkompilierten Hochleistungs-Methoden
 /// </summary>
 /// <param name="field">Feld, welches durchsucht werden soll</param>
 static void MiniSolverHashBuilder2(SokowahnField field)
 {
   CreateHashBuilder.CreateProject(field, PathTest);
 }
コード例 #16
0
ファイル: DrawSystem.cs プロジェクト: MaxKlaxxMiner/SokoWahn
    /// <summary>
    /// zeichnet ein bestimmtes Spielfeld
    /// </summary>
    /// <param name="field">Spielfeld, welches gezeichnet werden soll</param>
    public void DrawField(SokowahnField field)
    {
      if (field.width != drawField.width || field.height != drawField.height)
      {
        drawField = new SokowahnField(field);
        Init();
      }

      var drawData = drawField.fieldData;
      var f = field.fieldData;
      int w = field.width;

      var minField = new PointInt(int.MaxValue, int.MaxValue);
      var maxField = new PointInt(int.MinValue, int.MinValue);

      for (int y = 0; y < field.height; y++)
      {
        for (int x = 0; x < w; x++)
        {
          char c = f[x + y * w];
          if (drawData[x + y * w] == c) continue;

          if (x < minField.x) minField.x = x;
          if (y < minField.y) minField.y = y;
          if (x > maxField.x) maxField.x = x;
          if (y > maxField.y) maxField.y = y;

          drawData[x + y * w] = c;
          skin.BlitSprite(drawBitmap, x, y, SpriteType.Empty);
          switch (c)
          {
            case ' ': break;
            case '.': skin.BlitSprite(drawBitmap, x, y, SpriteType.EmptyFinish); break;
            case '$': skin.BlitSprite(drawBitmap, x, y, SpriteType.Box); break;
            case '*': skin.BlitSprite(drawBitmap, x, y, SpriteType.BoxFinish); break;
            case '@': skin.BlitSprite(drawBitmap, x, y, SpriteType.Player); break;
            case '+': skin.BlitSprite(drawBitmap, x, y, SpriteType.EmptyFinish); skin.BlitSprite(drawBitmap, x, y, SpriteType.Player); break;
            case '#':
            {
              var lo = SpriteType.WallFill;
              var ro = SpriteType.WallFill;
              var lu = SpriteType.WallFill;
              var ru = SpriteType.WallFill;

              if (CheckField(f, x - 1, y, w) && CheckField(f, x, y - 1, w)) lo = SpriteType.WallEdge;
              if (CheckField(f, x - 1, y, w) && !CheckField(f, x, y - 1, w)) lo = SpriteType.WallVertical;
              if (!CheckField(f, x - 1, y, w) && CheckField(f, x, y - 1, w)) lo = SpriteType.WallHorizon;
              if (!CheckField(f, x - 1, y, w) && !CheckField(f, x, y - 1, w)) lo = CheckField(f, x - 1, y - 1, w) ? SpriteType.WallCorner : SpriteType.WallFill;

              if (CheckField(f, x + 1, y, w) && CheckField(f, x, y - 1, w)) ro = SpriteType.WallEdge;
              if (CheckField(f, x + 1, y, w) && !CheckField(f, x, y - 1, w)) ro = SpriteType.WallVertical;
              if (!CheckField(f, x + 1, y, w) && CheckField(f, x, y - 1, w)) ro = SpriteType.WallHorizon;
              if (!CheckField(f, x + 1, y, w) && !CheckField(f, x, y - 1, w)) ro = CheckField(f, x + 1, y - 1, w) ? SpriteType.WallCorner : SpriteType.WallFill;

              if (CheckField(f, x - 1, y, w) && CheckField(f, x, y + 1, w)) lu = SpriteType.WallEdge;
              if (CheckField(f, x - 1, y, w) && !CheckField(f, x, y + 1, w)) lu = SpriteType.WallVertical;
              if (!CheckField(f, x - 1, y, w) && CheckField(f, x, y + 1, w)) lu = SpriteType.WallHorizon;
              if (!CheckField(f, x - 1, y, w) && !CheckField(f, x, y + 1, w)) lu = CheckField(f, x - 1, y + 1, w) ? SpriteType.WallCorner : SpriteType.WallFill;

              if (CheckField(f, x + 1, y, w) && CheckField(f, x, y + 1, w)) ru = SpriteType.WallEdge;
              if (CheckField(f, x + 1, y, w) && !CheckField(f, x, y + 1, w)) ru = SpriteType.WallVertical;
              if (!CheckField(f, x + 1, y, w) && CheckField(f, x, y + 1, w)) ru = SpriteType.WallHorizon;
              if (!CheckField(f, x + 1, y, w) && !CheckField(f, x, y + 1, w)) ru = CheckField(f, x + 1, y + 1, w) ? SpriteType.WallCorner : SpriteType.WallFill;

              skin.BlitSprite(drawBitmap, x, y, lo, SpriteParts.TopLeft);
              skin.BlitSprite(drawBitmap, x, y, ro, SpriteParts.TopRight);
              skin.BlitSprite(drawBitmap, x, y, lu, SpriteParts.BottomLeft);
              skin.BlitSprite(drawBitmap, x, y, ru, SpriteParts.BottomRight);
            } break;
            default: throw new Exception("unknown Char: '" + c + "'");
          }
        }
      }

      if (minField.x != int.MaxValue)
      {
        maxField.x = maxField.x - minField.x + 1;
        maxField.y = maxField.y - minField.y + 1;
        drawBitmap.Present(pictureBitmap, minField.x * skin.spriteSize.w, minField.y * skin.spriteSize.h, maxField.x * skin.spriteSize.w, maxField.y * skin.spriteSize.h);
      }
    }
コード例 #17
0
ファイル: MiniGame.cs プロジェクト: MaxKlaxxMiner/SokoWahn
    /// <summary>
    /// startet ein Mini-Konsolen Spiel
    /// </summary>
    /// <param name="field">Spielfeld, was gespielt werden soll</param>
    public static void Run(SokowahnField field)
    {
      var game = new SokowahnField(field);
      var steps = new Stack<ushort[]>();

      for (; ; )
      {
        string output = game.ToString();
        int playerChar = output.IndexOfAny(new[] { '@', '+' });

        Console.Clear();
        Console.ForegroundColor = ConsoleColor.Gray;
        Console.Write(output.Substring(0, playerChar));

        Console.ForegroundColor = ConsoleColor.Yellow;
        Console.Write(output[playerChar]);

        Console.ForegroundColor = ConsoleColor.Gray;
        Console.Write(output.Remove(0, playerChar + 1));

        Console.WriteLine(); Console.WriteLine();
        Console.WriteLine("Steps:  " + steps.Count.ToString("N0"));
        Console.WriteLine();
        Console.WriteLine("Remain: " + game.boxesRemain);

        if (game.boxesRemain == 0) return;

        bool step = false;
        var oldState = game.GetGameState();

        switch (Console.ReadKey(true).Key)
        {
          case ConsoleKey.Escape: return;

          case ConsoleKey.A:
          case ConsoleKey.NumPad4:
          case ConsoleKey.LeftArrow: step = game.MoveLeft(); break;

          case ConsoleKey.D:
          case ConsoleKey.NumPad6:
          case ConsoleKey.RightArrow: step = game.MoveRight(); break;

          case ConsoleKey.W:
          case ConsoleKey.NumPad8:
          case ConsoleKey.UpArrow: step = game.MoveUp(); break;

          case ConsoleKey.S:
          case ConsoleKey.NumPad2:
          case ConsoleKey.DownArrow: step = game.MoveDown(); break;

          case ConsoleKey.Z:
          case ConsoleKey.Delete:
          case ConsoleKey.Backspace:
          {
            if (steps.Count == 0) break;
            game.SetGameState(steps.Pop(), 0);
          } break;

          default: continue;
        }

        if (step)
        {
          steps.Push(oldState);
        }
      }
    }
コード例 #18
0
    void InitGame(string gameTxt)
    {
      playField = new SokowahnField(gameTxt);
      undoList.Clear();
      undoList.Push(playField.GetGameState());
      drawField = new SokowahnField(playField);
      for (int i = 0; i < drawField.fieldData.Length; i++) drawField.fieldData[i] = '-';

      int width = playField.width * BoxPixelWidth * Multi;
      int height = playField.height * BoxPixelHeight * Multi + 1;

      viewImage = new WriteableBitmap(width, height);
      viewContext = viewImage.GetBitmapContext();

      GameImage.Source = viewImage;

      UpdateScreen(playField);
    }
コード例 #19
0
ファイル: Program.cs プロジェクト: MaxKlaxxMiner/SokoWahn
    static ushort[] TestScan(int width, TopLeftTodo topLeftTodo, HashSet<ushort> ways, SokowahnField view, bool debug = true)
    {
      var state = topLeftTodo.state;
      view.SetGameState(state);

      var result = ScanBestTopLeftWay(state[0], width, ways, new HashSet<ushort>(state.Skip(1)));

      if (state.Length > 1 && CheckDeadlock(topLeftTodo, view, result[result.Count - 1])) return null;

      if (debug)
      {
        Console.SetCursorPosition(0, Math.Max(0, Console.CursorTop - 2));
        Console.WriteLine(new string(' ', Console.WindowWidth - 1));

        Console.SetCursorPosition(0, 1);
        Console.WriteLine(view.ToString());
        Console.WriteLine();

        string line = state[0] + " - " + string.Join(", ", result.Skip(1));
        Console.WriteLine(line);
        Console.WriteLine();
      }

      var known = new HashSet<ushort>(topLeftTodo.known);

      if (known.Contains(result[result.Count - 1])) return new[] { result[result.Count - 1] };

      var resultFiltered = result.Where(f => !known.Contains(f)).ToArray();

      return resultFiltered;
    }