백준 # 2174 로봇 시뮬레이션 (파이썬)

이더영·2022년 9월 25일
0

로봇 시뮬레이션 문제 바로가기

문제

가로 A(1≤A≤100), 세로 B(1≤B≤100) 크기의 땅이 있다. 이 땅 위에 로봇들이 N(1≤N≤100)개 있다.

로봇들의 초기 위치는 x좌표와 y좌표로 나타난다. 위의 그림에서 보듯 x좌표는 왼쪽부터, y좌표는 아래쪽부터 순서가 매겨진다. 또한 각 로봇은 맨 처음에 NWES 중 하나의 방향을 향해 서 있다. 초기에 서 있는 로봇들의 위치는 서로 다르다.

이러한 로봇들에 M(1≤M≤100)개의 명령을 내리려고 한다. 각각의 명령은 순차적으로 실행된다. 즉, 하나의 명령을 한 로봇에서 내렸으면, 그 명령이 완수될 때까지 그 로봇과 다른 모든 로봇에게 다른 명령을 내릴 수 없다. 각각의 로봇에 대해 수행하는 명령은 다음의 세 가지가 있다.

L: 로봇이 향하고 있는 방향을 기준으로 왼쪽으로 90도 회전한다.
R: 로봇이 향하고 있는 방향을 기준으로 오른쪽으로 90도 회전한다.
F: 로봇이 향하고 있는 방향을 기준으로 앞으로 한 칸 움직인다.
간혹 로봇들에게 내리는 명령이 잘못될 수도 있기 때문에, 당신은 로봇들에게 명령을 내리기 전에 한 번 시뮬레이션을 해 보면서 안전성을 검증하려 한다. 이를 도와주는 프로그램을 작성하시오.

잘못된 명령에는 다음의 두 가지가 있을 수 있다.

Robot X crashes into the wall: X번 로봇이 벽에 충돌하는 경우이다. 즉, 주어진 땅의 밖으로 벗어나는 경우가 된다.
Robot X crashes into robot Y: X번 로봇이 움직이다가 Y번 로봇에 충돌하는 경우이다.

입력

첫째 줄에 두 정수 A, B가 주어진다. 다음 줄에는 두 정수 N, M이 주어진다. 다음 N개의 줄에는 각 로봇의 초기 위치(x, y좌표 순) 및 방향이 주어진다. 다음 M개의 줄에는 각 명령이 명령을 내리는 순서대로 주어진다. 각각의 명령은 명령을 내리는 로봇, 명령의 종류(위에 나와 있는), 명령의 반복 회수로 나타낸다. 각 명령의 반복 회수는 1이상 100이하이다.

출력

첫째 줄에 시뮬레이션 결과를 출력한다. 문제가 없는 경우에는 OK를, 그 외의 경우에는 위의 형식대로 출력을 한다. 만약 충돌이 여러 번 발생하는 경우에는 가장 먼저 발생하는 충돌을 출력하면 된다.

예제 입력 1

5 4
2 2
1 1 E
5 4 W
1 F 7
2 F 7

예제 출력 1

Robot 1 crashes into the wall

문제 이해하기

  1. 시뮬레이션 문제 - 문제가 길고 복잡한 경향이 있지만, 문제에서 원하는 명령을 충실하게 수행하도록 프로그램을 짜면 된다.
  2. 좌표 문제 - 좌표 상에서 벽에 부딪히거나 다른 말과 좌표가 겹칠 경우 메시지를 출력해야 하는 유형의 문제다.
  3. 방향 문제 - 방향을 바꾸거나, 바라보고 있는 방향에 맞춰 좌표 상에서 이동해야 하는 유형의 문제다.

문제 풀기

# 2174 로봇 시뮬레이션
import sys

A, B = map(int, input().split())
N, M = map(int, input().split())

head_list = ['N', 'W', 'S', 'E'] 
left = ['W', 'S', 'E', 'N'] # left 명령 시 사용
right = ['E', 'N', 'W', 'S'] # right 명령 시 사용
dx = [0, -1, 0, 1] # head list의 방향에 따라 forward 명령 시 dx
dy = [1, 0, -1, 0] # head list의 방향에 따라 forward 명령 시 dy

issue = 0 # issue가 없는 상태 (벽에 부딪힘: 1, 충돌: 2)

pos = []
for _ in range(N):
  x, y, d = input().split()
  x = int(x)
  y = int(y)
  pos.append([x, y, d])

for _ in range(M):
  robot, typ, rpt = input().split()
  robot = int(robot)
  rpt = int(rpt)
  x = pos[robot -1][0] # 이동시킬 로봇의 x좌표
  y = pos[robot -1][1] # 이동시킬 로봇의 y좌표

  if typ == 'F': # 명령이 forward인 경우
    for i in range(len(head_list)):
      if pos[robot -1][2] == head_list[i]:
        for _ in range(rpt):
          pos[robot -1][0] += dx[i]
          pos[robot -1][1] += dy[i] # new x, new y로 업데이트
          for j in range(N): # 다른 로봇의 위치와 동일한 경우
            if j != robot -1:
              if pos[j][0] == pos[robot -1][0] and pos[j][1] == pos[robot -1][1]:
                issue = 2
                print(f'Robot {robot} crashes into robot {j+1}') 
                sys.exit(0)
        # print(pos[robot -1])
      
  if typ == 'L' : # 명령이 left인 경우
    for _ in range(rpt):
      for i in range(len(head_list)):
        if pos[robot -1][2] == head_list[i]:
          pos[robot -1][2] = left[i]
      # print(pos[robot -1])

  if typ == 'R': # 명령이 right인 경우
    for _ in range(rpt):
      for i in range(len(head_list)):
        if pos[robot -1][2] == head_list[i]:
          pos[robot -1][2] = right[i]
    # print(pos[robot -1])

  
  if (pos[robot -1][0] > A or pos[robot -1][1] > B or pos[robot -1][0] < 0 or pos[robot -1][1] < 0) and issue == 0: # 벽에 부딪히는 경우
    print(issue)
    issue = 1
    print(f'Robot {robot} crashes into the wall')

  if issue == 0:
    print('OK')
  1. left, right 명령 수행 시 로봇의 방향을 if문으로 일일이 확인해서 방향을 바꿔주는 것이 아니라, left, right 각각 리스트를 만들어 현재 로봇의 방향만 확인되면 간단하게 방향을 바꿀 수 있음
  2. dx, dy 리스트를 정의해서 현재 로봇이 바라보고 있는 방향별로 이동해야 할 방향을 명시

발전할 수 있는 방법

  1. '벽에 부딪히는 경우' 더 깔끔하게 구현하는 방법
    • -1로 좌표 테두리에 패딩을 넣어 벽에 부딪히는 경우를 일일히 if문으로 구현하지 않게 만들 수 있음
  2. 인덱스와 숫자 맞추기
    • robot의 number는 1부터 시작하는데, 로봇 리스트는 0부터 시작하다 보니 코드가 지저분해지는 경향이 있음
    • robot 리스트의 첫 번째 원소로 dummy element를 넣어 코드를 더욱 깔끔하게 할 수 있을 것 같음
  3. 로봇의 방향을 텍스트가 아닌 숫자로 받기
    • 로봇의 방향을 입력받을 때부터 0, 1, 2, 3으로 받았다면 명령을 수행할 때마다 반복문을 돌려 방향을 확인해야 하는 번거로움 없이 방향에 매칭되는 숫자에 따라 명령을 수행시키면 됨
  4. sys.exit(0)으로 반복문 한 번에 나가기 (반영 완료)
    • 원하는 결과를 출력한 후 이제 더이상 프로그램을 실행시키지 않아도 될 때는 sys.exit(0)을 통해 반복문을 한 번에 나가도록 할 수 있음

0개의 댓글