AI 체스 봇 개발 일지(8일차)

이동민·2023년 10월 22일
0

체스 봇 개발 일지 8일차

2023 10 22

지난번에 체크 때 못 피하는 기능을 고친 버전 2를 만들었다. 하지만 버전 1과 버전 2의 공통적인 문제점이 있다. 바로 한 수 앞을 내다보지 못한다는 것이다. 버전 2에서는 한 수 앞을 보지 못하여 체크일 때 또 잡히는 위치로 피하는 경우가 생겼다. 이 문제점들은 보안해서 버전 3을 만들 것이다.

1. 버전 3의 알고리즘

ai의 기물이 플레이어의 기물을 잡을 수 있는 상황에서 ai의 기물의 좌표를 i, j라고 하고 플레이어의 기물의 좌표를 x, y라고 한다. 그리고 스코어라는 변수에 플레이어의 기물의 점수를 더한다. 폰이면 1, 룩이면 2, 나이트 면 3... 이런 식으로 더한다. 그리고 플레이어의 기물의 좌표(x, y)를 기준으로 플레이어의 말 중 (x, y)의 기물을 잡을 수 있는지 탐색한다. 왜 (x, y)를 기준으로 보냐면 만약 ai의 기물이 플레이어의 기물을 잡았을 때 좌표 (x, y)로 가기 때문이다. 플레이어의 기물 중 (x, y)의 기물을 잡을 수 있는지 탐색하는 것이 곧 ai의 기물이 플레이어의 기물을 잡았을 때 다음 턴에 그 ai의 기물이 잡히는지 보는 것이다. 이것이 한 수 앞을 내다보는 것이다. ai의 기물이 플레이어의 기물을 잡고 ai의 기물도 잡힌다면 ai의 기물의 점수를 뺀다. 최종적으로 스코어가 양수이면 ai는 플레이어의 기물을 잡으러 동작을 한다. 만약 0이거나 음수이면 그 기물은 이동시키지 않는다.

2. 코드 설명

int fu(int x, int y, Piece _pBoard[][10]) { //탐색2  
	for (int i = 1; i <= 8; i++) {//x
		for (int j = 1; j <= 8; j++) {//y
			if (_pBoard[j][i].team == 1) {
				if (_pBoard[j][i].type == 1) {
					if (Pa_ch(1, i, j, x, y, _pBoard)) {
						score += _pBoard[y][x].type;
						srch(x, y, _pBoard);
						if (score > 0) {
							_move(i, j, x, y, _pBoard);
							score = 0;
						}
						else {
							score = 0;
							break;
						}
						return 1;
					}
				}
				else if (_pBoard[j][i].type == 2) {
					if (Ro_ch(1, i, j, x, y, _pBoard)) {
						//printf("scr: %d", score);
						score += _pBoard[y][x].type;
						//printf("%d", score);
						srch(x, y, _pBoard);
						if (score > 0) {
							_move(i, j, x, y, _pBoard);
							score = 0;
						}
						else {
							score = 0;
							break;
						}
						return 1;
					}
				}
				else if (_pBoard[j][i].type == 3) {
					if (Kn_ch(1, i, j, x, y, _pBoard)) {
						score += _pBoard[y][x].type;
						srch(x, y, _pBoard);
						if (score > 0) {
							_move(i, j, x, y, _pBoard);
							score = 0;
						}
						else {
							score = 0;
							break;
						}
						return 1;
					}
				}
				else if (_pBoard[j][i].type == 4) {
					if (Bi_ch(1, i, j, x, y, _pBoard)) {
						score += _pBoard[y][x].type;
						srch(x, y, _pBoard);
						if (score > 0) {
							_move(i, j, x, y, _pBoard);
							score = 0;
						}
						else {
							score = 0;
							break;
						}
						return 1;
					}
				}
				else if (_pBoard[j][i].type == 5) {
					if (Qu_ch(1, i, j, x, y, _pBoard)) {
						score += _pBoard[y][x].type;
						srch(x, y, _pBoard);
						if (score > 0) {
							_move(i, j, x, y, _pBoard);
							score = 0;
						}
						else {
							score = 0;
							break;
						}
						return 1;
					}
				}
				else if (_pBoard[j][i].type == 6) {
					if (Ki_ch(1, i, j, x, y, _pBoard)) {
						score += _pBoard[y][x].type;
						srch(x, y, _pBoard);
						if (score > 0) {
							_move(i, j, x, y, _pBoard);
							score = 0;
						}
						else {
							score = 0;
							break;
						}
						return 1;
					}
				}
			}
			
		}
	}
	return 0;
}

여기서 (x, y)는 플레이어의 기물의 좌표이다. (i, j)는 ai의 좌표이다. 폰을 예시로 보면 ai가 플레이어의 기물을 잡을 수 있을 경우 스코어를 더하고 srch라는 함수를 호출한다. srch라는 함수는 위에서 말한 것처럼 플레이어의 기물이 (x, y)으로 공격할 수 있는지 보고, 공격이 가능할 수 있다면 스코어를 차감한다. 그다음 다시 돌아와서 스코어가 양수이면 움직이고 0 또는 음수이면 움직이지 않는다.

아래 코드가 srch 중 일부이다. (폰, 룩)

void srch(int c,int d,Piece _pBoard[][10]) { //탐색 1
	
	for (int a = 1; a <= 8; a++) { //x
		for (int b = 1; b <= 8; b++) { //y
			if (_pBoard[b][a].team == 0) {
				if (_pBoard[b][a].type == 1) {
					if (Pa_sr(0, a, b, c, d, _pBoard)) {
						score -= (_pBoard[d][c].type);
						return;
					}
				}
				else if (_pBoard[b][a].type == 2) {
					if (Ro_sr(0, a, b, c, d, _pBoard)) {
						printf("in");
						score -= (_pBoard[d][c].type);
						return;
					}
				}
			}
		}
	}
	return;
}

Pa_sr 은 공격이 되는지 판별해 주는 함수이다. 룩은 Ro_sr이다.

3. 작동 장면

여기서 흰색(ai) (1, 1)의 룩이 (1, 7)의 폰을 잡을 수 있지만 만약 잡는다면 (1, 8)의 룩에게 잡히기 때문에 잡지 않는다.

4. 버전 3의 승률

버전 3의 승률은 확실히 버전 1보다는 높아진 게 보였다. 대략 10% 정도는 되는 것 같다.

5. 버전 3의 문제점

버전 3의 문제점은 잡아도 위험하지 않은 상황에서도 잡지 않을 때가 있다는 것이다.

위의 상황은 (1, 1)의 룩이 (1, 8)의 룩을 잡아도 되는 상황이지만

잡지 않고 폰을 전진시킨다.

6. 마치며

이번에는 한 수 앞을 내다볼 수 있는 버전 3을 만들었다. 하지만 역시나 문제점이 발생하였고 이 문제점은 버전 4에서 또 보완할 것이다. 점점 승률이 높아지는 게 보인다.

0개의 댓글