코딩 테스트(Coding Test)/백준

[백준] 9090번 : 틱택토 이기기 - 자바(Java)

다문다뭉 2024. 11. 3. 17:42

Problem 🔒

문제

https://www.acmicpc.net/problem/9290

 

남규는 재우와 틱택토를 하던 도중, 거의 이기기 직전에 다다랐다! 남규의 승리로부터 단 한 단계 전의 틱택토 게임판이 주어졌을 때, 승리를 위해 말을 어디에 놓아야 할지 알아내자.

입력

첫 번째 줄에는 테스트 케이스의 개수가 주어진다.

각 테스트 케이스는 현재 틱택토 게임판의 상태를 3줄에 걸쳐 나타내며, 그 다음 줄에는 남규의 말(x 또는 o)이 무엇인지가 주어진다. 게임판의 상태는 'x', 'o', '-'(빈칸)으로 이루어진다. 반드시 다음 한 번의 행동으로 남규가 게임을 이길 수 있는 상태만 주어진다.

출력

각 테스트 케이스마다 "Case x:"와 공백을 출력한 후, 아래의 3줄에 걸쳐 남규가 다음 한 수로 이긴 후 게임판의 상태를 출력한다. x는 테스트 케이스의 번호이며, 1부터 시작한다.

더보기

예제 입력 1

3
o--
-o-
xx-
x
o-x
--o
x--
x
xx-
o-o
---
o

예제 출력 1

Case 1:
o--
-o-
xxx
Case 2:
o-x
-xo
x--
Case 3:
xx-
ooo
---

Approach ⭕

  1. 'O'와 'X' 위치 저장
    • 게임판을 읽으면서 'O'와 'X' 위치를 저장했다.
    • 남규의 말이 무엇인지는 게임판을 읽은 후, 알려주기 때문에 'O'와 'X' 위치 둘 다 저장했다.
  2. 남규의 말 위치 저장
    • 남규가 사용하는 말의 해당 좌표를 Apoint 배열에 복사했다.
  3. 이길 수 있는 위치 찾기
    • Apoint의 두 좌표에 따라 케이스를 나눠서 처리
      • 행이 같은 경우, 해당 행에서 비어있는 위치에 말을 놓았다.
      • 열이 같은 경우, 해당 열에서 비어있는 위치에 말을 놓았다.
      • 대각선인 경우, 비어있는 대각선 위치에 말을 놓았다.
    • 비어있는 위치 계산
      • 게임판의 인덱스는 항상 0, 1, 2로 이루어져 있어 인덱스의 합은 항상 3이다.
      • 현재 말이 있는 위치의 인덱스 합을 3에서 빼면, 나머지 빈 칸의 인덱스를 찾을 수 있다.

주의할 점

발생할 수 있는 2가지의 대각선을 서로 구분할 필요가 없다. 비어있는 위치 계산식이 항상 같다.


Solution 💡

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class 틱택토이기기 {
    static String[][] map;
    static String nam;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int tc = Integer.parseInt(st.nextToken()); // 테케
        for(int t=0; t<tc; t++){

            map = new String[3][3];
            // O좌표 2개, X좌표 2개
            int oS = 0;
            int xS = 0;
            int[][] Opoint = new int[2][2];
            int[][] Xpoint = new int[2][2];

            // 현재 게임판
            for(int i=0; i<3; i++){
                String rline = br.readLine();
                String[] tokens = rline.split("");
                for(int j=0; j<3; j++){
                    map[i][j] = tokens[j];
                    if(map[i][j].equals("o")){
                        Opoint[oS][0] = i;
                        Opoint[oS++][1] = j;
                    }
                    if(map[i][j].equals("x")){
                        Xpoint[xS][0] = i;
                        Xpoint[xS++][1] = j;
                    }
                }
            }
            // 남규 말
            nam = br.readLine();

            int[][] Apoint = new int[2][2];
            if (nam.equals("o")){
                for(int i=0; i<2; i++){
                    for(int j=0; j<2; j++){
                        Apoint[i][j] = Opoint[i][j];
                    }
                }
            }else{
                for(int i=0; i<2; i++){
                    for(int j=0; j<2; j++){
                        Apoint[i][j] = Xpoint[i][j];
                    }
                }
            }

            // 케이스 나누기
            if(Apoint[0][0] == Apoint[1][0]){
                // 행이 같을 때
                int tmp = 3 - (Apoint[0][1] + Apoint[1][1]);
                map[Apoint[0][0]][tmp] = nam;

            }else if(Apoint[0][1] == Apoint[1][1]){
                // 열이 같을 때
                int tmp = 3 - (Apoint[0][0] + Apoint[1][0]);
                map[tmp][Apoint[0][1]] = nam;

            }else {
                // 대각선
                int tmp1 = 3 - (Apoint[0][0] + Apoint[1][0]);
                int tmp2 = 3 - (Apoint[0][1] + Apoint[1][1]);
                map[tmp1][tmp2] = nam;

            }

            PrintGraph(map, t+1);

        }// tc
    }

    public static void PrintGraph(String[][] graph, int t){
        System.out.println("Case " + t + ":");
        for (String[] row : graph) {
            for (String e : row) {
                System.out.print(e);
            }
            System.out.println();
        }
    }

}