2048这个游戏的本质是二位数组,就以4*4的二位数组来分析关键的逻辑以及实现。
我们所有的操作都是对这个二维数组的数据的操作。分为上下左右四个方向。
右三个主要 的类:
Box.class:如果在控制台上实现这个游戏,完全没有必要创建一个Box类,因为它此时只存放一个number值,完全可以有数组中的值来代替。不过考虑到后期游戏可能会在拓展到图形界面,Box可能会有点用(可能会加一些在矩阵中的位置,图片地址、颜色等属性信息)
Grid.class:进行一些游戏初始化和逻辑操作,如判断游戏是否结束、分别对上下左右四个方向操作每个方格等等。
Manager.class:进行游戏开始、结束的控制。
实现效果:
代码如下:
Box.class:
using System;
namespace Test
{
class Box
{
//private int row;
//private int col;
public int Number { get; set; }
//public bool IsMerge { get; set; }
public Box(int num)
{
this.Number = num;
//this.row = row;
//this.col = col;
//this.IsMerge = false;
}
}
}
Grid.class(实现一):
using System;
using System.Collections.Generic;
namespace Test
{
class Grid
{
private int row;
private int col;
private Box[,] grids;
private bool isFirst;
private int rdNumber;
public bool IsGameOver { get; private set; }
public Grid(int row, int col)
{
this.row = row;
this.col = col;
this.grids = new Box[row, col];
InitBoxs();
IsGameOver = false;
isFirst = true;
}
private void InitBoxs()
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
Box box = new Box(0);
grids[i, j] = box;
}
}
}
public void PrintGrid()
{
Console.WriteLine("==============================================");
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
Console.Write(grids[i, j].Number + "\t");
}
Console.WriteLine();
}
Console.WriteLine("==============================================");
}
public void RandomBox()
{
int count = 1;
//首次生成两个数字
if (isFirst)
{
count = 2;
isFirst = false;
}
Random rd = new Random();
for (int i = 0; i < count; )
{
if (rdNumber == 4)
{
rdNumber = 2;
}
else
{
int num = rd.Next(1, 11);
if (num < 9)
{
rdNumber = 2;
}
else
{
rdNumber = 4;
}
}
int boxRow = rd.Next(0, row);
int boxCol = rd.Next(0, col);
if (grids[boxRow, boxCol].Number == 0)
{
//Console.WriteLine("随机生成点为:[{0},{1}]", boxRow, boxCol);
grids[boxRow, boxCol].Number = rdNumber;
}
else
{
continue;
}
i++;
}
}
public bool MoveDirection(Direction dir)
{
bool isMove = false;
switch (dir)
{
case Direction.Up:
isMove = MoveUp();
break;
case Direction.Dowm:
isMove = MoveDown();
break;
case Direction.Left:
isMove = MoveLeft();
break;
case Direction.Right:
isMove = MoveRight();
break;
}
CheckIsGameOver();
return isMove;
}
//当矩阵满了的时候(数字都不为0),上下左右相邻没有数字相同的了,游戏就结束,否则游戏继续
private void CheckIsGameOver()
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (grids[i, j].Number == 0)
{
IsGameOver = false;
return;
}
}
}
//矩阵存满了不为0的数
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
//上下左右
if (i - 1 >= 0 && grids[i, j].Number == grids[i - 1, j].Number)
{
IsGameOver = false;
return;
}
if (i + 1 < row && grids[i, j].Number == grids[i + 1, j].Number)
{
IsGameOver = false;
return;
}
if (j - 1 >= 0 && grids[i, j].Number == grids[i, j - 1].Number)
{
IsGameOver = false;
return;
}
if (j + 1 < col && grids[i, j].Number == grids[i, j + 1].Number)
{
IsGameOver = false;
return;
}
}
}
IsGameOver = true;
}
//向下
private bool MoveDown()
{
bool isMoveBox = false; //是否移动格子
for (int j = 0; j < col; j++)
{
//将所有的格子往下面移
for (int i = row - 1; i >= 0; i--)
{
if (grids[i, j].Number == 0) //如果为0,代表该格子为空,上面的格子往下移
{
for (int k = i - 1; k >= 0; k--)
{
if (grids[k, j].Number != 0)
{
isMoveBox = true;
grids[i, j].Number = grids[k, j].Number;
grids[k, j].Number = 0;
break;
}
}
}
}
//合并格子
for (int i = row - 1; i >= 0; i--)
{
//如果遍历到最后一个格子 或者 当前格子的上面一个格子没有数字,结束循环
if (i == 0 || grids[i - 1, j].Number == 0)
{
break;
}
//Console.WriteLine("==================");
if (grids[i, j].Number == grids[i - 1, j].Number)
{
isMoveBox = true;
grids[i - 1, j].Number = 0;
grids[i, j].Number *= 2;
//合并完格子,上面的格子(往上数2个)往下面移
for (int k = i - 2; k >= 0; k--)
{
if (grids[k, j].Number == 0)
{
break;
}
grids[k + 1, j].Number = grids[k, j].Number;
grids[k, j].Number = 0;
}
}
}
}
return isMoveBox;
}
//向上
private bool MoveUp()
{
bool isMoveBox = false;
for (int j = 0; j < col; j++)
{
//将所有的格子往上面移
for (int i = 0; i < row; i++)
{
if (grids[i, j].Number == 0) //如果为0,代表该格子为空,下面的格子往上移
{
for (int k = i + 1; k < row; k++)
{
if (grids[k, j].Number != 0)
{
isMoveBox = true;
grids[i, j].Number = grids[k, j].Number;
grids[k, j].Number = 0;
break;
}
}
}
}
//合并格子
for (int i = 0; i < row; i++)
{
//如果遍历到最后一个格子 或者 当前格子的下面一个格子没有数字,结束循环
if (i == row - 1 || grids[i + 1, j].Number == 0)
{
break;
}
if (grids[i, j].Number == grids[i + 1, j].Number)
{
isMoveBox = true;
grids[i + 1, j].Number = 0;
grids[i, j].Number *= 2;
//合并完格子,下面的格子(往下数2个)往上面移
for (int k = i + 2; k < row; k++)
{
if (grids[k, j].Number == 0)
{
break;
}
grids[k - 1, j].Number = grids[k, j].Number;
grids[k, j].Number = 0;
}
}
}
}
return isMoveBox;
}
//向左
private bool MoveLeft()
{
bool isMoveBox = false; //是否移动格子
for (int i = 0; i < row; i++)
{
//将所有的格子往左边移
for (int j = 0; j < col; j++)
{
if (grids[i, j].Number == 0) //如果为0,代表该格子为空,右边的格子往左移
{
for (int k = j + 1; k < col; k++)
{
if (grids[i, k].Number != 0)
{
isMoveBox = true;
grids[i, j].Number = grids[i, k].Number;
grids[i, k].Number = 0;
break;
}
}
}
}
//合并格子
for (int j = 0; j < col; j++)
{
//如果遍历到最后一个格子 或者 当前格子的右边一个格子没有数字,结束循环
if (j == col - 1 || grids[i, j + 1].Number == 0)
{
break;
}
if (grids[i, j].Number == grids[i, j + 1].Number)
{
isMoveBox = true;
grids[i, j + 1].Number = 0;
grids[i, j].Number *= 2;
//合并完格子,右边的格子(往右数2个)往左边移
for (int k = j + 2; k < col; k++)
{
if (grids[k, j].Number == 0)
{
break;
}
grids[i, k - 1].Number = grids[i, k].Number;
grids[i, k].Number = 0;
}
}
}
}
return isMoveBox;
}
//向右
private bool MoveRight()
{
bool isMoveBox = false; //是否移动格子
for (int i = 0; i < row; i++)
{
//将所有的格子往右边移
for (int j = col - 1; j >= 0; j--)
{
if (grids[i, j].Number == 0) //如果为0,代表该格子为空,左边的格子往右移
{
for (int k = j - 1; k >= 0; k--)
{
if (grids[i, k].Number != 0)
{
isMoveBox = true;
grids[i, j].Number = grids[i, k].Number;
grids[i, k].Number = 0;
break;
}
}
}
}
//合并格子
for (int j = col - 1; j >= 0; j--)
{
//如果遍历到最后一个格子 或者 当前格子的左边一个格子没有数字,结束循环
if (j == 0 || grids[i, j - 1].Number == 0)
{
break;
}
if (grids[i, j].Number == grids[i, j - 1].Number)
{
isMoveBox = true;
grids[i, j - 1].Number = 0;
grids[i, j].Number *= 2;
//合并完格子,左边的格子(往右数2个)往右边移
for (int k = j - 2; k >= 0; k--)
{
if (grids[k, j].Number == 0)
{
break;
}
grids[i, k + 1].Number = grids[i, k].Number;
grids[i, k].Number = 0;
}
}
}
}
return isMoveBox;
}
}
enum Direction
{
Up,
Dowm,
Left,
Right
}
}
Grid.class(实现二):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Demo2048
{
/// <summary>
/// 网格类
/// </summary>
class Grid
{
int row = 0;//保存行数
int cols = 0;//列数
Box[,] gridList;
bool isFirst = true;//第一次
Random rdObj;
int rdNum = 2;//存储上一次的随机数字
private int boxCount = 0;
public bool IsGameOver { get; private set; }
public Grid(int row, int cols)
{
this.row = row < 4 ? 4 : row;
this.cols = cols < 4 ? 4 : cols;
gridList = new Box[row, cols];
rdObj = new Random();
// InitGrid();
}
public void InitGrid()
{
for (var i = 0; i < gridList.GetLength(0); i++)
{
for (var j = 0; j < gridList.GetLength(1); j++)
{
Box box = new Box(i, j);
gridList[i, j] = box;
}
}
this.RandomNum();
}
public void RandomNum()
{
int count = 0;
//第一次随机两个数
if (isFirst)
{
count = 2;
isFirst = false;
}
else
{//后面只随机一个数字
count = 1;
}
for (var i = 0; i < count; )
{
//随机下标,出现数字的位置
int r = rdObj.Next(0, row);
int c = rdObj.Next(0, cols);
if (gridList[r, c].Number != 0) continue;
//避免两次随机都是4
if (rdNum == 4)
{
rdNum = 2;
}
else
{ //随机数字,80%2,20%4
int a = rdObj.Next(1, 11);
if (a < 9) rdNum = 2;
else rdNum = 4;
}
//进行赋值
gridList[r, c].Number = rdNum;
boxCount++;
i++;
}
}
private void CheckIsGameOver()
{
//矩阵存满了不为0的数
for (int i = 0; i < row; i++)
{
for (int j = 0; j < cols; j++)
{
//下右
//if (i - 1 >= 0 && gridList[i, j].Number == gridList[i - 1, j].Number)
//{
// IsGameOver = false;
// return;
//}
if (i + 1 < row && gridList[i, j].Number == gridList[i + 1, j].Number)
{
IsGameOver = false;
return;
}
//if (j - 1 >= 0 && gridList[i, j].Number == gridList[i, j - 1].Number)
//{
// IsGameOver = false;
// return;
//}
if (j + 1 < cols && gridList[i, j].Number == gridList[i, j + 1].Number)
{
IsGameOver = false;
return;
}
}
}
IsGameOver = true;
}
public bool MoveDir(Direction dir)
{
bool isMove = false;
switch (dir)
{
case Direction.Up:
isMove = MoveUp();
break;
case Direction.Down:
isMove = MoveDown();
break;
case Direction.Left:
isMove = MoveLeft();
break;
case Direction.Right:
isMove = MoveRight();
break;
}
if (boxCount == 16)
{
CheckIsGameOver();
}
return isMove;
}
private bool MoveDown()
{
bool isMove = false;
//循环列的下标
int mergeIndex = -1;
for (var c = 0; c < gridList.GetLength(1); c++)
{
for (var r = gridList.GetLength(0) - 2; r >= 0; r--)
{
Box box = gridList[r, c];//当前进行检测判断是否可以往下移动或者合并的格子
if (box.Number == 0) continue;
for (var k = r + 1; k < gridList.GetLength(0); k++)
{
Box nextBox = gridList[k, c];
//进行空白格子判断
if (nextBox.Number == 0)
{
isMove = true;
//找到一个就往下移一个
nextBox.Number = box.Number;
box.Number = 0;
box = nextBox;
continue;
}
//进行格子合并的判断
if (nextBox.Number == box.Number)
{
if (mergeIndex == k)
{
break;
}
mergeIndex = k;
isMove = true;
nextBox.Number *= 2;
box.Number = 0;
boxCount--;
//nextBox.IsMerge = true;//表示已经被合并过了
// megreList.Enqueue(nextBox);
}
break;
}
}
}
//当次合并过的所有格子对象,重置IsMerge=false
// this.ResetMegreList();
return isMove;
}
private bool MoveUp()
{
bool isMove = false;
//循环列的下标
for (var c = 0; c < cols; c++)
{
int mergeIndex = -1;
for (int r = 1; r < row; r++)
{
Box currentBox = gridList[r, c];
if (currentBox.Number == 0)
{
continue;
}
for (int k = r - 1; k >= 0; k--)
{
Box nextBox = gridList[k, c];
if (nextBox.Number == 0)
{
isMove = true;
nextBox.Number = currentBox.Number;
currentBox.Number = 0;
currentBox = nextBox;
continue;
}
if (currentBox.Number == nextBox.Number)
{
if (mergeIndex == k)
{
break;
}
mergeIndex = k;
isMove = true;
nextBox.Number *= 2;
currentBox.Number = 0;
boxCount--;
}
break;
}
}
}
return isMove;
}
private bool MoveRight()
{
bool isMove = false;
//循环列的下标
for (var r = 0; r < row; r++)
{
int mergeIndex = -1;
for (var c = cols - 2; c >= 0; c--)
{
Box box = gridList[r, c];//当前进行检测判断是否可以往下移动或者合并的格子
if (box.Number == 0) continue;
for (var k = c + 1; k < cols; k++)
{
Box nextBox = gridList[r, k];
//进行空白格子判断
if (nextBox.Number == 0)
{
isMove = true;
//找到一个就往下移一个
nextBox.Number = box.Number;
box.Number = 0;
box = nextBox;
continue;
}
//进行格子合并的判断
if (nextBox.Number == box.Number)
{
if (mergeIndex == k)
{
break;
}
mergeIndex = k;
isMove = true;
nextBox.Number *= 2;
box.Number = 0;
boxCount--;
}
break;
}
}
}
return isMove;
}
private bool MoveLeft()
{
bool isMove = false;
//循环行的下标
for (var r = 0; r < row; r++)
{
int mergeIndex = -1;
for (int c = 1; c < cols; c++)
{
Box currentBox = gridList[r, c];
if (currentBox.Number == 0)
{
continue;
}
for (int k = c - 1; k >= 0; k--)
{
Box nextBox = gridList[r, k];
if (nextBox.Number == 0)
{
isMove = true;
nextBox.Number = currentBox.Number;
currentBox.Number = 0;
currentBox = nextBox;
continue;
}
if (currentBox.Number == nextBox.Number)
{
if (mergeIndex == k)
{
break;
}
mergeIndex = k;
isMove = true;
nextBox.Number *= 2;
currentBox.Number = 0;
boxCount--;
}
break;
}
}
}
return isMove;
}
public void Test()
{
Console.WriteLine("================================");
for (var i = 0; i < gridList.GetLength(0); i++)
{
for (var j = 0; j < gridList.GetLength(1); j++)
{
Console.Write(gridList[i, j].Number + "\t");
}
Console.Write("\n");
}
Console.WriteLine("================================");
}
}
}
Manager.cs:
using System;
namespace Test
{
class Manager
{
private static Grid grid = new Grid(4, 4);
static void Main()
{
StartGame();
}
public static void StartGame()
{
grid.RandomBox();
grid.PrintGrid();
Console.WriteLine("请按上下左右键");
while (grid.IsGameOver == false)
{
if (PlayController() == false)
{
if (grid.IsGameOver)
{
Console.WriteLine("------------------------------------------");
Console.WriteLine("------------------------------------------");
Console.WriteLine("------------------游戏结束----------------");
Console.WriteLine("------------------------------------------");
Console.WriteLine("------------------------------------------");
Console.WriteLine("------------------------------------------");
break;
}
continue;
}
//随机生成box
grid.RandomBox();
Console.Clear();
grid.PrintGrid();
}
}
public static bool PlayController()
{
bool isCanMove = false;
while (true)
{
bool isRightKey = false;
ConsoleKeyInfo info = Console.ReadKey();
switch (info.Key)
{
case ConsoleKey.UpArrow:
isRightKey = true;
isCanMove = grid.MoveDirection(Direction.Up);
//if (isCanMove == false)
//{
// Console.WriteLine("不能往上移动了!");
//}
break;
case ConsoleKey.DownArrow:
isRightKey = true;
isCanMove = grid.MoveDirection(Direction.Dowm);
//if (isCanMove == false)
//{
// Console.WriteLine("不能往下移动了!");
//}
break;
case ConsoleKey.LeftArrow:
isRightKey = true;
isCanMove = grid.MoveDirection(Direction.Left);
//if (isCanMove == false)
//{
// Console.WriteLine("不能往左移动了!");
//}
break;
case ConsoleKey.RightArrow:
isRightKey = true;
isCanMove = grid.MoveDirection(Direction.Right);
//if (isCanMove == false)
//{
// Console.WriteLine("不能往右移动了!");
//}
break;
}
if (isRightKey)
{
break;
}
}
return isCanMove;
}
}
}