Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions __tests__/ApplicationTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,17 @@ describe("자동차 경주 게임", () => {
});
});

test.each([
[["pobi,javaji"]],
[["pobi,eastjun"]]
])("이름에 대한 예외 처리", async (inputs) => {
// given
mockQuestions(inputs);

// when
const app = new App();

// then
await expect(app.play()).rejects.toThrow("[ERROR]");
});
test.each([[["pobi,javaji"]], [["pobi,eastjun"]]])(
"이름에 대한 예외 처리",
async (inputs) => {
// given
mockQuestions(inputs);

// when
const app = new App();

// then
await expect(app.play()).rejects.toThrow("[ERROR]");
}
);
});
2 changes: 1 addition & 1 deletion __tests__/StringTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ describe("문자열 테스트", () => {

test("at 메서드로 특정 위치의 문자 찾기", () => {
const input = "abc";
const result = input.at(0)
const result = input.at(0);

expect(result).toEqual("a");
});
Expand Down
40 changes: 40 additions & 0 deletions __tests__/inputTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import App from "../src/App.js";
import { MissionUtils } from "@woowacourse/mission-utils";

const mockUserInput = (inputs) => {
MissionUtils.Console.readLineAsync = jest.fn();

MissionUtils.Console.readLineAsync.mockImplementation(() => {
const input = inputs.shift();
return Promise.resolve(input);
});
};

describe("자동차 경주 게임", () => {
test("올바르지 않은 자동차 이름 예외 처리", async () => {
// given
const inputs = ["pobi,javaji"];

mockUserInput(inputs);

// when
const game = new App();

// then
await expect(game.play()).rejects.toThrow("[ERROR]");
});

test("올바르지 않은 경주 횟수 예외 처리", async () => {
// given
const invalidRound = "0";
const inputs = ["pobi,woni", invalidRound];

mockUserInput(inputs);

// when
const game = new App();

// then
await expect(game.play()).rejects.toThrow("[ERROR]");
});
});
18 changes: 18 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
### 요구사항별 구현 순서

- 주어진 횟수 동안 자동차는 전진 또는 멈출 수 있어야 한다.
- 주어 진 횟수(numberOfRounds)만큼 반복하며 각 자동차를 전진 또는 멈추게 한다.
- 무작위 값을 생성하여 이 값이 4 이상일 때만 자동차를 전진시킨다.
- 각 자동차에 이름을 부여하고 출력할 때 자동차 이름을 함께 출력한다.
- 사용자로부터 자동차 이름을 입력받아 각 자동차에 이름을 부여한다.
- 경주 결과를 출력할 때 자동차 이름과 진행 상황을 함께 출력한다.
- 자동차 이름은 쉼표(,)로 구분하며 이름은 5자 이하만 가능하다.
- 사용자로부터 입력받은 자동차 이름을 쉼표(,)로 분리하여 각 자동차에 부여한다.
- 자동차 이름의 길이를 검사하여 5자 이하만 허용한다.
- 사용자는 몇 번의 이동을 할 것인지를 입력할 수 있어야 한다.
- 사용자로부터 이동 횟수(numberOfRounds)를 입력받는다.
자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다.
- 경주가 종료된 후 우승자를 계산하고 출력한다.
- 우승자가 한 명 이상일 경우 쉼표(,)로 구분하여 출력한다.
- 사용자가 잘못된 값을 입력한 경우 "[ERROR]"로 시작하는 예외를 발생시킨 후 애플리케이션이 종료되어야 한다.
- 사용자 입력값을 검사하여 잘못된 값인 경우 예외를 발생시키고 애플리케이션을 종료한다.
98 changes: 95 additions & 3 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,97 @@
class App {
async play() {}
import { Console, Random } from "@woowacourse/mission-utils";

class RacingGame {
constructor() {
this.carNames = [];
this.numberOfRounds = 0;
this.raceProgress = [];
}

async getCarNames() {
const input = await Console.readLineAsync(
"Enter the car names for the race (separated by commas):"
);
const carNames = input.split(",");
this.validateCarNames(carNames);
}

validateCarNames(names) {
names.forEach((name) => {
if (name.length > 5) {
throw new Error(
"[ERROR] Car names can have a maximum of 5 characters."
);
}
});
this.carNames = names;
}

async getNumberOfRounds() {
const input = await Console.readLineAsync(
"How many rounds would you like to race?"
);
this.validateNumberOfRounds(input);
}

validateNumberOfRounds(rounds) {
const numberOfRounds = parseInt(rounds, 10);
if (isNaN(numberOfRounds) || numberOfRounds < 1) {
throw new Error(
"[ERROR] Please enter a valid number greater than or equal to 1."
);
}
this.numberOfRounds = numberOfRounds;
}

async race() {
Console.print("Race Results");

const initialProgress = new Array(this.carNames.length).fill("");
this.raceProgress = initialProgress;

for (let round = 0; round < this.numberOfRounds; round++) {
this.simulateRound();
}
}

simulateRound() {
for (let carIndex = 0; carIndex < this.carNames.length; carIndex++) {
const random = Random.pickNumberInRange(0, 9);
if (random >= 4) {
this.raceProgress[carIndex] += "-";
}
}
this.displayRaceProgress();
}

displayRaceProgress() {
this.carNames.forEach((name, carIndex) => {
Console.print(name + " : " + this.raceProgress[carIndex]);
});
Console.print("");
}

async determineWinner() {
const progressLengths = this.raceProgress.map(
(progress) => progress.length
);
const maxProgress = Math.max(...progressLengths);
const winners = this.carNames.filter(
(_, index) => progressLengths[index] === maxProgress
);

Console.print("Final Winner(s): " + winners);
}

async play() {
await this.getCarNames();
await this.getNumberOfRounds();
await this.race();
await this.determineWinner();
}
}

export default App;
export default RacingGame;

const game = new RacingGame();
game.play();