본문 바로가기
Algorithm(BOJ, Python)/Simulation

[백준_14503] 로봇청소기 python

by kurooru 2022. 8. 28.

확실히 시뮬레이션 문제를 풀 때에는,

여러 조건들을 함수화하여 체크하는 것이 좋은 것 같다.

# n, m 입력
n, m = map(int, input().split())

# r, c, d입력
r, c ,d = map(int, input().split())

# room 입력
room = [
    list(map(int, input().split()))
    for _ in range(n)
]

# 함수들
# all_cleaned_or_wall(x, y):
def all_cleaned_or_wall(x, y):
    dxs, dys = [-1, 1, 0, 0], [0, 0, 1, -1]
    for dx, dy in zip(dxs, dys):
        # 주변 위치
        nx, ny = x + dx, y + dy
        # 청소안되어있는 빈칸이 나오면,
        if not room[nx][ny] and not cleaned_area[nx][ny]:
            # 실패
            return False
    # 다 돌았는데 그런 칸이 안나오면 성공
    return True

# back_is_wall(x, y, dir)
def back_is_wall(x, y, dir):
    # dxs dys 북 동 남 서 순
    dxs, dys = [-1, 0, 1, 0], [0, 1, 0, -1]
    # 뒷 방향
    back_dir = (dir + 2) % 4
    # 뒷 좌표
    bx, by = x + dxs[back_dir], y + dys[back_dir]
    # 뒷 좌표가 벽이면,
    if room[bx][by]:
        # 성공
        return True
    # 아니면 실패
    return False

# step_back(x, y, dir)
def step_back(x, y, dir):

    # 전역 변수 선언
    global r, c
    
    # dxs dys 북 동 남 서 순
    dxs, dys = [-1, 0, 1, 0], [0, 1, 0, -1]
    # 뒷 방향
    back_dir = (dir + 2) % 4
    # 뒷 좌표
    bx, by = x + dxs[back_dir], y + dys[back_dir]

    # 좌표 바꿔주기
    r, c = bx, by

# left_is_wall(x, y, dir)
def left_is_wall(x, y, dir):
    
    # dxs dys 북 동 남 서 순
    dxs, dys = [-1, 0, 1, 0], [0, 1, 0, -1]
    # 왼쪽 방향
    left_dir = (dir - 1 + 4) % 4
    # 왼쪽 좌표
    ls, ly = x + dxs[left_dir], y + dys[left_dir]

    # 왼쪽 칸이 벽이면,
    if room[ls][ly]:
        # 성공
        return True
    # 아니면 실패
    return False

# left_is_dirty(x, y, dir)
def left_is_dirty(x, y, dir):
    # dxs dys 북 동 남 서 순
    dxs, dys = [-1, 0, 1, 0], [0, 1, 0, -1]
    # 왼쪽 방향
    left_dir = (dir - 1 + 4) % 4
    # 왼쪽 좌표
    ls, ly = x + dxs[left_dir], y + dys[left_dir]

    # 왼쪽 칸이 청소 안됐으면
    if not cleaned_area[ls][ly]:
        # 성공
        return True
    # 아니면 실패
    return False

# turn_left(dir)
def turn_left(dir):

    # 전역 변수 선언
    global d

    # dxs dys 북 동 남 서 순
    dxs, dys = [-1, 0, 1, 0], [0, 1, 0, -1]
    # 왼쪽 방향
    left_dir = (dir - 1 + 4) % 4

    # 방향 바꿔주기
    d = left_dir

# move_ahead(x, y, dir):
def move_ahead(x, y, dir):

    # 전역 변수 선언
    global r, c

    # dxs dys 북 동 남 서 순
    dxs, dys = [-1, 0, 1, 0], [0, 1, 0, -1]

    # 다음 위치
    nx, ny = x + dxs[dir], y + dys[dir]

    # 옮겨주기
    r, c = nx, ny

# 설계
# cleaned_area
cleaned_area = [
    [0] * m
    for _ in range(n)
]

# 청소기 시작 위치 청소
cleaned_area[r][c] = 1
while True:
    # 네 방향 모두 청소 되어있거나 벽이면서,
    # 뒤쪽 방향이 벽이라 후진 할 수 없는 경우
    if all_cleaned_or_wall(r, c) and back_is_wall(r, c, d):
        # 청소 끝남
        break

    # 네 방향 모두 청소 되어있거나 벽이지만,
    # 뒤쪽 방향이 갈 수 있으면,
    elif all_cleaned_or_wall(r, c) and not back_is_wall(r, c, d):
        # 한 칸 후진
        step_back(r, c, d)
    
    # 왼쪽 방향이 벽이 아니고,
    # 아직 청소하지 않은 공간이 존재한다면,
    elif not left_is_wall(r, c, d) and left_is_dirty(r, c, d):
        # 왼쪽으로 회전한 다음,
        turn_left(d)
        # 한 칸 전진하고,
        move_ahead(r, c, d)
        # 현재 위치 청소
        cleaned_area[r][c] = 1
    
    # 욎쪽 방향이 벽이거나,
    # 이미 청소된 구역이라면
    elif left_is_wall(r, c, d) or not left_is_dirty(r, c, d):
        # 왼쪽으로 회전
        turn_left(d)

# 정답용
area = 0

# 청소된 구역을 돌면서
for i in range(n):
    for j in range(m):
        # 답을 더해줌
        area += cleaned_area[i][j]

# 출력
print(area)