Last active
July 12, 2017 22:57
-
-
Save tomaszbartoszewski/c2606a233bf11cd2c922791c496a0752 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
One | |
5 5 | |
##### | |
# .# | |
# #$# | |
#@ # | |
##### | |
Two | |
7 7 | |
####### | |
# .#.# | |
#@# $ # | |
# #$ # | |
# # ### | |
# ### | |
####### | |
Three | |
6 6 | |
###### | |
#....# | |
# # | |
#$$$$# | |
#@ # | |
###### | |
Four | |
10 10 | |
########## | |
#.$ ## .## | |
### $.# # | |
# $ ## | |
# ### # | |
# # | |
#@ # | |
#$$$$$$$$# | |
#........# | |
########## | |
Five | |
12 8 | |
############ | |
#@# # | |
# # ##$$#### | |
# # ..# | |
# ### $.## | |
# $ $ . .# | |
# $ $ ..## | |
############ | |
6 | |
4 8 | |
#### | |
#@.# | |
#$ # | |
# # | |
# $# | |
#. # | |
# # | |
#### | |
7 | |
5 8 | |
##### | |
# .# | |
# $ # | |
##@## | |
##$## | |
# # | |
#. # | |
##### | |
8 | |
8 8 | |
#### | |
# ##### | |
# # | |
# $# # | |
# #### | |
#.$$@ # | |
## ..# | |
###### | |
9 | |
8 8 | |
##### | |
#.. ### | |
# . # | |
## $ ## | |
####$$@# | |
# # | |
# # | |
######## | |
10 | |
8 7 | |
######## | |
# #@ # | |
# # # | |
##$$ ## | |
# # | |
### ..# | |
##### |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
namespace Sokoban | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var levels = BoardDefinitionProvider.GetDefinitions().ToArray(); | |
Console.WriteLine("Provide level code:"); | |
var code = Console.ReadLine(); | |
var level = levels.FirstOrDefault(l => l.LevelSecret == code) ?? levels.FirstOrDefault(); | |
if (level == null) | |
Console.WriteLine("No levels available"); | |
while (level != null) | |
{ | |
Console.Clear(); | |
Console.WriteLine("Use arrows to move, R for level reset and Esc to exit"); | |
var game = new Game(level.Board); | |
BoardPrinter.Print(level.Board); | |
while (true) | |
{ | |
if (Console.KeyAvailable) | |
{ | |
var key = Console.ReadKey(true); | |
Move? direction = null; | |
switch (key.Key) | |
{ | |
case ConsoleKey.UpArrow: | |
direction = Move.Up; | |
break; | |
case ConsoleKey.DownArrow: | |
direction = Move.Down; | |
break; | |
case ConsoleKey.LeftArrow: | |
direction = Move.Left; | |
break; | |
case ConsoleKey.RightArrow: | |
direction = Move.Right; | |
break; | |
case ConsoleKey.R: | |
game = new Game(level.Board); | |
BoardPrinter.Print(level.Board); | |
break; | |
case ConsoleKey.Escape: | |
return; | |
} | |
if (direction != null) | |
{ | |
var fieldsToRefresh = game.MovePlayer(direction.Value).ToArray(); | |
BoardPrinter.RefreshFields(game.Board, fieldsToRefresh); | |
if (game.Won()) | |
break; | |
} | |
} | |
} | |
level = levels.FirstOrDefault(l => l.LevelId == level.LevelId + 1); | |
if (level == null) | |
Console.WriteLine("Victory!"); | |
else | |
Console.WriteLine($"New level {level.LevelId}! Code: {level.LevelSecret}"); | |
Console.ReadLine(); | |
} | |
} | |
} | |
public class Game | |
{ | |
private FieldLocation playerPosition; | |
public FieldValue[][] Board { get; } | |
private FieldValue this[FieldLocation fieldLocation] | |
{ | |
get { return Board[fieldLocation.Row][fieldLocation.Column]; } | |
set | |
{ | |
Board[fieldLocation.Row][fieldLocation.Column] = value; | |
if ((value & FieldValue.Player) == FieldValue.Player) | |
playerPosition = fieldLocation; | |
} | |
} | |
public Game(FieldValue[][] board) | |
{ | |
FieldValue[][] newBoard = new FieldValue[board.Length][]; | |
for (int i = 0; i < newBoard.Length; i++) | |
{ | |
newBoard[i] = (FieldValue[])board[i].Clone(); | |
} | |
this.Board = newBoard; | |
for (var row = 0; row < board.Length; row++) | |
for (var column = 0; column < board[row].Length; column++) | |
if ((board[row][column] & FieldValue.Player) == FieldValue.Player) | |
playerPosition = new FieldLocation(column, row); | |
} | |
public IEnumerable<FieldLocation> MovePlayer(Move move) | |
{ | |
switch (move) | |
{ | |
case Move.Up: | |
return TryMove(new FieldLocation(playerPosition.Column, playerPosition.Row - 1), new FieldLocation(playerPosition.Column, playerPosition.Row - 2)); | |
case Move.Down: | |
return TryMove(new FieldLocation(playerPosition.Column, playerPosition.Row + 1), new FieldLocation(playerPosition.Column, playerPosition.Row + 2)); | |
case Move.Left: | |
return TryMove(new FieldLocation(playerPosition.Column - 1, playerPosition.Row), new FieldLocation(playerPosition.Column - 2, playerPosition.Row)); | |
case Move.Right: | |
return TryMove(new FieldLocation(playerPosition.Column + 1, playerPosition.Row), new FieldLocation(playerPosition.Column + 2, playerPosition.Row)); | |
} | |
return Enumerable.Empty<FieldLocation>(); | |
} | |
private IEnumerable<FieldLocation> TryMove(FieldLocation destination, FieldLocation behindDestination) | |
{ | |
var destinationFieldValue = this[destination]; | |
if (destinationFieldValue == FieldValue.Wall) | |
yield break; | |
if (destinationFieldValue == FieldValue.Empty || destinationFieldValue == FieldValue.Goal) | |
{ | |
this[playerPosition] &= ~FieldValue.Player; | |
yield return playerPosition; | |
this[destination] |= FieldValue.Player; | |
yield return destination; | |
} | |
if ((destinationFieldValue & FieldValue.Box) == FieldValue.Box) | |
{ | |
var valueBehind = this[behindDestination]; | |
if (valueBehind == FieldValue.Wall || (valueBehind & FieldValue.Box) == FieldValue.Box) | |
yield break; | |
this[behindDestination] |= FieldValue.Box; | |
yield return behindDestination; | |
this[playerPosition] &= ~FieldValue.Player; | |
yield return playerPosition; | |
this[destination] = (this[destination] | FieldValue.Player) & ~FieldValue.Box; | |
yield return destination; | |
} | |
} | |
public bool Won() | |
{ | |
return !Board | |
.SelectMany(row => row.Select(field => field)) | |
.Any(field => field == FieldValue.Box || field == FieldValue.Goal); | |
} | |
} | |
public struct FieldLocation | |
{ | |
public int Row { get; set; } | |
public int Column { get; set; } | |
public FieldLocation(int column, int row) | |
{ | |
Row = row; | |
Column = column; | |
} | |
} | |
public static class BoardPrinter | |
{ | |
private static Dictionary<FieldValue, FieldDisplay> displayMapper = new Dictionary<FieldValue, FieldDisplay> | |
{ | |
{ FieldValue.Wall, new FieldDisplay(ConsoleColor.DarkRed) }, | |
{ FieldValue.Player, new FieldDisplay(ConsoleColor.DarkGreen) }, | |
{ FieldValue.Player | FieldValue.Goal, new FieldDisplay(ConsoleColor.DarkGreen) }, | |
{ FieldValue.Box, new FieldDisplay(ConsoleColor.Gray, ConsoleColor.DarkGray, 'X') }, | |
{ FieldValue.Box | FieldValue.Goal, new FieldDisplay(ConsoleColor.Gray, ConsoleColor.Blue, 'X') }, | |
{ FieldValue.Goal, new FieldDisplay(ConsoleColor.Blue) }, | |
{ FieldValue.Empty, new FieldDisplay(ConsoleColor.Green) } | |
}; | |
public static void Print(FieldValue[][] board) | |
{ | |
Console.Clear(); | |
foreach (var row in board) | |
{ | |
foreach (var fieldValue in row) | |
PrintField(fieldValue); | |
Console.WriteLine(); | |
} | |
} | |
public static void RefreshFields(FieldValue[][] board, FieldLocation[] fieldsToRefresh) | |
{ | |
foreach (var field in fieldsToRefresh) | |
{ | |
Console.SetCursorPosition(field.Column, field.Row); | |
PrintField(board[field.Row][field.Column]); | |
} | |
Console.SetCursorPosition(0, board.Length); | |
} | |
private static void PrintField(FieldValue fieldValue) | |
{ | |
var fieldDisplay = displayMapper[fieldValue]; | |
Console.BackgroundColor = fieldDisplay.BackgroundColor; | |
Console.ForegroundColor = fieldDisplay.ForegroundColor; | |
Console.Write(fieldDisplay.Sign); | |
Console.ResetColor(); | |
} | |
private struct FieldDisplay | |
{ | |
public ConsoleColor BackgroundColor { get; set; } | |
public ConsoleColor ForegroundColor { get; set; } | |
public char Sign { get; set; } | |
public FieldDisplay(ConsoleColor backgroundColor, ConsoleColor foregroundColor = ConsoleColor.White, char sign = ' ') | |
{ | |
BackgroundColor = backgroundColor; | |
ForegroundColor = foregroundColor; | |
Sign = sign; | |
} | |
} | |
} | |
[Flags] | |
public enum FieldValue : byte | |
{ | |
Empty = 0, | |
Wall = 1, | |
Player = 2, | |
Box = 4, | |
Goal = 8 | |
} | |
public enum Move : byte | |
{ | |
Up, | |
Down, | |
Left, | |
Right | |
} | |
public static class BoardDefinitionProvider | |
{ | |
private static Dictionary<char, FieldValue> fieldMap = new Dictionary<char, FieldValue> | |
{ | |
{ '#', FieldValue.Wall }, | |
{ '@', FieldValue.Player }, | |
{ '+', FieldValue.Player | FieldValue.Goal }, | |
{ '$', FieldValue.Box }, | |
{ '*', FieldValue.Box | FieldValue.Goal }, | |
{ '.', FieldValue.Goal }, | |
{ ' ', FieldValue.Empty } | |
}; | |
public static IEnumerable<BoardDefinition> GetDefinitions() | |
{ | |
var levelId = 1; | |
var allLines = File.ReadAllLines("_BoardDefinition.txt"); | |
var enumerator = allLines.GetEnumerator(); | |
while (enumerator.MoveNext()) | |
{ | |
var key = enumerator.Current as string; | |
enumerator.MoveNext(); | |
var size = (enumerator.Current as string).Split(' '); | |
var width = int.Parse(size[0]); | |
var height = int.Parse(size[1]); | |
var board = new FieldValue[height][]; | |
for (var i = 0; i < height; i++) | |
{ | |
board[i] = new FieldValue[width]; | |
enumerator.MoveNext(); | |
var line = enumerator.Current as string; | |
for (var c = 0; c < width; c++) | |
{ | |
board[i][c] = fieldMap[line[c]]; | |
} | |
} | |
yield return new BoardDefinition(levelId, key, board); | |
levelId++; | |
} | |
} | |
} | |
public class BoardDefinition | |
{ | |
public int LevelId { get; } | |
public string LevelSecret { get; } | |
public FieldValue[][] Board { get; } | |
public BoardDefinition(int levelId, string levelSecret, FieldValue[][] board) | |
{ | |
LevelId = levelId; | |
LevelSecret = levelSecret; | |
Board = board; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment