[백준 20061][python] 모노미노도미노 2

alllloha·2021년 10월 12일
0

문제 이해

모노미노도미노는 아래와 같이 생긴 보드에서 진행되는 게임이다. 보드는 빨간색 보드, 파란색 보드, 초록색 보드가 그림과 같이 붙어있는 형태이다. 게임에서 사용하는 좌표 (x, y)에서 x는 행, y는 열을 의미한다. 빨간색, 파란색, 초록색 보드가 사용하는 좌표는 그 색으로 그림에 적혀있다.

이 게임에서 사용하는 블록은 타일 하나 또는 두 개가 가로 또는 세로로 붙어있는 형태이다. 아래와 같이 세 종류가 있으며, 왼쪽부터 순서대로 크기가 1×1, 1×2, 2×1 이다.

  1. 블록을 놓을 위치를 빨간색 보드에서 선택하면, 그 위치부터 초록색 보드로 블록이 이동하고, 파란색 보드로 블록이 이동한다. 블록의 이동은 다른 블록을 만나거나 보드의 경계를 만나기 전까지 계속해서 이동한다.

  2. 초록색 보드에서 어떤 행이 타일로 가득 차 있다면, 그 행의 타일은 모두 사라진다. 사라진 이후에는 초록색 보드에서 사라진 행의 위에 있는 블록이 사라진 행의 수만큼 아래로 이동한다. 파란색의 경우는 열이 타일로 가득 차 있으면, 그 열의 타일이 모두 사라지며, 사라진 이후에는 파란색 보드에서 사라진 열의 왼쪽에 있는 블록이 사라진 열의 수만큼 오른쪽으로 이동한다. 이렇게 한 행이나 열이 타일로 가득 차서 사라지면 1점을 획득한다.

  3. 초록색 보드의 0, 1번 행과 파란색 보드의 0, 1번 열은 그림에는 연한색으로 표현되어 있는 특별한 칸이다. 초록색 보드의 0, 1번 행에 블록이 있으면, 블록이 있는 행의 수만큼 아래 행에 있는 타일이 사라지고, 초록색 보드의 모든 블록이 사라진 행의 수만큼 아래로 이동하고, 파란색 보드의 0, 1번 열에 블록이 있으면, 블록이 있는 열의 수만큼 오른쪽 열에 있는 타일이 사라지고, 파란색 보드의 모든 블록이 사라진 열의 수만큼 이동하게 된다. 위의 그림은 파란색 보드의 1번 열에 블록이 있기 때문에, 5번 열에 있는 블록이 모두 사라지고, 파란색 보드의 모든 블록이 오른쪽으로 한 칸 이동하게 된다.

  4. 행이나 열이 타일로 가득찬 경우와 연한 칸에 블록이 있는 경우가 동시에 발생할 수 있다. 이 경우에는 행이나 열이 타일로 가득 찬 경우가 없을 때까지 점수를 획득하는 과정이 모두 진행된 후, 연한 칸에 블록이 있는 경우를 처리해야 한다.

블록은 보드에 놓인 이후에 다른 블록과 합쳐지지 않는다. 블록을 놓은 위치가 순서대로 주어졌을 때, 얻은 점수와 초록색 보드와 파란색 보드에 타일이 있는 칸의 개수를 모두 구해보자.

입력

첫째 줄에 블록을 놓은 횟수 N(1 ≤ N ≤ 10,000)이 주어진다.

둘째 줄부터 N개의 줄에 블록을 놓은 정보가 한 줄에 하나씩 순서대로 주어지며, t x y와 같은 형태이다.

t = 1: 크기가 1×1인 블록을 (x, y)에 놓은 경우
t = 2: 크기가 1×2인 블록을 (x, y), (x, y+1)에 놓은 경우
t = 3: 크기가 2×1인 블록을 (x, y), (x+1, y)에 놓은 경우
블록이 차지하는 칸이 빨간색 칸의 경계를 넘어가는 경우는 입력으로 주어지지 않는다.

출력

첫째 줄에 블록을 모두 놓았을 때 얻은 점수를 출력한다.
둘째 줄에는 파란색 보드와 초록색 보드에서 타일이 들어있는 칸의 개수를 출력한다.

해결방법

  1. 주어진 위치에 블록을 놓는 move 함수를 만든다.
  2. 행 또는 열에 모든 블록이 있어 점수를 얻게되는 함수 remove를 만든다.
  3. 연한 부분에 블록이 있는 경우를 확인하고 아래 블록을 삭제하는 remove2 함수를 만든다.
  4. 남은 블록을 계산한다

코드

from copy import deepcopy

board = [[0]*10 for _ in range(4)]
for i in range(6):
    board.append([0,0,0,0])


#빨간색 칸에 놓인 블록이 이동하는 함수
def move(t, r, c):
    # t = 1: 크기가 1×1인 블록을 (x, y)에 놓은 경우
    if t == 1:
        #초록색으로 떨어지는 코드
        # 1을 더해도 좌표안에 들어가고, 다음 칸이 0이라면
        x, y = r, c
        while x + 1 < 10 and board[x+1][y] == 0:
            x += 1
        board[x][y] = 1

        #좌표 초기화
        x, y = r, c
        #파란색으로 떨어지는 코드
        while y + 1 < 10 and board[x][y+1] == 0:
            y += 1
        board[x][y] = 1

    # t = 2: 크기가 1×2인 블록을 (x, y), (x, y+1)에 놓은 경우
    if t == 2:
        x, y = r, c
        #초록색으로 떨어지는 코드
        while x + 1 < 10 and board[x+1][y] == 0 and board[x+1][y+1] == 0:
            x += 1
        board[x][y] = 1
        board[x][y+1] = 1

        x, y = r, c
        #파란색으로 떨어지는 코드
        while y + 2 < 10 and board[x][y+1] == 0 and board[x][y+2] == 0:
            y += 1
        board[x][y] = 1
        board[x][y+1] = 1

    #t = 3: 크기가 2×1인 블록을 (x, y), (x+1, y)에 놓은 경우
    if t == 3:
        x, y = r, c
        #초록색으로 떨어지는 코드
        while x + 2 < 10 and board[x+1][y] == 0 and board[x+2][y] == 0:
            x += 1
        board[x+1][y] = 1
        board[x][y] = 1

        x, y = r, c
        #파란색으로 떨어지는 코드
        while y + 1 < 10 and board[x][y+1] == 0 and board[x+1][y+1] == 0:
            y += 1
        board[x][y] = 1
        board[x+1][y] = 1

#행, 열이 차면 삭제하는 함수
def remove():
    score = 0
    #초록색 부분 확인
    for i in range(6, 10):
        green_cnt = 0
        for j in range(0, 4):
            if board[i][j] == 1:
                green_cnt += 1
        if green_cnt == 4:
            score += 1
            board[i] = [0, 0, 0, 0]

    #위에 있는 블록들 내리기
    for k in range(9, 3, -1):

        temp = k
        while temp+1 < 10 and board[temp+1] == [0, 0, 0, 0] :
            temp += 1
        
        #이동할 공간이 남아있었다면
        if temp != k:
            #위에 있는 행을 아래로 복사
            board[temp] = board[k]
            #위에 있는 행은 초기화
            board[k] = [0, 0, 0, 0]
    
    #파란색 부분 확인
    for i in range(6, 10):
        blue_cnt = 0
        for j in range(0, 4):
            if board[j][i] == 1:
                blue_cnt += 1
        if blue_cnt == 4:
            score += 1
            for k in range(4):
                board[k][i] = 0
    
    #왼쪽에 있는 블록들 오른쪽으로 넘기기
    for k in range(9, 3, -1):
        temp = k
        while temp + 1 < 10:
            #각 열 마다 0의 수를 확인하는 check 변수 생성
            check = 0
            for c in range(4):
                if board[c][temp+1] == 0:
                    check += 1
            #print(k, temp, check)
            #만일 모든 열이 비어있다면
            if check == 4:
                #다음 열로 이동한다
                temp += 1
            #열이 비어있지 않다면
            else:
                break
        if temp != k:
            #열을 이동시킨다
            #print(k, "->", temp)
            for c in range(4):
                board[c][temp] = board[c][k]
                board[c][k] = 0
    return score

#연한색 구간의 칸만큼 삭제하는 함수
def remove2():
    #초록 연한 구간 확인
    cnt = 0
    for i in range(4, 6):
        if board[i] != [0, 0, 0, 0]:
            cnt += 1
    
    #연한 구간 행의 수 만큼 아래 삭제
    for c in range(cnt):
        for k in range(9, 4, -1):
            board[k] = board[k-1]
    
    #위에 새롭게 0을 추가해야함
    for c in range(1, cnt+1):
        board[3+c] = [0, 0, 0, 0]

    #파란 연한 구간 확인
    cnt = 0
    for i in range(4, 6):
        chk = 0
        for c in range(4):
            if board[c][i] == 0:
                chk += 1
        if chk != 4:
            cnt += 1
    
    #연한 구간 열의 수 만큼 오른쪽 삭제
    for c in range(cnt):
        for k in range(9, 4, -1):
            for j in range(4):
                board[j][k] = board[j][k-1]
    
    #왼쪽에 새롭게 0을 추가해야함
    for c in range(1, cnt+1):
        for j in range(4):
            board[j][3+c] = 0


answer = 0
n = int(input())
for _ in range(n):
    t, x, y = map(int, input().split())

    move(t, x, y)
    # print("move")
    # for b in board:
    #     print(b)
    # print("")

    answer += remove()
    # print("remove1")
    # for b in board:
    #     print(b)
    # print("")

    remove2()
    # print("remove2")
    # for b in board:
    #     print(b)
    # print("")

    # for b in board:
    #     print(b)
    # print("")

print(answer)

count = 0
for i in range(4):
    for j in range(10):
        if board[i][j]:
            count += 1
for i in range(6, 10):
    for j in range(4):
        if board[i][j]:
            count += 1
print(count)

유의할 점

연한 칸의 블록을 삭제하고 연한 칸은 0으로 초기화해줘야 한다. 이 부분에서 실수가 있었다.

0개의 댓글