Study hard

(c++)백준 19235번: 모노미노도미노 본문

백준/시뮬레이션,구현

(c++)백준 19235번: 모노미노도미노

Nimgnoej 2020. 10. 14. 22:49

www.acmicpc.net/problem/19235

 

19235번: 모노미노도미노

모노미노도미노는 아래와 같이 생긴 보드에서 진행되는 게임이다. 보드는 빨간색 보드, 파란색 보드, 초록색 보드가 그림과 같이 붙어있는 형태이다. 게임에서 사용하는 좌표 (x, y)에서 x는 행,

www.acmicpc.net

 

[풀이]

문제에 나온 조건대로 시뮬레이션을 하는 문제였다. 

struct 배열을 이용하여 블록 정보를 넣는 순서대로 저장하였다.

빨간색 보드는 따로 만들지 않고 바로 초록색 블록과 파란색 블록에 블록을 넣는 방법으로 풀었다.

꽉찬 행이나 열을 먼저 다 지우고 블록들을 이동시켜주었다

 

구현한 것

- 블록을 초록색 보드와 파란색 보드에 세팅하는 setBlock()

- 초록색 보드에 타일로 꽉찬 행이 있는지 확인하는 greenFull()

- 파란색 보드에 타일로 꽉찬 열이 있는지 확인하는 blueFull()

- 초록색 연한 칸에 타일이 있는지 확인하는 greenSpecial()

- 파란색 연한 칸에 타일이 있는지 확인하는 blueSpecial()

- 해당 행 또는 열을 비워주는 Remove()

- 초록색 보드의 블록들을 내려주는 greenMove()

- 파란색 보드의 블록들을 내려주는 blueMove()

- 남은 타일 수 세는 countTile()

 

1. 블록 놓기

2. 초록보드에 꽉찬 행 없을 때까지 꽉찬 행 찾기 (재귀)

3. 초록보드 블록 움직임 → 꽉찬 행 있는지 확인 ↑(2번으로) 

4. 초록보드 연한 칸에 블록 있는지 확인 → 있는 행 수만큼 밑에서부터 제거 → 블록 움직임 →꽉찬 행 있는지 확인↑(2번으로)

5. 파란보드에 꽉찬 열 없을 때까지 꽉찬 열 찾기 (재귀)

6. 파란보드 블록 움직임 → 꽉찬 열 있는지 확인 ↑(5번으로)

4. 파란보드 연한 칸에 블록 있는지 확인 → 있는 열 수만큼 밑에서부터 제거 → 블록 움직임 →꽉찬 열 있는지 확인↑(5번으로)

 

※ 블록을 처음에 놓을 때 초록보드는 0행부터, 파란보드는 0열부터 빈 자리를 찾아야 한다. 제일 밑 행 혹은 제일 오른쪽 열부터 거꾸로 찾으면 원래는 다른 블록에 막혀서 못 들어갈 자리에 들어가게 되는 경우가 있다.

※블록을 움직일 때 원래 블록이 있던 자리에서부터 마지막으로 다른 블록이나 경계가 아닌 자리를 찾아야한다. 

 

#include <iostream>
using namespace std;

struct Block {
	int t;
	int x, y;
};

int N;
int Green[6][4] = { 0, };
int Blue[4][6] = { 0, };
Block block[10001];//블록 놓는 순서대로 저장, 인덱스 1~N
int score = 0;

void Remove(int color, int w) {
	//초록색 보드->w행 제거
	if (color == 0) {
		for (int i = 0; i < 4; i++) {
			Green[w][i] = 0;
		}
	}
	//파란색 보드->w열 제거
	else {
		for (int i = 0; i < 4; i++) {
			Blue[i][w] = 0;
		}
	}
}

void greenMove() {
	for (int i = 4; i >= 0; i--) {
		for (int j = 0; j < 4; j++) {
			//1*2블록이면 같이 내려가기
			if (j < 3 && Green[i][j] == 2 && Green[i][j+1] == 2) {
				if (Green[i + 1][j] == 0 && Green[i + 1][j + 1] == 0) {
					int k = i + 1;
					while (k <= 5 && Green[k][j] == 0 && Green[k][j + 1] == 0)
						k++;
					k--;
					Green[k][j] = 2;
					Green[k][j + 1] = 2;
					Green[i][j] = 0;
					Green[i][j + 1] = 0;

				}
			}
			else if (Green[i][j] != 2 && Green[i][j] != 0) {
				if (Green[i + 1][j] == 0) {
					int k = i + 1;
					while (k <= 5 && Green[k][j] == 0)
						k++;
					k--;
					Green[k][j] = Green[i][j];
					Green[i][j] = 0;
				}
			}
		}
	}
}

void blueMove() {
	for (int i = 4; i >= 0; i--) {
		for (int j = 0; j < 4; j++) {
			//2*1블록이면 같이 이동하기
			if (j < 3 && Blue[j][i] == 3 && Blue[j+1][i] == 3) {

				if (Blue[j][i + 1] == 0 && Blue[j + 1][i + 1] == 0) {
					int k = i + 1;
					while (k <= 5 && Blue[j][k] == 0 && Blue[j + 1][k] == 0)
						k++;
					k--;
					Blue[j][k] = 3;
					Blue[j + 1][k] = 3;
					Blue[j][i] = 0;
					Blue[j + 1][i] = 0;
				}
			}
			else if (Blue[j][i] != 3 && Blue[j][i] != 0) {
				if (Blue[j][i + 1] == 0) {
					int k = i + 1;
					while (k <= 5 && Blue[j][k] == 0)
						k++;
					k--;
					Blue[j][k] = Blue[j][i];
					Blue[j][i] = 0;
				}
			}
		}
	}
}

void greenFull() {
	bool flag;
	bool moved = false;
	//초록색에서 꽉찬 행 찾기
	for (int i = 5; i >= 2; i--) {
		flag = true;
		for (int j = 0; j < 4; j++) {
			if (Green[i][j] == 0) {
				flag = false;
				break;
			}
		}
		//꽉찬 행이 있으면
		if (flag == true) {
			//점수 올리고
			score++;
			//해당 행 타일 제거
			Remove(0, i);
			moved = true;
		}
	}
	if (moved == true) {
    		//블록 이동
		greenMove();
        	//다시 꽉찬 행 있는지 확인
		greenFull();
	}
}

void blueFull() {
	bool flag;
	bool moved = false;
	//파란색에서 꽉찬 열 찾기
	for (int i = 5; i >= 2; i--) {
		flag = true;
		for (int j = 0; j < 4; j++) {
			if (Blue[j][i] == 0) {
				flag = false;
				break;
			}
		}
		//꽉찬 열 있으면
		if (flag == true) {
			//점수 올리고
			score++;
			//해당 열 타일 제거
			Remove(1, i);
			moved = true;
		}
	}
	if (moved == true) {
    		//블록 이동
		blueMove();
        	//다시 꽉찬 열 있는지 확인
		blueFull();
	}
}

void greenSpecial() {
	int cnt = 0;
	//특별한 칸에 타일 있으면
	for (int i = 0; i < 2; i++) {
		for (int j = 0; j < 4; j++) {
			if (Green[i][j] != 0) {
				cnt++;
				break;
			}
		}
	}
	for (int c = 0; c < cnt; c++) {
		//행의 수만큼 제거
		Remove(0, 5 - c);
	}
	//블록 이동
	greenMove();
	//꽉찬 행 있는지 확인
	greenFull();
}

void blueSpecial() {
	int cnt = 0;
	//특별한 칸에 타일 있으면
	for (int i = 0; i < 2; i++) {
		for (int j = 0; j < 4; j++) {
			if (Blue[j][i] != 0) {
				cnt++;
				break;
			}
		}
	}
	for (int c = 0; c < cnt; c++) {
		//열의 수만큼 제거
		Remove(1, 5 - c);
	}
	//블록 이동
	blueMove();
	//꽉찬 열 있는지 확인
	blueFull();
}

void setBlock(int t, int x, int y) {
	//초록색 보드에 블록 내리기
	//1*1 경우 그냥 내려주기
	if (t == 1) {
		int k = 0;
		while (k <= 5 && Green[k][y] == 0)
			k++;
		k--;
		Green[k][y] = t;
	}
	//2*1인 경우에도 그냥 내려주기
	else if (t == 3) {
		int k = 0;
		while (k <= 4 && Green[k][y] == 0 && Green[k + 1][y] == 0)
			k++;
		k--;
		Green[k][y] = t;
		Green[k + 1][y] = t;
	}
	//1*2경우에는 y열과 y+1열 확인
	else if (t == 2) {
		int k = 0;
		while (k <= 5 && Green[k][y] == 0 && Green[k][y + 1] == 0)
			k++;
		k--;
		Green[k][y] = t;
		Green[k][y + 1] = t;
	}

	//파란색 보드에 보드 옮기기
	//1*1경우에는 그냥 옮기기
	if (t == 1) {
		int k = 0;
		while (k <= 5 && Blue[x][k] == 0)
			k++;
		k--;
		Blue[x][k] = t;
	}
	//1*2경우에도 그냥 옮기기
	else if (t == 2) {
		int k = 0;
		while (k <= 4 && Blue[x][k] == 0 && Blue[x][k + 1] == 0)
			k++;
		k--;
		Blue[x][k] = t;
		Blue[x][k + 1] = t;
	}
	//2*1경우에는 x행, x+1행 확인
	else if (t == 3) {
		int k = 0;
		while (k <= 5 && Blue[x][k] == 0 && Blue[x + 1][k] == 0)
			k++;
		k--;
		Blue[x][k] = t;
		Blue[x + 1][k] = t;
	}
	/*
	for (int i = 0; i < 4; i++) {
		for (int j = 0; j < 6; j++) {
			cout << Blue[i][j] << ' ';
		}
		cout << '\n';
	}
	cout << '\n';
	*/
}

int countTile() {
	int cnt = 0;
	for (int i = 0; i < 6; i++) {
		for (int j = 0; j < 4; j++) {
			if (Green[i][j] != 0)
				cnt++;
		}
	}
	for (int i = 0; i < 4; i++) {
		for (int j = 0; j < 6; j++) {
			if (Blue[i][j] != 0)
				cnt++;
		}
	}
	return cnt;
}

void solution() {
	cin >> N;
	for (int i = 1; i <= N; i++) {
		cin >> block[i].t >> block[i].x >> block[i].y;
	}
	for (int b = 1; b <= N; b++) {
		//블록 놓기
		setBlock(block[b].t, block[b].x, block[b].y);
		greenFull();
		greenSpecial();
		blueFull();
		blueSpecial();
	}
	
	int tiles = countTile();
	cout << score << '\n';
	cout << tiles << '\n';
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	solution();
	return 0;
}

 

 

'백준 > 시뮬레이션,구현' 카테고리의 다른 글

(c++)백준 17143번: 낚시왕  (0) 2020.10.17
(c++)백준 16235번: 나무 재테크  (0) 2020.10.16
(c++)백준 5373번: 큐빙  (0) 2020.10.15
(c++)백준 3190번: 뱀  (0) 2020.10.15
(c++)백준 19237번: 어른 상어  (0) 2020.10.14