该项目是基于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);