반응형
Notice
Recent Posts
Recent Comments
Link
관리 메뉴

개발 쥬스

[프로그래머스/Java] 혼자서 하는 틱택토 본문

알고리즘

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

DevJuice 2024. 7. 30. 15:20
반응형

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

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

단순한 구현 문제였지만 반례를 하나 놓쳐서 고생했던 문제입니다.

 

고찰 과정

String[] 형태의 board를 저는 단순 Charater 형으로 바꿔서 다루고 싶었기에 cBoard를 따로 만들어 올바른 틱택토인지 판단하였습니다. 문제 해결 과정은 다음과 같습니다.

  1. 2차원 배열의 보드(cBoard)를 돌아보며 첫 행인 경우 또는 첫 열인 경우에는 나올 수 있는 빙고를 확인해주고 'O'에 대한 빙고의 수 및 'X'에 대한 빙고 개수를 세어준다.
  2.  보드에서 나온 'O'의 총 개수와 'X'의 총 개수를 세어준다.
  3. 나온 각 틱택토 문자의 총 개수 및 빙고수를 바탕으로 올바른 틱택토인지 판별한다.
    • 'X'의 총 개수가 'O'의 총 개수보다 많으면 올바른 틱택토가 아니다.
    • 'X'의 총 개수가 'O'의 총 개수보다 같고 'O'가 이긴 상황이 나온 경우 올바른 틱택토가 아니다.
    • 'O'의 총 개수가 'X'의 총 개수보다 많고 'O'와 'X'의 개수 차이가 한 개보다 많거나 'X'의 빙고가 한 개 이상이거나 'O'의 빙고가 2개가 넘어가는 경우 올바른 틱택토가 아니다.

이를 바탕으로 코드를 구현하였습니다. 참고로 반례를 찾은 것 중에서 오래 걸렸던 부분이 3번의 마지막 항목이었는데 'O'의 빙고가 두 개가 나오는 경우도 가능하다는 점이었습니다. 왜냐하면 'O'가 놓인 자리가 가로, 세로, 대각선 중 두 부분이 겹쳐서 동시에 빙고 처리가 되는 경우도 나올 수가 있기 때문입니다.


코드

import java.util.*;

class Solution {
    
    private static final int OK = 1;
    private static final int NOT_OK = 0;
    
    private static final char SPACE = '.';
    
    public int solution(String[] board) {
        int answer = OK;
        char[][] cBoard = new char[3][3];
        Map<Character, int[]> map = new HashMap<>();
        
        // 문자열을 캐릭터형 2차원 배열에 담아두기
        for (int i = 0; i < 3; ++i) {
            cBoard[i] = board[i].toCharArray();
        }
        
        map.put('X', new int[2]); // 총 카운트, 빙고카운트
        map.put('O', new int[2]);
        
        for (int i = 0; i < 3; ++i) {
            for (int j = 0; j < 3; ++j) {
                if (cBoard[i][j] == SPACE) {
                    continue;
                }
                
                // 첫행일 때 
                if (i == 0) {
                    if (j == 0) { // 첫 열
                        // 가로 확인
                        if (cBoard[i][j] == cBoard[i][j + 1] && cBoard[i][j] == cBoard[i][j + 2]) {
                            ++map.get(cBoard[i][j])[1];
                        } 
                        
                        // 오른아래 대각 확인
                        if (cBoard[i][j] == cBoard[i + 1][j + 1] && cBoard[i][j] == cBoard[i + 2][j + 2]) {
                            ++map.get(cBoard[i][j])[1];
                        }
                        
                    } else if (j == 2) { // 마지막 열인 경우
                        // 왼쪽아래 대각 확인
                        if (cBoard[i][j] == cBoard[i + 1][j - 1] && cBoard[i][j] == cBoard[i + 2][j - 2]) {
                            ++map.get(cBoard[i][j])[1];
                        }
                    }
                    // 세로의 빙고 여부 보기
                    if (cBoard[i][j] == cBoard[i + 1][j] && cBoard[i][j] == cBoard[i + 2][j]) {
                        ++map.get(cBoard[i][j])[1];
                    }
                    
                    ++map.get(cBoard[i][j])[0];
                } else { // 첫행이 아닐 때 가로만
                    if (j == 0) {
                        if (cBoard[i][j] == cBoard[i][j + 1] && cBoard[i][j] == cBoard[i][j + 2]) {
                            ++map.get(cBoard[i][j])[1];
                        } 
                    }
                    
                    ++map.get(cBoard[i][j])[0];
                }
            }
        }
        
        int[] xInfo = map.get('X');
        int[] oInfo = map.get('O');
        
        if (xInfo[0] > oInfo[0]) { // X의 수가 더 많은 경우는 없다.
            answer = NOT_OK;
        } else if (xInfo[0] == oInfo[0]) {  // x가 이기거나 진행중
            if (oInfo[1] > 0) { // O의 빙고가 하나 이상 나오거나 X의 빙고가 2개 이상 나온 경우
                answer = NOT_OK;
            }
        } else {// 무승부도 가능 -> 꽉 채웠을 때
            if (oInfo[0] - xInfo[0] > 1 || xInfo[1] >= 1 || oInfo[1] > 2) {
                answer = NOT_OK;
            }
        }
        
        return answer;
    }
}
반응형