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;
}
修改后
原文地址:https://www.cnblogs.com/maxiaonong/p/13293902.html