From ce6479b30bba936219ee8fe7eb5d1f0de40c7477 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Sat, 3 Dec 2022 18:09:47 +0900 Subject: [PATCH 01/53] docs: readme --- docs/README.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/docs/README.md b/docs/README.md index e69de29..4e753e2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -0,0 +1,49 @@ +# 페어 매칭 + + + +# 기능 목록 + +## 페어 매칭 기능 + +### 조건 +- 미션을 수행할 페어는 기본적으로 2명씩 매칭 +- 인원이 홀수인 경우 3인으로 구성 +- 같은 레벨에서 이미 페어를 맺은 크루와는 다시 페어 매칭 불가능 + +### 구현 +- 이름 목록 -> List +- 크루 목록 random으로 섞기 -> Randoms.shuffle 활용 +- 홀수인 경우 마지막 남은 크루는 마지막 페어에 포함. +- 같은 레벨에서 만난적이 있는 크루면 다시 크루 목록의 순서를 랜덤으로 섞어서 매칭 시도 +- 3회 시도까지 매칭이 되지 않거나 매칭을 할 수 있는 경우의 수가 없으면 에러 메시지 출력 + +### 재매칭 시도 +- 안내 문구를 출력 후 매칭 진행 +- 아니오를 선택할 경우 코스, 레벨, 미션을 다시 선택 + +## 페어 조회 기능 +- 과정,레벨, 미션을 선택하면 미션의 페어 정보 출력 +- 매칭 이력이 없으면 매칭 이력 없음을 안내 + + +# 입출력 요구 사항 + +## 파일 입출력 +- 주어진 .md 파일을 활용한다. +- 두 파일의 내용은 수정이 가능하다. 그러나 크루들의 이름은 중복될 수 없다. + +## 기능 선택 +- 기능의 종류를 선택한다. +- 1,2,3,Q 이외의 입력이 들어오면 예외를 처리한다. + +## 페어 매칭 + +### 입력 + +- 미션에 대한 리스트를 출력한다. +- 과정, 레벨, 미션을 선택하고 리스트에 없는 목록을 입력한 경우 예외처리를 한다. + +### 출력 +- 이름 : 이름 형태로 출력한다. +- 크루 인원이 홀수인 경우 마지막은 3명으로 묶어서 출력한다. \ No newline at end of file From 8452ad0b131123af1b48a5997e6e0de1864e4476 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Sat, 3 Dec 2022 18:11:00 +0900 Subject: [PATCH 02/53] view: outputView --- .../java/pairmatching/view/InputView.java | 63 +++++++++++++++++++ .../java/pairmatching/view/OutputView.java | 39 ++++++++++++ src/main/java/pairmatching/view/View.java | 18 ++++++ 3 files changed, 120 insertions(+) create mode 100644 src/main/java/pairmatching/view/InputView.java create mode 100644 src/main/java/pairmatching/view/OutputView.java create mode 100644 src/main/java/pairmatching/view/View.java diff --git a/src/main/java/pairmatching/view/InputView.java b/src/main/java/pairmatching/view/InputView.java new file mode 100644 index 0000000..1e83d58 --- /dev/null +++ b/src/main/java/pairmatching/view/InputView.java @@ -0,0 +1,63 @@ +package pairmatching.view; + +import java.util.List; +import pairmatching.domain.type.Feature; +import pairmatching.domain.type.YesOrNo; +import pairmatching.util.io.ConsoleReader; + +public class InputView extends View { + + private static final String REQUEST_FEATURE = "기능을 선택하세요.\n" + + "1. 페어 매칭\n" + + "2. 페어 조회\n" + + "3. 페어 초기화\n" + + "Q. 종료"; + + private static final String REQUEST_INFORMATION = "#############################################\n" + + "과정: 백엔드 | 프론트엔드\n" + + "미션:\n" + + " - 레벨1: 자동차경주 | 로또 | 숫자야구게임\n" + + " - 레벨2: 장바구니 | 결제 | 지하철노선도\n" + + " - 레벨3: \n" + + " - 레벨4: 성능개선 | 배포\n" + + " - 레벨5: \n" + + "############################################\n" + + "과정, 레벨, 미션을 선택하세요.\n" + + "ex) 백엔드, 레벨1, 자동차경주"; + + private static final String REQUEST_YES_OR_NO = "매칭 정보가 있습니다. 다시 매칭하시겠습니까?\n" + + "네 | 아니오"; + + public Feature inputFeature() { + while (true) { + try { + print(REQUEST_FEATURE); + return ConsoleReader.readFeature(); + } catch (IllegalArgumentException e) { + printError(e.getMessage()); + } + } + } + + public YesOrNo inputRepeat() { + while (true) { + try { + print(REQUEST_YES_OR_NO); + return ConsoleReader.readYseOrNo(); + } catch (IllegalArgumentException e) { + printError(e.getMessage()); + } + } + } + + public List inputInformation() { + while (true) { + try { + print(REQUEST_INFORMATION); + return ConsoleReader.readInformation(); + } catch (IllegalArgumentException e) { + printError(e.getMessage()); + } + } + } +} diff --git a/src/main/java/pairmatching/view/OutputView.java b/src/main/java/pairmatching/view/OutputView.java new file mode 100644 index 0000000..069be0b --- /dev/null +++ b/src/main/java/pairmatching/view/OutputView.java @@ -0,0 +1,39 @@ +package pairmatching.view; + +import java.util.List; +import pairmatching.domain.type.Crew; +import pairmatching.domain.type.Pair; + +public class OutputView extends View { + + private static final String RESULT_MATCHING = "페어 매칭 결과입니다."; + private static final String INITIALIZED = "초기화 되었습니다."; + + public void showResult(List pairs) { + print(RESULT_MATCHING); + for (Pair pair : pairs) { + print(makePairFormat(pair)); + } + printEmptyLine(); + } + + public void initialized() { + print(INITIALIZED); + printEmptyLine(); + } + + @Override + public void printError(String message) { + super.printError(message); + } + + private String makePairFormat(Pair pair) { + Crew firstCrew = pair.getFirst(); + Crew secondCrew = pair.getSecond(); + Crew thirdCrew = pair.getThird(); + if (thirdCrew == null) { + return firstCrew.getName() + " : " + secondCrew.getName(); + } + return firstCrew.getName() + " : " + secondCrew.getName() + " : " + thirdCrew.getName(); + } +} diff --git a/src/main/java/pairmatching/view/View.java b/src/main/java/pairmatching/view/View.java new file mode 100644 index 0000000..42c8b47 --- /dev/null +++ b/src/main/java/pairmatching/view/View.java @@ -0,0 +1,18 @@ +package pairmatching.view; + +public class View { + + private static final String ERROR = "[ERROR]"; + + protected void print(String message) { + System.out.println(message); + } + + protected void printEmptyLine() { + System.out.println(); + } + + protected void printError(String message) { + System.out.println(ERROR + " " + message); + } +} From 4801e58b390709870d357c48d1b1ad41afdb83ef Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Sat, 3 Dec 2022 18:11:53 +0900 Subject: [PATCH 03/53] feat(type): add type --- .../java/pairmatching/domain/type/Course.java | 22 ++++++ .../java/pairmatching/domain/type/Crew.java | 46 +++++++++++++ .../pairmatching/domain/type/Feature.java | 34 ++++++++++ .../java/pairmatching/domain/type/Level.java | 32 +++++++++ .../pairmatching/domain/type/Mission.java | 51 ++++++++++++++ .../java/pairmatching/domain/type/Pair.java | 68 +++++++++++++++++++ .../pairmatching/domain/type/YesOrNo.java | 22 ++++++ 7 files changed, 275 insertions(+) create mode 100644 src/main/java/pairmatching/domain/type/Course.java create mode 100644 src/main/java/pairmatching/domain/type/Crew.java create mode 100644 src/main/java/pairmatching/domain/type/Feature.java create mode 100644 src/main/java/pairmatching/domain/type/Level.java create mode 100644 src/main/java/pairmatching/domain/type/Mission.java create mode 100644 src/main/java/pairmatching/domain/type/Pair.java create mode 100644 src/main/java/pairmatching/domain/type/YesOrNo.java diff --git a/src/main/java/pairmatching/domain/type/Course.java b/src/main/java/pairmatching/domain/type/Course.java new file mode 100644 index 0000000..e217a31 --- /dev/null +++ b/src/main/java/pairmatching/domain/type/Course.java @@ -0,0 +1,22 @@ +package pairmatching.domain.type; + +import java.util.stream.Stream; + +public enum Course { + BACKEND("백엔드"), + FRONTEND("프론트엔드"); + + private static final String INVALID_COURSE_NAME = "존재하지 않는 과정을 입력하셨습니다. ex) 백엔드, 프론트엔드"; + private final String name; + + Course(String name) { + this.name = name; + } + + public static Course matchOf(String name) { + return Stream.of(Course.values()) + .filter(course -> name.equals(course.name)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException(INVALID_COURSE_NAME)); + } +} diff --git a/src/main/java/pairmatching/domain/type/Crew.java b/src/main/java/pairmatching/domain/type/Crew.java new file mode 100644 index 0000000..4df4671 --- /dev/null +++ b/src/main/java/pairmatching/domain/type/Crew.java @@ -0,0 +1,46 @@ +package pairmatching.domain.type; + +import java.util.Objects; + +public class Crew { + private final Course course; + private final Name name; + + public Crew(Course course, Name name) { + this.course = course; + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Crew crew = (Crew) o; + return course == crew.course && Objects.equals(name, crew.name); + } + + @Override + public int hashCode() { + return Objects.hash(course, name); + } + + public Course getCourse() { + return course; + } + + public Name getName() { + return name; + } + + @Override + public String toString() { + return "Crew{" + + "course=" + course + + ", name=" + name + + '}'; + } +} diff --git a/src/main/java/pairmatching/domain/type/Feature.java b/src/main/java/pairmatching/domain/type/Feature.java new file mode 100644 index 0000000..ddd5f8d --- /dev/null +++ b/src/main/java/pairmatching/domain/type/Feature.java @@ -0,0 +1,34 @@ +package pairmatching.domain.type; + +import java.util.stream.Stream; + +public enum Feature { + PAIR_MATCHING("페어 매칭", "1"), + PAIR_SEARCH("페어 조회", "2"), + PAIR_INITIALIZE("페어 초기화", "3"), + QUIT("종료", "Q"); + + private static final String INVALID_FEATURE_KEY = "1,2,3,Q 이외에 다른 값을 입력할 수 없습니다."; + private final String name; + private final String keyType; + + Feature(String name, String keyType) { + this.name = name; + this.keyType = keyType; + } + + public static Feature matchOf(String keyType) { + return Stream.of(Feature.values()) + .filter(feature -> keyType.equals(feature.keyType)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException(INVALID_FEATURE_KEY)); + } + + public String getName() { + return name; + } + + public String getKeyType() { + return keyType; + } +} diff --git a/src/main/java/pairmatching/domain/type/Level.java b/src/main/java/pairmatching/domain/type/Level.java new file mode 100644 index 0000000..f809918 --- /dev/null +++ b/src/main/java/pairmatching/domain/type/Level.java @@ -0,0 +1,32 @@ +package pairmatching.domain.type; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public enum Level { + LEVEL1("레벨1"), + LEVEL2("레벨2"), + LEVEL3("레벨3"), + LEVEL4("레벨4"), + LEVEL5("레벨5"); + + private static final String INVALID_LEVEL_NAME = "레벨 입력이 옳바르지 않습니다."; + private final String name; + + Level(String name) { + this.name = name; + } + + public static Level matchOf(String name) { + return Stream.of(Level.values()) + .filter(level -> name.equals(level.name)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException(INVALID_LEVEL_NAME)); + } + + @Override + public String toString() { + return name; + } +} diff --git a/src/main/java/pairmatching/domain/type/Mission.java b/src/main/java/pairmatching/domain/type/Mission.java new file mode 100644 index 0000000..f00aff3 --- /dev/null +++ b/src/main/java/pairmatching/domain/type/Mission.java @@ -0,0 +1,51 @@ +package pairmatching.domain.type; + +import java.util.Arrays; +import java.util.stream.Stream; + +public enum Mission { + RACING_CAR("자동차경주", Level.LEVEL1), + LOTTO("로또", Level.LEVEL1), + BASE_BALL("숫자야구게임", Level.LEVEL1), + BASKET("장바구니", Level.LEVEL2), + CREDIT("결제", Level.LEVEL2), + SUBWAY("지하철노선도", Level.LEVEL2), + IMPROVEMENT("성능개선", Level.LEVEL4), + DISTRIBUTE("배포", Level.LEVEL4); + + private static final String INVALID_MISSION_NAME = "레벨에 맞는 정확한 미션 이름을 입력해주세요."; + private final String name; + private final Level level; + + Mission(String name, Level level) { + this.name = name; + this.level = level; + } + + public static Mission matchOf(String name) { + return Stream.of(Mission.values()) + .filter(mission -> name.equals(mission.name)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException(INVALID_MISSION_NAME)); + } + + public static Mission matchOf(String name, Level level) { + return Stream.of(Mission.values()) + .filter(mission -> name.equals(mission.name) && level.equals(mission.level)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException(INVALID_MISSION_NAME)); + } + + public String getName() { + return name; + } + + public Level getLevel() { + return level; + } + + @Override + public String toString() { + return level + ":" + name; + } +} diff --git a/src/main/java/pairmatching/domain/type/Pair.java b/src/main/java/pairmatching/domain/type/Pair.java new file mode 100644 index 0000000..0c45277 --- /dev/null +++ b/src/main/java/pairmatching/domain/type/Pair.java @@ -0,0 +1,68 @@ +package pairmatching.domain.type; + +import java.util.Objects; + +public class Pair { + private final Mission mission; + private final Crew first; + private final Crew second; + private final Crew third; + + public Pair(Mission mission, Crew first, Crew second) { + this.mission = mission; + this.first = first; + this.second = second; + this.third = null; + } + + public Pair(Mission mission, Crew first, Crew second, Crew third) { + this.mission = mission; + this.first = first; + this.second = second; + this.third = third; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Pair pair = (Pair) o; + return mission == pair.mission && Objects.equals(first, pair.first) && Objects.equals(second, + pair.second) && Objects.equals(third, pair.third); + } + + @Override + public int hashCode() { + return Objects.hash(mission, first, second, third); + } + + public Mission getMission() { + return mission; + } + + public Crew getFirst() { + return first; + } + + public Crew getSecond() { + return second; + } + + public Crew getThird() { + return third; + } + + @Override + public String toString() { + return "Pair{" + + "mission=" + mission + + ", first=" + first + + ", second=" + second + + ", third=" + third + + '}'; + } +} diff --git a/src/main/java/pairmatching/domain/type/YesOrNo.java b/src/main/java/pairmatching/domain/type/YesOrNo.java new file mode 100644 index 0000000..1f36496 --- /dev/null +++ b/src/main/java/pairmatching/domain/type/YesOrNo.java @@ -0,0 +1,22 @@ +package pairmatching.domain.type; + +import java.util.stream.Stream; + +public enum YesOrNo { + YES("네"), + NO("아니오"); + + private static final String INVALID_YES_OR_NO_NAME ="네 | 아니오 만 입력해주세요."; + private final String name; + + YesOrNo(String name) { + this.name = name; + } + + public static YesOrNo matchOf(String name) { + return Stream.of(YesOrNo.values()) + .filter(yesOrNo -> name.equals(yesOrNo.name)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException(INVALID_YES_OR_NO_NAME)); + } +} From e463e14b2f14491e9870192d8d15cf6d1d61d633 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Sat, 3 Dec 2022 18:15:57 +0900 Subject: [PATCH 04/53] feat(maker): add pairMaker --- .../domain/maker/EvenPairMaker.java | 19 +++++++++++++++++ .../domain/maker/OddPairMaker.java | 21 +++++++++++++++++++ .../pairmatching/domain/maker/PairMaker.java | 11 ++++++++++ 3 files changed, 51 insertions(+) create mode 100644 src/main/java/pairmatching/domain/maker/EvenPairMaker.java create mode 100644 src/main/java/pairmatching/domain/maker/OddPairMaker.java create mode 100644 src/main/java/pairmatching/domain/maker/PairMaker.java diff --git a/src/main/java/pairmatching/domain/maker/EvenPairMaker.java b/src/main/java/pairmatching/domain/maker/EvenPairMaker.java new file mode 100644 index 0000000..309a7f4 --- /dev/null +++ b/src/main/java/pairmatching/domain/maker/EvenPairMaker.java @@ -0,0 +1,19 @@ +package pairmatching.domain.maker; + +import java.util.ArrayList; +import java.util.List; +import pairmatching.domain.type.Crew; +import pairmatching.domain.type.Mission; +import pairmatching.domain.type.Pair; + +public class EvenPairMaker implements PairMaker { + + @Override + public List createPair(Mission mission, List names) { + List pairs = new ArrayList<>(); + for (int i = 0; i < names.size() - 1; i += 2) { + pairs.add(new Pair(mission, names.get(i), names.get(i + 1))); + } + return pairs; + } +} diff --git a/src/main/java/pairmatching/domain/maker/OddPairMaker.java b/src/main/java/pairmatching/domain/maker/OddPairMaker.java new file mode 100644 index 0000000..431eb26 --- /dev/null +++ b/src/main/java/pairmatching/domain/maker/OddPairMaker.java @@ -0,0 +1,21 @@ +package pairmatching.domain.maker; + +import java.util.ArrayList; +import java.util.List; +import pairmatching.domain.type.Crew; +import pairmatching.domain.type.Mission; +import pairmatching.domain.type.Pair; + +public class OddPairMaker implements PairMaker { + + @Override + public List createPair(Mission mission, List names) { + List pairs = new ArrayList<>(); + int lastIndex = names.size() - 3; + for (int i = 0; i < lastIndex; i += 2) { + pairs.add(new Pair(mission, names.get(i), names.get(i + 1))); + } + pairs.add(new Pair(mission, names.get(lastIndex), names.get(lastIndex + 1), names.get(lastIndex + 2))); + return pairs; + } +} diff --git a/src/main/java/pairmatching/domain/maker/PairMaker.java b/src/main/java/pairmatching/domain/maker/PairMaker.java new file mode 100644 index 0000000..9a17a7b --- /dev/null +++ b/src/main/java/pairmatching/domain/maker/PairMaker.java @@ -0,0 +1,11 @@ +package pairmatching.domain.maker; + +import java.util.List; +import pairmatching.domain.type.Crew; +import pairmatching.domain.type.Mission; +import pairmatching.domain.type.Pair; + +public interface PairMaker { + + List createPair(Mission mission, List names); +} From 011edd1690b3e2b4a051743ecfed5e1d14200568 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Sat, 3 Dec 2022 18:16:18 +0900 Subject: [PATCH 05/53] feat(io): add reader --- .../pairmatching/util/io/ConsoleReader.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/main/java/pairmatching/util/io/ConsoleReader.java diff --git a/src/main/java/pairmatching/util/io/ConsoleReader.java b/src/main/java/pairmatching/util/io/ConsoleReader.java new file mode 100644 index 0000000..c5c7db6 --- /dev/null +++ b/src/main/java/pairmatching/util/io/ConsoleReader.java @@ -0,0 +1,33 @@ +package pairmatching.util.io; + +import camp.nextstep.edu.missionutils.Console; +import java.util.List; +import pairmatching.domain.type.Course; +import pairmatching.domain.type.Feature; +import pairmatching.domain.type.Level; +import pairmatching.domain.type.Mission; +import pairmatching.domain.type.YesOrNo; + +public class ConsoleReader { + + private static final String COMMA = ","; + + public static Feature readFeature() { + String line = Console.readLine(); + return Feature.matchOf(line); + } + + public static List readInformation() { + String line = Console.readLine(); + String[] split = line.split(COMMA); + Course course = Course.matchOf(split[0].trim()); + Level level = Level.matchOf(split[1].trim()); + Mission mission = Mission.matchOf(split[2].trim(), level); + return List.of(course, level, mission); + } + + public static YesOrNo readYseOrNo() { + String line = Console.readLine(); + return YesOrNo.matchOf(line); + } +} From 0e6697a626619c52d0613a5095f8c9f449614b88 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Sat, 3 Dec 2022 18:17:21 +0900 Subject: [PATCH 06/53] feat(duplicateChecker): add duplicateChecker --- .../checker/DefaultDuplicateChecker.java | 26 +++++++++++++++++++ .../domain/checker/DuplicateChecker.java | 15 +++++++++++ 2 files changed, 41 insertions(+) create mode 100644 src/main/java/pairmatching/domain/checker/DefaultDuplicateChecker.java create mode 100644 src/main/java/pairmatching/domain/checker/DuplicateChecker.java diff --git a/src/main/java/pairmatching/domain/checker/DefaultDuplicateChecker.java b/src/main/java/pairmatching/domain/checker/DefaultDuplicateChecker.java new file mode 100644 index 0000000..5a3b1bf --- /dev/null +++ b/src/main/java/pairmatching/domain/checker/DefaultDuplicateChecker.java @@ -0,0 +1,26 @@ +package pairmatching.domain.checker; + +import java.util.List; +import pairmatching.domain.db.PairDatabase; +import pairmatching.domain.type.Course; +import pairmatching.domain.type.Mission; +import pairmatching.domain.type.Pair; + +public class DefaultDuplicateChecker implements DuplicateChecker { + + private final PairDatabase database; + + public DefaultDuplicateChecker(PairDatabase database) { + this.database = database; + } + + @Override + public boolean isDuplicate(Course course, Mission mission) { + return database.exist(course, mission); + } + + @Override + public boolean isDuplicatePair(String inputKey, List pairs) { + return pairs.stream().anyMatch(pair -> database.existPair(inputKey, pair)); + } +} diff --git a/src/main/java/pairmatching/domain/checker/DuplicateChecker.java b/src/main/java/pairmatching/domain/checker/DuplicateChecker.java new file mode 100644 index 0000000..69897a6 --- /dev/null +++ b/src/main/java/pairmatching/domain/checker/DuplicateChecker.java @@ -0,0 +1,15 @@ +package pairmatching.domain.checker; + + +import java.util.List; +import pairmatching.domain.type.Course; +import pairmatching.domain.type.Mission; +import pairmatching.domain.type.Pair; + + +public interface DuplicateChecker { + + boolean isDuplicate(Course course, Mission mission); + + boolean isDuplicatePair(String inputKey, List pairs); +} From e6adde70996351c34ee69773f9b3aa56a1e16785 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Sat, 3 Dec 2022 18:21:45 +0900 Subject: [PATCH 07/53] feat(fileLoader): add fileNameLoader --- .../pairmatching/util/io/FileNameLoader.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/main/java/pairmatching/util/io/FileNameLoader.java diff --git a/src/main/java/pairmatching/util/io/FileNameLoader.java b/src/main/java/pairmatching/util/io/FileNameLoader.java new file mode 100644 index 0000000..0b90c30 --- /dev/null +++ b/src/main/java/pairmatching/util/io/FileNameLoader.java @@ -0,0 +1,33 @@ +package pairmatching.util.io; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import pairmatching.domain.type.Name; + + +public class FileNameLoader implements NameLoader { + + private static final String IO_ERROR = "파일을 읽는데 에러가 발생했습니다."; + + @Override + public List loadNames(String path) { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + URL url = classLoader.getResource(path); + if (url == null) { + return new ArrayList<>(); + } + List names; + try { + names = Files.readAllLines(Paths.get(url.toURI())); + } catch (IOException | URISyntaxException e) { + throw new IllegalStateException(IO_ERROR); + } + return names.stream().map(Name::new).collect(Collectors.toList()); + } +} From 233f6c55aabb465a1bcbbec1bcb2e86f961f41c3 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Sat, 3 Dec 2022 18:30:15 +0900 Subject: [PATCH 08/53] feat(type): add name --- .../java/pairmatching/domain/type/Name.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/main/java/pairmatching/domain/type/Name.java diff --git a/src/main/java/pairmatching/domain/type/Name.java b/src/main/java/pairmatching/domain/type/Name.java new file mode 100644 index 0000000..4020385 --- /dev/null +++ b/src/main/java/pairmatching/domain/type/Name.java @@ -0,0 +1,32 @@ +package pairmatching.domain.type; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Name { + + private static final String NAME_ERROR = "이름 똑바로 입력하세요."; + private final String name; + + public Name(String name) { + validateName(name); + this.name = name; + } + + private void validateName(String name) { + Matcher matcher = Pattern.compile("^[a-zA-Z가-힣]{1,10}$").matcher(name); + if (matcher.matches()) { + return; + } + throw new IllegalStateException(NAME_ERROR); + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return name; + } +} From 355ad7c211283e149b8c2aecccbd68a1ac3e3fea Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Sat, 3 Dec 2022 18:30:27 +0900 Subject: [PATCH 09/53] feat(nameLoader): addNameLoader --- src/main/java/pairmatching/util/io/NameLoader.java | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/main/java/pairmatching/util/io/NameLoader.java diff --git a/src/main/java/pairmatching/util/io/NameLoader.java b/src/main/java/pairmatching/util/io/NameLoader.java new file mode 100644 index 0000000..fcacaf1 --- /dev/null +++ b/src/main/java/pairmatching/util/io/NameLoader.java @@ -0,0 +1,8 @@ +package pairmatching.util.io; + +import java.util.List; + +public interface NameLoader { + + List loadNames(String path); +} From af3573d3588a4fe04b4525d69438e4386dd3bfea Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Sat, 3 Dec 2022 18:32:20 +0900 Subject: [PATCH 10/53] feat(database): add database --- .../pairmatching/domain/db/PairDatabase.java | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 src/main/java/pairmatching/domain/db/PairDatabase.java diff --git a/src/main/java/pairmatching/domain/db/PairDatabase.java b/src/main/java/pairmatching/domain/db/PairDatabase.java new file mode 100644 index 0000000..675e401 --- /dev/null +++ b/src/main/java/pairmatching/domain/db/PairDatabase.java @@ -0,0 +1,55 @@ +package pairmatching.domain.db; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import pairmatching.domain.type.Course; +import pairmatching.domain.type.Mission; +import pairmatching.domain.type.Pair; + +public class PairDatabase { + + private static final String NOT_FOUND = "매칭 이력이 없습니다."; + + private final Map> memory = new HashMap<>(); + + + public void addAll(Course course, Mission mission, List pairs) { + memory.computeIfAbsent(course.toString() + " " + mission.toString(), key -> new ArrayList<>()).addAll(pairs); + } + + public boolean exist(Course course, Mission mission) { + return memory.containsKey(course.toString() + " " + mission.toString()); + } + + public boolean existPair(String inputKey, Pair data) { + List keys = findKeys(inputKey); + return keys.stream().map(memory::get) + .anyMatch(pairs -> matchPair(pairs, data)); + } + + public List getAll(Course course, Mission mission) { + List pairs = memory.get(course.toString() + " " + mission.toString()); + if (pairs == null) { + throw new IllegalArgumentException(NOT_FOUND); + } + return pairs; + } + + public void clear() { + memory.clear(); + } + + private List findKeys(String inputKey) { + return memory.keySet().stream() + .filter(key -> key.contains(inputKey)) + .collect(Collectors.toList()); + } + + private boolean matchPair(List pairs, Pair value) { + return pairs.stream() + .anyMatch(pair -> pair.equals(value)); + } +} From 0734e836758a674132db70d8a69cf0541adfb32a Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Sat, 3 Dec 2022 18:32:54 +0900 Subject: [PATCH 11/53] feat(crewLoader): add loader --- .../domain/loader/CrewLoader.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/main/java/pairmatching/domain/loader/CrewLoader.java diff --git a/src/main/java/pairmatching/domain/loader/CrewLoader.java b/src/main/java/pairmatching/domain/loader/CrewLoader.java new file mode 100644 index 0000000..4b6b820 --- /dev/null +++ b/src/main/java/pairmatching/domain/loader/CrewLoader.java @@ -0,0 +1,42 @@ +package pairmatching.domain.loader; + +import camp.nextstep.edu.missionutils.Randoms; +import java.util.List; +import java.util.stream.Collectors; +import pairmatching.domain.type.Course; +import pairmatching.domain.type.Crew; +import pairmatching.domain.type.Name; +import pairmatching.util.io.FileNameLoader; +import pairmatching.util.io.NameLoader; + +public class CrewLoader { + + private static final String backendPath = "backend-crew.md"; + private static final String frontendPath = "fontend-crew.md"; + private static final String INVALID_COURSE_NAME = "정확한 Course 타입 입력을 해야 합니다."; + private final NameLoader nameLoader = new FileNameLoader(); + + public List getNames(Course course) { + if (course.equals(Course.BACKEND)) { + return makeBackCrews(); + } + if (course.equals(Course.FRONTEND)) { + return makeFrontCrews(); + } + throw new IllegalArgumentException(INVALID_COURSE_NAME); + } + + private List makeBackCrews() { + List names = nameLoader.loadNames(backendPath); + List temp = names.stream().map(Name::toString).collect(Collectors.toList()); + List shuffles = Randoms.shuffle(temp); + return shuffles.stream().map(s -> new Crew(Course.BACKEND, new Name(s))).collect(Collectors.toList()); + } + + private List makeFrontCrews() { + List names = nameLoader.loadNames(frontendPath); + List temp = names.stream().map(Name::toString).collect(Collectors.toList()); + List shuffles = Randoms.shuffle(temp); + return shuffles.stream().map(s -> new Crew(Course.FRONTEND, new Name(s))).collect(Collectors.toList()); + } +} From fb245c4d25f66d388388739e12b8a7750d80ee7f Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Sat, 3 Dec 2022 18:33:07 +0900 Subject: [PATCH 12/53] feat(controller): add controller --- .../controller/PairMatchingController.java | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 src/main/java/pairmatching/controller/PairMatchingController.java diff --git a/src/main/java/pairmatching/controller/PairMatchingController.java b/src/main/java/pairmatching/controller/PairMatchingController.java new file mode 100644 index 0000000..aec0eda --- /dev/null +++ b/src/main/java/pairmatching/controller/PairMatchingController.java @@ -0,0 +1,75 @@ +package pairmatching.controller; + +import java.util.List; +import pairmatching.domain.PairMatchingGame; +import pairmatching.domain.type.Course; +import pairmatching.domain.type.Feature; +import pairmatching.domain.type.Level; +import pairmatching.domain.type.Mission; +import pairmatching.domain.type.Pair; +import pairmatching.view.InputView; +import pairmatching.view.OutputView; + +public class PairMatchingController { + + private final InputView inputView = new InputView(); + private final OutputView outputView = new OutputView(); + private final PairMatchingGame pairMatchingGame = new PairMatchingGame(); + + public void play() { + try { + chooseFeature(); + } catch(IllegalArgumentException | IllegalStateException e) { + outputView.printError(e.getMessage()); + } + } + + + private void chooseFeature() { + while (true) { + Feature feature = inputView.inputFeature(); + if (feature.equals(Feature.PAIR_MATCHING)) { + pairMatch(); + } + if (feature.equals(Feature.PAIR_SEARCH)) { + showMatch(); + } + if (feature.equals(Feature.PAIR_INITIALIZE)) { + initialize(); + } + if (feature.equals(Feature.QUIT)) { + return; + } + } + } + + public void pairMatch() { + while (true) { + List objects = inputView.inputInformation(); + boolean duplicateRequest = pairMatchingGame.isDuplicateRequest((Course) objects.get(0), + (Mission) objects.get(2)); + if (duplicateRequest) { + continue; + } + pairMatchingGame.pairMatch((Course) objects.get(0), (Level) objects.get(1), (Mission) objects.get(2)); + List pairs = pairMatchingGame.showPair((Course) objects.get(0), (Mission) objects.get(2)); + outputView.showResult(pairs); + return; + } + } + + public void showMatch() { + try { + List objects = inputView.inputInformation(); + List pairs = pairMatchingGame.showPair((Course) objects.get(0), (Mission) objects.get(2)); + outputView.showResult(pairs); + } catch (IllegalArgumentException | IllegalStateException e) { + outputView.printError(e.getMessage()); + } + } + + public void initialize() { + pairMatchingGame.initialize(); + outputView.initialized(); + } +} From 1fd08b4552dc078242da7bb3705fe997ba0af775 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Sat, 3 Dec 2022 18:33:17 +0900 Subject: [PATCH 13/53] feat(gameService): add service --- .../pairmatching/domain/PairMatchingGame.java | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/main/java/pairmatching/domain/PairMatchingGame.java diff --git a/src/main/java/pairmatching/domain/PairMatchingGame.java b/src/main/java/pairmatching/domain/PairMatchingGame.java new file mode 100644 index 0000000..92f4e79 --- /dev/null +++ b/src/main/java/pairmatching/domain/PairMatchingGame.java @@ -0,0 +1,49 @@ +package pairmatching.domain; + +import java.util.List; +import pairmatching.domain.checker.DefaultDuplicateChecker; +import pairmatching.domain.checker.DuplicateChecker; +import pairmatching.domain.db.PairDatabase; +import pairmatching.domain.loader.CrewLoader; +import pairmatching.domain.maker.EvenPairMaker; +import pairmatching.domain.maker.OddPairMaker; +import pairmatching.domain.maker.PairMaker; +import pairmatching.domain.type.Course; +import pairmatching.domain.type.Crew; +import pairmatching.domain.type.Level; +import pairmatching.domain.type.Mission; +import pairmatching.domain.type.Pair; + +public class PairMatchingGame { + + private final PairDatabase database = new PairDatabase(); + private final CrewLoader crewLoader = new CrewLoader(); + private final DuplicateChecker duplicateChecker = new DefaultDuplicateChecker(database); + + public boolean isDuplicateRequest(Course course, Mission mission) { + return duplicateChecker.isDuplicate(course, mission); + } + + public void pairMatch(Course course, Level level, Mission mission) { + List names = crewLoader.getNames(course); + PairMaker pairMaker = createPairMaker(names.size()); + List pairs = pairMaker.createPair(mission, names); + duplicateChecker.isDuplicatePair(level.toString(), pairs); + database.addAll(course, mission, pairs); + } + + public List showPair(Course course, Mission mission) { + return database.getAll(course, mission); + } + + public void initialize() { + database.clear(); + } + + private PairMaker createPairMaker(int number) { + if (number % 2 == 0) { + return new EvenPairMaker(); + } + return new OddPairMaker(); + } +} From b51427504ef20f1608b6c45a206384d11bc95996 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Sat, 3 Dec 2022 18:33:27 +0900 Subject: [PATCH 14/53] test(test): add test --- src/main/java/pairmatching/Application.java | 6 ++++-- src/test/java/pairmatching/code/CodeTest.java | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/pairmatching/Application.java b/src/main/java/pairmatching/Application.java index c619a21..66e82f3 100644 --- a/src/main/java/pairmatching/Application.java +++ b/src/main/java/pairmatching/Application.java @@ -1,8 +1,10 @@ package pairmatching; +import pairmatching.controller.PairMatchingController; + public class Application { public static void main(String[] args) { - // TODO 구현 진행 - + PairMatchingController pairMatchingController = new PairMatchingController(); + pairMatchingController.play(); } } diff --git a/src/test/java/pairmatching/code/CodeTest.java b/src/test/java/pairmatching/code/CodeTest.java index 9f779ab..162d986 100644 --- a/src/test/java/pairmatching/code/CodeTest.java +++ b/src/test/java/pairmatching/code/CodeTest.java @@ -10,7 +10,6 @@ public class CodeTest { @Test void parameterTest() { // given - // given // 메서드(public) 5개까지 제한 // 필드(클래스, 인스턴스 포함) 4개 제한 From e89c9dadcaca1e52e40b7b1c088d9baea0ec13e0 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:46:52 +0900 Subject: [PATCH 15/53] feat(pairMaker): add even, odd pair maker --- src/main/java/pairmatching/domain/maker/EvenPairMaker.java | 5 ++--- src/main/java/pairmatching/domain/maker/OddPairMaker.java | 7 +++---- src/main/java/pairmatching/domain/maker/PairMaker.java | 3 +-- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/main/java/pairmatching/domain/maker/EvenPairMaker.java b/src/main/java/pairmatching/domain/maker/EvenPairMaker.java index 309a7f4..51d524d 100644 --- a/src/main/java/pairmatching/domain/maker/EvenPairMaker.java +++ b/src/main/java/pairmatching/domain/maker/EvenPairMaker.java @@ -3,16 +3,15 @@ import java.util.ArrayList; import java.util.List; import pairmatching.domain.type.Crew; -import pairmatching.domain.type.Mission; import pairmatching.domain.type.Pair; public class EvenPairMaker implements PairMaker { @Override - public List createPair(Mission mission, List names) { + public List createPair(List names) { List pairs = new ArrayList<>(); for (int i = 0; i < names.size() - 1; i += 2) { - pairs.add(new Pair(mission, names.get(i), names.get(i + 1))); + pairs.add(new Pair(names.get(i), names.get(i + 1))); } return pairs; } diff --git a/src/main/java/pairmatching/domain/maker/OddPairMaker.java b/src/main/java/pairmatching/domain/maker/OddPairMaker.java index 431eb26..6968ee7 100644 --- a/src/main/java/pairmatching/domain/maker/OddPairMaker.java +++ b/src/main/java/pairmatching/domain/maker/OddPairMaker.java @@ -3,19 +3,18 @@ import java.util.ArrayList; import java.util.List; import pairmatching.domain.type.Crew; -import pairmatching.domain.type.Mission; import pairmatching.domain.type.Pair; public class OddPairMaker implements PairMaker { @Override - public List createPair(Mission mission, List names) { + public List createPair(List names) { List pairs = new ArrayList<>(); int lastIndex = names.size() - 3; for (int i = 0; i < lastIndex; i += 2) { - pairs.add(new Pair(mission, names.get(i), names.get(i + 1))); + pairs.add(new Pair(names.get(i), names.get(i + 1))); } - pairs.add(new Pair(mission, names.get(lastIndex), names.get(lastIndex + 1), names.get(lastIndex + 2))); + pairs.add(new Pair(names.get(lastIndex), names.get(lastIndex + 1), names.get(lastIndex + 2))); return pairs; } } diff --git a/src/main/java/pairmatching/domain/maker/PairMaker.java b/src/main/java/pairmatching/domain/maker/PairMaker.java index 9a17a7b..0e2502a 100644 --- a/src/main/java/pairmatching/domain/maker/PairMaker.java +++ b/src/main/java/pairmatching/domain/maker/PairMaker.java @@ -2,10 +2,9 @@ import java.util.List; import pairmatching.domain.type.Crew; -import pairmatching.domain.type.Mission; import pairmatching.domain.type.Pair; public interface PairMaker { - List createPair(Mission mission, List names); + List createPair(List names); } From c84bb62ed02ec8b52c14147ffd04d75b038c66a2 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:47:24 +0900 Subject: [PATCH 16/53] test(pairMaker): test even, odd pair maker --- .../domain/maker/PairMakerTest.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/test/java/pairmatching/domain/maker/PairMakerTest.java diff --git a/src/test/java/pairmatching/domain/maker/PairMakerTest.java b/src/test/java/pairmatching/domain/maker/PairMakerTest.java new file mode 100644 index 0000000..5f49684 --- /dev/null +++ b/src/test/java/pairmatching/domain/maker/PairMakerTest.java @@ -0,0 +1,43 @@ +package pairmatching.domain.maker; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import pairmatching.domain.type.Crew; +import pairmatching.domain.type.Pair; + +class PairMakerTest { + + @Test + void shouldReturnFinalPairLengthIs3WhenCrewsSizeAreOdd() { + //given + List crews = Stream.of("현승", "현규", "현자").map(Crew::makeBackendCrew).collect(Collectors.toList()); + PairMaker pairMaker = new OddPairMaker(); + + // when + List result = pairMaker.createPair(crews); + + // then + Pair lastPair = result.get(result.size() - 1); + assertThat(lastPair.getThird()).isNotNull(); + } + + @Test + void shouldReturnDoublePairWhenCrewsSizeIsEven() { + //given + List crews = Stream.of("현승", "현규", "현자", "현식").map(Crew::makeBackendCrew).collect(Collectors.toList()); + PairMaker pairMaker = new EvenPairMaker(); + + // when + List result = pairMaker.createPair(crews); + + // then + result.forEach((pair -> { + assertThat(pair.getFirst()).isNotNull(); + assertThat(pair.getSecond()).isNotNull(); + })); + } +} \ No newline at end of file From 60a9b52a80502684135a1e04ac7716a92d1b8da3 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:48:23 +0900 Subject: [PATCH 17/53] feat(pairStatus): add status interface --- .../java/pairmatching/luncher/status/PairStatus.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/java/pairmatching/luncher/status/PairStatus.java diff --git a/src/main/java/pairmatching/luncher/status/PairStatus.java b/src/main/java/pairmatching/luncher/status/PairStatus.java new file mode 100644 index 0000000..7e2b1ff --- /dev/null +++ b/src/main/java/pairmatching/luncher/status/PairStatus.java @@ -0,0 +1,10 @@ +package pairmatching.luncher.status; + +import pairmatching.luncher.controller.PairMatchingController; + +public interface PairStatus { + + PairStatus next(PairMatchingController context); + + boolean isRunnable(); +} From 7a35b3fca7a07e18503b292e07eb010ad90d9d9f Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:48:39 +0900 Subject: [PATCH 18/53] feat(pairStatus): add search status --- .../luncher/status/PairSearchStatus.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/main/java/pairmatching/luncher/status/PairSearchStatus.java diff --git a/src/main/java/pairmatching/luncher/status/PairSearchStatus.java b/src/main/java/pairmatching/luncher/status/PairSearchStatus.java new file mode 100644 index 0000000..042de77 --- /dev/null +++ b/src/main/java/pairmatching/luncher/status/PairSearchStatus.java @@ -0,0 +1,22 @@ +package pairmatching.luncher.status; + +import pairmatching.luncher.controller.PairMatchingController; +import pairmatching.exception.EmptyMatchedCrewException; + +public class PairSearchStatus implements PairStatus { + + @Override + public PairStatus next(PairMatchingController context) { + try { + context.requestShowMatchedCrew(); + } catch(EmptyMatchedCrewException e) { + context.printError(e.getMessage()); + } + return new PairFeatureStatus(); + } + + @Override + public boolean isRunnable() { + return true; + } +} From 38feca2dfaf92644c62e8913072a98b73dc12d31 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:49:05 +0900 Subject: [PATCH 19/53] feat(pairStatus): add retryStatus --- .../luncher/status/PairRetryStatus.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/main/java/pairmatching/luncher/status/PairRetryStatus.java diff --git a/src/main/java/pairmatching/luncher/status/PairRetryStatus.java b/src/main/java/pairmatching/luncher/status/PairRetryStatus.java new file mode 100644 index 0000000..7b42dc7 --- /dev/null +++ b/src/main/java/pairmatching/luncher/status/PairRetryStatus.java @@ -0,0 +1,23 @@ +package pairmatching.luncher.status; + +import pairmatching.domain.type.YesOrNo; +import pairmatching.luncher.controller.PairMatchingController; +import pairmatching.luncher.status.match.PairDirectMatchingStatus; +import pairmatching.luncher.status.match.PairReMatchingStatus; + +public class PairRetryStatus implements PairStatus { + + @Override + public PairStatus next(PairMatchingController context) { + YesOrNo yesOrNo = context.requestRetry(); + if (yesOrNo.equals(YesOrNo.YES)) { + return new PairDirectMatchingStatus(0); + } + return new PairReMatchingStatus(); + } + + @Override + public boolean isRunnable() { + return true; + } +} From 688086346cc53235e81eaf10a5e0203c18abd2a5 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:49:12 +0900 Subject: [PATCH 20/53] feat(pairStatus): add resetStatus --- .../luncher/status/PairResetStatus.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/main/java/pairmatching/luncher/status/PairResetStatus.java diff --git a/src/main/java/pairmatching/luncher/status/PairResetStatus.java b/src/main/java/pairmatching/luncher/status/PairResetStatus.java new file mode 100644 index 0000000..4fc866d --- /dev/null +++ b/src/main/java/pairmatching/luncher/status/PairResetStatus.java @@ -0,0 +1,17 @@ +package pairmatching.luncher.status; + +import pairmatching.luncher.controller.PairMatchingController; + +public class PairResetStatus implements PairStatus { + + @Override + public PairStatus next(PairMatchingController context) { + context.requestReset(); + return new PairFeatureStatus(); + } + + @Override + public boolean isRunnable() { + return false; + } +} From dadffdcd8064716b1d5eed2c0bcafd2debd0f40f Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:49:47 +0900 Subject: [PATCH 21/53] feat(pairStatus): add matchingStatus --- .../match/PairDirectMatchingStatus.java | 42 +++++++++++++++++++ .../status/match/PairMatchingStatus.java | 28 +++++++++++++ .../status/match/PairReMatchingStatus.java | 28 +++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 src/main/java/pairmatching/luncher/status/match/PairDirectMatchingStatus.java create mode 100644 src/main/java/pairmatching/luncher/status/match/PairMatchingStatus.java create mode 100644 src/main/java/pairmatching/luncher/status/match/PairReMatchingStatus.java diff --git a/src/main/java/pairmatching/luncher/status/match/PairDirectMatchingStatus.java b/src/main/java/pairmatching/luncher/status/match/PairDirectMatchingStatus.java new file mode 100644 index 0000000..568d68d --- /dev/null +++ b/src/main/java/pairmatching/luncher/status/match/PairDirectMatchingStatus.java @@ -0,0 +1,42 @@ +package pairmatching.luncher.status.match; + +import pairmatching.exception.DuplicateException; +import pairmatching.exception.DuplicatePairException; +import pairmatching.exception.ExceedTryCountException; +import pairmatching.luncher.controller.PairMatchingController; +import pairmatching.luncher.status.PairFeatureStatus; +import pairmatching.luncher.status.PairRetryStatus; +import pairmatching.luncher.status.PairStatus; + +public class PairDirectMatchingStatus implements PairStatus { + + private static final int LIMIT_MAX_TRY = 3; + private final int tryCount; + + public PairDirectMatchingStatus(int tryCount) { + validateTryCount(tryCount); + this.tryCount = tryCount; + } + @Override + public PairStatus next(PairMatchingController context) { + try { + context.directMatch(); + return new PairFeatureStatus(); + } catch (DuplicateException e) { + return new PairRetryStatus(); + } catch (DuplicatePairException e) { + return new PairDirectMatchingStatus(tryCount + 1); + } + } + + private void validateTryCount(int tryCount) { + if (tryCount >= LIMIT_MAX_TRY) { + throw new ExceedTryCountException(tryCount); + } + } + + @Override + public boolean isRunnable() { + return true; + } +} diff --git a/src/main/java/pairmatching/luncher/status/match/PairMatchingStatus.java b/src/main/java/pairmatching/luncher/status/match/PairMatchingStatus.java new file mode 100644 index 0000000..87be808 --- /dev/null +++ b/src/main/java/pairmatching/luncher/status/match/PairMatchingStatus.java @@ -0,0 +1,28 @@ +package pairmatching.luncher.status.match; + +import pairmatching.exception.DuplicateException; +import pairmatching.exception.DuplicatePairException; +import pairmatching.luncher.controller.PairMatchingController; +import pairmatching.luncher.status.PairFeatureStatus; +import pairmatching.luncher.status.PairRetryStatus; +import pairmatching.luncher.status.PairStatus; + +public class PairMatchingStatus implements PairStatus { + + @Override + public PairStatus next(PairMatchingController context) { + try { + context.requestPairMatch(); + return new PairFeatureStatus(); + } catch (DuplicateException e) { + return new PairRetryStatus(); + } catch (DuplicatePairException e) { + return new PairDirectMatchingStatus(1); + } + } + + @Override + public boolean isRunnable() { + return true; + } +} diff --git a/src/main/java/pairmatching/luncher/status/match/PairReMatchingStatus.java b/src/main/java/pairmatching/luncher/status/match/PairReMatchingStatus.java new file mode 100644 index 0000000..288b943 --- /dev/null +++ b/src/main/java/pairmatching/luncher/status/match/PairReMatchingStatus.java @@ -0,0 +1,28 @@ +package pairmatching.luncher.status.match; + +import pairmatching.exception.DuplicateException; +import pairmatching.exception.DuplicatePairException; +import pairmatching.luncher.controller.PairMatchingController; +import pairmatching.luncher.status.PairFeatureStatus; +import pairmatching.luncher.status.PairRetryStatus; +import pairmatching.luncher.status.PairStatus; + +public class PairReMatchingStatus implements PairStatus { + + @Override + public PairStatus next(PairMatchingController context) { + try { + context.requestRePairMatch(); + return new PairFeatureStatus(); + } catch (DuplicateException e) { + return new PairRetryStatus(); + } catch (DuplicatePairException e) { + return new PairDirectMatchingStatus(1); + } + } + + @Override + public boolean isRunnable() { + return true; + } +} From c931b61823dea3af56bb6a8f893e8daa0d72a264 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:49:58 +0900 Subject: [PATCH 22/53] feat(pairStatus): add quit status --- .../luncher/status/PairQuitStatus.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/main/java/pairmatching/luncher/status/PairQuitStatus.java diff --git a/src/main/java/pairmatching/luncher/status/PairQuitStatus.java b/src/main/java/pairmatching/luncher/status/PairQuitStatus.java new file mode 100644 index 0000000..2e31a1f --- /dev/null +++ b/src/main/java/pairmatching/luncher/status/PairQuitStatus.java @@ -0,0 +1,16 @@ +package pairmatching.luncher.status; + +import pairmatching.luncher.controller.PairMatchingController; + +public class PairQuitStatus implements PairStatus { + + @Override + public PairStatus next(PairMatchingController context) { + return null; + } + + @Override + public boolean isRunnable() { + return false; + } +} From 828192ee664fe0f89cc1f7b5c1eb0b661a044abe Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:50:31 +0900 Subject: [PATCH 23/53] feat(pairStatus): add feature status --- .../luncher/status/PairFeatureStatus.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/main/java/pairmatching/luncher/status/PairFeatureStatus.java diff --git a/src/main/java/pairmatching/luncher/status/PairFeatureStatus.java b/src/main/java/pairmatching/luncher/status/PairFeatureStatus.java new file mode 100644 index 0000000..3b1e844 --- /dev/null +++ b/src/main/java/pairmatching/luncher/status/PairFeatureStatus.java @@ -0,0 +1,32 @@ +package pairmatching.luncher.status; + +import pairmatching.luncher.controller.PairMatchingController; +import pairmatching.domain.type.Feature; +import pairmatching.luncher.status.match.PairMatchingStatus; + +public class PairFeatureStatus implements PairStatus { + + @Override + public PairStatus next(PairMatchingController context) { + Feature feature = context.inputFeature(); + return chooseStatus(feature); + } + + @Override + public boolean isRunnable() { + return true; + } + + private PairStatus chooseStatus(Feature feature) { + if (feature.equals(Feature.PAIR_MATCHING)) { + return new PairMatchingStatus(); + } + if (feature.equals(Feature.PAIR_SEARCH)) { + return new PairSearchStatus(); + } + if (feature.equals(Feature.PAIR_INITIALIZE)) { + return new PairResetStatus(); + } + return new PairQuitStatus(); + } +} From 1e062cee2f6ba89a47ee2f44786d93005164f106 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:50:55 +0900 Subject: [PATCH 24/53] feat(exception): add business exception --- .../java/pairmatching/exception/BusinessException.java | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/main/java/pairmatching/exception/BusinessException.java diff --git a/src/main/java/pairmatching/exception/BusinessException.java b/src/main/java/pairmatching/exception/BusinessException.java new file mode 100644 index 0000000..4f4ccee --- /dev/null +++ b/src/main/java/pairmatching/exception/BusinessException.java @@ -0,0 +1,8 @@ +package pairmatching.exception; + +public class BusinessException extends RuntimeException { + + public BusinessException(String message) { + super(message); + } +} From 8196d5c980383abd3c3ff8ae777772ca31f8bab9 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:51:12 +0900 Subject: [PATCH 25/53] feat(exception): add duplicate exception extends business exception --- .../pairmatching/exception/DuplicateException.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/java/pairmatching/exception/DuplicateException.java diff --git a/src/main/java/pairmatching/exception/DuplicateException.java b/src/main/java/pairmatching/exception/DuplicateException.java new file mode 100644 index 0000000..27b5cb9 --- /dev/null +++ b/src/main/java/pairmatching/exception/DuplicateException.java @@ -0,0 +1,10 @@ +package pairmatching.exception; + +public class DuplicateException extends BusinessException { + + private static final String ERROR_MESSAGE = "중복된 값이 존재합니다."; + + public DuplicateException() { + super(ERROR_MESSAGE); + } +} From 51cdd34538e88a7f74e142979cc726c3640c57df Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:51:21 +0900 Subject: [PATCH 26/53] feat(exception): add duplicate pair exception extends business exception --- .../pairmatching/exception/DuplicatePairException.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/java/pairmatching/exception/DuplicatePairException.java diff --git a/src/main/java/pairmatching/exception/DuplicatePairException.java b/src/main/java/pairmatching/exception/DuplicatePairException.java new file mode 100644 index 0000000..954ab1c --- /dev/null +++ b/src/main/java/pairmatching/exception/DuplicatePairException.java @@ -0,0 +1,10 @@ +package pairmatching.exception; + +public class DuplicatePairException extends BusinessException { + + private static final String ERROR_MESSAGE = "페어 매칭시 중복이 있습니다"; + + public DuplicatePairException() { + super(ERROR_MESSAGE); + } +} From 37bf5ac53573760ef1d08c0574c52b19f13cc502 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:51:32 +0900 Subject: [PATCH 27/53] feat(exception): add empty matched exception extends business exception --- .../exception/EmptyMatchedCrewException.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/java/pairmatching/exception/EmptyMatchedCrewException.java diff --git a/src/main/java/pairmatching/exception/EmptyMatchedCrewException.java b/src/main/java/pairmatching/exception/EmptyMatchedCrewException.java new file mode 100644 index 0000000..74fff7e --- /dev/null +++ b/src/main/java/pairmatching/exception/EmptyMatchedCrewException.java @@ -0,0 +1,10 @@ +package pairmatching.exception; + +public class EmptyMatchedCrewException extends BusinessException { + + private static final String ERROR_MESSAGE = "매칭 이력이 없습니다."; + + public EmptyMatchedCrewException() { + super(ERROR_MESSAGE); + } +} From 91df5781aaf251b8a61933c65d2158ab68c09ce4 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:51:44 +0900 Subject: [PATCH 28/53] feat(exception): add exceed try extends business exception --- .../exception/ExceedTryCountException.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/java/pairmatching/exception/ExceedTryCountException.java diff --git a/src/main/java/pairmatching/exception/ExceedTryCountException.java b/src/main/java/pairmatching/exception/ExceedTryCountException.java new file mode 100644 index 0000000..39f9010 --- /dev/null +++ b/src/main/java/pairmatching/exception/ExceedTryCountException.java @@ -0,0 +1,10 @@ +package pairmatching.exception; + +public class ExceedTryCountException extends BusinessException { + + private static final String ERROR_MESSAGE = "%d 시도했지만 더 이상 매칭할 수 없습니다."; + + public ExceedTryCountException(int tryCount) { + super(String.format(ERROR_MESSAGE, tryCount)); + } +} From 9ca4067824976517ada0a03a76ada4fab00daa23 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:52:14 +0900 Subject: [PATCH 29/53] feat(gameLauncher): add pairMatchingGameLauncher --- .../luncher/PairMatchingGameLauncher.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/main/java/pairmatching/luncher/PairMatchingGameLauncher.java diff --git a/src/main/java/pairmatching/luncher/PairMatchingGameLauncher.java b/src/main/java/pairmatching/luncher/PairMatchingGameLauncher.java new file mode 100644 index 0000000..b19c8c8 --- /dev/null +++ b/src/main/java/pairmatching/luncher/PairMatchingGameLauncher.java @@ -0,0 +1,27 @@ +package pairmatching.luncher; + +import pairmatching.luncher.controller.PairMatchingController; +import pairmatching.luncher.status.PairFeatureStatus; +import pairmatching.luncher.status.PairQuitStatus; +import pairmatching.luncher.status.PairStatus; +import pairmatching.exception.BusinessException; + +public class PairMatchingGameLauncher { + private final PairMatchingController pairMatchingController = new PairMatchingController(); + private PairStatus pairStatus = new PairFeatureStatus(); + + + public void play() { + while (pairStatus.isRunnable()) { + try { + pairStatus = pairStatus.next(pairMatchingController); + } catch(BusinessException e) { + pairMatchingController.printError(e.getMessage()); + pairStatus = new PairFeatureStatus(); + } catch (IllegalArgumentException | IllegalStateException e) { + pairMatchingController.printError(e.getMessage()); + pairStatus = new PairQuitStatus(); + } + } + } +} From 5736ace6e52f3d89e5e118608f3186c33784380c Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:52:41 +0900 Subject: [PATCH 30/53] docs(readme): improve input output details --- docs/README.md | 178 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 174 insertions(+), 4 deletions(-) diff --git a/docs/README.md b/docs/README.md index 4e753e2..285c976 100644 --- a/docs/README.md +++ b/docs/README.md @@ -41,9 +41,179 @@ ### 입력 -- 미션에 대한 리스트를 출력한다. +```text +기능을 선택하세요. +1. 페어 매칭 +2. 페어 조회 +3. 페어 초기화 +Q. 종료 +``` + +- 페어매칭 선택시 입력창 +```text + +############################################# +과정: 백엔드 | 프론트엔드 +미션: + - 레벨1: 자동차경주 | 로또 | 숫자야구게임 + - 레벨2: 장바구니 | 결제 | 지하철노선도 + - 레벨3: + - 레벨4: 성능개선 | 배포 + - 레벨5: +############################################ +과정, 레벨, 미션을 선택하세요. +ex) 백엔드, 레벨1, 자동차경주 +프론트엔드, 레벨1, 자동차경주 +``` +- **condition** - 과정, 레벨, 미션을 선택하고 리스트에 없는 목록을 입력한 경우 예외처리를 한다. - +- 3개만 입력 가능해야 함. + +- 매칭 정보가 있어서 아니오를 누른 경우 입력창 +```text +과정, 레벨, 미션을 선택하세요. +ex) 백엔드, 레벨1, 자동차경주 +``` + +- 매칭 정보가 있는 경우 확인 입력 창 +```text +매칭 정보가 있습니다. 다시 매칭하시겠습니까? +네 | 아니오 +``` ### 출력 -- 이름 : 이름 형태로 출력한다. -- 크루 인원이 홀수인 경우 마지막은 3명으로 묶어서 출력한다. \ No newline at end of file +- 페어 매칭 결과 +```text + +페어 매칭 결과입니다. +다비 : 신디 +쉐리 : 덴버 +제키 : 로드 +라라 : 윌터 +니콜 : 이브 +린다 : 시저 +보노 : 제시 : 제키 +``` + +- 초기화후 출력 +```text +초기화 되었습니다. +``` + + + +## 프로그램 사용 예시 +```text +기능을 선택하세요. +1. 페어 매칭 +2. 페어 조회 +3. 페어 초기화 +Q. 종료 +1 + +############################################# +과정: 백엔드 | 프론트엔드 +미션: + - 레벨1: 자동차경주 | 로또 | 숫자야구게임 + - 레벨2: 장바구니 | 결제 | 지하철노선도 + - 레벨3: + - 레벨4: 성능개선 | 배포 + - 레벨5: +############################################ +과정, 레벨, 미션을 선택하세요. +ex) 백엔드, 레벨1, 자동차경주 +프론트엔드, 레벨1, 자동차경주 + +페어 매칭 결과입니다. +다비 : 신디 +쉐리 : 덴버 +제키 : 로드 +라라 : 윌터 +니콜 : 이브 +린다 : 시저 +보노 : 제시 : 제키 + +기능을 선택하세요. +1. 페어 매칭 +2. 페어 조회 +3. 페어 초기화 +Q. 종료 +1 + +############################################# +과정: 백엔드 | 프론트엔드 +미션: + - 레벨1: 자동차경주 | 로또 | 숫자야구게임 + - 레벨2: 장바구니 | 결제 | 지하철노선도 + - 레벨3: + - 레벨4: 성능개선 | 배포 + - 레벨5: +############################################ +과정, 레벨, 미션을 선택하세요. +ex) 백엔드, 레벨1, 자동차경주 +프론트엔드, 레벨1, 자동차경주 + +매칭 정보가 있습니다. 다시 매칭하시겠습니까? +네 | 아니오 +아니오 + +과정, 레벨, 미션을 선택하세요. +ex) 백엔드, 레벨1, 자동차경주 +프론트엔드, 레벨1, 자동차경주 +매칭 정보가 있습니다. 다시 매칭하시겠습니까? +네 | 아니오 +네 + +페어 매칭 결과입니다. +이브 : 윌터 +보노 : 제키 +신디 : 로드 +제시 : 린다 +시저 : 라라 +니콜 : 다비 +리사 : 덴버 : 제키 + +기능을 선택하세요. +1. 페어 매칭 +2. 페어 조회 +3. 페어 초기화 +Q. 종료 +2 + +############################################# +과정: 백엔드 | 프론트엔드 +미션: + - 레벨1: 자동차경주 | 로또 | 숫자야구게임 + - 레벨2: 장바구니 | 결제 | 지하철노선도 + - 레벨3: + - 레벨4: 성능개선 | 배포 + - 레벨5: +############################################ +과정, 레벨, 미션을 선택하세요. +ex) 백엔드, 레벨1, 자동차경주 +프론트엔드, 레벨1, 자동차경주 + +페어 매칭 결과입니다. +이브 : 윌터 +보노 : 제키 +신디 : 로드 +제시 : 린다 +시저 : 라라 +니콜 : 다비 +리사 : 덴버 : 제키 + +기능을 선택하세요. +1. 페어 매칭 +2. 페어 조회 +3. 페어 초기화 +Q. 종료 +3 + +초기화 되었습니다. + +기능을 선택하세요. +1. 페어 매칭 +2. 페어 조회 +3. 페어 초기화 +Q. 종료 +Q +``` \ No newline at end of file From 648353a82f0cab702ee378715f6353cf6a9e0da8 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:53:19 +0900 Subject: [PATCH 31/53] fix(database): change database method argument --- src/main/java/pairmatching/db/Database.java | 57 +++++++++++++++++++ .../pairmatching/domain/db/PairDatabase.java | 55 ------------------ 2 files changed, 57 insertions(+), 55 deletions(-) create mode 100644 src/main/java/pairmatching/db/Database.java delete mode 100644 src/main/java/pairmatching/domain/db/PairDatabase.java diff --git a/src/main/java/pairmatching/db/Database.java b/src/main/java/pairmatching/db/Database.java new file mode 100644 index 0000000..5c335f8 --- /dev/null +++ b/src/main/java/pairmatching/db/Database.java @@ -0,0 +1,57 @@ +package pairmatching.db; + +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import pairmatching.domain.type.MatchingInformation; +import pairmatching.domain.type.Pair; + +public class Database { + + private final Map> memory = new HashMap<>(); + + public void addAll(MatchingInformation matchingInformation, List pairs) { + memory.computeIfAbsent(matchingInformation.toString(), key -> new LinkedHashSet<>()) + .addAll(pairs); + } + + public boolean exist(MatchingInformation matchingInformation) { + return memory.containsKey(matchingInformation.toString()); + } + + public boolean existPair(String inputKey, Pair data) { + List keys = findKeys(inputKey); + return keys.stream().map(memory::get) + .anyMatch(pairs -> matchPair(pairs, data)); + } + + public Set getAll(MatchingInformation matchingInformation) { + Set pairs = memory.get(matchingInformation.toString()); + if (pairs == null) { + return new LinkedHashSet<>(); + } + return pairs; + } + + public void clear() { + memory.clear(); + } + + public void removeKey(MatchingInformation matchingInformation) { + memory.remove(matchingInformation.toString()); + } + + private List findKeys(String inputKey) { + return memory.keySet().stream() + .filter(key -> key.contains(inputKey)) + .collect(Collectors.toList()); + } + + private boolean matchPair(Set pairs, Pair value) { + return pairs.stream() + .anyMatch(pair -> pair.equals(value)); + } +} diff --git a/src/main/java/pairmatching/domain/db/PairDatabase.java b/src/main/java/pairmatching/domain/db/PairDatabase.java deleted file mode 100644 index 675e401..0000000 --- a/src/main/java/pairmatching/domain/db/PairDatabase.java +++ /dev/null @@ -1,55 +0,0 @@ -package pairmatching.domain.db; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import pairmatching.domain.type.Course; -import pairmatching.domain.type.Mission; -import pairmatching.domain.type.Pair; - -public class PairDatabase { - - private static final String NOT_FOUND = "매칭 이력이 없습니다."; - - private final Map> memory = new HashMap<>(); - - - public void addAll(Course course, Mission mission, List pairs) { - memory.computeIfAbsent(course.toString() + " " + mission.toString(), key -> new ArrayList<>()).addAll(pairs); - } - - public boolean exist(Course course, Mission mission) { - return memory.containsKey(course.toString() + " " + mission.toString()); - } - - public boolean existPair(String inputKey, Pair data) { - List keys = findKeys(inputKey); - return keys.stream().map(memory::get) - .anyMatch(pairs -> matchPair(pairs, data)); - } - - public List getAll(Course course, Mission mission) { - List pairs = memory.get(course.toString() + " " + mission.toString()); - if (pairs == null) { - throw new IllegalArgumentException(NOT_FOUND); - } - return pairs; - } - - public void clear() { - memory.clear(); - } - - private List findKeys(String inputKey) { - return memory.keySet().stream() - .filter(key -> key.contains(inputKey)) - .collect(Collectors.toList()); - } - - private boolean matchPair(List pairs, Pair value) { - return pairs.stream() - .anyMatch(pair -> pair.equals(value)); - } -} From 89ef36b506f8d4664a4cc4c71aab831d6857169f Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:54:08 +0900 Subject: [PATCH 32/53] feat(crew): static method backend and frontend --- src/main/java/pairmatching/domain/type/Crew.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/pairmatching/domain/type/Crew.java b/src/main/java/pairmatching/domain/type/Crew.java index 4df4671..88e2d3b 100644 --- a/src/main/java/pairmatching/domain/type/Crew.java +++ b/src/main/java/pairmatching/domain/type/Crew.java @@ -11,6 +11,14 @@ public Crew(Course course, Name name) { this.name = name; } + public static Crew makeBackendCrew(String name) { + return new Crew(Course.BACKEND, new Name(name)); + } + + public static Crew makeFrontendCrew(String name) { + return new Crew(Course.FRONTEND, new Name(name)); + } + @Override public boolean equals(Object o) { if (this == o) { @@ -28,10 +36,6 @@ public int hashCode() { return Objects.hash(course, name); } - public Course getCourse() { - return course; - } - public Name getName() { return name; } From bc3c1a1347b9f399cd6da7234cc6b7944307d4be Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:54:55 +0900 Subject: [PATCH 33/53] fix(controller): fix controller to state pattern's context --- .../controller/PairMatchingController.java | 75 ------------------- .../controller/PairMatchingController.java | 59 +++++++++++++++ 2 files changed, 59 insertions(+), 75 deletions(-) delete mode 100644 src/main/java/pairmatching/controller/PairMatchingController.java create mode 100644 src/main/java/pairmatching/luncher/controller/PairMatchingController.java diff --git a/src/main/java/pairmatching/controller/PairMatchingController.java b/src/main/java/pairmatching/controller/PairMatchingController.java deleted file mode 100644 index aec0eda..0000000 --- a/src/main/java/pairmatching/controller/PairMatchingController.java +++ /dev/null @@ -1,75 +0,0 @@ -package pairmatching.controller; - -import java.util.List; -import pairmatching.domain.PairMatchingGame; -import pairmatching.domain.type.Course; -import pairmatching.domain.type.Feature; -import pairmatching.domain.type.Level; -import pairmatching.domain.type.Mission; -import pairmatching.domain.type.Pair; -import pairmatching.view.InputView; -import pairmatching.view.OutputView; - -public class PairMatchingController { - - private final InputView inputView = new InputView(); - private final OutputView outputView = new OutputView(); - private final PairMatchingGame pairMatchingGame = new PairMatchingGame(); - - public void play() { - try { - chooseFeature(); - } catch(IllegalArgumentException | IllegalStateException e) { - outputView.printError(e.getMessage()); - } - } - - - private void chooseFeature() { - while (true) { - Feature feature = inputView.inputFeature(); - if (feature.equals(Feature.PAIR_MATCHING)) { - pairMatch(); - } - if (feature.equals(Feature.PAIR_SEARCH)) { - showMatch(); - } - if (feature.equals(Feature.PAIR_INITIALIZE)) { - initialize(); - } - if (feature.equals(Feature.QUIT)) { - return; - } - } - } - - public void pairMatch() { - while (true) { - List objects = inputView.inputInformation(); - boolean duplicateRequest = pairMatchingGame.isDuplicateRequest((Course) objects.get(0), - (Mission) objects.get(2)); - if (duplicateRequest) { - continue; - } - pairMatchingGame.pairMatch((Course) objects.get(0), (Level) objects.get(1), (Mission) objects.get(2)); - List pairs = pairMatchingGame.showPair((Course) objects.get(0), (Mission) objects.get(2)); - outputView.showResult(pairs); - return; - } - } - - public void showMatch() { - try { - List objects = inputView.inputInformation(); - List pairs = pairMatchingGame.showPair((Course) objects.get(0), (Mission) objects.get(2)); - outputView.showResult(pairs); - } catch (IllegalArgumentException | IllegalStateException e) { - outputView.printError(e.getMessage()); - } - } - - public void initialize() { - pairMatchingGame.initialize(); - outputView.initialized(); - } -} diff --git a/src/main/java/pairmatching/luncher/controller/PairMatchingController.java b/src/main/java/pairmatching/luncher/controller/PairMatchingController.java new file mode 100644 index 0000000..d1c9275 --- /dev/null +++ b/src/main/java/pairmatching/luncher/controller/PairMatchingController.java @@ -0,0 +1,59 @@ +package pairmatching.luncher.controller; + +import java.util.Set; +import pairmatching.domain.PairMatchingGame; +import pairmatching.domain.type.Feature; +import pairmatching.domain.type.MatchingInformation; +import pairmatching.domain.type.Pair; +import pairmatching.domain.type.YesOrNo; +import pairmatching.view.InputView; +import pairmatching.view.OutputView; + +public class PairMatchingController { + + private final InputView inputView = new InputView(); + private final OutputView outputView = new OutputView(); + private final PairMatchingGame pairMatchingGame = new PairMatchingGame(); + private MatchingInformation cache; + public Feature inputFeature() { + return inputView.inputFeature(); + } + + public void requestPairMatch() { + MatchingInformation matchingInformation = inputView.inputMatchInformation(); + Set pairs = pairMatchingGame.pairMatch(matchingInformation); + outputView.showResult(pairs); + cache = matchingInformation; + } + + public void requestShowMatchedCrew() { + MatchingInformation matchingInformation = inputView.inputMatchInformation(); + Set pairs = pairMatchingGame.showPair(matchingInformation); + outputView.showResult(pairs); + } + + public void requestRePairMatch() { + MatchingInformation matchingInformation = inputView.inputReMatchInformation(); + Set pairs = pairMatchingGame.reMatch(matchingInformation); + outputView.showResult(pairs); + cache = matchingInformation; + } + + public void directMatch() { + Set pairs = pairMatchingGame.reMatch(cache); + outputView.showResult(pairs); + cache = null; + } + + public YesOrNo requestRetry() { + return inputView.inputRepeat(); + } + + public void requestReset() { + pairMatchingGame.reset(); + } + + public void printError(String message) { + outputView.printError(message); + } +} From 25fc2fecece6109745597c385d1cf4d69b96a800 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:55:52 +0900 Subject: [PATCH 34/53] feat(matchingInformation): add matchingInformation --- .../domain/type/MatchingInformation.java | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 src/main/java/pairmatching/domain/type/MatchingInformation.java diff --git a/src/main/java/pairmatching/domain/type/MatchingInformation.java b/src/main/java/pairmatching/domain/type/MatchingInformation.java new file mode 100644 index 0000000..b566de0 --- /dev/null +++ b/src/main/java/pairmatching/domain/type/MatchingInformation.java @@ -0,0 +1,56 @@ +package pairmatching.domain.type; + +public class MatchingInformation { + + private static final String COMMA = ","; + private static final int INPUT_SIZE = 3; + private static final String ERROR_INPUT_SIZE = "입력은 3가지만 입력하세요."; + + private final Course course; + private final Level level; + private final Subject subject; + private final Mission mission; + + private MatchingInformation(Course course, Level level, Subject subject) { + this.course = course; + this.level = level; + this.subject = subject; + this.mission = Mission.matchOf(level, subject); + } + + public static MatchingInformation of(String line) { + String[] split = line.split(COMMA); + validateSplit(split); + Course course = Course.matchOf(split[0].trim()); + Level level = Level.matchOf(split[1].trim()); + Subject subject = Subject.matchOf(split[2].trim()); + return new MatchingInformation(course, level, subject); + } + + private static void validateSplit(String[] split) { + if (split.length > INPUT_SIZE) { + throw new IllegalArgumentException(ERROR_INPUT_SIZE); + } + } + + public Course getCourse() { + return course; + } + + public Level getLevel() { + return level; + } + + public Subject getSubject() { + return subject; + } + + public Mission getMission() { + return mission; + } + + @Override + public String toString() { + return course + "," + level + "," + subject; + } +} From d6b83b22f017f2a034860dee486b49ac87cd060c Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:56:15 +0900 Subject: [PATCH 35/53] fix(pair): change toString --- .../java/pairmatching/domain/type/Pair.java | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/main/java/pairmatching/domain/type/Pair.java b/src/main/java/pairmatching/domain/type/Pair.java index 0c45277..64095f2 100644 --- a/src/main/java/pairmatching/domain/type/Pair.java +++ b/src/main/java/pairmatching/domain/type/Pair.java @@ -3,20 +3,17 @@ import java.util.Objects; public class Pair { - private final Mission mission; private final Crew first; private final Crew second; private final Crew third; - public Pair(Mission mission, Crew first, Crew second) { - this.mission = mission; + public Pair(Crew first, Crew second) { this.first = first; this.second = second; this.third = null; } - public Pair(Mission mission, Crew first, Crew second, Crew third) { - this.mission = mission; + public Pair(Crew first, Crew second, Crew third) { this.first = first; this.second = second; this.third = third; @@ -31,17 +28,13 @@ public boolean equals(Object o) { return false; } Pair pair = (Pair) o; - return mission == pair.mission && Objects.equals(first, pair.first) && Objects.equals(second, + return Objects.equals(first, pair.first) && Objects.equals(second, pair.second) && Objects.equals(third, pair.third); } @Override public int hashCode() { - return Objects.hash(mission, first, second, third); - } - - public Mission getMission() { - return mission; + return Objects.hash(first, second, third); } public Crew getFirst() { @@ -58,11 +51,10 @@ public Crew getThird() { @Override public String toString() { - return "Pair{" + - "mission=" + mission + - ", first=" + first + - ", second=" + second + - ", third=" + third + - '}'; + String result = first + " : " + second; + if (third != null) { + result = result + " : " + third; + } + return result; } } From ef9108d3a8cf62ce64d63a1f50510bfa905038de Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:56:49 +0900 Subject: [PATCH 36/53] fix(duplicateChecker): change method argument --- .../java/pairmatching/domain/checker/DuplicateChecker.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/pairmatching/domain/checker/DuplicateChecker.java b/src/main/java/pairmatching/domain/checker/DuplicateChecker.java index 69897a6..60b9879 100644 --- a/src/main/java/pairmatching/domain/checker/DuplicateChecker.java +++ b/src/main/java/pairmatching/domain/checker/DuplicateChecker.java @@ -2,14 +2,13 @@ import java.util.List; -import pairmatching.domain.type.Course; -import pairmatching.domain.type.Mission; +import pairmatching.domain.type.MatchingInformation; import pairmatching.domain.type.Pair; public interface DuplicateChecker { - boolean isDuplicate(Course course, Mission mission); + void checkDuplicate(MatchingInformation matchingInformation); - boolean isDuplicatePair(String inputKey, List pairs); + void checkDuplicatePair(String inputKey, List pairs); } From 25db2bf4edd1ea6d274f026b08036c6845a92be5 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:57:22 +0900 Subject: [PATCH 37/53] fix(course): change toString --- src/main/java/pairmatching/domain/type/Course.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/pairmatching/domain/type/Course.java b/src/main/java/pairmatching/domain/type/Course.java index e217a31..53faa2d 100644 --- a/src/main/java/pairmatching/domain/type/Course.java +++ b/src/main/java/pairmatching/domain/type/Course.java @@ -19,4 +19,9 @@ public static Course matchOf(String name) { .findAny() .orElseThrow(() -> new IllegalArgumentException(INVALID_COURSE_NAME)); } + + @Override + public String toString() { + return name; + } } From 7ec10edc72d8955c26ee0f19cc6e2099f21bdec9 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:57:33 +0900 Subject: [PATCH 38/53] fix(mission): change field type --- .../pairmatching/domain/type/Mission.java | 45 +++++++------------ 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/src/main/java/pairmatching/domain/type/Mission.java b/src/main/java/pairmatching/domain/type/Mission.java index f00aff3..0667c81 100644 --- a/src/main/java/pairmatching/domain/type/Mission.java +++ b/src/main/java/pairmatching/domain/type/Mission.java @@ -1,51 +1,36 @@ package pairmatching.domain.type; -import java.util.Arrays; + import java.util.stream.Stream; public enum Mission { - RACING_CAR("자동차경주", Level.LEVEL1), - LOTTO("로또", Level.LEVEL1), - BASE_BALL("숫자야구게임", Level.LEVEL1), - BASKET("장바구니", Level.LEVEL2), - CREDIT("결제", Level.LEVEL2), - SUBWAY("지하철노선도", Level.LEVEL2), - IMPROVEMENT("성능개선", Level.LEVEL4), - DISTRIBUTE("배포", Level.LEVEL4); + RACING_CAR(Subject.RACING_CAR, Level.LEVEL1), + LOTTO(Subject.LOTTO, Level.LEVEL1), + BASE_BALL(Subject.BASE_BALL, Level.LEVEL1), + BASKET(Subject.BASKET, Level.LEVEL2), + CREDIT(Subject.CREDIT, Level.LEVEL2), + SUBWAY(Subject.SUBWAY, Level.LEVEL2), + IMPROVEMENT(Subject.IMPROVEMENT, Level.LEVEL4), + DISTRIBUTE(Subject.DISTRIBUTE, Level.LEVEL4); private static final String INVALID_MISSION_NAME = "레벨에 맞는 정확한 미션 이름을 입력해주세요."; - private final String name; + private final Subject subject; private final Level level; - Mission(String name, Level level) { - this.name = name; + Mission(Subject subject, Level level) { + this.subject = subject; this.level = level; } - public static Mission matchOf(String name) { - return Stream.of(Mission.values()) - .filter(mission -> name.equals(mission.name)) - .findAny() - .orElseThrow(() -> new IllegalArgumentException(INVALID_MISSION_NAME)); - } - - public static Mission matchOf(String name, Level level) { + public static Mission matchOf(Level level, Subject subject) { return Stream.of(Mission.values()) - .filter(mission -> name.equals(mission.name) && level.equals(mission.level)) + .filter(mission -> subject.equals(mission.subject) && level.equals(mission.level)) .findAny() .orElseThrow(() -> new IllegalArgumentException(INVALID_MISSION_NAME)); } - public String getName() { - return name; - } - - public Level getLevel() { - return level; - } - @Override public String toString() { - return level + ":" + name; + return level + ":" + subject; } } From 3292e82d7d3b5b9dbe97de41c7ba9b595bca70e9 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:57:50 +0900 Subject: [PATCH 39/53] feat(subject): add subject --- .../pairmatching/domain/type/Subject.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/main/java/pairmatching/domain/type/Subject.java diff --git a/src/main/java/pairmatching/domain/type/Subject.java b/src/main/java/pairmatching/domain/type/Subject.java new file mode 100644 index 0000000..0469869 --- /dev/null +++ b/src/main/java/pairmatching/domain/type/Subject.java @@ -0,0 +1,33 @@ +package pairmatching.domain.type; + +import java.util.stream.Stream; + +public enum Subject { + + RACING_CAR("자동차경주"), + LOTTO("로또"), + BASE_BALL("숫자야구게임"), + BASKET("장바구니"), + CREDIT("결제"), + SUBWAY("지하철노선도"), + IMPROVEMENT("성능개선"), + DISTRIBUTE("배포"); + + private static final String INVALID_SUBJECT_NAME = "잘못된 과목을 입력하셨습니다."; + private final String name; + + Subject(String name) { + this.name = name; + } + + public static Subject matchOf(String name) { + return Stream.of(Subject.values()) + .filter(subject -> name.equals(subject.name)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException(INVALID_SUBJECT_NAME)); + } + + public String getName() { + return name; + } +} From b4db01136f2709e99db3f67bc90b53cd369abc4a Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:58:32 +0900 Subject: [PATCH 40/53] fix(application): change controller to launcher --- src/main/java/pairmatching/Application.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/pairmatching/Application.java b/src/main/java/pairmatching/Application.java index 66e82f3..f6c383a 100644 --- a/src/main/java/pairmatching/Application.java +++ b/src/main/java/pairmatching/Application.java @@ -1,10 +1,10 @@ package pairmatching; -import pairmatching.controller.PairMatchingController; +import pairmatching.luncher.PairMatchingGameLauncher; public class Application { public static void main(String[] args) { - PairMatchingController pairMatchingController = new PairMatchingController(); - pairMatchingController.play(); + PairMatchingGameLauncher pairMatchingGameLauncher = new PairMatchingGameLauncher(); + pairMatchingGameLauncher.play(); } } From 8e429d9b933045927e6139c28c3b78cd01622905 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 20:59:06 +0900 Subject: [PATCH 41/53] refactor(consoleReader): change object to domain class --- .../java/pairmatching/util/io/ConsoleReader.java | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/main/java/pairmatching/util/io/ConsoleReader.java b/src/main/java/pairmatching/util/io/ConsoleReader.java index c5c7db6..1f39333 100644 --- a/src/main/java/pairmatching/util/io/ConsoleReader.java +++ b/src/main/java/pairmatching/util/io/ConsoleReader.java @@ -1,29 +1,20 @@ package pairmatching.util.io; import camp.nextstep.edu.missionutils.Console; -import java.util.List; -import pairmatching.domain.type.Course; import pairmatching.domain.type.Feature; -import pairmatching.domain.type.Level; -import pairmatching.domain.type.Mission; +import pairmatching.domain.type.MatchingInformation; import pairmatching.domain.type.YesOrNo; public class ConsoleReader { - private static final String COMMA = ","; - public static Feature readFeature() { String line = Console.readLine(); return Feature.matchOf(line); } - public static List readInformation() { + public static MatchingInformation readInformation() { String line = Console.readLine(); - String[] split = line.split(COMMA); - Course course = Course.matchOf(split[0].trim()); - Level level = Level.matchOf(split[1].trim()); - Mission mission = Mission.matchOf(split[2].trim(), level); - return List.of(course, level, mission); + return MatchingInformation.of(line); } public static YesOrNo readYseOrNo() { From 7f18fcbac73cf0b64959ebf1735c23198687394f Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 21:00:52 +0900 Subject: [PATCH 42/53] refactor(duplicateChecker): change boolean type to throwing exception --- .../checker/DefaultDuplicateChecker.java | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/main/java/pairmatching/domain/checker/DefaultDuplicateChecker.java b/src/main/java/pairmatching/domain/checker/DefaultDuplicateChecker.java index 5a3b1bf..8343fd4 100644 --- a/src/main/java/pairmatching/domain/checker/DefaultDuplicateChecker.java +++ b/src/main/java/pairmatching/domain/checker/DefaultDuplicateChecker.java @@ -1,26 +1,32 @@ package pairmatching.domain.checker; import java.util.List; -import pairmatching.domain.db.PairDatabase; -import pairmatching.domain.type.Course; -import pairmatching.domain.type.Mission; +import pairmatching.db.Database; +import pairmatching.domain.type.MatchingInformation; import pairmatching.domain.type.Pair; +import pairmatching.exception.DuplicateException; +import pairmatching.exception.DuplicatePairException; public class DefaultDuplicateChecker implements DuplicateChecker { - private final PairDatabase database; + private final Database database; - public DefaultDuplicateChecker(PairDatabase database) { + public DefaultDuplicateChecker(Database database) { this.database = database; } @Override - public boolean isDuplicate(Course course, Mission mission) { - return database.exist(course, mission); + public void checkDuplicate(MatchingInformation matchingInformation) { + if (database.exist(matchingInformation)) { + throw new DuplicateException(); + } } @Override - public boolean isDuplicatePair(String inputKey, List pairs) { - return pairs.stream().anyMatch(pair -> database.existPair(inputKey, pair)); + public void checkDuplicatePair(String inputKey, List pairs) { + boolean duplicatePair = pairs.stream().anyMatch(pair -> database.existPair(inputKey, pair)); + if (duplicatePair) { + throw new DuplicatePairException(); + } } } From 0dc8cd5bc1e930e2d499e38fe7106c3620383b7d Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 21:03:14 +0900 Subject: [PATCH 43/53] feat(view): add inputView --- .../java/pairmatching/view/InputView.java | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/main/java/pairmatching/view/InputView.java b/src/main/java/pairmatching/view/InputView.java index 1e83d58..7b390e9 100644 --- a/src/main/java/pairmatching/view/InputView.java +++ b/src/main/java/pairmatching/view/InputView.java @@ -1,7 +1,7 @@ package pairmatching.view; -import java.util.List; import pairmatching.domain.type.Feature; +import pairmatching.domain.type.MatchingInformation; import pairmatching.domain.type.YesOrNo; import pairmatching.util.io.ConsoleReader; @@ -13,7 +13,13 @@ public class InputView extends View { + "3. 페어 초기화\n" + "Q. 종료"; - private static final String REQUEST_INFORMATION = "#############################################\n" + private static final String REQUEST_INFORMATION = "과정, 레벨, 미션을 선택하세요.\n" + + "ex) 백엔드, 레벨1, 자동차경주"; + + private static final String REQUEST_YES_OR_NO = "매칭 정보가 있습니다. 다시 매칭하시겠습니까?\n" + + "네 | 아니오"; + + private static final String SHOW_LIST = "#############################################\n" + "과정: 백엔드 | 프론트엔드\n" + "미션:\n" + " - 레벨1: 자동차경주 | 로또 | 숫자야구게임\n" @@ -21,12 +27,7 @@ public class InputView extends View { + " - 레벨3: \n" + " - 레벨4: 성능개선 | 배포\n" + " - 레벨5: \n" - + "############################################\n" - + "과정, 레벨, 미션을 선택하세요.\n" - + "ex) 백엔드, 레벨1, 자동차경주"; - - private static final String REQUEST_YES_OR_NO = "매칭 정보가 있습니다. 다시 매칭하시겠습니까?\n" - + "네 | 아니오"; + + "############################################\n"; public Feature inputFeature() { while (true) { @@ -50,9 +51,23 @@ public YesOrNo inputRepeat() { } } - public List inputInformation() { + public MatchingInformation inputMatchInformation() { + while (true) { + try { + printEmptyLine(); + print(SHOW_LIST); + print(REQUEST_INFORMATION); + return ConsoleReader.readInformation(); + } catch (IllegalArgumentException e) { + printError(e.getMessage()); + } + } + } + + public MatchingInformation inputReMatchInformation() { while (true) { try { + printEmptyLine(); print(REQUEST_INFORMATION); return ConsoleReader.readInformation(); } catch (IllegalArgumentException e) { From bd36c8635056426264b670bd72d65d97570f3d36 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 21:03:21 +0900 Subject: [PATCH 44/53] feat(view): add outputView --- src/main/java/pairmatching/view/OutputView.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/pairmatching/view/OutputView.java b/src/main/java/pairmatching/view/OutputView.java index 069be0b..c4d1c2e 100644 --- a/src/main/java/pairmatching/view/OutputView.java +++ b/src/main/java/pairmatching/view/OutputView.java @@ -1,6 +1,6 @@ package pairmatching.view; -import java.util.List; +import java.util.Set; import pairmatching.domain.type.Crew; import pairmatching.domain.type.Pair; @@ -9,7 +9,8 @@ public class OutputView extends View { private static final String RESULT_MATCHING = "페어 매칭 결과입니다."; private static final String INITIALIZED = "초기화 되었습니다."; - public void showResult(List pairs) { + + public void showResult(Set pairs) { print(RESULT_MATCHING); for (Pair pair : pairs) { print(makePairFormat(pair)); @@ -17,7 +18,7 @@ public void showResult(List pairs) { printEmptyLine(); } - public void initialized() { + public void reset() { print(INITIALIZED); printEmptyLine(); } From dd9ffa3026d2559ee327e6134de51498c60aa957 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 21:04:02 +0900 Subject: [PATCH 45/53] feat(view): add reset OutputView --- .../pairmatching/luncher/controller/PairMatchingController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/pairmatching/luncher/controller/PairMatchingController.java b/src/main/java/pairmatching/luncher/controller/PairMatchingController.java index d1c9275..52ded32 100644 --- a/src/main/java/pairmatching/luncher/controller/PairMatchingController.java +++ b/src/main/java/pairmatching/luncher/controller/PairMatchingController.java @@ -51,6 +51,7 @@ public YesOrNo requestRetry() { public void requestReset() { pairMatchingGame.reset(); + outputView.reset(); } public void printError(String message) { From 36161b7af193e163b214f3a92c34d804fa85e123 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 21:07:32 +0900 Subject: [PATCH 46/53] refactor(crewLoader): use static method --- src/main/java/pairmatching/domain/loader/CrewLoader.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/pairmatching/domain/loader/CrewLoader.java b/src/main/java/pairmatching/domain/loader/CrewLoader.java index 4b6b820..7b13db3 100644 --- a/src/main/java/pairmatching/domain/loader/CrewLoader.java +++ b/src/main/java/pairmatching/domain/loader/CrewLoader.java @@ -30,13 +30,13 @@ private List makeBackCrews() { List names = nameLoader.loadNames(backendPath); List temp = names.stream().map(Name::toString).collect(Collectors.toList()); List shuffles = Randoms.shuffle(temp); - return shuffles.stream().map(s -> new Crew(Course.BACKEND, new Name(s))).collect(Collectors.toList()); + return shuffles.stream().map(Crew::makeBackendCrew).collect(Collectors.toList()); } private List makeFrontCrews() { List names = nameLoader.loadNames(frontendPath); List temp = names.stream().map(Name::toString).collect(Collectors.toList()); List shuffles = Randoms.shuffle(temp); - return shuffles.stream().map(s -> new Crew(Course.FRONTEND, new Name(s))).collect(Collectors.toList()); + return shuffles.stream().map(Crew::makeFrontendCrew).collect(Collectors.toList()); } } From c25afd2ba69ee581008dcde127e6c3163514f9cf Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 21:14:44 +0900 Subject: [PATCH 47/53] test(crewLoader): test crew loader --- .../domain/loader/CrewLoaderTest.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/test/java/pairmatching/domain/loader/CrewLoaderTest.java diff --git a/src/test/java/pairmatching/domain/loader/CrewLoaderTest.java b/src/test/java/pairmatching/domain/loader/CrewLoaderTest.java new file mode 100644 index 0000000..674ab42 --- /dev/null +++ b/src/test/java/pairmatching/domain/loader/CrewLoaderTest.java @@ -0,0 +1,35 @@ +package pairmatching.domain.loader; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import org.junit.jupiter.api.Test; +import pairmatching.domain.type.Course; +import pairmatching.domain.type.Crew; + +class CrewLoaderTest { + + @Test + void shouldReturnBackendCrewWhenInputBackendCourse() { + // given + CrewLoader crewLoader = new CrewLoader(); + + // when + List crews = crewLoader.getNames(Course.BACKEND); + + // then + crews.forEach(crew -> assertThat(crew.getCourse()).isEqualTo(Course.BACKEND)); + } + + @Test + void shouldReturnFrontendCrewWhenInputFrontendCourse() { + // given + CrewLoader crewLoader = new CrewLoader(); + + // when + List crews = crewLoader.getNames(Course.FRONTEND); + + // then + crews.forEach(crew -> assertThat(crew.getCourse()).isEqualTo(Course.FRONTEND)); + } +} \ No newline at end of file From d55c18894eabb7c71de026caa02b4a288a6e9793 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 21:14:59 +0900 Subject: [PATCH 48/53] feat(crew): add course getter --- src/main/java/pairmatching/domain/type/Crew.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/pairmatching/domain/type/Crew.java b/src/main/java/pairmatching/domain/type/Crew.java index 88e2d3b..fc31bca 100644 --- a/src/main/java/pairmatching/domain/type/Crew.java +++ b/src/main/java/pairmatching/domain/type/Crew.java @@ -36,6 +36,9 @@ public int hashCode() { return Objects.hash(course, name); } + public Course getCourse() { + return course; + } public Name getName() { return name; } From d49f164fd08701b65965e71e22d0ca61e6091129 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 22:30:29 +0900 Subject: [PATCH 49/53] feat(name): add equals and hashcode --- .../java/pairmatching/domain/type/Name.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/main/java/pairmatching/domain/type/Name.java b/src/main/java/pairmatching/domain/type/Name.java index 4020385..f3b167c 100644 --- a/src/main/java/pairmatching/domain/type/Name.java +++ b/src/main/java/pairmatching/domain/type/Name.java @@ -1,5 +1,6 @@ package pairmatching.domain.type; +import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -21,6 +22,23 @@ private void validateName(String name) { throw new IllegalStateException(NAME_ERROR); } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Name name1 = (Name) o; + return Objects.equals(name, name1.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } + public String getName() { return name; } From a3454c17c14326eec71daf116528edf7e939a27e Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 22:30:43 +0900 Subject: [PATCH 50/53] feat(pair): add match function --- src/main/java/pairmatching/domain/type/Pair.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/pairmatching/domain/type/Pair.java b/src/main/java/pairmatching/domain/type/Pair.java index 64095f2..0d01a3e 100644 --- a/src/main/java/pairmatching/domain/type/Pair.java +++ b/src/main/java/pairmatching/domain/type/Pair.java @@ -1,6 +1,9 @@ package pairmatching.domain.type; +import java.util.HashSet; +import java.util.List; import java.util.Objects; +import java.util.Set; public class Pair { private final Crew first; @@ -19,6 +22,19 @@ public Pair(Crew first, Crew second, Crew third) { this.third = third; } + public boolean match(Pair other) { + Set existCrews = new HashSet<>(List.of(first, second)); + if (third != null) { + existCrews.add(third); + } + Set otherCrews = new HashSet<>(List.of(other.getFirst(), other.getSecond())); + if (other.getThird() != null) { + otherCrews.add(third); + } + existCrews.retainAll(otherCrews); + return existCrews.size() >= 2; + } + @Override public boolean equals(Object o) { if (this == o) { From 253014bebc48a4d4d4b1fec1eb1e5f8d0ffc214b Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 22:31:11 +0900 Subject: [PATCH 51/53] fix(pairMatchingGame): fix argument and function --- .../pairmatching/domain/PairMatchingGame.java | 46 ++++++++++++------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/src/main/java/pairmatching/domain/PairMatchingGame.java b/src/main/java/pairmatching/domain/PairMatchingGame.java index 92f4e79..4d634ec 100644 --- a/src/main/java/pairmatching/domain/PairMatchingGame.java +++ b/src/main/java/pairmatching/domain/PairMatchingGame.java @@ -1,45 +1,59 @@ package pairmatching.domain; import java.util.List; +import java.util.Set; import pairmatching.domain.checker.DefaultDuplicateChecker; import pairmatching.domain.checker.DuplicateChecker; -import pairmatching.domain.db.PairDatabase; +import pairmatching.db.Database; import pairmatching.domain.loader.CrewLoader; import pairmatching.domain.maker.EvenPairMaker; import pairmatching.domain.maker.OddPairMaker; import pairmatching.domain.maker.PairMaker; -import pairmatching.domain.type.Course; import pairmatching.domain.type.Crew; -import pairmatching.domain.type.Level; -import pairmatching.domain.type.Mission; +import pairmatching.domain.type.MatchingInformation; import pairmatching.domain.type.Pair; +import pairmatching.exception.EmptyMatchedCrewException; public class PairMatchingGame { - private final PairDatabase database = new PairDatabase(); + private final Database database = new Database(); private final CrewLoader crewLoader = new CrewLoader(); private final DuplicateChecker duplicateChecker = new DefaultDuplicateChecker(database); - public boolean isDuplicateRequest(Course course, Mission mission) { - return duplicateChecker.isDuplicate(course, mission); + public Set pairMatch(MatchingInformation matchingInformation) { + duplicateChecker.checkDuplicate(matchingInformation); + List pairs = makeCrewPairs(matchingInformation); + database.addAll(matchingInformation, pairs); + return database.getAll(matchingInformation); } - public void pairMatch(Course course, Level level, Mission mission) { - List names = crewLoader.getNames(course); - PairMaker pairMaker = createPairMaker(names.size()); - List pairs = pairMaker.createPair(mission, names); - duplicateChecker.isDuplicatePair(level.toString(), pairs); - database.addAll(course, mission, pairs); + public Set reMatch(MatchingInformation matchingInformation) { + database.removeKey(matchingInformation); + List pairs = makeCrewPairs(matchingInformation); + database.addAll(matchingInformation, pairs); + return database.getAll(matchingInformation); } - public List showPair(Course course, Mission mission) { - return database.getAll(course, mission); + public Set showPair(MatchingInformation matchingInformation) { + Set pairs = database.getAll(matchingInformation); + if (pairs.isEmpty()) { + throw new EmptyMatchedCrewException(); + } + return pairs; } - public void initialize() { + public void reset() { database.clear(); } + private List makeCrewPairs(MatchingInformation matchingInformation) { + List names = crewLoader.getNames(matchingInformation.getCourse()); + PairMaker pairMaker = createPairMaker(names.size()); + List pairs = pairMaker.createPair(names); + duplicateChecker.checkDuplicatePair(matchingInformation.getLevel().toString(), pairs); + return pairs; + } + private PairMaker createPairMaker(int number) { if (number % 2 == 0) { return new EvenPairMaker(); From e0f86586df781dc7cdae4168a3c0bbf218116f12 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 22:31:30 +0900 Subject: [PATCH 52/53] test(duplicateChecker): test duplicateChecker --- .../domain/checker/DuplicateCheckerTest.java | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/test/java/pairmatching/domain/checker/DuplicateCheckerTest.java diff --git a/src/test/java/pairmatching/domain/checker/DuplicateCheckerTest.java b/src/test/java/pairmatching/domain/checker/DuplicateCheckerTest.java new file mode 100644 index 0000000..04ef8e2 --- /dev/null +++ b/src/test/java/pairmatching/domain/checker/DuplicateCheckerTest.java @@ -0,0 +1,48 @@ +package pairmatching.domain.checker; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import pairmatching.db.Database; +import pairmatching.domain.maker.OddPairMaker; +import pairmatching.domain.type.Crew; +import pairmatching.domain.type.Level; +import pairmatching.domain.type.MatchingInformation; +import pairmatching.domain.type.Pair; +import pairmatching.exception.DuplicatePairException; + +class DuplicateCheckerTest { + + private final Database database = new Database(); + private final DuplicateChecker duplicateChecker = new DefaultDuplicateChecker(database); + + + @Test + void test() { + // given + database.addAll(MatchingInformation.of("백엔드, 레벨1, 자동차경주"), makeExistPairs()); + + // expect + assertThatThrownBy( + () -> duplicateChecker.checkDuplicatePair(Level.LEVEL1.toString(), makeInputPairs())) + .isInstanceOf(DuplicatePairException.class); + } + + private List makeInputPairs() { + return makePairs("현규", "현석", "현자", "현빈", "현상", "현종", "빈석"); + } + + private List makeExistPairs() { + return makePairs("현규", "현승", "현자", "현석", "현빈", "현상", "현종"); + } + + private List makePairs(String... names) { + List crews = Stream.of(names) + .map(Crew::makeBackendCrew) + .collect(Collectors.toList()); + return new OddPairMaker().createPair(crews); + } +} \ No newline at end of file From d84de0b8de0674e450395ec2194108200878c1f9 Mon Sep 17 00:00:00 2001 From: E1psycongr00 <39326175+E1psycongr00@users.noreply.github.com> Date: Mon, 5 Dec 2022 22:31:56 +0900 Subject: [PATCH 53/53] fix(database): fix exitPair logic --- src/main/java/pairmatching/db/Database.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/pairmatching/db/Database.java b/src/main/java/pairmatching/db/Database.java index 5c335f8..d8354b4 100644 --- a/src/main/java/pairmatching/db/Database.java +++ b/src/main/java/pairmatching/db/Database.java @@ -24,8 +24,9 @@ public boolean exist(MatchingInformation matchingInformation) { public boolean existPair(String inputKey, Pair data) { List keys = findKeys(inputKey); - return keys.stream().map(memory::get) - .anyMatch(pairs -> matchPair(pairs, data)); + return keys.stream() + .map(memory::get) + .anyMatch(pairs -> matchPairs(pairs, data)); } public Set getAll(MatchingInformation matchingInformation) { @@ -50,8 +51,8 @@ private List findKeys(String inputKey) { .collect(Collectors.toList()); } - private boolean matchPair(Set pairs, Pair value) { + private boolean matchPairs(Set pairs, Pair value) { return pairs.stream() - .anyMatch(pair -> pair.equals(value)); + .anyMatch(pair -> pair.match(value)); } }