ci paice
This commit is contained in:
103
matching.js
Normal file
103
matching.js
Normal file
@@ -0,0 +1,103 @@
|
||||
// Algoritmo di assegnazione persone -> stanze.
|
||||
// Vincolo: ogni stanza è mono-genere (M con M, F con F).
|
||||
// Strategia: 1) partiziona le stanze tra i due generi in modo che ciascun
|
||||
// genere ci stia (capienza sufficiente); 2) distribuisce casualmente le
|
||||
// persone nelle stanze del proprio genere, cercando di non lasciare stanze
|
||||
// completamente vuote.
|
||||
|
||||
(function (global) {
|
||||
function shuffle(arr, rng) {
|
||||
const a = arr.slice();
|
||||
for (let i = a.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(rng() * (i + 1));
|
||||
[a[i], a[j]] = [a[j], a[i]];
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
// Sceglie quali stanze vanno alle femmine e quali ai maschi.
|
||||
// Preferisce partizioni in cui la capienza femminile combacia esattamente
|
||||
// col numero di femmine (zero letti sprecati da quel lato => niente stanze
|
||||
// vuote lato femmine). Fallback: qualsiasi partizione valida.
|
||||
function chooseGenderPartition(rooms, nF, nM, rng) {
|
||||
const n = rooms.length;
|
||||
const total = rooms.reduce((s, r) => s + r.posti, 0);
|
||||
const valid = [];
|
||||
const exact = [];
|
||||
// esclude mask 0 e mask "tutte" così ogni genere ha almeno una stanza
|
||||
for (let mask = 1; mask < (1 << n) - 1; mask++) {
|
||||
let capF = 0;
|
||||
for (let i = 0; i < n; i++) if (mask & (1 << i)) capF += rooms[i].posti;
|
||||
const capM = total - capF;
|
||||
if (capF >= nF && capM >= nM) {
|
||||
valid.push(mask);
|
||||
if (capF === nF) exact.push(mask);
|
||||
}
|
||||
}
|
||||
const pool = exact.length ? exact : valid;
|
||||
if (!pool.length) {
|
||||
throw new Error(
|
||||
"Nessuna partizione valida: capienza insufficiente per il vincolo di genere."
|
||||
);
|
||||
}
|
||||
return pool[Math.floor(rng() * pool.length)];
|
||||
}
|
||||
|
||||
// Distribuisce le persone nelle stanze del proprio genere.
|
||||
// Prima assegna 1 persona a stanza (copertura => niente stanze vuote se
|
||||
// le persone sono >= delle stanze), poi riempie i letti restanti a caso.
|
||||
function fillRooms(roomsG, peopleG, rng) {
|
||||
const rooms = shuffle(roomsG, rng);
|
||||
const people = shuffle(peopleG, rng);
|
||||
const assign = {};
|
||||
rooms.forEach((r) => (assign[r.id] = []));
|
||||
|
||||
let idx = 0;
|
||||
if (people.length >= rooms.length) {
|
||||
for (const r of rooms) assign[r.id].push(people[idx++]);
|
||||
}
|
||||
|
||||
const slots = [];
|
||||
for (const r of rooms) {
|
||||
const free = r.posti - assign[r.id].length;
|
||||
for (let k = 0; k < free; k++) slots.push(r.id);
|
||||
}
|
||||
const freeSlots = shuffle(slots, rng);
|
||||
while (idx < people.length) {
|
||||
const roomId = freeSlots.shift();
|
||||
assign[roomId].push(people[idx++]);
|
||||
}
|
||||
return assign;
|
||||
}
|
||||
|
||||
function assign(rooms, participants, rng) {
|
||||
rng = rng || Math.random;
|
||||
const females = participants.filter((p) => p.genere === "F");
|
||||
const males = participants.filter((p) => p.genere === "M");
|
||||
|
||||
const mask = chooseGenderPartition(rooms, females.length, males.length, rng);
|
||||
const fRooms = rooms.filter((r, i) => mask & (1 << i));
|
||||
const mRooms = rooms.filter((r, i) => !(mask & (1 << i)));
|
||||
|
||||
const fAssign = fillRooms(fRooms, females.map((p) => p.nome), rng);
|
||||
const mAssign = fillRooms(mRooms, males.map((p) => p.nome), rng);
|
||||
|
||||
const byPerson = {};
|
||||
const roomGender = {};
|
||||
fRooms.forEach((r) => (roomGender[r.id] = "F"));
|
||||
mRooms.forEach((r) => (roomGender[r.id] = "M"));
|
||||
for (const rid in fAssign) fAssign[rid].forEach((nome) => (byPerson[nome] = rid));
|
||||
for (const rid in mAssign) mAssign[rid].forEach((nome) => (byPerson[nome] = rid));
|
||||
|
||||
return {
|
||||
byPerson, // nome -> roomId
|
||||
roomGender, // roomId -> "F" | "M"
|
||||
fRooms,
|
||||
mRooms,
|
||||
};
|
||||
}
|
||||
|
||||
const Matching = { assign, shuffle };
|
||||
if (typeof module !== "undefined" && module.exports) module.exports = Matching;
|
||||
global.Matching = Matching;
|
||||
})(typeof window !== "undefined" ? window : globalThis);
|
||||
Reference in New Issue
Block a user