using System;
using System.Collections.Generic;
class EightPuzzleSolver {
// State space tree node
class Node {
public Node parent;
public int[,] mat;
public int x, y;
public int cost;
public int level;
public Node(int[,] mat, int x, int y, int level, Node parent) {
this.mat = new int[3, 3];
Array.Copy(mat, this.mat, mat.Length);
this.x = x;
this.y = y;
this.level = level;
this.parent = parent;
this.cost = int.MaxValue;
}
}
// Function to print N x N matrix
static void PrintMatrix(int[,] mat) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
Console.Write(mat[i, j] + " ");
}
Console.WriteLine();
}
}
// Bottom, left, top, right movement
static readonly int[] row = {1, 0, -1, 0};
static readonly int[] col = {0, -1, 0, 1};
// Function to calculate misplaced tiles
static int CalculateCost(int[,] initial, int[,] goal) {
int count = 0;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
if (initial[i, j] != 0 && initial[i, j] != goal[i, j])
count++;
return count;
}
// Function to check if coordinates are valid
static bool IsSafe(int x, int y) {
return (x >= 0 && x < 3 && y >= 0 && y < 3);
}
// Print path from root node to destination node
static void PrintPath(Node root) {
if (root == null)
return;
PrintPath(root.parent);
PrintMatrix(root.mat);
Console.WriteLine();
}
// Custom comparator for priority queue simulation using SortedSet
class Comp : IComparer<Node> {
public int Compare(Node lhs, Node rhs) {
int costCompare = (lhs.cost + lhs.level).CompareTo(rhs.cost + rhs.level);
return costCompare != 0 ? costCompare : lhs.GetHashCode().CompareTo(rhs.GetHashCode());
}
}
// Function to solve the 8-puzzle using Branch and Bound
static void Solve(int[,] initial, int x, int y, int[,] goal) {
SortedSet<Node> pq = new SortedSet<Node>(new Comp()); // Simulating a priority queue
Node root = new Node(initial, x, y, 0, null);
root.cost = CalculateCost(initial, goal);
pq.Add(root);
while (pq.Count > 0) {
Node min = null;
foreach (var node in pq) {
min = node; break; // Get the node with the smallest cost
}
pq.Remove(min);
// If final state is reached, print the solution path
if (min.cost == 0) {
PrintPath(min);
return;
}
// Generate all possible child nodes
for (int i = 0; i < 4; i++) {
int newX = min.x + row[i], newY = min.y + col[i];
if (IsSafe(newX, newY)) {
int[,] newMat = new int[3, 3];
Array.Copy(min.mat, newMat, min.mat.Length);
// Swap blank tile
newMat[min.x, min.y] = newMat[newX, newY];
newMat[newX, newY] = 0;
Node child = new Node(newMat, newX, newY, min.level + 1, min);
child.cost = CalculateCost(child.mat, goal);
pq.Add(child);
}
}
}
}
// Driver Code
public static void Main(string[] args) {
// Initial configuration
int[,] initial = {
{1, 0, 2},
{3, 4, 5},
{6, 7, 8}
};
// Solvable Final configuration
int[,] goal = {
{0, 1, 2},
{3, 4, 5},
{6, 7, 8}
};
// Blank tile coordinates in initial configuration
int x = 0, y = 1;
Solve(initial, x, y, goal);
}
}