开篇
2048游戏现在很火啊,很多人应该已经玩过了。在博客园上也看见有人模仿做的GDI+版 2048游戏,鄙人暂且不做那么多动画的东西,毕竟是个小东东,在此奉上一个《控制台版2048》。
本文程序源码下载:http://pan.baidu.com/s/1mg8zntu
程序结构相对简单,一共200+行代码,注释很少,大家大概也看得懂,我在这解释下程序中各个方法的含义:
Main 方法程序入口,RePaint 类似Win32程序中的刷新界面,SquareRot90 矩形矩阵顺时针旋转90度角(参数可以为负,表示逆时针)。Merge 向左移动,合并单元格中值相同的元素,并进行整理(将所有元素靠左放置)RandomPoint 随机生成点,从矩阵的空位置(值为0)中随机生成一个点,若不存在空位置返回null。CanMove 判断是否可以继续移动,也是判断游戏是否结束的方法。IsEquals 判断两矩阵的值是否相同。CopyToB 将矩阵复制一份。
流程图如下:
上代码
主函数Main
static void Main(string[] args) { int[,] a = new int[4, 4]; a[1, 2] = 2; a[2, 2] = 2; a[2, 1] = 2; RePaint(a); while (true) { ConsoleKeyInfo key = Console.ReadKey(); switch (key.Key) { case ConsoleKey.UpArrow: a = SquareRot90(a, 3); a = Merge(a); a = SquareRot90(a, -3); break; case ConsoleKey.DownArrow: a = SquareRot90(a, 1); a = Merge(a); a = SquareRot90(a, -1); break; case ConsoleKey.LeftArrow: a = Merge(a); break; case ConsoleKey.RightArrow: a = SquareRot90(a, 2); a = Merge(a); a = SquareRot90(a, -2); break; } Point cp = RandomPoint(a); if (cp != null) { a[cp.X, cp.Y] = 2; RePaint(a); } if (cp == null && !CanMove(a)) { RePaint(a, "Game Over"); } } }
矩阵旋转方法
/// 矩形顺时针旋转90° /// </summary> /// <param name="rotNum">旋转次数</param> public static int[,] SquareRot90(int[,] a, int rotNum) { while (rotNum < 0) { rotNum += 4; } for (int rot_i = 0; rot_i < rotNum; rot_i++) { int[,] b = new int[a.GetLength(1), a.GetLength(0)]; for (int i = 0; i < a.GetLength(0); i++) { for (int j = 0; j < a.GetLength(1); j++) { b[j, a.GetLength(0) - i - 1] = a[i, j]; } } a = b; } return a; }
随机点方法
public static Point RandomPoint(int[,] a) { List<Point> lstP = new List<Point>(); for (int i = 0; i < a.GetLength(0); i++) { for (int j = 0; j < a.GetLength(1); j++) { if (a[i, j] == 0) { lstP.Add(new Point(i, j)); } } } if (lstP.Count == 0) { return null; } int rnd = new Random().Next(lstP.Count); return lstP[rnd]; }
矩阵向左合成方法
public static int[,] Merge(int[,] a) { for (int i = 0; i < a.GetLength(0); i++) { int lastNum = 0; int last_j = 0; for (int j = 0; j < a.GetLength(1); j++)//合并 { if (lastNum != a[i, j] && a[i, j] != 0) { lastNum = a[i, j]; last_j = j; } else if (lastNum == a[i, j]) { a[i, last_j] = 0; a[i, j] = lastNum + a[i, j]; } } last_j = 0; for (int j = 0; j < a.GetLength(1); j++)//整理 { if (a[i, j] != 0) { a[i, last_j] = a[i, j]; if (last_j != j) a[i, j] = 0; last_j++; } } } return a; }
是否可以继续移动CanMove方法
public static bool CanMove(int[,] a) { bool res = false; int[,] b = CopyToB(a); b = Merge(b); if (!IsEquals(a, b)) res = true; b = CopyToB(a); b = SquareRot90(b, 1); b = Merge(b); b = SquareRot90(b, -1); if (!IsEquals(a, b)) res = true; b = CopyToB(a); b = SquareRot90(b, 2); b = Merge(b); b = SquareRot90(b, -2); if (!IsEquals(a, b)) res = true; b = CopyToB(a); b = SquareRot90(b, 3); b = Merge(b); b = SquareRot90(b, -3); if (!IsEquals(a, b)) res = true; return res; }
CanMove中用到的IsEquals方法,判断矩阵相等
public static bool IsEquals(int[,] a, int[,] b) { bool res = true; for (int i = 0; i < a.GetLength(0); i++) { for (int j = 0; j < a.GetLength(1); j++) { if (b[i, j] != a[i, j]) { res = false; break; } } if (!res) break; } return res; }
CanMove中用到的矩阵复制方法CopyToB
public static int[,] CopyToB(int[,] a) { int[,] b = new int[a.GetLength(0), a.GetLength(1)]; for (int i = 0; i < a.GetLength(0); i++) { for (int j = 0; j < a.GetLength(1); j++) { b[i, j] = a[i, j]; } } return b; }
两个RePain方法,重新打印,前面的表示GameOver
public static void RePaint(int[,] a, string s) { while (true) { Console.Clear(); RePaint(a); Console.WriteLine(" " + s + " "); Console.ReadKey(); } } public static void RePaint(int[,] a) { Console.Clear(); for (int j = 0; j < a.GetLength(1); j++) { Console.Write("───"); } Console.Write(" "); for (int i = 0; i < a.GetLength(0); i++) { Console.Write("│"); for (int j = 0; j < a.GetLength(1); j++) { string s = ""; if (a[i, j] == 0) s = " "; else if (a[i, j] < 10) s = " " + a[i, j] + " "; else if (a[i, j] < 100) s = "" + a[i, j] + " "; else s = "" + a[i, j]; Console.Write(s + "│"); } Console.Write(" "); for (int j = 0; j < a.GetLength(1); j++) { Console.Write("───"); } Console.Write(" "); } }
辅助类Point
class Point { public Point(int x, int y) { this.X = x; this.Y = y; } public int X { get; set; } public int Y { get; set; } }
结束语
其实要写一个游戏并不是像想像中那么容易,要处理算法等问题,必须要事先仔细的设计,需要一张草纸作为设计图,这样会让工作效率大大提高。之前贴过毕设的游戏《保卫萝卜》,由于时间关系迟迟没有整理,等毕设答辩完成后,一定好好整理,给大家分享。现在功能基本完成了,在这先贴一个缩减版的游戏程序,链接: http://pan.baidu.com/s/1sjvxO7N 。程序有什么问题、BUG,希望大家多多留言。源码整理后再上传。
过几天是蓝桥杯比赛,哈哈,北京我来了。
本文程序源码下载:http://pan.baidu.com/s/1mg8zntu