@ TOC
一,效果展示
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIiZpdmLxITZ3cTZ5cjNxUTY0kDO5QTYjRDZkVjNmFDOmljN2QzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.gif)
二,玩法說明
遊戲的規則很簡單,你需要控制所有方塊向同一個方向運動,兩個相同數字方塊撞在一起之後合并成為他們的和,每次操作之後會随機生成一個2或者4,最終得到一個“2048”的方塊就算勝利了。
三,主要邏輯
- 4*4的二維數組, 然後周遊裡面的元素,統計所有的0,放到一個list裡面,然後
随機一個賦成2.Random.next(0,list.count)
- 循環開始,初始化指令行.
- 鍵盤輸入
對應四種操作的函數 操作之後先周遊一下有沒有空格 如果有就繼續 沒有空格還得再判斷一下能不能再動了 如果不能就死了上下左右
- 隻需要寫向左和向下的邏輯,向右和向上對應取反即可
- 如果有任何一個元素是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;
}
}
}
}