[백준] 7682_틱택토 (Javascript)

잭슨·2024년 5월 6일
0

알고리즘 문제 풀이

목록 보기
8/130
post-thumbnail

문제

BOJ7682_틱택토

풀이

요구사항

틱택토 게임에서 최종 상태인 경우와 최종 상태가 될 수 없는(아닌) 경우를 판별하는 프로그램을 작성하라.

해결방안

우선 최종 상태가 될 수 있는 경우부터 알아보자.

  • 가로로 3개가 연결된 경우
  • 세로로 3개가 연결된 경우
  • 대각선으로 3개가 연결된 경우
  • 판이 꽉 찬 경우

이제 위 조건을 충족하지만 최종상태가 될 수 없는 경우를 알아보자.

  • O의 개수가 X의 개수보다 많은 경우 (X가 먼저 시작하고, 판의 개수는 9개이기 때문에 O의 개수는 X의 개수보다 1개 적거나 동일할 수밖에 없다.)
  • X의 개수가 O의 개수보다 2개 이상 많을 경우 (서로 순서를 번갈아 가면서 게임을 진행하기 때문에 개수 차이는 2개 이상 날 수 없다.)
  • X가 3개 연결되었을 때 O의 개수는 X의 개수 -1가 아닌 경우 (X가 3개 연결되면 그대로 게임이 종료되기 때문에 O의 개수는 X의 개수 - 1 개여야 한다.)
  • O가 3개 연결되었을 때 X의 개수와 O의 개수가 동일하지 않을 경우 (O가 3개 연결되었을 때 X의 개수는 O의 개수오 동일해야 한다.)
  • X와 O 둘다 3개로 이어지지 않은 상태에서 X의 개수 + Y의 개수가 9보다 작을 경우 (아직 판이 꽉 차지 않은 상태이므로 게임을 더 진행할 수 있어서 최종 상태가 아니다.)

이 조건에 맞게 코드를 작성해주자.

코드

// 실제 게임에서 나올 수 있는 상태인지 확인하라
// O는 X의 개수보다 절대 많아질 수 없다.
// X의 개수 - O의 개수는 1보다 커질 수 없다.
// X가 3개 연결되어 있을 경우 O의 개수는 X의 개수 - 1개여야 한다.
// O가 3개 연결되어 있을 경우 X의 개수와 O의 개수는 동일하다.
// 누구도 이기지 않았고, X의 개수 + O의 개수 < 9 일경우 게임은 끝나지 않았다.

const filePath = process.platform === 'linux' ? '/dev/stdin' : './Javascript/input.txt';
const input = require('fs').readFileSync(filePath).toString().trim().split('\n');
let answer = '';

function vertical(arr, ox) {
    for (let i = 0; i < 3; i++) {
        if (arr[i] === ox && arr[i] === arr[i + 3] && arr[i + 3] === arr[i + 6]) return true;
    }
    return false;
}
function horizontal(arr, ox) {
    for (let i = 0; i < 9; i += 3) {
        if (arr[i] === ox && arr[i] === arr[i + 1] && arr[i + 1] === arr[i + 2]) return true;
    }
    return false;
}
function diagonal(arr, ox) {
    if (arr[0] === ox && arr[0] === arr[4] && arr[4] === arr[8]) return true;
    if (arr[2] === ox && arr[2] === arr[4] && arr[4] === arr[6]) return true;
    return false;
}
function checkCount(x, o) {
   	// 항상 x가 하나 더 많거나 같아야 한다.
    if (o > x) return false;
    if (x - o > 1) return false;
    return true;
}
function checkValid(countValid, xWin, oWin, xCount, oCount) {
    // 둘 다 이기는 경우는 없다. (둘 다 이길경우 X가 먼저 이기고 게임이 종료되기 때문)
    if (xWin && oWin) return false;
    if (!countValid) return false;
    // X가 승리한 경우 O의 개수는 X-1개여야 한다.
    if (xWin && oCount !== xCount - 1) return false;
  	// O가 승리한 경우 X의 개수는 O와 동일해야 한다.
    if (oWin && oCount !== xCount) return false;
  	// 아무도 이기지 못했고, 판이 꽉 차있지 않으면 게임이 끝난 것이 아니다.
    if (!oWin && !xWin && oCount + xCount < 9) return false;

    return true;
}
for (let row of input) {
    if (row === 'end') break;

    let xCount = 0;
    let oCount = 0;
    for (let i = 0; i < 9; i++) {
        if (row[i] === 'X') xCount++;
        if (row[i] === 'O') oCount++;
    }
    const countValid = checkCount(xCount, oCount);
    const xWin = vertical(row, 'X') || horizontal(row, 'X') || diagonal(row, 'X');
    const oWin = vertical(row, 'O') || horizontal(row, 'O') || diagonal(row, 'O');
    const isValid = checkValid(countValid, xWin, oWin, xCount, oCount);

    if (isValid) answer += 'valid\n';
    else answer += 'invalid\n';
}

console.log(answer.trimEnd());

profile
지속적인 성장

0개의 댓글