diff --git a/CoopSweeper/ArrayHelpers.cs b/CoopSweeper/ArrayHelpers.cs index caf436b..6b9c9a0 100644 --- a/CoopSweeper/ArrayHelpers.cs +++ b/CoopSweeper/ArrayHelpers.cs @@ -6,7 +6,7 @@ namespace CoopSweeper { public static class ArrayHelpers { - public static T[,] Clone2D(T[,] data) where T : ICloneable + public static T[,] Clone2D(T[,] data) where T : class, ICloneable { if (data == null) return null; diff --git a/CoopSweeper/CoopSweeper.csproj b/CoopSweeper/CoopSweeper.csproj index 457434f..87c92f6 100644 --- a/CoopSweeper/CoopSweeper.csproj +++ b/CoopSweeper/CoopSweeper.csproj @@ -5,10 +5,6 @@ netcoreapp2.0 - - - - diff --git a/CoopSweeper/GameTypes/Game.cs b/CoopSweeper/GameTypes/Game.cs index 5c7bbfe..2abad54 100644 --- a/CoopSweeper/GameTypes/Game.cs +++ b/CoopSweeper/GameTypes/Game.cs @@ -5,7 +5,7 @@ using System.Text; namespace CoopSweeper.GameTypes { - class Game + public class Game { private readonly Random _random = new Random(); private static int _checkID = 0; diff --git a/CoopSweeper/ICloneable.cs b/CoopSweeper/ICloneable.cs index fbce50c..adf8c5f 100644 --- a/CoopSweeper/ICloneable.cs +++ b/CoopSweeper/ICloneable.cs @@ -4,7 +4,7 @@ using System.Text; namespace CoopSweeper { - public interface ICloneable where T : ICloneable + public interface ICloneable where T : class, ICloneable { T Clone(); } diff --git a/CoopSweeper/Program.cs b/CoopSweeper/Program.cs index ce9faf2..8b8fa6b 100644 --- a/CoopSweeper/Program.cs +++ b/CoopSweeper/Program.cs @@ -1,5 +1,7 @@ using CoopSweeper.GameTypes; +using CoopSweeper.View; using System; +using System.Collections.Generic; using System.Text; using System.Threading; @@ -7,20 +9,23 @@ namespace CoopSweeper { class Program { - static IField[,] currentMap = null; const int MAP_POS_X = 3; const int MAP_POS_Y = 3; + static List _views = new List(); + static void Main(string[] args) { Console.OutputEncoding = Encoding.UTF8; Console.ForegroundColor = ConsoleColor.White; Console.BackgroundColor = ConsoleColor.Black; + Console.SetCursorPosition(0, 0); + Console.CursorVisible = false; Console.Clear(); var game = new Game(); - var cursorPosX = 0; - var cursorPosY = 0; - StartNewGame(game, cursorPosX, cursorPosY); + _views.Add(new GameView(game) { Position = new Position(1, 3) }); + _views.Add(new MenuBarView() { Position = new Position(0, 2) }); + StartNewGame(game); game.GameFinished += won => { Console.SetCursorPosition(0, 0); @@ -28,201 +33,40 @@ namespace CoopSweeper Console.Write("You won!"); else Console.Write("You lost!"); - DrawMap(MAP_POS_X, MAP_POS_Y, game.Map, cursorPosX, cursorPosY, true); - Console.ReadKey(); - StartNewGame(game, cursorPosX, cursorPosY); + Draw(false); + Console.ReadKey(true); + StartNewGame(game); }; ConsoleKey key = (ConsoleKey)(-1); - while ((key = Console.ReadKey().Key) != ConsoleKey.Escape) + Draw(true); + while ((key = Console.ReadKey(true).Key) != ConsoleKey.Escape) { - var oldCursorPosX = cursorPosX; - var oldCursorPosY = cursorPosY; - bool fullRedraw = false; - switch(key) - { - case ConsoleKey.UpArrow: - cursorPosY--; break; - case ConsoleKey.DownArrow: - cursorPosY++; break; - case ConsoleKey.LeftArrow: - cursorPosX--; break; - case ConsoleKey.RightArrow: - cursorPosX++; break; - case ConsoleKey.Spacebar: - fullRedraw = true; - game.Reveal(cursorPosX, cursorPosY); break; - case ConsoleKey.F: - fullRedraw = true; - game.ToggleMark(cursorPosX, cursorPosY); break; - } - if (cursorPosX < 0) cursorPosX = 0; - if (cursorPosY < 0) cursorPosY = 0; - if (cursorPosX >= game.Map.GetLength(0)) cursorPosX = game.Map.GetLength(0) - 1; - if (cursorPosY >= game.Map.GetLength(1)) cursorPosY = game.Map.GetLength(1) - 1; - if (fullRedraw) - DrawMap(3, 3, game.Map, cursorPosX, cursorPosY, true); - else if(oldCursorPosX != cursorPosX || oldCursorPosY != cursorPosY) - { - Console.SetCursorPosition(oldCursorPosX + 3, oldCursorPosY + 3); - DrawChar(game.Map[oldCursorPosX, oldCursorPosY], false); - Console.SetCursorPosition(cursorPosX + 3, cursorPosY + 3); - DrawChar(game.Map[cursorPosX, cursorPosY], true); - } + HandleKeyEvent(key); + Draw(false); Console.SetCursorPosition(0, 0); Console.CursorVisible = false; } } - private static void DrawChar(IField f, bool isCursor) + private static void Draw(bool fullRedraw) { - var oldBg = Console.BackgroundColor; - var oldFg = Console.ForegroundColor; - bool fgChanged = false; - bool bgChanged = false; - var c = 'E'; - var state = f.DisplayState; - switch (state) { - case DisplayState.EMPTY: - c = ' '; - break; - case DisplayState.NONE: - bgChanged = true; - fgChanged = true; - Console.ForegroundColor = ConsoleColor.Black; - Console.BackgroundColor = ConsoleColor.Gray; - //c = '◌'; - c = ' '; - break; - case DisplayState.QUESTIONMARK: - fgChanged = true; - bgChanged = true; - Console.BackgroundColor = ConsoleColor.Gray; - Console.ForegroundColor = ConsoleColor.DarkBlue; - c = '?'; - break; - case DisplayState.BOMB: - fgChanged = true; - Console.ForegroundColor = ConsoleColor.Red; - c = '☼'; - break; - case DisplayState.ERROR: - c = 'e'; - break; - case DisplayState.FLAG: - fgChanged = true; - bgChanged = true; - Console.BackgroundColor = ConsoleColor.Gray; - Console.ForegroundColor = ConsoleColor.DarkRed; - c = 'F'; - break; - case DisplayState.NUMBER1: - case DisplayState.NUMBER2: - case DisplayState.NUMBER3: - case DisplayState.NUMBER4: - case DisplayState.NUMBER5: - case DisplayState.NUMBER6: - case DisplayState.NUMBER7: - case DisplayState.NUMBER8: - fgChanged = true; - switch(state) - { - case DisplayState.NUMBER1: - Console.ForegroundColor = ConsoleColor.Green; - break; - case DisplayState.NUMBER2: - Console.ForegroundColor = ConsoleColor.Yellow; - break; - case DisplayState.NUMBER3: - Console.ForegroundColor = ConsoleColor.DarkYellow; - break; - case DisplayState.NUMBER4: - Console.ForegroundColor = ConsoleColor.DarkRed; - break; - default: - Console.ForegroundColor = ConsoleColor.Red; - break; - } - c = ((int)state).ToString()[0]; - break; - } - if (isCursor) - { - fgChanged = true; - bgChanged = true; - var s = Console.ForegroundColor; - Console.ForegroundColor = Console.BackgroundColor; - Console.BackgroundColor = s; - } - Console.Write(c); - if (fgChanged) - Console.ForegroundColor = oldFg; - if (bgChanged) - Console.BackgroundColor = oldBg; + foreach(var view in _views) + view.Draw(fullRedraw); } - public static void StartNewGame(Game game, int cursorPosX, int cursorPosY) + private static void HandleKeyEvent(ConsoleKey key) + { + foreach(var view in _views) + if (view.HandleKeyEvent(key)) + break; + } + + public static void StartNewGame(Game game) { game.GenerateGame(100, 30, 15); Console.Clear(); Console.SetCursorPosition(0, 0); - DrawBorder(MAP_POS_X - 1, MAP_POS_X - 1, game.Map.GetLength(0) + 2, game.Map.GetLength(1) + 2); - DrawMap(MAP_POS_X, MAP_POS_Y, game.Map, cursorPosX, cursorPosY, false); - } - - private static void DrawMap(int posX, int posY, IField[,] map, int cursorX, int cursorY, bool doChangeDetection) - { - for (var y = 0; y < map.GetLength(1); y++) - { - if(currentMap == null || !doChangeDetection) Console.SetCursorPosition(posX, posY + y); - for (var x = 0; x < map.GetLength(0); x++) - { - if (currentMap != null && doChangeDetection) - { - var currentField = currentMap[x, y]; - var newField = map[x, y]; - if (currentField == null || currentField.DisplayState != newField.DisplayState) - { - Console.SetCursorPosition(posX + x, posY + y); - DrawChar(map[x, y], x == cursorX && y == cursorY); - } - } - else - { - DrawChar(map[x, y], x == cursorX && y == cursorY); - } - } - } - currentMap = ArrayHelpers.Clone2D(map); - } - - private static void DrawBorder(int posX, int posY, int width, int height) - { - Console.SetCursorPosition(posX, posY); - var linebuilder = new StringBuilder(); - linebuilder.Append("╔"); - for (var x = 0; x < width - 2; x++) - linebuilder.Append("═"); - linebuilder.Append("╗"); - Console.Write(linebuilder); - for (var y = 1; y < height - 1; y++) - { - Console.SetCursorPosition(posX, posY + y); - Console.Write("║"); - Console.SetCursorPosition(posX + width - 1, posY + y); - Console.Write("║"); - } - Console.SetCursorPosition(posX, posY + height - 1); - linebuilder = new StringBuilder(); - linebuilder.Append("╚"); - for (var x = 0; x < width - 2; x++) - linebuilder.Append("═"); - linebuilder.Append("╝"); - Console.Write(linebuilder); - // ┌──┬──┐ ╔══╦══╗ ╒══╤══╕ ╓──╥──╖ - // │ │ │ ║ ║ ║ │ │ │ ║ ║ ║ - // ├──┼──┤ ╠══╬══╣ ╞══╪══╡ ╟──╫──╢ - // │ │ │ ║ ║ ║ │ │ │ ║ ║ ║ - // └──┴──┘ ╚══╩══╝ ╘══╧══╛ ╙──╨──╜ + Draw(true); } } } diff --git a/CoopSweeper/View/GameView.cs b/CoopSweeper/View/GameView.cs new file mode 100644 index 0000000..a770e02 --- /dev/null +++ b/CoopSweeper/View/GameView.cs @@ -0,0 +1,225 @@ +using CoopSweeper.GameTypes; +using System; +using System.Collections.Generic; +using System.Text; + +namespace CoopSweeper.View +{ + public class GameView : IView + { + private readonly Game _game; + private IField[,] _currentMap = null; + + public GameView(Game game) + { + _game = game; + } + + public Position Position { get; set; } + + public Position Cursor { get; set; } + + public Position MapPositon + { + get => new Position(Position.X + 1, Position.Y + 1); + set => Position = new Position(value.X - 1, value.Y - 1); + } + + public void Draw(bool fullRedraw) + { + if (fullRedraw) + DrawBorder(); + DrawMap(fullRedraw); + } + + private void DrawMap(bool fullRedraw) + { + for (var y = 0; y < _game.Map.GetLength(1); y++) + { + if (_currentMap == null || fullRedraw) Console.SetCursorPosition(MapPositon.X, MapPositon.Y + y); + for (var x = 0; x < _game.Map.GetLength(0); x++) + { + if (_currentMap != null && !fullRedraw) + { + var currentField = _currentMap[x, y]; + var newField = _game.Map[x, y]; + if (currentField == null || currentField.DisplayState != newField.DisplayState) + { + Console.SetCursorPosition(MapPositon.X + x, MapPositon.Y + y); + DrawChar(_game.Map[x, y], x == Cursor.X && y == Cursor.Y); + } + } + else + { + DrawChar(_game.Map[x, y], x == Cursor.X && y == Cursor.Y); + } + } + } + _currentMap = ArrayHelpers.Clone2D(_game.Map); + } + + private void DrawChar(IField f, bool isCursor) + { + var oldBg = Console.BackgroundColor; + var oldFg = Console.ForegroundColor; + bool fgChanged = false; + bool bgChanged = false; + var c = 'E'; + var state = f.DisplayState; + switch (state) + { + case DisplayState.EMPTY: + c = ' '; + break; + case DisplayState.NONE: + bgChanged = true; + fgChanged = true; + Console.ForegroundColor = ConsoleColor.Black; + Console.BackgroundColor = ConsoleColor.Gray; + //c = '◌'; + c = ' '; + break; + case DisplayState.QUESTIONMARK: + fgChanged = true; + bgChanged = true; + Console.BackgroundColor = ConsoleColor.Gray; + Console.ForegroundColor = ConsoleColor.DarkBlue; + c = '?'; + break; + case DisplayState.BOMB: + fgChanged = true; + Console.ForegroundColor = ConsoleColor.Red; + c = '☼'; + break; + case DisplayState.ERROR: + c = 'e'; + break; + case DisplayState.FLAG: + fgChanged = true; + bgChanged = true; + Console.BackgroundColor = ConsoleColor.Gray; + Console.ForegroundColor = ConsoleColor.DarkRed; + c = 'F'; + break; + case DisplayState.NUMBER1: + case DisplayState.NUMBER2: + case DisplayState.NUMBER3: + case DisplayState.NUMBER4: + case DisplayState.NUMBER5: + case DisplayState.NUMBER6: + case DisplayState.NUMBER7: + case DisplayState.NUMBER8: + fgChanged = true; + switch (state) + { + case DisplayState.NUMBER1: + Console.ForegroundColor = ConsoleColor.Green; + break; + case DisplayState.NUMBER2: + Console.ForegroundColor = ConsoleColor.Yellow; + break; + case DisplayState.NUMBER3: + Console.ForegroundColor = ConsoleColor.DarkYellow; + break; + case DisplayState.NUMBER4: + Console.ForegroundColor = ConsoleColor.DarkRed; + break; + default: + Console.ForegroundColor = ConsoleColor.Red; + break; + } + c = ((int)state).ToString()[0]; + break; + } + if (isCursor) + { + fgChanged = true; + bgChanged = true; + var s = Console.ForegroundColor; + Console.ForegroundColor = Console.BackgroundColor; + Console.BackgroundColor = s; + } + Console.Write(c); + if (fgChanged) + Console.ForegroundColor = oldFg; + if (bgChanged) + Console.BackgroundColor = oldBg; + } + private void DrawBorder() + { + var width = _game.Map.GetLength(0) + 2; + var height = _game.Map.GetLength(1) + 2; + Console.SetCursorPosition(Position.X, Position.Y); + var linebuilder = new StringBuilder(); + linebuilder.Append("╔"); + for (var x = 0; x < width - 2; x++) + linebuilder.Append("═"); + linebuilder.Append("╗"); + Console.Write(linebuilder); + for (var y = 1; y < height - 1; y++) + { + Console.SetCursorPosition(Position.X, Position.Y + y); + Console.Write("║"); + Console.SetCursorPosition(Position.X + width - 1, Position.Y + y); + Console.Write("║"); + } + Console.SetCursorPosition(Position.X, Position.Y + height - 1); + linebuilder = new StringBuilder(); + linebuilder.Append("╚"); + for (var x = 0; x < width - 2; x++) + linebuilder.Append("═"); + linebuilder.Append("╝"); + Console.Write(linebuilder); + // ┌──┬──┐ ╔══╦══╗ ╒══╤══╕ ╓──╥──╖ + // │ │ │ ║ ║ ║ │ │ │ ║ ║ ║ + // ├──┼──┤ ╠══╬══╣ ╞══╪══╡ ╟──╫──╢ + // │ │ │ ║ ║ ║ │ │ │ ║ ║ ║ + // └──┴──┘ ╚══╩══╝ ╘══╧══╛ ╙──╨──╜ + } + + public bool HandleKeyEvent(ConsoleKey key) + { + var oldCursorPos = Cursor; + bool fullRedraw = false; + bool keyHandled = true; + switch (key) + { + case ConsoleKey.UpArrow: + Cursor = new Position(Cursor.X, Math.Max(Cursor.Y - 1, 0)); + break; + case ConsoleKey.DownArrow: + Cursor = new Position(Cursor.X, Math.Min(Cursor.Y + 1, _game.Map.GetLength(1) - 1)); + break; + case ConsoleKey.LeftArrow: + Cursor = new Position(Math.Max(Cursor.X - 1, 0), Cursor.Y); + break; + case ConsoleKey.RightArrow: + Cursor = new Position(Math.Min(Cursor.X + 1, _game.Map.GetLength(0) - 1), Cursor.Y); + break; + case ConsoleKey.Spacebar: + fullRedraw = true; + _game.Reveal(Cursor.X, Cursor.Y); + break; + case ConsoleKey.F: + fullRedraw = true; + _game.ToggleMark(Cursor.X, Cursor.Y); + break; + default: + keyHandled = false; + break; + } + if (fullRedraw) + { + DrawMap(false); + } + else if (oldCursorPos != Cursor) + { + Console.SetCursorPosition(oldCursorPos.X + MapPositon.X, oldCursorPos.Y + MapPositon.Y); + DrawChar(_game.Map[oldCursorPos.X, oldCursorPos.Y], false); + Console.SetCursorPosition(Cursor.X + MapPositon.X, Cursor.Y + MapPositon.Y); + DrawChar(_game.Map[Cursor.X, Cursor.Y], true); + } + return keyHandled; + } + } +} diff --git a/CoopSweeper/View/IView.cs b/CoopSweeper/View/IView.cs new file mode 100644 index 0000000..1450395 --- /dev/null +++ b/CoopSweeper/View/IView.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CoopSweeper.View +{ + public interface IView + { + bool HandleKeyEvent(ConsoleKey key); + + Position Position { get; set; } + + void Draw(bool fullRedraw); + } +} diff --git a/CoopSweeper/View/MenuBarView.cs b/CoopSweeper/View/MenuBarView.cs new file mode 100644 index 0000000..c4c0775 --- /dev/null +++ b/CoopSweeper/View/MenuBarView.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CoopSweeper.View +{ + public class MenuBarView : IView + { + public Position Position { get; set; } + + public void Draw(bool fullRedraw) + { + Console.SetCursorPosition(Position.X, Position.Y); + Console.Write(" "); + Console.BackgroundColor = ConsoleColor.Gray; + Console.ForegroundColor = ConsoleColor.Black; + Console.Write("Configure Restart Exit"); + Console.ForegroundColor = ConsoleColor.Gray; + Console.BackgroundColor = ConsoleColor.Black; + Console.Write(" "); + } + + public bool HandleKeyEvent(ConsoleKey key) + { + return false; + } + } +} diff --git a/CoopSweeper/View/Position.cs b/CoopSweeper/View/Position.cs new file mode 100644 index 0000000..93c72a0 --- /dev/null +++ b/CoopSweeper/View/Position.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CoopSweeper.View +{ + public struct Position + { + public Position(int x, int y) + { + X = x; + Y = y; + } + + public int X { get; set; } + public int Y { get; set; } + + public override bool Equals(object obj) + { + if (!(obj is Position)) + return false; + + var position = (Position)obj; + return X == position.X && + Y == position.Y; + } + + public override int GetHashCode() + { + var hashCode = 1861411795; + hashCode = hashCode * -1521134295 + X.GetHashCode(); + hashCode = hashCode * -1521134295 + Y.GetHashCode(); + return hashCode; + } + + public static bool operator ==(Position a, Position b) => a.X == b.X && a.Y == b.Y; + public static bool operator !=(Position a, Position b) => a.X != b.X || a.Y != b.Y; + } +}