diff --git a/README.md b/README.md index 7c9722c..591cf11 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,47 @@ # ๐Ÿš€ ๋กœ๋˜ 1๋‹จ๊ณ„ - ์ž๋™ +## ๐Ÿ“‹๊ธฐ๋Šฅ ๊ตฌํ˜„ ๋ชฉ๋ก +* **UI ๋กœ์ง** + - [x] ๊ตฌ๋งค ๊ธˆ์•ก ์ž…๋ ฅ + - [x] ๋‹น์ฒจ ๋ฒˆํ˜ธ ์ž…๋ ฅ(๋ณด๋„ˆ์Šค ๋ณผ) + - [x] ๋กœ๋˜ ๋ฒˆํ˜ธ ์ถœ๋ ฅ + - [x] ๋‹น์ฒจ ๊ธˆ์•ก ์ถœ๋ ฅ + - [x] ์ˆ˜์ต๋ฅ  ์ถœ๋ ฅ + +* **๋น„์ง€๋‹ˆ์Šค ๋กœ์ง** + - [x] ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” 45๊นŒ์ง€ ํ—ˆ์šฉ + - [x] ๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” 6๊ฐœ + - [x] ๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋Š” 1๊ฐœ + - [x] ๋กœ๋˜ ํ•œ ์žฅ ๋‹น ๊ฐ€๊ฒฉ์€ 1000์› + - [x] ๋กœ๋˜ ํ‹ฐ์ผ“ ๊ฐฏ์ˆ˜ ๊ณ„์‚ฐ + - [x] ๋กœ๋˜ ๋ฒˆํ˜ธ ์ƒ์„ฑ + - [x] ์ผ์น˜ ์—ฌ๋ถ€ ํ™•์ธ + - [x] ๋‹น์ฒจ ๊ธˆ์•ก ๊ณ„์‚ฐ + - [x] ์ˆ˜์ต๋ฅ  ๊ณ„์‚ฐ + + +## ๐ŸŽฏ์˜ˆ์™ธ ์‚ฌํ•ญ ๋ชฉ๋ก +* **๊ตฌ๋งค ๊ธˆ์•ก ์ž…๋ ฅ** + - [x] 1000์› ์ดํ•˜์ผ ๊ฒฝ์šฐ + - [x] 1000์› ๋‹จ์œ„๊ฐ€ ์•„๋‹ ๊ฒฝ์šฐ + +* **๋กœ๋˜ ๋ฒˆํ˜ธ ์ž…๋ ฅ** + - [x] 46 ์ด์ƒ์˜ ์ž…๋ ฅ์ด ์žˆ์„ ๊ฒฝ์šฐ + - [x] ์ค‘๋ณต๋œ ์ˆ˜๊ฐ€ ์ž…๋ ฅ๋  ๊ฒฝ์šฐ + - [x] 6๊ฐœ ์ด์ƒ ์ž…๋ ฅ ๋  ๊ฒฝ์šฐ + - [x] ๋ณด๋„ˆ์Šค ๋ณผ์ด 1๊ฐœ ์ด์ƒ ์ž…๋ ฅ ๋  ๊ฒฝ์šฐ + + +## ํด๋ž˜์Šค ๋ฐ ๋งค์†Œ๋“œ +- Application +- Lotto +- Lottos +- WinningNumber +- Printer +- Receiver + + + ## ๊ธฐ๋Šฅ ์š”๊ตฌ์‚ฌํ•ญ - ๋กœ๋˜ ๊ตฌ์ž… ๊ธˆ์•ก์„ ์ž…๋ ฅํ•˜๋ฉด ๊ตฌ์ž… ๊ธˆ์•ก์— ํ•ด๋‹นํ•˜๋Š” ๋กœ๋˜๋ฅผ ๋ฐœ๊ธ‰ํ•ด์•ผ ํ•œ๋‹ค. - ๋กœ๋˜ 1์žฅ์˜ ๊ฐ€๊ฒฉ์€ 1000์›์ด๋‹ค. diff --git a/build.gradle b/build.gradle index db8d2fd..81a4222 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'java' apply plugin: 'eclipse' version = '1.0.0' -sourceCompatibility = 1.8 +sourceCompatibility = 14 repositories { mavenCentral() diff --git a/src/main/java/empty.txt b/src/main/java/empty.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/lotto/LottoApplication.java b/src/main/java/lotto/LottoApplication.java new file mode 100644 index 0000000..4de7857 --- /dev/null +++ b/src/main/java/lotto/LottoApplication.java @@ -0,0 +1,90 @@ + package lotto; + +import lotto.domain.Statistics; +import lotto.domain.factory.Issuer; +import lotto.domain.lotto.LottoTickets; +import lotto.domain.lotto.WinningNumber; +import lotto.domain.result.GameResults; +import lotto.ui.Printer; +import lotto.ui.Receiver; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class LottoApplication { + private static final String LOTTO_NUMBER_INPUT_DELIMITER = ", "; + private static final int LOTTO_TICKET_PRICE = 1000; + private static final String LOTTO_TICKET_PRICE_RANGE_EXCEPTION_MESSAGE = + "์ˆ˜๋™ ๊ตฌ๋งค ํ‹ฐ์ผ“์˜ ๊ฐฏ์ˆ˜๊ฐ€ ๊ตฌ์ž… ๊ธˆ์•ก์„ ์ดˆ๊ณผํ–ˆ์Šต๋‹ˆ๋‹ค."; + + private final Printer printer; + private final Receiver receiver; + + public LottoApplication(Printer printer, Receiver receiver) { + this.printer = printer; + this.receiver = receiver; + } + + public static void main(String[] args) { + LottoApplication app = new LottoApplication(new Printer(), new Receiver(System.in)); + app.run(); + } + + public void run() { + int purchaseAmount = receivePurchaseAmount(); + int manualTicketCount = receiveManualTicketCount(purchaseAmount); + LottoTickets lottoTickets = Issuer.issueManualLottoTickets(manualTicketCount, receiveManualTicketNumber(manualTicketCount)); + lottoTickets.addTickets(Issuer.issueLottoTickets(purchaseAmount, manualTicketCount)); + printer.printIssuedTickets(lottoTickets, manualTicketCount); + + WinningNumber winningNumber = new WinningNumber(receiveWinningNumber(), receiveBonusNumber()); + GameResults gameResults = lottoTickets.matchNumbers(winningNumber); + Statistics statistics = new Statistics(gameResults, purchaseAmount); + printer.printStatistics(statistics); + } + + private int receivePurchaseAmount() { + printer.requestPurchaseAmount(); + String purchaseAmount = receiver.receiveLine(); + return Integer.parseInt(purchaseAmount); + } + + private int receiveManualTicketCount(int purchaseAmount) { + printer.requestManualTicketCount(); + int manualTicketCount = Integer.parseInt(receiver.receiveLine()); + if(manualTicketCount > purchaseAmount/LOTTO_TICKET_PRICE){ + throw new IllegalArgumentException(LOTTO_TICKET_PRICE_RANGE_EXCEPTION_MESSAGE); + } + return manualTicketCount; + } + + private List> receiveManualTicketNumber(int manualTicketCount) { + printer.requestManualTicketNumber(); + List> manualTickets = new ArrayList<>(); + for(int count = 0; count receiveWinningNumber() { + printer.requestWinningNumber(); + String winningNumber = receiver.receiveLine(); + + return Arrays.stream(winningNumber.split(LOTTO_NUMBER_INPUT_DELIMITER)) + .map(Integer::valueOf) + .collect(Collectors.toList()); + } + + private int receiveBonusNumber() { + printer.requestBonusNumber(); + String bonusNumber = receiver.receiveLine(); + return Integer.parseInt(bonusNumber); + } +} diff --git a/src/main/java/lotto/domain/MatchCount.java b/src/main/java/lotto/domain/MatchCount.java new file mode 100644 index 0000000..5347988 --- /dev/null +++ b/src/main/java/lotto/domain/MatchCount.java @@ -0,0 +1,27 @@ +package lotto.domain; +public class MatchCount { + private final int matchCount; + private final boolean isBonusMatch; + public MatchCount(int matchCount, boolean isBonusMatch) { + this.matchCount = matchCount; + this.isBonusMatch = isBonusMatch; + } + public boolean isUnderThree() { + return matchCount < 3; + } + public boolean isMatchThree() { + return matchCount == 3; + } + public boolean isMatchFour() { + return matchCount == 4; + } + public boolean isMatchFiveWithoutBonus() { + return matchCount == 5 && !isBonusMatch; + } + public boolean isMatchFiveWithBonus() { + return matchCount == 5 && isBonusMatch; + } + public boolean isAllMatch() { + return matchCount == 6; + } +} \ No newline at end of file diff --git a/src/main/java/lotto/domain/Statistics.java b/src/main/java/lotto/domain/Statistics.java new file mode 100644 index 0000000..d90f9f2 --- /dev/null +++ b/src/main/java/lotto/domain/Statistics.java @@ -0,0 +1,35 @@ +package lotto.domain; + +import lotto.domain.dto.WinningResult; +import lotto.domain.result.GameResult; +import lotto.domain.result.GameResults; + +import java.util.List; +import java.util.stream.Collectors; + +public class Statistics { + private static final int IS_EQUAL_RATE = 1; + + private final GameResults gameResults; + private final int purchaseAmount; + + public Statistics(GameResults gameResults, int purchaseAmount) { + this.gameResults = gameResults; + this.purchaseAmount = purchaseAmount; + } + + public List winningResults() { + return GameResult.valuesWithoutUnderThreeMatched() + .stream() + .map(gameResult -> new WinningResult(gameResults.count(gameResult), gameResult)) + .collect(Collectors.toList()); + } + + public double calculateEarningRate() { + return gameResults.calculatePrize() / purchaseAmount; + } + + public boolean isProfit(double earningRate) { + return earningRate > IS_EQUAL_RATE; + } +} diff --git a/src/main/java/lotto/domain/dto/WinningResult.java b/src/main/java/lotto/domain/dto/WinningResult.java new file mode 100644 index 0000000..46f64b1 --- /dev/null +++ b/src/main/java/lotto/domain/dto/WinningResult.java @@ -0,0 +1,18 @@ +package lotto.domain.dto; + +import lotto.domain.result.GameResult; + +public class WinningResult { + private final int numberOfWinners; + private final GameResult gameResult; + public WinningResult(int numberOfWinners, GameResult gameResult) { + this.numberOfWinners = numberOfWinners; + this.gameResult = gameResult; + } + public int getNumberOfWinners() { + return numberOfWinners; + } + public GameResult getGameResult() { + return gameResult; + } +} \ No newline at end of file diff --git a/src/main/java/lotto/domain/factory/Issuer.java b/src/main/java/lotto/domain/factory/Issuer.java new file mode 100644 index 0000000..426f9de --- /dev/null +++ b/src/main/java/lotto/domain/factory/Issuer.java @@ -0,0 +1,35 @@ +package lotto.domain.factory; +import lotto.domain.lotto.LottoTicket; +import lotto.domain.lotto.LottoTickets; + +import java.util.ArrayList; +import java.util.List; +public class Issuer { + private static final int TICKET_PRICE = 1000; + private static final int MINIMUM_NUMBER_OF_TICKETS = 1; + private static final String MONEY_AMOUNT_EXCEPTION_MESSAGE = "๊ธˆ์•ก์€ " + TICKET_PRICE + "์› ์ด์ƒ์œผ๋กœ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."; + + public static LottoTickets issueManualLottoTickets(int manualTicketCount, List> manualLottoTicketNumbers){ + validate(manualTicketCount); + List manualLottoTickets = new ArrayList<>(); + for(int i = 0; i lottoTickets = new ArrayList<>(); + for (int i = 0; i < numberOfTickets; i++) { + lottoTickets.add(new LottoTicket()); + } + return new LottoTickets(lottoTickets); + } + private static void validate(int numberOfTickets) { + if (numberOfTickets < MINIMUM_NUMBER_OF_TICKETS) { + throw new IllegalArgumentException(MONEY_AMOUNT_EXCEPTION_MESSAGE); + } + } +} \ No newline at end of file diff --git a/src/main/java/lotto/domain/lotto/LottoNumber.java b/src/main/java/lotto/domain/lotto/LottoNumber.java new file mode 100644 index 0000000..a6f1a48 --- /dev/null +++ b/src/main/java/lotto/domain/lotto/LottoNumber.java @@ -0,0 +1,52 @@ +package lotto.domain.lotto; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +public class LottoNumber { + private static final int LOTTO_NUMBER_LOWER_BOUND = 1; + private static final int LOTTO_NUMBER_UPPER_BOUND = 45; + private static final String LOTTO_NUMBER_RANGE_EXCEPTION_MESSAGE = + "๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” " + LOTTO_NUMBER_LOWER_BOUND + " ์ด์ƒ, " + LOTTO_NUMBER_UPPER_BOUND + " ์ดํ•˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."; + private final int lottoNumber; + public LottoNumber(int lottoNumber) { + validate(lottoNumber); + this.lottoNumber = lottoNumber; + } + private void validate(int lottoNumber) { + if (!isInRange(lottoNumber)) { + throw new IllegalArgumentException(LOTTO_NUMBER_RANGE_EXCEPTION_MESSAGE); + } + } + private boolean isInRange(int lottoNumber) { + return lottoNumber >= LOTTO_NUMBER_LOWER_BOUND && lottoNumber <= LOTTO_NUMBER_UPPER_BOUND; + } + public static List range() { + return IntStream.range(LOTTO_NUMBER_LOWER_BOUND, LOTTO_NUMBER_UPPER_BOUND + 1) + .boxed() + .map(LottoNumber::new) + .collect(Collectors.toList()); + } + public static List setManualNumber(List manualNumber){ + List lottoNumberManualNumber = new ArrayList<>(); + for (Integer integer : manualNumber) { + lottoNumberManualNumber.add(new LottoNumber(integer)); + } + return lottoNumberManualNumber; + } + public int getLottoNumber() { + return lottoNumber; + } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + LottoNumber that = (LottoNumber) o; + return lottoNumber == that.lottoNumber; + } + @Override + public int hashCode() { + return Objects.hash(lottoNumber); + } +} \ No newline at end of file diff --git a/src/main/java/lotto/domain/lotto/LottoTicket.java b/src/main/java/lotto/domain/lotto/LottoTicket.java new file mode 100644 index 0000000..865b3e6 --- /dev/null +++ b/src/main/java/lotto/domain/lotto/LottoTicket.java @@ -0,0 +1,35 @@ +package lotto.domain.lotto; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; +public class LottoTicket { + private static final int NUMBER_OF_LOTTO_NUMBERS = 6; + private List lottoNumbers; + + public LottoTicket() { + List lottoNumbers = LottoNumber.range(); + lottoNumbers = generateLottoNumbers(lottoNumbers); + this.lottoNumbers = new ArrayList<>(lottoNumbers); + } + public LottoTicket(List manualLottoNumbers){ + List lottoNumbers = LottoNumber.setManualNumber(manualLottoNumbers); + this.lottoNumbers = new ArrayList<>(lottoNumbers); + } + + private List generateLottoNumbers(List lottoNumbers) { + Collections.shuffle(lottoNumbers); + lottoNumbers = lottoNumbers.stream() + .limit(NUMBER_OF_LOTTO_NUMBERS) + .sorted(Comparator.comparing(LottoNumber::getLottoNumber)) + .collect(Collectors.toList()); + return lottoNumbers; + } + public boolean contains(LottoNumber lottoNumber) { + return lottoNumbers.contains(lottoNumber); + } + public List getLottoNumbers() { + return lottoNumbers; + } +} \ No newline at end of file diff --git a/src/main/java/lotto/domain/lotto/LottoTickets.java b/src/main/java/lotto/domain/lotto/LottoTickets.java new file mode 100644 index 0000000..305c052 --- /dev/null +++ b/src/main/java/lotto/domain/lotto/LottoTickets.java @@ -0,0 +1,26 @@ +package lotto.domain.lotto; +import lotto.domain.result.GameResult; +import lotto.domain.result.GameResults; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +public class LottoTickets { + private final List lottoTickets; + public LottoTickets(List lottoTickets) { + this.lottoTickets = new ArrayList<>(lottoTickets); + } + public void addTickets(LottoTickets lottoTickets){ + this.lottoTickets.addAll(lottoTickets.getLottoTickets()); + } + public GameResults matchNumbers(WinningNumber winningNumber) { + List results = lottoTickets.stream() + .map(winningNumber::matchNumbers) + .map(GameResult::evaluate) + .collect(Collectors.toList()); + return new GameResults(results); + } + public List getLottoTickets() { + return lottoTickets; + } +} \ No newline at end of file diff --git a/src/main/java/lotto/domain/lotto/WinningNumber.java b/src/main/java/lotto/domain/lotto/WinningNumber.java new file mode 100644 index 0000000..d6c084a --- /dev/null +++ b/src/main/java/lotto/domain/lotto/WinningNumber.java @@ -0,0 +1,31 @@ +package lotto.domain.lotto; +import lotto.domain.MatchCount; + +import java.util.List; +import java.util.stream.Collectors; +public class WinningNumber { + private static final String BONUS_NUMBER_EXCEPTION_MESSAGE = "๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋Š” ๋‹น์ฒจ ๋ฒˆํ˜ธ์™€ ๋‹ค๋ฅธ ๋ฒˆํ˜ธ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."; + private final List winningNumbers; + private final LottoNumber bonusNumber; + public WinningNumber(List winningNumbers, int bonusNumber) { + validate(winningNumbers, bonusNumber); + this.winningNumbers = winningNumbers.stream() + .map(LottoNumber::new) + .collect(Collectors.toUnmodifiableList()); + this.bonusNumber = new LottoNumber(bonusNumber); + } + private void validate(List winningNumbers, int bonusNumber) { + if (winningNumbers.contains(bonusNumber)) { + throw new IllegalArgumentException(BONUS_NUMBER_EXCEPTION_MESSAGE); + } + } + public MatchCount matchNumbers(LottoTicket lottoTicket) { + int matchCount = Long.valueOf( + winningNumbers.stream() + .filter(lottoTicket::contains) + .count() + ).intValue(); + boolean isBonusMatch = lottoTicket.contains(bonusNumber); + return new MatchCount(matchCount, isBonusMatch); + } +} \ No newline at end of file diff --git a/src/main/java/lotto/domain/result/GameResult.java b/src/main/java/lotto/domain/result/GameResult.java new file mode 100644 index 0000000..bb87e59 --- /dev/null +++ b/src/main/java/lotto/domain/result/GameResult.java @@ -0,0 +1,41 @@ +package lotto.domain.result; +import lotto.domain.MatchCount; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; +public enum GameResult { + UNDER_THREE_MATCHED(MatchCount::isUnderThree, "2๊ฐœ ์ดํ•˜ ์ผ์น˜", 0), + THREE_MATCHED(MatchCount::isMatchThree, "3๊ฐœ ์ผ์น˜", 5_000), + FOUR_MATCHED(MatchCount::isMatchFour, "4๊ฐœ ์ผ์น˜", 50_000), + FIVE_MATCHED_WITHOUT_BONUS(MatchCount::isMatchFiveWithoutBonus, "5๊ฐœ ์ผ์น˜", 1_500_000), + FIVE_MATCHED_WITH_BONUS(MatchCount::isMatchFiveWithBonus, "5๊ฐœ ์ผ์น˜, ๋ณด๋„ˆ์Šค ๋ณผ ์ผ์น˜", 30_000_000), + ALL_MATCHED(MatchCount::isAllMatch, "6๊ฐœ ์ผ์น˜", 2_000_000_000); + private static final String UNSUPPORTED_MATCH_COUNT_EXCEPTION_MESSAGE = "์ผ์น˜ํ•˜๋Š” ๊ฒŒ์ž„ ๊ฒฐ๊ณผ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค."; + private final Predicate matchPredicate; + private final String description; + private final int prize; + GameResult(Predicate matchPredicate, String description, int prize) { + this.matchPredicate = matchPredicate; + this.description = description; + this.prize = prize; + } + public static GameResult evaluate(MatchCount matchCount) { + return Arrays.stream(GameResult.values()) + .filter(gameResult -> gameResult.matchPredicate.test(matchCount)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException(UNSUPPORTED_MATCH_COUNT_EXCEPTION_MESSAGE)); + } + public static List valuesWithoutUnderThreeMatched() { + return Arrays.stream(GameResult.values()) + .filter(gameResult -> !gameResult.equals(GameResult.UNDER_THREE_MATCHED)) + .collect(Collectors.toList()); + } + public String getDescription() { + return description; + } + public int getPrize() { + return prize; + } +} \ No newline at end of file diff --git a/src/main/java/lotto/domain/result/GameResults.java b/src/main/java/lotto/domain/result/GameResults.java new file mode 100644 index 0000000..c386efa --- /dev/null +++ b/src/main/java/lotto/domain/result/GameResults.java @@ -0,0 +1,24 @@ +package lotto.domain.result; +import java.util.ArrayList; +import java.util.List; +public class GameResults { + private static final double NO_PRIZE = 0; + private final List results; + public GameResults(List results) { + this.results = new ArrayList<>(results); + } + public double calculatePrize() { + return results.stream() + .map(GameResult::getPrize) + .mapToDouble(Double::valueOf) + .reduce(Double::sum) + .orElse(NO_PRIZE); + } + public int count(GameResult gameResult) { + return Long.valueOf( + results.stream() + .filter(gameResult::equals) + .count() + ).intValue(); + } +} \ No newline at end of file diff --git a/src/main/java/lotto/ui/Printer.java b/src/main/java/lotto/ui/Printer.java new file mode 100644 index 0000000..d2bcae0 --- /dev/null +++ b/src/main/java/lotto/ui/Printer.java @@ -0,0 +1,92 @@ +package lotto.ui; + +import lotto.domain.*; +import lotto.domain.dto.WinningResult; +import lotto.domain.lotto.LottoNumber; +import lotto.domain.lotto.LottoTicket; +import lotto.domain.lotto.LottoTickets; +import lotto.domain.result.GameResult; + +import java.util.List; +import java.util.stream.Collectors; + +public class Printer { + + private static final String PURCHASE_AMOUNT_REQUEST_MESSAGE = "๊ตฌ์ž…๊ธˆ์•ก์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”."; + private static final String MANUAL_TICKET_COUNT_REQUEST_MESSAGE = "์ˆ˜๋™์œผ๋กœ ๊ตฌ๋งคํ•  ๋กœ๋˜ ์ˆ˜๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."; + private static final String MANUAL_TICKET_NUMBER_REQUEST_MESSAGE = "์ˆ˜๋™์œผ๋กœ ๊ตฌ๋งคํ•  ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”."; + private static final String PURCHASE_MESSAGE = "์ˆ˜๋™์œผ๋กœ %d์žฅ, ์ž๋™์œผ๋กœ %d๊ฐœ๋ฅผ ๊ตฌ๋งคํ–ˆ์Šต๋‹ˆ๋‹ค."; + private static final String LOTTO_NUMBER_DELIMITER = ", "; + private static final String LOTTO_NUMBERS_MESSAGE = "[%s]\n"; + private static final String WINNING_NUMBER_REQUEST_MESSAGE = "์ง€๋‚œ ์ฃผ ๋‹น์ฒจ ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”."; + private static final String BONUS_NUMBER_REQUEST_MESSAGE = "๋ณด๋„ˆ์Šค ๋ณผ์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”."; + private static final String WINNING_STATISTICS_MESSAGE = "๋‹น์ฒจ ํ†ต๊ณ„"; + private static final String DIVIDER_LINE = "----------"; + private static final String WINNING_RESULT_MESSAGE = "%s (%d์›) - %d๊ฐœ\n"; + private static final String EARNING_RATE_MESSAGE = "์ด ์ˆ˜์ต๋ฅ ์€ %.2f์ž…๋‹ˆ๋‹ค.(๊ธฐ์ค€์ด 1์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฒฐ๊ณผ์ ์œผ๋กœ %s๋ผ๋Š” ์˜๋ฏธ์ž„)"; + private static final String PROFIT_MESSAGE = "์ด์ต"; + private static final String LOSS_MESSAGE = "์†ํ•ด"; + + public void requestPurchaseAmount() { + System.out.println(PURCHASE_AMOUNT_REQUEST_MESSAGE); + } + + public void printIssuedTickets(LottoTickets lottoTickets, int manualTicketCount) { + List tickets = lottoTickets.getLottoTickets(); + printNumberOfTickets(tickets, manualTicketCount); + printLottoTickets(tickets); + } + + public void requestManualTicketCount(){ + System.out.println(MANUAL_TICKET_COUNT_REQUEST_MESSAGE); + } + + public void requestManualTicketNumber(){ + System.out.println(MANUAL_TICKET_NUMBER_REQUEST_MESSAGE); + } + + private void printNumberOfTickets(List tickets, int manualTicketCount) { + int numberOfTickets = tickets.size() - manualTicketCount; + System.out.printf((PURCHASE_MESSAGE) + "%n", manualTicketCount, numberOfTickets); + } + + private void printLottoTickets(List tickets) { + for (LottoTicket ticket : tickets) { + String lottoNumbers = ticket.getLottoNumbers() + .stream() + .map(LottoNumber::getLottoNumber) + .map(String::valueOf) + .collect(Collectors.joining(LOTTO_NUMBER_DELIMITER)); + + System.out.printf(LOTTO_NUMBERS_MESSAGE, lottoNumbers); + } + } + + public void requestWinningNumber() { + System.out.println(WINNING_NUMBER_REQUEST_MESSAGE); + } + + public void requestBonusNumber() { + System.out.println(BONUS_NUMBER_REQUEST_MESSAGE); + } + + public void printStatistics(Statistics statistics) { + System.out.println(WINNING_STATISTICS_MESSAGE); + System.out.println(DIVIDER_LINE); + for (WinningResult winningResult : statistics.winningResults()) { + GameResult gameResult = winningResult.getGameResult(); + System.out.printf(WINNING_RESULT_MESSAGE, gameResult.getDescription(), gameResult.getPrize(), winningResult.getNumberOfWinners()); + } + System.out.println(); + + double earningRate = statistics.calculateEarningRate(); + System.out.printf(EARNING_RATE_MESSAGE, earningRate, profitAndLossMessage(statistics.isProfit(earningRate))); + } + + private String profitAndLossMessage(boolean isProfit) { + if (isProfit) { + return PROFIT_MESSAGE; + } + return LOSS_MESSAGE; + } +} diff --git a/src/main/java/lotto/ui/Receiver.java b/src/main/java/lotto/ui/Receiver.java new file mode 100644 index 0000000..b026746 --- /dev/null +++ b/src/main/java/lotto/ui/Receiver.java @@ -0,0 +1,16 @@ +package lotto.ui; + +import java.io.InputStream; +import java.util.Scanner; + +public class Receiver { + private final Scanner scanner; + + public Receiver(InputStream in) { + scanner = new Scanner(in); + } + + public String receiveLine() { + return scanner.nextLine(); + } +} diff --git a/src/test/java/empty.txt b/src/test/java/empty.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/test/java/lotto/LottoApplicationTest.java b/src/test/java/lotto/LottoApplicationTest.java new file mode 100644 index 0000000..d84b4b1 --- /dev/null +++ b/src/test/java/lotto/LottoApplicationTest.java @@ -0,0 +1,31 @@ +package lotto; + +import lotto.domain.*; +import lotto.ui.Printer; +import lotto.ui.Receiver; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayInputStream; +import java.util.*; + +import static org.assertj.core.api.Assertions.assertThat; + +public class LottoApplicationTest { + + @DisplayName("ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€๋ฅผ ์œ„ํ•œ ApplicationTest") + @Test + void application() { + //given + String input = "3000000\n1, 10, 25, 30, 31, 38\n44"; + LottoApplication app = new LottoApplication( + new Printer(), new Receiver(new ByteArrayInputStream(input.getBytes())) + ); + + //when + app.run(); + + //then + assertThat(true).isTrue(); + } +} diff --git a/src/test/java/lotto/domain/MatchCountTest.java b/src/test/java/lotto/domain/MatchCountTest.java new file mode 100644 index 0000000..4d499ea --- /dev/null +++ b/src/test/java/lotto/domain/MatchCountTest.java @@ -0,0 +1,32 @@ +package lotto.domain; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class MatchCountTest { + + @Test + void isUnderThree() { + } + + @Test + void isMatchThree() { + } + + @Test + void isMatchFour() { + } + + @Test + void isMatchFiveWithoutBonus() { + } + + @Test + void isMatchFiveWithBonus() { + } + + @Test + void isAllMatch() { + } +} \ No newline at end of file diff --git a/src/test/java/lotto/domain/StatisticsTest.java b/src/test/java/lotto/domain/StatisticsTest.java new file mode 100644 index 0000000..a3f0151 --- /dev/null +++ b/src/test/java/lotto/domain/StatisticsTest.java @@ -0,0 +1,84 @@ +package lotto.domain; + +import lotto.domain.Statistics; +import lotto.domain.dto.WinningResult; +import lotto.domain.result.GameResult; +import lotto.domain.result.GameResults; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class StatisticsTest { + + private final Statistics statistics; + + public StatisticsTest() { + List results = Arrays.asList(GameResult.THREE_MATCHED, GameResult.UNDER_THREE_MATCHED, GameResult.THREE_MATCHED, GameResult.ALL_MATCHED, + GameResult.THREE_MATCHED, GameResult.FOUR_MATCHED, GameResult.UNDER_THREE_MATCHED); + + GameResults gameResults = new GameResults(results); + statistics = new Statistics(gameResults, 7000); + } + + @DisplayName("์ถœ๋ ฅ์šฉ WinningResult dto ํ…Œ์ŠคํŠธ") + @Test + void winningResults() { + //given + //when + List winningResults = statistics.winningResults(); + + //then + assertThat(winningResults.get(0).getGameResult()).isEqualTo(GameResult.THREE_MATCHED); + assertThat(winningResults.get(0).getNumberOfWinners()).isEqualTo(3); + + assertThat(winningResults.get(1).getGameResult()).isEqualTo(GameResult.FOUR_MATCHED); + assertThat(winningResults.get(1).getNumberOfWinners()).isEqualTo(1); + + assertThat(winningResults.get(2).getGameResult()).isEqualTo(GameResult.FIVE_MATCHED_WITHOUT_BONUS); + assertThat(winningResults.get(2).getNumberOfWinners()).isEqualTo(0); + + assertThat(winningResults.get(3).getGameResult()).isEqualTo(GameResult.FIVE_MATCHED_WITH_BONUS); + assertThat(winningResults.get(3).getNumberOfWinners()).isEqualTo(0); + + assertThat(winningResults.get(4).getGameResult()).isEqualTo(GameResult.ALL_MATCHED); + assertThat(winningResults.get(4).getNumberOfWinners()).isEqualTo(1); + } + + @DisplayName("์ˆ˜์ต๋ฅ  ๊ณ„์‚ฐ") + @Test + void calculateEarningRate() { + //given + double expected = (double) 2_000_065_000 / 7000; + + //when + double actual = statistics.calculateEarningRate(); + + //then + assertThat(actual).isEqualTo(expected); + } + + @DisplayName("์ด๋“์ธ ๊ฒฝ์šฐ ๊ฒ€์ฆ") + @Test + void isProfit() { + //given when then + assertThat(statistics.isProfit(statistics.calculateEarningRate())).isTrue(); + } + + @DisplayName("์†ํ•ด์ธ ๊ฒฝ์šฐ ๊ฒ€์ฆ") + @Test + void isLoss() { + //given + List results = Arrays.asList(GameResult.THREE_MATCHED, GameResult.UNDER_THREE_MATCHED, GameResult.UNDER_THREE_MATCHED, + GameResult.UNDER_THREE_MATCHED, GameResult.UNDER_THREE_MATCHED, GameResult.UNDER_THREE_MATCHED, GameResult.UNDER_THREE_MATCHED); + + GameResults gameResults = new GameResults(results); + Statistics lossStatistics = new Statistics(gameResults, 7000); + + //when then + assertThat(lossStatistics.isProfit(lossStatistics.calculateEarningRate())).isFalse(); + } +} diff --git a/src/test/java/lotto/domain/dto/WinningResultTest.java b/src/test/java/lotto/domain/dto/WinningResultTest.java new file mode 100644 index 0000000..020f260 --- /dev/null +++ b/src/test/java/lotto/domain/dto/WinningResultTest.java @@ -0,0 +1,12 @@ +package lotto.domain.dto; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class WinningResultTest { + + @Test + void getNumberOfWinners() { + } +} \ No newline at end of file diff --git a/src/test/java/lotto/domain/factory/IssuerTest.java b/src/test/java/lotto/domain/factory/IssuerTest.java new file mode 100644 index 0000000..1d61f38 --- /dev/null +++ b/src/test/java/lotto/domain/factory/IssuerTest.java @@ -0,0 +1,42 @@ +package lotto.domain.factory; +import lotto.domain.factory.Issuer; +import lotto.domain.lotto.LottoTickets; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +class IssuerTest { + @Test + void issueLottoTickets() { + //given + int money = 10000; + int manualTicketCount = 2; + int expected = 8; + //when + LottoTickets lottoTickets = Issuer.issueLottoTickets(money, manualTicketCount); + //then + int actual = lottoTickets.getLottoTickets().size(); + assertThat(actual).isEqualTo(expected); + } + @Test + void moneyNotUnitOfLottoPrice() { + //given + int money = 14500; + int manualTicketCount = 2; + int expected = 12; + //when + LottoTickets lottoTickets = Issuer.issueLottoTickets(money, manualTicketCount); + //then + int actual = lottoTickets.getLottoTickets().size(); + assertThat(actual).isEqualTo(expected); + } + @ValueSource(ints = {999, 0, -1000}) + @ParameterizedTest + void invalidMoney(int money, int manualTicketCount) { + //when then + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> Issuer.issueLottoTickets(money, manualTicketCount)) + .withMessage("๊ธˆ์•ก์€ 1000์› ์ด์ƒ์œผ๋กœ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."); + } +} \ No newline at end of file diff --git a/src/test/java/lotto/domain/lotto/LottoNumberTest.java b/src/test/java/lotto/domain/lotto/LottoNumberTest.java new file mode 100644 index 0000000..b00d2a9 --- /dev/null +++ b/src/test/java/lotto/domain/lotto/LottoNumberTest.java @@ -0,0 +1,37 @@ +package lotto.domain.lotto; +import lotto.domain.lotto.LottoNumber; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +class LottoNumberTest { + @DisplayName("LottoNumber๊ฐ€ ์ƒ์„ฑํ•˜๋Š” ํ›„๋ณด ์ˆซ์ž๋Š” 1๋ถ€ํ„ฐ 45 ์‚ฌ์ด") + @Test + void range() { + //given + List numbers = LottoNumber.range(); + //when then + for (int containedNumber = 1; containedNumber <= 45; containedNumber++) { + assertThat(numbers.contains(new LottoNumber(containedNumber))).isTrue(); + } + } + @DisplayName("๋น„์ •์ƒ์ ์ธ ์ธ์ˆ˜๋กœ LottoNumber ์ƒ์„ฑ์‹œ ์˜ˆ์™ธ ๋ฐœ์ƒ") + @Test + void constructorException() { + //given + int lottoNumber = 46; + //when then + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> new LottoNumber(lottoNumber)) + .withMessage("๋กœ๋˜ ๋ฒˆํ˜ธ๋Š” 1 ์ด์ƒ, 45 ์ดํ•˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + @DisplayName("ํ•ด์‹œ์ฝ”๋“œ ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€ ์ปค") + @Test + void testCoverage() { + //given when then + LottoNumber lottoNumber = new LottoNumber(10); + int hashCode = lottoNumber.hashCode(); + assertThat(hashCode).isEqualTo(lottoNumber.hashCode()); + } +} \ No newline at end of file diff --git a/src/test/java/lotto/domain/lotto/LottoTicketTest.java b/src/test/java/lotto/domain/lotto/LottoTicketTest.java new file mode 100644 index 0000000..986e318 --- /dev/null +++ b/src/test/java/lotto/domain/lotto/LottoTicketTest.java @@ -0,0 +1,35 @@ +package lotto.domain.lotto; +import lotto.domain.lotto.LottoNumber; +import lotto.domain.lotto.LottoTicket; +import org.junit.jupiter.api.Test; +import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; + +class LottoTicketTest { + @Test + void numberOfLottoNumbers() { + //given + int expected = 6; + //when + LottoTicket lottoTicket = new LottoTicket(); + List lottoNumbers = lottoTicket.getLottoNumbers(); + int actual = lottoNumbers.size(); + //then + assertThat(actual).isEqualTo(expected); + } + @Test + void rangeOfLottoNumbers() { + //given + final int UPPER_BOUND = 45; + final int LOWER_BOUND = 1; + //when + LottoTicket lottoTicket = new LottoTicket(); + List lottoNumbers = lottoTicket.getLottoNumbers(); + //then + lottoNumbers.forEach( + lottoNumber -> assertThat(lottoNumber.getLottoNumber()) + .isGreaterThanOrEqualTo(LOWER_BOUND) + .isLessThanOrEqualTo(UPPER_BOUND) + ); + } +} \ No newline at end of file diff --git a/src/test/java/lotto/domain/lotto/WinningNumberTest.java b/src/test/java/lotto/domain/lotto/WinningNumberTest.java new file mode 100644 index 0000000..c49c455 --- /dev/null +++ b/src/test/java/lotto/domain/lotto/WinningNumberTest.java @@ -0,0 +1,21 @@ +package lotto.domain.lotto; +import lotto.domain.lotto.WinningNumber; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import java.util.Arrays; +import java.util.List; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +class WinningNumberTest { + @DisplayName("๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋Š” ๋‹น์ฒจ ๋ฒˆํ˜ธ์— ํฌํ•จ๋˜๋Š” ์ˆซ์ž์—ฌ์„œ๋Š” ์•ˆ๋œ๋‹ค.") + @Test + void notWinningNumberContainsBonus() { + //given + List lottoNumbers = Arrays.asList(1, 2, 3, 4, 10, 30); + int bonusNumber = 10; + //when then + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> new WinningNumber(lottoNumbers, bonusNumber)) + .withMessage("๋ณด๋„ˆ์Šค ๋ฒˆํ˜ธ๋Š” ๋‹น์ฒจ ๋ฒˆํ˜ธ์™€ ๋‹ค๋ฅธ ๋ฒˆํ˜ธ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } +} \ No newline at end of file diff --git a/src/test/java/lotto/domain/result/GameResultTest.java b/src/test/java/lotto/domain/result/GameResultTest.java new file mode 100644 index 0000000..4d95878 --- /dev/null +++ b/src/test/java/lotto/domain/result/GameResultTest.java @@ -0,0 +1,59 @@ +package lotto.domain.result; +import lotto.domain.MatchCount; +import lotto.domain.result.GameResult; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import java.util.stream.Stream; +import static org.assertj.core.api.Assertions.*; +class GameResultTest { + @DisplayName("์ผ์น˜ ๊ฒฐ๊ณผ์— ๋”ฐ๋ฅธ GameResult ์ƒ์„ฑ ํ…Œ์ŠคํŠธ") + @MethodSource(value = "provideEvaluate") + @ParameterizedTest(name = "matchCount = {0}, isBonusMatch = {1}, expected = {2}") + void evaluate(int count, boolean isBonusMatch, GameResult expected) { + //given + MatchCount matchCount = new MatchCount(count, isBonusMatch); + //when + GameResult gameResult = GameResult.evaluate(matchCount); + //then + assertThat(gameResult).isEqualTo(expected); + } + private static Stream provideEvaluate() { + return Stream.of( + Arguments.of(0, true, GameResult.UNDER_THREE_MATCHED), + Arguments.of(0, false, GameResult.UNDER_THREE_MATCHED), + Arguments.of(1, true, GameResult.UNDER_THREE_MATCHED), + Arguments.of(1, false, GameResult.UNDER_THREE_MATCHED), + Arguments.of(2, true, GameResult.UNDER_THREE_MATCHED), + Arguments.of(2, false, GameResult.UNDER_THREE_MATCHED), + Arguments.of(3, true, GameResult.THREE_MATCHED), + Arguments.of(3, false, GameResult.THREE_MATCHED), + Arguments.of(4, true, GameResult.FOUR_MATCHED), + Arguments.of(4, false, GameResult.FOUR_MATCHED), + Arguments.of(5, true, GameResult.FIVE_MATCHED_WITH_BONUS), + Arguments.of(5, false, GameResult.FIVE_MATCHED_WITHOUT_BONUS), + Arguments.of(6, false, GameResult.ALL_MATCHED) + ); + } + @DisplayName("๋น„์ •์ƒ์ ์ธ ์ผ์น˜ ๊ฒฐ๊ณผ์— ๋”ฐ๋ฅธ ์˜ˆ์™ธ ๋ฐœ์ƒ") + @Test + void evaluateException() { + //given + MatchCount matchCount = new MatchCount(7, true); + //when + //then + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> GameResult.evaluate(matchCount)) + .withMessage("์ผ์น˜ํ•˜๋Š” ๊ฒŒ์ž„ ๊ฒฐ๊ณผ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค."); + } + @DisplayName("description getter ํ…Œ์ŠคํŠธ") + @Test + void getDescription() { + //given + GameResult gameResult = GameResult.ALL_MATCHED; + //when then + assertThat(gameResult.getDescription()).isEqualTo("6๊ฐœ ์ผ์น˜"); + } +} \ No newline at end of file diff --git a/src/test/java/lotto/domain/result/GameResultsTest.java b/src/test/java/lotto/domain/result/GameResultsTest.java new file mode 100644 index 0000000..6a79b5a --- /dev/null +++ b/src/test/java/lotto/domain/result/GameResultsTest.java @@ -0,0 +1,40 @@ +package lotto.domain.result; +import lotto.domain.result.GameResult; +import lotto.domain.result.GameResults; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import java.util.Arrays; +import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; + +class GameResultsTest { + @DisplayName("๋ชจ๋“  ์ƒ๊ธˆ ๋”ํ•˜๊ธฐ") + @Test + void calculatePrize() { + //given + List results = Arrays.asList(GameResult.UNDER_THREE_MATCHED, GameResult.THREE_MATCHED, + GameResult.FOUR_MATCHED, GameResult.FIVE_MATCHED_WITH_BONUS, GameResult.FIVE_MATCHED_WITHOUT_BONUS, GameResult.ALL_MATCHED); + GameResults gameResults = new GameResults(results); + double expected = 2_031_555_000; + //when + double totalPrize = gameResults.calculatePrize(); + //then + assertThat(totalPrize).isEqualTo(expected); + } + @DisplayName("๋ชจ๋“  GameResult ๊ฒฝ์šฐ์— ๋Œ€ํ•ด count") + @Test + void count() { + //given + List results = Arrays.asList(GameResult.UNDER_THREE_MATCHED, GameResult.THREE_MATCHED, + GameResult.FOUR_MATCHED, GameResult.FIVE_MATCHED_WITH_BONUS, GameResult.FIVE_MATCHED_WITHOUT_BONUS, GameResult.ALL_MATCHED); + GameResults gameResults = new GameResults(results); + //when + //then + assertThat(gameResults.count(GameResult.UNDER_THREE_MATCHED)).isEqualTo(1); + assertThat(gameResults.count(GameResult.THREE_MATCHED)).isEqualTo(1); + assertThat(gameResults.count(GameResult.FOUR_MATCHED)).isEqualTo(1); + assertThat(gameResults.count(GameResult.FIVE_MATCHED_WITHOUT_BONUS)).isEqualTo(1); + assertThat(gameResults.count(GameResult.FIVE_MATCHED_WITH_BONUS)).isEqualTo(1); + assertThat(gameResults.count(GameResult.ALL_MATCHED)).isEqualTo(1); + } +} \ No newline at end of file diff --git a/src/test/java/lotto/ui/PrinterTest.java b/src/test/java/lotto/ui/PrinterTest.java new file mode 100644 index 0000000..6d0740e --- /dev/null +++ b/src/test/java/lotto/ui/PrinterTest.java @@ -0,0 +1,29 @@ +package lotto.ui; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class PrinterTest { + + @Test + void requestPurchaseAmount() { + + } + + @Test + void printIssuedTickets() { + } + + @Test + void requestWinningNumber() { + } + + @Test + void requestBonusNumber() { + } + + @Test + void printStatistics() { + } +} \ No newline at end of file