문제
맵 안에서의 캐릭터 이동을 구현시키는 문제이다. NxM 크기의 맵은 육지 또는 바다로 구성돼 있다. 캐릭터는 동서남북 중 한 곳을 바라본다. 캐릭터는 상하좌우로 움직일 수 있고, 바다로 되어 있는 공간에는 갈 수 없다. 또한 다음 매뉴얼을 따른다.
매뉴얼1. 현재 위치에서 현재 방향을 기준으로 왼쪽 방향(반시계 방향으로 90도 회전한 방향)부터 차례대로 갈 곳을 정한다.
매뉴얼2. 캐릭터의 바로 왼쪽 방향에서 아직 가보지 않은 칸이 존재한다면, 왼쪽 방향으로 회전한 다음 왼쪽으로 한 칸을 전진한다. 왼쪽 방향에 가보지 않은 칸이 없다면, 왼쪽 방향으로 회전만 수행하고 1단계로 돌아간다.
매뉴얼3. 만약 네 방향 모두 이미 가본 칸이거나 바다로 되어 있는 칸인 경우에는, 바라보는 방향을 유지한 채로 한 칸 뒤로 가고 1단계로 돌아간다. 단, 이때 뒤쪽 방향이 바다인 칸이라 뒤로 갈 수 없는 경우에는 움직임을 멈춘다.
위 과정을 반복적으로 수행하면서 캐릭터의 움직임에 이상이 있는지 테스트하려고 한다. 매뉴얼을 따라 캐릭터를 이동시킨 뒤에, 캐릭터가 방문한 칸의 수를 출력하는 프로그램을 만드시오.
입력 조건
1. 첫째 줄에 맵의 세로 크기 N과 가로 크기 M을 공백으로 구분하여 입력한다.
2. 둘째 줄에 게임 태릭터가 있는 칸의 좌표와 바라보는 방향이 서로 공백으로 구분하여 주어진다. 방향값은 0(북쪽), 1(동쪽), 2(남쪽), 3(서쪽)으로 존재한다.
3. 셋째 줄부터 맵의 정보가 주어진다. N개의 줄에서 바다(1)와 육지(0)로 구성된다. 맵의 외각은 항상 바다로 되어 있다.
4. 처음 캐릭터가 위치한 칸의 상태는 항상 육지이다.
출력 조건
1. 첫째 줄에 이동을 마친 후 캐릭터가 방문한 칸의 수를 출력한다.
내 코드
n,m = map(int,input().split())
coord = list(map(int,input().split()))
world=[list(map(int, input().split())) for _ in range(int(n))]
step = [(-1,0),(0,-1),(+1,0),(0,+1)] #상좌하우 (반시계방향)
dir=coord[2]
world[coord[0]][coord[1]]=2
# 가본 칸은 2
while(True):
if (dir == 0 and world[coord[0] - 1][coord[1]] == 0):
coord[0] = coord[0] + step[0][0]
coord[1] = coord[1] + step[0][1]
elif (dir == 1 and world[coord[0]][coord[1]-1] == 0):
coord[0] = coord[0] + step[1][0]
coord[1] = coord[1] + step[1][1]
elif (dir == 2 and world[coord[0]+1][coord[1]] == 0):
coord[0] = coord[0] + step[2][0]
coord[1] = coord[1] + step[2][1]
elif (dir == 3 and world[coord[0]][coord[1]+1] == 0):
coord[0] = coord[0] + step[3][0]
coord[1] = coord[1] + step[3][1]
else:
dir +=1
if (dir==4):
dir=0
world[coord[0]][coord[1]] = 2;
if (world[coord[0]+1][coord[1]]!=0 and world[coord[0]-1][coord[1]]!=0 and world[coord[0]][coord[1]+1]!=0 and world[coord[0]][coord[1]-1]!=0):
if(dir==0 and world[coord[0] + step[2][0]][coord[1] + step[2][1]]==2):
coord[0] = coord[0] + step[2][0]
coord[1] = coord[1] + step[2][1]
elif (dir == 1 and world[coord[0] + step[3][0]][coord[1] + step[3][1]]==2):
coord[0] = coord[0] + step[3][0]
coord[1] = coord[1] + step[3][1]
elif (dir == 2 and world[coord[0] + step[0][0]][coord[1] + step[0][1]]==2):
coord[0] = coord[0] + step[0][0]
coord[1] = coord[1] + step[0][1]
elif (dir == 3 and world[coord[0] + step[1][0]][coord[1] + step[1][1]]==2):
coord[0] = coord[0] + step[1][0]
coord[1] = coord[1] + step[1][1]
else:
break;
output = 0
for row in range(n):
for col in range(m):
if(world[row][col]==2):
output+=1
print(output)
해설 맵을 NxM 크기의 2차원 리스트로 활용하였다. 입력된 좌표를 맵에 넣어 조건을 만족하면 이동하거나, 루프를 탈출하게 하였다. 또한 초기 시작 좌표와 이미 한 차례 방문했던 곳은 육지(0)나 바다(1)가 아닌 (2)로 지정해 주었다. 그렇게 루프를 탈출한 후 (2)의 최종 개수를 카운트하여 출력하였다. 또한 앞선 예제에서 학습한 것 처럼 step 리스트에 이동값을 저장해놓아 좌표를 이동시켜주었다. 맵의 크기와 구조를 바꿔보아도 올바른 결과값을 반환함을 확인하였다.
반복문구성 크게 두 가지의 조건문으로 나누었다. 첫 번째 조건문에서는 방향에 따라 앞으로 나아가거나, 나아갈 수 없다면 반시계 방향으로 90도 회전하는 명령을 실행하였다. 두 번째 조건문에서는 현재 좌표 기준 사방이 육지가 아니라면 뒤로 한 칸 이동시키는 명령을 실행하였다. 육지가 아닌 경우 이미 왔던 곳이거나 바다인데, 바다인 경우 전체 루프를 탈출시키게 하였다.
평가 드디어 문제다운 문제를 해결하였다. 물론 주어진 타임리밋을 훨씬 넘겼고, 디버깅도 여러 차례 했지만 말이다..ㅎ_ㅎ 계속 학습하고 반복하다보면 능숙하게 문제를 해결할 수 있지 않을까....
참고
이것이 코딩테스트다 with Python (나동빈 저)