코딩테스트풀이

23.05.18 혼자서 하는 틱택토

best_spear_man 2023. 5. 19. 03:20

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

 

프로그래머스

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

programmers.co.kr

문제 설명:

주어진 틱택토 판을 보고, 다음의 틱택토 규칙대로 진행되었을 때 나올 수 있는 경우인지 아닌지를 판단해야한다.

1. O가 먼저둔다. (O,X,O,X,...)
2. 가로/세로/대각선 1줄(3개)를 완성시키면 해당 인원이 승리하고 게임이 종료된다(더이상 진행되지 않음).

 

시도 1:

먼저 순서를 잘 지켰는지를 확인한다. 순서를 잘 지켰다면 반드시 O가 X 보다 1개 많거나, 같아야한다.

def solution(board):
    count_o=0
    count_x=0
    for row in board:
        for i in row:
            if i=='O':
                count_o+=1
            elif i=='X':
                count_x+=1
    if not (count_x-1<count_o and count_o<count_x+2):
        return 0

순서를 잘 지켰다면, 다음으로는 게임이 이미 승리한 상태인지를 확인한다.

    def victory(board):
        vic=["O"*3,"X"*3]
        # row
        for v in vic:
            if v in board:
                return v[0]
        # col
        trancepose=[''.join(x) for x in list(zip(*board))]
        for v in vic:
            if v in trancepose:
                return v[0]
        # diagonal
        if board[0][0]==board[1][1] and board[1][1]==board[2][2]:
            return board[1][1]
        if board[2][0]==board[1][1] and board[1][1]==board[0][2]:
            return board[1][1]
        return False
    
    ...
    if victory(board)=="O" and (count_x>=count_o):
        return 0
    if victory(board)=="X" and (count_x!=count_o):
        return 0

보드 상태로부터 승리 유무 여부를 판단하는 함수 victory를 만들고, (O가 X보다 먼저 두므로 동시에 승리한 경우는 O의 승리로 간주하고 진행) O가 승리했을 시, 반드시 O가 X 보다 갯수가 많아야하고, 반대의 경우 반드시 갯수가 같아야한다는 것을 이용해 판별하려고했다.

 

그러나 이 방법은 실패하였다. 방법을 찾기위해 반례를 찾던 중 다음의 반례를 찾을 수 있었다.

XXX
OOX
OOO

위 예시를 위 코드에 대입할 경우, O가 승리한 경우이고 X갯수가 O보다 1개적으므로 1이 나온다. 실제로는 O가 이긴 후 1~2턴씩 더 진행된 경우거나, X가 이긴 후 1 턴 씩 더 진행된 경우이므로 성립되지 않는다. 전자를 가정하고 접근하는 경우 다른 O승리, O 갯수 5개 인 존재가능한 케이스와 분별이 불가능하다.

XOX
XOX
OOO

따라서 위 코드로는 이 반례를 해결할 수 없었다.

 

해결: O 승리과 X 승리 따로 체크하기

def victory(player,board):
    v=player*3
    if v in board:
        return True
    trancepose=[''.join(x) for x in list(zip(*board))]
    if v in trancepose:
        return True
    if board[0][0]==board[1][1] and board[1][1]==board[2][2]:
        return True if board[1][1]==player else False
    if board[2][0]==board[1][1] and board[1][1]==board[0][2]:
        return True if board[1][1]==player else False
    return False

...
    if victory("O",board) and (count_x>=count_o):
        return 0
    if victory("X",board) and (count_x!=count_o):
        return 0
    
    return 1

위와같이 O 승리와 X승리를 분리하여 둘 다 체크하면, 위와같은 반례도 해결할 수 있었다.