手把手教你写五子棋程序
- 编译环境:vs2019;
- 注意事项:项目属性中高级的字符集选项要设置为多字节;
- 关于图形库EasyX:需要用到该图形化库的库函数,没有下载安装的需要先下载安装改库,关于这个库的函数可自己找相关文档了解;
- 由于代码较多,为了方便管理,我添加了6个头文件来结构化模块化,所以不贴出完整代码,会挑出主要部分来叙述,我会将源文件上传CSDN,有需要可自行下载;
- 注:文章作为自己成长的记录,不足之处还请多指教,师承大帅。
项目分析
- 开始界面:一个简单的开始界面,有开始游戏和退出两个按钮和功能;
- 下面我们首先来看一下程序截图,然后封装这两个按钮:
程序截图
使用结构体封装按钮代码:
typedef struct MYBUTTON
{
int x;
int y;
int width;
int height;
char* str;
COLORREF cur_Color;
COLORREF in_Color;
COLORREF out_Color;
}MyButton, * p_MyButton;
- 首先定义一个结构体,包含按钮的x,y轴坐标,宽,高按钮颜色等;
关于结构体别名
- 不加typedef:struct 结构名;然后就可以用结构体名来定义结构体变量;
- 加typedef: typedef struct 结构体名 { 结构体 }结构体别名XXX;
- 结构体别名就相当于:struct 结构体名 结构体别名;
- 使用别名可以很方便的定义结构体变量。
初始化按钮结构体:
p_MyButton setButton(int x,int y,int width,int height,
COLORREF in_color,COLORREF out_color,const char *str)
{
p_MyButton pb = (p_MyButton)malloc(sizeof(MyButton));
assert(pb);
pb->x = x;
pb->y = y;
pb->width = width;
pb->height = height;
pb->cur_Color = out_color;
pb->in_Color = in_color;
pb->out_Color = out_color;
//这里这样写是因为字符串不能直接赋值
int strLong = strlen(str) + 1;
pb->str = (char*)malloc(sizeof(char) * strLong);
assert(pb->str);
strcpy_s(pb->str, strLong, str);
return pb;
}
封装按钮
void draw_Button(p_MyButton pb)
{
//这里调用easyx的库函数,easyx是一个封装的图形库
setlinecolor(BLUE);
setfillcolor(pb->cur_Color);
fillrectangle(pb->x, pb->y, pb->x + pb->width,
pb->y + pb->height);
settextcolor(WHITE);
setbkmode(TRANSPARENT);
settextstyle(30, 0, "楷体");
int textw = textwidth(pb->str);
int texth = textheight(pb->str);
int x = pb->x + (pb->width - textw) / 2;
int y = pb->y + (pb->height - texth) / 2;
outtextxy(x, y, pb->str);
}
关于文字居中问题:
- 可以据此图分析其原理,文字居中就相当于求解 ( a, b)这样的一个简单数学题;
游戏问题:
- 我们可以将整个棋盘理解为一个二维数组,0表示未落子为空的状态,1表示黑子(或白子),2表示白字(或黑子);
- 考虑到后期能会为玩家添加某些属性,所以我定义了这样一个结构体来管理(包含了玩家走的步数和唯一标识的ID,这个ID我用来区分和标识是该谁落子和谁落子):
typedef struct PCUSER
{
int User_ID;
int User_Step;
}Pc_User, * p_PcUser;
下面展示主函数:
int main()
{
StartMenu();
ExMessage m;
//初始化按钮
p_MyButton pb_1_play = setButton(100, 100, 200, 40, RED, BLUE, "play game");
p_MyButton pb_2_exit = setButton(100, 160, 200, 40, BLUE, RED, "exit");
//初始化玩家
p_PcUser pc_1 = setUser(1, 0);
p_PcUser pc_2 = setUser(2, 0);
//初始化棋子
p_MyChess pq_1 = setChess(5, WHITE);
p_MyChess pq_2 = setChess(5, BLACK);
int Arr_Chess[21][21] = { 0 };
//胜利function
bool isWin(const int Arr[][21],p_PcUser pc);
void textWin();
//void show(const int Arr[][21]);
BeginBatchDraw();
while (1)
{
FlushBatchDraw();
peekmessage(&m, EM_MOUSE);
draw_Button(pb_1_play);
draw_Button(pb_2_exit);
if (click_Button(m, pb_1_play))
{
FlushBatchDraw();
break;
}
if (click_Button(m, pb_2_exit))
{
exit(OVERFLOW);
}
}
drawMap();
//drawChess(200, 200, BLACK);
while (1)
{
FlushBatchDraw();
while (peekmessage(&m, EM_MOUSE))
{
//cout << "进来了" << endl;
if (pc_1->User_Step <= pc_2->User_Step && m.message == WM_LBUTTONDOWN
&& Arr_Chess[getX_Click(m)+4][getY_Click(m)+4]==0)
{
cout << "进来if条件了" << endl;
if (Click_Draw_Chess(m, pq_1))
{
Arr_Chess[getX_Click(m) + 4][getY_Click(m) + 4] = pc_1->User_ID;
pc_1->User_Step++;
//show(Arr_Chess);
}
//cout << pc_1->User_Step << ' ' << pc_2->User_Step << endl;
break;
}
else
if(pc_1->User_Step > pc_2->User_Step && m.message == WM_LBUTTONDOWN
&& Arr_Chess[getX_Click(m)+4][getY_Click(m)+4] == 0)
{
if (Click_Draw_Chess(m, pq_2))
{
Arr_Chess[getX_Click(m) + 4][getY_Click(m) + 4] = pc_2->User_ID;
pc_2->User_Step++;
//show(Arr_Chess);
}
//cout << pc_1->User_Step << ' ' << pc_2->User_Step << endl;
break;
}
}
FlushBatchDraw();
//cout << "老弟来啦!" << endl;
if (pc_1->User_Step >= 5 && isWin(Arr_Chess, pc_1))
{
textWin();
FlushBatchDraw();
//cout << "玩家1胜利" << endl;
break;
}
if (pc_2->User_Step >= 5 && isWin(Arr_Chess, pc_2))
{
textWin();
FlushBatchDraw();
//cout << "玩家2胜利" << endl;
break;
}
}
while (1);
EndBatchDraw();
return 0;
}
-
要解决的冲突问题:该谁落子;棋子不能覆盖(后手落子的玩家不能覆盖前一个玩家的落子);
-
要解决的判断胜负问题:我是用二维数组来做的棋盘,用全盘扫描来判断是否有玩家符合,所以要考虑扫描溢出的问题,下面我们来看一下扫面图解:
-
玩家胜出的情况无非就是我圈出来的这几种,所以判断胜负只需要做一个二维数组的全盘扫描,但是要注意扫描溢出问题,所以在定义棋盘数组的时候可以定义得大一些,我就吧棋盘的二维数组定义为2121的,但实际用到的只有1313;
-
关于音乐、音效,贴图等功能,各位可先自行尝试,后续我会分享有关内容。
-
下面来看一看运行截图:
-
关于该项目的主要几点和内容分析我就分析到这儿,如有疑问可私信或评论讨论,不足之处还请各位大佬指教,最后附上项目的网盘链接(嫌弃下载慢的可在我上传的资源中下载):https://pan.baidu.com/s/1txsNC7zMbJD3mvOcJog0WA 提取码:8bbr