[백준 silver3] 미로 만들기

이민선(Jasmine)·2023년 3월 6일
0
post-thumbnail

문제

홍준이는 미로 안의 한 칸에 남쪽을 보며 서있다. 미로는 직사각형 격자모양이고, 각 칸은 이동할 수 있거나, 벽을 포함하고 있다. 모든 행과 열에는 적어도 하나의 이동할 수 있는 칸이 있다. 홍준이는 미로에서 모든 행과 열의 이동할 수 있는 칸을 걸어다녔다. 그러면서 자신의 움직임을 모두 노트에 쓰기로 했다. 홍준이는 미로의 지도를 자기 노트만을 이용해서 그리려고 한다.

입력으로 홍준이가 적은 내용을 나타내는 문자열이 주어진다. 각 문자 하나는 한 번의 움직임을 말한다. ‘F’는 앞으로 한 칸 움직인 것이고, ‘L'과 ’R'은 방향을 왼쪽 또는 오른쪽으로 전환한 것이다. 즉, 90도를 회전하면서, 위치는 그대로인 것이다.

입력

첫째 줄에 홍준이가 적은 내용의 길이가 주어진다. 길이는 0보다 크고, 50보다 작다. 둘째 줄에 홍준이가 적은 내용이 내용이 주어진다.

출력

첫째 줄에 미로 지도를 출력한다. ‘.’은 이동할 수 있는 칸이고, ‘#’는 벽이다.

예제 입력 1

5
RRFRF

예제 출력 1

..
.#

예제 입력 2

6
LFFRFF

예제 출력 2

...
##.
##.

예제 입력 3

14
LFLFRRFLFRRFLF

예제 출력 3

#.#
...
#.#

예제 입력 4

19
FLFRFFRFFFRFFRFLFLL

예제 출력 4

#..#
....
.##.
....

예제 입력 5

31
FRFFFFFFLLFRFFFFFLLFRFFFFLFFLFF

예제 출력 5

######.
.......
#.#####
#.#...#
#.###.#
#.....#
#.#####

나의 코드

const input = require("fs")
  .readFileSync("example.txt")
  .toString()
  .trim()
  .split("\n");
  // 첫 좌표 배열에 넣어줌. 행과 열 좌표 변화를 담을 배열 별도로 선언
let dx = [0];
let dy = [0];
let [x, y] = [0, 0];

input.shift();
const moves = input[0].split("");
// 남, 서, 북, 동을 각각 0, 1, 2, 3으로 정함. 남쪽을 바라보며 시작하므로 currentDir = 0
let currentDir = 0;
moves.forEach((move) => {
// R이면 currentDir 1 증가, L이면 1 감소
  if (move === "R") {
    currentDir === 3 ? (currentDir = 0) : currentDir++;
  } else if (move === "L") {
    currentDir === 0 ? (currentDir = 3) : currentDir--;
  } else {
  // F일 때는 switch문 사용하여 좌표의 움직임을 각각 dx와 dy에 넣어줌.
    switch (currentDir) {
      case 0:
        x += 1;
        break;
      case 1:
        y -= 1;
        break;
      case 2:
        x -= 1;
        break;
      case 3:
        y += 1;
        break;
    }
    dx.push(x);
    dy.push(y);
  }
});

// 0행 0열부터 시작해야 하므로 dx와 dy 배열 내에 음수가 사라질 때까지 1씩 더함.
while (dx.some((v) => v < 0)) {
  dx = dx.map((v) => (v += 1));
}
while (dy.some((v) => v < 0)) {
  dy = dy.map((v) => (v += 1));
}
// 행과 열의 길이는 dx, dy에서 각각 최대값 - 최소값 + 1
const rowSize = Math.max(...dx) - Math.min(...dx) + 1;
const colSize = Math.max(...dy) - Math.min(...dy) + 1;
// 위에서 정한 행, 열 길이에 맞게 2차원 빈 배열 선언
let ans = [...Array(rowSize)].map((_) => [...Array(colSize)]);
// dx와 dy 좌표에 해당하는 원소들을 "."으로 먼저 채운 다음
dx.forEach((rowNumber, i) => (ans[rowNumber][dy[i]] = "."));
// 나머지 부분들을 "#"으로 채움.
ans = ans.map((row) => row.map((v) => (v ? v : "#")).join(""));
// 한줄씩 출력
for (let row of ans) console.log(row);

사실 어려워보여서 못 풀 줄 알았는데 풀고나니까 아주 뿌듯하다. ㅎㅎㅎ
오늘 이것이 코딩테스트다 뒤에 수록된 파이썬을 쓱싹 호다닥 읽고 구현 파트에 있는 문제의 파이썬 코드를 읽어보고 도움을 많이 받았다.

  • dx와 dy를 각각 선언하기
  • 남서북동을 각각 0,1,2,3으로 정해놓기
    이코테 책 아니었으면 이렇게 접근하지 못했을 것 같다. 앞으로도 꾸준히 읽고 많은 팁들을 전수 받아야지!
    화이팅!!

Python으로 다시 풀기

미래에서 왔음~
오늘은 2023년 8월 7일

파이썬으로 다시 풀어보았다.

from sys import stdin as s

s = open("input.txt", "rt")  # 주석 처리해야 하는 부분

n = int(s.readline().strip())
input = list(s.readline().strip())
current_dir = 0
# 남 서 북 동
dir_dic = {'L': -1, 'R': 1, 'F': 0}
go_forward_dic = {0: (1, 0), 1: (0, -1), 2: (-1, 0), 3: (0, 1)}
x, y = (0, 0)


def turn_90_degrees(L_or_R, current_dir):
    current_dir += dir_dic[L_or_R]
    if current_dir == -1:
        current_dir = 3
    elif current_dir == 4:
        current_dir = 0
    return current_dir


walk_record = [(0, 0)]
for i in input:
    current_dir = turn_90_degrees(i, current_dir)

    if i != 'F':
        continue

    x, y = x + go_forward_dic[current_dir][0], y + \
        go_forward_dic[current_dir][1]
    walk_record.append((x, y))

# x좌표에서 가장 작은 값, y좌표에서 가장 작은 값을 구하면 된다.
min_x = min(walk_record, key=lambda x: x[0])[0]
min_y = min(walk_record, key=lambda x: x[1])[1]
max_x = max(walk_record, key=lambda x: x[0])[0]
max_y = max(walk_record, key=lambda x: x[1])[1]

row_length, col_length = max_x - min_x + 1, max_y - min_y + 1
board = [['#' for _ in range(col_length)] for _ in range(row_length)]

for (i, j) in walk_record:
    i += abs(min_x)
    j += abs(min_y)
    board[i][j] = '.'

for row in board:
    print(''.join(row))

javascript로 풀었을 때는 board의 size를 구하기 전에 while문으로 음수가 없어질 때까지 모든 원소에 +1을 했군.
이번에 python으로 풀면서는 x좌표에서 가장 작은 값, 가장 큰 값, y 좌표에서 가장 작은 값, 가장 큰 값을 각각 구하여 절대값으로 board의 size를 구했다.

while문으로 순회하면서 +1씩 증가시키면 최악의 경우 최소값이 -50이고, 예를 들어 50번 북쪽으로 걸어가기만 했다면 2500번의 연산을 추가적으로 해줘야 한다. 불필요한 연산이므로 굳이 할 필요 없다는 생각은 든다.

profile
기록에 진심인 개발자 🌿

0개의 댓글