[백준] 3019번 테트리스 - Python / 알고리즘 중급 2/3 - 브루트 포스 - 문제

ByungJik_Oh·2025년 7월 24일
0

[Baekjoon Online Judge]

목록 보기
213/244
post-thumbnail



💡 문제

테트리스는 C열 필드위에서 플레이하는 유명한 게임이다. 필드의 행의 수는 무한하다. 한 번 움직일 때, 아래와 같은 일곱가지 블록 중 하나를 필드에 떨어뜨릴 수 있다.

블록을 떨어뜨리기 전에, 플레이어는 블록을 90, 180, 270도 회전시키거나 좌우로 움직일 수 있다. 이때, 블록이 필드를 벗어나지 않으면 된다. 블록을 필드의 바닥이나 이미 채워져있는 칸의 위에 놓여지게 된다.

창영이가 하고있는 테트리스는 일반적인 테트리스와 약간 규칙이 다르다. 블록이 떨어졌을 때, 블록과 블록 또는 블록과 바닥 사이에 채워져있지 않은 칸이 생기면 안 된다.

예를 들어, 아래와 같이 각 칸의 높이가 2, 1, 1, 1, 0, 1인 경우를 생각해보자. 블록 5번을 떨어뜨리는 방법의 수는 아래와 같이 다섯가지이다.

테트리스 필드의 각 칸의 높이와 떨어뜨려야 하는 블록의 번호가 주어진다. 이때, 블록을 놓는 서로 다른 방법의 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 C와 떨어뜨리는 블록의 번호 P가 주어진다. (1 ≤ C ≤ 100, 1 ≤ P ≤ 7)

둘째 줄에는 각 칸의 높이가 주어진다. 높이는 0보다 크거나 같고, 100보다 작거나 같은 자연수이다.

출력

첫째 줄에 블록을 떨어뜨리는 방법의 수를 출력한다.


💭 접근

블록과 블록, 블록과 바닥 사이에 빈칸이 존재해선 안되므로 입력으로 주어진 테트리스 필드 상태에 따라 블록을 놓아야 한다. 블록마다 모양이 다르므로 모양에 따라 맞춰 이해해보자.

  • 1번 블록
    1번 블록의 경우 아래와 같이 세워져 있는 경우 모든 칸에 놓을 수 있고, 가로로 누워 있는 경우 연속하는 4칸이 높이가 같아야 놓을 수 있다.
if p == 1:
    ans += c # 1번 블럭은 세로로 세웠을 때 모든 칸에 놓을 수 있음
    if c >= 4: # 1번 블럭이 가로일 때 연속한 4칸의 높이가 같아야 놓을 수 있음
        for i in range(c - 3):
            if blocks[i] == blocks[i + 1] and blocks[i + 1] == blocks[i + 2] and blocks[i + 2] == blocks[i + 3]:
                ans += 1
  • 2번 블록
    2번 블록의 경우 블록을 회전시키더라도 모양은 같기 때문에 연속하는 2칸의 높이만 같으면 놓을 수 있다.
elif p == 2:
    if c >= 2: # 2번 블럭은 연속한 2칸의 높이가 같아야 놓을 수 있음
        for i in range(c - 1):
            if blocks[i] == blocks[i + 1]:
                ans += 1
  • 3번 블록
    3번 블록의 경우 세로로 세워져 있을 땐 첫번째 칸이 두번째 칸보다 한칸 높아야 높을 수 있으며, 가로로 누워 있는 경우 세번째 칸이 첫번째, 두번째 칸보다 한칸 높아야 놓을 수 있다.
elif p == 3:
    if c >= 3: # 3번 블럭이 가로일 때 1번칸, 2번칸은 같고 3번칸은 1번칸, 2번칸보다 한칸 높아야 놓을 수 있음
        for i in range(c - 2):
            if blocks[i] == blocks[i + 1] and blocks[i] == blocks[i + 2] - 1:
                ans += 1
    if c >= 2: # 3번 블럭이 세로일 때 1번칸이 2번칸보다 한칸 높아야 놓을 수 있음
        for i in range(c - 1):
            if blocks[i] == blocks[i + 1] + 1:
                ans += 1
  • 4번 블록
    4번 블록은 3번 블록의 반대 모양으로, 3번 블록을 그대로 뒤집은 것과 같다.
elif p == 4:
    if c >= 3: # 4번 블럭이 가로일 때 1번칸이 2번칸, 3번칸보다 한칸 높아야 놓을 수 있음
        for i in range(c - 2):
            if blocks[i] == blocks[i + 1] + 1 and blocks[i] == blocks[i + 2] + 1:
                ans += 1
    if c >= 2: # 4번 블럭이 세로일 때 1번칸이 2번칸보다 한칸 낮아야 놓을 수 있음
        for i in range(c - 1):
            if blocks[i] == blocks[i + 1] - 1:
                ans += 1
  • 5번 블록
    5번 블록은 총 4가지의 경우가 있다. 가로로 누워 있는 경우 연속하는 3개의 칸의 높이가 같을 때, 또는 두번째 칸이 첫번째, 세번째 칸보다 한칸 낮을 때 놓을 수 있다. 세로로 세워진 경우엔 첫번째 칸이 두번째 칸보다 한칸 높거나 낮을 때 두 경우 모두 놓을 수 있다.
elif p == 5:
    if c >= 3: 
        for i in range(c - 2): 
            if blocks[i] == blocks[i + 1] and blocks[i + 1] == blocks[i + 2]:
                ans += 1 # 5번 블럭이 가로일 때 연속하는 3칸의 높이가 같아야 놓을 수 있음
            if blocks[i + 1] == blocks[i] - 1 and blocks[i + 1] == blocks[i + 2] - 1:
                ans += 1 # 5번 블럭이 가로일 때 1번칸, 3번칸이 2번칸보다 한칸 높아야 놓을 수 있음
    if c >= 2:
        for i in range(c - 1): 
            if blocks[i] == blocks[i + 1] + 1:
                ans += 1 # 5번 블럭이 세로일 때 1번칸이 2번칸보다 높아야 놓을 수 있음
            if blocks[i] == blocks[i + 1] - 1:
                ans += 1 # 5번 블럭이 세로일 때 1번칸이 2번칸보다 놓아야 놓을 수 있음 
  • 6번 블록
    6번 블록은 가로로 누워져 있을 땐 연속하는 3칸의 높이가 모두 같을 때, 또는 찻번째 칸이 두번째, 세번째 칸보다 한칸 낮을 때 놓을 수 있다. 세로로 세워져 있는 경우 연속하는 두칸의 높이가 같을 때, 또는 첫번째 칸이 두번째 칸보다 두칸 높을 때 놓을 수 있다.
elif p == 6:
    if c >= 3: 
        for i in range(c - 2): 
            if blocks[i] == blocks[i + 1] and blocks[i + 1] == blocks[i + 2]:
                ans += 1 # 6번 블럭이 가로일 때 연속하는 3칸의 높이가 같아야 놓을 수 있음
            if blocks[i] == blocks[i + 1] - 1 and blocks[i] == blocks[i + 2] - 1:
                ans += 1 # 6번 블럭이 가로일 때 1번칸이 2번칸, 3번칸보다 한칸 낮아야 놓을 수 있음
    if c >= 2:
        for i in range(c - 1):
            if blocks[i] == blocks[i + 1]:
                ans += 1 # 6번 블럭이 세로일 때 연속하는 2칸의 높이가 같아야 놓을 수 있음
            if blocks[i] == blocks[i + 1] + 2:
                ans += 1 # 6번 블럭이 세로일 때 1번칸이 2번칸보다 2칸 높아야 놓을 수 있음
  • 7번 블록
    7번 블록은 6번 블록의 반대 모양으로, 6번 블록을 그대로 뒤집은 것과 같다.
elif p == 7:
    if c >= 3:
        for i in range(c - 2):
            if blocks[i] == blocks[i + 1] and blocks[i + 1] == blocks[i + 2]:
                ans += 1 # 7번 블럭이 가로일 때 연속하는 3칸의 높이가 같아야 놓을 수 있음
            if blocks[i] == blocks[i + 1] and blocks[i] == blocks[i + 2] + 1:
                ans += 1 # 7번 블럭이 가로일 때 3번칸이 1번칸, 2번칸보다 한칸 낮아야 놓을 수 있음
    if c >= 2: 
        for i in range(c - 1):
            if blocks[i] == blocks[i + 1]:
                ans += 1 # 7번 블럭이 세로일 때 연속하는 2칸의 높이가 같아야 놓을 수 있음
            if blocks[i] == blocks[i + 1] - 2:
                ans += 1 # 7번 블럭이 세로일 때 1번칸이 2번칸보다 2칸 낮아야 놓을 수 있음

이처럼 각 블록의 생김새에 따라 입력으로 주어진 테트리스 필드를 탐색하며 해당 블록을 놓을 수 있는 구역인지 판단하며 놓을 수 있는 경우의 수를 세면 된다.


📒 코드

c, p = map(int, input().split())
blocks = list(map(int, input().split()))

ans = 0
if p == 1:
    ans += c # 1번 블럭은 세로로 세웠을 때 모든 칸에 놓을 수 있음
    if c >= 4: # 1번 블럭이 가로일 때 연속한 4칸의 높이가 같아야 놓을 수 있음
        for i in range(c - 3):
            if blocks[i] == blocks[i + 1] and blocks[i + 1] == blocks[i + 2] and blocks[i + 2] == blocks[i + 3]:
                ans += 1
elif p == 2:
    if c >= 2: # 2번 블럭은 연속한 2칸의 높이가 같아야 놓을 수 있음
        for i in range(c - 1):
            if blocks[i] == blocks[i + 1]:
                ans += 1
elif p == 3:
    if c >= 3: # 3번 블럭이 가로일 때 1번칸, 2번칸은 같고 3번칸은 1번칸, 2번칸보다 한칸 높아야 놓을 수 있음
        for i in range(c - 2):
            if blocks[i] == blocks[i + 1] and blocks[i] == blocks[i + 2] - 1:
                ans += 1
    if c >= 2: # 3번 블럭이 세로일 때 1번칸이 2번칸보다 한칸 높아야 놓을 수 있음
        for i in range(c - 1):
            if blocks[i] == blocks[i + 1] + 1:
                ans += 1
elif p == 4:
    if c >= 3: # 4번 블럭이 가로일 때 1번칸이 2번칸, 3번칸보다 한칸 높아야 놓을 수 있음
        for i in range(c - 2):
            if blocks[i] == blocks[i + 1] + 1 and blocks[i] == blocks[i + 2] + 1:
                ans += 1
    if c >= 2: # 4번 블럭이 세로일 때 1번칸이 2번칸보다 한칸 낮아야 놓을 수 있음
        for i in range(c - 1):
            if blocks[i] == blocks[i + 1] - 1:
                ans += 1
elif p == 5:
    if c >= 3: 
        for i in range(c - 2): 
            if blocks[i] == blocks[i + 1] and blocks[i + 1] == blocks[i + 2]:
                ans += 1 # 5번 블럭이 가로일 때 연속하는 3칸의 높이가 같아야 놓을 수 있음
            if blocks[i + 1] == blocks[i] - 1 and blocks[i + 1] == blocks[i + 2] - 1:
                ans += 1 # 5번 블럭이 가로일 때 1번칸, 3번칸이 2번칸보다 한칸 높아야 놓을 수 있음
    if c >= 2:
        for i in range(c - 1): 
            if blocks[i] == blocks[i + 1] + 1:
                ans += 1 # 5번 블럭이 세로일 때 1번칸이 2번칸보다 높아야 놓을 수 있음
            if blocks[i] == blocks[i + 1] - 1:
                ans += 1 # 5번 블럭이 세로일 때 1번칸이 2번칸보다 놓아야 놓을 수 있음 
elif p == 6:
    if c >= 3: 
        for i in range(c - 2): 
            if blocks[i] == blocks[i + 1] and blocks[i + 1] == blocks[i + 2]:
                ans += 1 # 6번 블럭이 가로일 때 연속하는 3칸의 높이가 같아야 놓을 수 있음
            if blocks[i] == blocks[i + 1] - 1 and blocks[i] == blocks[i + 2] - 1:
                ans += 1 # 6번 블럭이 가로일 때 1번칸이 2번칸, 3번칸보다 한칸 낮아야 놓을 수 있음
    if c >= 2:
        for i in range(c - 1):
            if blocks[i] == blocks[i + 1]:
                ans += 1 # 6번 블럭이 세로일 때 연속하는 2칸의 높이가 같아야 놓을 수 있음
            if blocks[i] == blocks[i + 1] + 2:
                ans += 1 # 6번 블럭이 세로일 때 1번칸이 2번칸보다 2칸 높아야 놓을 수 있음
elif p == 7:
    if c >= 3:
        for i in range(c - 2):
            if blocks[i] == blocks[i + 1] and blocks[i + 1] == blocks[i + 2]:
                ans += 1 # 7번 블럭이 가로일 때 연속하는 3칸의 높이가 같아야 놓을 수 있음
            if blocks[i] == blocks[i + 1] and blocks[i] == blocks[i + 2] + 1:
                ans += 1 # 7번 블럭이 가로일 때 3번칸이 1번칸, 2번칸보다 한칸 낮아야 놓을 수 있음
    if c >= 2: 
        for i in range(c - 1):
            if blocks[i] == blocks[i + 1]:
                ans += 1 # 7번 블럭이 세로일 때 연속하는 2칸의 높이가 같아야 놓을 수 있음
            if blocks[i] == blocks[i + 1] - 2:
                ans += 1 # 7번 블럭이 세로일 때 1번칸이 2번칸보다 2칸 낮아야 놓을 수 있음
print(ans)

💭 후기

각 블록의 생김새에 따라 경우를 일일히 따져보아야 하는 문제. 실수만 하지 않는다면 쉽게 해결할 수 있었던 문제였다.


🔗 문제 출처

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


profile
精進 "정성을 기울여 노력하고 매진한다"

0개의 댓글