Architecture

Roue du hasard intelligente

Moteur de suggestion WheelSuggestionEngine, progression par familles et fenêtre de difficulté (delta).

Roue du hasard intelligente

La page /roue-du-hasard appelle GET /api/users/random-trick. Ce endpoint ne tire pas un trick au hasard dans tout le catalogue : il s'appuie sur le service WheelSuggestionEngine (back/src/Service/WheelSuggestionEngine.php) pour proposer un combo (ou parfois un grab) adapté au profil du rider.

Principe

  1. Construire le profil rider à partir des combos déjà maîtrisés (UserComboRepository::aggregateBySubFamilyForUser).
  2. Déterminer les familles actives selon une progression linéaire wake.
  3. Choisir une subFamily en mode continuation (70 %) ou exploration (30 %).
  4. Filtrer les combos par fenêtre de difficulté (delta).
  5. Tirer un combo parmi les candidats avec une pondération favorisant les difficultés plus basses.
  6. Exclure les combos déjà maîtrisés globalement ou validés sur le défi mensuel en cours.

Progression des familles

Ordre de déblocage (slugs de catégories) :

flat → kicker → jib → air-trick

Une famille suivante n'est accessible que si la précédente atteint 30 % de couverture (UNLOCK_THRESHOLD) : part des combos accessibles déjà validés par le rider dans cette famille.

Un combo est considéré accessible si sa difficulté est inférieure ou égale à :

  • maxDifficulty du rider dans la famille + DIFFICULTY_DELTA (1,5), ou
  • BEGINNER_DIFFICULTY_CAP (3,0) si le rider n'a encore rien validé dans cette famille.

Fenêtre de difficulté (delta)

Constante principale : DIFFICULTY_DELTA = 1.5.

ModeFenêtre de difficulté
Continuation (subFamily déjà pratiquée)[maxDifficulty - 0,5 ; maxDifficulty + 1,5]
Exploration (nouvelle subFamily)[0 ; 3,0]

Si aucun combo ne correspond, le moteur élargit progressivement la recherche :

TentativeComportement
1Fenêtre standard (delta 1,5)
2Delta doublé (× 2)
3SubFamily sans filtre de difficulté
4Tout combo des familles actives
5Fallback : combo aléatoire non exclu (findRandomUnvalidatedCombo)

Continuation vs exploration

Quand les deux pools existent, 70 % de chance (CONTINUATION_WEIGHT) de rester sur une subFamily déjà connue, 30 % de proposer une subFamily jamais touchée dans les familles actives.

Exclusions

Ne sont jamais reproposés :

  • les combos marqués comme maîtrisés (UserCombo) ;
  • les combos déjà frappés sur la période mensuelle courante (monthly-YYYY-MM, via UserPeriodCombo).

Grabs sur la roue

L'endpoint random-trick peut aussi renvoyer un grab (type: "grab") lorsque :

  • la famille kicker est débloquée (isKickerUnlocked) ;
  • il reste au moins un grab non enregistré par le rider.

Si un combo suggéré et un grab éligible existent tous les deux, le type renvoyé est tiré aléatoirement entre combo et grab.

Réponse API

GET /api/users/random-trick renvoie un objet normalisé avec un champ type :

typeContenu
comboCombo suggéré (groups: combo:index) + métadonnées catégorie / KoC
grabGrab suggéré (groups: grab:index)

Codes HTTP :

CodeCas
200Suggestion trouvée
404Aucun combo ni grab disponible
401 / 404Non connecté ou utilisateur introuvable

Ancien endpoint

GET /api/users/random-unvalidated-combo existe encore : tirage aléatoire simple hors moteur intelligent (exclusions globales + mensuelles uniquement). La roue du hasard front utilise /api/users/random-trick.

Fichiers concernés

FichierRôle
back/src/Service/WheelSuggestionEngine.phpLogique de suggestion
back/src/Controller/UserController.phpEndpoint randomTrick
front/pages/roue-du-hasard.vueUI roue + validation
back/tests/Unit/Service/WheelSuggestionEngineTest.phpTests unitaires du moteur