diff --git a/build.gradle b/build.gradle index 449e0350a..82925122b 100644 --- a/build.gradle +++ b/build.gradle @@ -11,12 +11,12 @@ repositories { } dependencies { - implementation 'com.github.woowacourse-projects:mission-utils:1.0.0' + implementation 'com.github.woowacourse-projects:mission-utils:1.1.0' } java { toolchain { - languageVersion = JavaLanguageVersion.of(8) + languageVersion = JavaLanguageVersion.of(17) } } diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..b3a1ec3f1 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,49 @@ +# Flow +1. 기능을 선택한다. + - **1 ~ 3, Q가 아닌 경우 예외 발생** +2. 페어 매칭 + - 페어 매칭을 위한 정보를 입력받는다. + - 정보는 파일 입출력으로 입력된다. + - 입력된 정보를 바탕으로 페어를 매칭한다. + - 입력된 정보를 Shuffle을 통해 섞는다. + - 짝수로 나누어 페어를 매칭한다. + - 마지막에 남은 사람이 3명이라면 그 팀은 3명이 팀이다. + - 같은 레벨에서 이미 페어로 만난 적이 있다면, 다시 랜덤으로 섞는다. + - **3회 시도까지 매칭이 되지 않거나 매칭되는 경우의 수가 없다면, 에러 발생** + - 과정(백엔드/프론트엔드)와 레벨을 입력받는다. + - 매칭된 결과를 출력한다. + - 만약, 매칭이 되었는데 다시 1을 입력받는다면, 재 매칭 여부를 입력받는다. + - 네,아니오가 아닐 경우 예외 발생 +3. 페어 조회 + - 매칭된 적이 없는 경우, 매칭 이력이 없다는 예외를 발생시키# 다시 입력 받는다. + - 매칭된 적이 있다면, 페어를 조회한다. +4. 페어 초기화 + - 페어를 초기화한다. +5. 종료 + - 페어 매칭을 종료한다. + +# 기능 명세서 +- 기능을 선택한다. + - [X] 기능 입력받기 + - [X] 1 ~ 3, Q가 아닌 경우 예외 처리 +- 페어 매칭 + - [X] 파일 입출력 + - [X] 입력된 정보를 바탕으로 페어를 매칭한다. + - [X] 과정(백엔드/프론트엔드)와 레벨을 입력받는다. + - [X] 셔플 + - [X] 짝수로 나누어 페어를 매칭한다. + - [X] 마지막에 남은 사람이 3명이라면 그 팀은 3명이 팀이다. + - [X] 같은 레벨에서 이미 페어로 만난 적이 있다면, 다시 랜덤으로 섞는다. + - [X] 3회 시도까지 매칭이 되지 않거나 매칭되는 경우의 수가 없다면, 에러 처리 + - [X] 매칭된 결과를 출력한다. + - [X] 만약, 매칭이 되었는데 다시 1을 입력받는다면, 재 매칭 여부를 입력받는다. + - [X] 재 매칭 여부를 입력받는다. + - [X] 네, 아니오가 아닐 경우, 예외 발생 + - [X] 네일 경우, 다시 매칭한다. +- 페어 조회 + - [X] 매칭된 적이 없는 경우, 매칭 이력이 없다는 예외를 발생시키고 다시 입력 받는다. + - [X] 매칭된 적이 있다면, 페어를 조회한다. +- 페어 초기화 + - [X] 페어를 초기화한다. +- 종료 + - [X] 페어 매칭을 종료한다. \ No newline at end of file diff --git a/src/main/java/pairmatching/Application.java b/src/main/java/pairmatching/Application.java index 6f56e741c..d28479213 100644 --- a/src/main/java/pairmatching/Application.java +++ b/src/main/java/pairmatching/Application.java @@ -1,7 +1,12 @@ package pairmatching; +import pairmatching.controller.PairMatchingController; +import pairmatching.service.MatchingService; + public class Application { public static void main(String[] args) { - // TODO 구현 진행 + MatchingService matchingService = new MatchingService(); + PairMatchingController pairMatchingController = new PairMatchingController(matchingService); + pairMatchingController.run(); } } diff --git a/src/main/java/pairmatching/constants/ErrorMessage.java b/src/main/java/pairmatching/constants/ErrorMessage.java new file mode 100644 index 000000000..5aef846ed --- /dev/null +++ b/src/main/java/pairmatching/constants/ErrorMessage.java @@ -0,0 +1,25 @@ +package pairmatching.constants; + +public enum ErrorMessage { + INPUT_CHOICE_ERROR("1, 2, 3, Q 중에 입력해주세요."), + NO_MATCHING_ERROR("매칭 정보가 없습니다."), + INPUT_FORMAT_ERROR("입력 형식이 잘못되었습니다."), + INPUT_NO_VALUE("입력값이 없습니다."), + INVALID_POSITION_ERROR("백엔드, 프론트엔드 중에 입력해주세요."), + INVALID_LEVEL_ERROR(" 레벨1, 레벨2, 레벨3, 레벨4, 레벨5 중에 입력해주세요."), + INVALID_MISSION_ERROR("현재 %s은 미션을 지원하지 않습니다."), + INVALID_LEVEL_MISSION_ERROR("%s의 미션중에서 입력해주세요."), + INPUT_RETRY_ERROR("네, 아니오 중에 입력해주세요."), + MATCHING_ERROR("매칭에 실패하였습니다."), + FILE_READER_ERROR("파일을 읽을 수 없습니다."); + + private final String message; + + ErrorMessage(String message) { + this.message = message; + } + + public String getMessage() { + return "[ERROR] " + message; + } +} diff --git a/src/main/java/pairmatching/constants/FilePath.java b/src/main/java/pairmatching/constants/FilePath.java new file mode 100644 index 000000000..74890bc5d --- /dev/null +++ b/src/main/java/pairmatching/constants/FilePath.java @@ -0,0 +1,15 @@ +package pairmatching.constants; + +public enum FilePath { + FRONT_FILE_PATH("/Users/2sh/Desktop/java-pairmatching-precourse/src/main/resources/frontend-crew.md"), + BACK_FILE_PATH("/Users/2sh/Desktop/java-pairmatching-precourse/src/main/resources/backend-crew.md"); + private final String path; + + FilePath(String path) { + this.path = path; + } + + public String getPath() { + return path; + } +} diff --git a/src/main/java/pairmatching/constants/ProgressConstants.java b/src/main/java/pairmatching/constants/ProgressConstants.java new file mode 100644 index 000000000..5deb99b2e --- /dev/null +++ b/src/main/java/pairmatching/constants/ProgressConstants.java @@ -0,0 +1,19 @@ +package pairmatching.constants; + +public enum ProgressConstants { + PAIR_MATCHING("1"), + PAIR_SEARCH("2"), + PAIR_RESET("3"), + QUIT("Q"), + RETRY("네"), + NO_RETRY("아니오"); + private final String constName; + + ProgressConstants(String constName) { + this.constName = constName; + } + + public String getConstName() { + return constName; + } +} diff --git a/src/main/java/pairmatching/constants/ProgressMessage.java b/src/main/java/pairmatching/constants/ProgressMessage.java new file mode 100644 index 000000000..6ca7748e7 --- /dev/null +++ b/src/main/java/pairmatching/constants/ProgressMessage.java @@ -0,0 +1,32 @@ +package pairmatching.constants; + +public enum ProgressMessage { + START_CHOICE("기능을 선택하세요.\n1. 페어 매칭\n2. 페어 조회\n3. 페어 초기화\nQ. 종료"), + LINE("\n"), + COURSE_INFO("\n#############################################\n" + + "과정: 백엔드 | 프론트엔드\n" + + "미션:\n" + + " - 레벨1: 자동차경주 | 로또 | 숫자야구게임\n" + + " - 레벨2: 장바구니 | 결제 | 지하철노선도\n" + + " - 레벨3:\n" + + " - 레벨4: 성능개선 | 배포\n" + + " - 레벨5:\n" + + "############################################"), + RETRY_COURSE_CHECK("\n매칭 정보가 있습니다. 다시 매칭하시겠습니까?\n" + + "네 | 아니오"), + + CHOOSE_COURSE("과정, 레벨, 미션을 선택하세요.\n" + + "ex) 백엔드, 레벨1, 자동차경주\n" + + "프론트엔드, 레벨1, 자동차경주"), + PAIR_MATCHING_RESULT("\n페어 매칭 결과입니다."), + DELETE_MATCHING_RESULT("\n초기화 되었습니다.\n"); + private final String message; + + ProgressMessage(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } +} diff --git a/src/main/java/pairmatching/controller/PairMatchingController.java b/src/main/java/pairmatching/controller/PairMatchingController.java new file mode 100644 index 000000000..e32d07642 --- /dev/null +++ b/src/main/java/pairmatching/controller/PairMatchingController.java @@ -0,0 +1,149 @@ +package pairmatching.controller; + +import static pairmatching.constants.ErrorMessage.NO_MATCHING_ERROR; +import static pairmatching.constants.ProgressConstants.NO_RETRY; +import static pairmatching.constants.ProgressConstants.PAIR_MATCHING; +import static pairmatching.constants.ProgressConstants.PAIR_RESET; +import static pairmatching.constants.ProgressConstants.PAIR_SEARCH; +import static pairmatching.constants.ProgressConstants.QUIT; +import static pairmatching.constants.ProgressConstants.RETRY; +import static pairmatching.validator.InputChoiceValidator.validateInputChoice; +import static pairmatching.validator.InputCourseValidator.validateInputCourse; +import static pairmatching.validator.InputRetryValidator.validateInputRetry; +import static pairmatching.view.InputView.chooseFunction; +import static pairmatching.view.InputView.chooseRetryCourse; +import static pairmatching.view.InputView.inputRetryCheck; +import static pairmatching.view.OutputView.printErrorMessage; + +import pairmatching.domain.Course; +import pairmatching.service.MatchingService; +import pairmatching.view.InputView; +import pairmatching.view.OutputView; + +public class PairMatchingController { + private final MatchingService matchingService; + + public PairMatchingController(MatchingService matchingService) { + this.matchingService = matchingService; + } + + public void run() { + InputPeople(); + while (true) { + String choice = InputChoice(); + if (choice.equals(QUIT.getConstName())) { + break; + } + if (choice.equals(PAIR_MATCHING.getConstName())) { + pairMatching(); + } + if (choice.equals(PAIR_SEARCH.getConstName())) { + showMatchingHistory(); + } + if (choice.equals(PAIR_RESET.getConstName())) { + clearMatchingHistory(); + } + } + } + + private void InputPeople() { + matchingService.initPeople(); + } + + private String InputChoice() { + while (true) { + try { + return validateInputChoice(chooseFunction()); + } catch (IllegalArgumentException e) { + printErrorMessage(e.getMessage()); + } + } + } + + private Course InputCourse() { + while (true) { + try { + return validateInputCourse(InputView.chooseCourse()); + } catch (IllegalArgumentException e) { + printErrorMessage(e.getMessage()); + } + } + } + + private void pairMatching() { + Course course = InputCourse(); + chooseCourse(course); + } + + private void processRetryCourse(MatchingService matchingService, Course course) { + while (true) { + try { + String inputRetry = validateInputRetry(inputRetryCheck()); + if (inputRetry.equals(RETRY.getConstName())) { + matchingService.updatePairMatching(course); + showPairMatchingResult(course); + break; + } + if (inputRetry.equals(NO_RETRY.getConstName())) { + retryCourse(); + break; + } + } catch (IllegalArgumentException e) { + printErrorMessage(e.getMessage()); + } + } + } + + private void retryCourse() { + Course course = InputRetryCourse(); + chooseCourse(course); + } + + private void chooseCourse(Course course) { + boolean matchingHistoryByCourse = matchingService.findMatchingHistoryByCourse(course); + try { + if (!matchingHistoryByCourse) { + matchingService.pairMatching(course); + showPairMatchingResult(course); + } else { + processRetryCourse(matchingService, course); + } + } catch (IllegalArgumentException e) { + printErrorMessage(e.getMessage()); + } + } + + private Course InputRetryCourse() { + while (true) { + try { + return validateInputCourse(chooseRetryCourse()); + } catch (IllegalArgumentException e) { + printErrorMessage(e.getMessage()); + } + } + } + + private void showPairMatchingResult(Course course) { + OutputView.printMatchingResult(matchingService.pairMatchingResult(course)); + } + + private void showMatchingHistory() { + Course course = InputCourse(); + boolean matchingHistoryByCourse = matchingService.findMatchingHistoryByCourse(course); + + try { + if (matchingHistoryByCourse) { + OutputView.printMatchingResult(matchingService.pairMatchingResult(course)); + } else { + throw new IllegalArgumentException(NO_MATCHING_ERROR.getMessage()); + } + } catch (IllegalArgumentException e) { + printErrorMessage(e.getMessage()); + } + } + + private void clearMatchingHistory() { + matchingService.clearMatchingHistory(); + OutputView.printMatchingHistory(); + } +} diff --git a/src/main/java/pairmatching/domain/Course.java b/src/main/java/pairmatching/domain/Course.java new file mode 100644 index 000000000..cb649ace3 --- /dev/null +++ b/src/main/java/pairmatching/domain/Course.java @@ -0,0 +1,28 @@ +package pairmatching.domain; + +import pairmatching.domain.constants.Level; +import pairmatching.domain.constants.Position; + +public class Course { + private final Level level; + private final Position position; + private final String mission; + + public Course(Level level, Position position, String mission) { + this.level = level; + this.position = position; + this.mission = mission; + } + + public Position getPosition() { + return position; + } + + public Level getLevel() { + return level; + } + + public String getMission() { + return mission; + } +} diff --git a/src/main/java/pairmatching/domain/MatchingHistory.java b/src/main/java/pairmatching/domain/MatchingHistory.java new file mode 100644 index 000000000..0bdc64f0c --- /dev/null +++ b/src/main/java/pairmatching/domain/MatchingHistory.java @@ -0,0 +1,21 @@ +package pairmatching.domain; + +import java.util.List; + +public class MatchingHistory { + private Course course; + private List pair; + + public MatchingHistory(Course course, List pair) { + this.course = course; + this.pair = pair; + } + + public Course getCourse() { + return course; + } + + public List getPair() { + return pair; + } +} diff --git a/src/main/java/pairmatching/domain/Pair.java b/src/main/java/pairmatching/domain/Pair.java new file mode 100644 index 000000000..d330311cb --- /dev/null +++ b/src/main/java/pairmatching/domain/Pair.java @@ -0,0 +1,22 @@ +package pairmatching.domain; + +import java.util.ArrayList; +import java.util.List; + +public class Pair { + private List crews; + + public Pair(String one, String two) { + this.crews = new ArrayList<>(); + crews.add(one); + crews.add(two); + } + + public List getCrews() { + return crews; + } + + public void addCrew(String crew) { + this.crews.add(crew); + } +} diff --git a/src/main/java/pairmatching/domain/constants/Level.java b/src/main/java/pairmatching/domain/constants/Level.java new file mode 100644 index 000000000..a89115401 --- /dev/null +++ b/src/main/java/pairmatching/domain/constants/Level.java @@ -0,0 +1,28 @@ +package pairmatching.domain.constants; + +import java.util.Arrays; +import java.util.List; + +public enum Level { + LEVEL1("레벨1", Arrays.asList("자동차경주", "로또", "숫자야구게임")), + LEVEL2("레벨2", Arrays.asList("장바구니", "결제", "지하철노선도")), + LEVEL3("레벨3", null), + LEVEL4("레벨4", Arrays.asList("성능개선", "배포")), + LEVEL5("레벨5", null); + + private String name; + private List missions; + + Level(String name, List missions) { + this.name = name; + this.missions = missions; + } + + public String getName() { + return name; + } + + public List getMissions() { + return missions; + } +} \ No newline at end of file diff --git a/src/main/java/pairmatching/domain/constants/Position.java b/src/main/java/pairmatching/domain/constants/Position.java new file mode 100644 index 000000000..e06262f9a --- /dev/null +++ b/src/main/java/pairmatching/domain/constants/Position.java @@ -0,0 +1,16 @@ +package pairmatching.domain.constants; + +public enum Position { + BACKEND("백엔드"), + FRONTEND("프론트엔드"); + + private String position; + + Position(String position) { + this.position = position; + } + + public String getPosition() { + return position; + } +} diff --git a/src/main/java/pairmatching/repository/BackendRepository.java b/src/main/java/pairmatching/repository/BackendRepository.java new file mode 100644 index 000000000..c5c2b3980 --- /dev/null +++ b/src/main/java/pairmatching/repository/BackendRepository.java @@ -0,0 +1,22 @@ +package pairmatching.repository; + +import camp.nextstep.edu.missionutils.Randoms; +import java.util.ArrayList; +import java.util.List; + +public class BackendRepository { + private List backend; + + public BackendRepository() { + backend = new ArrayList<>(); + } + + public void save(List backend) { + this.backend = backend; + } + + public List getBackend() { + List shuffle = Randoms.shuffle(backend); + return shuffle; + } +} diff --git a/src/main/java/pairmatching/repository/FrontendRepository.java b/src/main/java/pairmatching/repository/FrontendRepository.java new file mode 100644 index 000000000..81c4feeeb --- /dev/null +++ b/src/main/java/pairmatching/repository/FrontendRepository.java @@ -0,0 +1,22 @@ +package pairmatching.repository; + +import camp.nextstep.edu.missionutils.Randoms; +import java.util.ArrayList; +import java.util.List; + +public class FrontendRepository { + private List frontend; + + public FrontendRepository() { + frontend = new ArrayList<>(); + } + + public void save(List frontend) { + this.frontend = frontend; + } + + public List getFrontend() { + List shuffle = Randoms.shuffle(frontend); + return shuffle; + } +} diff --git a/src/main/java/pairmatching/repository/MatchingHistoryRepository.java b/src/main/java/pairmatching/repository/MatchingHistoryRepository.java new file mode 100644 index 000000000..e94bc174a --- /dev/null +++ b/src/main/java/pairmatching/repository/MatchingHistoryRepository.java @@ -0,0 +1,48 @@ +package pairmatching.repository; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import pairmatching.domain.Course; +import pairmatching.domain.MatchingHistory; +import pairmatching.domain.constants.Level; + +public class MatchingHistoryRepository { + + Set matchingHistories = new HashSet<>(); + + public void deleteMatchingHistory(Course course) { + MatchingHistory matchingHistoryByCourse = findMatchingHistoryByCourse(course); + matchingHistories.remove(matchingHistoryByCourse); + } + + public void save(MatchingHistory matchingHistory) { + matchingHistories.add(matchingHistory); + } + + public MatchingHistory findMatchingHistoryByCourse(Course course) { + for (MatchingHistory matchingHistory : matchingHistories) { + if (matchingHistory.getCourse().getLevel().equals(course.getLevel()) && matchingHistory.getCourse() + .getPosition().equals(course.getPosition()) && matchingHistory.getCourse().getMission() + .equals(course.getMission())) { + return matchingHistory; + } + } + return null; + } + + public List findMatchingHistoryByLevel(Level level) { + List findMatchingHistories = new ArrayList<>(); + for (MatchingHistory matchingHistory : matchingHistories) { + if (matchingHistory.getCourse().getLevel().equals(level)) { + findMatchingHistories.add(matchingHistory); + } + } + return findMatchingHistories; + } + + public void clearMatchingHistory() { + matchingHistories.clear(); + } +} diff --git a/src/main/java/pairmatching/service/MatchingService.java b/src/main/java/pairmatching/service/MatchingService.java new file mode 100644 index 000000000..b06879f50 --- /dev/null +++ b/src/main/java/pairmatching/service/MatchingService.java @@ -0,0 +1,143 @@ +package pairmatching.service; + +import static pairmatching.constants.ErrorMessage.MATCHING_ERROR; +import static pairmatching.constants.FilePath.BACK_FILE_PATH; +import static pairmatching.constants.FilePath.FRONT_FILE_PATH; +import static pairmatching.domain.constants.Position.BACKEND; +import static pairmatching.domain.constants.Position.FRONTEND; + +import java.util.ArrayList; +import java.util.List; +import pairmatching.domain.Course; +import pairmatching.domain.MatchingHistory; +import pairmatching.domain.Pair; +import pairmatching.domain.constants.Position; +import pairmatching.repository.BackendRepository; +import pairmatching.repository.FrontendRepository; +import pairmatching.repository.MatchingHistoryRepository; +import pairmatching.utils.Reader; + +public class MatchingService { + private static final int ZERO = 0; + private static final int MAX_MATCHING_COUNT = 3; + private static final int MIN_PAIR_COUNT = 2; + private static final int MAX_PAIR_COUNT = 3; + private final FrontendRepository frontendRepository; + private final BackendRepository backendRepository; + private final MatchingHistoryRepository matchingHistoryRepository; + + + public MatchingService() { + this.frontendRepository = new FrontendRepository(); + this.backendRepository = new BackendRepository(); + this.matchingHistoryRepository = new MatchingHistoryRepository(); + } + + public void initPeople() { + List Frontend = Reader.readFile(FRONT_FILE_PATH.getPath()); + frontendRepository.save(Frontend); + List Backend = Reader.readFile(BACK_FILE_PATH.getPath()); + backendRepository.save(Backend); + } + + public boolean findMatchingHistoryByCourse(Course course) { + MatchingHistory matchingHistoryByCourse = matchingHistoryRepository.findMatchingHistoryByCourse(course); + if (matchingHistoryByCourse == null) { + return false; + } + return true; + } + + public void pairMatching(Course course) { + Position position = course.getPosition(); + if (position.equals(FRONTEND)) { + frontendMatching(course); + } + if (position.equals(BACKEND)) { + backendMatching(course); + } + } + + private void frontendMatching(Course course) { + List pairs = new ArrayList<>(); + int count = ZERO; + do { + if ((count++) == MAX_MATCHING_COUNT) { + throw new IllegalArgumentException(MATCHING_ERROR.getMessage()); + } + pairs.clear(); + List frontend = frontendRepository.getFrontend(); + pairs = matching(frontend); + } while (isMatched(course, pairs)); + matchingHistoryRepository.save(new MatchingHistory(course, pairs)); + } + + private void backendMatching(Course course) { + List pairs = new ArrayList<>(); + int count = ZERO; + do { + if ((count++) == MAX_MATCHING_COUNT) { + throw new IllegalArgumentException(MATCHING_ERROR.getMessage()); + } + pairs.clear(); + List backend = backendRepository.getBackend(); + pairs = matching(backend); + } while (isMatched(course, pairs)); + matchingHistoryRepository.save(new MatchingHistory(course, pairs)); + } + + private List matching(List pairByPosition) { + List pairs = new ArrayList<>(); + for (int i = 0; i < pairByPosition.size() - 1; i += 2) { + Pair pair = new Pair(pairByPosition.get(i), pairByPosition.get(i + 1)); + pairs.add(pair); + } + if (pairByPosition.size() % 2 == 1) { + int lastIndex = pairs.size() - 1; + pairs.get(lastIndex).addCrew(pairByPosition.get(pairByPosition.size() - 1)); + } + return pairs; + } + + + private boolean isMatched(Course course, List pairs) { + List matchingHistoryByLevel = matchingHistoryRepository.findMatchingHistoryByLevel( + course.getLevel()); + for (MatchingHistory matchingHistory : matchingHistoryByLevel) { + List pairHistory = matchingHistory.getPair(); + if (isSamePair(pairs, pairHistory)) { + return true; + } + } + return false; + } + + private boolean isSamePair(List pairs, List pairHistory) { + return pairHistory.stream() + .anyMatch(storedPair -> pairs.stream() + .anyMatch(pair -> isSameCrews(storedPair.getCrews(), pair.getCrews()))); + } + + private boolean isSameCrews(List crewsHistory, List crews) { + long count = crewsHistory.stream() + .filter(crews::contains) + .count(); + + return count == MIN_PAIR_COUNT || count == MAX_PAIR_COUNT; + } + + + public List pairMatchingResult(Course course) { + MatchingHistory matchingHistoryByCourse = matchingHistoryRepository.findMatchingHistoryByCourse(course); + return matchingHistoryByCourse.getPair(); + } + + public void updatePairMatching(Course course) { + matchingHistoryRepository.deleteMatchingHistory(course); + pairMatching(course); + } + + public void clearMatchingHistory() { + matchingHistoryRepository.clearMatchingHistory(); + } +} diff --git a/src/main/java/pairmatching/utils/Reader.java b/src/main/java/pairmatching/utils/Reader.java new file mode 100644 index 000000000..e2092c882 --- /dev/null +++ b/src/main/java/pairmatching/utils/Reader.java @@ -0,0 +1,25 @@ +package pairmatching.utils; + +import static pairmatching.constants.ErrorMessage.FILE_READER_ERROR; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class Reader { + + public static List readFile(String filePath) { + List lines = new ArrayList<>(); + try (BufferedReader br = new BufferedReader(new FileReader(filePath))) { + String line; + while ((line = br.readLine()) != null) { + lines.add(line); + } + } catch (IOException e) { + throw new IllegalArgumentException(FILE_READER_ERROR.getMessage()); + } + return lines; + } +} diff --git a/src/main/java/pairmatching/validator/InputChoiceValidator.java b/src/main/java/pairmatching/validator/InputChoiceValidator.java new file mode 100644 index 000000000..b191d6fb7 --- /dev/null +++ b/src/main/java/pairmatching/validator/InputChoiceValidator.java @@ -0,0 +1,19 @@ +package pairmatching.validator; + +import static pairmatching.constants.ErrorMessage.INPUT_CHOICE_ERROR; +import static pairmatching.constants.ProgressConstants.PAIR_MATCHING; +import static pairmatching.constants.ProgressConstants.PAIR_RESET; +import static pairmatching.constants.ProgressConstants.PAIR_SEARCH; +import static pairmatching.constants.ProgressConstants.QUIT; + +public class InputChoiceValidator { + + public static String validateInputChoice(String choice) { + if (!choice.equals(PAIR_MATCHING.getConstName()) && !choice.equals(PAIR_SEARCH.getConstName()) + && !choice.equals( + PAIR_RESET.getConstName()) && !choice.equals(QUIT.getConstName())) { + throw new IllegalArgumentException(INPUT_CHOICE_ERROR.getMessage()); + } + return choice; + } +} diff --git a/src/main/java/pairmatching/validator/InputCourseValidator.java b/src/main/java/pairmatching/validator/InputCourseValidator.java new file mode 100644 index 000000000..c9efcac78 --- /dev/null +++ b/src/main/java/pairmatching/validator/InputCourseValidator.java @@ -0,0 +1,65 @@ +package pairmatching.validator; + +import static pairmatching.constants.ErrorMessage.INPUT_FORMAT_ERROR; +import static pairmatching.constants.ErrorMessage.INPUT_NO_VALUE; +import static pairmatching.constants.ErrorMessage.INVALID_LEVEL_ERROR; +import static pairmatching.constants.ErrorMessage.INVALID_LEVEL_MISSION_ERROR; +import static pairmatching.constants.ErrorMessage.INVALID_MISSION_ERROR; +import static pairmatching.constants.ErrorMessage.INVALID_POSITION_ERROR; + +import pairmatching.domain.Course; +import pairmatching.domain.constants.Level; +import pairmatching.domain.constants.Position; + +public class InputCourseValidator { + public static Course validateInputCourse(String inputCourse) { + validateInput(inputCourse); + String[] parts = inputCourse.split(", "); + + if (parts.length != 3) { + throw new IllegalArgumentException(INPUT_FORMAT_ERROR.getMessage()); + } + + Position position = validatePosition(parts[0]); + Level level = validateLevel(parts[1]); + String mission = validateMission(level, parts[2]); + return new Course(level, position, mission); + } + + private static void validateInput(String course) { + if (course == null || course.isEmpty()) { + throw new IllegalArgumentException(INPUT_NO_VALUE.getMessage()); + } + } + + private static Position validatePosition(String part) { + for (Position position : Position.values()) { + if (position.getPosition().equals(part)) { + return position; + } + } + throw new IllegalArgumentException(INVALID_POSITION_ERROR.getMessage()); + } + + private static Level validateLevel(String part) { + for (Level level : Level.values()) { + if (level.getName().equals(part)) { + return level; + } + } + throw new IllegalArgumentException(INVALID_LEVEL_ERROR.getMessage()); + } + + private static String validateMission(Level level, String part) { + if (level.getMissions() == null) { + throw new IllegalArgumentException(String.format(INVALID_MISSION_ERROR.getMessage(), level.getName())); + } + for (String mission : level.getMissions()) { + if (mission.equals(part)) { + return mission; + } + } + throw new IllegalArgumentException(String.format(INVALID_LEVEL_MISSION_ERROR.getMessage(), level.getName())); + } + +} diff --git a/src/main/java/pairmatching/validator/InputRetryValidator.java b/src/main/java/pairmatching/validator/InputRetryValidator.java new file mode 100644 index 000000000..1db5cd4f2 --- /dev/null +++ b/src/main/java/pairmatching/validator/InputRetryValidator.java @@ -0,0 +1,15 @@ +package pairmatching.validator; + +import static pairmatching.constants.ErrorMessage.INPUT_RETRY_ERROR; +import static pairmatching.constants.ProgressConstants.NO_RETRY; +import static pairmatching.constants.ProgressConstants.RETRY; + +public class InputRetryValidator { + + public static String validateInputRetry(String retry) { + if (!retry.equals(RETRY.getConstName()) && !retry.equals(NO_RETRY.getConstName())) { + throw new IllegalArgumentException(INPUT_RETRY_ERROR.getMessage()); + } + return retry; + } +} diff --git a/src/main/java/pairmatching/view/InputView.java b/src/main/java/pairmatching/view/InputView.java new file mode 100644 index 000000000..d9d43ba98 --- /dev/null +++ b/src/main/java/pairmatching/view/InputView.java @@ -0,0 +1,32 @@ +package pairmatching.view; + +import static pairmatching.constants.ProgressMessage.CHOOSE_COURSE; +import static pairmatching.constants.ProgressMessage.COURSE_INFO; +import static pairmatching.constants.ProgressMessage.RETRY_COURSE_CHECK; +import static pairmatching.constants.ProgressMessage.START_CHOICE; +import static pairmatching.view.common.Printer.printer; + +import camp.nextstep.edu.missionutils.Console; + +public class InputView { + public static String chooseFunction() { + printer(START_CHOICE.getMessage()); + return Console.readLine(); + } + + public static String chooseCourse() { + printer(COURSE_INFO.getMessage()); + printer(CHOOSE_COURSE.getMessage()); + return Console.readLine(); + } + + public static String chooseRetryCourse(){ + printer(CHOOSE_COURSE.getMessage()); + return Console.readLine(); + } + + public static String inputRetryCheck() { + printer(RETRY_COURSE_CHECK.getMessage()); + return Console.readLine(); + } +} diff --git a/src/main/java/pairmatching/view/OutputView.java b/src/main/java/pairmatching/view/OutputView.java new file mode 100644 index 000000000..46afb5269 --- /dev/null +++ b/src/main/java/pairmatching/view/OutputView.java @@ -0,0 +1,29 @@ +package pairmatching.view; + +import static pairmatching.constants.ProgressMessage.DELETE_MATCHING_RESULT; +import static pairmatching.constants.ProgressMessage.LINE; +import static pairmatching.constants.ProgressMessage.PAIR_MATCHING_RESULT; +import static pairmatching.view.common.Printer.printer; + +import java.util.List; +import pairmatching.domain.Pair; + +public class OutputView { + public static void printErrorMessage(String message) { + printer(message + LINE.getMessage()); + } + + public static void printMatchingResult(List pairMatchingResult) { + printer(PAIR_MATCHING_RESULT.getMessage()); + for (Pair pair : pairMatchingResult) { + List crews = pair.getCrews(); + String formattedOutput = String.join(" : ", crews); + printer(formattedOutput); + } + printer(LINE.getMessage()); + } + + public static void printMatchingHistory() { + printer(DELETE_MATCHING_RESULT.getMessage()); + } +} diff --git a/src/main/java/pairmatching/view/common/Printer.java b/src/main/java/pairmatching/view/common/Printer.java new file mode 100644 index 000000000..1b7f23ee4 --- /dev/null +++ b/src/main/java/pairmatching/view/common/Printer.java @@ -0,0 +1,7 @@ +package pairmatching.view.common; + +public class Printer { + public static void printer(String message) { + System.out.println(message); + } +}