mirror of
https://github.com/deunix-educ/aventuriers-des-mots.git
synced 2026-10-13 02:11:58 +02:00
409d8b46c5
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
101 lines
3.8 KiB
GDScript
101 lines
3.8 KiB
GDScript
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 {}
|