| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- const Schmervice = require('@hapipal/schmervice')
-
- function engageEveryone(guys) {
- let done
- do {
- done = true
- for (let i = 0; i < guys.length; i++) {
- const guy = guys[i]
- if (!guy.fiance) {
- done = false
- const gal = guy.nextCandidate()
- if (!gal.fiance || gal.prefers(guy)) {
- guy.engageTo(gal)
- }
- }
- }
- } while (!done)
- }
-
- class Person {
- constructor(name) {
- let candidateIndex = 0
- this.name = name
- this.fiance = null
- this.candidates = []
- this.rank = p => {
- for (let i = 0; i < this.candidates.length; i++) {
- if (this.candidates[i] === p) return i
- }
- return this.candidates.length + 1
- }
- this.prefers = p => {
- return this.rank(p) < this.rank(this.fiance)
- }
- this.nextCandidate = () => {
- if (candidateIndex >= this.candidates.length) {
- return null
- }
- return this.candidates[candidateIndex++]
- }
-
- this.engageTo = p => {
- if (p.fiance) {
- p.fiance.fiance = null
- }
- p.fiance = this
- if (this.fiance) {
- this.fiance.fiance = null
- }
- this.fiance = p
- }
-
- this.swapWith = p => {
- const thisFiance = this.fiance
- const pFiance = p.fiance
- this.engageTo(pFiance)
- p.engageTo(thisFiance)
- }
- }
- }
-
- module.exports = class MatchService extends Schmervice.Service {
- constructor(...args) {
- super(...args)
- }
- async calcMatches(allQueuesByType) {
- const seekers = Object.keys(allQueuesByType['seeker']).map(id => ({
- profile_id: parseInt(id),
- queue: allQueuesByType['seeker'][id],
- }))
- const posters = Object.keys(allQueuesByType['poster']).map(id => ({
- profile_id: parseInt(id),
- queue: allQueuesByType['poster'][id],
- }))
-
- const diff = Math.abs(posters.length - seekers.length)
- const smallerList = posters.length < seekers.length ? posters : seekers
- // ADD DUMMY IDS TO THE SMALLER LIST
- for (let d = 0; d < diff; d++) {
- smallerList.push({ profile_id: `${d}-dummy`, queue: [] })
- }
- let allPeople = [...seekers, ...posters]
- const queuesById = allPeople.reduce((queuesById, profile) => {
- queuesById[profile.profile_id] = profile.queue
- return queuesById
- }, {})
- let allIds = allPeople.map(profile => profile.profile_id)
- seekers.forEach(profile => {
- profile.queue.forEach(id => allIds.push(id))
- })
- posters.forEach(profile => {
- profile.queue.forEach(id => allIds.push(id))
- })
- allIds = [...new Set(allIds)]
- const peopleById = allIds.reduce((peopleById, id) => {
- peopleById[id] = new Person(id)
- if (queuesById[id]) {
- peopleById[id].candidates = queuesById[id].map(
- queueId => new Person(queueId),
- )
- }
- return peopleById
- }, {})
- const seekerPeople = seekers.map(
- profile => peopleById[profile.profile_id],
- )
- const posterPeople = posters.map(
- profile => peopleById[profile.profile_id],
- )
- // You only need to engage from one side
- engageEveryone(seekerPeople)
- engageEveryone(posterPeople)
- // TODO: Test this, probably bug
-
- Object.values(peopleById).forEach(person => {
- if (person.fiance) {
- person.fiance.fiance = null
- }
- })
- return Object.values(peopleById).map(person => ({
- id: person.name,
- otp: person?.fiance?.name ?? null,
- }))
- }
- }
|