알고리즘/시뮬레이션

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

kyjdummy 2025. 9. 29. 21:56

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

 

 

[ 문제 요약 ]

  • 빨, 파, 초 보드가 그림과 같이 붙어 있습니다. x는 행, y는 열을 의미합니다.
  • 게임에 사용하는 블록은 타일 하나 또는 두 개가 가로, 세로로 붙어 있는 형태입니다.
  • 블록을 놓을 위치를 빨간색 보드에서 선택하면, 그 위치부터 초록색 보드와 파란색 보드로 블록이 이동합니다.
  • 블록의 이동은 다른 블록을 만나거나 보드의 경계를 만나기 전까지 계속해서 이동합니다.
  • 초록색 보드의 한 행이 모두 차있으면 그 행의 모든 블록이 사라지고, 사라진 행 위에 있는 블록은 사라진 행만큼 밑으로 이동합니다.
  • 파란색 보드의 한 열이 모두 차있으면 그 열의 모든 블록이 사라지고, 사리진 열 왼쪽에 있는 블록은 사라진 열만큼 오른쪽으로 이동합니다.
  • 이렇게 한 행이나 열이 타일로 가득 차서 사라지면 1점을 얻습니다.
  • 파란색 보드나, 초록색 보드의 0,1 행(열)에 블록이 있으면 초록색 보드는 가장 밑의 행, 파란색 보드는 가장 오른쪽 행이 0,1 행(열)에 있는 블록 행(열)수 만큼 없어지고, 없어진 만큼 블록이 초록 보드는 내려오고 파란 보드는 오른쪽으로 이동합니다.
  • 행이나 열이 타일로 가득 찬 경우와 0,1 행(열)에 블록이 있는 경우가 동시에 발생할 수 있다. 이 경우, 행이나 열이 타일로 가득 찬 경우가 없을 때가지 점수를 획득하는 과정이 모두 진행된 후, 연한 칸에 블록이 있는 경우를 처리해야 합니다.
  • 블록을 놓는 위치가 순서대로 주어질 때 얻은 점수와 초록, 파란 보드에 있는 타일의 최종 개수를 출력합니다.
  • 블록이 차지하는 칸이 빨간색 칸의 경계를 넘어가는 경우는 없습니다. 첫째 줄에 블록을 모두 놓았을 때 얻은 점수 출력 후 다음 줄에 파란 + 초록 보드의 남은 타일의 수를 출력합니다.

 

[ 테스트 케이스 설명 ]

2 // 블록을 놓을 횟수(1<=10,000)
1 1 1 // 블록크기(1:1칸, 2:가로2개, 3:세로2개), x(행), y(열)
2 3 0
답
0
6

 

 

[ 알고리즘 분류 ]

  • 구현
  • 시뮬레이션

 

[ 문제 해설 ]

 

문제 조건에 맞게 구현만 하면 됩니다.

 

초록 , 파란 보드에 먼저 블록을 떨어뜨립니다. 이때 떨어뜨리는 블록은 덩어리로 이동해야 합니다. 하나씩 이동하면 잘못된 위치에 떨어지게 됩니다.

 

그리고 파란 보드와 초록 보드에 행이나 열이 모두 차있다면 없애주고 행이나 열을 한 칸 뒤로 미룹니다.

 

마지막으로 연한 부분에 블록이 있는 경우 연한 부분에 블록이 없을 때까지 행이나 열을 한 칸씩 뒤로 미루면 됩니다.

 

[ 정답 코드 ]

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

class Main{
	
	static boolean map[][] = new boolean[10][10];
	static int score;
	
	public static void main(String[] args)throws Exception{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int T = Integer.parseInt(br.readLine());
		while(T-->0)
		{
			StringTokenizer st = new StringTokenizer(br.readLine());
			int s = Integer.parseInt(st.nextToken());// 블록크기(1:1칸, 2:가로2개, 3:세로2개)
			int y = Integer.parseInt(st.nextToken());// 행
			int x = Integer.parseInt(st.nextToken());// 열
			
			dropGreen(s, y, x); // 초록 보드에 떨어뜨린다.
			dropBlue(s, y, x);	// 파란 보드에 떨어드린다.

			deleteCol();// 파란 보드에 한열이 모두 차있으면 제거
			deleteRow();// 초록 보드에 한행이 모두 차있으면 제거

			// 연한 부분이 빌 때 까지 마지막행을 지운다.
			while(checkGreen())moveRow(9, 4);
			while(checkBlue()) moveCol(9, 4);
		}
		System.out.print(new StringBuilder().append(score).append('\n').append(cal()).toString());
	}
	static void dropGreen(int s, int y, int x) {
		if(s == 1) {
			int r = 4;
			while(r<=9 && !map[r][x]) ++r;
			map[r - 1][x] = true;
		}
		else if(s == 2) {
			int r = 4;
			while(r<=9 && !map[r][x] && !map[r][x + 1]) ++r;
			map[r - 1][x] = map[r - 1][x + 1] = true;
		}
		else if(s == 3) {
			int r = 5;
			while(r<=9 && !map[r][x]) ++r;
			map[r - 1][x] = map[r - 2][x] = true;
		}
	}
	static void dropBlue(int s, int y, int x) {
		if(s == 1) {
			int c = 4;
			while(c<=9 && !map[y][c]) ++c;
			map[y][c - 1] = true;
		}
		else if (s == 2)
		{
			 int c = 5;
			 while (c <= 9 && !map[y][c]) c++;
			 map[y][c - 1] = map[y][c - 2] = true;
		} else
		{
			 int c = 4;
			 while (c <= 9 && !map[y][c] && !map[y + 1][c]) c++;
			 map[y][c - 1] = map[y + 1][c - 1] = true;
		}
	}
	static boolean checkBlue() {
		for(int x=4; x<=5; x++)
			for(int y=0; y<=3; y++)
				if(map[y][x])
					return true;
		return false;
	}
	static boolean checkGreen() {
		for(int y=4; y<=5; y++)
			for(int x=0; x<=3; x++)
				if(map[y][x])
					return true;
		return false;
	}
	static void deleteCol() {
		// 행0~3, 열6~9
		for(int x=9; x>=4; x--)
			while(colCheckAndDel(x))// 해당 열 체크
			{
				moveCol(x, 4);// 해당 열 움직임, x에 대해 다시 한번 체크해야 하므로 x에 +1을 처리함
				score++;
			}
	}
	static void deleteRow() {
		// 행6~9 열 0~3
		for(int y=9; y>=4; y--)
		{
			while(rowCheckAndDel(y))
			{
				moveRow(y,4);
				score++;
			}
		}
	}
	static void moveRow(int y, int limit) {
		while(y!=limit)
		{
			for(int x=0; x<=3; x++)
				map[y][x] = map[y - 1][x];
			--y;
		}
		for(int x=0; x<=3; x++)
			map[limit][x] = false;
	}

	static void moveCol(int x, int limit) {
		while(x!=limit)
		{
			for(int y=0; y<=3; y++)
				map[y][x] = map[y][x - 1];
			--x;
		}
		for(int y=0; y<=3; y++)
			map[y][limit] = false;
	}
	static boolean rowCheckAndDel(int y) {
		boolean isBlock = true;
		
		for(int x=0; x<=3; x++)
			isBlock = isBlock && map[y][x];
		
		if(!isBlock) return false;
		
		for(int x=0; x<=3; x++)
			map[y][x] = false;
		
		return true;
	}
	static boolean colCheckAndDel(int x) {
		boolean isBlock = true;
		
		for(int y=0; y<=3; y++)// 해당 열에 블록이 있는지 체크
			isBlock = isBlock && map[y][x];
		
		if(!isBlock)return false;
		
		for(int y=0; y<=3; y++)
			map[y][x] = false;// 해당열 모두 false로
		
		return true;
	}
	static int cal() {
		int cnt = 0;
		for(int i=0; i<=3; i++)
		{
			for(int j=6; j<=9; j++)
			{
				if(map[i][j])++cnt;
				if(map[j][i])++cnt;
			}
		}
		return cnt;
	}
}

 

[ 테스트 케이스 ]

11
1 1 1
2 3 0
3 2 2
3 2 3
3 1 3
2 0 0
3 2 0
3 1 2
2 3 0
3 2 0
1 1 1
답
2
15
//////////////////
12
1 1 1
2 3 0
3 2 2
3 2 3
3 1 3
2 0 0
3 2 0
3 1 2
2 1 0
3 0 1
1 2 0
2 2 2
답
2
17
/////////
6
2 0 0
1 0 0
2 0 0
2 0 0
1 3 0
3 0 0
답
0
10
//////////
16
2 3 2
2 2 1
2 2 1
2 0 2
3 2 0
3 0 0
3 1 1
3 0 3
2 3 2
2 2 1
2 2 1
2 0 2
3 2 0
3 0 0
3 1 1
3 0 3
답
9
8
////////////////
5
3 2 0
3 2 1
3 2 2
2 0 0
3 2 3
답
2
12
///////////////
4
3 0 0
2 0 0
2 1 0
3 0 0
답
0
14