[BOJ 20061] 모노미노도미노 2(Python)

박현우·2021년 6월 24일
0

BOJ

목록 보기
82/87

문제

모노미노도미노 2


문제 해설


위와 같은 보드가 있고, 빨간색 필드에 3가지의 도형 중 하나 (1X1, 2X1, 1X2)를 넣어 초록, 파랑칸의 끝까지 밀어넣고 모두 도형으로 채워진 행,열이 존재하면 지우며 점수를 얻는 문제입니다.

저는 총 5개의 메소드를 만들어 활용했습니다. 딕셔너리에 green, blue 리스트를 넣어줘서 코드의 재사용성을 높였습니다.

1. draw
빨간색 필드에 도형을 그려넣는 메소드입니다. 저는 주어진 보드를 다음과 같이 바꾸었습니다.

이렇게 보드를 새로 만들면 나중에 있을 행 삭제에 편할 것 같기 때문에 바꿨습니다.
다만, blue 보드는 green에 그려진 것과 달리 좌표를 재설정 해야합니다.
blue 보드는 green보드의 반시계 방향으로 90도 회전한 것과 같습니다.

2. set_pos
각 보드에서 첫 좌표를 찾습니다. t가 2 혹은 3인 경우, 첫 좌표를 기준으로 가로 혹은 세로로 한칸씩 길어지기 때문입니다.

3. move
도형을 각 보드 끝까지 밀어넣습니다. 도중에 벽 혹은 다른 도형과 부딪히면 그 전 좌표에 도형을 넣고 빨간색 필드에서 삭제합니다.
t = 2, 3인 경우 green과 blue는 서로 반대의 도형을 가집니다.

4. remove
green, blue 필드에서 도형으로 가득찬 행이 있으면 삭제합니다. 삭제하고 answer의 값을 올려줍니다.
del을 사용해 가득찬 행을 지우고 연한 칸의 시작인 4번 인덱스에 0으로만 이루어진 리스트를 추가하는 방식을 사용했습니다.

5. soft_remove
각 필드의 연한 칸을 검사하는 메소드입니다. 만약 연한 필드에 도형이 존재하면 존재하는 행의 수만큼(최대 2) 해당 필드의 마지막 행을 제거합니다. 제거한 뒤 연한 칸의 시작인 4번 인덱스에 똑같이 0으로 이루어진 리스트를 추가합니다.


풀이 코드

import sys

input = sys.stdin.readline
green = [[0] * 4 for _ in range(10)]
blue = [[0] * 4 for _ in range(10)]
d = {0: green, 1: blue}
answer = 0
# green, blue에 도형 그리기
def draw(t, x, y):
    bx, by = y, 3 - x
    if t == 1:
        green[x][y] = 1
        blue[bx][by] = 1
    elif t == 2:
        green[x][y], green[x][y + 1] = 1, 1
        blue[bx][by], blue[bx + 1][by] = 1, 1
    else:
        green[x][y], green[x + 1][y] = 1, 1
        blue[bx][by], blue[bx][by - 1] = 1, 1


# green, blue 좌표 찾기
def set_pos(color):
    for i in range(4):
        for j in range(4):
            if d[color][i][j] == 1:
                return (i, j)


def move(t, x, y, color):
    if t == 1:
        for i in range(4, 10):
            if d[color][i][y] == 1:
                d[color][i - 1][y] = 1
                d[color][x][y] = 0
                return
        # 마지막까지 도형이 없을 경우 마지막에 넣어
        d[color][9][y] = 1
        d[color][x][y] = 0
    # 가로
    elif t == 2:
        for i in range(4, 10):
            if d[color][i][y] == 1 or d[color][i][y + 1] == 1:
                d[color][i - 1][y], d[color][i - 1][y + 1] = 1, 1
                d[color][x][y], d[color][x][y + 1] = 0, 0
                return
        d[color][9][y], d[color][9][y + 1] = 1, 1
        d[color][x][y], d[color][x][y + 1] = 0, 0
    # 세로
    else:
        for i in range(4, 10):
            if d[color][i][y] == 1:
                d[color][i - 1][y], d[color][i - 2][y] = 1, 1
                d[color][x][y], d[color][x + 1][y] = 0, 0
                return
        d[color][9][y], d[color][8][y] = 1, 1
        d[color][x][y], d[color][x + 1][y] = 0, 0


# 행삭제, 모두 1인 행이 있으면 삭제한다.
def remove(color):
    global answer
    row = []
    for i in range(9, 5, -1):
        cnt = 0
        for j in range(4):
            if d[color][i][j] == 1:
                cnt += 1
        # 행이 모두 1인 경우
        if cnt == 4:
            answer += 1
            row.append(i)
    for r in row:
        del d[color][r]
    for _ in range(len(row)):
        d[color].insert(4, [0, 0, 0, 0])


def soft_remove(color):
    cnt = 0
    for i in range(2):
        for j in range(4):
            # 연한 칸에 블록이 존재
            if d[color][4 + i][j] == 1:
                cnt += 1
                break
    # 존재하는 만큼 끝에있는 리스트 제거
    for i in range(cnt):
        d[color].pop()
        d[color].insert(4, [0, 0, 0, 0])


for _ in range(int(input())):
    t, x, y = map(int, input().split())
    draw(t, x, y)  # 1. 각 board에 도형을 그린다.
    gx, gy = set_pos(0)  # 2. 각 board의 시작점을 담는다.
    bx, by = set_pos(1)
    # 3. board에 그려진 도형을 움직인다.
    move(t, gx, gy, 0)
    # 단, green의 t2는 blue의 t3와 같으므로 처리해준다.
    move(5 - t, bx, by, 1) if t == 2 or t == 3 else move(t, bx, by, 1)
    # 4. 모두 도형이 있는 행을 찾아 제거한다.
    remove(0)
    remove(1)
    # 5. 연한 칸에 도형이 있는지 확인하고 지운다.
    soft_remove(0)
    soft_remove(1)
print(answer)
cnt = 0
for i in range(4):
    for j in range(4):
        if green[i + 6][j] == 1:
            cnt += 1
        if blue[i + 6][j] == 1:
            cnt += 1
print(cnt)

0개의 댓글