주사위를 구현하는 방법 - 주사위 굴리기 -

1. 문제

 

14499번: 주사위 굴리기 (acmicpc.net)

 

14499번: 주사위 굴리기

첫째 줄에 지도의 세로 크기 N, 가로 크기 M (1 ≤ N, M ≤ 20), 주사위를 놓은 곳의 좌표 x, y(0 ≤ x ≤ N-1, 0 ≤ y ≤ M-1), 그리고 명령의 개수 K (1 ≤ K ≤ 1,000)가 주어진다. 둘째 줄부터 N개의 줄에 지

www.acmicpc.net

 

지도 위에 주사위를 향하는 방향으로 반복적으로 굴리면서, 숫자를 주사위로 복사하거나 지도로 복사하는 명령을 반복적으로 수행할때, 각 명령마다 윗면에 쓰인 숫자를 출력하는 문제

 

 

2. 풀이

 

주사위를 굴릴때 생각해보면 위, 아래로 굴리냐, 아니면 오른쪽 왼쪽으로 굴리냐에 따라

 

사용하는 면이 정해져있다

 

위,아래로 굴리는 경우는 아래와 같고

 

 

오른쪽 왼쪽으로 굴린다면??

 

 

따라서 주사위를 굴릴때, 위, 아래로 굴릴때 숫자를 관리하는 배열과 좌,우로 굴릴때 숫자를 관리하는 배열을 따로 만들면 될것 같다

 

그런데 주사위는 회전하니까 회전하면서 숫자를 옮기기에 적절한 deque가 좋은것 같다

 

from collections import deque
from sys import stdin

#기본세팅
#사용 편의를 위해 x,y를 y,x로 바꿔줌

n,m,y,x,k = map(int,stdin.readline().split())

maps = [list(map(int,stdin.readline().split())) for _ in range(n)]

order_list = list(map(int,stdin.readline().split()))

#델타배열
#1,2,3,4는 동,서,북,남
delta = [0,[1,0],[-1,0],[0,-1],[0,1]]

#0번을 밑바닥이라고 한다면, 2번이 윗면
#주사위가 남,북으로 구르면 up_down
#주사위가 동,서로 구르면 left_right

up_down = deque([0,0,0,0])
left_right = deque([0,0,0,0])

 

문제에서 동서남북 방향 제시한 경우에 따라 델타배열도 적절하게 만들었음

 

 

각 deque의 인덱스에 따라 그림을 표시해보면.. 위와 같다

 

각각의 경우 0번이 밑바닥이고 2번이 윗면이다.

 

동쪽으로 굴리면 밑면이 1이 되니까 [0,1,2,3]이 [1,2,3,0]이 되어야하므로, rotate(-1)

 

서쪽으로 굴리면 밑면이 3이 되니까, [0,1,2,3]이 [3,0,1,2]가 되어야하므로, rotate(1)

 

남쪽으로 굴리면 밑면이 1이 되니까, [0,1,2,3]이 [1,2,3,0]이 되어야하므로, rotate(-1)

 

북쪽으로 굴리면 밑면이 3이 되니까, [0,1,2,3]이 [3,0,1,2]가 되어야하므로 rotate(1)

 

-------------------------------------------------------------------------------------------------------------------------------------

 

이걸 정확히 정의하고 나서 시뮬레이션을 시작하자

 

이제 명령 리스트를 순회하면서, 주사위를 굴릴거임

 

주사위의 좌표 x,y를 명령에 따라 일단 옮겨보면

 

#시뮬레이션 시작

#이동을 하고 회전시키면, 위,아래의 값을 다른 deque도 그대로 가져가야함
for order in order_list:
    
    #주사위의 좌표 이동

    dx = x + delta[order][0]
    dy = y + delta[order][1]

 

dx,dy가 맵의 범위를 벗어나려고 하는 경우는 명령을 무시해야하고, 출력도 하지 말아야하니까,

 

범위 안에 있는 경우에만 동작하도록

 

    #배열의 범위를 벗어나지 않는 경우에만 이동

    if dx >= 0 and dx <= m-1 and dy >= 0 and dy <= n-1:

 

 

이제 동쪽으로 이동하는 경우에, rotate(-1)로 회전시켜서 주사위를 굴리고

 

        #동쪽으로 이동하라고 한다면..
        #1번과 3번은 그대로 있지만,
        #left_right가 동쪽으로 움직이고나서 0번 2번을 그대로 가져감
        if order == 1:
            
            left_right.rotate(-1) #동쪽으로 1칸 이동

 

이동한 맵의 칸에 쓰인 수가 0인지 아닌지에 따라 0이면 주사위의 바닥면인 left_right[0]를 복사하고

 

0이 아니라면, 맵에 적힌 숫자를 주사위의 바닥면에 복사한다

 

그리고 맵에 적힌 숫자는 0으로 바꾼다

 

        #동쪽으로 이동하라고 한다면..
        #1번과 3번은 그대로 있지만,
        #left_right가 동쪽으로 움직이고나서 0번 2번을 그대로 가져감
        if order == 1:
            
            left_right.rotate(-1) #동쪽으로 1칸 이동

            #이동한 칸에 쓰인 수가 0이라면..

            if maps[dy][dx] == 0:
                
                maps[dy][dx] = left_right[0] #주사위 바닥면을 맵에 복사
            
            else:
                
                left_right[0] = maps[dy][dx] #주사위 바닥면에 맵 칸을 복사

                maps[dy][dx] = 0 #맵 칸은 0으로

            print(left_right[2]) #윗면 출력

 

그리고 나서 윗면을 출력하고, 마지막으로 중요한 점은 위 아래로 굴릴때와, 왼쪽 오른쪽으로 굴릴때

 

윗면 아랫면이 서로 공유된다는 점을 그림에서 보였다

 

 

 

예를 들어 남쪽으로 굴린다면? [1,0,3,2]가 되는데... 밑면이 1이고 윗면이 3이 된단 말이야

 

하지만 양 옆으로 굴리는 배열 [0,1,2,3]은 그대로 있는게 아니야.. 

 

 

위 아래로 한번 굴리면, 양 옆을 관리하는 배열의 윗면과 아랫면도 동일하게 바뀐다는 점을 생각해야한다

 

나머지 두면은 바뀌지 않지만, 굴릴때마다 윗면과 아랫면이 서로 똑같이 공유된다는 점을 고려해야한다 

 

            #다른 deque의 아래 위인 0,2번을 교체
            up_down[0] = left_right[0]
            up_down[2] = left_right[2]

 

그러면 나머지 order =2,3,4에서도 똑같이... 

 

rotate에 넣어야할 값만 달라진다는 점을 생각한다면..

 

from collections import deque
from sys import stdin

#기본세팅
#사용 편의를 위해 x,y를 y,x로 바꿔줌

n,m,y,x,k = map(int,stdin.readline().split())

maps = [list(map(int,stdin.readline().split())) for _ in range(n)]

order_list = list(map(int,stdin.readline().split()))

#델타배열
#1,2,3,4는 동,서,북,남
delta = [0,[1,0],[-1,0],[0,-1],[0,1]]

#0번을 밑바닥이라고 한다면, 2번이 윗면
#주사위가 남,북으로 구르면 up_down
#주사위가 동,서로 구르면 left_right

up_down = deque([0,0,0,0])
left_right = deque([0,0,0,0])

#시뮬레이션 시작

#이동을 하고 회전시키면, 위,아래의 값을 다른 deque도 그대로 가져가야함
for order in order_list:
    
    #주사위의 좌표 이동

    dx = x + delta[order][0]
    dy = y + delta[order][1]

    #배열의 범위를 벗어나지 않는 경우에만 이동

    if dx >= 0 and dx <= m-1 and dy >= 0 and dy <= n-1:
        
        #동쪽으로 이동하라고 한다면..
        #1번과 3번은 그대로 있지만,
        #left_right가 동쪽으로 움직이고나서 0번 2번을 그대로 가져감
        if order == 1:
            
            left_right.rotate(-1) #동쪽으로 1칸 이동

            #이동한 칸에 쓰인 수가 0이라면..

            if maps[dy][dx] == 0:
                
                maps[dy][dx] = left_right[0] #주사위 바닥면을 맵에 복사
            
            else:
                
                left_right[0] = maps[dy][dx] #주사위 바닥면에 맵 칸을 복사

                maps[dy][dx] = 0 #맵 칸은 0으로

            print(left_right[2]) #윗면 출력


            #다른 deque의 아래 위인 0,2번을 교체
            up_down[0] = left_right[0]
            up_down[2] = left_right[2]
        
        #서쪽으로 이동하라고 하면..
        
        elif order == 2:

            left_right.rotate(1)

            #이동한 칸에 쓰인 수가 0이라면..

            if maps[dy][dx] == 0:
                
                maps[dy][dx] = left_right[0] #주사위 바닥면을 맵에 복사
            
            else:
                
                left_right[0] = maps[dy][dx] #주사위 바닥면에 맵 칸을 복사

                maps[dy][dx] = 0 #맵 칸은 0으로

            print(left_right[2])

            up_down[0] = left_right[0]
            up_down[2] = left_right[2]
        
        #북쪽으로 이동하라고 한다면..
        elif order == 3:

            up_down.rotate(1)

            #이동한 칸에 쓰인 수가 0이라면..

            if maps[dy][dx] == 0:
                
                maps[dy][dx] = up_down[0] #주사위 바닥면을 맵에 복사
            
            else:
                
                up_down[0] = maps[dy][dx] #주사위 바닥면에 맵 칸을 복사

                maps[dy][dx] = 0 #맵 칸은 0으로

            print(up_down[2])

            left_right[0] = up_down[0]
            left_right[2] = up_down[2]
        
        #남쪽으로 이동하라고 한다면..
        else:

            up_down.rotate(-1)

            #이동한 칸에 쓰인 수가 0이라면..

            if maps[dy][dx] == 0:
                
                maps[dy][dx] = up_down[0] #주사위 바닥면을 맵에 복사
            
            else:
                
                up_down[0] = maps[dy][dx] #주사위 바닥면에 맵 칸을 복사

                maps[dy][dx] = 0 #맵 칸은 0으로

            print(up_down[2])

            left_right[0] = up_down[0]
            left_right[2] = up_down[2]
            

        x = dx
        y = dy

 

그리고 주사위를 한번 굴리고 나서 x=dx, y=dy로 실제 좌표를 옮겨주고 다음 반복으로 넘어가면 될 것이다

 

 

TAGS.

Comments