1. 程式人生 > >c#生成2048遊戲(1)

c#生成2048遊戲(1)

2048遊戲

需求分析

  • 可以使用W、S、A、D鍵進行操作
  • 遊戲開始時隨機的產生2個數值為2/4的方格,位置隨機
  • 每次按下移動鍵後,逐行計算移動後的方格值。每行移動的演算法是:先把移動倒數第二個數,有3種情況,如果次數本身是0,則不移動;或者前面有數,則不移動,如果相等則合併;不然則移動。
  • 一次移動結束後,在所有值為0的方格中隨機的分配一個2/4的值。
  • 所有方格值不為0且上下、左右相鄰的方格都不相等,或者任意方格的值為2048,則遊戲結束。
  • 4出現的概率為90%,2出現的概率為為10%。

分析

整個遊戲過程有3個類,格子類網格類還有遊戲管理類
格子類代表16個格子中的每一個格子,
成員變數:行下標、列下標,格子代表的數,是否是第一次合併,因為是控制檯程式所以不用顏色了

執行結果:
這裡寫圖片描述
這裡寫圖片描述

    /// <summary>
    /// 格子類
    /// </summary>
    class Box
    {
       private int row = 0;
       private int cols = 0;
        int num  = 0;
        bool isFirst = false;//是否是第一次合併
        public int Num
        {
            get
            {
                return num;
            }
            set
{ num = value; } } /// <summary> /// 獲取行數 /// </summary> public int Row { get { return row; } set { row = value; } } ///
<summary>
/// 獲取列數 /// </summary> public int Cols { get { return cols; } } public bool IsFirst { get { return isFirst; } set { isFirst = value; } } public Box(int row,int cols) { this.row = row; this.cols = cols; this.Num = 0; } } }

網格類,負責接收使用者的上下左右操作,然後讓網格內的格子進行相應的移動。然後判斷遊戲的輸贏.(主要操作)
成員變數有:行數,列數,所有格子數(二維陣列儲存),布林型判斷是否第一次產生隨機數,產生隨機數的數量,儲存上一次生成的隨機數的值,當前生成隨機數的個數,遊戲進行開關,合併開關集合

 /// <summary>
    /// 網格類
    /// </summary>
    public class Grid
    {
        int row = 4;//行數
        int cols = 4;//列數
        Box[,] boxList;//陣列,儲存
        bool isFirst = true; //判斷是否是第一次生成隨機數
        int count = 0; //選擇產生每一次隨機生成數字的數量,1or2
        int num = 2; //儲存上次隨機生成數
        int countNum = 0; //儲存生成了的數字的數量,一到16個以便進行遊戲輸贏判斷
        bool gameBegin; //遊戲開關
        Queue<Box> isMerage;//判斷是是否已經合併集合
        Random r;


        public Grid(int row, int cols)
        {
            this.row = row < 0 ? this.row : row;
            this.cols = cols < 0 ? this.cols : cols;
            boxList = new Box[row, cols];
            r = new Random();
            isMerage = new Queue<Box>();
            gameBegin = true; //初始化遊戲開始
        }
        /// <summary>
        /// 返回遊戲開關
        /// </summary>
        public bool GameBegin
        {
            get
            {
                return gameBegin;
            }
        }

        /// <summary>
        /// 初始化佈局
        /// </summary>
        public void Init()
        {
            for (int i = 0; i < boxList.GetLength(0); i++)
            {
                for (int j = 0; j < boxList.GetLength(1); j++)
                {
                    Box box = new Box(i, j);
                    boxList[i, j] = box;
                }
            }
            RandomNum();
            Test();
        }

        /// <summary>
        /// 隨機生成數字
        /// </summary>
        public void RandomNum()
        {
            //第一次生成兩個數字
            if (isFirst)
            {
                count = 2;
                isFirst = false;
            }
            //後面每一次只生成一個數字
            else
            {
                count = 1;
            }
            countNum += count;//生成一個隨機數字,個數加一,以便勝負的判斷
            for (int i = 0; i < count;)//容易形成死迴圈,萬一沒有位置初始化隨機數字容易陷入死迴圈
            {
                //隨機生成下標
                int rObj = r.Next(0, row);
                int cObj = r.Next(0, cols);
                if (boxList[rObj, cObj].Num != 0) {
                    continue;

                }
                //避免出現兩個4
                if (num == 4)
                {
                    num = 2;
                }
                else
                {
                    //隨機生成2,4的概率 ,90%2,20%4
                    int chance = r.Next(1, 11);
                    if (chance > 10) num = 2;
                    else num = 4;
                }
                Console.WriteLine("生成的數:" + num);
                boxList[rObj, cObj].Num = num;
                i++;
            }
        }

        /// <summary>
        /// 使用者輸入了按鍵,根據按鍵選擇移動方向的方法
        /// </summary>
        /// <param name="keyValue"></param>
        public void move(ConsoleKey keyValue)
        {
            switch (keyValue)
            {
                //W 向上
                case ConsoleKey.W: GoUp(); break;
                //S 向下
                case ConsoleKey.S: GoDown(); break;
                //A 向左
                case ConsoleKey.A: GoLetf(); break;
                //D 向右
                case ConsoleKey.D: GoRight(); break;

                default: Console.WriteLine("輸入了錯誤的選擇"); break;
            }
            ReSet();//做完一次操作後重置一下開關
        }

        /// <summary>
        /// 向右運動
        /// </summary>
        private void GoRight()
        {
                //行下標迴圈
                for (int r = 0; r < boxList.GetLength(0); r++)
                {
                    //列下標迴圈
                    for (int c = boxList.GetLength(1) - 2; c >= 0; c--) //按照每行有多少列來迴圈,從右邊到左邊
                    {
                        Box box = boxList[r, c];
                        if (box.Num == 0) continue;
                        for (int nc = c + 1; nc < boxList.GetLength(1); nc++)//數字移動的3種情況
                        {
                            Box nextBox = boxList[r, nc];
                            if (nextBox.Num == 0) //如果前面格子裡沒有數,就往前移
                            {
                                nextBox.Num = box.Num;
                                box.Num = 0;
                                box = nextBox;
                                continue;
                            }
                            if (box.Num == nextBox.Num && !nextBox.IsFirst)//如果格子裡的數和要往前移的格子裡的數是相同的,就可以合併
                            {
                                nextBox.IsFirst = true;
                                nextBox.Num *= 2;
                                box.Num = 0;
                                countNum--;//合併後網格上的格子數減一
                                isMerage.Enqueue(nextBox);//添加了已經合併的數,便於修改合併開關
                            }
                            break;//不能移動格子,也不能合併,格子本身不做任何操作
                        }
                }
            }
            GameSwitch();//判斷遊戲輸贏

        }

        /// <summary>
        /// 向左移動
        /// </summary>
        private void GoLetf()
        {
                //迴圈行下標
                for (int r = 0; r < boxList.GetLength(0); r++)
                {
                    //迴圈列下表
                    for (int c = boxList.GetLength(1) - 3; c < boxList.GetLength(1); c++)//按照每行有多少列來迴圈,從左邊到右邊
                    {
                        Box box = boxList[r, c];
                        if (box.Num == 0) continue;
                        for (int nc = c - 1; nc >= 0; nc--)
                        {
                        Box nextBox = boxList[r, nc];
                        if (box.Num == 0) continue;//檢測當前盒子是否需要往下移動
                        if (nextBox.Num == 0)
                            {
                                nextBox.Num = box.Num;
                                box.Num = 0;
                                box = nextBox;
                                continue;
                            }
                            if (nextBox.Num == box.Num && !nextBox.IsFirst)//合併操作
                            {
                                nextBox.Num *= 2;
                                nextBox.IsFirst = true;
                                box.Num = 0;
                                countNum--;//合併網格的元素減一
                                isMerage.Enqueue(nextBox);//新增已經合併的數,以便重置合併開關
                            }
                            break;
                        }
                }

            }
            GameSwitch();//判斷遊戲輸贏

        }

        /// <summary>
        /// 向上移動
        /// </summary>
        private void GoUp()
        {
                //迴圈列下標 
                for (int c = 0; c < boxList.GetLength(1); c++)
                {
                    //迴圈行下標
                    for (int r = boxList.GetLength(0) - 3; r < boxList.GetLength(0); r++)  //從下到上
                    {
                        Box box = boxList[r, c];
                        if (box.Num == 0) continue;//檢測當前盒子是否需要往下移動
                        for (int k = r - 1; k >= 0; k--)
                        {
                            Box nextBox = boxList[k, c];
                            if (nextBox.Num == 0)//如果上一格元素為空,則可以移動
                            {
                                nextBox.Num = box.Num; //把前面的元素移動到後面的元素
                                box.Num = 0;
                                box = nextBox;
                                continue;
                            }
                            if (box.Num == nextBox.Num && !nextBox.IsFirst)
                            {
                                nextBox.Num *= 2;
                                nextBox.IsFirst = true;
                                box.Num = 0;
                                countNum--;//合併網格,隨機數的個數元素減一
                                isMerage.Enqueue(nextBox);//新增已經合併的數,以便修改開關
                            }
                            break;
                        }
                    }
            }

            GameSwitch();//判斷遊戲輸贏
        }

        /// <summary>
        /// 向下的方法
        /// </summary>
        private void GoDown()
        {
                //迴圈列的下標
                for (var c = 0; c < boxList.GetLength(1); c++)
                {
                    for (var r = boxList.GetLength(0) - 2; r >= 0; r--)
                    {
                        Box box = boxList[r, c];//當前進行檢測判斷是否可以往下移動或者合併的格子
                        if (box.Num == 0) continue;
                        for (var k = r + 1; k < boxList.GetLength(0); k++)
                        {
                            Box nextBox = boxList[k, c];
                            //進行空白格子判斷
                            if (nextBox.Num == 0)
                            {
                                //找到一個就往下移一個
                                nextBox.Num = box.Num;
                                box.Num = 0;
                                box = nextBox;
                                continue;
                            }
                            //進行格子合併的判斷
                            if (nextBox.Num == box.Num && !nextBox.IsFirst)
                            {
                                nextBox.Num *= 2;
                                nextBox.IsFirst = true;
                                box.Num = 0;
                                isMerage.Enqueue(nextBox);//新增已經合併的數,以便重置開關
                                countNum--;//合併網格的元素減一
                            }
                            break;
                        }
                }

            }
            GameSwitch();//判斷遊戲輸贏

        }

        /// <summary>
        /// 列印佈局
        /// </summary>
        private void Test()
        {

            Console.WriteLine("-------------------------------");
            for (int i = 0; i < boxList.GetLength(0); i++)
            {
                for (int j = 0; j < boxList.GetLength(1); j++)
                {
                    if (boxList[i, j].Num==2048) //遊戲勝利
                    {
                        Console.WriteLine("遊戲勝利");
                        gameBegin = false;

                    }
                    Console.Write(boxList[i, j].Num + "\t");
                }
                Console.Write("\n");
            }
            Console.WriteLine("-------------------------------");
        }

        /// <summary>
        /// 重置開關
        /// </summary>
        private void ReSet()
        {
            while (isMerage.Count > 0)
            {
                isMerage.Dequeue().IsFirst = false;
            }
        }

        /// <summary>
        /// 選擇實現隨機數的的生成
        /// </summary>
        private void GameSwitch()
        {

            if (countNum < 16)//數的個數小於等於16時才能隨機生成
            {
                RandomNum();

            }
            if (countNum == 16)//該判斷一下輸贏了
            {
                IsGameOver();
            }
            Console.WriteLine("網格上的元素:" + countNum);
            Test();
        }
        /// <summary>
        /// 判斷遊戲是否進行
        /// </summary>
        public void IsGameOver()
        {

            for (int r = 0; r < row; r++)
            {
                for (int c = 0; c < cols; c++)
                {
                    if (c + 1 < row)//如果該元素列相鄰元素存在,就比較
                    {
                        if (boxList[r, c].Num == boxList[r, c+1].Num)
                        {
                            return;
                        }
                    }
                    if (r + 1 < cols)//如果該元素的行相鄰元素存在,就比較
                    {
                        if (boxList[r, c].Num == boxList[r+1, c].Num)
                        {
                             return;//如果該數與行相鄰相等,遊戲還可以進行
                        }
                    }
                }
            }
            gameBegin = false;
        }

    }

管理類,管理整個格局,遊戲開始到遊戲結束.
成員:格局類


 /// <summary>
    /// 管理遊戲類
    /// </summary>
    class Maneger
    {
        Grid gird;

        public Maneger()
        {
            gird = new Grid(4,4);
        }

        public void InitGame()
        {

            gird.Init();
            Console.WriteLine("2048遊戲開始,規則如下,通過aswd鍵滑動字串");
            Console.WriteLine("每滑動一次,所有的數字就會想滑動的方向靠攏");
            Console.WriteLine("只要有一個格子出現2048,就取得遊戲勝利");
        }
        /// <summary>
        /// 獲取使用者的輸入
        /// </summary>
        public void choice()
        {
            ConsoleKeyInfo key = Console.ReadKey();
            while (key.Key != ConsoleKey.Escape){ //輸出ESC退出
                gird.move(key.Key);
                //遊戲是否結束
                if (!gird.GameBegin)
                {
                    IsOver();
                    break;
                }
                key = Console.ReadKey();
            }
        }
       private void IsOver()
        {
                Console.WriteLine("遊戲結束");
        }
    }

開始程式


    class Program
    {
        static void Main(string[] args)
        {
            Maneger ma = new Maneger();
            ma.InitGame();
            ma.choice();

            Console.ReadLine();

        }

    }

目前2048還有BUG ,我已經修改了些許BUG,在下一篇c#生成2048遊戲(2)

相關推薦

c#生成2048遊戲1

2048遊戲 需求分析 可以使用W、S、A、D鍵進行操作 遊戲開始時隨機的產生2個數值為2/4的方格,位置隨機 每次按下移動鍵後,逐行計算移動後的方格值。每行移動的演算法是:先把移動倒數第二個數,有3種情況,如果次數本身是0,則不移動;或者前面有數,則不移

c++實現2048遊戲控制檯

#ifndef CGAME_H #define CGAME_H #include <windows.h> #include <String> #define ROW 4 //格子總行數 #define COLUMN 4 //格子總列數 class cGame { pub

Extreme Drift賽車遊戲C#原始碼詳解1

Extreme Drift賽車遊戲C#原始碼詳解(1) C#我只是一個萌新,由於搞過Java,還是可以看懂C#的 偶然間得到賽車遊戲Extreme Drift的原始碼 接下來我會花一段時間來解讀,這是一個我學習的過程,記錄在部落格 等到我完全解讀之後,我也許會考慮再加入聯機功能等

C#類和結構1

mar 安全 類型安全 readline 參數 部分 public 方法的參數 play 1、結構功能特性? 實現代碼? 結構用struct關鍵字定義的,與類類似,但有本質區別。結構實質是一個值類型,它不需要對分配的。 結構的特性: (1)、結構作為參數傳遞時,是值傳遞。

c++ 部分基礎知識 ---- 1

知識 gin href com cin http targe 基礎知識 ucs 灰dtj4慚fv腺伎孕6xnhttp://www.docin.com/app/user/userinfo?userid=179253887 傅zpf攣詿4隊餵皇影http://www.doci

設計一款c#自動程式碼生成器 1

1,構思配置驅動檔案生成 網上自動化指令碼生成的思路是 1)設定好對應的模板 2)讀取資料庫對應的檔案 3)根據模板對應的欄位替換生成 模板》讀取資料》生成對應檔案 為什麼會有做自動化指令碼的想法,是因為工作中發現protobuf 這個工具可以自動編譯根據伺服器生成對應的cs檔案 所以我這裡想仿

C#:執行緒1:什麼是執行緒?我們為什麼要使用執行緒?

最近在看公司上一個專案的原始碼,讓我感覺非常困惑的是,原始碼中使用了很多多執行緒的內容,所以給我的感覺是執行緒一直跳來跳去的,讓我感覺到很困惑。於是我就寫了這篇部落格,希望能夠更好的理解執行緒有關的內容。 一:什麼是執行緒 執行緒是和程序經常放在一起比較的兩個概念。按照我的理解,執行緒和程序

C#:撲克牌遊戲2:給CardLib新增Cards集合

(一):背景         在上一篇文章中,我們簡單建立了幾個可能在後面會用到的類並且放到了一個類庫中,接下來需要對這幾個類進行進一步的思考。首先一個問題是,我們原先在Deck類中,使用了一個數組來代表一副牌,但是我們知道,在一個撲克牌遊戲中,(例如鬥地

CocosCreator之KUOKUO帶你做隨機數遊戲1

開坑開坑啦,KUOKUO帶你入門CocosCreator,承諾不TJ,頂多慢一點{的console.log(滑稽)}本次引擎2.0.5 在我入門學習的時候是按照官方文件一條一條學習的,的確是有效。 但是我認為任務驅動的學習效率更高,例如,我開的坑。希望可以幫助更多的人入門CocosCreat

Zookeeper C API應用示例1——配置管理同步API

場景描述 服務端監控/configure目錄; 客戶端對/configure目錄讀/寫資料,建立/刪除子節點 服務端: 監控/configure目錄,有資料更新時,輸出/configure中的資料;子節點建立/刪除時,服務程式列出當前的子目錄列表。 程式碼如下: #include &

C++ Linux伺服器開發1——極速入門必備命令

1.shell簡介 shell是運維和系統管理員操作Linux系統的首選,是一個命令直譯器 命令列---------------->解釋執行 命令列相關:        行首“$”或"#“---------------

【深度探索C++物件模型】1關於物件

哎 再開新坑,希望19年能把開的這幾個坑都填上。 class : 類 class object : 類物件 1 C++物件模型 簡單來說,C++物件模型的例項的組成包括下面幾個部分: Nonstatic data members與**virtual pointer(vpt

C語言小筆記1

列舉型別的大小是4,和一個int整形大小一樣   就是最後一個逗號後面的表示式的值,比如: int a=1,b; b=(a+1,a+2,a+3); 那麼b的值就是a+3,也就是4   函式名   :printf  函式原型:in

c++重點語法彙總1

繼承性 從繼承源上看,繼承可分為單一繼承和多重繼承兩種 C++語言和C語言的關係 作為面向過程的程式設計語言(C語言),C++語言與C語言的關係可以用繼承和改進來概括 C語言是C++語言的一個子集 C語言的指標在C++語言中一樣使用,但是C++語言在動態記

c/c++程式設計排坑1-- 資料型別的“安靜”轉換

這裡主要介紹ANSI C的特性:當執行算術運算時,運算元的型別如果不同,就會發生轉換。資料型別一般朝著精度更高、長度更長的方向轉換,整型數如果轉換為signed不會丟失資訊,就轉換為signed,否則轉換為unsigned。 一、算術轉換(K&R C) 首先: 任何型別為char

數獨終局生成與求解1

專案Github地址 https://github.com/Tim-xiaofan/sudoku.git 準備與思考 Visual Studio GitHub程式碼託管配置 廖雪峰的網站有通俗易懂的Git教程 數獨問題 命令列引數的傳遞 (1)控制終

C# 指南學習筆記1-HelloWorld,字串內插

使用 Visual Studio 2017 生成 C# .NET Core Hello World 應用程式:https://docs.microsoft.com/zh-cn/dotnet/core/tutorials/with-visual-studio

運用html5 canvas做飛機大戰遊戲1

1、首先,寫出canvas前提,定義所需要的變數,如寬高、分數、生命值等。 <div style="text-align: center;"> <canvas id="canvas" width="480px" height="640px"&g

C++編譯與連結1-編譯與連結過程

大家知道計算機使用的一系列的1和0 那個一個C++語言程式又是如何從一個個.h和.cpp檔案變成包含1和0的可執行檔案呢? 可以認為有以下的幾個環節 源程式->預處理->編譯和優化->生成目標檔案->連結->可執行檔案

C# Invoke和BeginInvoke1

 近日,被Control的Invoke和BeginInvoke搞的頭大,就查了些相關的資料,整理如下。感謝這篇文章對我的理解Invoke和BeginInvoke的真正含義 。 (一)Control的Invoke和BeginInvoke 我們要基於以下認識: (1)Control的