Net-Game/Assets/Scripts/Solver.cs

167 lines
5.3 KiB
C#

using UnityEngine;
using System.Linq;
using System.Collections.Generic;
public class Solver : MonoBehaviour
{
public static bool CheckSolved(Tile[,] tiles, int width, int height)
{
// First check if all tiles are in their correct rotation
bool allCorrect = true;
foreach (var tile in tiles)
{
bool correct = tile.IsCorrectlyOriented();
tile.SetConnectionState(correct);
if (!correct) allCorrect = false;
}
if (!allCorrect) return false;
// Then verify the entire network is connected
return IsNetworkFullyConnected(tiles, width, 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];
// 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;
// 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)
{
// Create a list of tiles sorted by connection count (most constrained first)
var tileList = tiles.Cast<Tile>()
.Where(t => !t.locked)
.OrderBy(t => t.GetConnectionCount())
.ToList();
return SolveRecursive(tiles, width, height, tileList, 0);
}
private static bool SolveRecursive(Tile[,] tiles, int width, int height, List<Tile> 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
};
}