diff --git a/src/main/java/lotto/LottoApplication.java b/src/main/java/lotto/LottoApplication.java index 8a5efbe8e5..34d689e994 100644 --- a/src/main/java/lotto/LottoApplication.java +++ b/src/main/java/lotto/LottoApplication.java @@ -1,8 +1,10 @@ package lotto; import lotto.controller.LottoMachine; -import lotto.controller.WinningLotto; +import lotto.domain.WinningLotto; import lotto.domain.Lotto; +import lotto.domain.LottoNumber; +import lotto.domain.LottoResult; import lotto.ui.InputView; import lotto.ui.ResultView; import lotto.util.LottoNumberParser; @@ -10,15 +12,19 @@ public class LottoApplication { public static void main(String[] args) { String purchaseAmount = InputView.getPurchaseAmount(); + LottoMachine lottoMachine = new LottoMachine(purchaseAmount); Lotto lotto = lottoMachine.generate(); - ResultView.printLottoCount(lotto.count()); - ResultView.printLottoNumbersList(lotto.toString()); + + ResultView.printLotto(lotto); String winningNumbers = InputView.getWinningNumber(); - WinningLotto winningLotto = new WinningLotto(LottoNumberParser.parse(winningNumbers)); + String bonusNumber = InputView.getBonusNumber(); + + WinningLotto winningLotto = new WinningLotto(winningNumbers, bonusNumber); + LottoResult result = lotto.getMatchResult(winningLotto); - ResultView.printLottoResult(winningLotto.getResult(lotto)); - ResultView.printProfit(winningLotto.getProfit(lotto)); + ResultView.printLottoResult(result.toString()); + ResultView.printProfit(result.getProfit()); } } diff --git a/src/main/java/lotto/controller/LottoMachine.java b/src/main/java/lotto/controller/LottoMachine.java index 66765d8ebd..2884779e2e 100644 --- a/src/main/java/lotto/controller/LottoMachine.java +++ b/src/main/java/lotto/controller/LottoMachine.java @@ -3,6 +3,7 @@ import lotto.domain.Lotto; import lotto.domain.LottoNumbers; import lotto.domain.LottoPrice; +import lotto.util.LottoNumberParser; import lotto.util.RandomNumbersGenerator; import java.util.ArrayList; @@ -23,7 +24,7 @@ public Lotto generate() { List lottoNumbersList = new ArrayList<>(); for (int i = 0; i < lottoPrice.count(); i++) { - lottoNumbersList.add(new LottoNumbers(RandomNumbersGenerator.randomNumbers())); + lottoNumbersList.add(new LottoNumbers(LottoNumberParser.parse(RandomNumbersGenerator.randomNumbers()))); } return new Lotto(lottoPrice, lottoNumbersList); diff --git a/src/main/java/lotto/controller/WinningLotto.java b/src/main/java/lotto/controller/WinningLotto.java deleted file mode 100644 index ed31152aa2..0000000000 --- a/src/main/java/lotto/controller/WinningLotto.java +++ /dev/null @@ -1,23 +0,0 @@ -package lotto.controller; - -import lotto.domain.Lotto; -import lotto.domain.LottoNumbers; -import lotto.domain.LottoResult; - - -public class WinningLotto { - LottoNumbers winningNumbers; - - public WinningLotto(LottoNumbers winningNumbers) { - this.winningNumbers = winningNumbers; - } - - public String getResult(Lotto lotto) { - return lotto.getMatchResult(winningNumbers).toString(); - } - - public String getProfit(Lotto lotto) { - LottoResult lottoResult = lotto.getMatchResult(winningNumbers); - return String.valueOf(lotto.calculateProfit(lottoResult.prize())); - } -} diff --git a/src/main/java/lotto/domain/Lotto.java b/src/main/java/lotto/domain/Lotto.java index 2f84badf3c..fb7e176bad 100644 --- a/src/main/java/lotto/domain/Lotto.java +++ b/src/main/java/lotto/domain/Lotto.java @@ -4,29 +4,25 @@ import java.util.stream.Collectors; public class Lotto { - LottoPrice price; - List lottoNumbers; + private final LottoPrice price; + private final List lottoNumbers; public Lotto(LottoPrice price, List lottoNumbers) { this.price = price; this.lottoNumbers = lottoNumbers; } - public LottoResult getMatchResult(LottoNumbers winningNumbers) { + public LottoResult getMatchResult(WinningLotto winningLotto) { LottoResult result = new LottoResult(); for (LottoNumbers lottoNumbers : lottoNumbers) { - LottoRank rank = lottoNumbers.getMatchedRank(winningNumbers); + LottoRank rank = winningLotto.getMatchedRank(lottoNumbers); result.add(rank); } return result; } - public double calculateProfit(int prize) { - return price.getProfit(prize); - } - public String count() { return String.valueOf(price.count()); } diff --git a/src/main/java/lotto/domain/LottoNumber.java b/src/main/java/lotto/domain/LottoNumber.java index 7527f8455c..f6f6cc780c 100644 --- a/src/main/java/lotto/domain/LottoNumber.java +++ b/src/main/java/lotto/domain/LottoNumber.java @@ -5,6 +5,10 @@ public class LottoNumber { private final int number; + public LottoNumber(String number) { + this(Integer.parseInt(number)); + } + public LottoNumber(int number) { this.number = number; } diff --git a/src/main/java/lotto/domain/LottoNumbers.java b/src/main/java/lotto/domain/LottoNumbers.java index dbfc8a3a11..178134f63b 100644 --- a/src/main/java/lotto/domain/LottoNumbers.java +++ b/src/main/java/lotto/domain/LottoNumbers.java @@ -1,6 +1,10 @@ package lotto.domain; +import lotto.util.LottoNumberParser; + +import java.sql.Array; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -8,34 +12,32 @@ public class LottoNumbers { private final List numbers; - public LottoNumbers(List numbers) { - this.numbers = toLottoNumber(numbers); + public LottoNumbers(int... numbers) { + this(LottoNumberParser.parse(numbers)); } - private static List toLottoNumber(List numbers) { - List lottoNumbers = new ArrayList<>(); - - for (int number : numbers) { - lottoNumbers.add(new LottoNumber(number)); - } + public LottoNumbers(String numbers) { + this(LottoNumberParser.parse(numbers)); + } - return lottoNumbers; + public LottoNumbers(List numbers) { + this.numbers = numbers; } - public LottoRank getMatchedRank(LottoNumbers other) { + public int getMatchCount(LottoNumbers other) { int matchCount = 0; - for (int i = 0; i < numbers.size(); i++) { - if (matchesAtIndex(i, other)) { + for (LottoNumber number : numbers) { + if (other.contains(number)) { matchCount++; } } - return LottoRank.of(matchCount); + return matchCount; } - private boolean matchesAtIndex(int index, LottoNumbers other) { - return numbers.get(index).equals(other.numbers.get(index)); + public boolean contains(LottoNumber number) { + return numbers.contains(number); } @Override diff --git a/src/main/java/lotto/domain/LottoRank.java b/src/main/java/lotto/domain/LottoRank.java index 58687a9e2c..68c0103e9e 100644 --- a/src/main/java/lotto/domain/LottoRank.java +++ b/src/main/java/lotto/domain/LottoRank.java @@ -1,24 +1,27 @@ package lotto.domain; public enum LottoRank { - FIRST(6, 2_000_000_000), - SECOND(5, 30_000_000), - THIRD(4, 1_500_000), - FOURTH(3, 50_000), - NONE(0, 0); + FIRST(6, 2_000_000_000, false), + SECOND_BONUS(5, 30_000_000, true), + SECOND(5, 1_500_000, false), + THIRD(4, 50_000, false), + FOURTH(3, 5_000, false), + NONE(0, 0, false); private final int matchCount; private final int prize; + private final boolean requireBonus; - LottoRank(int matchCount, int prize) { + LottoRank(int matchCount, int prize, boolean requireBonus) { this.matchCount = matchCount; this.prize = prize; + this.requireBonus = requireBonus; } - public static LottoRank of(int matchCount) { + public static LottoRank of(int matchCount, boolean bonusMatch) { for (LottoRank rank : LottoRank.values()) { - if (isMatch(rank, matchCount)) { + if (isMatch(rank, matchCount, bonusMatch)) { return rank; } } @@ -26,16 +29,28 @@ public static LottoRank of(int matchCount) { return NONE; } - public static boolean isMatch(LottoRank rank, int matchCount) { + public static boolean isMatch(LottoRank rank, int matchCount, boolean requireBonus) { + return isCountMatch(rank, matchCount) && isBonusRequireMatch(rank, requireBonus); + } + + private static boolean isCountMatch(LottoRank rank, int matchCount) { return rank.matchCount == matchCount; } + private static boolean isBonusRequireMatch(LottoRank rank, boolean requireBonus) { + return rank.requireBonus == requireBonus; + } + public int getPrize(LottoRank rank, int count) { return rank.prize * count; } @Override public String toString() { - return String.format("%d개 일치 (%d원)", matchCount, prize); + return String.format("%d개%s(%d원)", matchCount, matchString(), prize); + } + + private String matchString() { + return requireBonus ? ", 보너스 볼 일치" : " 일치"; } } diff --git a/src/main/java/lotto/domain/LottoResult.java b/src/main/java/lotto/domain/LottoResult.java index 7f30d46324..cb2b19335d 100644 --- a/src/main/java/lotto/domain/LottoResult.java +++ b/src/main/java/lotto/domain/LottoResult.java @@ -25,7 +25,7 @@ public void add(LottoRank rank) { matchResult.put(rank, matchResult.get(rank) + 1); } - public int prize() { + private int prize() { int prize = 0; for (LottoRank rank : LottoRank.values()) { prize += rank.getPrize(rank, matchResult.get(rank)); @@ -34,6 +34,20 @@ public int prize() { return prize; } + private LottoPrice getPrice() { + int count = 0; + for (LottoRank rank : LottoRank.values()) { + count += matchResult.get(rank); + } + + return new LottoPrice(count); + } + + public String getProfit() { + LottoPrice price = getPrice(); + return String.valueOf(price.getProfit(prize())); + } + @Override public String toString() { return Arrays.stream(LottoRank.values()) diff --git a/src/main/java/lotto/domain/WinningLotto.java b/src/main/java/lotto/domain/WinningLotto.java new file mode 100644 index 0000000000..7ff2ed4c4f --- /dev/null +++ b/src/main/java/lotto/domain/WinningLotto.java @@ -0,0 +1,27 @@ +package lotto.domain; + + +import lotto.util.LottoNumberParser; + +public class WinningLotto { + private final LottoNumbers winningNumbers; + private final LottoNumber bonusNumber; + + public WinningLotto(String winningNumbers, String bonusNumber) { + this(new LottoNumbers(LottoNumberParser.parse(winningNumbers)), new LottoNumber(bonusNumber)); + } + + public WinningLotto(LottoNumbers winningNumbers, LottoNumber bonusNumber) { + if (winningNumbers.contains(bonusNumber)) { + throw new IllegalArgumentException(String.format("당첨 숫자와 보너스 숫자가 일치합니다. (%d)", bonusNumber)); + } + + this.winningNumbers = winningNumbers; + this.bonusNumber = bonusNumber; + } + + public LottoRank getMatchedRank(LottoNumbers numbers) { + int matchCount = winningNumbers.getMatchCount(numbers); + return LottoRank.of(matchCount, numbers.contains(bonusNumber)); + } +} diff --git a/src/main/java/lotto/ui/InputView.java b/src/main/java/lotto/ui/InputView.java index 1e33d57dda..82e65b6ba3 100644 --- a/src/main/java/lotto/ui/InputView.java +++ b/src/main/java/lotto/ui/InputView.java @@ -7,6 +7,7 @@ public class InputView { private static final String WINNING_NUMBER_MESSAGE = "지난 주 당첨 번호 6개를 입력해 주세요."; private static final Scanner scanner = new Scanner(System.in); + public static final String BONUS_BALL_MESSAGE = "보너스볼을 입력해주세요"; public static String getPurchaseAmount() { System.out.println(PURCHASE_AMOUNT_MESSAGE); @@ -18,5 +19,10 @@ public static String getWinningNumber() { return scanner.nextLine(); } + public static String getBonusNumber() { + System.out.println(BONUS_BALL_MESSAGE); + return scanner.nextLine(); + } + } diff --git a/src/main/java/lotto/ui/ResultView.java b/src/main/java/lotto/ui/ResultView.java index 42075cfab8..bece707366 100644 --- a/src/main/java/lotto/ui/ResultView.java +++ b/src/main/java/lotto/ui/ResultView.java @@ -1,17 +1,24 @@ package lotto.ui; +import lotto.domain.Lotto; + public class ResultView { private static final String LOTTO_COUNT_MESSAGE = "%s개를 구매했습니다.\n"; private static final String LOTTO_RESULT_MESSSAGE = "당첨 통계\n-------"; - public static void printLottoCount(String lottoCount) { + private static void printLottoCount(String lottoCount) { System.out.printf(LOTTO_COUNT_MESSAGE, lottoCount); } - public static void printLottoNumbersList(String lottoList) { + private static void printLottoNumbersList(String lottoList) { System.out.println(lottoList); } + public static void printLotto(Lotto lotto) { + printLottoCount(lotto.count()); + printLottoNumbersList(lotto.toString()); + } + public static void printLottoResult(String lottoResult) { System.out.println(LOTTO_RESULT_MESSSAGE); System.out.println(lottoResult); diff --git a/src/main/java/lotto/util/LottoNumberCache.java b/src/main/java/lotto/util/LottoNumberCache.java new file mode 100644 index 0000000000..9c06ec4c1b --- /dev/null +++ b/src/main/java/lotto/util/LottoNumberCache.java @@ -0,0 +1,31 @@ +package lotto.util; + +import lotto.domain.LottoNumber; + +import java.util.HashMap; +import java.util.Map; + +public class LottoNumberCache { + private static final int MIN = 1; + private static final int MAX = 45; + private static final LottoNumber NONE = new LottoNumber(0); + private static final Map Cache = new HashMap<>(); + + static { + for (int i = MIN; i <= MAX; i++) { + Cache.put(i, new LottoNumber(i)); + } + } + + public static LottoNumber get(int value) { + LottoNumber lottoNumber = Cache.getOrDefault(value, NONE); + if (lottoNumber == NONE) { + throw new IllegalArgumentException("로또의 숫자는 1에서 45 사이여야합니다."); + } + return Cache.get(value); + } + + public static LottoNumber get(String value) { + return get(Integer.parseInt(value)); + } +} diff --git a/src/main/java/lotto/util/LottoNumberParser.java b/src/main/java/lotto/util/LottoNumberParser.java index ecca99ceb2..da71081d86 100644 --- a/src/main/java/lotto/util/LottoNumberParser.java +++ b/src/main/java/lotto/util/LottoNumberParser.java @@ -1,6 +1,6 @@ package lotto.util; -import lotto.domain.LottoNumbers; +import lotto.domain.LottoNumber; import java.util.*; @@ -8,7 +8,7 @@ public class LottoNumberParser { private static final String SPLIT_REGELX = "[,\\s]+"; private static final int LOTTO_NUMBER_COUNT = 6; - public static LottoNumbers parse(String input) { + public static List parse(String input) { String[] splittedNumbers = input.split(SPLIT_REGELX); for (String splittedNumber : splittedNumbers) { System.out.println(splittedNumber); @@ -17,17 +17,34 @@ public static LottoNumbers parse(String input) { throw new IllegalArgumentException("정상적인 입력이 아닙니다."); } - return makeLottoNumbers(splittedNumbers); + return parse(splittedNumbers); } - private static LottoNumbers makeLottoNumbers(String[] numbers) { - List winningNumbers = new ArrayList<>(); + public static List parse(String[] numbers) { + List lottoNumbers = new ArrayList<>(); for (String number : numbers) { - winningNumbers.add(Integer.parseInt(number)); + lottoNumbers.add(LottoNumberCache.get(number)); } - return new LottoNumbers(winningNumbers); + return lottoNumbers; + } + + public static List parse (int... numbers) { + List list = new ArrayList<>(); + for (int number : numbers) { + list.add(LottoNumberCache.get(number)); + } + + return list; + } + + public static List parse(List numbers) { + List list = new ArrayList<>(); + for (int number : numbers) { + list.add(LottoNumberCache.get(number)); + } + return list; } private static boolean isValidInput(String[] input) { diff --git a/src/test/java/lotto/domain/LottoNumbersTest.java b/src/test/java/lotto/domain/LottoNumbersTest.java index f45c9a60d1..f936df7dea 100644 --- a/src/test/java/lotto/domain/LottoNumbersTest.java +++ b/src/test/java/lotto/domain/LottoNumbersTest.java @@ -1,36 +1,26 @@ package lotto.domain; 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.List; -import java.util.stream.Stream; import static org.assertj.core.api.Assertions.*; + public class LottoNumbersTest { @Test public void 생성() { - assertThat(new LottoNumbers(List.of(1, 2, 3, 4, 5, 6))).isEqualTo(new LottoNumbers(List.of(1, 2, 3, 4, 5, 6))); + assertThat(new LottoNumbers("1, 2, 3, 4, 5, 6")).isEqualTo(new LottoNumbers(1, 2, 3, 4, 5, 6)); } - @ParameterizedTest - @MethodSource("provideLottoNumbers") - public void 일치하는_숫자의_개수(List numbers, LottoRank expected) { - LottoNumbers lottoNumbers = new LottoNumbers(numbers); - LottoNumbers otherLottoNumbers = new LottoNumbers(List.of(1, 2, 3, 4, 5, 6)); - - assertThat(lottoNumbers.getMatchedRank(otherLottoNumbers)).isEqualTo(expected); + @Test + public void 포함_여부() { + LottoNumbers lottoNumbers = new LottoNumbers(1, 2, 3, 4, 5, 6); + assertThat(lottoNumbers.contains(new LottoNumber(1))).isTrue(); } + @Test + public void 일치_횟수_비교() { + LottoNumbers lottoNumbers = new LottoNumbers(1, 2, 3, 4, 5, 6); + LottoNumbers otherNumbers = new LottoNumbers(1, 2, 3, 4, 5, 6); - static Stream provideLottoNumbers() { - return Stream.of( - Arguments.of(List.of(1, 2, 3, 4, 5, 6), LottoRank.FIRST), - Arguments.of(List.of(1, 2, 3, 4, 5, 7), LottoRank.SECOND), - Arguments.of(List.of(1, 2, 3, 4, 8, 9), LottoRank.THIRD), - Arguments.of(List.of(1, 2, 3, 10, 11, 12), LottoRank.FOURTH) - ); + assertThat(lottoNumbers.getMatchCount(otherNumbers)).isEqualTo(6); } } diff --git a/src/test/java/lotto/domain/LottoTest.java b/src/test/java/lotto/domain/LottoTest.java index cfca8772b0..ec32ab6a32 100644 --- a/src/test/java/lotto/domain/LottoTest.java +++ b/src/test/java/lotto/domain/LottoTest.java @@ -10,24 +10,27 @@ public class LottoTest { @Test public void 로또_일치_여부() { List lottoNumbersList = List.of( - new LottoNumbers(List.of(1, 2, 3, 4, 5, 6)), - new LottoNumbers(List.of(1, 2, 3, 4, 5, 7)), - new LottoNumbers(List.of(1, 2, 3, 4, 7, 8)), - new LottoNumbers(List.of(1, 2, 3, 7, 8, 9)), - new LottoNumbers(List.of(1, 2, 7, 8, 9, 10)) + new LottoNumbers(1, 2, 3, 4, 5, 6), + new LottoNumbers(1, 2, 3, 4, 5, 7), + new LottoNumbers(1, 2, 3, 4, 7, 8), + new LottoNumbers(1, 2, 3, 7, 8, 9), + new LottoNumbers(1, 2, 7, 8, 9, 10), + new LottoNumbers(1, 2, 3, 4, 5, 11) ); LottoPrice price = new LottoPrice(6000); - LottoNumbers winningNumbers = new LottoNumbers(List.of(1, 2, 3, 4, 5, 6)); + LottoNumbers winningNumbers = new LottoNumbers(1, 2, 3, 4, 5, 6); + LottoNumber bonusNumber = new LottoNumber(11); LottoResult lottoResult = new LottoResult(); lottoResult.add(LottoRank.FIRST); + lottoResult.add(LottoRank.SECOND_BONUS); lottoResult.add(LottoRank.SECOND); lottoResult.add(LottoRank.THIRD); lottoResult.add(LottoRank.FOURTH); lottoResult.add(LottoRank.NONE); - assertThat(new Lotto(price, lottoNumbersList).getMatchResult(winningNumbers)).isEqualTo(lottoResult); + assertThat(new Lotto(price, lottoNumbersList).getMatchResult(new WinningLotto(winningNumbers, bonusNumber))).isEqualTo(lottoResult); } } diff --git a/src/test/java/lotto/domain/WinningLottoTest.java b/src/test/java/lotto/domain/WinningLottoTest.java new file mode 100644 index 0000000000..b4040c6c1a --- /dev/null +++ b/src/test/java/lotto/domain/WinningLottoTest.java @@ -0,0 +1,40 @@ +package lotto.domain; + +import lotto.util.LottoNumberParser; +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.List; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.*; + +public class WinningLottoTest { + static Stream provideLottoNumbers() { + return Stream.of( + Arguments.of("1, 2, 3, 4, 5, 6", LottoRank.FIRST), + Arguments.of("1, 2, 3, 4, 5, 13", LottoRank.SECOND_BONUS), + Arguments.of("1, 2, 3, 4, 5, 7", LottoRank.SECOND), + Arguments.of("1, 2, 3, 4, 8, 9", LottoRank.THIRD), + Arguments.of("1, 2, 3, 10, 11, 12", LottoRank.FOURTH) + ); + } + + @ParameterizedTest + @MethodSource("provideLottoNumbers") + public void 일치하는_숫자의_개수(String numbers, LottoRank expected) { + LottoNumbers lottoNumbers = new LottoNumbers(numbers); + LottoNumbers winningLottoNumbers = new LottoNumbers(1, 2, 3, 4, 5, 6); + LottoNumber bonusNumber = new LottoNumber(13); + WinningLotto winningLotto = new WinningLotto(winningLottoNumbers, bonusNumber); + + assertThat(winningLotto.getMatchedRank(lottoNumbers)).isEqualTo(expected); + } + + @Test + public void 보너스_숫자_중복() { + assertThatThrownBy(() -> new WinningLotto("1, 2, 3, 4, 5, 6", "1")).isInstanceOf(IllegalArgumentException.class); + } +} diff --git a/src/test/java/lotto/util/LottoNumberCacheTest.java b/src/test/java/lotto/util/LottoNumberCacheTest.java new file mode 100644 index 0000000000..7413a3e400 --- /dev/null +++ b/src/test/java/lotto/util/LottoNumberCacheTest.java @@ -0,0 +1,19 @@ +package lotto.util; + +import lotto.domain.LottoNumber; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.*; + +public class LottoNumberCacheTest { + @Test + public void 캐싱() { + assertThat(LottoNumberCache.get(1)).isEqualTo(new LottoNumber(1)); + } + + @Test + public void 유효하지_않은_숫자() { + assertThatThrownBy(() -> LottoNumberCache.get(46)).isInstanceOf(IllegalArgumentException.class); + } + +} diff --git a/src/test/java/lotto/util/LottoNumberParserTest.java b/src/test/java/lotto/util/LottoNumberParserTest.java new file mode 100644 index 0000000000..62671dcf3f --- /dev/null +++ b/src/test/java/lotto/util/LottoNumberParserTest.java @@ -0,0 +1,16 @@ +package lotto.util; + +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.*; + +public class LottoNumberParserTest { + @Test + public void 중복_숫자() { + assertThatThrownBy(() -> LottoNumberParser.parse("1, 2, 2, 3, 4, 5")).isInstanceOf(IllegalArgumentException.class); + } + + @Test + public void 숫자_개수_부족() { + assertThatThrownBy(() -> LottoNumberParser.parse("1, 2, 3, 4, 5")).isInstanceOf(IllegalArgumentException.class); + } +}