From ea07d132883792172e2a35eeec262f4b61f1417c Mon Sep 17 00:00:00 2001 From: chanminmaxscaler Date: Fri, 16 Dec 2022 10:03:25 +0900 Subject: [PATCH 01/20] =?UTF-8?q?docs:=20=EA=B0=9C=EB=B0=9C=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EB=AA=A9=EB=A1=9D=EC=9D=84=20=EC=9E=91=EC=84=B1?= =?UTF-8?q?=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 docs/README.md diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..afd190f7e --- /dev/null +++ b/docs/README.md @@ -0,0 +1,42 @@ +# 페어매칭 프로그램 + +## 개발 기능 목록 + +- [ ] 기능 명령어 선택 기능 + - [ ] 문자 한 개를 입력하는지 검증 + +- [ ] 기능 명령어 검증 기능 + - [ ] 1, 2, 3, Q 중 하나인지 검증 + +- [ ] 명령어 실행 기능 + - [ ] 명령어가 입력되면 각 명령에 맞는 기능 실행 + +- [ ] 과정, 레벨, 미션 선택 기능 + - [ ] ", "로 구분되는 문자열인지 검증 + +- [ ] 과정, 레벨, 미션 검증 기능 + - [ ] 각 보기에 부합하는지 검증 + +- [ ] 매칭 이력 확인 기능 + +- [ ] 매칭 기능 + - [ ] 파일 읽기 + - [ ] 크루원 이름 셔플 + - [ ] 2명(마지막 3명 허용)씩 매칭 + +- [ ] 매칭 검증 기능 + - [ ] 이름 중복 검증 + - [ ] 페어 사이즈 검증 + - [ ] 같은 레벨 하 매칭 중복 검증 + +- [ ] 재매칭 선택 기능 + - [ ] 한글 입력인지 검증 + +- [ ] 재매칭 선택 검증 기능 + - [ ] 네, 아니오 중 하나인지 검증 + +- [ ] 매칭 조회 기능 + - [ ] 매칭 이력 없을 경우 오류 + - [ ] 매칭 이력 있는 경우 출력 + +- [ ] 매칭 초기화 기능 \ No newline at end of file From 9d8afe36ede31f77bb6f56e3b67ee6850c9eccf5 Mon Sep 17 00:00:00 2001 From: chanminmaxscaler Date: Fri, 16 Dec 2022 10:44:33 +0900 Subject: [PATCH 02/20] =?UTF-8?q?feat:=20=EA=B8=B0=EB=8A=A5=20=EB=AA=85?= =?UTF-8?q?=EB=A0=B9=EC=96=B4=20=EC=84=A0=ED=83=9D=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=EC=9D=84=20=EA=B5=AC=ED=98=84=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit InputView 객체는 readCommand 메소드를 이용해 기능 명령어를 입력받는다. 기능 명령어 입력 시 입력 형식이 타당한지 Validator 객체로 검증한다. Validator 객체는 기능 명령어가 문자 한 개로 입력되지 않았다면, 오류를 발생시킨다. --- .../java/pairmatching/view/InputView.java | 21 +++++++++++ .../java/pairmatching/view/OutputView.java | 18 ++++++++++ .../pairmatching/view/message/Message.java | 35 +++++++++++++++++++ .../view/validator/Validator.java | 31 ++++++++++++++++ 4 files changed, 105 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/message/Message.java create mode 100644 src/main/java/pairmatching/view/validator/Validator.java diff --git a/src/main/java/pairmatching/view/InputView.java b/src/main/java/pairmatching/view/InputView.java new file mode 100644 index 000000000..f9196521c --- /dev/null +++ b/src/main/java/pairmatching/view/InputView.java @@ -0,0 +1,21 @@ +package pairmatching.view; + +import camp.nextstep.edu.missionutils.Console; +import pairmatching.view.validator.Validator; + +public class InputView { + + public String readCommand() { + return readValidInputBy(Validator.COMMAND); + } + + private String readValidInputBy(Validator validator) { + String input = Console.readLine(); + validateBy(input, validator); + return input; + } + + private void validateBy(String input, Validator validator) { + validator.validate(input); + } +} diff --git a/src/main/java/pairmatching/view/OutputView.java b/src/main/java/pairmatching/view/OutputView.java new file mode 100644 index 000000000..50f38d2ef --- /dev/null +++ b/src/main/java/pairmatching/view/OutputView.java @@ -0,0 +1,18 @@ +package pairmatching.view; + +import pairmatching.view.message.Message; + +public class OutputView { + + public void printCommandGuide() { + print(Message.COMMAND_GUIDE.getMessage()); + } + + public void printErrorMessage(String message) { + print(message); + } + + private void print(String message) { + System.out.print(message); + } +} diff --git a/src/main/java/pairmatching/view/message/Message.java b/src/main/java/pairmatching/view/message/Message.java new file mode 100644 index 000000000..0321d4ff7 --- /dev/null +++ b/src/main/java/pairmatching/view/message/Message.java @@ -0,0 +1,35 @@ +package pairmatching.view.message; + +public enum Message { + COMMAND_GUIDE("기능을 선택하세요.\n" + + "1. 페어 매칭\n" + + "2. 페어 조회\n" + + "3. 페어 초기화\n" + + "Q. 종료\n"), + CHOICE_GUIDE("#############################################\n" + + "과정: 백엔드 | 프론트엔드\n" + + "미션:\n" + + " - 레벨1: 자동차경주 | 로또 | 숫자야구게임\n" + + " - 레벨2: 장바구니 | 결제 | 지하철노선도\n" + + " - 레벨3: \n" + + " - 레벨4: 성능개선 | 배포\n" + + " - 레벨5: \n" + + "############################################\n" + + "과정, 레벨, 미션을 선택하세요.\n" + + "ex) 백엔드, 레벨1, 자동차경주\n"), + MATCHING_RESULT_GUIDE("페어 매칭 결과입니다.\n"), + MATCHING_DELIMITER(" : "), + RE_MATCHING_GUIDE("매칭 정보가 있습니다. 다시 매칭하시겠습니까?\n" + + "네 | 아니오\n"), + INITIALIZING("초기화 되었습니다.\n"); + + private final String message; + + Message(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } +} diff --git a/src/main/java/pairmatching/view/validator/Validator.java b/src/main/java/pairmatching/view/validator/Validator.java new file mode 100644 index 000000000..902177770 --- /dev/null +++ b/src/main/java/pairmatching/view/validator/Validator.java @@ -0,0 +1,31 @@ +package pairmatching.view.validator; + +public enum Validator { + COMMAND("\\w{1}", "[ERROR] 기능 선택은 한 개의 문자만 입력이 가능합니다."); + + private final String validFormat; + private final String errorMessage; + + Validator(String validFormat, String errorMessage) { + this.validFormat = validFormat; + this.errorMessage = errorMessage; + } + + public String getValidFormat() { + return validFormat; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void validate(String input) { + if (isInvalidFormat(input)) { + throw new IllegalArgumentException(errorMessage); + } + } + + private boolean isInvalidFormat(String input) { + return !input.matches(validFormat); + } +} From 036c63d339cb8fd13c74a9d493257b941f3fe4f1 Mon Sep 17 00:00:00 2001 From: chanminmaxscaler Date: Fri, 16 Dec 2022 10:45:35 +0900 Subject: [PATCH 03/20] =?UTF-8?q?feat:=20=EA=B8=B0=EB=8A=A5=20=EB=AA=85?= =?UTF-8?q?=EB=A0=B9=EC=96=B4=20=EA=B2=80=EC=A6=9D=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=EC=9D=84=20=EA=B5=AC=ED=98=84=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Controller 객체는 InputView 객체로부터 기능 명령어 입력 값을 받는다. Command 객체를 통해 입력 값이 명령어가 맞는지 검증한다. 명령어가 아닐 경우 오류를 발생시킨다. --- .../pairmatching/controller/Controller.java | 42 +++++++++++++++++++ .../java/pairmatching/domain/Command.java | 27 ++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 src/main/java/pairmatching/controller/Controller.java create mode 100644 src/main/java/pairmatching/domain/Command.java diff --git a/src/main/java/pairmatching/controller/Controller.java b/src/main/java/pairmatching/controller/Controller.java new file mode 100644 index 000000000..3482f26e4 --- /dev/null +++ b/src/main/java/pairmatching/controller/Controller.java @@ -0,0 +1,42 @@ +package pairmatching.controller; + +import pairmatching.domain.Command; +import pairmatching.view.InputView; +import pairmatching.view.OutputView; + +import java.util.function.Supplier; + +public class Controller { + + private final InputView inputView; + private final OutputView outputView; + + public Controller(InputView inputView, OutputView outputView) { + this.inputView = inputView; + this.outputView = outputView; + } + + public void runMain() { + executeCommand(); + } + + private void executeCommand() { + Command command = readValidValueBy(this::readCommand); + } + + private Command readCommand() { + outputView.printCommandGuide(); + String inputCommand = inputView.readCommand(); + return Command.valueOfCommand(inputCommand); + } + + private T readValidValueBy(Supplier inputReader) { + while (true) { + try { + return inputReader.get(); + } catch (IllegalArgumentException e) { + outputView.printErrorMessage(e.getMessage()); + } + } + } +} diff --git a/src/main/java/pairmatching/domain/Command.java b/src/main/java/pairmatching/domain/Command.java new file mode 100644 index 000000000..14240f894 --- /dev/null +++ b/src/main/java/pairmatching/domain/Command.java @@ -0,0 +1,27 @@ +package pairmatching.domain; + +import java.util.Arrays; + +public enum Command { + MATCHING("1"), + CHECKING("2"), + INITIALIZING("3"), + QUITTING("Q"); + + private final String command; + + Command(String command) { + this.command = command; + } + + public static Command valueOfCommand(String inputCommand) { + return Arrays.stream(values()) + .filter(value -> inputCommand.equals(value.getCommand())) + .findAny() + .orElseThrow(() -> new IllegalArgumentException(String.format("[ERROR] %s는 기능이 아닙니다.", inputCommand))); + } + + public String getCommand() { + return command; + } +} From e1caaef079ffbbd990393940199a4708fc98ddb3 Mon Sep 17 00:00:00 2001 From: chanminmaxscaler Date: Fri, 16 Dec 2022 11:03:02 +0900 Subject: [PATCH 04/20] =?UTF-8?q?feat:=20=EB=AA=85=EB=A0=B9=EC=96=B4=20?= =?UTF-8?q?=EC=8B=A4=ED=96=89=20=EA=B8=B0=EB=8A=A5=EC=9D=84=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Controller 객체의 executeCommand 메소드는 명령어를 입력받아, 명령어에 맞는 기능을 수행한다. Controller 객체는 입력 받은 명령어가 어떤 명령어인지 확인한 결과를 반환한다. --- src/main/java/pairmatching/controller/Controller.java | 11 +++++++++++ src/main/java/pairmatching/domain/Command.java | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/src/main/java/pairmatching/controller/Controller.java b/src/main/java/pairmatching/controller/Controller.java index 3482f26e4..7a7d57fb6 100644 --- a/src/main/java/pairmatching/controller/Controller.java +++ b/src/main/java/pairmatching/controller/Controller.java @@ -22,6 +22,17 @@ public void runMain() { private void executeCommand() { Command command = readValidValueBy(this::readCommand); + while (!command.isCommandOf(Command.QUITTING)) { + if (command.isCommandOf(Command.MATCHING)) { + + } + if (command.isCommandOf(Command.CHECKING)) { + + } + if (command.isCommandOf(Command.INITIALIZING)) { + + } + } } private Command readCommand() { diff --git a/src/main/java/pairmatching/domain/Command.java b/src/main/java/pairmatching/domain/Command.java index 14240f894..1e3d2e664 100644 --- a/src/main/java/pairmatching/domain/Command.java +++ b/src/main/java/pairmatching/domain/Command.java @@ -24,4 +24,8 @@ public static Command valueOfCommand(String inputCommand) { public String getCommand() { return command; } + + public boolean isCommandOf(Command command) { + return this.command.equals(command.getCommand()); + } } From e46b68c1b885fb9cd2e7817f32dc61db85ddd0ae Mon Sep 17 00:00:00 2001 From: chanminmaxscaler Date: Fri, 16 Dec 2022 11:39:44 +0900 Subject: [PATCH 05/20] =?UTF-8?q?feat:=20=EA=B3=BC=EC=A0=95,=20=EB=A0=88?= =?UTF-8?q?=EB=B2=A8,=20=EB=AF=B8=EC=85=98=20=EC=84=A0=ED=83=9D=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=EC=9D=84=20=EA=B5=AC=ED=98=84=ED=95=9C?= =?UTF-8?q?=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit InputView 객체가 사용자에게 과정, 레벨, 미션을 입력 받는다. Validator 객체는 사용자의 입력이 ", "로 구분되었는지 검증하고, 그렇지 않다면 오류를 발생시킨다. 사용자의 입력은 ", "로 나누어 리스트 자료형으로 반환하도록 한다. --- src/main/java/pairmatching/view/InputView.java | 10 ++++++++++ src/main/java/pairmatching/view/OutputView.java | 4 ++++ .../java/pairmatching/view/validator/Validator.java | 3 ++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/pairmatching/view/InputView.java b/src/main/java/pairmatching/view/InputView.java index f9196521c..403135b28 100644 --- a/src/main/java/pairmatching/view/InputView.java +++ b/src/main/java/pairmatching/view/InputView.java @@ -3,12 +3,22 @@ import camp.nextstep.edu.missionutils.Console; import pairmatching.view.validator.Validator; +import java.util.Arrays; +import java.util.List; + public class InputView { + private static final String CHOICE_DELIMITER = ", "; + public String readCommand() { return readValidInputBy(Validator.COMMAND); } + public List readChoices() { + String input = readValidInputBy(Validator.CHOICE); + return Arrays.asList(input.split(CHOICE_DELIMITER)); + } + private String readValidInputBy(Validator validator) { String input = Console.readLine(); validateBy(input, validator); diff --git a/src/main/java/pairmatching/view/OutputView.java b/src/main/java/pairmatching/view/OutputView.java index 50f38d2ef..5f3152e6d 100644 --- a/src/main/java/pairmatching/view/OutputView.java +++ b/src/main/java/pairmatching/view/OutputView.java @@ -8,6 +8,10 @@ public void printCommandGuide() { print(Message.COMMAND_GUIDE.getMessage()); } + public void printChoiceGuide() { + print(Message.CHOICE_GUIDE.getMessage()); + } + public void printErrorMessage(String message) { print(message); } diff --git a/src/main/java/pairmatching/view/validator/Validator.java b/src/main/java/pairmatching/view/validator/Validator.java index 902177770..8af111ac7 100644 --- a/src/main/java/pairmatching/view/validator/Validator.java +++ b/src/main/java/pairmatching/view/validator/Validator.java @@ -1,7 +1,8 @@ package pairmatching.view.validator; public enum Validator { - COMMAND("\\w{1}", "[ERROR] 기능 선택은 한 개의 문자만 입력이 가능합니다."); + COMMAND("\\w{1}", "[ERROR] 기능 선택은 한 개의 문자만 입력이 가능합니다."), + CHOICE(".{3,5},.{4},.{3,7}", "[ERROR] 올바른 입력이 아닙니다. \", \"로 구분하여 과정, 레벨, 미션을 입력하십시오."); private final String validFormat; private final String errorMessage; From ca995b29e8b51e3b9ea0ba6d459c3b7307be2ee1 Mon Sep 17 00:00:00 2001 From: chanminmaxscaler Date: Fri, 16 Dec 2022 11:41:32 +0900 Subject: [PATCH 06/20] =?UTF-8?q?feat:=20=EA=B3=BC=EC=A0=95,=20=EB=A0=88?= =?UTF-8?q?=EB=B2=A8,=20=EB=AF=B8=EC=85=98=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Controller 에서 입력을 받으면 Course, Level, Mission 객체가 각 입력값을 검증한다. 검증 시 각 입력값에 대한 존재 여부를 검증하며, Mission 객체는 레벨과 미션이 서로 부합하는지 여부도 검증한다. --- .../pairmatching/controller/Controller.java | 11 +++++ .../pairmatching/domain/choice/Choice.java | 15 ++++++ .../domain/choice/ChoiceMaker.java | 17 +++++++ .../java/pairmatching/domain/item/Course.java | 26 ++++++++++ .../java/pairmatching/domain/item/Level.java | 29 ++++++++++++ .../pairmatching/domain/item/Mission.java | 47 +++++++++++++++++++ 6 files changed, 145 insertions(+) create mode 100644 src/main/java/pairmatching/domain/choice/Choice.java create mode 100644 src/main/java/pairmatching/domain/choice/ChoiceMaker.java create mode 100644 src/main/java/pairmatching/domain/item/Course.java create mode 100644 src/main/java/pairmatching/domain/item/Level.java create mode 100644 src/main/java/pairmatching/domain/item/Mission.java diff --git a/src/main/java/pairmatching/controller/Controller.java b/src/main/java/pairmatching/controller/Controller.java index 7a7d57fb6..4550c5062 100644 --- a/src/main/java/pairmatching/controller/Controller.java +++ b/src/main/java/pairmatching/controller/Controller.java @@ -1,9 +1,12 @@ package pairmatching.controller; import pairmatching.domain.Command; +import pairmatching.domain.choice.Choice; +import pairmatching.domain.choice.ChoiceMaker; import pairmatching.view.InputView; import pairmatching.view.OutputView; +import java.util.List; import java.util.function.Supplier; public class Controller { @@ -24,6 +27,7 @@ private void executeCommand() { Command command = readValidValueBy(this::readCommand); while (!command.isCommandOf(Command.QUITTING)) { if (command.isCommandOf(Command.MATCHING)) { + Choice choice = readValidValueBy(this::readChoice); } if (command.isCommandOf(Command.CHECKING)) { @@ -41,6 +45,13 @@ private Command readCommand() { return Command.valueOfCommand(inputCommand); } + private Choice readChoice() { + outputView.printChoiceGuide(); + List choices = inputView.readChoices(); + ChoiceMaker choiceMaker = new ChoiceMaker(); + return choiceMaker.createChoice(choices); + } + private T readValidValueBy(Supplier inputReader) { while (true) { try { diff --git a/src/main/java/pairmatching/domain/choice/Choice.java b/src/main/java/pairmatching/domain/choice/Choice.java new file mode 100644 index 000000000..9a925d188 --- /dev/null +++ b/src/main/java/pairmatching/domain/choice/Choice.java @@ -0,0 +1,15 @@ +package pairmatching.domain.choice; + +import pairmatching.domain.item.Course; +import pairmatching.domain.item.Mission; + +public class Choice { + + private final Course course; + private final Mission mission; + + public Choice(Course course, Mission mission) { + this.course = course; + this.mission = mission; + } +} diff --git a/src/main/java/pairmatching/domain/choice/ChoiceMaker.java b/src/main/java/pairmatching/domain/choice/ChoiceMaker.java new file mode 100644 index 000000000..1ff376b1b --- /dev/null +++ b/src/main/java/pairmatching/domain/choice/ChoiceMaker.java @@ -0,0 +1,17 @@ +package pairmatching.domain.choice; + +import pairmatching.domain.item.Course; +import pairmatching.domain.item.Level; +import pairmatching.domain.item.Mission; + +import java.util.List; + +public class ChoiceMaker { + + public Choice createChoice(List choices) { + Course course = Course.valueOfCourse(choices.get(0)); + Level level = Level.valueOfLevel(choices.get(1)); + Mission mission = Mission.valueOfMissionAndLevel(choices.get(2), level); + return new Choice(course, mission); + } +} diff --git a/src/main/java/pairmatching/domain/item/Course.java b/src/main/java/pairmatching/domain/item/Course.java new file mode 100644 index 000000000..2ffe6cb04 --- /dev/null +++ b/src/main/java/pairmatching/domain/item/Course.java @@ -0,0 +1,26 @@ +package pairmatching.domain.item; + +import java.util.Arrays; + +public enum Course { + BACKEND("백엔드"), + FRONTEND("프론트엔드"); + + private static final String ERROR_MESSAGE = "[ERROR] %s 과정은 존재하지 않습니다."; + private String courseName; + + Course(String courseName) { + this.courseName = courseName; + } + + public static Course valueOfCourse(String name) { + return Arrays.stream(values()) + .filter(value -> name.equals(value.getCourseName())) + .findAny() + .orElseThrow(() -> new IllegalStateException(String.format(ERROR_MESSAGE, name))); + } + + public String getCourseName() { + return courseName; + } +} diff --git a/src/main/java/pairmatching/domain/item/Level.java b/src/main/java/pairmatching/domain/item/Level.java new file mode 100644 index 000000000..eb242c282 --- /dev/null +++ b/src/main/java/pairmatching/domain/item/Level.java @@ -0,0 +1,29 @@ +package pairmatching.domain.item; + +import java.util.Arrays; + +public enum Level { + LEVEL1("레벨1"), + LEVEL2("레벨2"), + LEVEL3("레벨3"), + LEVEL4("레벨4"), + LEVEL5("레벨5"); + + private static final String ERROR_MESSAGE = "[ERROR] %s 레벨은 존재하지 않습니다."; + private String levelName; + + Level(String levelName) { + this.levelName = levelName; + } + + public static Level valueOfLevel(String name) { + return Arrays.stream(values()) + .filter(value -> name.equals(value.getLevelName())) + .findAny() + .orElseThrow(() -> new IllegalStateException(String.format(ERROR_MESSAGE, name))); + } + + public String getLevelName() { + return levelName; + } +} diff --git a/src/main/java/pairmatching/domain/item/Mission.java b/src/main/java/pairmatching/domain/item/Mission.java new file mode 100644 index 000000000..5d025421a --- /dev/null +++ b/src/main/java/pairmatching/domain/item/Mission.java @@ -0,0 +1,47 @@ +package pairmatching.domain.item; + +import java.util.Arrays; + +public enum Mission { + CAR_RACING("자동차경주", Level.LEVEL1), + LOTTO("로또", Level.LEVEL1), + NUMBER_BASEBALL("숫자야구게임", Level.LEVEL1), + SHOPPING_BASKET("장바구니", Level.LEVEL2), + PAYMENT("결제", Level.LEVEL2), + SUBWAY_MAP("지하철노선도", Level.LEVEL2), + PERFORMANCE_IMPROVEMENT("성능개선", Level.LEVEL3), + PUBLISHING("배포", Level.LEVEL3); + + private static final String DISCORDANCE_ERROR_MESSAGE = "[ERROR] %s 미션은 \"%s\"이 아닙니다."; + private static final String VALUE_ERROR_MESSAGE = "[ERROR] %s 미션은 존재하지 않습니다."; + private final String missionName; + private final Level level; + + Mission(String missionName, Level level) { + this.missionName = missionName; + this.level = level; + } + + public static Mission valueOfMissionAndLevel(String missionName, Level level) { + Mission mission = valueOfMission(missionName); + if (level.equals(mission.getLevel())) { + throw new IllegalArgumentException(String.format(DISCORDANCE_ERROR_MESSAGE, missionName, level.getLevelName())); + } + return mission; + } + + public static Mission valueOfMission(String name) { + return Arrays.stream(values()) + .filter(value -> name.equals(value.getMissionName())) + .findAny() + .orElseThrow(() -> new IllegalStateException(String.format(VALUE_ERROR_MESSAGE, name))); + } + + public String getMissionName() { + return missionName; + } + + public Level getLevel() { + return level; + } +} From a5c90eca8db4b0eb2505cf863b0b4d25683dbfe8 Mon Sep 17 00:00:00 2001 From: chanminmaxscaler Date: Fri, 16 Dec 2022 11:49:32 +0900 Subject: [PATCH 07/20] =?UTF-8?q?feat:=20=EB=A7=A4=EC=B9=AD=20=EC=9D=B4?= =?UTF-8?q?=EB=A0=A5=20=ED=99=95=EC=9D=B8=20=EA=B8=B0=EB=8A=A5=EC=9D=84=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MatchingHistory 객체는 매칭 이력을 관리하는 객체이다. hasMatchingOf 메소드를 통해 매칭 이력이 있는지 확인하여 반환한다. --- .../pairmatching/controller/Controller.java | 4 +++- .../pairmatching/domain/choice/Choice.java | 19 +++++++++++++++++ .../java/pairmatching/domain/crew/Crew.java | 14 +++++++++++++ .../domain/matching/MatchingHistory.java | 21 +++++++++++++++++++ 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 src/main/java/pairmatching/domain/crew/Crew.java create mode 100644 src/main/java/pairmatching/domain/matching/MatchingHistory.java diff --git a/src/main/java/pairmatching/controller/Controller.java b/src/main/java/pairmatching/controller/Controller.java index 4550c5062..14abc802f 100644 --- a/src/main/java/pairmatching/controller/Controller.java +++ b/src/main/java/pairmatching/controller/Controller.java @@ -3,6 +3,7 @@ import pairmatching.domain.Command; import pairmatching.domain.choice.Choice; import pairmatching.domain.choice.ChoiceMaker; +import pairmatching.domain.matching.MatchingHistory; import pairmatching.view.InputView; import pairmatching.view.OutputView; @@ -28,7 +29,8 @@ private void executeCommand() { while (!command.isCommandOf(Command.QUITTING)) { if (command.isCommandOf(Command.MATCHING)) { Choice choice = readValidValueBy(this::readChoice); - + MatchingHistory history = new MatchingHistory(); + history.hasMatchingOf(choice); } if (command.isCommandOf(Command.CHECKING)) { diff --git a/src/main/java/pairmatching/domain/choice/Choice.java b/src/main/java/pairmatching/domain/choice/Choice.java index 9a925d188..8d6711756 100644 --- a/src/main/java/pairmatching/domain/choice/Choice.java +++ b/src/main/java/pairmatching/domain/choice/Choice.java @@ -3,6 +3,8 @@ import pairmatching.domain.item.Course; import pairmatching.domain.item.Mission; +import java.util.Objects; + public class Choice { private final Course course; @@ -12,4 +14,21 @@ public Choice(Course course, Mission mission) { this.course = course; this.mission = mission; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Choice choice = (Choice) o; + return course == choice.course && mission == choice.mission; + } + + @Override + public int hashCode() { + return Objects.hash(course, mission); + } } diff --git a/src/main/java/pairmatching/domain/crew/Crew.java b/src/main/java/pairmatching/domain/crew/Crew.java new file mode 100644 index 000000000..fe55b2de4 --- /dev/null +++ b/src/main/java/pairmatching/domain/crew/Crew.java @@ -0,0 +1,14 @@ +package pairmatching.domain.crew; + +import pairmatching.domain.item.Course; + +public class Crew { + + private final Course course; + private final String name; + + public Crew(Course course, String name) { + this.course = course; + this.name = name; + } +} \ No newline at end of file diff --git a/src/main/java/pairmatching/domain/matching/MatchingHistory.java b/src/main/java/pairmatching/domain/matching/MatchingHistory.java new file mode 100644 index 000000000..311c5ffea --- /dev/null +++ b/src/main/java/pairmatching/domain/matching/MatchingHistory.java @@ -0,0 +1,21 @@ +package pairmatching.domain.matching; + +import pairmatching.domain.choice.Choice; +import pairmatching.domain.crew.Crew; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public class MatchingHistory { + + private final Map> history; + + public MatchingHistory() { + this.history = new HashMap<>(); + } + + public boolean hasMatchingOf(Choice choice) { + return history.containsKey(choice); + } +} From cfd1fe8e2fbb6860522f9ccc1c68866aee538e44 Mon Sep 17 00:00:00 2001 From: chanminmaxscaler Date: Fri, 16 Dec 2022 13:29:38 +0900 Subject: [PATCH 08/20] =?UTF-8?q?feat:=20=EB=A7=A4=EC=B9=AD=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=EC=9D=84=20=EA=B5=AC=ED=98=84=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MatchingProgram 객체는 과정에 따라 나뉘어진 크루원의 이름을 읽는다. 크루원의 이름을 셔플한 후, 2명(마지막 3명 허용)씩 매칭한다. --- .../domain/matching/MatchingProgram.java | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 src/main/java/pairmatching/domain/matching/MatchingProgram.java diff --git a/src/main/java/pairmatching/domain/matching/MatchingProgram.java b/src/main/java/pairmatching/domain/matching/MatchingProgram.java new file mode 100644 index 000000000..5b0d57449 --- /dev/null +++ b/src/main/java/pairmatching/domain/matching/MatchingProgram.java @@ -0,0 +1,66 @@ +package pairmatching.domain.matching; + +import camp.nextstep.edu.missionutils.Randoms; +import pairmatching.domain.choice.Choice; +import pairmatching.domain.crew.Crew; +import pairmatching.domain.item.Course; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +public class MatchingProgram { + + private static final String BACKEND_CREW_PATH = "C:\\programming\\woowacourse\\practice\\java-pairmatching-precourse\\src\\main\\resources\\backend-crew.md"; + private static final String FRONTEND_CREW_PATH = "C:\\programming\\woowacourse\\practice\\java-pairmatching-precourse\\src\\main\\resources\\frontend-crew.md"; + private static final int BASIC_PAIR_SIZE = 2; + private static final int SPECIAL_PAIR_SIZE = 3; + private static final int START_NUMBER = 1; + + public List> match(Choice choice) throws IOException { + if (choice.hasCourseOf(Course.BACKEND)) { + List shuffledCrews = readShuffledCrews(BACKEND_CREW_PATH); + return matchBy(shuffledCrews); + } + List shuffledCrews = readShuffledCrews(FRONTEND_CREW_PATH); + return matchBy(shuffledCrews); + } + + private List readShuffledCrews(String path) throws IOException { + List shuffledNames = Randoms.shuffle(readNames(path)); + return shuffledNames.stream() + .map(name -> new Crew(Course.BACKEND, name)) + .collect(Collectors.toList()); + } + + private List> matchBy(List shuffledCrews) { + List> pairs = new ArrayList<>(); + int halfSize = shuffledCrews.size() / BASIC_PAIR_SIZE; + for (int i = 0; i < halfSize; i++) { + pairs.add(makeCrewPairByOrder(shuffledCrews, halfSize, i)); + } + return pairs; + } + + private Set makeCrewPairByOrder(List shuffledCrews, int halfSize, int order) { + if (order == halfSize - START_NUMBER) { + return makePair(shuffledCrews, order * BASIC_PAIR_SIZE, SPECIAL_PAIR_SIZE); + } + return makePair(shuffledCrews, order * BASIC_PAIR_SIZE, BASIC_PAIR_SIZE); + } + + private static Set makePair(List shuffledCrews, int skipSize, int pairSize) { + return shuffledCrews.stream() + .skip(skipSize) + .limit(pairSize) + .collect(Collectors.toSet()); + } + + public List readNames(String path) throws IOException { + return Files.readAllLines(Paths.get(path)); + } +} From c3608182adcd5169706936570428d2ff4eff5027 Mon Sep 17 00:00:00 2001 From: chanminmaxscaler Date: Fri, 16 Dec 2022 16:31:45 +0900 Subject: [PATCH 09/20] =?UTF-8?q?feat:=20=EB=A7=A4=EC=B9=AD=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EB=B0=8F=20=EA=B8=B0=EB=A1=9D=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=EC=9D=84=20=EA=B5=AC=ED=98=84=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MatchingProgram 객체는 매칭에 관한 기능을 담당한다. PairMatchingMachine 객체를 통해 페어 매칭한 결과를 얻는다. MatchingHistory 객체를 통해 페어 매칭 결과를 검증한다. 매칭이 3번 실패할 시 오류를 발생시킨다. --- .../pairmatching/controller/Controller.java | 11 ++++++++-- .../pairmatching/domain/choice/Choice.java | 8 +++++++ .../java/pairmatching/domain/crew/Crew.java | 8 +++++++ .../java/pairmatching/domain/item/Course.java | 2 +- .../pairmatching/domain/item/Mission.java | 4 ++++ .../domain/matching/MatchingHistory.java | 22 +++++++++++++++++-- 6 files changed, 50 insertions(+), 5 deletions(-) diff --git a/src/main/java/pairmatching/controller/Controller.java b/src/main/java/pairmatching/controller/Controller.java index 14abc802f..1f85883fd 100644 --- a/src/main/java/pairmatching/controller/Controller.java +++ b/src/main/java/pairmatching/controller/Controller.java @@ -4,6 +4,8 @@ import pairmatching.domain.choice.Choice; import pairmatching.domain.choice.ChoiceMaker; import pairmatching.domain.matching.MatchingHistory; +import pairmatching.domain.matching.MatchingProgram; +import pairmatching.domain.matching.PairMatchingMachine; import pairmatching.view.InputView; import pairmatching.view.OutputView; @@ -29,8 +31,13 @@ private void executeCommand() { while (!command.isCommandOf(Command.QUITTING)) { if (command.isCommandOf(Command.MATCHING)) { Choice choice = readValidValueBy(this::readChoice); - MatchingHistory history = new MatchingHistory(); - history.hasMatchingOf(choice); + MatchingProgram program = new MatchingProgram(new MatchingHistory(), new PairMatchingMachine()); + if (program.hasMatched(choice)) { + + } + if (!program.hasMatched(choice)) { + + } } if (command.isCommandOf(Command.CHECKING)) { diff --git a/src/main/java/pairmatching/domain/choice/Choice.java b/src/main/java/pairmatching/domain/choice/Choice.java index 8d6711756..fb872f933 100644 --- a/src/main/java/pairmatching/domain/choice/Choice.java +++ b/src/main/java/pairmatching/domain/choice/Choice.java @@ -31,4 +31,12 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(course, mission); } + + public boolean hasCourseOf(Course course) { + return this.course.equals(course); + } + + public boolean hasSameLevel(Choice choice) { + return mission.isSameLevel(choice.mission); + } } diff --git a/src/main/java/pairmatching/domain/crew/Crew.java b/src/main/java/pairmatching/domain/crew/Crew.java index fe55b2de4..a6b70e489 100644 --- a/src/main/java/pairmatching/domain/crew/Crew.java +++ b/src/main/java/pairmatching/domain/crew/Crew.java @@ -11,4 +11,12 @@ public Crew(Course course, String name) { this.course = course; this.name = name; } + + @Override + public String toString() { + return "Crew{" + + "course=" + course + + ", name='" + name + '\'' + + '}'; + } } \ No newline at end of file diff --git a/src/main/java/pairmatching/domain/item/Course.java b/src/main/java/pairmatching/domain/item/Course.java index 2ffe6cb04..b90c9ea83 100644 --- a/src/main/java/pairmatching/domain/item/Course.java +++ b/src/main/java/pairmatching/domain/item/Course.java @@ -7,7 +7,7 @@ public enum Course { FRONTEND("프론트엔드"); private static final String ERROR_MESSAGE = "[ERROR] %s 과정은 존재하지 않습니다."; - private String courseName; + private final String courseName; Course(String courseName) { this.courseName = courseName; diff --git a/src/main/java/pairmatching/domain/item/Mission.java b/src/main/java/pairmatching/domain/item/Mission.java index 5d025421a..64e5164ae 100644 --- a/src/main/java/pairmatching/domain/item/Mission.java +++ b/src/main/java/pairmatching/domain/item/Mission.java @@ -44,4 +44,8 @@ public String getMissionName() { public Level getLevel() { return level; } + + public boolean isSameLevel(Mission mission) { + return level.equals(mission.getLevel()); + } } diff --git a/src/main/java/pairmatching/domain/matching/MatchingHistory.java b/src/main/java/pairmatching/domain/matching/MatchingHistory.java index 311c5ffea..48095bdcb 100644 --- a/src/main/java/pairmatching/domain/matching/MatchingHistory.java +++ b/src/main/java/pairmatching/domain/matching/MatchingHistory.java @@ -4,12 +4,13 @@ import pairmatching.domain.crew.Crew; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Predicate; public class MatchingHistory { - - private final Map> history; + private final Map>> history; public MatchingHistory() { this.history = new HashMap<>(); @@ -18,4 +19,21 @@ public MatchingHistory() { public boolean hasMatchingOf(Choice choice) { return history.containsKey(choice); } + + public void record(Choice choice, List> pairs) { + history.put(choice, pairs); + } + + public boolean hasDuplicatePairInSameLevel(Choice choice, List> pairs) { + return history.keySet().stream() + .filter(pastChoice -> pastChoice.hasSameLevel(choice)) + .noneMatch(pastChoice -> hasSamePair(pastChoice, pairs)); + } + + private boolean hasSamePair(Choice choice, List> pairs) { + List> pastPairs = history.get(choice); + return pastPairs.stream() + .noneMatch(pair -> pairs.stream() + .anyMatch(Predicate.isEqual(pair))); + } } From 0f7ca80b766e5462d7ce9cc118ab80b822b4c2d9 Mon Sep 17 00:00:00 2001 From: chanminmaxscaler Date: Fri, 16 Dec 2022 16:32:02 +0900 Subject: [PATCH 10/20] =?UTF-8?q?feat:=20=EB=A7=A4=EC=B9=AD=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EB=B0=8F=20=EA=B8=B0=EB=A1=9D=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=EC=9D=84=20=EA=B5=AC=ED=98=84=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MatchingProgram 객체는 매칭에 관한 기능을 담당한다. PairMatchingMachine 객체를 통해 페어 매칭한 결과를 얻는다. MatchingHistory 객체를 통해 페어 매칭 결과를 검증한다. 매칭이 3번 실패할 시 오류를 발생시킨다. --- .../domain/matching/MatchingProgram.java | 67 ++++++------------- .../domain/matching/PairMatchingMachine.java | 66 ++++++++++++++++++ 2 files changed, 86 insertions(+), 47 deletions(-) create mode 100644 src/main/java/pairmatching/domain/matching/PairMatchingMachine.java diff --git a/src/main/java/pairmatching/domain/matching/MatchingProgram.java b/src/main/java/pairmatching/domain/matching/MatchingProgram.java index 5b0d57449..de23d0f88 100644 --- a/src/main/java/pairmatching/domain/matching/MatchingProgram.java +++ b/src/main/java/pairmatching/domain/matching/MatchingProgram.java @@ -1,66 +1,39 @@ package pairmatching.domain.matching; -import camp.nextstep.edu.missionutils.Randoms; import pairmatching.domain.choice.Choice; import pairmatching.domain.crew.Crew; -import pairmatching.domain.item.Course; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; import java.util.List; import java.util.Set; -import java.util.stream.Collectors; public class MatchingProgram { - private static final String BACKEND_CREW_PATH = "C:\\programming\\woowacourse\\practice\\java-pairmatching-precourse\\src\\main\\resources\\backend-crew.md"; - private static final String FRONTEND_CREW_PATH = "C:\\programming\\woowacourse\\practice\\java-pairmatching-precourse\\src\\main\\resources\\frontend-crew.md"; - private static final int BASIC_PAIR_SIZE = 2; - private static final int SPECIAL_PAIR_SIZE = 3; - private static final int START_NUMBER = 1; + private static final int MINIMUM_COUNT = 0; + private static final int MAXIMUM_COUNT = 3; + private static final String ERROR_MESSAGE = "[ERROR] 매칭 시도가 %d회를 초과하였습니다."; + private final MatchingHistory history; + private final PairMatchingMachine pairMatchingMachine; - public List> match(Choice choice) throws IOException { - if (choice.hasCourseOf(Course.BACKEND)) { - List shuffledCrews = readShuffledCrews(BACKEND_CREW_PATH); - return matchBy(shuffledCrews); - } - List shuffledCrews = readShuffledCrews(FRONTEND_CREW_PATH); - return matchBy(shuffledCrews); + public MatchingProgram(MatchingHistory history, PairMatchingMachine pairMatchingMachine) { + this.history = history; + this.pairMatchingMachine = pairMatchingMachine; } - private List readShuffledCrews(String path) throws IOException { - List shuffledNames = Randoms.shuffle(readNames(path)); - return shuffledNames.stream() - .map(name -> new Crew(Course.BACKEND, name)) - .collect(Collectors.toList()); + public boolean hasMatched(Choice choice) { + return history.hasMatchingOf(choice); } - private List> matchBy(List shuffledCrews) { - List> pairs = new ArrayList<>(); - int halfSize = shuffledCrews.size() / BASIC_PAIR_SIZE; - for (int i = 0; i < halfSize; i++) { - pairs.add(makeCrewPairByOrder(shuffledCrews, halfSize, i)); - } + public List> matchAndRecord(Choice choice) throws IOException { + List> pairs; + int count = MINIMUM_COUNT; + do { + pairs = pairMatchingMachine.makePairs(choice); + count++; + if (count == MAXIMUM_COUNT) { + throw new IllegalStateException(String.format(ERROR_MESSAGE, count)); + } + } while (!history.hasDuplicatePairInSameLevel(choice, pairs)); return pairs; } - - private Set makeCrewPairByOrder(List shuffledCrews, int halfSize, int order) { - if (order == halfSize - START_NUMBER) { - return makePair(shuffledCrews, order * BASIC_PAIR_SIZE, SPECIAL_PAIR_SIZE); - } - return makePair(shuffledCrews, order * BASIC_PAIR_SIZE, BASIC_PAIR_SIZE); - } - - private static Set makePair(List shuffledCrews, int skipSize, int pairSize) { - return shuffledCrews.stream() - .skip(skipSize) - .limit(pairSize) - .collect(Collectors.toSet()); - } - - public List readNames(String path) throws IOException { - return Files.readAllLines(Paths.get(path)); - } } diff --git a/src/main/java/pairmatching/domain/matching/PairMatchingMachine.java b/src/main/java/pairmatching/domain/matching/PairMatchingMachine.java new file mode 100644 index 000000000..99d15b842 --- /dev/null +++ b/src/main/java/pairmatching/domain/matching/PairMatchingMachine.java @@ -0,0 +1,66 @@ +package pairmatching.domain.matching; + +import camp.nextstep.edu.missionutils.Randoms; +import pairmatching.domain.choice.Choice; +import pairmatching.domain.crew.Crew; +import pairmatching.domain.item.Course; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +public class PairMatchingMachine { + + private static final String BACKEND_CREW_PATH = "C:\\programming\\woowacourse\\practice\\java-pairmatching-precourse\\src\\main\\resources\\backend-crew.md"; + private static final String FRONTEND_CREW_PATH = "C:\\programming\\woowacourse\\practice\\java-pairmatching-precourse\\src\\main\\resources\\frontend-crew.md"; + private static final int BASIC_PAIR_SIZE = 2; + private static final int SPECIAL_PAIR_SIZE = 3; + private static final int START_NUMBER = 1; + + public List> makePairs(Choice choice) throws IOException { + if (choice.hasCourseOf(Course.BACKEND)) { + List shuffledCrews = readShuffledCrews(BACKEND_CREW_PATH); + return makePairsBy(shuffledCrews); + } + List shuffledCrews = readShuffledCrews(FRONTEND_CREW_PATH); + return makePairsBy(shuffledCrews); + } + + private List> makePairsBy(List shuffledCrews) { + List> pairs = new ArrayList<>(); + int halfSize = shuffledCrews.size() / BASIC_PAIR_SIZE; + for (int i = 0; i < halfSize; i++) { + pairs.add(makeCrewPairByOrder(shuffledCrews, halfSize, i)); + } + return pairs; + } + + private Set makeCrewPairByOrder(List shuffledCrews, int halfSize, int order) { + if (order == halfSize - START_NUMBER) { + return makePair(shuffledCrews, order * BASIC_PAIR_SIZE, SPECIAL_PAIR_SIZE); + } + return makePair(shuffledCrews, order * BASIC_PAIR_SIZE, BASIC_PAIR_SIZE); + } + + private static Set makePair(List shuffledCrews, int skipSize, int pairSize) { + return shuffledCrews.stream() + .skip(skipSize) + .limit(pairSize) + .collect(Collectors.toSet()); + } + + private List readShuffledCrews(String path) throws IOException { + List shuffledNames = Randoms.shuffle(readNames(path)); + return shuffledNames.stream() + .map(name -> new Crew(Course.BACKEND, name)) + .collect(Collectors.toList()); + } + + public List readNames(String path) throws IOException { + return Files.readAllLines(Paths.get(path)); + } +} From abef6370e4ac9c5abfdbbe8e928590df70cc8050 Mon Sep 17 00:00:00 2001 From: chanminmaxscaler Date: Fri, 16 Dec 2022 16:32:56 +0900 Subject: [PATCH 11/20] =?UTF-8?q?feat:=20=EC=95=A0=ED=94=8C=EB=A6=AC?= =?UTF-8?q?=EC=BC=80=EC=9D=B4=EC=85=98=20=EC=8B=A4=ED=96=89=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=EC=9D=84=20=EA=B5=AC=ED=98=84=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/pairmatching/Application.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/pairmatching/Application.java b/src/main/java/pairmatching/Application.java index 6f56e741c..7557f471f 100644 --- a/src/main/java/pairmatching/Application.java +++ b/src/main/java/pairmatching/Application.java @@ -1,7 +1,12 @@ package pairmatching; +import pairmatching.controller.Controller; +import pairmatching.view.InputView; +import pairmatching.view.OutputView; + public class Application { public static void main(String[] args) { - // TODO 구현 진행 + Controller controller = new Controller(new InputView(), new OutputView()); + controller.runMain(); } } From 4498a31ee99b91998b9d01af75f529ca3a3dcacd Mon Sep 17 00:00:00 2001 From: chanminmaxscaler Date: Fri, 16 Dec 2022 16:34:38 +0900 Subject: [PATCH 12/20] =?UTF-8?q?docs:=20=EA=B0=9C=EB=B0=9C=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EB=AA=A9=EB=A1=9D=EC=9D=84=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 개발을 완료한 기능을 체크한다. 매칭 검증 기능에 대한 내용을 수정한다. --- docs/README.md | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/docs/README.md b/docs/README.md index afd190f7e..78d8db2c6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,32 +2,31 @@ ## 개발 기능 목록 -- [ ] 기능 명령어 선택 기능 - - [ ] 문자 한 개를 입력하는지 검증 +- [x] 기능 명령어 선택 기능 + - [x] 문자 한 개를 입력하는지 검증 -- [ ] 기능 명령어 검증 기능 - - [ ] 1, 2, 3, Q 중 하나인지 검증 +- [x] 기능 명령어 검증 기능 + - [x] 1, 2, 3, Q 중 하나인지 검증 -- [ ] 명령어 실행 기능 - - [ ] 명령어가 입력되면 각 명령에 맞는 기능 실행 +- [x] 명령어 실행 기능 + - [x] 명령어가 입력되면 각 명령에 맞는 기능 실행 -- [ ] 과정, 레벨, 미션 선택 기능 - - [ ] ", "로 구분되는 문자열인지 검증 +- [x] 과정, 레벨, 미션 선택 기능 + - [x] ", "로 구분되는 문자열인지 검증 -- [ ] 과정, 레벨, 미션 검증 기능 - - [ ] 각 보기에 부합하는지 검증 +- [x] 과정, 레벨, 미션 검증 기능 + - [x] 각 보기에 부합하는지 검증 -- [ ] 매칭 이력 확인 기능 +- [x] 매칭 이력 확인 기능 -- [ ] 매칭 기능 - - [ ] 파일 읽기 - - [ ] 크루원 이름 셔플 - - [ ] 2명(마지막 3명 허용)씩 매칭 +- [x] 매칭 기능 + - [x] 파일 읽기 + - [x] 크루원 이름 셔플 + - [x] 2명(마지막 3명 허용)씩 매칭 -- [ ] 매칭 검증 기능 - - [ ] 이름 중복 검증 - - [ ] 페어 사이즈 검증 - - [ ] 같은 레벨 하 매칭 중복 검증 +- [x] 매칭 검증 기능 + - [x] 같은 레벨 하 매칭 중복 검증 + - [x] 매칭 실패 시 오류 발생 - [ ] 재매칭 선택 기능 - [ ] 한글 입력인지 검증 From 6dfa2ca2181566ba3873e9af3f89acb14d367242 Mon Sep 17 00:00:00 2001 From: chanminmaxscaler Date: Fri, 16 Dec 2022 22:51:38 +0900 Subject: [PATCH 13/20] =?UTF-8?q?feat:=20=EC=9E=AC=EB=A7=A4=EC=B9=AD=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D=20=EB=B0=8F=20=EA=B2=80=EC=A6=9D=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=EC=9D=84=20=EA=B5=AC=ED=98=84=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit inputView에서 네, 아니오 중 하나인지 검증한다. 반환값은 boolean 값으로 하도록 한다. --- src/main/java/pairmatching/view/InputView.java | 10 ++++++++++ src/main/java/pairmatching/view/message/Message.java | 10 +++++----- .../java/pairmatching/view/validator/Validator.java | 5 +++-- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/main/java/pairmatching/view/InputView.java b/src/main/java/pairmatching/view/InputView.java index 403135b28..a331e0065 100644 --- a/src/main/java/pairmatching/view/InputView.java +++ b/src/main/java/pairmatching/view/InputView.java @@ -9,6 +9,7 @@ public class InputView { private static final String CHOICE_DELIMITER = ", "; + private final String RE_MATCHING_COMMAND = "네"; public String readCommand() { return readValidInputBy(Validator.COMMAND); @@ -19,6 +20,15 @@ public List readChoices() { return Arrays.asList(input.split(CHOICE_DELIMITER)); } + public boolean isReMatching() { + String input = readValidInputBy(Validator.RE_MATCHING); + return convertReMatchingCommandToBoolean(input); + } + + private boolean convertReMatchingCommandToBoolean(String input) { + return input.equals(RE_MATCHING_COMMAND); + } + private String readValidInputBy(Validator validator) { String input = Console.readLine(); validateBy(input, validator); diff --git a/src/main/java/pairmatching/view/message/Message.java b/src/main/java/pairmatching/view/message/Message.java index 0321d4ff7..e616effd9 100644 --- a/src/main/java/pairmatching/view/message/Message.java +++ b/src/main/java/pairmatching/view/message/Message.java @@ -1,12 +1,12 @@ package pairmatching.view.message; public enum Message { - COMMAND_GUIDE("기능을 선택하세요.\n" + + COMMAND_GUIDE("\n기능을 선택하세요.\n" + "1. 페어 매칭\n" + "2. 페어 조회\n" + "3. 페어 초기화\n" + "Q. 종료\n"), - CHOICE_GUIDE("#############################################\n" + + CHOICE_GUIDE("\n#############################################\n" + "과정: 백엔드 | 프론트엔드\n" + "미션:\n" + " - 레벨1: 자동차경주 | 로또 | 숫자야구게임\n" + @@ -17,11 +17,11 @@ public enum Message { "############################################\n" + "과정, 레벨, 미션을 선택하세요.\n" + "ex) 백엔드, 레벨1, 자동차경주\n"), - MATCHING_RESULT_GUIDE("페어 매칭 결과입니다.\n"), + MATCHING_RESULT_GUIDE("\n페어 매칭 결과입니다.\n"), MATCHING_DELIMITER(" : "), - RE_MATCHING_GUIDE("매칭 정보가 있습니다. 다시 매칭하시겠습니까?\n" + + RE_MATCHING_GUIDE("\n매칭 정보가 있습니다. 다시 매칭하시겠습니까?\n" + "네 | 아니오\n"), - INITIALIZING("초기화 되었습니다.\n"); + INITIALIZING("\n초기화 되었습니다.\n"); private final String message; diff --git a/src/main/java/pairmatching/view/validator/Validator.java b/src/main/java/pairmatching/view/validator/Validator.java index 8af111ac7..4dde11648 100644 --- a/src/main/java/pairmatching/view/validator/Validator.java +++ b/src/main/java/pairmatching/view/validator/Validator.java @@ -1,8 +1,9 @@ package pairmatching.view.validator; public enum Validator { - COMMAND("\\w{1}", "[ERROR] 기능 선택은 한 개의 문자만 입력이 가능합니다."), - CHOICE(".{3,5},.{4},.{3,7}", "[ERROR] 올바른 입력이 아닙니다. \", \"로 구분하여 과정, 레벨, 미션을 입력하십시오."); + COMMAND("\\w{1}", "[ERROR] 기능 선택은 한 개의 문자만 입력이 가능합니다.\n"), + CHOICE(".{3,5},.{4},.{3,7}", "[ERROR] 올바른 입력이 아닙니다. \", \"로 구분하여 과정, 레벨, 미션을 입력하십시오.\n"), + RE_MATCHING("(네|아니오)", "[ERROR] %s는 잘못된 입력입니다. 네, 아니오 중 한 가지를 입력하십시오.\n"); private final String validFormat; private final String errorMessage; From fb9d73302fc42c8001b8f1d40751def5b93a21cf Mon Sep 17 00:00:00 2001 From: chanminmaxscaler Date: Fri, 16 Dec 2022 22:53:28 +0900 Subject: [PATCH 14/20] =?UTF-8?q?feat:=20=EB=A7=A4=EC=B9=AD=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EB=B0=8F=20=EC=B4=88=EA=B8=B0=ED=99=94=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=EC=9D=84=20=EA=B5=AC=ED=98=84=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 매칭 조회 시 매칭 이력이 없을 경우 오류를 발생시킨다. 매칭 이력이 있는 경우 매칭 결과를 출력한다. 매칭 초기화 시 매칭 이력을 모두 없앤다. --- .../domain/matching/MatchingHistory.java | 12 +++++++ .../domain/matching/MatchingProgram.java | 33 ++++++++++++++++--- .../java/pairmatching/view/OutputView.java | 27 +++++++++++++++ 3 files changed, 68 insertions(+), 4 deletions(-) diff --git a/src/main/java/pairmatching/domain/matching/MatchingHistory.java b/src/main/java/pairmatching/domain/matching/MatchingHistory.java index 48095bdcb..6da532d37 100644 --- a/src/main/java/pairmatching/domain/matching/MatchingHistory.java +++ b/src/main/java/pairmatching/domain/matching/MatchingHistory.java @@ -36,4 +36,16 @@ private boolean hasSamePair(Choice choice, List> pairs) { .noneMatch(pair -> pairs.stream() .anyMatch(Predicate.isEqual(pair))); } + + public void delete(Choice choice) { + history.remove(choice); + } + + public List> getRecord(Choice choice) { + return history.get(choice); + } + + public void truncate() { + history.clear(); + } } diff --git a/src/main/java/pairmatching/domain/matching/MatchingProgram.java b/src/main/java/pairmatching/domain/matching/MatchingProgram.java index de23d0f88..3e944eac9 100644 --- a/src/main/java/pairmatching/domain/matching/MatchingProgram.java +++ b/src/main/java/pairmatching/domain/matching/MatchingProgram.java @@ -11,7 +11,8 @@ public class MatchingProgram { private static final int MINIMUM_COUNT = 0; private static final int MAXIMUM_COUNT = 3; - private static final String ERROR_MESSAGE = "[ERROR] 매칭 시도가 %d회를 초과하였습니다."; + private static final String UN_MATCHED_ERROR_MESSAGE = "[ERROR] 매칭 시도가 %d회를 초과하였습니다.\n"; + private static final String UN_MATCHED_CHOICE_ERROR_MESSAGE = "[ERROR] 매칭 이력이 없습니다.\n"; private final MatchingHistory history; private final PairMatchingMachine pairMatchingMachine; @@ -30,10 +31,34 @@ public List> matchAndRecord(Choice choice) throws IOException { do { pairs = pairMatchingMachine.makePairs(choice); count++; - if (count == MAXIMUM_COUNT) { - throw new IllegalStateException(String.format(ERROR_MESSAGE, count)); - } + validateMatchingCount(count); } while (!history.hasDuplicatePairInSameLevel(choice, pairs)); + history.record(choice, pairs); return pairs; } + + private void validateMatchingCount(int count) { + if (count == MAXIMUM_COUNT) { + throw new IllegalStateException(String.format(UN_MATCHED_ERROR_MESSAGE, count)); + } + } + + public void deleteHistory(Choice choice) { + history.delete(choice); + } + + public List> show(Choice choice) { + validate(choice); + return history.getRecord(choice); + } + + private void validate(Choice choice) { + if (!hasMatched(choice)) { + throw new IllegalArgumentException(UN_MATCHED_CHOICE_ERROR_MESSAGE); + } + } + + public void truncateHistory() { + history.truncate(); + } } diff --git a/src/main/java/pairmatching/view/OutputView.java b/src/main/java/pairmatching/view/OutputView.java index 5f3152e6d..9f0225b83 100644 --- a/src/main/java/pairmatching/view/OutputView.java +++ b/src/main/java/pairmatching/view/OutputView.java @@ -1,7 +1,12 @@ package pairmatching.view; +import pairmatching.domain.crew.Crew; import pairmatching.view.message.Message; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + public class OutputView { public void printCommandGuide() { @@ -12,6 +17,28 @@ public void printChoiceGuide() { print(Message.CHOICE_GUIDE.getMessage()); } + public void printMatchingResult(List> pairs) { + print(Message.MATCHING_RESULT_GUIDE.getMessage()); + for (Set pair : pairs) { + String result = makeMatchingResultMessage(pair); + print(result); + } + } + + private String makeMatchingResultMessage(Set pair) { + return pair.stream() + .map(Crew::getName) + .collect(Collectors.joining(Message.MATCHING_DELIMITER.getMessage())) + "\n"; + } + + public void printReMatchingGuide() { + print(Message.RE_MATCHING_GUIDE.getMessage()); + } + + public void printInitializingMessage() { + print(Message.INITIALIZING.getMessage()); + } + public void printErrorMessage(String message) { print(message); } From 72e72fcf715132fef717ac81a75835ad27141811 Mon Sep 17 00:00:00 2001 From: chanminmaxscaler Date: Fri, 16 Dec 2022 22:54:14 +0900 Subject: [PATCH 15/20] =?UTF-8?q?fix:=20Mission=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=EC=9D=98=20=EB=A0=88=EB=B2=A8=EA=B3=BC=20=EB=AF=B8?= =?UTF-8?q?=EC=85=98=EC=9D=84=20=ED=95=A8=EA=BB=98=20=EB=B9=84=EA=B5=90?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=ED=95=A8=EC=88=98=EB=A5=BC=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 조건문에서 부정 !을 추가한다. --- src/main/java/pairmatching/domain/item/Mission.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/pairmatching/domain/item/Mission.java b/src/main/java/pairmatching/domain/item/Mission.java index 64e5164ae..62db7195d 100644 --- a/src/main/java/pairmatching/domain/item/Mission.java +++ b/src/main/java/pairmatching/domain/item/Mission.java @@ -12,8 +12,8 @@ public enum Mission { PERFORMANCE_IMPROVEMENT("성능개선", Level.LEVEL3), PUBLISHING("배포", Level.LEVEL3); - private static final String DISCORDANCE_ERROR_MESSAGE = "[ERROR] %s 미션은 \"%s\"이 아닙니다."; - private static final String VALUE_ERROR_MESSAGE = "[ERROR] %s 미션은 존재하지 않습니다."; + private static final String DISCORDANCE_ERROR_MESSAGE = "[ERROR] %s 미션은 \"%s\"이 아닙니다.\n"; + private static final String VALUE_ERROR_MESSAGE = "[ERROR] %s 미션은 존재하지 않습니다.\n"; private final String missionName; private final Level level; @@ -24,7 +24,7 @@ public enum Mission { public static Mission valueOfMissionAndLevel(String missionName, Level level) { Mission mission = valueOfMission(missionName); - if (level.equals(mission.getLevel())) { + if (!level.equals(mission.getLevel())) { throw new IllegalArgumentException(String.format(DISCORDANCE_ERROR_MESSAGE, missionName, level.getLevelName())); } return mission; From 9d76d5ae8059a0c6bb3bf3825a812ec3192e277d Mon Sep 17 00:00:00 2001 From: chanminmaxscaler Date: Fri, 16 Dec 2022 22:55:01 +0900 Subject: [PATCH 16/20] =?UTF-8?q?chore:=20=EC=83=81=EC=88=98=20=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80,=20=ED=95=98=EB=93=9C=EC=BD=94=EB=94=A9=20?= =?UTF-8?q?=EB=93=B1=EC=9D=84=20=EC=88=98=EC=A0=95=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pairmatching/{domain => controller/command}/Command.java | 5 +++-- src/main/java/pairmatching/domain/crew/Crew.java | 4 ++++ src/main/java/pairmatching/domain/item/Course.java | 2 +- src/main/java/pairmatching/domain/item/Level.java | 4 ++-- 4 files changed, 10 insertions(+), 5 deletions(-) rename src/main/java/pairmatching/{domain => controller/command}/Command.java (79%) diff --git a/src/main/java/pairmatching/domain/Command.java b/src/main/java/pairmatching/controller/command/Command.java similarity index 79% rename from src/main/java/pairmatching/domain/Command.java rename to src/main/java/pairmatching/controller/command/Command.java index 1e3d2e664..87e1637c8 100644 --- a/src/main/java/pairmatching/domain/Command.java +++ b/src/main/java/pairmatching/controller/command/Command.java @@ -1,4 +1,4 @@ -package pairmatching.domain; +package pairmatching.controller.command; import java.util.Arrays; @@ -8,6 +8,7 @@ public enum Command { INITIALIZING("3"), QUITTING("Q"); + private static final String ERROR_MESSAGE = "[ERROR] %s는 기능이 아닙니다.\n"; private final String command; Command(String command) { @@ -18,7 +19,7 @@ public static Command valueOfCommand(String inputCommand) { return Arrays.stream(values()) .filter(value -> inputCommand.equals(value.getCommand())) .findAny() - .orElseThrow(() -> new IllegalArgumentException(String.format("[ERROR] %s는 기능이 아닙니다.", inputCommand))); + .orElseThrow(() -> new IllegalArgumentException(String.format(ERROR_MESSAGE, inputCommand))); } public String getCommand() { diff --git a/src/main/java/pairmatching/domain/crew/Crew.java b/src/main/java/pairmatching/domain/crew/Crew.java index a6b70e489..fd02e2516 100644 --- a/src/main/java/pairmatching/domain/crew/Crew.java +++ b/src/main/java/pairmatching/domain/crew/Crew.java @@ -12,6 +12,10 @@ public Crew(Course course, String name) { this.name = name; } + public String getName() { + return name; + } + @Override public String toString() { return "Crew{" + diff --git a/src/main/java/pairmatching/domain/item/Course.java b/src/main/java/pairmatching/domain/item/Course.java index b90c9ea83..0f7fc0154 100644 --- a/src/main/java/pairmatching/domain/item/Course.java +++ b/src/main/java/pairmatching/domain/item/Course.java @@ -6,7 +6,7 @@ public enum Course { BACKEND("백엔드"), FRONTEND("프론트엔드"); - private static final String ERROR_MESSAGE = "[ERROR] %s 과정은 존재하지 않습니다."; + private static final String ERROR_MESSAGE = "[ERROR] %s 과정은 존재하지 않습니다.\n"; private final String courseName; Course(String courseName) { diff --git a/src/main/java/pairmatching/domain/item/Level.java b/src/main/java/pairmatching/domain/item/Level.java index eb242c282..eff5ef793 100644 --- a/src/main/java/pairmatching/domain/item/Level.java +++ b/src/main/java/pairmatching/domain/item/Level.java @@ -9,8 +9,8 @@ public enum Level { LEVEL4("레벨4"), LEVEL5("레벨5"); - private static final String ERROR_MESSAGE = "[ERROR] %s 레벨은 존재하지 않습니다."; - private String levelName; + private static final String ERROR_MESSAGE = "[ERROR] %s 레벨은 존재하지 않습니다.\n"; + private final String levelName; Level(String levelName) { this.levelName = levelName; From 4c18bc6fa1ee550ed9be001707e2bb55cd46ce67 Mon Sep 17 00:00:00 2001 From: chanminmaxscaler Date: Sat, 17 Dec 2022 00:06:31 +0900 Subject: [PATCH 17/20] =?UTF-8?q?refactor:=20Controller=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=EB=A5=BC=20=EB=B6=84=EB=A6=AC=ED=95=9C?= =?UTF-8?q?=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit InputController, MainController 로 분리한다. --- .../pairmatching/controller/Controller.java | 73 -------------- .../controller/InputController.java | 76 +++++++++++++++ .../controller/MainController.java | 94 +++++++++++++++++++ 3 files changed, 170 insertions(+), 73 deletions(-) delete mode 100644 src/main/java/pairmatching/controller/Controller.java create mode 100644 src/main/java/pairmatching/controller/InputController.java create mode 100644 src/main/java/pairmatching/controller/MainController.java diff --git a/src/main/java/pairmatching/controller/Controller.java b/src/main/java/pairmatching/controller/Controller.java deleted file mode 100644 index 1f85883fd..000000000 --- a/src/main/java/pairmatching/controller/Controller.java +++ /dev/null @@ -1,73 +0,0 @@ -package pairmatching.controller; - -import pairmatching.domain.Command; -import pairmatching.domain.choice.Choice; -import pairmatching.domain.choice.ChoiceMaker; -import pairmatching.domain.matching.MatchingHistory; -import pairmatching.domain.matching.MatchingProgram; -import pairmatching.domain.matching.PairMatchingMachine; -import pairmatching.view.InputView; -import pairmatching.view.OutputView; - -import java.util.List; -import java.util.function.Supplier; - -public class Controller { - - private final InputView inputView; - private final OutputView outputView; - - public Controller(InputView inputView, OutputView outputView) { - this.inputView = inputView; - this.outputView = outputView; - } - - public void runMain() { - executeCommand(); - } - - private void executeCommand() { - Command command = readValidValueBy(this::readCommand); - while (!command.isCommandOf(Command.QUITTING)) { - if (command.isCommandOf(Command.MATCHING)) { - Choice choice = readValidValueBy(this::readChoice); - MatchingProgram program = new MatchingProgram(new MatchingHistory(), new PairMatchingMachine()); - if (program.hasMatched(choice)) { - - } - if (!program.hasMatched(choice)) { - - } - } - if (command.isCommandOf(Command.CHECKING)) { - - } - if (command.isCommandOf(Command.INITIALIZING)) { - - } - } - } - - private Command readCommand() { - outputView.printCommandGuide(); - String inputCommand = inputView.readCommand(); - return Command.valueOfCommand(inputCommand); - } - - private Choice readChoice() { - outputView.printChoiceGuide(); - List choices = inputView.readChoices(); - ChoiceMaker choiceMaker = new ChoiceMaker(); - return choiceMaker.createChoice(choices); - } - - private T readValidValueBy(Supplier inputReader) { - while (true) { - try { - return inputReader.get(); - } catch (IllegalArgumentException e) { - outputView.printErrorMessage(e.getMessage()); - } - } - } -} diff --git a/src/main/java/pairmatching/controller/InputController.java b/src/main/java/pairmatching/controller/InputController.java new file mode 100644 index 000000000..4d0a4ca8a --- /dev/null +++ b/src/main/java/pairmatching/controller/InputController.java @@ -0,0 +1,76 @@ +package pairmatching.controller; + +import pairmatching.controller.command.MainCommand; +import pairmatching.controller.command.ReMatchingCommand; +import pairmatching.domain.choice.Choice; +import pairmatching.domain.choice.ChoiceMaker; +import pairmatching.view.InputView; +import pairmatching.view.OutputView; + +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public class InputController { + + private final InputView inputView; + private final OutputView outputView; + + public InputController(InputView inputView, OutputView outputView) { + this.inputView = inputView; + this.outputView = outputView; + } + + public MainCommand readValidCommand() { + return repeatUntilGettingValidValue(this::readCommand); + } + + public Choice readValidChoice() { + return repeatUntilGettingValidValue(this::readChoice); + } + + public ReMatchingCommand readValidReMatchingCommand() { + return repeatUntilGettingValidValue(this::readReMatchingCommand); + } + + private MainCommand readCommand() { + outputView.printCommandGuide(); + String inputCommand = inputView.readCommand(); + return MainCommand.valueOfCommand(inputCommand); + } + + private Choice readChoice() { + outputView.printChoiceGuide(); + List choices = inputView.readChoices(); + ChoiceMaker choiceMaker = new ChoiceMaker(); + return choiceMaker.createChoice(choices); + } + + private ReMatchingCommand readReMatchingCommand() { + outputView.printReMatchingGuide(); + String input = inputView.readReMatchingCommand(); + return ReMatchingCommand.valueOfReMatchingCommand(input); + } + + private T repeatUntilGettingValidValue(Supplier getSomething) { + while (true) { + try { + return getSomething.get(); + } catch (IllegalArgumentException e) { + outputView.printErrorMessage(e.getMessage()); + } + } + } + + public void repeatUntilGettingValidValue(Consumer getSomething, T input) { + boolean isContinuing = true; + while (isContinuing) { + try { + getSomething.accept(input); + isContinuing = false; + } catch (IllegalArgumentException e) { + outputView.printErrorMessage(e.getMessage()); + } + } + } +} diff --git a/src/main/java/pairmatching/controller/MainController.java b/src/main/java/pairmatching/controller/MainController.java new file mode 100644 index 000000000..d00c96d1a --- /dev/null +++ b/src/main/java/pairmatching/controller/MainController.java @@ -0,0 +1,94 @@ +package pairmatching.controller; + +import pairmatching.controller.command.MainCommand; +import pairmatching.controller.command.ReMatchingCommand; +import pairmatching.domain.choice.Choice; +import pairmatching.domain.crew.Crew; +import pairmatching.domain.matching.MatchingHistory; +import pairmatching.domain.matching.MatchingProgram; +import pairmatching.domain.matching.PairMatchingMachine; +import pairmatching.view.InputView; +import pairmatching.view.OutputView; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +public class MainController { + + private final InputView inputView; + private final OutputView outputView; + private final InputController inputController; + + public MainController(InputView inputView, OutputView outputView) { + this.inputView = inputView; + this.outputView = outputView; + this.inputController = new InputController(inputView, outputView); + } + + public void runMain() { + try { + runProgram(); + } catch (IOException e) { + outputView.printErrorMessage(e.getMessage()); + } + } + + private void runProgram() throws IOException { + executeCommand(); + } + + private void executeCommand() throws IOException { + MainCommand command; + MatchingProgram program = new MatchingProgram(new MatchingHistory(), new PairMatchingMachine()); + do { + command = inputController.readValidCommand(); + decideAndExecute(command, program); + } while (!command.isCommandOf(MainCommand.QUITTING)); + } + + private void decideAndExecute(MainCommand command, MatchingProgram program) throws IOException { + if (command.isCommandOf(MainCommand.MATCHING)) { + executeMatchingCommand(program); + } + if (command.isCommandOf(MainCommand.CHECKING)) { + executeCheckingCommand(program); + } + if (command.isCommandOf(MainCommand.INITIALIZING)) { + executeInitializingCommand(program); + } + } + + private void executeMatchingCommand(MatchingProgram program) throws IOException { + List> pairs = new ArrayList<>(); + while (pairs.isEmpty()) { + Choice choice = inputController.readValidChoice(); + if (program.hasMatched(choice)) { + executeReMatchingCommand(program, choice); + } + if (!program.hasMatched(choice)) { + pairs = program.matchAndRecord(choice); + } + } + outputView.printMatchingResult(pairs); + } + + private void executeReMatchingCommand(MatchingProgram program, Choice choice) throws IOException { + ReMatchingCommand command = inputController.readValidReMatchingCommand(); + if (command.isCommandOf(ReMatchingCommand.RE_MATCHING)) { + program.deleteHistory(choice); + } + } + + private void executeCheckingCommand(MatchingProgram program) { + Choice choice = inputController.readValidChoice(); + List> pairs = program.show(choice); + outputView.printMatchingResult(pairs); + } + + private void executeInitializingCommand(MatchingProgram program) { + program.truncateHistory(); + outputView.printInitializingMessage(); + } +} From 66977afccb14fd1deb3e7f137419fe7676563ef9 Mon Sep 17 00:00:00 2001 From: chanminmaxscaler Date: Sat, 17 Dec 2022 00:07:09 +0900 Subject: [PATCH 18/20] =?UTF-8?q?refactor:=20=EC=9E=AC=EB=A7=A4=EC=B9=AD?= =?UTF-8?q?=20=EB=AA=85=EB=A0=B9=EC=96=B4=20=EC=9E=85=EB=A0=A5=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=EC=9D=84=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= =?UTF-8?q?=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit enum 으로 상수화하여 사용한다. --- .../{Command.java => MainCommand.java} | 8 ++--- .../controller/command/ReMatchingCommand.java | 30 +++++++++++++++++++ .../java/pairmatching/view/InputView.java | 10 ++----- .../view/validator/Validator.java | 2 +- 4 files changed, 37 insertions(+), 13 deletions(-) rename src/main/java/pairmatching/controller/command/{Command.java => MainCommand.java} (79%) create mode 100644 src/main/java/pairmatching/controller/command/ReMatchingCommand.java diff --git a/src/main/java/pairmatching/controller/command/Command.java b/src/main/java/pairmatching/controller/command/MainCommand.java similarity index 79% rename from src/main/java/pairmatching/controller/command/Command.java rename to src/main/java/pairmatching/controller/command/MainCommand.java index 87e1637c8..379ece5d1 100644 --- a/src/main/java/pairmatching/controller/command/Command.java +++ b/src/main/java/pairmatching/controller/command/MainCommand.java @@ -2,7 +2,7 @@ import java.util.Arrays; -public enum Command { +public enum MainCommand { MATCHING("1"), CHECKING("2"), INITIALIZING("3"), @@ -11,11 +11,11 @@ public enum Command { private static final String ERROR_MESSAGE = "[ERROR] %s는 기능이 아닙니다.\n"; private final String command; - Command(String command) { + MainCommand(String command) { this.command = command; } - public static Command valueOfCommand(String inputCommand) { + public static MainCommand valueOfCommand(String inputCommand) { return Arrays.stream(values()) .filter(value -> inputCommand.equals(value.getCommand())) .findAny() @@ -26,7 +26,7 @@ public String getCommand() { return command; } - public boolean isCommandOf(Command command) { + public boolean isCommandOf(MainCommand command) { return this.command.equals(command.getCommand()); } } diff --git a/src/main/java/pairmatching/controller/command/ReMatchingCommand.java b/src/main/java/pairmatching/controller/command/ReMatchingCommand.java new file mode 100644 index 000000000..76efea265 --- /dev/null +++ b/src/main/java/pairmatching/controller/command/ReMatchingCommand.java @@ -0,0 +1,30 @@ +package pairmatching.controller.command; + +import java.util.Arrays; + +public enum ReMatchingCommand { + RE_MATCHING("네"), + NON_RE_MATCHING("아니오"); + + private static final String ERROR_MESSAGE = "[ERROR] %s는 재매칭 명령어가 아닙니다.\n"; + private final String command; + + ReMatchingCommand(String command) { + this.command = command; + } + + public static ReMatchingCommand valueOfReMatchingCommand(String inputCommand) { + return Arrays.stream(values()) + .filter(value -> inputCommand.equals(value.getCommand())) + .findAny() + .orElseThrow(() -> new IllegalArgumentException(String.format(ERROR_MESSAGE, inputCommand))); + } + + public String getCommand() { + return command; + } + + public boolean isCommandOf(ReMatchingCommand command) { + return this.command.equals(command.getCommand()); + } +} \ No newline at end of file diff --git a/src/main/java/pairmatching/view/InputView.java b/src/main/java/pairmatching/view/InputView.java index a331e0065..6eb451981 100644 --- a/src/main/java/pairmatching/view/InputView.java +++ b/src/main/java/pairmatching/view/InputView.java @@ -9,7 +9,6 @@ public class InputView { private static final String CHOICE_DELIMITER = ", "; - private final String RE_MATCHING_COMMAND = "네"; public String readCommand() { return readValidInputBy(Validator.COMMAND); @@ -20,13 +19,8 @@ public List readChoices() { return Arrays.asList(input.split(CHOICE_DELIMITER)); } - public boolean isReMatching() { - String input = readValidInputBy(Validator.RE_MATCHING); - return convertReMatchingCommandToBoolean(input); - } - - private boolean convertReMatchingCommandToBoolean(String input) { - return input.equals(RE_MATCHING_COMMAND); + public String readReMatchingCommand() { + return readValidInputBy(Validator.RE_MATCHING); } private String readValidInputBy(Validator validator) { diff --git a/src/main/java/pairmatching/view/validator/Validator.java b/src/main/java/pairmatching/view/validator/Validator.java index 4dde11648..b9567e83e 100644 --- a/src/main/java/pairmatching/view/validator/Validator.java +++ b/src/main/java/pairmatching/view/validator/Validator.java @@ -3,7 +3,7 @@ public enum Validator { COMMAND("\\w{1}", "[ERROR] 기능 선택은 한 개의 문자만 입력이 가능합니다.\n"), CHOICE(".{3,5},.{4},.{3,7}", "[ERROR] 올바른 입력이 아닙니다. \", \"로 구분하여 과정, 레벨, 미션을 입력하십시오.\n"), - RE_MATCHING("(네|아니오)", "[ERROR] %s는 잘못된 입력입니다. 네, 아니오 중 한 가지를 입력하십시오.\n"); + RE_MATCHING("([가-힣]{1}|[가-힣]{3})", "[ERROR] %s는 잘못된 입력입니다. 네, 아니오 중 한 가지를 입력하십시오.\n"); private final String validFormat; private final String errorMessage; From eec48bc4c738a2914508ed227214599906b3257f Mon Sep 17 00:00:00 2001 From: chanminmaxscaler Date: Sat, 17 Dec 2022 00:07:32 +0900 Subject: [PATCH 19/20] =?UTF-8?q?chore:=20=ED=81=B4=EB=9E=98=EC=8A=A4?= =?UTF-8?q?=EB=AA=85=20=EB=B3=80=EA=B2=BD,=20=ED=8C=A8=ED=82=A4=EC=A7=80?= =?UTF-8?q?=20=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD=EC=9D=84=20=EB=B0=98?= =?UTF-8?q?=EC=98=81=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 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 7557f471f..a8e5c0085 100644 --- a/src/main/java/pairmatching/Application.java +++ b/src/main/java/pairmatching/Application.java @@ -1,12 +1,12 @@ package pairmatching; -import pairmatching.controller.Controller; +import pairmatching.controller.MainController; import pairmatching.view.InputView; import pairmatching.view.OutputView; public class Application { public static void main(String[] args) { - Controller controller = new Controller(new InputView(), new OutputView()); - controller.runMain(); + MainController mainController = new MainController(new InputView(), new OutputView()); + mainController.runMain(); } } From ecf41e029e60f691081a4954730186ba727face7 Mon Sep 17 00:00:00 2001 From: chanminmaxscaler Date: Sat, 17 Dec 2022 00:08:05 +0900 Subject: [PATCH 20/20] =?UTF-8?q?docs:=20=EA=B0=9C=EB=B0=9C=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EB=AA=A9=EB=A1=9D=EC=9D=84=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 개발 완료한 기능을 체크한다. 개발할 기능 목록을 수정한다. --- docs/README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/README.md b/docs/README.md index 78d8db2c6..31091dde8 100644 --- a/docs/README.md +++ b/docs/README.md @@ -27,15 +27,15 @@ - [x] 매칭 검증 기능 - [x] 같은 레벨 하 매칭 중복 검증 - [x] 매칭 실패 시 오류 발생 + - 매칭 실패 경우 + - [ ] 이름 중복 확인 기능 -- [ ] 재매칭 선택 기능 - - [ ] 한글 입력인지 검증 +- [x] 재매칭 선택 및 검증 기능 + - [x] 네, 아니오 중 하나인지 검증 + - [ ] 재매칭 아니오 선택 후 출력문 변화 -- [ ] 재매칭 선택 검증 기능 - - [ ] 네, 아니오 중 하나인지 검증 +- [x] 매칭 조회 기능 + - [x] 매칭 이력 없을 경우 오류 + - [x] 매칭 이력 있는 경우 출력 -- [ ] 매칭 조회 기능 - - [ ] 매칭 이력 없을 경우 오류 - - [ ] 매칭 이력 있는 경우 출력 - -- [ ] 매칭 초기화 기능 \ No newline at end of file +- [x] 매칭 초기화 기능 \ No newline at end of file