알고리즘

백준 20061 모노미노도미노2 C풀이 - Brute Force

머리큰개발자 2021. 4. 8. 01:24

4x4 테트리스 업그레이드 버젼 같은 문제이다.

 

빨간 칸에 1x1 혹은 1x2 박스를 놓으면 각각 파란영역과 초록영역으로 떨어진다.

테트리스와 마찬가지로 각 영역에서 블럭이 쌓이는 방향에 수직인 칸 4개가 꽉차면 한 줄이 사라지면서 점수를 1점 얻는다.

또한 마찬가지로 깨진 칸 위에 있는 블럭들이 정확하게 한 줄만 내려온다. (빈 칸으로 찾아 떨어지지 않는다.)

 

특이한 점으로는 연한 영역에 블럭이 있을 경우이다.

모든 줄이 깨지고 나서도 연한 영역에 블럭이 있을 경우, 있는 줄의 수만큼 밑의 칸을 밀어버린다.

 

정말 간단한 문제이지만, 블럭이라는 구조체를 만들지 않고 그냥 맵에다가 뿌렸기 때문에 하드 코딩이 되었다.

케이스 별로 하나하나 코딩을 했기 때문에 굉장히.. 길지만 직관적이어서 접근하는데 좋았다.

 

해결방식: 하드 코딩

 

고생한 점은 다음과 같다

1. 파란영역과 초록영역이 서로 방향이 다르기 때문에 맞춰서 판단하고 블럭을 내려야했다.

2. 블럭이 다음칸에 갈 수 있는지 판단할 때, 2칸짜리 블럭은 파란 영역과 초록영역에서 다르게 판단해야한다.

 

개선할 점은 다음과 같다.

1. 블럭을 구조체로 선언하여 타입별로 판단하면 좋을 것 같다.

2. 블럭을 미는 함수를 통일성 있게 구성하면 코드가 반의 반이 될 것 같다.

3. 맵이 커질 경우 비효율적이 되므로, 블럭을 밀 때 한 번에 가장 위의 경계까지 접근하는 것이 좋을 것 같다.

 

전체 코드

#include <stdio.h>
#define MAX_N 10
int N;
int t, x, y;
int Map[MAX_N+ 1][MAX_N+ 1];
int tile, score;
int dx[] = { 1,0 };
int dy[] = { 0,1 };
//REDZONE 0~3 , 0~3  SKYZONE 0~3, 4~5 BLUEZONE 0~3, 6~9;
//SHALLOWGREEN 4~5, 0~3 GREENZONE 6~9, 0~3 


//옅은 파랑 영역에 블럭이 있는지, 2줄 다 있으면 2 return, 1줄있으면 return1
int checkBlue() {
	for (int j = 4; j < 6; j++) {
		for (int i = 0; i < 4; i++) {
			if (Map[i][j] && (j == 4)) {
				return 2;
			}
			if (Map[i][j] &&( j == 5)) {
				return 1;
			}
		}
	}
	return 0;
}
//옅은 초록 영역에 블럭이 있는지
int checkGreen() {
	for (int i = 4; i < 6; i++) {
		for (int j = 0; j < 4; j++) {
			if (Map[i][j] && (i == 4)) {
				return 2;
			}
			if (Map[i][j] && (i == 5)) {
				return 1;
			}
		}
	}
	return 0;
}
//제거 및 옅은 영역에 있으면 밀기
void rid() {
	//blue zone 줄 제거
	for (int j = MAX_N - 1; j >= 6; j--) {
		int cnt = 0;
		for (int i = 0; i < 4; i++) {
			if (Map[i][j]) cnt++;
		}
		//깨져야하는 경우 j-1부터 다 오른쪽으로 한칸 밀기 + j 유지
		if (cnt == 4) {
			score++;
			//연한 칸에 있는 것도 밀기
			for (int tx = j - 1; tx >= 4; tx--) {
				for (int ty = 0; ty < 4; ty++) {
					Map[ty][tx + 1] = Map[ty][tx];
					Map[ty][tx] = 0;
				}
			}
			j++;

		}
	}
	//연한칸에 뭐가 있다면 다 오른쪽 밀기
	int pushblue = checkBlue();
	if (pushblue) {
		for (int i = 0; i < 4; i++) {
			for (int j = MAX_N - 1-pushblue; j >= 6 - pushblue; j--) {
				Map[i][j + pushblue] = Map[i][j];
				Map[i][j] = 0;
			}
		}
	}
	//green zone
	for (int i = MAX_N - 1; i >= 6; i--) {
		int cnt = 0;
		for (int j = 0; j < 4; j++) {
			if (Map[i][j]) cnt++;
		}
		//깨져야하는 경우 i-1부터 다 아래쪽으로 한칸 밀기 + i 유지
		if (cnt == 4) {
			score++;
			//연한 칸에 있는 것도 밀기
			for (int ty = i - 1; ty >= 4; ty--) {
				for (int tx = 0; tx < 4; tx++) {
					Map[ty+1][tx ] = Map[ty][tx];
					Map[ty][tx] = 0;
				}
			}
			i++;

		}
	}
	//연한칸에 뭐가 있다면 아래로 밀기
	int pushgreen = checkGreen();
	if (pushgreen) {
		for (int j = 0; j < 4; j++) {
			for (int i = MAX_N - 1 - pushgreen; i >= 6 - pushgreen; i--) {
				Map[i+pushgreen][j] = Map[i][j];
				Map[i][j] = 0;
			}
		}
	}
}
//빨간 영역에 블럭 놓기
void put(int t, int x, int y) {
	//블럭이 1개짜리일 경우
	if (t == 1) {
		Map[y][x] = 1;
		//push to blue
		int ty = y, tx = x;
		while (tx+1<MAX_N) {
			if (Map[ty][tx + 1]) break;
			Map[ty][tx + 1] = 1;
			Map[ty][tx] = 0;
			tx++;
		}
		//push to green
		ty = y, tx = x;
		while (ty+1 < MAX_N) {
			if (Map[ty + 1][tx])break;
			Map[ty + 1][tx] = 1;
			Map[ty][tx] = 0;
			ty++;
		}
		//제거하거나 연한영역에 있으면 밀어버림
		rid();
		//빨간 영역에서 제거
		Map[y][x] = 0;
	}
	//블럭이 x,y x,y+1 일 경우
	else if (t == 2) {
		Map[y][x] = 1;
		Map[y + 1][x] = 1;
		int ty1 = y,ty2=y+1, tx = x;
		//push to blue
		while (tx+1 < MAX_N) {
			//둘 중 하나라도 부딪히면 멈춤
			if (Map[ty1][tx+1] ||Map[ty2][tx + 1]) break;
			Map[ty1][tx] = 0;
			Map[ty2][tx] = 0;
			Map[ty1][tx + 1] = 1;
			Map[ty2][tx + 1] = 1;
			tx++;
		}
		//push to green;
		ty1 = y, ty2 = y + 1, tx = x;
		while (ty2 +1< MAX_N) {
			//맨 앞만 보면 됨
			if ( Map[ty2 + 1][tx]) break;
			Map[ty1][tx] = 0;
			Map[ty2][tx] = 0;
			Map[ty1 + 1][tx] = 1;
			Map[ty2 + 1][tx] = 1;
			ty1++;
			ty2++;
		}
		//제거 및 밀기
		rid();
		//빨간 영역에서 제거
		Map[y][x] = 0;
		Map[y + 1][x] = 0;

	}
	//블럭 x,y x+1,y 일경우
	else if (t == 3) {
		Map[y][x] = 1;
		Map[y][x + 1] = 1;
		int ty = y, tx1 = x, tx2 = x + 1;
		//push to blue
		while ( tx2 +1< MAX_N) {
			//맨 앞만 보면됨 
			if ( Map[ty][tx2 + 1]) break;
			Map[ty][tx1] = 0;
			Map[ty][tx2] = 0;
			Map[ty][tx1 + 1] = 1;
			Map[ty][tx2 + 1] = 1;
			tx1++;
			tx2++;
		}
		//push to green
		ty = y, tx1 = x, tx2 = x + 1;
		while (ty +1< MAX_N) {
			//둘 중 하나라도 부딪히면 끝
			if ( Map[ty+1][tx1] || Map[ty + 1][tx2]) break;
			Map[ty][tx1] = 0;
			Map[ty][tx2] = 0;
			Map[ty + 1][tx1] = 1;
			Map[ty + 1][tx2] = 1;
			ty++;
		}

		//제거 및 영역 밀기
		rid();
		//빨간 영역 블럭 제거
		Map[y][x] = 0;
		Map[y + 1][x] = 0;
	}
}
//남은 타일 수 세기
void check() {
	for (int i = 0; i < MAX_N; i++) {
		for (int j = 0; j < MAX_N; j++) {
			if (Map[i][j]) tile++;
		}
	}
}


int main() {
	scanf("%d", &N);
	for (int i = 0; i < N; i++) {
		scanf("%d %d %d", &t, &x, &y);
		put(t, x, y);
	}
	check();
	printf("%d\n%d", score, tile);
}

ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ왤케길어