Sokoban: Difference between revisions
Content added Content deleted
No edit summary |
|||
Line 744: | Line 744: | ||
=={{header|C sharp|C#}}== |
=={{header|C sharp|C#}}== |
||
<lang csharp> |
<lang csharp>using System.Collections.Generic; |
||
using System.Linq; |
|||
public class SokobanSolver |
|||
using System.Text; |
|||
namespace SokobanSolver |
|||
{ |
{ |
||
public class SokobanSolver |
|||
{ |
{ |
||
private class Board |
|||
public string Sol { get; internal set; } |
|||
public int X { get; internal set; } |
|||
public int Y { get; internal set; } |
|||
public Board(string cur, string sol, int x, int y) |
|||
{ |
{ |
||
Cur |
public string Cur { get; internal set; } |
||
Sol |
public string Sol { get; internal set; } |
||
X |
public int X { get; internal set; } |
||
Y |
public int Y { get; internal set; } |
||
public Board(string cur, string sol, int x, int y) |
|||
{ |
|||
Cur = cur; |
|||
Sol = sol; |
|||
X = x; |
|||
Y = y; |
|||
} |
|||
} |
} |
||
} |
|||
private string destBoard, currBoard; |
private string destBoard, currBoard; |
||
private int playerX, playerY, nCols; |
private int playerX, playerY, nCols; |
||
SokobanSolver(string[] board) |
SokobanSolver(string[] board) |
||
{ |
|||
nCols = board[0].Length; |
|||
StringBuilder destBuf = new StringBuilder(); |
|||
StringBuilder currBuf = new StringBuilder(); |
|||
for (int r = 0; r < board.Length; r++) |
|||
{ |
{ |
||
nCols = board[0].Length; |
|||
StringBuilder destBuf = new StringBuilder(); |
|||
StringBuilder currBuf = new StringBuilder(); |
|||
for (int r = 0; r < board.Length; r++) |
|||
{ |
{ |
||
for (int c = 0; c < nCols; c++) |
|||
{ |
|||
char ch = board[r][c]; |
char ch = board[r][c]; |
||
destBuf.Append(ch != '$' && ch != '@' ? ch : ' '); |
destBuf.Append(ch != '$' && ch != '@' ? ch : ' '); |
||
currBuf.Append(ch != '.' ? ch : ' '); |
currBuf.Append(ch != '.' ? ch : ' '); |
||
if (ch == '@') |
if (ch == '@') |
||
{ |
{ |
||
this.playerX = c; |
this.playerX = c; |
||
this.playerY = r; |
this.playerY = r; |
||
} |
|||
} |
} |
||
} |
} |
||
destBoard = destBuf.ToString(); |
|||
currBoard = currBuf.ToString(); |
|||
} |
} |
||
destBoard = destBuf.ToString(); |
|||
currBoard = currBuf.ToString(); |
|||
} |
|||
private string Move(int x, int y, int dx, int dy, string trialBoard) |
private string Move(int x, int y, int dx, int dy, string trialBoard) |
||
{ |
{ |
||
int newPlayerPos = (y + dy) * nCols + x + dx; |
int newPlayerPos = (y + dy) * nCols + x + dx; |
||
if (trialBoard[newPlayerPos] != ' ') |
if (trialBoard[newPlayerPos] != ' ') |
||
return null; |
return null; |
||
char[] trial = trialBoard.ToCharArray(); |
char[] trial = trialBoard.ToCharArray(); |
||
trial[y * nCols + x] = ' '; |
trial[y * nCols + x] = ' '; |
||
trial[newPlayerPos] = '@'; |
trial[newPlayerPos] = '@'; |
||
return new string(trial); |
return new string(trial); |
||
} |
} |
||
private string Push(int x, int y, int dx, int dy, string trialBoard) |
private string Push(int x, int y, int dx, int dy, string trialBoard) |
||
{ |
{ |
||
int newBoxPos = (y + 2 * dy) * nCols + x + 2 * dx; |
int newBoxPos = (y + 2 * dy) * nCols + x + 2 * dx; |
||
if (trialBoard[newBoxPos] != ' ') |
if (trialBoard[newBoxPos] != ' ') |
||
return null; |
return null; |
||
char[] trial = trialBoard.ToCharArray(); |
char[] trial = trialBoard.ToCharArray(); |
||
trial[y * nCols + x] = ' '; |
trial[y * nCols + x] = ' '; |
||
trial[(y + dy) * nCols + x + dx] = '@'; |
trial[(y + dy) * nCols + x + dx] = '@'; |
||
trial[newBoxPos] = '$'; |
trial[newBoxPos] = '$'; |
||
return new string(trial); |
return new string(trial); |
||
} |
} |
||
private bool IsSolved(string trialBoard) |
private bool IsSolved(string trialBoard) |
||
{ |
{ |
||
for (int i = 0; i < trialBoard.Length; i++) |
for (int i = 0; i < trialBoard.Length; i++) |
||
if ((destBoard[i] == '.') |
if ((destBoard[i] == '.') |
||
!= (trialBoard[i] == '$')) |
!= (trialBoard[i] == '$')) |
||
return false; |
return false; |
||
return true; |
return true; |
||
} |
} |
||
private string Solve() |
|||
{ |
|||
char[,] dirLabels = { { 'u', 'U' }, { 'r', 'R' }, { 'd', 'D' }, { 'l', 'L' } }; |
|||
int[,] dirs = { { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 } }; |
|||
ISet<string> history = new HashSet<string>(); |
|||
LinkedList<Board> open = new LinkedList<Board>(); |
|||
history.Add(currBoard); |
|||
open.AddLast(new Board(currBoard, string.Empty, playerX, playerY)); |
|||
private string Solve() |
|||
{ |
{ |
||
char[,] dirLabels = { { 'u', 'U' }, { 'r', 'R' }, { 'd', 'D' }, { 'l', 'L' } }; |
|||
Board item = open.First(); |
|||
int[,] dirs = { { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 } }; |
|||
open.RemoveFirst(); |
|||
string |
ISet<string> history = new HashSet<string>(); |
||
LinkedList<Board> open = new LinkedList<Board>(); |
|||
int x = item.X; |
|||
int y = item.Y; |
|||
history.Add(currBoard); |
|||
open.AddLast(new Board(currBoard, string.Empty, playerX, playerY)); |
|||
while (!open.Count.Equals(0)) |
|||
{ |
{ |
||
Board item = open.First(); |
|||
open.RemoveFirst(); |
|||
string cur = item.Cur; |
|||
string sol = item.Sol; |
|||
int x = item.X; |
|||
int y = item.Y; |
|||
for (int i = 0; i < dirs.GetLength(0); i++) |
|||
if (trial[(y + dy) * nCols + x + dx] == '$') |
|||
{ |
{ |
||
string trial = cur; |
|||
int dx = dirs[i, 0]; |
|||
int dy = dirs[i, 1]; |
|||
// are we standing next to a box ? |
|||
if (trial[(y + dy) * nCols + x + dx] == '$') |
|||
{ |
{ |
||
// |
// can we push it ? |
||
if ( |
if ((trial = Push(x, y, dx, dy, trial)) != null) |
||
{ |
{ |
||
// or did we already try this one ? |
|||
if (!history.Contains(trial)) |
|||
{ |
|||
string newSol = sol + dirLabels[i, 1]; |
string newSol = sol + dirLabels[i, 1]; |
||
if (IsSolved(trial)) |
if (IsSolved(trial)) |
||
return newSol; |
return newSol; |
||
open.AddLast(new Board(trial, newSol, x + dx, y + dy)); |
|||
history.Add(trial); |
|||
} |
|||
} |
|||
// otherwise try changing position |
|||
} |
|||
else if ((trial = Move(x, y, dx, dy, trial)) != null) |
|||
{ |
|||
if (!history.Contains(trial)) |
|||
{ |
|||
string newSol = sol + dirLabels[i, 0]; |
|||
open.AddLast(new Board(trial, newSol, x + dx, y + dy)); |
open.AddLast(new Board(trial, newSol, x + dx, y + dy)); |
||
history.Add(trial); |
history.Add(trial); |
||
} |
} |
||
} |
|||
// otherwise try changing position |
|||
} |
|||
else if ((trial = Move(x, y, dx, dy, trial)) != null) |
|||
{ |
|||
if (!history.Contains(trial)) |
|||
{ |
|||
string newSol = sol + dirLabels[i, 0]; |
|||
open.AddLast(new Board(trial, newSol, x + dx, y + dy)); |
|||
history.Add(trial); |
|||
} |
} |
||
} |
} |
||
} |
} |
||
return "No solution"; |
|||
} |
} |
||
return "No solution"; |
|||
} |
|||
public static void Main(string[] a) |
public static void Main(string[] a) |
||
{ |
|||
string level = "#######," + |
|||
"# #," + |
|||
"# #," + |
|||
"#. # #," + |
|||
"#. $$ #," + |
|||
"#.$$ #," + |
|||
"#.# @#," + |
|||
"#######"; |
|||
System.Console.WriteLine("Level:\n"); |
|||
foreach (string line in level.Split(',')) |
|||
{ |
{ |
||
string level = "#######," + |
|||
"# #," + |
|||
"# #," + |
|||
"#. # #," + |
|||
"#. $$ #," + |
|||
"#.$$ #," + |
|||
"#.# @#," + |
|||
"#######"; |
|||
System.Console.WriteLine("Level:\n"); |
|||
foreach (string line in level.Split(',')) |
|||
{ |
|||
System.Console.WriteLine(line); |
|||
} |
|||
System.Console.WriteLine("\nSolution:\n"); |
|||
System.Console.WriteLine(new SokobanSolver(level.Split(',')).Solve()); |
|||
} |
} |
||
System.Console.WriteLine("\nSolution:\n"); |
|||
System.Console.WriteLine(new SokobanSolver(level.Split(',')).Solve()); |
|||
} |
} |
||
}</lang> |
|||
} |
|||
</lang> |
|||
=={{header|D}}== |
=={{header|D}}== |