백준 뱀 코드 및 해설 (파이썬)

2021. 8. 24. 21:56algorithm

반응형

https://www.acmicpc.net/problem/3190

 

3190번: 뱀

 'Dummy' 라는 도스게임이 있다. 이 게임에는 뱀이 나와서 기어다니는데, 사과를 먹으면 뱀 길이가 늘어난다. 뱀이 이리저리 기어다니다가 벽 또는 자기자신의 몸과 부딪히면 게임이 끝난다. 게임

www.acmicpc.net

 

문제 설명이 좀 불친절하지 않나?? 그렇지 않나??!?!

뱀이 너무 이상하게 움직여서 짜증나는 문제였다.

뱀이 자기자신의 몸과 부딪히는게 어떤 상황인건지 한참 고민했다.

다음 이동할 곳으로 (무리하게!) 먼저 머리 먼저 옮기는데 그 곳에 지 몸이 있으면 부딪히는 거구만 으이구 

 

먼저 보드 크기, 사과 개수, 사과 위치, 방향 전환 시점 및 방향 등 필요한 정보를 모두 받아 변수에 저장한다. 보드는 0~ (N-1)이 아니라 (N+1) 크기로 만들어 1 ~ N 까지를 사용했다. 

뱀이 이동할 때 머리의 위치는 head에, 머리를 포함한 전체 뱀의 위치들은 snake에, 현재 시각은 now에, 현재 향하는 방향은 direction으로 저장했다. 

direction은 오른쪽인 경우 (0,1), 왜냐면 오른쪽으로 갈 때 앞으로 전진하려면 현재 좌표에서 (0,1)을 더해야 하니까. 

이런 식으로 direction을 정해줬다. 오른쪽, 왼쪽 방향 전환하는 것도 이 방향이라면 전진할 때 좌표 값에 얼마를 더해줘야 하는지를 기준으로 딕셔너리를 만들었다. 근데 다른 코드 보니까 멋지게 4로 나눈 나머지를 이용하더라? ㅎ

어쨌든 이제 뱀을 이동해줄 차례

now를 1씩 증가시키면서

현재가 방향 전환할 타이밍이라면 전환을 해주고, 아니라면 지금 방향 그대로 냅둔다. 이후 머리를 먼저 이동시킨다. 이때 머리가 이동한 그곳에 이미 뱀의 몸이 있으면 break로 루프를 빠져나온다. 아니라면 킵고잉~~~

사과의 유무에 따라 꼬리를 자를지 말지 결정한다. 사과가 있으면 일단 사과를 먹었으니 사과를 지우고, snake 리스트 앞에 head만 추가해준다. 사과가 없으면 snake 리스트 앞에 head 추가한 뒤에, snake의 마지막 요소를 pop한다. 

이렇게 이동을 끝낸 후 현재 head의 좌표가 1~N을 벗어났으면 break, 아니라면 킵고잉~~~

 

루프에 벗어났으면 현재 시점 now를 print해준다.

 

 

import sys

# 보드 크기
N = int(sys.stdin.readline())
# 1 ~ N
board = [[0] * (N+1) for _ in range(N+1)]

# 사과 개수
K = int(sys.stdin.readline())
apples = []
for i in range(K):
    apples.append(list(map(int, sys.stdin.readline().split())))

# 방향 변환 횟수
L = int(sys.stdin.readline())
turn = {}
for i in range(L):
    second, direction = sys.stdin.readline().split()
    # n초 '후'에 방향 전환이므로 +1
    turn[int(second)+1] = direction

head = [1,1] # 뱀의 머리 위치
snake = [[1,1]] # 뱀의 전체 몸통 위치
now = 0 # 현재 시각
direction = [0,1] # 현재 방향 (오른쪽으로 초기화)

# 오른쪽 방향 전환
right_turn = {(-1,0):(0,1), (1,0):(0,-1), (0,-1):(-1,0), (0,1):(1,0)}
# 왼쪽 방향 전환
left_turn = {(-1,0):(0,-1), (1,0):(0,1), (0,-1):(1,0), (0,1):(-1,0)}



while True:
    now += 1
    if now in turn.keys():
        if turn[now] == 'D': # 오른쪽
            direction = right_turn[tuple(direction)]
        else: # 왼쪽
            direction = left_turn[tuple(direction)]
    # 뱀 머리 방향대로 이동
    pre_head = head
    head = [x+y for x,y in zip(head, direction)]

    # 뱀의 머리가 몸통에 닿는 경우
    if head in snake:
        break

    # 뱀 나머지 부분 방향대로 이동
    # 사과가 있는 곳으로 이동한 경우
    if head in apples:
        apples.remove(head)
        snake = [head] + snake
    # 사과가 없는 경우
    else:
        snake = [head] + snake
        snake.pop(-1)

    # 보드 끝에 다다름
    if head[0] < 1 or head[0] > N or head[1] < 1 or head[1] > N:
        break

print(now)
반응형