📄 _gamer.cpp
字号:
//此文件定义了游戏者类以及由它派生出的human和robot类
#include "_Gamer.h"
#include <iostream.h>
#include<conio.h>
#include<math.h>
#define ReachAim 10*27 // 棋子达到目的地的加分
#define DisStep 1
#define EnemyScoreQuotiety 0.95
#define ConverDepth 550
#define DisjointVal 1
void _Gamer::Init(int *IDandChess,_Nodes* p) // 游戏者的初始化,参数分别为指向含有游戏者序号和
// 该游戏者所拥有的棋子的数组指针,指向棋盘的指针
{
Nodes=p; // 获得棋盘上的所有棋子
Sellect=-1; // 没有选定棋子
Aimplace=-1; // 没有目的节点
gamerID=IDandChess[0]; // IDandChess[]数组的第一个元素即为gamerID
for(int i=0;i<10;i++) // 给游戏者的棋子赋值,从棋盘reset函数中获得初始的
// 棋子的节点序号
{
MyChessman[i]=IDandChess[i+1];
}
}
//---------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------
_Message _Human::Input() // 消息控制
{
static int position=60; // position置为60即在棋盘的最中央
_Message msg; // 用于返回的消息
char ch;
int p,q,i,j,k;
ch=getch(); // 获得棋盘输入的信息
i=position; // i是当前的选择框位置
switch(ch)
{
case 'Q': // Q则退出
msg.wparam=EXIT;
return msg;
break;
case 'q': // Q则退出
msg.wparam=EXIT;
return msg;
break;
case 'R': // R则重新开局
msg.wparam=RESTART;
return msg;
break;
case 'r': // R则重新开局
msg.wparam=RESTART;
return msg;
break;
case 'H': // H则为悔棋
msg.wparam=REGRET;
return msg;
break;
case 'h': // H则为悔棋
msg.wparam=REGRET;
return msg;
break;
case 'a': // a为向左移动
if(i!=0) // 如果不是最顶端的棋子,则向左移动一格,
position=i-1; // 若已是最左端,则移动到上一行最右边的节点
// 若是最顶端则不作移动
msg.wparam=MOVESELLECT; // 消息类型为移动选择框
msg.lparam=position; // msg.lparam为当前选择框所在的节点序号
return msg;
break;
case 'A': // a为向左移动
if(i!=0) // 如果不是最顶端的棋子,则向左移动一格,
position=i-1; // 若已是最左端,则移动到上一行最右边的节点
// 若是最顶端则不作移动
msg.wparam=MOVESELLECT; // 消息类型为移动选择框
msg.lparam=position; // msg.lparam为当前选择框所在的节点序号
return msg;
break;
case 'd': // d为向右走棋
if(i!=120) // 如果不是最底端棋子的话,右移一格,若已是最
position=i+1; // 右端,则移动到下一行的最左边的节点
// 若是最底端则不作移动
msg.lparam=position; // msg.lparam为当前选择框所在的节点序号
msg.wparam=MOVESELLECT; // 消息类型为移动选择框
return msg;
break;
case 'D': // d为向右走棋
if(i!=120) // 如果不是最底端棋子的话,右移一格,若已是最
position=i+1; // 右端,则移动到下一行的最左边的节点
// 若是最底端则不作移动
msg.lparam=position; // msg.lparam为当前选择框所在的节点序号
msg.wparam=MOVESELLECT; // 消息类型为移动选择框
return msg;
break;
case 'w': // w为向上走棋
k=i;
if(i!=0)
{
p=Nodes[i].cood.x; // 取得当前节点的位置坐标
q=Nodes[i].cood.y;
for(;abs(Nodes[i-1].cood.y-Nodes[i].cood.y)<3;i--);
// 若序号为i-1的节点和序号为i的节点在同一行则循环(没有循环体)
i--; // 找到上一行最右端的棋子
for(j=i-1;abs(Nodes[i].cood.y-Nodes[j].cood.y)<3;j--)
// 序号为i的节点和序号为j的节点在同一行,循环
if(abs(Nodes[j].cood.x-p)<abs(Nodes[i].cood.x-p))
// 寻找横坐标与开始时的横坐标最相近的点
i=j; // 找到这个点
}
position=i;
msg.wparam=MOVESELLECT; // 消息类型为移动选择框
msg.lparam=position; // msg.lparam为当前选择框所在的节点序号
return msg;
break;
case 'W': // w为向上走棋
k=i;
if(i!=0)
{
p=Nodes[i].cood.x; // 取得当前节点的位置坐标
q=Nodes[i].cood.y;
for(;abs(Nodes[i-1].cood.y-Nodes[i].cood.y)<3;i--);
// 若序号为i-1的节点和序号为i的节点在同一行则循环(没有循环体)
i--; // 找到上一行最右端的棋子
for(j=i-1;abs(Nodes[i].cood.y-Nodes[j].cood.y)<3;j--)
// 序号为i的节点和序号为j的节点在同一行,循环
if(abs(Nodes[j].cood.x-p)<abs(Nodes[i].cood.x-p))
// 寻找横坐标与开始时的横坐标最相近的点
i=j; // 找到这个点
}
position=i;
msg.wparam=MOVESELLECT; // 消息类型为移动选择框
msg.lparam=position; // msg.lparam为当前选择框所在的节点序号
return msg;
break;
case 's': // s为向下走棋
k=i;
if(i!=120)
{
p=Nodes[i].cood.x; // 取得当前节点的位置坐标
q=Nodes[i].cood.y;
for(;abs(Nodes[i+1].cood.y-Nodes[i].cood.y)<3;i++);
// 序号为i+1的节点和序号为i的节点在同一行
i++; // 找到下一行最左端的棋子
for(j=i+1;abs(Nodes[j].cood.y-Nodes[i].cood.y)<3;j++)
// 序号为i的节点和序号为j的节点在同一行
if(abs(Nodes[j].cood.x-p)<abs(Nodes[i].cood.x-p))
// 寻找横坐标与开始时的横坐标最相近的点
i=j; // 找到这个点
}
position=i;
msg.wparam=MOVESELLECT; // 消息类型为移动选择框
msg.lparam=position; // msg.lparam为当前选择框所在的节点序号
return msg;
break;
case 'S': // s为向下走棋
k=i;
if(i!=120)
{
p=Nodes[i].cood.x; // 取得当前节点的位置坐标
q=Nodes[i].cood.y;
for(;abs(Nodes[i+1].cood.y-Nodes[i].cood.y)<3;i++);
// 序号为i+1的节点和序号为i的节点在同一行
i++; // 找到下一行最左端的棋子
for(j=i+1;abs(Nodes[j].cood.y-Nodes[i].cood.y)<3;j++)
// 序号为i的节点和序号为j的节点在同一行
if(abs(Nodes[j].cood.x-p)<abs(Nodes[i].cood.x-p))
// 寻找横坐标与开始时的横坐标最相近的点
i=j; // 找到这个点
}
position=i;
msg.wparam=MOVESELLECT; // 消息类型为移动选择框
msg.lparam=position; // msg.lparam为当前选择框所在的节点序号
return msg;
break;
case ' ': // 空格为选定棋子
if(this ->Sellect==-1) // 如果游戏者还未选定棋子
msg.wparam=SELLECT; // 则消息类型为选子
else
msg.wparam=MOVECHESSMAN;// 否则为走棋
msg.lparam=position; // msg.lparam为当前选择框所在的节点序号
return msg;
break;
default:break;
}
msg.wparam=REINPUT; // 什么都没有则重新输入
return msg;
}
//-------------------------------------------------------------------------------------
_Message _Robot::Input()
{
_Message msg; // 传递消息的变量
SearchDepth=4; // 搜索深度为4
Think(); // 思考的过程
msg.wparam=MOVECHESSMAN; // 只有移动棋子这一种消息
msg.lparam=Aimplace; // 目的节点
return msg;
}
_Robot::_Robot() // Robot的构造函数
{
GamerType = 0; // 游戏者类型为0,即电脑控制
GamerQuen = 0; // 游戏者顺序列表为空
SearchDepth = 4; // 搜索深度是4
NearWin = 0; // 表示还没有进入中盘
FarWin = 1; // 表示是刚开局
}
_Robot::~_Robot() // Robot的析构函数
{
_GamerQuen *t; // 用于释放游戏者顺序链表指针的中间变量
while( GamerQuen != 0 ) // 从前往后析构(删除指针)
{
t = GamerQuen;
if(t->Next != 0)
{
GamerQuen = t->Next ;
delete t;
t = 0;
}
else break;
}
delete t;
t = 0;
}
//-------------------------------------------------------------------------------------
void _Robot::Think() // 电脑玩家的思考
{
_Nodes tNodes[121]; // 存放棋盘的临时数组
_EvalueData data,data2,data3; // 存放全搜索的不同深度的评估值
for(int i=0;i<121;i++) // 将棋盘拷贝到tNodes中
{
tNodes[i] = Nodes[i];
for(int j=0;j<6;j++) // 指针的拷贝需要特别注意
if( Nodes[i].pointers[j] != NULL )
tNodes[i].pointers[j] = &tNodes[ Nodes[i].pointers[j]->index ];
}
/* 通常情况下,电脑玩家只需一步或者两步就可以胜利,但是由于搜索的深度大于这个步数,电脑会
继续搜索,以至于左右走动而不能够赢棋,下面的代码就是为了解决这个问题是写的 */
if( NearWin ==1 || FarWin ==1) // 如果将要胜利,则搜索一步或者两步,
{ // 取得其中的较大的评估值
data = Search(tNodes,1); // 存放较大的评估值
data2 = Search(tNodes,2); // 搜索一步
data3 = Search(tNodes,3); // 搜索两步
if( data.Score < data2.Score )
data = data2;
if( data.Score < data3.Score )
data = data3;
}
else //若离胜利还远,则采用剪枝法搜索
data = aBSearch(tNodes,SearchDepth,20000);
Sellect = data.start ; // 确定要选择的棋子
Aimplace = data.end ; // 确定目的节点
}
//-------------------------------------------------------------------------------------
_EvalueData _Robot::Evalue(_Nodes *tNodes,int type,int enemy)
{ // 评估函数,参数分别为指向棋盘的指针,
// 游戏者序号,对手的序号
_EvalueData data[2] = { {0,0,0},{0,0,0} }; //存放本方和对手的评估函数值
int Pos[2][10],k=0,h=0,i,j,walkway,Sumdis;
_Nodes *tnode;
for(i=0;i<121;i++) // 找到棋盘上属于本方和对手的棋子
{
if( tNodes[i].Chessman == type ) // pos[0]中存放本方的十个棋子
Pos[0][k++] = i ;
else if( tNodes[i].Chessman == enemy ) // pos[1]中存放对手的十个棋子
Pos[1][h++] = i ;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -