Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

개발 블로그

[Programmers/파이썬]프로그래머스(Lv.2) 프렌즈4블록 문제풀이 본문

Algorithm

[Programmers/파이썬]프로그래머스(Lv.2) 프렌즈4블록 문제풀이

토산인 2023. 3. 3. 00:26

프렌즈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)을 의미한다

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

입력 형식

  • 입력으로 판의 높이 m, 폭 n과 판의 배치 정보 board가 들어온다.
  • 2 ≦ n, m ≦ 30
  • board는 길이 n인 문자열 m개의 배열로 주어진다. 블록을 나타내는 문자는 대문자 A에서 Z가 사용된다.

출력 형식

입력으로 주어진 판 정보를 가지고 몇 개의 블록이 지워질지 출력하라.

입출력 예제

mnboardanswer

4 5 ["CCBDE", "AAADE", "AAABF", "CCBBF"] 14
6 6 ["TTTANT", "RRFACC", "RRRFCC", "TRRRAA", "TTMMMF", "TMMTTJ"] 1

 


사고 흐름

처음에는 dfs나 bfs로 풀려고 했다. 그런데 2*2 블록 형식을 맞추기가 어려웠고 어떻게 해야할지 고민했다

-> 그러다 n과 m의 범위가 30이하라서 배열 크기가 크지 않다고 생각해 그냥 하나씩 돌며 확인해야겠다고 생각

-> for문으로 각 원소를 돌며 만약 2*2 블록 안이 다 같으면 check리스트에서 0으로 표시한다 (터졌다는 뜻)

-> 그리고 0으로 터진 부분들을 재정렬해줘야 하는데 이 부분이 어려웠다.

-> 새로운 board를 만들어 터진부분(0)은 위에있는 블럭을 가져오는 식으로 만들었다. 

-> 그리고 그 과정을 반복하며 더이상 터지지못할때까지 진행한다

 

문제 핵심과 알고리즘

문제에 주어진 조건으로 구현하는 문제.

def solution(m, n, board):
    answer = 0
    
    while True :
        origin=block(m,n,board)
        new=block(m,n,origin)
        if origin==new :
            break
        board=new
    
    for i in new :
        answer+=i.count('')

    return answer

def block(m, n, board) :
    check=[[1 for j in range(n)] for i in range(m)] #터지는 블록 0으로 표시
    new_board=[["" for j in range(n)] for i in range(m)]	#재정렬할 새로운 board
    
    for x in range(m-1) :
        for y in range(n-1) :
            target=board[x][y] #타겟이 될 현재 위치의 캐릭터
            if board[x+1][y]==target and board[x][y+1]==target and board[x+1][y+1]==target :
                check[x][y],check[x+1][y],check[x][y+1],check[x+1][y+1]=0,0,0,0
                #2*2 블럭이 다 동일하면 0으로 표시

	#board를 돌며
    #0인 부분(터질부분)은 위에있는 원소를 가져오고, 
    #1인 부분은 그대로 board 원소를 가져온다
    for i in range(n-1, -1, -1) :
        for j in range(m-1, -1, -1) :
            if check[j][i]==0 :
                temp=j
                while check[temp][i]==0 and temp>=0:
                    temp-=1
                if temp>=0 :
                    new_board[j][i]=board[temp][i]
                    check[temp][i]=0
            else :
                new_board[j][i]=board[j][i]
                
    return new_board

문제 풀면서 헤맸던 부분

1. 터진 부분을 재정렬하는 부분

  터진 후 배열을 재정렬할때가 어려웠다. 이 방법 저 방법 시도한 뒤, 그냥 완전 새로운 배열을 만들었다. 

 

다른 사람 풀이 참고하여 배운 점

세부적인 구현 방법은 다르지만 다들 비슷하게 2*2블럭이 있으면 check하고 그 부분에서 재정렬했다. 

 

총평

풀 때는 어떻게 풀어야 할지 조금 막막했는데, 지금 와서 보니 별거 아니다. 재정렬하는 부분을 대수롭지 않게 생각했는데 그 부분을 생각하는게 제일 오래걸렸다. 뭐든 코드를 짜기전 설계하는 단계를 소홀히 하지말자..