一、24點游戲玩法規則效果展示 1、初始化界面 2、開始游戲界面 3、游戲超時界面 4、查看答案界面 5、答對界面 6、答錯界面 7、計算表達式的驗證界面 8、一副牌算完開始新一副牌界面 到這裡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