본문 바로가기
백준

[백준, Java] 2174번, 로봇 시뮬레이션(시뮬레이션, 구현)

by 열정적인 이찬형 2023. 6. 15.

주의사항

  • JAVA를 사용하여 프로그램을 사용하였습니다.
  • 백준에서 코드를 작성하였을 때 아래 형태에서 Main에서 결과가 출력되어야 합니다.
public class Main{ 	
	public static void main(String[] args){
    }
}

문제 설명


접근 방법

이 문제에 핵심

1. 로봇이 움직임을 수행하는 명령은 3가지(L, R, F)가 있습니다.

2. 로봇은 N, E, S, W 방향으로 이동할 수 있습니다.

3. 잘못된 명령인 경우 그에 대한 결과를 출력하고, 모든 명령이 수행하면 "OK"를 수행합니다.

4. 충돌이 중복으로 발생하면 가장 먼저 발생하는 충돌을 출력합니다.

 

알고리즘 진행 순서.

 

1. 입력된 정보를 저장합니다.

 

2. 명령에 맞게 로봇의 움직임을 수행합니다.

 

3. 로봇의 충돌이 발생할 때와 모두 수행할 때를 구분해서 결과를 출력합니다.

 

 

로봇의 움직이는 방향

※이 부분을 잘못 해석해서 문제를 푸는데 시간이 조금 더 걸렸습니다.

 

기본적으로 상하좌우로 생각하였지만 그게 잘못되었다.

 

원래대로 BFS를 할 때 상하좌우를 하면 행과 열의 값을 변경하는 값은

 

상 : {-1, 0}

 
하 : {1, 0}
 
좌 : {0, -1}
 
우 : {0, 1}

 

하지만 여기서는 N, E, S, W로 살펴보면

 

N(상) : {1, 0}

 

S(하) : {-1, 0}

 

W(좌) : {0, -1}
 
E(우) : {0, 1}

 

 

로봇의 움직이는 과정

 

 

왼쪽으로 방향 전환 : 'L'

 

if(robot.direction == 'N')
    robot.direction = 'W';
else if(robot.direction == 'E')
    robot.direction = 'N';
else if(robot.direction == 'S')
    robot.direction = 'E';
else
    robot.direction = 'S';

 

오른쪽으로 방향 전환 : 'R'

 

static void rightRotate(Robot robot){
    if(robot.direction == 'N')
        robot.direction = 'E';
    else if(robot.direction == 'E')
        robot.direction = 'S';
    else if(robot.direction == 'S')
        robot.direction = 'W';
    else
        robot.direction = 'N';
}

 

앞으로 전진 : 'F'

 

현재 로봇 방향에 맞게 이동합니다.

 

벽을 마주치면 : Robot X crashes into the wall

 

다른 로봇을 마주치면 : Robot X crashes into robot Y

 

출력한 뒤 모든 명령을 종료해주시면 됩니다.

 

※종료해도 되는 이유?

문제에서 여러 충돌이 발생하면 가장 먼저 충돌한 것을 출력하기 때문에 1번만이라도 충돌이 발생하면 해당 출력문이 결과가 됩니다.

 

예제입력 1.

1. 입력된 정보를 저장합니다.

 

A : 5, B : 4


N : 2, M : 2

 

        2번 로봇(W)
         
         
1번 로봇(E)        


명령문

1 F 7
2 F 7

 

2. 명령에 맞게 로봇의 움직임을 수행합니다.

 

1번 명령(1 F 7) : 1번 로봇을 7번 앞으로 전진해라!!

 

        2번 로봇(W)
         
         
1번 로봇(E) →→(충돌 발생)

 

→ 1번 로봇이 (E)방향으로 움직이다가 벽에 충돌하게 됩니다.

 

잘못된 명령!!!

 

모든 명령 수행 중단!!

 

출력문 : Robot 1 crashes into the wall

 

 

3. 로봇의 충돌이 발생할 때와 모두 수행할 때를 구분해서 결과를 출력합니다.

 

 
로봇의 충돌이  발생하였으므로 가장 먼저 충돌했을 때 출력문을 결과로 출력합니다.

 

Robot 1 crashes into the wall 을 결과로 출력합니다.

 

  • BufferedReader를 사용하여 입력되는 정보를 저장합니다.
  • StringTokenizer를 이용하여 A, B, N, M과 로봇 정보 및 명령을 저장합니다.
  • moveInit함수를 통해 방향별 움직임의 변경값을 초기화하였습니다.
  • M개의 명령을 순차대로 수행합니다.
  • M개의 명령 도중에 충돌이 발생하면 모든 명령을 중단합니다.
  • 충돌이 발생하였을 때는 가장 먼저 충돌할 때 출력문을 BufferedWriter에 저장합니다.
  • 모든 명령을 수행하였을 때 "OK"BufferedWriter에 저장합니다.
  • BufferedWriter에 저장된 결과를 출력합니다.
  • moveInit함수는 방향별 움직임의 변경값을 HashMap<>에 설정합니다.
  • inSpace함수는 움직이는 공간이 벽인지 확인하는 함수입니다.
  • leftRotate함수는 왼쪽으로 90도 회전하는 함수입니다.
  • rigthRotate함수는 오른쪽으로 90도 회전하는 함수입니다.

 

결과코드

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.StringTokenizer;

public class Main {
    //로봇 정보 관련 내부 클래스
    static class Robot{
        int r, c;
        char direction;
        public Robot(int r, int c, char direction){
            this.r = r;
            this.c = c;
            this.direction = direction;
        }
    }
    static HashMap<Character, int[]> move;	//방향별 움직임 저장 HashMap
    static Robot[] robots;	//로봇들 정보 저장 리스트
    static int A, B;	//좌표의 크기 관련 변수
    public static void main(String[] args) throws IOException {
        //입력값 처리하는 BufferedReader
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        //입력값 출력하는 BufferedWriter
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st = new StringTokenizer(br.readLine(), " ");
        StringBuilder sb = new StringBuilder();
        //입력값 A, B, N , M 저장
        A = Integer.parseInt(st.nextToken());
        B = Integer.parseInt(st.nextToken());
        st = new StringTokenizer(br.readLine()," ");
        int N = Integer.parseInt(st.nextToken());
        int M = Integer.parseInt(st.nextToken());
        robots = new Robot[N+1];
        moveInit();	//방향 관련 변경값 초기화
        //로봇 정보 저장
        for(int i=1;i<=N;i++){
            st = new StringTokenizer(br.readLine()," ");
            int c = Integer.parseInt(st.nextToken());
            int r = Integer.parseInt(st.nextToken());
            robots[i] = new Robot(r, c, st.nextToken().charAt(0));
        }
        boolean failFlag = false;	//충돌 발생 여부 확인 변수
        //모든 명령어 수행 과정
        for(int i=0;i<M;i++){
            st = new StringTokenizer(br.readLine()," ");
            int robot_idx = Integer.parseInt(st.nextToken());
            char command = st.nextToken().charAt(0);
            int cnt = Integer.parseInt(st.nextToken());

            Robot cur = robots[robot_idx];	//현재 명령을 수행할 로봇
            //'L' 왼쪽으로 회전
            if(command == 'L'){
                cnt %= 4;
                for(int j=0;j<cnt;j++)
                    leftRotate(cur);
            }
            //'R' 오른쪽으로 회전
            else if(command == 'R'){
                cnt %= 4;
                for(int j=0;j<cnt;j++)
                    rightRotate(cur);
            }
            //'F' 앞으로 이동
            else{
                int[] moveInfo = move.get(cur.direction);
                //반복 횟수만큼 앞으로 이동
                for(int s=0;s<cnt;s++){
                    int tempR = cur.r + moveInfo[0];	//방향에 맞게 y값 변경
                    int tempC = cur.c + moveInfo[1];	//방향에 맞게 x값 변경
                    boolean flag = false;	//충돌 여부 변수
                    if(inSpace(tempR, tempC)){	//벽에 충돌하지 않을 때
                        //다른 로봇과 충돌하는지 확인
                        for(int j=1;j<=N;j++){
                            if(robot_idx == j)	//동일한 로봇일 때
                                continue;
                            //다른 로봇과 충돌이 있을 때
                            if(robots[j].r == tempR && robots[j].c == tempC){
                                flag = true;	//충돌 여부 변경
                                sb.append("Robot ").append(robot_idx).append(" crashes into robot ").append(j);
                                break;
                            }
                        }
                    }else{	//벽과 충돌이 있을 때
                        flag = true;	//충돌 여부 변경
                        sb.append("Robot ").append(robot_idx).append(" crashes into the wall");
                    }
                    if(!flag){	//현재 로봇 이동
                        cur.r = tempR;
                        cur.c = tempC;
                    }else {	//충돌 발생시 명령 종료
                        failFlag = true;
                        break;
                    }
                }
            }
            if(failFlag)	//충돌 발생시 명령 종료
                break;
        }
        if(!failFlag)	//충돌이 발생하지 않으면 모든 명령 수행 완료!
            sb.append("OK");
        bw.write(sb.toString());	//결과 BufferedWriter 저장
        bw.flush();		//결과 출력
        bw.close();
        br.close();
    }
    //방향별 좌표 변경값 초기화하는 함수
    static void moveInit(){
        move = new HashMap<>();
        move.put('N', new int[]{1, 0});
        move.put('E', new int[]{0, 1});
        move.put('S', new int[]{-1, 0});
        move.put('W', new int[]{0, -1});
    }
    //움직일 좌표가 벽에 충돌하지 않는지 확인하는 함수
    static boolean inSpace(int r,int c){
        if(r > 0 && c > 0 && r <= B && c <= A)
            return true;
        return false;
    }
    //오른쪽 90도로 방향을 전환하는 함수
    static void rightRotate(Robot robot){
        if(robot.direction == 'N')
            robot.direction = 'E';
        else if(robot.direction == 'E')
            robot.direction = 'S';
        else if(robot.direction == 'S')
            robot.direction = 'W';
        else
            robot.direction = 'N';
    }
    //왼쪽 90도로 방향을 전환하는 함수
    static void leftRotate(Robot robot){
        if(robot.direction == 'N')
            robot.direction = 'W';
        else if(robot.direction == 'E')
            robot.direction = 'N';
        else if(robot.direction == 'S')
            robot.direction = 'E';
        else
            robot.direction = 'S';
    }
}

댓글