algorithm/Implementation

[백준20061/골드2] 모노미노도미노 2 - Python

ayeongjin 2025. 5. 21. 17:00

https://www.acmicpc.net/problem/20061

 

 

처음에 문제 이해가 안돼서 한참 다시 읽었다.

 

 

✅ 문제 조건

 

1. 빨간색 보드에 블록을 놓으면, 초록색 보드와 파란색 보드로 블록 이동

 

1-1. 초록색 보드

- 열 고정된 상태로 아래방향으로 블록 떨어짐
- 가로 줄이 모두 차면 제거, 위에 있는 블록은 아래로 이동
- 0, 1번 행 중 블록이 있으면, 가장 아래 행부터 차례로 한 줄씩 삭제, 비원진 만큼 위에서 밀어내림

 

1-2. 파란색 보드

- 행 고정된 상태로 오른쪽방향으로 블록 떨어짐
- 세로 줄이 모두 차면 제거, 왼쪽에 있는 블록은 오른쪽으로 이동
- 0, 1번 열 중 블록이 있으면, 가장 오른쪽 열부터 차례로 한 줄씩 삭제, 비워진 만큼 왼쪽에서 밀어내림

 

2. 주어진 사이클만큼 블록 이동후, 획득한 점수와 최종 보드 위의 블록 수 출력

 

 

✅ 접근 방식

일단 세가지 함수로 분리했다.

1. 매 사이클마다 블록 떨어뜨리는 함수

2. 블록이 각 행 또는 열마다 꽉 찼으면 해당 라인 삭제 후 점수 획득하는 함수

3. 연한칸의 (0, 1 열 또는 0, 1 행) 블록 유무 체크 후 라인 삭제하는 함수

 

💡 보드 배열 갱신

처음에는 보드의 라인을 정리하는 방법으로

new_arr = [line[:] for line in arr]

 

이런 깊은복사를 사용해서 새로운 배열을 생성하고 거기에 정리된 블록을 추가하려고 했다.

근데 구현하다보니 배열의 크기도 작고 참조가 끊어지지 않게 하고싶어서 pop, insert 방식으로 바꿨다.

 

 

 

✅ 구현

 

0. 입력 및 배열 초기화

N = int(input())

blue = [[0] * 6 for _ in range(4)]
green = [[0] * 4 for _ in range(6)]
score = 0

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

 

 

1. 매 사이클마다 블록 떨어뜨리는 함수

def drop_block(t, x, y):

    # 초록 보드
    if t == 1:
        r = 0
        while r+1 < 6 and green[r+1][y] == 0:
            r += 1
        green[r][y] = 1
    elif t == 2:
        r = 0
        while r+1 < 6 and green[r+1][y] == 0 and green[r+1][y+1] == 0:
            r += 1
        green[r][y] = 1
        green[r][y+1] = 1
    elif t == 3:
        r = 0
        while r+2 < 6 and green[r+2][y] == 0:
            r += 1
        green[r][y] = 1
        green[r+1][y] = 1

    # 파란 보드
    if t == 1:
        c = 0
        while c+1 < 6 and blue[x][c+1] == 0:
            c += 1
        blue[x][c] = 1
    elif t == 2:
        c = 0
        while c+2 < 6 and blue[x][c+2] == 0:
            c += 1
        blue[x][c] = 1
        blue[x][c+1] = 1
    elif t == 3:
        c = 0
        while c+1 < 6 and blue[x][c+1] == 0 and blue[x+1][c+1] == 0:
            c += 1
        blue[x][c] = 1
        blue[x+1][c] = 1

 

입력받은 t, x, y (블록 타입, 빨간 보드에 블록을 놓는 위치 x, y)를 파타미터로 바로 받아서

타입별로 블록을 밀면서 위치를 고정했다.

 

 

2. 블록이 각 행 또는 열마다 꽉 찼으면 해당 라인 삭제 후 점수 획득하는 함수

 

def check_line():
    global score

    # 초록
    while True:
        found = False
        for i in range(5, 1, -1):
            if all(green[i]):
                score += 1
                found = True
                for r in range(i, 0, -1):
                    green[r] = green[r - 1][:]
                green[0] = [0] * 4
                break
        if not found:
            break

    # 파랑
    while True:
        found = False
        for j in range(5, 1, -1):
            if all(blue[r][j] for r in range(4)):
                score += 1
                found = True
                for c in range(j, 0, -1):
                    for r in range(4):
                        blue[r][c] = blue[r][c - 1]
                for r in range(4):
                    blue[r][0] = 0
                break
        if not found:
            break

 

그리고 블록을 옮긴 후 꽉 찬 라인이 있는지 확인했다.

꽉 찬 라인이 있으면 다음 라인을 옮기면서 갱신했다.

초기 구현 결과, 이 과정에서 라인을 한번만 확인하고 다음을 계속 확인하지 않아서 틀렸다.

 

 

3. 연한칸의 (0, 1 열 또는 0, 1 행) 블록 유무 체크 후 라인 삭제하는 함수

 

def check_light():

    # 초록
    cnt = 0
    for i in [0, 1]:
        if any(green[i]):
            cnt += 1
    for _ in range(cnt):
        green.pop()
        green.insert(0, [0]*4)

    # 파랑
    cnt = 0
    for j in [0, 1]:
        if any(blue[i][j] for i in range(4)):
            cnt += 1
    for _ in range(cnt):
        for r in range(4):
            blue[r].pop()
            blue[r].insert(0, 0)

 

그리고 연한칸에 블록이 있을 경우 한번 더 맨 끝 라인을 삭제 후 블록을 밀어줬다.

 

 

✅ 정답 코드

'''
- 블록 타입 : 1*1, 1*2, 2*1
- 초록 보드
    - 열 고정된 상태로 아래방향으로 블록 떨어짐
    - 가로 줄이 모두 차면 제거, 위에 있는 블록은 아래로 이동
    - 0, 1번 행 중 블록이 있으면, 가장 아래 행부터 차례로 한 줄씩 삭제, 비원진 만큼 위에서 밀어내림
- 파란 보드
    - 행 고정된 상태로 오른쪽방향으로 블록 떨어짐
    - 세로 줄이 모두 차면 제거, 왼쪽에 있는 블록은 오른쪽으로 이동
    - 0, 1번 열 중 블록이 있으면, 가장 오른쪽 열부터 차례로 한 줄씩 삭제, 비워진 만큼 왼쪽에서 밀어내림
'''

N = int(input())

blue = [[0] * 6 for _ in range(4)]
green = [[0] * 4 for _ in range(6)]
score = 0


# 블록 떨어뜨리기
def drop_block(t, x, y):

    # 초록 보드
    if t == 1:
        r = 0
        while r+1 < 6 and green[r+1][y] == 0:
            r += 1
        green[r][y] = 1
    elif t == 2:
        r = 0
        while r+1 < 6 and green[r+1][y] == 0 and green[r+1][y+1] == 0:
            r += 1
        green[r][y] = 1
        green[r][y+1] = 1
    elif t == 3:
        r = 0
        while r+2 < 6 and green[r+2][y] == 0:
            r += 1
        green[r][y] = 1
        green[r+1][y] = 1

    # 파란 보드
    if t == 1:
        c = 0
        while c+1 < 6 and blue[x][c+1] == 0:
            c += 1
        blue[x][c] = 1
    elif t == 2:
        c = 0
        while c+2 < 6 and blue[x][c+2] == 0:
            c += 1
        blue[x][c] = 1
        blue[x][c+1] = 1
    elif t == 3:
        c = 0
        while c+1 < 6 and blue[x][c+1] == 0 and blue[x+1][c+1] == 0:
            c += 1
        blue[x][c] = 1
        blue[x+1][c] = 1


# 줄 제거 및 점수 계산
def check_line():
    global score

    # 초록
    while True:
        found = False
        for i in range(5, 1, -1):
            if all(green[i]):
                score += 1
                found = True
                for r in range(i, 0, -1):
                    green[r] = green[r - 1][:]
                green[0] = [0] * 4
                break
        if not found:
            break

    # 파랑
    while True:
        found = False
        for j in range(5, 1, -1):
            if all(blue[r][j] for r in range(4)):
                score += 1
                found = True
                for c in range(j, 0, -1):
                    for r in range(4):
                        blue[r][c] = blue[r][c - 1]
                for r in range(4):
                    blue[r][0] = 0
                break
        if not found:
            break


# 연한 칸 확인
def check_light():

    # 초록
    cnt = 0
    for i in [0, 1]:
        if any(green[i]):
            cnt += 1
    for _ in range(cnt):
        green.pop()
        green.insert(0, [0]*4)

    # 파랑
    cnt = 0
    for j in [0, 1]:
        if any(blue[i][j] for i in range(4)):
            cnt += 1
    for _ in range(cnt):
        for r in range(4):
            blue[r].pop()
            blue[r].insert(0, 0)


for _ in range(N):
    t, x, y = map(int, input().split())
    drop_block(t, x, y)
    check_line()
    check_light()

print(score)
print(sum(sum(line) for line in green) + sum(sum(line) for line in blue))

 

 

파이썬 아니었으면 못풀었을 거 같다..