这辈子再也不用Turbo C写东西了_(:зゝ∠)_
功能
- 有比较友好(大概友好吧:) )的界面。
- 采用贪心算法,能与计算机对弈
流程图
![](https://images2018.cnblogs.com/blog/1415620/201806/1415620-20180620222212527-297117452.png)
主函数
int main()
{
int gd = DETECT, gm = 0;
int key;
initgraph(&gd, &gm, "c:\\tc");
opencartoon(); /*开场动画*/
init(); /*界面和棋盘初始化*/
key = get_key();
while (!quit) { /*只要没有退出就继续*/
switch (key) {
case UP: move(0); break; /*下面四个是上下左右的操作*/
case DOWN: move(1); break;
case LEFT: move(2); break;
case RIGHT: move(3); break;
case ENTER: /*用户下棋*/
if (!res && userplace(WHITE)) { /*如果游戏没有结束且用户要下棋了*/
if ((res = judgewinner(1)) == 0) { /*如果用户没赢*/
computerplace(RED); /*则轮到电脑下棋*/
res = judgewinner(-1); /*判断电脑赢了吗*/
}
}
break;
case F1: judgerestart(); break; /*重新开始*/
case ESC: quit = judgequit(); break; /*退出*/
}
if (notchoose && res) { /*游戏结束了且用户没有选择是否继续留在游戏里*/
if (printres(res)) /*显示游戏结果(输赢),并判断用户是否继续留在游戏里*/
quit = 1; /*用户不愿意留在游戏里,退出*/
notchoose = 0; /*用户已做出选择*/
}
if (!quit) key = get_key(); /*如果没有退出,继续接受键盘事件*/
}
cleardevice(); /*清屏*/
goodbyecartoon(); /*退出动画*/
closegraph();
return 0;
}
处理键盘响应
- Turbo C中用
bioskey()
,会返回两个值:扫描码和ASCII码
- 扫描码和ASCII码各占8位
- 有些特殊的键没有ASCII码,只有扫描码,比如F1键。这时候ASCII码为0
/*键盘宏定义*/
#define UP 0x4800 /*方向键上*/
#define DOWN 0x5000 /*方向键下*/
#define LEFT 0x4b00 /*方向键左*/
#define RIGHT 0x4d00 /*方向键右*/
#define ENTER 13
#define ESC 27
#define F1 0x3B00
/*键值的定义*/
typedef union {
int word;
char byte;
}keycode;
/*返回按下的键值*/
int get_key()
{
keycode key;
key.word = bioskey(0); /*bioskey(0)会一直等待有键按下*/
return key.byte ? key.byte : key.word;
}
界面设计
- 将对话框的显示封装成函数dialog,允许定制对话框的颜色样式(包括边框颜色),定制文本内容
void init()
{
char *help_text[] = {"1.ESC - Quit", "2.Direct Key - Move", "3.Enter - Put chess", "4.F1 - Restart",
"Note: You move first.", "If there is no place", "to put chess, you", "would LOSE!"};
initialize(); /*初始化棋盘*/
cleardevice(); /*清屏*/
drawbackgroud(YELLOW);
n = m = 10; /*棋盘10行10列*/
cposx = 50; /*棋盘左上角坐标为(50, 80)*/
cposy = 80;
drawchessboard(cposx, cposy, n, m, DARKGRAY); /*画出棋盘*/
drawtitle(cposx - 3, 10, "======Five in a Row======", BLUE); /*写标题*/
dialog(cposx + (n + 1) * W + 10, 30, 200, 400, "***Help***", help_text, 8,
WHITE, BLUE, CYAN, LIGHTGRAY, BLUE, RED); /*帮助文档框*/
row = 5, col = 5; /*当前准心在第五行第五列*/
drawtarget(cposx, cposy, row, col, RED); /*绘准心*/
quit = 0; /*是否退出*/
res = 0; /*对弈结果*/
notchoose = 1; /*是否选择留在游戏中*/
tot = 0; /*下的总步数*/
}
void drawbackgroud(int color)
{
/*绘制背景*/
setbkcolor(color);
}
void drawchessboard(int x, int y, int r, int c, int color)
{
/*绘制棋盘*/
int height = (r + 1) * W;
int weight = (c + 1) * W;
int i;
setcolor(color);
line(x, y, x + weight, y);
line(x, y + height, x + weight, y + height);
line(x, y, x, y + height);
line(x + weight, y, x + weight, y + height);
setlinestyle(DOTTED_LINE, 0, 1); /*虚线*/
for (i = 1; i <= r; i++)
line(x, y + i * W, x + weight, y + i * W);
for (i = 1; i <= c; i++)
line(x + i * W, y, x + i * W, y + height);
}
void drawtitle(int x, int y, char *title, int color)
{
/*绘制标题*/
setcolor(color);
settextstyle(3, 0, 3);
outtextxy(x, y, title);
}
void dialog(int x, int y, int width, int height, char *title, char **message, int lines,
int bk, int shadow, int bkedge, int shadowedge, int titlec, int messagec)
{
/*bk对话框颜色、shadow阴影颜色、bkedge边框颜色、shadowedge阴影边框颜色、titlec标题文字颜色、messagec信息文字颜色*/
int i;
setcolor(shadowedge);
setlinestyle(SOLID_LINE, 0, 1);
rectangle(x + 20, y + 20, x + width + 20, y + height + 20);
setfillstyle(1, shadow);
floodfill((2 * x + width + 40) / 2, (2 * y + height + 40) / 2, shadowedge);
setcolor(bkedge);
rectangle(x + 10, y + 10, x + width + 10, y + height + 10);
setfillstyle(1, bk);
floodfill((2 * x + width) / 2, (2 * y + height) / 2, bkedge);
setcolor(titlec);
settextstyle(3, 0, 2);
outtextxy(x + 20, y + 20, title);
setcolor(messagec);
settextstyle(3, 0, 1);
for (i = 0; i < lines; i++)
outtextxy(x + 20, y + 20 + 30 * (i + 1), message[i]);
}
用户操作处理
/*简化代码*/
const int mover[] = {-1, 1, 0, 0};
const int movec[] = {0, 0, -1, 1};
void move(int type)
{
/*用户移动准心*/
int tr = row, tc = col;
tr += mover[type];
tc += movec[type];
if (tr == 0 || tr > n || tc == 0 || tc > m) return;
drawtarget(cposx, cposy, row, col, YELLOW); /*擦除原来的准心*/
drawtarget(cposx, cposy, tr, tc, RED);
row = tr;
col = tc;
}
int judgequit()
{
/*用户退出操作*/
int key;
unsigned size;
void *buf;
char *message[] = {"Do you want to quit?(Y/N)"};
/*这里要复制原先的图像,否则如果用户取消就回不去了。。。下面的重新开始游戏也一样*/
size = imagesize(100, 200, 520, 320);
buf = malloc(size);
getimage(100, 200, 520, 320, buf);
dialog(100, 200, 400, 100, "", message, 1,
WHITE, BLUE, LIGHTBLUE, GREEN, RED, BLUE);
key = get_key();
while (!(key == 'y' || key == 'n' || key == 'Y' || key == 'N')) {
key = get_key();
}
if (key == 'N' || key == 'n')
putimage(100, 200, buf, COPY_PUT);
free(buf);
return (key == 'y' || key == 'Y') ? 1 : 0;
}
int userplace(int color)
{
/*绘制用户的棋子*/
int px = cposx, py = cposy;
if (chess[row][col] == 0) {
setcolor(WHITE);
setlinestyle(SOLID_LINE, 0, 1);
px += col * W;
py += row * W;
circle(px, py, W / 4);
setfillstyle(1, color);
floodfill(px, py, WHITE);
chess[row][col] = 1;
tot++;
return 1;
} else
return 0;
}
int judgerestart()
{
/*重新开始游戏操作*/
int key;
unsigned size;
void *buf;
char *message[] = {"Do you want to restart?(Y/N)"};
size = imagesize(100, 200, 520, 320);
buf = malloc(size);
getimage(100, 200, 520, 320, buf);
dialog(100, 200, 400, 100, "", message, 1,
WHITE, BLUE, LIGHTBLUE, GREEN, RED, BLUE);
key = get_key();
while (!(key == 'y' || key == 'n' || key == 'Y' || key == 'N')) {
key = get_key();
}
if (key == 'N' || key == 'n')
putimage(100, 200, buf, COPY_PUT);
else
init();
free(buf);
return (key == 'y' || key == 'Y') ? 1 : 0;
}
计算机自动下棋——贪心算法实现
- 计算机的下棋策略是贪心的,可能不如搜索来的智能,但足以挑战初学者
void computerplace(int color)
{
/*计算机下棋,绘制*/
int cx = cposx, cy = cposy;
computerjudge();
setcolor(WHITE);
setlinestyle(SOLID_LINE, 0, 1);
cx += ccol * W;
cy += crow * W;
circle(cx, cy, W / 4);
setfillstyle(1, color);
floodfill(cx, cy, WHITE);
chess[crow][ccol] = -1;
tot++;
}
void computerjudge()
{
/*得到棋盘上哪一点是“最优的”*/
int i, j;
int tppr, tppc, tpcr, tpcc;
int pscore[MAXN][MAXN], cscore[MAXN][MAXN];
int mxp = 0, mxc = 0;
memset(pscore, 0, sizeof(pscore));
memset(cscore, 0, sizeof(cscore));
for (i = 1; i <= n; i++) {
for (j = 1; j <= m; j++) if (chess[i][j] == 0) {
getscore(i, j, pscore, 1);
getscore(i, j, cscore, -1);
}
}
for (i = 1; i <= n; i++) {
for (j = 1; j <= m; j++) {
if (pscore[i][j] > mxp) {
mxp = pscore[i][j];
tppr = i, tppc = j;
}
if (cscore[i][j] > mxc) {
mxc = cscore[i][j];
tpcr = i, tpcc = j;
}
}
}
if (mxp >= mxc) {
crow = tppr, ccol = tppc;
} else {
crow = tpcr, ccol = tpcc;
}
}
void getscore(int rr, int cc, int score[MAXN][MAXN], int who)
{
/*计算棋盘上每个点的分数*/
int another = -who;
int tot = 0;
int num, l, r;
int tr, tc;
int i, j;
for (i = 0; i < 4; i++) {
num = l = r = 0;
j = 1;
while (1) {
tr = rr + j * dirr[i];
tc = cc + j * dirc[i];
if (tr > 0 && tc > 0 && tr <= n && tc <= m && chess[tr][tc] == who) {
num++;
j++;
} else {
if (tr > 0 && tc > 0 && tr <= n && tc <= m && chess[tr][tc] == another)
l = 1;
break;
}
}
j = 1;
while (1) {
tr = rr + j * dirr[i + 4];
tc = cc + j * dirc[i + 4];
if (tr > 0 && tc > 0 && tr <= n && tc <= m && chess[tr][tc] == who) {
num++;
j++;
} else {
if (tr > 0 && tc > 0 && tr <= n && tc <= m && chess[tr][tc] == another)
r = 1;
break;
}
}
tot += judgetype(num, l, r);
}
score[rr][cc] = tot;
}
int judgetype(int num, int l, int r)
{
/*每种“类型”的得分*/
int sco = 0;
if (num >= 4)
sco += 10000;
else if (num == 3) {
if (!l && !r)
sco += 3000;
else if (!(l && r))
sco += 900;
} else if (num == 2) {
if (!l && !r)
sco += 460;
else if (!(l && r))
sco += 30;
} else if (num == 1) {
if (!l && !r)
sco += 45;
else if (!(l && r))
sco += 5;
} else if (num == 0) {
if (!l && !r)
sco += 3;
else if (!(l && r))
sco += 1;
}
return sco;
}
判断胜负
/*简化代码*/
const int dirr[] = {-1, 0, -1, -1, 1, 0, 1, 1};
const int dirc[] = {0, -1, -1, 1, 0, 1, 1, -1};
int judgewinner(int who)
{
int posr, posc;
int dir[8] = {0};
int i, j;
int tr, tc;
if (who == 1) {
posr = row;
posc = col;
} else {
posr = crow;
posc = ccol;
}
for (i = 0; i < 8; i++) {
j = 1;
while (1) {
tr = posr + j * dirr[i];
tc = posc + j * dirc[i];
if (tr > 0 && tc > 0 && tr <= n && tc <= m && chess[tr][tc] == who) {
dir[i]++;
j++;
} else
break;
}
}
for (i = 0; i < 4; i++) {
if (dir[i] + dir[i + 4] + 1 >= 5)
return who;
}
if (tot == n * m)
return -1;
return 0;
}
退出和进入游戏的动画
- 这一段代码几乎是抄一个博主写的,但我忘记是哪个博客给的了。。。(五子棋的代码本来也想复制一波的,但这位博主的代码实在不堪入目,自己重写了代码,并加入了计算机自动下棋功能)
- 凑代码量的东西,很简单:)
/*以下代码只贴“见”的字模*/
char jian64L[]={
/* 以下是 '见' 的 64点阵隶书 字模,512 byte */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x40,0x00,0x00,0x06,0x00,0x00,
0x00,0x00,0xF0,0x3F,0xFE,0x1F,0x00,0x00,
0x00,0x01,0xFF,0xFF,0xFF,0xFF,0x00,0x00,
0x00,0x01,0xFF,0xFF,0xFF,0xFF,0x80,0x00,
0x00,0x01,0xFF,0xFF,0xFF,0xFF,0x00,0x00,
0x00,0x01,0xF8,0x00,0x00,0x1F,0x00,0x00,
0x00,0x01,0xF0,0x00,0x00,0x1F,0x00,0x00,
0x00,0x00,0xF0,0x00,0x00,0x0F,0x00,0x00,
0x00,0x00,0xF0,0x0E,0x00,0x0F,0x00,0x00,
0x00,0x00,0xF0,0x1E,0x00,0x0F,0x00,0x00,
0x00,0x00,0xF0,0x1F,0x00,0x0F,0x00,0x00,
0x00,0x00,0xF0,0x1F,0x00,0x0F,0x00,0x00,
0x00,0x00,0xF0,0x1F,0x00,0x0F,0x00,0x00,
0x00,0x00,0xF0,0x1F,0x00,0x0F,0x00,0x00,
0x00,0x00,0xF0,0x1F,0x00,0x0F,0x00,0x00,
0x00,0x00,0xF0,0x1F,0x00,0x0F,0x00,0x00,
0x00,0x00,0xF0,0x1E,0x00,0x1F,0x00,0x00,
0x00,0x00,0xF0,0x1E,0x08,0x1F,0x00,0x00,
0x00,0x00,0xF0,0x1E,0x1C,0x1F,0x00,0x00,
0x00,0x00,0xF0,0x1E,0x1C,0x1F,0x00,0x00,
0x00,0x00,0xF0,0x1E,0x38,0x1F,0x80,0x00,
0x00,0x01,0xF0,0x3C,0x38,0x1F,0x80,0x00,
0x00,0x00,0xF0,0x3C,0x38,0x1F,0x00,0x00,
0x00,0x00,0x00,0x3C,0x70,0x0E,0x00,0x00,
0x00,0x00,0x00,0x78,0x70,0x00,0x00,0x00,
0x00,0x00,0x00,0xF8,0x70,0x00,0x00,0x00,
0x00,0x00,0x01,0xF0,0xF0,0x00,0x00,0x00,
0x00,0x00,0x03,0xE0,0xF0,0x00,0x00,0x00,
0x00,0x00,0x0F,0xC0,0xF8,0x00,0x00,0x00,
0x00,0x00,0x3F,0x80,0xFE,0x00,0x00,0x04,
0x00,0x00,0xFF,0x00,0x7F,0xC0,0x00,0x3C,
0x00,0x07,0xFE,0x00,0x3F,0xFF,0xFF,0xF8,
0x00,0x7F,0xF8,0x00,0x1F,0xFF,0xFF,0xF8,
0x0F,0xFF,0xE0,0x00,0x0F,0xFF,0xFF,0xF0,
0x1F,0xFF,0x80,0x00,0x03,0xFF,0xFF,0xF0,
0x0F,0xFC,0x00,0x00,0x00,0x7F,0xFF,0xE0,
0x07,0xE0,0x00,0x00,0x00,0x07,0xFF,0xC0,
0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x80,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
void tim(int p)
{
int i;
for(i = 0; i < p; i++)
delay(500);
}
void drawmat(char *mat,int matsize,int x,int y,int color)
/*依次:字模指针、点阵大小、起始坐标(x,y)、颜色*/
{
int i, j, k, n;
n = (matsize - 1) / 8 + 1;
for(j = 0; j < matsize; j++) {
for(i = 0; i < n; i++) {
for(k = 0;k < 8; k++) {
if(mat[j * n + i] & (0x80 >> k)) /*测试为1的位则显示*/
putpixel(x + i * 8 + k, y + j, color);
}
}
}
}
void opencartoon()
{
drawmat(huan64L, 64, 149, 200, 1); tim(1);
drawmat(ying64L, 64, 249, 200, 2); tim(1);
drawmat(shang64L, 64, 349, 200, 12); tim(1);
drawmat(wan64L, 64, 449, 200, 4); tim(1);
}
void goodbyecartoon()
{
drawmat(zai64L, 64, 200, 200, 13); tim(1);
drawmat(jian64L, 64, 376, 200, 2); tim(1);
}