문제 읽기🤔
문제가 너무 길어서 요약으로 대체합니다 :)
위와 같이 모노미노도미노 게임을 위한 보드가 주어진다.
모노미노도미노 게임에서 사용되는 블록은 다음과 같다.
빨간 보드에 블럭을 놓으면 해당 위치 기준으로 더 이상 움직일 수 없을 때까지 행/열을 따라 이동한다.
블럭이 사라지는 경우
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;
}
}
실행결과✅
'코딩테스트준비 > 백준' 카테고리의 다른 글
[백준][JAVA] BOJ 14725 개미굴 (0) | 2023.05.31 |
---|---|
[백준][JAVA] BOJ 20188 등산 마니아 (2) | 2023.05.03 |
[백준][JAVA] BOJ 2138 전구와 스위치 (0) | 2023.05.01 |
[백준][JAVA] BOJ 16954 움직이는 미로 탈출 (1) | 2023.05.01 |
[백준][JAVA] BOJ 14890 경사로 (0) | 2023.02.22 |