Skip to content

Instantly share code, notes, and snippets.

@tomaszbartoszewski
Last active July 12, 2017 22:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tomaszbartoszewski/c2606a233bf11cd2c922791c496a0752 to your computer and use it in GitHub Desktop.
Save tomaszbartoszewski/c2606a233bf11cd2c922791c496a0752 to your computer and use it in GitHub Desktop.
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
########
# #@ #
# # #
##$$ ##
# #
### ..#
#####
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