从0开始写中国象棋-走一步棋(当门炮,马来跳)(C++)

在文章 从0开始写中国象棋-创建棋盘与棋子

中,我们已经可以看到象棋游戏的界面了。

这是因为,我们创建了棋盘(棋盘数组),并在棋盘上放置一些数字来表示棋子。

让棋子动起来

现在,我们打算让棋子动起来。

棋子动起来,其实很简单,比如开局 炮二平五。

实际上就是棋子从棋盘上的一个位置移动到了棋盘的另一个位置。

实际上是棋盘在变化

对应棋盘的变化就是,棋盘从:

变成了:

由于棋盘上的棋子就是一个一个的不同的数字,所以,从计算机的角度来说,走一步棋就是给二维数组的一个位置设置一个新数字。

也就是,起点位置元素重新赋值为0(表示这里没有棋子了,棋子走到其他位置去了);

终点位置元素重新赋值为炮的ID(表示炮走棋来到了这里)。

程序实现 GoAhead(OneStep)

现在我们希望告诉程序,走一步棋,从一个位置走到另一个位置,程序就能够实现这个目标。

由于这种需求是在下棋双方走棋的时候反复出现的,所以我们可以很方便的用函数来实现。

这个函数大概像下面这样:

bool GoAhead(from_row, from_col, to_row, to_col);

其中,各个参数的意思是很明显的,我们就不解释了。

但是,函数返回值是bool,这个是干什么的呢?

因为用户可能会乱走棋,比如,蹩马腿了也要跳马,这个时候你就要告诉他不能走这步棋。这时候函数返回 false 。

现在让我们来实现这个函数:

bool GoAhead(int from_row, int from_col, int to_row, int to_col)
{
    //如果出发的地方没有旗子,就返回 false
    if()
}

这个时候我们才发现我们需要访问棋盘。

而棋盘是定义在main函数内的变量。我们访问不到。

怎么办?

C++全局变量

不在函数内定义的变量就叫全局变量。

为了能够让任何代码都访问到棋盘,我们在程序的一开始就定义棋盘。这样我们的函数就可以访问棋盘了。

//棋盘数组,不同的数字表示不同的棋子,0表示没有棋子
vector<vector<int>> chess_board
{
    { 1, 2, 3, 4, 5, 6, 7, 8, 9},
    { 0, 0, 0, 0, 0, 0, 0, 0, 0},
    { 0,10, 0, 0, 0, 0, 0,11, 0},
    {12, 0,13, 0,14, 0,15, 0,16},
    { 0, 0, 0, 0, 0, 0, 0, 0, 0},
    { 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {26, 0,27, 0,28, 0,29, 0,30},
    { 0,31, 0, 0, 0, 0, 0,32, 0},
    { 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {17,18,19,20,21,22,23,24,25},
};

bool GoAhead(int from_row, int from_col, int to_row, int to_col)
{
    //如果出发的地方没有旗子,就返回 false
    if (chess_board[from_row][from_col] != 0)
    {

    }
    else
    {
        return false;
    }
}

谁能告诉我能否走到哪里?

现在的问题是,当走棋的起点有棋子的时候,这个棋子能否到达目的地位置?

也就是走棋的合理性问题。

这里门道就多了:马走日,相走田,车走直路,炮翻山,小卒一去不会还。

如何实现这样的需求呢?

C++的方式是使用多态来实现。伪代码像下面这样:

//棋子类的基类
struct chess_base
{
    // 纯虚函数,表示 chess_base 是一个抽象类,专门用来做基类;
    //GoAhead 用来给各个派生类来重新实现 override
    virtual bool GoAhead(int from_row, int from_col, int to_row, int to_col) = 0;
};

struct Horse : public chess_base
{
    // 马实现自己的走棋
    bool GoAhead(int from_row, int from_col, int to_row, int to_col)
    {
        //ba la ba la ....
        return false;
    }
};

struct King : public chess_base
{
    // 帅实现自己的走棋
    bool GoAhead(int from_row, int from_col, int to_row, int to_col)
    {
        //ba la ba la ....
        return false;
    }
};

每个棋子都知道自己的规则,所以自己是知道能否走到目的地的。

这也就要求我们要替各个棋子来实现它们各自的走法。

棋子数组包含对象

之前,我们的棋子数组是不同位置(数组下标)表示不同棋子,棋子只有一个内容,就是它们的名字。

现在,我们希望用类对象来表示。名字只是棋子的一个成员变量。走棋GoAhead才是棋子的主要能力。

#include <iostream>
#include <string>
#include <vector>
#include <iomanip>
using namespace std;
 
//棋盘数组,不同的数字表示不同的棋子,0表示没有棋子
vector<vector<int>> chess_board
{
    { 1, 2, 3, 4, 5, 6, 7, 8, 9},
    { 0, 0, 0, 0, 0, 0, 0, 0, 0},
    { 0,10, 0, 0, 0, 0, 0,11, 0},
    {12, 0,13, 0,14, 0,15, 0,16},
    { 0, 0, 0, 0, 0, 0, 0, 0, 0},
    { 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {26, 0,27, 0,28, 0,29, 0,30},
    { 0,31, 0, 0, 0, 0, 0,32, 0},
    { 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {17,18,19,20,21,22,23,24,25},
};

//棋子类的基类
struct chess_base
{
    chess_base(const string& name1):name(name1){}
    // 纯虚函数,表示 chess_base 是一个抽象类,专门用来做基类;
    //GoAhead 用来给各个派生类来重新实现 override
    virtual bool GoAhead(int from_row, int from_col, int to_row, int to_col) = 0;
    string name;//棋子要显示的名字
};
//车 車
struct Chariot : public chess_base
{
    Chariot(const string& name1) :chess_base(name1) {}
    // 马实现自己的走棋
    bool GoAhead(int from_row, int from_col, int to_row, int to_col)
    {
        cout << from_row << "," << from_col << "," << to_row << "," << to_col << endl;
        //ba la ba la ....
        return false;
    }
};
//马 馬
struct Horse : public chess_base
{
    Horse(const string& name1):chess_base(name1){}
    // 马实现自己的走棋
    bool GoAhead(int from_row, int from_col, int to_row, int to_col)
    {
        cout << from_row << "," << from_col << "," << to_row << "," << to_col << endl;
        //ba la ba la ....
        return false;
    }
};
//炮 砲
struct Cannon : public chess_base
{
    Cannon(const string& name1) :chess_base(name1) {}
    // 马实现自己的走棋
    bool GoAhead(int from_row, int from_col, int to_row, int to_col)
    {
        cout << from_row << "," << from_col << "," << to_row << "," << to_col << endl;
        //ba la ba la ....
        return false;
    }
};
//将 帅
struct King : public chess_base
{
    King(const string& name1) :chess_base(name1) {}
    // 帅实现自己的走棋
    bool GoAhead(int from_row, int from_col, int to_row, int to_col)
    {
        //ba la ba la ....
        cout << from_row << "," << from_col << "," << to_row << "," << to_col << endl;
        return false;
    }
};
//士 仕
struct Official : public chess_base
{
    Official(const string& name1) :chess_base(name1) {}
    // 帅实现自己的走棋
    bool GoAhead(int from_row, int from_col, int to_row, int to_col)
    {
        //ba la ba la ....
        cout << from_row << "," << from_col << "," << to_row << "," << to_col << endl;
        return false;
    }
};
//相 象
struct Minister : public chess_base
{
    Minister(const string& name1) :chess_base(name1) {}
    // 帅实现自己的走棋
    bool GoAhead(int from_row, int from_col, int to_row, int to_col)
    {
        //ba la ba la ....
        cout << from_row << "," << from_col << "," << to_row << "," << to_col << endl;
        return false;
    }
};
//兵 卒
struct Soldier : public chess_base
{
    Soldier(const string& name1) :chess_base(name1) {}
    // 帅实现自己的走棋
    bool GoAhead(int from_row, int from_col, int to_row, int to_col)
    {
        //ba la ba la ....
        cout << from_row << "," << from_col << "," << to_row << "," << to_col << endl;
        return false;
    }
};

vector<chess_base*> chess_man
{
    nullptr,//下标为0不用,编号从1开始
    //上方黑方棋子
    new Chariot("车"),new Horse("马"), new Minister("相"), new Official("士"), new King("将"), new Official("士"), new Minister("相"), new Horse("马"), new Chariot("车"),

    new Cannon("炮"),new Cannon("炮"),

    new Soldier("兵"), new Soldier("兵"), new Soldier("兵"), new Soldier("兵"), new Soldier("兵"),

    //下方红方棋子
    new Chariot("車"), new Horse("馬"), new Minister("象"), new Official("仕"), new King("帥"), new Official("仕"), new Minister("象"), new Horse("馬"), new Chariot("車"),

    new Soldier("卒"), new Soldier("卒"), new Soldier("卒"), new Soldier("卒"), new Soldier("卒"),

    new Cannon("砲"), new Cannon("砲"),
};


int main(void)
{
    for (int row = 0; row < 10; row++)
    {
        for (int col = 0; col < 9; col++)
        {
            auto id = chess_board[row][col];
            if (id != 0)
            {
                cout <<setw(5)<< chess_man[id]->name ;//输出一个棋子
            }
            else
            {
                cout<<setw(5) << "_";//表示棋盘上的一个位置
            }
        }
        cout << endl;
        cout << endl;
    }
    return 0;
}

运行结果:

当门炮,马来跳

有了棋子对象之后,我们实现走棋就很好实现了。

    // 当门炮 : 炮二平五  ID 为 32 从(7,7) 移动到 (7,4)
    chess_man[32]->GoAhead(7, 7, 7, 4);
    // 马来跳 : 炮8进7  ID 为 8 从(7,7) 移动到 (7,4)
    chess_man[8]->GoAhead(0, 7, 2, 6);

此时,我们需要实现炮,马的 GoAhead 函数。

为了简单起见,我们不做合法性检查,让棋子直接在棋盘上从起点走到终点。

既然如此,其实所有棋子都是这样走棋的,我们把所有的棋子走棋都给实现了:

bool GoAhead(int from_row, int from_col, int to_row, int to_col)
{
    cout << "GoAhead " << from_row << "," << from_col << "," << to_row << "," << to_col << endl;
    //先保存原来的 ID, 为着放到终点
    auto id = chess_board[from_row][from_col];
    //离开之后,留下 0
    chess_board[from_row][from_col] = 0;
    //走到了目的地
    chess_board[to_row][to_col] = id;
    return false;
}

完整的代码

#include <iostream>
#include <string>
#include <vector>
#include <iomanip>
using namespace std;
 
//棋盘数组,不同的数字表示不同的棋子,0表示没有棋子
vector<vector<int>> chess_board
{
    /*      0  1  2  3  4  5  6  7  8*/
    /* 0*/{ 1, 2, 3, 4, 5, 6, 7, 8, 9},
    /* 1*/{ 0, 0, 0, 0, 0, 0, 0, 0, 0},
    /* 2*/{ 0,10, 0, 0, 0, 0, 0,11, 0},
    /* 3*/{12, 0,13, 0,14, 0,15, 0,16},
    /* 4*/{ 0, 0, 0, 0, 0, 0, 0, 0, 0},
    /* 5*/{ 0, 0, 0, 0, 0, 0, 0, 0, 0},
    /* 6*/{26, 0,27, 0,28, 0,29, 0,30},
    /* 7*/{ 0,31, 0, 0, 0, 0, 0,32, 0},
    /* 8*/{ 0, 0, 0, 0, 0, 0, 0, 0, 0},
    /* 9*/{17,18,19,20,21,22,23,24,25},
};

//棋子类的基类
struct chess_base
{
    chess_base(const string& name1):name(name1){}
    // 纯虚函数,表示 chess_base 是一个抽象类,专门用来做基类;
    //GoAhead 用来给各个派生类来重新实现 override
    virtual bool GoAhead(int from_row, int from_col, int to_row, int to_col) = 0;
    string name;//棋子要显示的名字
};
//车 車
struct Chariot : public chess_base
{
    Chariot(const string& name1) :chess_base(name1) {}
    // 马实现自己的走棋
    bool GoAhead(int from_row, int from_col, int to_row, int to_col)
    {
        cout << "GoAhead " << from_row << "," << from_col << "," << to_row << "," << to_col << endl;
        //先保存原来的 ID, 为着放到终点
        auto id = chess_board[from_row][from_col];
        //离开之后,留下 0
        chess_board[from_row][from_col] = 0;
        //走到了目的地
        chess_board[to_row][to_col] = id;
        return false;
    }
};
//马 馬
struct Horse : public chess_base
{
    Horse(const string& name1):chess_base(name1){}
    // 马实现自己的走棋
    bool GoAhead(int from_row, int from_col, int to_row, int to_col)
    {
        cout << "GoAhead " << from_row << "," << from_col << "," << to_row << "," << to_col << endl;
        //先保存原来的 ID, 为着放到终点
        auto id = chess_board[from_row][from_col];
        //离开之后,留下 0
        chess_board[from_row][from_col] = 0;
        //走到了目的地
        chess_board[to_row][to_col] = id;
        return false;
    }
};
//炮 砲
struct Cannon : public chess_base
{
    Cannon(const string& name1) :chess_base(name1) {}
    // 马实现自己的走棋
    bool GoAhead(int from_row, int from_col, int to_row, int to_col)
    {
        cout << "GoAhead " << from_row << "," << from_col << "," << to_row << "," << to_col << endl;
        //先保存原来的 ID, 为着放到终点
        auto id = chess_board[from_row][from_col];
        //离开之后,留下 0
        chess_board[from_row][from_col] = 0;
        //走到了目的地
        chess_board[to_row][to_col] = id;
        return false;
    }
};
//将 帅
struct King : public chess_base
{
    King(const string& name1) :chess_base(name1) {}
    // 帅实现自己的走棋
    bool GoAhead(int from_row, int from_col, int to_row, int to_col)
    {
        cout<<"GoAhead " << from_row << "," << from_col << "," << to_row << "," << to_col << endl;
        //先保存原来的 ID, 为着放到终点
        auto id = chess_board[from_row][from_col];
        //离开之后,留下 0
        chess_board[from_row][from_col] = 0;
        //走到了目的地
        chess_board[to_row][to_col] = id;
        return false;
    }
};
//士 仕
struct Official : public chess_base
{
    Official(const string& name1) :chess_base(name1) {}
    // 帅实现自己的走棋
    bool GoAhead(int from_row, int from_col, int to_row, int to_col)
    {
        cout << "GoAhead " << from_row << "," << from_col << "," << to_row << "," << to_col << endl;
        //先保存原来的 ID, 为着放到终点
        auto id = chess_board[from_row][from_col];
        //离开之后,留下 0
        chess_board[from_row][from_col] = 0;
        //走到了目的地
        chess_board[to_row][to_col] = id;
        return false;
    }
};
//相 象
struct Minister : public chess_base
{
    Minister(const string& name1) :chess_base(name1) {}
    // 帅实现自己的走棋
    bool GoAhead(int from_row, int from_col, int to_row, int to_col)
    {
        cout << "GoAhead " << from_row << "," << from_col << "," << to_row << "," << to_col << endl;
        //先保存原来的 ID, 为着放到终点
        auto id = chess_board[from_row][from_col];
        //离开之后,留下 0
        chess_board[from_row][from_col] = 0;
        //走到了目的地
        chess_board[to_row][to_col] = id;
        return false;
    }
};
//兵 卒
struct Soldier : public chess_base
{
    Soldier(const string& name1) :chess_base(name1) {}
    // 帅实现自己的走棋
    bool GoAhead(int from_row, int from_col, int to_row, int to_col)
    {
        cout << "GoAhead " << from_row << "," << from_col << "," << to_row << "," << to_col << endl;
        //先保存原来的 ID, 为着放到终点
        auto id = chess_board[from_row][from_col];
        //离开之后,留下 0
        chess_board[from_row][from_col] = 0;
        //走到了目的地
        chess_board[to_row][to_col] = id;
        return false;
    }
};

vector<chess_base*> chess_man
{
    nullptr,//下标为0不用,编号从1开始
    //上方黑方棋子
    new Chariot("车"),new Horse("马"), new Minister("相"), new Official("士"), new King("将"), new Official("士"), new Minister("相"), new Horse("马"), new Chariot("车"),

    new Cannon("炮"),new Cannon("炮"),

    new Soldier("兵"), new Soldier("兵"), new Soldier("兵"), new Soldier("兵"), new Soldier("兵"),

    //下方红方棋子
    new Chariot("車"), new Horse("馬"), new Minister("象"), new Official("仕"), new King("帥"), new Official("仕"), new Minister("象"), new Horse("馬"), new Chariot("車"),

    new Soldier("卒"), new Soldier("卒"), new Soldier("卒"), new Soldier("卒"), new Soldier("卒"),

    new Cannon("砲"), new Cannon("砲"),
};


int main(void)
{
    // 当门炮 : 炮二平五  ID 为 32 从(7,7) 移动到 (7,4)
    chess_man[32]->GoAhead(7, 7, 7, 4);
    // 马来跳 : 炮8进7  ID 为 8 从(7,7) 移动到 (7,4)
    chess_man[8]->GoAhead(0, 7, 2, 6);



    for (int row = 0; row < 10; row++)
    {
        for (int col = 0; col < 9; col++)
        {
            auto id = chess_board[row][col];
            if (id != 0)
            {
                cout <<setw(5)<< chess_man[id]->name ;//输出一个棋子
            }
            else
            {
                cout<<setw(5) << "_";//表示棋盘上的一个位置
            }
        }
        cout << endl;
        cout << endl;
    }
    return 0;
}

运行效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

C++程序员Carea

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值