diff --git a/Assets/Prefabs/TriCorner.prefab b/Assets/Prefabs/TriCorner.prefab index 3bcdd51f..7b7b6e24 100644 --- a/Assets/Prefabs/TriCorner.prefab +++ b/Assets/Prefabs/TriCorner.prefab @@ -150,6 +150,12 @@ MonoBehaviour: X: 0 Y: 0 RotationState: 0 + SolutionRotation: 0 + SolutionConnections: 0 + Barriers: 0 DisconnectedSprite: {fileID: 21300000, guid: 6372bc43b5bc06643a17e0415a13a216, type: 3} ConnectedSprite: {fileID: 21300000, guid: 96539ea64dfad3e408f1e117e46c2775, type: 3} locked: 0 + isCenterTile: 0 + baseConnections: + graphicRotationOffset: 0 diff --git a/Assets/Scripts/MapGenerator.cs b/Assets/Scripts/MapGenerator.cs index 5dfafce2..6e485c62 100644 --- a/Assets/Scripts/MapGenerator.cs +++ b/Assets/Scripts/MapGenerator.cs @@ -175,6 +175,14 @@ public class MapGenerator : MonoBehaviour tile.ApplyRotation(rotation); tile.SolutionRotation = rotation; + // if (type == "TriCorner") + // // roate plus 90 degrees + // tile.SolutionRotation += 1; + // else if (type == "Corner") + // // rotate 3 times + // tile.SolutionRotation += 4; + // // tile.SolutionRotation %= 4; + tile.SolutionConnections = connections; tile.Barriers = barriers[x, y]; diff --git a/Assets/Scripts/Solver.cs b/Assets/Scripts/Solver.cs index 05c011a4..2f1bfaea 100644 --- a/Assets/Scripts/Solver.cs +++ b/Assets/Scripts/Solver.cs @@ -1,95 +1,167 @@ using UnityEngine; +using System.Linq; +using System.Collections.Generic; public class Solver : MonoBehaviour { public static bool CheckSolved(Tile[,] tiles, int width, int height) { - bool solved = true; - for (int x = 0; x < width; x++) - for (int y = 0; y < height; y++) - tiles[x, y].SetConnectionState(IsTileCorrectlyConnected(tiles, x, y, width, height)); - + // First check if all tiles are in their correct rotation + bool allCorrect = true; foreach (var tile in tiles) - if (!IsTileCorrectlyConnected(tiles, tile.X, tile.Y, width, height)) - solved = false; + { + bool correct = tile.IsCorrectlyOriented(); + tile.SetConnectionState(correct); + if (!correct) allCorrect = false; + } - return solved; + if (!allCorrect) return false; + + // Then verify the entire network is connected + return IsNetworkFullyConnected(tiles, width, height); } - private static bool IsTileCorrectlyConnected(Tile[,] tiles, int x, int y, int width, int height) + private static bool IsNetworkFullyConnected(Tile[,] tiles, int width, int height) { + // Find the center tile (or first active tile if center isn't marked) + int startX = width / 2; + int startY = height / 2; + + // If center isn't marked, find first active tile + if (!tiles[startX, startY].isCenterTile) + { + for (int x = 0; x < width; x++) + { + for (int y = 0; y < height; y++) + { + if (tiles[x, y].GetConnectionCount() > 0) + { + startX = x; + startY = y; + break; + } + } + } + } + + bool[,] visited = new bool[width, height]; + FloodFill(tiles, visited, width, height, startX, startY); + + // Check if all tiles with connections were visited + for (int x = 0; x < width; x++) + { + for (int y = 0; y < height; y++) + { + if (tiles[x, y].GetConnectionCount() > 0 && !visited[x, y]) + return false; + } + } + + return true; + } + + private static void FloodFill(Tile[,] tiles, bool[,] visited, int width, int height, int x, int y) + { + if (x < 0 || x >= width || y < 0 || y >= height || visited[x, y]) + return; + + visited[x, y] = true; Tile tile = tiles[x, y]; - bool up = tile.HasConnection(0); - bool right = tile.HasConnection(1); - bool down = tile.HasConnection(2); - bool left = tile.HasConnection(3); + // Check all 4 directions + for (int dir = 0; dir < 4; dir++) + { + if (tile.HasConnection(dir)) + { + int nx = x + directions[dir].x; + int ny = y + directions[dir].y; + + // Wrap coordinates if needed (you'll need to pass wrapping info to solver) + if (nx < 0) nx = width - 1; + else if (nx >= width) nx = 0; + if (ny < 0) ny = height - 1; + else if (ny >= height) ny = 0; - bool connected = true; - - if (y < height - 1) - connected &= up == tiles[x, y + 1].HasConnection(2); - else if (up) connected = false; - - if (x < width - 1) - connected &= right == tiles[x + 1, y].HasConnection(3); - else if (right) connected = false; - - if (y > 0) - connected &= down == tiles[x, y - 1].HasConnection(0); - else if (down) connected = false; - - if (x > 0) - connected &= left == tiles[x - 1, y].HasConnection(1); - else if (left) connected = false; - - return connected; + // Only continue if neighbor has matching connection + if (tiles[nx, ny].HasConnection((dir + 2) % 4)) + { + FloodFill(tiles, visited, width, height, nx, ny); + } + } + } } public static bool AutoSolve(Tile[,] tiles, int width, int height) { - bool changed; - int[,] possible = new int[width, height]; + // Create a list of tiles sorted by connection count (most constrained first) + var tileList = tiles.Cast() + .Where(t => !t.locked) + .OrderBy(t => t.GetConnectionCount()) + .ToList(); - // Initialize the possible rotation states of all tiles (4-bit binary) - for (int x = 0; x < width; x++) - for (int y = 0; y < height; y++) - possible[x, y] = 0b1111; - - int limit = width * height * 10; // Prevent infinite loops - do - { - changed = false; - - for (int x = 0; x < width; x++) - for (int y = 0; y < height; y++) - { - int newMask = 0; - for (int rot = 0; rot < 4; rot++) - { - tiles[x, y].RotationState = rot; - if (IsTileCorrectlyConnected(tiles, x, y, width, height)) - newMask |= (1 << rot); - } - if (newMask != possible[x, y]) - { - possible[x, y] = newMask; - changed = true; - } - - if (newMask == 0) - return false; // No valid direction - - // If there is only one possible direction, lock it in - if ((newMask & (newMask - 1)) == 0) - { - int fixedRot = System.Convert.ToString(newMask, 2).LastIndexOf('1'); - tiles[x, y].RotationState = fixedRot; - tiles[x, y].transform.rotation = Quaternion.Euler(0, 0, -90 * fixedRot); - } - } - } while (changed && --limit > 0); - - return CheckSolved(tiles, width, height); + return SolveRecursive(tiles, width, height, tileList, 0); } -} + + private static bool SolveRecursive(Tile[,] tiles, int width, int height, List tileList, int index) + { + if (index >= tileList.Count) + return CheckSolved(tiles, width, height); + + Tile tile = tileList[index]; + + // Try all possible rotations for this tile + for (int rot = 0; rot < 4; rot++) + { + tile.RotationState = rot; + tile.transform.rotation = Quaternion.Euler(0, 0, -90 * rot); + + // Early pruning - check if this rotation causes immediate conflicts + if (!HasImmediateConflicts(tiles, width, height, tile)) + { + if (SolveRecursive(tiles, width, height, tileList, index + 1)) + return true; + } + } + + return false; + } + + private static bool HasImmediateConflicts(Tile[,] tiles, int width, int height, Tile tile) + { + int x = tile.X; + int y = tile.Y; + + // Check all 4 directions for conflicts + for (int dir = 0; dir < 4; dir++) + { + if (tile.HasConnection(dir)) + { + int nx = x + directions[dir].x; + int ny = y + directions[dir].y; + + // Wrap coordinates if needed + if (nx < 0) nx = width - 1; + else if (nx >= width) nx = 0; + if (ny < 0) ny = height - 1; + else if (ny >= height) ny = 0; + + Tile neighbor = tiles[nx, ny]; + int oppositeDir = (dir + 2) % 4; + + // If neighbor is locked and doesn't have matching connection, conflict + if (neighbor.locked && !neighbor.HasConnection(oppositeDir)) + return true; + } + } + + return false; + } + + // Directions: Right, Up, Left, Down (matches Net game encoding) + private static readonly Vector2Int[] directions = { + new Vector2Int(1, 0), // R + new Vector2Int(0, 1), // U + new Vector2Int(-1, 0), // L + new Vector2Int(0, -1) // D + }; +} \ No newline at end of file diff --git a/Assets/Sprites/LU-A.png b/Assets/Sprites/LU-A.png index c60c46b9..2abe7a70 100644 Binary files a/Assets/Sprites/LU-A.png and b/Assets/Sprites/LU-A.png differ diff --git a/Assets/Sprites/LU.png b/Assets/Sprites/LU.png index 7b10dbc5..8d1fa213 100644 Binary files a/Assets/Sprites/LU.png and b/Assets/Sprites/LU.png differ diff --git a/Assets/Sprites/LUR-A.png b/Assets/Sprites/LUR-A.png index 39405e0d..b9ef8482 100644 Binary files a/Assets/Sprites/LUR-A.png and b/Assets/Sprites/LUR-A.png differ diff --git a/Assets/Sprites/LUR.png b/Assets/Sprites/LUR.png index 7151d07f..9050cc6b 100644 Binary files a/Assets/Sprites/LUR.png and b/Assets/Sprites/LUR.png differ diff --git a/Assets/Sprites/Node-A.png b/Assets/Sprites/Node-A.png index a8f3b153..dd2d7e14 100644 Binary files a/Assets/Sprites/Node-A.png and b/Assets/Sprites/Node-A.png differ diff --git a/Assets/Sprites/Node.png b/Assets/Sprites/Node.png index 6ac5eb52..4bb872a6 100644 Binary files a/Assets/Sprites/Node.png and b/Assets/Sprites/Node.png differ