[구름톤 챌린지] 10일차 미션 GameJam - JavaScript

문제 출처

구름톤 챌린지

문제 설명

플레이어는 GmaeJam에 참가했다. GameJam은 현장에서 즉석으로 팀을 꾸려 게임의 규칙을 만든 뒤, 생각한 규칙을 코드로 옮겨서 게임을 만들어내는 대회이다.

플레이어가 속한 팀은 보드로 즐길 수 있는 간단한 보드게임을 만들었다. 게임의 진행 방법과 규친은 다음과 같다.

  1. 게임은 한 변의 길이가 N인 격자 보드 위에서 진행한다. 보드는 한 변의 길이가 1인 N^2개의 칸으로 나누어져 있다.
  2. 각 칸에는 command에 해당하는 방향으로 count 칸만큼 한 칸씩 이동하라는 지시가 적혀있다.
  3. 플레이하는 사람은 처음에 보드의 칸 중 하나에 말을 올려놓는다.
  4. 각 칸에 적힌 지시대로 말을 이동한다. 만약 이동 중에 보드 밖으로 나가게 된다면 반대쪽의 첫 번째 칸으로 이동한다.
  5. 만약 이동하다가 자신의 말이 이미 방문한 칸을 다시 지나야 할 경우에는 게임이 종료된다. 그 외의 경우 게임이 종료될 때까지 위의 4번 단계를 반복한다.
  6. 게임 점수는 시작칸을 포함한 말이 방문한 칸의 개수이다.

플레이어는 GameJam의 최종 발표 때 게임을 시연해 보기 위해, 구름이와 미리 연습게임을 진행해 보려고 한다. 플레이어와 구름이가 각각의 게임에서 처음에 말을 올려둔 칸이 주어졌을 때, 두 사람 중 누가 더 높은 점수를 흭득했는지를 구해보자.

구름이가 게임에서 승리하면 goorm과 구름이가 얻은 점수를 공백을 두고 출력하고, 플레이어가 승리하면 player와 플레이어가 얻은 점수를 공백을 두고 출력한다. 두 사람이 비기는 테스트 케이스는 주어지지 않는다.

제한 조건
  • 첫째 줄에 격자 보드의 크기 N이 주어진다.
  • 둘째 줄에는 구름이가 말을 올려둔 칸의 좌표가 공백을 두고 주어진다.
  • 셋째 줄에는 플레이어가 말을 올려둔 칸의 좌표가 공백을 두고 주어진다.
  • 다음 N개의 줄에는 보드의 각 칸에 적혀있는 지시 사항이 주어진다.
  • command는 U, D, R, L 중 하나이다. 각각 위, 아래, 오른쪽, 왼쪽을 의미한다.
  • 3 <= N <= 200
예시

입력 예
3
1 1
3 3
1L 2L 1D
2U 3R 1D
2R 2R 1U

출력 예
goorm 4

풀이
const readline = require("readline");
let rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});
let input = [];
rl.on("line", (line) => {
  input.push(line);
});

rl.on("close", () => {
  // 격자 보드의 크기
  const N = Number(input[0]);

  // 구름이 좌표 [1, 1]
  let gxy = input[1].split(" ").map((n) => Number(n) - 1);

  // 플레이어 좌표 [3, 3]
  let pxy = input[2].split(" ").map((n) => Number(n) - 1);

  // 보드
  const board = input.slice(3).map((b) => b.split(" "));

  // 각 점수를 구하는 함수
  const goormScore = playGame(N, board, gxy);
  const playerScore = playGame(N, board, pxy);

  console.log(
    goormScore > playerScore ? "goorm " + goormScore : "player " + playerScore
  );
});

// 게임 점수를 구하는 함수
function playGame(N, board, xy) {
  // 보드 크기와 같은 크기의 체크 배열 생성
  const check = Array.from({ length: N }, () => Array(N).fill(0));

  // 상 하 좌 우
  const command = {
    U: [-1, 0],
    D: [1, 0],
    R: [0, 1],
    L: [0, -1],
  };

  // 받아온 좌표
  let [x, y] = xy;

  // 게임을 종료시키는 플레그
  let flag = true;
  while (flag) {
    // 지시사항 분리
    // (N이 200까지라 200R의 경우 split으로 분리 불가)
    const len = board[x][y].length - 1;
    const cnt = Number(board[x][y].substring(0, len));
    const cmd = board[x][y].substring(len);

    // 위에 선언해 둔 이동할 좌표
    const [tx, ty] = command[cmd];

    // 구한 count만큼 for문을 통해 이동한다.
    for (let i = 0; i < cnt; i++) {
      // 이동하려는 장소가 이미 방문한 장소라면 종료
      if (check[x][y] === 1) {
        flag = false;
        break;
      }

      // 방문 체크
      check[x][y] = 1;

      // 이동
      x += tx;
      y += ty;

      // 칸이 넘어갔을 경우 반대 쪽으로 이동
      if (x < 0) x = N - 1;
      if (x === N) x = 0;
      if (y < 0) y = N - 1;
      if (y === N) y = 0;
    }
  }

  // 점수 구함
  return check.flat().filter((n) => n === 1).length;
}
정리

현재 구름톤 챌린지가 진행중인데 하루에 한 문제를 풀면서 머리를 굴려보아요.

피드백은 언제나 환영입니다. 😊

사용한 메서드

split() 메서드 - MDN
slice() 메서드 - MDN
map() 메서드 - MDN
flat() 메서드 - MDN
filter() 메서드 - MDN
substring() 메서드 - MDN
구조 분해 할당 - MDN