[구름톤 챌린지] GameJam

1ilsang
1ilsang
클라이밍 하실래염?
published

cover

문제 링크

끔찍한 시뮬레이션 문제이다.

별다른 특이 사항 없이 문제에서 제시한 대로 구현하면 된다.

접근법

구름과 플레이어 두 명이 각각 게임을 진행한다. 따라서 우리는 동일한 게임을 2번 실행해야 한다는 것을 알 수 있다.

초기화를 잘하던가, 똑같은 코드를 두 번 실행해야 한다.

게임 보드 칸에는 이동 횟수와 방향이 적혀있으며 게이머가 놓은 위치에서부터 칸의 명령을 따라 쭉 실행하면 된다.

만약 보드를 이탈하는 경우(처음/끝) 반대쪽 첫 칸으로 이동하게 된다(-1 -> length -1, length -> 0),

이때 이전에 방문했던 곳에 다시 온다면 게임이 종료된다. 우리는 두 번의 메모 맵이 필요하다.

두 플레이어가 게임을 종료했을 때 점수를 비교해 출력한다.

정리

  1. 유저의 위치를 받아 점수를 반환하는 함수를 만든다(내부 변수 사용으로 초기화 용이).
  2. 이동 거리만큼 이동한다.
    1. 보드 이탈시 좌표를 반대쪽 첫 칸으로 재설정해 준다.
    2. 이동할 때마다 메모를 한다.
  3. 점수 값을 비교 출력한다.

최종 코드

const readline = require('readline');
let rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});
let n;
const goorm = [];
const player = [];
const map = [];
const d = {
  U: [-1, 0],
  R: [0, 1],
  D: [1, 0],
  L: [0, -1],
};
const getBoardInfo = ({ r, c }) => {
  const cmd = map[r][c];
  const count = parseInt(cmd);
  const direction = cmd.slice(-1);
  return {
    cmd,
    count,
    direction,
  };
};
const setNextMove = ({ r, c, direction }) => {
  let nr = r + d[direction][0];
  let nc = c + d[direction][1];

  if (nr < 0) {
    nr = map.length - 1;
  } else if (nc < 0) {
    nc = map[0].length - 1;
  } else if (nr >= map.length) {
    nr = 0;
  } else if (nc >= map[0].length) {
    nc = 0;
  }
  return {
    nr,
    nc,
  };
};
const buildMemo = () => {
  const memo = map.map((row) => {
    return Array(row.length).fill(0);
  });
  return memo;
};
const playGame = ({ r, c }) => {
  // 최초 세팅. 현재 칸의 명령을 파싱한다.
  let { cmd, count, direction } = getBoardInfo({ r, c });
  let nr = r;
  let nc = c;
  let score = 1;

  const memo = buildMemo();
  memo[r][c] = 1;

  while (true) {
    // 이동 횟수가 0이라면 현재 위치 칸의 명령으로 초기화 한다.
    if (count === 0) {
      const curValues = getBoardInfo({ r: nr, c: nc });
      cmd = curValues.cmd;
      count = curValues.count;
      direction = curValues.direction;
    }
    // 다음 이동을 위해 nextRow, nextCol 값을 세팅한다.
    const nextPosition = setNextMove({ r: nr, c: nc, direction });
    nr = nextPosition.nr;
    nc = nextPosition.nc;
    // 만약 다음 좌표가 방문한적이 있다면 루프를 종료한다.
    if (memo[nr][nc]) {
      break;
    }
    // 이동 거리를 감소시키고 스코어를 추가한뒤 좌표를 메모한다.
    count--;
    score++;
    memo[nr][nc] = 1;
  }
  return score;
};
const getParsedLineNumbers = (line) =>
  line.split(' ').map((num) => Number(num) - 1);
const setFields = (line) => {
  const parsedLine = line.split(' ');
  map.push(parsedLine);
};

rl.on('line', (line) => {
  if (n === undefined) {
    n = Number(line);
    return;
  }
  if (goorm.length === 0) {
    goorm.push(...getParsedLineNumbers(line));
    return;
  }
  if (player.length === 0) {
    player.push(...getParsedLineNumbers(line));
    return;
  }
  if (map.length < n) {
    setFields(line);
    if (map.length < n) {
      return;
    }
  }
  const gScore = playGame({
    r: goorm[0],
    c: goorm[1],
  });
  const pScore = playGame({
    r: player[0],
    c: player[1],
  });
  const answer = gScore > pScore ? `goorm ${gScore}` : `player ${pScore}`;
  console.log(answer);
  rl.close();
});