天天看點

C# 之 帶你玩轉指令行版《2048》 -- 附源碼分享一,效果展示二,玩法說明三,主要邏輯四,代碼實作五,源碼分享

@ TOC

一,效果展示

C# 之 帶你玩轉指令行版《2048》 -- 附源碼分享一,效果展示二,玩法說明三,主要邏輯四,代碼實作五,源碼分享

二,玩法說明

  遊戲的規則很簡單,你需要控制所有方塊向同一個方向運動,兩個相同數字方塊撞在一起之後合并成為他們的和,每次操作之後會随機生成一個2或者4,最終得到一個“2048”的方塊就算勝利了。

三,主要邏輯

  • 4*4的二維數組, 然後周遊裡面的元素,統計所有的0,放到一個list裡面,然後

    Random.next(0,list.count)

    随機一個賦成2.
  • 循環開始,初始化指令行.
  • 鍵盤輸入

    上下左右

    對應四種操作的函數 操作之後先周遊一下有沒有空格 如果有就繼續 沒有空格還得再判斷一下能不能再動了 如果不能就死了
  • 隻需要寫向左和向下的邏輯,向右和向上對應取反即可
  • 如果有任何一個元素是2048 即獲勝

四,代碼實作

4.1 遊戲開始

遊戲開始:

  • 随機生成兩個2
  • 開啟遊戲循環
    • 每次校驗遊戲是夠結束
    • 檢測使用者操作(上下左右)
    • 輸出目前狀态到控制台
/// <summary>
/// 遊戲開始
/// </summary>
public void GameStart()
{
    Add2();
    Add2();
    Output();
    while (true)
    {
        // 用于周遊檢測按下按鍵之後和之前有沒有差別用的bool型變量
        bool flag = false;
        // 勝利條件 周遊
        foreach (int item in arr)     
        {
            if (item == 2048)
            {
                Console.WriteLine("\n(ノ´▽`)ノ♪ ------ 遊戲勝利 ------ (ノ´▽`)ノ♪");
                Last();
            }
        }

        // 這是用于檢測按下按鍵之後和之前有沒有差別用的備份數組​
        int[,] arrtmp = new int[4, 4];
        // 周遊給備份數組指派
        for (int i = 0; i < 4; i++)    
        {
            for (int j = 0; j < 4; j++)
            {
                arrtmp[i, j] = arr[i, j];
            }
        }

        // 擷取使用者操作 --> 上下左右
        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;
        }

        // 周遊檢測 按下方向鍵前的狀态 和  按下方向鍵之後的狀态是不是完全一樣的
        for (int i = 0; i < 4; i++)        
        {
            for (int j = 0; j < 4; j++)
            {
                if (arrtmp[i, j] != arr[i, j])
                {
                    // 一旦有任意一個元素在之前之後不一樣  那麼falg改為true
                    flag = true;          
                }
            }
        }
        if (flag)
        {
            // 如果falg是true 說明變了, 如果變了 就刷一個2出來,  
            // 反之就什麼也不幹
            Add2();    
        }

        // 輸出到控制台
        Output();

        // 檢測按下方向鍵之後死沒死
        if (!End())   
        {
            Console.WriteLine("\n(;´д`)ゞ  ------ 遊戲失敗 ------ (;´д`)ゞ");
            Last();
        }
    }
}           

4.2 随機生成

周遊非零元素 随機把一個賦為2

public void Add2()
{
    listOfCoo.Clear();
    // 周遊所有零元素的坐标
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            if (arr[i, j] == 0)
            {
                // 把周遊到的坐标 當成參數 執行個體化
                CoordinateTools coo = new CoordinateTools(i, j);
                // 把執行個體化的結果add到list裡
                listOfCoo.Add(coo);
            }
        }
    }
    // 如果清單裡一個元素都沒存進來 說明表裡沒有空格了 直接退出
    if (listOfCoo.Count == 0)
    {
        return;
    }
    // 從表裡随機取一個位置 ​
    int cooPlus = rd.Next(0, listOfCoo.Count);
    // 把這個位置指派改寫為2
    arr[listOfCoo[cooPlus].x, listOfCoo[cooPlus].y] = 2;
}           

4.3 數字移動

已向下移動為例:

  • 非0數向下移動,遇到非0數,相同則累加,不同則儲存到目前位置;
  • 向上移動的話,再翻轉一下就可以了
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 判斷勝負

判斷遊戲結束:

  • 周遊數組 有任何一個空元素都說明不可能死
    • 從2開始到2048進行周遊;目的是檢測 每一個數字 他上下左右相鄰有沒有和他一樣的數字
// 判斷遊戲結束
public bool End()
{
    // 周遊數組 有任何一個空元素都說明不可能死
    foreach (int item in arr)
    {
        if (item == 0)
            return true;
    }
    // 從2開始到2048進行周遊   
    // 目的是檢測 每一個數字 他上下左右相鄰有沒有和他一樣的數字 
    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)
                {
                    // 先把所有值為NUM的元素的下标 存到list裡
                    CoordinateTools coo = new CoordinateTools(i, j);  
                    listOfget2.Add(coo);
                }
            }
        }
        // 如果這個list 是空的  就說明目前表裡沒有num 回到FOR繼續
        if (listOfget2 == null)   
        {
            continue;
        }

        // 從清單裡的第一個元素開始 (每一個元素存的都是一組下标x,y)
        foreach (CoordinateTools item in listOfget2)
        {
            foreach (CoordinateTools item2 in listOfget2)
            {
                // 判斷 同一行的是不是列坐标差的絕對值是1  同一列的是不是行坐标差的絕對值是1
                if ((item.y == item2.y && Math.Abs(item.x - item2.x) == 1) || 
                    (item.x == item2.x && Math.Abs(item.y - item2.y) == 1))  
                {
                    // 如果有一個 就不用再循環了 肯定沒死
                    return true;    
                }
            }
        }
    }
    // 全周遊完了 就說明已經死了 傳回false
    return false;  
}           

4.5 重新開始

判斷遊戲結束後,提示使用者是“退出”還是“重玩”,根據使用者選擇進行邏輯處理

/// <summary>
/// 勝利或失敗之後的選擇
/// </summary>
public void Last()
{
    Console.WriteLine("\n輸入X退出 輸入R重新開始\n");
    while (true)
    {
        string str = Console.ReadLine();
        if (str == "x")
        {
            Environment.Exit(0);
        }
        //重新開始 --> 初始化
        if (str == "r")
        {
            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    arr[i, j] = 0;
                }
            }
            GameStart();
        }
    }
}           

五,源碼分享

using System;
using System.Collections.Generic;

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

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

            /// <summary>
            /// 輸出目前狀态
            /// </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<<指令行版2048>> 請按上下左右(↑←↓→)方向鍵操作");
            }

            /// <summary>
            /// 周遊非零元素 随機把一個賦為2
            /// </summary>
            public void Add2()
            {
                listOfCoo.Clear();
                // 周遊所有零元素的坐标
                for (int i = 0; i < 4; i++)
                {
                    for (int j = 0; j < 4; j++)
                    {
                        if (arr[i, j] == 0)
                        {
                            // 把周遊到的坐标 當成參數 執行個體化
                            CoordinateTools coo = new CoordinateTools(i, j);
                            // 把執行個體化的結果add到list裡
                            listOfCoo.Add(coo);
                        }
                    }
                }
                // 如果清單裡一個元素都沒存進來 說明表裡沒有空格了 直接退出
                if (listOfCoo.Count == 0)
                {
                    return;
                }
                // 從表裡随機取一個位置 ​
                int cooPlus = rd.Next(0, listOfCoo.Count);
                // 把這個位置指派改寫為2
                arr[listOfCoo[cooPlus].x, listOfCoo[cooPlus].y] = 2;
            }

            /// <summary>
            /// 遊戲開始
            /// </summary>
            public void GameStart()
            {
                Add2();
                Add2();
                Output();
                while (true)
                {
                    // 用于周遊檢測按下按鍵之後和之前有沒有差別用的bool型變量
                    bool flag = false;
                    // 勝利條件 周遊
                    foreach (int item in arr)     
                    {
                        if (item == 2048)
                        {
                            Console.WriteLine("\n(ノ´▽`)ノ♪ ------ 遊戲勝利 ------ (ノ´▽`)ノ♪");
                            Last();
                        }
                    }

                    // 這是用于檢測按下按鍵之後和之前有沒有差別用的備份數組​
                    int[,] arrtmp = new int[4, 4];
                    // 周遊給備份數組指派
                    for (int i = 0; i < 4; i++)    
                    {
                        for (int j = 0; j < 4; j++)
                        {
                            arrtmp[i, j] = arr[i, j];
                        }
                    }

                    // 擷取使用者操作 --> 上下左右
                    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;
                    }

                    // 周遊檢測 按下方向鍵前的狀态 和  按下方向鍵之後的狀态是不是完全一樣的
                    for (int i = 0; i < 4; i++)        
                    {
                        for (int j = 0; j < 4; j++)
                        {
                            if (arrtmp[i, j] != arr[i, j])
                            {
                                // 一旦有任意一個元素在之前之後不一樣  那麼falg改為true
                                flag = true;          
                            }
                        }
                    }
                    if (flag)
                    {
                        // 如果falg是true 說明變了, 如果變了 就刷一個2出來,  
                        // 反之就什麼也不幹
                        Add2();    
                    }

                    // 輸出到控制台
                    Output();

                    // 檢測按下方向鍵之後死沒死
                    if (!End())   
                    {
                        Console.WriteLine("\n(;´д`)ゞ  ------ 遊戲失敗 ------ (;´д`)ゞ");
                        Last();
                    }
                }
            }

            #region 核心邏輯 --> 向四個方向移動的控制
            /// <summary>
            /// 向下 非0數向下移動,遇到非0數,相同則累加,不同則儲存到目前位置
            /// </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>
            /// 向上移動: 先把數組上下翻轉 然後向下移動  移動完了再翻轉回來
            /// </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>
            /// 向左移動
            /// </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>
            /// 向右移動: 先把數組左右翻轉 然後向左移動  移動完了再翻轉回來
            /// </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>
            /// 判斷是否失敗
            /// </summary>
            /// <returns></returns>
            public bool End()
            {
                // 周遊數組 有任何一個空元素都說明不可能死
                foreach (int item in arr)
                {
                    if (item == 0)
                        return true;
                }
                // 從2開始到2048進行周遊   
                // 目的是檢測 每一個數字 他上下左右相鄰有沒有和他一樣的數字 
                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)
                            {
                                // 先把所有值為NUM的元素的下标 存到list裡
                                CoordinateTools coo = new CoordinateTools(i, j);  
                                listOfget2.Add(coo);
                            }
                        }
                    }
                    // 如果這個list 是空的  就說明目前表裡沒有num 回到FOR繼續
                    if (listOfget2 == null)   
                    {
                        continue;
                    }

                    // 從清單裡的第一個元素開始 (每一個元素存的都是一組下标x,y)
                    foreach (CoordinateTools item in listOfget2)
                    {
                        foreach (CoordinateTools item2 in listOfget2)
                        {
                            // 判斷 同一行的是不是列坐标差的絕對值是1  同一列的是不是行坐标差的絕對值是1
                            if ((item.y == item2.y && Math.Abs(item.x - item2.x) == 1) || 
                                (item.x == item2.x && Math.Abs(item.y - item2.y) == 1))  
                            {
                                // 如果有一個 就不用再循環了 肯定沒死
                                return true;    
                            }
                        }
                    }
                }
                // 全周遊完了 就說明已經死了 傳回false
                return false;  
            }

            /// <summary>
            /// 勝利或失敗之後的選擇
            /// </summary>
            public void Last()
            {
                Console.WriteLine("\n輸入X退出 輸入R重新開始\n");
                while (true)
                {
                    string str = Console.ReadLine();
                    if (str == "x")
                    {
                        Environment.Exit(0);
                    }
                    //重新開始 --> 初始化
                    if (str == "r")
                    {
                        for (int i = 0; i < 4; i++)
                        {
                            for (int j = 0; j < 4; j++)
                            {
                                arr[i, j] = 0;
                            }
                        }
                        GameStart();
                    }
                }
            }
        }

        /// <summary>
        /// 工具類 用于存儲搜尋到的數組的下标
        /// </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;
            }
        }
    }
}