Skip to content
FrançaisCreate a game

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).

  1. Ouvrez une conversation avec l’IA.
  2. 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.
  3. Copiez le prompt ci-dessous, complétez la partie « Mon scénario », envoyez.
  4. Importez le JSON obtenu dans l’éditeur Stratilead (ou lancez stratilead validate fichier.json).
  5. 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.
  6. Lancez le banc d’essai (bouton « Tester l’équilibre » ou stratilead bench fichier.json) et recollez les alertes B8xx à l’IA de la même façon.
  7. 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.


Tu es concepteur de jeux sérieux et expert en gestion d'entreprise. Tu écris des scénarios pour
Stratilead, un jeu web de simulation d'entreprise joué en classe par tours, dans le format JSON
dé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. Le fichier est un JSON strict : pas de commentaires, pas de virgule finale, guillemets doubles.
  2. "formatVersion": "1.0", "version": "1.0.0", id en minuscules avec tirets (boulangerie-quartier).
  3. Aucun champ inventé. Seuls les champs listés dans ce kit (ou dans la référence complète) existent.
  4. Identifiants en camelCase ASCII sans accents (coutMatiere, prixVente), uniques entre constantes, variables, décisions, formules et sorties de marché.
  5. Les pourcentages sont des ratios : 0.15 = 15 %, partout (constantes, bornes de décisions, formules).
  6. 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'.
  7. Toute grandeur utilisée dans une expression est déclarée quelque part.
  8. 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(...).
  9. Les formules doivent rester robustes avec des décisions absurdes (prix minimal, production nulle…) : utiliser min, max, safeDiv, clamp.
  10. Une décision per une liste a une valeur par élément : "initial": { "a": 10, "b": 20 }.
  11. score classe au profit cumulé par défaut (ex. cumul(resultatNet)).

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.


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.

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).


+ - * / % ^, 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).

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.

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).


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.


  1. 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.
  2. Déduisez les constantes de ces cibles (coût unitaire, salaire, frais fixes).
  3. 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 ≈ demandeParEntreprise dans les deux modes.
  4. É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.
  5. Capacité : de départ proche de la demande (10 à 20 % de marge), avec une demande qui croît pour obliger à investir ou recruter.
  6. 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.
  7. É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: 1 pour les gros chocs.
  8. 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’outil stratilead validate / stratilead bench fera ensuite la vérification réelle.
  9. 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.

  • Chaque décision a une help qui explique l’arbitrage (« plus de X, mais moins de Y »).
  • Chaque formule affichée a une description en une phrase.
  • Chaque événement a un teaching (la leçon à retenir).
  • 3 à 6 learningObjectives, 5 à 15 concepts reliés par concept.
  • 4 à 8 insights de 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 setup fondateur (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).

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

  • 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.next utilise le flux
  • Marché valable dans chaque mode de marketModes
  • Moments d’évaluation respectés (contraintes, déclencheurs, bots)
  • score défini ; faillite définie
  • Au moins : 1 dilemme, 1 quiz, 3 événements aléatoires, 1 événement manuel
  • help sur toutes les décisions, description sur les formules affichées, teaching sur les événements
  • Rapports : tableau de bord, compte de résultat, trésorerie, marché
  • facilitatorNotes avec le calcul d’un tour de référence