Algorithm
function solution(park, routes) {
let height;
let width;
for(let i=0; i<=park.length-1;i++) {
if(park[i].includes("S")){
height = i
width = park[i].indexOf("S")
break;
}
}
for(let i=0; i<=routes.length-1; i++){
const dir = routes[i][0]
const dis = Number(routes[i][2])
switch(dir){
case "N":{
if(!park[height-dis])continue;
for(let j=1;j<=dis;j++){
if(park[height-j][width]==="X") break;
if(j===dis) height-=dis
}
break;}
case "S":{
if(!park[height+dis])continue;
for(let j=1;j<=dis;j++){
if(park[height+j][width]==="X") break;
if(j===dis) height+=dis
}
break;}
case "W": {
if(!park[height][width-dis]) continue;
let westLoc = park[height].substr(width-dis,dis)
if(westLoc.includes("X")) break;
else width -= dis
break;}
case "E": {
if(!park[height][width+dis])continue;
let eastLoc = park[height].substr(width+1,dis)
if(eastLoc.includes("X")) break;
else width += dis
break;}
}
}
return [height,width];
}
꽤 길고 복잡한 느낌으로 짜긴 했다. 각 상황을 특정해서 switch-case
문으로 방향마다 실행되는 값을 다르게 주고 좀 더 빠른 처리를 위해 if
문으로 조건이 맞지 않는 부분을 빠르게 날렸다
결과적으로 시간은 나름 괜찮게 나왔는데 코드적으로 깔끔한지는 애매할 것 같다.
반복문은 break
문을 사용하기 쉽게 기본 for문
을 사용했다
break;
시켜 반복문을 제한한다routes
즉 어떻게 이동할 것인지 반복문을 돌리고 방향과 이동거리를 변수에 넣는다switch-case
문으로 방향별로 동작할 코드를 분류한다. 모든 코드는 시작할 때 공원을 넘어갈 경우라는 조건을 파악한 뒤 실행되도록 한다.park
의 index
로 판별하기 위해 반복문을 이용하고 1칸씩 이동할 때 경로에 "X"
가 있는지 판별substr
을 이용해 이동 거리에 "X"
가 있는지 판별한다width
와 height
에 적용다른사람 풀이
function solution(park, routes) {
const dirs = { E: [0, 1], W: [0, -1], S: [1, 0], N: [-1, 0] };
let [x, y] = [0, 0];
for (let i = 0; i < park.length; i++) {
if (park[i].includes('S')) {
[x, y] = [i, park[i].indexOf('S')];
break;
}
}
routes.forEach((route) => {
const [r, n] = route.split(' ');
let [nx, ny] = [x, y];
let cnt = 0;
while (cnt < n) {
[nx, ny] = [nx + dirs[r][0], ny + dirs[r][1]];
if (!park[nx] || !park[nx][ny] || park[nx][ny] === 'X') break;
cnt++;
}
if (cnt == n) [x, y] = [nx, ny];
});
return [x, y];
}
routes
를 반복문 돌려 현재 위치를 새로운 변수에 놓고 이동거리를 cnt
로 두어 계산한다.while
문으로 이동할 때마다 조건을 판별한 뒤 괜찮다면 마지막에 해당 거리로 이동한 좌표값을 집어 넣는다CS
프론트를 공부하다 보면 콜백지옥이란 얘기를 한번쯤 들어봤을 것이다.
비동기 처리 로직을 위해 콜백함수를 연속해서 사용할 때 발생하는 문제인데 예를 들면
$.get('url', function (response) {
parseValue(response, function (id) {
auth(id, function (result) {
display(result, function (text) {
console.log(text);
});
});
});
});
서버에서 데이터를 받아와 하면에 표시하기까지의 인코딩, 사용자 인증 등을 모두 처리해야 하는 경우가 있는데 만약 이 모든 과정을 비동기로 처리해야 한다면 콜백 안에 콜백을 계속 무는 형식으로 코딩하게 되어 가독성도 떨어지고 로직을 변경하기 힘든상태가 된다.
이 것이 콜백지옥이라고 부른다.
일반적으로 콜백 지옥을 해결하는 방법에는 Promise나 Async를 사용하는 방법이 있다.
function parseValueDone(id) {
auth(id, authDone);
}
function authDone(result) {
display(result, displayDone);
}
function displayDone(text) {
console.log(text);
}
$.get('url', function (response) {
parseValue(response, parseValueDone);
});
중첩했던 콜백 익명함수를 각각의 함수로 구분하여 먼저 Ajax 통신으로 받은 데이터를 parseValue()메서드로 파싱한다. parseValueDone()에 파싱한 결과값인 id가 전달되고 auth() 메서드가 실행된다.
auth()메서드로 인증을 거치고 나면 콜백 함수 authDone()이 실행
인증 결과 값인 result로 display()를 호출하면 마지막으로 displayDone()메서드가 수행되며 콘솔에 출력된다.
const condition = true; // true면 resolve, false면 reject
const promise = new Promise( (resolve, reject) => {
if(condition){
resolve('성공');
}else{
reject('실패');
}
});
promise
.then( (message) => {
console.log(message); // 성공(resolve)한 경우 실행
})
.catch( (error) => {
console.error(error); // 실패(reject)한 경우 실행
});
new Promise로 프로미스를 생성할 수 있으며, 안에 resolve와 reject를 매개변수로 갖는 콜백 함수를 넣어준다.
이렇게 만든 promise변수에 then과 catch메서드를 붙일 수 있고 프로미스 내부에서 resolve가 호출되면 then이 실행되고, reject가 호출되면 catch가 실행된다.
then이나 catch에서 다시 다른 then이나 catch로 붙일 수 있따.
function findAndSaveUser(Users){
Users.findOne( {}, ( err, user ) => { //첫 번째 콜백
if(err){
return console.error(err);
}
user.name = 'zero';
user.save( (err) => { // 두 번째 콜백
if(err){
return console.error(err);
}
}
Users.findOne( {gender : 'm'}, (err, user) => { // 세 번째 콜백
//생략
});
});
});
}
지금까지 잘 사용하고 있었지만 깊게 파보지 않아 기본적인 개념부터 다시 잡아보자
async/await은 JS 비동기 처리 패턴중 가장 최근 문법으로 기존의 비동기 처리 방식인 콜백 함수와 프로미스의 단점을 보완하고 개발자가 읽기 좋은 코드를 작성할 수 있게 도와준다.
async function 함수명(){
await 비동기_처리_메서드()
}
async function f(){
return 1;
}
f().then(alert); //1
위 함수에서 1을 Promise.resolve
로 감싸도 같은 결과를 반환
async function f() {
return Promise.resolve(1);
}
f().then(alert); // 1
await는 async 함수 안에서만 동작한다. promise가 처리될 때까지 기다리는 역할을 하고 결과는 그 이후 반환된다.
async function f() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("완료!"), 1000)
});
let result = await promise; // 프라미스가 이행될 때까지 기다림 (*)
alert(result); // "완료!"
}
f();
(*)
로 표시한 줄에서 실행이 잠시 '중단' 되었다가 promise가 처리되면 실행이 재개result
값이 변수 result에 할당되고 따라서 출력시 1초 뒤에 '완료!'가 출력된다await
는 promise가 처리 될 때까지 함수 실행을 기다리게 만드는 것으로 promise가 처리되면 그 결과와 함께 실행이 재개된다. promise가 처리되길 기다리는 동안에 엔진이 다른 일을 할 수있기에 CPU리소스는 낭비되지 않는다
.then()
등을 사용해야 했다. 하지만 async await 문법이 나오며 비동기에 대한 사고를 덜해도 된다.await가 던진 에러는 throw가 던진에러를 잡을때처럼 try...catch
문을 사용해 잡을 수 있다.
async function f() {
try {
let response = await fetch('http://유효하지-않은-주소');
} catch(err) {
alert(err); // TypeError: failed to fetch
}
}
f();