예제 #1
0
    /// <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();
    }
예제 #2
0
    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;
          }
        }
      }

    }
예제 #3
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
    }