【趣味分享】C#實現回味童年的24點算法游戲,
一、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 }
View Code
三、示例下載
GitHub:https://github.com/SeeYouBug2/twenty-four-Algorithm-Game.git
總結:前段時間因為閒著無聊,於是乎,就想了一下,必須找點事情來做。於是在上網浏覽網頁時不經意間看到了這個24點算法小游戲,然後就玩了一下,突然發現有種找回童年的感覺,因為本人童年的時候很喜歡玩24點算法游戲,對它非常感興趣,在家的時候就喜歡跟我大嫂和我表弟一起玩24點算法游戲,在學校就和同學一起玩,玩的還很happy,所以我玩24點算法游戲還是玩的挺多的,於是腦子裡就蹦出來這樣一個想法,這個24點算法游戲它是如何實現的呢?自己能否也做一個出來呢?順著這個想法我就上網查找了一些資料,然後就開始著手做了起來,整了半天,終於把它給整完了。總結一下這個24點游戲的核心內容就是使用到了遞歸算法和驗證表達式等相關知識。啰嗦了那麼多最後我總結分享一句話給大家:“興趣是你的最好老師,不管做任何事情,你都要尋找自己的興趣點,跟著自己的興趣走,你會學的更好,學的更深,學編程也不例外”。