六子棋

六子棋

一,这是我大二一次程序设计比赛的成果,相对而言感觉还可以,感觉对当时的自己挺有成就感,所以发出来分享一下,对于是菜鸟的自己,用了大概一个月时间

二,代码部分


#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<time.h>
#include <array>
#include <algorithm>
#include <functional>
#include<iostream>
using namespace std;

#pragma warning(disable:4996)

#define BLACK 0
#define WHITE 1
#define EMPTY 2

#define zero 0
#define one 1
#define two 30
#define three 32
#define four 600
#define five 800
#define six  500000

#define Azero 0
#define Aone -1
#define Atwo -50
#define Athree -52
#define Afour -800
#define Afive -1000
#define Asix  -1000000


#define DT 2         //搜索广度
#define CG 400       //可行域大小
#define GG 20000     //树层上线

int KK;


struct Point { //点结构
	int x, y;
};
struct Step { //步结构
	Point first, second;
	int value;
};

typedef struct Tree { //博弈树

	Point first, second;         //当前的两个决策点
	Point ffirst, fsecond;		 //根的选择
	int value;                   //当前棋盘
}Tree;

typedef struct cango {
	int x;
	int y;
	int va;                     //用于启发式搜索排序
}cango;

struct {
	bool operator()(cango a, cango b)const {
		return a.va > b.va;
	}
}customLessA;

struct {
	bool operator()(cango a, cango b)const {
		return a.va < b.va;
	}
}customLessB;


int Board[19][19];//存储棋盘信息,其元素值为 BLACK, WHITE, EMPTY 之一
///
///
/
/

//
///

/复制棋盘  展示棋盘
void copy(int Board[19][19], int board[19][19])           //棋盘复刻为动态数组
{
	for (int i = 0; i < 19; i++) {
		for (int j = 0; j < 19; j++) {
			board[i][j] = Board[i][j];
		}
	}
}

/评分模块
int power(int a[6], int tt)
{
	int j;
	int count1 = 0;   //我的棋子的个数
	int count2 = 0;   //对面的棋子的个数


	for (j = 0; j < 6; j++)     //数当前路中自己的棋子的个数   对面的棋子的个数   空白的个数
	{
		if (a[j] == tt)    count1++;
		if (a[j] == 1 - tt)count2++;
	}

	if (count2 == 0) {
		if (count1 == 0) { return zero; }
		if (count1 == 1) { return one; }
		if (count1 == 2) { return two; }
		if (count1 == 3) { return three; }
		if (count1 == 4) { return four; }
		if (count1 == 5) { return five; }
		if (count1 == 6) { return six; }
	}
	if (count1 == 0) {
		if (count2 == 0) { return Azero; }
		if (count2 == 1) { return Aone; }
		if (count2 == 2) { return Atwo; }
		if (count2 == 3) { return Athree; }
		if (count2 == 4) { return Afour; }
		if (count2 == 5) { return Afive; }
		if (count2 == 6) { return Asix; }
	}
	return 0;
}

void givepower(int tt, int chestmoble[3][3][3][3][3][3])    //tt是自己执棋的颜色
{
	int i[6];
	int a = 0;
	for (i[0] = 0; i[0] < 3; i[0]++) {
		for (i[1] = 0; i[1] < 3; i[1]++) {
			for (i[2] = 0; i[2] < 3; i[2]++) {
				for (i[3] = 0; i[3] < 3; i[3]++) {
					for (i[4] = 0; i[4] < 3; i[4]++) {
						for (i[5] = 0; i[5] < 3; i[5]++) {
							chestmoble[i[0]][i[1]][i[2]][i[3]][i[4]][i[5]] = power(i, tt);
						}
					}
				}
			}
		}
	}
}

int givevalue(int board[19][19], int tt, int chestmoble[3][3][3][3][3][3])         //计算如果下在当前点的话当前棋盘的得分
{
	int i, j;
	int value = 0;
	int value1 = 0;                //横向路价值
	int value2 = 0;                //竖向路价值
	int value3 = 0;                //左上右下斜向路价值
	int value4 = 0;                //右上左下斜向路价值
	int bb[19][19];
	for (i = 0; i < 19; i++) {
		for (j = 0; j < 19; j++) {
			bb[i][j] = board[i][j];
		}
	}
	横向路搜索价值
	for (i = 0; i < 19; i++) {
		for (j = 0; j < 14; j++) {
			value1 += chestmoble[bb[j][i]][bb[j + 1][i]][bb[j + 2][i]][bb[j + 3][i]][bb[j + 4][i]][bb[j + 5][i]];
		}
	}

	竖向路搜索价值
	for (i = 0; i < 19; i++) {
		for (j = 0; j < 14; j++) {
			value2 += chestmoble[bb[i][j]][bb[i][j + 1]][bb[i][j + 2]][bb[i][j + 3]][bb[i][j + 4]][bb[i][j + 5]];
		}
	}



	int p, q;    //斜向路搜索价值辅助变量
	右上左下  /   斜向路搜索价值
	//上半部分
	for (i = 5; i < 19; i++) {
		for (j = 0; j < i - 4; j++) {
			p = i - j;
			value3 += chestmoble[bb[p][j]][bb[p - 1][j + 1]][bb[p - 2][j + 2]][bb[p - 3][j + 3]][bb[p - 4][j + 4]][bb[p - 5][j + 5]];
		}
	}
	//下半部分
	for (i = 13; i > 0; i--) {
		for (j = 0; j < 14 - i; j++) {
			q = i + j;
			value3 += chestmoble[bb[q][18 - j]][bb[q + 1][17 - j]][bb[q + 2][16 - j]][bb[q + 3][15 - j]][bb[q + 4][14 - j]][bb[q + 5][13 - j]];
		}
	}

	///左上右下  \   斜向路搜索价值
	//上半部分
	for (i = 13; i > -1; i--) {
		for (j = 0; j < 14 - i; j++) {
			p = i + j;
			value4 += chestmoble[bb[p][j]][bb[p + 1][j + 1]][bb[p + 2][j + 2]][bb[p + 3][j + 3]][bb[p + 4][j + 4]][bb[p + 5][j + 5]];
		}
	}
	//下半部分
	for (i = 5; i < 18; i++) {
		for (j = 0; j < i - 4; j++) {
			q = i - j;
			value4 += chestmoble[bb[q][18 - j]][bb[q - 1][17 - j]][bb[q - 2][16 - j]][bb[q - 3][15 - j]][bb[q - 4][14 - j]][bb[q - 5][13 - j]];
		}
	}
	value = value1 + value2 + value3 + value4;

	return value;

}

局部优先模块
void judgecango(int bigboard[25][25], int yet[25][25], int x, int y, int& cc) {

	int a = x - 3;
	int b = y - 3;
	int i, j;
	for (i = x - DT; i < x + DT + 1; i++) {
		for (j = y - DT; j < y + DT + 1; j++) {
			if (bigboard[i][j] != -1 && bigboard[i][j] != 2 && yet[i][j] != 1) {     //当这个点不越界,不是棋子的时候,未被考虑过的时候
				bigboard[i][j] = 1;
				cc++;
				yet[i][j] = 1;
			}
		}
	}

}

void savecanpoint(int board[19][19], cango can[200], int& cc)
{
	cc = 0;
	int i, j;
	int bigboard[25][25];
	int yet[25][25];
	for (i = 0; i < 25; i++) {                       //初始化
		for (j = 0; j < 25; j++) {
			yet[i][j] = 0;                           //未被考虑  记未0  考虑后带入函数   记未1
			if (i < 3 || j < 3 || i>21 || j>21) {
				bigboard[i][j] = -1;                     //棋局外的点  -1
			}
			else {
				bigboard[i][j] = 0;                      //棋局内的点存为0
				if (board[i - 3][j - 3] != 2) {            //棋局内的点不是空白时
					bigboard[i][j] = 2;                  //棋局内是棋子的点 保存为 2 
				}
			}
		}
	}

	for (i = 0; i < 25; i++) {                           //将棋子附近的点标记为可行
		for (j = 0; j < 25; j++) {
			if (bigboard[i][j] == 2) {
				judgecango(bigboard, yet, i, j, cc);
			}
		}
	}

	int k = 0;                                         //保存适合行走数组的辅助变量
	for (i = 0; i < 25; i++) {
		for (j = 0; j < 25; j++) {
			if (bigboard[i][j] == 1) {
				can[k].x = i - 3;
				can[k].y = j - 3;
				k++;
			}
		}
	}
}

/启发式搜索模块

void sortA(cango can[CG], int cc, int chestmoble[3][3][3][3][3][3], int board[19][19],int tt,int& HH) {
	int SS;
	SS = givevalue(board, tt, chestmoble);
	for (int i = 0; i < cc; i++) {
		board[can[i].x][can[i].y] = tt;
		can[i].va = givevalue(board, tt, chestmoble);
		if (SS - can[i].va == 0) {
			HH++;
		}
		board[can[i].x][can[i].y] = EMPTY;
	}
	std::sort(can, can + cc, customLessA);
}

void sortB(cango can[CG], int cc, int chestmoble[3][3][3][3][3][3], int board[19][19], int tt,int& HH) {

	int SS;
	SS= givevalue(board, tt, chestmoble);
	for (int i = 0; i < cc; i++) {
		board[can[i].x][can[i].y] = 1-tt;
		can[i].va = givevalue(board, tt, chestmoble);
		if (SS - can[i].va == 0) {
			HH++;
		}
		board[can[i].x][can[i].y] = EMPTY;
	}
	std::sort(can, can + cc, customLessB);
}

/和局判断模块
bool peace(int board[19][19], int tt,int chestmoble[3][3][3][3][3][3]) {
	int VV;
	if (KK > 55) {
		VV= givevalue(board, tt, chestmoble);
		if (VV == 0) {
			return true;
		}
	}
	return false;
}

///博弈树模块

void searchtwo(int board[19][19], int tt, int chestmoble[3][3][3][3][3][3], Tree& FF, int CT) {
	int cc;
	cango can[CG];
	savecanpoint(board, can, cc);

	int VV;
	int ZZ = 100000;
	int i, j, k;
	int HH=0;
	sortB(can, cc, chestmoble, board,tt,HH);       //对可行步进行影响力排序
	if (peace(board, tt, chestmoble) != true) {
		cc = cc - HH;
	}
	//if (CT > 1 && cc > 100) {
		//cc = 100;
	//}
	//cout << cc << endl;
	for (i = 0; i < cc; i++) {
		for (j = i + 1; j < cc; j++) {
			board[can[i].x][can[i].y] = 1 - tt;
			board[can[j].x][can[j].y] = 1 - tt;
			//show(board);
			VV = givevalue(board, tt, chestmoble);
			//cout << "当前选择点为" << can[i].x <<"|"<< can[i].y << "|" << can[j].x << "|" << can[j].y << endl;
			// << "棋盘价值为" << VV << endl;
			if (CT == 1 && VV < FF.value) {
				FF.value = VV;
				//showFF(FF);
				FF.ffirst.x = FF.first.x;
				FF.ffirst.y = FF.first.y;
				FF.fsecond.x = FF.second.x;
				FF.fsecond.y = FF.second.y;
			}
			if (CT > 1) {
				//cout << "in";
				if (VV < FF.value) {
					board[can[i].x][can[i].y] = EMPTY;
					board[can[j].x][can[j].y] = EMPTY;
					return;
				}
				if (ZZ > VV) {
					ZZ = VV;
				}
			}
			board[can[i].x][can[i].y] = EMPTY;
			board[can[j].x][can[j].y] = EMPTY;
		}
	}
	if (ZZ > FF.value && CT > 1) {
		FF.value = ZZ;
		FF.ffirst.x = FF.first.x;
		FF.ffirst.y = FF.first.y;
		FF.fsecond.x = FF.second.x;
		FF.fsecond.y = FF.second.y;
	}
	return;
}

Step searchone(int board[19][19], int tt, int chestmoble[3][3][3][3][3][3])
{
	Step step;    //返回
	int cc;       //可行点计数
	cango can[CG];
	savecanpoint(board, can, cc);   //保存可行数组和可行点数
	Tree FF;                        //辅助用的树结构
	FF.first.x = 0;
	FF.first.y = 0;
	FF.ffirst.x = 0;
	FF.ffirst.y = 0;
	FF.second.x = 0;
	FF.second.y = 0;
	FF.fsecond.x = 0;
	FF.fsecond.y = 0;
	FF.value = 100000;             //树节点价值初始化
	int i, j, k;
	int CT = 1;                     //计数器 记录第N个枝杈
	int NN;                         //第一步能赢的判断
	int HH=0;


	sortA(can, cc, chestmoble, board,tt,HH);       //对可行步进行影响力排序
	//cout << HH << endl;
	//cc = cc - HH;
	//if (cc > 50) {
		//cc = 50;
	//}

	for (i = 0; i < cc; i++) {
		for (j = i + 1; j < cc; j++) {

			FF.first.x = can[i].x;
			FF.first.y = can[i].y;
			FF.second.x = can[j].x;
			FF.second.y = can[j].y;
			board[can[i].x][can[i].y] = tt;
			board[can[j].x][can[j].y] = tt;
			NN = givevalue(board, tt, chestmoble);
			if (NN > 400000) {
				step.first.x = can[i].x;
				step.first.y = can[i].y;
				step.second.x = can[j].x;
				step.second.y = can[j].y;
				step.value = NN;
				return step;
			}
			searchtwo(board, tt, chestmoble, FF, CT);
			board[can[i].x][can[i].y] = EMPTY;
			board[can[j].x][can[j].y] = EMPTY;
			CT++;
		}
	}
	step.first.x = FF.ffirst.x;
	step.first.y = FF.ffirst.y;
	step.second.x = FF.fsecond.x;
	step.second.y = FF.fsecond.y;
	step.value = FF.value;
	return step;
}

//
//

int main()
{
	Step step;//临时步结构
	char message[256];//通信消息缓冲
	int computerSide;//己方执棋颜色
	int start = 0;//对局开始标记
	srand(int(time(0)));
	//此处放置初始化代码



	//...

	while (1)	//程序主循环
	{
		fflush(stdout);//不要删除此语句,否则程序会出问题
		scanf("%s", message);//获取平台命令消息
		//分析命令
		if (strcmp(message, "name?") == 0)//向对战平台发送队名
		{
			fflush(stdin);
			/***********将"令狐冲"改为你的队名,不超过6个汉字或12个英文字母,否则无成绩************/
			/*******/		printf("name 发际线在作队\n");		/**只修改令狐冲,不要删除name空格****/
			/***********将"令狐冲"改为你的队名,不超过6个汉字或12个英文字母,否则无成绩************/
		}
		else if (strcmp(message, "new") == 0)//建立新棋局
		{
			int i, j;
			scanf("%s", message);//获取己方执棋颜色
			fflush(stdin);
			if (strcmp(message, "black") == 0)	computerSide = BLACK;  //执黑
			else  computerSide = WHITE;   //执白

			for (i = 0; i < 19; ++i)   //初始化棋局
				for (j = 0; j < 19; ++j)
					Board[i][j] = EMPTY;
			start = 1;
			KK = 0;
			if (computerSide == BLACK)
			{
				/**********生成第一手着法,并保存在step结构中,落子坐标为(step.first.x,step.first.y)**********/
				/****************************在下方填充代码,并替换我的示例代码******************************/


				step.first.x = 9;
				step.first.y = 9;


				/******************************在上面填充第一步行棋代码*******************************************/

				Board[step.first.x][step.first.y] = computerSide;//处理己方行棋
				printf("move %c%c@@\n", step.first.x + 'A', step.first.y + 'A');//输出着法
			}
		}
		else if (strcmp(message, "move") == 0)//行棋,本程序核心
		{
			scanf("%s", message);//获取对手行棋着法
			fflush(stdin);
			step.first.x = message[0] - 'A';		step.first.y = message[1] - 'A';
			step.second.x = message[2] - 'A';		step.second.y = message[3] - 'A';
			//处理对手行棋
			Board[step.first.x][step.first.y] = 1 - computerSide;
			if (!(step.second.x == -1 && step.second.y == -1)) Board[step.second.x][step.second.y] = 1 - computerSide;

			/**********************************************************************************************************/
			/***生成落子的坐标,保存在step结构中,第1子下在(step.first.x,step.first.y),第2子下在(step.first.x,step.first.y)*****/
			/**************************************在下方填充代码,并替换我的示例代码*****************************************/

			//生成第1子落子位置step.first.x和step.first.y
			//
			///
			///
			/
			/
			int i, j, k;
			int chestmoble[3][3][3][3][3][3];            //生成六元组   保存相应权重
			int tt = computerSide;                       //执子颜色赋值给tt


			memset(chestmoble, 0, sizeof(chestmoble));   //初始值全部赋值为0
			givepower(tt, chestmoble);                   //给予权重

			int board[19][19];
			copy(Board, board);
	
			if (peace(board, tt,chestmoble) == true) {
				int cc;                         //可行点计数
				cango can[CG];
				savecanpoint(board, can, cc);   //保存可行数组和可行点数
				step.first.x = can[0].x;
				step.first.y = can[0].y;
				step.second.x = can[1].x;
				step.second.y = can[1].y;
				Board[step.first.x][step.first.y] = computerSide;
				Board[step.second.x][step.second.y] = computerSide;
				//Board[can[0].x][can[0].y] = computerSide;
				//Board[can[1].x][can[1].y] = computerSide;
			}
			else {
				step = searchone(board, tt, chestmoble);
				Board[step.first.x][step.first.y] = computerSide;
				Board[step.second.x][step.second.y] = computerSide;
			}

			KK++;
			/
			/
			
			//
			///
			
			/
			/*
			/*****************************************在上面填充代码******************************************************/
			/**********************************************************************************************************/

			printf("move %c%c%c%c\n", step.first.x + 'A', step.first.y + 'A', step.second.x + 'A', step.second.y + 'A');//输出着法
		}
		else if (strcmp(message, "error") == 0)//着法错误
		{
			fflush(stdin);
		}
		else if (strcmp(message, "end") == 0)//对局结束
		{
			fflush(stdin);
			start = 0;
		}
		else if (strcmp(message, "quit") == 0)//退出引擎
		{
			fflush(stdin);
			printf("Quit!\n");
			break;
		}
	}
	return 0;
}

三、 核心算法的设计思路和实现要点
1,博弈树
2,最大最小值搜索
3,a,b剪枝
4,基于路的评分系统
5,局部优先
6,启发式搜索
7,和局判断
四、 算法时间、空间复杂度的估算(可选)
1,运算次数大概是10的6到7次方之间,导致有一些慢,进行了很多优化,如果电脑计算力好的话进行到四层会更强
2,运行内存900k
五、 完成过程中遇到的问题,排除问题的主要过程、使用的方法和技巧
1,博弈树的建立 递归
2,搜索次数太大,时间太慢,a,b剪枝,局部优先,启发式搜索
六、 所用方法的特别、新颖或创新之处(可选)
因为用到的是博弈树 情况很多 计算很慢 只能到第二层 为了优化时间采取了a,b,剪枝,局部优先,启发式搜索,虽然还是很慢,但比较之前快了不少了
七、 参考文献
闫文杰 六子棋计算机博弈关键技术研究,硕士学位论文 2010 06 01
明确说明所参考的论文、书籍、网络资料、开源代码或其他研究者的程序或成果等详细信息。

能帮到你们的话点个赞吧

  • 15
    点赞
  • 108
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
在C语言中实现六子棋的算法可以按照以下步骤进行: 1. 创建一个19×19的棋盘,可以使用二维数组表示。 2. 设置玩家的黑白子标记,可以使用常量或宏定义来表示。 3. 编写函数来检查当前棋盘状态,判断是否有玩家获胜或者是平局。 4. 编写函数来判断某个位置是否合法,即该位置是否在棋盘范围内且没有被占用。 5. 编写函数来处理玩家的下棋操作,根据玩家的输入更新棋盘状态。 6. 编写函数来实现AI的下棋操作,可以使用一些搜索算法,如博弈树、极大极小算法等,在棋盘上评估每个位置的得分,并选择最佳位置进行下棋。 7. 在主函数中循环执行玩家和AI的下棋操作,直到有一方获胜或者是平局。 通过以上算法实现,可以在C语言中实现六子棋的游戏。<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* [基于C语言的六子棋程序设计](https://download.csdn.net/download/weixin_50688639/85965510)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* [六子棋c++剪枝算法的实现](https://download.csdn.net/download/qq_28273781/10484356)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值