프로그래밍/알고리즘

BOJ 11559 · Puyo Puyo

반응형


알고리즘 분류 : BFS, 시뮬레이션  


게임 '뿌요 뿌요'를 프로그래밍하는 문제다. 주어진 뿌요뿌요 판에서 얼마나 많은 연쇄가 일어나는지 맞춰야 한다. BFS를 통해 전체 탐색을 하고, 터트릴 수 있는 블록이 있는지 확인하면서, 4개 이상이면 터트리고 아래로 떨어뜨리면 된다.


  • 1. 아래에서부터 블록(R,G,B,P,Y)을 확인한다. 빈 공간(.)은 무시한다.
  • 2. 블록을 발견하면, BFS 탐색을 통해 같은 색깔의 블록이 몇 개나 인접해있는지 확인한다.
  • 3. 만약 인접한 블록이 4개 이상이면, 서로 연결된 블록을 모두 터트린다. 터트린 블록은 빈 공간으로 만든다.
  • 4. 위쪽 끝까지 1~3 과정을 반복한다.
  • 5. 만약 블록이 한 번이라도 터졌다면, 정답 카운트를 1 증가시키고, 아래로 떨어질 수 있는 블록이 있는지 확인하고 떨어뜨린다.
  • 블록이 한 번이라도 터졌다면, 1~5 과정을 반복한다. 만약 한 번도 안 터졌다면 프로그램을 종료한다.




C++ 소스코드


#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;

struct puyo {
    int x, y;
};

const int n = 12, m = 6;
char a[n][m+1];
bool check[n][m+1];
const int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};

void fall() {
    // Puyo blocks fall down.
    for (int j=0; j<m; j++) {
        for (int i=n-1; i>=0; i--) {
            if (a[i][j] == '.') continue;
            for (int k=n-1; k>=i; k--) {
                if (a[k][j] == '.') {
                    a[k][j] = a[i][j];
                    a[i][j] = '.';
                }
            }
        }
    }
}

bool bfs(int i, int j, char c) {
    queue<puyo> q;
    vector<puyo> block;
    q.push({i, j});
    check[i][j] = true;
    block.push_back({i, j});
    // Count same blocks
    while (!q.empty()) {
        int x = q.front().x, y = q.front().y; q.pop();
        for (int k=0; k<4; k++) {
            int nx = x+dx[k], ny = y+dy[k];
            if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
            if (check[nx][ny] || a[nx][ny] != c) continue;
            check[nx][ny] = true;
            block.push_back({nx, ny});
            q.push({nx, ny});
        }
    }
    // Crash blocks if block >= 4
    if ((int)block.size() >= 4) {
        for (auto k : block) a[k.x][k.y] = '.';
        return true;
    } else return false;
}

bool crash() {
    // Find out if exist blocks which can be crashed.
    bool crashed = false;
    memset(check, false, sizeof(check));
    for (int i=n-1; i>=0; i--) {
        for (int j=m-1; j>=0; j--) {
            if (check[i][j] || a[i][j] == '.') continue;
            if (bfs(i, j, a[i][j])) crashed = true;
        }
    }
    return crashed;
}

void solve() {
    int ans = 0;
    while (crash()) {
        fall();
        ans += 1;
    }
    printf("%d\n", ans);
}

int main() {
    for (int i=0; i<n; i++) scanf("%s", a[i]);
    solve();
    return 0;
}




Python 3 소스코드


from sys import stdin
from collections import deque
input = stdin.readline

N, M = 12, 6
a = [list(input().strip()) for _ in range(N)]

def fall():
    for j in range(M):
        for i in range(N-1, -1, -1):
            if a[i][j] == '.':
                continue
            for k in range(N-1, i-1, -1):
                if a[k][j] == '.':
                    a[k][j] = a[i][j]
                    a[i][j] = '.'

def bfs(i, j, c, check):
    q = deque()
    block = [(i, j)]
    q.append((i, j))
    check[i][j] = True
    while q:
        x, y = q.popleft()
        for dx, dy in (1, 0), (-1, 0), (0, 1), (0, -1):
            nx, ny = x+dx, y+dy
            if nx < 0 or nx >= N or ny < 0 or ny >= M:
                continue
            if not check[nx][ny] and a[nx][ny] == c:
                check[nx][ny] = True
                block.append((nx, ny))
                q.append((nx, ny))
    if len(block) >= 4:
        for x, y in block:
            a[x][y] = '.'
        return True
    else:
        return False

def crash():
    crashed = False
    check = [[False]*M for _ in range(N)]
    for i in range(N-1, -1, -1):
        for j in range(M-1, -1, -1):
            if check[i][j] or a[i][j] == '.':
                continue
            if bfs(i, j, a[i][j], check):
                crashed = True
    return crashed

def solve(ans):
    while crash():
        fall()
        ans += 1
    print(ans)

solve(0)




참고


반응형