開篇
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("\n\n\n\n\t\t" + s + "\n\n"); Console.ReadKey(); } } public static void RePaint(int[,] a) { Console.Clear(); for (int j = 0; j < a.GetLength(1); j++) { Console.Write("───"); } Console.Write("\n"); 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("\n"); for (int j = 0; j < a.GetLength(1); j++) { Console.Write("───"); } Console.Write("\n"); } }
輔助類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