Generation ran in a single worker, one proposition after another, using one core. A pool of workers now takes propositions by rank, as many as the cores set: automatic by default (every logical CPU), or a count from 1 to that number. Each proposition is still computed from its own derived seed, so the result is byte-identical whatever the core count, ordered by identifier. One progress bar sums the workers; Cancel stops them all; the duration estimate counts the cores. The setting is per session and never written. Checked: 2872 node, 586 browser, 62 long; 5 workers in Electron. --- FR --- [ADD] génération : réserve de travailleurs sur les processeurs, cœurs La génération tournait dans un seul travailleur, une proposition après l'autre, sur un seul cœur. Une réserve de travailleurs prend maintenant les propositions par rang, autant que de cœurs réglés : automatique par défaut (tous les processeurs logiques), ou un nombre de 1 à ce total. Chaque proposition se calcule toujours depuis sa graine dérivée : le résultat est identique à l'octet quel que soit le nombre de cœurs, rangé par identifiant. Une seule barre ; Annuler arrête tout ; l'estimation compte les cœurs. Réglage de séance, jamais écrit. Vérifié : 2872, 586, 62. Assisted-by: Claude Opus 5.5
114 lines
5.2 KiB
JavaScript
114 lines
5.2 KiB
JavaScript
// © 2026 TechnoLibre (http://www.technolibre.ca)
|
|
// License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
|
|
|
// Les textes des commandes de la génération et des propositions (§ 5.7,
|
|
// § 14.6) : refus et libellés figés, puis les refus du contrôleur de
|
|
// génération et de la saisie de ses réglages (§ 5.9, § 5.10, § 15.4). Cette
|
|
// table ne porte que des codes. Un nombre et une durée se mettent en forme
|
|
// par creerFormat, sur la composition que la traduction passe à l'entrée.
|
|
import { creerFormat } from '../format.js';
|
|
import { cite, compte, phraseDeRaison } from './aides.js';
|
|
|
|
// Le nom de chaque réglage de génération, celui que la saisie affiche.
|
|
const NOMS_DES_REGLAGES = new Map([
|
|
['graine', 'Graine'],
|
|
['nombre', 'Propositions par génération'],
|
|
['arret', 'Mouvements par proposition'],
|
|
['historique', "Historique d'acceptation"],
|
|
]);
|
|
|
|
// Les cœurs d'un calcul, dits quand il en emploie plus d'un : « , sur
|
|
// 4 cœurs » ; rien pour un seul, ou quand le nombre n'est pas donné.
|
|
function surCoeurs(coeurs, texte) {
|
|
return typeof coeurs === 'number' && coeurs > 1 ? `, sur ${creerFormat(texte).nombre(coeurs)} cœurs` : '';
|
|
}
|
|
|
|
// L'estimation d'une génération longue, en mots : l'ordre de grandeur et les
|
|
// cœurs qu'elle emploierait, puis la mesure dont il vient ; ou le seuil d'une
|
|
// génération sans mesure.
|
|
function phraseEstimation(estimation, texte) {
|
|
if (estimation.inconnue === true) {
|
|
return (
|
|
"Aucune durée n'est encore mesurée sur ce poste dans cette séance, et ce réglage demande plus de " +
|
|
'dix fois le réglage par défaut'
|
|
);
|
|
}
|
|
const format = creerFormat(texte);
|
|
const { mesure } = estimation;
|
|
const plafond = estimation.auDelaDuPlafond ? ", au-delà du plafond d'usage de trente minutes" : '';
|
|
return (
|
|
`Ce réglage prendrait ${format.ordreDeGrandeur(estimation.secondes)}${surCoeurs(estimation.coeurs, texte)}` +
|
|
`${plafond}, d'après le dernier calcul, ` +
|
|
`${format.duree(mesure.dureeMs)} pour ${format.nombre(mesure.mouvements)} mouvements ` +
|
|
`sur ${compte(mesure.participants, 'participant', 'participants')}${surCoeurs(mesure.coeurs, texte)}`
|
|
);
|
|
}
|
|
|
|
export const TABLE = new Map([
|
|
// --- Les refus des propositions (§ 5.7) ------------------------------------
|
|
['PROPOSITION_INCONNUE', ({ id }) => `La proposition n° ${id} n'est pas dans cet événement.`],
|
|
|
|
// --- Les libellés figés du journal (§ 8.2, § 8.3) --------------------------
|
|
[
|
|
'ENTREE_ENREGISTRER_GENERATION',
|
|
({ n, premier, dernier }) =>
|
|
`Généré ${compte(n, 'proposition', 'propositions')} ` +
|
|
`(n° ${premier === dernier ? premier : `${premier} à ${dernier}`})`,
|
|
],
|
|
['ENTREE_RETENIR_PROPOSITION', ({ id }) => `Retenu la proposition n° ${id}`],
|
|
[
|
|
'ENTREE_EFFACER_PROPOSITIONS',
|
|
({ n, gardee }) =>
|
|
`Effacé ${compte(n, 'proposition', 'propositions')}` +
|
|
`${gardee === null || gardee === undefined ? '' : `, gardé la retenue (n° ${gardee})`}`,
|
|
],
|
|
|
|
// --- Le contrôleur de génération (§ 5.9, § 5.10, § 15.4) -------------------
|
|
['GENERATION_EN_COURS', () => "Une génération est déjà en cours : l'annuler, ou attendre qu'elle s'achève."],
|
|
[
|
|
'AUCUN_PARTICIPANT',
|
|
() => "Aucune personne à placer : la liste des participants est vide, ou chacun en est exclu.",
|
|
],
|
|
['AUCUNE_TABLE', () => "Aucune table : la génération place les personnes autour des tables de l'événement."],
|
|
// Le travailleur de génération n'a pas démarré, ou s'est arrêté sans
|
|
// résultat : rien n'est enregistré, et aucun geste de la page ne le relance.
|
|
[
|
|
'TRAVAILLEUR_EN_ECHEC',
|
|
() =>
|
|
"Le calcul hors de la page n'a pas pu se faire : le navigateur n'a pas démarré le travailleur de génération, " +
|
|
"ou l'a arrêté sans résultat. Rien n'est enregistré ; relancer le logiciel le recharge.",
|
|
],
|
|
[
|
|
'CONFIRMATION_REQUISE',
|
|
({ estimation }, texte) =>
|
|
`${phraseEstimation(estimation, texte)}. Confirmer « Générer » lance quand même la génération.`,
|
|
],
|
|
[
|
|
'REGLAGE_HORS_DOMAINE',
|
|
({ reglage }) =>
|
|
`Le réglage ${cite(NOMS_DES_REGLAGES.get(reglage) ?? String(reglage))} sort de son domaine : ` +
|
|
"la génération n'a pas eu lieu.",
|
|
],
|
|
// rang : la place du placement dans la suite des graines du lancement,
|
|
// jamais un numéro de proposition, puisque rien n'est enregistré ; chaque
|
|
// violation se dit par le texte de son code (libelles/moteur.js).
|
|
[
|
|
'GENERATION_INVARIANT_VIOLE',
|
|
({ rang, violations }, texte) =>
|
|
`Le placement que la génération a rendu au rang ${rang} de ce lancement enfreint ` +
|
|
`${compte(violations.length, 'règle', 'règles')} ; rien n'est enregistré. ` +
|
|
violations.map((violation) => phraseDeRaison(violation.code, violation, texte)).join(' '),
|
|
],
|
|
|
|
// --- La saisie des réglages (§ 5.7) -----------------------------------------
|
|
// max null : le domaine n'a pas de borne supérieure.
|
|
[
|
|
'HORS_DOMAINE',
|
|
({ min, max }, texte) => {
|
|
const { nombre } = creerFormat(texte);
|
|
return max === null || max === undefined
|
|
? `La valeur doit être d'au moins ${nombre(min)}.`
|
|
: `La valeur doit être comprise entre ${nombre(min)} et ${nombre(max)}.`;
|
|
},
|
|
],
|
|
]);
|