Example #1
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);
    }
Example #2
0
    /// <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);
        }
      }
    }
Example #3
0
    /// <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;
    }
    /// <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
    }