[코테]프로그래머스 - 기둥과 보 설치

프로그래머스 lv3_기둥과 보 설치 [2020 KAKAO BLIND RECUITEMENT 기출]

생각보다 하드 코딩하는 부분이 많았다.

완전 하드하게 짰을 때 고치는 과정에서 애먹어서 함수형태로 조금 리팩토링하였고,

그래도 테스트 케이스 반 정도가 오답이어서 질문하기를 참고했다.

가장 많이 도움 된 답변( https://programmers.co.kr/questions/15598 )을 보고 알 수 있었다.

내가 is_available_remove_row(y, x) 에서 row에 의존하는 기둥과 보의 존재를 조건을 주지않고 무조건 설치가 가능한지 체크를 했기 때문에 에러가 난 것.

해당 row를 지웠을 때 연관된 좌표들을 모두 설치가 가능하냐는 조건을 돌렸기에, 실제 map_ 에는 연관이 없는 지점이어도 설치가 가능한지 체크해버리기 때문에 False로 빠져나가는 경우가 꽤 있었던 것으로 보인다.

# 해답 확인..

# build_frame = [[x,y,a(기둥 보 여부),b(설치는 1, 삭제는 0)]... ]
def solution(n, build_frame):
    answer = []
    # 기둥은 1, 보는 2, 둘 다 설치 시 3으로 표현
    map_ = [[0 for __ in range(n+4)] for _ in range(n+4)]

    # 기둥 설치 가능한지
    def is_available_install_column(ny,nx):
        return ny == 2 or map_[ny-1][nx] in (1,3) or map_[ny][nx-1] in (2,3) or map_[ny][nx] in (2,3)

    def is_available_install_row(ny, nx):
        # 설치하고자 하는 좌표 밑에 기둥이 있을 때
        if map_[ny-1][nx] in (1,3):
            return True
        # 설치하고자 하는 좌표 오른쪽 밑에 기둥이 있을 때
        elif map_[ny-1][nx+1] in (1,3):
            return True
        # 양 옆에 보가 있을 때
        elif map_[ny][nx-1] in (2,3) and map_[ny][nx+1] in (2,3):
            return True
        else:
            return False

    def is_available_remove_column(ny, nx):
        # 기둥 윗부분(y+1, x)에 기둥이 있다면 그 부분에 대한 설치 조건을 체크한다.
        if map_[ny+1][x] in (1, 3):
            if not is_available_install_column(ny+1, nx):
                return False

        # 기둥 윗부분(y+1, x)에 보가 설치 되어 있다면 ..
        if map_[ny+1][x] in (2,3):
            if not is_available_install_row(ny+1, x):
                return False

        # 기둥 윗부분(y+1, x)에 보가 걸쳐 있다면((y+1, x-1)에 설치)
        if map_[ny+1][x-1] in (2,3):
            if not is_available_install_row(ny+1, x-1):
                return False

        return True

    def is_available_remove_row(ny, nx):
        # 보의 시작점(y, x)과 오른쪽에 (y, x+1) 대한 설치 조건 체크
        # 시작점에 대해서는 기둥은 체크 안해도 될 듯

        # 보를 지운 위치의 기둥 확인
        if map_[ny][nx] in (1,3):
            if not is_available_install_column(ny, nx):
                return False
        # 보를 지운 위치의 오른쪽 기둥 확인
        if map_[ny][nx+1] in (1,3):
            if not is_available_install_column(ny, nx+1):
                return False
        # 보를 지운 위치의 왼쪽 보 확인
        if map_[ny][nx-1] in (2,3):
            if not is_available_install_row(ny, nx-1):
                return False
        # 보를 지운 위치의 오른쪽 보 확인
        if map_[ny][nx+1] in (2,3):
            if not is_available_install_row(ny, nx+1):
                return False

        return True

    # 기둥은 0, 보는 1로 나타냄
    for condition in build_frame:
        x,y,a,b = condition
        y += 2
        x += 2

        ''' 아웃 오브 인덱스 에러 처리는 이후에 생각하자 '''

        # 설치의 경우
        if b == 1:
            # 기둥 설치 시 설치하고자 하는 좌표 (y, x) 기준으로,
            if a == 0:
                # (y-1, x)에 기둥이 설치되어 있거나, (y, x-1) or (y, x)에 보가 설치되어 있어야 한다.
                # (아니면 땅이거나 (y == 0))
                if is_available_install_column(y,x):
                    map_[y][x] += 1
                    answer.append([x-2,y-2,a])

            # 보 설치 시 설치하고자 하는 좌표 (y, x) 기준으로,
            elif a == 1:
                # (y-1, x) or (y-1, x+1)에 기둥이 설치되어 있거나, (y, x-1) and (y, x+1)에 보가 설치되어 있어야 한다.
                if is_available_install_row(y,x):
                    map_[y][x] += 2
                    answer.append([x-2,y-2,a])

        # 삭제의 경우
        if b == 0:
            if [x-2,y-2,a] not in answer:
                continue

            # 기둥 삭제 시 (y, x)
            if a == 0:
                # 우선 삭제해본다.
                map_[y][x] -= 1

                # 기둥 윗부분(y+1, x)에 기둥이 있다면 그 부분에 대한 설치 조건을 체크한다.
                if is_available_remove_column(y,x):
                    answer.remove([x-2,y-2,a])

                # 만약 설치 조건에 어긋난다면, 삭제를 시행하지 않음 #
                else:
                    map_[y][x] += 1

            # 보 삭제 시 (y, x)
            if a == 1:
                map_[y][x] -= 2

                # 보의 시작점(y, x)과 오른쪽에 (y, x+1) 대한 설치 조건 체크
                # 시작점에 대해서는 기둥은 체크 안해도 될 듯
                if is_available_remove_row(y,x):
                    answer.remove([x-2,y-2,a])
                else:
                    # 설치 조건에 어긋나면, 삭제 시행하지 않음
                    map_[y][x] += 2

    answer.sort(key=lambda k:(k[0], k[1], k[2]))

    return answer