基于wxWidgets实现一个五子棋游戏
2.2 功能1、显示一个15*15线组成的围棋棋盘。
2、棋子只能落在线的交点上。
3、黑白子交替下棋。
4、当黑子或者白子连续五个子组成一条直线,则为胜利。
实例:双人对战
#include2.3 加入AI算法实现人机对战#include using namespace std; //面板类 class GoPanel:public wxPanel{ vector 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);
最常见的基本棋型大体有以下几种:连五,活四,冲四,活三,眠三,活二,眠二。
- 必胜
- 将胜
- 待胜
- 不胜
| 棋型 | 进攻方 | 防守方 |
|---|---|---|
| 连五 | 胜 | 负 |
| 活四 | 必胜 | 必负 |
| 冲四 | 必须进攻 | 必须防守 |
| 活三 | 必须进攻 | 必须防守 |
| 眠三 | 可以进攻 | 可以进攻 |
| 活二 | 可以进攻 | 可以进攻 |
| 眠二 | 可以进攻 | 可以进攻 |
- 规则:
1、连五直接判定胜负。
2、活四、冲四、活三抢占关键点。
3、眠三、活二、眠二优先进攻。
判断整个棋盘黑白所有的棋型,选取优势棋型进攻防守。例如,执白,如果黑棋的棋型优于白棋防守;反之进攻。
- 实例:加入AI算法的人机五子棋对战
注:机器方仅有防守功能,需进一步优化
#include#include using namespace std; //面板类 class GoPanel:public wxPanel { vector 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 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);



