?? _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 + -