使用C#控制台应用程序完成一个2048小游戏
曾经使用C#控制台应用程序写的一个2048,现在翻出来回顾一下
- Box类是2048中每一个小格子的相关信息,包括格子的横纵坐标、格子的值和格子是否刚合并这些信息。
- Grid类是网格的相关信息,包括网格的长宽(默认是4X4,也可以改成其他形式的),分数等。
- Manager2048类是个大杂烩的类,写的很乱,什么乱七八糟的方法都丢在了里面。
=================================贼好看的分割线=============
Program.CS
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace _031_test 8 { 9 /// <summary> 10 /// 2048 11 /// </summary> 12 class Program 13 { 14 static void Main(string[] args) 15 { 16 Manager2048 m2048 = new Manager2048(); 17 m2048.Strat(); 18 m2048.Control(); 19 20 21 Console.ReadLine(); 22 } 23 } 24 }
Box.CS
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace _031_test 8 { 9 /// <summary> 10 /// 格子 11 /// </summary> 12 class Box 13 { 14 //格子的坐标 15 int row; 16 int col; 17 public int Row { get { return row; } } 18 public int Col { get { return col; } } 19 //格子的值 20 public int Value { get; set; } 21 //是否已经合并 22 public bool IsMerge { get; set; } 23 24 public Box(int row,int col) 25 { 26 this.row = row; 27 this.col = col; 28 //初始化默认值为0 29 this.Value = 0; 30 this.IsMerge = false; 31 } 32 33 34 } 35 }
Grid.CS
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.IO; 7 8 namespace _031_test 9 { 10 /// <summary> 11 /// 网格 12 /// </summary> 13 class Grid 14 { 15 //网格的长宽 16 int rows; 17 int cols; 18 public int Rows { get { return rows; } } 19 public int Cols { get { return cols; } } 20 21 public int score; 22 23 public int randomTimes = 0;//判断游戏是否结束的标识位16结束 24 Random random; 25 //存放格子对象 26 public Box[,] bList; 27 //是否是第一次,第一次则出现两个数,否则只出现一个数 28 bool isFirst = true; 29 30 public Grid(int rows, int cols) 31 { 32 this.random = new Random(); 33 this.rows = rows < 4 ? 4 : rows; 34 this.cols = cols < 4 ? 4 : cols; 35 bList = new Box[rows, cols]; 36 } 37 38 //初始化 39 public void InitGrid() 40 { 41 //对网格中的每一个格子进行初始化,并将每一个格子对象存入bList中 42 for (int i = 0; i < bList.GetLength(0); i++) 43 { 44 for (int j = 0; j < bList.GetLength(1); j++) 45 { 46 Box box = new Box(i, j); 47 bList[i, j] = box; 48 } 49 } 50 RandomNum(); 51 } 52 /////////////////////////////////// 53 //随机---包括生成的数字和位置 54 public void RandomNum() 55 { 56 //count表示要生成的数字的个数,进行判断,初始化时候生成两个,否则就一个 57 int count; 58 if (isFirst) { count = 2; isFirst = false; } 59 else count = 1; 60 61 int i = 0; 62 while (i < count) 63 { 64 //随机出现数字的下标 65 int r = random.Next(0, rows); 66 int c = random.Next(0, cols); 67 //若随机到的位置已经有值了,则返回重新随机 68 if (bList[r, c].Value != 0) continue; 69 //随机2和4 出现几率 80% 20% 70 int valuePercent = random.Next(1, 11); 71 //将出现的值 72 int value; 73 if (valuePercent < 9) value = 2; 74 else value = 4; 75 bList[r, c].Value = value; 76 i++; 77 //当randomTimes到16时说明所有格子都满了 78 randomTimes++; 79 } 80 } 81 82 //显示游戏界 83 public void DisPlay() 84 { 85 Console.WriteLine("==============================="); 86 for (var i = 0; i < bList.GetLength(0); i++) 87 { 88 for (var j = 0; j < bList.GetLength(1); j++) 89 { 90 Console.Write(bList[i, j].Value + "\t"); 91 } 92 Console.WriteLine("\n"); 93 } 94 Console.WriteLine("==============================="); 95 Console.WriteLine("当前分数:" + score + "历史最高:" + Int32.Parse(File.ReadAllText("score.txt"))); 96 } 97 98 99 100 } 101 }
Manager2048.CS
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.IO; 7 8 namespace _031_test 9 { 10 /// <summary> 11 /// 控制器 12 /// </summary> 13 class Manager2048 14 { 15 Grid g; 16 17 public Manager2048() 18 { 19 g = new Grid(4, 4); 20 } 21 22 //开始游戏 23 24 public void Strat() 25 { 26 g.InitGrid(); 27 g.DisPlay(); 28 Console.WriteLine("游戏开始,请直接使用方向键进行操作"); 29 } 30 31 public void Control() 32 { 33 while (true) 34 { 35 //ConsoleKeyInfo可以直接接受一个字符不需要再按下回车键确认 36 ConsoleKeyInfo keyInfo = Console.ReadKey(); 37 switch (keyInfo.Key) 38 { 39 case ConsoleKey.UpArrow: Up(); break; 40 case ConsoleKey.DownArrow: Down(); break; 41 case ConsoleKey.LeftArrow: Left(); break; 42 case ConsoleKey.RightArrow: Right(); break; 43 default: Console.WriteLine("按错了"); break; 44 } 45 if (g.randomTimes==g.Rows*g.Cols&&!CanWeMergeInFull()) 46 { 47 Console.WriteLine("游戏结束"); 48 break; 49 } 50 } 51 } 52 53 public void Up() 54 { 55 bool ismove=false; 56 //遍历每一个box,检测该box是否要移动 57 for (int i = 1; i < g.bList.GetLength(0); i++)//向上移动不需要考虑第一行的上移,所以直接i=1 58 { 59 for (int j = 0; j < g.bList.GetLength(1); j++) 60 { 61 //如果该box值不是0,说明该box需要移动,否则继续遍历下一个box 62 if (g.bList[i, j].Value != 0) 63 { 64 int temp = g.bList[i, j].Value; 65 //从该box的上一行开始一直遍历到最顶上 66 int k = i - 1; 67 while (k >= 0) 68 { 69 if (g.bList[k, j].Value != 0 || k == 0) break; 70 else k--; 71 } 72 //如果碰到了和要移动的box值一样的box,就要把他们合并(IsMerge:当这个box是这一轮合并来的box时,则不能合并) 73 if (temp == g.bList[k, j].Value && g.bList[k, j].IsMerge==false) 74 { 75 g.bList[i, j].Value = 0; 76 g.bList[k, j].Value = temp * 2; 77 g.score += temp * 2; 78 if (g.score > Int32.Parse(File.ReadAllText("score.txt"))) 79 { 80 File.WriteAllText("score.txt", g.score.ToString()); 81 } 82 g.bList[k, j].IsMerge = true; 83 g.randomTimes--; 84 ismove = true; 85 } 86 else if (temp == g.bList[k, j].Value && g.bList[k, j].IsMerge==true) 87 { 88 g.bList[i, j].Value = 0; 89 g.bList[k + 1, j].Value = temp; 90 //i=k+1表示该box并没有移动 91 if (i == k + 1) ismove = false; 92 else ismove = true; 93 } 94 //值不一样的时候,就把要移动的box放到这个box下面去 95 else if (g.bList[k, j].Value != 0) 96 { 97 g.bList[i, j].Value = 0; 98 g.bList[k + 1, j].Value = temp; 99 if (i == k + 1) ismove = false; 100 else ismove = true; 101 } 102 //这种情况是遍历到最顶行的box且该box为0时,直接把要动的box移到这 103 else 104 { 105 g.bList[i, j].Value = 0; 106 g.bList[k, j].Value = temp; 107 if (i == k) ismove = false; 108 else ismove = true; 109 } 110 } 111 } 112 } 113 if (ismove && !IsFull()) g.RandomNum();//当所有格子都满了时就不随机生成数字 114 else Console.WriteLine("该方向无法移动"); 115 ResetIsMerge();//重置所有box的合并状态为false 116 g.DisPlay(); 117 } 118 119 public void Down() 120 { 121 bool ismove = false; 122 //错误写法:for (int i = 0; i < g.bList.GetLength(0) - 1; i++) 123 //以上写法会导致上层的数先被遍历从而导致先移动完毕,所以要从最后一个数开始遍历 124 for (int i = g.bList.GetLength(0) - 2; i >= 0; i--) 125 { 126 for (int j = g.bList.GetLength(1) - 1; j >= 0; j--) 127 { 128 if (g.bList[i, j].Value != 0) 129 { 130 int temp = g.bList[i, j].Value; 131 int k = i + 1; 132 while (k <= g.bList.GetLength(0) - 1) 133 { 134 if (g.bList[k, j].Value != 0 || k == g.bList.GetLength(0) - 1) break; 135 else k++; 136 } 137 if (temp == g.bList[k, j].Value && g.bList[k, j].IsMerge == false) 138 { 139 g.bList[i, j].Value = 0; 140 g.bList[k, j].Value = temp * 2; 141 g.bList[k, j].IsMerge = true; 142 g.score += temp * 2; 143 if (g.score > Int32.Parse(File.ReadAllText("score.txt"))) 144 { 145 File.WriteAllText("score.txt", g.score.ToString()); 146 } 147 g.randomTimes--; 148 ismove = true; 149 } 150 else if (temp == g.bList[k, j].Value && g.bList[k, j].IsMerge == true) 151 { 152 g.bList[i, j].Value = 0; 153 g.bList[k - 1, j].Value = temp; 154 if (i == k - 1) ismove = false; 155 else ismove = true; 156 } 157 else if (g.bList[k, j].Value != 0) 158 { 159 g.bList[i, j].Value = 0; 160 g.bList[k - 1, j].Value = temp; 161 if (i == k - 1) ismove = false; 162 else ismove = true; 163 } 164 else 165 { 166 g.bList[i, j].Value = 0; 167 g.bList[k, j].Value = temp; 168 if (i == k) ismove = false; 169 else ismove = true; 170 } 171 } 172 } 173 } 174 if (ismove && !IsFull()) g.RandomNum(); 175 else Console.WriteLine("该方向无法移动"); 176 ResetIsMerge(); 177 g.DisPlay(); 178 } 179 180 public void Left() 181 { 182 bool ismove = false; 183 for (int i = 0; i < g.bList.GetLength(0); i++) 184 { 185 for (int j = 1; j < g.bList.GetLength(1); j++) 186 { 187 if (g.bList[i, j].Value != 0) 188 { 189 int temp = g.bList[i, j].Value; 190 int k = j - 1; 191 while (k >= 0) 192 { 193 if (g.bList[i, k].Value != 0 || k == 0) break; 194 else k--; 195 } 196 if (temp == g.bList[i, k].Value && g.bList[i, k].IsMerge == false) 197 { 198 g.bList[i, j].Value = 0; 199 g.bList[i, k].Value = temp * 2; 200 g.score += temp * 2; 201 if (g.score > Int32.Parse(File.ReadAllText("score.txt"))) 202 { 203 File.WriteAllText("score.txt", g.score.ToString()); 204 } 205 g.bList[k, j].IsMerge = true; 206 g.randomTimes--; 207 ismove = true; 208 } 209 else if (temp == g.bList[i, k].Value && g.bList[i, k].IsMerge == true) 210 { 211 g.bList[i, j].Value = 0; 212 g.bList[i, k + 1].Value = temp; 213 if (j == k + 1) ismove = false; 214 else ismove = true; 215 } 216 else if (g.bList[i, k].Value != 0) 217 { 218 g.bList[i, j].Value = 0; 219 g.bList[i, k + 1].Value = temp; 220 if (j == k + 1) ismove = false; 221 else ismove = true; 222 } 223 else 224 { 225 g.bList[i, j].Value = 0; 226 g.bList[i, k].Value = temp; 227 if (j == k) ismove = false; 228 else ismove = true; 229 } 230 } 231 } 232 } 233 if (ismove && !IsFull()) g.RandomNum(); 234 else Console.WriteLine("该方向无法移动"); 235 ResetIsMerge(); 236 g.DisPlay(); 237 } 238 239 public void Right() 240 { 241 bool ismove = false; 242 //错误写法:for (int i = 0; i < g.bList.GetLength(0) - 1; i++) 243 //以上写法会导致上层的数先被遍历从而导致先移动完毕,所以要从最后一个数开始遍历 244 for (int i = g.bList.GetLength(0) - 1; i >= 0; i--) 245 { 246 for (int j = g.bList.GetLength(1) - 2; j >= 0; j--) 247 { 248 if (g.bList[i, j].Value != 0) 249 { 250 int temp = g.bList[i, j].Value; 251 int k = j + 1; 252 while (k <= g.bList.GetLength(1) - 1) 253 { 254 if (g.bList[i, k].Value != 0 || k == g.bList.GetLength(1) - 1) break; 255 else k++; 256 } 257 if (temp == g.bList[i, k].Value && g.bList[i, k].IsMerge == false) 258 { 259 g.bList[i, j].Value = 0; 260 g.bList[i, k].Value = temp * 2; 261 g.score += temp * 2; 262 if (g.score > Int32.Parse(File.ReadAllText("score.txt"))) 263 { 264 File.WriteAllText("score.txt", g.score.ToString()); 265 } 266 g.bList[k, j].IsMerge = true; 267 g.randomTimes--; 268 ismove = true; 269 } 270 else if (temp == g.bList[i, k].Value && g.bList[i, k].IsMerge == true) 271 { 272 g.bList[i, j].Value = 0; 273 g.bList[i, k - 1].Value = temp; 274 if (j == k - 1) ismove = false; 275 else ismove = true; 276 } 277 else if (g.bList[i, k].Value != 0) 278 { 279 g.bList[i, j].Value = 0; 280 g.bList[i, k - 1].Value = temp; 281 if (j == k - 1) ismove = false; 282 else ismove = true; 283 } 284 else 285 { 286 g.bList[i, j].Value = 0; 287 g.bList[i, k].Value = temp; 288 if (j == k) ismove = false; 289 else ismove = true; 290 } 291 } 292 } 293 } 294 if (ismove && !IsFull()) g.RandomNum(); 295 else Console.WriteLine("该方向无法移动"); 296 ResetIsMerge(); 297 g.DisPlay(); 298 } 299 300 //判断网格是否已满 301 public bool IsFull() 302 { 303 for (int i = 0; i < g.Rows; i++) 304 { 305 for (int j = 0; j < g.Cols; j++) 306 { 307 if (g.bList[i, j].Value == 0) 308 { 309 return false; 310 } 311 } 312 } 313 return true; 314 } 315 316 //重置所有box合并状态 317 public void ResetIsMerge() 318 { 319 for (int i = 0; i < g.Rows; i++) 320 { 321 for (int j = 0; j < g.Cols; j++) 322 { 323 g.bList[i, j].IsMerge = false; 324 } 325 } 326 } 327 328 //网格满时是否还可以继续合并 true表示还有能合并的 329 public bool CanWeMergeInFull() 330 { 331 for (int i = 0; i < g.Rows; i++) 332 { 333 for (int j = 0; j < g.Cols; j++) 334 { 335 //检测上方向 336 if (i - 1 >= 0 && g.bList[i, j].Value == g.bList[i - 1, j].Value) 337 { 338 return true; 339 } 340 //检测下方向 341 if (i + 1 < g.Rows && g.bList[i, j].Value == g.bList[i + 1, j].Value) 342 { 343 return true; 344 } 345 //检测左方向 346 if (j - 1 >= 0 && g.bList[i, j].Value == g.bList[i, j - 1].Value) 347 { 348 return true; 349 } 350 //检测右方向 351 if (j + 1 < g.Cols && g.bList[i, j].Value == g.bList[i, j + 1].Value) 352 { 353 return true; 354 } 355 } 356 } 357 return false; 358 } 359 360 } 361 }
=================================贼好看的分割线=============
最终效果: