Kit IA — générer un scénario Stratilead avec une IA
This content is not available in your language yet.
Ce kit permet de faire écrire un scénario Stratilead complet et cohérent par une IA générale (Claude, ou un autre grand modèle).
Mode d’emploi (pour l’humain)
Section intitulée « Mode d’emploi (pour l’humain) »- Ouvrez une conversation avec l’IA.
- Joignez ou collez dans cet ordre :
- ce fichier
KIT-IA.md; - l’exemple simple
scenarios/officiels/limonade/scenario.json; - pour un scénario riche, l’exemple complet
scenarios/officiels/usine-ram/scenario.json; - pour un scénario très avancé, la référence complète et le langage de formules.
- ce fichier
- Copiez le prompt ci-dessous, complétez la partie « Mon scénario », envoyez.
- Importez le JSON obtenu dans l’éditeur Stratilead (ou lancez
stratilead validate fichier.json). - S’il y a des erreurs ou des alertes, recollez-les telles quelles à l’IA : « Corrige ces problèmes de validation : … ». Recommencez jusqu’à zéro erreur.
- Lancez le banc d’essai (bouton « Tester l’équilibre » ou
stratilead bench fichier.json) et recollez les alertesB8xxà l’IA de la même façon. - Jouez une partie test en solo avant de l’utiliser en classe.
La plateforme proposera un bouton « Télécharger le kit IA » qui rassemble tous ces fichiers en un seul.
Prompt à copier
Section intitulée « Prompt à copier »Tu es concepteur de jeux sérieux et expert en gestion d'entreprise. Tu écris des scénarios pourStratilead, un jeu web de simulation d'entreprise joué en classe par tours, dans le format JSONdécrit par le KIT-IA joint. Les exemples joints montrent le format attendu.
Mon scénario :- Secteur et entreprise jouée : [ex. une boulangerie de quartier]- Public : [ex. BTS MCO, 1re année]- Durée de session : [ex. 1 h 30, 6 tours]- Ce que les joueurs doivent apprendre : [ex. marge, gestion des invendus, saisonnalité, embauche]- Décisions souhaitées : [ex. prix par produit, quantités produites, horaires d'ouverture, personnel]- Événements souhaités : [ex. canicule, hausse du prix du beurre, concurrent qui ouvre]- Mode de marché : [partagé, parallèle, ou les deux]- Niveaux de difficulté : [ex. facile et normal]- Langue : français
Consignes :1. Respecte strictement le format du KIT-IA (formatVersion "1.0"). N'invente aucun champ.2. Calibre d'abord une entreprise de référence (§6 du kit) et vérifie mentalement un tour complet avec les chiffres : chiffre d'affaires, coûts, résultat, trésorerie. Indique ce calcul dans pedagogy.facilitatorNotes.3. Toutes les grandeurs utilisées dans une expression doivent être déclarées. Respecte les moments d'évaluation (§4.4 du kit).4. Rédige tous les textes en français clair, avec des aides (help) et des descriptions qui expliquent les concepts, des enseignements (teaching) pour chaque événement et des insights pour le débrief.5. Prévois des images dans "assets" avec un texte "alt" descriptif, sans "src".6. Réponds avec le JSON complet dans un seul bloc de code, puis une courte liste des choix de calibrage et des points à tester en priorité.1. Règles impératives
Section intitulée « 1. Règles impératives »- Le fichier est un JSON strict : pas de commentaires, pas de virgule finale, guillemets doubles.
"formatVersion": "1.0","version": "1.0.0",iden minuscules avec tirets (boulangerie-quartier).- Aucun champ inventé. Seuls les champs listés dans ce kit (ou dans la référence complète) existent.
- Identifiants en camelCase ASCII sans accents (
coutMatiere,prixVente), uniques entre constantes, variables, décisions, formules et sorties de marché. - Les pourcentages sont des ratios :
0.15= 15 %, partout (constantes, bornes de décisions, formules). - Une chaîne JSON dans un champ « valeur ou expression » est une expression. Un texte littéral dans une expression s’écrit entre apostrophes :
fournisseur == 'local'. - Toute grandeur utilisée dans une expression est déclarée quelque part.
- Pas de dépendance circulaire entre formules : pour réutiliser un résultat passé, utiliser une variable (sa valeur est celle du début du tour) ou
prev(...). - Les formules doivent rester robustes avec des décisions absurdes (prix minimal, production nulle…) : utiliser
min,max,safeDiv,clamp. - Une décision
perune liste a une valeur par élément :"initial": { "a": 10, "b": 20 }. scoreclasse au profit cumulé par défaut (ex.cumul(resultatNet)).
2. Le modèle en une page
Section intitulée « 2. Le modèle en une page »Chaque tour (mois, trimestre, saison…) :
variables (début du tour) + décisions des joueurs → formules (calculées dans l'ordre des dépendances, automatiquement) → marché (répartit les clients entre entreprises selon leur attractivité) → next des variables (valeurs du tour suivant) → score, classement| Brique | Section | Rôle |
|---|---|---|
| Constantes | constants |
Paramètres fixes (coûts unitaires, salaires, taux) |
| Courbes | curves |
Barèmes et rendements décroissants par points |
| Variables | variables |
État reporté d’un tour à l’autre (trésorerie, stock, effectif, réputation) |
| Décisions | decisions |
Entrées des joueurs à chaque tour (ou une fois en setup) |
| Contraintes | constraints |
Vérifications pendant la saisie (erreur bloquante ou alerte) |
| Formules | formulas |
Règles de calcul du tour (chiffre d’affaires, coûts, résultat…) |
| Marché | market |
Concurrence : répartition de la demande |
| Événements | events |
Infos, chocs, dilemmes, quiz |
| Bots | bots |
Entreprises pilotées par l’ordinateur |
| Difficultés | difficulties |
Niveaux (filtrer avec levels, surcharger avec set) |
| Score | scoring |
Classement, faillite, trophées, badges |
| Rapports | reports |
Ce que voient joueurs, intervenant et écran projeté |
| Pédagogie | pedagogy |
Objectifs, glossaire, conseils, enseignements de fin, notes animateur |
Portée (scope) : company (défaut, une valeur par entreprise) ou world (une valeur pour tout le marché : météo, prix des matières, taille du marché). Listes (lists) : une grandeur "per": "produit" a une valeur par produit.
3. Structure du fichier (champs autorisés)
Section intitulée « 3. Structure du fichier (champs autorisés) »LocalizedText = une chaîne simple (dans la langue de meta.language) ou { "fr": "…", "en": "…" }. Les textes longs acceptent du Markdown simple et des gabarits {{ expression }} ou {{ expression | money }} (filtres : money, percent, integer, number, number(2)).
Champs d’affichage communs à toutes les grandeurs : label (requis), description, format (money | number | integer | percent | boolean), decimals, unit, group, icon (nom d’icône Lucide), concept (id du glossaire), visibility (private | public | facilitator | hidden), revealInDebrief, levels (ids de niveaux de difficulté).
{ "$schema": "https://stratilead.fr/schema/scenario-1.0.json", "formatVersion": "1.0", "id": "mon-scenario", "version": "1.0.0",
"meta": { "title": "…", "subtitle": "…", "summary": "≤ 200 caractères", "description": "markdown", "sector": "industrie|hotellerie|restauration|transport|commerce|services|tech|agriculture|sante|finance|energie|culture|autre", "tags": ["…"], "language": "fr", "languages": ["fr"], "audience": "…", "estimatedDuration": { "min": 60, "max": 90 }, "authors": [{ "name": "…" }], "license": "CC-BY-4.0", "cover": "cleAsset" },
"settings": { "currency": "EUR", "roundLabel": { "singular": "mois", "plural": "mois" }, "companyLabel": { "singular": "hôtel", "plural": "hôtels" }, "rounds": { "default": 8, "min": 4, "max": 12 }, "practiceRound": true, "marketModes": ["shared", "parallel"], // le premier est le défaut "playModes": ["teams", "individual"], "sharedModeLuck": "independent", // ou "identical" "limits": { "maxPlayers": 256, "maxCompanies": 16, "teamSize": { "min": 1, "max": 5 } }, "decisionTime": { "default": 300, "min": 120, "max": 1200 } // secondes },
"theme": { "primaryColor": "#2563EB", "accentColor": "#F59E0B", "background": "cleAsset", "logo": "cleAsset", "companyAvatars": ["cleAsset"] }, "assets": { "cover": { "alt": "description précise de l'image attendue" } },
"groups": [ { "id": "commercial", "label": "Commercial", "icon": "megaphone", "description": "…" } ], "roles": [ { "id": "pdg", "label": "PDG", "groups": ["strategie"], "captain": true }, { "id": "daf", "label": "DAF", "groups": ["finance"] } ],
"lists": { "produit": { "label": "Produits", "items": [ { "id": "a", "label": "…", "description": "…", "image": "cleAsset" } ] } },
"constants": [ { "id": "coutUnitaire", "label": "…", "value": 12, "format": "money" }, { "id": "coutParProduit", "label": "…", "per": "produit", "value": { "a": 10, "b": 15 } }, // "*" = autres éléments { "id": "tresorerieInitiale", "label": "…", "value": 100000, "format": "money", "adjustable": { "min": 50000, "max": 300000, "step": 10000 } } ],
"curves": { "maCourbe": { "label": "…", "points": [[0, 0], [100, 1]], "interpolation": "linear|step|smooth", "extrapolation": "clamp|linear" } },
"variables": [ { "id": "tresorerie", "label": "Trésorerie", "format": "money", "initial": "tresorerieInitiale", "next": "tresorerie + fluxTresorerie" }, { "id": "reputation", "label": "…", "initial": 50, "next": "reputation + 0.5 * (cible - reputation)", "min": 0, "max": 100, "visibility": "public" }, { "id": "prixMatiere", "label": "…", "scope": "world", "initial": 1, "next": "prixMatiere + 0.3 * (1 - prixMatiere) + normal(0, 0.04)", "min": 0.5, "max": 2 } ],
"decisions": [ { "id": "prix", "label": "…", "type": "money", "per": "produit", "min": 1, "max": 50, "step": 0.5, "initial": { "a": 10, "b": 15 }, "default": "previous", "group": "commercial", "widget": "input", "help": "Explique l'arbitrage", "visibility": "public", "preview": ["margeUnitaire"] }, { "id": "embauches", "label": "…", "type": "integer", "min": 0, "max": 10, "initial": 0, "default": 0 }, { "id": "licenciements", "label": "…", "type": "integer", "min": 0, "max": "employes", "default": 0 }, { "id": "fournisseur", "label": "…", "type": "choice", "initial": "local", "default": "previous", "widget": "cards", "levels": ["normal"], "auto": "'local'", "options": [ { "id": "local", "label": "…", "description": "…", "props": { "facteurCout": 1, "facteurQualite": 0.8 } }, { "id": "import", "label": "…", "props": { "facteurCout": 0.8, "facteurQualite": 0.6 }, "enabledIf": "round >= 2" } ] }, { "id": "options", "label": "…", "type": "multiChoice", "minSelected": 0, "maxSelected": 2, "initial": [], "options": [ … ] }, { "id": "canaux", "label": "…", "type": "allocation", "format": "percent", "total": 1, "allocationMode": "exact", "options": [ { "id": "web", "label": "Web" }, { "id": "presse", "label": "Presse" } ], "initial": { "web": 0.5, "presse": 0.5 } }, { "id": "positionnement", "label": "…", "phase": "setup", "type": "choice", "initial": "milieu", "options": [ … ] }, { "id": "ouvert", "label": "…", "type": "boolean", "labels": { "true": "Ouvert", "false": "Fermé" }, "initial": true } ],
"constraints": [ { "id": "c1", "check": "investissement <= max(0, tresorerie) + emprunt", "message": "…{{ … }}…", "severity": "error|warning", "group": "finance" } ],
"formulas": [ { "id": "ca", "label": "Chiffre d'affaires", "per": "produit", "expr": "ventes * prix", "format": "money", "description": "…" }, { "id": "caTotal", "label": "…", "expr": "sum(ca)", "format": "money" }, { "id": "tailleMarche", "label": "…", "scope": "world", "per": "produit", "expr": "demandeBase * saisonnalite" } ],
"market": { "segments": [ { "id": "clients", "label": "…", "per": "produit", "size": "tailleMarche * if(mode == 'shared', companyCount * 1.2, 4.2)", // portée monde "attractiveness": "pow(prixReference / prix, elasticite) * pow(qualite / 60, 1.2)", // portée entreprise, ≥ 0 "supply": "stock + production", // portée entreprise ; absent = illimité "outsideOption": "0.2 * if(mode == 'shared', companyCount, 1)", // portée monde "spillover": 0.5, "integerUnits": true, "virtualCompetitors": [ { "id": "concurrents", "label": "…", "modes": ["parallel"], "attractiveness": "3" } ], "outputs": { "demand": "demande", "sales": "ventes", "share": { "id": "partDeMarche", "label": "Part de marché", "format": "percent", "visibility": "public" }, "lost": "ventesPerdues" } } ] },
"events": [ { "id": "choc", "type": "effect", "scope": "world", "tone": "negative", "title": "…", "text": "…", "image": "cleAsset", "trigger": { "type": "random", "probability": 0.15, "from": 2 }, "maxOccurrences": 1, "cooldown": 0, "effects": [ { "target": "coutUnitaire", "op": "multiply", "value": 1.3, "duration": 2 } ], "teaching": "La leçon", "concept": "…", "levels": ["normal"] }, { "id": "panne", "type": "effect", "scope": "company", "select": { "type": "each" }, "trigger": { "type": "random", "probability": "clamp(0.3 - prev(maintenance, 1, 0) / 10000, 0.02, 0.3)", "from": 2 }, "effects": [ { "target": "capacite", "op": "multiply", "value": 0.8, "duration": 1 } ], "title": "…", "text": "…", "teaching": "…" }, { "id": "offre", "type": "dilemma", "scope": "company", "title": "…", "text": "…", "trigger": { "type": "random", "probability": 0.15, "from": 3, "when": "stock > 100" }, "options": [ { "id": "oui", "label": "…", "description": "…", "effects": [ … ], "outcomes": [ { "probability": 0.7, "text": "…", "effects": [ … ] }, { "probability": 0.3, "text": "…", "effects": [ … ] } ] }, { "id": "non", "label": "…", "description": "…" } ], "default": "non", "teaching": "…" }, { "id": "rumeur", "type": "info", "display": "news", "title": "…", "text": "…", "trigger": { "type": "scheduled", "round": 3 }, "rumor": true, "revealText": "…" }, { "id": "alerteDecouvert", "type": "info", "scope": "company", "tone": "negative", "title": "…", "text": "…{{ -tresorerie | money }}…", "trigger": { "type": "condition", "when": "tresorerie < 0", "from": 2 }, "manual": false, "teaching": "…" }, { "id": "quiz1", "type": "quiz", "title": "…", "trigger": { "type": "scheduled", "round": 2 }, "question": "…", "answers": [ { "id": "a", "label": "…", "correct": true }, { "id": "b", "label": "…" } ], "timeLimit": 30, "explanation": "…", "reward": { "threshold": 0.5, "effects": [ { "target": "produitsExceptionnels", "op": "add", "value": 2000, "duration": 1 } ] } }, { "id": "aide", "type": "effect", "trigger": { "type": "manual" }, "title": "…", "text": "…", "effects": [ … ] } ],
"bots": { "default": 2, "max": 6, "profiles": [ { "id": "prudent", "name": "Nom d'entreprise", "description": "…", "noise": 0.05, "helpers": { "cibleVentes": "prev(ventes, 1, demandeBase) * 1.05" }, "decisions": { "prix": "prixReference * 1.05", "production": "max(0, cibleVentes - stock)", "fournisseur": "'local'" }, "dilemmas": { "offre": "'non'" } } ] },
"difficulties": { "default": "normal", "levels": [ { "id": "facile", "label": "Découverte", "description": "…", "set": { "constants.tresorerieInitiale.value": 200000, "events.choc.trigger.probability": 0.05, "settings.rounds.default": 6, "bots.default": 1 } }, { "id": "normal", "label": "Normal" } ] },
"scoring": { "score": "cumul(resultatNet)", "label": "Bénéfice cumulé", "format": "money", "order": "desc", "tiebreak": ["tresorerie"], "showDuringGame": true, "bankruptcy": { "when": "tresorerie < -50000", "action": "rescue|continue|eliminate", "message": "…", "effects": [ … ], "maxRescues": 2 }, "awards": [ { "id": "qualite", "label": "…", "icon": "gem", "by": "qualite", "order": "desc" } ], "objectives": [ { "id": "b1", "label": "…", "description": "…", "icon": "…", "check": "cumul(ventesPerdues) == 0" } ] },
"reports": { "dashboard": { "kpis": ["tresorerie", "resultatNet", "caTotal"] }, "pages": [ { "id": "resultat", "label": "…", "icon": "…", "widgets": [ { "type": "statement", "title": "…", "period": "rounds", "rows": [ { "ref": "caTotal", "style": "total" }, { "ref": "couts", "sign": -1 }, { "label": "…", "expr": "a + b", "sign": -1 }, { "ref": "resultatNet", "style": "total" } ] }, { "type": "kpi", "refs": ["…"] }, { "type": "chart", "chart": "line|bar|area|pie|stackedBar", "title": "…", "series": ["…"], "compare": "rounds|companies", "items": ["a"] }, { "type": "table", "title": "…", "compare": "rounds|companies|items", "columns": ["…"], "items": ["a"] }, { "type": "text", "text": "markdown" } ] } ], "facilitator": { "columns": ["…"] }, "screen": { "kpis": ["…"], "charts": [ { "chart": "bar", "compare": "companies", "series": ["…"] } ] } },
"pedagogy": { "learningObjectives": ["…"], "briefing": "markdown + {{ }}", "concepts": [ { "id": "marge", "term": "Marge", "definition": "…", "formula": "prix − coût" } ], "tips": [ { "round": 1, "text": "…" }, { "when": "prev(ventesPerdues, 1, 0) > 10", "text": "…" } ], "insights": [ { "id": "i1", "when": "cumul(ventesPerdues) > 100", "tone": "warning|positive|neutral", "text": "…{{ }}…" } ], "debriefQuestions": ["…"], "facilitatorNotes": "markdown : déroulé, repères chiffrés, erreurs fréquentes" }}Les commentaires // ci-dessus sont des explications : il ne faut pas les reproduire dans le JSON.
Précisions indispensables
Section intitulée « Précisions indispensables »Décisions — types : number, integer, money, percent (ratio), boolean, choice, multiChoice, allocation. Widgets : slider, input, stepper, toggle, cards, select, radio, checkboxes, allocation. min/max/step : nombre ou expression. default : "previous" (défaut, reprend la valeur précédente) ou une valeur ; mettre 0 pour les flux ponctuels (embauches, investissements). auto : expression utilisée quand la décision n’est pas proposée (niveau de difficulté, enabledIf faux). Pour un choice, initial/default sont des ids d’options sans apostrophes ; dans auto et les bots, ce sont des expressions avec apostrophes ("'local'").
Lecture des options : fournisseur == 'local' ; fournisseur.facteurCout (propriété de l’option choisie) ; has(options, idOption) ; count(options) ; options.cout (somme sur les options cochées) ; canaux.web (montant alloué).
Effets d’événements : target = variable, constante ou formule (jamais une décision ni une sortie de marché). Sur une variable : changement ponctuel et définitif, sans duration. Sur une constante ou formule : modificateur temporaire avec duration (défaut 1, ou "permanent") et delay. op : add, multiply, set. items pour cibler certains éléments d’une liste. Pour qu’un coût ou un gain ponctuel apparaisse dans le compte de résultat, créer des formules chargesExceptionnelles et produitsExceptionnels valant "0", et les modifier avec add + "duration": 1.
Déclencheurs : scheduled (round ou rounds), random (probability, from, to, when), condition (when, probability), manual (seulement à la main par l’intervenant). Tout événement peut aussi être déclenché à la main sauf si "manual": false. maxOccurrences et cooldown limitent les répétitions.
Portée des événements : scope: "world" (défaut) = un seul tirage, l’événement concerne tout le marché et ses effets sur des grandeurs d’entreprise touchent toutes les entreprises ; un dilemme world est posé à chaque entreprise, qui choisit pour elle-même. scope: "company" = l’événement vise des entreprises précises selon select : each (défaut : chaque entreprise fait son propre tirage avec probability/when), random (count entreprises au hasard), top/bottom (by, count). Un modificateur créé par un événement company ou par l’option d’un dilemme ne s’applique qu’à l’entreprise concernée, même s’il cible une constante (celle-ci prend alors une valeur différente pour cette entreprise).
Fonctions d’événements : active(id) → booléen (un modificateur de cet événement est actif pour moi ce tour) ; occurred(id) → nombre de déclenchements subis depuis le début ; dilemma(id) → texte, id de l’option choisie ce tour ('' sinon).
Variables : une variable sans next garde sa valeur (elle ne change que par les événements). Les tirages random()/normal() sont faits par entreprise, par élément de liste (dans une grandeur per) et par appel ; en marché parallèle toutes les entreprises reçoivent les mêmes tirages, en marché partagé ils sont indépendants (ou identiques si settings.sharedModeLuck vaut "identical").
Bots : helpers = expressions intermédiaires du bot ; les décisions sont évaluées dans l’ordre d’écriture et peuvent lire celles déjà calculées ; une décision de setup peut y figurer (constantes seulement). Un déclencheur condition se déclenche à chaque tour où la condition est vraie (sauf maxOccurrences/cooldown). Le briefing est rendu au tour 1 (au lobby, avec les valeurs initial des décisions de setup).
Tour d’essai (settings.practiceRound) : le tour 1 est joué une fois « pour voir » (seuls les événements programmés au tour 1 ont lieu), puis tout est remis à l’état initial.
Faillite : continue (signalée), rescue (effets puis on continue, maxRescues fois), eliminate. En classe, préférer rescue ou continue.
Visibilité dans les rapports : un widget "compare": "companies" ne peut afficher que des grandeurs public (ou de portée world).
4. Langage de formules (résumé)
Section intitulée « 4. Langage de formules (résumé) »4.1 Syntaxe
Section intitulée « 4.1 Syntaxe »+ - * / % ^, comparaisons == != < <= > >=, logique and or not (ou && || !), condition c ? a : b. Nombres avec point décimal (0.15, 150_000). Textes entre apostrophes. Division par zéro = 0. Pas de conversion implicite booléen → nombre : utiliser num(condition).
4.2 Fonctions
Section intitulée « 4.2 Fonctions »| Famille | Fonctions |
|---|---|
| Maths | abs, min(a,b,…), max(a,b,…), clamp(x,bas,haut), round(x,d), floor, ceil, sqrt, pow(x,y), exp, ln, log10, sign, safeDiv(a,b,repli), normalCdf(x,moy,ecart), normalLoss(x,moy,ecart) (dépassement attendu au-delà de x : refus d’embarquement, ruptures) |
| Logique | if(c,a,b), switch(v, k1,r1, k2,r2, …, défaut), between(x,bas,haut), num(b) |
| Listes | sum(v), avg(v), min(v), max(v), count(v), countIf(v), argmax(v), argmin(v) ; indice prix[idElement] ; item = élément courant |
| Concurrence | market_sum(x), market_avg(x), market_min(x), market_max(x), market_count(), share(x), rank(x), rank_asc(x) |
| Temps | prev(e, n=1, défaut), cumul(e), avgLast(e, n), minLast(e, n), maxLast(e, n), stdevLast(e, n), growth(e) |
| Hasard | random(), uniform(a,b), randomInt(a,b), normal(moy, écart), chance(p) |
| Divers | curve(idCourbe, x), active(idEvt), occurred(idEvt), dilemma(idDilemme) |
Grandeurs intégrées : round (1 au premier tour), rounds, isLastRound, isPractice, mode ('shared'/'parallel'), difficulty, companyCount (1 en parallèle), isBot, leaderboardRank, item.
Précisions : round seul = numéro du tour, round(x, d) = arrondi (d facultatif, défaut 0). number(d) est un filtre de gabarit avec d décimales (number(1), number(2)). avgLast(e, n) moyenne sur les tours disponibles s’il y en a moins de n.
4.3 Listes
Section intitulée « 4.3 Listes »Dans une grandeur "per": "produit", prix = le prix du produit en cours. Ailleurs, prix est un vecteur à agréger : sum(ventes * prix). prix[b] = prix du produit b. ventes[*] = le vecteur complet même dans une grandeur de la même liste : ventes / max(1, sum(ventes[*])). Dans une agrégation, min(a, b), if(c, a, b) etc. s’appliquent élément par élément. Les bornes min/max et auto d’une décision per sont évaluées pour chaque élément.
4.4 Moments d’évaluation (source d’erreurs n° 1)
Section intitulée « 4.4 Moments d’évaluation (source d’erreurs n° 1) »| Moment | Où | Peut utiliser |
|---|---|---|
| Création | initial des variables |
constantes, décisions setup, grandeurs intégrées |
| Annonce (début de tour) | déclencheurs (probability, when, select.by), enabledIf, auto, tips.when, décisions des bots, value des effets d’un événement effect, gabarits {{ }} des textes d’événements, des help, du briefing et des conseils |
constantes, variables, setup, intégrées, prev(…), formules qui ne dépendent ni des décisions du tour ni du marché ni du hasard |
| Saisie | min/max/step, constraints (et leurs message), preview |
+ décisions du tour et formules qui en dépendent, sans marché ni hasard |
| Résolution | expr, next, marché, effets de dilemmes et quiz |
tout ; variables = valeur de début de tour |
| Clôture | score, tiebreak, bankruptcy |
tout ; variables = valeur de fin de tour |
| Fin de partie | insights, awards.by, objectives.check |
comme la clôture, avec cumul/prev |
Le hasard est interdit dans les contraintes, aperçus, bornes, enabledIf, déclencheurs, score, textes et enseignements. Pour un résultat du tour précédent à l’annonce : prev(resultatNet).
5. Recettes de modélisation
Section intitulée « 5. Recettes de modélisation »| Besoin | Modèle |
|---|---|
| Ventes limitées au stock | bloc market avec supply, ou min(stock + production, demande) |
| Stock | variable stock, next: "max(0, stock + production - ventes)" |
| Produit périssable | invendus perdus : pas de variable de stock, supply = production du tour |
| Capacité | min(machines * capaciteParMachine, effectif * productivite) |
| Effet retardé | next d’une variable, ou prev(x) |
| Rendement décroissant | ln(1 + budget / echelle) ou une curve |
| Réputation/qualité qui évolue lentement | next: "x + 0.5 * (cible - x)" |
| Notoriété qui s’érode | next: "notoriete + gain - erosion" avec min: 0, max: 100 |
| Saisonnalité | formule monde switch(round % 4, …) ou curve sur round |
| Prix de marché qui varie | variable monde avec retour à la moyenne + normal() |
| Investissement durable | décision ponctuelle (default: 0) + variable cumulée (next: "x + achat") |
| Amortissement | valeurInvestie / dureeAmortissement en charge, sans sortie de trésorerie |
| Emprunt | variable emprunt, décisions nouvelEmprunt/remboursement, intérêts emprunt * taux / 4 |
| Découvert | if(tresorerie < 0, -tresorerie * tauxDecouvert, 0) |
| Impôt | max(0, resultatAvantImpot) * tauxImpot |
| Surbooking | Dans le bloc market, supply = capacite * (1 + tauxSurbooking) pour accepter des réservations au-delà de la capacité ; puis presents = ventes * (1 - tauxDefection) (défection = annulations et no-shows, avec une part aléatoire), refoules = max(0, presents - capacite), servis = min(presents, capacite), indemnisation × refoules et perte de réputation. Comme un tour agrège toute une période, séparer les nuits (ou vols) de pointe, où la demande dépasse la capacité, des nuits ordinaires : deux segments de marché avec des supply distincts. Sans cette séparation, le surbooking n’a d’effet que si la demande totale de la période dépasse la capacité |
| Plusieurs segments de marché | Ils sont indépendants (pas de report entre eux, pas de capacité partagée) : découper la supply entre segments |
| Coût ou gain ponctuel d’un événement | formules chargesExceptionnelles/produitsExceptionnels = "0", modifiées par add + duration: 1 |
Trésorerie ≠ résultat. Le flux de trésorerie compte les achats de la production (y compris stockée), les investissements, les emprunts et remboursements ; le résultat compte le coût des produits vendus, les amortissements et les dépréciations. Les deux doivent être calculés.
6. Méthode de calibrage (obligatoire)
Section intitulée « 6. Méthode de calibrage (obligatoire) »- Fixez une entreprise de référence au tour 1 : volumes, prix, effectif, capacité. Écrivez son compte de résultat cible, adapté au secteur. Repères : industrie — coûts variables 35–50 %, personnel 20–30 %, autres charges 10–20 % ; services et hôtellerie — coûts variables 20–30 %, personnel 35–45 %, frais fixes 15–25 % ; commerce — achats 60–70 %, personnel 10–20 %. Dans tous les cas, résultat net 5–12 % au tour de référence. Écartez-vous de ces repères si le secteur l’exige, en le justifiant dans les notes.
- Déduisez les constantes de ces cibles (coût unitaire, salaire, frais fixes).
- Marché qui marche dans les deux modes :
- normaliser l’attractivité pour qu’elle vaille ≈ 1 au prix de référence et à la qualité de départ ;
outsideOption = k × (mode partagé ? companyCount : 1)avec k ≈ 0,2 ;- en parallèle, un concurrent virtuel d’attractivité V ≈ 3 ;
size = demandeParEntreprise × (mode partagé ? companyCount × (1 + k) : 1 + V + k): ainsi, au prix de référence, chaque entreprise vend ≈demandeParEntreprisedans les deux modes.
- Élasticité : 1,5 (produit différencié, luxe) à 3,5 (produit banalisé). Vérifiez, au tour de référence, dans le mode de marché par défaut et sans changer l’effectif, qu’une baisse de prix de 10 % n’est pas rentable à coup sûr, et qu’une hausse de 10 % ne l’est pas non plus. Si le résultat dépend de la saison ou de la saturation de la capacité, c’est normal : dites-le dans les notes de l’animateur, c’est une leçon du jeu.
- Capacité : de départ proche de la demande (10 à 20 % de marge), avec une demande qui croît pour obliger à investir ou recruter.
- Trésorerie de départ : environ 1 tour de charges totales (personnel compris), soit 2 à 4 tours de frais fixes hors personnel. Seuil de faillite : entre −0,25 tour de chiffre d’affaires (sévère, usine-ram) et −1 tour (clément) ; en classe, préférez
rescueàeliminate. - Événements : l’impact d’un choc ne dépasse pas 30 à 50 % du résultat d’un tour ; probabilités de 0,08 à 0,2 ;
maxOccurrences: 1pour les gros chocs. - Faites le calcul complet d’un tour avec ces chiffres et notez-le dans
facilitatorNotes(« Repères chiffrés »). Si vous pouvez exécuter du code, écrivez un petit simulateur des formules pour vérifier ; sinon, détaillez le calcul poste par poste. L’outilstratilead validate/stratilead benchfera ensuite la vérification réelle. - Chemins autorisés dans
difficulties.set:constants.X.value,variables.X.initial|min|max,decisions.X.min|max|step|initial|default|auto,formulas.X.expr|visibility,events.X.trigger.probability|trigger.from|maxOccurrences|manual,market.segments.X.spillover|outsideOption,settings.rounds.default|min|max,settings.decisionTime.default,bots.default,bots.profiles.X.decisions.Y,bots.profiles.X.noise,scoring.bankruptcy.when.
7. Qualité pédagogique et ludique
Section intitulée « 7. Qualité pédagogique et ludique »- Chaque décision a une
helpqui explique l’arbitrage (« plus de X, mais moins de Y »). - Chaque formule affichée a une
descriptionen une phrase. - Chaque événement a un
teaching(la leçon à retenir). - 3 à 6
learningObjectives, 5 à 15conceptsreliés parconcept. - 4 à 8
insightsde fin de partie (positifs et négatifs) avec des chiffres via{{ }}. - Au moins un dilemme et un quiz ; des chocs positifs et négatifs.
- Un choix de
setupfondateur (positionnement) rend chaque équipe différente. - Des décisions simples en mode facile (les autres en
levels: ["normal", …]+auto). - Des trophées (
awards) variés : tout le monde ne gagne pas sur le profit. - 3 profils de bots aux stratégies contrastées (prudent, agressif, innovant).
8. Erreurs fréquentes à éviter
Section intitulée « 8. Erreurs fréquentes à éviter »| Erreur | Correction |
|---|---|
"value": "15%" ou 15 pour 15 % |
0.15 |
fournisseur == local |
fournisseur == 'local' |
"initial": "'local'" sur une décision choice |
"initial": "local" |
| Formule qui utilise le marché dans une contrainte ou un aperçu | Contraintes uniquement sur des grandeurs connues avant le marché |
Déclencheur qui lit resultatNet |
prev(resultatNet) |
Effet avec duration sur une variable |
Retirer duration, ou viser une formule |
| Formule A dépend de B qui dépend de A | Passer par une variable ou prev |
sum(ventes) dans une formule per la même liste quand on voulait le produit courant |
Écrire ventes |
| Ventes non limitées par le stock | supply du marché, ou min() |
| Marché parallèle sans concurrent virtuel | Ajouter un virtualCompetitors avec "modes": ["parallel"] |
Tableau compare: "companies" avec une grandeur privée |
"visibility": "public" sur la grandeur, ou changer de widget |
| Coût ponctuel appliqué directement sur la trésorerie | Formule chargesExceptionnelles pour qu’il apparaisse dans le compte de résultat |
9. Liste de contrôle finale
Section intitulée « 9. Liste de contrôle finale »- JSON strict,
formatVersion: "1.0", aucun champ inventé - Tous les identifiants utilisés sont déclarés ; aucun doublon
- Pourcentages en ratio
- Compte de résultat (
resultatNet) et flux de trésorerie (fluxTresorerie) calculés ;tresorerie.nextutilise le flux - Marché valable dans chaque mode de
marketModes - Moments d’évaluation respectés (contraintes, déclencheurs, bots)
-
scoredéfini ; faillite définie - Au moins : 1 dilemme, 1 quiz, 3 événements aléatoires, 1 événement manuel
-
helpsur toutes les décisions,descriptionsur les formules affichées,teachingsur les événements - Rapports : tableau de bord, compte de résultat, trésorerie, marché
-
facilitatorNotesavec le calcul d’un tour de référence