[杂项项目]C语言打造智能AI小游戏——三子棋

三子棋具体就不多介绍了,AI棋用O表示,我们的棋用X表示。先手后手自己选。这里主要说一下AI算法。首先AI会对整个棋盘MAP[3][3]进行遍历,每个格子都有一个权值weight[i][j]。权值的第一次计算方法是对每一行i每一列j进行计算,计算基于这一格有几种获胜的路线。例如没有走时,9个格的权值为:

[][][]     3 2 3

[][][]     2 4 2

[][][]     3 2 3

角落有横竖斜三种获胜方法,边有横竖两种方法,中心有横竖两斜4种方法。假如某格有X阻挡,那么权值会相应变化,例如

[][][]     2 1 2

[]X[]     1 0 1

[][][]     2 1 2

由于有中心阻挡,那么角只有横竖两种方法赢,因此权值为2。但该AI还需继续优化。例如以下:

[]X[]     1 0 1

[]0[]     1 0 2

XX0     0 0 0

AI面对这种情况,本来下在第一个格子就赢了,但他会选择权值为2的格子。因此我们可以在现有权值条件的情况下,在附加个权值。假如某一格子的路线上已经有AI的子了,那么该条路线上未落子的所有格子权值再加1,如果有两个已落子的AI格子权值就加2。例如以下情况:

            原权值       优化权值

[]X[]     2 0 2          5 0 3

[]0[]     2 0 2          3 0 4

[]X0     2 0 0          3 0 0

第一个格子5是由于斜路线上有两个子,那在原有的基础2上先加1,再加2,所以权值为2+1+2。第2行第3列权值为4,因为横竖两条路线均有1个子,因此权值为2+1+1,其余格子路线上均有1个子,因此权值为2+1。这样落在权值5那个格子上AI就赢了。

但是仅仅这些判断是不够的。例如:

           初始         优化

X[]X     0 1 0       0 2 0

[]0[]     1 0 1       2 0 2

[][]0     1 2 0       2 4 0

AI会选择权值为4的格子。那此时AI选择权值为2的格子时,你只需要走一步就赢了,AI就输了,因此该AI算法还得继续。

那么AI可以逆向思考一番,AI可以考虑一下当前情况在计算AI权值的同时再计算一次我们的权值。例如上面例子:

           AI权值       你的权值       优化AI      优化你

X[]X     0 1 0         0 1 0            0 2 0         0 4 0

[]0[]     1 0 1         1 0 0            2 0 2         2 0 0

[][]0     1 2 0         1 0 0            2 4 0         2 0 0

我们把两个权值相加(另外把AI的权值应该再加1,因为AI判断赢要优先于输或平,假如AI方有权值大的,代表一步能赢的,我方也有这种情况,那相加权值相同,AI既可以选择赢棋那一格,也可以选择堵你将要赢的那一格。但AI判断赢要优先于堵对方赢。例子就不举了):

           相加权值       再加1权值

X[]X     0 6 0            0 7 0

[]0[]     4 0 2            5 0 3

[][]0     4 4 0            5 4 0

因此AI判断到这里就会堵你了。

AI算法就介绍到这里,至于三子棋程序,由于过于简单,就不过多介绍了。主要介绍AI思想,Windows系统编译的程序。如果是Linux需要把以下代码改下。接下来我就贴上代码,供参考,如有不懂欢迎留言。

project.h

#pragma once
#define COLUMN 3
#define ROW 3
#define GOON 0
#define WIN -1
#define DEFEAT 1
void init(char(*MAP)[COLUMN]);
int victory(char(*MAP)[COLUMN]);
bool check(char(*MAP)[COLUMN]);
void show(char(*MAP)[COLUMN]);
void check_stemp(char(*MAP)[COLUMN], int *x, int *y);
void ai_auto(char(*MAP)[COLUMN]);
int menu();
int first_hand(char(*MAP)[COLUMN]);
int ai_hand(char(*MAP)[COLUMN]);
void play(char(*MAP)[COLUMN]);

project.c

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"project.h"
int vis[ROW][COLUMN];
int weight[ROW][COLUMN];
int x, y;
void init(char(*MAP)[COLUMN]) {
	for (int i = 0; i < ROW; i++)
		for (int j = 0; j < COLUMN; j++) {
			MAP[i][j] = ' ';
			vis[i][j] = 0;
		}
}
int victory(char(*MAP)[COLUMN]) {
	for (int i = 0; i < 3; i++) {
		if (MAP[i][0] == 'X'&&MAP[i][1] == 'X'&&MAP[i][2] == 'X')
			return WIN;
		else if (MAP[i][0] == 'O'&&MAP[i][1] == 'O'&&MAP[i][2] == 'O')
			return DEFEAT;
		if (MAP[0][i] == 'X'&&MAP[1][i] == 'X'&&MAP[2][i] == 'X')
			return WIN;
		else if (MAP[0][i] == 'O'&&MAP[1][i] == 'O'&&MAP[2][i] == 'O')
			return DEFEAT;
	}
	if (MAP[0][0] == 'X'&&MAP[1][1] == 'X'&&MAP[2][2] == 'X')
		return WIN;
	else if (MAP[0][0] == 'O'&&MAP[1][1] == 'O'&&MAP[2][2] == 'O')
		return DEFEAT;
	if (MAP[0][2] == 'X'&&MAP[1][1] == 'X'&&MAP[2][0] == 'X')
		return WIN;
	else if (MAP[0][2] == 'O'&&MAP[1][1] == 'O'&&MAP[2][0] == 'O')
		return DEFEAT;
	return GOON;
}
bool check(char(*MAP)[COLUMN]) {
	for (int i = 0; i < ROW; i++)
		for (int j = 0; j < COLUMN; j++)
			if (!vis[i][j])
				return false;
	return true;
}
void show(char(*MAP)[COLUMN]) {
	printf("-------------\n");
	for (int i = 0; i < ROW; i++) {
		printf("|");
		for (int j = 0; j < COLUMN; j++) {
			printf(" %c ", MAP[i][j]);
			printf("|");
		}
		printf("\n");
		printf("-------------\n");
	}
}
void check_stemp(char(*MAP)[COLUMN], int *x, int *y) {
	while (*x > 3 || *x <= 0 || *y>3 || *y <= 0 || MAP[*y - 1][*x - 1] != ' ') {
		system("cls");
		show(MAP);
		printf("Input error, please reenter!\n");
		scanf("%d%d", x, y);
	}
	MAP[*y - 1][*x - 1] = 'X';
	vis[*y - 1][*x - 1] = 1;
}
void Empowerment(char(*MAP)[COLUMN], int(*weight)[COLUMN], char ai_X, char ai_0, int flag) {
	for (int i = 0; i < 3; i++) {
		if (MAP[i][0] != ai_X&&MAP[i][1] != ai_X&&MAP[i][2] != ai_X) {
			weight[i][0]++;
			weight[i][1]++;
			weight[i][2]++;
			int tmp = 1;
			for (int j = 0; j < 3; j++)
				if (MAP[i][j] == ai_0) {
					weight[i][0] += tmp+flag;
					weight[i][1] += tmp+flag;
					weight[i][2] += tmp+flag;
					tmp += 10;
				}
		}
		if (MAP[0][i] != ai_X&&MAP[1][i] != ai_X&&MAP[2][i] != ai_X) {
			weight[0][i]++;
			weight[1][i]++;
			weight[2][i]++;
			int tmp = 1;
			for (int j = 0; j < 3; j++)
				if (MAP[j][i] == ai_0) {
					weight[0][i] += tmp+flag;
					weight[1][i] += tmp+flag;
					weight[2][i] += tmp+flag;
					tmp += 10;
				}
		}
	}
	if (MAP[0][0] != ai_X&&MAP[1][1] != ai_X&&MAP[2][2] != ai_X) {
		weight[0][0]++;
		weight[1][1]++;
		weight[2][2]++;
		int tmp = 1;
		for (int j = 0; j < 3; j++)
			if (MAP[j][j] == ai_0) {
				weight[0][0] += tmp+flag;
				weight[1][1] += tmp+flag;
				weight[2][2] += tmp+flag;
				tmp += 10;
			}

	}
	if (MAP[0][2] != ai_X&&MAP[1][1] != ai_X&&MAP[2][0] != ai_X) {
		weight[0][2]++;
		weight[1][1]++;
		weight[2][0]++;
		int tmp = 1;
		for (int j = 0; j < 3; j++)
			if (MAP[j][2 - j] == ai_0) {
				weight[0][2] += tmp+flag;
				weight[1][1] += tmp+flag;
				weight[2][0] += tmp+flag;
				tmp += 10;
			}
	}
}
void ai_auto(char(*MAP)[COLUMN]) {
	int weight[3][3] = { 0 };
	Empowerment(MAP, weight, 'X', 'O', 1);
	Empowerment(MAP, weight, 'O', 'X', 0);
	int maxn = -1;
	int maxm = -1;
	for (int i = 0; i < 3; i++)
		for (int j = 0; j < 3; j++) {
			if (vis[i][j])
				weight[i][j] = -1;
			if (maxn < weight[i][j]) {
				maxn = weight[i][j];
				maxm = i * 3 + j;
			}
		}
	MAP[maxm / 3][maxm % 3] = 'O';
	vis[maxm / 3][maxm % 3] = 1;
}
int menu() {
	int tmp;
	printf("*************************************************************\n");
	printf("* Please enter: * 1:First hand * 2.Back hand * Others:Close *\n");
	printf("*************************************************************\n");
	scanf("%d", &tmp);
	return tmp;
}
int first_hand(char(*MAP)[COLUMN]) {
	system("cls");
	show(MAP);
	printf("Please enter:x y\n");
	scanf("%d%d", &x, &y);
	check_stemp(MAP, &x, &y);
	system("cls");
	show(MAP);
	if (victory(MAP) == WIN) {
		printf("Congratulations on your victory, you are as smart as Qianyouyou.\n");
		return 1;
	}
	else if (check(MAP)) {
		printf("Draw.As smart as me.\n");
		return 1;
	}
	system("pause");
	return 0;
}
int ai_hand(char(*MAP)[COLUMN]) {
	ai_auto(MAP);
	system("cls");
	show(MAP);
	if (victory(MAP) == DEFEAT) {
		printf("You lose, you're as stupid as a pig.\n");
		return 1;
	}
	else if (check(MAP)) {
		printf("Draw.As smart as me.\n");
		return 1;
	}
	return 0;
}
void play(char(*MAP)[COLUMN]) {
	while (!check(MAP) || victory(MAP) == GOON) {
		if (first_hand(MAP))
			break;
		if (ai_hand(MAP))
			break;
	}
	system("pause");
}

main.c

#include<stdio.h>
#include<stdlib.h>
#include"project.h"
char MAP[ROW][COLUMN];
int main() {
	char str[2];
	do {
		init(MAP);
		switch (menu()) {
		case 1:
			first_hand(MAP);
		case 2: {
			ai_hand(MAP);
			play(MAP);
		}
		default: {
			printf("Do you need to start again?(Y/N)");
			scanf("%s", str);
		}break;
		}
	} while (str[0] == 'Y' || str[0] == 'y');
	printf("Thank you for using!\n");
	system("pause");
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章