알바하는데 새로 가르치는 학생들이 10년생이라고 한다. 허
머쓱이는 RPG게임을 하고 있습니다. 게임에는 up, down, left, right 방향키가 있으며 각 키를 누르면 위, 아래, 왼쪽, 오른쪽으로 한 칸씩 이동합니다. 예를 들어 [0,0]에서 up을 누른다면 캐릭터의 좌표는 [0, 1], down을 누른다면 [0, -1], left를 누른다면 [-1, 0], right를 누른다면 [1, 0]입니다. 머쓱이가 입력한 방향키의 배열 keyinput와 맵의 크기 board이 매개변수로 주어집니다. 캐릭터는 항상 [0,0]에서 시작할 때 키 입력이 모두 끝난 뒤에 캐릭터의 좌표 [x, y]를 return하도록 solution 함수를 완성해주세요.
- [0, 0]은 board의 정 중앙에 위치합니다. 예를 들어 board의 가로 크기가 9라면 캐릭터는 왼쪽으로 최대 [-4, 0]까지 오른쪽으로 최대 [4, 0]까지 이동할 수 있습니다.
제한사항
- board은 [가로 크기, 세로 크기] 형태로 주어집니다.
- board의 가로 크기와 세로 크기는 홀수입니다.
- board의 크기를 벗어난 방향키 입력은 무시합니다.
- 0 ≤ keyinput의 길이 ≤ 50
- 1 ≤ board[0] ≤ 99
- 1 ≤ board[1] ≤ 99
- keyinput은 항상 up, down, left, right만 주어집니다.
입출력 예keyinputboardresult
["left", "right", "up", "right", "right"] | [11, 11] | [2, 1] |
["down", "down", "down", "down", "down"] | [7, 9] | [0, -4] |
입출력 예 설명
입출력 예 설명 #1
- [0, 0]에서 왼쪽으로 한 칸 오른쪽으로 한 칸 위로 한 칸 오른쪽으로 두 칸 이동한 좌표는 [2, 1]입니다.
입출력 예 설명 #2
- [0, 0]에서 아래로 다섯 칸 이동한 좌표는 [0, -5]이지만 맵의 세로 크기가 9이므로 아래로는 네 칸을 넘어서 이동할 수 없습니다. 따라서 [0, -4]를 return합니다.
유니티 배울 때 기억이 새록새록 떠오르는 문제였다. 직접 입력은 아니었지만 문자열 배열 내에서 "right", "left", "ip", "down"을 찾아 x좌표와 y좌표를 바꾸어주는 문제였다.
사실 처음 보고 바로 떠오른 것은 for문 내의 if문이었으나...
인간의 자만은 끝이 없는 법. 좀더 간지나는 방법을 사용해서 구해보기로 했다.
가장 먼저 떠올린건 역시 match().
- keyinput 배열을 join("")하여 하나의 문자열로 만들어줌
- 문자열 내에서 match()를 통해 각 방향의 수를 가진 배열을 생성
- match()의 결과로 나온 배열의 길이 = 각 방향이 나온 개수 = 이동한 거리 이므로, match()의 결과 배열의 length = 각 방향으로 이동한 거리가 됨
- left, down은 -, right, up은 +로 하여 answer 배열에 최종 이동거리를 넣어줌
keyinput = keyinput.join("") answer[0] = keyinput.match(/right/g).length - keyinput.match(/left/g).length answer[1] = keyinput.match(/up/g).length - keyinput.match(/down/g).length |
아이디어는 괜찮았고, 실제로 순탄하게 진행 되었다. 하지만.....!
문제는 3번. 그중에서도 length를 이용한 부분에서 계속 오류가 나는 것이었다. 왜지???
에러 코드를 잘 읽어보니
TypeError: Cannot read properties of null (reading 'length')
라는 에러가 발생하였다. 한마디로 null 값은 length를 정의할 수 없다는 것이었다.
match()를 실행한 결과는 배열로 나타나는데, 만약 ["left", "right", "up", "right", "right"] 배열에서 match(/right/g)를 실행하면
["right", "right", "right"] 라는 배열이 만들어진다는 것이다. 이 경우에는 length를 사용해 길이를 구할 수 있다.
하지만 match(/down/g)을 실행한다면???
배열 내에 "down"이 없기 때문에 반환값이 null이 된다. null은 아예 빈 값이기 때문에 길이를 정의할 수 조차 없다.
이러한 경우 떄문에 자꾸 에러가 발생한 것이었다. 그럼 다른 방법을 찾아봐야 한다.
결국 가장 간단하지만 스테레오타입인 for-if 문을 사용하기로 했다.
keyinput의 길이만큼 for문을 돌리고, 각 요소별로 이동 거리 지정을 해준다.
이때 중요한 조건을 빼먹으면 안되는데
- board의 크기를 벗어난 방향키 입력은 무시합니다.
이것이다.
예를 들어 board의 크기가 5라면 가로로는 -2.5부터 +2.5까지 움직일 수 있게 된다. 이때 가로로 -2 또는 2까지 움직인 경우, 다음 키 입력이 가로 이동이라면 더이상 이동하지 않아야 한다.
board = 3x3 | right | right | right | left |
조건 만족 | (0,0) | (1,0) | (1,0) | (0,0) |
조건 불만족 | (0,0) | (1,0) | (2,0) | (1,0) |
board의 가로 길이가 3이므로 한계점은 (-1.5, -1.5)이다. 좌표는 1씩 움직이므로 1에서 한칸 더 움직인다면 한계점인 1.5를 넘게 되어 움직일 수가 없게 된다. 즉, 한계점을 넘는 이동을 하게 된다면 이전 좌표를 계속 유지 해야 하는 것이다.
이를 구현하기 위해 if문 안에 또 if문을 넣었다. 쉽게말해
if(keyinput의 요소가 "방향"이라면){
if(한계점을 넘을 경우){
움직임 정지
} else {
해당방향으로 한칸 움직임
}
}
이라는 것이다.
움직임은 ++ 또는 --로 구현하면 되지만, 제자리에 멈추는 것은 어떻게 구현할까 하다가, 그냥 움직이기 이전 상태를 유지하면 되는 것이 아닌가? 싶어 좌표 = 좌표 형태로 써 주었다.
function solution(keyinput, board) { var answer = []; let hor = 0 let ver = 0 for (let i = 0; i < keyinput.length; i++) { if (keyinput[i] == "left") { if (hor <= -parseInt(board[0]/2)) { hor = hor } else { hor-- } } else if (keyinput[i] == "right") { if (hor >= parseInt(board[0]/2)) { hor = hor } else { hor++ } } if (keyinput[i] == "down") { if (ver <= -parseInt(board[1]/2)) { ver = ver } else { ver-- } } else if (keyinput[i] == "up") { if (ver >= parseInt(board[1]/2)) { ver = ver } else { ver++ } } } answer = [hor, ver] return answer; } |
코드가 너무 길고 복잡한 감이 없지않아 많지만 그래도 돌아가기는 하니.....
다른 분들 보니 굉장히 간결하게 하시던데 열심히 해서 나도 그런 경지에 오르고 싶다고 생각했다.
푼건 3일인데 쓰다보니 날짜가 넘어가 버렸다. 이런이런
'코딩 테스트 풀이 > 프로그래머스' 카테고리의 다른 글
[LV0] 옹알이(1) (0) | 2023.01.07 |
---|---|
[LV0] 최빈값 구하기 (0) | 2023.01.07 |
[LV0] 문자열 계산하기 (0) | 2023.01.02 |
[LV0] 숨어있는 숫자의 덧셈(2) (0) | 2022.12.31 |
[LV0] 가까운 수 (0) | 2022.12.30 |