[ 백준 ] 21922 학부 연구생 민상

codesver·2023년 7월 17일
0

Baekjoon

목록 보기
71/72
post-thumbnail

📌 Problem

N x M 크기의 연구실에는 몇가지의 물건들이 놓여져 있다. 물건은 각각 1, 2, 3, 4, 9로 나타나며 9는 에어컨을 말한다. 에어컨에서는 4방향(동서남북)으로 바람이 분다. 바람은 연구실 내부에서만 순환하고 연구실 벽에 닿으면 사라진다. 각각의 물건은 다음과 같이 바람의 방향을 변환시킨다.

연구실에서 에어컨 바람이 닿는 칸의 수를 구하면 된다.

📌 Code

// 연구실의 크기 입력
StringTokenizer tokenizer = new StringTokenizer(reader.readLine());
int row = Integer.parseInt(tokenizer.nextToken());  // 연구실의 row
int col = Integer.parseInt(tokenizer.nextToken());  // 연구실의 column

Laboratory laboratory = new Laboratory(row, col);   // 연구실 생성

// 물건 삽입
for (int r = 0; r < row; r++) {
    tokenizer = new StringTokenizer(reader.readLine());
    for (int c = 0; c < col; c++)
        laboratory.addThing(r, c, Integer.parseInt(tokenizer.nextToken()));
}

// 연구실의 에어컨 전원 on
laboratory.turnOnAirConditioners();

// 에어컨이 닿는 위치 개수 출력
result.append(laboratory.availableSeats());
public class Laboratory {

    private final Thing[][] things;             // 연구실의 물건들
    private final boolean[][][] windBlew;       // 각 자리의 방향별 바람이 부는 여부
    private final boolean[][] availableSeat;    // 각 자리별 바람이 부는 여부

    public Laboratory(int row, int col) {
        things = new Thing[row][col];
        windBlew = new boolean[row][col][4];
        availableSeat = new boolean[row][col];
    }

    /**
     * 연구실에 물건을 추가한다.
     * @param row 물건을 추가하는 row
     * @param col 물건을 추가하는 column
     * @param type 추가하고자 하는 물건의 타입 (0, 1, 2, 3, 4, 9)
     */
    public void addThing(int row, int col, int type) {
        things[row][col] = Thing.values()[type == 9 ? 5 : type];
    }

    /**
     * 연구실에서 에어컨을 찾아서 전원을 켠다.
     */
    public void turnOnAirConditioners() {
        for (int row = 0; row < things.length; row++)
            for (int col = 0; col < things[row].length; col++)
                if (things[row][col].isAirConditioner())
                    for (Direction direction : Direction.values())
                        windBlow(row, col, direction);
    }

    /**
     * 바람의 진행 방향을 따라간다.
     * @param row 현재 바람이 닿은 위치 row
     * @param col 현재 바람이 닿은 위치 column
     * @param direction 바람이 부는 방향
     */
    private void windBlow(int row, int col, Direction direction) {
        availableSeat[row][col] = windBlew[row][col][direction.dir] = true;
        direction = things[row][col].convert(direction);    // 물건에 따라 바람이 부는 방향을 바꾼다.
        try {
            if (!windBlew[row + direction.row][col + direction.col][direction.dir])
                windBlow(row + direction.row, col + direction.col, direction);
        } catch (ArrayIndexOutOfBoundsException ignored) {
        }
    }

    /**
     * 바람이 닿는 자리의 수를 구한다.
     * @return 바람이 닿는 자리의 수
     */
    public int availableSeats() {
        int count = 0;
        for (boolean[] seats : availableSeat)
            for (boolean seat : seats) if (seat) count++;
        return count;
    }
}

public enum Thing {
    NULL, ONE, TWO, THREE, FOUR, AIR_CONDITIONER;

    /**
     * 물건이 에어컨인지 확인한다.
     * @return 에어컨 여부
     */
    public boolean isAirConditioner() {
        return this == AIR_CONDITIONER;
    }

    /**
     * 물건에 따라 바람의 방향을 바꾼다.
     * @param direction 바람의 기존 방향
     * @return 바람의 바뀐 방향
     */
    public Direction convert(Direction direction) {
        if (this == ONE) return direction.isVertical() ? direction : direction.reverse();
        else if (this == TWO) return direction.isVertical() ? direction.reverse() : direction;
        else if (this == THREE) return direction.isVertical() ? direction.postDirection() : direction.preDirection();
        else if (this == FOUR) return direction.isVertical() ? direction.preDirection() : direction.postDirection();
        else return direction;
    }
}

public enum Direction {
    NORTH(-1, 0, 0),
    EAST(0, 1, 1),
    SOUTH(1, 0, 2),
    WEST(0, -1, 3);

    final int row, col, dir;

    Direction(int row, int col, int dir) {
        this.row = row;
        this.col = col;
        this.dir = dir;
    }

    /**
     * 방향이 수직인지 확인한다.
     * @return 수직 여부
     */
    public boolean isVertical() {
        return this == NORTH || this == SOUTH;
    }

    /**
     * 반대 방향으로 변환한다.
     * @return 변환된 방향
     */
    public Direction reverse() {
        return Direction.values()[(this.dir + 2) % 4];
    }

    /**
     * 현재 방향을 반시계 방향으로 90도 회전한다.
     * @return 회전한 방향
     */
    public Direction preDirection() {
        return Direction.values()[(this.dir + 3) % 4];
    }

    /**'
     * 현재 방향을 시계 방향으로 90도 회전한다.
     * @return 회전한 방향
     */
    public Direction postDirection() {
        return Direction.values()[(this.dir + 1) % 4];
    }
}
profile
Hello, Devs!

1개의 댓글

comment-user-thumbnail
2023년 7월 17일

저도 개발자인데 같이 교류 많이 해봐요 ㅎㅎ! 서로 화이팅합시다!

답글 달기