크레인 인형 뽑기 게임
인프런에서 자바스크립트 알고리즘 기초 강의만 듣다가 처음으로 다른 사이트에 있는 문제에 도전하였다. 프로그래머스 사이트를 이용하였고 작성한 코드 제출 후 모든 테스트 케이스가 다 맞는 짜릿함을 맛봐서 내가 고민한 흔적과 삽질(?)의 순간들을 기록으로 남겨야겠다는 생각이 들었다. 또 다른 사람의 풀이를 볼 수 있어서 좀 더 효율적인 코드가 있으면 내 코드랑도 한번 비교를 해봐야겠다.
https://programmers.co.kr/learn/courses/30/lessons/64061#
코딩테스트 연습 - 크레인 인형뽑기 게임
[[0,0,0,0,0],[0,0,1,0,3],[0,2,5,0,1],[4,2,4,4,2],[3,5,1,3,1]] [1,5,3,5,1,2,1,4] 4
programmers.co.kr
처음 문제를 봤을 때 설명이 구구절절 길어서 뭔가 요구하는게 많겠구나 싶었지만 정말 간단한 문제였다. 이런 완성도가 높은 문제를 처음 접해봐서 그런지 간단해던 것에 비해 코드를 짜기까지 시간이 정말 오래걸렸다.
문제의 설명이 친절해서 어떻게 접근해야하는지 단번에 알 수 있었다. 인형은 2차원 배열로 들어있고 뽑은걸 스택으로 쌓아 중복된 인형을 제거하고 제거한 인형 개수를 출력하면 되는 것이였다.
function solution(board, moves) {
let answer = 0;
// 인형 담는 바구니
let stack = [];
// 배열의 순서대로 크레인이 해당 열의 위치에서 인형을 뽑는다
// i는 열, j는 행이다.
for (let i = 0; i < moves.length; i++) {
// 인형은 위에서부터 들어올리므로 해당 열(i)에서 행인 j값을 하나씩 증가시키며
// 행의 순서대로 0인지 체크하고 아니라면 들어올리고 그 자리를 0으로 바꾼다.
let j = 0;
while (board[j][moves[i] - 1] === 0) {
j++;
// 열의 행이 전부 빈칸(0)이라 j가 격자판 행의 최대값에 다르면 while문 종료
if (j === board.length - 1) break;
}
// j 값이 정해진 후 그 자리가 0이 아니면 뽑아야하는 인형이다.
if (board[j][moves[i] - 1] > 0) {
// 마지막에 들어간 인형이 새로 뽑힌 인형과 같을 경우 스택에서 제거를 하고 카운트(+2)를 한다.
if (stack.slice(-1)[0] === board[j][moves[i] - 1]) {
stack.pop();
answer += 2;
} else stack.push(board[j][moves[i] - 1]); // 중복이 아니라면 인형을 스택에 추가
board[j].splice(moves[i] - 1, 1, 0); // 인형 분류가 끝난 후 뽑힌 자리를 0으로 바꾼다.
}
}
return answer;
}
다 풀고나서 보니 정말 간단한건데 역시나 실수는 있기 마련이었다. 오늘은 특히나 while문 안에서 break를 안걸어줘서 j가 최대 행의 값을 넘어 undefined으로 계산되는 에러가 발생했다. 왜 에러가 나는지도 모르고 여러 값을 고쳐봤지만 이를 발견하고 깨닫기까지 긴 시간이 소요됐다.
( while 대신에 for문으로 돌렸으면 에러를 볼일도 없었을 것이다...😂)
1차원 배열이면 undefined은 while문 안에서 false로 계산되는데 2차원 배열에서는 값을 불러내는 과정에서 undefined의 [1]인 열을 찾으려하니 당연히 에러가 발생할 수밖에 없다. 2차원 배열 문제에선 특히나 유심히 봐야겠다는 생각이 들었다.
인프런 강사님의 풀이를 보니 내 코드가 다소 직관적이지는 않은 것 같다.
배열 moves의 요소들을 돌 때 for문 보다는 forEach 같은 내장함수를 쓰는 게 자바스크립트를 활용하는 입장에서는 더 좋은 습관이지 않을까 싶다. 또한 stack 의 맨 마지막 요소를 추출할 땐 stack.slice(-1)[0] 보다는 stack[stack.length-1]를 쓰는 게 좀 더 직관적이고 배열의 요소를 바꿀 때도 마찬가지로 board[j].splice(moves[i] - 1, 1, 0) 이 코드처럼 slice()로 제거 후 0을 추가하는 것보다 board[j][moves[i] - 1] = 0 이렇게 바로 할당을 하는 게 더 이해하기가 수월하다.