mirror of
https://github.com/deunix-educ/aventuriers-des-mots.git
synced 2026-10-13 02:11:58 +02:00
Never repeat an exercise within a mission; remove near-duplicate sentences (0.5.5)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -70,6 +70,21 @@ func pick_exercise_for_mission(
|
|||||||
return picked if picked != null else {}
|
return picked if picked != null else {}
|
||||||
|
|
||||||
|
|
||||||
|
## Comme pick_exercise_for_mission, mais ne redonne jamais un exercice deja vu
|
||||||
|
## pendant la mission tant qu'il en reste un autre (un enfant ne doit pas voir
|
||||||
|
## deux fois la meme phrase dans une meme mission).
|
||||||
|
func pick_unseen_exercise_for_mission(
|
||||||
|
mission: Dictionary, seen_ids: Array[String], difficulty: int
|
||||||
|
) -> Dictionary:
|
||||||
|
var candidates: Array[Dictionary] = _candidates_for(
|
||||||
|
mission["rule_id"], mission["exercise_type"]
|
||||||
|
)
|
||||||
|
var picked: Variant = ExercisePicker.pick_unseen(
|
||||||
|
_filter_by_difficulty(candidates, difficulty), candidates, seen_ids, _rng
|
||||||
|
)
|
||||||
|
return picked if picked != null else {}
|
||||||
|
|
||||||
|
|
||||||
## Ne garde que les candidats a la difficulte demandee ; si aucun ne la
|
## Ne garde que les candidats a la difficulte demandee ; si aucun ne la
|
||||||
## propose, retombe sur l'ensemble des candidats plutot que de n'en donner
|
## propose, retombe sur l'ensemble des candidats plutot que de n'en donner
|
||||||
## aucun (le contenu disponible est encore limite, voir docs/specs/decisions.md).
|
## aucun (le contenu disponible est encore limite, voir docs/specs/decisions.md).
|
||||||
|
|||||||
@@ -8,18 +8,30 @@
|
|||||||
"type": "sentence_correction",
|
"type": "sentence_correction",
|
||||||
"instruction": "Touche le mot qui contient une erreur, puis corrige-le.",
|
"instruction": "Touche le mot qui contient une erreur, puis corrige-le.",
|
||||||
"tokens": [
|
"tokens": [
|
||||||
{ "text": "Les", "correct": true },
|
{
|
||||||
|
"text": "Les",
|
||||||
|
"correct": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"text": "petit",
|
"text": "petit",
|
||||||
"correct": false,
|
"correct": false,
|
||||||
"expected": "petits",
|
"expected": "petits",
|
||||||
"rule_id": "regle_accord_adjectif"
|
"rule_id": "regle_accord_adjectif"
|
||||||
},
|
},
|
||||||
{ "text": "chiens", "correct": true },
|
{
|
||||||
{ "text": "courent.", "correct": true }
|
"text": "canards",
|
||||||
|
"correct": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "nagent.",
|
||||||
|
"correct": true
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"hint": "Le déterminant « les » indique un pluriel.",
|
"hint": "Le déterminant « les » indique un pluriel.",
|
||||||
"explanation": "L'adjectif « petit » s'accorde avec le nom « chiens », qui est au pluriel : il faut écrire « petits ».",
|
"explanation": "L'adjectif « petit » s'accorde avec le nom « canards », qui est au pluriel : il faut écrire « petits ».",
|
||||||
"review_tags": ["pluriel", "accord_adjectif"],
|
"review_tags": [
|
||||||
|
"pluriel",
|
||||||
|
"accord_adjectif"
|
||||||
|
],
|
||||||
"review_status": "draft"
|
"review_status": "draft"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,18 @@
|
|||||||
"difficulty": 1,
|
"difficulty": 1,
|
||||||
"type": "multiple_choice",
|
"type": "multiple_choice",
|
||||||
"instruction": "Choisis le bon groupe de mots.",
|
"instruction": "Choisis le bon groupe de mots.",
|
||||||
"question": "Les ... chiens jouent.",
|
"question": "Les ... singes mangent.",
|
||||||
"answers": ["petit", "petits", "petite"],
|
"answers": [
|
||||||
|
"petit",
|
||||||
|
"petits",
|
||||||
|
"petite"
|
||||||
|
],
|
||||||
"correct_answer": 1,
|
"correct_answer": 1,
|
||||||
"hint": "Observe le déterminant « les » et le nom « chiens ».",
|
"hint": "Observe le déterminant « les » et le nom « singes ».",
|
||||||
"explanation": "Le groupe nominal est au pluriel. L'adjectif prend ici la marque du pluriel.",
|
"explanation": "Le groupe nominal est au pluriel. L'adjectif prend ici la marque du pluriel.",
|
||||||
"review_tags": ["pluriel", "accord_adjectif"],
|
"review_tags": [
|
||||||
|
"pluriel",
|
||||||
|
"accord_adjectif"
|
||||||
|
],
|
||||||
"review_status": "draft"
|
"review_status": "draft"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,19 @@
|
|||||||
"difficulty": 1,
|
"difficulty": 1,
|
||||||
"type": "multiple_choice",
|
"type": "multiple_choice",
|
||||||
"instruction": "Choisis le bon groupe de mots.",
|
"instruction": "Choisis le bon groupe de mots.",
|
||||||
"question": "Les ... fleurs sentent bon.",
|
"question": "Les ... roses sentent bon.",
|
||||||
"answers": ["joli", "jolie", "jolies"],
|
"answers": [
|
||||||
|
"joli",
|
||||||
|
"jolie",
|
||||||
|
"jolies"
|
||||||
|
],
|
||||||
"correct_answer": 2,
|
"correct_answer": 2,
|
||||||
"hint": "Observe le déterminant « les » et le nom « fleurs ».",
|
"hint": "Observe le déterminant « les » et le nom « roses ».",
|
||||||
"explanation": "Le nom « fleurs » est féminin pluriel. L'adjectif prend la marque du féminin et du pluriel : « jolies ».",
|
"explanation": "Le nom « roses » est féminin pluriel. L'adjectif prend la marque du féminin et du pluriel : « jolies ».",
|
||||||
"review_tags": ["genre", "pluriel", "accord_adjectif"],
|
"review_tags": [
|
||||||
|
"genre",
|
||||||
|
"pluriel",
|
||||||
|
"accord_adjectif"
|
||||||
|
],
|
||||||
"review_status": "draft"
|
"review_status": "draft"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,17 @@
|
|||||||
"difficulty": 2,
|
"difficulty": 2,
|
||||||
"type": "multiple_choice",
|
"type": "multiple_choice",
|
||||||
"instruction": "Choisis le bon groupe de mots.",
|
"instruction": "Choisis le bon groupe de mots.",
|
||||||
"question": "Le chat est ... .",
|
"question": "Le mouton est ... .",
|
||||||
"answers": ["petit", "petits", "petite"],
|
"answers": [
|
||||||
|
"petit",
|
||||||
|
"petits",
|
||||||
|
"petite"
|
||||||
|
],
|
||||||
"correct_answer": 0,
|
"correct_answer": 0,
|
||||||
"hint": "Le nom « chat » est masculin singulier.",
|
"hint": "Le nom « mouton » est masculin singulier.",
|
||||||
"explanation": "Au masculin singulier, l'adjectif ne prend ni « s » ni « e » : on écrit « petit ».",
|
"explanation": "Au masculin singulier, l'adjectif ne prend ni « s » ni « e » : on écrit « petit ».",
|
||||||
"review_tags": ["accord_adjectif"],
|
"review_tags": [
|
||||||
|
"accord_adjectif"
|
||||||
|
],
|
||||||
"review_status": "draft"
|
"review_status": "draft"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,18 @@
|
|||||||
"difficulty": 2,
|
"difficulty": 2,
|
||||||
"type": "multiple_choice",
|
"type": "multiple_choice",
|
||||||
"instruction": "Choisis le bon groupe de mots.",
|
"instruction": "Choisis le bon groupe de mots.",
|
||||||
"question": "La robe est ... .",
|
"question": "La jupe est ... .",
|
||||||
"answers": ["joli", "jolie", "jolis"],
|
"answers": [
|
||||||
|
"joli",
|
||||||
|
"jolie",
|
||||||
|
"jolis"
|
||||||
|
],
|
||||||
"correct_answer": 1,
|
"correct_answer": 1,
|
||||||
"hint": "Le nom « robe » est féminin singulier.",
|
"hint": "Le nom « jupe » est féminin singulier.",
|
||||||
"explanation": "Le nom « robe » est féminin singulier. L'adjectif prend la marque du féminin : « jolie ».",
|
"explanation": "Le nom « jupe » est féminin singulier. L'adjectif prend la marque du féminin : « jolie ».",
|
||||||
"review_tags": ["genre", "accord_adjectif"],
|
"review_tags": [
|
||||||
|
"genre",
|
||||||
|
"accord_adjectif"
|
||||||
|
],
|
||||||
"review_status": "draft"
|
"review_status": "draft"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,12 +14,24 @@
|
|||||||
"expected": "La",
|
"expected": "La",
|
||||||
"rule_id": "regle_accord_determinant"
|
"rule_id": "regle_accord_determinant"
|
||||||
},
|
},
|
||||||
{ "text": "fleur", "correct": true },
|
{
|
||||||
{ "text": "est", "correct": true },
|
"text": "tulipe",
|
||||||
{ "text": "jolie.", "correct": true }
|
"correct": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "est",
|
||||||
|
"correct": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "jaune.",
|
||||||
|
"correct": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"hint": "Le nom « tulipe » est féminin.",
|
||||||
|
"explanation": "« Tulipe » est un nom féminin : il faut le déterminant féminin « La ».",
|
||||||
|
"review_tags": [
|
||||||
|
"genre",
|
||||||
|
"accord_determinant"
|
||||||
],
|
],
|
||||||
"hint": "Le nom « fleur » est féminin.",
|
|
||||||
"explanation": "« Fleur » est un nom féminin : il faut le déterminant féminin « La ».",
|
|
||||||
"review_tags": ["genre", "accord_determinant"],
|
|
||||||
"review_status": "draft"
|
"review_status": "draft"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,17 @@
|
|||||||
"difficulty": 1,
|
"difficulty": 1,
|
||||||
"type": "multiple_choice",
|
"type": "multiple_choice",
|
||||||
"instruction": "Choisis le bon déterminant.",
|
"instruction": "Choisis le bon déterminant.",
|
||||||
"question": "... fleurs sentent bon.",
|
"question": "... pommes sentent bon.",
|
||||||
"answers": ["La", "Les"],
|
"answers": [
|
||||||
|
"La",
|
||||||
|
"Les"
|
||||||
|
],
|
||||||
"correct_answer": 1,
|
"correct_answer": 1,
|
||||||
"hint": "Le nom « fleurs » est au pluriel.",
|
"hint": "Le nom « pommes » est au pluriel.",
|
||||||
"explanation": "« Fleurs » est au pluriel : il faut le déterminant pluriel « Les ».",
|
"explanation": "« Pommes » est au pluriel : il faut le déterminant pluriel « Les ».",
|
||||||
"review_tags": ["pluriel", "accord_determinant"],
|
"review_tags": [
|
||||||
|
"pluriel",
|
||||||
|
"accord_determinant"
|
||||||
|
],
|
||||||
"review_status": "draft"
|
"review_status": "draft"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,17 @@
|
|||||||
"difficulty": 3,
|
"difficulty": 3,
|
||||||
"type": "multiple_choice",
|
"type": "multiple_choice",
|
||||||
"instruction": "Choisis le bon déterminant.",
|
"instruction": "Choisis le bon déterminant.",
|
||||||
"question": "... maison est grande.",
|
"question": "... cabane est grande.",
|
||||||
"answers": ["Le", "La"],
|
"answers": [
|
||||||
|
"Le",
|
||||||
|
"La"
|
||||||
|
],
|
||||||
"correct_answer": 1,
|
"correct_answer": 1,
|
||||||
"hint": "« Maison » se termine par un -n, mais écoute bien son genre.",
|
"hint": "Dis « une » ou « un » devant « cabane » pour trouver son genre.",
|
||||||
"explanation": "« Maison » est un nom féminin : il faut le déterminant féminin « La ».",
|
"explanation": "« Cabane » est un nom féminin : il faut le déterminant féminin « La ».",
|
||||||
"review_tags": ["genre", "accord_determinant"],
|
"review_tags": [
|
||||||
|
"genre",
|
||||||
|
"accord_determinant"
|
||||||
|
],
|
||||||
"review_status": "draft"
|
"review_status": "draft"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,20 +8,38 @@
|
|||||||
"type": "sentence_correction",
|
"type": "sentence_correction",
|
||||||
"instruction": "Touche le mot qui contient une erreur, puis corrige-le.",
|
"instruction": "Touche le mot qui contient une erreur, puis corrige-le.",
|
||||||
"tokens": [
|
"tokens": [
|
||||||
{ "text": "Les", "correct": true },
|
|
||||||
{
|
{
|
||||||
"text": "chat",
|
"text": "Les",
|
||||||
|
"correct": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "lapin",
|
||||||
"correct": false,
|
"correct": false,
|
||||||
"expected": "chats",
|
"expected": "lapins",
|
||||||
"rule_id": "regle_pluriel_nom"
|
"rule_id": "regle_pluriel_nom"
|
||||||
},
|
},
|
||||||
{ "text": "dorment", "correct": true },
|
{
|
||||||
{ "text": "dans", "correct": true },
|
"text": "mangent",
|
||||||
{ "text": "le", "correct": true },
|
"correct": true
|
||||||
{ "text": "jardin.", "correct": true }
|
},
|
||||||
|
{
|
||||||
|
"text": "dans",
|
||||||
|
"correct": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "le",
|
||||||
|
"correct": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "pré.",
|
||||||
|
"correct": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"hint": "Le déterminant « les » indique plusieurs lapins.",
|
||||||
|
"explanation": "Le nom « lapin » doit prendre la marque du pluriel, un -s, car il est annoncé par « les » : il faut écrire « lapins ».",
|
||||||
|
"review_tags": [
|
||||||
|
"pluriel",
|
||||||
|
"pluriel_nom"
|
||||||
],
|
],
|
||||||
"hint": "Le déterminant « les » indique plusieurs chats.",
|
|
||||||
"explanation": "Le nom « chat » doit prendre la marque du pluriel, un -s, car il est annoncé par « les » : il faut écrire « chats ».",
|
|
||||||
"review_tags": ["pluriel", "pluriel_nom"],
|
|
||||||
"review_status": "draft"
|
"review_status": "draft"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,21 +8,42 @@
|
|||||||
"type": "sentence_correction",
|
"type": "sentence_correction",
|
||||||
"instruction": "Touche le mot qui contient une erreur, puis corrige-le.",
|
"instruction": "Touche le mot qui contient une erreur, puis corrige-le.",
|
||||||
"tokens": [
|
"tokens": [
|
||||||
{ "text": "Les", "correct": true },
|
|
||||||
{ "text": "petits", "correct": true },
|
|
||||||
{
|
{
|
||||||
"text": "chat",
|
"text": "Les",
|
||||||
|
"correct": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "gros",
|
||||||
|
"correct": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "poisson",
|
||||||
"correct": false,
|
"correct": false,
|
||||||
"expected": "chats",
|
"expected": "poissons",
|
||||||
"rule_id": "regle_pluriel_nom"
|
"rule_id": "regle_pluriel_nom"
|
||||||
},
|
},
|
||||||
{ "text": "jouent", "correct": true },
|
{
|
||||||
{ "text": "dans", "correct": true },
|
"text": "nagent",
|
||||||
{ "text": "le", "correct": true },
|
"correct": true
|
||||||
{ "text": "jardin.", "correct": true }
|
},
|
||||||
|
{
|
||||||
|
"text": "dans",
|
||||||
|
"correct": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "la",
|
||||||
|
"correct": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "mare.",
|
||||||
|
"correct": true
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"hint": "Cherche le déterminant, même si un autre mot s'intercale avant le nom.",
|
"hint": "Cherche le déterminant, même si un autre mot s'intercale avant le nom.",
|
||||||
"explanation": "« Les » indique le pluriel, même si l'adjectif « petits » s'intercale avant le nom : il faut écrire « chats ».",
|
"explanation": "« Les » indique le pluriel, même si l'adjectif « gros » s'intercale avant le nom : il faut écrire « poissons ».",
|
||||||
"review_tags": ["pluriel", "pluriel_nom"],
|
"review_tags": [
|
||||||
|
"pluriel",
|
||||||
|
"pluriel_nom"
|
||||||
|
],
|
||||||
"review_status": "draft"
|
"review_status": "draft"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,17 @@
|
|||||||
"difficulty": 3,
|
"difficulty": 3,
|
||||||
"type": "multiple_choice",
|
"type": "multiple_choice",
|
||||||
"instruction": "Choisis le bon mot.",
|
"instruction": "Choisis le bon mot.",
|
||||||
"question": "Les petits ... courent vite.",
|
"question": "Les grands ... volent haut.",
|
||||||
"answers": ["chien", "chiens"],
|
"answers": [
|
||||||
|
"oiseau",
|
||||||
|
"oiseaux"
|
||||||
|
],
|
||||||
"correct_answer": 1,
|
"correct_answer": 1,
|
||||||
"hint": "Cherche le déterminant, même si un autre mot s'intercale avant le nom.",
|
"hint": "Cherche le déterminant, même si un autre mot s'intercale avant le nom.",
|
||||||
"explanation": "« Les » indique le pluriel, même si l'adjectif « petits » s'intercale avant le nom : il faut écrire « chiens ».",
|
"explanation": "« Les » indique le pluriel, même si l'adjectif « grands » s'intercale avant le nom : il faut écrire « oiseaux ».",
|
||||||
"review_tags": ["pluriel", "pluriel_nom"],
|
"review_tags": [
|
||||||
|
"pluriel",
|
||||||
|
"pluriel_nom"
|
||||||
|
],
|
||||||
"review_status": "draft"
|
"review_status": "draft"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
"difficulty": 1,
|
"difficulty": 1,
|
||||||
"type": "multiple_choice",
|
"type": "multiple_choice",
|
||||||
"instruction": "Choisis le bon mot.",
|
"instruction": "Choisis le bon mot.",
|
||||||
"question": "Nous allons ... la plage.",
|
"question": "Elle va ... la boulangerie.",
|
||||||
"answers": [
|
"answers": [
|
||||||
"a",
|
"a",
|
||||||
"à"
|
"à"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
"difficulty": 1,
|
"difficulty": 1,
|
||||||
"type": "multiple_choice",
|
"type": "multiple_choice",
|
||||||
"instruction": "Choisis le bon mot.",
|
"instruction": "Choisis le bon mot.",
|
||||||
"question": "Ma maison ... grande.",
|
"question": "Ma chambre ... grande.",
|
||||||
"answers": [
|
"answers": [
|
||||||
"et",
|
"et",
|
||||||
"est"
|
"est"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
"difficulty": 2,
|
"difficulty": 2,
|
||||||
"type": "multiple_choice",
|
"type": "multiple_choice",
|
||||||
"instruction": "Choisis le bon mot.",
|
"instruction": "Choisis le bon mot.",
|
||||||
"question": "Le gâteau ... sur la table.",
|
"question": "Le gâteau ... dans le four.",
|
||||||
"answers": [
|
"answers": [
|
||||||
"et",
|
"et",
|
||||||
"est"
|
"est"
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ Genere automatiquement depuis `data/` par `tools/generate_content_review.py`. Ne
|
|||||||
|
|
||||||
### Choix multiples
|
### Choix multiples
|
||||||
|
|
||||||
- **ce1_accord_adjectif_qcm_01** (difficulte 1) : Les ... chiens jouent.
|
- **ce1_accord_adjectif_qcm_01** (difficulte 1) : Les ... singes mangent.
|
||||||
- Reponses : petit, petits, petite
|
- Reponses : petit, petits, petite
|
||||||
- Reponse attendue : petits
|
- Reponse attendue : petits
|
||||||
- Indice : Observe le déterminant « les » et le nom « chiens ».
|
- Indice : Observe le déterminant « les » et le nom « singes ».
|
||||||
- Explication : Le groupe nominal est au pluriel. L'adjectif prend ici la marque du pluriel.
|
- Explication : Le groupe nominal est au pluriel. L'adjectif prend ici la marque du pluriel.
|
||||||
- Statut : draft
|
- Statut : draft
|
||||||
- **ce1_accord_adjectif_qcm_02** (difficulte 1) : La ... maison est jolie.
|
- **ce1_accord_adjectif_qcm_02** (difficulte 1) : La ... maison est jolie.
|
||||||
@@ -30,23 +30,23 @@ Genere automatiquement depuis `data/` par `tools/generate_content_review.py`. Ne
|
|||||||
- Indice : Observe le déterminant « les » et le nom « jardins ».
|
- Indice : Observe le déterminant « les » et le nom « jardins ».
|
||||||
- Explication : Le nom « jardins » est masculin pluriel. L'adjectif prend la marque du pluriel : « jolis ».
|
- Explication : Le nom « jardins » est masculin pluriel. L'adjectif prend la marque du pluriel : « jolis ».
|
||||||
- Statut : draft
|
- Statut : draft
|
||||||
- **ce1_accord_adjectif_qcm_04** (difficulte 1) : Les ... fleurs sentent bon.
|
- **ce1_accord_adjectif_qcm_04** (difficulte 1) : Les ... roses sentent bon.
|
||||||
- Reponses : joli, jolie, jolies
|
- Reponses : joli, jolie, jolies
|
||||||
- Reponse attendue : jolies
|
- Reponse attendue : jolies
|
||||||
- Indice : Observe le déterminant « les » et le nom « fleurs ».
|
- Indice : Observe le déterminant « les » et le nom « roses ».
|
||||||
- Explication : Le nom « fleurs » est féminin pluriel. L'adjectif prend la marque du féminin et du pluriel : « jolies ».
|
- Explication : Le nom « roses » est féminin pluriel. L'adjectif prend la marque du féminin et du pluriel : « jolies ».
|
||||||
- Statut : draft
|
- Statut : draft
|
||||||
- **ce1_accord_adjectif_qcm_05** (difficulte 2) : Le chat est ... .
|
- **ce1_accord_adjectif_qcm_05** (difficulte 2) : Le mouton est ... .
|
||||||
- Reponses : petit, petits, petite
|
- Reponses : petit, petits, petite
|
||||||
- Reponse attendue : petit
|
- Reponse attendue : petit
|
||||||
- Indice : Le nom « chat » est masculin singulier.
|
- Indice : Le nom « mouton » est masculin singulier.
|
||||||
- Explication : Au masculin singulier, l'adjectif ne prend ni « s » ni « e » : on écrit « petit ».
|
- Explication : Au masculin singulier, l'adjectif ne prend ni « s » ni « e » : on écrit « petit ».
|
||||||
- Statut : draft
|
- Statut : draft
|
||||||
- **ce1_accord_adjectif_qcm_06** (difficulte 2) : La robe est ... .
|
- **ce1_accord_adjectif_qcm_06** (difficulte 2) : La jupe est ... .
|
||||||
- Reponses : joli, jolie, jolis
|
- Reponses : joli, jolie, jolis
|
||||||
- Reponse attendue : jolie
|
- Reponse attendue : jolie
|
||||||
- Indice : Le nom « robe » est féminin singulier.
|
- Indice : Le nom « jupe » est féminin singulier.
|
||||||
- Explication : Le nom « robe » est féminin singulier. L'adjectif prend la marque du féminin : « jolie ».
|
- Explication : Le nom « jupe » est féminin singulier. L'adjectif prend la marque du féminin : « jolie ».
|
||||||
- Statut : draft
|
- Statut : draft
|
||||||
- **ce1_accord_adjectif_qcm_07** (difficulte 3) : Les chats de la maison sont ... .
|
- **ce1_accord_adjectif_qcm_07** (difficulte 3) : Les chats de la maison sont ... .
|
||||||
- Reponses : petit, petits, petite
|
- Reponses : petit, petits, petite
|
||||||
@@ -63,9 +63,9 @@ Genere automatiquement depuis `data/` par `tools/generate_content_review.py`. Ne
|
|||||||
|
|
||||||
### Corrections de phrase
|
### Corrections de phrase
|
||||||
|
|
||||||
- **ce1_accord_adjectif_correction_01** (difficulte 2) : Les [petit -> petits] chiens courent.
|
- **ce1_accord_adjectif_correction_01** (difficulte 2) : Les [petit -> petits] canards nagent.
|
||||||
- Indice : Le déterminant « les » indique un pluriel.
|
- Indice : Le déterminant « les » indique un pluriel.
|
||||||
- Explication : L'adjectif « petit » s'accorde avec le nom « chiens », qui est au pluriel : il faut écrire « petits ».
|
- Explication : L'adjectif « petit » s'accorde avec le nom « canards », qui est au pluriel : il faut écrire « petits ».
|
||||||
- Statut : draft
|
- Statut : draft
|
||||||
- **ce1_accord_adjectif_correction_02** (difficulte 1) : Les enfants [sage -> sages] jouent dehors.
|
- **ce1_accord_adjectif_correction_02** (difficulte 1) : Les enfants [sage -> sages] jouent dehors.
|
||||||
- Indice : Le nom « enfants » est au pluriel.
|
- Indice : Le nom « enfants » est au pluriel.
|
||||||
@@ -123,11 +123,11 @@ Genere automatiquement depuis `data/` par `tools/generate_content_review.py`. Ne
|
|||||||
- Indice : Le nom « oiseaux » est au pluriel.
|
- Indice : Le nom « oiseaux » est au pluriel.
|
||||||
- Explication : « Oiseaux » est au pluriel : il faut le déterminant pluriel « Les ».
|
- Explication : « Oiseaux » est au pluriel : il faut le déterminant pluriel « Les ».
|
||||||
- Statut : draft
|
- Statut : draft
|
||||||
- **ce1_accord_determinant_qcm_04** (difficulte 1) : ... fleurs sentent bon.
|
- **ce1_accord_determinant_qcm_04** (difficulte 1) : ... pommes sentent bon.
|
||||||
- Reponses : La, Les
|
- Reponses : La, Les
|
||||||
- Reponse attendue : Les
|
- Reponse attendue : Les
|
||||||
- Indice : Le nom « fleurs » est au pluriel.
|
- Indice : Le nom « pommes » est au pluriel.
|
||||||
- Explication : « Fleurs » est au pluriel : il faut le déterminant pluriel « Les ».
|
- Explication : « Pommes » est au pluriel : il faut le déterminant pluriel « Les ».
|
||||||
- Statut : draft
|
- Statut : draft
|
||||||
- **ce1_accord_determinant_qcm_05** (difficulte 2) : J'ai ... chat noir.
|
- **ce1_accord_determinant_qcm_05** (difficulte 2) : J'ai ... chat noir.
|
||||||
- Reponses : un, une
|
- Reponses : un, une
|
||||||
@@ -147,18 +147,18 @@ Genere automatiquement depuis `data/` par `tools/generate_content_review.py`. Ne
|
|||||||
- Indice : « Arbre » se termine par un -e, mais il est masculin.
|
- Indice : « Arbre » se termine par un -e, mais il est masculin.
|
||||||
- Explication : « Arbre » est un nom masculin, même s'il se termine par -e : il faut le déterminant masculin « Le ».
|
- Explication : « Arbre » est un nom masculin, même s'il se termine par -e : il faut le déterminant masculin « Le ».
|
||||||
- Statut : draft
|
- Statut : draft
|
||||||
- **ce1_accord_determinant_qcm_08** (difficulte 3) : ... maison est grande.
|
- **ce1_accord_determinant_qcm_08** (difficulte 3) : ... cabane est grande.
|
||||||
- Reponses : Le, La
|
- Reponses : Le, La
|
||||||
- Reponse attendue : La
|
- Reponse attendue : La
|
||||||
- Indice : « Maison » se termine par un -n, mais écoute bien son genre.
|
- Indice : Dis « une » ou « un » devant « cabane » pour trouver son genre.
|
||||||
- Explication : « Maison » est un nom féminin : il faut le déterminant féminin « La ».
|
- Explication : « Cabane » est un nom féminin : il faut le déterminant féminin « La ».
|
||||||
- Statut : draft
|
- Statut : draft
|
||||||
|
|
||||||
### Corrections de phrase
|
### Corrections de phrase
|
||||||
|
|
||||||
- **ce1_accord_determinant_correction_01** (difficulte 1) : [Le -> La] fleur est jolie.
|
- **ce1_accord_determinant_correction_01** (difficulte 1) : [Le -> La] tulipe est jaune.
|
||||||
- Indice : Le nom « fleur » est féminin.
|
- Indice : Le nom « tulipe » est féminin.
|
||||||
- Explication : « Fleur » est un nom féminin : il faut le déterminant féminin « La ».
|
- Explication : « Tulipe » est un nom féminin : il faut le déterminant féminin « La ».
|
||||||
- Statut : draft
|
- Statut : draft
|
||||||
- **ce1_accord_determinant_correction_02** (difficulte 1) : [La -> Le] chat dort sous la table.
|
- **ce1_accord_determinant_correction_02** (difficulte 1) : [La -> Le] chat dort sous la table.
|
||||||
- Indice : Le nom « chat » est masculin.
|
- Indice : Le nom « chat » est masculin.
|
||||||
@@ -204,7 +204,7 @@ Genere automatiquement depuis `data/` par `tools/generate_content_review.py`. Ne
|
|||||||
- Indice : Essaie de remplacer par « avait ».
|
- Indice : Essaie de remplacer par « avait ».
|
||||||
- Explication : « avait » convient ici : c'est le verbe avoir, on écrit « a » sans accent.
|
- Explication : « avait » convient ici : c'est le verbe avoir, on écrit « a » sans accent.
|
||||||
- Statut : draft
|
- Statut : draft
|
||||||
- **ce2_a_a_qcm_02** (difficulte 1) : Nous allons ... la plage.
|
- **ce2_a_a_qcm_02** (difficulte 1) : Elle va ... la boulangerie.
|
||||||
- Reponses : a, à
|
- Reponses : a, à
|
||||||
- Reponse attendue : à
|
- Reponse attendue : à
|
||||||
- Indice : Essaie de remplacer par « avait ».
|
- Indice : Essaie de remplacer par « avait ».
|
||||||
@@ -303,7 +303,7 @@ Genere automatiquement depuis `data/` par `tools/generate_content_review.py`. Ne
|
|||||||
- Indice : Essaie de remplacer par « était ».
|
- Indice : Essaie de remplacer par « était ».
|
||||||
- Explication : « était » ne convient pas ici, mais « et puis » convient : c'est « et », qui relie deux mots.
|
- Explication : « était » ne convient pas ici, mais « et puis » convient : c'est « et », qui relie deux mots.
|
||||||
- Statut : draft
|
- Statut : draft
|
||||||
- **ce2_et_est_qcm_03** (difficulte 1) : Ma maison ... grande.
|
- **ce2_et_est_qcm_03** (difficulte 1) : Ma chambre ... grande.
|
||||||
- Reponses : et, est
|
- Reponses : et, est
|
||||||
- Reponse attendue : est
|
- Reponse attendue : est
|
||||||
- Indice : Essaie de remplacer par « était ».
|
- Indice : Essaie de remplacer par « était ».
|
||||||
@@ -321,7 +321,7 @@ Genere automatiquement depuis `data/` par `tools/generate_content_review.py`. Ne
|
|||||||
- Indice : Essaie de remplacer par « était ».
|
- Indice : Essaie de remplacer par « était ».
|
||||||
- Explication : « était » ne convient pas ici, mais « et puis » convient : c'est « et », qui relie deux mots.
|
- Explication : « était » ne convient pas ici, mais « et puis » convient : c'est « et », qui relie deux mots.
|
||||||
- Statut : draft
|
- Statut : draft
|
||||||
- **ce2_et_est_qcm_06** (difficulte 2) : Le gâteau ... sur la table.
|
- **ce2_et_est_qcm_06** (difficulte 2) : Le gâteau ... dans le four.
|
||||||
- Reponses : et, est
|
- Reponses : et, est
|
||||||
- Reponse attendue : est
|
- Reponse attendue : est
|
||||||
- Indice : Essaie de remplacer par « était ».
|
- Indice : Essaie de remplacer par « était ».
|
||||||
@@ -606,11 +606,11 @@ Genere automatiquement depuis `data/` par `tools/generate_content_review.py`. Ne
|
|||||||
- Indice : Le déterminant « la » indique une seule porte.
|
- Indice : Le déterminant « la » indique une seule porte.
|
||||||
- Explication : « La » indique un seul objet : le nom reste au singulier, sans -s : « porte ».
|
- Explication : « La » indique un seul objet : le nom reste au singulier, sans -s : « porte ».
|
||||||
- Statut : draft
|
- Statut : draft
|
||||||
- **ce1_pluriel_nom_qcm_07** (difficulte 3) : Les petits ... courent vite.
|
- **ce1_pluriel_nom_qcm_07** (difficulte 3) : Les grands ... volent haut.
|
||||||
- Reponses : chien, chiens
|
- Reponses : oiseau, oiseaux
|
||||||
- Reponse attendue : chiens
|
- Reponse attendue : oiseaux
|
||||||
- Indice : Cherche le déterminant, même si un autre mot s'intercale avant le nom.
|
- Indice : Cherche le déterminant, même si un autre mot s'intercale avant le nom.
|
||||||
- Explication : « Les » indique le pluriel, même si l'adjectif « petits » s'intercale avant le nom : il faut écrire « chiens ».
|
- Explication : « Les » indique le pluriel, même si l'adjectif « grands » s'intercale avant le nom : il faut écrire « oiseaux ».
|
||||||
- Statut : draft
|
- Statut : draft
|
||||||
- **ce1_pluriel_nom_qcm_08** (difficulte 3) : Les belles ... brillent dans le ciel.
|
- **ce1_pluriel_nom_qcm_08** (difficulte 3) : Les belles ... brillent dans le ciel.
|
||||||
- Reponses : étoile, étoiles
|
- Reponses : étoile, étoiles
|
||||||
@@ -621,9 +621,9 @@ Genere automatiquement depuis `data/` par `tools/generate_content_review.py`. Ne
|
|||||||
|
|
||||||
### Corrections de phrase
|
### Corrections de phrase
|
||||||
|
|
||||||
- **ce1_pluriel_nom_correction_01** (difficulte 1) : Les [chat -> chats] dorment dans le jardin.
|
- **ce1_pluriel_nom_correction_01** (difficulte 1) : Les [lapin -> lapins] mangent dans le pré.
|
||||||
- Indice : Le déterminant « les » indique plusieurs chats.
|
- Indice : Le déterminant « les » indique plusieurs lapins.
|
||||||
- Explication : Le nom « chat » doit prendre la marque du pluriel, un -s, car il est annoncé par « les » : il faut écrire « chats ».
|
- Explication : Le nom « lapin » doit prendre la marque du pluriel, un -s, car il est annoncé par « les » : il faut écrire « lapins ».
|
||||||
- Statut : draft
|
- Statut : draft
|
||||||
- **ce1_pluriel_nom_correction_02** (difficulte 1) : Des [pomme -> pommes] sont dans le panier.
|
- **ce1_pluriel_nom_correction_02** (difficulte 1) : Des [pomme -> pommes] sont dans le panier.
|
||||||
- Indice : Le déterminant « des » indique plusieurs pommes.
|
- Indice : Le déterminant « des » indique plusieurs pommes.
|
||||||
@@ -633,9 +633,9 @@ Genere automatiquement depuis `data/` par `tools/generate_content_review.py`. Ne
|
|||||||
- Indice : Le déterminant « le » indique un seul chien.
|
- Indice : Le déterminant « le » indique un seul chien.
|
||||||
- Explication : « Le » indique un seul animal : le nom reste au singulier, sans -s : « chien ».
|
- Explication : « Le » indique un seul animal : le nom reste au singulier, sans -s : « chien ».
|
||||||
- Statut : draft
|
- Statut : draft
|
||||||
- **ce1_pluriel_nom_correction_04** (difficulte 3) : Les petits [chat -> chats] jouent dans le jardin.
|
- **ce1_pluriel_nom_correction_04** (difficulte 3) : Les gros [poisson -> poissons] nagent dans la mare.
|
||||||
- Indice : Cherche le déterminant, même si un autre mot s'intercale avant le nom.
|
- Indice : Cherche le déterminant, même si un autre mot s'intercale avant le nom.
|
||||||
- Explication : « Les » indique le pluriel, même si l'adjectif « petits » s'intercale avant le nom : il faut écrire « chats ».
|
- Explication : « Les » indique le pluriel, même si l'adjectif « gros » s'intercale avant le nom : il faut écrire « poissons ».
|
||||||
- Statut : draft
|
- Statut : draft
|
||||||
|
|
||||||
### Dictees
|
### Dictees
|
||||||
|
|||||||
@@ -346,3 +346,11 @@ Ajouts à l'arborescence proposée :
|
|||||||
**Vérification** : copie des vrais profils de l'utilisateur dans un profil temporaire, puis parcours de chaque écran (récompense, carte, collection, espace adulte, réglages, introduction, choix de profil) et chargement de toutes les missions de leur niveau : aucune erreur de script. À retenir : tout état relu de JSON doit être converti avant d'être affecté à un tableau typé.
|
**Vérification** : copie des vrais profils de l'utilisateur dans un profil temporaire, puis parcours de chaque écran (récompense, carte, collection, espace adulte, réglages, introduction, choix de profil) et chargement de toutes les missions de leur niveau : aucune erreur de script. À retenir : tout état relu de JSON doit être converti avant d'être affecté à un tableau typé.
|
||||||
|
|
||||||
**Son (non reproduit)** : sur la machine de développement, les exports Linux (4.6.3 et 4.7.2) jouent bien la voix de la dictée par le parcours réel (flux PipeWire non coupé, niveau mesuré sur le moniteur du périphérique). Cause de l'absence de son chez l'utilisateur non identifiée ; diagnostic demandé (pilote audio, sortie par défaut, messages console).
|
**Son (non reproduit)** : sur la machine de développement, les exports Linux (4.6.3 et 4.7.2) jouent bien la voix de la dictée par le parcours réel (flux PipeWire non coupé, niveau mesuré sur le moniteur du périphérique). Cause de l'absence de son chez l'utilisateur non identifiée ; diagnostic demandé (pilote audio, sortie par défaut, messages console).
|
||||||
|
|
||||||
|
## 36. Redites : jamais deux fois le même exercice dans une mission (version 0.5.5)
|
||||||
|
|
||||||
|
**Cause du « même énoncé deux fois »** : le tirage n'excluait que le dernier exercice vu, donc une mission de 3 exercices pouvait donner A, B, A (le point 34 n'avait traité que les doublons de contenu). Le tirage exclut maintenant tous les exercices déjà vus dans la mission (`ExercisePicker.pick_unseen`, `ExerciseEngine.pick_unseen_exercise_for_mission`) : d'abord à la difficulté visée, puis toutes difficultés, et ne répète que si le contenu est épuisé. Test de non-régression sur l'hôte d'exercice (10 missions simulées).
|
||||||
|
|
||||||
|
**Phrases quasi identiques** : 14 énoncés (QCM et corrections) trop proches d'une autre phrase (ex. « Les petits chiens courent. » / « Les petits chiens jouent. » / « Les petits chiens courent vite. ») ont été remplacés par des phrases originales distinctes, indices et explications ajustés. Garde-fou permanent `tests/data/test_no_near_duplicate_sentences.gd` : deux phrases d'au moins 4 mots ne peuvent pas partager 75 % ou plus de leurs mots. Les dictées (audio déjà généré) n'ont pas été modifiées.
|
||||||
|
|
||||||
|
**Voix** : l'utilisateur confirme que la voix de synthèse (« La fleur est belle. ») fonctionne avec le build Linux.
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ config_version=5
|
|||||||
[application]
|
[application]
|
||||||
|
|
||||||
config/name="Les Aventuriers des mots"
|
config/name="Les Aventuriers des mots"
|
||||||
config/version="0.5.4"
|
config/version="0.5.5"
|
||||||
run/main_scene="res://scenes/boot/boot.tscn"
|
run/main_scene="res://scenes/boot/boot.tscn"
|
||||||
config/features=PackedStringArray("4.6", "Forward Plus")
|
config/features=PackedStringArray("4.6", "Forward Plus")
|
||||||
config/icon="res://icon.svg"
|
config/icon="res://icon.svg"
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ var _current_exercise_scene: Control = null
|
|||||||
var _current_difficulty := 1
|
var _current_difficulty := 1
|
||||||
var _attempt_number := 1
|
var _attempt_number := 1
|
||||||
var _completed_count := 0
|
var _completed_count := 0
|
||||||
var _last_exercise_id := ""
|
var _seen_exercise_ids: Array[String] = []
|
||||||
var _outcomes: Array[String] = []
|
var _outcomes: Array[String] = []
|
||||||
var _pending_outcome := ""
|
var _pending_outcome := ""
|
||||||
|
|
||||||
@@ -97,9 +97,10 @@ func _on_rule_panel_continued(rule_panel: Control) -> void:
|
|||||||
|
|
||||||
|
|
||||||
func _load_next_exercise() -> void:
|
func _load_next_exercise() -> void:
|
||||||
_current_exercise = ExerciseEngine.pick_exercise_for_mission(
|
_current_exercise = ExerciseEngine.pick_unseen_exercise_for_mission(
|
||||||
_mission, _last_exercise_id, _current_difficulty
|
_mission, _seen_exercise_ids, _current_difficulty
|
||||||
)
|
)
|
||||||
|
_seen_exercise_ids.append(_current_exercise.get("id", ""))
|
||||||
_attempt_number = 1
|
_attempt_number = 1
|
||||||
_update_progress_label()
|
_update_progress_label()
|
||||||
|
|
||||||
@@ -196,7 +197,6 @@ func _on_feedback_continued(feedback: Control, is_terminal: bool) -> void:
|
|||||||
_current_difficulty = ProgressManager.next_difficulty_for_skill(
|
_current_difficulty = ProgressManager.next_difficulty_for_skill(
|
||||||
_skill_id, _current_difficulty
|
_skill_id, _current_difficulty
|
||||||
)
|
)
|
||||||
_last_exercise_id = _current_exercise.get("id", "")
|
|
||||||
_completed_count += 1
|
_completed_count += 1
|
||||||
_outcomes.append(_pending_outcome)
|
_outcomes.append(_pending_outcome)
|
||||||
|
|
||||||
|
|||||||
@@ -23,3 +23,24 @@ static func pick(
|
|||||||
pool = candidates
|
pool = candidates
|
||||||
|
|
||||||
return pool[rng.randi_range(0, pool.size() - 1)]
|
return pool[rng.randi_range(0, pool.size() - 1)]
|
||||||
|
|
||||||
|
|
||||||
|
## Tire un exercice qui n'a pas encore ete vu pendant la mission : d'abord
|
||||||
|
## parmi `preferred` (la difficulte visee), puis parmi `all` si tous les
|
||||||
|
## preferes ont ete vus. Quand tout a ete vu (mission plus longue que le
|
||||||
|
## contenu disponible), retombe sur `pick` en evitant au moins le dernier vu.
|
||||||
|
static func pick_unseen(
|
||||||
|
preferred: Array[Dictionary],
|
||||||
|
all: Array[Dictionary],
|
||||||
|
seen_ids: Array[String],
|
||||||
|
rng: RandomNumberGenerator
|
||||||
|
) -> Variant:
|
||||||
|
for source in [preferred, all]:
|
||||||
|
var pool: Array[Dictionary] = []
|
||||||
|
for candidate: Dictionary in source:
|
||||||
|
if not seen_ids.has(candidate["id"]):
|
||||||
|
pool.append(candidate)
|
||||||
|
if not pool.is_empty():
|
||||||
|
return pool[rng.randi_range(0, pool.size() - 1)]
|
||||||
|
var last := "" if seen_ids.is_empty() else seen_ids[seen_ids.size() - 1]
|
||||||
|
return pick(preferred, last, rng)
|
||||||
|
|||||||
@@ -31,3 +31,25 @@ func test_returns_the_only_candidate_even_if_excluded() -> void:
|
|||||||
var candidates: Array[Dictionary] = [{"id": "a"}]
|
var candidates: Array[Dictionary] = [{"id": "a"}]
|
||||||
var picked: Dictionary = ExercisePicker.pick(candidates, "a", rng)
|
var picked: Dictionary = ExercisePicker.pick(candidates, "a", rng)
|
||||||
assert_eq(picked["id"], "a")
|
assert_eq(picked["id"], "a")
|
||||||
|
|
||||||
|
|
||||||
|
func test_pick_unseen_never_repeats_while_others_remain() -> void:
|
||||||
|
var rng := RandomNumberGenerator.new()
|
||||||
|
rng.seed = 3
|
||||||
|
var candidates: Array[Dictionary] = [{"id": "a"}, {"id": "b"}, {"id": "c"}]
|
||||||
|
var seen: Array[String] = []
|
||||||
|
for _i in range(3):
|
||||||
|
var picked: Dictionary = ExercisePicker.pick_unseen(candidates, candidates, seen, rng)
|
||||||
|
assert_false(seen.has(picked["id"]), "un exercice deja vu a ete redonne")
|
||||||
|
seen.append(picked["id"])
|
||||||
|
assert_eq(seen.size(), 3)
|
||||||
|
|
||||||
|
|
||||||
|
func test_pick_unseen_falls_back_to_other_difficulty_then_to_repeat() -> void:
|
||||||
|
var rng := RandomNumberGenerator.new()
|
||||||
|
var preferred: Array[Dictionary] = [{"id": "a"}]
|
||||||
|
var all: Array[Dictionary] = [{"id": "a"}, {"id": "b"}]
|
||||||
|
var picked: Dictionary = ExercisePicker.pick_unseen(preferred, all, ["a"], rng)
|
||||||
|
assert_eq(picked["id"], "b")
|
||||||
|
var again: Dictionary = ExercisePicker.pick_unseen(preferred, all, ["a", "b"], rng)
|
||||||
|
assert_true(["a", "b"].has(again["id"]))
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
extends GutTest
|
||||||
|
## Deux phrases qui ne different que d'un mot (« Les petits chiens courent. »
|
||||||
|
## / « Les petits chiens jouent. ») donnent a l'enfant l'impression d'une
|
||||||
|
## redite. On compare les ensembles de mots : au-dela de 75 % de mots communs
|
||||||
|
## (phrases d'au moins 4 mots), les deux phrases sont jugees trop proches.
|
||||||
|
|
||||||
|
const EXERCISES_DIR := "res://data/exercises"
|
||||||
|
const DICTATIONS_DIR := "res://data/dictations"
|
||||||
|
const MAX_SIMILARITY := 0.75
|
||||||
|
const MIN_WORDS := 4
|
||||||
|
|
||||||
|
|
||||||
|
func test_no_two_sentences_are_nearly_identical() -> void:
|
||||||
|
var entries := _collect()
|
||||||
|
var close: Array[String] = []
|
||||||
|
for i in range(entries.size()):
|
||||||
|
for j in range(i + 1, entries.size()):
|
||||||
|
var a: Array = entries[i]["words"]
|
||||||
|
var b: Array = entries[j]["words"]
|
||||||
|
if a.size() < MIN_WORDS or b.size() < MIN_WORDS:
|
||||||
|
continue
|
||||||
|
var common := 0
|
||||||
|
for word: String in a:
|
||||||
|
if b.has(word):
|
||||||
|
common += 1
|
||||||
|
var similarity := float(common) / float(maxi(a.size(), b.size()))
|
||||||
|
if similarity >= MAX_SIMILARITY:
|
||||||
|
close.append(
|
||||||
|
(
|
||||||
|
"%s « %s » ~ %s « %s »"
|
||||||
|
% [
|
||||||
|
entries[i]["id"],
|
||||||
|
entries[i]["text"],
|
||||||
|
entries[j]["id"],
|
||||||
|
entries[j]["text"]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assert_eq(close.size(), 0, "Phrases trop proches :\n%s" % "\n".join(close))
|
||||||
|
assert_gt(entries.size(), 100)
|
||||||
|
|
||||||
|
|
||||||
|
func _collect() -> Array[Dictionary]:
|
||||||
|
var entries: Array[Dictionary] = []
|
||||||
|
for path in _json_files(EXERCISES_DIR):
|
||||||
|
var data := _read(path)
|
||||||
|
var sentence := ""
|
||||||
|
if data.get("type", "") == "multiple_choice":
|
||||||
|
var answers: Array = data["answers"]
|
||||||
|
sentence = str(data["question"]).replace(
|
||||||
|
"...", str(answers[int(data["correct_answer"])])
|
||||||
|
)
|
||||||
|
elif data.get("type", "") == "sentence_correction":
|
||||||
|
var words: Array[String] = []
|
||||||
|
for token: Dictionary in data["tokens"]:
|
||||||
|
words.append(token["text"] if token["correct"] else token["expected"])
|
||||||
|
sentence = " ".join(words)
|
||||||
|
if not sentence.is_empty():
|
||||||
|
entries.append({"id": data["id"], "text": sentence, "words": _words(sentence)})
|
||||||
|
for path in _json_files(DICTATIONS_DIR):
|
||||||
|
var data := _read(path)
|
||||||
|
var text: String = data["target_text"]
|
||||||
|
entries.append({"id": data["id"], "text": text, "words": _words(text)})
|
||||||
|
return entries
|
||||||
|
|
||||||
|
|
||||||
|
## Mots distincts, en minuscules, sans ponctuation.
|
||||||
|
func _words(sentence: String) -> Array[String]:
|
||||||
|
var cleaned := ""
|
||||||
|
for character in sentence.to_lower():
|
||||||
|
if character == "'" or character == " ":
|
||||||
|
cleaned += " "
|
||||||
|
elif character.to_upper() != character or "éèêàâîïôûùçœ".contains(character):
|
||||||
|
cleaned += character
|
||||||
|
else:
|
||||||
|
cleaned += " "
|
||||||
|
var result: Array[String] = []
|
||||||
|
for word in cleaned.split(" ", false):
|
||||||
|
if not result.has(word):
|
||||||
|
result.append(word)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
func _json_files(path: String) -> Array[String]:
|
||||||
|
var found: Array[String] = []
|
||||||
|
var dir := DirAccess.open(path)
|
||||||
|
if dir == null:
|
||||||
|
return found
|
||||||
|
for sub in dir.get_directories():
|
||||||
|
found.append_array(_json_files(path.path_join(sub)))
|
||||||
|
for file_name in dir.get_files():
|
||||||
|
if file_name.ends_with(".json"):
|
||||||
|
found.append(path.path_join(file_name))
|
||||||
|
return found
|
||||||
|
|
||||||
|
|
||||||
|
func _read(path: String) -> Dictionary:
|
||||||
|
var file := FileAccess.open(path, FileAccess.READ)
|
||||||
|
var parsed: Variant = JSON.parse_string(file.get_as_text())
|
||||||
|
return parsed if typeof(parsed) == TYPE_DICTIONARY else {}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://bignj6rqf37vv
|
||||||
@@ -86,3 +86,31 @@ func test_wrong_answer_escalates_hint_then_explanation_then_reveal() -> void:
|
|||||||
var skill_state := ProgressManager.get_skill_state("accord_groupe_nominal")
|
var skill_state := ProgressManager.get_skill_state("accord_groupe_nominal")
|
||||||
assert_eq(skill_state["recent_results"], [false, false, false])
|
assert_eq(skill_state["recent_results"], [false, false, false])
|
||||||
assert_eq(skill_state["recent_hint_used"], [false, true, true])
|
assert_eq(skill_state["recent_hint_used"], [false, true, true])
|
||||||
|
|
||||||
|
|
||||||
|
func test_a_mission_never_shows_the_same_exercise_twice() -> void:
|
||||||
|
# Regression : le tirage n'excluait que le dernier exercice, donc le meme
|
||||||
|
# enonce pouvait revenir dans une meme mission (A, B, A). On s'arrete au
|
||||||
|
# troisieme exercice charge, sans le terminer (pas de changement de scene).
|
||||||
|
for _run in range(10):
|
||||||
|
var host := await _start_host()
|
||||||
|
host.get_node("%OverlayContainer").get_child(0).continued.emit()
|
||||||
|
await wait_process_frames(1)
|
||||||
|
var shown: Array[String] = []
|
||||||
|
for step in range(3):
|
||||||
|
shown.append(host.get_current_exercise()["id"])
|
||||||
|
if step == 2:
|
||||||
|
break
|
||||||
|
var scene: Control = host.get_node("%ExerciseContainer").get_child(0)
|
||||||
|
scene.answer_submitted.emit(host.get_current_exercise()["correct_answer"])
|
||||||
|
await wait_process_frames(1)
|
||||||
|
var overlay: Control = host.get_node("%OverlayContainer")
|
||||||
|
var feedback: Control = overlay.get_child(overlay.get_child_count() - 1)
|
||||||
|
feedback.get_node("%ContinueButton").pressed.emit()
|
||||||
|
await wait_process_frames(1)
|
||||||
|
var unique := {}
|
||||||
|
for exercise_id in shown:
|
||||||
|
unique[exercise_id] = true
|
||||||
|
assert_eq(unique.size(), 3, "exercices vus : %s" % [shown])
|
||||||
|
host.queue_free()
|
||||||
|
await wait_process_frames(1)
|
||||||
|
|||||||
Reference in New Issue
Block a user