当前访客身份:游客 [ 登录  | 注册加入尚学堂]
直播

Queen

拥有积分:3
这家伙太懒,还没有签名!

博客分类

笔记中心

课题中心

提问中心

答题中心

解答题中心

【趣味分享】C#实现回味童年的24点算法游戏

Queen 发表于 22天前 (2016-12-27 09:43:40)  |  评论(0)  |  阅读次数(42)| 0 人收藏此文章,   我要收藏   

 一、24点游戏玩法规则效果展示

1、初始化界面

2、开始游戏界面

3、游戏超时界面

 

4、查看答案界面

 

5、答对界面

6、答错界面

7、计算表达式的验证界面

 

8、一副牌算完开始新一副牌界面

 到这里24点算法基本操作图就结束了,下面来看看示例代码吧。

二、完整代码演示

 关于代码解释,为了方便读者浏览时更好理解代码的含义,我把注释都写在代码里面了。因为一开始我只考虑到功能上的实现并没有考虑代码的优化所以代码我就全写在一个页面了。至于那些生成扑克牌类、计算类等代码优化方面的内容就留给想要实现这个24点算法游戏的读者自己去完善吧。

  1 using System;
  2 using System.Collections;
  3 using System.Collections.Generic;
  4 using System.ComponentModel;
  5 using System.Data;
  6 using System.Drawing;
  7 using System.IO;
  8 using System.Linq;
  9 using System.Text;
 10 using System.Threading.Tasks;
 11 using System.Windows.Forms;
 12 
 13 namespace XF_24Point
 14 {
 15     public partial class frnMain : Form
 16     {
 17         private int A, B, C, D;//牌面大小对应的数字大小也用于交换数字的位置
 18         private int NumberA, NumberB, NumberC, NumberD;//牌面大小对应的数字大小
 19         private int topCard;//显示在窗体四张牌中扑克牌的编号(1-52)
 20         DateTime beginTime;//记录开始时间
 21       
 22         #region 一副牌的生成
 23         //结构: 值得一提的是,在C++中,struct的功能得到了强化,struct不仅可以添加成员变量,还可以添加成员函数,和class类似。
 24         struct card
 25         {
 26             public int face;//牌面大小,数字大小
 27             public int suit;//牌面花色,如梅花、黑桃、红心、方块,只能有四张
 28             public int count;//牌面点数,牌面上的的图案点数
 29             public bool faceup;//牌面是否向上
 30         }
 31         private card[] PlayingCards;//一副牌
 32 
 33         //生成一副牌
 34         private void GetPlayingCareds()
 35         {
 36             PlayingCards = new card[53];
 37             int i;//牌面大小
 38             int j;//牌面花色
 39             for (i = 0; i < 13; i++)
 40             {
 41                 for (j = 1; j <= 4; j++)
 42                 {
 43                     PlayingCards[j + i * 4].face = i + 1;//PlayingCards[j + i * 4]:指的是:j + i * 4  =>获取文件图片扑克牌的序号
 44                     PlayingCards[j + i * 4].suit = j;//牌面花色,如梅花、黑桃、红心、方块,只能有四张
 45                     if (i < 10)
 46                     {
 47                         PlayingCards[j + i * 4].count = i + 1;//牌面点数,牌面上的的图案点数
 48                     }
 49                     else
 50                     {
 51                         PlayingCards[j + i * 4].count = 10;
 52                     }
 53                     PlayingCards[j + i * 4].faceup = false;
 54                 }
 55             }
 56         }
 57         //洗牌 :Shuffle
 58         private void Shuffle()
 59         {
 60             Random random = new Random((int)DateTime.Now.Ticks);
 61             card middleCard;//作为临时交换牌顺序的变量
 62             int j, k;
 63             for (int i = 0; i < 1000; i++)
 64             {
 65                 j = (int)random.Next(1, 52);
 66                 k = (int)random.Next(1, 52);
 67                 //打乱牌的顺序(随机交换牌的顺序)
 68                 middleCard = PlayingCards[j];
 69                 PlayingCards[j] = PlayingCards[k];
 70                 PlayingCards[k] = middleCard;
 71             }
 72         }
 73         //开始游戏的时候发四张牌
 74         private void btnStart_Click(object sender, EventArgs e)
 75         {
 76             lblInput.Text = "";
 77             GetPlayingCareds();//生成一副牌
 78             Shuffle();//洗牌
 79             topCard = 0;//显示在窗体四张牌中扑克牌的编号(1-52)
 80             int imageNum;//文件夹中扑克牌图片的编号(文件名)
 81             string path;
 82             //画第一张牌
 83             topCard = topCard = 1;
 84             pictureBox1.Visible = true;
 85             //获得文件中某张牌并且知道是什么花色对应的编号计算公式:
 86             //牌面花色(1、2、3、4):要获得某张牌的的花色
 87             //(牌面数字大小-1)*4:要获得的某张牌的前一个牌面大小如:要获得的牌是10,前一个牌面就是9
 88             //牌面花色(1、2、3、4)+(牌面数字大小-1)*4
 89             imageNum = PlayingCards[topCard].suit + (PlayingCards[topCard].face - 1) * 4;//文件图片编号
 90             path = Directory.GetCurrentDirectory() + @"\images\" + imageNum.ToString() + ".bmp";
 91             pictureBox1.Image = Image.FromFile(path);
 92             NumberA = Convert.ToInt32(PlayingCards[topCard].face);//牌面大小对应的数字大小
 93             btnNumber1.Text = NumberA.ToString();
 94             //画第二张牌
 95             topCard = topCard + 1;
 96             pictureBox2.Visible = true;
 97             imageNum = PlayingCards[topCard].suit + (PlayingCards[topCard].face - 1) * 4;
 98             path = Directory.GetCurrentDirectory() + @"\images\" + imageNum.ToString() + ".bmp";
 99             pictureBox2.Image = Image.FromFile(path);
100             NumberB = Convert.ToInt32(PlayingCards[topCard].face);
101             btnNumber2.Text = NumberB.ToString();
102             //画第三张牌
103             topCard = topCard + 1;
104             pictureBox3.Visible = true;
105             imageNum = PlayingCards[topCard].suit + (PlayingCards[topCard].face - 1) * 4;
106             path = Directory.GetCurrentDirectory() + @"\images\" + imageNum.ToString() + ".bmp";
107             pictureBox3.Image = Image.FromFile(path);
108             NumberC = Convert.ToInt32(PlayingCards[topCard].face);
109             btnNumber3.Text = NumberC.ToString();
110             //画第四张牌
111             topCard = topCard + 1;
112             pictureBox4.Visible = true;
113             imageNum = PlayingCards[topCard].suit + (PlayingCards[topCard].face - 1) * 4;
114             path = Directory.GetCurrentDirectory() + @"\images\" + imageNum.ToString() + ".bmp";
115             pictureBox4.Image = Image.FromFile(path);
116             NumberD = Convert.ToInt32(PlayingCards[topCard].face);
117             btnNumber4.Text = NumberD.ToString();
118             //初始化界面控件
119             btnStart.Visible = false;//开始游戏
120             groupBox1.Visible = true;//计算表达式
121             groupBox2.Visible = true;//查看答案
122             groupBox3.Visible = true;//游戏规则
123             lblShowTime.Visible = true;//显示时间
124             timer1.Enabled = true;//启用时钟
125             beginTime = DateTime.Now;
126         }
127         #endregion
128 
129         public frnMain()
130         {
131             InitializeComponent();
132             Initialize();//初始化窗体上的控件的方法
133         }
134 
135         //初始化窗体上的控件的方法,一开始隐藏
136         private void Initialize()
137         {
138             pictureBox1.Visible = false;
139             pictureBox2.Visible = false;
140             pictureBox3.Visible = false;
141             pictureBox4.Visible = false;
142             groupBox1.Visible = false;
143             groupBox2.Visible = false;
144             groupBox3.Visible = false;
145             lblResult.Visible = false;
146             lblShowTime.Visible = false;
147         }
148 
149         #region 计算表达式的输入
150         //第一张牌
151         private void btnNumber1_Click(object sender, EventArgs e)
152         {
153             lblInput.Text = lblInput.Text + btnNumber1.Text.Trim();
154         }
155         //第二张牌
156         private void btnNumber2_Click(object sender, EventArgs e)
157         {
158             lblInput.Text = lblInput.Text + btnNumber2.Text.Trim();
159         }
160         //第三张牌
161         private void btnNumber3_Click(object sender, EventArgs e)
162         {
163             lblInput.Text = lblInput.Text + btnNumber3.Text.Trim();
164         }
165         //第四章牌
166         private void btnNumber4_Click(object sender, EventArgs e)
167         {
168             lblInput.Text = lblInput.Text + btnNumber4.Text.Trim();
169         }
170         //加号
171         private void btnAdd_Click(object sender, EventArgs e)
172         {
173             lblInput.Text = lblInput.Text + btnAdd.Text.Trim();
174         }
175         //减号
176         private void btnMinus_Click(object sender, EventArgs e)
177         {
178             lblInput.Text = lblInput.Text + btnMinus.Text.Trim();
179         }
180         //乘号
181         private void btnMulti_Click(object sender, EventArgs e)
182         {
183             lblInput.Text = lblInput.Text + btnMulti.Text.Trim();
184         }
185         //除号
186         private void btnDivide_Click(object sender, EventArgs e)
187         {
188             lblInput.Text = lblInput.Text + btnDivide.Text.Trim();
189         }
190         //左括号
191         private void btnLeft_Click(object sender, EventArgs e)
192         {
193             lblInput.Text = lblInput.Text + btnLeft.Text.Trim();
194         }
195         //右括号
196         private void btnRight_Click(object sender, EventArgs e)
197         {
198             lblInput.Text = lblInput.Text + btnRight.Text.Trim();
199         }
200         //删除最后一个字符
201         private void btnDelete_Click(object sender, EventArgs e)
202         {
203             string input = lblInput.Text.Trim();
204             lblInput.Text = input.Substring(0, input.Length - 1);
205         }
206         //清除所有字符
207         private void btnClear_Click(object sender, EventArgs e)
208         {
209             lblInput.Text = "";
210         }
211 
212         #endregion
213 
214         //确定按钮
215         private void btnEnter_Click(object sender, EventArgs e)
216         {
217             if (lblInput.Text.Trim()== "")
218             {
219                 MessageBox.Show("计算表达式不能为空!");
220                 return;
221             }
222             if (CheckForNumber(lblInput.Text.Trim()))//检查输入表达式中输入的数字是否匹配
223             {
224                 //计算表达式的结果第一层
225                 int result = Deal(lblInput.Text.Trim());//调用Deal()处理方法,对用户输入的表达式做一系列判断计算,返回最终的结果
226                 lblResult.Visible = true;
227                 if (result == 24)
228                 {
229                     lblResult.Text = "<<---恭喜您,答对了!--->>";
230                     timer1.Enabled = false;//暂停时钟
231                 }
232                 else
233                 {
234                     lblResult.Text = "<<--抱歉,您的回答有误!-->>";
235                 }
236             }
237         }
238 
239         #region 验证确定按钮包含的一系列方法:检查计算用户输入表达式结果是否正确
240         //处理Deal谓词表达式中的括号
241         private int Deal(string InputExp)
242         {
243             int result = 0;
244             while (InputExp.IndexOf(')') != -1)//判断是否存在括号 input.IndexOf(')') !=-1,表明存在括号
245             {
246                 //3*8÷(9-8)=24、(10+2)*(3-1)=24
247                 int rightLoc = InputExp.IndexOf(')');//右括号的位置
248                 string temp = InputExp.Substring(0, rightLoc);//从0(开始位置)到右括号的位置,不包括右括号(10+2
249                 int leftLoc = temp.LastIndexOf('(');//左括号的位置0
250                 string first = InputExp.Substring(0, leftLoc);//从0到左括号的位置,空
251                 string middle = InputExp.Substring(leftLoc + 1, rightLoc - leftLoc - 1);//括号中间的部分10+2
252                 string last = InputExp.Substring(rightLoc + 1);//右括号后面的部分*(3-1)
253                 //计算表达式的结果第二层
254                 InputExp = first + Formula(middle) + last; //""+10+2+*(3-1)注意:+表示连接,连接两个字符串
255             }
256             //计算表达式的结果第二层
257             result = Formula(InputExp);//调用用户输入表达式检查、计算方法,返回用户输入表达式的结果Formula:公式
258             return result;
259         }
260 
261         //最简式运算 Formula:公式
262         private int Formula(string InputExp)
263         {
264             int length = InputExp.Length;//验证表达式的长度
265             ArrayList OpeLoc = new ArrayList();//记录运算操作符位置   
266             ArrayList Ope = new ArrayList();//记录运算操作符 
267             ArrayList Value = new ArrayList();//记录数值内容 ,也就是记录输入表达式的数字的值
268             int i;//全局变量i,运用于方法体内每个循环
269             for (i = 0; i < length; i++)
270             {
271                 if (IsOperator(InputExp[i]))//检查获判断一个符号是否是基本算符 
272                 {
273                     OpeLoc.Add(i);//记录并添加运算操作符位置x
274                     Ope.Add(InputExp[i]);//记录并添加运算操作符  
275                 }
276             }
277             if (OpeLoc.Count == 0)
278             {
279                 return int.Parse(InputExp);//处理无运算符的情况
280             }
281             //计算表达式的结果第三层
282             RebuildOperator(ref OpeLoc, ref Ope);//对运算符进行重新组合,把负号和减号区分开来
283             if (!CheckFunction(OpeLoc, length))
284             {
285                 return 0;//检查功能,判断运算符组是否合法  ,也就是运算符位置是否正确
286             }
287             int j = 0;
288             for (i = 0; i < OpeLoc.Count; i++)
289             {
290                 Value.Add(int.Parse(InputExp.Substring(j, Convert.ToInt32(OpeLoc[i]) - j)));
291                 j = Convert.ToInt32(OpeLoc[i]) + 1;//最后一个数值的索引
292             }
293             //substring(开始索引,字符长度)
294             Value.Add(int.Parse(InputExp.Substring(j, length - j)));//处理最后一个数值的添加
295             //计算表达式的结果第四层
296             return Calculate(Ope, Value);//调用用户输入表达式的计算方法,参数1:运算符,参数2:数值
297         }
298 
299         //处理四则混合运算等基础运算(+-*/)
300         private int Calculate(ArrayList Ope, ArrayList Values)
301         {
302             int i;//全局变量i,运用于方法体内每个循环
303             for (i = 0; i < Ope.Count; i++)//处理乘法、除法 
304             {
305                 switch (Convert.ToChar(Ope[i]))
306                 {
307                     case '*':
308                         Values[i] = Convert.ToInt32(Values[i]) * Convert.ToInt32(Values[i + 1]);
309                         Values.RemoveAt(i + 1);
310                         Ope.RemoveAt(i);
311                         i--;
312                         break;
313                     case '/':
314                         Values[i] = Convert.ToInt32(Values[i]) * Convert.ToInt32(Values[i + 1]);
315                         Values.RemoveAt(i + 1);
316                         Ope.RemoveAt(i);
317                         i--;
318                         break;
319                 }
320             }
321             for (i = 0; i < Ope.Count; i++)//处理加法和减法 
322             {
323                 switch ((char)Ope[i])
324                 {
325                     case '+':
326                         Values[i] = Convert.ToInt32(Values[i]) + Convert.ToInt32(Values[i + 1]);
327                         Values.RemoveAt(i + 1);
328                         Ope.RemoveAt(i);
329                         i--;
330                         break;
331                     case '-':
332                         Values[i] = Convert.ToInt32(Values[i]) - Convert.ToInt32(Values[i + 1]); ;
333                         Values.RemoveAt(i + 1);
334                         Ope.RemoveAt(i);
335                         i--;
336                         break;
337                 }
338             }
339             return Convert.ToInt32(Values[0].ToString());
340         }
341 
342         //判断运算符组是否合法
343         private bool CheckFunction(ArrayList OpeLoc, int length)
344         {
345             if (Convert.ToInt32(OpeLoc[0]) == 0)//判断第一个运算符的的索引是否为0,也就是运算符排在表达式第一个
346                 return false;
347             int i;
348             for (i = 1; i < OpeLoc.Count; i++)
349             {
350                 if (Convert.ToInt32(OpeLoc[i]) - Convert.ToInt32(OpeLoc[i - 1]) == 1)//检查判断两个运算符是否连续
351                     return false;
352             }
353             //判断最后一个运算符的的索引是否等于表达式索引的,也就是该运算符排在表达式末尾
354             if (Convert.ToInt32(OpeLoc[OpeLoc.Count - 1]) == length - 1)
355                 return false;
356             return true;
357         }
358         //对负号的处理和重构
359         private void RebuildOperator(ref ArrayList OpeLoc, ref ArrayList Ope)
360         {
361             ArrayList DelItem = new ArrayList();
362             if (Convert.ToInt32(OpeLoc[0].ToString()) == 0 && Convert.ToChar(Ope[0]) == '-')//判断第一个符号是否是负号  ,索引为0的符号
363             {
364                 DelItem.Add(0);
365             }
366             int i;
367             for (i = 1; i < OpeLoc.Count; i++)
368             {
369                 //判断是否有相邻的算符且后一个是负号,且后一个运算符-前一个运算符==1
370                 if (Convert.ToChar(Ope[i]) == '-' && Convert.ToChar(Ope[i - 1]) != '-' && (Convert.ToInt32(OpeLoc[i]) - Convert.ToInt32(OpeLoc[i - 1])) != 1)
371                 {
372                     DelItem.Add(i);
373                 }
374             }
375             for (i = DelItem.Count - 1; i > 0; i--)//将负号和减号分开处理  
376             {
377                 //移除运算符和所在运算符所在位置
378                 Ope.RemoveAt(Convert.ToInt32(DelItem[i]));
379                 OpeLoc.RemoveAt(Convert.ToInt32(DelItem[i]));
380             }
381         }
382         //判断一个符号是否是基本算符 
383         private bool IsOperator(char c)
384         {
385             if (c == '+' || c == '-' || c == '*' || c == '/')
386                 return true;//判断是否是四则混合运算算符
387             else
388                 return false;
389         }
390         //检查输入的计算公式是否有错误,牌是否有重复或则输入有误或输入的牌超过四张
391         private bool CheckForNumber(string InputExp)//InputExp:用户输入的表达式如:(6*2)*(6/3)
392         {
393             bool result = true;
394             //先找出分隔符,再返回用户输入以这些分隔符分隔的的string类型数字数组
395             string[] str = InputExp.Split(new char[] { '+', '-', '*', '/', '(', ')' }, StringSplitOptions.RemoveEmptyEntries);
396             if (str.Length != 4)
397             {
398                 MessageBox.Show("抱歉,输入有误!请重新输入");
399                 result = false;
400                 return result;
401             }
402             int[] InputNums = new int[4];//用户输入计算表达式的数字
403             int[] CreatNums = { NumberA, NumberB, NumberC, NumberD };//生成的四张牌对应的数字,在生成牌时已经赋值
404             Array.Sort(CreatNums);//排序:升序
405             for (int i = 0; i < 4; i++)
406             {
407                 InputNums[i] = Convert.ToInt32(str[i]);//用户输入的数字
408             }
409             Array.Sort(InputNums);//排序:升序
410             for (int i = 0; i < 4; i++)
411             {
412                 if (InputNums[i] != CreatNums[i])//判断生成的牌对应的数字与用户输入的数字是否一一匹配,如果不匹配则表明牌有重复
413                 {
414                     result = false;
415                     MessageBox.Show("抱歉,每张牌只能使用一次!");
416                     return result;
417                 }
418             }
419             return result;
420         }
421 
422         #endregion
423 
424         //查看答案按钮
425         private void btnAnswer_Click(object sender, EventArgs e)
426         {
427 
428             int index = 1;//记录答案个数
429             #region 点击查看答案按钮,输入按钮禁用,时钟停止,清空答案栏
430             btnAdd.Enabled = false;
431             btnMinus.Enabled = false;
432             btnDivide.Enabled = false;
433             btnMulti.Enabled = false;
434             btnNumber1.Enabled = false;
435             btnNumber2.Enabled = false;
436             btnNumber3.Enabled = false;
437             btnNumber4.Enabled = false;
438             btnDelete.Enabled = false;
439             btnClear.Enabled = false;
440             btnLeft.Enabled = false;
441             btnRight.Enabled = false;
442             btnEnter.Enabled = false;
443             timer1.Enabled = false;//停止时钟
444             txtAnswer.Text = "";//清空答案栏
445             #endregion
446             #region 首先:(ABCD位置)24种情况的遍历,然后:计算24点的方法,接着:把字符表达式转为数值表达式
447             for (int i = 1; i <= 24; i++)
448             {
449                 ChangeOfPosition24(i);//24种情况的位置转换的方法
450                 ArrayList first = new ArrayList();//数字集合对象
451                 ArrayList firstStr = new ArrayList();//字符集合对象
452                 first.Add(A.ToString());
453                 firstStr.Add("A");
454                 //此方法的核心思路:本来一开始是有ABCD四张牌,第一次对A、B进行加减乘除,再把得到的结果result返回去,第二次调用对result、C重复第一次操作
455                 //第三次也是重复,不过这次返回去的结果就是计算出来的结果
456                 cal(ref first, ref firstStr, B, 'B');
457                 cal(ref first, ref firstStr, C, 'C');
458                 cal(ref first, ref firstStr, D, 'D');
459 
460                 for (int j = 0; j < first.Count; j++)
461                 {
462                     if (Convert.ToInt32(Convert.ToDouble(first[j].ToString())) == 24)
463                     {
464                         //replaceString参数(字符表达式,'字符',数值),此方法的核心思想是,一个一个字符替换为对应的数值
465                         firstStr[j] = replaceString(firstStr[j].ToString(), 'A', A);
466                         firstStr[j] = replaceString(firstStr[j].ToString(), 'B', B);
467                         firstStr[j] = replaceString(firstStr[j].ToString(), 'C', C);
468                         firstStr[j] = replaceString(firstStr[j].ToString(), 'D', D);
469                         //追加文本答案
470                         txtAnswer.AppendText("答案" + index + ": " + firstStr[j].ToString() + "=24;" + "\r\n");
471                         index++;
472                     }
473                 }
474             }
475             if (txtAnswer.Text.Trim() == "")
476             {
477                 txtAnswer.Text = "此题无解";
478             }
479             #endregion
480         }
481 
482         #region 点击查看答案按钮要做的一系列处理计算
483         //1、(ABCD)24种情况的位置转换
484         public void ChangeOfPosition24(int i)
485         {
486             //24种位置转换 
487             //此方法的核心思想:要让A/B/C/D四个数两两算一次,如:+加号运算符
488             //(A+B) (A+C) (A+D) (B+C) (B+D) (C+D)一共有6种情况,以此类推减号也有6种情况,
489             //加减乘除四种运算符加起来总共就有24种情况
490             //补充:上面的意思是A在第一个位置有6种情况,同理
491             //B在第一个位置也有6种情况,C在第一个位置也有6种情况,D在第一个位置也有6种情况
492             switch (i)
493             {
494                 case 1:
495                     A = NumberA; B = NumberB; C = NumberC; D = NumberD;
496                     break;
497                 case 2:
498                     A = NumberA; B = NumberB; D = NumberC; C = NumberD;
499                     break;
500                 case 3:
501                     A = NumberA; C = NumberB; B = NumberC; D = NumberD;
502                     break;
503                 case 4:
504                     A = NumberA; C = NumberB; D = NumberC; B = NumberD;
505                     break;
506                 case 5:
507                     A = NumberA; D = NumberB; B = NumberC; C = NumberD;
508                     break;
509                 case 6:
510                     A = NumberA; D = NumberB; C = NumberC; B = NumberD;
511                     break;
512                 case 7:
513                     B = NumberA; A = NumberB; C = NumberC; D = NumberD;
514                     break;
515                 case 8:
516                     B = NumberA; A = NumberB; D = NumberC; C = NumberD;
517                     break;
518                 case 9:
519                     B = NumberA; C = NumberB; A = NumberC; D = NumberD;
520                     break;
521                 case 10:
522                     B = NumberA; C = NumberB; D = NumberC; A = NumberD;
523                     break;
524                 case 11:
525                     B = NumberA; D = NumberB; A = NumberC; C = NumberD;
526                     break;
527                 case 12:
528                     B = NumberA; D = NumberB; C = NumberC; A = NumberD;
529                     break;
530                 case 13:
531                     C = NumberA; A = NumberB; B = NumberC; D = NumberD;
532                     break;
533                 case 14:
534                     C = NumberA; A = NumberB; D = NumberC; B = NumberD;
535                     break;
536                 case 15:
537                     C = NumberA; B = NumberB; A = NumberC; D = NumberD;
538                     break;
539                 case 16:
540                     C = NumberA; B = NumberB; D = NumberC; A = NumberD;
541                     break;
542                 case 17:
543                     C = NumberA; D = NumberB; A = NumberC; B = NumberD;
544                     break;
545                 case 18:
546                     C = NumberA; D = NumberB; B = NumberC; A = NumberD;
547                     break;
548                 case 19:
549                     D = NumberA; A = NumberB; B = NumberC; C = NumberD;
550                     break;
551                 case 20:
552                     D = NumberA; A = NumberB; C = NumberC; B = NumberD;
553                     break;
554                 case 21:
555                     D = NumberA; B = NumberB; A = NumberC; C = NumberD;
556                     break;
557                 case 22:
558                     D = NumberA; B = NumberB; C = NumberC; A = NumberD;
559                     break;
560                 case 23:
561                     D = NumberA; C = NumberB; A = NumberC; B = NumberD;
562                     break;
563                 case 24:
564                     D = NumberA; C = NumberB; B = NumberC; A = NumberD;
565                     break;
566             }
567         }
568 
569         //2、24点计算方法(加减乘除)
570         //注意:ref:传入传出,out:传出
571         //此方法的核心思路:本来一开始是有ABCD四张牌,第一次对A、B进行加减乘除,再把得到的结果result返回去,第二次调用对result、C重复第一次操作
572         //第三次也是重复,不过这次返回去的结果就是计算出来的结果
573         private void cal(ref ArrayList num, ref ArrayList numStr, int num2, char num2Str)//传入参数A=6,"A",B=4,"B"
574         {
575             ArrayList newNum = new ArrayList();//数值集合对象
576             ArrayList newNumStr = new ArrayList();//字符集合对象
577             int temp;
578             for (int i = 0; i < num.Count; i++)
579             {
580                 int num1 = Convert.ToInt32(num[i].ToString());
581 
582                 #region 加法的情况
583                 temp = num1 + num2;
584                 newNum.Add(temp.ToString());//数字:6+4
585                 newNumStr.Add(numStr[i].ToString() + "+" + num2Str);//字符A+B
586                 #endregion
587 
588                 #region 减法的情况
589                 if (num1 > num2)
590                 {
591                     temp = num1 - num2;
592                     newNum.Add(temp.ToString());//数字:6-4
593                     newNumStr.Add(numStr[i].ToString() + "-" + num2Str);//字符A-B
594                 }
595                 else
596                 {
597                     temp = num2 - num1;
598                     newNum.Add(temp.ToString());
599                     //检查是否存在+-运算符,若查找返回索引的结果不等于-1,表示存在+-运算符
600                     if (numStr[i].ToString().IndexOf('+') != -1 || numStr[i].ToString().IndexOf('-') != -1)
601                     {
602                         newNumStr.Add(num2Str + "-" + "(" + numStr[i].ToString() + ")");//B-(A)
603                     }
604                     else
605                     {
606                         newNumStr.Add(num2Str + "-" + numStr[i].ToString());//B-A
607                     }
608                 }
609                 #endregion
610 
611                 #region 乘法的情况
612                 temp = num1 * num2;
613                 newNum.Add(temp.ToString());
614                 //利用IndexOf()检查是否有+-运算符-1:指的是没有
615                 if (numStr[i].ToString().IndexOf("+") == -1 && numStr[i].ToString().IndexOf("-") == -1)
616                 {
617                     newNumStr.Add(numStr[i].ToString() + "*" + num2Str);//A*B
618                 }
619                 else
620                 {
621                     newNumStr.Add("(" + numStr[i].ToString() + ")" + "*" + num2Str);//(A+B)*C
622                 }
623                 #endregion
624 
625                 #region 除法的情况
626                 if (num1 > num2)
627                 {
628                     if (num2 != 0 && num1 % num2 == 0)//除数不为0,而且两数相除余数要为0,也就是要能整除
629                     {
630                         temp = num1 / num2;
631                         newNum.Add(temp.ToString());
632                         if (numStr[i].ToString().IndexOf("+") == -1 && numStr[i].ToString().IndexOf("-") == -1)
633                         {
634                             newNumStr.Add(numStr[i].ToString() + "/" + num2Str);//A/B
635                         }
636                         else
637                         {
638                             newNumStr.Add("(" + numStr[i].ToString() + ")" + "/" + num2Str);//(A+B)/C
639                         }
640                     }
641                 }
642                 else
643                 {
644                     if (num1 != 0 && num2 % num1 == 0)
645                     {
646                         temp = num2 / num1;
647                         newNum.Add(temp.ToString());
648                         if (numStr[i].ToString().IndexOf("+") == -1 && numStr[i].ToString().IndexOf("-") == -1)
649                         {
650                             newNumStr.Add(num2Str + "/" + numStr[i].ToString());
651                         }
652                         else
653                         {
654                             newNumStr.Add(num2Str + "/" + "(" + numStr[i].ToString() + ")");
655                         }
656                     }
657                 }
658                 #endregion
659             }
660             //要返回的集合结果
661             num = newNum;
662             numStr = newNumStr;
663         }
664 
665         //3、用数值表达式替换字符串表达式的方法,此方法的核心思想是,一个一个字符替换为对应的数值
666         private object replaceString(string ExpressionStr, char NumStr, int Num)
667         {
668             //参数(字符表达式=(A-B)*C+D,'字符'=A,数值=5)=>数值表达式=(13-12)*8+3
669             int loc = ExpressionStr.IndexOf(NumStr);
670             string first = ExpressionStr.Substring(0, loc);
671             ExpressionStr = first + Convert.ToInt16(Num) + ExpressionStr.Substring(loc + 1);
672             return ExpressionStr;
673         }
674 
675         #endregion
676 
677         //点击下一轮按钮
678         private void btnNext_Click(object sender, EventArgs e)
679         {
680             #region 点击下一轮按钮更新初始化数据
681             btnAdd.Enabled = true;
682             btnMinus.Enabled = true;
683             btnDivide.Enabled = true;
684             btnMulti.Enabled = true;
685             btnNumber1.Enabled = true;
686             btnNumber2.Enabled = true;
687             btnNumber3.Enabled = true;
688             btnNumber4.Enabled = true;
689             btnDelete.Enabled = true;
690             btnClear.Enabled = true;
691             btnLeft.Enabled = true;
692             btnRight.Enabled = true;
693             btnEnter.Enabled = true;
694             lblInput.Text = "";
695             txtAnswer.Text = "";
696             lblResult.Visible = false;
697             lblShowTime.Text = "";
698             timer1.Enabled = true;
699             beginTime = DateTime.Now;
700             #endregion
701 
702             int imageNum;
703             string path;
704             //画第一张牌
705             if (topCard >= 52)
706             {
707                 MessageBox.Show("恭喜你已算完整副牌,开始新的一副牌。");
708                 topCard = 0;
709                 Shuffle();//洗牌
710             }
711             topCard = topCard + 1;
712             imageNum = PlayingCards[topCard].suit + (PlayingCards[topCard].face - 1) * 4;
713             path = Directory.GetCurrentDirectory() + @"\images\" + imageNum.ToString() + ".bmp";
714             pictureBox1.Image = Image.FromFile(path);
715             NumberA = Convert.ToInt32(PlayingCards[topCard].face);
716             btnNumber1.Text = NumberA.ToString();
717             //画第二张牌
718             if (topCard >= 52)
719             {
720                 MessageBox.Show("恭喜你已算完整副牌,开始新的一副牌。");
721                 topCard = 0;
722                 Shuffle();
723             }
724             topCard = topCard + 1;
725             imageNum = PlayingCards[topCard].suit + (PlayingCards[topCard].face - 1) * 4;
726             path = Directory.GetCurrentDirectory() + @"\images\" + imageNum.ToString() + ".bmp";
727             pictureBox2.Image = Image.FromFile(path);
728             NumberB = Convert.ToInt32(PlayingCards[topCard].face);
729             btnNumber2.Text = NumberB.ToString();
730             //画第三张牌
731             if (topCard >= 52)
732             {
733                 MessageBox.Show("恭喜你已算完整副牌,开始新的一副牌。");
734                 topCard = 0;
735                 Shuffle();
736             }
737             topCard = topCard + 1;
738             imageNum = PlayingCards[topCard].suit + (PlayingCards[topCard].face - 1) * 4;
739             path = Directory.GetCurrentDirectory() + @"\images\" + imageNum.ToString() + ".bmp";
740             pictureBox3.Image = Image.FromFile(path);
741             NumberC = Convert.ToInt32(PlayingCards[topCard].face);
742             btnNumber3.Text = NumberC.ToString();
743             //画第四张牌
744             if (topCard >= 52)
745             {
746                 MessageBox.Show("恭喜你已算完整副牌,开始新的一副牌。");
747                 topCard = 0;
748                 Shuffle();
749             }
750             topCard = topCard + 1;
751             imageNum = PlayingCards[topCard].suit + (PlayingCards[topCard].face - 1) * 4;
752             path = Directory.GetCurrentDirectory() + @"\images\" + imageNum.ToString() + ".bmp";
753             pictureBox4.Image = Image.FromFile(path);
754             NumberD = Convert.ToInt32(PlayingCards[topCard].face);
755             btnNumber4.Text = NumberD.ToString();
756         }
757 
758         //计时器
759         private void timer1_Tick(object sender, EventArgs e)
760         {
761             TimeSpan ts = DateTime.Now - beginTime;
762             lblShowTime.Text = "用时:" + ts.Minutes + "分" + ts.Seconds.ToString() + "秒";
763             if (ts.Seconds == 30|ts.Seconds==59)
764             {
765                 MessageBox.Show("我等到花儿都谢了,怎么还没算出来呀,需要帮助的话就点击查看答案哦!!!", "时间警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
766                 lblShowTime.ForeColor = Color.Red;
767             }
768         }
769     }
770 }

三、示例下载

GitHub:https://github.com/SeeYouBug2/twenty-four-Algorithm-Game.git

总结:前段时间因为闲着无聊,于是乎,就想了一下,必须找点事情来做。于是在上网浏览网页时不经意间看到了这个24点算法小游戏,然后就玩了一下,突然发现有种找回童年的感觉,因为本人童年的时候很喜欢玩24点算法游戏,对它非常感兴趣,在家的时候就喜欢跟我大嫂和我表弟一起玩24点算法游戏,在学校就和同学一起玩,玩的还很happy,所以我玩24点算法游戏还是玩的挺多的,于是脑子里就蹦出来这样一个想法,这个24点算法游戏它是如何实现的呢?自己能否也做一个出来呢?顺着这个想法我就上网查找了一些资料,然后就开始着手做了起来,整了半天,终于把它给整完了。总结一下这个24点游戏的核心内容就是使用到了递归算法和验证表达式等相关知识。啰嗦了那么多最后我总结分享一句话给大家:“兴趣是你的最好老师,不管做任何事情,你都要寻找自己的兴趣点,跟着自己的兴趣走,你会学的更好,学的更深,学编程也不例外”。

分享到:0
关注微信,跟着我们扩展技术视野。每天推送IT新技术文章,每周聚焦一门新技术。微信二维码如下:
微信公众账号:尚学堂(微信号:bjsxt-java)
北京总部地址:北京市海淀区西三旗桥东建材城西路85号神州科技园B座三层尚学堂 咨询电话:400-009-1906 010-56233821
Copyright 2007-2015 北京尚学堂科技有限公司 京ICP备13018289号-1 京公网安备11010802015183