生活随笔
收集整理的這篇文章主要介紹了
[C++] 井字棋游戏源码
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
?
TicTac.h
1 #define EX 1
//該點左鼠標
2 #define OH 2
//該點右鼠標
3
4 class CMyApp :
public CWinApp
5 {
6 public:
7 virtual BOOL InitInstance ();
8 };
9
10 class CMainWindow :
public CWnd
//不是繼承CFrameWnd 因此需要在CMainWindow()自己定義窗口類了
11 {
12 protected:
13 static const CRect m_rcSquares[
9];
// Grid coordinates
14 int m_nGameGrid[
9];
// 9個格子的狀態(tài)是否被下0沒下;1左下了;2右下了
15 int m_nNextChar;
// 下一個鼠標狀態(tài)左or右 (EX or OH)
16 bool ptab[
9][
8];
//玩家的獲勝的狀態(tài)表
17 bool ctab[
9][
8];
//電腦的獲勝的狀態(tài)表
18 int win[
2][
8];
//每種狀態(tài)表里的棋子數(shù)
19
20 int GetRectID (CPoint point);
21 void DrawBoard (CDC*
pDC);
22 void DrawX (CDC* pDC,
int nPos);
23 void DrawO (CDC* pDC,
int nPos);
24 void CpDraw(CDC*
pDC);
25 void InitGame();
26 void out();
27 void ResetGame ();
28 bool CheckForGameOver ();
29 int IsWinner ();
30 BOOL IsDraw ();
31
32 public:
33 CMainWindow ();
34
35 protected:
36 virtual void PostNcDestroy ();
//在程序終止之前銷毀CMainWindow對象
37
38 afx_msg
void OnPaint ();
39 afx_msg
void OnLButtonDown (UINT nFlags, CPoint point);
40 afx_msg
void OnLButtonDblClk (UINT nFlags, CPoint point);
41 afx_msg
void OnRButtonDown (UINT nFlags, CPoint point);
42
43 DECLARE_MESSAGE_MAP ()
44 };
TicTac.cpp
1 #include <afxwin.h>
2 #include
"TicTac.h"
3 #include <fstream>
4 #include <iostream>
5 #include<iomanip>
6 using namespace std;
7 CMyApp myApp;
8 /*ofstream Cout("out.txt");
9 void CMainWindow::out(){
10 Cout<<"ptab[][]=:\n";
11 for(int i=0;i<9;i++){
12 for(int j=0;j<8;j++)
13 Cout<<setw(3)<<ptab[i][j]<<' ';
14 Cout<<'\n';
15 }
16 Cout<<"ctab[][]=:\n";
17 for(int i=0;i<9;i++){
18 for(int j=0;j<8;j++)
19 Cout<<setw(3)<<ctab[i][j]<<' ';
20 Cout<<'\n';
21 }
22 Cout<<"win[][]=:\n";
23 for(int i=0;i<2;i++){
24 for(int j=0;j<8;j++)
25 Cout<<setw(3)<<win[i][j]<<' ';
26 Cout<<'\n';
27 }
28 }*/
29 /
30 // CMyApp member functions
31
32 BOOL CMyApp::InitInstance ()
33 {
34 m_pMainWnd =
new CMainWindow;
35 m_pMainWnd->
ShowWindow (m_nCmdShow);
36 m_pMainWnd->
UpdateWindow ();
37 return TRUE;
38 }
39
40 /
41 // CMainWindow message map and member functions
42
43 BEGIN_MESSAGE_MAP (CMainWindow, CWnd)
44 ON_WM_PAINT ()
45 ON_WM_LBUTTONDOWN ()
46 ON_WM_LBUTTONDBLCLK ()
47 ON_WM_RBUTTONDOWN ()
48 END_MESSAGE_MAP ()
49
50 //9個矩形區(qū)域用來判定鼠標是否點進某一區(qū)域
51 const CRect CMainWindow::m_rcSquares[
9] =
{
52 CRect (
16,
16,
112,
112),
53 CRect (
128,
16,
224,
112),
54 CRect (
240,
16,
336,
112),
55 CRect (
16,
128,
112,
224),
56 CRect (
128,
128,
224,
224),
57 CRect (
240,
128,
336,
224),
58 CRect (
16,
240,
112,
336),
59 CRect (
128,
240,
224,
336),
60 CRect (
240,
240,
336,
336)
61 };
62
63 CMainWindow::CMainWindow ()
64 {
65 //初始化游戲
66 InitGame();
67
68
69
70 //注冊一個 WNDCLASS 窗口類.
71 CString strWndClass =
AfxRegisterWndClass (
72 CS_DBLCLKS,
// Class style(有雙擊時間發(fā)生的窗口類型)
73 AfxGetApp ()->LoadStandardCursor (IDC_ARROW),
// Class cursor(加載一個系統(tǒng)光標,也可自己定義)
74 (HBRUSH) (COLOR_3DFACE +
1),
// Background brush(每次::BeginPaint時用它清空客戶區(qū));COLOR_3DFACE+1是指定窗口具有與按鈕對話框一致的背景色和其他一些3D屬性;默認為灰亮色
75 AfxGetApp ()->LoadStandardIcon (IDI_WINLOGO)
// Class icon(加載系統(tǒng)圖標,也可自己定義)
76 );
77
78 //調(diào)用CWnd::CreateEx()創(chuàng)建主窗口
79 //第一個參數(shù)表示0個或是多個WS_EX標志組合;2:AfxRegisterWndClass()返回的WNDCLASS名稱;
80 //3、標題;4、窗口樣式
81 CreateEx (
0, strWndClass, _T (
"井字棋"),
82 WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX,
//WS_THICKFRAME窗口可調(diào)大小屬性(這里不用)
83 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
//初始位置和大小,這里用CW_USEDEFAULT讓W(xué)indows拾取窗口和大小
84 NULL, NULL);
85
86 //處理窗口位置和尺寸
87 CRect rect (
0,
0,
352,
352);
//理想客戶區(qū)窗口矩形形狀
88 CalcWindowRect (&rect);
//根據(jù)分辨率、菜單...計算窗口矩形大小(必須在窗口創(chuàng)建后調(diào)用)
89
90 SetWindowPos (NULL,
0,
0, rect.Width (), rect.Height (),
91 SWP_NOZORDER | SWP_NOMOVE |
SWP_NOREDRAW);
92 }
93
94 //在程序結(jié)束之前銷毀創(chuàng)建的CMainWindow對象
95 void CMainWindow::PostNcDestroy ()
96 {
97 delete
this;
98 }
99
100 //OnPaint()響應(yīng)每次重繪棋盤
101 void CMainWindow::OnPaint ()
102 {
103 CPaintDC dc (
this);
104 DrawBoard (&
dc);
105 }
106
107
108 //單擊鼠標左鍵響應(yīng)
109 void CMainWindow::OnLButtonDown (UINT nFlags, CPoint point)
110 {
111 CClientDC dc (
this);
112
113 //如果不該左鍵響應(yīng)(即不該左鍵下,返回)
114 if (m_nNextChar !=
EX){
115 return ;
116 }
117
118 //獲得點擊矩形區(qū)域編號
119 //如果沒有點中或者已經(jīng)被下棋了,返回
120 int nPos =
GetRectID (point);
121 if ((nPos == -
1) || (m_nGameGrid[nPos] !=
0))
122 return;
123
124 //標記已下并改變下一個點擊狀態(tài)
125 m_nGameGrid[nPos] =
EX;
126 m_nNextChar =
OH;
127
128 //畫上圖并判斷游戲是否結(jié)束
129 DrawX (&
dc, nPos);
130 if(CheckForGameOver ())
return;
131
132 //后續(xù)改變勝利表和各人、機各勝利組合的棋子數(shù)
133 for(
int i=
0;i<
8;i++
){
134 if(ptab[nPos][i]){
135 win[
0][i]++
;
136 ctab[nPos][i]=
false;
137 win[
1][i]=
5;
138 }
139 }
140
141 //電腦下棋
142 CpDraw(&
dc);
143 if(CheckForGameOver ())
return;
144 }
145
146 //單擊鼠標右鍵響應(yīng)(同左鍵)
147 void CMainWindow::OnRButtonDown (UINT nFlags, CPoint point)
148 {
149 if (m_nNextChar !=
OH)
150 return;
151
152 int nPos =
GetRectID (point);
153 if ((nPos == -
1) || (m_nGameGrid[nPos] !=
0))
154 return;
155
156 m_nGameGrid[nPos] =
OH;
157 m_nNextChar =
EX;
158
159 CClientDC dc (
this);
160 DrawO (&
dc, nPos);
161 CheckForGameOver ();
162 }
163
164 //左鍵雙擊邊框重新開始
165 //dc.GetPixel (Point point)獲取當前光標下像素顏色判斷與黑色匹配
166 void CMainWindow::OnLButtonDblClk (UINT nFlags, CPoint point)
167 {
168 CClientDC dc (
this);
169 if (dc.GetPixel (point) == RGB (
0,
0,
0))
170 ResetGame ();
171 }
172
173 //判定鼠標是否點進矩形某一區(qū)域,點進返回區(qū)域編號,沒有返回-1
174 //此處用了一個rect.PtInRect(Point point)函數(shù)幫助判定
175 int CMainWindow::GetRectID (CPoint point)
176 {
177 for (
int i=
0; i<
9; i++
) {
178 if (m_rcSquares[i].PtInRect (point))
179 return i;
180 }
181 return -
1;
182 }
183
184 //畫上棋盤并畫上圈和叉
185 void CMainWindow::DrawBoard (CDC*
pDC)
186 {
187 //畫上棋盤
188 CPen pen (PS_SOLID,
16, RGB (
0,
0,
0));
189 CPen* pOldPen = pDC->SelectObject (&
pen);
190
191 pDC->MoveTo (
120,
16);
192 pDC->LineTo (
120,
336);
193
194 pDC->MoveTo (
232,
16);
195 pDC->LineTo (
232,
336);
196
197 pDC->MoveTo (
16,
120);
198 pDC->LineTo (
336,
120);
199
200 pDC->MoveTo (
16,
232);
201 pDC->LineTo (
336,
232);
202
203 //畫上叉和圈
204 for (
int i=
0; i<
9; i++
) {
205 if (m_nGameGrid[i] ==
EX)
206 DrawX (pDC, i);
207 else if (m_nGameGrid[i] ==
OH)
208 DrawO (pDC, i);
209 }
210 pDC->
SelectObject (pOldPen);
211 }
212
213 //畫叉函數(shù)
214 void CMainWindow::DrawX (CDC* pDC,
int nPos)
215 {
216 CPen pen (PS_SOLID,
16, RGB (
255,
0,
0));
//寬為16像素的紅筆
217 CPen* pOldPen = pDC->SelectObject (&
pen);
218
219 CRect rect =
m_rcSquares[nPos];
220 rect.DeflateRect (
16,
16);
//把矩形每個方向都縮進16個像素作為線條邊框
221 pDC->
MoveTo (rect.left, rect.top);
222 pDC->
LineTo (rect.right, rect.bottom);
223 pDC->
MoveTo (rect.left, rect.bottom);
224 pDC->
LineTo (rect.right, rect.top);
225
226 pDC->
SelectObject (pOldPen);
227 }
228
229 //畫圈函數(shù)
230 void CMainWindow::DrawO (CDC* pDC,
int nPos)
231 {
232 CPen pen (PS_SOLID,
16, RGB (
0,
0,
255));
//寬為16像素的紅筆
233 CPen* pOldPen = pDC->SelectObject (&
pen);
234 pDC->SelectStockObject (NULL_BRUSH);
//空畫刷是為了防止畫出的圓內(nèi)部出現(xiàn)白色遮住背景
235
236 CRect rect =
m_rcSquares[nPos];
237 rect.DeflateRect (
16,
16);
//把矩形每個方向都縮進16個像素作為圓的邊框
238 pDC->
Ellipse (rect);
239
240 pDC->
SelectObject (pOldPen);
241 }
242
243 //電腦畫圖
244 void CMainWindow::CpDraw(CDC*
pDC)
245 {
246 int grades[
2][
9];
247 int m,i,max=
0;
248 int u;
249
250 for(m=
0;m<
9;m++
)
251 {
252 grades[
0][m]=
0;
253 grades[
1][m]=
0;
254
255 if(m_nGameGrid[m]==
0)
256 {
257 for(i=
0;i<
8;i++
)
258 {
259 //計算玩家在空棋格上的獲勝分數(shù)
260 if(ptab[m][i] && win[
0][i]!=
5)
261 {
262 switch(win[
0][i])
263 {
264 case 0:
265 grades[
0][m]+=
1;
266 break;
267 case 1:
268 grades[
0][m]+=
2000;
269 break;
270 case 2:
271 grades[
0][m]+=
10000;
272 break;
273 }
274 }
275
276 //計算計算機在空格上的獲勝分數(shù)
277 if(ctab[m][i] && win[
1][i]!=
5)
278 {
279 switch(win[
1][i])
280 {
281 case 0:
282 grades[
1][m]+=
1;
283 break;
284 case 1:
285 grades[
1][m]+=
2001;
286 break;
287 case 2:
288 grades[
1][m]+=
10001;
289 break;
290 }
291 }
292 }
293
294 if(max==
0)u=
m;
295
296 if(grades[
0][m]>
max){
297 max=grades[
0][m];
298 u=
m;
299 }
300 else if(grades[
0][m]==
max){
301 if(grades[
1][m]>grades[
1][u])u=
m;
302 }
303
304 if(grades[
1][m]>
max){
305 max=grades[
1][m];
306 u=
m;
307 }
308 else if(grades[
1][m]==
max){
309 if(grades[
0][m]>grades[
0][u])u=
m;
310 }
311 }
312 }
313
314 //標記已下并改變下一個點擊狀態(tài)
315 m_nGameGrid[u]=
OH;
316 m_nNextChar =
EX;
317
318 //畫上圖
319 DrawO(pDC,u);
320
321 //后續(xù)改變勝利表和各人、機各勝利組合的棋子數(shù)
322 for(i=
0;i<
8;i++
){
323 if(ctab[u][i]){
324 win[
1][i]++
;
325 ptab[u][i]=
false;
326 win[
0][i]=
5;
327 }
328 }
329 }
330
331 //響應(yīng)勝利結(jié)束的函數(shù)
332 bool CMainWindow::CheckForGameOver ()
333 {
334 int nWinner;
335
336 //通過調(diào)用IsWinner ()函數(shù)獲取誰獲勝;并用MessageBox輸出勝利消息;響應(yīng)OK后重開一局
337 //==Message(CString,_T(標題),類型)
338 if (nWinner =
IsWinner ()) {
339 CString
string = (nWinner == EX) ?
340 _T (
"X wins!") : _T (
"O wins!");
341 MessageBox (
string, _T (
"Game Over"), MB_ICONEXCLAMATION |
MB_OK);
342 ResetGame ();
343 return 1;
344 }
345
346 //通過IsDraw ()函數(shù)判斷是否平局
347 else if (IsDraw ()) {
348 MessageBox (_T (
"It's a draw!"), _T (
"Game Over"),
349 MB_ICONEXCLAMATION |
MB_OK);
350 ResetGame ();
351 return 1;
352 }
353 return 0;
354 }
355
356 //判斷輸贏EX左勝;OH右勝;0沒有勝
357 int CMainWindow::IsWinner ()
358 {
359 //用靜態(tài)數(shù)組存儲獲勝組合
360 static int nPattern[
8][
3] =
{
361 0,
1,
2,
362 3,
4,
5,
363 6,
7,
8,
364 0,
3,
6,
365 1,
4,
7,
366 2,
5,
8,
367 0,
4,
8,
368 2,
4,
6
369 };
370
371 for (
int i=
0; i<
8; i++
) {
372 if ((m_nGameGrid[nPattern[i][
0]] == EX) &&
373 (m_nGameGrid[nPattern[i][
1]] == EX) &&
374 (m_nGameGrid[nPattern[i][
2]] ==
EX))
375 return EX;
376
377 if ((m_nGameGrid[nPattern[i][
0]] == OH) &&
378 (m_nGameGrid[nPattern[i][
1]] == OH) &&
379 (m_nGameGrid[nPattern[i][
2]] ==
OH))
380 return OH;
381 }
382 return 0;
383 }
384
385 //判斷是否平局函數(shù)
386 BOOL CMainWindow::IsDraw ()
387 {
388 for (
int i=
0; i<
9; i++
) {
389 if (m_nGameGrid[i] ==
0)
390 return FALSE;
391 }
392 return TRUE;
393 }
394
395 //初始化游戲
396 void CMainWindow::InitGame()
397 {
398
399 int i,k;
400 int count=
0;
401
402 //設(shè)定玩家與計算機在各個獲勝組合中的棋子數(shù)
403 for(i=
0;i<
8;i++
)
404 {
405 win[
0][i]=
0;
406 win[
1][i]=
0;
407 }
408
409 //初始化棋盤狀態(tài)
410 ::ZeroMemory (m_nGameGrid,
9*
sizeof(
int));
411 memset(ctab,
0,
sizeof(ctab));
412 memset(ptab,
0,
sizeof(ptab));
413 //設(shè)定水平方向的獲勝組合
414 for(i=
0;i<=
6;i+=
3)
415 {
416 for(k=
0;k<
3;k++)
//3個棋子1個獲勝組合
417 {
418 ptab[i+k][count]=
true;
419 ctab[i+k][count]=
true;
420 }
421 count++
;
422 }
423
424 //設(shè)定垂直方向的獲勝組合
425 for(k=
0;k<
3;k++
)
426 {
427 for(i=
0;i<=
6;i+=
3)
//3個棋子1個獲勝組合
428 {
429 ptab[i+k][count]=
true;
430 ctab[i+k][count]=
true;
431 }
432 count++
;
433 }
434
435
436 //設(shè)定對角線方向上的獲勝組合
437 for(i=
2;i<=
6;i+=
2){
438 ptab[i][count]=
true;
439 ctab[i][count]=
true;
440 }count++
;
441 for(i=
0;i<=
8;i+=
4){
442 ptab[i][count]=
true;
443 ctab[i][count]=
true;
444 }
445
446
447 srand(unsigned(time(NULL)));
448
449 m_nNextChar = EX;
//玩家先走
450 }
451 //重新開始初始化
452 void CMainWindow::ResetGame ()
453 {
454 InitGame();
455 Invalidate ();
//使控件的整個圖面無效并導(dǎo)致重繪控件
456 }
人機對戰(zhàn)井字棋
?
總結(jié)
以上是生活随笔為你收集整理的[C++] 井字棋游戏源码的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。