728x90

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

 

프로그래머스

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

programmers.co.kr

 

문제


더보기

틱택토는 두 사람이 하는 게임으로 처음에 3x3의 빈칸으로 이루어진 게임판에 선공이 "O", 후공이 "X"를 번갈아가면서 빈칸에 표시하는 게임입니다. 가로, 세로, 대각선으로 3개가 같은 표시가 만들어지면 같은 표시를 만든 사람이 승리하고 게임이 종료되며 9칸이 모두 차서 더 이상 표시를 할 수 없는 경우에는 무승부로 게임이 종료됩니다.

할 일이 없어 한가한 머쓱이는 두 사람이 하는 게임인 틱택토를 다음과 같이 혼자서 하려고 합니다.

  • 혼자서 선공과 후공을 둘 다 맡는다.
  • 틱택토 게임을 시작한 후 "O"와 "X"를 혼자서 번갈아 가면서 표시를 하면서 진행한다.

틱택토는 단순한 규칙으로 게임이 금방 끝나기에 머쓱이는 한 게임이 종료되면 다시 3x3 빈칸을 그린 뒤 다시 게임을 반복했습니다. 그렇게 틱택토 수 십 판을 했더니 머쓱이는 게임 도중에 다음과 같이 규칙을 어기는 실수를 했을 수도 있습니다.

  • "O"를 표시할 차례인데 "X"를 표시하거나 반대로 "X"를 표시할 차례인데 "O"를 표시한다.
  • 선공이나 후공이 승리해서 게임이 종료되었음에도 그 게임을 진행한다.

게임 도중 게임판을 본 어느 순간 머쓱이는 본인이 실수를 했는지 의문이 생겼습니다. 혼자서 틱택토를 했기에 게임하는 과정을 지켜본 사람이 없어 이를 알 수는 없습니다. 그러나 게임판만 봤을 때 실제로 틱택토 규칙을 지켜서 진행했을 때 나올 수 있는 상황인지는 판단할 수 있을 것 같고 문제가 없다면 게임을 이어서 하려고 합니다.

머쓱이가 혼자서 게임을 진행하다 의문이 생긴 틱택토 게임판의 정보를 담고 있는 문자열 배열 board가 매개변수로 주어질 때, 이 게임판이 규칙을 지켜서 틱택토를 진행했을 때 나올 수 있는 게임 상황이면 1을 아니라면 0을 return 하는 solution 함수를 작성해 주세요.

 

입출력( + 추가적인 Test Case)


board result
["O.X", ".O.", "..X"] 1
["OOO", "...", "XXX"] 0
["...", ".X.", "..."] 0
["...", "...", "..."] 1
["OXX",".OX","..O"] 1
["OXX","OXX","OOO"] 0
["O.X","OOX",".OX"] 0

제한사항


더보기
  • board의 길이 = board[i]의 길이 = 3
    • board의 원소는 모두 "O", "X", "."으로만 이루어져 있습니다.
  • board[i][j]는 i + 1행 j + 1열에 해당하는 칸의 상태를 나타냅니다.
    • "."은 빈칸을, "O"와 "X"는 해당 문자로 칸이 표시되어 있다는 의미입니다.

풀이방법


틱택토가 성립이 안되는 경우가 있습니다.

1. 순서가 어긋난 경우

2. X가 성립되고 O를 놓는 경우

3. O가 성립되고 X를 놓는 경우

총 3가지가 있습니다.

 

1번의 경우

O의 개수는 cnt_o, X의 개수는 cnt_X 입니다.

cnt_x > cnt_o 의 경우

cnt_o > cnt_x + 1 의 경우 2가지 중 하나라도 성립되는 경우 오류입니다.

 

tic_o는 O가 성립된 경우, tic_x는 X가 성립된 경우 입니다.

 

2번의 경우

tic_x == 1 이면서 cnt_o > cnt_x 이면, X가 성립되고 O를 놓은 경우이므로 오류입니다.

 

3번의 경우

tic_o == 1 이면서 cnt_o == cnt_x 이면, O가 성립되고, X를 놓는 경우이므로 오류입니다.

 

총 3가지의 경우를 거치고 오류가 없다면 틱택토는 성립합니다.

코드


def tic_tac_toe(player, board):
    tic = 0

    for i in range(3):
        if all(player == cell for cell in board[i]):
            tic += 1

    for j in range(3):
        if all(player == board[i][j] for i in range(3)):
            tic += 1

    if all(board[i][i] == player for i in range(3)):
        tic += 1
    if all(board[i][2 - i] == player for i in range(3)):
        tic += 1

    return tic


def solution(board):
    board_list = [list(i) for i in board]

    # x, o 개수 세기
    cnt_x, cnt_o = 0, 0
    for i in range(3):
        for j in range(3):
            if board_list[i][j] == 'X':
                cnt_x += 1
            elif board_list[i][j] == 'O':
                cnt_o += 1
            else:
                continue

    # 순서가 어긋난 경우
    if cnt_x > cnt_o or cnt_o > cnt_x + 1:
        return 0
        
	# x와 o의 틱택토 성립하는지 확인
    tic_o = tic_tac_toe('O', board)
    tic_x = tic_tac_toe('X', board)

    # o 가 완성된 이후 x를 놓은 경우
    if tic_o == 1 and (cnt_x == cnt_o):
        return 0

    # x 가 완성된 이후 o를 놓은 경우
    if tic_x == 1 and (cnt_o > cnt_x):
        return 0

    return 1

 

all functions을 사용하지 않은 경우

더보기
def tic_tac_toe(board_list):
    tic_o = 0
    if board_list[0] == ['O', 'O', 'O'] or board_list[1] == ['O', 'O', 'O'] or board_list[2] == ['O', 'O', 'O']:
        tic_o += 1

    if board_list[0][0] == 'O' and board_list[1][0] == 'O' and board_list[2][0] == 'O':
        tic_o += 1
    elif board_list[0][1] == 'O' and board_list[1][1] == 'O' and board_list[2][1] == 'O':
        tic_o += 1
    elif board_list[0][2] == 'O' and board_list[1][2] == 'O' and board_list[2][2] == 'O':
        tic_o += 1

    if board_list[0][0] == 'O' and board_list[1][1] == 'O' and board_list[2][2] == 'O':
        tic_o += 1
    elif board_list[0][2] == 'O' and board_list[1][1] == 'O' and board_list[2][0] == 'O':
        tic_o += 1

    tic_x = 0
    if board_list[0] == ['X', 'X', 'X'] or board_list[1] == ['X', 'X', 'X'] or board_list[2] == ['X', 'X', 'X']:
        tic_x += 1

    if board_list[0][0] == 'X' and board_list[1][0] == 'X' and board_list[2][0] == 'X':
        tic_x += 1
    elif board_list[0][1] == 'X' and board_list[1][1] == 'X' and board_list[2][1] == 'X':
        tic_x += 1
    elif board_list[0][2] == 'X' and board_list[1][2] == 'X' and board_list[2][2] == 'X':
        tic_x += 1

    if board_list[0][0] == 'X' and board_list[1][1] == 'X' and board_list[2][2] == 'X':
        tic_x += 1
    elif board_list[0][2] == 'X' and board_list[1][1] == 'X' and board_list[2][0] == 'X':
        tic_x += 1

    return tic_o, tic_x


def solution(board):
    board_list = [list(i) for i in board]

    # x, o 개수 세기
    cnt_x, cnt_o = 0, 0
    for i in range(3):
        for j in range(3):
            if board_list[i][j] == 'X':
                cnt_x += 1
            elif board_list[i][j] == 'O':
                cnt_o += 1
            else:
                continue

    # 순서가 어긋난 경우
    if cnt_x > cnt_o or cnt_o > cnt_x + 1:
        return 0

    tic_o, tic_x = tic_tac_toe(board_list)

    # o 가 완성되었는데 x를 놓은 경우
    if tic_o == 1 and (cnt_x == cnt_o):
        return 0

    # x 가 완성되었는데 o를 놓은 경우
    if tic_x == 1 and (cnt_o > cnt_x):
        return 0

    answer = 1
    return answer

상당히 코드가 더럽다. all function을 사용해서 깔끔하게 바꾸었다. 

 

결론


처음에 규칙을 찾느라 어려웠다. 틱택토를 해본적도 없었기 때문이다. 규칙을 빨리 찾고나서 구현은 생각보다 쉬웠다. 하지만 밑에 있는 코드는 너무 복잡해 보여서 Python의 all function을 사용해서 깔끔하게 바꾸었다. 덕분에 all function을 배워갔다.

728x90