[ 백준 ] 2174 로봇 시뮬레이션

codesver·2023년 7월 11일
0

Baekjoon

목록 보기
21/72
post-thumbnail

📌 Problem

가로 A * 세로 B 크기의 필드에 N개의 로봇들이 있다. N개의 로봇들은 명령에 따라 움직인다. 명령은 다음과 같다.

Robot Number, Command, Repeat
Robot Number : 로봇의 배치 순서이다. 먼저 배치된 로봇이 1번이고 이후로 1씩 증가한다.
Command : 명령의 종류로 L은 반시계 90도, R은 시계 90도 회전이다. F는 앞으로 1칸 움직인다.
Repeat : 명령의 반복 횟수이다.
- 1 F 3은 1번 로봇을 앞으로 3칸 움직이는 것이다.

잘못된 명령을 내리는 경우도 생긴다. 잘못된 명령을 내리면 추가 명령을 하지 않으며 오류 내용을 출력한다.

벽에 충돌하는 경우 : 필드는 벽으로 둘러 쌓여 있다. 벽에 충돌하면 Robot X crashes into the wall을 출력한다.
다른 로봇과 충돌하는 경우 : 다른 로봇과 충돌하면 Robot X crashes into robot Y를 출력한다.
- X와 Y는 각각 로봇의 번호이다.

만약 모든 명령에 오류가 없다면 OK를 출력한다.

📌 Code

// 필드의 크기를 입력
StringTokenizer tokenizer = new StringTokenizer(reader.readLine());
int A = Integer.parseInt(tokenizer.nextToken());    // 필드의 가로 크기
int B = Integer.parseInt(tokenizer.nextToken());    // 필드의 세로 크기

// 로봇 배치와 명령의 수를 입력
tokenizer = new StringTokenizer(reader.readLine());
int N = Integer.parseInt(tokenizer.nextToken());    // 로봇 배치 수
int M = Integer.parseInt(tokenizer.nextToken());    // 명령 수

// Command 센터 생성
CommandCenter commandCenter = new CommandCenter(A, B);

// N번의 로봇 배치
while (N-- > 0) {
    // 로봇 배치 정보를 입력
    tokenizer = new StringTokenizer(reader.readLine());
    int x = Integer.parseInt(tokenizer.nextToken());    // 로봇의 x축 위치
    int y = Integer.parseInt(tokenizer.nextToken());    // 로봇의 y축 위치
    String direction = tokenizer.nextToken();           // 로봇의 방향
    
    // 로봇 배치
    commandCenter.deployRobot(x, y, direction);
}

// 오류 명령일 때 예외 처리
try {
    // M번의 명령
    while (M-- > 0) {
        // 명령 정보 입력
        tokenizer = new StringTokenizer(reader.readLine());
        int rno = Integer.parseInt(tokenizer.nextToken());      // 로봇의 번호
        String command = tokenizer.nextToken();                 // 명령
        int repeat = Integer.parseInt(tokenizer.nextToken());   // 반복 회수
        
        // 로봇에게 명령
        commandCenter.commandRobot(rno, command, repeat);
    }
    
    // 명령에 오류가 없으면 OK 출력
    result.append("OK");
} catch (RobotException exception) {
    // 명령에 오류가 있으면 오류문 출력
    result.append(exception.getMessage());
}
// 명령을 처리하는 중앙 센터
public class CommandCenter {

    private final List<Robot> robots = new ArrayList<>();   // 로봇 번호 = index + 1
    private final Robot[][] robotMap;                       // 로봇 위치 = (row, column) = (x, y)

    public CommandCenter(int maxX, int maxY) {
        robotMap = new Robot[maxX][maxY];
    }

    /**
     * 로봇을 배치한다.
     * @param x 로봇의 x축 위치
     * @param y 로봇의 y축 위치
     * @param direction 로봇이 바라보는 방향
     */
    public void deployRobot(int x, int y, String direction) {
        Robot robot = new Robot(robots.size() + 1, x, y, direction);
        robots.add(robot);
        robotMap[x - 1][y - 1] = robot;
    }

    /**
     * 로봇에게 명령을 내린다.
     * @param rno 명령을 내리고자 하는 로봇의 번호
     * @param command 명령
     * @param repeat 명령 반복 횟수
     */
    public void commandRobot(int rno, String command, int repeat) {
        Robot robot = robots.get(rno - 1);
        while (repeat-- > 0) robot.readCommand(command, robotMap);
    }
}

public class Robot {

    private final int rno;          // 로봇의 번호
    private int x, y;               // 로봇의 위치
    private Direction direction;    // 로봇이 바라보는 방향

    public Robot(int rno, int x, int y, String direction) {
        this.rno = rno;
        this.x = x;
        this.y = y;
        this.direction = Direction.createDirection(direction);
    }

    /**
     * 명령을 해석하고 처리한다.
     * @param command 명령
     * @param robotMap 전체 로봇 위치 정보
     */
    public void readCommand(String command, Robot[][] robotMap) {
        // 반시계 방향으로 90도 회전
        if (command.equals("L")) direction = direction.preDirection();
        // 시계 방향으로 90도 회전
        else if (command.equals("R")) direction = direction.postDirection();
        // 바라보는 방향으로 전진
        else if (command.equals("F")) moveForward(robotMap);
        // throw new RobotException("Unresolved command");
    }

    /**
     * 로봇이 바라보는 방향으로 1칸 전진한다.
     * @param robotMap 전체 로봇 위치 정보
     */
    private void moveForward(Robot[][] robotMap) {
        int nextX = x + direction.getX();   // 전진한 후의 x축 위치
        int nextY = y + direction.getY();   // 전진한 후의 y축 위치

        // 전진 가능 여부를 검사한다.
        try {
            // 전진할 위치에 다른 로봇이 있으면 다른 로봇과의 충돌 예외 발생
            if (robotMap[nextX - 1][nextY - 1] != null)
                throw new RobotException(rno, robotMap[nextX - 1][nextY - 1].rno);
        } catch (ArrayIndexOutOfBoundsException e) {
            // 전진할 위치에 벽이 있으면 벽과의 충돌 예외 발생
            throw new RobotException(rno);
        }
        
        // 충돌이 발생하지 않는다면 전진
        robotMap[x - 1][y - 1] = null;
        robotMap[(x = nextX) - 1][(y = nextY) - 1] = this;
    }
}

public class RobotException extends RuntimeException {

    public RobotException(String message) {
        super(message);
    }

    /**
     * 벽과의 충돌 예외를 던진다.
     * @param rno 충돌하는 로봇의 번호
     */
    public RobotException(int rno) {
        super("Robot " + rno + " crashes into the wall");
    }

    /**
     * 다른 로봇과의 충돌 예외를 던진다.
     * @param from 충돌하는 로봇의 번호
     * @param to 충돌 당하는 로봇의 번호
     */
    public RobotException(int from, int to) {
        super("Robot " + from + " crashes into robot " + to);
    }
}

public enum Direction {
    NORTH(0, "N", 0, 1),
    EAST(1, "E", 1, 0),
    SOUTH(2, "S", 0, -1),
    WEST(3, "W", -1, 0);

    private final int index;        // 방향 번호
    private final String direction; // 방향
    private final int x, y;         // 방향 정보

    Direction(int index, String direction, int x, int y) {
        this.index = index;
        this.direction = direction;
        this.x = x;
        this.y = y;
    }

    /**
     * 방향값을 통해 방향 방향 인스턴스를 생성한다.
     * @param dir 방향값 (N, E, S, W)
     * @return 방향 인스턴스
     */
    public static Direction createDirection(String dir) {
        for (Direction direction : values())
            if (direction.direction.equals(dir)) return direction;
        throw new RuntimeException("Wrong direction is given");
    }

    /**
     * 반시계 방향으로 90도 회전한다.
     * @return 회전한 방향
     */
    public Direction preDirection() {
        return values()[(this.index + values().length - 1) % values().length];
    }

    /**
     * 시계 방향으로 90도 회전한다.
     * @return 회전한 방향
     */
    public Direction postDirection() {
        return values()[(this.index + 1) % values().length];
    }
    
    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }
}
profile
Hello, Devs!

0개의 댓글