알고리즘

프로그래머스_혼자서 하는 틱_Day2

Leo.K 2024. 2. 7. 14:43

 

알고리즘 풀이 챌린지 2일 차이다. 
오늘은 마찬가지로 프로그래머스 level2로 분류되어 있는 구현 문제를 가져와 풀이해 보았다. 

https://school.programmers.co.kr/learn/courses/30/lessons/160585?language=python3

 

프로그래머스

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

programmers.co.kr

 

문제를 읽다 보면 머쓱이의 실수를 고려해야 하나 하는 의심이 들었지만 그냥 그럴 수도 있겠다~ 정도만 생각하고 가볍게 읽어도 될 것 같다. 머쓱이의 실수와는 별개로 결과론적으로 봤을 때, 규칙 내에서 가능한 경우의 수 인지만 판단하면 된다.

틱택토라는 게임 자체도 3 x 3 크기의 고정판이며 선공 후공이 정해져 있기 때문에 규칙을 코드로 구현만 한다면 간단한 문제이다. 

나는 처음에 O의 개수와 X의 개수를 기준으로 조건을 분기하다 보니 너무 복잡했었는데, 직접 써보고 나니까 공통적인 규칙이 존재했다. 

 이러한 구현의 문제를 풀이하는 경우, 가능한 경우의 수를 하나하나 찾는 것은 너무나도 어려운 일이다. 모든 경우의 수 에서 불가능한 경우만 제외하고, 나머지를 구하는 방식이 구현이 훨씬 간단하다.
그렇다면 규칙을  위반한 경우의 수를 살펴보자. 

1. 선공이 ("O")이며 번갈아 가며 후공을 한 번씩 진행한다.
즉, X의 개수가 O의 개수보다 많을 수 없다. 또한, O의 개수가 X 보다 많다면 1개보다 더 많을 수 없다

2. O가 이긴 경우, O의 개수와 X의 개수가 같을 수 없다. 

3. X가 이긴 경우, O의 개수는 X의 개수와 같아야 한다. 

 

 

위의 이미지 조건을 참고하여 코드로 작성해보면 아래와 같다. 

Java

더보기
import java.util.*;
import java.util.stream.*;
class Solution {
    public int solution(String[] board) {
        int Ocnt = 0; 
        int Xcnt = 0; 
        
        // 맵 초기화
        String [][] map = new String[board.length][board[0].length()];
        for(int i=0; i<board.length; i++){
            String tmp[] = board[i].split("");
            for(int j=0; j<board[i].length(); j++){
                if(tmp[j].equals("O")) Ocnt++;
                else if(tmp[j].equals("X")) Xcnt++;
                map[i][j] = tmp[j];
            }
        }
        if(Ocnt < Xcnt) return 0;
        if(Ocnt - Xcnt > 1) return 0; 
        if(check(map, "O")) {
            System.out.println(Ocnt);
            System.out.println(Xcnt);
            if(Ocnt == Xcnt) return 0;
        }
        
        if(check(map, "X")) {
            if(Ocnt > Xcnt) return 0;
        }

        return 1;
    }
    
    public boolean check(String [][] map, String winner) {
        //가로 줄 체크 (행 체크)
        for(String tmp[] : map) {
            String temp = winner + winner + winner;
            String collect = Arrays.stream(tmp).collect(Collectors.joining());
            if(collect.equals(temp)) return true;
        }
        
        //세로 줄 체크 (열 체크)
        for(int y=0; y<3; y++){
            if(map[0][y].equals(map[1][y]) && map[1][y].equals(map[2][y]) && map[2][y].equals(winner)) return true;     
        }
        
        
        //대각 선 줄 체크 (행 인덱스 == 열 인덱스)
        if(map[0][0].equals(map[1][1]) && map[1][1].equals(map[2][2]) && map[2][2].equals(winner)) return true;
        if(map[2][0].equals(map[1][1]) && map[1][1].equals(map[0][2]) && map[0][2].equals(winner)) return true;
        
        
        return false;
    }
}

 

Python

더보기
def solution(board):
    board = [list(row) for row in board]

    oCnt, xCnt = 0, 0
    for row in board:
        for c in row:
            if c == 'O':
                oCnt += 1
            elif c == 'X':
                xCnt += 1
                
    
    if oCnt < xCnt: return 0
    
    if oCnt > xCnt + 1: return 0
    
    if winner(board, 'O'):
        if oCnt == xCnt: return 0
    
    if winner(board, 'X'):
        if oCnt == xCnt + 1: return 0
    return 1

def winner(board, t):
    #가로줄 판단 
    for row in board: 
        if row == [t, t, t]: return True
    
    
    #세로줄 판단
    for col in range(3):
        if([board[row][col] for row in range(3)] == [t, t, t,]): return True
    
    #대각선 판단
    if [board[0][0], board[1][1], board[2][2]] == [t, t, t]: return True
    if [board[2][0], board[1][1], board[0][2]] == [t, t, t]: return True
    
    return False