Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ 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)
}
}

test {
useJUnitPlatform()
}
}
15 changes: 15 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# 페어 매칭

## 기능 목록

1. 페어 매칭
- 과정과 미션 목록을 출력해 준다.
- 매칭하고자 하는 과정, 레벨, 미션을 입력 받는다.
- 이미 매칭한 내역이 있다면 다시 매칭을 할지 질문한다.
- 다시 매칭하지 않을 경우 과정, 레벨, 미션을 다시 입력 받는다.
- 매칭이 정상적으로 수행되면 결과가 출력된다.
- 같은 레벨동안은 여러 미션동안 같은 페어를 만나지 않는다.
2. 페어 조회
- 과정, 레벨, 미션을 선택하면 해당 미션의 페어 정보를 출력한다.
- 매칭 이력이 없으면 매칭 이력이 없다고 안내한다.
3. 페어 초기화
24 changes: 24 additions & 0 deletions docs/고민.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# 고민

## 중복된 매칭

결국 관건은 어떻게 같은 레벨에서 한번 만났던 페어인지 판별하는 것일 듯 하다.
매칭 정보를 단순히 가지고 있는 것 뿐 아니라, 재매칭의 경우 이전 매칭을 업데이트 해 주는 것 까지 생각해 주어야 한다.

그렇다면 해당 정보의 계층 구조는 아래와 같으려나

- 파트
- 레벨 정보
- 미션 정보
- 크루 페어


페어매칭 흐름

1. 과정, 레벨, 미션을 통해 해당 미션의 페어 매칭 기록이 존재하는지 확인한다.
1. 존재하지 않는다면 바로 매칭을 시작
2. 존재한다면 재매칭 할지 질의

-> 즉 정보는 과정 > 레벨 > 미션 하위에 매칭 결과가 저장되어야 하는 구조라고 생각된다.

미션까지를 다 만들어 두고...
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
34 changes: 33 additions & 1 deletion src/main/java/pairmatching/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,39 @@
package pairmatching;

import pairmatching.controller.MatchingController;
import pairmatching.view.InputView;
import pairmatching.view.OutputView;

public class Application {
private static final MatchingController matchingController = new MatchingController();
private static final InputView inputView = new InputView();
private static final OutputView outputView = new OutputView();


public static void main(String[] args) {
// TODO 구현 진행
String menu;
do {
menu = inputView.getMenu();
if (menu.equals("1")) {
handle(matchingController::createPair);
}
if (menu.equals("2")) {
handle(matchingController::readPair);
}
if (menu.equals("3")) {
handle(matchingController::resetPair);
}

} while (!menu.equals("Q"));
}

private static void handle(Runnable runnable){
try{
runnable.run();
} catch (IllegalArgumentException e){
outputView.printErrorMessage(e);
} finally {
outputView.newLine();
}
}
}
51 changes: 51 additions & 0 deletions src/main/java/pairmatching/controller/MatchingController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package pairmatching.controller;

import java.util.Set;
import pairmatching.domain.MatchingService;
import pairmatching.domain.Pair;
import pairmatching.domain.ShuffleCrewMatcher;
import pairmatching.dto.MissionDto;
import pairmatching.view.InputView;
import pairmatching.view.OutputView;

public class MatchingController {
private static final MatchingService matchingService = new MatchingService(new ShuffleCrewMatcher());
private static final InputView inputView = new InputView();
private static final OutputView outputView = new OutputView();

public MatchingController (){
resetPair();
}

public void createPair(){
inputView.pairMatchingView();
while(true){
MissionDto missionDto = inputView.getMissionDto();
if(matchingService.isMatched(missionDto)){
if(!inputView.reMatching()){
matchingService.removeHistory(missionDto);
continue;
}
}

//매칭 정보가 없다면
Set<Pair> pairs = matchingService.matching(missionDto);
outputView.printMatchingResult(pairs);

return;
}
}

public void readPair(){
MissionDto missionDto = inputView.getMissionDto();
if(matchingService.isMatched(missionDto)){
outputView.printMatchingResult(matchingService.getResult(missionDto));
return;
}
throw new IllegalArgumentException("매칭 이력이 없습니다.");
}

public void resetPair(){
matchingService.reset();
}
}
12 changes: 12 additions & 0 deletions src/main/java/pairmatching/domain/CrewMatcher.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package pairmatching.domain;

import camp.nextstep.edu.missionutils.Randoms;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;

public abstract class CrewMatcher {
abstract public Set<Pair> matching(List<String> crewName);
}
55 changes: 55 additions & 0 deletions src/main/java/pairmatching/domain/MatchingService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package pairmatching.domain;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import pairmatching.dto.MissionDto;
import pairmatching.repository.CrewRepository;
import pairmatching.repository.matching.MatchingHistory;

public class MatchingService {

private static MatchingHistory matchingHistory = new MatchingHistory();
private static final CrewRepository crewRepository = new CrewRepository();
private final CrewMatcher crewMatcher;

public MatchingService(CrewMatcher crewMatcher) {
this.crewMatcher = crewMatcher;
}

public boolean isMatched(MissionDto missionDto) {
return matchingHistory.isMatched(missionDto);
}

public Set<Pair> matching(MissionDto dto){
List<String> crewName = new ArrayList<>();

if (dto.getCourse().equals("백엔드")) {
crewName = crewRepository.getBackendCrewName();
}
if (dto.getCourse().equals("프론트엔드")) {
crewName = crewRepository.getFrontendCrewNames();
}
for(int i = 0; i<3; i++){
Set<Pair> pairs = crewMatcher.matching(crewName);
if(!matchingHistory.isDuplicated(dto, pairs)){
matchingHistory.save(dto, pairs);
return pairs;
}
}

throw new IllegalArgumentException("매칭에 실패했습니다.");
}

public void removeHistory(MissionDto missionDto) {
matchingHistory.removeHistory(missionDto);
}

public Set<Pair> getResult(MissionDto missionDto) {
return matchingHistory.getResult(missionDto);
}

public void reset() {
matchingHistory = new MatchingHistory();
}
}
58 changes: 58 additions & 0 deletions src/main/java/pairmatching/domain/Pair.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package pairmatching.domain;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

public class Pair {
private final List<String> crews;

public Pair(String... names){
crews = Arrays.stream(names)
.toList();
}

public Pair(Collection collection){
crews = new ArrayList<>(collection);
}

public List<String> getCrews() {
return crews;
}

public boolean isContains(String crewName){
return crews.contains(crewName);
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Pair pair = (Pair) o;
return crews.size() == pair.crews.size()
&& pair.crews.containsAll(crews);
}

@Override
public int hashCode() {
return Objects.hash(crews);
}

@Override
public String toString() {
return "Pair{" +
"crews=" + String.join(" : ", crews.stream()
.toList()) +
'}';
}
}
23 changes: 23 additions & 0 deletions src/main/java/pairmatching/domain/ShuffleCrewMatcher.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package pairmatching.domain;

import camp.nextstep.edu.missionutils.Randoms;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;

public class ShuffleCrewMatcher extends CrewMatcher {

@Override
public Set<Pair> matching(List<String> crewName) {
Queue<String> shuffledName = new LinkedList<>(Randoms.shuffle(crewName));
Set<Pair> pairs = new HashSet<>();
while (shuffledName.size() > 3) {
pairs.add(new Pair(shuffledName.poll(), shuffledName.poll()));
}
pairs.add(new Pair(shuffledName));

return pairs;
}
}
74 changes: 74 additions & 0 deletions src/main/java/pairmatching/dto/MissionDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package pairmatching.dto;

import java.util.HashMap;
import java.util.List;

public class MissionDto {
private static final HashMap<String, List<String>> missionMap = new HashMap<>();
static {
missionMap.put("레벨1", List.of("자동차경주","로또","숫자야구게임"));
missionMap.put("레벨2", List.of("장바구니","결제","지하철노선도"));
missionMap.put("레벨3", List.of());
missionMap.put("레벨4", List.of("성능개선","배포"));
missionMap.put("레벨5", List.of());
}
private final String course;
private final int level;
private final String mission;

private MissionDto(String course, String level, String mission) {
this.course = course;
this.level = Integer.parseInt(level.replace("레벨", ""));
this.mission = mission;
}

public static MissionDto from(List<String> input){
validateInput(input);
return new MissionDto(input.get(0), input.get(1), input.get(2));
}

private static void validateInput(List<String> input) {
if(input.size() != 3){
throw new IllegalArgumentException("입력 형식이 잘못되었습니다");
}

validateCourse(input.get(0));
validateLevel(input.get(1));
validateMission(input);
}


private static void validateCourse(String course) {
if (course.equals("백엔드") || course.equals("프론트엔드")) {
return;
}
throw new IllegalArgumentException("존재하지 않는 과정입니다.");
}

private static void validateLevel(String level) {
if(level.matches("레벨+[1-5]")){
return;
}
throw new IllegalArgumentException("존재하지 않는 레벨입니다.");
}

private static void validateMission(List<String> input) {
if (missionMap.get(input.get(1)).contains(input.get(2))) {
return;
}

throw new IllegalArgumentException("존재하지 않는 미션입니다.");
}

public String getCourse() {
return course;
}

public int getLevel() {
return level;
}

public String getMission() {
return mission;
}
}
Loading