# C # takes you to play the command-line version of 2048 -- with source code sharing

Posted by KFC on Wed, 17 Nov 2021 13:42:09 +0100

# 2, Play instructions

the rules of the game are very simple. You need to control all squares to move in the same direction. After two identical digital squares collide together, they are merged into their sum. After each operation, a 2 or 4 will be randomly generated, and finally a "2048" square will be regarded as victory.

# 3, Main logic

• 4 * 4 two-dimensional array, then traverse the elements inside, count all zeros, put them in a list, and assign Random.next(0,list.count) to 2
• The loop begins, initializing the command line
• Enter the function corresponding to the four operations up, down, left and right on the keyboard. After the operation, first traverse whether there are spaces. If there are spaces, continue. If there are no spaces, you have to judge whether you can move again. If not, you will die
• Just write the logic to the left and down, and take the opposite to the right and up
• If any element is 2048, it wins

# 4, Code implementation

## 4.1 game start

Game start:

• Randomly generate two 2
• Start game cycle
• Each verification game is enough to end
• Detect user operation (up, down, left and right)
• Output current status to console
```/// <summary>
///The game begins
/// </summary>
public void GameStart()
{
Output();
while (true)
{
// It is used to traverse the bool type variable used to detect whether there is a difference between after pressing the key and before
bool flag = false;
// Victory condition traversal
foreach (int item in arr)
{
if (item == 2048)
{
Console.WriteLine("\n(ﾉ´▽｀)ﾉ♪ ------ Game victory ------ (ﾉ´▽｀)ﾉ♪");
Last();
}
}

// This is a backup array used to detect whether there is a difference between after pressing the key and before
int[,] arrtmp = new int[4, 4];
// Traversal assigns a value to the backup array
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
arrtmp[i, j] = arr[i, j];
}
}

// Get user actions -- > up, down, left and right
switch (info.Key)
{
case ConsoleKey.UpArrow:
MoveUp();
break;
case ConsoleKey.DownArrow:
MoveDown();
break;
case ConsoleKey.LeftArrow:
MoveLeft();
break;
case ConsoleKey.RightArrow:
MoveRight();
break;
}

// Traverse to detect whether the state before pressing the direction key is exactly the same as that after pressing the direction key
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (arrtmp[i, j] != arr[i, j])
{
// Once any element is different before and after, false is changed to true
flag = true;
}
}
}
if (flag)
{
// If false is true, it means that it has changed. If it has changed, brush a 2,
// On the contrary, do nothing
}

// Output to console
Output();

// Detect whether it is dead after pressing the direction key
if (!End())
{
Console.WriteLine("\n(；´д｀)ゞ  ------ Game failure ------ (；´д｀)ゞ");
Last();
}
}
}
```

## 4.2 random generation

Traverse non-zero elements and randomly assign one to 2

```public void Add2()
{
listOfCoo.Clear();
// Traverse the coordinates of all zero elements
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (arr[i, j] == 0)
{
// Instantiate the traversed coordinates as parameters
CoordinateTools coo = new CoordinateTools(i, j);
// add the instantiation result to the list
}
}
}
// If no element in the list is saved, there is no space in the table and you can exit directly
if (listOfCoo.Count == 0)
{
return;
}
// Take a random position from the table
int cooPlus = rd.Next(0, listOfCoo.Count);
// Change this position assignment to 2
arr[listOfCoo[cooPlus].x, listOfCoo[cooPlus].y] = 2;
}
```

## 4.3 digital mobile

Moved down as an example:

• Non-zero numbers move downward. When non-zero numbers are encountered, they are accumulated if they are the same, and saved to the current position if they are different;
• If you move up, just turn it over again
```public void MoveDown()
{
for (int j = 0; j < 4; j++)
{
for (int i = 2; i >= 0; i--)
{
if (arr[i, j] == 0) continue;
for (int k = i + 1; k < 4; k++)
{
if (arr[k, j] != 0)
{
if (arr[i, j] == arr[k, j])
{
arr[k, j] += arr[i, j];
arr[i, j] = 0;
break;
}
else if (arr[i, j] != arr[k, j] && k - 1 != i)
{
arr[k - 1, j] = arr[i, j];
arr[i, j] = 0;
break;
}
else if (arr[i, j] != arr[k, j] && k - 1 == i)
{
break;
}
}
if (k == 3)
{
arr[k, j] = arr[i, j];
arr[i, j] = 0;
break;
}
}
}
}
}
```

## 4.4 judging the outcome

Judge the end of the game:

• Any empty element in the traversal array indicates that it cannot die
• Traverse from 2 to 2048; The purpose is to detect whether each number is adjacent up, down, left and right, and whether there is the same number as him
```// Judge the end of the game
public bool End()
{
// Any empty element in the traversal array indicates that it cannot die
foreach (int item in arr)
{
if (item == 0)
return true;
}
// Traverse from 2 to 2048
// The purpose is to detect whether each number is adjacent up, down, left and right, and whether there is the same number as him
for (int num = 2; num <= 2048; num *= 2)
{
List<CoordinateTools> listOfget2 = new List<CoordinateTools>();
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (arr[i, j] == num)
{
// First save the subscripts of all elements with NUM value in the list
CoordinateTools coo = new CoordinateTools(i, j);
}
}
}
// If the list is empty, it means that there is no num in the current table. Go back to FOR to continue
if (listOfget2 == null)
{
continue;
}

// Start with the first element in the list (each element contains a set of subscripts x,y)
foreach (CoordinateTools item in listOfget2)
{
foreach (CoordinateTools item2 in listOfget2)
{
// Judge whether the absolute value of column coordinate difference in the same row is 1 and whether the absolute value of row coordinate difference in the same column is 1
if ((item.y == item2.y && Math.Abs(item.x - item2.x) == 1) ||
(item.x == item2.x && Math.Abs(item.y - item2.y) == 1))
{
// If there's one, you don't have to recycle it. It's definitely not dead
return true;
}
}
}
}
// After the full traversal, it indicates that it is dead and returns false
return false;
}
```

## 4.5 restart

After judging the end of the game, prompt the user whether to "exit" or "play again", and carry out logical processing according to the user's choice

```/// <summary>
///Choice after victory or defeat
/// </summary>
public void Last()
{
Console.WriteLine("\n input X Exit input R restart\n");
while (true)
{
if (str == "x")
{
Environment.Exit(0);
}
//Restart -- > initialization
if (str == "r")
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
arr[i, j] = 0;
}
}
GameStart();
}
}
}
```

# 5, Source sharing

```using System;
using System.Collections.Generic;

namespace CSharp_2048
{
class Program
{
static void Main(string[] args)
{
Class2048 class2048 = new Class2048();
class2048.GameStart();
}
/// <summary>
///Games 2048
/// </summary>
class Class2048
{

public int[,] arr = new int[4, 4];
public Random rd = new Random();
public List<CoordinateTools> listOfCoo = new List<CoordinateTools>();

/// <summary>
///Output current status
/// </summary>
public void Output()
{
string str = "    ";
Console.Clear();
Console.WriteLine("┏┉┉┉┉┉┉┉┉┳┉┉┉┉┉┉┉┉┳┉┉┉┉┉┉┉┉┳┉┉┉┉┉┉┉┉┓");
Console.WriteLine("┋        ┋        ┋        ┋        ┋");
Console.WriteLine("┋ {0}   ┋  {1}  ┋  {2}  ┋  {3}  ┋",
arr[0, 0] == 0 ? str : arr[0, 0].ToString().PadLeft(4, ' '),
arr[0, 1] == 0 ? str : arr[0, 1].ToString().PadLeft(4, ' '),
arr[0, 2] == 0 ? str : arr[0, 2].ToString().PadLeft(4, ' '),
arr[0, 3] == 0 ? str : arr[0, 3].ToString().PadLeft(4, ' '));
Console.WriteLine("┋        ┋        ┋        ┋        ┋");
Console.WriteLine("┣┉┉┉┉┉┉┉┉╋┉┉┉┉┉┉┉┉╋┉┉┉┉┉┉┉┉╋┉┉┉┉┉┉┉┉┫");
Console.WriteLine("┋        ┋        ┋        ┋        ┋");
Console.WriteLine("┋  {0}  ┋  {1}  ┋  {2}  ┋  {3}  ┋",
arr[1, 0] == 0 ? str : arr[1, 0].ToString().PadLeft(4, ' '),
arr[1, 1] == 0 ? str : arr[1, 1].ToString().PadLeft(4, ' '),
arr[1, 2] == 0 ? str : arr[1, 2].ToString().PadLeft(4, ' '),
arr[1, 3] == 0 ? str : arr[1, 3].ToString().PadLeft(4, ' '));
Console.WriteLine("┋        ┋        ┋        ┋        ┋");
Console.WriteLine("┣┉┉┉┉┉┉┉┉╋┉┉┉┉┉┉┉┉╋┉┉┉┉┉┉┉┉╋┉┉┉┉┉┉┉┉┫");
Console.WriteLine("┋        ┋        ┋        ┋        ┋");
Console.WriteLine("┋  {0}  ┋  {1}  ┋  {2}  ┋  {3}  ┋",
arr[2, 0] == 0 ? str : arr[2, 0].ToString().PadLeft(4, ' '),
arr[2, 1] == 0 ? str : arr[2, 1].ToString().PadLeft(4, ' '),
arr[2, 2] == 0 ? str : arr[2, 2].ToString().PadLeft(4, ' '),
arr[2, 3] == 0 ? str : arr[2, 3].ToString().PadLeft(4, ' '));
Console.WriteLine("┋        ┋        ┋        ┋        ┋");
Console.WriteLine("┣┉┉┉┉┉┉┉┉╋┉┉┉┉┉┉┉┉╋┉┉┉┉┉┉┉┉╋┉┉┉┉┉┉┉┉┫");
Console.WriteLine("┋        ┋        ┋        ┋        ┋");
Console.WriteLine("┋  {0}  ┋  {1}  ┋  {2}  ┋  {3}  ┋",
arr[3, 0] == 0 ? str : arr[3, 0].ToString().PadLeft(4, ' '),
arr[3, 1] == 0 ? str : arr[3, 1].ToString().PadLeft(4, ' '),
arr[3, 2] == 0 ? str : arr[3, 2].ToString().PadLeft(4, ' '),
arr[3, 3] == 0 ? str : arr[3, 3].ToString().PadLeft(4, ' '));
Console.WriteLine("┋        ┋        ┋        ┋        ┋");
Console.WriteLine("┗┉┉┉┉┉┉┉┉┻┉┉┉┉┉┉┉┉┻┉┉┉┉┉┉┉┉┻┉┉┉┉┉┉┉┉┛");
Console.WriteLine("\n<<Command line version 2048>> Please press up, down, left and right(↑←↓→)Direction key operation");
}

/// <summary>
///Traverse non-zero elements and randomly assign one to 2
/// </summary>
{
listOfCoo.Clear();
// Traverse the coordinates of all zero elements
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (arr[i, j] == 0)
{
// Instantiate the traversed coordinates as parameters
CoordinateTools coo = new CoordinateTools(i, j);
// add the instantiation result to the list
}
}
}
// If no element in the list is saved, there is no space in the table and you can exit directly
if (listOfCoo.Count == 0)
{
return;
}
// Take a random position from the table
int cooPlus = rd.Next(0, listOfCoo.Count);
// Change this position assignment to 2
arr[listOfCoo[cooPlus].x, listOfCoo[cooPlus].y] = 2;
}

/// <summary>
///The game begins
/// </summary>
public void GameStart()
{
Output();
while (true)
{
// It is used to traverse the bool type variable used to detect whether there is a difference between after pressing the key and before
bool flag = false;
// Victory condition traversal
foreach (int item in arr)
{
if (item == 2048)
{
Console.WriteLine("\n(ﾉ´▽｀)ﾉ♪ ------ Game victory ------ (ﾉ´▽｀)ﾉ♪");
Last();
}
}

// This is a backup array used to detect whether there is a difference between after pressing the key and before
int[,] arrtmp = new int[4, 4];
// Traversal assigns a value to the backup array
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
arrtmp[i, j] = arr[i, j];
}
}

// Get user actions -- > up, down, left and right
switch (info.Key)
{
case ConsoleKey.UpArrow:
MoveUp();
break;
case ConsoleKey.DownArrow:
MoveDown();
break;
case ConsoleKey.LeftArrow:
MoveLeft();
break;
case ConsoleKey.RightArrow:
MoveRight();
break;
}

// Traverse to detect whether the state before pressing the direction key is exactly the same as that after pressing the direction key
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (arrtmp[i, j] != arr[i, j])
{
// Once any element is different before and after, false is changed to true
flag = true;
}
}
}
if (flag)
{
// If false is true, it means that it has changed. If it has changed, brush a 2,
// On the contrary, do nothing
}

// Output to console
Output();

// Detect whether it is dead after pressing the direction key
if (!End())
{
Console.WriteLine("\n(；´д｀)ゞ  ------ Game failure ------ (；´д｀)ゞ");
Last();
}
}
}

#region core logic -- > control of moving in four directions
/// <summary>
///Move down non-zero numbers. When non-zero numbers are encountered, they are accumulated if they are the same, and saved to the current position if they are different
/// </summary>
public void MoveDown()
{
for (int j = 0; j < 4; j++)
{
for (int i = 2; i >= 0; i--)
{
if (arr[i, j] == 0) continue;
for (int k = i + 1; k < 4; k++)
{
if (arr[k, j] != 0)
{
if (arr[i, j] == arr[k, j])
{
arr[k, j] += arr[i, j];
arr[i, j] = 0;
break;
}
else if (arr[i, j] != arr[k, j] && k - 1 != i)
{
arr[k - 1, j] = arr[i, j];
arr[i, j] = 0;
break;
}
else if (arr[i, j] != arr[k, j] && k - 1 == i)
{
break;
}
}
if (k == 3)
{
arr[k, j] = arr[i, j];
arr[i, j] = 0;
break;
}
}
}
}
}
/// <summary>
///Move up: first flip the array up and down, then move it down, and then flip it back
/// </summary>
public void MoveUp()
{
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 4; j++)
{
int tmp = 0;
tmp = arr[i, j];
arr[i, j] = arr[3 - i, j];
arr[3 - i, j] = tmp;
}
}
MoveDown();
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 4; j++)
{
int tmp = 0;
tmp = arr[i, j];
arr[i, j] = arr[3 - i, j];
arr[3 - i, j] = tmp;
}
}
}

/// <summary>
///Move left
/// </summary>
public void MoveLeft()
{
for (int i = 0; i < 4; i++)
{
for (int j = 1; j < 4; j++)
{
if (arr[i, j] == 0) continue;
for (int k = j - 1; k >= 0; k--)
{
if (arr[i, k] != 0)
{
if (arr[i, j] == arr[i, k])
{
arr[i, k] += arr[i, j];
arr[i, j] = 0;
break;
}
else if (arr[i, j] != arr[i, k] && k + 1 != j)
{
arr[i, k + 1] = arr[i, j];
arr[i, j] = 0;
break;
}
else if (arr[i, j] != arr[i, k] && k + 1 == j)
{
break;
}
}
if (k == 0)
{
arr[i, k] = arr[i, j];
arr[i, j] = 0;
break;
}
}
}
}
}
/// <summary>
///Move right: first flip the array left and right, then move it left, and then flip it back
/// </summary>
public void MoveRight()
{
for (int j = 0; j < 2; j++)
{
for (int i = 0; i < 4; i++)
{
int tmp = 0;
tmp = arr[i, j];
arr[i, j] = arr[i, 3 - j];
arr[i, 3 - j] = tmp;
}
}
MoveLeft();
for (int j = 0; j < 2; j++)
{
for (int i = 0; i < 4; i++)
{
int tmp = 0;
tmp = arr[i, j];
arr[i, j] = arr[i, 3 - j];
arr[i, 3 - j] = tmp;
}
}
}
#endregion

/// <summary>
///Judge whether it fails
/// </summary>
/// <returns></returns>
public bool End()
{
// Any empty element in the traversal array indicates that it cannot die
foreach (int item in arr)
{
if (item == 0)
return true;
}
// Traverse from 2 to 2048
// The purpose is to detect whether each number is adjacent up, down, left and right, and whether there is the same number as him
for (int num = 2; num <= 2048; num *= 2)
{
List<CoordinateTools> listOfget2 = new List<CoordinateTools>();
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (arr[i, j] == num)
{
// First save the subscripts of all elements with NUM value in the list
CoordinateTools coo = new CoordinateTools(i, j);
}
}
}
// If the list is empty, it means that there is no num in the current table. Go back to FOR to continue
if (listOfget2 == null)
{
continue;
}

// Start with the first element in the list (each element contains a set of subscripts x,y)
foreach (CoordinateTools item in listOfget2)
{
foreach (CoordinateTools item2 in listOfget2)
{
// Judge whether the absolute value of column coordinate difference in the same row is 1 and whether the absolute value of row coordinate difference in the same column is 1
if ((item.y == item2.y && Math.Abs(item.x - item2.x) == 1) ||
(item.x == item2.x && Math.Abs(item.y - item2.y) == 1))
{
// If there's one, you don't have to recycle it. It's definitely not dead
return true;
}
}
}
}
// After the full traversal, it indicates that it is dead and returns false
return false;
}

/// <summary>
///Choice after victory or defeat
/// </summary>
public void Last()
{
Console.WriteLine("\n input X Exit input R restart\n");
while (true)
{
if (str == "x")
{
Environment.Exit(0);
}
//Restart -- > initialization
if (str == "r")
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
arr[i, j] = 0;
}
}
GameStart();
}
}
}
}

/// <summary>
///The tool class is used to store the index of the searched array
/// </summary>
class CoordinateTools
{
public int x { set; get; }
public int y { set; get; }
public CoordinateTools(int i, int j)
{
this.x = i;
this.y = j;
}
}
}
}
```

Topics: C#