This commit is contained in:
Adrien MALINGREY 2025-05-05 02:49:57 +02:00
parent 23cac370a1
commit f8bd1d35cd
5 changed files with 190 additions and 101 deletions

View File

@ -1,8 +1,10 @@
<?php <?php
include_once "dico.php"; include_once "dico.php";
const MAX_ESSAIS = 0;
class Grille implements Iterator, ArrayAccess { class Grille implements Iterator, ArrayAccess {
public $grille; public $grille;
public $hauteur; public $hauteur;
@ -22,20 +24,7 @@ class Grille implements Iterator, ArrayAccess {
$this->lignes = []; $this->lignes = [];
$this->colonnes = []; $this->colonnes = [];
$this->lettres_suivantes = []; $this->lettres_suivantes = tries(max($hauteur, $largeur));
foreach ($hauteur == $largeur ? [$hauteur] : [$hauteur, $largeur] as $longueur) {
$this->lettres_suivantes[$longueur] = [];
foreach (mots_permutes($longueur) as $mots) {
$mot = implode(" ", $mots);
$ref = &$this->lettres_suivantes[$longueur];
for ($i = 0; $i < $longueur; $i++) {
$lettre = $mot[$i];
if (!isset($ref[$lettre])) $ref[$lettre] = [];
$ref = &$ref[$lettre];
}
$ref = [];
}
}
$this->positions = []; $this->positions = [];
for ($y = 0; $y < $hauteur; $y++) { for ($y = 0; $y < $hauteur; $y++) {
@ -45,7 +34,7 @@ class Grille implements Iterator, ArrayAccess {
$this->nb_positions = count($this->positions); $this->nb_positions = count($this->positions);
mt_srand($id == "" ? null : crc32($id)); mt_srand($id == "" ? null : crc32($id));
$this->grilles = $this->generateur(); $this->grilles = $this->generateur(0);
} }
public function get_ligne($y, $largeur) public function get_ligne($y, $largeur)
@ -64,10 +53,8 @@ class Grille implements Iterator, ArrayAccess {
return $colonne; return $colonne;
} }
public function generateur($i = 0) public function generateur($i, $lettres_suivantes_ligne = NULL)
{ {
global $dico;
if ($i == $this->nb_positions) { if ($i == $this->nb_positions) {
yield $this; yield $this;
return; return;
@ -75,42 +62,45 @@ class Grille implements Iterator, ArrayAccess {
[$x, $y] = $this->positions[$i]; [$x, $y] = $this->positions[$i];
$lettres_suivantes_ligne = $this->lettres_suivantes[$this->largeur]; if ($x) {
for ($x2 = 0; $x2 < $x; $x2++) $lettres_suivantes_ligne = $lettres_suivantes_ligne->noeud[$this->grille[$y][$x-1]];
$lettres_suivantes_ligne = $lettres_suivantes_ligne[$this->grille[$y][$x2]]; } else {
$lettres_suivantes_ligne = $this->lettres_suivantes[$this->largeur];
}
$lettres_suivantes_colonne = $this->lettres_suivantes[$this->hauteur]; $lettres_suivantes_colonne = $this->lettres_suivantes[$this->hauteur];
for ($y2 = 0; $y2 < $y; $y2++) for ($y2 = 0; $y2 < $y; $y2++)
$lettres_suivantes_colonne = $lettres_suivantes_colonne[$this->grille[$y2][$x]]; $lettres_suivantes_colonne = $lettres_suivantes_colonne->noeud[$this->grille[$y2][$x]];
$lettres_communes = array_intersect_key( $lettres_communes = array_intersect(
$lettres_suivantes_ligne, array_keys($lettres_suivantes_ligne->noeud),
$lettres_suivantes_colonne array_keys($lettres_suivantes_colonne->noeud)
); );
uksort($lettres_communes, function ($a, $b) { usort($lettres_communes, function ($a, $b) {
return mt_rand(-1, 1); return mt_rand(-1, 1);
}); });
if (MAX_ESSAIS) $lettres_communes = array_slice($lettres_communes, 0, MAX_ESSAIS);
foreach ($lettres_communes as $lettre => $_) { foreach ($lettres_communes as $lettre) {
$this->grille[$y][$x] = $lettre; $this->grille[$y][$x] = $lettre;
$mots = []; $mots = [];
if ($x == $this->largeur - 1) $mots = explode(" ", $this->get_ligne($y, $this->largeur)); if ($x == $this->largeur - 1) $mots = explode(" ", $this->get_ligne($y, $this->largeur));
else if ($lettre == " ") $mots = explode(" ", $this->get_ligne($y, $x)); else if ($lettre == " ") $mots = explode(" ", $this->get_ligne($y, $x));
$mots = array_filter($mots, function($mot) { else $mots = [];
return strlen($mot) > 1; $this->lignes[$y] = array_filter($mots, function($mot) {
return strlen($mot) >= 2;
}); });
if (count($mots) >= 1) { if (count($this->lignes[$y])) {
$dernier_mot = array_pop($mots); $mot = array_pop($this->lignes[$y]);
$this->lignes[$y] = $mots; if (strlen($mot > 2) && in_array($mot, array_merge(...$this->lignes, ...$this->colonnes))) continue;
if (in_array($dernier_mot, array_merge(...$this->lignes, ...$this->colonnes))) continue; else $this->lignes[$y][] = $mot;
else $this->lignes[$y][] = $dernier_mot;
} }
if ($y == $this->hauteur - 1) { if ($y == $this->hauteur - 1) {
$mots = explode(" ", $this->get_colonne($x, $this->hauteur)); $mots = explode(" ", $this->get_colonne($x, $this->hauteur));
foreach ($mots as $rang => $mot) { foreach ($mots as $rang => $mot) {
if (strlen($mot) <= 1) continue; if (strlen($mot) < 2) continue;
if (in_array($mot, array_merge(...$this->lignes, ...$this->colonnes))) continue 2; if (strlen($mot > 2) && in_array($mot, array_merge(...$this->lignes, ...$this->colonnes))) continue 2;
else $this->colonnes[$x][$rang] = $mot; else $this->colonnes[$x][$rang] = $mot;
} }
} else { } else {
@ -118,7 +108,7 @@ class Grille implements Iterator, ArrayAccess {
} }
if ($i < $this->nb_positions) { if ($i < $this->nb_positions) {
yield from $this->generateur($i + 1); yield from $this->generateur($i + 1, $lettres_suivantes_ligne);
} else { } else {
yield $this; yield $this;
} }

106
Trie.php Normal file
View File

@ -0,0 +1,106 @@
<?php
class Trie implements ArrayAccess, Countable //, Iterator
{
public array $noeud = [];
private array $cles_en_cours = [];
private mixed $valeur_en_cours;
private $marcheur;
private $nb_branches = 0;
// ArrayAccess
public function offsetExists($cles): bool {
if (!count($cles)) {
return false;
}
$cle = array_shift($cles);
if (count($cles)) {
return $this->noeud[$cle]->offsetExists($cles);
} else {
return isset($this->noeud[$cles]);
}
}
public function offsetGet($cles): mixed {
if (!count($cles)) {
throw new \OutOfBoundsException("Liste de clés vide.");
}
$cle = array_shift($cles);
if (!isset($this->noeud[$cle])) $this->noeud[$cle] = new Trie();
if (count($cles)) {
return $this->noeud[$cle]->offsetGet($cles);
} else {
return $this->noeud[$cle];
}
}
public function offsetSet($cles, $valeur): void {
if (!count($cles)) {
throw new \OutOfBoundsException("Liste de clés vide.");
return;
}
$cle = array_shift($cles);
if (!isset($this->noeud[$cle])) $this->noeud[$cle] = new Trie();
if (count($cles)) {
$this->noeud[$cle]->offsetSet($cles, $valeur);
} else {
$this->noeud[$cle] = $valeur;
}
$this->nb_branches++;
}
public function offsetUnset($cles): void {
if ($this->offsetExists(cles)) {
$cle = array_shift($cles);
if (count($cles)) {
$this->noeud[$cle]->offsetUnset($cles);
} else {
unset($this->noeud[$cle]);
}
$this->nb_branches--;
}
}
// Countable
public function count(): int {
return $this->nb_branches;
}
/*
// Iterator
public function marcheurs(): generator {
foreach ($this->noeud as $cle => $branche) {
if ($branche instanceof Trie) {
foreach($branche as $sous_cles => $feuille) {
$this->cles_en_cours = [$cle, ...$sous_cles];
yield $feuille;
}
} else {
$this->cles_en_cours = [$cle];
yield $branche;
}
}
}
public function current(): mixed {
return $this->marcheur->current();
}
public function key(): array {
return $this->cles_en_cours;
}
public function next(): void {
$this->marcheur->next();
}
public function rewind(): void {
$this->marcheur = $this->marcheurs();
}
public function valid(): bool {
return $this->marcheur->valid();
}
*/
}

View File

@ -378,7 +378,7 @@ BECASSINE Une bonne partie du finistère Michel Laclos
BEL Un vieux beau Georges Perec BEL Un vieux beau Georges Perec
BEL Avant l'été, mais on ne peut en être sûr qu'après Pangloss BEL Avant l'été, mais on ne peut en être sûr qu'après Pangloss
BEL Ne peut jamais arriver avant le printemps, contrairement aux trois autres Pangloss BEL Ne peut jamais arriver avant le printemps, contrairement aux trois autres Pangloss
BELLE Sûrement pas la première venue, mais la dernière partie, çà c'est sûr Pangloss BELLE Sûrement pas la première venue, mais la dernière partie, ça c'est sûr ! Pangloss
BENIN Anodin sauf en afrique Jean Teularge BENIN Anodin sauf en afrique Jean Teularge
BENIOUIOUI Apparemment, il consent à se marier à l'église Jacques Drillon BENIOUIOUI Apparemment, il consent à se marier à l'église Jacques Drillon
BERET Complément populaire de la baguette Jean-Marie Lamy BERET Complément populaire de la baguette Jean-Marie Lamy

1 #MOT Définition Auteur
378 BEL Un vieux beau Georges Perec
379 BEL Avant l'été, mais on ne peut en être sûr qu'après Pangloss
380 BEL Ne peut jamais arriver avant le printemps, contrairement aux trois autres Pangloss
381 BELLE Sûrement pas la première venue, mais la dernière partie, çà c'est sûr Pangloss BELLE Sûrement pas la première venue, mais la dernière partie, ça c'est sûr ! Pangloss
382 BENIN Anodin sauf en afrique Jean Teularge
383 BENIOUIOUI Apparemment, il consent à se marier à l'église Jacques Drillon
384 BERET Complément populaire de la baguette Jean-Marie Lamy

View File

@ -1,8 +1,10 @@
<?php <?php
include_once "Trie.php";
const MIN_LETTRES_MOT_1 = 2; const MIN_PREMIER_MOT = 1;
const MIN_LETTRES_MOT_2 = 1; const MIN_MOTS_SUIVANTS = 1;
$dico = [[""]]; $dico = [[""]];
if (($lecteur = fopen("dico.csv", "r")) !== FALSE) { if (($lecteur = fopen("dico.csv", "r")) !== FALSE) {
@ -31,39 +33,21 @@ if (($lecteur = fopen("dico.csv", "r")) !== FALSE) {
fclose($lecteur); fclose($lecteur);
} }
function mots_espaces($longueur) function tries($longueur_max) {
{
global $dico; global $dico;
foreach ($dico[$longueur] as $mot => $definition) { $_tries = [[]];
yield [$mot]; for ($longueur = 1; $longueur <= $longueur_max; $longueur++) {
} $_tries[$longueur] = new Trie();
for ($i = MIN_LETTRES_MOT_1; ($j = $longueur - $i - 1) >= MIN_LETTRES_MOT_2; $i++) { foreach ($dico[$longueur] as $mot => $definition) {
foreach ($dico[$i] as $mot => $definition) { $_tries[$longueur][str_split($mot)] = [];
foreach (mots_espaces($j) as $mots) { }
if (!in_array($mot, $mots)) { for ($position_espace = MIN_PREMIER_MOT; $position_espace + MIN_MOTS_SUIVANTS < $longueur; $position_espace++) {
yield [$mot, ...$mots]; $mots_suivants = $_tries[$longueur - $position_espace - 1];
} foreach ($dico[$position_espace] as $premier_mot => $definition) {
$_tries[$longueur][str_split($premier_mot . " ")] = $mots_suivants;
} }
} }
} }
} return $_tries;
function permutations(array $elements)
{
if (count($elements) <= 1) {
yield $elements;
} else {
foreach (permutations(array_slice($elements, 1)) as $permutation) {
foreach (range(0, count($elements) - 1) as $i) {
yield [...array_slice($permutation, 0, $i), $elements[0], ...array_slice($permutation, $i)];
}
}
}
}
function mots_permutes($longueur) {
foreach (mots_espaces($longueur) as $mots) {
yield from permutations($mots);
}
} }

View File

@ -1,13 +1,21 @@
<?php <?php
if (!isset($_GET["grille"])) {
$_GET["grille"] = uniqid();
header("Location: " . dirname($_SERVER['DOCUMENT_URI']) . "?" . http_build_query($_GET));
exit;
}
include_once "dico.php"; include_once "dico.php";
include_once "Grille.php"; include_once "Grille.php";
const HAUTEUR_DEFAUT = 7; const HAUTEUR_DEFAUT = 6;
const HAUTEUR_MIN = 2; const HAUTEUR_MIN = 2;
const HAUTEUR_MAX = 10; const HAUTEUR_MAX = 10;
const LARGEUR_DEFAUT = 7; const LARGEUR_DEFAUT = 6;
const LARGEUR_MIN = 2; const LARGEUR_MIN = 2;
const LARGEUR_MAX = 10; const LARGEUR_MAX = 10;
@ -19,6 +27,7 @@ $hauteur = filter_input(INPUT_GET, 'lignes', FILTER_VALIDATE_INT, [
"max_range" => HAUTEUR_MAX "max_range" => HAUTEUR_MAX
] ]
]); ]);
$largeur = filter_input(INPUT_GET, 'colonnes', FILTER_VALIDATE_INT, [ $largeur = filter_input(INPUT_GET, 'colonnes', FILTER_VALIDATE_INT, [
"options" => [ "options" => [
"default" => LARGEUR_DEFAUT, "default" => LARGEUR_DEFAUT,
@ -27,11 +36,7 @@ $largeur = filter_input(INPUT_GET, 'colonnes', FILTER_VALIDATE_INT, [
] ]
]); ]);
if (isset($_GET["grille"])) { $id = htmlspecialchars($_GET["grille"]);
$id = htmlspecialchars($_GET["grille"]);
} else {
$id = uniqid();
}
$grille = new Grille($hauteur, $largeur, $id); $grille = new Grille($hauteur, $largeur, $id);
$grille->current(); $grille->current();
@ -44,9 +49,9 @@ if ($grille->valid()) {
} }
$definitions_horizontales = []; $definitions_horizontales = [];
foreach ($grille->lignes as $y => $mots) { for ($y = 0; $y < $hauteur; $y++) {
$definitions_horizontales[$y] = []; $definitions_horizontales[$y] = [];
foreach ($mots as $mot) { foreach ($grille->lignes[$y] as $mot) {
$definitions = $dico[strlen($mot)][$mot]; $definitions = $dico[strlen($mot)][$mot];
if (count($definitions)) { if (count($definitions)) {
$definitions_horizontales[$y][] = $definitions[mt_rand(0, count($definitions) - 1)]; $definitions_horizontales[$y][] = $definitions[mt_rand(0, count($definitions) - 1)];
@ -54,9 +59,9 @@ if ($grille->valid()) {
} }
} }
$definitions_verticales = []; $definitions_verticales = [];
foreach ($grille->colonnes as $x => $mots) { for ($x = 0 ; $x < $largeur; $x++) {
$definitions_verticales[$x] = []; $definitions_verticales[$x] = [];
foreach ($mots as $mot) { foreach ($grille->colonnes[$x] as $mot) {
$definitions = $dico[strlen($mot)][$mot]; $definitions = $dico[strlen($mot)][$mot];
if (count($definitions)) { if (count($definitions)) {
$definitions_verticales[$x][] = $definitions[mt_rand(0, count($definitions) - 1)]; $definitions_verticales[$x][] = $definitions[mt_rand(0, count($definitions) - 1)];
@ -70,7 +75,7 @@ if ($grille->valid()) {
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>MOTS CROISÉS</title> <title>⬜⬜⬜⬜⬛⬜⬜⬜⬜⬜⬜⬜</title>
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<link rel="icon" href="favicon.svg"> <link rel="icon" href="favicon.svg">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
@ -128,7 +133,7 @@ if ($grille->valid()) {
<?php else: ?> <?php else: ?>
<td class="case blanche"> <td class="case blanche">
<input id="<?= chr($x + 65) . ($y + 1) ?>" type="text" maxlength="1" size="1" pattern="[A-Z]" placeholder="<?= $grille[$y][$x] ?>" <input id="<?= chr($x + 65) . ($y + 1) ?>" type="text" maxlength="1" size="1" pattern="[A-Z]" placeholder="<?= $grille[$y][$x] ?>"
title="<?= " " . strip_tags(implode("\n→ ", $definitions_horizontales[$y])) . "\n↓ " . strip_tags(implode("\n↓ ", $definitions_verticales[$x])) ?>" /> title="<?= strip_tags(" " . implode("\n→ ", $definitions_horizontales[$y]) . "\n↓ " . implode("\n↓ ", $definitions_verticales[$x])) ?>" />
</td> </td>
<?php endif; ?> <?php endif; ?>
<?php endfor; ?> <?php endfor; ?>
@ -141,14 +146,16 @@ if ($grille->valid()) {
<ol type="1"> <ol type="1">
<?php foreach ($definitions_horizontales as $y => $definitions): ?> <?php foreach ($definitions_horizontales as $y => $definitions): ?>
<li> <li>
<?php if (count($definitions) == 1): ?> <?php if (count($definitions)): ?>
<?= $definitions[0] ?> <?php if (count($definitions) == 1): ?>
<?php else: ?> <?= $definitions[0] ?>
<ol> <?php else: ?>
<?php foreach ($definitions as $definition) : ?> <ol>
<li><?= $definition ?></li> <?php foreach ($definitions as $definition) : ?>
<?php endforeach ?> <li><?= $definition ?></li>
</ol> <?php endforeach ?>
</ol>
<?php endif ?>
<?php endif ?> <?php endif ?>
</li> </li>
<?php endforeach; ?> <?php endforeach; ?>
@ -159,14 +166,16 @@ if ($grille->valid()) {
<ol type="A"> <ol type="A">
<?php foreach ($definitions_verticales as $x => $definitions): ?> <?php foreach ($definitions_verticales as $x => $definitions): ?>
<li> <li>
<?php if (count($definitions) == 1): ?> <?php if (count($definitions)): ?>
<?= $definitions[0] ?> <?php if (count($definitions) == 1): ?>
<?php else: ?> <?= $definitions[0] ?>
<ol> <?php else: ?>
<?php foreach ($definitions as $definition) : ?> <ol>
<li><?= $definition ?></li> <?php foreach ($definitions as $definition) : ?>
<?php endforeach ?> <li><?= $definition ?></li>
</ol> <?php endforeach ?>
</ol>
<?php endif ?>
<?php endif ?> <?php endif ?>
</li> </li>
<?php endforeach; ?> <?php endforeach; ?>