这是一个很经典的题目。
明白规则
我们首先要了解这个游戏到底是怎么玩的,首先会有不同图形构成的地图,到达不同的图形代表发生不同的事件,我们通过掷骰子选择往前走几步或者往后退几步,比如走到幸运转盘的时候,用户可选择方案:交换位置或者是让对方退回原点,走到地雷就往回退六个格,暂停就不进不退,让对方走,如果走到时空隧道,前进十个图形。按照这样的规则,谁先走到最后一个格谁就获胜。
这个游戏最重要的是画地图的逻辑和行走的逻辑。
画图逻辑
首先我们来梳理一下画地图的逻辑:
当我们看见这个地图的时候我们的反应是什么?我们可能会想,为什么这个地图是弯折的?它原来是不是直着的一百个图形?图形的排布有没有规律呢?我们能否采取一些行动让相同的图形放在一起呢?我们要带着问题去看视频更有利于我们学习逻辑。
首先我们不考虑这个地图整体形状,我们观察到这个地图是由100个图形构成的。于是我们定义了一个长度为100的数组来放置这些图形。
public static int[] Map = new int[100];//声明一个长度为100的数组用来画地图
然后我们就初始写了一个方法初始化地图
public static void InitMap() { //初始化地图 //我用0表示普通,显示给用户就是 □ //....1...幸运轮盘,显示组用户就 ◎ //....2...地雷,显示给用户就是 ☆ //....3...暂停,显示给用户就是 ▲ //....4...时空隧道,显示组用户就 卐 int[] luckyturn = { 6, 23, 40, 55, 69, 83 };//幸运轮盘◎ int[] landMine = { 5, 13, 17, 33, 38, 50, 64, 80, 94 };//地雷☆ int[] pause = { 9, 27, 60, 93 };//暂停▲ int[] timeTunnel = { 20, 25, 45, 63, 72, 88, 90 };//时空隧道卐 //把数组中下标为6, 23, 40, 55, 69, 83的地方的值改为1 for (int i = 0; i < luckyturn.Length; i++) { //int temp = luckyturn[i]; Map[luckyturn[i]] = 1; } for (int i = 0; i < landMine.Length; i++) { Map[landMine[i]] = 2; } for (int i = 0; i < pause.Length; i++) { Map[pause[i]] = 3; } for (int i = 0; i < timeTunnel.Length; i++) { Map[timeTunnel[i]] = 4; } }
我们把不同位置的相同图形放在了一起,然后给这些相同的图形放在一个相同的索引中。这样就更加便于管理。
因为涉及要画地图我们就要考虑到玩家的问题我们是不是要考虑玩家是不是在地图上呢?
于是我们声明了一个数组用来存放玩家A和玩家B
public static int[] PlayerPos = new int[2] { 0, 0 };//声明一个数组用来存玩家A和玩家B
我们现在就要把我们刚才放在一起的位置数字用图形表示出来了
public static string DrawStringMap(int pos) { string temp = ""; #region 画第一行的逻辑 //如果玩家A和玩家B在一起并且在地图上就画<> if (PlayerPos[0] == PlayerPos[1] && PlayerPos[0] == pos) { Console.ForegroundColor = ConsoleColor.Yellow; temp = "<>"; } else if (PlayerPos[0] == pos)//如果玩家A在地图上就画A { Console.ForegroundColor = ConsoleColor.Yellow; temp = "A"; } else if (PlayerPos[1] == pos)//如果玩家B在地图上就画B { Console.ForegroundColor = ConsoleColor.Yellow; temp = "B"; } else //如果玩家A和玩家B不在一起也不在这个坐标上就画该显示的地图图标 { switch (Map[pos]) { case 0: Console.ForegroundColor = ConsoleColor.Gray; temp = "□"; break; case 1: Console.ForegroundColor = ConsoleColor.Red; temp = "◎"; break; case 2: Console.ForegroundColor = ConsoleColor.Blue; temp = "☆"; break; case 3: Console.ForegroundColor = ConsoleColor.Green; temp = "▲"; break; case 4: Console.ForegroundColor = ConsoleColor.Magenta; temp = "卐"; break; }//end switch }//end else return temp; #endregion }
上面这些行为我们都是只关注了图形的各自的形状,现在我们就要宏观来看了,我们的地图是拐弯的,当我们作为一个人的时候可以很清楚知道地图可以像一个绳子一样进行弯折,但是电脑如何知道呢?这里我们就要动点小手脚,当我们画完第一行,该画列的时候我们完全可以看作前面全是空格的一行,那这样还跟第一行有区别吗?
首先我们要用for先画出来第一行,只有画出来第一行以后我们才能在这个基础上进行思考,这就是我们进行i+1学习时的i,而我们学习第一列或者第二行的时候只需要在这个基础上做出一点点改变。比如当我们画第二行的时候只需要把第一行for倒序是输出(即forr),改变初始值和终值即可。第二列又和第一列一样(甚至不需要填补前边的空格,只需要换行)当我们做完每行每列以后,我们可以把相同画法的行抽象出来,因为我们发现第一行和第三行的画法只有for的初始和结束值是不一样的,剩下都是一样的。于是就有了下面的方法。
public static void DrawMapLeftToRight(int left, int right) { for (int i = left; i <= right; i++) { Console.Write(DrawStringMap(i));//调用上边画图的方法 } }
有了上述的方法我们就可以简写第一行还有第三行的代码,剩下部分代码大家自行作参考。
public static void DrawMap() { //第一行 DrawMapLeftToRight(0, 29); //第一竖列 for (int i = 30; i <= 34; i++) { for (int j = 0; j <= 28; j++) { Console.Write(" ");//强调这里是Write而不是WriteLine } Console.WriteLine(DrawStringMap(i));//调用画图的方法 } //第二横行 for (int i = 64; i >= 35; i--) { Console.Write(DrawStringMap(i)); } //第二竖行 for (int i = 65; i <= 69; i++) { Console.WriteLine(DrawStringMap(i)); } //第三横行 DrawMapLeftToRight(70, 99); Console.WriteLine(); }
下面我们来关注输入姓名部分代码的书写
首先我们应该定义一个数组来放置两个用户的姓名
public static string[] PlayerNames = new string[2];
然后根据我们的逻辑写出输入用户名字部分的代码
Console.WriteLine("请输入玩家A的姓名"); PlayerNames[0] = Console.ReadLine(); while (PlayerNames[0]=="") { Console.WriteLine("玩家A的姓名不能为空,请重新输入"); PlayerNames[0] = Console.ReadLine(); } Console.WriteLine("请输入玩家B的姓名"); PlayerNames[1] = Console.ReadLine(); while (PlayerNames[1] == PlayerNames[0] || PlayerNames[1] == "") { if (PlayerNames[1] == PlayerNames[0]) { Console.WriteLine("玩家B的姓名和玩家A的姓名[{0}]不能相同相同",PlayerNames[0]); } else { Console.WriteLine("玩家B的姓名为空,请重新输入"); } PlayerNames[1] = Console.ReadLine();
然后我们开始写掷骰子的代
这里我们就又要强调游戏规则,如果忘了可以回去看看。
public static void RowTouZi(int playerPos) { Random r = new Random(); int num = r.Next(1,7); string msg = ""; //存放要显示的字符 Console.WriteLine("{0}按任意键开始掷骰子", PlayerNames[playerPos]); ConsoleKeyInfo coninfo = Console.ReadKey(true); Console.WriteLine("{0}掷出了{1}", PlayerNames[playerPos], num); Console.WriteLine("{0}按任意键开始行动.....", PlayerNames[playerPos]); Console.ReadKey(true); PlayerPos[playerPos] += num; CheckPos();//这是写的一个方法防止超出范围 if (PlayerPos[playerPos] == PlayerPos[1 - playerPos]) { msg=string.Format("玩家{0}踩到了玩家{1},玩家{2}退6格", PlayerNames[playerPos], PlayerNames[1 - playerPos], PlayerNames[1 - playerPos]); PlayerPos[1 - playerPos] -= 6; CheckPos(); } else { switch (Map[PlayerPos[playerPos]]) { case 0: msg="行动完了"; break; case 1: msg = string.Format("{0}走到了幸运轮盘,请选择 1----交换位置,2----轰炸对方", PlayerNames[playerPos]); int number = ReadInt(msg, 1, 2);//这里是写的一个方法让用户只能输入1或者2 if (number == 1) { int temp = 0; temp = PlayerPos[playerPos]; PlayerPos[playerPos] = PlayerPos[1 - playerPos]; PlayerPos[1 - playerPos] = temp; msg=string.Format("玩家{0}选择了与玩家{1}交换位置", PlayerNames[playerPos], PlayerNames[1 - playerPos]); } else { PlayerPos[1 - playerPos] = 0; msg=string.Format("玩家{0}选择轰炸玩家{1}", PlayerNames[playerPos], PlayerNames[1 - playerPos]); } break; case 2: //踩到地雷了 msg="恭喜你,能踩到地雷,百年不遇,退6格"; PlayerPos[playerPos] -= 6; CheckPos(); break; case 3: msg="踩到暂停了"; flag[playerPos] = true; break; case 4: msg="恭喜你,这个猥琐家伙竟然穿越了10步"; PlayerPos[playerPos] += 10; CheckPos(); break; } } Console.Clear(); DrawMap(); Console.WriteLine(msg); }
下面我们来梳理一下上面代码出现的一些陌生的方法下面
下面这个方法是防止出界报错的。
public static void CheckPos() { if (PlayerPos[0]>99) { PlayerPos[0] = 99; } if (PlayerPos[1]>99) { PlayerPos[1] = 99; } if (PlayerPos[0]<0) { PlayerPos[0] = 0; } if (PlayerPos[1]<0) { PlayerPos[1] = 0; } }
还有下面这个方法,根据传过来的数字返回一个数字(主要用于判断踩到幸运转盘的时候用户的选择)
public static int ReadInt(string msg, int min, int max) { while (true) { try { Console.WriteLine(msg); int number = Convert.ToInt32(Console.ReadLine()); if (number >= min && number <= max) { return number; } else { Console.WriteLine("你的输入不合法!只能输入{0}到{1}之间的数字!", min, max); continue; } } catch { Console.WriteLine("输入有误,请重新输入!"); } }
写到这里我们的大部分的问题都能解决了,但是我们发现我们还是不能实现用户交替投掷骰子。那现在我们就要再声明一个数组来实现用户交替投掷骰子的需求。
public static bool[] flag = new bool[] { false,false};
while (PlayerPos[0]<=99 && PlayerPos[1]<=99) { //玩家A掷骰子 if (flag[0]==false) { RowTouZi(0); } else { flag[0] = false; } if (PlayerPos[0]==99) { Console.WriteLine("恭喜玩家A胜利了"); break; } //玩家B掷骰子 if (flag[1]==false) { RowTouZi(1); } else { flag[1] = false; } if (PlayerPos[1]==99) { Console.WriteLine("恭喜玩家B胜利了"); break; } Console.WriteLine("行动完毕..."); } Console.ReadKey(); }
上面就是我的一点见解,欢迎斧正!