혼자서 하는 틱택토

원용현·2023년 2월 25일
0

프로그래머스

목록 보기
38/49

링크

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

문제

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

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

혼자서 선공과 후공을 둘 다 맡는다.
틱택토 게임을 시작한 후 "O"와 "X"를 혼자서 번갈아 가면서 표시를 하면서 진행한다.
틱택토는 단순한 규칙으로 게임이 금방 끝나기에 머쓱이는 한 게임이 종료되면 다시 3x3 빈칸을 그린 뒤 다시 게임을 반복했습니다. 그렇게 틱택토 수 십 판을 했더니 머쓱이는 게임 도중에 다음과 같이 규칙을 어기는 실수를 했을 수도 있습니다.

"O"를 표시할 차례인데 "X"를 표시하거나 반대로 "X"를 표시할 차례인데 "O"를 표시한다.
선공이나 후공이 승리해서 게임이 종료되었음에도 그 게임을 진행한다.
게임 도중 게임판을 본 어느 순간 머쓱이는 본인이 실수를 했는지 의문이 생겼습니다. 혼자서 틱택토를 했기에 게임하는 과정을 지켜본 사람이 없어 이를 알 수는 없습니다. 그러나 게임판만 봤을 때 실제로 틱택토 규칙을 지켜서 진행했을 때 나올 수 있는 상황인지는 판단할 수 있을 것 같고 문제가 없다면 게임을 이어서 하려고 합니다.

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

문제 풀이

board라는 O와 X로 구성된 2차원 배열을 보고 틱택토 게임의 진행조건에 알맞은 형태를 가지고 있는지 확인하면 된다.

틱택토 게임은 O와 X가 서로 번갈아가며 한 번씩 칸을 칠하는 단순한 게임이고 O가 선공이기 때문에 비교적 간단하게 찾아낼 수 있다.

코드를 구성할 때 두 가지 방식으로 접근이 가능한데 하나는 잘 진행되고 있는 경기인지 판별하는 것이고, 하나는 잘못 진행된 경기인지 판별하는 것이다. 이 글에서는 잘 진행되는 경기인지 판별하는 방식으로 코드를 작성할 것이다.

잘 진행되는 경기라면 아래의 조건을 만족할 것이다.

  1. 승리조건을 만족한 경우
    1-1. O가 승리 -> X는 패배, O가 X보다 1가 더 많아야 함.
    1-2. X가 승리 -> O는 패배, O와 X의 개수가 같아야 함.
  2. 승리조건을 만족하지 못한 경우
    O의 개수가 X와 같거나 1개 더 많아야 한다.

위의 것들을 만족하기 위해서는 O와 X가 각각 몇개씩 있는지 계산을 해야하며, 승리조건을 만족하는 줄이 존재하는지 확인해야한다.

그 후에 위의 조건에 따라서 0 혹은 1을 반환하면 코드를 작성할 수 있다.

코드

// 승리 조건에 만족 못하면 0을 반환하는 방식으로 코드를 작성
function solution(board) {
    // o와 x의 개수 계산
    let countO = 0
    let countX = 0
    
    for(let i = 0; i < 3; i++) {
        for(let j = 0; j < 3; j++) {
            if(board[i][j] === "O") countO++
            else if(board[i][j] === "X") countX++
        }
    }
    
    // 승리 조건에 만족하는 줄수 구하기
    let winO = 0
    let winX = 0
    
    for(let i = 0; i < 3; i++) {
        if(board[i][0] === "O" && board[i][1] === "O" && board[i][2] === "O") winO++
        else if(board[0][i] === "O" && board[1][i] === "O" && board[2][i] === "O") winO++
        else if(board[i][0] === "X" && board[i][1] === "X" && board[i][2] === "X") winX++
        else if(board[0][i] === "X" && board[1][i] === "X" && board[2][i] === "X") winX++
    }
    if(board[0][0] === "O" && board[1][1] === "O" && board[2][2] === "O") winO++
    else if(board[0][2] === "O" && board[1][1] === "O" && board[2][0] === "O") winO++
    else if(board[0][0] === "X" && board[1][1] === "X" && board[2][2] === "X") winX++
    else if(board[0][2] === "X" && board[1][1] === "X" && board[2][0] === "X") winX++
    
    // 게임이 끝나지 않은 경우 -> winO === winX === 0, o의 개수는 x와 같거나 +1
    if(!winO && !winX && (countO === countX || countO === countX + 1)) return 1
    
    // o가 승리한 경우 -> o의 개수는 x + 1
    if(winO && !winX && countO === countX + 1) return 1
    
    // x가 승리한 경우 -> o와 x의 개수는 같다
    if(!winO && winX && countO === countX) return 1
    
    return 0
}

다른 접근

코드를 작성할 때 처음부터 잘 진행되고 있는 게임인지 확인하는 방식으로 접근했기 때문에 위의 코드처럼 작성되었지만, 만약에 진행이 이상한 게임인지 확인하는 방식으로 접근한다면 아래의 조건을 만족할 것이다.

  1. O와 X의 개수가 이상
    O가 될 수 있는 개수는 X와 같거나 X보다 1개 많음.
  2. 둘 모두 승리
  3. O가 승리
    O가 승리했는데 X의 개수가 O와 같거나 X가 더 많음.
  4. X가 승리
    X가 승리했는데 O와 X의 개수가 같지 않음.

0개의 댓글