[ADD] engine: configuration normalised into an indexed instance
The engine works on dense arrays, not on the operator's objects.
normaliser checks the configuration, derives anchored, partially fixed and
mobile statuses from the reservations themselves, and suspends an excluded
person's reservations without stopping on them. It never refuses a room
that is too small: that is a property of the configuration, which the
diagnosis names and the search refuses (§ 5.9). A plan converts both ways
between ids and indices, seats in ascending id.
Checked: a reservation after an excluded one, and a conflict found under
« tous », each fail their mutant; an independent oracle agreed throughout.
--- FR ---
[ADD] moteur : configuration normalisée en une instance indexée
Le moteur travaille sur des tableaux denses, pas sur les objets de
l'opérateur. normaliser vérifie la configuration, dérive les statuts
ancré, partiellement fixé et mobile des réservations elles-mêmes, et
suspend les réservations d'un exclu sans s'y arrêter. Il ne refuse jamais
une salle trop petite : c'est une propriété de la configuration, que le
diagnostic nomme et que la recherche refuse (§ 5.9). Un plan passe dans
les deux sens des ids aux index, sièges par id croissant.
Vérifié : une réservation après celle d'un exclu, et un conflit découvert
sous « tous », font chacune tomber leur mutant ; un oracle indépendant
concorde partout.
Assisted-by: Claude Opus 5.5
2026-10-05 17:27:06 -04:00
|
|
|
|
// © 2026 TechnoLibre (http://www.technolibre.ca)
|
|
|
|
|
|
// License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
|
|
|
|
|
|
|
|
|
|
|
// Passage de la configuration, forme par identifiants, à l'instance indexée
|
|
|
|
|
|
// que consomme le moteur (§ 4, § 5.2), et conversion d'un plan entre ses deux
|
|
|
|
|
|
// formes (§ 8.9). Les formes sont décrites dans types.js.
|
|
|
|
|
|
//
|
[IMP] engine: single owners, regeneration, property grid
The search recomputed the collision excess and the gaps that the measure
already gives — two arithmetics for one quantity. It now reads them from
the measure, and the redundancy total has one owner. Contract values, the
indexed-plan guard and the population split are defined once. regenerer
rebuilds a proposition from its derived seed, stop count and history
length, which the spec now lists (§ 8.9). A property grid runs seeded
random rooms through the whole chain.
Checked: 435 node and 20 long tests; redefining the excess or the gaps in
the measure now fails the search tests too.
--- FR ---
[IMP] moteur : propriétaires uniques, régénération, grille de propriétés
La recherche recalculait l'excédent de collisions et les écarts que la
mesure donne déjà — deux arithmétiques pour une grandeur. Elle les lit
désormais dans la mesure, et le total de redondance a un seul
propriétaire. Valeurs du contrat, garde du plan indexé et partition des
populations sont définies une fois. regenerer reconstruit une proposition
depuis sa graine dérivée, son arrêt et la longueur de son historique,
que le spec énumère désormais (§ 8.9). Une grille de propriétés fait
traverser toute la chaîne à des salles tirées d'une graine.
Vérifié : 435 épreuves node et 20 longues ; redéfinir l'excédent ou les
écarts dans la mesure fait désormais tomber aussi la recherche.
Assisted-by: Claude Opus 5.5
2026-10-06 04:23:02 -04:00
|
|
|
|
// Ce module définit aussi, une seule fois pour tout le moteur (§ 13.2), ce
|
|
|
|
|
|
// que les autres modules lisent de ces formes : les valeurs du contrat —
|
|
|
|
|
|
// STATUT, LIBRE, RESERVE, SANS_GROUPE —, la garde de forme d'un plan indexé,
|
|
|
|
|
|
// le nombre de places d'un tour, et la répartition des personnes entre les
|
|
|
|
|
|
// trois populations du § 5.4. Les autres modules et leurs épreuves les
|
|
|
|
|
|
// importent, sans en redéfinir aucun.
|
|
|
|
|
|
//
|
[ADD] engine: configuration normalised into an indexed instance
The engine works on dense arrays, not on the operator's objects.
normaliser checks the configuration, derives anchored, partially fixed and
mobile statuses from the reservations themselves, and suspends an excluded
person's reservations without stopping on them. It never refuses a room
that is too small: that is a property of the configuration, which the
diagnosis names and the search refuses (§ 5.9). A plan converts both ways
between ids and indices, seats in ascending id.
Checked: a reservation after an excluded one, and a conflict found under
« tous », each fail their mutant; an independent oracle agreed throughout.
--- FR ---
[ADD] moteur : configuration normalisée en une instance indexée
Le moteur travaille sur des tableaux denses, pas sur les objets de
l'opérateur. normaliser vérifie la configuration, dérive les statuts
ancré, partiellement fixé et mobile des réservations elles-mêmes, et
suspend les réservations d'un exclu sans s'y arrêter. Il ne refuse jamais
une salle trop petite : c'est une propriété de la configuration, que le
diagnostic nomme et que la recherche refuse (§ 5.9). Un plan passe dans
les deux sens des ids aux index, sièges par id croissant.
Vérifié : une réservation après celle d'un exclu, et un conflit découvert
sous « tous », font chacune tomber leur mutant ; un oracle indépendant
concorde partout.
Assisted-by: Claude Opus 5.5
2026-10-05 17:27:06 -04:00
|
|
|
|
// Trois familles de refus :
|
|
|
|
|
|
// - ErreurConfiguration, avec un code, pour ce qu'une saisie, un import ou un
|
|
|
|
|
|
// plan périmé peut porter : une donnée incohérente avec le reste de la
|
|
|
|
|
|
// configuration, ou une capacité, un nombre de tours, un tour désigné hors
|
|
|
|
|
|
// de son domaine ;
|
|
|
|
|
|
// - TypeError, quand la configuration sort de l'une des formes que garantit
|
|
|
|
|
|
// le code qui la bâtit — stockage, import, interface — et qu'aucune saisie
|
|
|
|
|
|
// ne produit : un identifiant de participant ou de table qui n'est pas un
|
|
|
|
|
|
// entier ≥ 1, une appartenance ni chaîne ni null, un exclu présent et non
|
|
|
|
|
|
// booléen, une portée ni « tous » ni « tour », des contraintes qui ne sont
|
|
|
|
|
|
// pas un objet de quatre booléens, une liste qui n'est pas un tableau. Ces
|
|
|
|
|
|
// formes sont les seules que normaliser contrôle par TypeError ; une valeur
|
|
|
|
|
|
// qui en sort est une faute de l'appelant, qu'aucune valeur par défaut ne
|
|
|
|
|
|
// masque ;
|
|
|
|
|
|
// - RangeError, pour un plan indexé qui n'a pas la forme de l'instance : seul
|
|
|
|
|
|
// le moteur produit cette forme, et l'écart y est une faute de code.
|
|
|
|
|
|
//
|
|
|
|
|
|
// Les champs que normaliser ne lit pas — nom, prénom, numéro de table — ne
|
|
|
|
|
|
// sont pas examinés. Aucune fonction ne modifie ce qu'elle reçoit.
|
|
|
|
|
|
import { ErreurConfiguration } from './erreurs.js';
|
|
|
|
|
|
|
[IMP] engine: single owners, regeneration, property grid
The search recomputed the collision excess and the gaps that the measure
already gives — two arithmetics for one quantity. It now reads them from
the measure, and the redundancy total has one owner. Contract values, the
indexed-plan guard and the population split are defined once. regenerer
rebuilds a proposition from its derived seed, stop count and history
length, which the spec now lists (§ 8.9). A property grid runs seeded
random rooms through the whole chain.
Checked: 435 node and 20 long tests; redefining the excess or the gaps in
the measure now fails the search tests too.
--- FR ---
[IMP] moteur : propriétaires uniques, régénération, grille de propriétés
La recherche recalculait l'excédent de collisions et les écarts que la
mesure donne déjà — deux arithmétiques pour une grandeur. Elle les lit
désormais dans la mesure, et le total de redondance a un seul
propriétaire. Valeurs du contrat, garde du plan indexé et partition des
populations sont définies une fois. regenerer reconstruit une proposition
depuis sa graine dérivée, son arrêt et la longueur de son historique,
que le spec énumère désormais (§ 8.9). Une grille de propriétés fait
traverser toute la chaîne à des salles tirées d'une graine.
Vérifié : 435 épreuves node et 20 longues ; redéfinir l'excédent ou les
écarts dans la mesure fait désormais tomber aussi la recherche.
Assisted-by: Claude Opus 5.5
2026-10-06 04:23:02 -04:00
|
|
|
|
/**
|
|
|
|
|
|
* Statuts d'un participant (§ 4.2), valeurs de instance.statut. normaliser
|
|
|
|
|
|
* les dérive des réservations ; aucun n'est déclaré. Un partiellement fixé
|
|
|
|
|
|
* compte parmi les mobiles dans les populations du § 5.4.
|
|
|
|
|
|
*/
|
|
|
|
|
|
export const STATUT = Object.freeze({ MOBILE: 0, PARTIELLEMENT_FIXE: 1, ANCRE: 2 });
|
|
|
|
|
|
|
|
|
|
|
|
/** Case de instance.fixe sans table imposée. */
|
|
|
|
|
|
export const LIBRE = -1;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Case d'un plan indexé : la réserve. Elle vaut LIBRE, et une rangée de
|
|
|
|
|
|
* instance.fixe se lit ainsi comme le plan qui assied chacun à ses seuls
|
|
|
|
|
|
* tours fixés et le laisse en réserve aux autres : le diagnostic mesure ce
|
|
|
|
|
|
* plan, le plafond a priori part de cet itinéraire.
|
|
|
|
|
|
*/
|
|
|
|
|
|
export const RESERVE = -1;
|
|
|
|
|
|
|
|
|
|
|
|
/** instance.groupe d'un participant sans appartenance. */
|
|
|
|
|
|
export const SANS_GROUPE = -1;
|
[ADD] engine: configuration normalised into an indexed instance
The engine works on dense arrays, not on the operator's objects.
normaliser checks the configuration, derives anchored, partially fixed and
mobile statuses from the reservations themselves, and suspends an excluded
person's reservations without stopping on them. It never refuses a room
that is too small: that is a property of the configuration, which the
diagnosis names and the search refuses (§ 5.9). A plan converts both ways
between ids and indices, seats in ascending id.
Checked: a reservation after an excluded one, and a conflict found under
« tous », each fail their mutant; an independent oracle agreed throughout.
--- FR ---
[ADD] moteur : configuration normalisée en une instance indexée
Le moteur travaille sur des tableaux denses, pas sur les objets de
l'opérateur. normaliser vérifie la configuration, dérive les statuts
ancré, partiellement fixé et mobile des réservations elles-mêmes, et
suspend les réservations d'un exclu sans s'y arrêter. Il ne refuse jamais
une salle trop petite : c'est une propriété de la configuration, que le
diagnostic nomme et que la recherche refuse (§ 5.9). Un plan passe dans
les deux sens des ids aux index, sièges par id croissant.
Vérifié : une réservation après celle d'un exclu, et un conflit découvert
sous « tous », font chacune tomber leur mutant ; un oracle indépendant
concorde partout.
Assisted-by: Claude Opus 5.5
2026-10-05 17:27:06 -04:00
|
|
|
|
|
|
|
|
|
|
// Case d'un plan indexé qu'indexerPlan n'a pas encore remplie ; jamais rendue.
|
|
|
|
|
|
const NON_PLACE = -2;
|
|
|
|
|
|
|
|
|
|
|
|
// Plus grand entier que représente un Int32Array : une capacité au-delà s'y
|
|
|
|
|
|
// tronquerait sans bruit.
|
|
|
|
|
|
const ENTIER_32_MAX = 2 ** 31 - 1;
|
|
|
|
|
|
|
|
|
|
|
|
const NOMS_CONTRAINTES = [
|
|
|
|
|
|
'separerAppartenances',
|
|
|
|
|
|
'nouveauxVoisins',
|
|
|
|
|
|
'nouvelleTable',
|
|
|
|
|
|
'varierAppartenances',
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
// Valeur citée dans un message : une chaîne s'écrit entre guillemets, pour
|
|
|
|
|
|
// ne pas se lire comme le nombre qu'elle contient.
|
|
|
|
|
|
const decrire = (valeur) => (typeof valeur === 'string' ? JSON.stringify(valeur) : String(valeur));
|
|
|
|
|
|
|
|
|
|
|
|
function exigerListe(valeur, nom) {
|
|
|
|
|
|
if (!Array.isArray(valeur)) throw new TypeError(`configuration.${nom} : liste attendue`);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function exigerIdentifiant(id, quoi) {
|
|
|
|
|
|
if (!Number.isInteger(id) || id < 1) {
|
|
|
|
|
|
throw new TypeError(`${quoi} d'identifiant ${decrire(id)} : entier ≥ 1 attendu`);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function exigerAppartenance({ id, appartenance }) {
|
|
|
|
|
|
if (appartenance !== null && typeof appartenance !== 'string') {
|
|
|
|
|
|
throw new TypeError(
|
|
|
|
|
|
`participant ${id} : appartenance chaîne ou null attendue, reçu ${decrire(appartenance)}`,
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Vrai pour un participant exclu ; un champ exclu absent vaut false.
|
|
|
|
|
|
function estExclu({ id, exclu }) {
|
|
|
|
|
|
if (exclu === undefined) return false;
|
|
|
|
|
|
if (typeof exclu !== 'boolean') {
|
|
|
|
|
|
throw new TypeError(`participant ${id} : exclu booléen attendu, reçu ${decrire(exclu)}`);
|
|
|
|
|
|
}
|
|
|
|
|
|
return exclu;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Copie des quatre contraintes : une modification ultérieure de la
|
|
|
|
|
|
// configuration n'atteint pas l'instance.
|
|
|
|
|
|
function copierContraintes(contraintes) {
|
|
|
|
|
|
if (typeof contraintes !== 'object' || contraintes === null) {
|
|
|
|
|
|
throw new TypeError('configuration.contraintes : objet attendu');
|
|
|
|
|
|
}
|
|
|
|
|
|
const copie = {};
|
|
|
|
|
|
for (const nom of NOMS_CONTRAINTES) {
|
|
|
|
|
|
if (typeof contraintes[nom] !== 'boolean') {
|
|
|
|
|
|
throw new TypeError(`contrainte ${nom} : booléen attendu, reçu ${decrire(contraintes[nom])}`);
|
|
|
|
|
|
}
|
|
|
|
|
|
copie[nom] = contraintes[nom];
|
|
|
|
|
|
}
|
|
|
|
|
|
return copie;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Groupe de chaque participant présent, présents triés par identifiant
|
[IMP] engine: single owners, regeneration, property grid
The search recomputed the collision excess and the gaps that the measure
already gives — two arithmetics for one quantity. It now reads them from
the measure, and the redundancy total has one owner. Contract values, the
indexed-plan guard and the population split are defined once. regenerer
rebuilds a proposition from its derived seed, stop count and history
length, which the spec now lists (§ 8.9). A property grid runs seeded
random rooms through the whole chain.
Checked: 435 node and 20 long tests; redefining the excess or the gaps in
the measure now fails the search tests too.
--- FR ---
[IMP] moteur : propriétaires uniques, régénération, grille de propriétés
La recherche recalculait l'excédent de collisions et les écarts que la
mesure donne déjà — deux arithmétiques pour une grandeur. Elle les lit
désormais dans la mesure, et le total de redondance a un seul
propriétaire. Valeurs du contrat, garde du plan indexé et partition des
populations sont définies une fois. regenerer reconstruit une proposition
depuis sa graine dérivée, son arrêt et la longueur de son historique,
que le spec énumère désormais (§ 8.9). Une grille de propriétés fait
traverser toute la chaîne à des salles tirées d'une graine.
Vérifié : 435 épreuves node et 20 longues ; redéfinir l'excédent ou les
écarts dans la mesure fait désormais tomber aussi la recherche.
Assisted-by: Claude Opus 5.5
2026-10-06 04:23:02 -04:00
|
|
|
|
// croissant : un libellé reçoit le numéro de sa première apparition,
|
|
|
|
|
|
// SANS_GROUPE marque l'absence d'appartenance. L'égalité de chaînes fait le
|
|
|
|
|
|
// groupe. La Map ne sert qu'à retrouver un libellé déjà numéroté.
|
[ADD] engine: configuration normalised into an indexed instance
The engine works on dense arrays, not on the operator's objects.
normaliser checks the configuration, derives anchored, partially fixed and
mobile statuses from the reservations themselves, and suspends an excluded
person's reservations without stopping on them. It never refuses a room
that is too small: that is a property of the configuration, which the
diagnosis names and the search refuses (§ 5.9). A plan converts both ways
between ids and indices, seats in ascending id.
Checked: a reservation after an excluded one, and a conflict found under
« tous », each fail their mutant; an independent oracle agreed throughout.
--- FR ---
[ADD] moteur : configuration normalisée en une instance indexée
Le moteur travaille sur des tableaux denses, pas sur les objets de
l'opérateur. normaliser vérifie la configuration, dérive les statuts
ancré, partiellement fixé et mobile des réservations elles-mêmes, et
suspend les réservations d'un exclu sans s'y arrêter. Il ne refuse jamais
une salle trop petite : c'est une propriété de la configuration, que le
diagnostic nomme et que la recherche refuse (§ 5.9). Un plan passe dans
les deux sens des ids aux index, sièges par id croissant.
Vérifié : une réservation après celle d'un exclu, et un conflit découvert
sous « tous », font chacune tomber leur mutant ; un oracle indépendant
concorde partout.
Assisted-by: Claude Opus 5.5
2026-10-05 17:27:06 -04:00
|
|
|
|
function numeroterGroupes(presents) {
|
|
|
|
|
|
const groupe = new Int32Array(presents.length);
|
|
|
|
|
|
const groupes = [];
|
|
|
|
|
|
const numeroDe = new Map();
|
|
|
|
|
|
for (let p = 0; p < presents.length; p += 1) {
|
|
|
|
|
|
const { appartenance } = presents[p];
|
|
|
|
|
|
if (appartenance === null) {
|
[IMP] engine: single owners, regeneration, property grid
The search recomputed the collision excess and the gaps that the measure
already gives — two arithmetics for one quantity. It now reads them from
the measure, and the redundancy total has one owner. Contract values, the
indexed-plan guard and the population split are defined once. regenerer
rebuilds a proposition from its derived seed, stop count and history
length, which the spec now lists (§ 8.9). A property grid runs seeded
random rooms through the whole chain.
Checked: 435 node and 20 long tests; redefining the excess or the gaps in
the measure now fails the search tests too.
--- FR ---
[IMP] moteur : propriétaires uniques, régénération, grille de propriétés
La recherche recalculait l'excédent de collisions et les écarts que la
mesure donne déjà — deux arithmétiques pour une grandeur. Elle les lit
désormais dans la mesure, et le total de redondance a un seul
propriétaire. Valeurs du contrat, garde du plan indexé et partition des
populations sont définies une fois. regenerer reconstruit une proposition
depuis sa graine dérivée, son arrêt et la longueur de son historique,
que le spec énumère désormais (§ 8.9). Une grille de propriétés fait
traverser toute la chaîne à des salles tirées d'une graine.
Vérifié : 435 épreuves node et 20 longues ; redéfinir l'excédent ou les
écarts dans la mesure fait désormais tomber aussi la recherche.
Assisted-by: Claude Opus 5.5
2026-10-06 04:23:02 -04:00
|
|
|
|
groupe[p] = SANS_GROUPE;
|
[ADD] engine: configuration normalised into an indexed instance
The engine works on dense arrays, not on the operator's objects.
normaliser checks the configuration, derives anchored, partially fixed and
mobile statuses from the reservations themselves, and suspends an excluded
person's reservations without stopping on them. It never refuses a room
that is too small: that is a property of the configuration, which the
diagnosis names and the search refuses (§ 5.9). A plan converts both ways
between ids and indices, seats in ascending id.
Checked: a reservation after an excluded one, and a conflict found under
« tous », each fail their mutant; an independent oracle agreed throughout.
--- FR ---
[ADD] moteur : configuration normalisée en une instance indexée
Le moteur travaille sur des tableaux denses, pas sur les objets de
l'opérateur. normaliser vérifie la configuration, dérive les statuts
ancré, partiellement fixé et mobile des réservations elles-mêmes, et
suspend les réservations d'un exclu sans s'y arrêter. Il ne refuse jamais
une salle trop petite : c'est une propriété de la configuration, que le
diagnostic nomme et que la recherche refuse (§ 5.9). Un plan passe dans
les deux sens des ids aux index, sièges par id croissant.
Vérifié : une réservation après celle d'un exclu, et un conflit découvert
sous « tous », font chacune tomber leur mutant ; un oracle indépendant
concorde partout.
Assisted-by: Claude Opus 5.5
2026-10-05 17:27:06 -04:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!numeroDe.has(appartenance)) {
|
|
|
|
|
|
numeroDe.set(appartenance, groupes.length);
|
|
|
|
|
|
groupes.push(appartenance);
|
|
|
|
|
|
}
|
|
|
|
|
|
groupe[p] = numeroDe.get(appartenance);
|
|
|
|
|
|
}
|
|
|
|
|
|
return { groupe, groupes };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Tables imposées par les réservations : fixe[p * R + r] = index de table,
|
|
|
|
|
|
// LIBRE sinon. Chaque réservation est vérifiée dans sa forme — participant et
|
|
|
|
|
|
// table connus, tour dans 1..R —, exclus compris ; celle d'un exclu s'arrête
|
|
|
|
|
|
// là, suspendue, sans effet (§ 4.4). Une réservation qui répète la table déjà
|
|
|
|
|
|
// imposée au même tour ne change rien ; une autre table au même tour lève
|
|
|
|
|
|
// RESERVATION_CONFLIT.
|
|
|
|
|
|
function fixerReservations(reservations, contexte) {
|
|
|
|
|
|
const { connus, indexDe, indexTableDe, idsTables, N, R } = contexte;
|
|
|
|
|
|
const fixe = new Int32Array(N * R).fill(LIBRE);
|
|
|
|
|
|
for (let i = 0; i < reservations.length; i += 1) {
|
|
|
|
|
|
const { participant: id, table: idTable, portee, tour } = reservations[i];
|
|
|
|
|
|
if (!connus.has(id)) {
|
|
|
|
|
|
throw new ErreurConfiguration('RESERVATION_INCONNUE', { reservation: i, participant: id });
|
|
|
|
|
|
}
|
|
|
|
|
|
const t = indexTableDe.get(idTable);
|
|
|
|
|
|
if (t === undefined) {
|
|
|
|
|
|
throw new ErreurConfiguration('RESERVATION_INCONNUE', { reservation: i, table: idTable });
|
|
|
|
|
|
}
|
|
|
|
|
|
// Tours couverts, numérotés à partir de 0 : chacun des R tours pour la
|
|
|
|
|
|
// portée « tous », le tour désigné pour la portée « tour ».
|
|
|
|
|
|
let premier;
|
|
|
|
|
|
let dernier;
|
|
|
|
|
|
if (portee === 'tous') {
|
|
|
|
|
|
premier = 0;
|
|
|
|
|
|
dernier = R - 1;
|
|
|
|
|
|
} else if (portee === 'tour') {
|
|
|
|
|
|
if (!Number.isInteger(tour) || tour < 1 || tour > R) {
|
|
|
|
|
|
throw new ErreurConfiguration('RESERVATION_TOUR', { reservation: i, tour });
|
|
|
|
|
|
}
|
|
|
|
|
|
premier = tour - 1;
|
|
|
|
|
|
dernier = tour - 1;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
throw new TypeError(
|
|
|
|
|
|
`réservation ${i} : portée ${decrire(portee)}, « tous » ou « tour » attendue`,
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
const p = indexDe.get(id);
|
|
|
|
|
|
if (p === undefined) continue;
|
|
|
|
|
|
for (let r = premier; r <= dernier; r += 1) {
|
|
|
|
|
|
const imposee = fixe[p * R + r];
|
|
|
|
|
|
if (imposee === LIBRE) {
|
|
|
|
|
|
fixe[p * R + r] = t;
|
|
|
|
|
|
} else if (imposee !== t) {
|
|
|
|
|
|
throw new ErreurConfiguration('RESERVATION_CONFLIT', {
|
|
|
|
|
|
participant: id,
|
|
|
|
|
|
tour: r + 1,
|
|
|
|
|
|
tables: [idsTables[imposee], idTable],
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return fixe;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Lève SURRESERVATION quand, à un tour, une table reçoit plus de personnes
|
|
|
|
|
|
// fixées que de sièges (§ 5.9). Le compte porte sur les personnes, lues dans
|
|
|
|
|
|
// fixe : une réservation répétée ne compte qu'une fois. Les tables se
|
|
|
|
|
|
// parcourent par index, chacune par tours croissants.
|
|
|
|
|
|
function verifierSurreservation(fixe, { N, T, R, capacite, idsTables }) {
|
|
|
|
|
|
const fixees = new Int32Array(T * R);
|
|
|
|
|
|
for (let p = 0; p < N; p += 1) {
|
|
|
|
|
|
for (let r = 0; r < R; r += 1) {
|
|
|
|
|
|
const t = fixe[p * R + r];
|
|
|
|
|
|
if (t !== LIBRE) fixees[t * R + r] += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
for (let t = 0; t < T; t += 1) {
|
|
|
|
|
|
for (let r = 0; r < R; r += 1) {
|
|
|
|
|
|
if (fixees[t * R + r] > capacite[t]) {
|
|
|
|
|
|
throw new ErreurConfiguration('SURRESERVATION', {
|
|
|
|
|
|
table: idsTables[t],
|
|
|
|
|
|
tour: r + 1,
|
|
|
|
|
|
reservees: fixees[t * R + r],
|
|
|
|
|
|
capacite: capacite[t],
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Statut de chaque participant, dérivé de fixe et non de la forme des
|
|
|
|
|
|
// réservations (§ 4.2) : ancré quand la même table est imposée à chacun des R
|
|
|
|
|
|
// tours, mobile quand aucune ne l'est, partiellement fixé sinon. Un ancré
|
|
|
|
|
|
// compte dans k et dans ancresParTable ; un partiellement fixé compte parmi
|
|
|
|
|
|
// les mobiles.
|
|
|
|
|
|
function deriverStatuts(fixe, N, T, R) {
|
|
|
|
|
|
const statut = new Uint8Array(N);
|
|
|
|
|
|
const ancresParTable = new Int32Array(T);
|
|
|
|
|
|
let k = 0;
|
|
|
|
|
|
for (let p = 0; p < N; p += 1) {
|
|
|
|
|
|
const premiere = fixe[p * R];
|
|
|
|
|
|
let memeTable = true;
|
|
|
|
|
|
let aucune = true;
|
|
|
|
|
|
for (let r = 0; r < R; r += 1) {
|
|
|
|
|
|
const t = fixe[p * R + r];
|
|
|
|
|
|
if (t !== premiere) memeTable = false;
|
|
|
|
|
|
if (t !== LIBRE) aucune = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (aucune) {
|
[IMP] engine: single owners, regeneration, property grid
The search recomputed the collision excess and the gaps that the measure
already gives — two arithmetics for one quantity. It now reads them from
the measure, and the redundancy total has one owner. Contract values, the
indexed-plan guard and the population split are defined once. regenerer
rebuilds a proposition from its derived seed, stop count and history
length, which the spec now lists (§ 8.9). A property grid runs seeded
random rooms through the whole chain.
Checked: 435 node and 20 long tests; redefining the excess or the gaps in
the measure now fails the search tests too.
--- FR ---
[IMP] moteur : propriétaires uniques, régénération, grille de propriétés
La recherche recalculait l'excédent de collisions et les écarts que la
mesure donne déjà — deux arithmétiques pour une grandeur. Elle les lit
désormais dans la mesure, et le total de redondance a un seul
propriétaire. Valeurs du contrat, garde du plan indexé et partition des
populations sont définies une fois. regenerer reconstruit une proposition
depuis sa graine dérivée, son arrêt et la longueur de son historique,
que le spec énumère désormais (§ 8.9). Une grille de propriétés fait
traverser toute la chaîne à des salles tirées d'une graine.
Vérifié : 435 épreuves node et 20 longues ; redéfinir l'excédent ou les
écarts dans la mesure fait désormais tomber aussi la recherche.
Assisted-by: Claude Opus 5.5
2026-10-06 04:23:02 -04:00
|
|
|
|
statut[p] = STATUT.MOBILE;
|
[ADD] engine: configuration normalised into an indexed instance
The engine works on dense arrays, not on the operator's objects.
normaliser checks the configuration, derives anchored, partially fixed and
mobile statuses from the reservations themselves, and suspends an excluded
person's reservations without stopping on them. It never refuses a room
that is too small: that is a property of the configuration, which the
diagnosis names and the search refuses (§ 5.9). A plan converts both ways
between ids and indices, seats in ascending id.
Checked: a reservation after an excluded one, and a conflict found under
« tous », each fail their mutant; an independent oracle agreed throughout.
--- FR ---
[ADD] moteur : configuration normalisée en une instance indexée
Le moteur travaille sur des tableaux denses, pas sur les objets de
l'opérateur. normaliser vérifie la configuration, dérive les statuts
ancré, partiellement fixé et mobile des réservations elles-mêmes, et
suspend les réservations d'un exclu sans s'y arrêter. Il ne refuse jamais
une salle trop petite : c'est une propriété de la configuration, que le
diagnostic nomme et que la recherche refuse (§ 5.9). Un plan passe dans
les deux sens des ids aux index, sièges par id croissant.
Vérifié : une réservation après celle d'un exclu, et un conflit découvert
sous « tous », font chacune tomber leur mutant ; un oracle indépendant
concorde partout.
Assisted-by: Claude Opus 5.5
2026-10-05 17:27:06 -04:00
|
|
|
|
} else if (memeTable) {
|
[IMP] engine: single owners, regeneration, property grid
The search recomputed the collision excess and the gaps that the measure
already gives — two arithmetics for one quantity. It now reads them from
the measure, and the redundancy total has one owner. Contract values, the
indexed-plan guard and the population split are defined once. regenerer
rebuilds a proposition from its derived seed, stop count and history
length, which the spec now lists (§ 8.9). A property grid runs seeded
random rooms through the whole chain.
Checked: 435 node and 20 long tests; redefining the excess or the gaps in
the measure now fails the search tests too.
--- FR ---
[IMP] moteur : propriétaires uniques, régénération, grille de propriétés
La recherche recalculait l'excédent de collisions et les écarts que la
mesure donne déjà — deux arithmétiques pour une grandeur. Elle les lit
désormais dans la mesure, et le total de redondance a un seul
propriétaire. Valeurs du contrat, garde du plan indexé et partition des
populations sont définies une fois. regenerer reconstruit une proposition
depuis sa graine dérivée, son arrêt et la longueur de son historique,
que le spec énumère désormais (§ 8.9). Une grille de propriétés fait
traverser toute la chaîne à des salles tirées d'une graine.
Vérifié : 435 épreuves node et 20 longues ; redéfinir l'excédent ou les
écarts dans la mesure fait désormais tomber aussi la recherche.
Assisted-by: Claude Opus 5.5
2026-10-06 04:23:02 -04:00
|
|
|
|
statut[p] = STATUT.ANCRE;
|
[ADD] engine: configuration normalised into an indexed instance
The engine works on dense arrays, not on the operator's objects.
normaliser checks the configuration, derives anchored, partially fixed and
mobile statuses from the reservations themselves, and suspends an excluded
person's reservations without stopping on them. It never refuses a room
that is too small: that is a property of the configuration, which the
diagnosis names and the search refuses (§ 5.9). A plan converts both ways
between ids and indices, seats in ascending id.
Checked: a reservation after an excluded one, and a conflict found under
« tous », each fail their mutant; an independent oracle agreed throughout.
--- FR ---
[ADD] moteur : configuration normalisée en une instance indexée
Le moteur travaille sur des tableaux denses, pas sur les objets de
l'opérateur. normaliser vérifie la configuration, dérive les statuts
ancré, partiellement fixé et mobile des réservations elles-mêmes, et
suspend les réservations d'un exclu sans s'y arrêter. Il ne refuse jamais
une salle trop petite : c'est une propriété de la configuration, que le
diagnostic nomme et que la recherche refuse (§ 5.9). Un plan passe dans
les deux sens des ids aux index, sièges par id croissant.
Vérifié : une réservation après celle d'un exclu, et un conflit découvert
sous « tous », font chacune tomber leur mutant ; un oracle indépendant
concorde partout.
Assisted-by: Claude Opus 5.5
2026-10-05 17:27:06 -04:00
|
|
|
|
ancresParTable[premiere] += 1;
|
|
|
|
|
|
k += 1;
|
|
|
|
|
|
} else {
|
[IMP] engine: single owners, regeneration, property grid
The search recomputed the collision excess and the gaps that the measure
already gives — two arithmetics for one quantity. It now reads them from
the measure, and the redundancy total has one owner. Contract values, the
indexed-plan guard and the population split are defined once. regenerer
rebuilds a proposition from its derived seed, stop count and history
length, which the spec now lists (§ 8.9). A property grid runs seeded
random rooms through the whole chain.
Checked: 435 node and 20 long tests; redefining the excess or the gaps in
the measure now fails the search tests too.
--- FR ---
[IMP] moteur : propriétaires uniques, régénération, grille de propriétés
La recherche recalculait l'excédent de collisions et les écarts que la
mesure donne déjà — deux arithmétiques pour une grandeur. Elle les lit
désormais dans la mesure, et le total de redondance a un seul
propriétaire. Valeurs du contrat, garde du plan indexé et partition des
populations sont définies une fois. regenerer reconstruit une proposition
depuis sa graine dérivée, son arrêt et la longueur de son historique,
que le spec énumère désormais (§ 8.9). Une grille de propriétés fait
traverser toute la chaîne à des salles tirées d'une graine.
Vérifié : 435 épreuves node et 20 longues ; redéfinir l'excédent ou les
écarts dans la mesure fait désormais tomber aussi la recherche.
Assisted-by: Claude Opus 5.5
2026-10-06 04:23:02 -04:00
|
|
|
|
statut[p] = STATUT.PARTIELLEMENT_FIXE;
|
[ADD] engine: configuration normalised into an indexed instance
The engine works on dense arrays, not on the operator's objects.
normaliser checks the configuration, derives anchored, partially fixed and
mobile statuses from the reservations themselves, and suspends an excluded
person's reservations without stopping on them. It never refuses a room
that is too small: that is a property of the configuration, which the
diagnosis names and the search refuses (§ 5.9). A plan converts both ways
between ids and indices, seats in ascending id.
Checked: a reservation after an excluded one, and a conflict found under
« tous », each fail their mutant; an independent oracle agreed throughout.
--- FR ---
[ADD] moteur : configuration normalisée en une instance indexée
Le moteur travaille sur des tableaux denses, pas sur les objets de
l'opérateur. normaliser vérifie la configuration, dérive les statuts
ancré, partiellement fixé et mobile des réservations elles-mêmes, et
suspend les réservations d'un exclu sans s'y arrêter. Il ne refuse jamais
une salle trop petite : c'est une propriété de la configuration, que le
diagnostic nomme et que la recherche refuse (§ 5.9). Un plan passe dans
les deux sens des ids aux index, sièges par id croissant.
Vérifié : une réservation après celle d'un exclu, et un conflit découvert
sous « tous », font chacune tomber leur mutant ; un oracle indépendant
concorde partout.
Assisted-by: Claude Opus 5.5
2026-10-05 17:27:06 -04:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return { statut, ancresParTable, k };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Instance indexée d'une configuration (§ 4, § 5.2). Les participants exclus
|
|
|
|
|
|
* en sont absents (§ 4.4) : ni index ni groupe, et leurs réservations,
|
|
|
|
|
|
* suspendues, ne fixent rien et ne prennent aucun siège.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Lève ErreurConfiguration sur la première règle enfreinte — participants,
|
|
|
|
|
|
* puis tables, nombre de tours, réservations une à une, surréservation :
|
|
|
|
|
|
* PARTICIPANT_DOUBLON, TABLE_DOUBLON, CAPACITE (non entière, < 2, ou au-delà
|
|
|
|
|
|
* d'un Int32Array), TOURS (R non entier ou < 1), RESERVATION_INCONNUE
|
|
|
|
|
|
* (participant ou table), RESERVATION_TOUR (tour absent ou hors de 1..R),
|
|
|
|
|
|
* RESERVATION_CONFLIT (une personne à deux tables d'un même tour),
|
|
|
|
|
|
* SURRESERVATION (plus de personnes fixées que de sièges à une table, à un
|
|
|
|
|
|
* tour). Une salle trop petite n'est pas refusée : nombrePlacesManquantes la
|
|
|
|
|
|
* chiffre, et la recherche la refuse (§ 5.9). Les détails désignent
|
|
|
|
|
|
* participants et tables par identifiant, les tours par leur numéro à partir
|
|
|
|
|
|
* de 1, et la réservation fautive par son rang dans
|
|
|
|
|
|
* configuration.reservations, à partir de 0.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Lève TypeError sur les seules formes qu'énumère l'en-tête du module :
|
|
|
|
|
|
* identifiants de participant et de table, appartenance, exclu, portée,
|
|
|
|
|
|
* contraintes, listes. Une capacité, un nombre de tours ou un tour désigné
|
|
|
|
|
|
* hors de leur forme lèvent CAPACITE, TOURS ou RESERVATION_TOUR ; une
|
|
|
|
|
|
* réservation qui désigne un participant ou une table absents de la
|
|
|
|
|
|
* configuration lève RESERVATION_INCONNUE, quelle que soit la forme de la
|
|
|
|
|
|
* valeur qui les désigne.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param {import('./types.js').Configuration} configuration
|
|
|
|
|
|
* @returns {import('./types.js').Instance}
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function normaliser(configuration) {
|
|
|
|
|
|
const { participants, tables, tours: R, reservations } = configuration;
|
|
|
|
|
|
exigerListe(participants, 'participants');
|
|
|
|
|
|
exigerListe(tables, 'tables');
|
|
|
|
|
|
exigerListe(reservations, 'reservations');
|
|
|
|
|
|
const contraintes = copierContraintes(configuration.contraintes);
|
|
|
|
|
|
|
|
|
|
|
|
// connus porte tous les identifiants, exclus compris : un doublon reste un
|
|
|
|
|
|
// doublon, et la réservation d'un exclu n'est pas inconnue.
|
|
|
|
|
|
const connus = new Set();
|
|
|
|
|
|
const presents = [];
|
|
|
|
|
|
const exclus = [];
|
|
|
|
|
|
for (const participant of participants) {
|
|
|
|
|
|
exigerIdentifiant(participant.id, 'participant');
|
|
|
|
|
|
if (connus.has(participant.id)) {
|
|
|
|
|
|
throw new ErreurConfiguration('PARTICIPANT_DOUBLON', { participant: participant.id });
|
|
|
|
|
|
}
|
|
|
|
|
|
connus.add(participant.id);
|
|
|
|
|
|
exigerAppartenance(participant);
|
|
|
|
|
|
if (estExclu(participant)) exclus.push(participant.id);
|
|
|
|
|
|
else presents.push(participant);
|
|
|
|
|
|
}
|
|
|
|
|
|
presents.sort((a, b) => a.id - b.id);
|
|
|
|
|
|
exclus.sort((a, b) => a - b);
|
|
|
|
|
|
|
|
|
|
|
|
const T = tables.length;
|
|
|
|
|
|
const idsTables = [];
|
|
|
|
|
|
const indexTableDe = new Map();
|
|
|
|
|
|
const capacite = new Int32Array(T);
|
|
|
|
|
|
for (let t = 0; t < T; t += 1) {
|
|
|
|
|
|
const { id, capacite: places } = tables[t];
|
|
|
|
|
|
exigerIdentifiant(id, 'table');
|
|
|
|
|
|
if (indexTableDe.has(id)) throw new ErreurConfiguration('TABLE_DOUBLON', { table: id });
|
|
|
|
|
|
if (!Number.isInteger(places) || places < 2 || places > ENTIER_32_MAX) {
|
|
|
|
|
|
throw new ErreurConfiguration('CAPACITE', { table: id, capacite: places });
|
|
|
|
|
|
}
|
|
|
|
|
|
idsTables.push(id);
|
|
|
|
|
|
indexTableDe.set(id, t);
|
|
|
|
|
|
capacite[t] = places;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!Number.isInteger(R) || R < 1) throw new ErreurConfiguration('TOURS', { tours: R });
|
|
|
|
|
|
|
|
|
|
|
|
const N = presents.length;
|
|
|
|
|
|
const ids = presents.map((participant) => participant.id);
|
|
|
|
|
|
const indexDe = new Map(ids.map((id, p) => [id, p]));
|
|
|
|
|
|
const { groupe, groupes } = numeroterGroupes(presents);
|
|
|
|
|
|
const fixe = fixerReservations(reservations, { connus, indexDe, indexTableDe, idsTables, N, R });
|
|
|
|
|
|
verifierSurreservation(fixe, { N, T, R, capacite, idsTables });
|
|
|
|
|
|
const { statut, ancresParTable, k } = deriverStatuts(fixe, N, T, R);
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
N,
|
|
|
|
|
|
T,
|
|
|
|
|
|
R,
|
|
|
|
|
|
ids,
|
|
|
|
|
|
indexDe,
|
|
|
|
|
|
exclus: new Set(exclus),
|
|
|
|
|
|
idsTables,
|
|
|
|
|
|
indexTableDe,
|
|
|
|
|
|
capacite,
|
|
|
|
|
|
groupe,
|
|
|
|
|
|
groupes,
|
|
|
|
|
|
fixe,
|
|
|
|
|
|
statut,
|
|
|
|
|
|
ancresParTable,
|
|
|
|
|
|
k,
|
|
|
|
|
|
n: N - k,
|
|
|
|
|
|
contraintes,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Plan indexé d'un plan par identifiants : tableDe[p * R + r] = index de
|
|
|
|
|
|
* table, −1 pour la réserve. plan.tables déclare chaque table de l'instance
|
|
|
|
|
|
* une fois, et chaque liste se rattache à sa table par l'identifiant déclaré
|
|
|
|
|
|
* à la même position ; l'ordre des tables et celui des ids dans une liste
|
|
|
|
|
|
* sont indifférents. Un plan accepté revient donc de planDepuisIndex à
|
|
|
|
|
|
* l'identique, à ces deux ordres près.
|
|
|
|
|
|
*
|
|
|
|
|
|
* La forme indexée n'a pas de case pour un participant absent d'un tour,
|
|
|
|
|
|
* placé deux fois ou étranger à l'instance, ni pour une table que le plan ne
|
|
|
|
|
|
* déclare pas : au lieu de perdre l'écart, indexerPlan lève
|
|
|
|
|
|
* ErreurConfiguration — PLAN_TOURS (tours ou réserves en nombre ≠ R),
|
|
|
|
|
|
* PLAN_TABLE_INCONNUE, PLAN_TABLE_DOUBLON, PLAN_TABLE_ABSENTE (une table de
|
|
|
|
|
|
* l'instance que plan.tables ne déclare pas), PLAN_LISTES (un tour sans
|
|
|
|
|
|
* exactement une liste par table déclarée), PLAN_INCONNU, PLAN_EXCLU_PLACE
|
|
|
|
|
|
* (participant exclu de l'instance), PLAN_DOUBLE_PLACE (deux fois dans un
|
|
|
|
|
|
* tour, réserve comprise), PLAN_NON_ASSIS (ni à une table ni en réserve à un
|
|
|
|
|
|
* tour). Les capacités et les réservations ne sont pas examinées.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param {import('./types.js').Instance} instance
|
|
|
|
|
|
* @param {import('./types.js').Plan} plan
|
|
|
|
|
|
* @returns {Int32Array}
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function indexerPlan(instance, plan) {
|
|
|
|
|
|
const { N, T, R, ids, idsTables, indexDe, indexTableDe, exclus } = instance;
|
|
|
|
|
|
if (plan.tours.length !== R || plan.reserves.length !== R) {
|
|
|
|
|
|
throw new ErreurConfiguration('PLAN_TOURS', {
|
|
|
|
|
|
attendu: R,
|
|
|
|
|
|
tours: plan.tours.length,
|
|
|
|
|
|
reserves: plan.reserves.length,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
// Index de table de chaque liste, par position dans plan.tables.
|
|
|
|
|
|
const tableDeListe = [];
|
|
|
|
|
|
const declarees = new Set();
|
|
|
|
|
|
for (const id of plan.tables) {
|
|
|
|
|
|
const t = indexTableDe.get(id);
|
|
|
|
|
|
if (t === undefined) throw new ErreurConfiguration('PLAN_TABLE_INCONNUE', { table: id });
|
|
|
|
|
|
if (declarees.has(id)) throw new ErreurConfiguration('PLAN_TABLE_DOUBLON', { table: id });
|
|
|
|
|
|
declarees.add(id);
|
|
|
|
|
|
tableDeListe.push(t);
|
|
|
|
|
|
}
|
|
|
|
|
|
// Sans id inconnu ni doublon, une table manque exactement quand le plan en
|
|
|
|
|
|
// déclare moins que l'instance ; la première absente, dans l'ordre de
|
|
|
|
|
|
// l'instance, est nommée.
|
|
|
|
|
|
if (tableDeListe.length !== T) {
|
|
|
|
|
|
const absente = idsTables.find((id) => !declarees.has(id));
|
|
|
|
|
|
throw new ErreurConfiguration('PLAN_TABLE_ABSENTE', { table: absente });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const tableDe = new Int32Array(N * R).fill(NON_PLACE);
|
|
|
|
|
|
const placer = (id, r, t) => {
|
|
|
|
|
|
const p = indexDe.get(id);
|
|
|
|
|
|
if (p === undefined) {
|
|
|
|
|
|
const code = exclus.has(id) ? 'PLAN_EXCLU_PLACE' : 'PLAN_INCONNU';
|
|
|
|
|
|
throw new ErreurConfiguration(code, { participant: id, tour: r + 1 });
|
|
|
|
|
|
}
|
|
|
|
|
|
if (tableDe[p * R + r] !== NON_PLACE) {
|
|
|
|
|
|
throw new ErreurConfiguration('PLAN_DOUBLE_PLACE', { participant: id, tour: r + 1 });
|
|
|
|
|
|
}
|
|
|
|
|
|
tableDe[p * R + r] = t;
|
|
|
|
|
|
};
|
|
|
|
|
|
for (let r = 0; r < R; r += 1) {
|
|
|
|
|
|
const listes = plan.tours[r];
|
|
|
|
|
|
if (listes.length !== tableDeListe.length) {
|
|
|
|
|
|
throw new ErreurConfiguration('PLAN_LISTES', {
|
|
|
|
|
|
tour: r + 1,
|
|
|
|
|
|
listes: listes.length,
|
|
|
|
|
|
tables: tableDeListe.length,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
for (let i = 0; i < listes.length; i += 1) {
|
|
|
|
|
|
for (const id of listes[i]) placer(id, r, tableDeListe[i]);
|
|
|
|
|
|
}
|
|
|
|
|
|
for (const id of plan.reserves[r]) placer(id, r, RESERVE);
|
|
|
|
|
|
for (let p = 0; p < N; p += 1) {
|
|
|
|
|
|
if (tableDe[p * R + r] === NON_PLACE) {
|
|
|
|
|
|
throw new ErreurConfiguration('PLAN_NON_ASSIS', { participant: ids[p], tour: r + 1 });
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return tableDe;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
[IMP] engine: single owners, regeneration, property grid
The search recomputed the collision excess and the gaps that the measure
already gives — two arithmetics for one quantity. It now reads them from
the measure, and the redundancy total has one owner. Contract values, the
indexed-plan guard and the population split are defined once. regenerer
rebuilds a proposition from its derived seed, stop count and history
length, which the spec now lists (§ 8.9). A property grid runs seeded
random rooms through the whole chain.
Checked: 435 node and 20 long tests; redefining the excess or the gaps in
the measure now fails the search tests too.
--- FR ---
[IMP] moteur : propriétaires uniques, régénération, grille de propriétés
La recherche recalculait l'excédent de collisions et les écarts que la
mesure donne déjà — deux arithmétiques pour une grandeur. Elle les lit
désormais dans la mesure, et le total de redondance a un seul
propriétaire. Valeurs du contrat, garde du plan indexé et partition des
populations sont définies une fois. regenerer reconstruit une proposition
depuis sa graine dérivée, son arrêt et la longueur de son historique,
que le spec énumère désormais (§ 8.9). Une grille de propriétés fait
traverser toute la chaîne à des salles tirées d'une graine.
Vérifié : 435 épreuves node et 20 longues ; redéfinir l'excédent ou les
écarts dans la mesure fait désormais tomber aussi la recherche.
Assisted-by: Claude Opus 5.5
2026-10-06 04:23:02 -04:00
|
|
|
|
/**
|
|
|
|
|
|
* La garde de forme d'un plan indexé, la seule du moteur : planDepuisIndex,
|
|
|
|
|
|
* mesurer et plafondsRealises l'appellent avant de lire une case. Lève
|
|
|
|
|
|
* RangeError quand tableDe n'a pas N × R cases, ou qu'une case n'est ni
|
|
|
|
|
|
* RESERVE ni un index de table entier de 0 à T − 1. Le message nomme alors
|
|
|
|
|
|
* le participant, par identifiant, le tour et la valeur de la première case
|
|
|
|
|
|
* fautive dans l'ordre des cases, p × R + r croissant ; une chaîne s'y cite
|
|
|
|
|
|
* entre guillemets, pour ne pas se lire comme le nombre qu'elle contient.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Sans elle, une case de trop serait ignorée, et une chaîne numérique comme
|
|
|
|
|
|
* "0" assiérait la personne à la table qu'elle désigne là où une
|
|
|
|
|
|
* comparaison stricte à instance.fixe n'y reconnaîtrait pas sa réservation.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param {import('./types.js').Instance} instance
|
|
|
|
|
|
* @param {ArrayLike<number>} tableDe
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function exigerPlanIndexe({ N, T, R, ids }, tableDe) {
|
|
|
|
|
|
if (tableDe.length !== N * R) {
|
|
|
|
|
|
throw new RangeError(`plan indexé de ${tableDe.length} cases, N × R = ${N * R} attendues`);
|
|
|
|
|
|
}
|
|
|
|
|
|
for (let i = 0; i < tableDe.length; i += 1) {
|
|
|
|
|
|
const t = tableDe[i];
|
|
|
|
|
|
if (t !== RESERVE && !(Number.isInteger(t) && t >= 0 && t < T)) {
|
|
|
|
|
|
throw new RangeError(
|
|
|
|
|
|
`plan indexé : participant ${ids[Math.floor(i / R)]}, tour ${(i % R) + 1}, `
|
|
|
|
|
|
+ `index de table ${decrire(t)} hors de −1..${T - 1}`,
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
[ADD] engine: configuration normalised into an indexed instance
The engine works on dense arrays, not on the operator's objects.
normaliser checks the configuration, derives anchored, partially fixed and
mobile statuses from the reservations themselves, and suspends an excluded
person's reservations without stopping on them. It never refuses a room
that is too small: that is a property of the configuration, which the
diagnosis names and the search refuses (§ 5.9). A plan converts both ways
between ids and indices, seats in ascending id.
Checked: a reservation after an excluded one, and a conflict found under
« tous », each fail their mutant; an independent oracle agreed throughout.
--- FR ---
[ADD] moteur : configuration normalisée en une instance indexée
Le moteur travaille sur des tableaux denses, pas sur les objets de
l'opérateur. normaliser vérifie la configuration, dérive les statuts
ancré, partiellement fixé et mobile des réservations elles-mêmes, et
suspend les réservations d'un exclu sans s'y arrêter. Il ne refuse jamais
une salle trop petite : c'est une propriété de la configuration, que le
diagnostic nomme et que la recherche refuse (§ 5.9). Un plan passe dans
les deux sens des ids aux index, sièges par id croissant.
Vérifié : une réservation après celle d'un exclu, et un conflit découvert
sous « tous », font chacune tomber leur mutant ; un oracle indépendant
concorde partout.
Assisted-by: Claude Opus 5.5
2026-10-05 17:27:06 -04:00
|
|
|
|
/**
|
|
|
|
|
|
* Plan par identifiants d'un plan indexé : les tables dans l'ordre de
|
|
|
|
|
|
* l'instance, chaque liste de table et chaque réserve en ids croissants
|
[IMP] engine: single owners, regeneration, property grid
The search recomputed the collision excess and the gaps that the measure
already gives — two arithmetics for one quantity. It now reads them from
the measure, and the redundancy total has one owner. Contract values, the
indexed-plan guard and the population split are defined once. regenerer
rebuilds a proposition from its derived seed, stop count and history
length, which the spec now lists (§ 8.9). A property grid runs seeded
random rooms through the whole chain.
Checked: 435 node and 20 long tests; redefining the excess or the gaps in
the measure now fails the search tests too.
--- FR ---
[IMP] moteur : propriétaires uniques, régénération, grille de propriétés
La recherche recalculait l'excédent de collisions et les écarts que la
mesure donne déjà — deux arithmétiques pour une grandeur. Elle les lit
désormais dans la mesure, et le total de redondance a un seul
propriétaire. Valeurs du contrat, garde du plan indexé et partition des
populations sont définies une fois. regenerer reconstruit une proposition
depuis sa graine dérivée, son arrêt et la longueur de son historique,
que le spec énumère désormais (§ 8.9). Une grille de propriétés fait
traverser toute la chaîne à des salles tirées d'une graine.
Vérifié : 435 épreuves node et 20 longues ; redéfinir l'excédent ou les
écarts dans la mesure fait désormais tomber aussi la recherche.
Assisted-by: Claude Opus 5.5
2026-10-06 04:23:02 -04:00
|
|
|
|
* (§ 8.9). Lève ce que lève exigerPlanIndexe.
|
[ADD] engine: configuration normalised into an indexed instance
The engine works on dense arrays, not on the operator's objects.
normaliser checks the configuration, derives anchored, partially fixed and
mobile statuses from the reservations themselves, and suspends an excluded
person's reservations without stopping on them. It never refuses a room
that is too small: that is a property of the configuration, which the
diagnosis names and the search refuses (§ 5.9). A plan converts both ways
between ids and indices, seats in ascending id.
Checked: a reservation after an excluded one, and a conflict found under
« tous », each fail their mutant; an independent oracle agreed throughout.
--- FR ---
[ADD] moteur : configuration normalisée en une instance indexée
Le moteur travaille sur des tableaux denses, pas sur les objets de
l'opérateur. normaliser vérifie la configuration, dérive les statuts
ancré, partiellement fixé et mobile des réservations elles-mêmes, et
suspend les réservations d'un exclu sans s'y arrêter. Il ne refuse jamais
une salle trop petite : c'est une propriété de la configuration, que le
diagnostic nomme et que la recherche refuse (§ 5.9). Un plan passe dans
les deux sens des ids aux index, sièges par id croissant.
Vérifié : une réservation après celle d'un exclu, et un conflit découvert
sous « tous », font chacune tomber leur mutant ; un oracle indépendant
concorde partout.
Assisted-by: Claude Opus 5.5
2026-10-05 17:27:06 -04:00
|
|
|
|
*
|
|
|
|
|
|
* @param {import('./types.js').Instance} instance
|
|
|
|
|
|
* @param {ArrayLike<number>} tableDe
|
|
|
|
|
|
* @returns {import('./types.js').Plan}
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function planDepuisIndex(instance, tableDe) {
|
[IMP] engine: single owners, regeneration, property grid
The search recomputed the collision excess and the gaps that the measure
already gives — two arithmetics for one quantity. It now reads them from
the measure, and the redundancy total has one owner. Contract values, the
indexed-plan guard and the population split are defined once. regenerer
rebuilds a proposition from its derived seed, stop count and history
length, which the spec now lists (§ 8.9). A property grid runs seeded
random rooms through the whole chain.
Checked: 435 node and 20 long tests; redefining the excess or the gaps in
the measure now fails the search tests too.
--- FR ---
[IMP] moteur : propriétaires uniques, régénération, grille de propriétés
La recherche recalculait l'excédent de collisions et les écarts que la
mesure donne déjà — deux arithmétiques pour une grandeur. Elle les lit
désormais dans la mesure, et le total de redondance a un seul
propriétaire. Valeurs du contrat, garde du plan indexé et partition des
populations sont définies une fois. regenerer reconstruit une proposition
depuis sa graine dérivée, son arrêt et la longueur de son historique,
que le spec énumère désormais (§ 8.9). Une grille de propriétés fait
traverser toute la chaîne à des salles tirées d'une graine.
Vérifié : 435 épreuves node et 20 longues ; redéfinir l'excédent ou les
écarts dans la mesure fait désormais tomber aussi la recherche.
Assisted-by: Claude Opus 5.5
2026-10-06 04:23:02 -04:00
|
|
|
|
exigerPlanIndexe(instance, tableDe);
|
[ADD] engine: configuration normalised into an indexed instance
The engine works on dense arrays, not on the operator's objects.
normaliser checks the configuration, derives anchored, partially fixed and
mobile statuses from the reservations themselves, and suspends an excluded
person's reservations without stopping on them. It never refuses a room
that is too small: that is a property of the configuration, which the
diagnosis names and the search refuses (§ 5.9). A plan converts both ways
between ids and indices, seats in ascending id.
Checked: a reservation after an excluded one, and a conflict found under
« tous », each fail their mutant; an independent oracle agreed throughout.
--- FR ---
[ADD] moteur : configuration normalisée en une instance indexée
Le moteur travaille sur des tableaux denses, pas sur les objets de
l'opérateur. normaliser vérifie la configuration, dérive les statuts
ancré, partiellement fixé et mobile des réservations elles-mêmes, et
suspend les réservations d'un exclu sans s'y arrêter. Il ne refuse jamais
une salle trop petite : c'est une propriété de la configuration, que le
diagnostic nomme et que la recherche refuse (§ 5.9). Un plan passe dans
les deux sens des ids aux index, sièges par id croissant.
Vérifié : une réservation après celle d'un exclu, et un conflit découvert
sous « tous », font chacune tomber leur mutant ; un oracle indépendant
concorde partout.
Assisted-by: Claude Opus 5.5
2026-10-05 17:27:06 -04:00
|
|
|
|
const { N, T, R, ids, idsTables } = instance;
|
|
|
|
|
|
const tours = [];
|
|
|
|
|
|
const reserves = [];
|
|
|
|
|
|
for (let r = 0; r < R; r += 1) {
|
|
|
|
|
|
const listes = Array.from({ length: T }, () => []);
|
|
|
|
|
|
const reserve = [];
|
|
|
|
|
|
// Les ids croissent avec l'index : parcourir les participants par index
|
|
|
|
|
|
// range chaque liste en ids croissants, sans tri.
|
|
|
|
|
|
for (let p = 0; p < N; p += 1) {
|
|
|
|
|
|
const t = tableDe[p * R + r];
|
[IMP] engine: single owners, regeneration, property grid
The search recomputed the collision excess and the gaps that the measure
already gives — two arithmetics for one quantity. It now reads them from
the measure, and the redundancy total has one owner. Contract values, the
indexed-plan guard and the population split are defined once. regenerer
rebuilds a proposition from its derived seed, stop count and history
length, which the spec now lists (§ 8.9). A property grid runs seeded
random rooms through the whole chain.
Checked: 435 node and 20 long tests; redefining the excess or the gaps in
the measure now fails the search tests too.
--- FR ---
[IMP] moteur : propriétaires uniques, régénération, grille de propriétés
La recherche recalculait l'excédent de collisions et les écarts que la
mesure donne déjà — deux arithmétiques pour une grandeur. Elle les lit
désormais dans la mesure, et le total de redondance a un seul
propriétaire. Valeurs du contrat, garde du plan indexé et partition des
populations sont définies une fois. regenerer reconstruit une proposition
depuis sa graine dérivée, son arrêt et la longueur de son historique,
que le spec énumère désormais (§ 8.9). Une grille de propriétés fait
traverser toute la chaîne à des salles tirées d'une graine.
Vérifié : 435 épreuves node et 20 longues ; redéfinir l'excédent ou les
écarts dans la mesure fait désormais tomber aussi la recherche.
Assisted-by: Claude Opus 5.5
2026-10-06 04:23:02 -04:00
|
|
|
|
if (t === RESERVE) reserve.push(ids[p]);
|
|
|
|
|
|
else listes[t].push(ids[p]);
|
[ADD] engine: configuration normalised into an indexed instance
The engine works on dense arrays, not on the operator's objects.
normaliser checks the configuration, derives anchored, partially fixed and
mobile statuses from the reservations themselves, and suspends an excluded
person's reservations without stopping on them. It never refuses a room
that is too small: that is a property of the configuration, which the
diagnosis names and the search refuses (§ 5.9). A plan converts both ways
between ids and indices, seats in ascending id.
Checked: a reservation after an excluded one, and a conflict found under
« tous », each fail their mutant; an independent oracle agreed throughout.
--- FR ---
[ADD] moteur : configuration normalisée en une instance indexée
Le moteur travaille sur des tableaux denses, pas sur les objets de
l'opérateur. normaliser vérifie la configuration, dérive les statuts
ancré, partiellement fixé et mobile des réservations elles-mêmes, et
suspend les réservations d'un exclu sans s'y arrêter. Il ne refuse jamais
une salle trop petite : c'est une propriété de la configuration, que le
diagnostic nomme et que la recherche refuse (§ 5.9). Un plan passe dans
les deux sens des ids aux index, sièges par id croissant.
Vérifié : une réservation après celle d'un exclu, et un conflit découvert
sous « tous », font chacune tomber leur mutant ; un oracle indépendant
concorde partout.
Assisted-by: Claude Opus 5.5
2026-10-05 17:27:06 -04:00
|
|
|
|
}
|
|
|
|
|
|
tours.push(listes);
|
|
|
|
|
|
reserves.push(reserve);
|
|
|
|
|
|
}
|
|
|
|
|
|
return { tables: [...idsTables], tours, reserves };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
[IMP] engine: single owners, regeneration, property grid
The search recomputed the collision excess and the gaps that the measure
already gives — two arithmetics for one quantity. It now reads them from
the measure, and the redundancy total has one owner. Contract values, the
indexed-plan guard and the population split are defined once. regenerer
rebuilds a proposition from its derived seed, stop count and history
length, which the spec now lists (§ 8.9). A property grid runs seeded
random rooms through the whole chain.
Checked: 435 node and 20 long tests; redefining the excess or the gaps in
the measure now fails the search tests too.
--- FR ---
[IMP] moteur : propriétaires uniques, régénération, grille de propriétés
La recherche recalculait l'excédent de collisions et les écarts que la
mesure donne déjà — deux arithmétiques pour une grandeur. Elle les lit
désormais dans la mesure, et le total de redondance a un seul
propriétaire. Valeurs du contrat, garde du plan indexé et partition des
populations sont définies une fois. regenerer reconstruit une proposition
depuis sa graine dérivée, son arrêt et la longueur de son historique,
que le spec énumère désormais (§ 8.9). Une grille de propriétés fait
traverser toute la chaîne à des salles tirées d'une graine.
Vérifié : 435 épreuves node et 20 longues ; redéfinir l'excédent ou les
écarts dans la mesure fait désormais tomber aussi la recherche.
Assisted-by: Claude Opus 5.5
2026-10-06 04:23:02 -04:00
|
|
|
|
/**
|
|
|
|
|
|
* Places qu'offre chaque tour : Σ c_t, la somme des capacités. Ni les
|
|
|
|
|
|
* participants ni les réservations n'y entrent. Le nombre de places
|
|
|
|
|
|
* manquantes et le diagnostic d'une salle tendue la lisent ici.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param {import('./types.js').Instance} instance T et capacite sont lus
|
|
|
|
|
|
* @returns {number}
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function nombrePlaces({ T, capacite }) {
|
|
|
|
|
|
let places = 0;
|
|
|
|
|
|
for (let t = 0; t < T; t += 1) places += capacite[t];
|
|
|
|
|
|
return places;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
[ADD] engine: configuration normalised into an indexed instance
The engine works on dense arrays, not on the operator's objects.
normaliser checks the configuration, derives anchored, partially fixed and
mobile statuses from the reservations themselves, and suspends an excluded
person's reservations without stopping on them. It never refuses a room
that is too small: that is a property of the configuration, which the
diagnosis names and the search refuses (§ 5.9). A plan converts both ways
between ids and indices, seats in ascending id.
Checked: a reservation after an excluded one, and a conflict found under
« tous », each fail their mutant; an independent oracle agreed throughout.
--- FR ---
[ADD] moteur : configuration normalisée en une instance indexée
Le moteur travaille sur des tableaux denses, pas sur les objets de
l'opérateur. normaliser vérifie la configuration, dérive les statuts
ancré, partiellement fixé et mobile des réservations elles-mêmes, et
suspend les réservations d'un exclu sans s'y arrêter. Il ne refuse jamais
une salle trop petite : c'est une propriété de la configuration, que le
diagnostic nomme et que la recherche refuse (§ 5.9). Un plan passe dans
les deux sens des ids aux index, sièges par id croissant.
Vérifié : une réservation après celle d'un exclu, et un conflit découvert
sous « tous », font chacune tomber leur mutant ; un oracle indépendant
concorde partout.
Assisted-by: Claude Opus 5.5
2026-10-05 17:27:06 -04:00
|
|
|
|
/**
|
|
|
|
|
|
* Places qui manquent à chaque tour pour asseoir tous les participants :
|
|
|
|
|
|
* max(0, N − Σ c_t). La quantité égale max(0, n − Σ (c_t − a_t)) et ne
|
|
|
|
|
|
* dépend d'aucune réservation (§ 5.9) : un ancré retire une personne des
|
|
|
|
|
|
* mobiles et un siège de la capacité libre, un partiellement fixé reste
|
|
|
|
|
|
* parmi les mobiles et ne retire rien.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param {import('./types.js').Instance} instance
|
|
|
|
|
|
* @returns {number}
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function nombrePlacesManquantes(instance) {
|
[IMP] engine: single owners, regeneration, property grid
The search recomputed the collision excess and the gaps that the measure
already gives — two arithmetics for one quantity. It now reads them from
the measure, and the redundancy total has one owner. Contract values, the
indexed-plan guard and the population split are defined once. regenerer
rebuilds a proposition from its derived seed, stop count and history
length, which the spec now lists (§ 8.9). A property grid runs seeded
random rooms through the whole chain.
Checked: 435 node and 20 long tests; redefining the excess or the gaps in
the measure now fails the search tests too.
--- FR ---
[IMP] moteur : propriétaires uniques, régénération, grille de propriétés
La recherche recalculait l'excédent de collisions et les écarts que la
mesure donne déjà — deux arithmétiques pour une grandeur. Elle les lit
désormais dans la mesure, et le total de redondance a un seul
propriétaire. Valeurs du contrat, garde du plan indexé et partition des
populations sont définies une fois. regenerer reconstruit une proposition
depuis sa graine dérivée, son arrêt et la longueur de son historique,
que le spec énumère désormais (§ 8.9). Une grille de propriétés fait
traverser toute la chaîne à des salles tirées d'une graine.
Vérifié : 435 épreuves node et 20 longues ; redéfinir l'excédent ou les
écarts dans la mesure fait désormais tomber aussi la recherche.
Assisted-by: Claude Opus 5.5
2026-10-06 04:23:02 -04:00
|
|
|
|
return Math.max(0, instance.N - nombrePlaces(instance));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Replie valeurs[p] sur les trois populations du § 5.4, en un passage, dans
|
|
|
|
|
|
* l'ordre canonique : chacun compte dans « tous », puis parmi les ancrés, ou
|
|
|
|
|
|
* parmi les mobiles, partiellement fixés compris. C'est le seul endroit qui
|
|
|
|
|
|
* range une personne dans sa population : les agrégats des indicateurs et
|
|
|
|
|
|
* les chiffres du manque le lisent tous deux.
|
|
|
|
|
|
*
|
|
|
|
|
|
* replier(cumul, valeur) rend le cumul suivant sans modifier celui qu'il
|
|
|
|
|
|
* reçoit : les trois populations partent du même initial, et une population
|
|
|
|
|
|
* sans membre le garde.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @template C
|
|
|
|
|
|
* @param {ArrayLike<*>} valeurs une par personne, dans l'ordre de instance.ids
|
|
|
|
|
|
* @param {ArrayLike<number>} statut instance.statut
|
|
|
|
|
|
* @param {C} initial
|
|
|
|
|
|
* @param {function(C, *): C} replier
|
|
|
|
|
|
* @returns {{tous: C, mobiles: C, ancres: C}}
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function replierParPopulation(valeurs, statut, initial, replier) {
|
|
|
|
|
|
let tous = initial;
|
|
|
|
|
|
let mobiles = initial;
|
|
|
|
|
|
let ancres = initial;
|
|
|
|
|
|
for (let p = 0; p < valeurs.length; p += 1) {
|
|
|
|
|
|
const valeur = valeurs[p];
|
|
|
|
|
|
tous = replier(tous, valeur);
|
|
|
|
|
|
if (statut[p] === STATUT.ANCRE) ancres = replier(ancres, valeur);
|
|
|
|
|
|
else mobiles = replier(mobiles, valeur);
|
|
|
|
|
|
}
|
|
|
|
|
|
return { tous, mobiles, ancres };
|
[ADD] engine: configuration normalised into an indexed instance
The engine works on dense arrays, not on the operator's objects.
normaliser checks the configuration, derives anchored, partially fixed and
mobile statuses from the reservations themselves, and suspends an excluded
person's reservations without stopping on them. It never refuses a room
that is too small: that is a property of the configuration, which the
diagnosis names and the search refuses (§ 5.9). A plan converts both ways
between ids and indices, seats in ascending id.
Checked: a reservation after an excluded one, and a conflict found under
« tous », each fail their mutant; an independent oracle agreed throughout.
--- FR ---
[ADD] moteur : configuration normalisée en une instance indexée
Le moteur travaille sur des tableaux denses, pas sur les objets de
l'opérateur. normaliser vérifie la configuration, dérive les statuts
ancré, partiellement fixé et mobile des réservations elles-mêmes, et
suspend les réservations d'un exclu sans s'y arrêter. Il ne refuse jamais
une salle trop petite : c'est une propriété de la configuration, que le
diagnostic nomme et que la recherche refuse (§ 5.9). Un plan passe dans
les deux sens des ids aux index, sièges par id croissant.
Vérifié : une réservation après celle d'un exclu, et un conflit découvert
sous « tous », font chacune tomber leur mutant ; un oracle indépendant
concorde partout.
Assisted-by: Claude Opus 5.5
2026-10-05 17:27:06 -04:00
|
|
|
|
}
|