如何用c#jsp实现猜数字游戏bingo游戏的数字生成

下次自动登录
现在的位置:
& 综合 & 正文
用C#写的一个猜数字的游戏
游戏的规则是由计算机产生一个随机数,然后与用户输入的数字比较,然后给出大小提示,直到猜对为止。
2namespace guess
class readyguess
//用户输入参数
public int formatinput()
int i = <span style="COLOR: #;
i = Convert.ToInt16(Console.ReadLine()); 12
if (i == <span style="COLOR: #) 13
System.Environment.Exit(-<span style="COLOR: #); 14
catch (FormatException) 17
Console.WriteLine("输入参数有误,请重新输入:"); 19
return <span style="COLOR: #; 20
public int Rannumber()
//由计算机产生一个随机数(0~100)的类 28
Random R 30
Ran = new Random(); 31
int i = Convert.ToInt32(Ran.NextDouble() * <span style="COLOR: #0); 32
public void Commentguess(int count)
//根据游戏者的次数给出评价 36
switch (count)
case <span style="COLOR: #: 41
case <span style="COLOR: #: 42
case <span style="COLOR: #: 43
case <span style="COLOR: #: 44
case <span style="COLOR: #: 45
case <span style="COLOR: #: 46
Console.WriteLine("而且你非常聪明!猜了{0}次就对了!", count); 47
case <span style="COLOR: #: 49
case <span style="COLOR: #: 50
case <span style="COLOR: #: 51
case <span style="COLOR: #: 52
case <span style="COLOR: #: 53
Console.WriteLine("你还行!猜了{0}次!", count); 54
default: 56
Console.WriteLine("不过你真笨,猜了{0}次才对!", count); 57
public void right()
//版权所有 61
Console.WriteLine("以上程序由Simon.Yang编写,谢谢使用。"); 63
Console.WriteLine(
".cn"); 64
class test 68
static void Main(string[] args) 70
int i, j,count=<span style="COLOR: #; 73 loop:
Console.WriteLine("请输入一个0到100之间的整数,退出请按0"); 74
readyguess guessnumber =new readyguess(); 75
i= guessnumber.Rannumber(); 77
count++; 80
j = guessnumber.formatinput(); 81
if (j != <span style="COLOR: #) 82
if (i & j) 84
Console.WriteLine("请输入更大的数。"); 85
if (i & j) 86
Console.WriteLine("请输入更小的数。"); 87
while (i != j); 91
if (i == j)
Console.WriteLine("恭喜你!你猜对了"); 93
mentguess(count); 94
guessnumber.right(); 95
Console.WriteLine("要继续吗?请按1继续,按0退出"); 96
if(( y= Convert.ToInt32(Console.ReadLine()))==<span style="COLOR: #) 97
}<span style="COLOR: #0}<span style="COLOR: #1<span style="COLOR: #2<span style="COLOR: #3
&&&&推荐文章:
【上篇】【下篇】  大学宿舍玩游戏的时候,为了简化重复的键鼠动作,有学习过按键精灵和TC脚本开发工具,并做了一些小脚本,基本达到了当时的需求。不知不觉,已经毕业了3年了,无聊之余又玩起了游戏,对于一些无趣的重复行为,于是又想写个脚本来处理下。比如跑任务,自动补血等,没想到现在的游戏对于按键精灵和TC基本上都是封杀。对于我这种小白,过游戏安全检测这种棘手的事,也许花费很多时间,都没有结果。经常测试,发现游戏不会对自己写的C#脚本进行检测,所以决定用C#来写。
  研究了几天,突然间又不想玩游戏了,所以把这几天的研究成果分享给大家,希望对后来的人有启发。我玩的是一款QQ的游戏,我想要做的脚本就是 扫货脚本(当有人摆摊价格低于自己预设的价格时,自动购买下来,倒卖)。
  经过分析,最难的步骤是怎么识别摊位上的价格,第一感觉,这不就是文字识别吗,于是找了一个.Net 唯一开源的Tesseract-ocr。经过测试,发现Tesseract-ocr只适合白底黑字的文字识别,于是对图片进行了以下处理
增加亮度100
增加对比度100
//反向 &游戏文字是白色的
/// &summary&
/// &/summary&
/// &param name="bitmapImage"&&/param&
/// &returns&&/returns&
public static Bitmap ApplyInvert(Bitmap source)
//create a blank bitmap the same size as original
Bitmap newBitmap = new Bitmap(source.Width, source.Height);
//get a graphics object from the new image
Graphics g = Graphics.FromImage(newBitmap);
// create the negative color matrix
ColorMatrix colorMatrix = new ColorMatrix(new float[][]
new float[] {-1, 0, 0, 0, 0},
new float[] {0, -1, 0, 0, 0},
new float[] {0, 0, -1, 0, 0},
new float[] {0, 0, 0, 1, 0},
new float[] {1, 1, 1, 0, 1}
// create some image attributes
ImageAttributes attributes = new ImageAttributes();
attributes.SetColorMatrix(colorMatrix);
g.DrawImage(source, new Rectangle(0, 0, source.Width, source.Height),
0, 0, source.Width, source.Height, GraphicsUnit.Pixel, attributes);
//dispose the Graphics object
g.Dispose();
return newB
/// &summary&
/// 图片变成灰度
/// &/summary&
/// &param name="b"&&/param&
/// &returns&&/returns&
public static Bitmap ToGray(Bitmap b)
for (int x = 0; x & b.W x++)
for (int y = 0; y & b.H y++)
Color c = b.GetPixel(x, y);
int luma = (int)(c.R * 0.3 + c.G * 0.59 + c.B * 0.11);//转换灰度的算法
b.SetPixel(x, y, Color.FromArgb(luma, luma, luma));
/// &summary&
/// 图像变成黑白
/// &/summary&
/// &param name="b"&&/param&
/// &returns&&/returns&
public static Bitmap ToBlackWhite(Bitmap b)
for (int x = 0; x & b.W x++)
for (int y = 0; y & b.H y++)
Color c = b.GetPixel(x, y);
if (c.R & (byte)255)
b.SetPixel(x, y, Color.FromArgb(0, 0, 0));
/// &summary&
/// 图像亮度调整
/// &/summary&
/// &param name="b"&&/param&
/// &param name="degree"&&/param&
/// &returns&&/returns&
public static Bitmap KiLighten(Bitmap b, int degree)
if (b == null)
if (degree & -255) degree = -255;
if (degree & 255) degree = 255;
int width = b.W
int height = b.H
int pix = 0;
BitmapData data = b.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
byte* p = (byte*)data.Scan0;
int offset = data.Stride - width * 3;
for (int y = 0; y & y++)
for (int x = 0; x & x++)
// 处理指定位置像素的亮度
for (int i = 0; i & 3; i++)
pix = p[i] +
if (degree & 0) p[i] = (byte)Math.Max(0, pix);
if (degree & 0) p[i] = (byte)Math.Min(255, pix);
b.UnlockBits(data);
/// &summary&
/// 图像对比度调整
/// &/summary&
/// &param name="b"&原始图&/param&
/// &param name="degree"&对比度[-100, 100]&/param&
/// &returns&&/returns&
public static Bitmap KiContrast(Bitmap b, int degree)
if (b == null)
if (degree & -100) degree = -100;
if (degree & 100) degree = 100;
double pixel = 0;
double contrast = (100.0 + degree) / 100.0;
contrast *=
int width = b.W
int height = b.H
BitmapData data = b.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
byte* p = (byte*)data.Scan0;
int offset = data.Stride - width * 3;
for (int y = 0; y & y++)
for (int x = 0; x & x++)
// 处理指定位置像素的对比度
for (int i = 0; i & 3; i++)
pixel = ((p[i] / 255.0 - 0.5) * contrast + 0.5) * 255;
if (pixel & 0) pixel = 0;
if (pixel & 255) pixel = 255;
p[i] = (byte)
b.UnlockBits(data);
  经过以上处理,发现识别率高了很多,可是不知道什么原因对单个价格,如9,6,5 这种无法识别,而且对于3,8,0,很容易混淆,对于这种扫货的脚本来说,价格识别率必须是100%对的。后来又去学习怎么训练字库,花了很多时间,最终得出一个结论,OCR训练识别率的前提是 文字能被识别,但是识别错了,如果连文字都识别不出,那么没有训练的必要了,就这样,放弃了。
  当天晚上,看了一篇别人识别网站验证码的文章,又看了国内的脚本开发的文字识别,看到大漠插件的字库,是一个个像素组成的字。灵光一闪,每个价格的笔画不同,位置不同,同样大小的图片,Base64值肯定不一样啊,第二天做了实验,证明自己的想法是对的,哪怕一个像素不对,都是不一样的。于是写了个脚本,把摊位里1-2000的价格都抓下来,然后处理成黑白后分割成小图片。
/// &summary&
/// 图像转Base字符串
/// &/summary&
/// &returns&&/returns&
public static string ToBaseMd5(this Bitmap img)
if (img == null)
return string.E
return Convert.ToBase64String(ToByte(img));
  做脚本嘛,最重要的截取指定区域的图片嘛,直接上代码。
Bitmap image = new Bitmap(26, 18);
Graphics imgGraphics = Graphics.FromImage(image);
//设置截屏区域
imgGraphics.CopyFromScreen(X, Y, 0, 0, new Size(26, 18));
image.Save(path, ImageFormat.Tiff);
以上的技术,基本上可以把识别文字的价格问题解决了,当然中途花了很多时间来做重复的事。
  接下来有个问题,怎么定位价格啊,各种按钮的位置,因此要找个参照物,简单的说就是,截取一个参考物的图片,然后其他元素的位置相对这个参照物进行设置。转化成技术来说,就是一张小图在另一张大图里面找到位置,并返回相对坐标。尝试了几种方法,最终使用&AForge 这个开源项目来处理,代码如下
/// &summary&
/// 判断图像是否存在
/// &/summary&
/// &param name="template"&&/param&
/// &param name="bmp"&&/param&
/// &returns&&/returns&
public static bool ContainsImg(this Bitmap template, Bitmap bmp)
// create template matching algorithm's instance // (set similarity threshold to 92.1%)
ExhaustiveTemplateMatching tm = new ExhaustiveTemplateMatching(0.921f); // find all matchings with specified above similarity
TemplateMatch[] matchings = tm.ProcessImage(template, bmp); // highlight found matchings
return matchings.Length & 0;
/// &summary&
/// 判断图像是否存在另外的图像中,并返回坐标
/// &/summary&
/// &param name="template"&&/param&
/// &param name="bmp"&&/param&
/// &returns&&/returns&
public static Point ContainsGetPoint(this Bitmap template, Bitmap bmp)
// create template matching algorithm's instance // (set similarity threshold to 92.1%)
ExhaustiveTemplateMatching tm = new ExhaustiveTemplateMatching(0.921f); // find all matchings with specified above similarity
TemplateMatch[] matchings = tm.ProcessImage(template, bmp); // highlight found matchings
BitmapData data = template.LockBits(new Rectangle(0, 0, template.Width, template.Height), ImageLockMode.ReadWrite, template.PixelFormat);
Point p = new Point();
if (matchings.Length & 0)
Drawing.Rectangle(data, matchings[0].Rectangle, Color.White);
p = matchings[0].Rectangle.L
template.UnlockBits(data);
  现在价格可以识别了,通过找图,界面的各个坐标都确定了,现在就是写模拟鼠标和键盘的操作了。这个网上很多,我的很简单
对于我的游戏来说鼠标操作,就是移动和左击
public class MouseHelper
[DllImport("user32.dll")]
private static extern bool SetCursorPos(int X, int Y);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, UIntPtr dwExtraInfo);
/// &summary&
/// 鼠标左击
/// &/summary&
public static void LeftClick()
mouse_event(0x02, 0, 0, 0, UIntPtr.Zero);
mouse_event(0x04, 0, 0, 0, UIntPtr.Zero);
/// &summary&
/// 鼠标移动到指定的位置
/// &/summary&
/// &param name="x"&&/param&
/// &param name="y"&&/param&
public static void MovePoint(Point p)
SetCursorPos(p.X, p.Y);
  键盘可以用C#自带的方法 SendKeys
SendKeys.Send("输入文本");//用于输入文字
SendKeys.SendWait("{ENTER}");用于输入按键命令
  基本上就这些了,另外附上一些可能会用到的技能
找到游戏句柄
/// &summary&
/// 获取游戏句柄
/// &/summary&
/// &returns&&/returns&
public static int GetFFoHandle()
Process[] processes = Process.GetProcessesByName("进程名称");
var p = processes.FirstOrDefault();
if (p == null)
return p.MainWindowHandle.ToInt32();
根据句柄获取游戏的位置
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
public int L
public int T
public int R
public int B
 根据句柄将游戏窗体移动到某个位置
/// &summary&
/// 根据句柄移动窗体
/// &/summary&
/// &param name="hWnd"&&/param&
/// &param name="hWndInsertAfter"&&/param&
/// &param name="x"&&/param&
/// &param name="Y"&&/param&
/// &param name="cx"&&/param&
/// &param name="cy"&&/param&
/// &param name="wFlags"&&/param&
/// &returns&&/returns&
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);
其他什么快捷键啊,啥的,网上一大堆就不写了。
好了,就这些,通过以上的代码,可以完成大部分简单的前台脚本了,写的比较乱,但是对于正在研究中的人,我想一定省了不少事。
阅读(...) 评论(){"debug":false,"apiRoot":"","paySDK":"/api/js","wechatConfigAPI":"/api/wechat/jssdkconfig","name":"production","instance":"column","tokens":{"X-XSRF-TOKEN":null,"X-UDID":null,"Authorization":"oauth c3cef7c66aa9e6a1e3160e20"}}
{"database":{"Post":{"":{"contributes":[],"title":"用C#编写一个控制台版猜数字游戏(四)","author":"differentrain","content":"这一节里尝试美化一下这个猜数字游戏。所谓的美化,当然是要设计UI了。开始写这个系列的时候,我最初的打算是先用命令行写,再用winform写,然后用wpf写,最后用Directx写(、、)……后来仔细想了想,费力耗时不说,与我想表达的东西的关系不大,而且我的UI设计水平也非常渣,所以就算了。而更为重要的是,从我学习的过程看,我更喜欢贴上去就能运行的范例程序,要是用那些去实现还得贴上大量无用的设计器代码,要不就有系统限制或使用第三方类库必须安装SDK之类各种各样的麻烦,所以放弃了。所以还是继续用命令行来做吧....言归正传,所谓的命令行UI,自然是用字符组成的(简单)图案。所以第一步首先要设计一个界面范本,以下就是我做的界面范本了,非常简洁和难看,见谅。┏━━━━━━━━━━━━━┓\n┃
猜数字控制台版
//标题\n┣━━━━━━━━━━━━━┫\n┃重开=R 开关音乐=M 退出=ESC┃
//按键说明\n┣━━━┳━━━━━━━━━┫\n┃回合 1┃您的猜测
//回合,用户输入,对勾表示可以确认\n┣━━━┻━━━━━━━━━┫\n┃
//记录\n┃
┃\n┣━━━━━━━━━━━━━┫\n┃
//提示部分\n┗━━━━━━━━━━━━━┛\n如果没有意外的话,你看到的上面的内容应该是混乱的,这是因为字体的原因,因为我使用了制表符,它只有在宋体等字体下才会如预期显示,幸运的是,windows自带的控制台是OK的。而实际的运行效果应该是这样的:要实现这个UI的功能,需要解决两个部分:要实现这个UI的功能,需要解决两个部分:1.在指定区域显示文字和修改。2.获取用户输入内容。3.播放声音。他们都可以通过中的成员实现。具体来说的话,一个控制台包括两部分,控制台窗口很好理解,就是窗口大小,而缓冲区值得是显示文字的区域,他们的大小和位置可以通过、、来实现。这里需要注意的概念是,它们的宽度是以字符(一个汉字/制表符占两个字符)为单位的,高度是以行数为单位的,而且缓冲区的大小一定要大于或等于控制台窗口的大小。显示文字的方法无需赘述,需要说的是在指定位置显示字符串,需要先用控制光标的所在位置,然后输出,当然,这时也可以通过和来指定文字的前景色和背景色。至于获取文字输入内容则很简单,用就可以了,每次读取一个按键,参数设为True的话,不会显示用户输入的字符了。而播放音乐则很有意思,控制台自带了指令,可以播放声音。前一个参数表示声音的频率,后一个参数表示持续时间。只要输入音符对应的频率和持续事件,按照顺序播放,就可以形成旋律了。在官方文档的下面,给出了演奏《玛丽有只小羊羔》的例子.....
protected enum Tone\n
GbelowC = 196,\n
Asharp = 233,\n
Csharp = 277,\n
Dsharp = 311,\n
Fsharp = 370,\n
Gsharp = 415, \n
}\n例子中的这个枚举提供了中央C范围的音符对应的频率,自己加工播放喜欢的音乐吧,虽然效果非常差,但是总归是有了游戏该有的声音不是吗....我为了偷懒,没写音符,而是随机播放小三和弦的音。具体的看代码吧。为了省事,就不用C++的DLL了,直接在第一章的基础上改。//类 MusicHelper ,播放音乐。\n\nusing System;\nusing ponentModel;\n\n\npublic class MusicHelper\n{\n
private BackgroundWorker BGMThead = new BackgroundWorker();\n
private int[] Minor = { 262, 311, 392 }; //小三和弦音。\n
private Random Rnd = new Random();\n\n
public MusicHelper()\n
BGMThead.WorkerSupportsCancellation = true;//可以取消。\n
BGMThead.DoWork += BGMThead_DoWork;\n
private void BGMThead_DoWork(object sender, DoWorkEventArgs e)\n
Console.Beep(Minor[Rnd.Next(0, 2)], 200);\n\n
} while (BGMThead.CancellationPending == false);\n
e.Cancel = true;\n
public void PlayBGM()\n
switch (BGMThead.IsBusy) //判断是否在执行异步任务。\n
case false:\n
BGMThead.RunWorkerAsync();\n
case true:\n
BGMThead.CancelAsync();\n
}\n\n}\n上面的代码使用了。这是.net程序实现多线程最简单的方法。值得一提的是,上面这样的写法非常容易产生内存泄漏,理想的写法是要实现IDispose接口,并在那里加上BGMThead.DoWork -= BGMThead_DoW语句。网络上关于.net内存泄漏的分析有很多,这里就不赘述了,这里只谈我们的程序无需这样做的原因。在实际应用是关于MusicHelper类的实例只有1个,且没有其他引用。DoWork事件不是静态类型。总结一下就是,几乎所有的内存泄漏问题,都是由于对于引用类型对象处理不当造成的,只有在一个对象“没有被使用”或“被销毁”时,才会被自动垃圾回收。//静态类QuizHelper,封装生成谜题和判断谜题的方法。\n\nusing System;\nusing System.Collections.Generic;\n\npublic static class QuizHelper\n{\n\n
private static int i, j;\n
private static List&int& NumList;\n
private static Random Rnd = new Random();\n\n
public static void MakeQuiz(out int[] Quiz)\n
Quiz = new int[4];\n
NumList = new List&int& { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };\n\n
for (i = 0; i & 4; i++)\n
Quiz[i] = NumList[Rnd.Next(0, 9 - i)];\n
NumList.Remove(Quiz[i]);\n
public static void GetFlag(ref int[] Quiz, ref char[] EnterChars, out int FlagA, out int FlagB)\n
FlagA = 0;\n
FlagB = 0;\n
for (i = 0; i & 4; i++)\n
for (j = 0; j & 4; j++)\n
if (EnterChars[j] == (char)(Quiz[i] + 48))\n
if (j == i)\n
++FlagA;\n
++FlagB;\n
}\n\n}\n这里的函数用到了和关键字,ref是指的是指通过引用方式传递,类似C++中的&VariableName,效率高,在传递比较“大”的参数,比如超长字符串,巨大结构体的时候可以这么来,而out的特性使得函数可以返回多个值,前文讲到的winAPI中有很多都利用了这一点。//静态类,封装显示UI的方法\n\nusing System;\n\npublic static class UIHelper\n{\n\n
//私有常量,一些常用的字符串。\n
private const string WORD_ONE = \"1\";\n
private const string WORD_A = \"A\";\n
private const string WORD_B = \"B\";\n
private const string WORD_SPACE = \" \";\n
private const string UI_ANSWER_EMPTY = \"
private const string UI_LOG_EMPTY = \"
private const string UI_LOG_A = \".
private const string UI_LOG_B = \"
private const string UI_STATUS_EMPTY = \"
private const string UI_ANSWER_ENTER_OK = \"√\";\n
private const string UI_STATUS_WIN = \"胜利!\";\n
private const string UI_STATUS_LOST = \"失败!正确答案为 \";\n\n
private static int IntTemp;\n\n\n
//私有方法:改变文字。\n
private static void WriteText(string Text, ConsoleColor FontColor)\n
Console.ForegroundColor = FontColor;\n
Console.Write(Text);\n
private static void WriteText(string Text, ConsoleColor FontColor, ConsoleColor BackColor)\n
Console.BackgroundColor = BackColor;\n
WriteText(Text, FontColor);\n
private static void WriteText(string Text, int LeftPos, int TopPos, ConsoleColor FontColor, ConsoleColor BackColor)\n
Console.SetCursorPosition(LeftPos, TopPos);\n
WriteText(Text, FontColor, BackColor);\n
//在输入的位置显示/关闭光标。\n
public static void ShowCursorPos(bool IsShow)\n
Console.CursorVisible = IsShow;\n
Console.SetCursorPosition(20, 5);\n
//公共方法:初始化游戏UI\n
public static void GameInitialize()\n
//设置控制台,并输出UI\n \n
WriteText(\"┏━━━━━━━━━━━━━┓\\n┃
猜数字控制台版
┃\\n┣━━━━━━━━━━━━━┫\\n┃\", ConsoleColor.White, ConsoleColor.Black);\n
WriteText(\"重开=R 开关音乐=M 退出=ESC\", ConsoleColor.Gray);\n
WriteText(\"┃\\n┣━━━┳━━━━━━━━━┫\\n┃回合 1┃您的猜测 \", ConsoleColor.White);\n
WriteText(UI_ANSWER_EMPTY, ConsoleColor.White, ConsoleColor.DarkGray);\n
WriteText(\"┃\\n┣━━━┻━━━━━━━━━┫\\n┃
┃\\n┣━━━━━━━━━━━━━┫\\n┃
┃\\n┗━━━━━━━━━━━━━┛\", ConsoleColor.White, ConsoleColor.Black);\n
//公共方法:清除UI非初始内容。\n
public static void ClearUI()\n
PrintRound(1); //回合栏清空\n
ClearEnter();\n
for (IntTemp = 7; IntTemp & 16; IntTemp++) //清空提示列表。\n
WriteText(UI_LOG_EMPTY, 5, IntTemp, ConsoleColor.DarkGray, ConsoleColor.Black);\n
PrintStatus(false);\n
ShowCursorPos(true);\n
public static void ClearEnter()\n
WriteText(UI_ANSWER_EMPTY, 19, 5, ConsoleColor.White, ConsoleColor.DarkGray); //输入栏清空\n
//公共方法:显示猜测的记录。\n
public static void PrintLog(int Round, string GuessNumber, int FlagA, int FlagB)\n
WriteText(Round.ToString() + UI_LOG_A + GuessNumber + UI_LOG_B + FlagA.ToString() + WORD_A + FlagB.ToString() + WORD_B, 5, 6 + Round, ConsoleColor.Gray, ConsoleColor.Black);\n
//显示用户输入\n
public static void PrintEnter(char EnterChar,int Index)\n
WriteText(EnterChar.ToString(), 20+Index, 5, ConsoleColor.White, ConsoleColor.DarkGray);\n
//显示输入是否正确\n
public static void PrintEnterRight(bool IsRight)\n
WriteText((IsRight == true) ? UI_ANSWER_ENTER_OK : WORD_SPACE, 26, 5, ConsoleColor.Gray, ConsoleColor.DarkGray);\n
//显示回合数\n
public static void PrintRound(int Round)\n
WriteText(Round.ToString(), 7, 5, ConsoleColor.White, ConsoleColor.Black);\n
//显示状态栏。\n
public static void PrintStatus(bool IsWin)\n
WriteText((IsWin == true) ? UI_STATUS_WIN : UI_STATUS_EMPTY, 2, 17, ConsoleColor.White, ConsoleColor.Black);\n
public static void PrintStatus(int[] Quiz)\n
WriteText(UI_STATUS_LOST + Quiz[0].ToString() + Quiz[1].ToString() + Quiz[2].ToString() + Quiz[3].ToString(), 2, 17, ConsoleColor.White, ConsoleColor.Black);\n
Console.CursorVisible = false;\n
}\n\n\n}\n这里想多说说关于的问题。MSDN的文档说的已经非常清楚了字符串是引用类型,而当我们使用+运算符拼接字符串的时候,其实返回的是新的字符串。举例的话,类似这样:string a=\"a\"; //a引用了对象\"a\"\nstring b=\"b\"; //b引用了对象\"b\"\na+=b; //这时变量a引用的对象为新对象\"ab\",而对象\"a\"和\"b\"根据实际情况可能会被垃圾回收器回收。\n当如我们的程序这样需要拼接的字符串长度很小的时候,这样做没有问题,但是如果是很长的字符串,就最好使用进行组合了,当然,使用StringBuilder的时候,最好设置好他的和属性,以便获得最佳的效果。回看我们的代码,代码定义了许多常量,用来存放需要经常用到的字符串,这样做的目的是减少程序开销,而之所以在GameInitialize方法中直接使用了字符串,是因为它们中有很多UI的“装饰”部分内容,以后不再使用,等待自动垃圾回收即可。而在代码中使用了许多Object.ToString()方法同样是为了节约开销。诚然类似\"a\"+1.tostring()的语句直接写成\"a\"+1也并不不可,然而如果查看相应汇编代码,就可以很明显的看出差异。这是因为1是值类型(int/int32),而\"a\"则是引用类型,而在\"a\"+1的过程里,会先把1变为引用类型,这个过程被称作装箱(参考与)。装箱会构造一个新对象,拆箱则需要经过大量计算,两者的效率都不是非常理想。而tostring()方法则不是通过装箱拆箱实现的,效率较高。//Main\n\nusing System;\nnamespace CS20ConsoleBullsandCows\n{\n\n
class Program\n
struct GameInfo\n
public static int Round = 1;\n
public static int FlagA = 0;\n
public static int FlagB = 0;\n
public static int EnterIndex = 0;\n
public static char[] EnterChars = new char[4];\n
public static int[] Quiz;\n
static void Main(string[] args)\n
bool EndGame = false;\n
bool CanEnter;\n
int TempInt;\n
ConsoleKeyInfo TempKeyInfo;\n
MusicHelper MH = new MusicHelper();\n
UIHelper.GameInitialize();\n
UIHelper.ShowCursorPos(true);\n
MH.PlayBGM();\n\n
TempKeyInfo = Console.ReadKey(true);\n
//Key与KeyChar的区别在于,前者表示按键,后者表示案件对应的字符。\n
switch (TempKeyInfo.Key)\n
case ConsoleKey.Escape: //ESC退出游戏\n
EndGame = true;\n
case ConsoleKey.M:\n
MH.PlayBGM();\n
case ConsoleKey.R:\n
UIHelper.ClearUI();\n
UIHelper.ShowCursorPos(true);\n
GameInfo.Round = 1;\n
GameInfo.EnterIndex = 0;\n
for (TempInt = 0; TempInt & 4; TempInt++)\n
GameInfo.EnterChars[TempInt] = (char)0;\n
case ConsoleKey.Enter:\n
if (Console.CursorVisible == true & GameInfo.EnterIndex == 4)\n
if (GameInfo.Round == 1) //windows自带的扫雷就是类似的生成方式~~\n
QuizHelper.MakeQuiz(out GameInfo.Quiz);\n
QuizHelper.GetFlag(ref GameInfo.Quiz, ref GameInfo.EnterChars, out GameInfo.FlagA, out GameInfo.FlagB);\n
UIHelper.PrintLog(GameInfo.Round, GameInfo.EnterChars[0].ToString() + GameInfo.EnterChars[1].ToString() + GameInfo.EnterChars[2].ToString() + GameInfo.EnterChars[3].ToString(), GameInfo.FlagA, GameInfo.FlagB);\n
UIHelper.ClearEnter();\n
for (TempInt = 0; TempInt & 4; TempInt++)\n
GameInfo.EnterChars[TempInt] = (char)0;\n
GameInfo.EnterIndex = 0;\n
if (GameInfo.FlagA == 4)\n
UIHelper.ShowCursorPos(false);\n
UIHelper.PrintStatus(true);\n
else if (GameInfo.Round & 9)\n
++GameInfo.Round;\n
UIHelper.PrintRound(GameInfo.Round);\n
UIHelper.ShowCursorPos(true);\n
UIHelper.ShowCursorPos(false);\n
UIHelper.PrintStatus(GameInfo.Quiz);\n
default:\n
if (Console.CursorVisible == true)\n
if (TempKeyInfo.KeyChar & 47 && TempKeyInfo.KeyChar & 58 && GameInfo.EnterIndex & 4)\n
CanEnter = true;\n
for (TempInt = GameInfo.EnterIndex; TempInt & -1; TempInt--)\n
if (GameInfo.EnterChars[TempInt] == TempKeyInfo.KeyChar)\n
CanEnter = false;\n
if (CanEnter == true)\n
GameInfo.EnterChars[GameInfo.EnterIndex] = TempKeyInfo.KeyChar;\n
UIHelper.PrintEnter(TempKeyInfo.KeyChar, GameInfo.EnterIndex);\n
++GameInfo.EnterIndex;\n
else if (TempKeyInfo.Key == ConsoleKey.Backspace & GameInfo.EnterIndex & 0)\n
GameInfo.EnterChars[GameInfo.EnterIndex - 1] = (char)0;\n
UIHelper.PrintEnter(' ', GameInfo.EnterIndex - 1);\n
--GameInfo.EnterIndex;\n
UIHelper.PrintEnterRight((GameInfo.EnterIndex == 4) ? true : false);\n
Console.SetCursorPosition(20 + GameInfo.EnterIndex, 5);\n
} while (EndGame == false);\n
}\n}\n首先要说一下一般意义上的游戏,一般意义上的游戏,也是需要建立无限的主循环,然后使用消息来控制游戏的比如点击,移动之类的操作,具体来说类似这样:伪代码\n循环体\n
事件/消息处理1\n
事件/消息处理2\n
更新画面\n循环体结束\n这也就是为什么竞技游戏对电脑配置要求高的原因,配置越高,画面上物体的移动和变化的细节就呈现的越多,而操作也可以更精细。不过我们的程序不必采取这种方式,直接在需要的地方更新画面就可以了……其他没什么可说的,另外对于程序整体来说,我虽然对一些东西做了封装,但更多的只是整理和归纳,而非所谓的面向对象式的设计,因为毕竟不是多复杂的东西。嗯,如果要为本节概括一个中心思想的话,就是坑和取舍。《用C#编写一个控制台版猜数字游戏》(四),完。","updated":"T16:14:17.000Z","canComment":false,"commentPermission":"anyone","commentCount":0,"collapsedCount":0,"likeCount":1,"state":"published","isLiked":false,"slug":"","isTitleImageFullScreen":false,"rating":"none","titleImage":"","links":{"comments":"/api/posts//comments"},"reviewers":[],"topics":[{"url":"/topic/","id":"","name":"C#"},{"url":"/topic/","id":"","name":"控制台"},{"url":"/topic/","id":"","name":"脑洞"}],"adminClosedComment":false,"titleImageSize":{"width":0,"height":0},"href":"/api/posts/","excerptTitle":"","tipjarState":"closed","annotationAction":[],"sourceUrl":"","pageCommentsCount":0,"hasPublishingDraft":false,"snapshotUrl":"","publishedTime":"T00:14:17+08:00","url":"/p/","lastestLikers":[{"bio":"滑板/旅行/游戏/Coding","isFollowing":false,"hash":"bd3afbc35a2ffacbfd502fdf","uid":56,"isOrg":false,"slug":"yang-jiang-hai","isFollowed":false,"description":"Shanda Game Development Engineer","name":"杨江海","profileUrl":"/people/yang-jiang-hai","avatar":{"id":"285a52e1f152f584f20e875ab8cd6d9f","template":"/{id}_{size}.jpg"},"isOrgWhiteList":false}],"summary":"这一节里尝试美化一下这个猜数字游戏。所谓的美化,当然是要设计UI了。开始写这个系列的时候,我最初的打算是先用命令行写,再用winform写,然后用wpf写,最后用Directx写(、、)……后来仔细想了想,费力耗时不说,与我想表达的东西的关系…","reviewingCommentsCount":0,"meta":{"previous":null,"next":null},"annotationDetail":null,"commentsCount":0,"likesCount":1,"FULLINFO":true}},"User":{"differentrain":{"isFollowed":false,"name":"雨少主","headline":"赋辞羞笔墨, 程序懂毛皮。 曾想搞音乐, 惟能买耳机。","avatarUrl":"/fb2fd8979_s.jpg","isFollowing":false,"type":"people","slug":"differentrain","bio":"宅","hash":"33b6fa3aae4eeb70fb0ce62e9bd358f7","uid":12,"isOrg":false,"description":"赋辞羞笔墨, 程序懂毛皮。 曾想搞音乐, 惟能买耳机。","profileUrl":"/people/differentrain","avatar":{"id":"fb2fd8979","template":"/{id}_{size}.jpg"},"isOrgWhiteList":false,"badge":{"identity":null,"bestAnswerer":null}}},"Comment":{},"favlists":{}},"me":{},"global":{},"columns":{"next":{}},"columnPosts":{},"columnSettings":{"colomnAuthor":[],"uploadAvatarDetails":"","contributeRequests":[],"contributeRequestsTotalCount":0,"inviteAuthor":""},"postComments":{},"postReviewComments":{"comments":[],"newComments":[],"hasMore":true},"favlistsByUser":{},"favlistRelations":{},"promotions":{},"switches":{"couldAddVideo":false},"draft":{"titleImage":"","titleImageSize":{},"isTitleImageFullScreen":false,"canTitleImageFullScreen":false,"title":"","titleImageUploading":false,"error":"","content":"","draftLoading":false,"globalLoading":false,"pendingVideo":{"resource":null,"error":null}},"drafts":{"draftsList":[],"next":{}},"config":{"userNotBindPhoneTipString":{}},"recommendPosts":{"articleRecommendations":[],"columnRecommendations":[]},"env":{"isAppView":false,"appViewConfig":{"content_padding_top":128,"content_padding_bottom":56,"content_padding_left":16,"content_padding_right":16,"title_font_size":22,"body_font_size":16,"is_dark_theme":false,"can_auto_load_image":true,"app_info":"OS=iOS"},"isApp":false},"sys":{}}

我要回帖

更多关于 封印者bingo数字券 的文章

 

随机推荐