프로그래머스 2018 KAKAO BLIND RECRUITMENT [1차] 프렌즈4블록 [JAVA] - 22년 9월 11일

Denia·2022년 9월 11일
0

코딩테스트 준비

목록 보기
64/201

구현 문제에 맞게 풀어서 정답을 맞추긴 했으나 코드가 좀 지저분하다. 깔끔하게 짜면서 기능도 잘 구현하고 싶은데 역시 두개를 동시에 잘 하는건 어려운 것 같다.
기능 구현 후 리팩토링을 따로 하는게 맞는거 같은데 ... 조금 귀찮다 ㅎㅎ..

package com.company;

class Solution {
    //확인해야 하는 direction 의 dx , dy를 정의 , 계산을 쉽게 하기 위해 마지막에 {-1,0} 을 또 추가함
    int[][] directions = {{-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}};
    //다른 메서드에서 boardHeight 사용하기 위해서 변수 설정
    int boardHeight;
    //다른 메서드에서 boardWidth 사용하기 위해서 변수 설정
    int boardWidth;
    //String 배열 대신에 board 값을 쉽게 컨트롤 하기 위해서 char 2차원 배열로 설정
    char[][] boardCharArr;
    public int solution(int height, int width, String[] board) {
        //정답을 저장할 변수
        int answer = 0;

        //boardHeight, boardWidth 를 board 에 해당하는 값으로 초기화
        boardHeight = height;
        boardWidth = width;

        //boardCharArr 초기화
        boardCharArr = new char[height][width];

        //String 배열인 board 를 char 2차원 배열로 변환하는 과정
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                boardCharArr[i][j] = board[i].charAt(j);
            }
        }

        //boardCharArr 을 무한 루프 돌면서 블럭을 처리
        while(true) {
            //블럭의 모든 요소들을 돌면서 삭제 해야하는 블럭을 확인 후 isDeletedBlock 으로 반환
            boolean[][] isDeletedBlock = checkBlockInBoard();

            //null 이 나오면 지울 게 없다는 것, while문 종료
            if (isDeletedBlock == null) break;

            //isDeletedBlock 의 값에 맞춰서 블럭을 삭제하고, 공중에 떠있는 블럭을 아래로 내린다.
            // 그리고 여기서 나온 반환값으로 answer 를 업데이트
            answer += updateBoard(isDeletedBlock);
        }

        return answer;
    }

    private boolean[][] checkBlockInBoard() {
        //몇개의 블럭을 지워야 하는지 저장할 변수
        int deleteCount = 0;

        //return 해줄 2차원 boolean 배열을 저장
        boolean[][] isDeletedBlock = new boolean[boardHeight][boardWidth];

        //boardCharArr 의 모든 요소를 돌면서 인접한 블럭 중에 지워야 하는 블럭이 있는지 확인
        //지워야 하는 블럭의 수가 있으면 deleteCount 에 합해준다.
        for (int heightIndex = 0; heightIndex < boardHeight; heightIndex++) {
            for (int widthIndex = 0; widthIndex < boardWidth; widthIndex++) {
                deleteCount += checkNearBlockToDelete(heightIndex, widthIndex, isDeletedBlock);
            }
        }

        //지워야 하는 블럭이 있으면 2차원 boolean 배열을 반환 , 지워야 하는 블럭이 없으면 null 을 반환
        return deleteCount == 0 ? null : isDeletedBlock;
    }

    //해당 좌표의 근처를 모둗 확인하여 지워야 하는 블럭이 있는지 확인한다.
    private int checkNearBlockToDelete(int heightIndex, int widthIndex, boolean[][] isDeletedBlock) {
        //몇개의 블럭을 지워야 하는지 저장할 변수
        int deleteCount = 0;

        //처음에 받아온 좌표에 어떤 글자가 들어있는지 저장
        char c = boardCharArr[heightIndex][widthIndex];

        //해당 칸이 공백일 경우 확인하지 않고 해당 메서드를 종료
        if(c == ' ') return 0;

        //4방향에 대해서 체크
            //1시, 5시, 7시, 11시 에 4개의 블럭들이 존재하는지 확인
        for (int i = 0; i < 4; i = i + 2) {
            boolean isExistDeleteBlockInThisDirection = true;
            //방향당 자기 주변 블럭 체크 , directions 변수 에 자기 주변 블럭 체크 용 dx, dy 기입해둠
            for (int j = i; j < i + 3; j++) {
                //moveHeight , moveWidth 에 가상으로 옮긴 좌표를 대입
                int moveHeight = heightIndex + directions[j][0];
                int moveWidth = widthIndex + directions[j][1];

                //moveHeight , moveWidth 가 올바른 index를 가지고 있지 않거나,
                //확인해야 하는 글자와 동일한 글자를 가지고 있지 않으면
                //해당 방향은 지워야 하는 블럭들이 존재하지 않으므로 isExistDeleteBlockInThisDirection 를 false로 변경 후 break
                if (!isRightIndex(moveHeight, moveWidth) || boardCharArr[moveHeight][moveWidth] != c) {
                    isExistDeleteBlockInThisDirection = false;
                    break;
                }
            }

            // isExistDeleteBlockInThisDirection 가 false 면 해당 방향은 지워야 하는 블럭이 존재하지 않으므로 다음 방향을 살펴본다.
            if(!isExistDeleteBlockInThisDirection) continue;

            //지워야 하는 블럭이 존재하므로 좌표값에 맞게 isDeletedBlock 에 체크를 해둔다.
            //그리고 지워야 하는 블럭의 개수를 deleteCount 에 업데이트
            for (int j = i; j < i + 3; j++) {
                int moveHeight = heightIndex + directions[j][0];
                int moveWidth = widthIndex + directions[j][1];

                isDeletedBlock[moveHeight][moveWidth] = true;
                deleteCount++;
            }
        }

        return deleteCount;
    }

    //올바른 Index를 가지고 있는지 확인하는 메서드
    private boolean isRightIndex(int heightIndex, int widthIndex){
        return 0 <= heightIndex && heightIndex < boardHeight && 0 <= widthIndex && widthIndex < boardWidth;
    }


    //boardCharArr 의 내용을 업데이트 하는 메서드
    private int updateBoard(boolean[][] isDeletedBlock) {
        //지운 블럭의 수를 return
        int deleteCount = 0;

        //isDeletedBlock 을 확인하여 지워야 하는 블럭을 확인하고
        // 지운 블럭들은 boardCharArr에 ' ' 로 변경 
        for (int i = 0; i < boardHeight; i++) {
            for (int j = 0; j < boardWidth; j++) {
                if(isDeletedBlock[i][j]){
                    boardCharArr[i][j] = ' ';
                    deleteCount++;
                }
            }
        }

        //먼저 열을 기준으로 하여 행을 돌면서 ' '이 있는지 확인
        //' '인 행 위로 ' '이 아닌 글자가 있으면 아래로 가져온다.
        for (int i = 0; i < boardWidth; i++) {
            for (int j = boardHeight - 1; j >= 0; j--) {
                //해당 칸이 ' '이면
                if(boardCharArr[j][i] == ' '){
                    //바로 윗 행부터 첫 행까지 돌면서 글자가 있는 칸을 찾고 그 칸을 현재의 ' '칸에 대입
                    for (int k = j - 1; k >= 0; k--) {
                        char tempChar = boardCharArr[k][i];
                        if(tempChar != ' '){
                            boardCharArr[j][i] = tempChar;
                            boardCharArr[k][i] = ' ';
                            break;
                        }
                    }
                }
            }
        }

        //지운 deleteCount 반환
        return deleteCount;
    }
}

profile
HW -> FW -> Web

0개의 댓글