Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

match.js 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. const Schmervice = require('@hapipal/schmervice')
  2. function engageEveryone(guys) {
  3. let done
  4. do {
  5. done = true
  6. for (let i = 0; i < guys.length; i++) {
  7. const guy = guys[i]
  8. if (!guy.fiance) {
  9. done = false
  10. const gal = guy.nextCandidate()
  11. if (!gal.fiance || gal.prefers(guy)) {
  12. guy.engageTo(gal)
  13. }
  14. }
  15. }
  16. } while (!done)
  17. }
  18. class Person {
  19. constructor(name) {
  20. let candidateIndex = 0
  21. this.name = name
  22. this.fiance = null
  23. this.candidates = []
  24. this.rank = p => {
  25. for (let i = 0; i < this.candidates.length; i++) {
  26. if (this.candidates[i] === p) return i
  27. }
  28. return this.candidates.length + 1
  29. }
  30. this.prefers = p => {
  31. return this.rank(p) < this.rank(this.fiance)
  32. }
  33. this.nextCandidate = () => {
  34. if (candidateIndex >= this.candidates.length) {
  35. return null
  36. }
  37. return this.candidates[candidateIndex++]
  38. }
  39. this.engageTo = p => {
  40. if (p.fiance) {
  41. p.fiance.fiance = null
  42. }
  43. p.fiance = this
  44. if (this.fiance) {
  45. this.fiance.fiance = null
  46. }
  47. this.fiance = p
  48. }
  49. this.swapWith = p => {
  50. const thisFiance = this.fiance
  51. const pFiance = p.fiance
  52. this.engageTo(pFiance)
  53. p.engageTo(thisFiance)
  54. }
  55. }
  56. }
  57. module.exports = class MatchService extends Schmervice.Service {
  58. constructor(...args) {
  59. super(...args)
  60. }
  61. async calcMatches(allQueuesByType) {
  62. const seekers = Object.keys(allQueuesByType['seeker']).map(id => ({
  63. profile_id: parseInt(id),
  64. queue: allQueuesByType['seeker'][id],
  65. }))
  66. const posters = Object.keys(allQueuesByType['poster']).map(id => ({
  67. profile_id: parseInt(id),
  68. queue: allQueuesByType['poster'][id],
  69. }))
  70. const diff = Math.abs(posters.length - seekers.length)
  71. const smallerList = posters.length < seekers.length ? posters : seekers
  72. // ADD DUMMY IDS TO THE SMALLER LIST
  73. for (let d = 0; d < diff; d++) {
  74. smallerList.push({ profile_id: `${d}-dummy`, queue: [] })
  75. }
  76. let allPeople = [...seekers, ...posters]
  77. const queuesById = allPeople.reduce((queuesById, profile) => {
  78. queuesById[profile.profile_id] = profile.queue
  79. return queuesById
  80. }, {})
  81. let allIds = allPeople.map(profile => profile.profile_id)
  82. seekers.forEach(profile => {
  83. profile.queue.forEach(id => allIds.push(id))
  84. })
  85. posters.forEach(profile => {
  86. profile.queue.forEach(id => allIds.push(id))
  87. })
  88. allIds = [...new Set(allIds)]
  89. const peopleById = allIds.reduce((peopleById, id) => {
  90. peopleById[id] = new Person(id)
  91. if (queuesById[id]) {
  92. peopleById[id].candidates = queuesById[id].map(
  93. queueId => new Person(queueId),
  94. )
  95. }
  96. return peopleById
  97. }, {})
  98. const seekerPeople = seekers.map(
  99. profile => peopleById[profile.profile_id],
  100. )
  101. const posterPeople = posters.map(
  102. profile => peopleById[profile.profile_id],
  103. )
  104. // You only need to engage from one side
  105. engageEveryone(seekerPeople)
  106. engageEveryone(posterPeople)
  107. // TODO: Test this, probably bug
  108. Object.values(peopleById).forEach(person => {
  109. if (person.fiance) {
  110. person.fiance.fiance = null
  111. }
  112. })
  113. return Object.values(peopleById).map(person => ({
  114. id: person.name,
  115. otp: person?.fiance?.name ?? null,
  116. }))
  117. }
  118. }