[JS][백준]14499_주사위 굴리기
Algorithm/BaeKJoon

[JS][백준]14499_주사위 굴리기

문제 번호

 

14499번: 주사위 굴리기

첫째 줄에 지도의 세로 크기 N, 가로 크기 M (1 ≤ N, M ≤ 20), 주사위를 놓은 곳의 좌표 x, y(0 ≤ x ≤ N-1, 0 ≤ y ≤ M-1), 그리고 명령의 개수 K (1 ≤ K ≤ 1,000)가 주어진다. 둘째 줄부터 N개의 줄에 지

www.acmicpc.net

 

 

 

알고리즘 분류

 

문제 풀이

 구현 문제에서 자주 등장하는 배열을 돌리는 방법을 알고 있다면 어렵지 않게 풀 수 있다.

 

 그러니 우선 배열을 돌리는 방법에 대해서 생각해보자. 배열은 두 가지 방향으로 돌릴 수 있다. 오른쪽, 왼쪽 말이다.

우선 오른쪽으로 돌려본다. 왼쪽에 있던 내용물은 한 칸 오른쪽으로 이동해야 하고 가장 마지막 칸에 있는 내용물은 0번 인덱스로 가야 한다. 돌리고자 하는 배열이 arr일 때 다음과 같이 코드를 작성하면 오른쪽으로 돌려진다.

 const temp = [...arr];  
 for (let i = 0; i < arr.length; i++) {
   arr[i] = temp[(i + arr.length - 1) % arr.length];
 }

 이제 반대쪽인 왼쪽으로도 돌려보자. 

const temp = [...arr];
for (let i = 0; i < arr.length; i++) {
    arr[i] = temp[(i + 1) % arr.length];
}

 잘 보면 다른거 다 똑같고 'arr.length - 1'과 'i+1'만 서로 다르다. 

 

 이제 주사위의 가로를 나타내는 1차원 배열, 주사위의 세로를 나타내는 1차원 배열을 1개씩 준비한다. 각각의 배열은 명령에 따라서 주사위가 회전함에 따라 변화하게 된다. 가로 상태는 나타내는 배열은 4의 size를 갖고 있으며 1번 인덱스가 하늘 방향, 3번 인덱스가 땅 방향을 보고 있는 주사위 면이라고 생각하고 사용하였다. 세로 상태 배열 역시 마찬가지이다. 

 

 이제 명령에 따라서 주사위를 회전시켜주면된다. 이때 주의할 점은 가로방향으로 회전시킨다고 가로 방향 배열만 바꿔주면 안된다. 가로로 회전하게 되더라도 세로 상태에도 영향을 끼치기 때문이다. 가로 방향으로 1번 회전하더라도 하늘을 보고 있는 면과 땅을 보고 있는 면이 바뀌기 때문에 세로 상태를 나타내는 배열도 수정해주어야 한다. 

 그러니까 가로든 세로든 회전을 하고 나면 하늘, 땅을 보고 있는 면의 인덱스(0,3)를 수정해 주어야 한다.

  // 지도의 상태에 따라서 주사위에 끼치는 영향이 다르다.
  if (map[y][x] == 0) {
    map[y][x] = h[3];
  } else {
    h[3] = map[y][x];
    map[y][x] = 0;
  }
  // 가로로 돌려도 세로배열에 영향을 끼친다. 
  v[1] = h[1];
  v[3] = h[3];

 

전체 코드

/**
 * 오른동 윗북
 * 좌표 (y,x);
 * if 지도 0 : 주사위 -> 지도
 * else : 지도 -> 주사위 && 지도는 0이됨.
 * 
 * 1. 주사위의 굴러감을 어떻게 구현할것인가.
 *  세로가로 길이는 각각 4이다.
 *  세로 가로를 각각 1차원 배열로 나타낸다.
 *  각각 몇번째 인덱스가 하늘, 바닥을 가리키는지 지정한다.
 *    1번인덱스가 하늘, 3번 인덱스가 바닥을 가리킨다고 하자.
 * 
 * 2. 세로로 굴러갈때 가로의 변화.
 *     2개가 변함. 세로의 몇번 칸들이 가로의 몇번칸에 들어오는지 구현한다.
 *     세로는 1차원 배열 밀기로 구현하면된다.
 *        세로를 굴린다.
 *        가로에도 변경사항을 적용시킨다. 
 *     가로로 굴릴때 역시 마찬가지다.  
 *     세로의 1번 인덱스 = 가로의 1번 인덱스
 *     세로의 3번 인덱스 = 가로의 3번 인덱스 
 */
function main() {
  let answer = '';
  const input = require('fs').readFileSync('input.txt').toString().trim().split('\n');
  const [N, M, y, x, K] = input[0].trim().split(' ').map(Number);
  let map = input.slice(1, N + 1).map(_ => _.trim().split(' ').map(Number));
  const c = input[N + 1].trim().split(' ').map(Number);

  let h = [0, 0, 0, 0]; // 주사위 가로
  let v = [0, 0, 0, 0]; // 주사위 세로
  answer = sol(N, M, x, y, map, c, h, v);
  return console.log(answer.trim());
}
function sol(N, M, x, y, map, c, h, v) {
  let answer = '';

  const dx = [1, -1, 0, 0];
  const dy = [0, 0, -1, 1];
  for (let i = 0; i < c.length; i++) {
    let [nx, ny] = [x + dx[c[i] - 1], y + dy[c[i] - 1]];
    if (nx < 0 || nx >= M || ny < 0 || ny >= N) continue; // 지도를 벗어나면 명령무시.

    if (c[i] == 1 || c[i] == 2) { // 동,서
      answer += rotateH(map, nx, ny, h, v, c[i]) + '\n';
    } else if (c[i] == 3 || c[i] == 4) { // 북,남
      answer += rotateV(map, nx, ny, h, v, c[i]) + '\n';
    }
    [x, y] = [nx, ny];
  }

  return answer.trim();
}
function rotateH(map, x, y, h, v, way) { // 가로 돌리기
  const temp = [...h];

  if (way == 1) { // -> 방향으로 돌리기. 동쪽
    for (let i = 0; i < h.length; i++) {
      h[i] = temp[(i + h.length - 1) % h.length];
    }
  } else if (way == 2) { // <- 방향으로 돌리기. 서쪽
    for (let i = 0; i < h.length; i++) {
      h[i] = temp[(i + 1) % h.length];
    }
  }
  // 지도의 상태에 따라서 주사위에 끼치는 영향이 다르다.
  if (map[y][x] == 0) {
    map[y][x] = h[3];
  } else {
    h[3] = map[y][x];
    map[y][x] = 0;
  }
  // 가로로 돌려도 세로배열에 영향을 끼친다. 
  v[1] = h[1];
  v[3] = h[3];

  return h[1]; // 하늘을 보고있는 면을 반환한다.
}
function rotateV(map, x, y, h, v, way) { // 세로 돌리기
  let temp = [...v];

  if (way == 4) { // ->. 남쪽
    for (let i = 0; i < v.length; i++) {
      v[i] = temp[(i + v.length - 1) % v.length];
    }
  } else if (way == 3) { // <-. 북쪽
    for (let i = 0; i < v.length; i++) {
      v[i] = temp[(i + 1) % v.length];
    }
  }

  if (map[y][x] == 0) {
    map[y][x] = v[3];
  } else {
    v[3] = map[y][x];
    map[y][x] = 0;
  }

  h[1] = v[1];
  h[3] = v[3];

  return v[1];
}
main();

특이사항

 배열 돌리기만 잘하면 어렵지 않게 풀 수 있다.

문제에서 지도의 좌표를 (r, c)로 준다. 문제를 대충 읽어서 (y, x)인 줄 알았는데 (x, y)였다. 주어진 예제 입력들은 (y, x)로 잘못 넣어도 정답이 잘 나온다... 그래서 한 번 틀렸는데 다시 잘 읽고 (x, y)로 넣으니까 맞더라 ㅠ

'Algorithm > BaeKJoon' 카테고리의 다른 글

[JS][백준]2493_탑  (0) 2022.10.07
[JS][백준]1504_특정한 최단 경로  (0) 2022.09.28
[JS][백준]1916_최소비용 구하기  (0) 2022.09.23
[JS][백준]1107_리모컨  (0) 2022.09.20
[JS][백준]1238_파티  (0) 2022.09.20