프로그래밍/알고리즘

[Python] 백준 20056번 - 마법사 상어와 파이어볼

고등어찌짐 2022. 9. 29. 23:45

 

아이디어

1. 파이어 볼을 움직일 때, 각 방향에 대해 얼마나 움직일지를 미리 리스트에 저장한 후 계산

2. 행, 열이 넘어가는 경우를 체크하는 함수 작성

3. 파이어볼을 모두 합치고, 쪼개는 작업을 함. 

4. 질량이 0 인 파이어볼은 board 내에서 제거 


풀이 코드

# 행, 열이 넘어가는 경우 체크
def over_flow(x):
    if x < 0:
        x = n - abs(x) % n

    if x >= n:
        x = x % n

    return x


# 현재 위치, 속도, 방향으로부터 다음 위치를 계산한다
def get_coords(x, y, d, s):
    go = [(-1, 0), (-1, 1), (0, 1), (1, 1), (1, 0), (1, -1), (0, -1), (-1, -1)]
    gox = x + go[d][0] * s
    goy = y + go[d][1] * s
    return over_flow(gox), over_flow(goy)


# 파이어볼을 움직인다
def move_fireball(arr):
    new_board = [[[] for _ in range(n)] for _ in range(n)]
    for i in range(n):
        for j in range(n):
            if arr[i][j]:
                for t_ball in arr[i][j]:
                    mass, speed, direction = t_ball[0], t_ball[1], t_ball[2]
                    nx, ny = get_coords(i, j, direction, speed)
                    new_board[nx][ny].append((mass, speed, direction))
    return new_board


# 파이어볼을 모두 합치고 쪼갠다
def split_sum_ball(arr):
    for i in range(n):
        for j in range(n):
            if len(arr[i][j]) >= 2:
                # 같은 칸의 파이어볼은 모두 하나로 합쳐진다
                t_m, t_s = 0, 0
                even_chk, odd_chk = False, False
                for b in arr[i][j]:
                    t_m += b[0]
                    t_s += b[1]
                    if b[2] % 2 == 0:
                        even_chk = True
                    else:
                        odd_chk = True

                # 4개로 나누기
                t_mass = t_m // 5
                t_speed = t_s // len(arr[i][j])
                if even_chk and odd_chk:
                    arr[i][j] = [(t_mass, t_speed, 1), (t_mass, t_speed, 3), (t_mass, t_speed, 5), (t_mass, t_speed, 7)]
                else:
                    arr[i][j] = [(t_mass, t_speed, 0), (t_mass, t_speed, 2), (t_mass, t_speed, 4), (t_mass, t_speed, 6)]

            # 질량이 0 인 파이어볼은 소멸되어 없어진다
            del_t = []
            if arr[i][j]:
                for b in arr[i][j]:
                    if b[0] != 0:
                        del_t.append((b[0], b[1], b[2]))

                arr[i][j] = del_t

    return arr


if __name__ == '__main__':
    n, m, k = map(int, input().split())
    fireball = []
    for _ in range(m):
        fireball.append(list(map(int, input().split())))
    dir = [[7, 0, 1], [6, -1, 2], [5, 4, 3]]
    board = [[[] for _ in range(n)] for _ in range(n)]
    for ball in fireball:
        board[ball[0] - 1][ball[1] - 1].append((ball[2], ball[3], ball[4]))

    for _ in range(k):
        # 모든 파이어볼 이동
        board = move_fireball(board)

        # 2개 이상 파이어볼이 있는 칸의 변화
        board = split_sum_ball(board)

    ans = 0
    for i in range(n):
        for j in range(n):
           if board[i][j]:
               for b in board[i][j]:
                   ans += b[0]

    print(ans)