나의 풀이
이 문제가 level.1 오답률 2등이던데 이유를 알 것 같다. 조건을 명확하게 지켜야 정답이된다.
문제 풀이 순서는 아래와 같다.
📌 1. 시작 포인트 찾기
시작 포인트가 매번 0,0이 아니기 때문에 매 route마다 찾아야한다.
function findStartingPoint(park) {
let [nowX, nowY] = [0, 0];
for (let i = 0; i < park.length; i++) {
if (park[i].indexOf('S') !== -1) {
nowX = park[i].indexOf('S');
nowY = i;
break;
}
}
return [nowX, nowY];
}
for문으로 순회하면서 'S' 가 있으면 그 때의 index를 활용해서 x좌표, y좌표를 구했다.
📌 2. routes를 순회하면서 방향에 맞게 이동한다.
단, 조건이있다.
1️⃣ 공원 밖으로는 이동할 수 없다.
2️⃣ 움직이는 경로에 장애물이 없어야 한다.
이 두가지의 조건이 만족하면 3️⃣ 좌표를 이동시켰다.
1️⃣ 공원 밖으로는 이동할 수 없다.
function isOutsidePark(direction, { nowX, nowY }, move, park) {
if (direction === 'E') return nowX + move > park[nowY].length - 1;
if (direction === 'W') return nowX < move;
if (direction === 'S') return park.length - 1 < nowY + move;
if (direction === 'N') return nowY < move;
}
예를 들어 만약 동쪽으로 이동해야한다면 '현재 좌표 + 움직여야할 거리'가 공원을 벗어나면 return 시켜서 forEach가 다음 순회로 넘어가게했다.
2️⃣ 움직이는 경로에 장애물이 없어야 한다.
function isObstacle(direction, { nowX, nowY }, move, park) {
switch (direction) {
case 'E':
for (let i = nowX; i <= nowX + move; i++) {
if (park[nowY][i] === 'X') return true;
}
break;
case 'W':
for (let i = nowX; i >= nowX - move; i--) {
if (park[nowY][i] === 'X') return true;
}
break;
case 'S':
for (let i = nowY; i <= nowY + move; i++) {
if (park[i][nowX] === 'X') return true;
}
break;
case 'N':
for (let i = nowY; i >= nowY - move; i--) {
if (park[i][nowX] === 'X') return true;
}
}
}
for문이 포함되어있기에 복잡도를 조금이라도 줄이기 위해 일부러 1️⃣ 먼저 체크하고 통과하면 2️⃣이 진행되도록 뒤쪽에 배치했다.
여기서 핵심은 i가 어디서부터 시작되고 어디에서 끝나는지이다. 처음에 이 부분을 놓쳐서 계속틀렸었다.
for문이 하는 역할은 현재 위치부터 앞으로 가야할 위치까지 장애물, 즉 'X'가 있는지 확인하는 것이다.
3️⃣ 좌표 이동 ❗️
function moveCoordinate(direction, coordinate, move) {
if (direction === 'E') coordinate.nowX += move;
if (direction === 'W') coordinate.nowX -= move;
if (direction === 'S') coordinate.nowY += move;
if (direction === 'N') coordinate.nowY -= move;
}
여기서만은 유일하게 구조분해 할당을 하지않았다
why? 구조 분해 할당은 프로퍼티를 개별적인 변수로 분리하여 할당하는 것이기 때문에 원본 객체와의 연결이 끊어진다. 즉 원본 객체와는 독립적으로 동작한다. 한마디로 객체를 인수로 주었지만 전달 받은 함수가 구조분해 할당으로 객체를 받으면 전달 받은 함수 내에서 변경된 값은 외부로 전달되지 않는다. 따라서 객체 형태 그대로 전달하고 전달 받은 함수도 객체 그대로 사용하여 참조에 의한 전달을 해야 전달 받은 함수내부에서 값을 변경하면 외부도 변경이 된다.
function moveCoordinate(direction, {nowX, nowY}, move) {
if (direction === 'E') nowX += move;
if (direction === 'W') nowX -= move;
if (direction === 'S') nowY += move;
if (direction === 'N') nowY -= move;
}
이렇게 구조분해 할당을 사용하면 개별적인 변수로 분리된다. 따라서 매개변수 nowX와 nowY는 원본 객체의 nowX와 nowY 속성 값이 아니라 그들의 복사본인 개별변수이다. 그렇기 때문에 nowX와 nowY를 변경해도 원본 객체의 속성 값은 변경되지 않는다.
이는 원시값으로 전달되었기 때문에 외부 객체와의 연결이 끊어진 것이다.
리팩터링 전
function solution(park, routes) {
const result = {};
let [nowX, nowY] = [0, 0];
// find "S"
for (let i = 0; i < park.length; i++) {
if (park[i].indexOf('S') !== -1) {
nowX = park[i].indexOf('S');
nowY = i;
break;
}
}
routes.forEach((route, outIndex) => {
let [direction, move] = route.split(' ');
move = +move;
if (direction === 'E') {
if (nowX + move <= park[nowY].length - 1) {
for (let i = nowX; i <= nowX + move; i++) {
if (park[nowY][i] === 'X') return;
}
nowX += move;
result[outIndex] = true;
return;
}
}
if (direction === 'W') {
if (nowX >= move) {
for (let i = nowX; i >= nowX - move; i--) {
if (park[nowY][i] === 'X') return;
}
nowX -= move;
result[outIndex] = true;
return;
}
}
if (direction === 'S') {
if (park.length - 1 >= nowY + move) {
for (let i = nowY; i <= nowY + move; i++) {
if (park[i][nowX] === 'X') return;
}
nowY += move;
result[outIndex] = true;
return;
}
}
if (direction === 'N') {
if (nowY >= move) {
for (let i = nowY; i >= nowY - move; i--) {
if (park[i][nowX] === 'X') return;
}
nowY -= move;
result[outIndex] = true;
return;
}
}
});
console.log(result);
//end
return [nowY, nowX];
}
리팩터링 후
function solution(park, routes) {
// route 테스트용 객체
// const routeTest = {};
let [nowX, nowY] = findStartingPoint(park);
const coordinate = { nowX, nowY };
routes.forEach((route, index) => {
const [direction, move] = route
.split(' ')
.map((value) => (Number(value) ? +value : value));
if (isOutsidePark(direction, coordinate, move, park)) return;
if (isObstacle(direction, coordinate, move, park)) return;
moveCoordinate(direction, coordinate, move);
// routeTest[index] = true;
});
return [coordinate.nowY, coordinate.nowX];
}
function findStartingPoint(park) {
let [nowX, nowY] = [0, 0];
for (let i = 0; i < park.length; i++) {
if (park[i].indexOf('S') !== -1) {
nowX = park[i].indexOf('S');
nowY = i;
break;
}
}
return [nowX, nowY];
}
function isOutsidePark(direction, { nowX, nowY }, move, park) {
if (direction === 'E') return nowX + move > park[nowY].length - 1;
if (direction === 'W') return nowX < move;
if (direction === 'S') return park.length - 1 < nowY + move;
if (direction === 'N') return nowY < move;
}
function isObstacle(direction, { nowX, nowY }, move, park) {
switch (direction) {
case 'E':
for (let i = nowX; i <= nowX + move; i++) {
if (park[nowY][i] === 'X') return true;
}
break;
case 'W':
for (let i = nowX; i >= nowX - move; i--) {
if (park[nowY][i] === 'X') return true;
}
break;
case 'S':
for (let i = nowY; i <= nowY + move; i++) {
if (park[i][nowX] === 'X') return true;
}
break;
case 'N':
for (let i = nowY; i >= nowY - move; i--) {
if (park[i][nowX] === 'X') return true;
}
}
}
function moveCoordinate(direction, coordinate, move) {
if (direction === 'E') coordinate.nowX += move;
if (direction === 'W') coordinate.nowX -= move;
if (direction === 'S') coordinate.nowY += move;
if (direction === 'N') coordinate.nowY -= move;
}
'알고리즘 > 프로그래머스 - JS' 카테고리의 다른 글
[프로그래머스-JS] level.2 이모티콘 할인 행사 ⭐️⭐️ (0) | 2023.06.13 |
---|---|
[프로그래머스-JS] level.2 거리두기 확인하기 (0) | 2023.06.10 |
[프로그래머스-JS] level.1 신고 결과 받기 📌 (1) | 2023.06.07 |
[프로그래머스-JS] level.2 요격 시스템 📌 (0) | 2023.06.02 |
[프로그래머스 - JS][kakao] level.1 성격 유형 검사하기 (0) | 2023.05.30 |