骑士飞行棋 C#代码详解
最近看见一个骑士飞行棋的小游戏代码,感觉这个代码中将大多数C#的基础知识都运用到了,是一个新手检验学习成果的有效方法,特此将这个代码整理一遍。这是一个控制台程序。这是代码下载地址,代码中的注释非常详细介绍了每段代码的作用:
http://files.cnblogs.com/files/xiaohua92/%E9%AA%91%E5%A3%AB%E9%A3%9E%E8%A1%8C%E6%A3%8B.zip
首先要了解一下 骑士飞行棋 这个游戏的游戏规则:
1)参与游戏的一共有两个人,暂且称之为A和B.两个人轮流掷筛子,根据掷得的点数在地图上移动
2)地图上有5中元素,分别是无效果:□ 幸运轮盘:◎ 地雷:☆ 暂停:▲ 时空隧道:卍 。其中当走到□时候没有任何特殊效果,当走到幸运轮盘的时候会让你选择是要跟对手交换位置还是要轰炸对手(轰炸效果为让对手后退6格),当走到地雷的时候会自动倒退6格,当走到暂时的时候下一次暂停掷筛子一次,当走到时空隧道的时候会前进10格
3)如果A踩到了B,既A在B之后到了B所在的位置,此时B将要退回原点
4)为了调试方便,在代码中给游戏加了一个作弊按钮:在掷筛子的时候,按Tab键之后再按F1键的话,会让玩家自主输入想要掷的点数
代码构成:
一共设立了5个类,分别是Program(Main函数所在类)\drawMap(用来绘制地图)\baseUse(一些必要的基本函数)\Initial(初始化姓名以及地图等)\match(比赛逻辑) 。其中:
Program类:定义了公共的静态变量以及Main函数
drawMap类:定义了drawMaps()函数(用来绘制地图),getMapString()函数(主要用来在绘制地图的时候,确定当前位置图标)
baseUse类:定义了ShowUI()函数(用来绘制飞行棋的名称),ReadInt(int min, int max)函数(用来读取用户输入的数字), checkPos()函数(用来检查玩家当前位 置是否超出边界)
Initial类:InitialMap()函数(用来初始化地图信息),InitialName()函数(用来记录玩家输入的用户名)
match类:Action(int playerNumber)类(用来玩家掷筛子之后的逻辑判断)
下面附上所有代码 :
Program类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace 骑士飞行棋
{
class Program
{
//在下面的数组存储我们游戏地图各各关卡
//数组的下标为0的元素对应地图上的第1格 下标为1的元素对应元素第2格...下标为n的元素对应n+1格
//在数组中 1:表示幸运轮盘 ◎
// 2: 表示地雷 ☆
// 3: 表示暂停 ▲
// 4: 表示时空隧道 卍
// 0: 表示普通 □
public static int[] map = new int[];//地图中一共100个点
public static string[] names = new string[];//names[0]中存储玩家A的姓名,names[1]中存储玩家B的姓名
public static int[] playerPos = { , };//playerPos[0]中存储玩家A的位置,playerPos[1]中存储玩家B的位置
public static int step = ;//用于存放产生的随机数
public static string input = "";//用于存储用户的输入
public static string msg = "";//用于存储当用户踩到某个关卡,输出的话
public static bool[] isStop = { false, false };//isStop[0]表示玩家A是否上一次走到暂停,isStop[1]表示玩家B是否上一次走到暂停
public static Random r = new Random(); static void Main(string[] args)
{
baseUse.ShowUI();
Initial.InitialName();
Console.Clear();
baseUse.ShowUI();
Console.WriteLine("对战开始......");
Console.WriteLine("{0}用A来表示", names[]);
Console.WriteLine("{0}用B来表示", names[]);
Console.WriteLine("如果AB在同一位置,用<>表示");
Initial.InitialMap();
drawMap.drawMaps();
Console.WriteLine("开始游戏......");
while (playerPos[] < && playerPos[] < )
{
match.Action();//玩家A掷筛子
if (Program.playerPos[] < )//当玩家没有胜利的时候,玩家B可以继续掷筛子
match.Action();//玩家B掷筛子
}
Console.ReadKey();
}
}
}
drawMap类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace 骑士飞行棋
{
class drawMap
{
public static void drawMaps()
{
Console.WriteLine("图例:幸运轮盘:◎ 地雷:☆ 暂停:▲ 时空隧道:卍 ");//向玩家解释各个图标的含义
//绘制第一行
for(int i=;i<;i++)
Console.Write(getMapString(i));
Console.WriteLine();
//绘制右边边第一列
for (int i = ; i < ; i++)
{
for (int j = ; j < ; j++)
Console.Write(" ");
Console.Write(getMapString(i));
Console.WriteLine();
}
//绘制第二行
for (int i = ; i >= ; i--)
Console.Write(getMapString(i));
Console.WriteLine();
//绘制左边第一列
for (int i = ; i < ; i++)
{ Console.Write(getMapString(i));
Console.WriteLine();
}
//绘制第三行
for (int i = ; i < ; i++)
Console.Write(getMapString(i));
Console.WriteLine();
} static string getMapString(int pos)
{
string result = "";
if (Program.playerPos[] == pos&&Program.playerPos[]==pos)
{
Console.ForegroundColor = ConsoleColor.Yellow;
result = "<>";
}
else if (Program.playerPos[] == pos)
{
Console.ForegroundColor = ConsoleColor.Yellow;
result = "A";
}
else if (Program.playerPos[] == pos)
{
Console.ForegroundColor = ConsoleColor.Yellow;
result = "B";
}
else
{
switch (Program.map[pos])
{
case :
Console.ForegroundColor = ConsoleColor.White;//设置控制台当前位置的颜色为白色
result = "□";
break;
case :
Console.ForegroundColor = ConsoleColor.Red;
result = "◎";
break;
case :
Console.ForegroundColor = ConsoleColor.Green;
result = "☆";
break;
case :
Console.ForegroundColor = ConsoleColor.Blue;
result = "▲";
break;
case :
Console.ForegroundColor = ConsoleColor.DarkBlue;
result = "卍";
break;
}
}
return result;
}
}
}
baseUse类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace 骑士飞行棋
{
class baseUse
{ public static void ShowUI()
{
Console.WriteLine("*******************************************************");
Console.WriteLine("* *");
Console.WriteLine("* 骑 士 飞 行 棋 *");
Console.WriteLine("* *");
Console.WriteLine("*******************************************************"); }
/// <summary>
/// 用户输入一个min-max之间的数字
/// </summary>
/// <param name="min">最小值</param>
/// <param name="max">最大值</param>
/// <returns></returns>
public static int ReadInt(int min, int max)
{
while (true)
{
try
{
Console.WriteLine("请输入{0}和{1}之间的数字!", min, max);
int number = Convert.ToInt32(Console.ReadLine());
if (number < min || number > max)
{
Console.WriteLine("请输入{0}和{1}之间的数字!", min, max);
continue;
}
return number;
}
catch
{
Console.WriteLine("输入的不是数字,请重新输入!");
}
}
} public static void checkPos()
{
for (int i = ; i <= ; i++)
{
if (Program.playerPos[i] > )
{
Program.playerPos[i] = ;
}
if (Program.playerPos[i] < )
{
Program.playerPos[i] = ;
}
}
}
}
}
Initial类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace 骑士飞行棋
{
class Initial
{
public static void InitialName()
{
Console.WriteLine("请输入玩家A的姓名");
Program.names[]=Console.ReadLine();
//判断输入的姓名是否为空,如果为空的话则提示并要求用户重新输入
while(Program.names[]=="")
{
Console.WriteLine("玩家A姓名不能为空,请重新输入!");
Program.names[] = Console.ReadLine();
} Console.WriteLine("请输入玩家B的姓名");
Program.names[] = Console.ReadLine();
while (Program.names[] == "" || Program.names[] == Program.names[])
{
if (Program.names[] == "")
{
Console.WriteLine("玩家B姓名不能为空,请重新输入!");
Program.names[] = Console.ReadLine();
}
else if (Program.names[] == Program.names[])
{
Console.WriteLine("玩家A和玩家B的姓名不能一样,请重新输入!");
Program.names[] = Console.ReadLine();
}
} } public static void InitialMap()
{
//下面各组数据分别用于存储幸运转盘,地雷,暂停和时空隧道的坐标
int[] luckyTurn = { , , , , , };//幸运轮盘 1
int[] landMine = { , , , , , , , , };//地雷 2
int[] pause = { , , , };//暂停 3
int[] timeTunnel = { , , , , , , };//时空隧道 4 //初始化map数组的数据
for (int i = ; i < ; i++)
Program.map[i] = ; //将幸运轮盘的位置填入地图中
for (int i = ; i < luckyTurn.Length; i++)
Program.map[luckyTurn[i]] = ;
//将地雷的位置填入地图中
for (int i = ; i < landMine.Length; i++)
Program.map[landMine[i]] = ;
//将暂停的位置填入地图中
for (int i = ; i < pause.Length; i++)
Program.map[pause[i]] = ;
//将时空隧道的位置填入地图中
for (int i = ; i < timeTunnel.Length; i++)
Program.map[timeTunnel[i]] = ; } }
}
match类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace 骑士飞行棋
{
class match
{
public static void Action(int playerNumber)
{
if (Program.isStop[playerNumber] == false)
{
Console.WriteLine("{0}按任意键开始掷筛子......", Program.names[playerNumber]);
ConsoleKeyInfo sec = Console.ReadKey(true);//读取用户在键盘上键入的内容
Program.step = Program.r.Next(, );//产生一个1到6之间的随机数 //当用户先输入Tab,在输入F1之后,就进入作弊环节,在状态下用户可以任意输入一个1到100之间的数字来当做自己掷的点数
if (sec.Key == ConsoleKey.Tab)//如果用户键入的内容为Tab键
{
ConsoleKeyInfo sec1 = Console.ReadKey(true);//新建一个变量用来读取用户在键盘上的输入
//如果用户按下了F1键
if (sec1.Key == ConsoleKey.F1)
{
Program.step = baseUse.ReadInt(, );//让用户输入一个1到100之间的数字
}
} Console.WriteLine("{0}掷出了{1}", Program.names[playerNumber], Program.step);
Console.WriteLine("{0}按任意键开始行动......", Program.names[playerNumber]);
Console.ReadKey(); Program.playerPos[playerNumber] += Program.step;//用户向前走step步
baseUse.checkPos();//检查是否超出了边界 if (Program.playerPos[playerNumber] == Program.playerPos[ - playerNumber])//当玩家A/B踩到了玩家B/A的时候
{
Program.playerPos[ - playerNumber] = ;
Program.msg = string.Format("{0}踩到了{1},{1}退回了原点", Program.names[playerNumber], Program.names[ - playerNumber]);
}
else //如果没有踩到的话
{
switch (Program.map[Program.playerPos[playerNumber]])
{
case ://没有踩到任何机关
Program.msg = "";
break;
case ://进入了幸运轮盘
Console.Clear();
Console.WriteLine("你走到了幸运轮盘,请选择运气?");
Console.WriteLine("1 ---交换位置 2---轰炸对方");
int userSelect = baseUse.ReadInt(, );
if (userSelect == )//与对方交换位置
{
int temp = Program.playerPos[playerNumber];
Program.playerPos[playerNumber] = Program.playerPos[ - playerNumber];
Program.playerPos[ - playerNumber] = temp;
Program.msg = string.Format("{0}选了与对方交换位置", Program.names[playerNumber]);
}
else//轰炸对方
{
Program.playerPos[ - playerNumber] -= ;
Program.msg = string.Format("{0}轰炸了{1},{1}退回了6格", Program.names[playerNumber], Program.names[ - playerNumber]);
baseUse.checkPos();
}
break;
case ://踩到了地雷
Program.playerPos[playerNumber] -= ;
baseUse.checkPos();
Program.msg = string.Format("{0}踩到了地雷,{0}退了6格", Program.names[playerNumber]);
break;
case :
//暂停一次
Program.isStop[playerNumber] = true;
Program.msg = string.Format("{0}走到了红灯,下次暂停一次啊", Program.names[playerNumber]);
break;
case :
//踩到时空隧道
Program.playerPos[playerNumber] += ;
baseUse.checkPos();
Program.msg = string.Format("{0}进入了时空隧道,爽死了,进了10格", Program.names[playerNumber]);
break;
}
}
}
else
Program.isStop[playerNumber] = false; if (Program.playerPos[playerNumber] >= )//当有人胜利的时候
{
Console.Clear();
if (Program.playerPos[] >= )
{
Console.WriteLine("{0}胜利了!!游戏结束", Program.names[]);
}
else
{
Console.WriteLine("{0}胜利了!!游戏结束", Program.names[]);
}
}
else//如果没有人走到尽头
{
Console.Clear();
drawMap.drawMaps();
if (Program.msg != "")
{
Console.WriteLine(Program.msg);
}
Console.WriteLine("{0}掷出了{1},行动完成!", Program.names[playerNumber], Program.step);
Console.WriteLine("*************玩家A和玩家B的位置*********");
Console.WriteLine("{0}的位置为:{1}", Program.names[], Program.playerPos[] + );
Console.WriteLine("{0}的位置为:{1}", Program.names[], Program.playerPos[] + );
}
} }
}
学习总结:
1)如果所定义的静态变量没有声明为public,则在另外的类里无法引用,只能在所定义的类中使用。方法亦然。当声明为public之后,可以在其他类中通过 类型.方法名 的方式来引用。关于静态类型的更多说明,可以看C#中的static静态变量的用法一文。
2)在代码中新接触的语句:
ConsoleKeyInfo sec = Console.ReadKey(true);//读取用户在键盘上键入的内容
Program.step = Program.r.Next(, );//产生一个1到6之间的随机数 if (sec.Key == ConsoleKey.Tab); //如果用户键入的内容为Tab键 Console.ForegroundColor = ConsoleColor.White; //设置控制台当前位置的颜色为白色
骑士飞行棋 C#代码详解的更多相关文章
- ASP.NET MVC 5 学习教程:生成的代码详解
原文 ASP.NET MVC 5 学习教程:生成的代码详解 起飞网 ASP.NET MVC 5 学习教程目录: 添加控制器 添加视图 修改视图和布局页 控制器传递数据给视图 添加模型 创建连接字符串 ...
- ARM Cortex-M底层技术(2)—启动代码详解
杂谈 工作了一天,脑袋比较乱.一直想把底层的知识写成一个系列,希望可以坚持下去.为什么要写底层的东西呢?首先,工作用到了这部分内容,最近和内部Flash打交道比较多,自然而然会接触到一些底层的东西:第 ...
- BM算法 Boyer-Moore高质量实现代码详解与算法详解
Boyer-Moore高质量实现代码详解与算法详解 鉴于我见到对算法本身分析非常透彻的文章以及实现的非常精巧的文章,所以就转载了,本文的贡献在于将两者结合起来,方便大家了解代码实现! 算法详解转自:h ...
- Github-karpathy/char-rnn代码详解
Github-karpathy/char-rnn代码详解 zoerywzhou@gmail.com http://www.cnblogs.com/swje/ 作者:Zhouwan 2016-1-10 ...
- 代码详解:TensorFlow Core带你探索深度神经网络“黑匣子”
来源商业新知网,原标题:代码详解:TensorFlow Core带你探索深度神经网络“黑匣子” 想学TensorFlow?先从低阶API开始吧~某种程度而言,它能够帮助我们更好地理解Tensorflo ...
- JAVA类与类之间的全部关系简述+代码详解
本文转自: https://blog.csdn.net/wq6ylg08/article/details/81092056类和类之间关系包括了 is a,has a, use a三种关系(1)is a ...
- Java中String的intern方法,javap&cfr.jar反编译,javap反编译后二进制指令代码详解,Java8常量池的位置
一个例子 public class TestString{ public static void main(String[] args){ String a = "a"; Stri ...
- Kaggle网站流量预测任务第一名解决方案:从模型到代码详解时序预测
Kaggle网站流量预测任务第一名解决方案:从模型到代码详解时序预测 2017年12月13日 17:39:11 机器之心V 阅读数:5931 近日,Artur Suilin 等人发布了 Kaggl ...
- 基础 | batchnorm原理及代码详解
https://blog.csdn.net/qq_25737169/article/details/79048516 https://www.cnblogs.com/bonelee/p/8528722 ...
随机推荐
- 转 脸书pop动画的五个步骤
http://blog.csdn.net/u013741809/article/details/38511741 5 Steps For Using Facebook Pop // 1. Pick ...
- STL总结之vector
STL中vector是通常作为数组使用,不过它更像一个动态数组,在实际项目开发中大量使用. 优点:存储空间连续,可以使用下标访问,时间复杂度O(1). 缺点:不适合从中间删除和添加元素. C++标准规 ...
- FZU2234 牧场物语 DP
题意:先去再回,不能吃重复的,获取最大值 分析:等价于两个人同时去,不能吃重复的 定义dp[i][j][k]表示从起点走k步,第一个人的横坐标是i,第二个人的横坐标是j的最最大值 这个题和bc上一个回 ...
- POJ 1185 (状态压缩DP)
中文题目,题意就不说了. 不得不说这是一道十分经典的状态压缩DP的题目. 思路: 通过分析可以发现,第i行的格子能不能放大炮仅与第i-1和i-2行的放法有关,而与前面的放法无关,因此,如果我们知道了i ...
- SQL Server数据库大型应用解决方案总结【转】
[IT168 技术]随着互联网应用的广泛普及,海量数据的存储和访问成为了系统设计的瓶颈问题.对于一个大型的互联网应用,每天百万级甚至上亿的PV无疑对数据库造成了相当高的负载.对于系统的稳定性和扩展性造 ...
- Velocity介绍
Velocity是一个基于Java的模版引擎,它是一个简单并且功能强大的开发工具,你可以非常容易地创建和呈现出.在这个介绍当中,我们希望可以给出一个使用基本Velocity的概述. 使用Velocit ...
- 输入一个正数 n,输出所有和为 n 连续正数序列。 java实现
用了半小时才写出来啊, 其实这种思路应用范围很广,利用有序性这个特点,比如本体只要是有序就行,例如两个集合是有序的,求交集,有序数组的查找,有序数组的归并,有序有了优化的可能. 输入一个正数 n,输出 ...
- 五指cms标签说明汇总
1.栏目列表标签 只有一级导航: {wz:content action="category" cid="0" pagesize="100" ...
- Ubuntu14.04安装Oracle12C
原文:http://www.techienote.com/2014/04/how-to-install-oracle-12c-enterprise-edition-database-ubuntu-13 ...
- 如何把.rar文件隐藏在一个图片内
首先假设我们要隐藏的.rar文件叫a.rar,图片叫a.jpg.先把他俩放到同一个目录下,然后通过“cmd”进入windows命令行,进入目标目录下,使用以下命令进行隐藏: copy/B a.jpg ...