编程-C语言-课程设计-黑白棋
余年寄山水
981次浏览
2021年01月18日 14:45
最佳经验
本文由作者推荐
bypassed-灯影组
黑白棋实验报告
一、功能说明:
主要由三个界面实现。现以界面为序进行逐一介绍。
界面一:自动恢复:
功能简介:恢复棋局。
进入条件:
当上次从下棋界面进行了非正常跳出时,跳出。如果这个非正常跳出是关闭窗口,
则在下次打开 程序时跳出。
(定义:
下棋界面的非正常跳出指的是在一局棋没有下完并且也没有储 存的状态下,
点击
restart
按钮或者关闭窗口。
)
跳出方向:
有询问是否进行自动回复的按钮。如果选择是,则回到下棋界面,并恢复 上次未下
完的棋局。如果选择否,对上次未下完的棋局进行清空并进入游戏模式选择界面。
界面二:游戏模式选择
功能简介:游戏模式选择。主要有一下几种模式:
人人对弈
人机对弈,玩家先手
人机对弈,玩家后手
机机对弈
(其中,每种有
AI
参与的模式中的每个
AI
均可以有
6
种选择)
读取记录
(从三个记录中选取一个进行读取,若该记录为空,则会在本界面中有文字提示。
)
进入条件:
A.
在保存或下完后从下棋界面点击restart
时。
B.
上次是正常退出,这次打开程序时
跳出方向:
点击确定则按照选取的模式开始新的游戏,进入下棋界面。
点击确定读取且读取成功,则按照读取文件的信息继续游戏,进入下棋界面。
界面特色:
按照人人对弈、机机对弈、人机对弈的逻辑要求,从显示上提示玩家颜色 、
AI1
策略、
AI2
策略的有意义与否并若无意义,则无法对该量进行更改 。
界面三:下棋界面
功能简介:主要包括以下几个方面。
A.
下棋:
a.
人人对弈
b.
人机对弈(在玩家被欠手时,会
Sleep3000ms
)
c.
机机对弈(在任一方被欠手时,会
Sleep3000ms
)
双方
ai
均在控制者按任意键时开始走子。
B.
悔棋:悔到上一次玩家操作时的状态。
C.
落子提示:提示下一方的可落子点(染灰)
,可以通过
reminder
按钮进行 关闭。提
示上一次所落的点位(黄框)
。
D.
执棋方提示与现在比分提示。
E.
搜索进度提示:在有搜索的< br>AI
进行运行时,在开始搜索“如果
AI
走点
P
”时,将点
P
的颜色染成绿色,从而与落子提示一同构成搜索进度提示。
F.
背景音乐:选取古筝曲《春江花月夜》循环播放。且在这个界面可以执行暂停、
继续操作。
G.
储存:选择储存的目标文件与确定储存按钮。
H.
Restart
按钮
(
在悔棋和保存时,会有情况判断。拒绝开局 和游戏结束时的保存和悔棋,并在界面中
有文字提示说明。
(结束时悔棋太赖了
~而保存功能主要是为了以后接着下的,结束时
保存无意义,想留一下棋局的话直接按
prt sc
吧
~
)
)
进入条件:
A.
在模式选择界面选择玩游戏模式并按确定键时
B.
在模式选择界面选择 读取时
C.
在
自动恢复界面选择“是”
(自动回复)时。
跳出方向:
在按
restart
按钮时,< br>会根据是否是正常跳出,
跳到自动恢复界面或游戏模式选择界面。
其它特色:
鼠标操作手动截流。
(
graphics.h
的获取鼠标信息函数不截流,会导致明明只按了一下
却响应多下的情况,于是手动对次进行了一下调整。
)
AI
功能说明:
(六个
AI
基本依 强弱序,搜索一与搜索二强弱差异不大)
随机策略
:
从所有能走的点中随机选取一个点落子。
(为
1
所写)
贪吃策略
:
考虑
5
步,选择所有五步后的情况中,己方子数最多的一种情况进行走子。
复合估价
:
针对一个随输入棋盘情况的不同而动态调整估价值的估值函数进行直接估价,走
子。
这个动态估价函数会在一个比较复杂的估价列表的基础上,对于十二种不同的特
定边角情况进行 判断然后进行估价调整。
复合的地方在于:首先,它会判断一下有没有点能走完之后使得对手 欠手。如果
有,直接走。其次,在临终局
12
步时,进入残局搜索,一搜到底。
搜索
(
一
)
:
针对一个随输入棋盘情况的不同而 动态调整估价值的估价函数进行
4
步搜索估价,
走子。
(
估值函数比 较慢,所以只能搜
4
步了
.....)
这个估价函数随行动力和边角稳定点 的数目会有微调。
(估值函数为
1
所写)
并且:
首先,< br>它会判断一下有没有点能走完之后使得对手欠手。
如果有,
直接走。
其次,在临 终局
12
步时,进入残局搜索,一搜到底。
搜索
(
二
)
:
针
对一个静态估价值的估价函数进行
5
步搜索估价,走子。
这个估价函数的主要原理就是角、边、其它地方的价格不再同一个数量级上,其
他地方的价格之间有细 微差距。
并且:
首先,
它会判断一下有没有点能走完之后使得对手欠手。< br>如果有,
直接走。
其次,在临终局
12
步时,进入残局搜索,一搜到底 。
搜索
(
三
)
:
针对一个随输入棋盘情况的不同而动态调整估价值的估价函数进行
5
步搜索估价,
走 子。
这个估价函数就是复合估价的估价函数。
< br>并且:
首先,
它会判断一下有没有点能走完之后使得对手欠手。
如果有,
直接走。
其次,在临终局
12
步时,进入残局搜索,一搜到底。
二、分工说明:
1
完成:
AI ai001 ()
nt wendingdian(qp qipan,int i,int j)
int gujia3(qp qipan,int b)
实现随机
AI
功能与搜索一
AI
的估价核心。
2
完成:
其它函数和功能。
三、函数说明:
头文件:
#include
#include
#include
#include
#include
#include
#pragma comment(lib,
using namespace std;
全局参量与结构体的定义
int
qiz i[10][10];//
棋子状态:
0
为空,
1
为黑,
2
为白,
3
为空但目前可让黑棋下,
4
为空但目前
可让白棋下 。
int qishou;//
棋手状态:
1
为黑,
2
为白。
int music;//
音乐状态:
1
为开,
0
为关。
int reminder;//
提示状态:
1
为开,
0
为关。
int wanjiayanse;//
玩家颜色:
1
为黑(后手)
,
2
为白(先手)
。
int mode;//
游戏模式:
1
为人人对弈,
2
为人机对弈
,3
为机机对弈。
int black,white;//
当前状态下某种颜色棋子的数目,分别为白色和黑色。
char black1,black2,white1,white2;//
不能直接输出数 据,于是将
black
与
white
存在这两组字符数
中。
int couldmoveblack,couldmovewhite;//
记录截止到现 在最后一次该黑
/
白走时,
它所能走的不同步
数。
int ifjieshu;//
标记游戏是否已经结束,
0
为未结束,
1
为 结束。
int ifrestart;//
标记现在是否急切地需要进行
r estart
的操作,
如果真的需要的话,
为
1
,
否则为< br>0
。
int ifneedautoload=1;//
标记是否需 要启动自动读取。
0
为需要,
1
为不需要。
int if load=0;//
是否进行了自动读取,
0
为否;
1
为是。
int savecase=1;//
标记储存量,
0
为不需要执行储存 操作,
1
、
2
、
3
分别为需要对文件
1
、
2
、
3
进
行储存操作
int loadcase =1;//
标记读取量,
0
为不需要执行读取操作,
1
、
2
、
3
分别为需要对文件
1
、
2
、
3
进
行读取操作
int
ifcouldload=0;//
这个 量是针对手动读取的,如果为
1,
则认为这个量不可读,否则,则认为可
读。
int kindofai=1; //
这个量标记了现在
AI
的状态。
//1
为随机
AI
//2
为
3
步贪吃
AI
//3
为复合
ai1
//4
为搜索
(
一
)AI014
//5
为搜索
(
二
)
//6
为搜索
(
三
)
int kindofai_=1;//
这个量标记了现在
AI
的状态。
//1
为随机
AI
//2
为
3
步贪吃
AI
//3
为复合
ai1
//4
为搜索
(
一
)AI014
//5
为搜索
(
二
)
//6
为搜索
(
三
)
struct xx
{
int a[9][9][65];//
储存全部棋盘的状态
(
0
为空,
1
为黑,
2
为白 ,
3
为空但目前可让黑棋下,
4
为空但目前可让白棋下。
)
int n;//
为目前已走的步数,确切的说为目前棋盘上的棋子总数再减去
4
。
int c[65];//
第
i
部到底是谁走的?
1为黑,
2
为白。
int x[65];//
第
i
步所走位置的
x
坐标
int y[65];//
第
i
步所走位置的
y
坐标
};
struct yy
{
int left;
int right;
int upper;
int under;
int upperleft;
int underleft;
int upperright;
int underright;
int sum;
};
struct AI
{
int x;
int y;
};
xx
chucun;//
用结构体
xx
定义储存量,但这个东西其 实也就只能算是历史量了
~
。我拒绝在初始
状态下进行储存!
yy
zhuangtai[9][9];//
用结构体
yy
定义棋子状态,有8
个参量表示
8
个方向能吃到的子的数目。
一个参量表示这八个量的总和 。
在后面有越序调用的函数的声明。
(
略
)
储存相关函数:
void savex (wchar_t *place)
//
这个函数是对于存档进行转存,将
中的全部内容存到
*place
中,并将
清空
void savexx ()
//
这个函数是根据全局变量
savecase
进行转 存
,1
、
2
、
3
分别对应
、
、
,
然后对
savecase
进行归
1
。
void loadx (wchar_t *place)
//
这个函数是 将
*place
转存到
中,再将
save
读到内存
void loadxx ()
//
这个函数是根据
loadcase进行读取,
1
、
2
、
3
分别对应
、< br>
、
,然后
对
loadcase
进行归
1。
void pdifcouldload ()
//
这个函数是根 据
loadcase
进行判断该量可不可以读取,
1
、
2
、
3
分别对应
、
、
,将结果储存在
ifcouldload
中。
void saveas ()
//
这个函数是针对在游戏中点击“确定储存”后的不同情况,进行不同的处理。
void pdifneedautoload ()
//
这个函数是读一下
save
的第一个数据(
ifjieshu
)
,
如果结束了,认为 不再需要自动读取,否则
认为需要进行自动读取。
void save ()
//
这是个储存几乎所有全局参量的函数
,
到
void load ()
//
这是个读取几乎所有全局参量的函数
,
从
界面与控制相关函数:
void menuload0 ()
//
这个是在系统检测到你上一次没有正常退出时跳出的菜单
void menu0 ()
//
这是执行最初的那个选择菜单
.
在这个选择菜单中, 通过一系列鼠标操作对一些控制游戏模式
的全局参量进行修改。
//
并且,在这个菜单中还可以选择读取。
void countandchangestyle ()
//
计数
black
与< br>white
并将其转存到
black1
、
2
与
whi te1
、
2
中。然后再画出来。
void drawscreen0 ()
//
绘制图像
,
所有与棋盘状态无关的部分。
yy jszhuangtai (int qz[10][10],int m,int n,int a)
//a
为要判断的子的颜色,
1
为黑,
2
为白。返回的是对于一个 输入的棋盘状态,计算
m,n
位的
子,在八个方向能吃到的子数。
//
用于判断能否走棋以及怎么走棋。
void judgement (int a)
//a
为要判断的子的颜色,
1
为黑,
2
为白。
//
对棋盘上的所有位置调用
jszhuangtai
进行调用,并计入到全 局参数
YY zhuangtai
中。
void drawscreen1 ()
//
初始化棋盘上的那四个子
void drawscreen2 (int qz[10][10])
//
针对棋盘上的落子情况进行绘图,只是画那些与子相关的部分。
void musiccontrol ()
//
切换
music
的播放与暂停并刷屏
void remindercontrol ()
//
切换提示的显示与否并刷屏
void huiqicaozuo ()
//
对于点击“悔棋”之后的具体状态,进行悔棋的具体操作并储存。
void mousecontrol ()
//
绘图,定义鼠标状态结构体,判断走棋点
//
根据游戏模式获取玩家鼠标操作内容或
ai
返回数据
/*
根据不同的点击位置,调用函数:
musiccontrol ();
remindercontrol ();
huiqicaozuo ();
savecase change
saveas ();
落子(落子之后进行棋手转换、储存)
//
所有在主界面中与鼠标有关的操纵,可以说是执行的主程序
Ai
相关函数(基础)
AI ai001 ()
//
是个随机
AI
AI ai002 ()
//
这个
AI
会寻找全场吃子最多的点并返回。
AI ai003 ()
//
这个
AI
会寻找全场吃子最少的点并返回。
AI ai004 ()
//
这是混合
AI
。
//
在后
27
步执行
ai002
//
否则,按照占角、占边、占
3 3
位的顺序进行抢点性返回。
//
如果没有可抢的点,则执行
ai003
AI ai005 ()
//
这是个直接估价然后作调整的
ai
。
//
先有一个基础价:角高,可能使对方得角的点低,
3 3
位高,
1 3
位高,
2
、
7
路为负值。
//
以及之后有以下十二中边角特殊情况的估值调整
/*
一、说白了,就是想吃对方边上的子
~