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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.example.silverbridgeX_user.matching.algorithm;

import com.example.silverbridgeX_user.matching.domain.MatchRequest;
import com.example.silverbridgeX_user.user.domain.User;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

public class AdjacencyGraphBuilder {

public static List<Integer>[] buildAdjacencyGraph(List<MatchRequest> matchRequests) {
int n = matchRequests.size();
List<Integer>[] graph = new ArrayList[n + 1];

for (int i = 1; i <= n; i++) {
graph[i] = new ArrayList<>();
}

for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
if (canConnect(matchRequests.get(i - 1), matchRequests.get(j - 1))) {
graph[i].add(j);
graph[j].add(i);
}
}
}

return graph;
}

private static boolean canConnect(MatchRequest a, MatchRequest b) {
User A = a.getUser();
User B = b.getUser();

// String sexA = A.getSex();
// String sexB = B.getSex();
//
// if (sexA == null || sexB == null) return false;

Double latA = A.getLatitude();
Double lonA = A.getLongitude();
Double latB = B.getLatitude();
Double lonB = B.getLongitude();

if (latA == null || lonA == null || latB == null || lonB == null) return false;

// LocalDate birthA = A.getBirth();
// LocalDate birthB = B.getBirth();
//
// if (birthA == null || birthB == null) return false;

// return !sexA.equals(sexB) &&
// GeoUtils.haversine(latA, lonA, latB, lonB) <= 3.0 &&
// Math.abs(birthA.getYear() - birthB.getYear()) <= 10;
return GeoUtils.haversine(latA, lonA, latB, lonB) <= 3.0;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.example.silverbridgeX_user.matching.algorithm;

import java.util.List;

public class BipartiteMatcher {
private final List<Integer>[] adj;
private final Integer[] matching; // match[v] = u
private boolean[] visited;

public BipartiteMatcher(List<Integer>[] adj) {
this.adj = adj;
this.matching = new Integer[adj.length]; // 1-based index
}

public int run() {
int res = 0;
for (int u = 1; u < adj.length; u++) {
visited = new boolean[adj.length];
if (dfs(u)) {
res++;
}
}
return res;
}

private boolean dfs(int u) {
for (int v : adj[u]) {
if (visited[v]) continue;
visited[v] = true;

if (matching[v] == 0 || dfs(matching[v])) {
matching[v] = u;
return true;
}
}
return false;
}

public Integer[] getMatching() {
return matching;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.example.silverbridgeX_user.matching.algorithm;

public class GeoUtils {

private static final double EARTH_RADIUS_KM = 6371.0;

public static double haversine(double lat1, double lon1, double lat2, double lon2) {
double dLat = Math.toRadians(lat2 - lat1);
double dLon = Math.toRadians(lon2 - lon1);

lat1 = Math.toRadians(lat1);
lat2 = Math.toRadians(lat2);

double a = Math.pow(Math.sin(dLat / 2), 2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(dLon / 2), 2);

double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

return EARTH_RADIUS_KM * c;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package com.example.silverbridgeX_user.matching.algorithm;

import java.util.ArrayDeque;
import java.util.List;
import java.util.Queue;

public class Matcher {

private final List<Integer>[] adj;
private final Integer[] matching;
private final Integer[] parent;
private final Integer[] color;
private final Integer[] visited;
private final Integer[] group;

public Matcher(List<Integer>[] adj) {
this.adj = adj;
this.matching = new Integer[adj.length];
this.parent = new Integer[adj.length];
this.color = new Integer[adj.length];
this.visited = new Integer[adj.length];
this.group = new Integer[adj.length];
}

public int run() {
int res = 0;
for (int i = 1; i < adj.length; i++) {
matching[i] = 0;
}

for (int i = 1; i < adj.length; i++) {
if (matching[i] == 0) {
if (findAugmentPath(i)) {
res++;
}
}
}

return res;
}

private boolean findAugmentPath(int r) {
for (int i = 1; i < adj.length; i++) {
parent[i] = 0;
color[i] = -1;
visited[i] = 0;
group[i] = i;
}

Queue<Integer> q = new ArrayDeque<>();

color[r] = 0;
visited[r] = 1;
q.add(r);

while (!q.isEmpty()) {
int u = q.poll();
for (int v : adj[u]) {
if (color[v] == -1) {
parent[v] = u;
color[v] = 1;

if (matching[v] == 0) {
flipAugmentPath(r, v);
return true;
}

color[matching[v]] = 0;
visited[matching[v]] = 1;
q.add(matching[v]);
}
else if (color[v] == 0 && !group[u].equals(group[v])) {
int p = lca(group[r], group[u], group[v]);

group_blossom(p, u, v);
group_blossom(p, v, u);

for (int i = 1; i < adj.length; i++) {
if (visited[i] != 0 && color[i] != 0) {
color[i] = 0;
q.add(i);
}
}
}
}
}
return false;
}

private void flipAugmentPath(int root, int u) {
while (parent[u] != root) {
int v = parent[u];
int w = matching[v];

matching[u] = v;
matching[v] = u;

matching[w] = 0;
u = w;
}
matching[u] = root;
matching[root] = u;
}

private int lca(int root, int u, int v) {
Integer[] check = new Integer[adj.length];
for (int i = 1; i < adj.length; i++) {
check[i] = 0;
}

while (u != root) {
check[u] = 1;
u = group[parent[matching[u]]];
}

while (v != root) {
if (check[v] != 0) return v;
v = group[parent[matching[v]]];
}

return root;
}

private void group_blossom(int p, int u, int v) {
while (group[u] != p) {
int nv = matching[u];
int nu = parent[nv];
if (visited[nv] == 0) {
visited[nv] = 1;
}

parent[u] = v;
group[u] = p;
group[nv] = p;
u = nu;
v = nv;
}
}

public Integer[] getMatching() {
return matching;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

import com.example.silverbridgeX_user.matching.domain.MatchRequest;
import com.example.silverbridgeX_user.matching.domain.MatchStatus;
import com.example.silverbridgeX_user.matching.dto.MatchingDto;
import com.example.silverbridgeX_user.user.domain.User;

import java.util.List;

public class MatchingConverter {

public static MatchRequest toMatchRequest(User user) {
Expand All @@ -12,4 +15,19 @@ public static MatchRequest toMatchRequest(User user) {
.user(user)
.build();
}

public static MatchingDto.Request toMatchingDtoRequest(User a, User b) {
MatchingDto.Participant participantA = MatchingDto.Participant.builder()
.id(a.getId())
.name(a.getNickname())
.build();
MatchingDto.Participant participantB = MatchingDto.Participant.builder()
.id(b.getId())
.name(b.getNickname())
.build();

return MatchingDto.Request.builder()
.participants(List.of(participantA, participantB))
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,8 @@ public class MatchRequest extends BaseEntity {
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;

public void updateStatus(MatchStatus status) {
this.status = status;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.example.silverbridgeX_user.matching.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.List;

public class MatchingDto {

@Builder
@Getter
@AllArgsConstructor
@NoArgsConstructor
public static class Participant {
private Long id;
private String name;
}

@Builder
@Getter
@AllArgsConstructor
@NoArgsConstructor
public static class Request {
private List<Participant> participants;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
package com.example.silverbridgeX_user.matching.repository;

import com.example.silverbridgeX_user.matching.domain.MatchRequest;
import com.example.silverbridgeX_user.matching.domain.MatchStatus;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;

public interface MatchingRepository extends JpaRepository<MatchRequest, Long> {

@Query("SELECT m FROM MatchRequest m JOIN FETCH m.user WHERE m.status = :status ORDER BY m.createdAt ASC")
List<MatchRequest> findAllWithUserByStatus(@Param("status") MatchStatus status);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.example.silverbridgeX_user.matching.scheduler;

import com.example.silverbridgeX_user.matching.service.MatchingService;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

@Component
@RequiredArgsConstructor
public class MatchingScheduler {

private final MatchingService matchingService;

@Scheduled(cron = "0 18,38,58 * * * *")
public void executeMatching() {
System.out.println("매칭 알고리즘 실행됨: " + LocalDateTime.now());
matchingService.executeMatchingAlgorithm();
}
}
Loading
Loading