五子棋工程心得
1.工程框架
1.1分级管理
- 对于一个工程的编辑来说为了更好的管理所有的应用,main函数中只包括几个工程管理外不要加其他的函数,这样有利于你的层级管理如下:
int main(int argc,char const *argv[])
{
loop:
//项目初始化
project_init();
//项目运行
project_run();
//项目资源回收
project_uninit();
goto loop;
return 0;
}
- 对于不同功能的函数进行分类为初始化、运行、资源回收三个工程函数,让它们分别管理工程里的初始化、运行,资源回收的相应函数。例如:
void project_init()
{
//初始化lcd
lcd_init();
//初始化touch
touch_init();
//棋盘棋子置空
pieces_init();
}
1.2在工程管理头文件中定义、管理全局变量
这样的作法一般用于多文件全局变量,不建议用于单文件的全局变量,单文件建议用(static修饰)。
/*
多文件全局变量!
以及跨文件宏定义!
*/
#ifndef _PROJECT_H_
#define _PROJECT_H_
#define quit_game 0xff
#define undraw 0xfe
#define Empty_pieces 0x00
#define NonEmpty_pieces 0x01
#define black 0
#define white 1
#define colorless 0xfd
#define Covered 1
#define unCovered 0
typedef struct coordinate{
int x;
int y;
int Function_flag;
}Coordinate;
typedef struct piecesdata{
char pieces[16][16];
char black_white[16][16];
char game_progress[16][16];
char pieces_color;
char blackcount;
char whitecount;
}Piecesdata;
Coordinate location;
Piecesdata ps;
#endif
/*
单文件全局变量静态化
*/
static char fd_lcd;
2.算法简析
2.1网格定点算法简析
- 对于一个触摸屏上的网格点查询附近的点的采用最小距离有两种;坐标做差取最小,i = (x-15)/30;x =
(i30+15-x)>(i30+45-x)?(i30+45):(i30+15);y坐标也相同的处理。功能当你想点击周围四个点被覆盖的点,由于电容屏的精确度较低,我们需要提高用户的体验感
做的处理,采用欧拉公式法:x = (pow2((30-minx),miny)<pow2(minx, (30-miny))
?(x-30):(pow2(minx, (30-miny))<pow2((30-minx), (30-miny))?(x):(x-30)));
/*
网格定点算法
location.x,location.y为全局变量
网格的开始坐标为(175,15)
结束坐标为(625,465)
*/
#define pow2(x,y) ((x)*(x)+(y)*(y))
void location_change_grid()
{
int x,y;
x = location.x;
y = location.y;
if(abs(y-400)>240||abs(x-240) > 240)
{
location.Function_flag = undraw;
}
else
{
int i,j;
i = (x-15)/30;
x = (i*30+15-x)>(i*30+45-x)?(i*30+45):(i*30+15);
j = (y-175)/30;
y = (j*30+175-y)>(j*30+205-y)?(j*30+205):(j*30+175);
/*
功能当你想点击周围四个点被覆盖的点,
由于电容屏的精确度较低,我们需要提高用户
的体验感 做的处理
*/
if(ps.pieces[(x-15)/30][(y-175)/30] != Empty_pieces)
{
int minx,miny;
if(x < location.x && y < location.y) //在相对位置的第一象限
{
minx = abs(location.x - x);
miny = abs(location.y - y);
x = (pow2((30-minx),miny)<pow2(minx, (30-miny))
?(x+30):(pow2(minx, (30-miny))<pow2((30-minx), (30-miny))?(x):(x+30)));
y = (pow2((30-minx),miny)<pow2(minx, (30-miny))
?(pow2((30-minx), miny)<pow2((30-minx), (30-miny))?(y):(y+30)):(y+30));
}
else if(x > location.x && y < location.y) //在相对位置的第二象限
{
minx = abs(location.x - x);
miny = abs(location.y - y);
x = (pow2((30-minx),miny)<pow2(minx, (30-miny))
?(x-30):(pow2(minx, (30-miny))<pow2((30-minx), (30-miny))?(x):(x-30)));
y = (pow2((30-minx),miny)<pow2(minx, (30-miny))
?(pow2((30-minx), miny)<pow2((30-minx), (30-miny))?(y):(y+30)):(y+30));
}
else if(x > location.x && y > location.y)//在相对位置的第三象限
{
minx = abs(location.x - x);
miny = abs(location.y - y);
x = (pow2((30-minx),miny)<pow2(minx, (30-miny))
?(x-30):(pow2(minx, (30-miny))<pow2((30-minx), (30-miny))?(x):(x-30)));
y = (pow2((30-minx),miny)<pow2(minx, (30-miny))
?(pow2((30-minx), miny)<pow2((30-minx), (30-miny))?(y):(y-30)):(y-30));
}
else if(x < location.x && y > location.y)//在相对位置的第四象限
{
minx = abs(location.x - x);
miny = abs(location.y - y);
x = (pow2((30-minx),miny)<pow2(minx, (30-miny))
?(x+30):(pow2(minx, (30-miny))<pow2((30-minx), (30-miny))?(x):(x+30)));
y = (pow2((30-minx),miny)<pow2(minx, (30-miny))
?(pow2((30-minx), miny)<pow2((30-minx), (30-miny))?(y):(y-30)):(y-30));
}
else //其他
{
location.Function_flag = undraw;
}
}
}
location.x = x;
location.y = y;
}
minx = abs(location.x - x);
miny = abs(location.y - y);
//三点与获取点之间的次进点,前项x为最近点
//采用最小距离公式——欧拉公式
x = (pow2((30-minx),miny)<pow2(minx, (30-miny))
?(x-30):(pow2(minx, (30-miny))<pow2((30-minx), (30-miny))?(x):(x-30)));
//同上
y = (pow2((30-minx),miny)<pow2(minx, (30-miny))
?(pow2((30-minx), miny)<pow2((30-minx), (30-miny))?(y):(y-30)):(y-30));
2.2判定游戏是否结束
- 对于五子棋的游戏结束有以有连成五子或以上的子就结束,可能出现的情况是左斜对角,右斜对角,横,竖。分别用函数实现如下的int
passTop_right(int i,int j,int n,int m) 参数:当前位置为i,j;原位置n,m。
/*
将棋盘的信息存储在
typedef struct piecesdata{
char pieces[16][16];//是否下有棋子
char black_white[16][16];//是黑子还是白子或无子
char game_progress[16][16];//是否以及判定过这一个点
char pieces_color;//当前下子的颜色
char blackcount;//黑子数
char whitecount;//白字数
}Piecesdata;中
*/
#define max(x,y) ((x)>(y)?(x):(y))
static char win;
int passTop_right(int i,int j,int n,int m);
int pass_right(int i,int j,int n,int m);
int passBottom_right(int i,int j,int n,int m);
int pass_Bottom(int i,int j,int n,int m);
int pass(int i, int j, int n, int m);
int game_over()
{
for(int i = 0;i < 16;i++)
{
for(int j = 0;j < 16;j++)
{
ps.game_progress[i][j] = 0;
}
}
int count;
for(int j = 0;j < 16;j++)
{
for(int i = 0;i < 16;i++)
{
count = 0;
if(ps.game_progress[i][j] == unCovered)
{
count = pass(i, j, i, j);
}
if(count >= 5)
{
if(ps.black_white[i][j] == black)
win = black;
else
win = white;
location.Function_flag = -1;
break;
}
}
}
}
//判断当前位置左上角是否有五子,返回左上方向上的棋子数
int passTop_right(int i,int j,int n,int m)
{
if(ps.black_white[i][j] == colorless||ps.black_white[i][j]!=ps.black_white[n][m]
||i < 0||j < 0||i >= 16||j >= 16)
{
return 0;
}
return passTop_right(i-1, j+1, n, m)+1;
}
//判断当前位置左角是否有五子,返回左方向上的棋子数
int pass_right(int i,int j,int n,int m)
{
if(ps.black_white[i][j] == colorless||ps.black_white[i][j]!=ps.black_white[n][m]
||i < 0||j < 0||i >= 16||j >= 16)
{
return 0;
}
return pass_right(i, j+1, n, m)+1;
}
//判断当前位置左下角是否有五子,返回左下方向上的棋子数
int passBottom_right(int i,int j,int n,int m)
{
if(ps.black_white[i][j] == colorless||ps.black_white[i][j]!=ps.black_white[n][m]
||i < 0||j < 0||i >= 16||j >= 16)
{
return 0;
}
return passBottom_right(i+1, j+1, n, m)+1;
}
//判断当前位置下角是否有五子,返回下方向上的棋子数
int pass_Bottom(int i,int j,int n,int m)
{
if(ps.black_white[i][j] == colorless||ps.black_white[i][j]!=ps.black_white[n][m]
||i < 0||j < 0||i >= 16||j >= 16)
{
return 0;
}
return pass_Bottom(i+1, j, n, m)+1;
}
//返回所有路径上的最多的个数。
int pass(int i, int j, int n, int m)
{
int Top_right,right,Bottom_right,Bottom;
Top_right = passTop_right(i, j, n, m);
right = pass_right(i, j, n, m);
Bottom_right = passBottom_right(i, j, n, m);
Bottom = pass_Bottom(i, j, n, m);
return (max(Top_right,max(right,max(Bottom,Bottom_right))));
}
2020/7/17 10:27 finish 艺果yiguo
https://pan.baidu.com/s/1300HNo43HgPZwtXF-wt1Qw
提取码:yigu