[ 백준 ] 15662 톱니바퀴 2

codesver·2023년 7월 11일
0

Baekjoon

목록 보기
56/72
post-thumbnail

📌 Problem

8개의 톱니를 가지는 T개의 톱니바퀴가 일렬로 연결되어 있다. 각각의 톱니는 S극(1)과 N극(0) 중 하나를 가지고 있다. 하나의 톱니바퀴를 회전시키면 이웃하는 톱니바퀴들은 연결 상태에 따라 반대 방향으로 회전한다. 서로 다른 극으로 연결되어 있다면 같이 회전한다. 같은 극으로 연결되어 있다면 회전 하지 않는다. K번의 회전을 한 후에 모든 톱니바퀴 중에서 S극이 상단 톱니의 상태인 톱니바퀴들의 개수를 확인한다.

📌 Code

// 톱니바퀴들의 집합으로 이루어진 기계
Machine machine = new Machine();

// 톱니바퀴를 기계에 장착
int T = Integer.parseInt(reader.readLine());
while (T-- > 0)
    machine.addGear(Arrays.stream(reader.readLine().split(""))
            .mapToInt(Integer::parseInt).toArray());

// 톱니바퀴를 K번 회전
StringTokenizer tokenizer;
int K = Integer.parseInt(reader.readLine());
while (K-- > 0) {
    tokenizer = new StringTokenizer(reader.readLine());
    int gno = Integer.parseInt(tokenizer.nextToken()) - 1;  // 회전시키는 톱니바퀴 번호
    int rotate = Integer.parseInt(tokenizer.nextToken());   // 회전시키는 방향 번호

    // 톱니바퀴 회전
    machine.rotateGear(gno, rotate == 1 ? Rotation.CLOCKWISE : Rotation.COUNTER_CLOCKWISE);
}

// 기계에 포함된 톱니바퀴들의 상단 S극 톱니의 수 출력
result.append(machine.sumGearsTop());
public class Machine {

    private final List<Gear> gears = new ArrayList<>(); // 기계에 삽입된 톱니바퀴들

    /**
     * 새로운 톱니바퀴를 추가한다.
     * @param sawtooth 추가하는 톱니바퀴의 톱니 상대 배열
     */
    public void addGear(int[] sawtooth) {
        gears.add(new Gear(sawtooth));
    }

    /**
     * 톱니바퀴를 회전시킨다. (기계에 의해 회전)
     * @param gno 회전시키고자하는 톱니바퀴 번호
     * @param rotation 회전시키고자하는 방향
     */
    public void rotateGear(int gno, Rotation rotation) {
        Gear gear = gears.get(gno); // 회전시키고자하는 톱니바퀴
        
        // 왼쪽 톱니바퀴를 확인하고 다른 극으로 연결되어 있으면 왼쪽 톱니바퀴 회전
        if (gno >= 1 && gear.moveTogether(gears.get(gno - 1), Direction.LEFT))
            rotateGear(gno - 1, rotation.counter(), Direction.LEFT);
        
        // 오른쪽 톱니바퀴를 확인하고 다른 극으로 연결되어 있으면 오른쪽 톱니바퀴 회전
        if (gno + 1 < gears.size() && gear.moveTogether(gears.get(gno + 1), Direction.RIGHT))
            rotateGear(gno + 1, rotation.counter(), Direction.RIGHT);
        
        // 톱니바퀴 회전
        gear.rotate(rotation);
    }

    /**
     * 톱니바퀴를 회전시킨다. (다른 톱니바퀴에 의해 회전)
     * @param gno 회전시키고자하는 톱니바퀴
     * @param rotation 회전시키고자하는 방향
     * @param direction 연결된 톱니바퀴를 확인하는 방향
     */
    private void rotateGear(int gno, Rotation rotation, Direction direction) {
        Gear gear = gears.get(gno); // 회전시키고자하는 톱니바퀴
        
        // 왼쪽 방향으로 확인중이며 왼쪽 톱니바퀴를 확인하고 다른 극으로 연결되어 있으면 왼쪽 톱니바퀴 회전
        if (direction == Direction.LEFT && gno >= 1 && gear.moveTogether(gears.get(gno - 1), direction))
            rotateGear(gno - 1, rotation.counter(), direction);
        // 오른쪽 방향으로 확인중이며 오른쪽 톱니바퀴를 확인하고 다른 극으로 연결되어 있으면 오른쪽 톱니바퀴 회전
        else if (direction == Direction.RIGHT && gno + 1 < gears.size() && gear.moveTogether(gears.get(gno + 1), direction))
            rotateGear(gno + 1, rotation.counter(), direction);
        
        // 톱니바퀴 회전
        gear.rotate(rotation);
    }

    /**
     * 톱니바퀴들에서 상단 톱니가 S극인 톱니바퀴들의 개수를 확인한다.
     * @return 상단 톱니가 S극인 톱니바퀴들의 개수
     */
    public int sumGearsTop() {
        return gears.stream().mapToInt(Gear::getTop).sum();
    }
}

public class Gear {

    private int top = 0;            // 상단 톱니 index
    private final int[] sawtooth;   // 톱니 상태 배열

    public Gear(int[] sawtooth) {
        this.sawtooth = sawtooth;
    }

    /**
     * 이웃하는 톱니바퀴와 다른 극으로 연결되어 있는지 확인한다.
     * @param gear 이웃하는 톱니바퀴
     * @param direction 이웃하는 위치 (현재 톱니바퀴 기준)
     * @return 상극 연결 여부
     */
    public boolean moveTogether(Gear gear, Direction direction) {
        return direction == Direction.LEFT && getLeft() != gear.getRight() ||
                direction == Direction.RIGHT && getRight() != gear.getLeft();
    }

    /**
     * 톱니바퀴를 회전시킨다.
     * @param rotation 회전 방향
     */
    public void rotate(Rotation rotation) {
        if (rotation == Rotation.CLOCKWISE) top = (top + 7) % 8;
        else if (rotation == Rotation.COUNTER_CLOCKWISE) top = (top + 1) % 8;
    }

    /**
     * 톱니바퀴의 상단 톱니 상태를 확인한다.
     * @return 상단 톱니 상태
     */
    public int getTop() {
        return sawtooth[top];
    }

    /**
     * 톱니바퀴의 좌측 톱니 상태를 확인한다.
     * @return 좌측 톱니 상태
     */
    private int getLeft() {
        return sawtooth[(top + 6) % 8];
    }

    /**
     * 톱니바퀴의 우측 톱니 상태를 확인한다.
     * @return 우측 톱니 상태
     */
    private int getRight() {
        return sawtooth[(top + 2) % 8];
    }
}

public enum Rotation {
    CLOCKWISE(1), COUNTER_CLOCKWISE(-1);

    private final int rotate;

    Rotation(int rotate) {
        this.rotate = rotate;
    }

    public Rotation counter() {
        return rotate == 1 ? COUNTER_CLOCKWISE : CLOCKWISE;
    }
}

public enum Direction {LEFT, RIGHT}
profile
Hello, Devs!

0개의 댓글