二、C++应用:五子棋

2 五子棋

2.1 需求

基于wxWidgets实现一个五子棋游戏

2.2 功能

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

#include <wx/wx.h>
#include <vector>
using namespace std;
//面板类
class GoPanel:public wxPanel{
vector<wxPoint> vec;
const int cellsize = 30;
const int linelen = cellsize*14;
enum ChessType{
    EMPTY,BLACK,WHITE,
};
ChessType broad[15][15] = {EMPTY};
bool black = true;
wxPoint offset;
public:
    GoPanel(wxFrame* pframe):wxPanel(pframe){
    	//将面板与绘图绑定
	Bind(wxEVT_PAINT,&GoPanel::OnPaint,this);
	Bind(wxEVT_LEFT_DOWN,&GoPanel::OnLeftDown,this);
    }	
    void OnLeftDown(wxMouseEvent& event){
    	wxPoint point =  event.GetPosition();
	int x = round(1.0*(point.x-offset.x)/cellsize);
	int y = round(1.0*(point.y-offset.y)/cellsize);
	if(broad[x][y] != EMPTY || x >= 15 || y >= 15) return;
	broad[x][y] = black?BLACK:WHITE;
	black = !black;
	Refresh();
	if(Check(x,y)){
	    wxMessageBox(broad[x][y] == BLACK?"Black Win":"White Win","Note");
	}
    }
    bool Check(int x,int y)const {
	ChessType type = broad[x][y];
        int count = 1;
	//横向检测
	for(int i = x+1;i < 15;++i){
	    if(broad[i][y] == type){
	    	++count;
	    }else{
	    	break;
	    }
	}
	if(count >= 5) return true;
	for(int i = x-1;i >= 0;--i){
	    if(broad[i][y] == type){
	    	++count;
	    }else{
	    	break;
	    }
	}
	if(count >= 5) return true;
	//纵向检测
	count = 1;
	for(int i = y+1;i < 15;++i){
	    if(broad[x][i] == type){
	    	++count;
	    }else{
	    	break;
	    }
	}
	if(count >= 5) return true;
	for(int i = y-1;i >= 0;--i){
	    if(broad[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(broad[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(broad[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(broad[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(broad[x-i][y+i] == type){
	    	++count;
	    }else{
	    	break;
	    }
	}
	if(count >= 5) return true;
	
	return false;
    }
    void OnPaint(wxPaintEvent&){
    	//定义画笔
	wxPaintDC dc(this);
	//棋盘居中
	wxSize size = GetClientSize();
	int left = (size.GetWidth()-linelen)/2;
	int top = (size.GetHeight()-linelen)/2;
	offset = wxPoint(left,top);
	for(int i = 0;i < 15;++i){
	    //dc.DrawLine(wxPoint(left,top+cellsize*i),wxPoint(left+linelen,top+cellsize*i));
	    //dc.DrawLine(wxPoint(left+cellsize*i,top),wxPoint(left+cellsize*i,top+linelen));
	    dc.DrawLine(wxPoint(0,cellsize*i)+offset,wxPoint(linelen,cellsize*i)+offset);
	    dc.DrawLine(wxPoint(cellsize*i,0)+offset,wxPoint(cellsize*i,linelen)+offset);
	}
        for(int i = 0;i < 15;++i){
	    for(int j = 0;j < 15;++j){
	        if(broad[i][j] != EMPTY) DisplayChess(dc,i,j);
	    }
	}
    }
    void DisplayChess(wxPaintDC& dc,int x,int y){
	dc.SetBrush(broad[x][y] == WHITE? *wxWHITE_BRUSH:*wxBLACK_BRUSH);
        //dc.DrawCircle(offset.x+x*cellsize,offset.y+y*cellsize,cellsize/2);
        //dc.DrawCircle(wxPoint(x*cellsize,y*cellsize)+offset,cellsize/2);
        dc.DrawCircle(wxPoint(x,y)*cellsize+offset,cellsize/2);
    }
};
//框架类
//框架类中添加面板类
class GoFrame:public wxFrame{
public:
     GoFrame(const char* title):wxFrame(nullptr,wxID_ANY,title){
     	wxPanel* p = new GoPanel(this);
     }
};
//应用程序类
//应用程序类中添加框架类
class GoApp:public wxApp{
public:
    bool OnInit()override{
    	GoFrame* pframe = new GoFrame("Name");
	pframe->Show();
	return true;
    };
};

wxIMPLEMENT_APP(GoApp);

2.3 加入AI算法实现人机对战

最常见的基本棋型大体有以下几种:连五,活四,冲四,活三,眠三,活二,眠二。

  • 必胜
    在这里插入图片描述
  • 将胜
    在这里插入图片描述
  • 待胜
    在这里插入图片描述
  • 不胜

在这里插入图片描述

棋型进攻方防守方
连五
活四必胜必负
冲四必须进攻必须防守
活三必须进攻必须防守
眠三可以进攻可以进攻
活二可以进攻可以进攻
眠二可以进攻可以进攻
  • 规则:
    1、连五直接判定胜负。
    2、活四、冲四、活三抢占关键点。
    3、眠三、活二、眠二优先进攻。

判断整个棋盘黑白所有的棋型,选取优势棋型进攻防守。例如,执白,如果黑棋的棋型优于白棋防守;反之进攻。

  • 实例:加入AI算法的人机五子棋对战
    注:机器方仅有防守功能,需进一步优化
#include <wx/wx.h>
#include <vector>
using namespace std;
//面板类
class GoPanel:public wxPanel {
    vector<wxPoint> vec;
    const int cellsize = 30;
    const int linelen = cellsize*14;
    enum ChessType {
        EMPTY,BLACK,WHITE,
    };
    ChessType broad[15][15] = {EMPTY};
    bool black = true;
    wxPoint offset;
    pair<int,int> nextpos;
    int maxcount = 0;
public:
    GoPanel(wxFrame* pframe):wxPanel(pframe) {
        //将面板与绘图绑定
        Bind(wxEVT_PAINT,&GoPanel::OnPaint,this);
        Bind(wxEVT_LEFT_DOWN,&GoPanel::OnLeftDown,this);
    }
    void OnLeftDown(wxMouseEvent& event) {
        wxPoint point =  event.GetPosition();
        int x = round(1.0*(point.x-offset.x)/cellsize);
        int y = round(1.0*(point.y-offset.y)/cellsize);
        if(broad[x][y] != EMPTY || x >= 15 || y >= 15) return;
        Chess(x,y);
        Refresh();
        Chess(nextpos.first,nextpos.second); //机器(白棋)
        Refresh();
    }
    void Chess(int x,int y) {
        broad[x][y] = black?BLACK:WHITE;
        black = !black;
        if(Check(x,y)) {
            wxMessageBox(broad[x][y] == BLACK?"Black Win":"White Win","Note");
        }
    }
    bool Check(int x,int y) {
        ChessType type = broad[x][y];
        int count = 1;
        maxcount = 0;
        int tryx1 = -1,tryy1 = -1, tryx2 = -1,tryy2 = -1;
        int add1= 0, add2 = 0;
        //横向检测
        for(int i = x+1; i < 15; ++i) {
            if(broad[i][y] == type) {
                ++count;
            } else {
                if(broad[i][y] == EMPTY) {
                    tryx1 = i;
                    tryy1 = y;
                    int j = i+1;
                    while(j<15 && broad[j][y] == type) {
                        ++add1;
                        ++j;
                    }
                }
                break;
            }
        }
        if(count >= 5) return true;
        for(int i = x-1; i >= 0; --i) {
            if(broad[i][y] == type) {
                ++count;
            } else {
                if(broad[i][y] == EMPTY) {
                    tryx2 = i;
                    tryy2 = y;
                    int j = i-1;
                    while(j>=0 && broad[j][y] == type) {
                        ++add2;
                        --j;
                    }
                }
                break;
            }
        }
        if(count >= 5) return true;
        if(maxcount < count+max(add1,add2) && (tryx1 != -1 || tryx2!=-1)) {
            maxcount = count+max(add1,add2);
            if(add1 == add2) {
                if(tryx1 == -1) {
                    nextpos = make_pair(tryx2,tryy2);
                } else {
                    nextpos = make_pair(tryx1,tryy1);
                }
            } else {
                nextpos = add1 > add2?make_pair(tryx1,tryy1):make_pair(tryx2,tryy2);
            }
        }
        cout << "横向检测:" << maxcount << " Point:" << nextpos.first << "," << nextpos.second << endl;
        //纵向检测
        tryx1 = tryy1 = tryx2 = tryy2 = -1;
        add1 = add2 = 0;
        count = 1;
        for(int i = y+1; i < 15; ++i) {
            if(broad[x][i] == type) {
                ++count;
            } else {
                if(broad[x][i] == EMPTY) {
                    tryx1 = x;
                    tryy1 = i;
                    int j = i+1;
                    while(j<15 && broad[x][j] == type) {
                        ++add1;
                        ++j;
                    }
                }
                break;
            }
        }
        if(count >= 5) return true;
        for(int i = y-1; i >= 0; --i) {
            if(broad[x][i] == type) {
                ++count;
            } else {
                if(broad[x][i] == EMPTY) {
                    tryx2 = x;
                    tryy2 = i;
                    int j = i-1;
                    while(j>=0 && broad[x][j] == type) {
                        ++add2;
                        --j;
                    }
                }
                break;
            }
        }
        if(count >= 5) return true;
        if(maxcount < count+max(add1,add2)&&(tryx1!=-1 || tryx2!=-1)) {
            maxcount = count+max(add1,add2);
            if(add1 == add2) {
                if(tryx1 == -1) {
                    nextpos = make_pair(tryx2,tryy2);
                } else {
                    nextpos = make_pair(tryx1,tryy1);
                }
            } else {
                nextpos = add1 > add2?make_pair(tryx1,tryy1):make_pair(tryx2,tryy2);
            }
        }
        cout << "纵向检测:" << maxcount << " Point:" << nextpos.first << "," << nextpos.second << endl;
        //斜向检测
        count = 1;
        tryx1 = tryy1 = tryx2 = tryy2 = -1;
        add1 = add2 = 0;
        for(int i = 1; i <= 5 && x+i < 15 && y+i < 15; ++i) {
            if(broad[x+i][y+i] == type) {
                ++count;
            } else {
                if(broad[x+i][y+i] == EMPTY) {
                    tryx1 = x+i;
                    tryy1 = y+i;
                    int j = i+i+1,k = y+i+1;
                    while(j < 15 && broad[j][k] == type) {
                        ++add1;
                        ++j;
			++k;
                    }
                }
                break;
            }
        }
        if(count >= 5) return true;
        for(int i = 1; i<=5 && x-i>=0 && y-i>=0; ++i) {
            if(broad[x-i][y-i] == type) {
                ++count;
            } else {
                if(broad[x-i][y-i] == EMPTY) {
                    tryx2 = x-i;
                    tryy2 = y-i;
                    int j = x-i-1,k = y-i-1;
                    while(j >=0 && broad[j][k] == type) {
                        ++add2;
                        --j;
			--k;
                    }
                }
                break;
            }
        }
        if(count >= 5) return true;
        if(maxcount < count+max(add1,add2)&&(tryx1!=-1||tryx2!=-1)) {
            maxcount = count+max(add1,add2);
            if(add1 == add2) {
                if(tryx1 == -1) {
                    nextpos = make_pair(tryx2,tryy2);
                } else {
                    nextpos = make_pair(tryx1,tryy1);
                }
            } else {
                nextpos = add1 > add2?make_pair(tryx1,tryy1):make_pair(tryx2,tryy2);
            }
        }
        cout << "斜向检测:" << maxcount << " Point:" << nextpos.first << "," << nextpos.second << endl;
        //反斜检测
        count = 1;
        tryx1 = tryy1 = tryx2 = tryy2 = -1;
        add1 = add2 = 0;
        for(int i = 1; i <= 5 && x+i < 15 && y-i >= 0; ++i) {
            if(broad[x+i][y-i] == type) {
                ++count;
            } else {
                if(broad[x+i][y-i] == EMPTY) {
                    tryx1 = x+i;
                    tryy1 = y-i;
                    int j = x+i+1,k = y-i-1;
                    while(j < 15 && k>=0 && broad[j][k] == type) {
                        ++add1;
                        ++j;
                        --k;
                    }
                }
                break;
            }
        }
        if(count >= 5) return true;
        for(int i = 1; i<=5 && x-i>=0 && y+i<15; ++i) {
            if(broad[x-i][y+i] == type) {
                ++count;
            } else {
                if(broad[x-i][y+i] == EMPTY) {
                    tryx2 = x-i;
                    tryy2 = y+i;
                    int j = x-i-1,k = y+i+1;
                    while(j >=0 && k<15 && broad[j][k] == type) {
                        ++add2;
                        --j;
                        ++k;
                    }
                }
                break;
            }
        }
        if(count >= 5) return true;
        if(maxcount < count+max(add1,add2)&&(tryx1!=-1||tryx2!=-1)) {
            maxcount = count+max(add1,add2);
            if(add1 == add2) {
                if(tryx1 == -1) {
                    nextpos = make_pair(tryx2,tryy2);
                } else {
                    nextpos = make_pair(tryx1,tryy1);
                }
            } else {
                nextpos = add1 > add2?make_pair(tryx1,tryy1):make_pair(tryx2,tryy2);
            }
        }
        cout << "反斜检测:" << maxcount << " Point:" << nextpos.first << "," << nextpos.second << endl;
        return false;
    }
    void OnPaint(wxPaintEvent&) {
        //定义画笔
        wxPaintDC dc(this);
        //棋盘居中
        wxSize size = GetClientSize();
        int left = (size.GetWidth()-linelen)/2;
        int top = (size.GetHeight()-linelen)/2;
        offset = wxPoint(left,top);
        for(int i = 0; i < 15; ++i) {
            //dc.DrawLine(wxPoint(left,top+cellsize*i),wxPoint(left+linelen,top+cellsize*i));
            //dc.DrawLine(wxPoint(left+cellsize*i,top),wxPoint(left+cellsize*i,top+linelen));
            dc.DrawLine(wxPoint(0,cellsize*i)+offset,wxPoint(linelen,cellsize*i)+offset);
            dc.DrawLine(wxPoint(cellsize*i,0)+offset,wxPoint(cellsize*i,linelen)+offset);
        }
        for(int i = 0; i < 15; ++i) {
            for(int j = 0; j < 15; ++j) {
                if(broad[i][j] != EMPTY) DisplayChess(dc,i,j);
            }
        }
    }
    void DisplayChess(wxPaintDC& dc,int x,int y) {
        dc.SetBrush(broad[x][y] == WHITE? *wxWHITE_BRUSH:*wxBLACK_BRUSH);
        //dc.DrawCircle(offset.x+x*cellsize,offset.y+y*cellsize,cellsize/2);
        //dc.DrawCircle(wxPoint(x*cellsize,y*cellsize)+offset,cellsize/2);
        dc.DrawCircle(wxPoint(x,y)*cellsize+offset,cellsize/2);
    }
};
//框架类
//框架类中添加面板类
class GoFrame:public wxFrame {
public:
    GoFrame(const char* title):wxFrame(nullptr,wxID_ANY,title) {
        wxPanel* p = new GoPanel(this);
        SetSize(wxSize(500,500));
    }
};
//应用程序类
//应用程序类中添加框架类
class GoApp:public wxApp {
public:
    bool OnInit()override {
        GoFrame* pframe = new GoFrame("Name");
        pframe->Show();
        return true;
    };
};

wxIMPLEMENT_APP(GoApp);
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值