C++小程序之五子棋
1)运行的环境:VS2015。
2)目的:主要是在控制台实现简单的五子棋操作,黑棋先行,输入xy(坐标)即表示落子。代码如下:
1 #include <iostream> 2 #include <conio.h> 3 #include <string> 4 5 using namespace std; 6 char board[16][16], o; 7 8 //此函数是存储一个棋盘矩阵16*16,注意board是全局变量,所以没有返回 9 void init() { 10 for (int i = 1; i <= 31; i++) 11 for (int j = 1; j <= 31; j++) 12 board[i][j] = '+'; 13 for (int i = 1, ii = 0; ii <= 30; i++, ii += 2) board[0][i] = i + 64; // A的ascll码对应65 14 for (int j = 1, jj = 0; jj <= 30; j++, jj += 2) board[j][0] = j + 64; 15 board[0][0] = '*'; 16 //// 调试 17 //for (int i = 0; i < 16; ++i) { 18 // for (int j = 0; j < 16; ++j) cout << board[i][j] << " "; 19 // cout << endl; 20 //} 21 22 } 23 24 // 打印棋盘状态,其实就是打印全局变量board,+是棋子放置的中心点 25 void display() { 26 cout << "|================================================|" << endl; 27 for (int i = 0; i <= 15; i++) { 28 cout << "|"; 29 for (int j = 0; j <= 15; j++) { 30 cout << board[i][j]; 31 if (j != 15 && i != 0) cout << "--"; 32 else cout << " "; 33 } 34 cout << "|" << endl << "| | | | | | | | | | | | | | | | |" << endl; 35 } 36 cout << "|================================================|" << endl; 37 } 38 39 /* 40 此函数是放置棋子。 41 先确定是何种颜色的棋子,然后根据输入的放置位置(行,列),判断是否是非法放置。 42 若是非法放置,重新放置,回掉;否则修改board,将对应位置的+变字母。 43 color:0代表黑棋,1代表白色。 44 */ 45 void place(bool color) { 46 string colour; 47 char x, y; // x是行,y是列数 48 x = y = ' '; 49 system("cls"); 50 display(); 51 if (!color) colour = "黑"; 52 if (color) colour = "白"; 53 cout << colour << "方放置棋子,请输入棋子的行和列(大写字母):"; 54 cin >> x >> y; 55 if (x - 64>16 || y - 64>16 || x - 64<1 || y - 64<1) { 56 cout << "该位置超出棋盘范围,请重新放置!" << x << y << endl; 57 system("pause"); 58 place(color); 59 } 60 if (board[x - 64][y - 64] == 'b' || board[x - 64][y - 64] == 'w') { 61 cout << "该位置已有棋子" << board[x - 64][y - 64] << ",请重新放置!" << endl; 62 system("pause"); 63 place(color); 64 } 65 if (!color) board[x - 64][y - 64] = 'b'; 66 if (color) board[x - 64][y - 64] = 'w'; 67 } 68 69 // 判断输赢,返回225是和棋,0是黑方胜,1是白的胜利。 70 int compute() { 71 int num=0; // 统计棋盘上棋子的总共个数 72 for (int i = 1; i <= 15; i++) 73 for (int j = 1; j <= 15; j++) 74 if (board[i][j] == 'b' || board[i][j] == 'w') num++; 75 if (num == 225) return 2; 76 // 下面判断输赢,这段应该可以优化,存在重复判断了 77 for (int i = 1; i <= 15; i++) 78 for (int j = 1; j <= 15; j++) { 79 if (board[i][j] == 'b'&&board[i][j] == board[i + 1][j] && board[i][j] == board[i + 2][j] && board[i][j] == board[i + 3][j] && board[i][j] == board[i + 4][j]) return 0; 80 if (board[i][j] == 'w'&&board[i][j] == board[i + 1][j] && board[i][j] == board[i + 2][j] && board[i][j] == board[i + 3][j] && board[i][j] == board[i + 4][j]) return 1; 81 if (board[i][j] == 'b'&&board[i][j] == board[i][j + 1] && board[i][j] == board[i][j + 2] && board[i][j] == board[i][j + 3] && board[i][j] == board[i][j + 4]) return 0; 82 if (board[i][j] == 'w'&&board[i][j] == board[i][j + 1] && board[i][j] == board[i][j + 2] && board[i][j] == board[i][j + 3] && board[i][j] == board[i][j + 4]) return 1; 83 if (board[i][j] == 'b'&&board[i][j] == board[i + 1][j + 1] && board[i][j] == board[i + 2][j + 2] && board[i][j] == board[i + 3][j + 3] && board[i][j] == board[i + 4][j + 4]) return 0; 84 if (board[i][j] == 'w'&&board[i][j] == board[i + 1][j + 1] && board[i][j] == board[i + 2][j + 2] && board[i][j] == board[i + 3][j + 3] && board[i][j] == board[i + 4][j + 4]) return 1; 85 if (board[i][j] == 'b'&&board[i][j] == board[i - 1][j + 1] && board[i][j] == board[i - 2][j + 2] && board[i][j] == board[i - 3][j + 3] && board[i][j] == board[i - 4][j + 4]) return 0; 86 if (board[i][j] == 'w'&&board[i][j] == board[i - 1][j + 1] && board[i][j] == board[i - 2][j + 2] && board[i][j] == board[i - 3][j + 3] && board[i][j] == board[i - 4][j + 4]) return 1; 87 } 88 return -1; 89 } 90 int main() { 91 game_start: 92 init(); 93 system("cls"); // system()函数是发出一条DOS命令,“cls”应该是清空的意思 94 system("title 双人五子棋"); // 设置CMD窗口标题 95 cout << "Copyright (C) XiyuWang 2018 All rights reserved." << endl; 96 cout << "双人五子棋小游戏" << endl; 97 cout << "小提示:棋盘中b代表黑方(black),w代表白方(white)" << endl; 98 cout << "请按任意键开始游戏......"; 99 _getch(); // 从控制台读取一个字符,但不显示在屏幕上。可以赋值,此函数有返回值 100 while (true) { 101 place(0); 102 if (compute() == 0) { 103 system("cls"); 104 display(); 105 cout << "黑方胜!" << endl; 106 break; 107 } 108 if (compute() == 2) { 109 system("cls"); 110 display(); 111 cout << "平局!" << endl; 112 break; 113 } 114 place(1); 115 if (compute() == 1) { 116 system("cls"); 117 display(); 118 cout << "白方胜!" << endl; 119 break; 120 } 121 if (compute() == 2) { 122 system("cls"); 123 display(); 124 cout << "平局!" << endl; 125 break; 126 } 127 } 128 cout << "再来一局?Y/N "; 129 o = _getch(); // 这里_getch()抓取控制台输入,但是控制台不显示 130 if (o == 'Y' || o == 'y') goto game_start; 131 return 0; 132 }
3)问题:
调试发现存在bug,比如:黑棋已经落在(A,A)点,此时白棋输入(A,A)后判断为非法输入,会被要求重新输入。
至此没问题,但是重新输入合法的白棋位置后,刷新显示,发现上一次错误输入的(A,A)也变成白棋。
4) 找到问题原因:
如重复放置,会进入60行判断,并进入此if。然后再这if中回调自身。接着再次输入,正确,不进入此if,一直运行到65行,并成功放置。
但是此时只是上一次错误放置进入if中的那个会调结束。因此,还会再次进入65行,并进去。就像递归。不行可以打断点调试。
5)尝试解决如下:修改重复放置的判断
将连if改为if .... else if就可以,因为回调的函数返回是在else if (重复放)里面,这个已经与下面两个是排斥的选择。
#include <iostream> #include <conio.h> #include <string> using namespace std; char board[16][16], o; //此函数是存储一个棋盘矩阵16*16,注意board是全局变量,所以没有返回 void init() { for (int i = 1; i <= 31; i++) for (int j = 1; j <= 31; j++) board[i][j] = '+'; for (int i = 1, ii = 0; ii <= 30; i++, ii += 2) board[0][i] = i + 64; // A的ascll码对应65 for (int j = 1, jj = 0; jj <= 30; j++, jj += 2) board[j][0] = j + 64; board[0][0] = '*'; //// 调试 //for (int i = 0; i < 16; ++i) { // for (int j = 0; j < 16; ++j) cout << board[i][j] << " "; // cout << endl; //} } // 打印棋盘状态,其实就是打印全局变量board,+是棋子放置的中心点 void display() { cout << "|================================================|" << endl; for (int i = 0; i <= 15; i++) { cout << "|"; for (int j = 0; j <= 15; j++) { cout << board[i][j]; if (j != 15 && i != 0) cout << "--"; else cout << " "; } cout << "|" << endl << "| | | | | | | | | | | | | | | | |" << endl; } cout << "|================================================|" << endl; } /* 此函数是放置棋子。 先确定是何种颜色的棋子,然后根据输入的放置位置(行,列),判断是否是非法放置。 若是非法放置,重新放置,回掉;否则修改board,将对应位置的+变字母。 color:0代表黑棋,1代表白色。 */ void place(bool color) { string colour; char x, y; // x是行,y是列数 x = y = ' '; system("cls"); display(); if (!color) colour = "黑"; if (color) colour = "白"; cout << colour << "方放置棋子,请输入棋子的行和列(大写字母):"; cin >> x >> y; if (x - 64>16 || y - 64>16 || x - 64<1 || y - 64<1) { cout << "该位置超出棋盘范围,请重新放置!" << x << y << endl; system("pause"); place(color); } else if (board[x - 64][y - 64] == 'b' || board[x - 64][y - 64] == 'w') { cout << "该位置已有棋子" << board[x - 64][y - 64] << ",请重新放置!" << endl; system("pause"); place(color); } else if (!color) board[x - 64][y - 64] = 'b'; else board[x - 64][y - 64] = 'w'; } // 判断输赢,返回225是和棋,0是黑方胜,1是白的胜利。 int compute() { int num=0; // 统计棋盘上棋子的总共个数 for (int i = 1; i <= 15; i++) for (int j = 1; j <= 15; j++) if (board[i][j] == 'b' || board[i][j] == 'w') num++; if (num == 225) return 2; // 下面判断输赢,这段应该可以优化,存在重复判断了 for (int i = 1; i <= 15; i++) for (int j = 1; j <= 15; j++) { if (board[i][j] == 'b'&&board[i][j] == board[i + 1][j] && board[i][j] == board[i + 2][j] && board[i][j] == board[i + 3][j] && board[i][j] == board[i + 4][j]) return 0; if (board[i][j] == 'w'&&board[i][j] == board[i + 1][j] && board[i][j] == board[i + 2][j] && board[i][j] == board[i + 3][j] && board[i][j] == board[i + 4][j]) return 1; if (board[i][j] == 'b'&&board[i][j] == board[i][j + 1] && board[i][j] == board[i][j + 2] && board[i][j] == board[i][j + 3] && board[i][j] == board[i][j + 4]) return 0; if (board[i][j] == 'w'&&board[i][j] == board[i][j + 1] && board[i][j] == board[i][j + 2] && board[i][j] == board[i][j + 3] && board[i][j] == board[i][j + 4]) return 1; if (board[i][j] == 'b'&&board[i][j] == board[i + 1][j + 1] && board[i][j] == board[i + 2][j + 2] && board[i][j] == board[i + 3][j + 3] && board[i][j] == board[i + 4][j + 4]) return 0; if (board[i][j] == 'w'&&board[i][j] == board[i + 1][j + 1] && board[i][j] == board[i + 2][j + 2] && board[i][j] == board[i + 3][j + 3] && board[i][j] == board[i + 4][j + 4]) return 1; if (board[i][j] == 'b'&&board[i][j] == board[i - 1][j + 1] && board[i][j] == board[i - 2][j + 2] && board[i][j] == board[i - 3][j + 3] && board[i][j] == board[i - 4][j + 4]) return 0; if (board[i][j] == 'w'&&board[i][j] == board[i - 1][j + 1] && board[i][j] == board[i - 2][j + 2] && board[i][j] == board[i - 3][j + 3] && board[i][j] == board[i - 4][j + 4]) return 1; } return -1; } int main() { game_start: init(); system("cls"); // system()函数是发出一条DOS命令,“cls”应该是清空的意思 system("title 双人五子棋"); // 设置CMD窗口标题 cout << "Copyright (C) XiyuWang 2018 All rights reserved." << endl; cout << "双人五子棋小游戏" << endl; cout << "小提示:棋盘中b代表黑方(black),w代表白方(white)" << endl; cout << "请按任意键开始游戏......"; _getch(); // 从控制台读取一个字符,但不显示在屏幕上。可以赋值,此函数有返回值 while (true) { place(0); if (compute() == 0) { system("cls"); display(); cout << "黑方胜!" << endl; break; } if (compute() == 2) { system("cls"); display(); cout << "平局!" << endl; break; } place(1); if (compute() == 1) { system("cls"); display(); cout << "白方胜!" << endl; break; } if (compute() == 2) { system("cls"); display(); cout << "平局!" << endl; break; } } cout << "再来一局?Y/N "; o = _getch(); // 这里_getch()抓取控制台输入,但是控制台不显示 if (o == 'Y' || o == 'y') goto game_start; return 0; }