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

1, Effect display

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()
{
    Add2();
    Add2();
    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
        ConsoleKeyInfo info = Console.ReadKey(true);  
        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
            Add2();    
        }

        // 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
                listOfCoo.Add(coo);
            }
        }
    }
    // 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);  
                    listOfget2.Add(coo);
                }
            }
        }
        // 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)
    {
        string str = Console.ReadLine();
        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>
            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
                            listOfCoo.Add(coo);
                        }
                    }
                }
                // 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()
            {
                Add2();
                Add2();
                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
                    ConsoleKeyInfo info = Console.ReadKey(true);  
                    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
                        Add2();    
                    }

                    // 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);  
                                listOfget2.Add(coo);
                            }
                        }
                    }
                    // 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)
                {
                    string str = Console.ReadLine();
                    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#