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