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

이동민·2023년 9월 8일
0

체스 봇 개발 일지 3일차

2023 09 08

저번 2일차까지 코드 분석을 했다. 이제부터는 더 많은 게임의 기능을 구현해볼 것이다. 캐슬링, 승진, 체크까지 구현해볼 생각이다. 오늘은 캐슬링을 구현할 것이다.

1. 캐슬링이란

일단 구현에 앞서 캐슬링이란 킹을 두 칸 옆으로 옮기고 룩을 킹의 반대편 옆으로 옮길 수 있는 규칙이다. 캐슬링에는 2가지 종류가 있다. 바로 킹사이드 캐슬링과 퀸 사이드 캐슬링이다. 말 그대로 킹쪽 룩과 자리를 바꾸면 킹 사이드, 퀸 쪽 룩과 바꾸면 퀸 사이드이다. 그리고 캐슬링을 하기 위해서는 3가지 조건을 충족해야 한다. 첫 번째는 킹과 캐슬링을 할 룩 사이의 공간을 완전히 비워야 한다는 것이고, 두 번째는 킹과 캐슬링을 할 룩이 게임을 시작하고 한 번도 이동한 적이 없어야 한다는 것이다. 세 번째는 체크 상태가 아니어야 한다는 것이다.

2. 구현

처음에 일단 킹과 룩의 움직임을 카운트 해줄 변수를 만든다. 그리고 킹 또는 룩이 움직였으면 그 변수를 증가시킨다. 이 변수를 이용해 두 번째 조건을 판단할 것이다. 그 다음 킹의 위치를 (ax,ay)로 받고 룩의 위치를 (bx,by)로 받는다. 그리고 룩의 bx,by (룩의 위치)로 퀸 사이드인지 킹 사이드인지 판별한다. 킹 사이드이면 옆으로 2칸이 다 비였는지 확인한다. 퀸 사이드면 3칸을 확인한다. 이 조건이 모두 충족이 된다면 킹과 룩을 정해진 자리로 이동시킨다.

int Ro(int team, int ax, int ay, int bx, int by, Piece _pBoard[][10]) {
	if (ax != bx && ay != by) {
		printf("impossible\n");
		return 0;
	}
	
	if (ax == bx) {	//y축 이동
		for (int y = min(ay, by) + 1; y < max(ay, by); y++) {
			if (_pBoard[y][ax].type > 0) {
				printf("impossible\n");
				return 0;
			}
		}
		if (_pBoard[by][bx].team != team) {
			if (ax == 1 && ay == 8) br1++; //검은색 첫번째 룩이 이동한다면 br1 증가
			else if (ax == 8 && ay == 8) br2++; //검은색 두번째 룩이 이동한다면 br2 증가
			else if (ax == 1 && ay == 1) wr1++; //하얀색 첫번째 룩이 이동한다면 wr1 증가
			else if (ax == 8 && ay == 1) wr2++; //하얀색 두번째 룩이 이동한다면 wr2 증가
			_move(ax, ay, bx, by, _pBoard);
			printf("attack\n");
			else return 2;
		}
		else if (_pBoard[by][bx].team == team) {
			printf("same team impossible\n");
			return 0;
		}
		else if (_pBoard[by][bx].team == -1) {
			if (ax == 1 && ay == 8) br1++;
			else if (ax == 8 && ay == 8) br2++;
			else if (ax == 1 && ay == 1) wr1++;
			else if (ax == 8 && ay == 1) wr2++;
			_move(ax, ay, bx, by, _pBoard);
			printf("move\n");
			else return 1;
		}
	}
	if (ay == by) {	//x축 이동
		for (int x = min(ax, bx) + 1; x < max(ax, bx); x++) {
			if (_pBoard[ay][x].type > 0) {
				printf("impossible\n");
				return 0;
			}
		}
		if (_pBoard[by][bx].team != -1 && _pBoard[by][bx].team != team) {
			if (ax == 1 && ay == 8) br1++;
			else if (ax == 8 && ay == 8) br2++;
			else if (ax == 1 && ay == 1) wr1++;
			else if (ax == 8 && ay == 1) wr2++;
			_move(ax, ay, bx, by, _pBoard);
			printf("attack\n");
			else return 2;
		}
		else if (_pBoard[by][bx].team == team) {
			printf("same team impossible\n");
			return 0;
		}
		else if (_pBoard[by][bx].team == -1) {
			if (ax == 1 && ay == 8) br1++;
			else if (ax == 8 && ay == 8) br2++;
			else if (ax == 1 && ay == 1) wr1++;
			else if (ax == 8 && ay == 1) wr2++;
			_move(ax, ay, bx, by, _pBoard);
			printf("move\n");
			else return 1;
		}
	}
	return 0;
}	 //complete

br1, br2, wr1, wr2 라는 변수들이 바로 룩의 이동을 카운트하는 변수들이다. 이동 할 룩의 좌표에 따라 그에 맞는 변수를 증가시킨다.

int Ki(int team, int ax, int ay, int bx, int by, Piece _pBoard[][10]) {
	castling = 0;
	if (_pBoard[by][bx].team == team) { //이동하려는곳의 말이 이동하는 말과 팀이 같다면
		if (_pBoard[by][bx].type == 2) { //이동하려는곳의 말이 룩이라면
			if (_pBoard[ay][ax].team == 1 && w_cnt == 0) { //이동하려는 말이 하얀색이고  그 말이 지금까지 이동을 안했다면
				if (bx == 1 && by == 1) { //캐슬링 할 룩이 wr1이라면
					if (wr1 == 0) { //캐슬링 할 룩이 지금까지 이동을 안했다면
						if (_pBoard[1][2].type == 0 && _pBoard[1][3].type == 0) { //캐슬링 할려는 말 왕과 룩 사이가 비어있다면
							_move(ax, ay, 2, 1, _pBoard); //왕을 이동한다
							_move(bx, by, 3, 1, _pBoard); //룩을 이동한다
							castling = 1;//캐슬링을 성공했다는뜻
							w_cnt++; //하얀색 왕이 이동했으므로 증가
							return 1; //이동 성공
						}
					}
				}
				if (bx == 8 && by == 1) { //캐슬링 할 룩이 wr2라면
					if (wr2 == 0) {
						if (_pBoard[1][5].type == 0 && _pBoard[1][6].type == 0 && _pBoard[1][7].type == 0) {
							_move(ax, ay, 6, 1, _pBoard);
							_move(bx, by, 5, 1, _pBoard);
							castling = 1;
							w_cnt++;
							return 1;
						}
					}
				}
			}
			else if (_pBoard[ay][ax].team == 0 && b_cnt == 0) { //이동하려는 말이 검은색이고 그 말이 지금까지 이동을 안했다면
				//printf("%d %d", bx, by);
				if (bx == 1 && by == 8) { //캐슬링 할 룩이 br1 이라면
					if (br1 == 0) {
						if (_pBoard[8][2].type == 0 && _pBoard[8][3].type == 0)
						{
							_move(ax, ay, 2, 8, _pBoard);
							_move(bx, by, 3, 8, _pBoard);
							castling = 1;
							b_cnt++;
							return 1;
						}
					}
				}
				else if (bx == 8 && by == 8) { //캐슬링 할 룩이 br2 이라면
					if (br2 == 0) {
						if (_pBoard[8][5].type == 0 && _pBoard[8][6].type == 0 && _pBoard[8][7].type == 0)
						{
							_move(ax, ay, 6, 8, _pBoard);
							_move(bx, by, 5, 8, _pBoard);
							castling = 1;
							b_cnt++;
							return 1;
						}
					}
				}
			}

		}
		if (castling == 0) { //캐슬링을 실패했다면
			printf("same team impossible\n");
			return 0; //이동 실패
		}
	}
	if (abs(ay - by) > 1 || abs(ax - bx) > 1) {
		printf("impossible\n");
		return 0;
	}
	else if (_pBoard[by][bx].type < 1) {
		if (_pBoard[ay][ax].team == 0) {
			b_cnt++;
		} 
		else if (_pBoard[ay][ax].team == 1) {
			w_cnt++;
		} 
		printf("move\n");
		_move(ax, ay, bx, by, _pBoard);
		else return 1;
	}
	else if (_pBoard[by][bx].team != team) {
		if (_pBoard[ay][ax].team == 0) {
			b_cnt++;
		}
		else if (_pBoard[ay][ax].team == 1) {
			w_cnt++;
		}
		printf("attack\n");
		_move(ax, ay, bx, by, _pBoard);
		else return 2;
	}
	else
		printf("error\n");
	return 0;
}

맨 1,2번째 if문에서 선택한 기물이 룩이고 선택한 왕과 팀이 같은지 확인한다. 그 다음 룩의 팀과 어느 룩이냐에 따라 경우를 나눈다. 그리고 이에 맞게 위해서 만든 변수를 이용하여 이전에 이동을 했는지 확인한다. 만약 이동을 안했다면 킹과 룩을 알맞은 자리로 이동시킨다. 마지막으로 캐슬링이라는 변수에 1을 넣어 성공 여부를 판단하고 성공했다면 1을 리턴, 실패했다면 0을 리턴한다.

3. 마치며

첫 번째 추가 기능 구현을 마쳤다. 캐슬링은 이동되는 자리가 정해져 있어 약간의 노가다만 있었을 뿐 그렇게 어렵지는 않았다. 다음에는 폰이 끝까지 이동하면 다른 기물로 바꿀 수 있는 계승을 구현해볼 것이다.

0개의 댓글