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

[자판기] 조나현 미션 제출합니다. #165

Open
wants to merge 37 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
1ca4928
docs : 구현할 기능 목록 정리
chonahyeon Dec 3, 2022
94ea98a
feat(view) : 자판기 게임 메세지
chonahyeon Dec 3, 2022
d1f9a51
feat(exception) : 금액은 숫자만 입력되어야한다
chonahyeon Dec 3, 2022
6650ec6
feat(exception): 상품 추가 입력 양식이 잘못됬을 때
chonahyeon Dec 3, 2022
c3b82b7
feat(view): 상품 추가 입력 받기
chonahyeon Dec 3, 2022
28633f4
feat(exception): 상품 금액이 100원 이상 10원 단위가 아닐 때
chonahyeon Dec 3, 2022
2063666
feat(view): 투입 금액 입력받기
chonahyeon Dec 3, 2022
1a722c0
docs: 상품 가격 예외 처리
chonahyeon Dec 3, 2022
1420216
feat(vendingmachine): 자판기 금액 생성하기
chonahyeon Dec 3, 2022
508080e
feat(moneyGenerator): 자판기가 보유한 금액으로 동전을 생성한다
chonahyeon Dec 3, 2022
6a65f2a
refactor(moneyGenerator): 불필요한 부분 제거
chonahyeon Dec 3, 2022
b9aec22
docs: 구현할 기능 목록 업데이트
chonahyeon Dec 3, 2022
ce6bd69
rename(vendingmachine): 패키지 명 변경
chonahyeon Dec 3, 2022
83631ed
feat: 기능 구현 완료
chonahyeon Dec 3, 2022
3973f7b
refactor(vendingmachine): if문 간결화
chonahyeon Dec 3, 2022
cc6add8
refactor(goods): set 제거
chonahyeon Dec 3, 2022
03d89f2
refactor(goods): 함수 기능 분리하기
chonahyeon Dec 3, 2022
aa9ae82
refactor(exception): 금액이 10원 미만일 때
chonahyeon Dec 3, 2022
cd0f87c
rename(exception): 함수명 수정
chonahyeon Dec 3, 2022
3fa9e75
refactor(goods): 불필요한 함수 제거
chonahyeon Dec 3, 2022
fa7865f
refactor(vendingmachine): stringbuilder 개선
chonahyeon Dec 3, 2022
f863b7d
test(exception): 자판기 게임 예외 테스트
chonahyeon Dec 3, 2022
5f7ed37
fix(exception): 상품 등록 양식 Regex 수정
chonahyeon Dec 3, 2022
f698b2a
test(goods): 상품 구매 테스트
chonahyeon Dec 3, 2022
a19d6f1
refactor(controller): VendingMachineManager 중복된 생성 제거
chonahyeon Dec 4, 2022
8b3854e
rename(controller): 자료형이 들어간 메서드,변수명 수정
chonahyeon Dec 4, 2022
19960e4
rename(vendingmachine): 클래스 명 변경
chonahyeon Dec 4, 2022
9eb9cea
refactor(vendingmachine): 반복 조건 개선
chonahyeon Dec 4, 2022
c63e4b1
refactor(controller): 접근 제어자 변경
chonahyeon Dec 4, 2022
59ee977
refactor(controller): 주석 제거 및 로직 개선
chonahyeon Dec 4, 2022
e32a8e9
refactor(vendingmachine): 코드 간격 조정
chonahyeon Dec 4, 2022
dc96223
refactor(view): 코드 중복 제거하기
chonahyeon Dec 4, 2022
c18814d
rename(goods): 메서드 명 변경
chonahyeon Dec 4, 2022
f6fad65
refactor(goods): replace 개선하기
chonahyeon Dec 4, 2022
f1fd401
rename(goods): c 변수명 수정
chonahyeon Dec 4, 2022
ad64e59
rename(exception): 클래스명 변경
chonahyeon Dec 4, 2022
f566811
refactor(vendingmachine): orElseGet 사용하기
chonahyeon Dec 4, 2022
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: 26 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# 미션 - 자판기

---
### 구현할 기능 목록

👉 자판기 금액
- [X] 자판기가 보유한 금액을 생성한다.

👉 자판기 금액
- [ ] 상품 리스트를 만든다.

👉 잔돈 반환
- [ ] 사용자의 금액이 상품의 최저 가격보다 적으면 잔돈을 반환한다.
- [ ] 모든 상품이 소진된 경우 잔돈을 반환한다.
- [ ] 지폐를 잔돈으로 반환하지 않는다.
- [ ] 잔돈 반환시 현재 보유한 최소 개수의 동전으로 잔돈을 반환한다.
- [ ] 잔돈을 반환할 수 없는 경우 잔돈으로 반환할 수 있는 금액만 반환한다.


👉 예외 사항
- [X] 금액은 숫자만 입력되어야한다.
- [X] 상품가격은 100원부터 시작한다.
- [X] 상품가격은 10원으로 나누어 떨어져야한다.
- [X] 입력 양식에 어긋나면 예외처리
- [X] 개별 상품은 [] 대괄호로 묶인다.
- [X] 상품들은 ; 으로 구분된다.
8 changes: 8 additions & 0 deletions src/main/java/vendingmachine/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
package vendingmachine;

import vendingmachine.controller.VendingMachineController;

public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
VendingMachineController vendingMachineController = new VendingMachineController();
try{
vendingMachineController.gameStart();
}catch (Exception e){
System.out.println(e.getMessage());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exception시 error 메시지 출력 후 재입력을 받아야 하는데 출력 후에 앱이 끝날 것 같아요

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분은 요구사항에서 확인을 못했네요😥

}
}
}
16 changes: 0 additions & 16 deletions src/main/java/vendingmachine/Coin.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package vendingmachine.controller;

import vendingmachine.vendingmachine.Coin;
import vendingmachine.goods.GoodsManager;
import vendingmachine.vendingmachine.CoinMaker;
import vendingmachine.view.InputView;
import vendingmachine.view.OutputView;

public class VendingMachineController {
InputView inputView = new InputView();
OutputView outputView = new OutputView();
CoinMaker coinMaker = new CoinMaker();
GoodsManager goodsManager;

public void gameStart() {
String money = inputView.inputVendingMoney();
makeVendingMachineCoin(money);
}

private void makeVendingMachineCoin(String money) {
coinMaker.randomCoin(money);
outputView.vendingMachineCoin(Coin.makeCoinList());
makeGoodsCataLog();
}

private void makeGoodsCataLog() {
String goodsCataLog = inputView.inputGoodsPriceAmount();
goodsManager = new GoodsManager(goodsCataLog);
InputUserMoney();
}

private void InputUserMoney() {
int money = Integer.parseInt(inputView.inputUserMoney());
outputView.remainMoney(money);
purchaseGoods(money);
}


private void purchaseGoods(int money) {
while (goodsManager.validMinPurchase(money)) {
String goods = inputView.inputPurchaseGoods();
if (!goodsManager.validPurchase(goods, money)) break;

money = goodsManager.purchaseGoods(goods, money);
outputView.remainMoney(money);
}
returnCoin(money);
}

private void returnCoin(int money) {
if (money == 0) return;
outputView.returnCoinList(coinMaker.remainCoinList(money));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package vendingmachine.exception;

import vendingmachine.goods.Goods;

import java.util.HashMap;

public class VendingMachineValidator {

public void allOfValidInput(String money){
validMoneyInputForm(money);
validMoneyType(money);

}

private void validMoneyInputForm(String money) {
final String ONLY_NUMBER = "^[0-9]*$";

if (!money.matches(ONLY_NUMBER))
throw new IllegalArgumentException("[ERROR] 금액은 숫자만 입력하세요.");
}

private void validMoneyType(String money) {
if (Integer.parseInt(money) < 10)
throw new IllegalArgumentException("[ERROR] 자판기 금액은 10원부터 시작입니다.");
if (Integer.parseInt(money) % 10 !=0)
throw new IllegalArgumentException("[ERROR] 자판기 금액은 10원 단위로 입력해주세요.");
}

public void validGoodsName(String goods, HashMap<String, Goods> goodsInfo){
if(goodsInfo.get(goods)==null)
throw new IllegalArgumentException("[ERROR] 상품 리스트에 존재하는 상품만 입력하세요.");
}

public void validGoodsInputForm(String goods) {
final String GOODS_INPUT_FORM = "\\[[0-9가-힇A-Za-z]+,?[0-9]*,?[0-9]*\\];?";

if (goods.replaceAll(GOODS_INPUT_FORM, "").length() != 0)
throw new IllegalArgumentException("[ERROR] 상품명, 가격, 수량은 쉼표로, 개별 상품은 대괄호([])로 묶어주세요.");
}

public void validGoodsMoneyType(String money) {
int subMoney = Integer.parseInt(money);
if (subMoney < 100)
throw new IllegalArgumentException("[ERROR] 상품 가격은 100원부터 시작합니다.");
if (subMoney % 10 != 0)
throw new IllegalArgumentException("[ERROR] 상품 가격은 10원 단위로 입력하세요.");
}
}
28 changes: 28 additions & 0 deletions src/main/java/vendingmachine/goods/Goods.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package vendingmachine.goods;

public class Goods {
private int price;
private int amount;

public Goods(String[] goodsInformation){
makeGoodsInfo(goodsInformation);
}

public int getAmount() {
return amount;
}

public int getPrice() {
return price;
}

public void reduceAmount() {
amount--;
}

void makeGoodsInfo(String[] goodsInformation) {
price = Integer.parseInt(goodsInformation[1]);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

숫자 보다 상수를 이용하면 좋을 것 같아요

amount = Integer.parseInt(goodsInformation[2]);
}
}

54 changes: 54 additions & 0 deletions src/main/java/vendingmachine/goods/GoodsManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package vendingmachine.goods;

import vendingmachine.exception.VendingMachineValidator;

import java.util.HashMap;

public class GoodsManager {
VendingMachineValidator vendingMachineValidator = new VendingMachineValidator();
private final HashMap<String, Goods> goodsInfo = new HashMap<>();
private int minPrice = Integer.MAX_VALUE;


public GoodsManager(String goodsList){
makeGoodsInformation(goodsList);
minPriceGoodsList();
}

private void makeGoodsInformation(String goodsList) {
String[] itemList = goodsList.split(";");

for (String item : itemList) {
String[] goodsInformation = item.replaceAll("[\\[\\]]","").split(",");

vendingMachineValidator.validGoodsMoneyType(goodsInformation[1]);

Goods goods = new Goods(goodsInformation);
goodsInfo.put(goodsInformation[0],goods);
}
}

private void minPriceGoodsList() {
for (Goods g : goodsInfo.values())
if (g.getPrice() < minPrice) minPrice = g.getPrice();
}

public boolean validPurchase(String purchaseGoods, int money) {
vendingMachineValidator.validGoodsName(purchaseGoods,goodsInfo);
Goods goods = goodsInfo.get(purchaseGoods);
return goods.getPrice() <= money && goods.getAmount() != 0;
}

public boolean validMinPurchase(int money) {
return money >= minPrice;
}

public int purchaseGoods(String purchaseGoods, int money) {
Goods goods = goodsInfo.get(purchaseGoods);
if (goods.getAmount() != 0)
goods.reduceAmount();
return money - goods.getPrice();
}


}
44 changes: 44 additions & 0 deletions src/main/java/vendingmachine/vendingmachine/Coin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package vendingmachine.vendingmachine;

import java.util.Arrays;

public enum Coin {
COIN_500(500, 0),
COIN_100(100, 0),
COIN_50(50, 0),
COIN_10(10, 0);

private final int amount;
private int count;

Coin(final int amount, final int count) {
this.amount = amount;
this.count = count;
}


// 추가 기능 구현
public int getCount() {
return count;
}

public int getAmount() {
return amount;
}

public void addCoin() {
count++;
}

public static Coin getCoin(int amount) {
return Arrays.stream(values()).filter(a -> a.getAmount() == amount).findAny().orElseGet(() -> null);
}

public static StringBuilder makeCoinList() {
StringBuilder sb = new StringBuilder();
Arrays.stream(values()).forEach(coin -> sb.append(coin.getAmount()).append("원 - ").append(coin.getCount()).append("개").append("\n"));
return sb;
}


}
43 changes: 43 additions & 0 deletions src/main/java/vendingmachine/vendingmachine/CoinMaker.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package vendingmachine.vendingmachine;

import camp.nextstep.edu.missionutils.Randoms;

import java.util.*;

public class CoinMaker {

public void randomCoin(String money) {
int vendingMoney = Integer.parseInt(money);
List<Integer> vendingMoneyList = Arrays.asList(500, 100, 50, 10);

while (vendingMoney != 0) {
int num = Randoms.pickNumberInList(vendingMoneyList);
if (vendingMoney - num >= 0) {
vendingMoney -= num;
Coin.getCoin(num).addCoin();
}
}

}

public HashMap<Integer, Integer> remainCoinList(int money) {
HashMap<Integer, Integer> coinList = new LinkedHashMap<>();

for (Coin coin : Coin.values()) {
if (money <= 0) break;
int require = money / coin.getAmount();

if (require > coin.getCount()) {
money -= (coin.getCount() * coin.getAmount());
coinList.put(coin.getAmount(), coin.getCount());
continue;
}

money -= (require * coin.getAmount());
coinList.put(coin.getAmount(), require);
}
return coinList;
}


}
12 changes: 12 additions & 0 deletions src/main/java/vendingmachine/view/GameMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package vendingmachine.view;

public class GameMessage {
public static final String INPUT_VENDINGMACHINE_MONEY = "자판기가 보유하고 있는 금액을 입력해 주세요.";
public static final String INPUT_GOODS_PRICE_AMOUNT = "상품명과 가격, 수량을 입력해 주세요.";
public static final String INPUT_USER_MONEY = "투입 금액을 입력해 주세요.";
public static final String INPUT_PURCHASE_GOODS = "구매할 상품명을 입력해 주세요.";

public static final String OUTPUT_USER_MONEY = "투입 금액: ";
public static final String OUTPUT_VENDINGMACHINE_MONEY = "자판기가 보유한 동전";
public static final String OUTPUT_REMAIN_MONEY = "잔돈";
}
36 changes: 36 additions & 0 deletions src/main/java/vendingmachine/view/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package vendingmachine.view;

import camp.nextstep.edu.missionutils.Console;
import vendingmachine.exception.VendingMachineValidator;

public class InputView {
VendingMachineValidator vendingMachineValidator = new VendingMachineValidator();

public String inputVendingMoney(){
System.out.println(GameMessage.INPUT_VENDINGMACHINE_MONEY);
String vendingMoney = Console.readLine();
vendingMachineValidator.allOfValidInput(vendingMoney);
return vendingMoney;
}

public String inputGoodsPriceAmount(){
System.out.println(GameMessage.INPUT_GOODS_PRICE_AMOUNT);
String goods = Console.readLine();
vendingMachineValidator.validGoodsInputForm(goods);
return goods;
}

public String inputUserMoney(){
System.out.println(GameMessage.INPUT_USER_MONEY);
String userMoney = Console.readLine();
vendingMachineValidator.allOfValidInput(userMoney);
return userMoney;
}

public String inputPurchaseGoods(){
System.out.println(GameMessage.INPUT_PURCHASE_GOODS);
String goods = Console.readLine();
return goods;
}

}
Loading