中國象棋的中國棋文化,也是中華民族的文化瑰寶,它源遠流長,趣味濃厚,基本規則簡明易懂。中國象棋在中國的群眾中基礎遠遠超過圍棋,是普及最廣的棋類項目,中國象棋已流傳到十幾個國家和地區。 中國象棋使用方形格狀棋盤,圓形棋子共有32個,紅黑二色各有16個棋子,擺放和活動在交叉點上。雙方交替行棋,先把對方的將(帥)“將死”的一方獲勝。
我們今天就來看看我們自己能不能寫出這樣一個游戲呢?
今天就不話不多說了,先說一下,今天我們做的是一個簡易版的單機中國象棋,希望大家理解,聯網對弈的話需要用到的知識過多,數據庫以及網絡協議這些大部分同學都沒有學,所以我們今天就簡單的實現《中國象棋》的簡單對弈,主要是希望同學們可以理解其中的邏輯關系,之后就可以更好的去完善
行吧,我們現在就開始吧!!!
今天先出場的就不是我們的老朋友結構體了,而是我們的新朋友枚舉類型
1
2
3
4
5
6
7
8
9
10
11
12
|
enum Pieces //棋子 { NONE = -1, 車, 馬, 象, 士, 將, 砲, 卒, 俥, 馬, 相, 仕, 帥, 炮, 兵, BEGIN, END, }; //給id賦值 enum Pieces redChess[] = { 車, 馬, 象, 士, 將, 砲, 卒 }; enum Pieces blackChess[] = { 俥, 馬, 相, 仕, 帥, 炮, 兵 }; //繪制時轉化成字符串 const char * ChessName[] = { "車" , "馬" , "象" , "士" , "將" , "砲" , "卒" , "俥" , "馬" , "相" , "仕" , "帥" , "炮" , "兵" }; |
接下來出場的是我們的老朋友結構體
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
//每一個棋子的屬性 struct Chess { enum Pieces id; //棋子名稱 DWORD type; //棋子類型,紅?黑? short x; short y; bool isRiver; //是否過了河 }; //游戲地圖 struct Chess map[ROW][COL]; struct State { int begr; int begc; int endr; int endc; int state; }state = {-1,-1,-1,-1,BEGIN}; |
我們的初始化函數,一定要想好其中的邏輯
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
//初始化數據 void init() { //遍歷地圖 for ( size_t i = 0; i < ROW; i++) { size_t temp = 0; for ( size_t k = 0; k < COL; k++) { map[i][k].id = NONE; //先把棋子置為沒有 if (i <= 4) //黑棋子 { map[i][k].type = BLACK; if (i == 0) //放置第一行的棋子 { //0 1 2 3 4 if (k <= 4) { temp = k; } // 3 2 1 0 else { // k == 5 temp = 4 - (k - 4); /* 4 - (5-4) //3 4 - (6-4) //2 4 - (7-4) //1 4 - (8-4) //0 */ } map[i][k].id = blackChess[temp]; } //設置炮 if (i == 2 && (k == 1 || k == 7)) { map[i][k].id = blackChess[5]; } //設置兵 if (i == 3 && k % 2 == 0) { map[i][k].id = blackChess[6]; } } else //紅棋 { map[i][k].type = RED; if (i == 9) //放置第一行的棋子 { //0 1 2 3 4 if (k <= 4) { temp = k; } // 3 2 1 0 else { // k == 5 temp = 4 - (k - 4); /* 4 - (5-4) //3 4 - (6-4) //2 4 - (7-4) //1 4 - (8-4) //0 */ } map[i][k].id = redChess[temp]; } //設置炮 if (i == 7 && (k == 1 || k == 7)) { map[i][k].id = redChess[5]; } //設置兵 if (i == 6 && k % 2 == 0) { map[i][k].id = redChess[6]; } } map[i][k].isRiver = false ; map[i][k].x = k * GRID_SIZE + INTERVAL; map[i][k].y = i * GRID_SIZE + INTERVAL; } } } |
接下來是我們的繪制函數
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
//繪制 void draw() { setfillcolor(RGB(252, 215, 162)); setlinestyle(PS_SOLID, 2); //設置文字的樣式 settextstyle(30, 0, "楷體" ); for ( size_t i = 0; i < ROW; i++) { for ( size_t k = 0; k < COL; k++) { if (map[i][k].id == NONE) continue ; settextcolor(map[i][k].type); setlinecolor(map[i][k].type); //繪制棋子 fillcircle(map[i][k].x, map[i][k].y, 30); fillcircle(map[i][k].x, map[i][k].y, 25); outtextxy(map[i][k].x - 15, map[i][k].y - 15, ChessName[map[i][k].id]); } } } |
后面是我們的重點,鼠標控制函數,以后類似的游戲項目都會有這樣的函數,好好理解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
//鼠標操作 void mouseEvent() { ExMessage msg; //定義消息結構體變量 if (peekmessage(&msg, EM_MOUSE)) { if (msg.message == WM_LBUTTONDOWN) //鼠標左鍵按下 { //通過鼠標坐標得出點擊的數組的下標 //k * GRID_SIZE + INTERVAL = x; int col = (msg.x - INTERVAL) / GRID_SIZE; int row = (msg.y - INTERVAL) / GRID_SIZE; //下標校準 if (msg.x > map[row][col].x + 30 && msg.y < map[row][col].y + 30) { col++; } if (msg.x < map[row][col].x + 30 && msg.y > map[row][col].y + 30) { row++; } if (msg.x > map[row][col].x + 30 && msg.y > map[row][col].y + 30) { row++; col++; } //printf("(%d %d)\n", row, col); if (state.state == BEGIN) { state.begr = row; state.begc = col; state.state = END; } else if (state.state == END) { state.endr = row; state.endc = col; state.state = BEGIN; } chessMove(); } } } |
重點中的重點,棋子的移動函數,游戲的規則也就在這里體現出來
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
//移動棋子 void chessMove() { printf ( "beg(%d %d) end(%d %d)\n" , state.begr, state.begc, state.endr, state.endc); bool canMove = false ; //什么情況下能夠移動棋子 if (!(state.begr == state.endr && state.begc == state.endc) && //點擊的不是同一個棋子 state.endr!=-1 && state.begr!=-1&& //下標必須合法 map[state.begr][state.begc].id != NONE //沒有棋子不能移動 /*&&map[state.begr][state.begc].type != map[state.endr][state.endc].type*/ ) //不能自己吃自己 { switch (map[state.begr][state.begc].id) { case 車: case 俥: if (state.begr == state.endr || state.begc == state.endc) { //起始點和結束點之間是否有阻礙 if (hasBlock(&state)) { canMove = true ; } } break ; case 馬: case 馬: break ; case 象: case 相: break ; case 士: case 仕: break ; case 將: case 帥: break ; case 砲: case 炮: break ; case 卒: case 兵: break ; default : break ; } if (canMove) { printf ( "canMove\n" ); map[state.endr][state.endc].id = map[state.begr][state.begc].id; map[state.begr][state.begc].id = NONE; map[state.endr][state.endc].isRiver = map[state.begr][state.begc].isRiver; map[state.endr][state.endc].type = map[state.begr][state.begc].type; } } } |
最后就是我們的主函數,進行調用,讓項目運行起來
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
int main() { //創建圖形窗口 initgraph(740, 820,EW_SHOWCONSOLE); //設置背景模式 setbkmode(TRANSPARENT); //貼棋盤 IMAGE img_board; loadimage(&img_board, "./res/ChessBoard.png" ); init(); //雙緩沖繪圖,防止閃屏 BeginBatchDraw(); while ( true ) { cleardevice(); putimage(0, 0, &img_board); draw(); mouseEvent(); FlushBatchDraw(); } EndBatchDraw(); getchar (); return 0; } |
這樣一個簡易版的《中國象棋》游戲項目就解決啦,重點就是邏輯,一定要想清楚,想要實現聯網的同學就要更加的去想清楚,以及去提高自己的能力,好啦,希望可以讓大家從中感受到編程的快樂吧,也希望大家可以給UP主一個關注,非常感謝大家了!!!
到此這篇關于C++ 中國象棋的實現流程詳解的文章就介紹到這了,更多相關C++ 中國象棋內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://blog.csdn.net/weixin_45713725/article/details/121161188