본문 바로가기
프로그래밍/알고리즘 문제풀이

[pg] 프로그래머스 혼자서 하는 틱택토

by 노잼인간이라불립니다 2023. 9. 8.

1. 문제 정의

 3x3의 빙고게임과 동일하다. 3x3의 테이블에 O 또는 X를 순서대로 표시하면서 먼저 빙고를 만드는 쪽이 승리하는 게임이다. 그러나 이 문제에서는 제일 마지막 상황에서의 3x3 테이블의 상태를 보여주고, 이것이 정상적인 게임인가, 아니면 비정상적인 게임인가를 찾아내는 게임이다. (O가 선공이고 X가 후공인데 O의 갯수는 2개 X의 갯수는 3개라면 비정상적인 게임)

 

2. 내가 한 시도

 3x3의 매우 적은 경우의 수를 가지고 있는 빙고게임에도 불구하고, 경우의 수를 공통화 시켜서 짧은 코드를 짜려고 시도하다가 많은 삽질을 경험했다.

 그래서 결국에는 3x3에서 나올 수 있는 비정상 게임의 경우의 수를 걸러내는 식으로 진행했다.

 

3. 코드

import java.util.HashMap;
import java.util.Map;

/**
 * 프로그래머스 LV2
 * 혼자서하는틱택토
 * 접근 방법: 정상적이지 않은 게임의 조건을 생각해내는 것이 포인트였으나, 각각의 경우의 수를 생각하기가 힘들었음.
 * 최대한 쪼개서 정상적이지 않은 경우를 걸러내는 식으로 구현
 */
public class Solution {
    public int solution(String[] board) {
        int oSum = 0; // 'O'갯수
        int xSum = 0; // 'X'갯수

        /*
         * O빙고와 X빙고가 공존할 때 쓰기 위한 맵
         */
        Map<Character, Character> map = new HashMap<>();
        map.put('O', 'X');
        map.put('X', 'O');

        /*
         * 이차원 배열로 변환
         */
        char[][] game = new char[3][3];

        /*
         * 이차원 배열에 데이터를 넣고, O의 갯수와 X의 갯수를 구함
         */
        for (int i = 0; i < board.length; i++) {
            game[i] = board[i].toCharArray();
            for (int j = 0; j < game[i].length; j++) {
                char c = game[i][j];
                if (c == 'O') oSum++;
                if (c == 'X') xSum++;
            }
        }

        // 가로 세로 빙고일 경우 o,x 모두 3개일 경우 체크, o,x 갯수 체크
        // 1. o보다 x가 많을경우
        // 2. o가 x보다 2 이상 많을 경우
        // 3. o가 이겼을 경우 x는 o-1, x가 이겼을 경우 o=x.
        for (int i = 0; i < 3; i++) {

            // 가로
            if (game[i][0] == game[i][1] && game[i][1] == game[i][2] && game[i][0] != '.') {
                Character character = map.get(game[i][0]);
                /*
                 * 0,X 빙고 공존하는지 확인
                 */
                for (int j = i + 1; j < 3; j++) {
                    if (game[j][0] == character && game[j][1] == character && game[j][2] == character) {
                        return 0;
                    }
                }
                /*
                 * 0로 끝났을 때
                 */
                if (game[i][0] == 'O') {
                    if (oSum - xSum == 1) {
                        return 1;
                    }
                    return 0;
                }
                /*
                 * X로 끝났을 때
                 */
                if (game[i][0] == 'X') {
                    if (oSum - xSum == 0) {
                        return 1;
                    }
                    return 0;
                }
            }

            // 세로
            if (game[0][i] == game[1][i] && game[1][i] == game[2][i] && game[0][i] != '.') {
                Character character = map.get(game[0][i]);
                /*
                 * O,X 공존하는지 확인
                 */
                for (int j = i + 1; j < 3; j++) {
                    if (game[0][j] == character && game[1][j] == character && game[2][j] == character) {
                        return 0;
                    }
                }
                /*
                 * O로 끝났을 때
                 */
                if (game[0][i] == 'O') {
                    if (oSum - xSum == 1) {
                        return 1;
                    }
                    return 0;
                }
                /*
                 * X로 끝났을 때
                 */
                if (game[0][i] == 'X') {
                    if (oSum - xSum == 0) {
                        return 1;
                    }
                    return 0;
                }

            }
        }


        // 빙고가 없는 경우  또는 대각선 빙고일 경우 o,x 갯수만 확인하면 된다.
        // 1. o로 끝났을 경우 x는 o-1, x가 빙고일 경우 o=x.
        // 2. o가 x보다 2이상 큰경우
        // 3. x가 o보다 큰 경우.

        /*
         * 왼쪽대각선
         */
        if (game[0][0] == game[1][1] && game[1][1] == game[2][2] && game[0][0] != '.') {
            /*
             * O,X 갯수확인
             */
            if (game[0][0] == 'O') {
                if (oSum == xSum + 1) {
                    return 1;
                }
                return 0;
            }
            if (oSum == xSum) {
                return 1;
            }
            return 0;
        }

        /*
         * 오른쪽 대각선
         */
        if (game[2][0] == game[1][1] && game[1][1] == game[0][2] && game[2][0] != '.') {
            /*
             * O,X 갯수확인
             */
            if (game[2][0] == 'O') {
                if (oSum == xSum + 1) {
                    return 1;
                }
                return 0;
            }
            if (oSum == xSum) {
                return 1;
            }
            return 0;
        }

        // 빙고가 없는 경우
        if (oSum == xSum || oSum == xSum + 1) {
            return 1;
        }
        return 0;


    }
}

 

4. 회고

 3x3 빙고 게임에서 비정상적인 게임의 경우의수를 찾아내는 것이 핵심이었던 것 같다. 경우의 수는 많지 않았지만, 이 경우의 수를 찾아내서 걸러내는 로직을 작성하는 것에 조금 시간이 들었던 것 같다.

 복잡한 문제나 경우의 수와 같은 문제를 풀 경우에는 노트에 문제를 작게작게 쪼개서 정리하는 습관을 들이면 좋을 것 같다. 아직 문제를 작게 작게 쪼개어 생각하는 습관과 그것을 메모로 풀어내서 정리하는 능력이 부족 한 것 같다.

 

참조

https://school.programmers.co.kr/learn/courses/30/lessons/160585