코딩테스트

프렌즈 4블록

Twisted 2025. 2. 24. 21:53

프렌즈 4블록 풀어보기

 

프로그래머스

SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

이번 문제는 2018 KAKAOBLIND 문제인 프렌즈4블록 문제이다. 

 

카카오프렌즈 블록이 2X2의 형태로 4개가 붙어있는경우 해당 블록들이 사라지며 점수를 얻는 게임이라 한다.

자세한 내용은 문제를 한번 읽어보길 바란다.

 

가장 먼저 실행한 것은 이차원 배열을 만들어 주는 것이었다. 

(a,b)처럼 특정 위치의 값을 바꾸거나 생성, 삭제를 위해 먼저 이차원 배열을 만들었다. 

크기는 m x n 으로 문제에서 주어진다.

 

그렇다면 이렇게 만든 block에 어떻게 각각의 프렌즈 값들을 넣어야 할까?

나는 toCharArray()라는 메서드를 이용하였다.

개인적으로 이 메서드는 자주 사용되는것 같아 외워두면 도움이 많이 되는 것 같다.

// 보드에 각각의 값 주입
for (int i = 0; i < board.length; i++) {
    block[i] = board[i].toCharArray();
}

이러한 방식으로 사용을 하게되면 toCharArray()로 인해 board에 들어있던 단어는 Char형태로 잘게 쪼개져 각각의 block[i]의 값에 배정이 된다.

예를 들어 HELP 인 경우 block[i][0] = 'H', block[i][1] = 'E' ... 이런식으로 저장이 되는 것이다.

 

그럼 여기까지 하여 게임 보드를 완성 시켰다. 

 

다음으로 해야할 작업은 중복되지 않도록 제거할 블록을 저장하는 HashSet을 만들어 주었다. 

HashSet<Pair> delete = new HashSet<>();

Set은 기본적으로 중복을 허용하지 않는 데이터 구조이기 때문에 이처럼 만들어 주었고 Pair라는 객체를 만들어 주어 각각의 좌표 값인 x,y값을 저장해 줄 수 있도록 구성하였다.

 

다음코드는 조금 길다.

while (Pass) {
    Pass = false;
    delete.clear();

    // 없어질 블록 정의
    for (int x = 0; x < m - 1; x++) {
        for (int y = 0; y < n - 1; y++) {
            if (block[x][y] == '0') continue;

            if (block[x][y] == block[x][y + 1] &&
                    block[x][y] == block[x + 1][y] &&
                    block[x][y] == block[x + 1][y + 1]) {

                delete.add(new Pair(x, y));
                delete.add(new Pair(x, y + 1));
                delete.add(new Pair(x + 1, y));
                delete.add(new Pair(x + 1, y + 1));
            }
        }
    }

    // 블록 삭제 및 카운트 증가
    for (Pair p : delete) {
        if (block[p.x][p.y] != '0') {
            block[p.x][p.y] = '0';
            answer++;
            Pass = true;
        }
    }

    // 블록 떨어뜨리기 (중력 적용)
    for (int y = 0; y < n; y++) {
        for (int x = m - 1; x > 0; x--) {
            if (block[x][y] == '0') {
                for (int k = x - 1; k >= 0; k--) {
                    if (block[k][y] != '0') {
                        block[x][y] = block[k][y];
                        block[k][y] = '0';
                        break;
                    }
                }
            }
        }
    }
}

Pass라는 값을 false로 만들어주는 부분이 있는데 초기 선언을 true로 하여 먼저 한번은 실행이 되도록 만든 것이다.

그리고 해당 while문 내에서 블록의 삭제가 일어난 경우 Pass의 값을 true로 만들어 한번 더 while문 내부의 로직이 실행되도록 구성하였다. 추가적으로 Pass를 false로 초기화 하고나면 해시셋도 .clear()메서드를 이용하여 비워주어야 한다.

 

없어질 블록을 찾는것은 다음과 같다.

for (int x = 0; x < m - 1; x++) {
    for (int y = 0; y < n - 1; y++) {
        if (block[x][y] == '0') continue;

        if (block[x][y] == block[x][y + 1] &&
                block[x][y] == block[x + 1][y] &&
                block[x][y] == block[x + 1][y + 1]) {

            delete.add(new Pair(x, y));
            delete.add(new Pair(x, y + 1));
            delete.add(new Pair(x + 1, y));
            delete.add(new Pair(x + 1, y + 1));
        }
    }
}

(0,0)부터 시작하여 m-1, n-1까지 진행한다 이러한 이유는 기준점으로 하여금 2*2의 칸을 조사하여야 하는데 가장 마지막의 값은 존재자체가 하지 않으므로 Exception이 일어나기 때문이다.

그렇게 각각의 값을 조사하여 삭제할 HashSet에 추가를 해준다.

 

// 블록 삭제 및 카운트 증가
for (Pair p : delete) {
    if (block[p.x][p.y] != '0') {
        block[p.x][p.y] = '0';
        answer++;
        Pass = true;
    }
}

이후 delete에 있는 Pair의 값들을 순회하며 해당칸의 값이 0이 아닌경우 0으로 만들고 사라진 블럭의 개수를 +1 해주는 것이다. 여기서 Pass의값을 true로 만들어주는 일도 일어난다.

삭제가 일어난 경우 블록을 재정렬 하였을 때 다시 검사하는 부분이 필요하기 때문이다.

 

// 블록 떨어뜨리기 (중력 적용)
for (int y = 0; y < n; y++) {
    for (int x = m - 1; x > 0; x--) {
        if (block[x][y] == '0') {
            for (int k = x - 1; k >= 0; k--) {
                if (block[k][y] != '0') {
                    block[x][y] = block[k][y];
                    block[k][y] = '0';
                    break;
                }
            }
        }
    }
}

블록을 정렬하는 코드는 다음과 같다.

for문을 세번이나 쓰며 이게 맞나라는 생각이 들었는데 마땅히 다른 생각이 나질 않는다. 

좋은 아이디어가 있으면 공유 부탁한다. 제발...

 

이 코드는 아래에서 부터 시작하여 비어있는경우 위를 탐색하여 값이 있으면 데려오는 코드이다.

유심히 한번 읽어보면 바로 이해가 될 것이다. 

 

주요 코드는 이렇게 끝이다.

이번 문제는 푸는데 총 1시간 10~15분 정도 걸렸던 것 같다.

크게 어려웠던 부분은 없지만 블록을 한번 삭제하고 난 후 재정렬 하는 부분에서 조금 걸렸던 것 같다.

 

'코딩테스트' 카테고리의 다른 글

N개의 최소공배수  (0) 2025.02.22
방금 그곡  (0) 2025.02.21
피로도  (0) 2025.02.20
2018 KAKAO BLIND RECRUITMENT [1차 캐시]  (0) 2025.02.18
피보나치 수열(프로그래머스)  (0) 2025.02.17