⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 five.cpp

📁 EVC 环境下的五子棋, 用模块器5.0可以跑一下!
💻 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 + -