[雜項項目]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;
}

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