方法的具体实现
newBlock()
生成一个新方块
private Random random = new Random();
///
/// 生成一个新的方块
///
private void newBlock()
{
//按空方块的总数量随机出此次新增的方块索引
int r = random.Next(0, Row * Colum - blockCount);
int value = random.Next(0, 10);
//随机到0-7时值为2,8或9时值为4
value = value >= 8 ? 4 : 2;
//按照索引找到目标方块
for (int i = 0; i < Row; i++)
{
for (int j = 0; j < Colum; j++)
{
if (Map[i, j] == 0)
{
if (r == 0)
{
Map[i, j] = value;
//更新不为空的方块数量
blockCount++;
//加个标记
LastBlockPoint = new Point(i, j);
return;
}
r--;
}
}
}
}
singleMove(Point[] points)
一行或一列坐标的移动,分解为每个坐标向前移动
2,2,4,4 >> 4,0,4,4 >> 4,4,0,4>>4,8,0,0
具体实现如下
///
/// 一行或一列坐标的移动
///
///
private void singleMove(Point[] points)
{
int cur = 0;
for (int i = 1; i < points.Length; i++)
{
int iValue = getMapValue(points[i]);
if (iValue == 0)
{
continue;
}
cur += fall(points, i, cur);
}
}
///
/// 在一行或一列坐标中,索引为i1的向i2落去
///
/// 坐标集合
///
/// 下落目标点坐标
/// 下落是否产生了融合 0:是 1:否
private int fall(Point[] points, int i1, int i2)
{
int value1 = getMapValue(points[i1]);
int value2 = getMapValue(points[i2]);
if (value1 == value2)
{
setMapValue(points[i2], value2 * 2);
setMapValue(points[i1], 0);
//有方块位置发生了变化,记录变化的位置
Moved.Add(points[i1], points[i2]);
blockCount--;
Score += value2 * 2;
return 1;
}
if (value2 == 0)
{
setMapValue(points[i2], value1);
setMapValue(points[i1], 0);
Moved.Add(points[i1], points[i2]);
return 0;
}
if (i2 + 1 != i1)
{
setMapValue(points[i2 + 1], value1);
setMapValue(points[i1], 0);
Moved.Add(points[i1], points[i2 + 1]);
}
return 1;
}
public int getMapValue(Point p)
{
return Map[p.X, p.Y];
}
private void setMapValue(Point p, int value)
{
Map[p.X, p.Y] = value;
}
bool Operate(Direction direction)
一次操作,返回操作是否有效
只需要按方向生成坐标的数组,再分别调用singleMove即可。
///
/// 向某个方向移动
///
///
/// 是否是有效的操作(游戏是否产生了变化)
public bool Operate(Direction direction)
{
if (isGameOver())
{
GameOvered();
return false;
}
Moved = new Dictionary();
switch (direction)
{
case Direction.Up:
{
for (int c = 0; c < Colum; c++)
{
Point[] points = new Point[Row];
for (int r = 0; r < Row; r++)
{
points[r] = new Point(r, c);
}
singleMove(points);
}
}
break;
case Direction.Down:
{
for (int c = 0; c < Colum; c++)
{
Point[] points = new Point[Row];
for (int r = 0; r < Row; r++)
{
points[Row - 1 - r] = new Point(r, c);
}
singleMove(points);
}
}
break;
case Direction.Left:
{
for (int r = 0; r < Row; r++)
{
Point[] points = new Point[Colum];
for (int c = 0; c < Colum; c++)
{
points[c] = new Point(r, c);
}
singleMove(points);
}
}
break;
case Direction.Right:
{
for (int r = 0; r < Row; r++)
{
Point[] points = new Point[Colum];
for (int c = 0; c < Colum; c++)
{
points[Colum - 1 - c] = new Point(r, c);
}
singleMove(points);
}
}
break;
default:
return false;
}
//如果所有方块都没有移动(Moved.Count==0),此次操作无效
bool isChange = Moved.Count == 0 ? false : true;
if (isChange)
{
StepNum++;
newBlock();
//如果游戏结束,调用委托
if (isGameOver())
{
GameOvered?.Invoke();
}
}
return isChange;
}
bool isGameOver()
判断游戏是否结束
当所有方块与其右侧下侧值都不同,游戏结束
///
/// 是否GameOver
///
/// res
private bool isGameOver()
{
if (blockCount != Row * Colum)
{
return false;
}
for (int i = 0; i < Row; i++)
{
for (int j = 0; j < Colum; j++)
{
if (i + 1 < Row && Map[i, j] == Map[i + 1, j])
{
return false;
}
if (j + 1 < Colum && Map[i, j] == Map[i, j + 1])
{
return false;
}
}
}
return true;
}
控制台调用
framework里带的Point类坐标为double型,用不到,所以封装了个简单的,够用就行
public class Point
{
public int X { get; set; }
public int Y { get; set; }
public Point(int x, int y)
{
X = x;
Y = y;
}
public override string ToString()
{
return "(" + X + "," + Y + ")";
}
}
之后会实现WPF版本,所以UI实现和逻辑还是分开比较好
将G2048类和Point类放一起生成动态库BizLogic.dll
新建控制台程序添加引用,调用即可
using BizLogic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
G2048 g = new G2048();
g.GameOvered += GGWP;
Console.WriteLine(g.ToString());
while (true)
{
int i = 0;
try
{
i = Convert.ToInt16(Console.ReadLine());
g.Operate((G2048.Direction)i);
Console.WriteLine(g.ToString());
}
catch { }
}
}
//游戏结束的实现
static void GGWP()
{
Console.WriteLine("GGWP");
}
}
}