From e8d4ae1cef056117313da0d7bb5d390386281d9d Mon Sep 17 00:00:00 2001 From: Rimi Date: Thu, 23 Jan 2025 02:34:36 +0900 Subject: [PATCH 01/28] =?UTF-8?q?:sparkles:=20[Feat]=20=EB=A7=A4=EC=B9=AD?= =?UTF-8?q?=20API=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EA=B5=AC=EC=A1=B0=20?= =?UTF-8?q?=EC=84=A4=EA=B3=84=20=EB=B0=8F=20=EA=B3=84=EC=82=B0=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controller/MatchingController.java | 31 +++++ .../service/MatchingFacadeService.java | 14 +++ .../MatchingPriorityCalculateService.java | 12 ++ .../MatchingPriorityEvaluateService.java | 107 ++++++++++++++++++ .../matching/service/MatchingService.java | 12 ++ 5 files changed, 176 insertions(+) create mode 100644 src/main/java/com/gamegoo/gamegoo_v2/matching/Controller/MatchingController.java create mode 100644 src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityCalculateService.java create mode 100644 src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityEvaluateService.java create mode 100644 src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/Controller/MatchingController.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/Controller/MatchingController.java new file mode 100644 index 00000000..d354efee --- /dev/null +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/Controller/MatchingController.java @@ -0,0 +1,31 @@ +package com.gamegoo.gamegoo_v2.matching.Controller; + +import com.gamegoo.gamegoo_v2.account.auth.annotation.AuthMember; +import com.gamegoo.gamegoo_v2.account.member.domain.Member; +import com.gamegoo.gamegoo_v2.core.common.ApiResponse; +import com.gamegoo.gamegoo_v2.matching.service.MatchingFacadeService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "Matching", description = "매칭 정보 관련 API") +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v2/internal/matching") +@Validated +public class MatchingController { + + private final MatchingFacadeService matchingFacadeService; + + @Operation(summary = "매칭 우선순위 계산 및 기록 저장 API", description = "API for calculating priority score and recording " + + "matchign") + @GetMapping + public ApiResponse getMemberJWT(@AuthMember Member member) { + return ApiResponse.ok(matchingFacadeService.calculatePriorityAndRecording()); + } + +} diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingFacadeService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingFacadeService.java index 107d6502..c24a07a4 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingFacadeService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingFacadeService.java @@ -24,6 +24,20 @@ public class MatchingFacadeService { private final MemberValidator memberValidator; private final BlockValidator blockValidator; + /** + * 매칭 우선순위 계산 및 기록 저장 API + */ + @Transactional + public String calculatePriorityAndRecording() { + // 현재 매칭 중인 matchingRecord 조회 + + // 내 매칭 기록 생성 + + // + + return "response DTO 변경 예정"; + } + /** * 두 회원 사이 매칭을 통한 채팅방 시작 Facade 메소드 * diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityCalculateService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityCalculateService.java new file mode 100644 index 00000000..c6a86b16 --- /dev/null +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityCalculateService.java @@ -0,0 +1,12 @@ +package com.gamegoo.gamegoo_v2.matching.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class MatchingPriorityCalculateService { + +} diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityEvaluateService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityEvaluateService.java new file mode 100644 index 00000000..6668d7f8 --- /dev/null +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityEvaluateService.java @@ -0,0 +1,107 @@ +package com.gamegoo.gamegoo_v2.matching.service; + +import com.gamegoo.gamegoo_v2.account.member.domain.Position; +import com.gamegoo.gamegoo_v2.account.member.domain.Tier; +import com.gamegoo.gamegoo_v2.account.member.domain.Mike; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class MatchingPriorityEvaluateService { + + /** + * 매너레벨 점수 계산 + */ + public int getMannerPriority(Integer otherManner, Integer myManner, int maxMannerPriority, + int mannerDifferenceMultiplier) { + int mannerDifference = Math.abs(myManner - otherManner); + return maxMannerPriority - mannerDifference * mannerDifferenceMultiplier; + } + + /** + * 랭킹 우선순위 점수 점수 계산 + * + * @param myTier 내 티어 + * @param myRank 내 랭크 + * @param otherTier 타겟 티어 + * @param otherRank 타겟 랭크 + * @param maxTierRankPriority 최대 점수 + * @param tierMultiplier 티어 점수 + * @param maxRankScore 랭크 점수 + * @return 랭킹 우선순위 값 + */ + public int getTierRankPriority(Tier myTier, Integer myRank, Tier otherTier, Integer otherRank, + int maxTierRankPriority, int tierMultiplier, int maxRankScore) { + int myScore = getTierRankScore(myTier, myRank, tierMultiplier, maxRankScore); + int otherScore = getTierRankScore(otherTier, otherRank, tierMultiplier, maxRankScore); + int scoreDifference = Math.abs(myScore - otherScore); + + return maxTierRankPriority - scoreDifference; + } + + /** + * 티어, 랭크 점수 계산 + * + * @param tier 티어 + * @param rank 랭크 + * @param tierMultiplier 티어 점수 + * @param maxRankScore 랭크 점수 + * @return 랭킹 점수 + */ + private int getTierRankScore(Tier tier, int rank, int tierMultiplier, int maxRankScore) { + return tier.ordinal() * tierMultiplier + (maxRankScore - rank); + } + + /** + * 포지션 우선순위 점수 계산 + * + * @param myWantPosition 내 주포지션 + * @param otherMainPosition 타겟 주포지션 + * @param otherSubPosition 타겟 부포지션 + * @param mainPositionPriority 높은 추가 점수 + * @param subPositionPriority 중간 추가 점수 + * @param defaultPositionPriority 낮은 추가 점수 + * @return 포지션 우선순위 점수 + */ + public int getPositionPriority(Position myWantPosition, Position otherMainPosition, Position otherSubPosition, + int mainPositionPriority, int subPositionPriority, int defaultPositionPriority) { + int priority = 0; + + if (myWantPosition == otherMainPosition || myWantPosition == Position.ANY || otherMainPosition == Position.ANY) { + priority += mainPositionPriority; + } else if (myWantPosition == otherSubPosition || otherSubPosition == Position.ANY) { + priority += subPositionPriority; + } else { + priority += defaultPositionPriority; + } + + return priority; + } + + /** + * 마이크 우선순위 점수 계산 + * + * @param myMike 내 마이크 + * @param otherMike 타겟 마이크 + * @param mikeMatchPriority 마이크 점수 + * @param mikePartialMatchPriority 마이크 부분 점수 + * @return 마이크 우선순위 점수 + */ + public int getMikePriority(Mike myMike, Mike otherMike, int mikeMatchPriority, int mikePartialMatchPriority) { + if (myMike == Mike.UNAVAILABLE && otherMike == Mike.UNAVAILABLE) { + return mikeMatchPriority; + } + if (myMike == Mike.AVAILABLE && otherMike == Mike.AVAILABLE) { + return mikeMatchPriority; + } + if ((myMike == Mike.AVAILABLE && otherMike == Mike.ONLY_LISTEN) || + (myMike == Mike.ONLY_LISTEN && otherMike == Mike.AVAILABLE)) { + return mikePartialMatchPriority; + } + return 0; + } + +} diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java new file mode 100644 index 00000000..4334c6e4 --- /dev/null +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java @@ -0,0 +1,12 @@ +package com.gamegoo.gamegoo_v2.matching.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class MatchingService { + +} From c56a307b101737c472dcf04a40335c3e95b219f2 Mon Sep 17 00:00:00 2001 From: Rimi Date: Thu, 23 Jan 2025 02:56:16 +0900 Subject: [PATCH 02/28] =?UTF-8?q?:sparkles:=20[Feat]=20=EA=B0=81=20?= =?UTF-8?q?=EA=B2=8C=EC=9E=84=EB=AA=A8=EB=93=9C=EB=A7=88=EB=8B=A4=20?= =?UTF-8?q?=EB=8B=AC=EB=9D=BC=EC=A7=80=EB=8A=94=20=EA=B3=84=EC=82=B0?= =?UTF-8?q?=EC=9D=84=20=EA=B5=AC=ED=98=84,=20=20MatchingPriorityCalculateS?= =?UTF-8?q?ervice?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MatchingPriorityCalculateService.java | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityCalculateService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityCalculateService.java index c6a86b16..7ffc3f77 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityCalculateService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityCalculateService.java @@ -1,5 +1,8 @@ package com.gamegoo.gamegoo_v2.matching.service; +import com.gamegoo.gamegoo_v2.account.member.domain.Mike; +import com.gamegoo.gamegoo_v2.account.member.domain.Position; +import com.gamegoo.gamegoo_v2.account.member.domain.Tier; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -9,4 +12,104 @@ @Transactional(readOnly = true) public class MatchingPriorityCalculateService { + private final MatchingPriorityEvaluateService matchingPriorityEvaluateService; + + /** + * FAST 모드 우선순위 계산 + */ + public int calculateFastPriority(Position myWantPosition, Position otherMainPosition, Position otherSubPosition, + Mike myMike, Mike otherMike, Integer myManner, Integer otherManner, + Tier myTier, Integer myRank, Tier otherTier, Integer otherRank) { + int priority = 0; + + // 포지션 우선순위 + priority += matchingPriorityEvaluateService.getPositionPriority(myWantPosition, otherMainPosition, + otherSubPosition, 5, 3, 1); + + // 마이크 우선순위 + priority += matchingPriorityEvaluateService.getMikePriority(myMike, otherMike, 5, 3); + + // 매너 우선순위 + priority += matchingPriorityEvaluateService.getMannerPriority(otherManner, myManner, 10, 2); + + // 티어 및 랭킹 우선순위 + priority += matchingPriorityEvaluateService.getTierRankPriority(myTier, myRank, otherTier, otherRank, 50, 5, + 10); + + return priority; + } + + /** + * SOLO 모드 우선순위 계산 + */ + public int calculateSoloPriority(Position myWantPosition, Position otherMainPosition, Position otherSubPosition, + Mike myMike, Mike otherMike, Integer myManner, Integer otherManner, + Tier myTier, Integer myRank, Tier otherTier, Integer otherRank) { + int priority = 0; + + // 포지션 우선순위 + priority += matchingPriorityEvaluateService.getPositionPriority(myWantPosition, otherMainPosition, + otherSubPosition, 8, 4, 2); + + // 마이크 우선순위 + priority += matchingPriorityEvaluateService.getMikePriority(myMike, otherMike, 4, 2); + + // 매너 우선순위 + priority += matchingPriorityEvaluateService.getMannerPriority(otherManner, myManner, 15, 3); + + // 티어 및 랭킹 우선순위 + priority += matchingPriorityEvaluateService.getTierRankPriority(myTier, myRank, otherTier, otherRank, 60, 6, + 12); + + return priority; + } + + /** + * FREE 모드 우선순위 계산 + */ + public int calculateFreePriority(Position myWantPosition, Position otherMainPosition, Position otherSubPosition, + Mike myMike, Mike otherMike, Integer myManner, Integer otherManner, + Tier myTier, Integer myRank, Tier otherTier, Integer otherRank) { + int priority = 0; + + // 포지션 우선순위 + priority += matchingPriorityEvaluateService.getPositionPriority(myWantPosition, otherMainPosition, + otherSubPosition, 6, 3, 1); + + // 마이크 우선순위 + priority += matchingPriorityEvaluateService.getMikePriority(myMike, otherMike, 6, 4); + + // 매너 우선순위 + priority += matchingPriorityEvaluateService.getMannerPriority(otherManner, myManner, 12, 2); + + // 티어 및 랭킹 우선순위 + priority += matchingPriorityEvaluateService.getTierRankPriority(myTier, myRank, otherTier, otherRank, 45, 4, 9); + + return priority; + } + + /** + * ARAM 모드 우선순위 계산 + */ + public int calculateAramPriority(Position myWantPosition, Position otherMainPosition, Position otherSubPosition, + Mike myMike, Mike otherMike, Integer myManner, Integer otherManner, + Tier myTier, Integer myRank, Tier otherTier, Integer otherRank) { + int priority = 0; + + // 포지션 우선순위 + priority += matchingPriorityEvaluateService.getPositionPriority(myWantPosition, otherMainPosition, + otherSubPosition, 4, 2, 1); + + // 마이크 우선순위 + priority += matchingPriorityEvaluateService.getMikePriority(myMike, otherMike, 3, 2); + + // 매너 우선순위 + priority += matchingPriorityEvaluateService.getMannerPriority(otherManner, myManner, 8, 1); + + // 티어 및 랭킹 우선순위 + priority += matchingPriorityEvaluateService.getTierRankPriority(myTier, myRank, otherTier, otherRank, 30, 3, 6); + + return priority; + } + } From 374883e7b87d3ec3d26d32ba7f7faaee403adc2d Mon Sep 17 00:00:00 2001 From: Rimi Date: Fri, 24 Jan 2025 03:28:47 +0900 Subject: [PATCH 03/28] =?UTF-8?q?:sparkles:=20[Feat]=20Mike=20ENUM=20?= =?UTF-8?q?=EA=B0=92=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F,=20=EB=A7=A4?= =?UTF-8?q?=EC=B9=AD=20=EC=9A=B0=EC=84=A0=EC=88=9C=EC=9C=84=20=EA=B3=84?= =?UTF-8?q?=EC=82=B0=20=EB=A1=9C=EC=A7=81=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../account/member/domain/Mike.java | 1 - .../MatchingPriorityCalculateService.java | 117 ++++++++++++------ .../MatchingPriorityEvaluateService.java | 4 - 3 files changed, 76 insertions(+), 46 deletions(-) diff --git a/src/main/java/com/gamegoo/gamegoo_v2/account/member/domain/Mike.java b/src/main/java/com/gamegoo/gamegoo_v2/account/member/domain/Mike.java index 33188944..f10b4b07 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/account/member/domain/Mike.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/account/member/domain/Mike.java @@ -2,6 +2,5 @@ public enum Mike { UNAVAILABLE, - ONLY_LISTEN, AVAILABLE, } diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityCalculateService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityCalculateService.java index 7ffc3f77..fa5288d8 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityCalculateService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityCalculateService.java @@ -22,19 +22,16 @@ public int calculateFastPriority(Position myWantPosition, Position otherMainPosi Tier myTier, Integer myRank, Tier otherTier, Integer otherRank) { int priority = 0; - // 포지션 우선순위 - priority += matchingPriorityEvaluateService.getPositionPriority(myWantPosition, otherMainPosition, - otherSubPosition, 5, 3, 1); - - // 마이크 우선순위 - priority += matchingPriorityEvaluateService.getMikePriority(myMike, otherMike, 5, 3); - // 매너 우선순위 - priority += matchingPriorityEvaluateService.getMannerPriority(otherManner, myManner, 10, 2); + priority += matchingPriorityEvaluateService.getMannerPriority(otherManner, myManner, 16, 4); - // 티어 및 랭킹 우선순위 - priority += matchingPriorityEvaluateService.getTierRankPriority(myTier, myRank, otherTier, otherRank, 50, 5, - 10); + // 티어 및 랭킹 점수 + int averageTierRank = (myRank + otherRank) / 2; + priority += matchingPriorityEvaluateService.getTierRankPriority(myTier, averageTierRank, otherTier, + averageTierRank, 40, 5, 10); + + // 마이크 우선순위 + priority += matchingPriorityEvaluateService.getMikePriority(myMike, otherMike, 3, 2); return priority; } @@ -47,19 +44,16 @@ public int calculateSoloPriority(Position myWantPosition, Position otherMainPosi Tier myTier, Integer myRank, Tier otherTier, Integer otherRank) { int priority = 0; - // 포지션 우선순위 - priority += matchingPriorityEvaluateService.getPositionPriority(myWantPosition, otherMainPosition, - otherSubPosition, 8, 4, 2); - - // 마이크 우선순위 - priority += matchingPriorityEvaluateService.getMikePriority(myMike, otherMike, 4, 2); - // 매너 우선순위 - priority += matchingPriorityEvaluateService.getMannerPriority(otherManner, myManner, 15, 3); + priority += matchingPriorityEvaluateService.getMannerPriority(otherManner, myManner, 16, 4); - // 티어 및 랭킹 우선순위 - priority += matchingPriorityEvaluateService.getTierRankPriority(myTier, myRank, otherTier, otherRank, 60, 6, - 12); + // 티어 및 랭킹 제한 확인 + if (!validateSoloRankRange(myTier, otherTier)) { + return 0; + } + + // 마이크 우선순위 + priority += matchingPriorityEvaluateService.getMikePriority(myMike, otherMike, 3, 2); return priority; } @@ -72,44 +66,85 @@ public int calculateFreePriority(Position myWantPosition, Position otherMainPosi Tier myTier, Integer myRank, Tier otherTier, Integer otherRank) { int priority = 0; - // 포지션 우선순위 - priority += matchingPriorityEvaluateService.getPositionPriority(myWantPosition, otherMainPosition, - otherSubPosition, 6, 3, 1); - - // 마이크 우선순위 - priority += matchingPriorityEvaluateService.getMikePriority(myMike, otherMike, 6, 4); - // 매너 우선순위 - priority += matchingPriorityEvaluateService.getMannerPriority(otherManner, myManner, 12, 2); + priority += matchingPriorityEvaluateService.getMannerPriority(otherManner, myManner, 16, 4); + + // 티어 및 랭킹 제한 확인 + if (myTier.ordinal() < 5 && otherTier.ordinal() >= 6) { + return 0; + } - // 티어 및 랭킹 우선순위 - priority += matchingPriorityEvaluateService.getTierRankPriority(myTier, myRank, otherTier, otherRank, 45, 4, 9); + // 마이크 우선순위 + priority += matchingPriorityEvaluateService.getMikePriority(myMike, otherMike, 3, 2); return priority; } /** - * ARAM 모드 우선순위 계산 + * 칼바람 모드 우선순위 계산 */ public int calculateAramPriority(Position myWantPosition, Position otherMainPosition, Position otherSubPosition, Mike myMike, Mike otherMike, Integer myManner, Integer otherManner, Tier myTier, Integer myRank, Tier otherTier, Integer otherRank) { int priority = 0; - // 포지션 우선순위 - priority += matchingPriorityEvaluateService.getPositionPriority(myWantPosition, otherMainPosition, - otherSubPosition, 4, 2, 1); + // 매너 우선순위 + priority += matchingPriorityEvaluateService.getMannerPriority(otherManner, myManner, 16, 4); // 마이크 우선순위 priority += matchingPriorityEvaluateService.getMikePriority(myMike, otherMike, 3, 2); - // 매너 우선순위 - priority += matchingPriorityEvaluateService.getMannerPriority(otherManner, myManner, 8, 1); + return priority; + } - // 티어 및 랭킹 우선순위 - priority += matchingPriorityEvaluateService.getTierRankPriority(myTier, myRank, otherTier, otherRank, 30, 3, 6); + /** + * 정밀 매칭 검증 메서드 + */ + public boolean validatePreciseMatching(Mike myMike, Mike otherMike, Position myWantPosition, + Position otherMainPosition, Position otherSubPosition, + Tier myTier, Tier otherTier) { + // 마이크가 다를 경우 매칭 실패 + if (!myMike.equals(otherMike)) { + return false; + } + + // 내가 원하는 포지션이 상대 포지션이 아닐 경우 매칭 실패 + if (!otherMainPosition.equals(myWantPosition) && !otherSubPosition.equals(myWantPosition)) { + return false; + } + + // 티어 차이가 1개 이상 나면 매칭 실패 + return Math.abs(myTier.ordinal() - otherTier.ordinal()) <= 1; + } - return priority; + /** + * 개인 랭크 제한 검증 + */ + private boolean validateSoloRankRange(Tier myTier, Tier otherTier) { + int[][] allowedRanges = { + {0, 1, 2}, // 아이언 + {0, 1, 2}, // 브론즈 + {0, 1, 2, 3}, // 실버 + {2, 3, 4}, // 골드 + {3, 4, 5}, // 플레티넘 + {4, 5, 6}, // 에메랄드 + {5, 6} // 다이아몬드 + }; + + int myTierIndex = myTier.ordinal(); + int otherTierIndex = otherTier.ordinal(); + + if (myTierIndex >= allowedRanges.length) { + return false; // 마스터 이상은 제외 + } + + for (int tier : allowedRanges[myTierIndex]) { + if (tier == otherTierIndex) { + return true; + } + } + + return false; } } diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityEvaluateService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityEvaluateService.java index 6668d7f8..e35f47a2 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityEvaluateService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityEvaluateService.java @@ -97,10 +97,6 @@ public int getMikePriority(Mike myMike, Mike otherMike, int mikeMatchPriority, i if (myMike == Mike.AVAILABLE && otherMike == Mike.AVAILABLE) { return mikeMatchPriority; } - if ((myMike == Mike.AVAILABLE && otherMike == Mike.ONLY_LISTEN) || - (myMike == Mike.ONLY_LISTEN && otherMike == Mike.AVAILABLE)) { - return mikePartialMatchPriority; - } return 0; } From 00b4ee89ae979db5bc8b876fb9ad12a00cfb6138 Mon Sep 17 00:00:00 2001 From: Rimi Date: Fri, 24 Jan 2025 04:00:05 +0900 Subject: [PATCH 04/28] =?UTF-8?q?:sparkles:=20[Feat]=20=EB=B9=A0=EB=A5=B8?= =?UTF-8?q?=20=EB=8C=80=EC=A0=84=20=EC=A0=9C=EC=99=B8,=20MatchingPriorityC?= =?UTF-8?q?alculateService=20=EB=A7=A4=EC=B9=AD=20=ED=83=80=EC=9E=85,=20?= =?UTF-8?q?=EA=B2=8C=EC=9E=84=20=EB=AA=A8=EB=93=9C=EC=97=90=20=EB=94=B0?= =?UTF-8?q?=EB=A5=B8=20=EC=9A=B0=EC=84=A0=EC=88=9C=EC=9C=84=20=EA=B0=92=20?= =?UTF-8?q?=EA=B3=84=EC=82=B0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MatchingPriorityCalculateService.java | 72 +++++++++++++------ .../MatchingPriorityEvaluateService.java | 21 +++--- 2 files changed, 59 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityCalculateService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityCalculateService.java index fa5288d8..10d120af 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityCalculateService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityCalculateService.java @@ -15,45 +15,65 @@ public class MatchingPriorityCalculateService { private final MatchingPriorityEvaluateService matchingPriorityEvaluateService; /** - * FAST 모드 우선순위 계산 + * 정밀 매칭 우선순위 계산 */ - public int calculateFastPriority(Position myWantPosition, Position otherMainPosition, Position otherSubPosition, + public int calculatePrecisePriority(Integer myManner, Integer otherManner) { + return matchingPriorityEvaluateService.getMannerPriority(otherManner, myManner, 16, 4); + } + + /** + * 빠른대전 우선순위 계산 + */ + public int calculateFastPriority(Position myMainP, Position mySubP, Position myWantP, + Position otherMainP, Position otherSubP, Position otherWantP, Mike myMike, Mike otherMike, Integer myManner, Integer otherManner, - Tier myTier, Integer myRank, Tier otherTier, Integer otherRank) { + Tier mySoloTier, Integer mySoloRank, Tier myFreeTier, Integer myFreeRank, + Tier otherSoloTier, Integer otherSoloRank, Tier otherFreeTier, + Integer otherFreeRank) { int priority = 0; // 매너 우선순위 priority += matchingPriorityEvaluateService.getMannerPriority(otherManner, myManner, 16, 4); - // 티어 및 랭킹 점수 - int averageTierRank = (myRank + otherRank) / 2; - priority += matchingPriorityEvaluateService.getTierRankPriority(myTier, averageTierRank, otherTier, - averageTierRank, 40, 5, 10); + // TODO: 티어 및 랭킹 점수 계산 + // priority += matchingPriorityEvaluateService.getTierRankPriority(myTier, myRank, otherTier, otherRank, 40, 4); + + // 포지션 우선순위 + priority += matchingPriorityEvaluateService.getPositionPriority(myWantP, otherMainP, otherSubP, 3, 2, 1); + priority += matchingPriorityEvaluateService.getPositionPriority(otherWantP, myMainP, mySubP, 3, 2, 1); // 마이크 우선순위 - priority += matchingPriorityEvaluateService.getMikePriority(myMike, otherMike, 3, 2); + priority += matchingPriorityEvaluateService.getMikePriority(myMike, otherMike, 3); return priority; } /** - * SOLO 모드 우선순위 계산 + * 개인 랭크 모드 우선순위 계산 */ - public int calculateSoloPriority(Position myWantPosition, Position otherMainPosition, Position otherSubPosition, + public int calculateSoloPriority(Position myMainP, Position mySubP, Position myWantP, + Position otherMainP, Position otherSubP, Position otherWantP, Mike myMike, Mike otherMike, Integer myManner, Integer otherManner, Tier myTier, Integer myRank, Tier otherTier, Integer otherRank) { + // 티어 및 랭킹 제한 확인 + if (!validateSoloRankRange(myTier, otherTier)) { + return 0; + } + int priority = 0; // 매너 우선순위 priority += matchingPriorityEvaluateService.getMannerPriority(otherManner, myManner, 16, 4); - // 티어 및 랭킹 제한 확인 - if (!validateSoloRankRange(myTier, otherTier)) { - return 0; - } + // 티어 및 랭킹 점수 계산 + priority += matchingPriorityEvaluateService.getTierRankPriority(myTier, myRank, otherTier, otherRank, 40, 4); + + // 포지션 우선순위 + priority += matchingPriorityEvaluateService.getPositionPriority(myWantP, otherMainP, otherSubP, 3, 2, 1); + priority += matchingPriorityEvaluateService.getPositionPriority(otherWantP, myMainP, mySubP, 3, 2, 1); // 마이크 우선순위 - priority += matchingPriorityEvaluateService.getMikePriority(myMike, otherMike, 3, 2); + priority += matchingPriorityEvaluateService.getMikePriority(myMike, otherMike, 5); return priority; } @@ -61,21 +81,29 @@ public int calculateSoloPriority(Position myWantPosition, Position otherMainPosi /** * FREE 모드 우선순위 계산 */ - public int calculateFreePriority(Position myWantPosition, Position otherMainPosition, Position otherSubPosition, + public int calculateFreePriority(Position myMainP, Position mySubP, Position myWantP, + Position otherMainP, Position otherSubP, Position otherWantP, Mike myMike, Mike otherMike, Integer myManner, Integer otherManner, Tier myTier, Integer myRank, Tier otherTier, Integer otherRank) { + // 티어 및 랭킹 제한 확인 + if (myTier.ordinal() < 5 && otherTier.ordinal() >= 6) { + return 0; + } + int priority = 0; // 매너 우선순위 priority += matchingPriorityEvaluateService.getMannerPriority(otherManner, myManner, 16, 4); - // 티어 및 랭킹 제한 확인 - if (myTier.ordinal() < 5 && otherTier.ordinal() >= 6) { - return 0; - } + // 티어 및 랭킹 점수 계산 + priority += matchingPriorityEvaluateService.getTierRankPriority(myTier, myRank, otherTier, otherRank, 40, 4); + + // 포지션 우선순위 + priority += matchingPriorityEvaluateService.getPositionPriority(myWantP, otherMainP, otherSubP, 3, 2, 1); + priority += matchingPriorityEvaluateService.getPositionPriority(otherWantP, myMainP, mySubP, 3, 2, 1); // 마이크 우선순위 - priority += matchingPriorityEvaluateService.getMikePriority(myMike, otherMike, 3, 2); + priority += matchingPriorityEvaluateService.getMikePriority(myMike, otherMike, 3); return priority; } @@ -92,7 +120,7 @@ public int calculateAramPriority(Position myWantPosition, Position otherMainPosi priority += matchingPriorityEvaluateService.getMannerPriority(otherManner, myManner, 16, 4); // 마이크 우선순위 - priority += matchingPriorityEvaluateService.getMikePriority(myMike, otherMike, 3, 2); + priority += matchingPriorityEvaluateService.getMikePriority(myMike, otherMike, 3); return priority; } diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityEvaluateService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityEvaluateService.java index e35f47a2..c0c7b5bc 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityEvaluateService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityEvaluateService.java @@ -30,13 +30,12 @@ public int getMannerPriority(Integer otherManner, Integer myManner, int maxManne * @param otherRank 타겟 랭크 * @param maxTierRankPriority 최대 점수 * @param tierMultiplier 티어 점수 - * @param maxRankScore 랭크 점수 * @return 랭킹 우선순위 값 */ public int getTierRankPriority(Tier myTier, Integer myRank, Tier otherTier, Integer otherRank, - int maxTierRankPriority, int tierMultiplier, int maxRankScore) { - int myScore = getTierRankScore(myTier, myRank, tierMultiplier, maxRankScore); - int otherScore = getTierRankScore(otherTier, otherRank, tierMultiplier, maxRankScore); + int maxTierRankPriority, int tierMultiplier) { + int myScore = getTierRankScore(myTier, myRank, tierMultiplier); + int otherScore = getTierRankScore(otherTier, otherRank, tierMultiplier); int scoreDifference = Math.abs(myScore - otherScore); return maxTierRankPriority - scoreDifference; @@ -48,11 +47,10 @@ public int getTierRankPriority(Tier myTier, Integer myRank, Tier otherTier, Inte * @param tier 티어 * @param rank 랭크 * @param tierMultiplier 티어 점수 - * @param maxRankScore 랭크 점수 * @return 랭킹 점수 */ - private int getTierRankScore(Tier tier, int rank, int tierMultiplier, int maxRankScore) { - return tier.ordinal() * tierMultiplier + (maxRankScore - rank); + private int getTierRankScore(Tier tier, int rank, int tierMultiplier) { + return tier.ordinal() * tierMultiplier - rank; } /** @@ -84,13 +82,12 @@ public int getPositionPriority(Position myWantPosition, Position otherMainPositi /** * 마이크 우선순위 점수 계산 * - * @param myMike 내 마이크 - * @param otherMike 타겟 마이크 - * @param mikeMatchPriority 마이크 점수 - * @param mikePartialMatchPriority 마이크 부분 점수 + * @param myMike 내 마이크 + * @param otherMike 타겟 마이크 + * @param mikeMatchPriority 마이크 점수 * @return 마이크 우선순위 점수 */ - public int getMikePriority(Mike myMike, Mike otherMike, int mikeMatchPriority, int mikePartialMatchPriority) { + public int getMikePriority(Mike myMike, Mike otherMike, int mikeMatchPriority) { if (myMike == Mike.UNAVAILABLE && otherMike == Mike.UNAVAILABLE) { return mikeMatchPriority; } From bb8e081fc21c5ce0288fc6f704477a19945b38e9 Mon Sep 17 00:00:00 2001 From: Rimi Date: Sat, 25 Jan 2025 18:59:20 +0900 Subject: [PATCH 05/28] =?UTF-8?q?:sparkles:=20[Feat]=20=EB=A7=A4=EC=B9=AD?= =?UTF-8?q?=20=EC=9A=B0=EC=84=A0=EC=88=9C=EC=9C=84=20API=20DTO=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../matching/dto/PriorityValue.java | 22 ++++++++++++++ .../dto/response/PriorityListResponse.java | 29 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 src/main/java/com/gamegoo/gamegoo_v2/matching/dto/PriorityValue.java create mode 100644 src/main/java/com/gamegoo/gamegoo_v2/matching/dto/response/PriorityListResponse.java diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/PriorityValue.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/PriorityValue.java new file mode 100644 index 00000000..291d4ee4 --- /dev/null +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/PriorityValue.java @@ -0,0 +1,22 @@ +package com.gamegoo.gamegoo_v2.matching.dto; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class PriorityValue { + + Long memberId; + String matchingUuid; + int priorityValue; + + public static PriorityValue of(Long memberId, String matchingUuid, int priorityValue) { + return PriorityValue.builder() + .memberId(memberId) + .matchingUuid(matchingUuid) + .priorityValue(priorityValue) + .build(); + } + +} diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/response/PriorityListResponse.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/response/PriorityListResponse.java new file mode 100644 index 00000000..0eb5be7a --- /dev/null +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/response/PriorityListResponse.java @@ -0,0 +1,29 @@ +package com.gamegoo.gamegoo_v2.matching.dto.response; + +import com.gamegoo.gamegoo_v2.account.member.domain.Member; +import com.gamegoo.gamegoo_v2.matching.dto.PriorityValue; +import lombok.Builder; +import lombok.Getter; + +import java.util.List; + +@Getter +@Builder +public class PriorityListResponse { + + List myPriorityList; + List otherPriorityList; + MatchingMemberInfoResponse myMatchingInfo; + + public static PriorityListResponse of(List mypriorityList, List otherpriorityList, + Member member, String matchingUuid) { + MatchingMemberInfoResponse matchingMemberInfoResponse = MatchingMemberInfoResponse.of(member, matchingUuid); + + return PriorityListResponse.builder() + .myPriorityList(mypriorityList) + .otherPriorityList(otherpriorityList) + .myMatchingInfo(matchingMemberInfoResponse) + .build(); + } + +} From b4f2e9455dbfe6dc69a9fe9e5c1d28a13980780b Mon Sep 17 00:00:00 2001 From: Rimi Date: Sat, 25 Jan 2025 18:59:37 +0900 Subject: [PATCH 06/28] =?UTF-8?q?:sparkles:=20[Feat]=20=EB=A7=A4=EC=B9=AD?= =?UTF-8?q?=20=EC=9A=B0=EC=84=A0=EC=88=9C=EC=9C=84=20API=20DTO=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/InitializingMatchingRequest.java | 32 +++++++++++ .../response/MatchingMemberInfoResponse.java | 55 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 src/main/java/com/gamegoo/gamegoo_v2/matching/dto/request/InitializingMatchingRequest.java create mode 100644 src/main/java/com/gamegoo/gamegoo_v2/matching/dto/response/MatchingMemberInfoResponse.java diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/request/InitializingMatchingRequest.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/request/InitializingMatchingRequest.java new file mode 100644 index 00000000..9f3f683c --- /dev/null +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/request/InitializingMatchingRequest.java @@ -0,0 +1,32 @@ +package com.gamegoo.gamegoo_v2.matching.dto.request; + +import com.gamegoo.gamegoo_v2.account.member.domain.Mike; +import com.gamegoo.gamegoo_v2.account.member.domain.Position; +import com.gamegoo.gamegoo_v2.matching.domain.GameMode; +import com.gamegoo.gamegoo_v2.matching.domain.MatchingType; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; + +import java.util.List; + +@Getter +public class InitializingMatchingRequest { + + @NotNull(message = "gameMode 는 비워둘 수 없습니다.") + GameMode gameMode; + + @NotNull(message = "mike 는 비워둘 수 없습니다.") + Mike mike; + + @NotNull(message = "matching_type은 비워둘 수 없습니다.") + MatchingType matchingType; + + Position mainP; + + Position subP; + + Position wantP; + + List gameStyleIdList; + +} diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/response/MatchingMemberInfoResponse.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/response/MatchingMemberInfoResponse.java new file mode 100644 index 00000000..dd53e18c --- /dev/null +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/response/MatchingMemberInfoResponse.java @@ -0,0 +1,55 @@ +package com.gamegoo.gamegoo_v2.matching.dto.response; + +import com.gamegoo.gamegoo_v2.account.member.domain.Member; +import com.gamegoo.gamegoo_v2.account.member.domain.Mike; +import com.gamegoo.gamegoo_v2.account.member.domain.Position; +import com.gamegoo.gamegoo_v2.account.member.domain.Tier; +import com.gamegoo.gamegoo_v2.game.dto.response.GameStyleResponse; +import com.gamegoo.gamegoo_v2.matching.domain.GameMode; +import lombok.Builder; +import lombok.Getter; + +import java.util.List; + +@Getter +@Builder +public class MatchingMemberInfoResponse { + + Long memberId; + String matchingUuid; + String gameName; + String tag; + Tier tier; + Integer rank; + Integer mannerLevel; + Integer profileImg; + GameMode gameMode; + Position mainP; + Position subP; + Position wantP; + Mike mike; + List gameStyleResponseList; + + public static MatchingMemberInfoResponse of(Member member, String matchingUuid) { + List gameStyleResponseList = member.getMemberGameStyleList().stream() + .map(memberGameStyle -> GameStyleResponse.of(memberGameStyle.getGameStyle())) + .toList(); + + return MatchingMemberInfoResponse.builder() + .memberId(member.getId()) + .matchingUuid(matchingUuid) + .mike(member.getMike()) + .gameName(member.getGameName()) + .tag(member.getTag()) + .tier(member.getTier()) + .rank(member.getGameRank()) + .profileImg(member.getProfileImage()) + .mannerLevel(member.getMannerLevel()) + .mainP(member.getMainPosition()) + .subP(member.getSubPosition()) + .wantP(member.getWantPosition()) + .gameStyleResponseList(gameStyleResponseList) + .build(); + } + +} From 14b3e7f17f50fe37d69eb8e1d2e5af6e34c948df Mon Sep 17 00:00:00 2001 From: Rimi Date: Sat, 25 Jan 2025 19:01:28 +0900 Subject: [PATCH 07/28] =?UTF-8?q?:sparkles:=20[Feat]=20GameStyle=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=ED=95=98=EB=8A=94=20=EB=A1=9C=EC=A7=81=20Mem?= =?UTF-8?q?berFacadeService=EA=B0=80=20=EC=95=84=EB=8B=8C=20MemberService?= =?UTF-8?q?=20=EB=82=B4=EC=97=90=EC=84=9C=20=EC=A7=84=ED=96=89=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../account/member/domain/Member.java | 7 +++++ .../member/service/MemberFacadeService.java | 17 +---------- .../account/member/service/MemberService.java | 29 ++++++++++++++++++- 3 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/gamegoo/gamegoo_v2/account/member/domain/Member.java b/src/main/java/com/gamegoo/gamegoo_v2/account/member/domain/Member.java index 08159286..faa76064 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/account/member/domain/Member.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/account/member/domain/Member.java @@ -178,4 +178,11 @@ public Double updateMannerRank(Double mannerRank) { return this.mannerRank; } + public void updateMemberByMatchingRecord(Mike mike, Position mainP, Position subP, Position wantP) { + this.mike = mike; + this.mainPosition = mainP; + this.subPosition = subP; + this.wantPosition = wantP; + } + } diff --git a/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberFacadeService.java b/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberFacadeService.java index 8c1d6d3a..3aa37129 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberFacadeService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberFacadeService.java @@ -1,22 +1,18 @@ package com.gamegoo.gamegoo_v2.account.member.service; import com.gamegoo.gamegoo_v2.account.member.domain.Member; -import com.gamegoo.gamegoo_v2.account.member.domain.MemberGameStyle; import com.gamegoo.gamegoo_v2.account.member.dto.request.GameStyleRequest; import com.gamegoo.gamegoo_v2.account.member.dto.request.IsMikeRequest; import com.gamegoo.gamegoo_v2.account.member.dto.request.PositionRequest; import com.gamegoo.gamegoo_v2.account.member.dto.request.ProfileImageRequest; import com.gamegoo.gamegoo_v2.account.member.dto.response.MyProfileResponse; import com.gamegoo.gamegoo_v2.account.member.dto.response.OtherProfileResponse; -import com.gamegoo.gamegoo_v2.game.domain.GameStyle; import com.gamegoo.gamegoo_v2.social.block.service.BlockService; import com.gamegoo.gamegoo_v2.social.friend.service.FriendService; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; - @Service @RequiredArgsConstructor @Transactional(readOnly = true) @@ -114,18 +110,7 @@ public String setPosition(Member member, PositionRequest request) { */ @Transactional public String setGameStyle(Member member, GameStyleRequest request) { - // request의 Gamestyle 조회 - List requestGameStyleList = memberService.findRequestGameStyle(request); - - // 현재 DB의 GameStyle 조회 - List currentMemberGameStyleList = memberService.findCurrentMemberGameStyleList(member); - - // request에 없고, DB에 있는 GameStyle 삭제 - memberService.removeUnnecessaryGameStyles(member, requestGameStyleList, currentMemberGameStyleList); - - // request에 있고, DB에 없는 GameStyle 추가 - memberService.addNewGameStyles(member, requestGameStyleList, currentMemberGameStyleList); - + memberService.setGameStyle(member, request); return "게임 스타일 수정이 완료되었습니다"; } diff --git a/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberService.java b/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberService.java index faf8c345..ce8ac342 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberService.java @@ -130,6 +130,27 @@ public void setPosition(Member member, Position mainPosition, Position subPositi member.updatePosition(mainPosition, subPosition, wantPosition); } + /** + * 게임 스타일 수정 + * + * @param member 사용자 + * @param request 게임스타일 리스트 + */ + @Transactional + public void setGameStyle(Member member, GameStyleRequest request) { + // request의 Gamestyle 조회 + List requestGameStyleList = findRequestGameStyle(request); + + // 현재 DB의 GameStyle 조회 + List currentMemberGameStyleList = findCurrentMemberGameStyleList(member); + + // request에 없고, DB에 있는 GameStyle 삭제 + removeUnnecessaryGameStyles(member, requestGameStyleList, currentMemberGameStyleList); + + // request에 있고, DB에 없는 GameStyle 추가 + addNewGameStyles(member, requestGameStyleList, currentMemberGameStyleList); + } + /** * request id로 GameStyle Entity 조회 * @@ -163,7 +184,7 @@ public void removeUnnecessaryGameStyles(Member member, List requested currentMemberGameStyles.stream() .filter(mgs -> !requestedGameStyles.contains(mgs.getGameStyle())) .forEach(mgs -> { - mgs.removeMember(member); // Remove bidirectional relationship + mgs.removeMember(member); memberGameStyleRepository.delete(mgs); }); } @@ -190,4 +211,10 @@ public void addNewGameStyles(Member member, List requestedGameStyles, }); } + @Transactional + public void updateMemberByMatchingInfo(Member member, Mike mike, Position mainP, Position subP, Position wantP, + List gameStyleIdList) { + member.updateMemberByMatchingRecord(mike, mainP, subP, wantP); + } + } From d6f06e760201f9e2e4f956a4cc8d00a1a3649e9c Mon Sep 17 00:00:00 2001 From: Rimi Date: Sat, 25 Jan 2025 19:10:42 +0900 Subject: [PATCH 08/28] =?UTF-8?q?:sparkles:=20[Feat]=20setGameStyle=20Serv?= =?UTF-8?q?ice=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/service/MemberFacadeService.java | 2 +- .../account/member/service/MemberService.java | 16 +++++++--------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberFacadeService.java b/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberFacadeService.java index 3aa37129..ef56385d 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberFacadeService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberFacadeService.java @@ -110,7 +110,7 @@ public String setPosition(Member member, PositionRequest request) { */ @Transactional public String setGameStyle(Member member, GameStyleRequest request) { - memberService.setGameStyle(member, request); + memberService.setGameStyle(member, request.getGameStyleIdList()); return "게임 스타일 수정이 완료되었습니다"; } diff --git a/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberService.java b/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberService.java index ce8ac342..0260ba0c 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberService.java @@ -6,7 +6,6 @@ import com.gamegoo.gamegoo_v2.account.member.domain.Mike; import com.gamegoo.gamegoo_v2.account.member.domain.Position; import com.gamegoo.gamegoo_v2.account.member.domain.Tier; -import com.gamegoo.gamegoo_v2.account.member.dto.request.GameStyleRequest; import com.gamegoo.gamegoo_v2.account.member.repository.MemberGameStyleRepository; import com.gamegoo.gamegoo_v2.account.member.repository.MemberRepository; import com.gamegoo.gamegoo_v2.core.exception.MemberException; @@ -131,15 +130,13 @@ public void setPosition(Member member, Position mainPosition, Position subPositi } /** - * 게임 스타일 수정 - * - * @param member 사용자 - * @param request 게임스타일 리스트 + * @param member 회원 + * @param gameStyleIdList 수정할 게임 스타일 리스트 */ @Transactional - public void setGameStyle(Member member, GameStyleRequest request) { + public void setGameStyle(Member member, List gameStyleIdList) { // request의 Gamestyle 조회 - List requestGameStyleList = findRequestGameStyle(request); + List requestGameStyleList = findRequestGameStyle(gameStyleIdList); // 현재 DB의 GameStyle 조회 List currentMemberGameStyleList = findCurrentMemberGameStyleList(member); @@ -156,8 +153,8 @@ public void setGameStyle(Member member, GameStyleRequest request) { * * @return request의 GamestyleList */ - public List findRequestGameStyle(GameStyleRequest request) { - return request.getGameStyleIdList().stream() + public List findRequestGameStyle(List gameStyleIdList) { + return gameStyleIdList.stream() .map(id -> gameStyleRepository.findById(id).orElseThrow(() -> new MemberException(ErrorCode.GAMESTYLE_NOT_FOUND))) .toList(); } @@ -215,6 +212,7 @@ public void addNewGameStyles(Member member, List requestedGameStyles, public void updateMemberByMatchingInfo(Member member, Mike mike, Position mainP, Position subP, Position wantP, List gameStyleIdList) { member.updateMemberByMatchingRecord(mike, mainP, subP, wantP); + setGameStyle(member, gameStyleIdList); } } From e2996c92fb38525008953e8941044013195d4786 Mon Sep 17 00:00:00 2001 From: Rimi Date: Sat, 25 Jan 2025 19:23:24 +0900 Subject: [PATCH 09/28] =?UTF-8?q?:sparkles:=20[Feat]=20=EB=A7=A4=EC=B9=AD?= =?UTF-8?q?=20=EC=A0=95=EB=B3=B4=EB=A1=9C=20Member=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/service/MemberFacadeService.java | 2 +- .../service/MemberGameStyleService.java | 87 +++++++++++++++++++ .../account/member/service/MemberService.java | 82 ++--------------- .../Controller/MatchingController.java | 17 +++- .../service/MatchingFacadeService.java | 19 ++-- .../matching/service/MatchingService.java | 11 +++ 6 files changed, 135 insertions(+), 83 deletions(-) create mode 100644 src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberGameStyleService.java diff --git a/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberFacadeService.java b/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberFacadeService.java index ef56385d..6f30da67 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberFacadeService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberFacadeService.java @@ -110,7 +110,7 @@ public String setPosition(Member member, PositionRequest request) { */ @Transactional public String setGameStyle(Member member, GameStyleRequest request) { - memberService.setGameStyle(member, request.getGameStyleIdList()); + memberService.updateGameStyle(member, request.getGameStyleIdList()); return "게임 스타일 수정이 완료되었습니다"; } diff --git a/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberGameStyleService.java b/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberGameStyleService.java new file mode 100644 index 00000000..ba36dfdc --- /dev/null +++ b/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberGameStyleService.java @@ -0,0 +1,87 @@ +package com.gamegoo.gamegoo_v2.account.member.service; + +import com.gamegoo.gamegoo_v2.account.member.domain.Member; +import com.gamegoo.gamegoo_v2.account.member.domain.MemberGameStyle; +import com.gamegoo.gamegoo_v2.account.member.repository.MemberGameStyleRepository; +import com.gamegoo.gamegoo_v2.core.exception.MemberException; +import com.gamegoo.gamegoo_v2.core.exception.common.ErrorCode; +import com.gamegoo.gamegoo_v2.game.domain.GameStyle; +import com.gamegoo.gamegoo_v2.game.repository.GameStyleRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class MemberGameStyleService { + + private final GameStyleRepository gameStyleRepository; + private final MemberGameStyleRepository memberGameStyleRepository; + + + /** + * request id로 GameStyle Entity 조회 + * + * @return request의 GamestyleList + */ + public List findRequestGameStyle(List gameStyleIdList) { + return gameStyleIdList.stream() + .map(id -> gameStyleRepository.findById(id).orElseThrow(() -> new MemberException(ErrorCode.GAMESTYLE_NOT_FOUND))) + .toList(); + } + + /** + * 현재 DB의 MemberGameStyle List 조회 + * + * @return MemberGameStyleList + */ + public List findCurrentMemberGameStyleList(Member member) { + return new ArrayList<>(member.getMemberGameStyleList()); + } + + /** + * 불필요한 GameStyle 제거 + * + * @param member 회원 + * @param requestedGameStyles 새로운 GameStyle + * @param currentMemberGameStyles 현재 Gamestyle + */ + @Transactional + public void removeUnnecessaryGameStyles(Member member, List requestedGameStyles, + List currentMemberGameStyles) { + currentMemberGameStyles.stream() + .filter(mgs -> !requestedGameStyles.contains(mgs.getGameStyle())) + .forEach(mgs -> { + mgs.removeMember(member); + memberGameStyleRepository.delete(mgs); + }); + } + + /** + * 새로운 GameStyle 추가 + * + * @param member 사용자 + * @param requestedGameStyles 변경 후 게임스타일 + * @param currentMemberGameStyles 변경 전 게임스타일 + */ + @Transactional + public void addNewGameStyles(Member member, List requestedGameStyles, + List currentMemberGameStyles) { + List currentGameStyles = currentMemberGameStyles.stream() + .map(MemberGameStyle::getGameStyle) + .toList(); + + requestedGameStyles.stream() + .filter(gs -> !currentGameStyles.contains(gs)) + .forEach(gs -> { + MemberGameStyle newMemberGameStyle = MemberGameStyle.create(gs, member); + memberGameStyleRepository.save(newMemberGameStyle); + }); + } + + +} diff --git a/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberService.java b/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberService.java index 0260ba0c..fb0d5db8 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberService.java @@ -6,18 +6,15 @@ import com.gamegoo.gamegoo_v2.account.member.domain.Mike; import com.gamegoo.gamegoo_v2.account.member.domain.Position; import com.gamegoo.gamegoo_v2.account.member.domain.Tier; -import com.gamegoo.gamegoo_v2.account.member.repository.MemberGameStyleRepository; import com.gamegoo.gamegoo_v2.account.member.repository.MemberRepository; import com.gamegoo.gamegoo_v2.core.exception.MemberException; import com.gamegoo.gamegoo_v2.core.exception.common.ErrorCode; import com.gamegoo.gamegoo_v2.game.domain.GameStyle; -import com.gamegoo.gamegoo_v2.game.repository.GameStyleRepository; import com.gamegoo.gamegoo_v2.utils.PasswordUtil; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.ArrayList; import java.util.List; @Service @@ -26,8 +23,7 @@ public class MemberService { private final MemberRepository memberRepository; - private final GameStyleRepository gameStyleRepository; - private final MemberGameStyleRepository memberGameStyleRepository; + private final MemberGameStyleService memberGameStyleService; /** * Member 생성 메소드 @@ -134,85 +130,25 @@ public void setPosition(Member member, Position mainPosition, Position subPositi * @param gameStyleIdList 수정할 게임 스타일 리스트 */ @Transactional - public void setGameStyle(Member member, List gameStyleIdList) { + public void updateGameStyle(Member member, List gameStyleIdList) { // request의 Gamestyle 조회 - List requestGameStyleList = findRequestGameStyle(gameStyleIdList); + List requestGameStyleList = memberGameStyleService.findRequestGameStyle(gameStyleIdList); // 현재 DB의 GameStyle 조회 - List currentMemberGameStyleList = findCurrentMemberGameStyleList(member); + List currentMemberGameStyleList = + memberGameStyleService.findCurrentMemberGameStyleList(member); // request에 없고, DB에 있는 GameStyle 삭제 - removeUnnecessaryGameStyles(member, requestGameStyleList, currentMemberGameStyleList); + memberGameStyleService.removeUnnecessaryGameStyles(member, requestGameStyleList, currentMemberGameStyleList); // request에 있고, DB에 없는 GameStyle 추가 - addNewGameStyles(member, requestGameStyleList, currentMemberGameStyleList); - } - - /** - * request id로 GameStyle Entity 조회 - * - * @return request의 GamestyleList - */ - public List findRequestGameStyle(List gameStyleIdList) { - return gameStyleIdList.stream() - .map(id -> gameStyleRepository.findById(id).orElseThrow(() -> new MemberException(ErrorCode.GAMESTYLE_NOT_FOUND))) - .toList(); - } - - /** - * 현재 DB의 MemberGameStyle List 조회 - * - * @return MemberGameStyleList - */ - public List findCurrentMemberGameStyleList(Member member) { - return new ArrayList<>(member.getMemberGameStyleList()); - } - - /** - * 불필요한 GameStyle 제거 - * - * @param member 회원 - * @param requestedGameStyles 새로운 GameStyle - * @param currentMemberGameStyles 현재 Gamestyle - */ - @Transactional - public void removeUnnecessaryGameStyles(Member member, List requestedGameStyles, - List currentMemberGameStyles) { - currentMemberGameStyles.stream() - .filter(mgs -> !requestedGameStyles.contains(mgs.getGameStyle())) - .forEach(mgs -> { - mgs.removeMember(member); - memberGameStyleRepository.delete(mgs); - }); - } - - /** - * 새로운 GameStyle 추가 - * - * @param member 사용자 - * @param requestedGameStyles 변경 후 게임스타일 - * @param currentMemberGameStyles 변경 전 게임스타일 - */ - @Transactional - public void addNewGameStyles(Member member, List requestedGameStyles, - List currentMemberGameStyles) { - List currentGameStyles = currentMemberGameStyles.stream() - .map(MemberGameStyle::getGameStyle) - .toList(); - - requestedGameStyles.stream() - .filter(gs -> !currentGameStyles.contains(gs)) - .forEach(gs -> { - MemberGameStyle newMemberGameStyle = MemberGameStyle.create(gs, member); - memberGameStyleRepository.save(newMemberGameStyle); - }); + memberGameStyleService.addNewGameStyles(member, requestGameStyleList, currentMemberGameStyleList); } @Transactional - public void updateMemberByMatchingInfo(Member member, Mike mike, Position mainP, Position subP, Position wantP, - List gameStyleIdList) { + public void updateMikePosition(Member member, Mike mike, Position mainP, Position subP, Position wantP) { + // 마이크, 포지션 수정 member.updateMemberByMatchingRecord(mike, mainP, subP, wantP); - setGameStyle(member, gameStyleIdList); } } diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/Controller/MatchingController.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/Controller/MatchingController.java index d354efee..6e5013c6 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/Controller/MatchingController.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/Controller/MatchingController.java @@ -3,6 +3,8 @@ import com.gamegoo.gamegoo_v2.account.auth.annotation.AuthMember; import com.gamegoo.gamegoo_v2.account.member.domain.Member; import com.gamegoo.gamegoo_v2.core.common.ApiResponse; +import com.gamegoo.gamegoo_v2.matching.dto.request.InitializingMatchingRequest; +import com.gamegoo.gamegoo_v2.matching.dto.response.PriorityListResponse; import com.gamegoo.gamegoo_v2.matching.service.MatchingFacadeService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -21,11 +23,18 @@ public class MatchingController { private final MatchingFacadeService matchingFacadeService; - @Operation(summary = "매칭 우선순위 계산 및 기록 저장 API", description = "API for calculating priority score and recording " + - "matchign") + @Operation(summary = "매칭 우선순위 계산 및 기록 저장 API", description = "API for calculating and recording matching \n\n" + + "gameMode: FAST, SOLO, FREE, ARAM string 을 넣어주세요. \n\n" + + "mike: UNAVAILABLE 또는 AVAILABLE 를 넣어주세요. \n\n" + + "matchingType: \"BASIC\" 또는 \"PRECISE\"를 넣어주세요.\n\n" + + "mainP: ANY, TOP, JUNGLE, MID, ADC, SUP string 을 넣어주세요. \n\n" + + "subP: ANY, TOP, JUNGLE, MID, ADC, SUP string 을 넣어주세요. \n\n" + + "wantP: ANY, TOP, JUNGLE, MID, ADC, SUP string 을 넣어주세요. \n\n" + + "gameStyleList: 1 ~ 17 int 를 넣어주세요.") @GetMapping - public ApiResponse getMemberJWT(@AuthMember Member member) { - return ApiResponse.ok(matchingFacadeService.calculatePriorityAndRecording()); + public ApiResponse InitializeMatching(@AuthMember Member member, + InitializingMatchingRequest request) { + return ApiResponse.ok(matchingFacadeService.calculatePriorityAndRecording(member, request)); } } diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingFacadeService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingFacadeService.java index c24a07a4..e66b5bc7 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingFacadeService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingFacadeService.java @@ -1,6 +1,7 @@ package com.gamegoo.gamegoo_v2.matching.service; import com.gamegoo.gamegoo_v2.account.member.domain.Member; +import com.gamegoo.gamegoo_v2.account.member.service.MemberService; import com.gamegoo.gamegoo_v2.chat.domain.Chatroom; import com.gamegoo.gamegoo_v2.chat.service.ChatCommandService; import com.gamegoo.gamegoo_v2.chat.service.ChatQueryService; @@ -8,6 +9,7 @@ import com.gamegoo.gamegoo_v2.core.common.validator.MemberValidator; import com.gamegoo.gamegoo_v2.core.exception.ChatException; import com.gamegoo.gamegoo_v2.core.exception.common.ErrorCode; +import com.gamegoo.gamegoo_v2.matching.dto.request.InitializingMatchingRequest; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -23,19 +25,26 @@ public class MatchingFacadeService { private final ChatCommandService chatCommandService; private final MemberValidator memberValidator; private final BlockValidator blockValidator; + private final MemberService memberService; /** * 매칭 우선순위 계산 및 기록 저장 API */ @Transactional - public String calculatePriorityAndRecording() { - // 현재 매칭 중인 matchingRecord 조회 + public String calculatePriorityAndRecording(Member member, InitializingMatchingRequest request) { + // 1. 매칭 정보로 member 업데이트 + // 마이크, 포지션 변경 + memberService.updateMikePosition(member, request.getMike(), request.getMainP(), request.getSubP(), + request.getWantP()); + // 게임스타일 변경 + memberService.updateGameStyle(member, request.getGameStyleIdList()); + + // 2. matchingRecord DB에 저장 - // 내 매칭 기록 생성 - // + // 3. 현재 대기 중인 사용자 조회 후, 해당 사용자와의 우선순위 계산 - return "response DTO 변경 예정"; + return "D"; } /** diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java index 4334c6e4..0f03ed92 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java @@ -9,4 +9,15 @@ @Transactional(readOnly = true) public class MatchingService { + private final MatchingPriorityCalculateService matchingPriorityCalculateService; + + //// TODO : 게임 모드, 매칭에 따라 우선순위 계산하는 서비스 + //public int calculatePriority() { + // + //} + + // TODO : 현재 PENDING 상태인 모든 매칭 대기자 조회 + + // TODO : Matching Record 데이터 추가 + } From 3e9ca64610a607b9d8c362f52164d18f391b8749 Mon Sep 17 00:00:00 2001 From: Rimi Date: Sun, 26 Jan 2025 18:30:47 +0900 Subject: [PATCH 10/28] =?UTF-8?q?:sparkles:=20[Feat]=20=EB=A7=A4=EC=B9=AD?= =?UTF-8?q?=20=EC=9A=B0=EC=84=A0=EC=88=9C=EC=9C=84=20=EA=B3=84=EC=82=B0=20?= =?UTF-8?q?Facade=20Service=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controller/MatchingController.java | 21 +-- .../matching/domain/MatchingRecord.java | 36 +++-- .../repository/MatchingRecordRepository.java | 29 ++++ .../service/MatchingFacadeService.java | 47 ++++-- .../matching/service/MatchingService.java | 153 +++++++++++++++++- 5 files changed, 246 insertions(+), 40 deletions(-) create mode 100644 src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepository.java diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/Controller/MatchingController.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/Controller/MatchingController.java index 6e5013c6..4d4caed0 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/Controller/MatchingController.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/Controller/MatchingController.java @@ -23,17 +23,18 @@ public class MatchingController { private final MatchingFacadeService matchingFacadeService; - @Operation(summary = "매칭 우선순위 계산 및 기록 저장 API", description = "API for calculating and recording matching \n\n" - + "gameMode: FAST, SOLO, FREE, ARAM string 을 넣어주세요. \n\n" - + "mike: UNAVAILABLE 또는 AVAILABLE 를 넣어주세요. \n\n" - + "matchingType: \"BASIC\" 또는 \"PRECISE\"를 넣어주세요.\n\n" - + "mainP: ANY, TOP, JUNGLE, MID, ADC, SUP string 을 넣어주세요. \n\n" - + "subP: ANY, TOP, JUNGLE, MID, ADC, SUP string 을 넣어주세요. \n\n" - + "wantP: ANY, TOP, JUNGLE, MID, ADC, SUP string 을 넣어주세요. \n\n" - + "gameStyleList: 1 ~ 17 int 를 넣어주세요.") + @Operation(summary = "매칭 우선순위 계산 및 기록 저장 API", description = """ + API for calculating and recording matching + gameMode: FAST, SOLO, FREE, ARAM string 을 넣어주세요.\s + mike: UNAVAILABLE 또는 AVAILABLE 를 넣어주세요.\s + matchingType: "BASIC" 또는 "PRECISE"를 넣어주세요. \s + mainP: ANY, TOP, JUNGLE, MID, ADC, SUP string 을 넣어주세요.\s + subP: ANY, TOP, JUNGLE, MID, ADC, SUP string 을 넣어주세요.\s + wantP: ANY, TOP, JUNGLE, MID, ADC, SUP string 을 넣어주세요.\s + gameStyleList: 1 ~ 17 int 를 넣어주세요.""") @GetMapping - public ApiResponse InitializeMatching(@AuthMember Member member, - InitializingMatchingRequest request) { + public ApiResponse InitializeMatching(@AuthMember Member member, + InitializingMatchingRequest request) { return ApiResponse.ok(matchingFacadeService.calculatePriorityAndRecording(member, request)); } diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/domain/MatchingRecord.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/domain/MatchingRecord.java index 8b73eb13..6b2c3d94 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/domain/MatchingRecord.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/domain/MatchingRecord.java @@ -13,8 +13,10 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.Index; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -23,6 +25,13 @@ @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table( + indexes = { + @Index(name = "idx_matching_record_created_at_status_game_mode", columnList = "createdAt, status, " + + "gameMode"), + @Index(name = "idx_matching_record_member_id", columnList = "member_id") + } +) public class MatchingRecord extends BaseDateTimeEntity { @Id @@ -93,24 +102,21 @@ public class MatchingRecord extends BaseDateTimeEntity { private Member targetMember; // MatchingRecord 생성 메서드 - public static MatchingRecord create(GameMode gameMode, Position mainPosition, Position subPosition, - Position wantPosition, Mike mike, Tier soloTier, int soloRank, - double soloWinRate, Tier freeTier, int freeRank, double freeWinRate, - MatchingType matchingType, int mannerLevel, Member member) { + public static MatchingRecord create(GameMode gameMode, MatchingType matchingType, Member member) { return MatchingRecord.builder() .gameMode(gameMode) - .mainPosition(mainPosition) - .subPosition(subPosition) - .wantPosition(wantPosition) - .mike(mike) - .soloTier(soloTier) - .soloRank(soloRank) - .soloWinRate(soloWinRate) - .freeTier(freeTier) - .freeRank(freeRank) - .freeWinRate(freeWinRate) + .mainPosition(member.getMainPosition()) + .subPosition(member.getSubPosition()) + .wantPosition(member.getWantPosition()) + .mike(member.getMike()) + .soloTier(member.getTier()) // TODO: + .soloRank(member.getGameRank()) // TODO: + .soloWinRate(member.getWinRate()) // TODO: + .freeTier(member.getTier()) // TODO: + .freeRank(member.getGameRank()) // TODO: + .freeWinRate(member.getWinRate()) // TODO: .matchingType(matchingType) - .mannerLevel(mannerLevel) + .mannerLevel(member.getMannerLevel()) .member(member) .build(); } diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepository.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepository.java new file mode 100644 index 00000000..f61f299d --- /dev/null +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepository.java @@ -0,0 +1,29 @@ +package com.gamegoo.gamegoo_v2.matching.repository; + +import com.gamegoo.gamegoo_v2.matching.domain.GameMode; +import com.gamegoo.gamegoo_v2.matching.domain.MatchingRecord; +import com.gamegoo.gamegoo_v2.matching.domain.MatchingStatus; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.time.LocalDateTime; +import java.util.List; + +public interface MatchingRecordRepository extends JpaRepository { + + @Query(value = """ + SELECT m + FROM MatchingRecord m + WHERE m.createdAt > :createdAt + AND m.status = :status + AND m.gameMode = :gameMode + GROUP BY m.member.id + """) + List findMatchingRecordsWithGroupBy( + @Param("createdAt") LocalDateTime createdAt, + @Param("status") MatchingStatus status, + @Param("gameMode") GameMode gameMode + ); + +} diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingFacadeService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingFacadeService.java index e66b5bc7..119b6fc0 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingFacadeService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingFacadeService.java @@ -9,12 +9,18 @@ import com.gamegoo.gamegoo_v2.core.common.validator.MemberValidator; import com.gamegoo.gamegoo_v2.core.exception.ChatException; import com.gamegoo.gamegoo_v2.core.exception.common.ErrorCode; +import com.gamegoo.gamegoo_v2.matching.domain.MatchingRecord; import com.gamegoo.gamegoo_v2.matching.dto.request.InitializingMatchingRequest; +import com.gamegoo.gamegoo_v2.matching.dto.response.PriorityListResponse; +import com.gamegoo.gamegoo_v2.social.block.service.BlockService; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; @Service @RequiredArgsConstructor @@ -26,25 +32,48 @@ public class MatchingFacadeService { private final MemberValidator memberValidator; private final BlockValidator blockValidator; private final MemberService memberService; + private final MatchingService matchingService; + private final BlockService blockService; /** * 매칭 우선순위 계산 및 기록 저장 API */ @Transactional - public String calculatePriorityAndRecording(Member member, InitializingMatchingRequest request) { + public PriorityListResponse calculatePriorityAndRecording(Member member, InitializingMatchingRequest request) { // 1. 매칭 정보로 member 업데이트 - // 마이크, 포지션 변경 + // 1-1. 마이크, 포지션 변경 memberService.updateMikePosition(member, request.getMike(), request.getMainP(), request.getSubP(), request.getWantP()); - // 게임스타일 변경 + // 1-2. 게임스타일 변경 memberService.updateGameStyle(member, request.getGameStyleIdList()); - - // 2. matchingRecord DB에 저장 - - // 3. 현재 대기 중인 사용자 조회 후, 해당 사용자와의 우선순위 계산 - - return "D"; + // 2. matchingRecord DB에 저장 + MatchingRecord matchingRecord = matchingService.createMatchingRecord(member, request.getMatchingType(), + request.getGameMode()); + + // 3. 현재 대기 중인 사용자 조회 + List pendingMatchingRecords = matchingService.getPENDINGMatchingRecords(request.getGameMode()); + + // 4. 차단당한 사용자 제외 + List targetMemberIds = new ArrayList<>(); + for (MatchingRecord record : pendingMatchingRecords) { + targetMemberIds.add(record.getMember().getId()); + } + + // 차단 여부 확인 + Map blockedStatusMap = blockService.isBlockedByTargetMembersBatch(member, targetMemberIds); + + // 차단되지 않은 사용자만 필터링 + List filteredPENDINGMatchingRecords = new ArrayList<>(); + for (MatchingRecord record : pendingMatchingRecords) { + Long targetMemberId = record.getMember().getId(); + if (!blockedStatusMap.getOrDefault(targetMemberId, false)) { + filteredPENDINGMatchingRecords.add(record); + } + } + + // 5. myPriorityList, otherPriorityList 조회 + return matchingService.calculatePriorityList(matchingRecord, filteredPENDINGMatchingRecords); } /** diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java index 0f03ed92..fda43719 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java @@ -1,23 +1,164 @@ package com.gamegoo.gamegoo_v2.matching.service; +import com.gamegoo.gamegoo_v2.account.member.domain.Member; +import com.gamegoo.gamegoo_v2.matching.domain.GameMode; +import com.gamegoo.gamegoo_v2.matching.domain.MatchingRecord; +import com.gamegoo.gamegoo_v2.matching.domain.MatchingStatus; +import com.gamegoo.gamegoo_v2.matching.domain.MatchingType; +import com.gamegoo.gamegoo_v2.matching.dto.PriorityValue; +import com.gamegoo.gamegoo_v2.matching.dto.response.PriorityListResponse; +import com.gamegoo.gamegoo_v2.matching.repository.MatchingRecordRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + @Service @RequiredArgsConstructor @Transactional(readOnly = true) public class MatchingService { private final MatchingPriorityCalculateService matchingPriorityCalculateService; + private final MatchingRecordRepository matchingRecordRepository; + + public PriorityListResponse calculatePriorityList(MatchingRecord myMatchingRecord, + List otherMatchingRecords) { + // 우선순위 리스트 초기화 + List myPriorityList = new ArrayList<>(); + List otherPriorityList = new ArrayList<>(); + + for (MatchingRecord otherRecord : otherMatchingRecords) { + Long otherMemberId = otherRecord.getMember().getId(); + + // 자신이 아닌 다른 멤버와 비교 + if (!myMatchingRecord.getMember().getId().equals(otherMemberId)) { + // 나의 우선순위 계산 + int otherPriority = calculatePriority(myMatchingRecord.getGameMode(), myMatchingRecord, otherRecord); + myPriorityList.add(PriorityValue.of(otherMemberId, otherRecord.getMatchingUuid(), otherPriority)); + + // 상대방 관점에서 나의 우선순위 계산 + int myPriority = calculatePriority(myMatchingRecord.getGameMode(), otherRecord, myMatchingRecord); + otherPriorityList.add(PriorityValue.of(myMatchingRecord.getMember().getId(), + myMatchingRecord.getMatchingUuid(), myPriority)); + } + } + + // PriorityListResponse 반환 + return PriorityListResponse.of(myPriorityList, otherPriorityList, myMatchingRecord.getMember(), + myMatchingRecord.getMatchingUuid()); + } + + + public int calculatePriority(GameMode gameMode, MatchingRecord myRecord, MatchingRecord otherRecord) { + return switch (gameMode) { + case SOLO -> + // 개인 랭크 모드 우선순위 계산 + matchingPriorityCalculateService.calculateSoloPriority( + myRecord.getMainPosition(), + myRecord.getSubPosition(), + myRecord.getWantPosition(), + otherRecord.getMainPosition(), + otherRecord.getSubPosition(), + otherRecord.getWantPosition(), + myRecord.getMike(), + otherRecord.getMike(), + myRecord.getMannerLevel(), + otherRecord.getMannerLevel(), + myRecord.getSoloTier(), + myRecord.getSoloRank(), + otherRecord.getSoloTier(), + otherRecord.getSoloRank() + ); + case FREE -> + // 자유 랭크 모드 우선순위 계산 + matchingPriorityCalculateService.calculateFreePriority( + myRecord.getMainPosition(), + myRecord.getSubPosition(), + myRecord.getWantPosition(), + otherRecord.getMainPosition(), + otherRecord.getSubPosition(), + otherRecord.getWantPosition(), + myRecord.getMike(), + otherRecord.getMike(), + myRecord.getMannerLevel(), + otherRecord.getMannerLevel(), + myRecord.getFreeTier(), + myRecord.getFreeRank(), + otherRecord.getFreeTier(), + otherRecord.getFreeRank() + ); + case ARAM -> + // 칼바람 모드 우선순위 계산 + matchingPriorityCalculateService.calculateAramPriority( + myRecord.getWantPosition(), + otherRecord.getMainPosition(), + otherRecord.getSubPosition(), + myRecord.getMike(), + otherRecord.getMike(), + myRecord.getMannerLevel(), + otherRecord.getMannerLevel(), + myRecord.getSoloTier(), + myRecord.getSoloRank(), + otherRecord.getSoloTier(), + otherRecord.getSoloRank() + ); + case FAST -> + // 빠른대전 우선순위 계산 + matchingPriorityCalculateService.calculateFastPriority( + myRecord.getMainPosition(), + myRecord.getSubPosition(), + myRecord.getWantPosition(), + otherRecord.getMainPosition(), + otherRecord.getSubPosition(), + otherRecord.getWantPosition(), + myRecord.getMike(), + otherRecord.getMike(), + myRecord.getMannerLevel(), + otherRecord.getMannerLevel(), + myRecord.getSoloTier(), + myRecord.getSoloRank(), + myRecord.getFreeTier(), + myRecord.getFreeRank(), + otherRecord.getSoloTier(), + otherRecord.getSoloRank(), + otherRecord.getFreeTier(), + otherRecord.getFreeRank() + ); + }; + } + + + /** + * 매칭 대기 중인 Matching Records List 조회 + * + * @param gameMode 게임모드 + * @return 대기 중인 매칭 리스트 + */ + public List getPENDINGMatchingRecords(GameMode gameMode) { + LocalDateTime fiveMinutesAgo = LocalDateTime.now().minusMinutes(5); - //// TODO : 게임 모드, 매칭에 따라 우선순위 계산하는 서비스 - //public int calculatePriority() { - // - //} + return matchingRecordRepository.findMatchingRecordsWithGroupBy( + fiveMinutesAgo, + MatchingStatus.PENDING, + gameMode + ); - // TODO : 현재 PENDING 상태인 모든 매칭 대기자 조회 + } - // TODO : Matching Record 데이터 추가 + /** + * 매칭기록 생성 및 DB 저장 + * + * @param member 회원 + * @param matchingType 매칭 유형 + * @param gameMode 게임 모드 + * @return 매칭 기록 + */ + public MatchingRecord createMatchingRecord(Member member, MatchingType matchingType, GameMode gameMode) { + MatchingRecord matchingRecord = MatchingRecord.create(gameMode, matchingType, member); + return matchingRecordRepository.save(matchingRecord); + } } From 3c2b9dbc2929b15f25b953faeae7383bf4d3eb85 Mon Sep 17 00:00:00 2001 From: Rimi Date: Sun, 26 Jan 2025 19:19:20 +0900 Subject: [PATCH 11/28] =?UTF-8?q?:sparkles:=20[Feat]=20=EC=A0=9C=ED=95=9C?= =?UTF-8?q?=20=EC=A1=B0=EA=B1=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MatchingPriorityCalculateService.java | 32 +++++++++++++++---- .../matching/service/MatchingService.java | 29 +++++++++++------ 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityCalculateService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityCalculateService.java index 10d120af..f4f2e302 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityCalculateService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityCalculateService.java @@ -111,9 +111,7 @@ public int calculateFreePriority(Position myMainP, Position mySubP, Position myW /** * 칼바람 모드 우선순위 계산 */ - public int calculateAramPriority(Position myWantPosition, Position otherMainPosition, Position otherSubPosition, - Mike myMike, Mike otherMike, Integer myManner, Integer otherManner, - Tier myTier, Integer myRank, Tier otherTier, Integer otherRank) { + public int calculateAramPriority(Mike myMike, Mike otherMike, Integer myManner, Integer otherManner) { int priority = 0; // 매너 우선순위 @@ -125,19 +123,39 @@ public int calculateAramPriority(Position myWantPosition, Position otherMainPosi return priority; } + public boolean validateMatching(Position myMainP, Position mySubP, Position myWantP, Position otherMainP, + Position otherSubP, Position otherWantP) { + // 1. + // 1.1 A의 찾는 포지션(myWantP)이 B의 부 포지션(otherSubP)일 경우 + if ((myMainP == otherSubP || otherMainP == mySubP) && myWantP == otherSubP) { + return true; + } + + // 1.2 B의 찾는 포지션(otherWantP)이 A의 부 포지션(mySubP)일 경우 + if ((otherMainP == mySubP || myMainP == otherSubP) && otherWantP == mySubP) { + return true; + } + + // 2. 주/부 포지션이 순서 상관없이 겹칠 경우 false 반환 + if ((myMainP == otherMainP || myMainP == otherSubP) && (mySubP == otherMainP || mySubP == otherSubP)) { + return false; + } + + return true; + } + /** * 정밀 매칭 검증 메서드 */ - public boolean validatePreciseMatching(Mike myMike, Mike otherMike, Position myWantPosition, - Position otherMainPosition, Position otherSubPosition, - Tier myTier, Tier otherTier) { + public boolean validatePreciseMatching(Mike myMike, Mike otherMike, Position myWantP, Position otherMainP, + Position otherSubP, Tier myTier, Tier otherTier) { // 마이크가 다를 경우 매칭 실패 if (!myMike.equals(otherMike)) { return false; } // 내가 원하는 포지션이 상대 포지션이 아닐 경우 매칭 실패 - if (!otherMainPosition.equals(myWantPosition) && !otherSubPosition.equals(myWantPosition)) { + if (!otherMainP.equals(myWantP) && !otherSubP.equals(myWantP)) { return false; } diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java index fda43719..3417d3ed 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java @@ -53,6 +53,25 @@ public PriorityListResponse calculatePriorityList(MatchingRecord myMatchingRecor public int calculatePriority(GameMode gameMode, MatchingRecord myRecord, MatchingRecord otherRecord) { + // 공통 조건 + if (!matchingPriorityCalculateService.validateMatching(myRecord.getMainPosition(), myRecord.getSubPosition(), + myRecord.getWantPosition(), otherRecord.getMainPosition(), otherRecord.getSubPosition(), + otherRecord.getWantPosition())) { + return 0; + } + + // 정밀 매칭 + if (myRecord.getMatchingType() == MatchingType.PRECISE) { + if (matchingPriorityCalculateService.validatePreciseMatching(myRecord.getMike(), otherRecord.getMike(), + myRecord.getWantPosition(), otherRecord.getMainPosition(), otherRecord.getSubPosition(), + myRecord.getSoloTier(), otherRecord.getSoloTier())) { + return matchingPriorityCalculateService.calculatePrecisePriority(myRecord.getMannerLevel(), + otherRecord.getMannerLevel()); + } + return 0; + } + + // 겜구 매칭 return switch (gameMode) { case SOLO -> // 개인 랭크 모드 우선순위 계산 @@ -93,18 +112,10 @@ public int calculatePriority(GameMode gameMode, MatchingRecord myRecord, Matchin case ARAM -> // 칼바람 모드 우선순위 계산 matchingPriorityCalculateService.calculateAramPriority( - myRecord.getWantPosition(), - otherRecord.getMainPosition(), - otherRecord.getSubPosition(), myRecord.getMike(), otherRecord.getMike(), myRecord.getMannerLevel(), - otherRecord.getMannerLevel(), - myRecord.getSoloTier(), - myRecord.getSoloRank(), - otherRecord.getSoloTier(), - otherRecord.getSoloRank() - ); + otherRecord.getMannerLevel()); case FAST -> // 빠른대전 우선순위 계산 matchingPriorityCalculateService.calculateFastPriority( From 87d435b127455ffe658463806da6c10b6e3adfc8 Mon Sep 17 00:00:00 2001 From: Rimi Date: Sun, 26 Jan 2025 23:54:54 +0900 Subject: [PATCH 12/28] =?UTF-8?q?:bug:=20[fix]=20=EC=9A=B0=EC=84=A0?= =?UTF-8?q?=EC=88=9C=EC=9C=84=20API=20=EA=B5=AC=ED=98=84=20=EC=95=88?= =?UTF-8?q?=EB=90=98=EB=8A=94=EA=B1=B0=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/service/MemberFacadeService.java | 3 +- .../service/MemberGameStyleService.java | 30 +++++++++++++++---- .../account/member/service/MemberService.java | 23 -------------- .../Controller/MatchingController.java | 27 +++++++---------- .../matching/domain/MatchingRecord.java | 3 +- .../request/InitializingMatchingRequest.java | 2 +- .../service/MatchingFacadeService.java | 23 ++++++++------ .../MatchingPriorityEvaluateService.java | 8 ++--- .../matching/service/MatchingService.java | 1 - 9 files changed, 55 insertions(+), 65 deletions(-) diff --git a/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberFacadeService.java b/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberFacadeService.java index 6f30da67..e15ae481 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberFacadeService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberFacadeService.java @@ -21,6 +21,7 @@ public class MemberFacadeService { private final MemberService memberService; private final FriendService friendService; private final BlockService blockService; + private final MemberGameStyleService memberGameStyleService; /** * 내 프로필 조회 @@ -110,7 +111,7 @@ public String setPosition(Member member, PositionRequest request) { */ @Transactional public String setGameStyle(Member member, GameStyleRequest request) { - memberService.updateGameStyle(member, request.getGameStyleIdList()); + memberGameStyleService.updateGameStyle(member, request.getGameStyleIdList()); return "게임 스타일 수정이 완료되었습니다"; } diff --git a/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberGameStyleService.java b/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberGameStyleService.java index ba36dfdc..f2838fb2 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberGameStyleService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberGameStyleService.java @@ -22,13 +22,31 @@ public class MemberGameStyleService { private final GameStyleRepository gameStyleRepository; private final MemberGameStyleRepository memberGameStyleRepository; + /** + * @param member 회원 + * @param gameStyleIdList 수정할 게임 스타일 리스트 + */ + @Transactional + public void updateGameStyle(Member member, List gameStyleIdList) { + // request의 Gamestyle 조회 + List requestGameStyleList = findRequestGameStyle(gameStyleIdList); + + // 현재 DB의 GameStyle 조회 + List currentMemberGameStyleList = findCurrentMemberGameStyleList(member); + + // request에 없고, DB에 있는 GameStyle 삭제 + removeUnnecessaryGameStyles(member, requestGameStyleList, currentMemberGameStyleList); + + // request에 있고, DB에 없는 GameStyle 추가 + addNewGameStyles(member, requestGameStyleList, currentMemberGameStyleList); + } /** * request id로 GameStyle Entity 조회 * * @return request의 GamestyleList */ - public List findRequestGameStyle(List gameStyleIdList) { + private List findRequestGameStyle(List gameStyleIdList) { return gameStyleIdList.stream() .map(id -> gameStyleRepository.findById(id).orElseThrow(() -> new MemberException(ErrorCode.GAMESTYLE_NOT_FOUND))) .toList(); @@ -39,7 +57,7 @@ public List findRequestGameStyle(List gameStyleIdList) { * * @return MemberGameStyleList */ - public List findCurrentMemberGameStyleList(Member member) { + private List findCurrentMemberGameStyleList(Member member) { return new ArrayList<>(member.getMemberGameStyleList()); } @@ -51,8 +69,8 @@ public List findCurrentMemberGameStyleList(Member member) { * @param currentMemberGameStyles 현재 Gamestyle */ @Transactional - public void removeUnnecessaryGameStyles(Member member, List requestedGameStyles, - List currentMemberGameStyles) { + protected void removeUnnecessaryGameStyles(Member member, List requestedGameStyles, + List currentMemberGameStyles) { currentMemberGameStyles.stream() .filter(mgs -> !requestedGameStyles.contains(mgs.getGameStyle())) .forEach(mgs -> { @@ -69,8 +87,8 @@ public void removeUnnecessaryGameStyles(Member member, List requested * @param currentMemberGameStyles 변경 전 게임스타일 */ @Transactional - public void addNewGameStyles(Member member, List requestedGameStyles, - List currentMemberGameStyles) { + protected void addNewGameStyles(Member member, List requestedGameStyles, + List currentMemberGameStyles) { List currentGameStyles = currentMemberGameStyles.stream() .map(MemberGameStyle::getGameStyle) .toList(); diff --git a/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberService.java b/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberService.java index fb0d5db8..1c246726 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberService.java @@ -2,21 +2,17 @@ import com.gamegoo.gamegoo_v2.account.member.domain.LoginType; import com.gamegoo.gamegoo_v2.account.member.domain.Member; -import com.gamegoo.gamegoo_v2.account.member.domain.MemberGameStyle; import com.gamegoo.gamegoo_v2.account.member.domain.Mike; import com.gamegoo.gamegoo_v2.account.member.domain.Position; import com.gamegoo.gamegoo_v2.account.member.domain.Tier; import com.gamegoo.gamegoo_v2.account.member.repository.MemberRepository; import com.gamegoo.gamegoo_v2.core.exception.MemberException; import com.gamegoo.gamegoo_v2.core.exception.common.ErrorCode; -import com.gamegoo.gamegoo_v2.game.domain.GameStyle; import com.gamegoo.gamegoo_v2.utils.PasswordUtil; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; - @Service @RequiredArgsConstructor @Transactional(readOnly = true) @@ -125,25 +121,6 @@ public void setPosition(Member member, Position mainPosition, Position subPositi member.updatePosition(mainPosition, subPosition, wantPosition); } - /** - * @param member 회원 - * @param gameStyleIdList 수정할 게임 스타일 리스트 - */ - @Transactional - public void updateGameStyle(Member member, List gameStyleIdList) { - // request의 Gamestyle 조회 - List requestGameStyleList = memberGameStyleService.findRequestGameStyle(gameStyleIdList); - - // 현재 DB의 GameStyle 조회 - List currentMemberGameStyleList = - memberGameStyleService.findCurrentMemberGameStyleList(member); - - // request에 없고, DB에 있는 GameStyle 삭제 - memberGameStyleService.removeUnnecessaryGameStyles(member, requestGameStyleList, currentMemberGameStyleList); - - // request에 있고, DB에 없는 GameStyle 추가 - memberGameStyleService.addNewGameStyles(member, requestGameStyleList, currentMemberGameStyleList); - } @Transactional public void updateMikePosition(Member member, Mike mike, Position mainP, Position subP, Position wantP) { diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/Controller/MatchingController.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/Controller/MatchingController.java index 4d4caed0..33f1fe9f 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/Controller/MatchingController.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/Controller/MatchingController.java @@ -1,41 +1,34 @@ package com.gamegoo.gamegoo_v2.matching.Controller; -import com.gamegoo.gamegoo_v2.account.auth.annotation.AuthMember; -import com.gamegoo.gamegoo_v2.account.member.domain.Member; import com.gamegoo.gamegoo_v2.core.common.ApiResponse; import com.gamegoo.gamegoo_v2.matching.dto.request.InitializingMatchingRequest; import com.gamegoo.gamegoo_v2.matching.dto.response.PriorityListResponse; import com.gamegoo.gamegoo_v2.matching.service.MatchingFacadeService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @Tag(name = "Matching", description = "매칭 정보 관련 API") @RestController @RequiredArgsConstructor -@RequestMapping("/api/v2/internal/matching") +@RequestMapping("/api/v2/internal") @Validated public class MatchingController { private final MatchingFacadeService matchingFacadeService; - @Operation(summary = "매칭 우선순위 계산 및 기록 저장 API", description = """ - API for calculating and recording matching - gameMode: FAST, SOLO, FREE, ARAM string 을 넣어주세요.\s - mike: UNAVAILABLE 또는 AVAILABLE 를 넣어주세요.\s - matchingType: "BASIC" 또는 "PRECISE"를 넣어주세요. \s - mainP: ANY, TOP, JUNGLE, MID, ADC, SUP string 을 넣어주세요.\s - subP: ANY, TOP, JUNGLE, MID, ADC, SUP string 을 넣어주세요.\s - wantP: ANY, TOP, JUNGLE, MID, ADC, SUP string 을 넣어주세요.\s - gameStyleList: 1 ~ 17 int 를 넣어주세요.""") - @GetMapping - public ApiResponse InitializeMatching(@AuthMember Member member, - InitializingMatchingRequest request) { - return ApiResponse.ok(matchingFacadeService.calculatePriorityAndRecording(member, request)); + @Operation(summary = "매칭 우선순위 계산 및 기록 저장 API", description = "API for calculating and recording matching") + @PostMapping("/matching/priority/{memberId}") + public ApiResponse InitializeMatching(@PathVariable(name = "memberId") Long memberId, + @RequestBody @Valid InitializingMatchingRequest request) { + return ApiResponse.ok(matchingFacadeService.calculatePriorityAndRecording(memberId, request)); } } diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/domain/MatchingRecord.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/domain/MatchingRecord.java index 6b2c3d94..218715fc 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/domain/MatchingRecord.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/domain/MatchingRecord.java @@ -98,7 +98,7 @@ public class MatchingRecord extends BaseDateTimeEntity { private Member member; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "target_id", nullable = false) + @JoinColumn(name = "target_id") private Member targetMember; // MatchingRecord 생성 메서드 @@ -141,6 +141,7 @@ private MatchingRecord(GameMode gameMode, Position mainPosition, Position subPos this.matchingType = matchingType; this.mannerLevel = mannerLevel; this.member = member; + this.targetMember = null; } // status 변경 diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/request/InitializingMatchingRequest.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/request/InitializingMatchingRequest.java index 9f3f683c..aebd17e7 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/request/InitializingMatchingRequest.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/request/InitializingMatchingRequest.java @@ -18,7 +18,7 @@ public class InitializingMatchingRequest { @NotNull(message = "mike 는 비워둘 수 없습니다.") Mike mike; - @NotNull(message = "matching_type은 비워둘 수 없습니다.") + @NotNull(message = "matchingType은 비워둘 수 없습니다.") MatchingType matchingType; Position mainP; diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingFacadeService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingFacadeService.java index 119b6fc0..e9436076 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingFacadeService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingFacadeService.java @@ -1,6 +1,7 @@ package com.gamegoo.gamegoo_v2.matching.service; import com.gamegoo.gamegoo_v2.account.member.domain.Member; +import com.gamegoo.gamegoo_v2.account.member.service.MemberGameStyleService; import com.gamegoo.gamegoo_v2.account.member.service.MemberService; import com.gamegoo.gamegoo_v2.chat.domain.Chatroom; import com.gamegoo.gamegoo_v2.chat.service.ChatCommandService; @@ -34,27 +35,31 @@ public class MatchingFacadeService { private final MemberService memberService; private final MatchingService matchingService; private final BlockService blockService; + private final MemberGameStyleService memberGameStyleService; /** * 매칭 우선순위 계산 및 기록 저장 API */ @Transactional - public PriorityListResponse calculatePriorityAndRecording(Member member, InitializingMatchingRequest request) { - // 1. 매칭 정보로 member 업데이트 - // 1-1. 마이크, 포지션 변경 + public PriorityListResponse calculatePriorityAndRecording(Long memberId, InitializingMatchingRequest request) { + // 사용자 조회 + Member member = memberService.findMemberById(memberId); + + // 매칭 정보로 member 업데이트 + // 마이크, 포지션 변경 memberService.updateMikePosition(member, request.getMike(), request.getMainP(), request.getSubP(), request.getWantP()); - // 1-2. 게임스타일 변경 - memberService.updateGameStyle(member, request.getGameStyleIdList()); + // 게임스타일 변경 + memberGameStyleService.updateGameStyle(member, request.getGameStyleIdList()); - // 2. matchingRecord DB에 저장 + // matchingRecord DB에 저장 MatchingRecord matchingRecord = matchingService.createMatchingRecord(member, request.getMatchingType(), request.getGameMode()); - // 3. 현재 대기 중인 사용자 조회 + // 현재 대기 중인 사용자 조회 List pendingMatchingRecords = matchingService.getPENDINGMatchingRecords(request.getGameMode()); - // 4. 차단당한 사용자 제외 + // 차단당한 사용자 제외 List targetMemberIds = new ArrayList<>(); for (MatchingRecord record : pendingMatchingRecords) { targetMemberIds.add(record.getMember().getId()); @@ -72,7 +77,7 @@ public PriorityListResponse calculatePriorityAndRecording(Member member, Initial } } - // 5. myPriorityList, otherPriorityList 조회 + // myPriorityList, otherPriorityList 조회 return matchingService.calculatePriorityList(matchingRecord, filteredPENDINGMatchingRecords); } diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityEvaluateService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityEvaluateService.java index c0c7b5bc..9be66bb2 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityEvaluateService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityEvaluateService.java @@ -3,13 +3,9 @@ import com.gamegoo.gamegoo_v2.account.member.domain.Position; import com.gamegoo.gamegoo_v2.account.member.domain.Tier; import com.gamegoo.gamegoo_v2.account.member.domain.Mike; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; +import org.springframework.stereotype.Component; -@Service -@RequiredArgsConstructor -@Transactional(readOnly = true) +@Component public class MatchingPriorityEvaluateService { /** diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java index 3417d3ed..4d6c483f 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java @@ -32,7 +32,6 @@ public PriorityListResponse calculatePriorityList(MatchingRecord myMatchingRecor for (MatchingRecord otherRecord : otherMatchingRecords) { Long otherMemberId = otherRecord.getMember().getId(); - // 자신이 아닌 다른 멤버와 비교 if (!myMatchingRecord.getMember().getId().equals(otherMemberId)) { // 나의 우선순위 계산 From d2c828c33213ec1ca904f1d16c26e0de621d7f64 Mon Sep 17 00:00:00 2001 From: Rimi Date: Mon, 27 Jan 2025 00:03:34 +0900 Subject: [PATCH 13/28] =?UTF-8?q?:bug:=20[fix]=20PENDING->Pending,=20Membe?= =?UTF-8?q?rService,=20MemberGameStyleService=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gamegoo_v2/account/member/service/MemberService.java | 1 - .../gamegoo_v2/matching/service/MatchingFacadeService.java | 2 +- .../gamegoo/gamegoo_v2/matching/service/MatchingService.java | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberService.java b/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberService.java index 1c246726..c9a6b00c 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/account/member/service/MemberService.java @@ -19,7 +19,6 @@ public class MemberService { private final MemberRepository memberRepository; - private final MemberGameStyleService memberGameStyleService; /** * Member 생성 메소드 diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingFacadeService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingFacadeService.java index e9436076..788a8b2a 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingFacadeService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingFacadeService.java @@ -57,7 +57,7 @@ public PriorityListResponse calculatePriorityAndRecording(Long memberId, Initial request.getGameMode()); // 현재 대기 중인 사용자 조회 - List pendingMatchingRecords = matchingService.getPENDINGMatchingRecords(request.getGameMode()); + List pendingMatchingRecords = matchingService.getPendingMatchingRecords(request.getGameMode()); // 차단당한 사용자 제외 List targetMemberIds = new ArrayList<>(); diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java index 4d6c483f..24123e5e 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java @@ -147,7 +147,7 @@ public int calculatePriority(GameMode gameMode, MatchingRecord myRecord, Matchin * @param gameMode 게임모드 * @return 대기 중인 매칭 리스트 */ - public List getPENDINGMatchingRecords(GameMode gameMode) { + public List getPendingMatchingRecords(GameMode gameMode) { LocalDateTime fiveMinutesAgo = LocalDateTime.now().minusMinutes(5); return matchingRecordRepository.findMatchingRecordsWithGroupBy( From 52ce6d9156fae2398121cb9daaf2b49ea12127c4 Mon Sep 17 00:00:00 2001 From: Rimi Date: Sat, 1 Feb 2025 16:37:27 +0900 Subject: [PATCH 14/28] =?UTF-8?q?:sparkles:=20[Feat]=20=EA=B2=9C=EA=B5=AC?= =?UTF-8?q?=EB=A7=A4=EC=B9=AD=20DB=20=EC=A1=B0=ED=9A=8C=ED=95=A0=20?= =?UTF-8?q?=EB=95=8C,=20=EC=A1=B0=EA=B1=B4=20=EC=A0=9C=EC=99=B8=ED=95=98?= =?UTF-8?q?=EA=B3=A0=20=EC=A1=B0=ED=9A=8C=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../matching/domain/MatchingRecord.java | 9 - .../repository/MatchingRecordRepository.java | 25 +-- .../MatchingRecordRepositoryCustom.java | 20 ++ .../MatchingRecordRepositoryCustomImpl.java | 130 ++++++++++++ .../MatchingPriorityCalculateService.java | 196 ------------------ ...vice.java => MatchingScoreCalculator.java} | 11 +- .../matching/service/MatchingService.java | 88 +------- .../service/MatchingStrategyProcessor.java | 137 ++++++++++++ 8 files changed, 307 insertions(+), 309 deletions(-) create mode 100644 src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepositoryCustom.java create mode 100644 src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepositoryCustomImpl.java delete mode 100644 src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityCalculateService.java rename src/main/java/com/gamegoo/gamegoo_v2/matching/service/{MatchingPriorityEvaluateService.java => MatchingScoreCalculator.java} (91%) create mode 100644 src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingStrategyProcessor.java diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/domain/MatchingRecord.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/domain/MatchingRecord.java index 218715fc..33bf8d59 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/domain/MatchingRecord.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/domain/MatchingRecord.java @@ -13,10 +13,8 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import jakarta.persistence.Index; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; -import jakarta.persistence.Table; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -25,13 +23,6 @@ @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -@Table( - indexes = { - @Index(name = "idx_matching_record_created_at_status_game_mode", columnList = "createdAt, status, " + - "gameMode"), - @Index(name = "idx_matching_record_member_id", columnList = "member_id") - } -) public class MatchingRecord extends BaseDateTimeEntity { @Id diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepository.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepository.java index f61f299d..12ddb666 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepository.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepository.java @@ -2,28 +2,19 @@ import com.gamegoo.gamegoo_v2.matching.domain.GameMode; import com.gamegoo.gamegoo_v2.matching.domain.MatchingRecord; -import com.gamegoo.gamegoo_v2.matching.domain.MatchingStatus; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; import java.time.LocalDateTime; import java.util.List; -public interface MatchingRecordRepository extends JpaRepository { +public interface MatchingRecordRepository extends JpaRepository, + MatchingRecordRepositoryCustom { - @Query(value = """ - SELECT m - FROM MatchingRecord m - WHERE m.createdAt > :createdAt - AND m.status = :status - AND m.gameMode = :gameMode - GROUP BY m.member.id - """) - List findMatchingRecordsWithGroupBy( - @Param("createdAt") LocalDateTime createdAt, - @Param("status") MatchingStatus status, - @Param("gameMode") GameMode gameMode - ); + /** + * 5분 이내, 특정 게임 모드, PENDING 상태의 매칭 레코드 조회 + */ + default List findRecentValidMatchingRecords(GameMode gameMode) { + return findValidMatchingRecords(LocalDateTime.now().minusMinutes(5), gameMode); + } } diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepositoryCustom.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepositoryCustom.java new file mode 100644 index 00000000..25411c6f --- /dev/null +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepositoryCustom.java @@ -0,0 +1,20 @@ +package com.gamegoo.gamegoo_v2.matching.repository; + +import com.gamegoo.gamegoo_v2.matching.domain.GameMode; +import com.gamegoo.gamegoo_v2.matching.domain.MatchingRecord; + +import java.time.LocalDateTime; +import java.util.List; + +public interface MatchingRecordRepositoryCustom { + + /** + * 매칭 가능한 유효한 레코드 조회 (5분 이내, 특정 게임 모드, PENDING 상태) + * + * @param createdAt 5분 전 시간 기준 + * @param gameMode 게임 모드 + * @return 매칭 가능한 레코드 리스트 + */ + List findValidMatchingRecords(LocalDateTime createdAt, GameMode gameMode); + +} diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepositoryCustomImpl.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepositoryCustomImpl.java new file mode 100644 index 00000000..240e0e02 --- /dev/null +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepositoryCustomImpl.java @@ -0,0 +1,130 @@ +package com.gamegoo.gamegoo_v2.matching.repository; + +import com.gamegoo.gamegoo_v2.matching.domain.GameMode; +import com.gamegoo.gamegoo_v2.account.member.domain.Position; +import com.gamegoo.gamegoo_v2.matching.domain.MatchingRecord; +import com.gamegoo.gamegoo_v2.matching.domain.MatchingStatus; +import com.gamegoo.gamegoo_v2.account.member.domain.Tier; +import com.gamegoo.gamegoo_v2.matching.domain.QMatchingRecord; +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.core.types.dsl.EnumPath; +import com.querydsl.core.types.dsl.Expressions; +import com.querydsl.jpa.impl.JPAQueryFactory; +import com.querydsl.jpa.JPAExpressions; +import lombok.RequiredArgsConstructor; + +import java.time.LocalDateTime; +import java.util.List; + +import static com.gamegoo.gamegoo_v2.matching.domain.QMatchingRecord.matchingRecord; + +@RequiredArgsConstructor +public class MatchingRecordRepositoryCustomImpl implements MatchingRecordRepositoryCustom { + + private final JPAQueryFactory queryFactory; + + @Override + public List findValidMatchingRecords(LocalDateTime createdAt, GameMode gameMode) { + return queryFactory.selectFrom(matchingRecord) + .where( + matchingRecord.createdAt.gt(createdAt), // 5분 이내 + matchingRecord.status.eq(MatchingStatus.PENDING), // 상태 PENDING + matchingRecord.gameMode.eq(gameMode), // 특정 게임 모드 + existsValidMatchSubquery(), // 유효한 매칭만 가져오기 + applyGameModeFilter(gameMode) // 게임모드별 추가 필터 적용 (SOLO, FREE) + ) + .orderBy(matchingRecord.member.id.asc(), matchingRecord.createdAt.desc()) // 최신순 정렬 + .fetch(); + } + + /** + * 게임 모드에 따른 추가 필터 적용 + */ + private BooleanExpression applyGameModeFilter(GameMode gameMode) { + return switch (gameMode) { + case SOLO -> validateSoloRankFilter(); // 개인 랭크 티어 검증 + case FREE -> validateFreeRankFilter(); // 자유 랭크 티어 검증 + default -> Expressions.TRUE; // 다른 게임 모드는 필터 없음 + }; + } + + /** + * SOLO 모드 - 개인 랭크 제한 검증 (validateSoloRankRange 적용) + */ + private BooleanExpression validateSoloRankFilter() { + return validateSoloRankRange(matchingRecord.soloTier); + } + + /** + * FREE 모드 - 자유 랭크 제한 검증 + */ + private BooleanExpression validateFreeRankFilter() { + return matchingRecord.freeTier.in(Tier.IRON, Tier.BRONZE, Tier.SILVER, Tier.GOLD) + .and(matchingRecord.freeTier.notIn(Tier.EMERALD, Tier.DIAMOND, Tier.MASTER, Tier.GRANDMASTER, + Tier.CHALLENGER)); + } + + + /** + * 매칭 유효성 검사 서브쿼리 + */ + private BooleanExpression existsValidMatchSubquery() { + QMatchingRecord otherRecord = new QMatchingRecord("otherRecord"); + + return JPAExpressions.selectOne() + .from(otherRecord) + .where( + otherRecord.member.id.ne(matchingRecord.member.id), // 다른 멤버와의 매칭 + isValidMatchingPosition(matchingRecord, otherRecord) // 포지션 조건 체크 + ) + .exists(); + } + + /** + * 매칭 가능한 포지션 조건 ] + */ + private BooleanExpression isValidMatchingPosition(QMatchingRecord myRecord, QMatchingRecord otherRecord) { + BooleanExpression condition1 = myRecord.mainPosition.ne(Position.ANY) + .and(otherRecord.subPosition.ne(Position.ANY)) + .and(myRecord.mainPosition.eq(otherRecord.subPosition) + .or(otherRecord.mainPosition.eq(myRecord.subPosition))) + .and(myRecord.wantPosition.eq(otherRecord.subPosition)); + + BooleanExpression condition2 = myRecord.subPosition.ne(Position.ANY) + .and(otherRecord.wantPosition.ne(Position.ANY)) + .and(otherRecord.wantPosition.eq(myRecord.subPosition)) + .and(otherRecord.mainPosition.eq(myRecord.subPosition) + .or(myRecord.mainPosition.eq(otherRecord.subPosition))); + + BooleanExpression condition3 = myRecord.mainPosition.ne(Position.ANY) + .and(myRecord.subPosition.ne(Position.ANY)) + .and(otherRecord.mainPosition.ne(Position.ANY)) + .and(otherRecord.subPosition.ne(Position.ANY)) + .and(myRecord.mainPosition.eq(otherRecord.mainPosition) + .or(myRecord.mainPosition.eq(otherRecord.subPosition))) + .and(myRecord.subPosition.eq(otherRecord.mainPosition) + .or(myRecord.subPosition.eq(otherRecord.subPosition))) + .not(); + + return condition1.or(condition2).or(condition3); + } + + + /** + * 개인 랭크 제한 검증 (SOLO 모드 전용) - QueryDSL에서 적용 가능하도록 수정 + */ + private BooleanExpression validateSoloRankRange(EnumPath tierPath) { + return tierPath.eq(Tier.IRON).or(tierPath.eq(Tier.BRONZE)).and(matchingRecord.soloTier.in(Tier.IRON, + Tier.BRONZE, Tier.SILVER)) + .or(tierPath.eq(Tier.SILVER).and(matchingRecord.soloTier.in(Tier.IRON, Tier.BRONZE, Tier.SILVER, + Tier.GOLD))) + .or(tierPath.eq(Tier.GOLD).and(matchingRecord.soloTier.in(Tier.SILVER, Tier.GOLD, Tier.PLATINUM))) + .or(tierPath.eq(Tier.PLATINUM).and(matchingRecord.soloTier.in(Tier.GOLD, Tier.PLATINUM, Tier.EMERALD))) + .or(tierPath.eq(Tier.EMERALD).and(matchingRecord.soloTier.in(Tier.PLATINUM, Tier.EMERALD, + Tier.DIAMOND))) + .or(tierPath.eq(Tier.DIAMOND).and(matchingRecord.soloTier.in(Tier.EMERALD, Tier.DIAMOND))) + .or(Expressions.FALSE); // 마스터 이상 필터 적용 안 함 + } + + +} diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityCalculateService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityCalculateService.java deleted file mode 100644 index f4f2e302..00000000 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityCalculateService.java +++ /dev/null @@ -1,196 +0,0 @@ -package com.gamegoo.gamegoo_v2.matching.service; - -import com.gamegoo.gamegoo_v2.account.member.domain.Mike; -import com.gamegoo.gamegoo_v2.account.member.domain.Position; -import com.gamegoo.gamegoo_v2.account.member.domain.Tier; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@RequiredArgsConstructor -@Transactional(readOnly = true) -public class MatchingPriorityCalculateService { - - private final MatchingPriorityEvaluateService matchingPriorityEvaluateService; - - /** - * 정밀 매칭 우선순위 계산 - */ - public int calculatePrecisePriority(Integer myManner, Integer otherManner) { - return matchingPriorityEvaluateService.getMannerPriority(otherManner, myManner, 16, 4); - } - - /** - * 빠른대전 우선순위 계산 - */ - public int calculateFastPriority(Position myMainP, Position mySubP, Position myWantP, - Position otherMainP, Position otherSubP, Position otherWantP, - Mike myMike, Mike otherMike, Integer myManner, Integer otherManner, - Tier mySoloTier, Integer mySoloRank, Tier myFreeTier, Integer myFreeRank, - Tier otherSoloTier, Integer otherSoloRank, Tier otherFreeTier, - Integer otherFreeRank) { - int priority = 0; - - // 매너 우선순위 - priority += matchingPriorityEvaluateService.getMannerPriority(otherManner, myManner, 16, 4); - - // TODO: 티어 및 랭킹 점수 계산 - // priority += matchingPriorityEvaluateService.getTierRankPriority(myTier, myRank, otherTier, otherRank, 40, 4); - - // 포지션 우선순위 - priority += matchingPriorityEvaluateService.getPositionPriority(myWantP, otherMainP, otherSubP, 3, 2, 1); - priority += matchingPriorityEvaluateService.getPositionPriority(otherWantP, myMainP, mySubP, 3, 2, 1); - - // 마이크 우선순위 - priority += matchingPriorityEvaluateService.getMikePriority(myMike, otherMike, 3); - - return priority; - } - - /** - * 개인 랭크 모드 우선순위 계산 - */ - public int calculateSoloPriority(Position myMainP, Position mySubP, Position myWantP, - Position otherMainP, Position otherSubP, Position otherWantP, - Mike myMike, Mike otherMike, Integer myManner, Integer otherManner, - Tier myTier, Integer myRank, Tier otherTier, Integer otherRank) { - // 티어 및 랭킹 제한 확인 - if (!validateSoloRankRange(myTier, otherTier)) { - return 0; - } - - int priority = 0; - - // 매너 우선순위 - priority += matchingPriorityEvaluateService.getMannerPriority(otherManner, myManner, 16, 4); - - // 티어 및 랭킹 점수 계산 - priority += matchingPriorityEvaluateService.getTierRankPriority(myTier, myRank, otherTier, otherRank, 40, 4); - - // 포지션 우선순위 - priority += matchingPriorityEvaluateService.getPositionPriority(myWantP, otherMainP, otherSubP, 3, 2, 1); - priority += matchingPriorityEvaluateService.getPositionPriority(otherWantP, myMainP, mySubP, 3, 2, 1); - - // 마이크 우선순위 - priority += matchingPriorityEvaluateService.getMikePriority(myMike, otherMike, 5); - - return priority; - } - - /** - * FREE 모드 우선순위 계산 - */ - public int calculateFreePriority(Position myMainP, Position mySubP, Position myWantP, - Position otherMainP, Position otherSubP, Position otherWantP, - Mike myMike, Mike otherMike, Integer myManner, Integer otherManner, - Tier myTier, Integer myRank, Tier otherTier, Integer otherRank) { - // 티어 및 랭킹 제한 확인 - if (myTier.ordinal() < 5 && otherTier.ordinal() >= 6) { - return 0; - } - - int priority = 0; - - // 매너 우선순위 - priority += matchingPriorityEvaluateService.getMannerPriority(otherManner, myManner, 16, 4); - - // 티어 및 랭킹 점수 계산 - priority += matchingPriorityEvaluateService.getTierRankPriority(myTier, myRank, otherTier, otherRank, 40, 4); - - // 포지션 우선순위 - priority += matchingPriorityEvaluateService.getPositionPriority(myWantP, otherMainP, otherSubP, 3, 2, 1); - priority += matchingPriorityEvaluateService.getPositionPriority(otherWantP, myMainP, mySubP, 3, 2, 1); - - // 마이크 우선순위 - priority += matchingPriorityEvaluateService.getMikePriority(myMike, otherMike, 3); - - return priority; - } - - /** - * 칼바람 모드 우선순위 계산 - */ - public int calculateAramPriority(Mike myMike, Mike otherMike, Integer myManner, Integer otherManner) { - int priority = 0; - - // 매너 우선순위 - priority += matchingPriorityEvaluateService.getMannerPriority(otherManner, myManner, 16, 4); - - // 마이크 우선순위 - priority += matchingPriorityEvaluateService.getMikePriority(myMike, otherMike, 3); - - return priority; - } - - public boolean validateMatching(Position myMainP, Position mySubP, Position myWantP, Position otherMainP, - Position otherSubP, Position otherWantP) { - // 1. - // 1.1 A의 찾는 포지션(myWantP)이 B의 부 포지션(otherSubP)일 경우 - if ((myMainP == otherSubP || otherMainP == mySubP) && myWantP == otherSubP) { - return true; - } - - // 1.2 B의 찾는 포지션(otherWantP)이 A의 부 포지션(mySubP)일 경우 - if ((otherMainP == mySubP || myMainP == otherSubP) && otherWantP == mySubP) { - return true; - } - - // 2. 주/부 포지션이 순서 상관없이 겹칠 경우 false 반환 - if ((myMainP == otherMainP || myMainP == otherSubP) && (mySubP == otherMainP || mySubP == otherSubP)) { - return false; - } - - return true; - } - - /** - * 정밀 매칭 검증 메서드 - */ - public boolean validatePreciseMatching(Mike myMike, Mike otherMike, Position myWantP, Position otherMainP, - Position otherSubP, Tier myTier, Tier otherTier) { - // 마이크가 다를 경우 매칭 실패 - if (!myMike.equals(otherMike)) { - return false; - } - - // 내가 원하는 포지션이 상대 포지션이 아닐 경우 매칭 실패 - if (!otherMainP.equals(myWantP) && !otherSubP.equals(myWantP)) { - return false; - } - - // 티어 차이가 1개 이상 나면 매칭 실패 - return Math.abs(myTier.ordinal() - otherTier.ordinal()) <= 1; - } - - /** - * 개인 랭크 제한 검증 - */ - private boolean validateSoloRankRange(Tier myTier, Tier otherTier) { - int[][] allowedRanges = { - {0, 1, 2}, // 아이언 - {0, 1, 2}, // 브론즈 - {0, 1, 2, 3}, // 실버 - {2, 3, 4}, // 골드 - {3, 4, 5}, // 플레티넘 - {4, 5, 6}, // 에메랄드 - {5, 6} // 다이아몬드 - }; - - int myTierIndex = myTier.ordinal(); - int otherTierIndex = otherTier.ordinal(); - - if (myTierIndex >= allowedRanges.length) { - return false; // 마스터 이상은 제외 - } - - for (int tier : allowedRanges[myTierIndex]) { - if (tier == otherTierIndex) { - return true; - } - } - - return false; - } - -} diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityEvaluateService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingScoreCalculator.java similarity index 91% rename from src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityEvaluateService.java rename to src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingScoreCalculator.java index 9be66bb2..023ad0e2 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingPriorityEvaluateService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingScoreCalculator.java @@ -6,7 +6,7 @@ import org.springframework.stereotype.Component; @Component -public class MatchingPriorityEvaluateService { +public class MatchingScoreCalculator { /** * 매너레벨 점수 계산 @@ -84,13 +84,10 @@ public int getPositionPriority(Position myWantPosition, Position otherMainPositi * @return 마이크 우선순위 점수 */ public int getMikePriority(Mike myMike, Mike otherMike, int mikeMatchPriority) { - if (myMike == Mike.UNAVAILABLE && otherMike == Mike.UNAVAILABLE) { - return mikeMatchPriority; + if (!myMike.equals(otherMike)) { + return 0; } - if (myMike == Mike.AVAILABLE && otherMike == Mike.AVAILABLE) { - return mikeMatchPriority; - } - return 0; + return mikeMatchPriority; } } diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java index 24123e5e..e305bd28 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java @@ -3,7 +3,6 @@ import com.gamegoo.gamegoo_v2.account.member.domain.Member; import com.gamegoo.gamegoo_v2.matching.domain.GameMode; import com.gamegoo.gamegoo_v2.matching.domain.MatchingRecord; -import com.gamegoo.gamegoo_v2.matching.domain.MatchingStatus; import com.gamegoo.gamegoo_v2.matching.domain.MatchingType; import com.gamegoo.gamegoo_v2.matching.dto.PriorityValue; import com.gamegoo.gamegoo_v2.matching.dto.response.PriorityListResponse; @@ -12,7 +11,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @@ -21,7 +19,7 @@ @Transactional(readOnly = true) public class MatchingService { - private final MatchingPriorityCalculateService matchingPriorityCalculateService; + private final MatchingStrategyProcessor matchingStrategyProcessor; private final MatchingRecordRepository matchingRecordRepository; public PriorityListResponse calculatePriorityList(MatchingRecord myMatchingRecord, @@ -50,22 +48,11 @@ public PriorityListResponse calculatePriorityList(MatchingRecord myMatchingRecor myMatchingRecord.getMatchingUuid()); } - public int calculatePriority(GameMode gameMode, MatchingRecord myRecord, MatchingRecord otherRecord) { - // 공통 조건 - if (!matchingPriorityCalculateService.validateMatching(myRecord.getMainPosition(), myRecord.getSubPosition(), - myRecord.getWantPosition(), otherRecord.getMainPosition(), otherRecord.getSubPosition(), - otherRecord.getWantPosition())) { - return 0; - } - // 정밀 매칭 if (myRecord.getMatchingType() == MatchingType.PRECISE) { - if (matchingPriorityCalculateService.validatePreciseMatching(myRecord.getMike(), otherRecord.getMike(), - myRecord.getWantPosition(), otherRecord.getMainPosition(), otherRecord.getSubPosition(), - myRecord.getSoloTier(), otherRecord.getSoloTier())) { - return matchingPriorityCalculateService.calculatePrecisePriority(myRecord.getMannerLevel(), - otherRecord.getMannerLevel()); + if (matchingStrategyProcessor.validatePreciseMatching(myRecord, otherRecord)) { + return matchingStrategyProcessor.calculatePrecisePriority(myRecord, otherRecord); } return 0; } @@ -74,73 +61,19 @@ public int calculatePriority(GameMode gameMode, MatchingRecord myRecord, Matchin return switch (gameMode) { case SOLO -> // 개인 랭크 모드 우선순위 계산 - matchingPriorityCalculateService.calculateSoloPriority( - myRecord.getMainPosition(), - myRecord.getSubPosition(), - myRecord.getWantPosition(), - otherRecord.getMainPosition(), - otherRecord.getSubPosition(), - otherRecord.getWantPosition(), - myRecord.getMike(), - otherRecord.getMike(), - myRecord.getMannerLevel(), - otherRecord.getMannerLevel(), - myRecord.getSoloTier(), - myRecord.getSoloRank(), - otherRecord.getSoloTier(), - otherRecord.getSoloRank() - ); + matchingStrategyProcessor.calculateSoloPriority(myRecord, otherRecord); case FREE -> // 자유 랭크 모드 우선순위 계산 - matchingPriorityCalculateService.calculateFreePriority( - myRecord.getMainPosition(), - myRecord.getSubPosition(), - myRecord.getWantPosition(), - otherRecord.getMainPosition(), - otherRecord.getSubPosition(), - otherRecord.getWantPosition(), - myRecord.getMike(), - otherRecord.getMike(), - myRecord.getMannerLevel(), - otherRecord.getMannerLevel(), - myRecord.getFreeTier(), - myRecord.getFreeRank(), - otherRecord.getFreeTier(), - otherRecord.getFreeRank() - ); + matchingStrategyProcessor.calculateFreePriority(myRecord, otherRecord); case ARAM -> // 칼바람 모드 우선순위 계산 - matchingPriorityCalculateService.calculateAramPriority( - myRecord.getMike(), - otherRecord.getMike(), - myRecord.getMannerLevel(), - otherRecord.getMannerLevel()); + matchingStrategyProcessor.calculateAramPriority(myRecord, otherRecord); case FAST -> // 빠른대전 우선순위 계산 - matchingPriorityCalculateService.calculateFastPriority( - myRecord.getMainPosition(), - myRecord.getSubPosition(), - myRecord.getWantPosition(), - otherRecord.getMainPosition(), - otherRecord.getSubPosition(), - otherRecord.getWantPosition(), - myRecord.getMike(), - otherRecord.getMike(), - myRecord.getMannerLevel(), - otherRecord.getMannerLevel(), - myRecord.getSoloTier(), - myRecord.getSoloRank(), - myRecord.getFreeTier(), - myRecord.getFreeRank(), - otherRecord.getSoloTier(), - otherRecord.getSoloRank(), - otherRecord.getFreeTier(), - otherRecord.getFreeRank() - ); + matchingStrategyProcessor.calculateFastPriority(myRecord, otherRecord); }; } - /** * 매칭 대기 중인 Matching Records List 조회 * @@ -148,13 +81,8 @@ public int calculatePriority(GameMode gameMode, MatchingRecord myRecord, Matchin * @return 대기 중인 매칭 리스트 */ public List getPendingMatchingRecords(GameMode gameMode) { - LocalDateTime fiveMinutesAgo = LocalDateTime.now().minusMinutes(5); - return matchingRecordRepository.findMatchingRecordsWithGroupBy( - fiveMinutesAgo, - MatchingStatus.PENDING, - gameMode - ); + return matchingRecordRepository.findRecentValidMatchingRecords(gameMode); } diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingStrategyProcessor.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingStrategyProcessor.java new file mode 100644 index 00000000..41a3f12e --- /dev/null +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingStrategyProcessor.java @@ -0,0 +1,137 @@ +package com.gamegoo.gamegoo_v2.matching.service; + +import com.gamegoo.gamegoo_v2.matching.domain.MatchingRecord; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class MatchingStrategyProcessor { + + private final MatchingScoreCalculator matchingScoreCalculator; + + /** + * 정밀 매칭 우선순위 계산 + */ + public int calculatePrecisePriority(MatchingRecord myRecord, MatchingRecord otherRecord) { + return matchingScoreCalculator.getMannerPriority( + otherRecord.getMannerLevel(), myRecord.getMannerLevel(), 16, 4); + } + + /** + * 빠른대전 우선순위 계산 + */ + public int calculateFastPriority(MatchingRecord myRecord, MatchingRecord otherRecord) { + int priority = 0; + + // 매너 우선순위 + priority += matchingScoreCalculator.getMannerPriority( + otherRecord.getMannerLevel(), myRecord.getMannerLevel(), 16, 4); + + // TODO: 티어 및 랭킹 점수 계산 + // priority += matchingPriorityEvaluateService.getTierRankPriority(myRecord.getTier(), myRecord.getRank(), + // otherRecord.getTier(), otherRecord.getRank(), 40, 4); + + // 포지션 우선순위 + priority += matchingScoreCalculator.getPositionPriority( + myRecord.getWantPosition(), otherRecord.getMainPosition(), otherRecord.getSubPosition(), 3, 2, 1); + priority += matchingScoreCalculator.getPositionPriority( + otherRecord.getWantPosition(), myRecord.getMainPosition(), myRecord.getSubPosition(), 3, 2, 1); + + // 마이크 우선순위 + priority += matchingScoreCalculator.getMikePriority(myRecord.getMike(), otherRecord.getMike(), 3); + + return priority; + } + + /** + * 개인 랭크 모드 우선순위 계산 + */ + public int calculateSoloPriority(MatchingRecord myRecord, MatchingRecord otherRecord) { + int priority = 0; + + // 매너 우선순위 + priority += matchingScoreCalculator.getMannerPriority( + otherRecord.getMannerLevel(), myRecord.getMannerLevel(), 16, 4); + + // 티어 및 랭킹 점수 계산 + priority += matchingScoreCalculator.getTierRankPriority( + myRecord.getSoloTier(), myRecord.getSoloRank(), + otherRecord.getSoloTier(), otherRecord.getSoloRank(), 40, 4); + + // 포지션 우선순위 + priority += matchingScoreCalculator.getPositionPriority( + myRecord.getWantPosition(), otherRecord.getMainPosition(), otherRecord.getSubPosition(), 3, 2, 1); + priority += matchingScoreCalculator.getPositionPriority( + otherRecord.getWantPosition(), myRecord.getMainPosition(), myRecord.getSubPosition(), 3, 2, 1); + + // 마이크 우선순위 + priority += matchingScoreCalculator.getMikePriority(myRecord.getMike(), otherRecord.getMike(), 5); + + return priority; + } + + /** + * FREE 모드 우선순위 계산 + */ + public int calculateFreePriority(MatchingRecord myRecord, MatchingRecord otherRecord) { + int priority = 0; + + // 매너 우선순위 + priority += matchingScoreCalculator.getMannerPriority( + otherRecord.getMannerLevel(), myRecord.getMannerLevel(), 16, 4); + + // 티어 및 랭킹 점수 계산 + priority += matchingScoreCalculator.getTierRankPriority( + myRecord.getFreeTier(), myRecord.getFreeRank(), + otherRecord.getFreeTier(), otherRecord.getFreeRank(), 40, 4); + + // 포지션 우선순위 + priority += matchingScoreCalculator.getPositionPriority( + myRecord.getWantPosition(), otherRecord.getMainPosition(), otherRecord.getSubPosition(), 3, 2, 1); + priority += matchingScoreCalculator.getPositionPriority( + otherRecord.getWantPosition(), myRecord.getMainPosition(), myRecord.getSubPosition(), 3, 2, 1); + + // 마이크 우선순위 + priority += matchingScoreCalculator.getMikePriority(myRecord.getMike(), otherRecord.getMike(), 3); + + return priority; + } + + /** + * 칼바람 모드 우선순위 계산 + */ + public int calculateAramPriority(MatchingRecord myRecord, MatchingRecord otherRecord) { + int priority = 0; + + // 매너 우선순위 + priority += matchingScoreCalculator.getMannerPriority( + otherRecord.getMannerLevel(), myRecord.getMannerLevel(), 16, 4); + + // 마이크 우선순위 + priority += matchingScoreCalculator.getMikePriority(myRecord.getMike(), otherRecord.getMike(), 3); + + return priority; + } + + /** + * 정밀 매칭 검증 메서드 + */ + public boolean validatePreciseMatching(MatchingRecord myRecord, MatchingRecord otherRecord) { + // 마이크가 다를 경우 매칭 실패 + if (!myRecord.getMike().equals(otherRecord.getMike())) { + return false; + } + + // 내가 원하는 포지션이 상대 포지션이 아닐 경우 매칭 실패 + if (!otherRecord.getMainPosition().equals(myRecord.getWantPosition()) && + !otherRecord.getSubPosition().equals(myRecord.getWantPosition())) { + return false; + } + + // 티어 차이가 1개 이상 나면 매칭 실패 + return Math.abs(myRecord.getSoloTier().ordinal() - otherRecord.getSoloTier().ordinal()) <= 1; + } + + +} From 2ed159f27fe16f9f257749c68135514063a0380d Mon Sep 17 00:00:00 2001 From: Rimi Date: Sat, 1 Feb 2025 16:41:55 +0900 Subject: [PATCH 15/28] =?UTF-8?q?:sparkles:=20[Feat]=20=EC=A3=BC=EC=84=9D?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gamegoo_v2/matching/service/MatchingService.java | 8 +++++++- .../matching/service/MatchingStrategyProcessor.java | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java index e305bd28..622d71c8 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java @@ -22,6 +22,13 @@ public class MatchingService { private final MatchingStrategyProcessor matchingStrategyProcessor; private final MatchingRecordRepository matchingRecordRepository; + /** + * 매칭 우선순위 리스트 계산 후 조회 + * + * @param myMatchingRecord 내 매칭 정보 + * @param otherMatchingRecords 상대방 매칭 정보 + * @return 우선순위 계산 API 응답 DTO + */ public PriorityListResponse calculatePriorityList(MatchingRecord myMatchingRecord, List otherMatchingRecords) { // 우선순위 리스트 초기화 @@ -81,7 +88,6 @@ public int calculatePriority(GameMode gameMode, MatchingRecord myRecord, Matchin * @return 대기 중인 매칭 리스트 */ public List getPendingMatchingRecords(GameMode gameMode) { - return matchingRecordRepository.findRecentValidMatchingRecords(gameMode); } diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingStrategyProcessor.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingStrategyProcessor.java index 41a3f12e..396a4600 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingStrategyProcessor.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingStrategyProcessor.java @@ -72,7 +72,7 @@ public int calculateSoloPriority(MatchingRecord myRecord, MatchingRecord otherRe } /** - * FREE 모드 우선순위 계산 + * 자유 랭크 모드 우선순위 계산 */ public int calculateFreePriority(MatchingRecord myRecord, MatchingRecord otherRecord) { int priority = 0; From 6cf005d929fcf396f01f267dab63808dd4756967 Mon Sep 17 00:00:00 2001 From: Rimi Date: Sun, 2 Feb 2025 18:03:19 +0900 Subject: [PATCH 16/28] =?UTF-8?q?:sparkles:=20[Feat]=20=EC=A3=BC=EC=84=9D?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/MatchingFacadeService.java | 6 +++- .../service/MatchingScoreCalculator.java | 6 ++++ .../matching/service/MatchingService.java | 8 +++++ .../service/MatchingStrategyProcessor.java | 32 ++++++++++++++++--- 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingFacadeService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingFacadeService.java index 788a8b2a..398f99ee 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingFacadeService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingFacadeService.java @@ -38,7 +38,11 @@ public class MatchingFacadeService { private final MemberGameStyleService memberGameStyleService; /** - * 매칭 우선순위 계산 및 기록 저장 API + * 매칭 우선순위 계산 및 DB 저장 + * + * @param memberId 회원 ID + * @param request 회원 정보 + * @return 매칭 정보 */ @Transactional public PriorityListResponse calculatePriorityAndRecording(Long memberId, InitializingMatchingRequest request) { diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingScoreCalculator.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingScoreCalculator.java index 023ad0e2..d5ffc8f4 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingScoreCalculator.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingScoreCalculator.java @@ -10,6 +10,12 @@ public class MatchingScoreCalculator { /** * 매너레벨 점수 계산 + * + * @param otherManner 상대방 매너 점수 + * @param myManner 내 매너 점수 + * @param maxMannerPriority 매너 점수 최대 우선순위 값 + * @param mannerDifferenceMultiplier 매너 점수 별 가중치 값 + * @return 최종 매너점수 */ public int getMannerPriority(Integer otherManner, Integer myManner, int maxMannerPriority, int mannerDifferenceMultiplier) { diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java index 622d71c8..691b227a 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java @@ -55,6 +55,14 @@ public PriorityListResponse calculatePriorityList(MatchingRecord myMatchingRecor myMatchingRecord.getMatchingUuid()); } + /** + * 우선순위 점수 계산 + * + * @param gameMode 게임모드 + * @param myRecord 내 매칭 정보 + * @param otherRecord 상대방 매칭 정보 + * @return 우선순위 점수 + */ public int calculatePriority(GameMode gameMode, MatchingRecord myRecord, MatchingRecord otherRecord) { // 정밀 매칭 if (myRecord.getMatchingType() == MatchingType.PRECISE) { diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingStrategyProcessor.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingStrategyProcessor.java index 396a4600..b2261bc9 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingStrategyProcessor.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingStrategyProcessor.java @@ -11,7 +11,11 @@ public class MatchingStrategyProcessor { private final MatchingScoreCalculator matchingScoreCalculator; /** - * 정밀 매칭 우선순위 계산 + * 정밀매칭 우선순위 계산 + * + * @param myRecord 내 매칭 정보 + * @param otherRecord 상대방 매칭 정보 + * @return 우선순위 점수 */ public int calculatePrecisePriority(MatchingRecord myRecord, MatchingRecord otherRecord) { return matchingScoreCalculator.getMannerPriority( @@ -20,6 +24,10 @@ public int calculatePrecisePriority(MatchingRecord myRecord, MatchingRecord othe /** * 빠른대전 우선순위 계산 + * + * @param myRecord 내 매칭 정보 + * @param otherRecord 상대방 매칭 정보 + * @return 우선순위 점수 */ public int calculateFastPriority(MatchingRecord myRecord, MatchingRecord otherRecord) { int priority = 0; @@ -45,7 +53,11 @@ public int calculateFastPriority(MatchingRecord myRecord, MatchingRecord otherRe } /** - * 개인 랭크 모드 우선순위 계산 + * 개인랭크 모드 우선순위 계산 + * + * @param myRecord 내 매칭 정보 + * @param otherRecord 상대방 매칭 정보 + * @return 우선순위 점수 */ public int calculateSoloPriority(MatchingRecord myRecord, MatchingRecord otherRecord) { int priority = 0; @@ -72,7 +84,11 @@ public int calculateSoloPriority(MatchingRecord myRecord, MatchingRecord otherRe } /** - * 자유 랭크 모드 우선순위 계산 + * 자유랭크 모드 우선순위 계산 + * + * @param myRecord 내 매칭 정보 + * @param otherRecord 상대방 매칭 정보 + * @return 우선순위 점수 */ public int calculateFreePriority(MatchingRecord myRecord, MatchingRecord otherRecord) { int priority = 0; @@ -100,6 +116,10 @@ public int calculateFreePriority(MatchingRecord myRecord, MatchingRecord otherRe /** * 칼바람 모드 우선순위 계산 + * + * @param myRecord 내 매칭 정보 + * @param otherRecord 상대방 매칭 정보 + * @return 우선순위 점수 */ public int calculateAramPriority(MatchingRecord myRecord, MatchingRecord otherRecord) { int priority = 0; @@ -115,7 +135,11 @@ public int calculateAramPriority(MatchingRecord myRecord, MatchingRecord otherRe } /** - * 정밀 매칭 검증 메서드 + * 정밀 매칭 검증 + * + * @param myRecord 내 매칭 정보 + * @param otherRecord 상대방 매칭 정보 + * @return 매칭 가능 여부 */ public boolean validatePreciseMatching(MatchingRecord myRecord, MatchingRecord otherRecord) { // 마이크가 다를 경우 매칭 실패 From ea3641b50447f2ee4e76e3c2026fb1f6407d31e9 Mon Sep 17 00:00:00 2001 From: Rimi Date: Sun, 2 Feb 2025 18:19:08 +0900 Subject: [PATCH 17/28] =?UTF-8?q?:white=5Fcheck=5Fmark:=20[Test]=20Matchin?= =?UTF-8?q?gScoreCalculatorTest=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/MatchingScoreCalculator.java | 2 +- .../matching/MatchingScoreCalculatorTest.java | 85 +++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingScoreCalculatorTest.java diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingScoreCalculator.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingScoreCalculator.java index d5ffc8f4..f2458058 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingScoreCalculator.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingScoreCalculator.java @@ -58,7 +58,7 @@ private int getTierRankScore(Tier tier, int rank, int tierMultiplier) { /** * 포지션 우선순위 점수 계산 * - * @param myWantPosition 내 주포지션 + * @param myWantPosition 내가 원하는 포지션 * @param otherMainPosition 타겟 주포지션 * @param otherSubPosition 타겟 부포지션 * @param mainPositionPriority 높은 추가 점수 diff --git a/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingScoreCalculatorTest.java b/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingScoreCalculatorTest.java new file mode 100644 index 00000000..353b53a6 --- /dev/null +++ b/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingScoreCalculatorTest.java @@ -0,0 +1,85 @@ +package com.gamegoo.gamegoo_v2.service.matching; + +import com.gamegoo.gamegoo_v2.account.member.domain.Position; +import com.gamegoo.gamegoo_v2.account.member.domain.Tier; +import com.gamegoo.gamegoo_v2.account.member.domain.Mike; +import com.gamegoo.gamegoo_v2.matching.service.MatchingScoreCalculator; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import static org.assertj.core.api.Assertions.assertThat; + +@ActiveProfiles("test") +@SpringBootTest +class MatchingScoreCalculatorTest { + + @Autowired + MatchingScoreCalculator calculator; + + @Test + @DisplayName("매너레벨 점수 계산: 동일한 매너 점수") + void testGetMannerPriority_SameManner() { + int result = calculator.getMannerPriority(5, 5, 16, 4); + assertThat(result).isEqualTo(16); + } + + @Test + @DisplayName("매너레벨 점수 계산: 매너 차이가 있을 때") + void testGetMannerPriority_DifferentManner() { + int result = calculator.getMannerPriority(5, 1, 16, 4); + assertThat(result).isEqualTo(0); + } + + @Test + @DisplayName("랭킹 우선순위 점수 계산: 동일한 티어 및 랭크") + void testGetTierRankPriority_SameTierAndRank() { + int result = calculator.getTierRankPriority(Tier.GOLD, 4, Tier.GOLD, 4, 40, 4); + assertThat(result).isEqualTo(40); + } + + @Test + @DisplayName("랭킹 우선순위 점수 계산: 티어와 랭크 차이") + void testGetTierRankPriority_DifferentTierAndRank() { + int result = calculator.getTierRankPriority(Tier.GOLD, 1, Tier.SILVER, 2, 40, 4); + assertThat(result).isEqualTo(35); + } + + @Test + @DisplayName("포지션 우선순위 점수 계산: 내가 원하는 포지션이 상대방 부포지션") + void testGetPositionPriority_SameMainPosition() { + int result = calculator.getPositionPriority(Position.TOP, Position.TOP, Position.MID, 3, 2, 1); + assertThat(result).isEqualTo(3); + } + + @Test + @DisplayName("포지션 우선순위 점수 계산: 내가 원하는 포지션이 상대방 부 포지션") + void testGetPositionPriority_SubPositionMatch() { + int result = calculator.getPositionPriority(Position.MID, Position.TOP, Position.MID, 3, 2, 1); + assertThat(result).isEqualTo(2); + } + + @Test + @DisplayName("포지션 우선순위 점수 계산: ANY 포지션 포함") + void testGetPositionPriority_AnyPosition() { + int result = calculator.getPositionPriority(Position.ANY, Position.JUNGLE, Position.MID, 50, 30, 10); + assertThat(result).isEqualTo(50); + } + + @Test + @DisplayName("마이크 우선순위 점수 계산: 동일한 마이크 설정") + void testGetMikePriority_SameMike() { + int result = calculator.getMikePriority(Mike.AVAILABLE, Mike.AVAILABLE, 2); + assertThat(result).isEqualTo(2); + } + + @Test + @DisplayName("마이크 우선순위 점수 계산: 다른 마이크 설정") + void testGetMikePriority_DifferentMike() { + int result = calculator.getMikePriority(Mike.AVAILABLE, Mike.UNAVAILABLE, 2); + assertThat(result).isEqualTo(0); + } + +} From bca80d4cfab595c91be1cd78b3a9f00de08ddb02 Mon Sep 17 00:00:00 2001 From: Rimi Date: Sun, 2 Feb 2025 20:01:08 +0900 Subject: [PATCH 18/28] =?UTF-8?q?:white=5Fcheck=5Fmark:=20[Test]=20Matchin?= =?UTF-8?q?gStrategyProcessorTest=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../account/member/domain/Member.java | 2 - .../service/MatchingStrategyProcessor.java | 6 +- .../MatchingStrategyProcessorTest.java | 282 ++++++++++++++++++ 3 files changed, 285 insertions(+), 5 deletions(-) create mode 100644 src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingStrategyProcessorTest.java diff --git a/src/main/java/com/gamegoo/gamegoo_v2/account/member/domain/Member.java b/src/main/java/com/gamegoo/gamegoo_v2/account/member/domain/Member.java index faa76064..5eb9abbd 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/account/member/domain/Member.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/account/member/domain/Member.java @@ -104,7 +104,6 @@ public class Member extends BaseDateTimeEntity { @OneToMany(mappedBy = "member", cascade = CascadeType.ALL) private List memberGameStyleList = new ArrayList<>(); - // 회원가입용 create public static Member create(String email, String password, LoginType loginType, String gameName, String tag, Tier tier, int gameRank, double winRate, int gameCount, boolean isAgree) { int randomProfileImage = ThreadLocalRandom.current().nextInt(1, 9); @@ -124,7 +123,6 @@ public static Member create(String email, String password, LoginType loginType, .build(); } - // 회원가입용 Builder @Builder private Member(String email, String password, int profileImage, LoginType loginType, String gameName, String tag, Tier tier, int gameRank, double winRate, int gameCount, boolean isAgree) { diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingStrategyProcessor.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingStrategyProcessor.java index b2261bc9..8879fc84 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingStrategyProcessor.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingStrategyProcessor.java @@ -37,8 +37,8 @@ public int calculateFastPriority(MatchingRecord myRecord, MatchingRecord otherRe otherRecord.getMannerLevel(), myRecord.getMannerLevel(), 16, 4); // TODO: 티어 및 랭킹 점수 계산 - // priority += matchingPriorityEvaluateService.getTierRankPriority(myRecord.getTier(), myRecord.getRank(), - // otherRecord.getTier(), otherRecord.getRank(), 40, 4); + priority += matchingScoreCalculator.getTierRankPriority(myRecord.getSoloTier(), myRecord.getSoloRank(), + otherRecord.getSoloTier(), otherRecord.getSoloRank(), 40, 4); // 포지션 우선순위 priority += matchingScoreCalculator.getPositionPriority( @@ -154,7 +154,7 @@ public boolean validatePreciseMatching(MatchingRecord myRecord, MatchingRecord o } // 티어 차이가 1개 이상 나면 매칭 실패 - return Math.abs(myRecord.getSoloTier().ordinal() - otherRecord.getSoloTier().ordinal()) <= 1; + return Math.abs(myRecord.getSoloTier().ordinal() - otherRecord.getSoloTier().ordinal()) < 1; } diff --git a/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingStrategyProcessorTest.java b/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingStrategyProcessorTest.java new file mode 100644 index 00000000..37ed584e --- /dev/null +++ b/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingStrategyProcessorTest.java @@ -0,0 +1,282 @@ +package com.gamegoo.gamegoo_v2.service.matching; + +import com.gamegoo.gamegoo_v2.account.member.domain.Mike; +import com.gamegoo.gamegoo_v2.account.member.domain.Position; +import com.gamegoo.gamegoo_v2.account.member.domain.Tier; +import com.gamegoo.gamegoo_v2.account.member.domain.Member; +import com.gamegoo.gamegoo_v2.account.member.domain.LoginType; +import com.gamegoo.gamegoo_v2.matching.domain.GameMode; +import com.gamegoo.gamegoo_v2.matching.domain.MatchingRecord; +import com.gamegoo.gamegoo_v2.matching.domain.MatchingType; +import com.gamegoo.gamegoo_v2.matching.service.MatchingScoreCalculator; +import com.gamegoo.gamegoo_v2.matching.service.MatchingStrategyProcessor; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import static org.assertj.core.api.Assertions.assertThat; + +@ActiveProfiles("test") +@SpringBootTest +class MatchingStrategyProcessorTest { + + @Autowired + MatchingScoreCalculator calculator; + + @Autowired + MatchingStrategyProcessor processor; + + @Test + @DisplayName("정밀 매칭 우선순위 계산") + void testCalculatePrecisePriority() { + // given + // 랭크 점수 차이 : 0 점 + Member member1 = createMember("user1@gmail.com", Tier.GOLD, true); + Member member2 = createMember("user2@gmail.com", Tier.GOLD, false); + + // 매너 점수 차이 : 8점 + member1.updateMannerLevel(4); + member2.updateMannerLevel(2); + + // when + MatchingRecord record1 = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member1); + MatchingRecord record2 = createMatchingRecord(GameMode.SOLO, MatchingType.BASIC, member2); + + int result = processor.calculatePrecisePriority(record1, record2); + + // then + int expectedPriority = 16 - (Math.abs(record1.getMannerLevel() - record2.getMannerLevel()) * 4); + assertThat(result).isEqualTo(expectedPriority); + } + + @Test + @DisplayName("개인랭크 우선순위 계산") + void testCalculateSoloPriorityWithStateChanges() { + // given + Member member1 = createMember("user1@gmail.com", Tier.DIAMOND, true); + Member member2 = createMember("user2@gmail.com", Tier.PLATINUM, true); + + // 마이크 차이 : 5점 + member1.updateMike(Mike.AVAILABLE); + member2.updateMike(Mike.UNAVAILABLE); + + // 포지션 점수 차이 : 2+3=5점 + member1.updatePosition(Position.TOP, Position.MID, Position.ANY); + member2.updatePosition(Position.JUNGLE, Position.SUP, Position.MID); + + // 매너 점수 차이 : 8점 + member1.updateMannerLevel(5); + member2.updateMannerLevel(3); + + // when + MatchingRecord record1 = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member1); + MatchingRecord record2 = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member2); + int result = processor.calculateSoloPriority(record1, record2); + + // then + int expectedPriority = 16 - (Math.abs(record1.getMannerLevel() - record2.getMannerLevel()) * 4) + + (40 - Math.abs(record1.getSoloTier().ordinal() * 4 + record1.getSoloRank() - + record2.getSoloTier().ordinal() * 4 - record2.getSoloRank())) + + (record1.getMike().equals(record2.getMike()) ? 5 : 0) + getPositionExpectedPriority(member1, member2); + + assertThat(result).isEqualTo(expectedPriority); + } + + + @Test + @DisplayName("자유랭크 우선순위 계산") + void testCalculateFreePriority() { + // given + // 랭크 점수 차이 : 4점 + Member member1 = createMember("user1@gmail.com", Tier.BRONZE, true); + Member member2 = createMember("user2@gmail.com", Tier.SILVER, true); + + // 포지션 점수 차이 : 6점 + member1.updatePosition(Position.MID, Position.SUP, Position.ANY); + member2.updatePosition(Position.JUNGLE, Position.ADC, Position.MID); + + // 매너 점수 차이 : 4점 + member1.updateMannerLevel(3); + member2.updateMannerLevel(2); + + // 마이크 점수 차이 : 3점 + member1.updateMike(Mike.AVAILABLE); + member2.updateMike(Mike.UNAVAILABLE); + + // when + MatchingRecord record1 = createMatchingRecord(GameMode.FREE, MatchingType.BASIC, member1); + MatchingRecord record2 = createMatchingRecord(GameMode.FREE, MatchingType.BASIC, member2); + int result = processor.calculateFreePriority(record1, record2); + + // then + int expectedPriority = 16 - (Math.abs(record1.getMannerLevel() - record2.getMannerLevel()) * 4) + + (40 - Math.abs(record1.getFreeTier().ordinal() * 4 + record1.getFreeRank() - + record2.getFreeTier().ordinal() * 4 - record2.getFreeRank())) + + (record1.getMike().equals(record2.getMike()) ? 3 : 0) + getPositionExpectedPriority(member1, member2); + + assertThat(result).isEqualTo(expectedPriority); + } + + @Test + @DisplayName("빠른대전 우선순위 계산") + void testCalculateFastPriority() { + // given + // 랭크 점수 차이 : 4점 + Member member1 = createMember("user1@gmail.com", Tier.BRONZE, true); + Member member2 = createMember("user2@gmail.com", Tier.SILVER, true); + + // 포지션 점수 차이 : 6점 + member1.updatePosition(Position.MID, Position.SUP, Position.ANY); + member2.updatePosition(Position.JUNGLE, Position.ADC, Position.MID); + + // 매너 점수 차이 : 4점 + member1.updateMannerLevel(3); + member2.updateMannerLevel(2); + + // 마이크 점수 차이 : 3점 + member1.updateMike(Mike.AVAILABLE); + member2.updateMike(Mike.UNAVAILABLE); + + // when + MatchingRecord record1 = createMatchingRecord(GameMode.FREE, MatchingType.BASIC, member1); + MatchingRecord record2 = createMatchingRecord(GameMode.FREE, MatchingType.BASIC, member2); + int result = processor.calculateFastPriority(record1, record2); + + // then + int expectedPriority = 16 - (Math.abs(record1.getMannerLevel() - record2.getMannerLevel()) * 4) + + (40 - Math.abs(record1.getFreeTier().ordinal() * 4 + record1.getFreeRank() - + record2.getFreeTier().ordinal() * 4 - record2.getFreeRank())) + + (record1.getMike().equals(record2.getMike()) ? 3 : 0) + getPositionExpectedPriority(member1, member2); + + assertThat(result).isEqualTo(expectedPriority); + } + + + @Test + @DisplayName("칼바람 모드 우선순위 계산 - 다양한 마이크 설정") + void testCalculateAramPriority() { + // given + Member member1 = createMember("user1@gmail.com", Tier.GOLD, true); + Member member2 = createMember("user2@gmail.com", Tier.GOLD, false); + + // 마이크 점수 차이 : 3점 + member1.updateMike(Mike.AVAILABLE); + member2.updateMike(Mike.UNAVAILABLE); + + // when + MatchingRecord record1 = createMatchingRecord(GameMode.ARAM, MatchingType.BASIC, member1); + MatchingRecord record2 = createMatchingRecord(GameMode.ARAM, MatchingType.BASIC, member2); + int result = processor.calculateAramPriority(record1, record2); + + // then + int expectedPriority = 16 - (Math.abs(record1.getMannerLevel() - record2.getMannerLevel()) * 4) + + (record1.getMike().equals(record2.getMike()) ? 3 : 0); + + assertThat(result).isEqualTo(expectedPriority); + } + + + @Nested + @DisplayName("정밀 매칭 검증") + class ValidatePreciseMatchingTests { + + @Test + @DisplayName("성공 케이스") + void testValidatePreciseMatching_Success() { + Member member1 = createMember("user1@gmail.com", Tier.GOLD, true); + member1.updatePosition(Position.TOP, Position.MID, Position.MID); + Member member2 = createMember("user2@gmail.com", Tier.GOLD, true); + member2.updatePosition(Position.MID, Position.JUNGLE, Position.MID); + MatchingRecord record1 = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member1); + MatchingRecord record2 = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member2); + + boolean isValid = processor.validatePreciseMatching(record1, record2); + assertThat(isValid).isTrue(); + } + + @Test + @DisplayName("실패 케이스: 티어 차이") + void testValidatePreciseMatching_Fail_Tier() { + // given + Member member1 = createMember("user1@gmail.com", Tier.GOLD, true); + Member member2 = createMember("user2@gmail.com", Tier.SILVER, true); + + // when + MatchingRecord record1 = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member1); + MatchingRecord record2 = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member2); + + boolean isValid = processor.validatePreciseMatching(record1, record2); + + // then + assertThat(isValid).isFalse(); + } + + @Test + @DisplayName("실패 케이스: 포지션 불일치") + void testValidatePreciseMatching_Fail_Position() { + // given + Member member1 = createMember("user1@gmail.com", Tier.GOLD, true); + member1.updatePosition(Position.TOP, Position.MID, Position.MID); + Member member2 = createMember("user2@gmail.com", Tier.GOLD, true); + member2.updatePosition(Position.JUNGLE, Position.SUP, Position.MID); + + // when + MatchingRecord record1 = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member1); + MatchingRecord record2 = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member2); + + boolean isValid = processor.validatePreciseMatching(record1, record2); + + // then + assertThat(isValid).isFalse(); + } + + @Test + @DisplayName("실패 케이스: 마이크 불일치") + void testValidatePreciseMatching_Fail_Mike() { + // given + Member member1 = createMember("user1@gmail.com", Tier.GOLD, true); + member1.updateMike(Mike.UNAVAILABLE); + Member member2 = createMember("user2@gmail.com", Tier.GOLD, false); + member2.updateMike(Mike.AVAILABLE); + + // when + MatchingRecord record1 = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member1); + MatchingRecord record2 = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member2); + + boolean isValid = processor.validatePreciseMatching(record1, record2); + + // then + assertThat(isValid).isFalse(); + } + + } + + private Member createMember(String email, Tier tier, boolean hasMike) { + return Member.create(email, "password123", LoginType.GENERAL, "gameUser", "TAG", + tier, 4, 55.0, 100, hasMike); + } + + private MatchingRecord createMatchingRecord(GameMode mode, MatchingType type, Member member) { + return MatchingRecord.create(mode, type, member); + } + + private int getPositionExpectedPriority(Member member1, Member member2) { + // 포지션 expectedPriority 계산 + int positionPriority = 0; + + positionPriority += calculator.getPositionPriority( + member1.getWantPosition(), member2.getMainPosition(), member2.getSubPosition(), + 3, 2, 1 + ); + + positionPriority += calculator.getPositionPriority( + member2.getWantPosition(), member1.getMainPosition(), member1.getSubPosition(), + 3, 2, 1 + ); + return positionPriority; + } + +} From 2b95339abbfc945300f6cd3c11dd8dafc1a59445 Mon Sep 17 00:00:00 2001 From: Rimi Date: Sun, 2 Feb 2025 20:03:40 +0900 Subject: [PATCH 19/28] =?UTF-8?q?:white=5Fcheck=5Fmark:=20[Test]=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../matching/MatchingScoreCalculatorTest.java | 21 ++++++++------- .../MatchingStrategyProcessorTest.java | 26 +++++++++---------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingScoreCalculatorTest.java b/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingScoreCalculatorTest.java index 353b53a6..710779a4 100644 --- a/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingScoreCalculatorTest.java +++ b/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingScoreCalculatorTest.java @@ -17,68 +17,69 @@ class MatchingScoreCalculatorTest { @Autowired - MatchingScoreCalculator calculator; + MatchingScoreCalculator matchingScoreCalculator; @Test @DisplayName("매너레벨 점수 계산: 동일한 매너 점수") void testGetMannerPriority_SameManner() { - int result = calculator.getMannerPriority(5, 5, 16, 4); + int result = matchingScoreCalculator.getMannerPriority(5, 5, 16, 4); assertThat(result).isEqualTo(16); } @Test @DisplayName("매너레벨 점수 계산: 매너 차이가 있을 때") void testGetMannerPriority_DifferentManner() { - int result = calculator.getMannerPriority(5, 1, 16, 4); + int result = matchingScoreCalculator.getMannerPriority(5, 1, 16, 4); assertThat(result).isEqualTo(0); } @Test @DisplayName("랭킹 우선순위 점수 계산: 동일한 티어 및 랭크") void testGetTierRankPriority_SameTierAndRank() { - int result = calculator.getTierRankPriority(Tier.GOLD, 4, Tier.GOLD, 4, 40, 4); + int result = matchingScoreCalculator.getTierRankPriority(Tier.GOLD, 4, Tier.GOLD, 4, 40, 4); assertThat(result).isEqualTo(40); } @Test @DisplayName("랭킹 우선순위 점수 계산: 티어와 랭크 차이") void testGetTierRankPriority_DifferentTierAndRank() { - int result = calculator.getTierRankPriority(Tier.GOLD, 1, Tier.SILVER, 2, 40, 4); + int result = matchingScoreCalculator.getTierRankPriority(Tier.GOLD, 1, Tier.SILVER, 2, 40, 4); assertThat(result).isEqualTo(35); } @Test @DisplayName("포지션 우선순위 점수 계산: 내가 원하는 포지션이 상대방 부포지션") void testGetPositionPriority_SameMainPosition() { - int result = calculator.getPositionPriority(Position.TOP, Position.TOP, Position.MID, 3, 2, 1); + int result = matchingScoreCalculator.getPositionPriority(Position.TOP, Position.TOP, Position.MID, 3, 2, 1); assertThat(result).isEqualTo(3); } @Test @DisplayName("포지션 우선순위 점수 계산: 내가 원하는 포지션이 상대방 부 포지션") void testGetPositionPriority_SubPositionMatch() { - int result = calculator.getPositionPriority(Position.MID, Position.TOP, Position.MID, 3, 2, 1); + int result = matchingScoreCalculator.getPositionPriority(Position.MID, Position.TOP, Position.MID, 3, 2, 1); assertThat(result).isEqualTo(2); } @Test @DisplayName("포지션 우선순위 점수 계산: ANY 포지션 포함") void testGetPositionPriority_AnyPosition() { - int result = calculator.getPositionPriority(Position.ANY, Position.JUNGLE, Position.MID, 50, 30, 10); + int result = matchingScoreCalculator.getPositionPriority(Position.ANY, Position.JUNGLE, Position.MID, 50, 30, + 10); assertThat(result).isEqualTo(50); } @Test @DisplayName("마이크 우선순위 점수 계산: 동일한 마이크 설정") void testGetMikePriority_SameMike() { - int result = calculator.getMikePriority(Mike.AVAILABLE, Mike.AVAILABLE, 2); + int result = matchingScoreCalculator.getMikePriority(Mike.AVAILABLE, Mike.AVAILABLE, 2); assertThat(result).isEqualTo(2); } @Test @DisplayName("마이크 우선순위 점수 계산: 다른 마이크 설정") void testGetMikePriority_DifferentMike() { - int result = calculator.getMikePriority(Mike.AVAILABLE, Mike.UNAVAILABLE, 2); + int result = matchingScoreCalculator.getMikePriority(Mike.AVAILABLE, Mike.UNAVAILABLE, 2); assertThat(result).isEqualTo(0); } diff --git a/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingStrategyProcessorTest.java b/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingStrategyProcessorTest.java index 37ed584e..d55d85a7 100644 --- a/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingStrategyProcessorTest.java +++ b/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingStrategyProcessorTest.java @@ -24,10 +24,10 @@ class MatchingStrategyProcessorTest { @Autowired - MatchingScoreCalculator calculator; + MatchingScoreCalculator matchingScoreCalculator; @Autowired - MatchingStrategyProcessor processor; + MatchingStrategyProcessor matchingStrategyProcessor; @Test @DisplayName("정밀 매칭 우선순위 계산") @@ -45,7 +45,7 @@ void testCalculatePrecisePriority() { MatchingRecord record1 = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member1); MatchingRecord record2 = createMatchingRecord(GameMode.SOLO, MatchingType.BASIC, member2); - int result = processor.calculatePrecisePriority(record1, record2); + int result = matchingStrategyProcessor.calculatePrecisePriority(record1, record2); // then int expectedPriority = 16 - (Math.abs(record1.getMannerLevel() - record2.getMannerLevel()) * 4); @@ -74,7 +74,7 @@ void testCalculateSoloPriorityWithStateChanges() { // when MatchingRecord record1 = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member1); MatchingRecord record2 = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member2); - int result = processor.calculateSoloPriority(record1, record2); + int result = matchingStrategyProcessor.calculateSoloPriority(record1, record2); // then int expectedPriority = 16 - (Math.abs(record1.getMannerLevel() - record2.getMannerLevel()) * 4) + @@ -109,7 +109,7 @@ void testCalculateFreePriority() { // when MatchingRecord record1 = createMatchingRecord(GameMode.FREE, MatchingType.BASIC, member1); MatchingRecord record2 = createMatchingRecord(GameMode.FREE, MatchingType.BASIC, member2); - int result = processor.calculateFreePriority(record1, record2); + int result = matchingStrategyProcessor.calculateFreePriority(record1, record2); // then int expectedPriority = 16 - (Math.abs(record1.getMannerLevel() - record2.getMannerLevel()) * 4) + @@ -143,7 +143,7 @@ void testCalculateFastPriority() { // when MatchingRecord record1 = createMatchingRecord(GameMode.FREE, MatchingType.BASIC, member1); MatchingRecord record2 = createMatchingRecord(GameMode.FREE, MatchingType.BASIC, member2); - int result = processor.calculateFastPriority(record1, record2); + int result = matchingStrategyProcessor.calculateFastPriority(record1, record2); // then int expectedPriority = 16 - (Math.abs(record1.getMannerLevel() - record2.getMannerLevel()) * 4) + @@ -169,7 +169,7 @@ void testCalculateAramPriority() { // when MatchingRecord record1 = createMatchingRecord(GameMode.ARAM, MatchingType.BASIC, member1); MatchingRecord record2 = createMatchingRecord(GameMode.ARAM, MatchingType.BASIC, member2); - int result = processor.calculateAramPriority(record1, record2); + int result = matchingStrategyProcessor.calculateAramPriority(record1, record2); // then int expectedPriority = 16 - (Math.abs(record1.getMannerLevel() - record2.getMannerLevel()) * 4) + @@ -193,7 +193,7 @@ void testValidatePreciseMatching_Success() { MatchingRecord record1 = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member1); MatchingRecord record2 = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member2); - boolean isValid = processor.validatePreciseMatching(record1, record2); + boolean isValid = matchingStrategyProcessor.validatePreciseMatching(record1, record2); assertThat(isValid).isTrue(); } @@ -208,7 +208,7 @@ void testValidatePreciseMatching_Fail_Tier() { MatchingRecord record1 = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member1); MatchingRecord record2 = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member2); - boolean isValid = processor.validatePreciseMatching(record1, record2); + boolean isValid = matchingStrategyProcessor.validatePreciseMatching(record1, record2); // then assertThat(isValid).isFalse(); @@ -227,7 +227,7 @@ void testValidatePreciseMatching_Fail_Position() { MatchingRecord record1 = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member1); MatchingRecord record2 = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member2); - boolean isValid = processor.validatePreciseMatching(record1, record2); + boolean isValid = matchingStrategyProcessor.validatePreciseMatching(record1, record2); // then assertThat(isValid).isFalse(); @@ -246,7 +246,7 @@ void testValidatePreciseMatching_Fail_Mike() { MatchingRecord record1 = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member1); MatchingRecord record2 = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member2); - boolean isValid = processor.validatePreciseMatching(record1, record2); + boolean isValid = matchingStrategyProcessor.validatePreciseMatching(record1, record2); // then assertThat(isValid).isFalse(); @@ -267,12 +267,12 @@ private int getPositionExpectedPriority(Member member1, Member member2) { // 포지션 expectedPriority 계산 int positionPriority = 0; - positionPriority += calculator.getPositionPriority( + positionPriority += matchingScoreCalculator.getPositionPriority( member1.getWantPosition(), member2.getMainPosition(), member2.getSubPosition(), 3, 2, 1 ); - positionPriority += calculator.getPositionPriority( + positionPriority += matchingScoreCalculator.getPositionPriority( member2.getWantPosition(), member1.getMainPosition(), member1.getSubPosition(), 3, 2, 1 ); From ebba37a1269a35404f52633a9c12a76e02c3bf5c Mon Sep 17 00:00:00 2001 From: Rimi Date: Tue, 4 Feb 2025 16:50:18 +0900 Subject: [PATCH 20/28] =?UTF-8?q?:white=5Fcheck=5Fmark:=20[Test]=20Matchin?= =?UTF-8?q?gService=20=EB=A7=A4=EC=B9=AD=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../matching/dto/PriorityValue.java | 29 +++- .../response/MatchingMemberInfoResponse.java | 2 + .../dto/response/PriorityListResponse.java | 2 + .../service/matching/MatchingServiceTest.java | 164 ++++++++++++++++++ 4 files changed, 194 insertions(+), 3 deletions(-) create mode 100644 src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingServiceTest.java diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/PriorityValue.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/PriorityValue.java index 291d4ee4..4c014264 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/PriorityValue.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/PriorityValue.java @@ -2,14 +2,18 @@ import lombok.Builder; import lombok.Getter; +import lombok.ToString; + +import java.util.Objects; @Getter @Builder +@ToString public class PriorityValue { - Long memberId; - String matchingUuid; - int priorityValue; + private final Long memberId; + private final String matchingUuid; + private final int priorityValue; public static PriorityValue of(Long memberId, String matchingUuid, int priorityValue) { return PriorityValue.builder() @@ -19,4 +23,23 @@ public static PriorityValue of(Long memberId, String matchingUuid, int priorityV .build(); } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PriorityValue that = (PriorityValue) o; + return priorityValue == that.priorityValue && + Objects.equals(memberId, that.memberId) && + Objects.equals(matchingUuid, that.matchingUuid); + } + + @Override + public int hashCode() { + return Objects.hash(memberId, matchingUuid, priorityValue); + } + } diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/response/MatchingMemberInfoResponse.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/response/MatchingMemberInfoResponse.java index dd53e18c..343bed1d 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/response/MatchingMemberInfoResponse.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/response/MatchingMemberInfoResponse.java @@ -7,12 +7,14 @@ import com.gamegoo.gamegoo_v2.game.dto.response.GameStyleResponse; import com.gamegoo.gamegoo_v2.matching.domain.GameMode; import lombok.Builder; +import lombok.EqualsAndHashCode; import lombok.Getter; import java.util.List; @Getter @Builder +@EqualsAndHashCode public class MatchingMemberInfoResponse { Long memberId; diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/response/PriorityListResponse.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/response/PriorityListResponse.java index 0eb5be7a..cfedcb56 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/response/PriorityListResponse.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/response/PriorityListResponse.java @@ -3,12 +3,14 @@ import com.gamegoo.gamegoo_v2.account.member.domain.Member; import com.gamegoo.gamegoo_v2.matching.dto.PriorityValue; import lombok.Builder; +import lombok.EqualsAndHashCode; import lombok.Getter; import java.util.List; @Getter @Builder +@EqualsAndHashCode public class PriorityListResponse { List myPriorityList; diff --git a/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingServiceTest.java b/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingServiceTest.java new file mode 100644 index 00000000..62583657 --- /dev/null +++ b/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingServiceTest.java @@ -0,0 +1,164 @@ +package com.gamegoo.gamegoo_v2.service.matching; + +import com.gamegoo.gamegoo_v2.account.member.domain.LoginType; +import com.gamegoo.gamegoo_v2.account.member.domain.Member; +import com.gamegoo.gamegoo_v2.account.member.domain.Position; +import com.gamegoo.gamegoo_v2.account.member.domain.Tier; +import com.gamegoo.gamegoo_v2.account.member.repository.MemberRepository; +import com.gamegoo.gamegoo_v2.matching.domain.GameMode; +import com.gamegoo.gamegoo_v2.matching.domain.MatchingRecord; +import com.gamegoo.gamegoo_v2.matching.domain.MatchingType; +import com.gamegoo.gamegoo_v2.matching.dto.PriorityValue; +import com.gamegoo.gamegoo_v2.matching.dto.response.MatchingMemberInfoResponse; +import com.gamegoo.gamegoo_v2.matching.dto.response.PriorityListResponse; +import com.gamegoo.gamegoo_v2.matching.repository.MatchingRecordRepository; +import com.gamegoo.gamegoo_v2.matching.service.MatchingService; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Random; + +import static org.assertj.core.api.Assertions.assertThat; + +@ActiveProfiles("test") +@SpringBootTest +class MatchingServiceTest { + + @Autowired + MatchingService matchingService; + + @Autowired + private MemberRepository memberRepository; + + @Autowired + MatchingRecordRepository matchingRecordRepository; + + private Member member; + + @AfterEach + void tearDown() { + matchingRecordRepository.deleteAll(); + } + + @BeforeEach + void setUp() { + member = createMember("user1@gmail.com", "User1", "Tag1", Tier.GOLD, 2, true, Position.ADC, Position.MID, + Position.SUP, 2); + } + + @Nested + @DisplayName("매칭 우선순위 리스트 계산 후 조회") + class getMatchingPriorityList { + + @DisplayName("매칭 리스트 조회 성공 : 대기자가 없는 경우") + @Test + void getMatchingPriorityListSucceedsWhenNoUser() { + // given + MatchingRecord matchingRecord = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member); + + // when + PriorityListResponse priorityListResponse = matchingService.calculatePriorityList(matchingRecord, + new ArrayList<>()); + + // then + MatchingMemberInfoResponse matchingMemberInfoResponse = MatchingMemberInfoResponse.of(member, + matchingRecord.getMatchingUuid()); + + + assertThat(priorityListResponse.getMyPriorityList()).isEqualTo(new ArrayList<>()); + assertThat(priorityListResponse.getOtherPriorityList()).isEqualTo(new ArrayList<>()); + assertThat(priorityListResponse.getMyMatchingInfo()).isEqualTo(matchingMemberInfoResponse); + } + + @DisplayName("매칭 리스트 조회 성공 : 랜덤 대기자 20명") + @Test + void validateMatchingPriorityLists() { + // given + MatchingRecord matchingRecord = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member); + + Random random = new Random(); + List allMatchingRecords = new ArrayList<>(); + + for (int i = 0; i < 20; i++) { + String email = "user" + i + "@gmail.com"; + String gameName = "USER" + i; + String tag = "TAG" + i; + Tier tier = Tier.values()[random.nextInt(Tier.values().length)]; + int gameRank = random.nextInt(4) + 1; + boolean hasMike = random.nextBoolean(); + Position mainP = Position.values()[random.nextInt(Position.values().length)]; + Position subP = Position.values()[random.nextInt(Position.values().length)]; + Position wantP = Position.values()[random.nextInt(Position.values().length)]; + int mannerLevel = random.nextInt(4) + 1; + + Member tempMember = createMember(email, gameName, tag, tier, gameRank, hasMike, mainP, subP, wantP, + mannerLevel); + MatchingRecord tempMatchingRecord = createMatchingRecord(GameMode.SOLO, MatchingType.BASIC, + tempMember); + + allMatchingRecords.add(tempMatchingRecord); + } + + // when + PriorityListResponse priorityListResponse = matchingService.calculatePriorityList(matchingRecord, + allMatchingRecords); + + // 예상되는 우선순위 리스트를 수동으로 생성 + List expectedMyPriorityList = new ArrayList<>(); + List expectedOtherPriorityList = new ArrayList<>(); + + for (MatchingRecord otherRecord : allMatchingRecords) { + Long otherMemberId = otherRecord.getMember().getId(); + if (!matchingRecord.getMember().getId().equals(otherMemberId)) { + int otherPriority = matchingService.calculatePriority(matchingRecord.getGameMode(), + matchingRecord, otherRecord); + expectedMyPriorityList.add(PriorityValue.of(otherMemberId, otherRecord.getMatchingUuid(), + otherPriority)); + + int myPriority = matchingService.calculatePriority(matchingRecord.getGameMode(), otherRecord, + matchingRecord); + expectedOtherPriorityList.add(PriorityValue.of(matchingRecord.getMember().getId(), + matchingRecord.getMatchingUuid(), myPriority)); + } + } + + // 정렬 (ID 기준으로 정렬하여 비교) + Comparator priorityComparator = Comparator.comparing(PriorityValue::getMemberId); + expectedMyPriorityList.sort(priorityComparator); + expectedOtherPriorityList.sort(priorityComparator); + priorityListResponse.getMyPriorityList().sort(priorityComparator); + priorityListResponse.getOtherPriorityList().sort(priorityComparator); + + // then - 우선순위 리스트가 예상과 같은지 검증 + assertThat(priorityListResponse.getMyPriorityList()).isEqualTo(expectedMyPriorityList); + assertThat(priorityListResponse.getOtherPriorityList()).isEqualTo(expectedOtherPriorityList); + } + + } + + private Member createMember(String email, String gameName, String tag, Tier tier, int gameRank, boolean hasMike, + Position mainP, Position subP, + Position wantP, int mannerLevel) { + + Member member = Member.create(email, "password123", LoginType.GENERAL, gameName, tag, tier, gameRank, 55.0, + 100, hasMike); + member.updateMannerLevel(mannerLevel); + member.updatePosition(mainP, subP, wantP); + return memberRepository.save(member); + } + + private MatchingRecord createMatchingRecord(GameMode mode, MatchingType type, Member member) { + MatchingRecord matchingRecord = MatchingRecord.create(mode, type, member); + return matchingRecordRepository.save(matchingRecord); + } + +} From e4749ffdf682f3bf9acf8c064a5039be1992a70e Mon Sep 17 00:00:00 2001 From: Rimi Date: Tue, 4 Feb 2025 17:19:34 +0900 Subject: [PATCH 21/28] =?UTF-8?q?:white=5Fcheck=5Fmark:=20[Test]=20Matchin?= =?UTF-8?q?gService=20=EB=A7=A4=EC=B9=AD=20=EA=B2=8C=EC=9E=84=EB=AA=A8?= =?UTF-8?q?=EB=93=9C,=20=EB=A7=A4=EC=B9=AD=ED=83=80=EC=9E=85=EC=97=90=20?= =?UTF-8?q?=EB=94=B0=EB=A5=B8=20=EC=9A=B0=EC=84=A0=EC=88=9C=EC=9C=84=20?= =?UTF-8?q?=EA=B3=84=EC=82=B0=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../matching/service/MatchingService.java | 1 - .../service/matching/MatchingServiceTest.java | 143 ++++++++++++++++-- 2 files changed, 134 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java index 691b227a..41087f67 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java @@ -97,7 +97,6 @@ public int calculatePriority(GameMode gameMode, MatchingRecord myRecord, Matchin */ public List getPendingMatchingRecords(GameMode gameMode) { return matchingRecordRepository.findRecentValidMatchingRecords(gameMode); - } /** diff --git a/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingServiceTest.java b/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingServiceTest.java index 62583657..fece8062 100644 --- a/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingServiceTest.java +++ b/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingServiceTest.java @@ -7,12 +7,14 @@ import com.gamegoo.gamegoo_v2.account.member.repository.MemberRepository; import com.gamegoo.gamegoo_v2.matching.domain.GameMode; import com.gamegoo.gamegoo_v2.matching.domain.MatchingRecord; +import com.gamegoo.gamegoo_v2.matching.domain.MatchingStatus; import com.gamegoo.gamegoo_v2.matching.domain.MatchingType; import com.gamegoo.gamegoo_v2.matching.dto.PriorityValue; import com.gamegoo.gamegoo_v2.matching.dto.response.MatchingMemberInfoResponse; import com.gamegoo.gamegoo_v2.matching.dto.response.PriorityListResponse; import com.gamegoo.gamegoo_v2.matching.repository.MatchingRecordRepository; import com.gamegoo.gamegoo_v2.matching.service.MatchingService; +import com.gamegoo.gamegoo_v2.matching.service.MatchingStrategyProcessor; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -37,7 +39,10 @@ class MatchingServiceTest { MatchingService matchingService; @Autowired - private MemberRepository memberRepository; + MatchingStrategyProcessor matchingStrategyProcessor; + + @Autowired + MemberRepository memberRepository; @Autowired MatchingRecordRepository matchingRecordRepository; @@ -63,7 +68,8 @@ class getMatchingPriorityList { @Test void getMatchingPriorityListSucceedsWhenNoUser() { // given - MatchingRecord matchingRecord = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member); + MatchingRecord matchingRecord = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member, + MatchingStatus.PENDING); // when PriorityListResponse priorityListResponse = matchingService.calculatePriorityList(matchingRecord, @@ -81,9 +87,10 @@ void getMatchingPriorityListSucceedsWhenNoUser() { @DisplayName("매칭 리스트 조회 성공 : 랜덤 대기자 20명") @Test - void validateMatchingPriorityLists() { + void validateMatchingPriorityListsSucceeds() { // given - MatchingRecord matchingRecord = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member); + MatchingRecord matchingRecord = createMatchingRecord(GameMode.SOLO, MatchingType.PRECISE, member, + MatchingStatus.PENDING); Random random = new Random(); List allMatchingRecords = new ArrayList<>(); @@ -100,12 +107,12 @@ void validateMatchingPriorityLists() { Position wantP = Position.values()[random.nextInt(Position.values().length)]; int mannerLevel = random.nextInt(4) + 1; - Member tempMember = createMember(email, gameName, tag, tier, gameRank, hasMike, mainP, subP, wantP, + Member targetMember = createMember(email, gameName, tag, tier, gameRank, hasMike, mainP, subP, wantP, mannerLevel); - MatchingRecord tempMatchingRecord = createMatchingRecord(GameMode.SOLO, MatchingType.BASIC, - tempMember); + MatchingRecord targetMatchingRecord = createMatchingRecord(GameMode.SOLO, MatchingType.BASIC, + targetMember, MatchingStatus.PENDING); - allMatchingRecords.add(tempMatchingRecord); + allMatchingRecords.add(targetMatchingRecord); } // when @@ -145,6 +152,122 @@ void validateMatchingPriorityLists() { } + @Nested + @DisplayName("매칭 우선순위 점수 계산") + class getMatchingPriority { + + @DisplayName("매칭 우선순위 점수 계산 : 개인 랭크") + @Test + void getMatchingPrioritySucceedsWhenSoloGameMode() { + // given + MatchingRecord myMatchingRecord = createMatchingRecord(GameMode.SOLO, MatchingType.BASIC, member, + MatchingStatus.PENDING); + Member targetMember = createMember("target@gmail.com", "target", "tag", Tier.SILVER, 1, true, + Position.SUP, Position.TOP, Position.ADC, 3); + MatchingRecord targetMatchingRecord = createMatchingRecord(GameMode.SOLO, MatchingType.BASIC, + targetMember, MatchingStatus.PENDING); + + // when + int priority = matchingService.calculatePriority(myMatchingRecord.getGameMode(), myMatchingRecord, + targetMatchingRecord); + + // then + int expectedPriority = matchingStrategyProcessor.calculateSoloPriority(myMatchingRecord, + targetMatchingRecord); + assertThat(priority).isEqualTo(expectedPriority); + } + + @DisplayName("매칭 우선순위 점수 계산 : 자유랭크") + @Test + void getMatchingPrioritySucceedsWhenFreeGameMode() { + // given + MatchingRecord myMatchingRecord = createMatchingRecord(GameMode.FREE, MatchingType.BASIC, member, + MatchingStatus.PENDING); + Member targetMember = createMember("target@gmail.com", "target", "tag", Tier.SILVER, 1, true, + Position.SUP, Position.TOP, Position.ADC, 3); + MatchingRecord targetMatchingRecord = createMatchingRecord(GameMode.FREE, MatchingType.BASIC, + targetMember, MatchingStatus.PENDING); + + // when + int priority = matchingService.calculatePriority(myMatchingRecord.getGameMode(), myMatchingRecord, + targetMatchingRecord); + + // then + int expectedPriority = matchingStrategyProcessor.calculateFreePriority(myMatchingRecord, + targetMatchingRecord); + assertThat(priority).isEqualTo(expectedPriority); + } + + + @DisplayName("매칭 우선순위 점수 계산 : 칼바람") + @Test + void getMatchingPrioritySucceedsWhenAramGameMode() { + // given + MatchingRecord myMatchingRecord = createMatchingRecord(GameMode.ARAM, MatchingType.BASIC, member, + MatchingStatus.PENDING); + Member targetMember = createMember("target@gmail.com", "target", "tag", Tier.SILVER, 1, true, + Position.ANY, Position.ANY, Position.ANY, 3); + MatchingRecord targetMatchingRecord = createMatchingRecord(GameMode.ARAM, MatchingType.BASIC, + targetMember, MatchingStatus.PENDING); + + // when + int priority = matchingService.calculatePriority(myMatchingRecord.getGameMode(), myMatchingRecord, + targetMatchingRecord); + + // then + int expectedPriority = matchingStrategyProcessor.calculateAramPriority(myMatchingRecord, + targetMatchingRecord); + assertThat(priority).isEqualTo(expectedPriority); + } + + @DisplayName("매칭 우선순위 점수 계산 : 빠른 대전") + @Test + void getMatchingPrioritySucceedsWhenFastGameMode() { + // given + MatchingRecord myMatchingRecord = createMatchingRecord(GameMode.FAST, MatchingType.BASIC, member, + MatchingStatus.PENDING); + Member targetMember = createMember("target@gmail.com", "target", "tag", Tier.SILVER, 1, true, + Position.SUP, Position.TOP, Position.ADC, 3); + MatchingRecord targetMatchingRecord = createMatchingRecord(GameMode.FAST, MatchingType.BASIC, + targetMember, MatchingStatus.PENDING); + + // when + int priority = matchingService.calculatePriority(myMatchingRecord.getGameMode(), myMatchingRecord, + targetMatchingRecord); + + // then + int expectedPriority = matchingStrategyProcessor.calculateFastPriority(myMatchingRecord, + targetMatchingRecord); + assertThat(priority).isEqualTo(expectedPriority); + } + + @DisplayName("매칭 우선순위 점수 계산 : 정밀 매칭") + @Test + void getMatchingPrioritySucceedsWhenPreciseMatchingType() { + // given + MatchingRecord myMatchingRecord = createMatchingRecord(GameMode.FAST, MatchingType.PRECISE, member, + MatchingStatus.PENDING); + Member targetMember = createMember("target@gmail.com", "target", "tag", Tier.SILVER, 1, true, + Position.SUP, Position.TOP, Position.ADC, 3); + MatchingRecord targetMatchingRecord = createMatchingRecord(GameMode.FAST, MatchingType.PRECISE, + targetMember, MatchingStatus.PENDING); + + // when + int priority = matchingService.calculatePriority(myMatchingRecord.getGameMode(), myMatchingRecord, + targetMatchingRecord); + + // then + int expectedPriority = 0; + if (matchingStrategyProcessor.validatePreciseMatching(myMatchingRecord, targetMatchingRecord)) { + expectedPriority = matchingStrategyProcessor.calculatePrecisePriority(myMatchingRecord, + targetMatchingRecord); + } + assertThat(priority).isEqualTo(expectedPriority); + } + + } + + private Member createMember(String email, String gameName, String tag, Tier tier, int gameRank, boolean hasMike, Position mainP, Position subP, Position wantP, int mannerLevel) { @@ -156,8 +279,10 @@ private Member createMember(String email, String gameName, String tag, Tier tier return memberRepository.save(member); } - private MatchingRecord createMatchingRecord(GameMode mode, MatchingType type, Member member) { + private MatchingRecord createMatchingRecord(GameMode mode, MatchingType type, Member member, + MatchingStatus status) { MatchingRecord matchingRecord = MatchingRecord.create(mode, type, member); + matchingRecord.updateStatus(status); return matchingRecordRepository.save(matchingRecord); } From 2caa5aa000d879d9898a88eaaf5916b639c10e6a Mon Sep 17 00:00:00 2001 From: Rimi Date: Tue, 4 Feb 2025 17:43:30 +0900 Subject: [PATCH 22/28] =?UTF-8?q?:white=5Fcheck=5Fmark:=20[Test]=20Matchin?= =?UTF-8?q?gServiceTest=20=EB=8C=80=EA=B8=B0=20=EC=A4=91=EC=9D=B8=20?= =?UTF-8?q?=EB=A7=A4=EC=B9=AD=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/matching/MatchingServiceTest.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingServiceTest.java b/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingServiceTest.java index fece8062..c519caef 100644 --- a/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingServiceTest.java +++ b/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingServiceTest.java @@ -267,6 +267,47 @@ void getMatchingPrioritySucceedsWhenPreciseMatchingType() { } + @DisplayName("대기 중인 매칭 리스트 조회") + @Test + void getPendingMatchingRecordLists() { + // given + Random random = new Random(); + GameMode gameMode = GameMode.values()[random.nextInt(GameMode.values().length)]; + List allMatchingRecords = new ArrayList<>(); + + for (int i = 0; i < 20; i++) { + // 랜덤값 생성 + String email = "user" + i + "@gmail.com"; + String gameName = "USER" + i; + String tag = "TAG" + i; + Tier tier = Tier.values()[random.nextInt(Tier.values().length)]; + int gameRank = random.nextInt(4) + 1; + boolean hasMike = random.nextBoolean(); + Position mainP = Position.values()[random.nextInt(Position.values().length)]; + Position subP = Position.values()[random.nextInt(Position.values().length)]; + Position wantP = Position.values()[random.nextInt(Position.values().length)]; + int mannerLevel = random.nextInt(4) + 1; + GameMode randomGameMode = GameMode.values()[random.nextInt(GameMode.values().length)]; + MatchingType randomMatchingType = MatchingType.values()[random.nextInt(MatchingType.values().length)]; + MatchingStatus randomMatchingStatus = MatchingStatus.PENDING; + + Member targetMember = createMember(email, gameName, tag, tier, gameRank, hasMike, mainP, subP, wantP, + mannerLevel); + MatchingRecord targetMatchingRecord = createMatchingRecord(randomGameMode, randomMatchingType, targetMember, + randomMatchingStatus); + + // MatchingRecord 리스트에 저장 + allMatchingRecords.add(targetMatchingRecord); + } + + // when + List matchingRecords = matchingService.getPendingMatchingRecords(gameMode); + + // then + List expectedMatchingRecords = + matchingRecordRepository.findRecentValidMatchingRecords(gameMode); + assertThat(matchingRecords.size()).isEqualTo(expectedMatchingRecords.size()); + } private Member createMember(String email, String gameName, String tag, Tier tier, int gameRank, boolean hasMike, Position mainP, Position subP, From 721f2c7d3501e720aca806434abbb20b12f589fa Mon Sep 17 00:00:00 2001 From: Rimi Date: Tue, 4 Feb 2025 17:46:06 +0900 Subject: [PATCH 23/28] =?UTF-8?q?:white=5Fcheck=5Fmark:=20[Test]=20Matchin?= =?UTF-8?q?gServiceTest=20=EB=A7=A4=EC=B9=AD=20=EA=B8=B0=EB=A1=9D=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/matching/MatchingServiceTest.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingServiceTest.java b/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingServiceTest.java index c519caef..3730aa79 100644 --- a/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingServiceTest.java +++ b/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingServiceTest.java @@ -309,6 +309,19 @@ void getPendingMatchingRecordLists() { assertThat(matchingRecords.size()).isEqualTo(expectedMatchingRecords.size()); } + @DisplayName("매칭 기록 생성") + @Test + void createMatchingRecord() { + // when + MatchingRecord matchingRecord = matchingService.createMatchingRecord(member, MatchingType.BASIC, GameMode.FREE); + + // then + assertThat(matchingRecord).isNotNull(); + assertThat(matchingRecord.getGameMode()).isEqualTo(GameMode.FREE); + assertThat(matchingRecord.getMatchingType()).isEqualTo(MatchingType.BASIC); + assertThat(matchingRecord.getMember()).isEqualTo(member); + } + private Member createMember(String email, String gameName, String tag, Tier tier, int gameRank, boolean hasMike, Position mainP, Position subP, Position wantP, int mannerLevel) { From a06936855183cb2730928750c3d6e7e72ffc5c2c Mon Sep 17 00:00:00 2001 From: Rimi Date: Tue, 4 Feb 2025 22:02:46 +0900 Subject: [PATCH 24/28] =?UTF-8?q?:sparkles:=20[Feat]=20=ED=8A=B9=EC=A0=95?= =?UTF-8?q?=20=EC=82=AC=EC=9A=A9=EC=9E=90=EC=9D=98=20=EA=B0=80=EC=9E=A5=20?= =?UTF-8?q?=EC=B5=9C=EA=B7=BC=20matchingRecord=20=EC=A1=B0=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/MatchingRecordRepositoryCustom.java | 9 +++++++++ .../MatchingRecordRepositoryCustomImpl.java | 13 +++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepositoryCustom.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepositoryCustom.java index 25411c6f..3764c362 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepositoryCustom.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepositoryCustom.java @@ -1,5 +1,6 @@ package com.gamegoo.gamegoo_v2.matching.repository; +import com.gamegoo.gamegoo_v2.account.member.domain.Member; import com.gamegoo.gamegoo_v2.matching.domain.GameMode; import com.gamegoo.gamegoo_v2.matching.domain.MatchingRecord; @@ -17,4 +18,12 @@ public interface MatchingRecordRepositoryCustom { */ List findValidMatchingRecords(LocalDateTime createdAt, GameMode gameMode); + /** + * 가장 최근 기록 불러오기 + * + * @param member 사용자 + * @return 사용자의 가장 최근 매칭 기록 + */ + MatchingRecord findLatestByMember(Member member); + } diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepositoryCustomImpl.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepositoryCustomImpl.java index 240e0e02..1e988305 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepositoryCustomImpl.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepositoryCustomImpl.java @@ -1,5 +1,6 @@ package com.gamegoo.gamegoo_v2.matching.repository; +import com.gamegoo.gamegoo_v2.account.member.domain.Member; import com.gamegoo.gamegoo_v2.matching.domain.GameMode; import com.gamegoo.gamegoo_v2.account.member.domain.Position; import com.gamegoo.gamegoo_v2.matching.domain.MatchingRecord; @@ -37,6 +38,18 @@ public List findValidMatchingRecords(LocalDateTime createdAt, Ga .fetch(); } + @Override + public MatchingRecord findLatestByMember(Member member) { + QMatchingRecord matchingRecord = QMatchingRecord.matchingRecord; + + return queryFactory + .selectFrom(matchingRecord) + .where(matchingRecord.member.eq(member)) + .orderBy(matchingRecord.createdAt.desc()) + .limit(1) + .fetchOne(); + } + /** * 게임 모드에 따른 추가 필터 적용 */ From d4e7dc06c07c3f18dde1cba649b4192497d0f56b Mon Sep 17 00:00:00 2001 From: Rimi Date: Tue, 4 Feb 2025 22:49:01 +0900 Subject: [PATCH 25/28] =?UTF-8?q?:white=5Fcheck=5Fmark:=20[Test]=20Matchin?= =?UTF-8?q?gFacadeServiceTest=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/InitializingMatchingRequest.java | 2 + .../matching/MatchingFacadeServiceTest.java | 125 ++++++++++++++++++ 2 files changed, 127 insertions(+) diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/request/InitializingMatchingRequest.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/request/InitializingMatchingRequest.java index aebd17e7..9b82a184 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/request/InitializingMatchingRequest.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/dto/request/InitializingMatchingRequest.java @@ -5,11 +5,13 @@ import com.gamegoo.gamegoo_v2.matching.domain.GameMode; import com.gamegoo.gamegoo_v2.matching.domain.MatchingType; import jakarta.validation.constraints.NotNull; +import lombok.Builder; import lombok.Getter; import java.util.List; @Getter +@Builder public class InitializingMatchingRequest { @NotNull(message = "gameMode 는 비워둘 수 없습니다.") diff --git a/src/test/java/com/gamegoo/gamegoo_v2/integration/matching/MatchingFacadeServiceTest.java b/src/test/java/com/gamegoo/gamegoo_v2/integration/matching/MatchingFacadeServiceTest.java index bb48df96..928549e3 100644 --- a/src/test/java/com/gamegoo/gamegoo_v2/integration/matching/MatchingFacadeServiceTest.java +++ b/src/test/java/com/gamegoo/gamegoo_v2/integration/matching/MatchingFacadeServiceTest.java @@ -2,6 +2,8 @@ import com.gamegoo.gamegoo_v2.account.member.domain.LoginType; import com.gamegoo.gamegoo_v2.account.member.domain.Member; +import com.gamegoo.gamegoo_v2.account.member.domain.Mike; +import com.gamegoo.gamegoo_v2.account.member.domain.Position; import com.gamegoo.gamegoo_v2.account.member.domain.Tier; import com.gamegoo.gamegoo_v2.account.member.repository.MemberRepository; import com.gamegoo.gamegoo_v2.chat.domain.Chat; @@ -16,7 +18,17 @@ import com.gamegoo.gamegoo_v2.core.exception.common.ErrorCode; import com.gamegoo.gamegoo_v2.core.exception.common.GlobalException; import com.gamegoo.gamegoo_v2.external.socket.SocketService; +import com.gamegoo.gamegoo_v2.matching.domain.GameMode; +import com.gamegoo.gamegoo_v2.matching.domain.MatchingRecord; +import com.gamegoo.gamegoo_v2.matching.domain.MatchingStatus; +import com.gamegoo.gamegoo_v2.matching.domain.MatchingType; +import com.gamegoo.gamegoo_v2.matching.dto.PriorityValue; +import com.gamegoo.gamegoo_v2.matching.dto.request.InitializingMatchingRequest; +import com.gamegoo.gamegoo_v2.matching.dto.response.MatchingMemberInfoResponse; +import com.gamegoo.gamegoo_v2.matching.dto.response.PriorityListResponse; +import com.gamegoo.gamegoo_v2.matching.repository.MatchingRecordRepository; import com.gamegoo.gamegoo_v2.matching.service.MatchingFacadeService; +import com.gamegoo.gamegoo_v2.matching.service.MatchingService; import com.gamegoo.gamegoo_v2.social.block.domain.Block; import com.gamegoo.gamegoo_v2.social.block.repository.BlockRepository; import org.junit.jupiter.api.AfterEach; @@ -29,14 +41,19 @@ import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.context.bean.override.mockito.MockitoSpyBean; +import org.w3c.dom.ls.LSInput; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import java.util.Optional; +import java.util.Random; import java.util.UUID; import java.util.concurrent.TimeUnit; +import static org.assertj.core.api.Assertions.as; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.within; @@ -69,6 +86,12 @@ public class MatchingFacadeServiceTest { @Autowired private MatchingFacadeService matchingFacadeService; + @Autowired + MatchingService matchingService; + + @Autowired + private MatchingRecordRepository matchingRecordRepository; + @MockitoBean private SocketService socketService; @@ -87,6 +110,7 @@ void tearDown() { memberChatroomRepository.deleteAllInBatch(); chatroomRepository.deleteAllInBatch(); blockRepository.deleteAllInBatch(); + matchingRecordRepository.deleteAllInBatch(); memberRepository.deleteAllInBatch(); } @@ -219,6 +243,88 @@ void startChatroomByMatchingSucceedsWhenChatroomNotExists() { } + @DisplayName("매칭 우선순위 계산 및 DB 저장 테스트") + @Test + void getPriorityListAndCheckRecord() { + // given + // 유저 정보 생성 + Member matchingMember = createMatchingMember("user1@gmail.com", "User1", "Tag1", Tier.GOLD, 2, true, + Position.ADC, Position.MID, Position.SUP, 2); + + // dto 생성 + InitializingMatchingRequest request = InitializingMatchingRequest.builder() + .mike(Mike.UNAVAILABLE) + .matchingType(MatchingType.BASIC) + .mainP(Position.TOP) + .subP(Position.ADC) + .wantP(Position.JUNGLE) + .gameMode(GameMode.SOLO) + .gameStyleIdList(List.of()) + .build(); + + MatchingRecord matchingRecord = MatchingRecord.create(request.getGameMode(), request.getMatchingType(), + matchingMember); + matchingRecord.updateStatus(MatchingStatus.PENDING); + + // 랜덤 대기 유저 생성 + Random random = new Random(); + for (int i = 0; i < 20; i++) { + // 랜덤값 생성 + String email = "user" + i + "@gmail.com"; + String gameName = "USER" + i; + String tag = "TAG" + i; + Tier tier = Tier.values()[random.nextInt(Tier.values().length)]; + int gameRank = random.nextInt(4) + 1; + boolean hasMike = random.nextBoolean(); + Position mainP = Position.values()[random.nextInt(Position.values().length)]; + Position subP = Position.values()[random.nextInt(Position.values().length)]; + Position wantP = Position.values()[random.nextInt(Position.values().length)]; + int mannerLevel = random.nextInt(4) + 1; + GameMode randomGameMode = GameMode.values()[random.nextInt(GameMode.values().length)]; + MatchingType randomMatchingType = MatchingType.values()[random.nextInt(MatchingType.values().length)]; + MatchingStatus randomMatchingStatus = MatchingStatus.PENDING; + + Member targetMember = createMatchingMember(email, gameName, tag, tier, gameRank, hasMike, mainP, subP, + wantP, mannerLevel); + createMatchingRecord(randomGameMode, randomMatchingType, targetMember, randomMatchingStatus); + } + + // when + PriorityListResponse priorityListResponse = + matchingFacadeService.calculatePriorityAndRecording(matchingMember.getId(), request); + + // then + assertThat(priorityListResponse).isNotNull(); + + // 1. Member 정보 업데이트 검증 + //assertThat(matchingMember.getMike()).isEqualTo(request.getMike()); + //assertThat(matchingMember.getMainPosition()).isEqualTo(request.getMainP()); + //assertThat(matchingMember.getSubPosition()).isEqualTo(request.getSubP()); + //assertThat(matchingMember.getWantPosition()).isEqualTo(request.getWantP()); + //assertThat(matchingMember.getMemberGameStyleList()).isEqualTo(request.getGameStyleIdList()); + + // 2. 생성된 MatchingRecord 검증 + + // 3. Priority 검증 + List recentValidMatchingRecords = + matchingRecordRepository.findRecentValidMatchingRecords(request.getGameMode()); + PriorityListResponse expectedPriorityList = matchingService.calculatePriorityList(matchingRecord, + recentValidMatchingRecords); + + assertThat(priorityListResponse).isNotNull(); + + // 정렬 (ID 기준으로 정렬하여 비교) + Comparator priorityComparator = Comparator.comparing(PriorityValue::getMemberId); + expectedPriorityList.getMyPriorityList().sort(priorityComparator); + expectedPriorityList.getOtherPriorityList().sort(priorityComparator); + priorityListResponse.getMyPriorityList().sort(priorityComparator); + priorityListResponse.getOtherPriorityList().sort(priorityComparator); + + assertThat(priorityListResponse.getMyPriorityList()).isEqualTo(expectedPriorityList.getMyPriorityList()); + assertThat(priorityListResponse.getOtherPriorityList()).isEqualTo(expectedPriorityList.getOtherPriorityList()); + } + + private Member createMember(String email, String gameName) { return memberRepository.save(Member.builder() .email(email) @@ -259,4 +365,23 @@ private Block blockMember(Member member, Member targetMember) { return blockRepository.save(Block.create(member, targetMember)); } + private Member createMatchingMember(String email, String gameName, String tag, Tier tier, int gameRank, + boolean hasMike, + Position mainP, Position subP, + Position wantP, int mannerLevel) { + + Member member = Member.create(email, "password123", LoginType.GENERAL, gameName, tag, tier, gameRank, 55.0, + 100, hasMike); + member.updateMannerLevel(mannerLevel); + member.updatePosition(mainP, subP, wantP); + return memberRepository.save(member); + } + + private MatchingRecord createMatchingRecord(GameMode mode, MatchingType type, Member member, + MatchingStatus status) { + MatchingRecord matchingRecord = MatchingRecord.create(mode, type, member); + matchingRecord.updateStatus(status); + return matchingRecordRepository.save(matchingRecord); + } + } From e10de4b5b61521229295be97897fdb12bf0a36c7 Mon Sep 17 00:00:00 2001 From: Rimi Date: Tue, 4 Feb 2025 23:00:31 +0900 Subject: [PATCH 26/28] =?UTF-8?q?:bug:=20[Fix]=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20JPA=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../matching/repository/MatchingRecordRepository.java | 10 ---------- .../gamegoo_v2/matching/service/MatchingService.java | 3 ++- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepository.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepository.java index 12ddb666..4099bd16 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepository.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/repository/MatchingRecordRepository.java @@ -1,20 +1,10 @@ package com.gamegoo.gamegoo_v2.matching.repository; -import com.gamegoo.gamegoo_v2.matching.domain.GameMode; import com.gamegoo.gamegoo_v2.matching.domain.MatchingRecord; import org.springframework.data.jpa.repository.JpaRepository; -import java.time.LocalDateTime; -import java.util.List; public interface MatchingRecordRepository extends JpaRepository, MatchingRecordRepositoryCustom { - /** - * 5분 이내, 특정 게임 모드, PENDING 상태의 매칭 레코드 조회 - */ - default List findRecentValidMatchingRecords(GameMode gameMode) { - return findValidMatchingRecords(LocalDateTime.now().minusMinutes(5), gameMode); - } - } diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java index 41087f67..6188d760 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingService.java @@ -11,6 +11,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @@ -96,7 +97,7 @@ public int calculatePriority(GameMode gameMode, MatchingRecord myRecord, Matchin * @return 대기 중인 매칭 리스트 */ public List getPendingMatchingRecords(GameMode gameMode) { - return matchingRecordRepository.findRecentValidMatchingRecords(gameMode); + return matchingRecordRepository.findValidMatchingRecords(LocalDateTime.now().minusMinutes(5), gameMode); } /** From 812acedba80b7271c73e7c8e3eb181cd35601e89 Mon Sep 17 00:00:00 2001 From: Rimi Date: Tue, 4 Feb 2025 23:28:39 +0900 Subject: [PATCH 27/28] =?UTF-8?q?:white=5Fcheck=5Fmark:=20[Test]=20Matchin?= =?UTF-8?q?gFacadeServiceTest=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../matching/MatchingFacadeServiceTest.java | 50 ++++++++++++------- .../service/matching/MatchingServiceTest.java | 3 +- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/test/java/com/gamegoo/gamegoo_v2/integration/matching/MatchingFacadeServiceTest.java b/src/test/java/com/gamegoo/gamegoo_v2/integration/matching/MatchingFacadeServiceTest.java index 928549e3..8f1fff16 100644 --- a/src/test/java/com/gamegoo/gamegoo_v2/integration/matching/MatchingFacadeServiceTest.java +++ b/src/test/java/com/gamegoo/gamegoo_v2/integration/matching/MatchingFacadeServiceTest.java @@ -24,7 +24,6 @@ import com.gamegoo.gamegoo_v2.matching.domain.MatchingType; import com.gamegoo.gamegoo_v2.matching.dto.PriorityValue; import com.gamegoo.gamegoo_v2.matching.dto.request.InitializingMatchingRequest; -import com.gamegoo.gamegoo_v2.matching.dto.response.MatchingMemberInfoResponse; import com.gamegoo.gamegoo_v2.matching.dto.response.PriorityListResponse; import com.gamegoo.gamegoo_v2.matching.repository.MatchingRecordRepository; import com.gamegoo.gamegoo_v2.matching.service.MatchingFacadeService; @@ -41,11 +40,10 @@ import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.context.bean.override.mockito.MockitoSpyBean; -import org.w3c.dom.ls.LSInput; +import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; -import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Optional; @@ -53,7 +51,6 @@ import java.util.UUID; import java.util.concurrent.TimeUnit; -import static org.assertj.core.api.Assertions.as; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.within; @@ -66,6 +63,7 @@ @ActiveProfiles("test") @SpringBootTest +@Transactional public class MatchingFacadeServiceTest { @MockitoSpyBean @@ -248,7 +246,7 @@ void startChatroomByMatchingSucceedsWhenChatroomNotExists() { void getPriorityListAndCheckRecord() { // given // 유저 정보 생성 - Member matchingMember = createMatchingMember("user1@gmail.com", "User1", "Tag1", Tier.GOLD, 2, true, + Member matchingMember = createMatchingMember("matchinguser@gmail.com", "User1", "Tag1", Tier.GOLD, 2, true, Position.ADC, Position.MID, Position.SUP, 2); // dto 생성 @@ -262,10 +260,6 @@ void getPriorityListAndCheckRecord() { .gameStyleIdList(List.of()) .build(); - MatchingRecord matchingRecord = MatchingRecord.create(request.getGameMode(), request.getMatchingType(), - matchingMember); - matchingRecord.updateStatus(MatchingStatus.PENDING); - // 랜덤 대기 유저 생성 Random random = new Random(); for (int i = 0; i < 20; i++) { @@ -293,21 +287,37 @@ void getPriorityListAndCheckRecord() { PriorityListResponse priorityListResponse = matchingFacadeService.calculatePriorityAndRecording(matchingMember.getId(), request); + Member updatedMember = memberRepository.findByEmail("matchinguser@gmail.com") + .orElseThrow(() -> new AssertionError("테스트 실패: Member가 존재하지 않음")); + + MatchingRecord matchingRecord = MatchingRecord.create(request.getGameMode(), request.getMatchingType(), + updatedMember); + matchingRecord.updateStatus(MatchingStatus.PENDING); + // then assertThat(priorityListResponse).isNotNull(); // 1. Member 정보 업데이트 검증 - //assertThat(matchingMember.getMike()).isEqualTo(request.getMike()); - //assertThat(matchingMember.getMainPosition()).isEqualTo(request.getMainP()); - //assertThat(matchingMember.getSubPosition()).isEqualTo(request.getSubP()); - //assertThat(matchingMember.getWantPosition()).isEqualTo(request.getWantP()); - //assertThat(matchingMember.getMemberGameStyleList()).isEqualTo(request.getGameStyleIdList()); + assertThat(updatedMember.getMike()).isEqualTo(request.getMike()); + assertThat(updatedMember.getMainPosition()).isEqualTo(request.getMainP()); + assertThat(updatedMember.getSubPosition()).isEqualTo(request.getSubP()); + assertThat(updatedMember.getWantPosition()).isEqualTo(request.getWantP()); // 2. 생성된 MatchingRecord 검증 + MatchingRecord actualMatchingRecord = matchingRecordRepository.findLatestByMember(updatedMember); + + assertThat(actualMatchingRecord.getGameMode()).isEqualTo(request.getGameMode()); + assertThat(actualMatchingRecord.getMatchingType()).isEqualTo(request.getMatchingType()); + assertThat(actualMatchingRecord.getStatus()).isEqualTo(MatchingStatus.PENDING); + assertThat(actualMatchingRecord.getMember().getId()).isEqualTo(updatedMember.getId()); + assertThat(actualMatchingRecord.getMainPosition()).isEqualTo(request.getMainP()); + assertThat(actualMatchingRecord.getSubPosition()).isEqualTo(request.getSubP()); + assertThat(actualMatchingRecord.getWantPosition()).isEqualTo(request.getWantP()); + assertThat(actualMatchingRecord.getMike()).isEqualTo(request.getMike()); // 3. Priority 검증 List recentValidMatchingRecords = - matchingRecordRepository.findRecentValidMatchingRecords(request.getGameMode()); + matchingRecordRepository.findValidMatchingRecords(LocalDateTime.now().minusMinutes(5), GameMode.SOLO); PriorityListResponse expectedPriorityList = matchingService.calculatePriorityList(matchingRecord, recentValidMatchingRecords); @@ -320,8 +330,14 @@ void getPriorityListAndCheckRecord() { priorityListResponse.getMyPriorityList().sort(priorityComparator); priorityListResponse.getOtherPriorityList().sort(priorityComparator); - assertThat(priorityListResponse.getMyPriorityList()).isEqualTo(expectedPriorityList.getMyPriorityList()); - assertThat(priorityListResponse.getOtherPriorityList()).isEqualTo(expectedPriorityList.getOtherPriorityList()); + assertThat(priorityListResponse.getMyPriorityList()) + .usingRecursiveComparison() + .ignoringFields("matchingUuid") + .isEqualTo(expectedPriorityList.getMyPriorityList()); + assertThat(priorityListResponse.getOtherPriorityList()) + .usingRecursiveComparison() + .ignoringFields("matchingUuid") + .isEqualTo(expectedPriorityList.getOtherPriorityList()); } diff --git a/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingServiceTest.java b/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingServiceTest.java index 3730aa79..5899c60f 100644 --- a/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingServiceTest.java +++ b/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingServiceTest.java @@ -24,6 +24,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Comparator; import java.util.List; @@ -305,7 +306,7 @@ void getPendingMatchingRecordLists() { // then List expectedMatchingRecords = - matchingRecordRepository.findRecentValidMatchingRecords(gameMode); + matchingRecordRepository.findValidMatchingRecords(LocalDateTime.now().minusMinutes(5), gameMode); assertThat(matchingRecords.size()).isEqualTo(expectedMatchingRecords.size()); } From 93002d14012fd84024e9745a06e3c1aae328e86a Mon Sep 17 00:00:00 2001 From: Rimi Date: Wed, 5 Feb 2025 00:32:02 +0900 Subject: [PATCH 28/28] =?UTF-8?q?:recycle:=20[refactor]=20MatchingScoreCal?= =?UTF-8?q?culator=20static=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/MatchingScoreCalculator.java | 18 ++++----- .../service/MatchingStrategyProcessor.java | 38 +++++++++---------- .../matching/MatchingScoreCalculatorTest.java | 24 +++++------- .../MatchingStrategyProcessorTest.java | 7 +--- 4 files changed, 37 insertions(+), 50 deletions(-) diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingScoreCalculator.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingScoreCalculator.java index f2458058..220d4e48 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingScoreCalculator.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingScoreCalculator.java @@ -3,9 +3,7 @@ import com.gamegoo.gamegoo_v2.account.member.domain.Position; import com.gamegoo.gamegoo_v2.account.member.domain.Tier; import com.gamegoo.gamegoo_v2.account.member.domain.Mike; -import org.springframework.stereotype.Component; -@Component public class MatchingScoreCalculator { /** @@ -17,8 +15,8 @@ public class MatchingScoreCalculator { * @param mannerDifferenceMultiplier 매너 점수 별 가중치 값 * @return 최종 매너점수 */ - public int getMannerPriority(Integer otherManner, Integer myManner, int maxMannerPriority, - int mannerDifferenceMultiplier) { + public static int getMannerPriority(Integer otherManner, Integer myManner, int maxMannerPriority, + int mannerDifferenceMultiplier) { int mannerDifference = Math.abs(myManner - otherManner); return maxMannerPriority - mannerDifference * mannerDifferenceMultiplier; } @@ -34,8 +32,8 @@ public int getMannerPriority(Integer otherManner, Integer myManner, int maxManne * @param tierMultiplier 티어 점수 * @return 랭킹 우선순위 값 */ - public int getTierRankPriority(Tier myTier, Integer myRank, Tier otherTier, Integer otherRank, - int maxTierRankPriority, int tierMultiplier) { + public static int getTierRankPriority(Tier myTier, Integer myRank, Tier otherTier, Integer otherRank, + int maxTierRankPriority, int tierMultiplier) { int myScore = getTierRankScore(myTier, myRank, tierMultiplier); int otherScore = getTierRankScore(otherTier, otherRank, tierMultiplier); int scoreDifference = Math.abs(myScore - otherScore); @@ -51,7 +49,7 @@ public int getTierRankPriority(Tier myTier, Integer myRank, Tier otherTier, Inte * @param tierMultiplier 티어 점수 * @return 랭킹 점수 */ - private int getTierRankScore(Tier tier, int rank, int tierMultiplier) { + private static int getTierRankScore(Tier tier, int rank, int tierMultiplier) { return tier.ordinal() * tierMultiplier - rank; } @@ -66,8 +64,8 @@ private int getTierRankScore(Tier tier, int rank, int tierMultiplier) { * @param defaultPositionPriority 낮은 추가 점수 * @return 포지션 우선순위 점수 */ - public int getPositionPriority(Position myWantPosition, Position otherMainPosition, Position otherSubPosition, - int mainPositionPriority, int subPositionPriority, int defaultPositionPriority) { + public static int getPositionPriority(Position myWantPosition, Position otherMainPosition, Position otherSubPosition, + int mainPositionPriority, int subPositionPriority, int defaultPositionPriority) { int priority = 0; if (myWantPosition == otherMainPosition || myWantPosition == Position.ANY || otherMainPosition == Position.ANY) { @@ -89,7 +87,7 @@ public int getPositionPriority(Position myWantPosition, Position otherMainPositi * @param mikeMatchPriority 마이크 점수 * @return 마이크 우선순위 점수 */ - public int getMikePriority(Mike myMike, Mike otherMike, int mikeMatchPriority) { + public static int getMikePriority(Mike myMike, Mike otherMike, int mikeMatchPriority) { if (!myMike.equals(otherMike)) { return 0; } diff --git a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingStrategyProcessor.java b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingStrategyProcessor.java index 8879fc84..a006916a 100644 --- a/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingStrategyProcessor.java +++ b/src/main/java/com/gamegoo/gamegoo_v2/matching/service/MatchingStrategyProcessor.java @@ -8,8 +8,6 @@ @RequiredArgsConstructor public class MatchingStrategyProcessor { - private final MatchingScoreCalculator matchingScoreCalculator; - /** * 정밀매칭 우선순위 계산 * @@ -18,7 +16,7 @@ public class MatchingStrategyProcessor { * @return 우선순위 점수 */ public int calculatePrecisePriority(MatchingRecord myRecord, MatchingRecord otherRecord) { - return matchingScoreCalculator.getMannerPriority( + return MatchingScoreCalculator.getMannerPriority( otherRecord.getMannerLevel(), myRecord.getMannerLevel(), 16, 4); } @@ -33,21 +31,21 @@ public int calculateFastPriority(MatchingRecord myRecord, MatchingRecord otherRe int priority = 0; // 매너 우선순위 - priority += matchingScoreCalculator.getMannerPriority( + priority += MatchingScoreCalculator.getMannerPriority( otherRecord.getMannerLevel(), myRecord.getMannerLevel(), 16, 4); // TODO: 티어 및 랭킹 점수 계산 - priority += matchingScoreCalculator.getTierRankPriority(myRecord.getSoloTier(), myRecord.getSoloRank(), + priority += MatchingScoreCalculator.getTierRankPriority(myRecord.getSoloTier(), myRecord.getSoloRank(), otherRecord.getSoloTier(), otherRecord.getSoloRank(), 40, 4); // 포지션 우선순위 - priority += matchingScoreCalculator.getPositionPriority( + priority += MatchingScoreCalculator.getPositionPriority( myRecord.getWantPosition(), otherRecord.getMainPosition(), otherRecord.getSubPosition(), 3, 2, 1); - priority += matchingScoreCalculator.getPositionPriority( + priority += MatchingScoreCalculator.getPositionPriority( otherRecord.getWantPosition(), myRecord.getMainPosition(), myRecord.getSubPosition(), 3, 2, 1); // 마이크 우선순위 - priority += matchingScoreCalculator.getMikePriority(myRecord.getMike(), otherRecord.getMike(), 3); + priority += MatchingScoreCalculator.getMikePriority(myRecord.getMike(), otherRecord.getMike(), 3); return priority; } @@ -63,22 +61,22 @@ public int calculateSoloPriority(MatchingRecord myRecord, MatchingRecord otherRe int priority = 0; // 매너 우선순위 - priority += matchingScoreCalculator.getMannerPriority( + priority += MatchingScoreCalculator.getMannerPriority( otherRecord.getMannerLevel(), myRecord.getMannerLevel(), 16, 4); // 티어 및 랭킹 점수 계산 - priority += matchingScoreCalculator.getTierRankPriority( + priority += MatchingScoreCalculator.getTierRankPriority( myRecord.getSoloTier(), myRecord.getSoloRank(), otherRecord.getSoloTier(), otherRecord.getSoloRank(), 40, 4); // 포지션 우선순위 - priority += matchingScoreCalculator.getPositionPriority( + priority += MatchingScoreCalculator.getPositionPriority( myRecord.getWantPosition(), otherRecord.getMainPosition(), otherRecord.getSubPosition(), 3, 2, 1); - priority += matchingScoreCalculator.getPositionPriority( + priority += MatchingScoreCalculator.getPositionPriority( otherRecord.getWantPosition(), myRecord.getMainPosition(), myRecord.getSubPosition(), 3, 2, 1); // 마이크 우선순위 - priority += matchingScoreCalculator.getMikePriority(myRecord.getMike(), otherRecord.getMike(), 5); + priority += MatchingScoreCalculator.getMikePriority(myRecord.getMike(), otherRecord.getMike(), 5); return priority; } @@ -94,22 +92,22 @@ public int calculateFreePriority(MatchingRecord myRecord, MatchingRecord otherRe int priority = 0; // 매너 우선순위 - priority += matchingScoreCalculator.getMannerPriority( + priority += MatchingScoreCalculator.getMannerPriority( otherRecord.getMannerLevel(), myRecord.getMannerLevel(), 16, 4); // 티어 및 랭킹 점수 계산 - priority += matchingScoreCalculator.getTierRankPriority( + priority += MatchingScoreCalculator.getTierRankPriority( myRecord.getFreeTier(), myRecord.getFreeRank(), otherRecord.getFreeTier(), otherRecord.getFreeRank(), 40, 4); // 포지션 우선순위 - priority += matchingScoreCalculator.getPositionPriority( + priority += MatchingScoreCalculator.getPositionPriority( myRecord.getWantPosition(), otherRecord.getMainPosition(), otherRecord.getSubPosition(), 3, 2, 1); - priority += matchingScoreCalculator.getPositionPriority( + priority += MatchingScoreCalculator.getPositionPriority( otherRecord.getWantPosition(), myRecord.getMainPosition(), myRecord.getSubPosition(), 3, 2, 1); // 마이크 우선순위 - priority += matchingScoreCalculator.getMikePriority(myRecord.getMike(), otherRecord.getMike(), 3); + priority += MatchingScoreCalculator.getMikePriority(myRecord.getMike(), otherRecord.getMike(), 3); return priority; } @@ -125,11 +123,11 @@ public int calculateAramPriority(MatchingRecord myRecord, MatchingRecord otherRe int priority = 0; // 매너 우선순위 - priority += matchingScoreCalculator.getMannerPriority( + priority += MatchingScoreCalculator.getMannerPriority( otherRecord.getMannerLevel(), myRecord.getMannerLevel(), 16, 4); // 마이크 우선순위 - priority += matchingScoreCalculator.getMikePriority(myRecord.getMike(), otherRecord.getMike(), 3); + priority += MatchingScoreCalculator.getMikePriority(myRecord.getMike(), otherRecord.getMike(), 3); return priority; } diff --git a/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingScoreCalculatorTest.java b/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingScoreCalculatorTest.java index 710779a4..14d9acbe 100644 --- a/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingScoreCalculatorTest.java +++ b/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingScoreCalculatorTest.java @@ -6,65 +6,59 @@ import com.gamegoo.gamegoo_v2.matching.service.MatchingScoreCalculator; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; import static org.assertj.core.api.Assertions.assertThat; @ActiveProfiles("test") -@SpringBootTest class MatchingScoreCalculatorTest { - @Autowired - MatchingScoreCalculator matchingScoreCalculator; - @Test @DisplayName("매너레벨 점수 계산: 동일한 매너 점수") void testGetMannerPriority_SameManner() { - int result = matchingScoreCalculator.getMannerPriority(5, 5, 16, 4); + int result = MatchingScoreCalculator.getMannerPriority(5, 5, 16, 4); assertThat(result).isEqualTo(16); } @Test @DisplayName("매너레벨 점수 계산: 매너 차이가 있을 때") void testGetMannerPriority_DifferentManner() { - int result = matchingScoreCalculator.getMannerPriority(5, 1, 16, 4); + int result = MatchingScoreCalculator.getMannerPriority(5, 1, 16, 4); assertThat(result).isEqualTo(0); } @Test @DisplayName("랭킹 우선순위 점수 계산: 동일한 티어 및 랭크") void testGetTierRankPriority_SameTierAndRank() { - int result = matchingScoreCalculator.getTierRankPriority(Tier.GOLD, 4, Tier.GOLD, 4, 40, 4); + int result = MatchingScoreCalculator.getTierRankPriority(Tier.GOLD, 4, Tier.GOLD, 4, 40, 4); assertThat(result).isEqualTo(40); } @Test @DisplayName("랭킹 우선순위 점수 계산: 티어와 랭크 차이") void testGetTierRankPriority_DifferentTierAndRank() { - int result = matchingScoreCalculator.getTierRankPriority(Tier.GOLD, 1, Tier.SILVER, 2, 40, 4); + int result = MatchingScoreCalculator.getTierRankPriority(Tier.GOLD, 1, Tier.SILVER, 2, 40, 4); assertThat(result).isEqualTo(35); } @Test @DisplayName("포지션 우선순위 점수 계산: 내가 원하는 포지션이 상대방 부포지션") void testGetPositionPriority_SameMainPosition() { - int result = matchingScoreCalculator.getPositionPriority(Position.TOP, Position.TOP, Position.MID, 3, 2, 1); + int result = MatchingScoreCalculator.getPositionPriority(Position.TOP, Position.TOP, Position.MID, 3, 2, 1); assertThat(result).isEqualTo(3); } @Test @DisplayName("포지션 우선순위 점수 계산: 내가 원하는 포지션이 상대방 부 포지션") void testGetPositionPriority_SubPositionMatch() { - int result = matchingScoreCalculator.getPositionPriority(Position.MID, Position.TOP, Position.MID, 3, 2, 1); + int result = MatchingScoreCalculator.getPositionPriority(Position.MID, Position.TOP, Position.MID, 3, 2, 1); assertThat(result).isEqualTo(2); } @Test @DisplayName("포지션 우선순위 점수 계산: ANY 포지션 포함") void testGetPositionPriority_AnyPosition() { - int result = matchingScoreCalculator.getPositionPriority(Position.ANY, Position.JUNGLE, Position.MID, 50, 30, + int result = MatchingScoreCalculator.getPositionPriority(Position.ANY, Position.JUNGLE, Position.MID, 50, 30, 10); assertThat(result).isEqualTo(50); } @@ -72,14 +66,14 @@ void testGetPositionPriority_AnyPosition() { @Test @DisplayName("마이크 우선순위 점수 계산: 동일한 마이크 설정") void testGetMikePriority_SameMike() { - int result = matchingScoreCalculator.getMikePriority(Mike.AVAILABLE, Mike.AVAILABLE, 2); + int result = MatchingScoreCalculator.getMikePriority(Mike.AVAILABLE, Mike.AVAILABLE, 2); assertThat(result).isEqualTo(2); } @Test @DisplayName("마이크 우선순위 점수 계산: 다른 마이크 설정") void testGetMikePriority_DifferentMike() { - int result = matchingScoreCalculator.getMikePriority(Mike.AVAILABLE, Mike.UNAVAILABLE, 2); + int result = MatchingScoreCalculator.getMikePriority(Mike.AVAILABLE, Mike.UNAVAILABLE, 2); assertThat(result).isEqualTo(0); } diff --git a/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingStrategyProcessorTest.java b/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingStrategyProcessorTest.java index d55d85a7..81eee3f2 100644 --- a/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingStrategyProcessorTest.java +++ b/src/test/java/com/gamegoo/gamegoo_v2/service/matching/MatchingStrategyProcessorTest.java @@ -23,9 +23,6 @@ @SpringBootTest class MatchingStrategyProcessorTest { - @Autowired - MatchingScoreCalculator matchingScoreCalculator; - @Autowired MatchingStrategyProcessor matchingStrategyProcessor; @@ -267,12 +264,12 @@ private int getPositionExpectedPriority(Member member1, Member member2) { // 포지션 expectedPriority 계산 int positionPriority = 0; - positionPriority += matchingScoreCalculator.getPositionPriority( + positionPriority += MatchingScoreCalculator.getPositionPriority( member1.getWantPosition(), member2.getMainPosition(), member2.getSubPosition(), 3, 2, 1 ); - positionPriority += matchingScoreCalculator.getPositionPriority( + positionPriority += MatchingScoreCalculator.getPositionPriority( member2.getWantPosition(), member1.getMainPosition(), member1.getSubPosition(), 3, 2, 1 );