https://www.algospot.com/judge/problem/read/TICTACTOE
algospot.com :: TICTACTOE
틱택토 문제 정보 문제 틱택토는 3x3 크기의 게임판에서 하는 3목 게임입니다. 두 명이 번갈아가며 o와 x를 게임판의 빈 칸에 쓰되, 먼저 같은 글자를 가로, 세로 혹은 대각선으로 3개 쓰이도록 하
www.algospot.com
코드설명
동적계획법(Dynamic Programming, DP) + 게임이론(Game Theory) 을 활용합니다.
문제에서 유의할점은, 무조건 'x'가 먼저 시작하는 것이 아닌, 판의 상태에 따라 그다음 두어야할 숫자가 달라집니다.
코드
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.Arrays; import java.util.StringTokenizer; public class Main { private static int C, N, W, H, K; private static int answer = 0; private static int[] cache = new int[(int) Math.pow(3, 9)]; private static char[][] arr; public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine()); C = Integer.parseInt(st.nextToken()); while(C-- > 0){ arr = new char[3][3]; for(int i=0;i<3;i++) { st = new StringTokenizer(br.readLine()); arr[i] = st.nextToken().toCharArray(); } Arrays.fill(cache, -2); int oCnt = 0; int xCnt = 0; for(int i=0;i<3;i++) { for(int j=0;j<3;j++) { if(arr[i][j] == 'o') { oCnt += 1; }else if(arr[i][j] == 'x'){ xCnt += 1; } } } int result = 0; // System.out.println(isFinished(arr, 'x')); // System.out.println(isFinished(arr, 'o')); // // System.out.println("oCnt:"+oCnt+" xCnt:"+xCnt); //'o'를 두어야할 차례일 경우. if(xCnt == oCnt + 1) { result = canWin(arr, 'o'); if(result == 0) System.out.println("TIE"); else if(result == 1) System.out.println("o"); else if(result == -1) System.out.println("x"); } //'x'를 두어야할 차례일 경우 else if(xCnt == oCnt) { result = canWin(arr, 'x'); if(result == 0) System.out.println("TIE"); else if(result == 1) System.out.println("x"); else if(result == -1) System.out.println("o"); } } } //현재 플레이어가 이길 수 있는지 확인합니다. //반환값 : 1 (승리), 0 (무승부), -1(패배) private static int canWin(char[][] board, char turn) { //이전 상대가 둬서 이미 성공한 경우, 현재 플레이어는 패배한것 이다. if(isFinished(board, (char) ('o' + 'x' - turn))) return -1; if(cache[bijection(board)] != -2) return cache[bijection(board)]; //모든 빈 칸에 대해 시도합니다. //상방의 최선의 승패를 저장합니다. int minValue = 2; for(int r = 0; r < 3; r++) { for(int c =0; c < 3; c++) { if(board[r][c] == '.') { board[r][c] = turn; minValue = Math.min(minValue, canWin(board, (char) ('o' + 'x' - turn))); board[r][c] = '.'; } } } //만약, minValue가 2라면, '.'칸이 없어서 결과를 처리하지 못한경우 //minValue가 0 이라면, '.'칸이 없어서 결과를 처리하지 못한경우로 이미 비긴것으로 처리한 경우 //플레이할 수 없거나, 어떻게 해도 비기는 것이 최선인경우 if(minValue == 2 || minValue == 0) return cache[bijection(board)] = 0; //다음판의 게임자가 졌다면 내가 이긴것이므로 -minValue를 반환합니다. return cache[bijection(board)] = -minValue; } static int bijection(char[][] board) { int ret = 0; for(int r=0; r<3; r++) { for(int c =0; c<3; c++) { ret = ret * 3; if(board[r][c] == 'o') ret++; else if(board[r][c] =='x') ret += 2; } } return ret; } // private static boolean isFinished(char[][] board, char turn) { // // 가로, 세로 검사 // for (int i = 0; i < 3; i++) { // if (board[i][0] == turn && board[i][1] == turn && board[i][2] == turn) return true; // if (board[0][i] == turn && board[1][i] == turn && board[2][i] == turn) return true; // } // // // 대각선 검사 // if (board[0][0] == turn && board[1][1] == turn && board[2][2] == turn) return true; // if (board[0][2] == turn && board[1][1] == turn && board[2][0] == turn) return true; // // return false; // } // //주어진 플레이어가 승리했는지 확인합니다. private static boolean isFinished(char[][] board, char turn) { //가로, 세로 검사 for(int i=0; i<3; i++) { boolean isSame = true; for(int j=0; j<3; j++) { if(board[i][j] != turn) { isSame = false; break; } } if(isSame == true) { return true; } isSame = true; for(int j=0; j<3; j++) { if(board[j][i] != turn) { isSame = false; break; } } if(isSame == true) { return true; } } //대각선 검사. boolean isSame = true; for(int i=0;i<3;i++) { if(board[i][i] != turn) { isSame = false; break; } } if(isSame == true) { return true; } //대각선 검사. isSame = true; for(int i=0;i<3;i++) { if(board[3-i-1][i] != turn) { isSame = false; break; } } if(isSame == true) { return true; } return false; } }