우아한 테크코스]프리코스 2주차 - 기능 요구 사항

손지민·2023년 10월 31일
0

기능 요구 사항

초간단 자동차 경주 게임을 구현한다.

  • 주어진 횟수 동안 n대의 자동차는 전진 또는 멈출 수 있다.
  • 각 자동차에 이름을 부여할 수 있다. 전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다.
  • 자동차 이름은 쉼표(,)를 기준으로 구분하며 이름은 5자 이하만 가능하다.
  • 사용자는 몇 번의 이동을 할 것인지를 입력할 수 있어야 한다.
  • 전진하는 조건은 0에서 9 사이에서 무작위 값을 구한 후 무작위 값이 4 이상일 경우이다.
  • 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우승자는 한 명 이상일 수 있다.
  • 우승자가 여러 명일 경우 쉼표(,)를 이용하여 구분한다.
  • 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생시킨 후 애플리케이션은 종료되어야 한다.

작성한 코드

package racingcar;

import camp.nextstep.edu.missionutils.Console;
import camp.nextstep.edu.missionutils.Randoms;

import java.util.ArrayList;
import java.util.List;

public class Application {

    public static void main(String[] args) {
        try {
            List<Car> cars = createCars(); // 차 생성
            int tryCount = getTryCount(); // 시도 횟수

            for (int i = 0; i < tryCount; i++) { // 입력한 시도 횟수만큼 반복
                race(cars); // 자동차 무작위 값에 따라 전진 여부를 결정(1회전)하고 업데이트
                printCurrentPositions(cars); // 차량 위치 업데이트 후 현재 자동차들의 위치를 출력
            }

            List<String> winners = getWinners(cars); // 우승자를 결정하여 반환
            announceWinner(winners); // 우승자를 알림
        } catch (IllegalArgumentException e) {
            handleException(e); // 예외 처리 메서드 호출
        }
    }

    // 예외 처리를 위한 메서드
    private static void handleException(IllegalArgumentException e) {
        System.out.println("예외가 발생했습니다: " + e.getMessage());
        throw e; // 예외 다시 던지기
    }

    // 사용자로부터 입력받은 자동차 이름을 리스트에 추가하여 반환하는 메서드
    private static List<Car> createCars() {
        System.out.println("경주할 자동차 이름을 입력하세요. (이름은 쉼표(,) 기준으로 구분)");
        String input = Console.readLine();
        String[] carNames = input.split(",");
        List<Car> cars = new ArrayList<>();

        for (String name : carNames) {
            try {
                validateCarName(name);
                cars.add(new Car(name.trim()));
            } catch (IllegalArgumentException e) {
                throw e; // 발생한 예외를 상위 메서드로 다시 던집니다
            }
        }

        return cars;
    }

    // 입력받은 자동차 이름이 유효한지 검증하는 메서드
    private static void validateCarName(String name) {
        if (name.length() > 5) {
            throw new IllegalArgumentException("자동차 이름은 5자 이하여야 합니다.");
        }
    }

    // 사용자로부터 시도 횟수를 입력받아 반환하는 메서드
    private static int getTryCount() {
        System.out.println("시도할 회수는 몇 회인가요?");
        String input = Console.readLine();

        try {
            return Integer.parseInt(input);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("숫자를 입력해주세요.");
        }
    }

    // 주어진 자동차 리스트에 대해 무작위 값에 따라 전진 여부를 결정하고 업데이트하는 메서드
    private static void race(List<Car> cars) {
        for (Car car : cars) { // 차 수만큼 반복 1회전
            car.move(Randoms.pickNumberInRange(0, 9));
        }
    }

    // 현재 자동차들의 위치를 출력하는 메서드, 차량 수만큼
    private static void printCurrentPositions(List<Car> cars) {
        System.out.println();
        for (Car car : cars) {
            System.out.println(car.getName() + " : " + "-".repeat(car.getPosition()));
        }
        System.out.println();
    }

    // 우승자를 결정하여 반환하는 메서드
    private static List<String> getWinners(List<Car> cars) {
        int maxPosition = 0;
        List<String> winners = new ArrayList<>();

        for (Car car : cars) {
            if (car.getPosition() > maxPosition) {
                maxPosition = car.getPosition();
            }
        }

        for (Car car : cars) {
            if (car.getPosition() == maxPosition) {
                winners.add(car.getName());
            }
        }

        return winners;
    }

    // 우승자를 알리는 메시지를 출력하는 메서드
    private static void announceWinner(List<String> winners) {
        String winnerName = String.join(", ", winners);
        System.out.println("최종 우승자 : " + winnerName);
    }
}

// 자동차를 나타내는 클래스
class Car {
    private final String name; // 자동차 이름
    private int position; // 현재 위치

    // 생성자: 자동차의 이름을 받아 초기 위치를 0으로 설정
    public Car(String name) {
        this.name = name;
        this.position = 0;
    }
    // 주사위를 굴려 나온 숫자에 따라 위치를 변경
    public void move(int number) {
        if (number >= 4) {
            this.position++;
        }
    }

    // 자동차 이름 반환
    public String getName() {
        return name;
    }

    // 현재 위치 반환
    public int getPosition() {
        return position;
    }
}

마주한 문제

1. 들여쓰기 간격이 너무 좁게 나타남

2. 환경세팅 초기화하니 또 한글 깨짐

3. IllegalArgumentException의 처리

  • 발생한 IllegalArgumentException은 main 메서드에서 호출한 getTryCount()와 validateCarName()내에서 던져지므로, main 메서드는 이 예외를 처리하지 않습니다. 대신, 예외는 main 메서드가 포함된 프로그램 전체에서 전파됩니다. Java 프로그램은 기본적으로 예외를 처리하는 메커니즘이 내장되어 있어, 해당 예외가 처리되지 않으면 프로그램이 중단됩니다.

1주차에 illeagalArgumentException 처리 방식

  • 예외를 main으로 던지고 처리하도록 배웠는데, 예외 발생 후 종료되게하려면 System.exit(o)을 사용하고 싶은데, 요구사항에 System.exit(o)을 사용하지 않게 되어있어 처리하지않고, 알아서 종료되게 두었다.

2주차 IllegalArgumentException main으로 전파

  • 예외를 던지면 잡아서 처리해야된다고 배워서 그냥 오류 난 곳에서 illegalArgumentException 발생시키고 알아서 Java 프로그램이 처리하게 두고 끝날게 아니라 main으로 전파하여 예외 처리하고자했다. main에 try{}catch(){}를 사용하여 던진거 받아서 다시 예외처리하고자 했다.
    1. validateCarName()->createCars()->main()->handleException(IllegalArgumentException e)->main()->예외 처리가 안돼서 종료
    2. getTryCount()->main->handleException()->main()->예외 처리가 안돼서 종료

4. 예외를 전파해서 메인까지는 보냈는데 예외 처리가 안돼서 프로그램이 종료되게 하는 방식이 맞는건지 잘 모르겠다.

ChatGpt 한테 물어본 문제점

  • 이 코드에서 자동차 이름을 5자 이상으로 설정하면 IllegalArgumentException이 발생합니다. 이는 validateCarName() 메소드에서 수행되며, 자동차의 이름이 5자를 초과하는 경우 예외를 발생시킵니다.
    handleException()은 이 예외를 캐치하고 메시지를 출력한 뒤에, 다시 해당 예외를 던집니다. 이것이 프로그램 종료로 이어지는 과정입니다. 주의해야 할 점은 handleException()은 예외를 다시 던지지만, 이 예외를 처리하는 데 필요한 추가적인 조치가 없어서 해당 예외가 main()으로 전파되어 프로그램이 종료되는 것입니다.
    코드에서 handleException()이 예외를 다시 던지고 있지만, main() 메소드에서 이 예외를 적절하게 처리하지 않고 있어서 프로그램이 종료되고 있습니다. 이러한 예외처리 로직이 아직 미비하여 프로그램이 그냥 종료되는 것입니다.
    • 예외를 처리하고 종료하는 방법이 있나? 과제에서 원하는 방식이 뭘까?

5. Car 클래스를 분리해서 호출해서 사용하고 싶은데 안됨.

  • class Car 을 같은 Application.java 클래스 안에서 만들어서 정상 동작함.
    • 새로운 Car.java 클래스 파일을 Application.java랑 같은 racingcar 패키지 안에서 만들면 호출해서 쓸 수 있을거라고 생각했는데 호출해서 사용이 안된다... 어디가 문제일까?

일단 되는 방법 1

racingcar 패키지 안에 java 클래스 파일 만들면 호출 안되는데, racingcar 밖에 car 패키지 만들고 그 안에 Car.java 파일 넣고, car.Car 호출하니까 된다. 왜 그럴까?

profile
Developer

0개의 댓글