코딩테스트준비/백준

[백준][JAVA] BOJ 20061 모노미노도미노2

소윤파크 2023. 5. 1. 19:42
반응형

문제 읽기🤔


문제가 너무 길어서 요약으로 대체합니다 :)

위와 같이 모노미노도미노 게임을 위한 보드가 주어진다.

모노미노도미노 게임에서 사용되는 블록은 다음과 같다.

빨간 보드에 블럭을 놓으면 해당 위치 기준으로 더 이상 움직일 수 없을 때까지 행/열을 따라 이동한다.

 

블럭이 사라지는 경우

1) (초록)행//(파랑)열이 모두 블럭으로 채워진 경우

  -> 해당 줄의 블럭은 모두 사라짐, 해당 줄의 앞줄에 존재하는 블럭들은 사라진 행/열의 개수만큼 행/열을 따라 뒤로 이동

  -> 1점을 얻는다.

2) 희미한 부분에 블럭이 채워진 경우

  -> 희미한 부분에 블럭이 있는 (초록)행/(파랑)열의 수만큼 맨 뒷 행/열에 있는 타일들이 사라짐

  -> 해당 줄의 앞줄에 존재하는 블럭들은 사라진 행/열의 개수만큼 행/열을 따라 뒤로 이동

1, 2번 경우가 모두 발생하는 경우에는 1을 실행한 후 2를 실행한다.

 

얻은 총 점수초록색 보드, 파란색 보드에 타일이 있는 칸의 개수를 출력하라.

 

 

문제 풀이📝


꼼꼼하게 구현만 잘하면 되는 시뮬레이션 문제였다.

 

1. 빨간색 보드에 놓은 블럭을 파란색 보드, 초록색 보드로 이동시킨다.

2. (초록)행/(파랑)열이 블럭으로 모두 채워졌는지 검사한다.

  -> 채워진 행/열이 존재한다면 해당 행/열의 타일들을 지우고, 앞쪽의 타일들을 이동시킨다.

  -> 총 점수에 1점을 더해준다.

3. 희미한 부분에 블럭이 있는 경우를 검사한다.

  -> 희미한 부분에 블럭이 있는 (초록)행/(파랑)열의 개수만큼 맨 뒤부터 한 줄씩 타일을 지우고, 앞쪽의 타일들을 이동시킨다.

 

함수를 잘 재사용하여 깔끔한 코드를 짜고 싶었지만,,, 쉽지가 않았다.

다음에 기회가 된다면 꼭 리팩토링 하고 싶다.

 

 

구현🛠️


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

// 초록색 보드와 파란색 보드의 위치를 헷갈렸습니다^^,,,
// 반대로 생각하고 읽으시면 됩니다.
public class Main {

    static final int MAX = 6;
    static final int GREEN = 0;
    static final int BLUE = 1;

    // 우, 상
    static final int[] DR = {0, 1};
    static final int[] DC = {1, 0};

    static int[][] greenBoard;
    static int[][] blueBoard;

    static int score;


    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        greenBoard = new int[MAX - 2][MAX];
        blueBoard = new int[MAX][MAX - 2];

        int N = Integer.parseInt(br.readLine());
        for (int i = 0; i < N; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            int type = Integer.parseInt(st.nextToken());
            int row = Integer.parseInt(st.nextToken());
            int col = Integer.parseInt(st.nextToken());
            put(type, row, col);
        }
        System.out.println(score);
        System.out.println(getRemainingTiles());
    }

    static void put(int type, int row, int col) {


        switch (type) {
            // 1x1
            case 1:
                drop(new int[]{row, 0}, new int[]{row, 0}, GREEN);
                drop(new int[]{0, col}, new int[]{0, col}, BLUE);
                break;
            // 1x2
            case 2:
                drop(new int[]{row, 0}, new int[]{row, 1}, GREEN);
                drop(new int[]{0, col}, new int[]{0, col + 1}, BLUE);
                break;
            // 2x1
            case 3:
                drop(new int[]{row, 0}, new int[]{row + 1, 0}, GREEN);
                drop(new int[]{0, col}, new int[]{1, col}, BLUE);
                break;
        }

        // 한 행/열이 꽉 찼는지 확인
        checkLine();
        // 희미한 구역 확인
        checkFaintArea();
    }

    static void drop(int[] start, int[] end, int color) {

        int[][] board = (color == GREEN ? greenBoard : blueBoard);
        int[] nStart = {start[0], start[1]};
        int[] nEnd = {end[0], end[1]};

        while (true) {
            int nx1 = nStart[0] + DR[color];
            int ny1 = nStart[1] + DC[color];
            int nx2 = nEnd[0] + DR[color];
            int ny2 = nEnd[1] + DC[color];
            // 끝에 도달
            if (isOutOfBound(nx1, ny1) || isOutOfBound(nx2, ny2)) {
                break;
            }
            // 다른 블럭과 충돌
            if (board[nx1][ny1] != 0 || board[nx2][ny2] != 0) {
                break;
            }
            nStart[0] = nx1;
            nStart[1] = ny1;
            nEnd[0] = nx2;
            nEnd[1] = ny2;
        }
        board[nStart[0]][nStart[1]] = 1;
        board[nEnd[0]][nEnd[1]] = 1;
    }

    static boolean isOutOfBound(int r, int c) {
        if (r >= MAX || c >= MAX) {
            return true;
        }
        return false;
    }

    static void checkLine(){

        int greenCount = 0;
        int greenIdx = -1;

        int blueCount = 0;
        int blueIdx = -1;

        for (int i = MAX - 1; i >= 2; i--) {

            int gCount = 0;
            int bCount = 0;
            for (int j = 0; j < 4; j++) {
                if (greenBoard[j][i] != 0) {
                    gCount++;
                }
                if (blueBoard[i][j] != 0) {
                    bCount++;
                }
            }
            // 한 줄이 꽉 채워진 경우
            if (gCount == 4){
                greenCount++;
                greenIdx = i;
                pop(greenIdx, GREEN);
            }

            if (bCount == 4){
                blueCount++;
                blueIdx = i;
                pop(blueIdx, BLUE);
            }
        }

        // 한 줄 이상이 채워져서 사라진 경우에만 -> 앞쪽의 블럭들을 (지운 줄의 개수)칸 만큼 옮긴다
        if (greenIdx != -1){
            pull(greenCount, greenIdx - 1, GREEN);
        }

        if (blueIdx != -1){
            pull(blueCount, blueIdx - 1, BLUE);
        }

        score = score + greenCount + blueCount;
    }

    static void checkFaintArea() {

        int greenCount = 0;
        int blueCount = 0;

        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 4; j++) {
                if (greenBoard[j][i] != 0) {
                    greenCount++;
                    break;
                }
            }
        }
        // 맨 뒤부터 한 줄씩 지워나간다
        for (int i = 0; i < greenCount; i++) {
            pop((MAX - i) - 1, GREEN);
        }
        // 지운 줄의 앞쪽의 블럭들을 (지운 줄의 개수)칸 만큼 옮긴다
        pull(greenCount, (MAX - greenCount) - 1, GREEN);

        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 4; j++) {
                if (blueBoard[i][j] != 0) {
                    blueCount++;
                    break;
                }
            }
        }
        for (int i = 0; i < blueCount; i++) {
            pop((MAX - i) - 1, BLUE);
        }
        pull(blueCount, (MAX - blueCount) - 1, BLUE);
    }

    static void pop(int idx, int color){

        for (int i = 0; i < 4; i++) {
            if (color == GREEN){
                greenBoard[i][idx] = 0;
            }
            if (color == BLUE){
                blueBoard[idx][i] = 0;
            }
        }
    }

    static void pull(int count, int idx, int color) {

        for (int i = 0; i < 4; i++) {

            for (int j = idx; j >= 0; j--) {

                if (color == GREEN){
                    if (greenBoard[i][j] != 0){
                        greenBoard[i][j] = 0;
                        greenBoard[i + DR[color] * count][j + DC[color] * count] = 1;
                    }
                }

                if (color == BLUE){
                    if (blueBoard[j][i] != 0){
                        blueBoard[j][i] = 0;
                        blueBoard[j + DR[color] * count][i + DC[color] * count] = 1;
                    }
                }
            }
        }
    }

    static int getRemainingTiles() {

        int total = 0;

        for (int i = 0; i < MAX - 2; i++) {

            for (int j = 2; j < MAX; j++) {

                if (greenBoard[i][j] != 0) {
                    total++;
                }
                if (blueBoard[j][i] != 0) {
                    total++;
                }
            }
        }
        return total;
    }
}

 

 

실행결과✅