교내 전공과목인 윈도우즈 API수업을 정리합니다
1. Tic-Tac-Toe 프로그램을 수읽기(재귀함수)를 통해 사용해보자
인공지능의 min-max-Game Tree, 즉 수 읽기 알고리즘을 적용시켜 보자
(1) 소스코드, 구현사항
// init 함수
void init(HWND hWnd) { //파라미터를 가지도록 변경
int i, j;
turn = 1;
iCount = 0;
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++) {
pan[i][j] = 0;
}
InvalidateRect(hWndMain, NULL, TRUE);
}
//evaluate함수
int evaluate(int depth = 0) {
if (winpoint(2)) // 컴퓨터가 이기는 결과에 점수 증가
return 10 + depth;
else if (winpoint(1)) // 컴퓨터가 지는 결과에 점수 감수
return -10 - depth;
else
return 0;
}
//minmax함수
int minmax(int* pos, int depth, int turn) {
int score;
int best;
int position;
if (turn == 1)
best = 99;
else
best = -99;
if (depth == 0 || winpoint(1) || winpoint(2))
return evaluate(depth);
for (int i = 0; i < 9; i++) {
if (pan[i % 3][i / 3] == 0) {// 선하향 후우향, 빈 칸이라면
pan[i % 3][i / 3] = turn; // 탐색을 위해 현재 차례에 컴퓨터의 돌을 놓기 (예상)
if (turn == 1)
/*재귀함수*/
score = minmax(pos, depth - 1, 2); // 컴퓨터 차례로 넘겨서 이전 칸의 minmax값 찾기
else
score = minmax(pos, depth - 1, 1); // 플레이어 차례로 넘겨서 이전 칸의 minmax값 찾기
pan[i % 3][i / 3] = 0; // 계산을 끝낸 후, 현 자리를 초기화 한다
if (turn == 1) { // 플레이어 조사시, 최적값이 '최소'가 되는 것을 찾아 기록한다
if (score < best) {
best = score;
position = i; // i기준의 최적값(최소) 위치 기록
}
}
else { // 컴퓨터 조사시, 최적값이 '최대'가 되는 것을 찾아 기록한다
if (score > best) {
best = score;
position = i; // i기준의 최적값(최대) 위치 기록
}
}
}
}
*pos = position; // 최종 위치를 선택(주소값이니까 전역st)
return best; //최적값 반환
}
필요한 설명은 주석에 달았으나, 이 함수가 제일 중요하다.
i를 통해 각 칸에 대하여, 경로의 최적값을 판단하기 위한 점수를 부여한다
이 함수가 끝날 때 최적위치와 최적값을 저장한다
// computer함수, 실제로 computer가 바둑을 두게 됨
int computer() {
int depth = 0;
int pos = 0;
for (int i = 0; i < 9; i++)
if(pan[i%3][i/3] == 0)
depth++; //depth는 현재 비어있는 칸의 수로 결정
minmax(&pos, depth, 2); // 컴퓨터의 최적을 찾으러 감
pan[pos % 3][pos / 3] = 2; // 여기는 컴퓨터 꺼
if (winpoint(2)) // 이겼다면 1이 들어옴(true)
return 1;
else // 졌다면
return 0;
}
minmax를 쓰게되는 함수.
//WndProc > WM_LBUTTONDOWN의 일부
if (pan[x][y] == 0) {
pan[x][y] = turn;
iCount++;
// turn = (turn == 1 ? 2 : 1); // 컴퓨터와 승부할 것이니 이제 필요없음
InvalidateRect(hWnd, NULL, TRUE);
UpdateWindow(hWnd);
//메세지박스 응답선택에 따른 반응
if (winpoint(1)) { // 1이 이겼다면
wsprintf(buf, TEXT("사용자 win. \n 새로 시작하겠습니까?"));
if (MessageBox(hWnd, buf, TEXT("TicTacToe"), MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
init(hWnd);
else
SendMessage(hWnd, WM_CLOSE, 0L, 0L);
return 0;
}
else if (iCount == 9) { // 더 이상 둘 곳이 없어 비기거나 플레이어가 졌다면
if (MessageBox(hWnd, TEXT("Game Over. \n 새로 시작하겠습니까?"), TEXT("TicTacToe"),
MB_YESNO | MB_ICONEXCLAMATION) == IDYES) {
init(hWnd);
//turn =1; //얜 없어도 될 것 같아서 가렸음
}
else
SendMessage(hWnd, WM_CLOSE, 0L, 0L);
return 0;
}
else { //게임이 진행중이라면,
int ret = computer(); // 컴퓨터의 승(1)패(0)값을 받아옴
iCount++;
InvalidateRect(hWnd, NULL, TRUE);
UpdateWindow(hWnd);
if (ret) { //컴퓨터가 이겼다면
wsprintf(buf, TEXT(" 컴퓨터 win. \n 새로 시작하겠습니까?"));
if (MessageBox(hWnd, buf, TEXT("MinMax"), MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
init(hWnd);
else
SendMessage(hWnd, WM_CLOSE, 0L, 0L);
return 0;
}
return 0;
}
}
조건문이 minmax를 활용하도록 바꼈다.
(2) 실행결과
컴퓨터를 절대 이길 수 없는, 지거나 비기기만 하는 게임이 진행됨