[문제풀이] 블록 게임
업데이트:
2019 Kakao Blind Recruitment 기출 문제
문제 링크 : 블록 게임
풀이 시간 : 시간 측정 불가(중간에 다른 작업 하는라)
1. 문제 풀이
먼저 블록의 종류에 따라 직사각형을 만들 수 있는지 판단해야 한다.
검은 블록은 위에서 아래로 떨어지기 때문에
ㄴ모양과 ㄴ을 뒤집은 모양, ㅗ 모양만이 직사각형을 만들 수 있다.
1) 각 블록을 저장한 뒤 각 블록의 type을 정한다.
2) 직사각형이 되는 type의 블록들만 검사한다.
3) 0에서 검은 블록이 내려와야하는 위치까지 다른 블록이 있는지 체크
4-1) 다른 블록이 없는 경우, answer를 증가하고 종료
4-2) 있지만 type이 0인 경우, 직사각형을 못 만들기 때문에 종료
4-3) 있지만 type이 0이 아닌 경우, 다른 블록을 기준으로 3번으로 이동
2. 소스 코드
static public int solution(int[][] board) {
answer = 0;
// 각 block를 저장, 번호를 Key값으로 사용
hm = new HashMap<Integer, Block>();
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board.length; j++) {
if (board[i][j] != 0) {
// 각 block의 좌표를 저장
if (!hm.containsKey(board[i][j])) {
hm.put(board[i][j], new Block());
}
hm.get(board[i][j]).y.add(i);
hm.get(board[i][j]).x.add(j);
}
}
}
Iterator<Integer> iter = hm.keySet().iterator();
// 각 block의 type 저장
while (iter.hasNext()) {
makeType(hm.get(iter.next()));
}
iter = hm.keySet().iterator();
// 각 block이 직사각형이되는지 체크
while (iter.hasNext()) {
Block b = hm.get(iter.next());
// type이 0이 아니고 이미 check가 되었느지
if (b.type != 0 && !b.check) {
search(b, board);
}
}
return answer;
}
static boolean check(int[][] board, int y, int x) {
for (int i = 0; i <= y; i++) {
// 만약 검은 색 돌이 떨어지는 곳에 다른 블록이 있을 때
if (board[i][x] != 0) {
if (hm.get(board[i][x]).type == 0) {
// type이 0이면 직사각형을 못 만들기 때문에
return false;
} else {
// 위에 있는 block이 직사각형이 되는지 판단
if (!search(hm.get(board[i][x]), board)) {
return false;
}
}
}
}
return true;
}
static boolean search(Block b, int[][] board) {
int y = b.y.get(0);
int x = b.x.get(0);
// 타입별로 가능한지 체크
if (b.type == 1) {
if(!check(board, y, x+1)) {
return false;
}
if(!check(board, y, x+2)) {
return false;
}
} else if (b.type == 2) {
if(!check(board, y+1, x-1)) {
return false;
}
} else if (b.type == 3) {
if(!check(board, y+1, x+1)) {
return false;
}
} else if (b.type == 4) {
if(!check(board, y, x-2)) {
return false;
}
if(!check(board, y, x-1)) {
return false;
}
} else {
if(!check(board, y, x+1)) {
return false;
}
if(!check(board, y, x-1)) {
return false;
}
}
answer++;
b.check = true;
// 만들 수 있으면 block 삭제
for (int i = 0; i < 4; i++) {
board[b.y.get(i)][b.x.get(i)] = 0;
}
return true;
}
static void makeType(Block b) {
// 직사각형을 못만드는 경우
if (b.y.get(0) == b.y.get(1)) {
b.type = 0;
} else {
if (b.y.get(1) == b.y.get(2) && b.y.get(2) == b.y.get(3)) {
if (b.x.get(0) == b.x.get(1)) {
// 가로로 긴 ㄴ 모양
b.type = 1;
} else if (b.x.get(0) == b.x.get(1) + 1) {
// ㅗ 모양
b.type = 5;
} else {
// 가로로 긴 ㄴ 모양 반대
b.type = 4;
}
} else if (b.y.get(2) == b.y.get(3)) {
if (b.x.get(0) == b.x.get(2)) {
// 세로로 긴 ㄴ 모양
b.type = 3;
} else {
// 세로로 긴 ㄴ 모양 반대
b.type = 2;
}
}
}
}
static class Block {
int type;
boolean check;
ArrayList<Integer> y;
ArrayList<Integer> x;
Block() {
this.type = 0;
this.check = false;
this.y = new ArrayList<Integer>();
this.x = new ArrayList<Integer>();
}
}
3. 후기
다 풀고 해설을 봤을 때는 약간 풀이 방법이 다르지만
직사각형을 만들 수 있는 경우를 찾는 것은 똑같다.