메모리: 31120 KB, 시간: 64 ms
자료 구조, 덱, 구현, 큐, 시뮬레이션
2024년 3월 13일 04:26:27
'Dummy' 라는 도스게임이 있다. 이 게임에는 뱀이 나와서 기어다니는데, 사과를 먹으면 뱀 길이가 늘어난다. 뱀이 이리저리 기어다니다가 벽 또는 자기자신의 몸과 부딪히면 게임이 끝난다.
게임은 NxN 정사각 보드위에서 진행되고, 몇몇 칸에는 사과가 놓여져 있다. 보드의 상하좌우 끝에 벽이 있다. 게임이 시작할때 뱀은 맨위 맨좌측에 위치하고 뱀의 길이는 1 이다. 뱀은 처음에 오른쪽을 향한다.
뱀은 매 초마다 이동을 하는데 다음과 같은 규칙을 따른다.
사과의 위치와 뱀의 이동경로가 주어질 때 이 게임이 몇 초에 끝나는지 계산하라.
첫째 줄에 보드의 크기 N이 주어진다. (2 ≤ N ≤ 100) 다음 줄에 사과의 개수 K가 주어진다. (0 ≤ K ≤ 100)
다음 K개의 줄에는 사과의 위치가 주어지는데, 첫 번째 정수는 행, 두 번째 정수는 열 위치를 의미한다. 사과의 위치는 모두 다르며, 맨 위 맨 좌측 (1행 1열) 에는 사과가 없다.
다음 줄에는 뱀의 방향 변환 횟수 L 이 주어진다. (1 ≤ L ≤ 100)
다음 L개의 줄에는 뱀의 방향 변환 정보가 주어지는데, 정수 X와 문자 C로 이루어져 있으며. 게임 시작 시간으로부터 X초가 끝난 뒤에 왼쪽(C가 'L') 또는 오른쪽(C가 'D')로 90도 방향을 회전시킨다는 뜻이다. X는 10,000 이하의 양의 정수이며, 방향 전환 정보는 X가 증가하는 순으로 주어진다.
첫째 줄에 게임이 몇 초에 끝나는지 출력한다.
from collections import deque
n = int(input())
k = int(input())
apples = []
move = []
for i in range(k):
a, b = map(int, input().split())
apples.append((a, b))
l = int(input())
for i in range(l):
x, c = input().split()
move.append([int(x), c])
move_seconds = [move_time[0] for move_time in move]
board = [[0] * (n + 2) for _ in range(n + 2)] # 보드판 넘어서는 것 고려하여 n+2 설정
# 보드위에 사과 두기
for apple in apples:
a, b = apple
board[a][b] = 1
second = 0
direction = [(0, 1), (1, 0), (0, -1), (-1, 0)] # 동남서북
d = 0
snake = deque([(1, 1)])
while True:
moved_snake = deque()
cur_direction = direction[d]
second += 1
tail_x, tail_y = snake[-1]
for body in snake: # 뱀머리 1칸 이동
x, y = body
nx, ny = x + cur_direction[0], y + cur_direction[1]
moved_snake.append((nx, ny))
snake = moved_snake
head_x, head_y = snake.popleft()
if (
head_x == 0 or head_x == n + 1 or head_y == 0 or head_y == n + 1
): # 뱀 머리 보드판 부딪힘?
print(second)
break
if (head_x, head_y) in snake or (
head_x == tail_x and head_y == tail_y
): # 뱀 머리 몸통에 부딪힘?
print(second)
break
else:
snake.appendleft((head_x, head_y))
if board[head_x][head_y] == 1: # 뱀머리가 사과와 만남
snake.append((tail_x, tail_y))
if second in move_seconds: # 뱀의 머리 방향 조정
if move[move_seconds.index(second)][1] == "L":
d -= 1
if d == -1:
d = 3
elif move[move_seconds.index(second)][1] == "D":
d += 1
if d == 4:
d = 0
아이디어는 뱀이 움직이는 board를 n+2로 초기화한다. 그 이유는 벽을 넘는 경우를 생각해서 상하좌우에 1줄씩 추가 했기 때문이다. 이 코드의 문제점은 머리가 방향 전환을 할때, 머리만 좌표가 변해야하는데, 나머지 몸통까지 평행이동해버리는 문제점이 발생했다. 또한, 보드판에 변형을 가했을 때, 사과의 좌표또한 변경시켜줘야하는 일이 생기므로 실수 할 수 있다.
N = int(input())
K = int(input())
apples = []
for i in range(K):
a, b = map(int, input().split())
apples.append((a, b))
L = int(input())
directions = [input().split() for _ in range(L)]
directions = [(int(x), c) for x, c in directions]
# 뱀의 초기 위치 및 방향 설정 (오른쪽을 바라보고 있음)
snake = [(1, 1)]
dx, dy = 0, 1 # 초기 이동 방향
time = 0 # 게임이 진행된 시간
direction_idx = 0 # 다음에 적용할 방향 변환의 인덱스
# 방향 전환 함수
def turn(direction, C):
if C == 'L':
return -direction[1], direction[0]
else:
return direction[1], -direction[0]
# 게임 시작
while True:
time += 1
# 뱀의 머리 위치 갱신
head = (snake[0][0] + dx, snake[0][1] + dy)
# 벽 또는 자기 자신과 부딪히면 게임 종료
if head in snake or not(1 <= head[0] <= N) or not(1 <= head[1] <= N):
break
snake.insert(0, head)
# 사과가 있으면 꼬리를 움직이지 않음
if head not in apples:
snake.pop()
else: # 사과를 먹으면 사과 목록에서 제거
apples.remove(head)
# 방향 전환 시간이 되면 방향 전환
if direction_idx < L and time == directions[direction_idx][0]:
dx, dy = turn((dx, dy), directions[direction_idx][1])
direction_idx += 1
print(time)