(Python) 프로그래머스 17679. 프렌즈4블록

최권민·2023년 8월 17일
0

알고리즘 풀이

목록 보기
12/13
post-thumbnail

문제

프렌즈4블록
블라인드 공채를 통과한 신입 사원 라이언은 신규 게임 개발 업무를 맡게 되었다. 이번에 출시할 게임 제목은 "프렌즈4블록".
같은 모양의 카카오프렌즈 블록이 2×2 형태로 4개가 붙어있을 경우 사라지면서 점수를 얻는 게임이다.

만약 판이 위와 같이 주어질 경우, 라이언이 2×2로 배치된 7개 블록과 콘이 2×2로 배치된 4개 블록이 지워진다. 같은 블록은 여러 2×2에 포함될 수 있으며, 지워지는 조건에 만족하는 2×2 모양이 여러 개 있다면 한꺼번에 지워진다.

블록이 지워진 후에 위에 있는 블록이 아래로 떨어져 빈 공간을 채우게 된다.

만약 빈 공간을 채운 후에 다시 2×2 형태로 같은 모양의 블록이 모이면 다시 지워지고 떨어지고를 반복하게 된다.

위 초기 배치를 문자로 표시하면 아래와 같다.

TTTANT
RRFACC
RRRFCC
TRRRAA
TTMMMF
TMMTTJ

각 문자는 라이언(R), 무지(M), 어피치(A), 프로도(F), 네오(N), 튜브(T), 제이지(J), 콘(C)을 의미한다

입력으로 블록의 첫 배치가 주어졌을 때, 지워지는 블록은 모두 몇 개인지 판단하는 프로그램을 제작하라.
상세보기


  • 오랜만에 푸는 구현 및 시뮬레이션 문제
  • lv2지만, lv2 중에서는 난이도가 조금 있는 편
  • 요구사항을 파악하는 것은 쉬웠지만, 구현을 어떻게 할 지 고민을 많이 했음
  • 오랜만에 파이썬을 사용하니, 뭔가 생각의 폭도 그렇고 선택지도 그렇고 넓어진 느낌
def spin_list(rst):                 # 리스트 회전시키기
    tup = zip(*rst[::-1])           # zip으로 회전시킬 경우, tuple형태로 묶이기 때문에
    return [list(x) for x in tup]   # return하면서 list로 바꾸는 과정이 필요

def solution(m, n, board):          # m : x축, n : y축. 여기서는 회전시키므로 바꿔서 사용
    field = spin_list(board)
    answer = 0
    while True:
        flag = False
        visited = [[0]*m for _ in range(n)]     # 같은 블록이 여러 2x2에 포함될 수 있으므로 바로 변환하면 안됨 -> 변환할 좌표 리스트
        for i in range(n-1):
            for j in range(m-1):
                if field[i+1][j+1] != 0 and field[i][j] == field[i+1][j] == field[i][j+1] == field[i+1][j+1]:
                    # 4개가 같은 지 확인. 이것도 for문처리하고 싶었지만, 그러려면 for문이 4개가 더 필요해서 수작업
                    visited[i][j] = 1
                    visited[i+1][j] = 1
                    visited[i][j+1] = 1
                    visited[i+1][j+1] = 1
                    flag = True
        
        if not flag:                # 바뀐 게 없다면 : 아래의 과정이 필요가 없으니까 종료
            break
        
        for i in range(n):
            for j in range(m):
                if visited[i][j]:       # 바뀌었다면
                    field[i][j] = -1    # -1로 (일단) 바꿔주고
                    field[i].append(0)  # 뒤에 0을 집어넣음(리스트의 전체 길이 유지)
                    answer += 1

            field[i] = [x for x in field[i] if x != -1] # -1을 없애기
        

    return answer

문제 해설

  • 두 가지 과정을 반복하는 문제라고 생각했다.
    1. 리스트를 순회하며 지울 수 있는 블럭을 표시한다.
    2. 지운 후 정렬한다.
  • 1번과 같은 경우에는 큰 어려움이 없지만, 2번의 경우 위의 블록을 아래로 내리는 작업이 필요하기 때문에 번거로웠다.
    • 그래서, 그냥 리스트를 90도로 회전하면 y축 선에서 해결할 수 있지 않을까? 라는 생각이 들었고 spin_list를 통해 전체 리스트를 회전시켜 문제를 진행하였다.
  • for문이 너무 많이 사용된다는 생각도 들었는데, 조건이 명확한 구현 문제를 풀 때는 어쩔 수 없는 부분이 있다고 생각한다.
  • 중간에 4개가 같은 지 확인하는 부분도, for문을 쓰는 게 문제의 확장성을 생각하면 더 좋겠지만(조건이 3x3, 4x4가 될 수도 있으니까) 2중 for문이 두 개가 추가되는 게 마음에 들지 않아 이번 문제에는 수기로 해결하였다.

❗ 오답노트

  • 항상 x축과 y축을 헷갈리곤 한다... 일반적인 그래프와 프로그래밍 상 x, y는 다르니까.
  • 이번에는 다른 데는 다 잘해놓고, visited에만 x,y를 바꿔 적어서 index error가 발생했다.
    • 순서를 바꾸는 것으로 해결되었지만, 이런 지엽적인 실수는 디버깅이 조금 어렵긴 하다. 두 번째 예제를 기준으로 test를 진행하였는데, 두 번째 예제는 x와 y의 크기가 동일하여 티가 나질 않았다...
profile
하나의 궤적을 따라서

1개의 댓글

comment-user-thumbnail
2023년 8월 17일

즐겁게 읽었습니다. 유용한 정보 감사합니다.

답글 달기