Algorithm

[programmers] 1차 프렌즈4블록 python

[프로그래머스] [1차] 프렌즈4블록

문제

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

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

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

만약 빈 공간을 채운 후에 다시 2×2 형태로 같은 모양의 블록이 모이면 다시 지워지고 떨어지고를 반복하게 된다.
입력으로 블록의 첫 배치가 주어졌을 때, 지워지는 블록은 모두 몇 개인지 판단하는 프로그램을 제작하라.

풀이과정

솔직히 너무 긴 코드여서 풀이과정을 남기기도 좀 쪽팔리긴 하지만.. 스스로 해냈다는 것에 심취해서 그래도 남긴다..... 😶

다른 짧은 코드의 풀이는 프렌즈 4블록 - 2018 카카오 공채 (python) by tjdud0123 에서 참고하시면 좋을 것 같습니다 !!!!

문제에서 말하는 것을 모두 구현하는 것에 중점을 두었다.

  1. 2x2가 모두 같은 블럭인지 확인하기
    먼저 2x2가 모두 같은 블럭인 경우에는 지워야하기에 이 부분은 check함수로 구현했다. 시작점 x,y에서부터 2x2칸씩 돌면서 모두 같은 경우에는 True를 리턴하고, 아니면 False를 리턴하도록 하였다.

  2. 모두 같은 블럭이면 나중에 팝하기 위해 표시하기
    모두 같은 블럭인 경우에는 판에서 지워야하기에 표시를 하는 부분도 구현했다. 이 부분은 update 함수에 구현했는데, erase라는 set에 해당 자리의 인덱스 값을 추가했다.

  3. 2x2가 모두 같은 블럭을 없애기
    같은 블럭을 없애고, 위의 블럭들을 아래로 내려주기 위해 move라는 함수를 구현했다. move함수의 핵심은 행열변환인데, 보드의 블럭들은 위에서 아래로 내려와야하므로 행열변환을 한뒤 없애야하는 블럭을 pop하고, 그 리스트의 맨 앞에 0을 삽입하면서 내려오는 것과 같도록 하였다. 이후 다시 행열변환을 하여 원래 모양으로 돌린 뒤 리턴한다.

소스코드

소요 시간 44:01, ide 사용

def check(boardInfo, x, y):
    value = boardInfo[x][y][0]
    for i in range(x, x + 2):
        for j in range(y, y + 2):
            if value != boardInfo[i][j][0]:
                return False
    return True


def update(erase, boardInfo, x, y):
    for i in range(x, x + 2):
        for j in range(y, y + 2):
            boardInfo[i][j][1] = 1
            erase.add((i, j))


def move(m, n, boardInfo):
    t = []
    for i in range(n):
        t.append([j[i] for j in boardInfo])  # 행열 변환

    idx = []
    for i in range(n):
        for j in range(m):
            if t[i][j][1]:
                idx.append((i, j))

    while idx:
        x, y = idx.pop(0)
        t[x].pop(y)
        t[x].insert(0, [0,0])

    b = []
    for j in range(m):
        b.append([i[j] for i in t])

    return b


def solution(m, n, board):
    answer = 0
    boardInfo = []
    # board 초기화
    for i in range(m):
        temp = []
        for j in range(n):
            temp.append([board[i][j], 0])
        boardInfo.append(temp)

    erase = set()
    while True:
        flag = False
        for i in range(m):
            for j in range(n):
                if boardInfo[i][j][0] == 0:
                    continue
                if i == m-1 or j == n-1:
                    continue
                if check(boardInfo, i, j):  # 2x2가 모두 같으면
                    update(erase, boardInfo, i, j)
                    flag = True

        answer += len(erase)
        erase = set()
        if flag:
            # 행방향으로 돌면서 한칸씩 내려줌.
            boardInfo = move(m, n, boardInfo)
        else:
            break

    return answer