2048 console game (C#)
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
5
down vote
favorite
So about a week ago I decided to write a simple console version of 2048 game. Well, as you'll see, it came out not that simple... And took a lot more time and practice than expected (should've done it with 2d array...). But anyway here's a code, and I want to know how can it be optimized and improved? I want to know my mistakes and how it can be done easier. If you have some general tips on coding style, readability or anything else I'd appreciate your help.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace Game
class Program
static void Main()
Console.CursorVisible = false;
do
Game game = new Game(4, 8, 2);
string key;
do
Console.WriteLine("1. New game");
Console.WriteLine("2. Quit");
key = Console.ReadLine();
Console.Clear();
while (key != "1" && key != "2");
switch (key)
case "1":
game.Run();
break;
case "2":
Environment.Exit(0);
break;
Console.Clear();
while (true);
public enum Direction
Left,
Right,
Up,
Down
class Cell : IEquatable<Cell>, ICloneable
public int Value get; set;
public int X get; set;
public int Y get; set;
public Cell(int value, int x, int y)
Value = value;
X = x;
Y = y;
// Double the value
public void Double() => Value *= 2;
// Display value of cell at certain coordinates
public void Display()
Console.SetCursorPosition((Y - 1) * 5 + 1, (X - 1) * 2 + 1);
ColorChanger.ColorCell(Value.ToString());
// Erase value of cell at certain coordinates
public void Erase()
Console.SetCursorPosition((Y - 1) * 5 + 1, (X - 1) * 2 + 1);
ColorChanger.ColorCell(" ");
#region overriding section
public static bool operator ==(Cell cell1, Cell cell2)
return cell1.Value == cell2.Value && cell1.X == cell2.X && cell1.Y == cell2.Y;
public static bool operator !=(Cell cell1, Cell cell2)
return !(cell1.Value == cell2.Value && cell1.X == cell2.X && cell1.Y == cell2.Y);
public bool Equals(Cell cell)
if (cell is null)
return false;
return Value == cell.Value && X == cell.X && Y == cell.Y;
public override bool Equals(object obj)
Cell cell = obj as Cell;
if (obj == null)
return false;
return Value == cell.Value && X == cell.X && Y == cell.Y;
public override int GetHashCode()
return Value.GetHashCode() ^ X.GetHashCode() ^ Y.GetHashCode();
public object Clone() => MemberwiseClone();
#endregion
class Game
// Length & Width of game field (doesn't have to be equal)
int length;
int width;
int Length
get => length;
set
if (value >= 2)
length = value;
else
length = 2;
int Width
get => width;
set
if (value >= 2)
width = value;
else
width = 2;
// Stats of current game
int Score get; set;
static int Highscore get; set;
int Moves get; set;
// List of current cells & cells on previous move
List<Cell> cells;
List<Cell> prevCells;
Random rand = new Random();
// Initializing the game with field parameters and cell amount at the beginning
public Game(int length, int width, int initialCellAmount)
cells = new List<Cell>();
prevCells = new List<Cell>();
Length = length;
Width = width;
Score = 0;
Moves = 0;
for (int i = 0; i < initialCellAmount; i++)
AddCell();
// Launching the game
public void Run()
DisplayField();
DisplayCells();
DisplayStats();
do
if (Console.KeyAvailable)
while (true);
// Checking for any cell on field that moved
bool IsMoved()
foreach (Cell cell in prevCells)
if (cells.Contains(cell) == false)
Moves++;
return true;
return false;
// Adding new cell on the field (90% - '2', 10% - '4')
void AddCell()
if (IsFieldFull())
return;
Cell cell;
do
cell = new Cell(rand.NextDouble() < 0.9 ? 2 : 4, rand.Next(1, Length), rand.Next(1, Width));
while (cells.Any(c => c.X == cell.X && c.Y == cell.Y));
cells.Add(cell);
// Drawing the field
void DisplayField()
for (int i = 0; i < Length + 1; i++)
");
Console.WriteLine();
// Displaying existing cells
void DisplayCells()
foreach (Cell cell in cells)
cell.Display();
// Displaying score, highscore and moves
void DisplayStats()
Console.SetCursorPosition(0, 9);
Console.WriteLine($"Score: Score Highscore: Highscoren" +
$"Moves: Moves");
// Cells movement algorithm
void MoveCells(Direction dir)
dir == Direction.Up ? 1 : -1;
for (int i = -1; i + 1 < cells.Count(); i++)
getCoord(getCurr(), true) != getCoord(getNext(), true))
Cell temp = getNext();
setCoord(ref temp, border);
continue;
if (getCurr().Value == getNext().Value)
getCurr().Double();
CalculateScore(getCurr().Value);
cells.Remove(getNext());
i--;
else
Cell temp = getNext();
setCoord(ref temp, getCoord(getCurr(), false) + n);
// Setting new score and highscore
void CalculateScore(int value)
Score += value;
if (Score > Highscore)
Highscore = Score;
// Choosing movement direction of corresponding key
void HandleKey()
prevCells = cells.Select(c => (Cell)c.Clone()).ToList();
ConsoleKeyInfo cki = Console.ReadKey(true);
switch (cki.Key)
case ConsoleKey.LeftArrow:
MoveCells(Direction.Left);
break;
case ConsoleKey.RightArrow:
MoveCells(Direction.Right);
break;
case ConsoleKey.UpArrow:
MoveCells(Direction.Up);
break;
case ConsoleKey.DownArrow:
MoveCells(Direction.Down);
break;
// Checking for field overflow
bool IsFieldFull()
return cells.Count() == Length * Width;
// Checking if there is no cell that can be moved
bool IsOver()
if (!IsFieldFull())
return false;
cells = cells.OrderBy(c => c.X).ThenBy(c => c.Y).ToList();
int[,] values = new int[Length, Width];
foreach (Cell cell in cells)
values[cell.X - 1, cell.Y - 1] = cell.Value;
for (int i = 0; i < Length; i++)
for (int j = 0; j < Width; j++)
center == bottom)
return false;
return true;
// Searching for cell with 2048
bool IsWon()
return cells.Any(c => c.Value == 2048);
// Class for changing color for cells
static class ColorChanger
// Get color for corresponding value of cell
static ConsoleColor GetCellColor(string value)
switch (value)
case "2":
return ConsoleColor.Blue;
case "4":
return ConsoleColor.Magenta;
case "8":
return ConsoleColor.Cyan;
case "16":
return ConsoleColor.Green;
case "32":
return ConsoleColor.Yellow;
case "64":
return ConsoleColor.DarkBlue;
case "128":
return ConsoleColor.DarkMagenta;
case "256":
return ConsoleColor.DarkCyan;
case "512":
return ConsoleColor.DarkGreen;
case "1024":
return ConsoleColor.DarkYellow;
default:
return ConsoleColor.Red;
// Color certain cell with optional background color
public static void ColorCell(string value, ConsoleColor bgColor = ConsoleColor.Black)
ConsoleColor defaultFg = Console.ForegroundColor;
ConsoleColor defaultBg = Console.BackgroundColor;
Console.ForegroundColor = GetCellColor(value);
Console.BackgroundColor = bgColor;
Console.WriteLine(value);
Console.ForegroundColor = defaultFg;
Console.BackgroundColor = defaultBg;
c# performance game console 2048
add a comment |Â
up vote
5
down vote
favorite
So about a week ago I decided to write a simple console version of 2048 game. Well, as you'll see, it came out not that simple... And took a lot more time and practice than expected (should've done it with 2d array...). But anyway here's a code, and I want to know how can it be optimized and improved? I want to know my mistakes and how it can be done easier. If you have some general tips on coding style, readability or anything else I'd appreciate your help.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace Game
class Program
static void Main()
Console.CursorVisible = false;
do
Game game = new Game(4, 8, 2);
string key;
do
Console.WriteLine("1. New game");
Console.WriteLine("2. Quit");
key = Console.ReadLine();
Console.Clear();
while (key != "1" && key != "2");
switch (key)
case "1":
game.Run();
break;
case "2":
Environment.Exit(0);
break;
Console.Clear();
while (true);
public enum Direction
Left,
Right,
Up,
Down
class Cell : IEquatable<Cell>, ICloneable
public int Value get; set;
public int X get; set;
public int Y get; set;
public Cell(int value, int x, int y)
Value = value;
X = x;
Y = y;
// Double the value
public void Double() => Value *= 2;
// Display value of cell at certain coordinates
public void Display()
Console.SetCursorPosition((Y - 1) * 5 + 1, (X - 1) * 2 + 1);
ColorChanger.ColorCell(Value.ToString());
// Erase value of cell at certain coordinates
public void Erase()
Console.SetCursorPosition((Y - 1) * 5 + 1, (X - 1) * 2 + 1);
ColorChanger.ColorCell(" ");
#region overriding section
public static bool operator ==(Cell cell1, Cell cell2)
return cell1.Value == cell2.Value && cell1.X == cell2.X && cell1.Y == cell2.Y;
public static bool operator !=(Cell cell1, Cell cell2)
return !(cell1.Value == cell2.Value && cell1.X == cell2.X && cell1.Y == cell2.Y);
public bool Equals(Cell cell)
if (cell is null)
return false;
return Value == cell.Value && X == cell.X && Y == cell.Y;
public override bool Equals(object obj)
Cell cell = obj as Cell;
if (obj == null)
return false;
return Value == cell.Value && X == cell.X && Y == cell.Y;
public override int GetHashCode()
return Value.GetHashCode() ^ X.GetHashCode() ^ Y.GetHashCode();
public object Clone() => MemberwiseClone();
#endregion
class Game
// Length & Width of game field (doesn't have to be equal)
int length;
int width;
int Length
get => length;
set
if (value >= 2)
length = value;
else
length = 2;
int Width
get => width;
set
if (value >= 2)
width = value;
else
width = 2;
// Stats of current game
int Score get; set;
static int Highscore get; set;
int Moves get; set;
// List of current cells & cells on previous move
List<Cell> cells;
List<Cell> prevCells;
Random rand = new Random();
// Initializing the game with field parameters and cell amount at the beginning
public Game(int length, int width, int initialCellAmount)
cells = new List<Cell>();
prevCells = new List<Cell>();
Length = length;
Width = width;
Score = 0;
Moves = 0;
for (int i = 0; i < initialCellAmount; i++)
AddCell();
// Launching the game
public void Run()
DisplayField();
DisplayCells();
DisplayStats();
do
if (Console.KeyAvailable)
while (true);
// Checking for any cell on field that moved
bool IsMoved()
foreach (Cell cell in prevCells)
if (cells.Contains(cell) == false)
Moves++;
return true;
return false;
// Adding new cell on the field (90% - '2', 10% - '4')
void AddCell()
if (IsFieldFull())
return;
Cell cell;
do
cell = new Cell(rand.NextDouble() < 0.9 ? 2 : 4, rand.Next(1, Length), rand.Next(1, Width));
while (cells.Any(c => c.X == cell.X && c.Y == cell.Y));
cells.Add(cell);
// Drawing the field
void DisplayField()
for (int i = 0; i < Length + 1; i++)
");
Console.WriteLine();
// Displaying existing cells
void DisplayCells()
foreach (Cell cell in cells)
cell.Display();
// Displaying score, highscore and moves
void DisplayStats()
Console.SetCursorPosition(0, 9);
Console.WriteLine($"Score: Score Highscore: Highscoren" +
$"Moves: Moves");
// Cells movement algorithm
void MoveCells(Direction dir)
dir == Direction.Up ? 1 : -1;
for (int i = -1; i + 1 < cells.Count(); i++)
getCoord(getCurr(), true) != getCoord(getNext(), true))
Cell temp = getNext();
setCoord(ref temp, border);
continue;
if (getCurr().Value == getNext().Value)
getCurr().Double();
CalculateScore(getCurr().Value);
cells.Remove(getNext());
i--;
else
Cell temp = getNext();
setCoord(ref temp, getCoord(getCurr(), false) + n);
// Setting new score and highscore
void CalculateScore(int value)
Score += value;
if (Score > Highscore)
Highscore = Score;
// Choosing movement direction of corresponding key
void HandleKey()
prevCells = cells.Select(c => (Cell)c.Clone()).ToList();
ConsoleKeyInfo cki = Console.ReadKey(true);
switch (cki.Key)
case ConsoleKey.LeftArrow:
MoveCells(Direction.Left);
break;
case ConsoleKey.RightArrow:
MoveCells(Direction.Right);
break;
case ConsoleKey.UpArrow:
MoveCells(Direction.Up);
break;
case ConsoleKey.DownArrow:
MoveCells(Direction.Down);
break;
// Checking for field overflow
bool IsFieldFull()
return cells.Count() == Length * Width;
// Checking if there is no cell that can be moved
bool IsOver()
if (!IsFieldFull())
return false;
cells = cells.OrderBy(c => c.X).ThenBy(c => c.Y).ToList();
int[,] values = new int[Length, Width];
foreach (Cell cell in cells)
values[cell.X - 1, cell.Y - 1] = cell.Value;
for (int i = 0; i < Length; i++)
for (int j = 0; j < Width; j++)
center == bottom)
return false;
return true;
// Searching for cell with 2048
bool IsWon()
return cells.Any(c => c.Value == 2048);
// Class for changing color for cells
static class ColorChanger
// Get color for corresponding value of cell
static ConsoleColor GetCellColor(string value)
switch (value)
case "2":
return ConsoleColor.Blue;
case "4":
return ConsoleColor.Magenta;
case "8":
return ConsoleColor.Cyan;
case "16":
return ConsoleColor.Green;
case "32":
return ConsoleColor.Yellow;
case "64":
return ConsoleColor.DarkBlue;
case "128":
return ConsoleColor.DarkMagenta;
case "256":
return ConsoleColor.DarkCyan;
case "512":
return ConsoleColor.DarkGreen;
case "1024":
return ConsoleColor.DarkYellow;
default:
return ConsoleColor.Red;
// Color certain cell with optional background color
public static void ColorCell(string value, ConsoleColor bgColor = ConsoleColor.Black)
ConsoleColor defaultFg = Console.ForegroundColor;
ConsoleColor defaultBg = Console.BackgroundColor;
Console.ForegroundColor = GetCellColor(value);
Console.BackgroundColor = bgColor;
Console.WriteLine(value);
Console.ForegroundColor = defaultFg;
Console.BackgroundColor = defaultBg;
c# performance game console 2048
2
Bravo, well done! The code is very readable and well structured.
â Olivier Jacot-Descombes
Feb 24 at 15:26
@OlivierJacot-Descombes, thanks, but aside of that I still think there is a room for improvement :)
â Glitch
Feb 24 at 15:33
The code is very readable and well structured. you think? I'm not so sure about it...
â t3chb0t
Feb 25 at 15:30
@t3chb0t then provide some clarification, what you think is wrong and needs to be improved?
â Glitch
Feb 25 at 15:42
add a comment |Â
up vote
5
down vote
favorite
up vote
5
down vote
favorite
So about a week ago I decided to write a simple console version of 2048 game. Well, as you'll see, it came out not that simple... And took a lot more time and practice than expected (should've done it with 2d array...). But anyway here's a code, and I want to know how can it be optimized and improved? I want to know my mistakes and how it can be done easier. If you have some general tips on coding style, readability or anything else I'd appreciate your help.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace Game
class Program
static void Main()
Console.CursorVisible = false;
do
Game game = new Game(4, 8, 2);
string key;
do
Console.WriteLine("1. New game");
Console.WriteLine("2. Quit");
key = Console.ReadLine();
Console.Clear();
while (key != "1" && key != "2");
switch (key)
case "1":
game.Run();
break;
case "2":
Environment.Exit(0);
break;
Console.Clear();
while (true);
public enum Direction
Left,
Right,
Up,
Down
class Cell : IEquatable<Cell>, ICloneable
public int Value get; set;
public int X get; set;
public int Y get; set;
public Cell(int value, int x, int y)
Value = value;
X = x;
Y = y;
// Double the value
public void Double() => Value *= 2;
// Display value of cell at certain coordinates
public void Display()
Console.SetCursorPosition((Y - 1) * 5 + 1, (X - 1) * 2 + 1);
ColorChanger.ColorCell(Value.ToString());
// Erase value of cell at certain coordinates
public void Erase()
Console.SetCursorPosition((Y - 1) * 5 + 1, (X - 1) * 2 + 1);
ColorChanger.ColorCell(" ");
#region overriding section
public static bool operator ==(Cell cell1, Cell cell2)
return cell1.Value == cell2.Value && cell1.X == cell2.X && cell1.Y == cell2.Y;
public static bool operator !=(Cell cell1, Cell cell2)
return !(cell1.Value == cell2.Value && cell1.X == cell2.X && cell1.Y == cell2.Y);
public bool Equals(Cell cell)
if (cell is null)
return false;
return Value == cell.Value && X == cell.X && Y == cell.Y;
public override bool Equals(object obj)
Cell cell = obj as Cell;
if (obj == null)
return false;
return Value == cell.Value && X == cell.X && Y == cell.Y;
public override int GetHashCode()
return Value.GetHashCode() ^ X.GetHashCode() ^ Y.GetHashCode();
public object Clone() => MemberwiseClone();
#endregion
class Game
// Length & Width of game field (doesn't have to be equal)
int length;
int width;
int Length
get => length;
set
if (value >= 2)
length = value;
else
length = 2;
int Width
get => width;
set
if (value >= 2)
width = value;
else
width = 2;
// Stats of current game
int Score get; set;
static int Highscore get; set;
int Moves get; set;
// List of current cells & cells on previous move
List<Cell> cells;
List<Cell> prevCells;
Random rand = new Random();
// Initializing the game with field parameters and cell amount at the beginning
public Game(int length, int width, int initialCellAmount)
cells = new List<Cell>();
prevCells = new List<Cell>();
Length = length;
Width = width;
Score = 0;
Moves = 0;
for (int i = 0; i < initialCellAmount; i++)
AddCell();
// Launching the game
public void Run()
DisplayField();
DisplayCells();
DisplayStats();
do
if (Console.KeyAvailable)
while (true);
// Checking for any cell on field that moved
bool IsMoved()
foreach (Cell cell in prevCells)
if (cells.Contains(cell) == false)
Moves++;
return true;
return false;
// Adding new cell on the field (90% - '2', 10% - '4')
void AddCell()
if (IsFieldFull())
return;
Cell cell;
do
cell = new Cell(rand.NextDouble() < 0.9 ? 2 : 4, rand.Next(1, Length), rand.Next(1, Width));
while (cells.Any(c => c.X == cell.X && c.Y == cell.Y));
cells.Add(cell);
// Drawing the field
void DisplayField()
for (int i = 0; i < Length + 1; i++)
");
Console.WriteLine();
// Displaying existing cells
void DisplayCells()
foreach (Cell cell in cells)
cell.Display();
// Displaying score, highscore and moves
void DisplayStats()
Console.SetCursorPosition(0, 9);
Console.WriteLine($"Score: Score Highscore: Highscoren" +
$"Moves: Moves");
// Cells movement algorithm
void MoveCells(Direction dir)
dir == Direction.Up ? 1 : -1;
for (int i = -1; i + 1 < cells.Count(); i++)
getCoord(getCurr(), true) != getCoord(getNext(), true))
Cell temp = getNext();
setCoord(ref temp, border);
continue;
if (getCurr().Value == getNext().Value)
getCurr().Double();
CalculateScore(getCurr().Value);
cells.Remove(getNext());
i--;
else
Cell temp = getNext();
setCoord(ref temp, getCoord(getCurr(), false) + n);
// Setting new score and highscore
void CalculateScore(int value)
Score += value;
if (Score > Highscore)
Highscore = Score;
// Choosing movement direction of corresponding key
void HandleKey()
prevCells = cells.Select(c => (Cell)c.Clone()).ToList();
ConsoleKeyInfo cki = Console.ReadKey(true);
switch (cki.Key)
case ConsoleKey.LeftArrow:
MoveCells(Direction.Left);
break;
case ConsoleKey.RightArrow:
MoveCells(Direction.Right);
break;
case ConsoleKey.UpArrow:
MoveCells(Direction.Up);
break;
case ConsoleKey.DownArrow:
MoveCells(Direction.Down);
break;
// Checking for field overflow
bool IsFieldFull()
return cells.Count() == Length * Width;
// Checking if there is no cell that can be moved
bool IsOver()
if (!IsFieldFull())
return false;
cells = cells.OrderBy(c => c.X).ThenBy(c => c.Y).ToList();
int[,] values = new int[Length, Width];
foreach (Cell cell in cells)
values[cell.X - 1, cell.Y - 1] = cell.Value;
for (int i = 0; i < Length; i++)
for (int j = 0; j < Width; j++)
center == bottom)
return false;
return true;
// Searching for cell with 2048
bool IsWon()
return cells.Any(c => c.Value == 2048);
// Class for changing color for cells
static class ColorChanger
// Get color for corresponding value of cell
static ConsoleColor GetCellColor(string value)
switch (value)
case "2":
return ConsoleColor.Blue;
case "4":
return ConsoleColor.Magenta;
case "8":
return ConsoleColor.Cyan;
case "16":
return ConsoleColor.Green;
case "32":
return ConsoleColor.Yellow;
case "64":
return ConsoleColor.DarkBlue;
case "128":
return ConsoleColor.DarkMagenta;
case "256":
return ConsoleColor.DarkCyan;
case "512":
return ConsoleColor.DarkGreen;
case "1024":
return ConsoleColor.DarkYellow;
default:
return ConsoleColor.Red;
// Color certain cell with optional background color
public static void ColorCell(string value, ConsoleColor bgColor = ConsoleColor.Black)
ConsoleColor defaultFg = Console.ForegroundColor;
ConsoleColor defaultBg = Console.BackgroundColor;
Console.ForegroundColor = GetCellColor(value);
Console.BackgroundColor = bgColor;
Console.WriteLine(value);
Console.ForegroundColor = defaultFg;
Console.BackgroundColor = defaultBg;
c# performance game console 2048
So about a week ago I decided to write a simple console version of 2048 game. Well, as you'll see, it came out not that simple... And took a lot more time and practice than expected (should've done it with 2d array...). But anyway here's a code, and I want to know how can it be optimized and improved? I want to know my mistakes and how it can be done easier. If you have some general tips on coding style, readability or anything else I'd appreciate your help.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace Game
class Program
static void Main()
Console.CursorVisible = false;
do
Game game = new Game(4, 8, 2);
string key;
do
Console.WriteLine("1. New game");
Console.WriteLine("2. Quit");
key = Console.ReadLine();
Console.Clear();
while (key != "1" && key != "2");
switch (key)
case "1":
game.Run();
break;
case "2":
Environment.Exit(0);
break;
Console.Clear();
while (true);
public enum Direction
Left,
Right,
Up,
Down
class Cell : IEquatable<Cell>, ICloneable
public int Value get; set;
public int X get; set;
public int Y get; set;
public Cell(int value, int x, int y)
Value = value;
X = x;
Y = y;
// Double the value
public void Double() => Value *= 2;
// Display value of cell at certain coordinates
public void Display()
Console.SetCursorPosition((Y - 1) * 5 + 1, (X - 1) * 2 + 1);
ColorChanger.ColorCell(Value.ToString());
// Erase value of cell at certain coordinates
public void Erase()
Console.SetCursorPosition((Y - 1) * 5 + 1, (X - 1) * 2 + 1);
ColorChanger.ColorCell(" ");
#region overriding section
public static bool operator ==(Cell cell1, Cell cell2)
return cell1.Value == cell2.Value && cell1.X == cell2.X && cell1.Y == cell2.Y;
public static bool operator !=(Cell cell1, Cell cell2)
return !(cell1.Value == cell2.Value && cell1.X == cell2.X && cell1.Y == cell2.Y);
public bool Equals(Cell cell)
if (cell is null)
return false;
return Value == cell.Value && X == cell.X && Y == cell.Y;
public override bool Equals(object obj)
Cell cell = obj as Cell;
if (obj == null)
return false;
return Value == cell.Value && X == cell.X && Y == cell.Y;
public override int GetHashCode()
return Value.GetHashCode() ^ X.GetHashCode() ^ Y.GetHashCode();
public object Clone() => MemberwiseClone();
#endregion
class Game
// Length & Width of game field (doesn't have to be equal)
int length;
int width;
int Length
get => length;
set
if (value >= 2)
length = value;
else
length = 2;
int Width
get => width;
set
if (value >= 2)
width = value;
else
width = 2;
// Stats of current game
int Score get; set;
static int Highscore get; set;
int Moves get; set;
// List of current cells & cells on previous move
List<Cell> cells;
List<Cell> prevCells;
Random rand = new Random();
// Initializing the game with field parameters and cell amount at the beginning
public Game(int length, int width, int initialCellAmount)
cells = new List<Cell>();
prevCells = new List<Cell>();
Length = length;
Width = width;
Score = 0;
Moves = 0;
for (int i = 0; i < initialCellAmount; i++)
AddCell();
// Launching the game
public void Run()
DisplayField();
DisplayCells();
DisplayStats();
do
if (Console.KeyAvailable)
while (true);
// Checking for any cell on field that moved
bool IsMoved()
foreach (Cell cell in prevCells)
if (cells.Contains(cell) == false)
Moves++;
return true;
return false;
// Adding new cell on the field (90% - '2', 10% - '4')
void AddCell()
if (IsFieldFull())
return;
Cell cell;
do
cell = new Cell(rand.NextDouble() < 0.9 ? 2 : 4, rand.Next(1, Length), rand.Next(1, Width));
while (cells.Any(c => c.X == cell.X && c.Y == cell.Y));
cells.Add(cell);
// Drawing the field
void DisplayField()
for (int i = 0; i < Length + 1; i++)
");
Console.WriteLine();
// Displaying existing cells
void DisplayCells()
foreach (Cell cell in cells)
cell.Display();
// Displaying score, highscore and moves
void DisplayStats()
Console.SetCursorPosition(0, 9);
Console.WriteLine($"Score: Score Highscore: Highscoren" +
$"Moves: Moves");
// Cells movement algorithm
void MoveCells(Direction dir)
dir == Direction.Up ? 1 : -1;
for (int i = -1; i + 1 < cells.Count(); i++)
getCoord(getCurr(), true) != getCoord(getNext(), true))
Cell temp = getNext();
setCoord(ref temp, border);
continue;
if (getCurr().Value == getNext().Value)
getCurr().Double();
CalculateScore(getCurr().Value);
cells.Remove(getNext());
i--;
else
Cell temp = getNext();
setCoord(ref temp, getCoord(getCurr(), false) + n);
// Setting new score and highscore
void CalculateScore(int value)
Score += value;
if (Score > Highscore)
Highscore = Score;
// Choosing movement direction of corresponding key
void HandleKey()
prevCells = cells.Select(c => (Cell)c.Clone()).ToList();
ConsoleKeyInfo cki = Console.ReadKey(true);
switch (cki.Key)
case ConsoleKey.LeftArrow:
MoveCells(Direction.Left);
break;
case ConsoleKey.RightArrow:
MoveCells(Direction.Right);
break;
case ConsoleKey.UpArrow:
MoveCells(Direction.Up);
break;
case ConsoleKey.DownArrow:
MoveCells(Direction.Down);
break;
// Checking for field overflow
bool IsFieldFull()
return cells.Count() == Length * Width;
// Checking if there is no cell that can be moved
bool IsOver()
if (!IsFieldFull())
return false;
cells = cells.OrderBy(c => c.X).ThenBy(c => c.Y).ToList();
int[,] values = new int[Length, Width];
foreach (Cell cell in cells)
values[cell.X - 1, cell.Y - 1] = cell.Value;
for (int i = 0; i < Length; i++)
for (int j = 0; j < Width; j++)
center == bottom)
return false;
return true;
// Searching for cell with 2048
bool IsWon()
return cells.Any(c => c.Value == 2048);
// Class for changing color for cells
static class ColorChanger
// Get color for corresponding value of cell
static ConsoleColor GetCellColor(string value)
switch (value)
case "2":
return ConsoleColor.Blue;
case "4":
return ConsoleColor.Magenta;
case "8":
return ConsoleColor.Cyan;
case "16":
return ConsoleColor.Green;
case "32":
return ConsoleColor.Yellow;
case "64":
return ConsoleColor.DarkBlue;
case "128":
return ConsoleColor.DarkMagenta;
case "256":
return ConsoleColor.DarkCyan;
case "512":
return ConsoleColor.DarkGreen;
case "1024":
return ConsoleColor.DarkYellow;
default:
return ConsoleColor.Red;
// Color certain cell with optional background color
public static void ColorCell(string value, ConsoleColor bgColor = ConsoleColor.Black)
ConsoleColor defaultFg = Console.ForegroundColor;
ConsoleColor defaultBg = Console.BackgroundColor;
Console.ForegroundColor = GetCellColor(value);
Console.BackgroundColor = bgColor;
Console.WriteLine(value);
Console.ForegroundColor = defaultFg;
Console.BackgroundColor = defaultBg;
c# performance game console 2048
edited Feb 24 at 15:06
asked Feb 24 at 14:55
Glitch
756
756
2
Bravo, well done! The code is very readable and well structured.
â Olivier Jacot-Descombes
Feb 24 at 15:26
@OlivierJacot-Descombes, thanks, but aside of that I still think there is a room for improvement :)
â Glitch
Feb 24 at 15:33
The code is very readable and well structured. you think? I'm not so sure about it...
â t3chb0t
Feb 25 at 15:30
@t3chb0t then provide some clarification, what you think is wrong and needs to be improved?
â Glitch
Feb 25 at 15:42
add a comment |Â
2
Bravo, well done! The code is very readable and well structured.
â Olivier Jacot-Descombes
Feb 24 at 15:26
@OlivierJacot-Descombes, thanks, but aside of that I still think there is a room for improvement :)
â Glitch
Feb 24 at 15:33
The code is very readable and well structured. you think? I'm not so sure about it...
â t3chb0t
Feb 25 at 15:30
@t3chb0t then provide some clarification, what you think is wrong and needs to be improved?
â Glitch
Feb 25 at 15:42
2
2
Bravo, well done! The code is very readable and well structured.
â Olivier Jacot-Descombes
Feb 24 at 15:26
Bravo, well done! The code is very readable and well structured.
â Olivier Jacot-Descombes
Feb 24 at 15:26
@OlivierJacot-Descombes, thanks, but aside of that I still think there is a room for improvement :)
â Glitch
Feb 24 at 15:33
@OlivierJacot-Descombes, thanks, but aside of that I still think there is a room for improvement :)
â Glitch
Feb 24 at 15:33
The code is very readable and well structured. you think? I'm not so sure about it...
â t3chb0t
Feb 25 at 15:30
The code is very readable and well structured. you think? I'm not so sure about it...
â t3chb0t
Feb 25 at 15:30
@t3chb0t then provide some clarification, what you think is wrong and needs to be improved?
â Glitch
Feb 25 at 15:42
@t3chb0t then provide some clarification, what you think is wrong and needs to be improved?
â Glitch
Feb 25 at 15:42
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
4
down vote
accepted
Bravo, well done! The code is very readable and well structured.
If you intend to make several console games, you will notice that some things remain the same. To allow reusability I suggest abstracting certain aspects through interfaces. It also reduces dependencies between components, enhances testability and allows you to easily replace a component by another one.
public interface IMainUserInterface
void StartGame(IGameLoop gameLoop, IGame game);
public interface IGameLoop
void Run(IGame game);
public interface IGame
void DisplayField();
void DisplayCells();
void DisplayStats();
void MakeMove(ConsoleKeyInfo cki);
bool IsOver();
bool IsWon();
The IMainUserInterface
implementation:
public class MainUserInterface : IMainUserInterface
public void StartGame(IGameLoop gameLoop, IGame game)
Console.CursorVisible = false;
do
string key;
do
Console.WriteLine("1. New game");
Console.WriteLine("2. Quit");
key = Console.ReadLine();
Console.Clear();
while (key != "1" && key != "2");
switch (key)
case "1":
gameLoop.Run(game);
break;
case "2":
Environment.Exit(0);
break;
Console.Clear();
while (true);
The IGameLoop
implementation:
public class GameLoop : IGameLoop
void Run(IGame game)
game.DisplayField();
game.DisplayCells();
game.DisplayStats();
do
if (Console.KeyAvailable)
game.MakeMove(Console.ReadKey(true));
game.DisplayCells();
game.DisplayStats();
bool isOver = game.IsOver();
bool isWon = game.IsWon();
if (isOver
while (true);
I won't show the game implementation here. The Main
method becomes
class Program
static void Main()
IMainUserInterface userInterface = new MainUserInterface();
IGameLoop gameLoop = new GameLoop();
IGame game = new Game2048();
userInterface.StartGame(gameLoop, game);
Thank you, I will definitely include interfaces in my next projects :)
â Glitch
Feb 24 at 18:05
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
4
down vote
accepted
Bravo, well done! The code is very readable and well structured.
If you intend to make several console games, you will notice that some things remain the same. To allow reusability I suggest abstracting certain aspects through interfaces. It also reduces dependencies between components, enhances testability and allows you to easily replace a component by another one.
public interface IMainUserInterface
void StartGame(IGameLoop gameLoop, IGame game);
public interface IGameLoop
void Run(IGame game);
public interface IGame
void DisplayField();
void DisplayCells();
void DisplayStats();
void MakeMove(ConsoleKeyInfo cki);
bool IsOver();
bool IsWon();
The IMainUserInterface
implementation:
public class MainUserInterface : IMainUserInterface
public void StartGame(IGameLoop gameLoop, IGame game)
Console.CursorVisible = false;
do
string key;
do
Console.WriteLine("1. New game");
Console.WriteLine("2. Quit");
key = Console.ReadLine();
Console.Clear();
while (key != "1" && key != "2");
switch (key)
case "1":
gameLoop.Run(game);
break;
case "2":
Environment.Exit(0);
break;
Console.Clear();
while (true);
The IGameLoop
implementation:
public class GameLoop : IGameLoop
void Run(IGame game)
game.DisplayField();
game.DisplayCells();
game.DisplayStats();
do
if (Console.KeyAvailable)
game.MakeMove(Console.ReadKey(true));
game.DisplayCells();
game.DisplayStats();
bool isOver = game.IsOver();
bool isWon = game.IsWon();
if (isOver
while (true);
I won't show the game implementation here. The Main
method becomes
class Program
static void Main()
IMainUserInterface userInterface = new MainUserInterface();
IGameLoop gameLoop = new GameLoop();
IGame game = new Game2048();
userInterface.StartGame(gameLoop, game);
Thank you, I will definitely include interfaces in my next projects :)
â Glitch
Feb 24 at 18:05
add a comment |Â
up vote
4
down vote
accepted
Bravo, well done! The code is very readable and well structured.
If you intend to make several console games, you will notice that some things remain the same. To allow reusability I suggest abstracting certain aspects through interfaces. It also reduces dependencies between components, enhances testability and allows you to easily replace a component by another one.
public interface IMainUserInterface
void StartGame(IGameLoop gameLoop, IGame game);
public interface IGameLoop
void Run(IGame game);
public interface IGame
void DisplayField();
void DisplayCells();
void DisplayStats();
void MakeMove(ConsoleKeyInfo cki);
bool IsOver();
bool IsWon();
The IMainUserInterface
implementation:
public class MainUserInterface : IMainUserInterface
public void StartGame(IGameLoop gameLoop, IGame game)
Console.CursorVisible = false;
do
string key;
do
Console.WriteLine("1. New game");
Console.WriteLine("2. Quit");
key = Console.ReadLine();
Console.Clear();
while (key != "1" && key != "2");
switch (key)
case "1":
gameLoop.Run(game);
break;
case "2":
Environment.Exit(0);
break;
Console.Clear();
while (true);
The IGameLoop
implementation:
public class GameLoop : IGameLoop
void Run(IGame game)
game.DisplayField();
game.DisplayCells();
game.DisplayStats();
do
if (Console.KeyAvailable)
game.MakeMove(Console.ReadKey(true));
game.DisplayCells();
game.DisplayStats();
bool isOver = game.IsOver();
bool isWon = game.IsWon();
if (isOver
while (true);
I won't show the game implementation here. The Main
method becomes
class Program
static void Main()
IMainUserInterface userInterface = new MainUserInterface();
IGameLoop gameLoop = new GameLoop();
IGame game = new Game2048();
userInterface.StartGame(gameLoop, game);
Thank you, I will definitely include interfaces in my next projects :)
â Glitch
Feb 24 at 18:05
add a comment |Â
up vote
4
down vote
accepted
up vote
4
down vote
accepted
Bravo, well done! The code is very readable and well structured.
If you intend to make several console games, you will notice that some things remain the same. To allow reusability I suggest abstracting certain aspects through interfaces. It also reduces dependencies between components, enhances testability and allows you to easily replace a component by another one.
public interface IMainUserInterface
void StartGame(IGameLoop gameLoop, IGame game);
public interface IGameLoop
void Run(IGame game);
public interface IGame
void DisplayField();
void DisplayCells();
void DisplayStats();
void MakeMove(ConsoleKeyInfo cki);
bool IsOver();
bool IsWon();
The IMainUserInterface
implementation:
public class MainUserInterface : IMainUserInterface
public void StartGame(IGameLoop gameLoop, IGame game)
Console.CursorVisible = false;
do
string key;
do
Console.WriteLine("1. New game");
Console.WriteLine("2. Quit");
key = Console.ReadLine();
Console.Clear();
while (key != "1" && key != "2");
switch (key)
case "1":
gameLoop.Run(game);
break;
case "2":
Environment.Exit(0);
break;
Console.Clear();
while (true);
The IGameLoop
implementation:
public class GameLoop : IGameLoop
void Run(IGame game)
game.DisplayField();
game.DisplayCells();
game.DisplayStats();
do
if (Console.KeyAvailable)
game.MakeMove(Console.ReadKey(true));
game.DisplayCells();
game.DisplayStats();
bool isOver = game.IsOver();
bool isWon = game.IsWon();
if (isOver
while (true);
I won't show the game implementation here. The Main
method becomes
class Program
static void Main()
IMainUserInterface userInterface = new MainUserInterface();
IGameLoop gameLoop = new GameLoop();
IGame game = new Game2048();
userInterface.StartGame(gameLoop, game);
Bravo, well done! The code is very readable and well structured.
If you intend to make several console games, you will notice that some things remain the same. To allow reusability I suggest abstracting certain aspects through interfaces. It also reduces dependencies between components, enhances testability and allows you to easily replace a component by another one.
public interface IMainUserInterface
void StartGame(IGameLoop gameLoop, IGame game);
public interface IGameLoop
void Run(IGame game);
public interface IGame
void DisplayField();
void DisplayCells();
void DisplayStats();
void MakeMove(ConsoleKeyInfo cki);
bool IsOver();
bool IsWon();
The IMainUserInterface
implementation:
public class MainUserInterface : IMainUserInterface
public void StartGame(IGameLoop gameLoop, IGame game)
Console.CursorVisible = false;
do
string key;
do
Console.WriteLine("1. New game");
Console.WriteLine("2. Quit");
key = Console.ReadLine();
Console.Clear();
while (key != "1" && key != "2");
switch (key)
case "1":
gameLoop.Run(game);
break;
case "2":
Environment.Exit(0);
break;
Console.Clear();
while (true);
The IGameLoop
implementation:
public class GameLoop : IGameLoop
void Run(IGame game)
game.DisplayField();
game.DisplayCells();
game.DisplayStats();
do
if (Console.KeyAvailable)
game.MakeMove(Console.ReadKey(true));
game.DisplayCells();
game.DisplayStats();
bool isOver = game.IsOver();
bool isWon = game.IsWon();
if (isOver
while (true);
I won't show the game implementation here. The Main
method becomes
class Program
static void Main()
IMainUserInterface userInterface = new MainUserInterface();
IGameLoop gameLoop = new GameLoop();
IGame game = new Game2048();
userInterface.StartGame(gameLoop, game);
edited Mar 8 at 0:21
answered Feb 24 at 16:09
Olivier Jacot-Descombes
2,3611016
2,3611016
Thank you, I will definitely include interfaces in my next projects :)
â Glitch
Feb 24 at 18:05
add a comment |Â
Thank you, I will definitely include interfaces in my next projects :)
â Glitch
Feb 24 at 18:05
Thank you, I will definitely include interfaces in my next projects :)
â Glitch
Feb 24 at 18:05
Thank you, I will definitely include interfaces in my next projects :)
â Glitch
Feb 24 at 18:05
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f188273%2f2048-console-game-c%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
2
Bravo, well done! The code is very readable and well structured.
â Olivier Jacot-Descombes
Feb 24 at 15:26
@OlivierJacot-Descombes, thanks, but aside of that I still think there is a room for improvement :)
â Glitch
Feb 24 at 15:33
The code is very readable and well structured. you think? I'm not so sure about it...
â t3chb0t
Feb 25 at 15:30
@t3chb0t then provide some clarification, what you think is wrong and needs to be improved?
â Glitch
Feb 25 at 15:42