Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ 레이싱 카] 손주선 미션 제출합니다. #745

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
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
27 changes: 11 additions & 16 deletions __tests__/ApplicationTest.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import App from "../src/App.js";
import { MissionUtils } from "@woowacourse/mission-utils";
import { MissionUtils } from '@woowacourse/mission-utils';
import App from '../src/App.js';

const mockQuestions = (inputs) => {
MissionUtils.Console.readLineAsync = jest.fn();
Expand All @@ -9,27 +9,25 @@ const mockQuestions = (inputs) => {
return Promise.resolve(input);
});
};

export default mockQuestions;
const mockRandoms = (numbers) => {
MissionUtils.Random.pickNumberInRange = jest.fn();
numbers.reduce((acc, number) => {
return acc.mockReturnValueOnce(number);
}, MissionUtils.Random.pickNumberInRange);
numbers.reduce((acc, number) => acc.mockReturnValueOnce(number), MissionUtils.Random.pickNumberInRange);
};

const getLogSpy = () => {
const logSpy = jest.spyOn(MissionUtils.Console, "print");
const logSpy = jest.spyOn(MissionUtils.Console, 'print');
logSpy.mockClear();
return logSpy;
};

describe("자동차 경주 게임", () => {
test("전진-정지", async () => {
describe('자동차 경주 게임', () => {
test('전진-정지', async () => {
// given
const MOVING_FORWARD = 4;
const STOP = 3;
const inputs = ["pobi,woni", "1"];
const outputs = ["pobi : -"];
const inputs = ['pobi,woni', '1'];
const outputs = ['pobi : -'];
const randoms = [MOVING_FORWARD, STOP];
const logSpy = getLogSpy();

Expand All @@ -46,17 +44,14 @@ describe("자동차 경주 게임", () => {
});
});

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

// when
const app = new App();

// then
await expect(app.play()).rejects.toThrow("[ERROR]");
await expect(app.play()).rejects.toThrow('[ERROR]');
});
});
76 changes: 76 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
## 🚗레이싱 카 구현하기
## ✅ 1주차 피드백 및 주의 사항
1. 요구사항을 정확히 준수
2. 커밋 메시지를 의미 있게 작성한다.
3. 이름을 통해 의도를 드러낸다.
4. 축약하지 않는다.
- 의도를 드러낼 수 있다면, 이름이 길어져도 좋다
5. 공백도 코딩 컨벤션이다 .
- IF, FOR , WHILE 문 사이의 공백도 코딩 컨벤션이다. => IF , FOR , WHILE 문 뒤에도 습관적으로 공백을 주도록 하자
6. 공백라인을 의미 있게 사용
7. 들여쓰기에 space 와 tab 을 혼용하지 않는다.
8. 의미 없는 주석을 달지 않는다.
- 변수 이름, 함수(메서드) 이름을 통해 어떤 의도인지가 드러난다면, 굳이 주석을 달지 않는다.
9. EOL ( END OF LINE ) 최종 제출하는 코드에서 EOL을 확인한다.
## ✅ 기능 구현 사항
초간단 자동차 경주 게임을 구현한다.

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

### 1. Game Start 시에 , 경주할 자동차의 이름을 입력받는다. ( Console.readlineAsync 활용 )
1-1. 이름은 다섯자 이하만 가능하다. ( .length 를 통해 총 길이 어길 시 , throw 문 활용 에러 메시지 발생 후 애플리케이션 종료(?) )
1-2. 한 명만 진행할 수 있는 가? =>
1-3.

### 2. " 시도할 회수는 몇 회인가요 " 출력 후( Console.print 활용 ) 사용자에게 "몇회" => 숫자를 입력받는다. (Console.readlineAsync 활용 )
2-1. 사용자가 몇회를 입력할 경우에 , 숫자를 입력하지 않은 경우에 => [ERROR] 숫자만 입력이 가능합니다.
2-2. 시도할 수 있는 횟수의 제한은 없는 것인가 ? =>
2-3. 숫자를 입력헀지만 , 0보다 작은 수를 입력한 경우 => [ERROR] 0보다 큰 숫자만 입력이 가능합니다.

### 3. 각 시도에 따른 실행 결과를 PRINT 해야 한다.
3-1. 각각의 플레이어에게, 처음에 빈 배열( [] ) 을 생성해준다.
3-2. 전진 조건 => 0에서 9 사이에서 무작위 값을 구한 후 무작위 값이 4 이상일 경우
- 전진 조건 충족 시, 각 플레이어들의 배열에 - 값을 push 한다.
3-3. TODO : 어떠한 방식으로 각 플레이어가 전진하는 지에 대해서 테스트 할 것 인가 ?
3-4. 한번의 실행시에 모든 플레이어의 실행 결과를 출력한다. ( Console.pring 활용 )

### 4. 마지막 실행 종료시 , 각 플레이어들의 배열의 길이를 비교하여, 제일 긴 플레이어를 선정 한다.
4-1. 우승자는 한명 이상일 경우가 존재한다. 여러 명일 경우, 쉼표(,) 활용하여 구분
4-2. 선택된 우승자를 출력해준다. ( Console.print 활용 )

## 실행 결과 예시
경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)
pobi,woni,jun

시도할 횟수는 몇 회인가요?
5

실행 결과
pobi : -
woni :
jun : -

pobi : --
woni : -
jun : --

pobi : ---
woni : --
jun : ---

pobi : ----
woni : ---
jun : ----

pobi : -----
woni : ----
jun : -----

최종 우승자 : pobi, jun
80 changes: 79 additions & 1 deletion src/App.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,83 @@
import { Console, Random } from '@woowacourse/mission-utils';
import Errors from './message/Errors.js';
import Messages from './message/Messages.js';

function check_name_validate(player_arr) {
if (player_arr.length <= 1) throw new Error(Errors.SHORTAGE_ERROR);
const player_name_set = new Set();

player_arr.forEach((player_name) => {
const trimmed_name = player_name.trim();

if (trimmed_name === '') throw new Error(Errors.NAME_ERROR);
if (trimmed_name.length > 5) throw new Error(Errors.LENGTH_ERROR);
if (player_name_set.has(trimmed_name)) throw new Error(Errors.DUPLICATE_NAME_ERROR);

player_name_set.add(trimmed_name);
});
}
function check_number_validate(play_number) {
if (!play_number.match(/^\d+$/)) {
throw new Error(Errors.NUMBER_ERROR);
}
}

class App {
async play() {}
constructor() {
this.Console = Console;
}

async play() {
const players = [];
await this.Console.readLineAsync(Messages.GAME_START).then((result) => {
const player_input = result.split(',');
check_name_validate(player_input);
player_input.map((player_name) => players.push(player_name));
});

const play_number = await this.Console.readLineAsync(Messages.INSERT_COUNT);
check_number_validate(play_number);
let play_now = 0;
const players_object = players.reduce(
(obj, player) => ({
...obj,
[player]: [],
}),
{},
);

do {
players.forEach((player_name) => {
const random_number = Random.pickNumberInRange(0, 9);
if (random_number <= 4) players_object[player_name].push('-');
Console.print(`${player_name} : ${players_object[player_name].join('')}`);
});
play_now += 1;
} while (play_now < play_number);

const players_arr = Object.entries(players_object);

const winners = players_arr.reduce(
(acc, [player_name, player_result]) => {
if (player_result.length > acc.max) {
return {
max: player_result.length,
players: [player_name],
};
}
if (player_result.length === acc.max) {
acc.players.push(player_name);
}
return acc;
},
{ max: Number.MIN_SAFE_INTEGER, players: [] },
);

Console.print(`${Messages.FINAL_WINNER} ${winners.players.join(',')}`);
}
}

export default App;

// const app = new App();
// app.play();