基于wxWidgets的五子棋小游戏

该项目是基于wxWidgets提供的GUI的开发框架,采用C++语言进行代码编写,实现双人对战;并根据五子棋的基本棋形添加了AI算法,白棋(电脑)根据黑棋(玩家)的进攻策略进行防守,实现简单的人机对战。

功能

1、显示一个15*15线组成的围棋棋盘。
2、棋子只能落在线的交点上。
3、黑白子交替下棋。
4、当黑子或者白子连续五个子组成一条直线,则为胜利。

具体流程:

1、wxWidgets程序封装了main()函数和消息循环。整个程序通过继承wxApp类,并用全局宏wxIMPLEMENT_APP,传入wxApp派生类的类名实现对类的实例化和消息循环。

// 调用宏定义IMPLEMENT_APP()实例化应用化程序
wxIMPLEMENT_APP(GoBangApp);

2、在进入消息循环之前,创建主窗口的工作通过wxApp派生类中重新实现wxApp的虚函数OnInit来实现(重载)。

// 程序类:继承wxApp
class GoBangApp:public wxApp{
public:
        // 重载wxApp::OnInit()成员函数,并在其中创建框架类的对象
        bool OnInit()override{
                GoBangFrame* pframe = new GoBangFrame("Gobang");
                pframe->Show();
                return true;
        }
};

3、主窗口是wxFrame的派生类,其中控件都作为主窗口的成员变量,在主窗口类的构造函数中初始化。

// 框架类:继承wxFrame
// 在框架类的构造函数中创建面板类的对象
class GoBangFrame:public wxFrame{
public:
        GoBangFrame(const char* AppTitle):wxFrame(nullptr,wxID_ANY,AppTitle){
                wxPanel* ppanel = new GoBangPanel(this);
                SetSize(wxSize(500,500));
        }
};

4、创建面板类(放置控件的窗口),继承wxPanel,用来装载一些可见元素的窗口,通过在面板类向窗体加入事件;在wxFrame派生类的构造函数中创建。

  • 成员变量:定义了一些棋盘的基本信息、棋子的基本信息;基本信息主要包括位置、颜色、尺寸等;
  • 成员函数:记录了一些事件:鼠标单击事件、鼠标移动事件、绘制事件;

在面板类的构造函数中对事件进行绑定操作。

class GoBangPanel:public wxPanel{
        const int cellsize = 30;
        const int linelen = 14*cellsize;
        const int chess_size = cellsize/2;
        vector<wxPoint> chess_position;
        enum ChessType{
                EMPTY,BLACK,WHITE,
        };
        ChessType board[15][15] = {EMPTY};
        bool Black_flag = true;
        wxPoint offset;
        wxPoint Mouse_Position;
        int maxcount = 0;
        pair<int,int> Ai_position;
public:
        // 构造函数用来添加绑定
        GoBangPanel(wxFrame* pframe):wxPanel(pframe){
                Bind(wxEVT_PAINT,&GoBangPanel::OnPaint,this);
                Bind(wxEVT_MOTION,&GoBangPanel::OnMove,this);
                Bind(wxEVT_LEFT_DOWN,&GoBangPanel::OnLeftDown,this);
        }
}

5、五子棋双人对战

#include <wx/wx.h>
#include <vector>
using namespace std;
// 应用程序类:继承wxPanel
// 面板
class GoBangPanel:public wxPanel{
        const int cellsize = 30;
        const int linelen = 14*cellsize;
        const int chess_size = cellsize/2;
        vector<wxPoint> chess_position;
        enum ChessType{
                EMPTY,BLACK,WHITE,
        };
        ChessType board[15][15] = {EMPTY};
        bool Black_flag = true;
        wxPoint offset;
        wxPoint Mouse_Position;
public:
        // 构造函数用来添加绑定
        GoBangPanel(wxFrame* pframe):wxPanel(pframe){
                Bind(wxEVT_PAINT,&GoBangPanel::OnPaint,this);
                Bind(wxEVT_MOTION,&GoBangPanel::OnMove,this);
                Bind(wxEVT_LEFT_DOWN,&GoBangPanel::OnLeftDown,this);
        }
        // 鼠标事件
        void OnMove(wxMouseEvent& event){
                Mouse_Position = event.GetPosition();
                Refresh();
        }
        void OnLeftDown(wxMouseEvent& event){
                wxPoint p = event.GetPosition();
                int x = round(1.0*(p.x-offset.x)/cellsize);
                int y = round(1.0*(p.y-offset.y)/cellsize);
                if(x<0 || x>15) return;
                if(y<0 || y>15) return;
                if(EMPTY != board[x][y]) return;

                board[x][y] = Black_flag?BLACK:WHITE;
                Black_flag = !Black_flag;
                Refresh(); // 刷新页面
                if(Check(x,y)){
                        wxMessageBox(board[x][y] == BLACK?"Black win":"White win","Note");
                }
        }
        bool Check(int x,int y){
                ChessType type = board[x][y];
                // 横向判断
                int count = 1;
                for(int i=x+1;i<15;i++){ // 向右查找
                        if(board[i][y] == type) count++;
                        else break;
                }
                if(count >= 5) return true;
                for(int i=x-1;i>=0;i--){ // 向左查找
                        if(board[i][y] == type) count++;
                        else break;
                }
                if(count >= 5) return true;
                // 纵向判断
                count = 1;
                for(int i=y+1;y<15;i++){ // 向下查找
                        if(board[x][i] == type) count++;
                        else break;
                }
                if(count >= 5) return true;
                for(int i=y-1;y>=0;i--){ // 向上查找
                        if(board[x][i] == type) count++;
                        else break;
                }
                if(count >= 5) return true;
                // 斜向判断 \
                count = 1;
                for(int i=1;i<=5 && x+i<15 && y+i<15;i++){ // 右下方查找
                        if(board[x+i][y+i] == type) count++;
                        else break;
                }
                if(count >= 5) return true;
                for(int i=1;i<=5 && x+i>=0 && y+i>=0;i++){ // 左上方查找
                        if(board[x-i][y-i] == type) count++;
                        else break;
                }
                if(count >= 5) return true;
                // 斜向判断 \
                count = 1;
                for(int i=1;i<=5 && x+i<15 && y+i<15;i++){ // 右下方查找
                        if(board[x+i][y+i] == type) count++;
                        else break;
                }
                if(count >= 5) return true;
                for(int i=1;i<=5 && x+i>=0 && y+i>=0;i++){ // 左上方查找
                        if(board[x-i][y-i] == type) count++;
                        else break;
                }
                if(count >= 5) return true;
                // 斜向判断 /
                count = 1;
                for(int i=1;i<=5 && x+i<15 && y+i>=0;i++){ // 右上方查找
                        if(board[x+i][y-i] == type) count++;
                        else break;
                }
                if(count >= 5) return true;
                for(int i=1;i<=5 && x+i>=0 && y+i<15;i++){ // 左下方查找
                        if(board[x-i][y+i] == type) count++;
                        else break;
                }
                if(count >= 5) return true;
                return false;
        }
        void OnPaint(wxPaintEvent &event){
                wxPaintDC dc(this);
                // 棋盘 15*15
                wxSize board_size = GetClientSize();
                int left = (board_size.GetWidth() - linelen)/2;
                int top = (board_size.GetHeight() - linelen)/2;
                offset = wxPoint(left,top);
                for(int i=0;i<15;i++){
                        dc.DrawLine(wxPoint(0,i*cellsize)+offset,wxPoint(linelen,i*cellsize)+offset);   // 横线
                        dc.DrawLine(wxPoint(i*cellsize,0)+offset,wxPoint(i*cellsize,linelen)+offset);   // 竖线
                }
                // 显示棋子信息
                for(int i=0;i<15;i++){
                        for(int j=0;j<15;j++){
                                if(EMPTY != board[i][j]) DisplayChess(dc,i,j);
                        }
                }
                dc.SetBrush(Black_flag?*wxBLACK_BRUSH:*wxWHITE_BRUSH);
                dc.DrawCircle(Mouse_Position,chess_size);
        }
        // 显示棋子
        void DisplayChess(wxPaintDC& dc,int x,int y){
                dc.SetBrush(board[x][y] == WHITE?*wxWHITE_BRUSH:*wxBLACK_BRUSH);
                dc.DrawCircle(wxPoint(x,y)*cellsize+offset,chess_size);
        }
};
// 框架类:继承wxFrame
// 在框架类的构造函数中创建面板类的对象
class GoBangFrame:public wxFrame{
public:
        GoBangFrame(const char* AppTitle):wxFrame(nullptr,wxID_ANY,AppTitle){
                wxPanel* ppanel = new GoBangPanel(this);
                SetSize(wxSize(500,500));
        }
};
// 程序类:继承wxApp
class GoBangApp:public wxApp{
public:
        // 重载wxApp::OnInit()成员函数,并在其中创建框架类的对象
        bool OnInit()override{
                GoBangFrame* pframe = new GoBangFrame("Gobang");
                pframe->Show();
                return true;
        }
};

// 调用宏定义IMPLEMENT_APP()实例化应用化程序
wxIMPLEMENT_APP(GoBangApp);

6、根据五子棋的基本棋形,添加AI算法,白棋(电脑)根据黑棋(玩家)的进攻策略进行防守,实现简单的人机对战。

  • 在下完一个黑棋之后,分别对黑棋所在位置的8个方向进行判断,对连续的黑棋进行堵截;如果有多个位置可以防守,设定一个权重,在权重大(连续黑棋多的)的位置进行防守。

基本棋形:

  • 必胜:连五、活四


  • 将胜:冲四、活三


  • 待胜:眠三


  • 不胜:活二、眠二


#include <wx/wx.h>
#include <vector>
using namespace std;
// 应用程序类:继承wxPanel
// 面板
class GoBangPanel:public wxPanel{
        const int cellsize = 30;
        const int linelen = 14*cellsize;
        const int chess_size = cellsize/2;
        vector<wxPoint> chess_position;
        enum ChessType{
                EMPTY,BLACK,WHITE,
        };
        ChessType board[15][15] = {EMPTY};
        bool Black_flag = true;
        wxPoint offset;
        wxPoint Mouse_Position;
        int maxcount = 0;
        pair<int,int> Ai_position;
public:
        // 构造函数用来添加绑定
        GoBangPanel(wxFrame* pframe):wxPanel(pframe){
                Bind(wxEVT_PAINT,&GoBangPanel::OnPaint,this);
                Bind(wxEVT_MOTION,&GoBangPanel::OnMove,this);
                Bind(wxEVT_LEFT_DOWN,&GoBangPanel::OnLeftDown,this);
        }
        // 鼠标事件
        void OnMove(wxMouseEvent& event){
                Mouse_Position = event.GetPosition();
                Refresh();
        }
        void OnLeftDown(wxMouseEvent& event){
                wxPoint p = event.GetPosition();
                int x = round(1.0*(p.x-offset.x)/cellsize);
                int y = round(1.0*(p.y-offset.y)/cellsize);
                if(x<0 || x>15) return;
                if(y<0 || y>15) return;
                if(EMPTY != board[x][y]) return;
                PlayChess(x,y);                                     // 玩家 黑子
                cout << "black:[" << x << "," << y << "]" << endl;
                cout << "white:[" << Ai_position.first << "," << Ai_position.second << "]" << endl;
                PlayChess2(Ai_position.first,Ai_position.second);    // 电脑 白子
        }
        void PlayChess(int x,int y){
                board[x][y] = Black_flag?BLACK:WHITE;
                Black_flag = !Black_flag;
                Refresh(); // 刷新页面
                if(Check(x,y)){
                        wxMessageBox(board[x][y] == BLACK?"Black win":"White win","Note");
                }
        }
        void PlayChess2(int x,int y){
                board[x][y] = Black_flag?BLACK:WHITE;
                Black_flag = !Black_flag;
                Refresh(); // 刷新页面
                if(Check2(x,y)){
                        wxMessageBox(board[x][y] == BLACK?"Black win":"White win","Note");
                }
        }
        bool Check(int x,int y){
                ChessType type = board[x][y];
                maxcount = 0;
                int ai_x1=-1,ai_y1=-1,ai_x2=-1,ai_y2=-1;
                int weight1=0,weight2=0;

                // -1 的情况:
                // 横向判断
                int count = 1;
                for(int i=x+1;i<15;i++){ // 向右查找
                        if(board[i][y] == type){
                                count++;
                        }else{
                                if(EMPTY == board[i][y]){
                                        ai_x1 = i;
                                        ai_y1 = y;
                                        int j = i+1;
                                        while(j<15 && board[j][y] == type){
                                                weight1++;
                                                j++;
                                        }
                                }
                                break;
                        }
                }
                // cout << "1:[" << ai_x1 << "," << ai_y1 << "]" << endl;
                if(count >= 5) return true;
                for(int i=x-1;i>=0;i--){ // 向左查找
                        if(board[i][y] == type){
                                count++;
                        }else{
                                if(EMPTY == board[i][y]){
                                        ai_x2 = i;
                                        ai_y2 = y;
                                        int j = i-1;
                                        while(j>=0 && board[j][y] == type){
                                                weight2++;
                                                j--;
                                        }
                                }
                                break;
                        }
                }
                // cout << "2:[" << ai_x2 << "," << ai_y2 << "]" << endl;
                if(count >= 5) return true;
                // cout << "weight1:" << weight1 << " weight2:" << weight2 << endl;
                // 更新电脑白棋位置
                cout << maxcount << endl;
                if(maxcount < count+max(weight1,weight2) && (-1 != ai_x1 || -1 != ai_x2)){
                        maxcount = count+max(weight1,weight2);
                        if(weight1 == weight2){
                                if(-1 != ai_x1){
                                        Ai_position = make_pair(ai_x1,ai_y1); // 默认下右边
                                        // cout << "key1" << endl;
                                }else{
                                        Ai_position = make_pair(ai_x2,ai_y2);
                                        // cout << "key2" << endl;
                                }
                        }else{
                                Ai_position = (weight1 > weight2)?make_pair(ai_x1,ai_y1):make_pair(ai_x2,ai_y2);
                                // cout << "key3" << endl;
                        }
                }
                // cout << "white2:[" << Ai_position.first << "," << Ai_position.second << "]" << endl;
                // 纵向判断
                weight1 = weight2 = 0;
                ai_x1 = ai_x2 = ai_y1 = ai_y2 = -1;
                count = 1;
                for(int i=y+1;y<15;i++){ // 向下查找
                        if(board[x][i] == type){
                                count++;
                        }else{
                                if(EMPTY == board[x][i]){
                                        ai_x1 = x;
                                        ai_y1 = i;
                                        int j = i+1;
                                        while(j<15 && board[x][j] == type){
                                                weight1++;
                                                j++;
                                        }
                                }
                                break;
                        }
                }
                if(count >= 5) return true;
                for(int i=y-1;y>=0;i--){ // 向上查找
                        if(board[x][i] == type){
                                count++;
                        }else{
                                if(EMPTY == board[x][i]){
                                        ai_x2 = x;
                                        ai_y2 = i;
                                        int j = i-1;
                                        while(j>=0 && type == board[x][j]){
                                                weight2++;
                                                j--;
                                        }
                                }
                                break;
                        }
                }
                if(count >= 5) return true;
                // 更新电脑白棋位置
                cout << maxcount << endl;
                if(maxcount < count+max(weight1,weight2) && (-1 != ai_x1 || -1 != ai_x2)){
                        maxcount = count+max(weight1,weight2);
                        if(weight1 == weight2){
                                if(-1 != ai_x1){
                                        Ai_position = make_pair(ai_x1,ai_y1); // 默认下右边
                                        cout << "key1" << endl;
                                }else{
                                        Ai_position = make_pair(ai_x2,ai_y2);
                                        cout << "key2" << endl;
                                }
                        }else{
                                Ai_position = (weight1 > weight2)?make_pair(ai_x1,ai_y1):make_pair(ai_x2,ai_y2);
                                cout << "key3" << endl;
                        }
                }
                // 斜向判断 \
                count = 1;
                weight1 = weight2 = 0;
                ai_x1 = ai_x2 = ai_y1 = ai_y2 = -1;
                for(int i=1;i<=5 && x+i<15 && y+i<15;i++){ // 右下方查找
                        if(board[x+i][y+i] == type){
                                count++;
                        }else{
                                if(EMPTY == board[x+i][y+i]){
                                        ai_x1 = x+i;
                                        ai_y1 = y+i;
                                        int j = x+i+1,k = y+i+1;
                                        while(j<15 && k<15 && type == board[j][k]){
                                                weight1++;
                                                j++;
                                                k++;
                                        }
                                }
                                break;
                        }
                }
                if(count >= 5) return true;
                for(int i=1;i<=5 && x+i>=0 && y+i>=0;i++){ // 左上方查找
                        if(board[x-i][y-i] == type){
                                count++;
                        }else{
                                if(EMPTY == board[x-i][y-i]){
                                        ai_x2 = x-i;
                                        ai_y2 = y-i;
                                        int j = x-i-1,k = y-i-1;
                                        while(j>=0 && k>=0 && type == board[j][k]){
                                                weight2++;
                                                j--;
                                                k--;

                                        }
                                }
                                break;
                        }
                }
                if(count >= 5) return true;
                // 更新电脑白棋位置
                cout << maxcount << endl;
                if(maxcount < count+max(weight1,weight2) && (-1 != ai_x1 || -1 != ai_x2)){
                        maxcount = count+max(weight1,weight2);
                        if(weight1 == weight2){
                                if(-1 != ai_x1){
                                        Ai_position = make_pair(ai_x1,ai_y1); // 默认下右边
                                        // cout << "key1" << endl;
                                }else{
                                        Ai_position = make_pair(ai_x2,ai_y2);
                                        // cout << "key2" << endl;
                                }
                        }else{
                                Ai_position = (weight1 > weight2)?make_pair(ai_x1,ai_y1):make_pair(ai_x2,ai_y2);
                                // cout << "key3" << endl;
                        }
                }
                // 斜向判断 /
                count = 1;
                for(int i=1;i<=5 && x+i<15 && y+i>=0;i++){ // 右上方查找
                        if(board[x+i][y-i] == type) count++;
                        else{
                                if(EMPTY == board[x+i][y-i]){
                                        ai_x1 = x+i;
                                        ai_y1 = y-i;
                                        int j = x+i+1,k = y-i-1;
                                        while(j<15 && k>=0 && type == board[j][k]){
                                                weight1++;
                                                j++;
                                                k--;
                                        }
                                }
                                break;
                        }
                }
                if(count >= 5) return true;
                for(int i=1;i<=5 && x+i>=0 && y+i<15;i++){ // 左下方查找
                        if(board[x-i][y+i] == type) count++;
                        else{
                                if(EMPTY == board[x-i][y+i]){
                                        ai_x2 = x-i;
                                        ai_y2 = y+i;
                                        int j = x-i-1,k = y+i+1;
                                        while(j>=0 && k<15 && type == board[j][k]){
                                                weight2++;
                                                j--;
                                                k++;
                                        }
                                }
                                break;
                        }
                }
                if(count >= 5) return true;
                // 更新电脑白棋位置
                cout << maxcount << endl;
                if(maxcount < count+max(weight1,weight2) && (-1 != ai_x1 || -1 != ai_x2)){
                        maxcount = count+max(weight1,weight2);
                        if(weight1 == weight2){
                                if(-1 != ai_x1){
                                        Ai_position = make_pair(ai_x1,ai_y1); // 默认下右边
                                        // cout << "key1" << endl;
                                }else{
                                        Ai_position = make_pair(ai_x2,ai_y2);
                                        // cout << "key2" << endl;
                                }
                        }else{
                                Ai_position = (weight1 > weight2)?make_pair(ai_x1,ai_y1):make_pair(ai_x2,ai_y2);
                                // cout << "key3" << endl;
                        }
                }
                return false;
        }
        bool Check2(int x,int y){
                ChessType type = board[x][y];
                // 横向判断
                int count = 1;
                for(int i=x+1;i<15;i++){ // 向右查找
                        if(board[i][y] == type) count++;
                        else break;
                }
                if(count >= 5) return true;
                for(int i=x-1;i>=0;i--){ // 向左查找
                        if(board[i][y] == type) count++;
                        else break;
                }
                if(count >= 5) return true;
                // 纵向判断
                count = 1;
                for(int i=y+1;y<15;i++){ // 向下查找
                        if(board[x][i] == type) count++;
                        else break;
                }
                if(count >= 5) return true;
                for(int i=y-1;y>=0;i--){ // 向上查找
                        if(board[x][i] == type) count++;
                        else break;
                }
                if(count >= 5) return true;
                // 斜向判断 \
                count = 1;
                for(int i=1;i<=5 && x+i<15 && y+i<15;i++){ // 右下方查找
                        if(board[x+i][y+i] == type) count++;
                        else break;
                }
                if(count >= 5) return true;
                for(int i=1;i<=5 && x+i>=0 && y+i>=0;i++){ // 左上方查找
                        if(board[x-i][y-i] == type) count++;
                        else break;
                }
                if(count >= 5) return true;
                // 斜向判断 \
                count = 1;
                for(int i=1;i<=5 && x+i<15 && y+i<15;i++){ // 右下方查找
                        if(board[x+i][y+i] == type) count++;
                        else break;
                }
                if(count >= 5) return true;
                for(int i=1;i<=5 && x+i>=0 && y+i>=0;i++){ // 左上方查找
                        if(board[x-i][y-i] == type) count++;
                        else break;
                }
                if(count >= 5) return true;
                // 斜向判断 /
                count = 1;
                for(int i=1;i<=5 && x+i<15 && y+i>=0;i++){ // 右上方查找
                        if(board[x+i][y-i] == type) count++;
                        else break;
                }
                if(count >= 5) return true;
                for(int i=1;i<=5 && x+i>=0 && y+i<15;i++){ // 左下方查找
                        if(board[x-i][y+i] == type) count++;
                        else break;
                }
                if(count >= 5) return true;
                return false;
        }
        void OnPaint(wxPaintEvent &event){
                wxPaintDC dc(this);
                // 棋盘 15*15
                wxSize board_size = GetClientSize();
                int left = (board_size.GetWidth() - linelen)/2;
                int top = (board_size.GetHeight() - linelen)/2;
                offset = wxPoint(left,top);
                for(int i=0;i<15;i++){
                        dc.DrawLine(wxPoint(0,i*cellsize)+offset,wxPoint(linelen,i*cellsize)+offset);   // 横线
                        dc.DrawLine(wxPoint(i*cellsize,0)+offset,wxPoint(i*cellsize,linelen)+offset);   // 竖线
                }
                // 显示棋子信息
                for(int i=0;i<15;i++){
                        for(int j=0;j<15;j++){
                                if(EMPTY != board[i][j]) DisplayChess(dc,i,j);
                        }
                }
                dc.SetBrush(Black_flag?*wxBLACK_BRUSH:*wxWHITE_BRUSH);
                dc.DrawCircle(Mouse_Position,chess_size);
        }
        // 显示棋子
        void DisplayChess(wxPaintDC& dc,int x,int y){
                dc.SetBrush(board[x][y] == WHITE?*wxWHITE_BRUSH:*wxBLACK_BRUSH);
                dc.DrawCircle(wxPoint(x,y)*cellsize+offset,chess_size);
        }
};
// 框架类:继承wxFrame
// 在框架类的构造函数中创建面板类的对象
class GoBangFrame:public wxFrame{
public:
        GoBangFrame(const char* AppTitle):wxFrame(nullptr,wxID_ANY,AppTitle){
                wxPanel* ppanel = new GoBangPanel(this);
                SetSize(wxSize(500,500));
        }
};
// 程序类:继承wxApp
class GoBangApp:public wxApp{
public:
        // 重载wxApp::OnInit()成员函数,并在其中创建框架类的对象
        bool OnInit()override{
                GoBangFrame* pframe = new GoBangFrame("Gobang");
                pframe->Show();
                return true;
        }
};

// 调用宏定义IMPLEMENT_APP()实例化应用化程序
wxIMPLEMENT_APP(GoBangApp);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容