[백준/Node.js] 뱀 #3190

welchs·2021년 7월 31일
0

백준

목록 보기
1/10

풀이 1

var fs = require('fs');
var input = fs.readFileSync('/dev/stdin').toString().split('\n');

const Node = class {
  position;
  prev;
  next;
  constructor(y, x) {
    this.position = [y, x];
  }
};

const solution = (N, K, applePositions, L, directionInfo) => {
  // dy dx: 명령어가 D일 경우 +1, L일 경우 -1하여 다음 dy dx를 구함
  const DIRECTION_ORDER = [
    [0, 1],
    [1, 0],
    [0, -1],
    [-1, 0],
  ];
  let directionIdx = 0;
  // 뱀의 위치 저장 및 초기화
  const snake = new Set();
  let head = new Node(0, 0);
  let tail = head;
  snake.add('0,0');
  let time = 0;
  let isFinish = false;

  // 뱀 move 함수
  const moveSnake = () => {
    const [dy, dx] = DIRECTION_ORDER[directionIdx];
    const [currentY, currentX] = head.position;
    const [nextY, nextX] = [currentY + dy, currentX + dx];
    const newKey = `${nextY},${nextX}`;

    if (snake.has(newKey)) return true; // 뱀의 몸에 부딪힌 경우
    if (nextY < 0 || nextY >= N || nextX < 0 || nextX >= N) return true; // 벽에 부딪힌 경우

    snake.add(newKey);
    const newHead = new Node(nextY, nextX);
    newHead.prev = head;
    head.next = newHead;
    head = newHead;
    const appleIdx = applePositions.findIndex(
      ([y, x]) => nextY === y && nextX === x
    );
    if (appleIdx === -1) {
      const [tailY, tailX] = tail.position;
      const tailKey = `${tailY},${tailX}`;
      snake.delete(tailKey);
      tail = tail.next;
      tail.prev = null;
    } else {
      applePositions.splice(appleIdx, 1);
    }

    return false;
  };

  // 게임 진행
  while (!isFinish) {
    if (directionInfo[0] && Number(directionInfo[0][0]) === time) {
      const [_, command] = directionInfo.shift();
      if (command === 'D') directionIdx = (directionIdx + 1) % 4;
      else {
        directionIdx--;
        if (directionIdx < 0) directionIdx += 4;
      }
    }

    time++;
    isFinish = moveSnake();
  }
  return time;
};

const N = Number(input[0]);
const K = Number(input[1]);
const applePositions = input
  .slice(2, 2 + K)
  .map((v) => v.split(' ').map((v) => Number(v) - 1));
const L = Number(input[2 + K]);
const directionInfo = input.slice(3 + K).map((v) => v.split(' '));
console.log(solution(N, K, applePositions, L, directionInfo));

짧은 썰

풀이 2는 두 번째로 푼 걸로 풀이시간이 56분이나 걸렸다.
함수 단위로 쪼개보려했는데도 생각보다 많이 쪼개지 못해서 디버깅이에 시간을 많이 허비한 느낌..
다음에 풀 때는 더 아름답게 풀어볼 수 있도록 해야 겠다. (코드들이 별로 마음에 안드네..)

풀이 2

const fs = require('fs');

const Node = class {
  prev;
  next;
  position;

  constructor(position) {
    this.position = position;
  }
};
// dxdy: 오른쪽, 아래쪽, 왼쪽, 위쪽 순서
// command가 D일경우 currentDirection += 1;
// command가 L일경우 currentDirection -= 1;
const DIRECTION = [
  [0, 1],
  [1, 0],
  [0, -1],
  [-1, 0],
];

const changeCurrentDirection = (currentDirection, command) => {
  if (command === 'D') currentDirection = (currentDirection + 1) % 4;
  else if (command === 'L')
    currentDirection = currentDirection === 0 ? 3 : currentDirection - 1;

  return currentDirection;
};

const moveSnake = (snake, head, tail, currentDirection, apples, N) => {
  const [dx, dy] = DIRECTION[currentDirection];
  const [x, y] = head.position;
  const [nextX, nextY] = [x + dx, y + dy];

  // board 밖으로 나간 경우
  if (nextX < 1 || nextX > N || nextY < 1 || nextY > N) return [true];
  // 몸통에 부딪힌 경우
  if (snake.has(JSON.stringify([nextX, nextY]))) return [true];

  const newHead = new Node([nextX, nextY]);
  head.next = newHead;
  newHead.prev = head;
  head = newHead;
  snake.add(JSON.stringify(head.position));
  let appleIdx;
  if (
    (appleIdx = apples.findIndex(
      ([ax, ay]) => ax === nextX && ay === nextY
    )) !== -1
  ) {
    apples.splice(appleIdx, 1);
  } else {
    snake.delete(JSON.stringify(tail.position));
    tail.next.prev = null;
    tail = tail.next;
  }
  return [false, head, tail];
};

const solution = (N, K, apples, L, commands) => {
  const snake = new Set();
  let head, tail;
  head = tail = new Node([1, 1]);
  snake.add(JSON.stringify(head.position));
  let isGameOver = false;
  let time = 0;
  let currentDirection = 0;
  let commandIdx = 0;
  while (!isGameOver) {
    if (commands[commandIdx] && time === Number(commands[commandIdx][0])) {
      const command = commands[commandIdx][1];
      currentDirection = changeCurrentDirection(currentDirection, command);
      commandIdx++;
    }
    [isGameOver, head, tail] = moveSnake(
      snake,
      head,
      tail,
      currentDirection,
      apples,
      N
    );
    time++;
  }

  return time;
};

const input = fs.readFileSync('/dev/stdin').toString().trim().split('\n');
const N = Number(input[0]);
const K = Number(input[1]);
const apples = input.slice(2, 2 + K).map((v) => v.split(' ').map(Number));
const L = Number(input[2 + K]);
const commands = input.slice(3 + K).map((v) => v.split(' '));

console.log(solution(N, K, apples, L, commands));
profile
고수가 되고 싶은 조빱

0개의 댓글