📄 five.cpp
字号:
#include "StdAfx.h"
/**
*
* 文件名: Five.cpp
* 描述: 五子棋游戏类函数实现
* 五子棋游戏主类,用于进行一个游戏。
* 包括游戏的初始化,行棋,自动获取下一步棋等操作。
* 作者: 魏罡
* 时间: 2005.7.10 - 2005.10.6
*
* file name: Five.h
* description: The main class for gobang. Used to play a game.
* author: WEI-Gang
* time: 2005.7.10 - 2005.10.6
*
*/
#include "Five.h"
#include <stdlib.h>
#include <time.h>
/////////////////////////////////////////////////
CFive::CFive(){
shift = NULL;
tree = NULL;
Clear();
}
CFive::~CFive(){
if(shift){
delete shift;
}
if(tree){
delete tree;
}
}
int CFive::Play(int x,int y){
//行棋,正常返回0,得胜返回1,黑子禁手返回-1,和棋返回4。
//行棋失败返回>=5
if(times < 0){
return 100;
}
int result = 0;
if(map[x][y] != 'K'){
return 5;
}
switch(times){
case 0://第一手棋
result = FirstPlay(x,y);
break;
case 1://第二手棋
result = SecondPlay(x,y);
break;
case 2://第三手棋
result = ThirdPlay(x,y);
break;
default:
result = OtherPlay(x,y);
break;
}
if(result<3){
if(times%2){
map[x][y] = 'B';
}
else{
map[x][y] = 'H';
}
if(times ++ == 224){
times = -1;
return 4;
}
else if(result != 0){
times = -1;
}
}
return result;
}
void CFive::AutoPlay(int &x,int &y){
//自动获取下一着棋
switch(times){
case 0://第一手棋
FirstAutoPlay(x,y);
break;
case 1://第二手棋
SecondAutoPlay(x,y);
break;
case 2://第三手棋
ThirdAutoPlay(x,y);
break;
default:
OtherAutoPlay(x,y);
break;
}
if(shift){
shift->RShift(x,y);
}
}
void CFive::Clear(){
//清除所有行棋(初始化棋盘)
if(shift){
delete shift;
shift = NULL;
}
if(tree){
delete tree;
tree = NULL;
}
times = 0;
for(int i = 0;i < 15;i++){
for(int j = 0;j < 15;j++){
map[i][j] = 'K';
bd[i][j].col = 'K';
bd[i][j].sin = -1;
bd[i][j].val = 0;
}
}
}
void CFive::Back(){
//悔棋
//......
//通过经验树,查找上次行棋结点。
}
///////////////////////////////////////////////////////////////
//
int CFive::FirstPlay(int x,int y){
//第一手行棋
if(x != 7 || y != 7){
return 6;
}
return BDPlay(x,y,'H');
}
int CFive::SecondPlay(int x,int y){
//第二手行棋
tempx = x,tempy = y;
if(x<6 || x>8 || y<6 || y>8){//非直指、斜指开局
//生成转换类
shift = new CShift(x,y);
//生成经验树
tree = new CTree();
shift->Shift(x,y);
return BDPlay(x,y,'B');
}
else{
if(tempx == 7 || tempy == 7){
BDPlay(8,7,'B');
}
else{
BDPlay(8,6,'B');
}
}
return 0;
}
int CFive::ThirdPlay(int x,int y){
//第三手行棋
if(shift == NULL){
//生成转换类
shift = new CShift(tempx,tempy,x,y);
//生成经验树
tree = new CTree();
shift->Shift(x,y);
return BDPlay(x,y,'H');
}
else{
return OtherPlay(x,y);
}
}
int CFive::OtherPlay(int x,int y){
//一二三手后的行棋
shift->Shift(x,y);
char col = times%2?'B':'H';
return BDPlay(x,y,col);
}
///////////////////////////////////////////////////////////////
//
void CFive::FirstAutoPlay(int &x,int &y){
//获得第一手行棋
x = 7;
y = 7;
}
void CFive::SecondAutoPlay(int &x,int &y){
//获得第二手行棋
srand(WCE_FCTN(time) (NULL));
do{
x = rand()%3 + 6;
y = rand()%3 + 6;
}while(x == 7 && y == 7);
}
void CFive::ThirdAutoPlay(int &x,int &y){
//获得第三手行棋
if(shift != NULL){
OtherAutoPlay(x,y);
}
else{
srand(WCE_FCTN(time) (NULL));
do{
x = rand()%5 + 5;
y = rand()%5 + 5;
}while(bd[x][y].col != 'K');
}
}
void CFive::OtherAutoPlay(int &x,int &y){
//获得一二三手后的行棋
int sx[225],sy[225];
if(tree != NULL){
//经验树存在则从经验树中查找
if(tree->GetMax(x,y,sx,sy) > 0){
return;
}
else{
for(int i = 0;sx[i] > 0;i++){
bd[sx[i]][sy[i]].sin = times;
}
}
}
//从关键棋子中获取
while(keychessmans.NotEmpty()){
char col;
keychessmans.GetChessman(x,y,col,times%2?'B':'H');
if(bd[x][y].col == 'K' && Count(x,y,col)>5){
return;
}
}
int max = 0;
for(int i = 0;i < 15;i++){
for(int j = 0;j < 15;j++){
if(bd[i][j].val > max && bd[i][j].col == 'K' && bd[i][j].sin != times){
max = bd[i][j].val;
x = i;
y = j;
}
}
}
if(tree && max == 0){
tree->GetMax(x,y,sx,sy);
}
}
///////////////////////////////////////////////
//
int CFive::BDPlay(int x,int y,char col){
//内部棋盘行棋,正常返回0,得胜返回1,黑子禁手返回-1,和棋返回4。
bd[x][y].col = col;
if(tree){
//经验树存在,则记录行棋
char layout[450];
int count = 0;
int kc = 1;
//生成棋盘布局
for(int i = 0;i < 15;i ++){
for(int j = 0;j < 15;j ++){
if(bd[i][j].col == 'K'){
kc ++;
}
else{
if(kc>1){
layout[count] = char(kc/10) + 'a';
count ++;
layout[count] = char(kc%10) + '0';
count ++;
kc = 1;
layout[count] = 'K';
count ++;
}
layout[count] = bd[i][j].col;
count ++;
}
}
}
layout[count] = '\0';
tree->Play(x,y,layout);
}
//计算结果
int result = Count(x,y,col);
if(result == 10 || (result > 10 && col == 'B')){//得胜
if(tree){
tree->ChangeValue(1);
tree->Save(times);
}
return 1;
}
if(col == 'H'){//黑子有禁手
if(result == 11 || result == 8 || result == 6){
if(tree){
tree->ChangeValue(-1);
tree->Save(times);
}
return -1;
}
}
if(tree){
//经验树存在,则读入数据
tree->ReadData(times);
}
//改变权值
ChangeValue(x,y,col,1);
return 0;
}
int CFive::Count(int x,int y,char col){
//计算(x,y)落子后连子情况。
//返回值:长连11,五10,活四9,四四8,四三7,三三6,四4,活三3,其他0
int n[4];
int a = 0;
int r4 = 0;
int r3 = 0;
int h4 = 0;
//分别计算四个方向
n[0] = Count(x,y,1,0,col);
if( n[0] == 5 ){
return 10;
}
n[1] = Count(x,y,0,1,col);
if( n[1] == 5 ){
return 10;
}
n[2] = Count(x,y,1,1,col);
if( n[2] == 5 ){
return 10;
}
n[3] = Count(x,y,-1,1,col);
if( n[3] == 5 ){
return 10;
}
for(int i = 0;i < 4;i++){
switch(n[i]){
case 6:
return 11;
case 4:
a = 8;
break;
case 3:
h4 ++;
break;
case 2:
r4 ++;
break;
case 1:
r3 ++;
break;
}
}
if((h4 + r4) > 1){
a = 8;//双四
}
else if(r3 > 1){
a = 6;//双三
}
else if((h4 + r4) == 1){
if(r3 == 1){
a = 7;//四三
}
else{
if(h4 == 1){
a = 9;//活四
}
else{
a = 4;//四
}
}
}
else if(r3 == 1){
a = 3;//三
}
return a;
}
int CFive::Count(int x,int y,int dx,int dy,char col){
//计算(x,y)落子后dx,dy方向连子情况。
//返回值:长连6,五5,双四4,活四3,四2,活三1,其他0
///////////////////////////////////////////////////////////////////////////
//开始统计从(bx,by)处开始,dx,dy方向的空白数和已方连续的棋子数,
int bx = x + dx;
int by = y + dy;
int blank_f = 0; //空白数
int count_f[2] = {0,0}; //连续的棋子数,只记录两次
while(blank_f < 2 && bx >= 0 && bx < 15 && by >= 0 && by <15){//出界或两次空白结束计数
if(bd[bx][by].col == col){
count_f[blank_f] ++;//已方棋子
}
else if(bd[bx][by].col == 'K'){
blank_f ++;//空白
}
else{
break;//敌方棋子,结束统计
}
bx += dx;//增长
by += dy;
}
///////////////////////////////////////////////////////////////////////////
//开始统计从(bx,by)处开始,-dx,-dy方向的空白数和已方连续的棋子数,
bx = x - dx;
by = y - dy;
int blank_s = 0;
int count_s[2] = {0,0};
while(blank_s < 2 && bx >= 0 && bx < 15 && by >= 0 && by <15){
if(bd[bx][by].col == col){
count_s[blank_s] ++;
}
else if(bd[bx][by].col == 'K'){
blank_s ++;
}
else{
break;
}
bx -= dx;
by -= dy;
}
////////////////////////////////////////////////////////
//根据统计结果分析连子情况
int middle = count_f[0] + count_s[0];
if(middle > 4){
return 6;
}
else if(middle == 4){
return 5;
}
else if(middle == 3){
if(blank_f == 0){
if(blank_s == 0){
return 0;
}
else{
return 2;
}
}
else{
if(blank_s == 0){
return 2;
}
else {
return 3;
}
}
}
else{
int f = middle + count_f[1];
int s = middle + count_s[1];
if(f > 2 && s > 2){
return 4;
}
if(f > 2 || s > 2){
return 2;
}
if(f == 2 && blank_f > 1 && blank_s > 0){
return 1;
}
if(s == 2 && blank_f > 0 && blank_s > 1){
return 1;
}
}
return 0;
}
void CFive::ChangeValue(int x,int y,char col,int v){
//col色棋子(x,y)处落子后,权值变更,v为增减开关
//以下为基本权值变更示意图,*为落子处。
//2 1 2 1 2
//1 4 3 4 1
//2 3 * 3 2
//1 4 3 4 1
//2 1 2 1 2
int bix = x>1?-2:-x;
int biy = y>1?-2:-y;
int eix = x<13?2:14-x;
int eiy = y<13?2:14-y;
int i = 0;
int j = 0;
for(i = bix;i <= eix;i++){
for(j = biy;j <= eiy;j++){
if(i%2 == 0 && j%2 == 0){
bd[x+i][y+j].val += v * 2;
}
else if(i%2 != 0 && j%2 != 0){
bd[x+i][y+j].val += v * 4;
}
else if(i == 0 || j == 0){
bd[x+i][y+j].val += v * 3;
}
else{
bd[x+i][y+j].val += v * 1;
}
}
}
////////////////////////////////////////////////
//附加权值计算,活三3,四4
//关健棋子值计算:成五400,活四、白双四、四三251
//白双三102,
int fx = x;
int fy = y;
int res = 0;
//每方向寻找两个空格
for(i = -1;i < 2;i++){
for(j = -1;j < 2;j++){
if(j == 0 && i == 0){
continue;
}
fx = x,fy = y;
if(FindBlank(fx,fy,i,j,col)){
res = CountValue(Count(fx,fy,col),col);
if(res > 50){
if(v > 0){
keychessmans.Add(fx,fy,res,col);
}
}
else{
bd[fx][fy].val += v*res;
}
if(FindBlank(fx,fy,i,j,col)){
res = CountValue(Count(fx,fy,col),col);
if(res > 50){
if(v > 0){
keychessmans.Add(fx,fy,res,col);
}
}
else{
bd[fx][fy].val += v*res;
}
}
}
}
}
}
int CFive::FindBlank(int &x,int &y,int dx,int dy,char col){
//寻找col颜色(x,y)处dx,dy方向的空白,成功返回1,失败返回0
x += dx;
y += dy;
while(x>=0 && x<15 && y>=0 && y<15){
if(bd[x][y].col == 'K'){
return 1;
}
if(bd[x][y].col != col){
return 0;
}
x += dx;
y += dy;
}
return 0;
}
int CFive::CountValue(int result,char col){
//根据传入结果和棋子颜色,计算出关健棋子和附加权值
//成五400,活四、白双四、四三251,白双三102
//活三3,四4
if((result == 11 && col == 'B') || result == 10){
return 400;
}
if(result == 9 || (result == 8 && col == 'B') || (result == 7)){
return 251;
}
if(result == 6 && col == 'B'){
return 102;
}
return result;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -