diff --git a/build.gradle b/build.gradle index 531750c..6174c60 100644 --- a/build.gradle +++ b/build.gradle @@ -11,5 +11,6 @@ repositories { dependencies { compile('ch.qos.logback:logback-classic:1.2.3') testCompile('junit:junit:4.12') + //testCompile('harcrest-all:org.hamcrest.hamcrest-all:1.3') testCompile('org.assertj:assertj-core:3.9.0') } \ No newline at end of file diff --git a/src/main/java/Todo.md b/src/main/java/Todo.md new file mode 100644 index 0000000..ba601a0 --- /dev/null +++ b/src/main/java/Todo.md @@ -0,0 +1,27 @@ +## Todo List + +- 금액 입력받기 +- 금액에 맞는 로또 구입하기 + done +- 각 로또에 맞는 번호 자동생성 + - 숫자는 1 ~ 45 랜덤값 + done +- 구입한 로또번호 출력 + - 정렬하여 출력 + +- 잔액은 상점이 갖는다. 최대 구입가능한 로또만 구입함. + done + +- 당첨될 로또번호 6개 입력 +- 구매한 로또들의 당첨상황 확인 +- 수익률 계산 +- 당첨상황 및 수익률 출력 + + +## Todo List +1. LottoClient 메소드 + +- 1) 로또결과 (로또 객체와 완전 상관없는 부분) 따로 빼고 클라이언트에서 호출 + - 2) 네이밍 + - 3) 유틸 +- 4) 접근 제어 \ No newline at end of file diff --git a/src/main/java/lotto/HitNumber.java b/src/main/java/lotto/HitNumber.java new file mode 100644 index 0000000..1e8426c --- /dev/null +++ b/src/main/java/lotto/HitNumber.java @@ -0,0 +1,57 @@ +package lotto; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class HitNumber { + final List hitNumbers; + static final String DELIMITER = ", "; + + public HitNumber(String inputNumber) { + if (!isValid(inputNumber)) + throw new IllegalArgumentException(); + hitNumbers = Collections.unmodifiableList( + toIntList(split(inputNumber, DELIMITER))); + } + + + public static boolean isValid(String answer) { + String[] numbers = split(answer, DELIMITER); + return Arrays.asList(numbers) + .stream() + .allMatch(e -> validateNumber(e)) && numbers.length == LottoGenerator.LOTTO_NUMBER_COUNT; + } + + private static boolean validateNumber(String number) { + int num = 0; + try { + num = toInt(number); + } catch (NumberFormatException e) { + return false; + } + if (num > LottoGenerator.NUMBER_UPPER_BOUND || num < LottoGenerator.NUMBER_LOWER_BOUND) return false; + + return true; + } + + private static String[] split(String input, String delimiter) { + return input.split(delimiter); + } + + private static List toIntList(String[] inputStr) { + return Arrays.asList(inputStr).stream().map(e -> toInt(e)).collect(Collectors.toList()); + + } + + private static int toInt(String number) { + return Integer.parseInt(number); + } + + public int increment(int number){ + if(hitNumbers.contains(number)) + return 1; + return 0; + } +} diff --git a/src/main/java/lotto/InputUI.java b/src/main/java/lotto/InputUI.java new file mode 100644 index 0000000..233e136 --- /dev/null +++ b/src/main/java/lotto/InputUI.java @@ -0,0 +1,22 @@ +package lotto; + +import java.util.Scanner; + +public class InputUI { + private static Scanner scanner = new Scanner(System.in); + + public static int getForLottoMoney() { + System.out.println("구입금액을 입력해 주세요"); + try { + return Integer.parseInt(scanner.nextLine()); + } catch (Exception e) { + throw new IllegalArgumentException(); + } + } + + public static String getHitNumber() { + System.out.println("지난 주 당첨 번호를 입력해 주세요."); + return scanner.nextLine(); + } + +} diff --git a/src/main/java/lotto/Lotto.java b/src/main/java/lotto/Lotto.java new file mode 100644 index 0000000..f0bf735 --- /dev/null +++ b/src/main/java/lotto/Lotto.java @@ -0,0 +1,34 @@ +package lotto; + +import java.util.List; + +public class Lotto { + private List lottoNumbers; + + public Lotto() + { + this(LottoGenerator.generateNum()); + } + + private Lotto(List lottoNumbers){ + this.lottoNumbers = lottoNumbers; + } + + + public static Lotto getLottoByInput(List lottoNumbers){ + return new Lotto(lottoNumbers); + } + + public int compareLotto(HitNumber hitNumber) { + int count = 0 ; + for(int number : lottoNumbers) { + count += hitNumber.increment(number); + } + return count; + } + + @Override + public String toString() { + return lottoNumbers.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/lotto/LottoClient.java b/src/main/java/lotto/LottoClient.java new file mode 100644 index 0000000..00d5170 --- /dev/null +++ b/src/main/java/lotto/LottoClient.java @@ -0,0 +1,114 @@ +package lotto; + +import java.util.*; +import java.util.stream.Collectors; + +public class LottoClient { + private static final int LOTTO_PRICE = 1000; + private static Map resultAwardMap; + static { + LOTTO_AWARDS basicAwards = LOTTO_AWARDS.BASIC; + resultAwardMap = new TreeMap(); + resultAwardMap.put(3, basicAwards.getThree_correct()); + resultAwardMap.put(4, basicAwards.getFour_correct()); + resultAwardMap.put(5, basicAwards.getFive_correct()); + resultAwardMap.put(6, basicAwards.getSix_correct()); + } + + private enum LOTTO_AWARDS { + BASIC(5000, 50000, 1500000, 2000000000); + + private int three_correct; + private int four_correct; + private int five_correct; + private int six_correct; + + LOTTO_AWARDS(int three_correct, int four_correct, int five_correct, int six_correct) { + this.three_correct = three_correct; + this.four_correct = four_correct; + this.five_correct = five_correct; + this.six_correct = six_correct; + } + + public int getThree_correct() { + return three_correct; + } + + public int getFour_correct() { + return four_correct; + } + + public int getFive_correct() { + return five_correct; + } + + public int getSix_correct() { + return six_correct; + } + } + + public static void main(String[] args) { + run(); + } + + private static void run() { + printResult(makeLottoes()); + } + + private static List makeLottoes(){ + Money money = new Money(InputUI.getForLottoMoney()); + List lottoes = new LottoFactory().createLotto(maxLottoToBuy(money)); + + ResultUI.printBuyedLottoes( + lottoes.stream() + .map(x -> x.toString()) + .collect(Collectors.toList())); + return lottoes; + } + + private static void printResult(List lottoes){ + HitNumber hitNumber = new HitNumber(InputUI.getHitNumber()); + + List results = calculateResults(lottoes, hitNumber); + + for (Integer numOfHits : resultAwardMap.keySet()) { + ResultUI.printResultStatics( + numOfHits, + resultAwardMap.get(numOfHits), + Collections.frequency(results, numOfHits) + ); + } + ResultUI.printBenefitRate(calculateBenefitRate(lottoes, hitNumber)); + } + + + public static double calculateBenefitRate(List lottoes, HitNumber hitNumber) { + List lottoResults = calculateResults(lottoes, hitNumber); + double sum = getSum(lottoResults); + return floor(sum / (lottoResults.size() * LOTTO_PRICE) * 100); + } + + private static double getSum(List lottoResults) { + return (double) lottoResults.stream() + .filter(x -> resultAwardMap.containsKey(x)) + .mapToInt(x -> resultAwardMap.get(x)) + .sum(); + } + + private static double floor(double target) { + int intTarget = (int) (target * 10); + return intTarget / 10.0; + } + + private static List calculateResults(List lottoes, HitNumber hitNumber) { + List results = new ArrayList(); + for (Lotto lotto : lottoes) { + results.add(lotto.compareLotto(hitNumber)); + } + return results; + } + + public static int maxLottoToBuy(Money money) { + return money.getMoney() / LOTTO_PRICE; + } +} diff --git a/src/main/java/lotto/LottoFactory.java b/src/main/java/lotto/LottoFactory.java new file mode 100644 index 0000000..51d9b4a --- /dev/null +++ b/src/main/java/lotto/LottoFactory.java @@ -0,0 +1,19 @@ +package lotto; + +import java.util.ArrayList; +import java.util.List; + +public class LottoFactory { + LottoGenerator generator; + + public LottoFactory(){ + this.generator = new LottoGenerator(); + } + public List createLotto(int maxLottoCount) { + List newLottoes = new ArrayList(); + for (int i = 0; i < maxLottoCount; i++) { + newLottoes.add(new Lotto()); + } + return newLottoes; + } +} diff --git a/src/main/java/lotto/LottoGenerator.java b/src/main/java/lotto/LottoGenerator.java new file mode 100644 index 0000000..9cb6ccc --- /dev/null +++ b/src/main/java/lotto/LottoGenerator.java @@ -0,0 +1,27 @@ +package lotto; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Random; + +public class LottoGenerator { + public static final int LOTTO_NUMBER_COUNT = 6; + public static final int NUMBER_LOWER_BOUND = 1; + public static final int NUMBER_UPPER_BOUND = 45; + static List validNumberSet; + + static { + validNumberSet = new ArrayList(); + for (int i = NUMBER_LOWER_BOUND ; i < NUMBER_UPPER_BOUND; i++) { + validNumberSet.add(i + 1); + } + } + + public static List generateNum() { + Collections.shuffle(validNumberSet, new Random(System.currentTimeMillis())); + List result = new ArrayList(validNumberSet.subList(0, LOTTO_NUMBER_COUNT)); + Collections.sort(result); + return result; + } +} diff --git a/src/main/java/lotto/Money.java b/src/main/java/lotto/Money.java new file mode 100644 index 0000000..3746588 --- /dev/null +++ b/src/main/java/lotto/Money.java @@ -0,0 +1,16 @@ +package lotto; + +public class Money { + private int money; + + public Money(int money) { + if (money < 0) { + throw new IllegalArgumentException(); + } + this.money = money; + } + + public int getMoney() { + return money; + } +} diff --git a/src/main/java/lotto/ResultUI.java b/src/main/java/lotto/ResultUI.java new file mode 100644 index 0000000..2da1481 --- /dev/null +++ b/src/main/java/lotto/ResultUI.java @@ -0,0 +1,20 @@ +package lotto; + +import java.util.List; + +public class ResultUI { + + public static void printBuyedLottoes(List lottoes) { + System.out.printf("%d개를 구매했습니다.\n", lottoes.size()); + for (String lotto : lottoes) + System.out.println(lotto); + } + + public static void printResultStatics(int numOfHits, int prize, int numOfPrizes) { + System.out.printf("%d개 일치 (%d원)- %d개\n", numOfHits, prize, numOfPrizes); + } + + public static void printBenefitRate(double benefitRate) { + System.out.printf("총 수익률은 %.1f%% 입니다.\n", benefitRate); + } +} diff --git a/src/test/java/TestCaseTest.java b/src/test/java/TestCaseTest.java new file mode 100644 index 0000000..6147e2a --- /dev/null +++ b/src/test/java/TestCaseTest.java @@ -0,0 +1,47 @@ +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestCaseTest { + class TestOutput { + private String prop1; + private int prop2; + + TestOutput(String prop1, int prop2) { + this.prop1 = prop1; + this.prop2 = prop2; + } + } + + List outputList; + String[] outputArr; + TestOutput outputBean; + + String outputStr; + int outputInt; + + String nullObj; + + @Before + public void setUp() { + nullObj = null; + outputStr = "ABC"; + outputInt = 1; + outputList = new ArrayList(); + outputList.add("A-B1"); + outputList.add("A-B2"); + outputList.add("A-B3"); + outputArr = new String[]{"A-B1", "A-B2", "A-B3"}; + outputBean = new TestOutput(outputStr, outputInt); + + } + + @Test + public void contains() { + assertThat("A-B1").isIn(outputList).contains("A-B2", "A-B3"); + } +} diff --git a/src/test/java/lotto/LottoTest.java b/src/test/java/lotto/LottoTest.java new file mode 100644 index 0000000..0235fa5 --- /dev/null +++ b/src/test/java/lotto/LottoTest.java @@ -0,0 +1,114 @@ +package lotto; + +import org.assertj.core.api.SoftAssertions; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class LottoTest { + Lotto singleLotto; + LottoFactory lottoFactory; + + @Before + public void setUp() { + lottoFactory = new LottoFactory(); + singleLotto = new Lotto(); + } + + @Test + public void 로또갯수() { + assertThat(LottoClient.maxLottoToBuy(new Money(5000))).isEqualTo(5); + } + + @Test + public void 로또구입금액딱맞음() { + assertThat(LottoClient.maxLottoToBuy(new Money(5000))).isEqualTo(5); + } + + @Test + public void 로또구입금액잔액있음() { + assertThat(LottoClient.maxLottoToBuy(new Money(5300))).isEqualTo(5); + } + + @Test(expected = IllegalArgumentException.class) + public void 로또구입금액음수() { + new Money(-100); + } + + @Test + public void 로또구입금액그냥돈없음() { + assertThat(LottoClient.maxLottoToBuy(new Money(999))).isEqualTo(0); + } + + @Test + public void 번호자동생성갯수확인() { + assertThat(LottoGenerator.generateNum()).hasSize(6); + } + + @Test + public void 입력로또번호검증성공케이스() { + final String expectedInput = "1, 2, 3, 4, 5, 6"; + SoftAssertions assertions = new SoftAssertions(); + assertions.assertThat(HitNumber.isValid(expectedInput)) + .as("정상 케이스").isTrue(); + assertions.assertThat(HitNumber.isValid("1, 2, 3, 4, 5, 0")) + .as("1보다 작은 애").isFalse(); + assertions.assertThat(HitNumber.isValid("1, 2, 3, 4, 5, 46")) + .as("45 넘는 애").isFalse(); + assertions.assertThat(HitNumber.isValid("1, 2, 3")) + .as("숫자 여섯 개 아닐 떄").isFalse(); + assertions.assertThat(HitNumber.isValid("1, b, 3, 4, 5, 6")) + .as("숫자 자리에 문자일 때").isFalse(); + assertions.assertAll(); + } + + @Test + public void 당첨상황확인() { + HitNumber hitNumbers = new HitNumber("1, 2, 3, 4, 5, 6"); + + SoftAssertions assertions = new SoftAssertions(); + assertions.assertThat(Lotto.getLottoByInput(Arrays.asList(1, 2, 3, 11, 12, 13)).compareLotto(hitNumbers)) + .as("3개케이스").isEqualTo(3); + assertions.assertThat(Lotto.getLottoByInput(Arrays.asList(1, 2, 3, 4, 12, 13)).compareLotto(hitNumbers)) + .as("4개케이스").isEqualTo(4); + assertions.assertThat(Lotto.getLottoByInput(Arrays.asList(1, 2, 3, 4, 5, 13)).compareLotto(hitNumbers)) + .as("5개케이스").isEqualTo(5); + assertions.assertThat(Lotto.getLottoByInput(Arrays.asList(1, 2, 3, 4, 5, 6)).compareLotto(hitNumbers)) + .as("6개케이스").isEqualTo(6); + assertions.assertThat(Lotto.getLottoByInput(Arrays.asList(1, 2, 10, 11, 12, 13)).compareLotto(hitNumbers)) + .as("미당첨케이스").isLessThan(3); + assertions.assertAll(); + } + + @Test + public void 수익률계산() { + double expected_1 = 250; + double expected_2 = 35.7; + Lotto nonHitLotto = Lotto.getLottoByInput(Arrays.asList(11, 12, 13, 14, 15, 16)); + Lotto thirdHitLotto = Lotto.getLottoByInput(Arrays.asList(1, 2 , 3, 14, 15, 16)); + HitNumber hitNumber = new HitNumber("1, 2, 3, 4, 5, 6"); + List lottoes1 = new ArrayList(); + List lottoes2 = new ArrayList(); + lottoes1.add(nonHitLotto); + lottoes1.add(thirdHitLotto); + for(int i = 0 ; i < 13 ; i++){ + lottoes2.add(nonHitLotto); + } + lottoes2.add(thirdHitLotto); + SoftAssertions assertions = new SoftAssertions(); + assertions.assertThat(LottoClient.calculateBenefitRate(lottoes1, hitNumber)) + .as("2개 중 3 등 하나") + .isEqualTo(expected_1); + + assertions.assertThat(LottoClient.calculateBenefitRate(lottoes2,hitNumber)) + .as("14개 중 3 등 하나") + .isEqualTo(expected_2); + + assertions.assertAll(); + } +}