« Polyominos, pavages et solveurs SAT » : différence entre les versions
Aucun résumé des modifications |
(les balise sont pas les bonnes) |
||
| (5 versions intermédiaires par le même utilisateur non affichées) | |||
| Ligne 1 : | Ligne 1 : | ||
Étudiant: MALABRE |
'''Étudiant''' : MALABRE Étienne |
||
| ⚫ | |||
| ⚫ | |||
| ⚫ | |||
| ⚫ | |||
| ⚫ | |||
| ⚫ | |||
| ⚫ | |||
| ⚫ | |||
Dans notre cas pour |
Dans notre cas, pour résoudre ce problème, nous utilisons un '''solveur SAT''' (ici, SAT13). Celui-ci prend en entrée une suite d'instructions logiques composées uniquement d’opérateurs '''ET''', '''OU''' et '''NON''', plus particulièrement sous la [https://fr.wikipedia.org/wiki/Forme_normale_conjonctive forme normale conjonctive (FNC)]. |
||
== Utilisation de SAT13 == |
== Utilisation de SAT13 == |
||
<code>SAT13</code> est un solveur qui accepte une '''formule logique en forme normale conjonctive (FNC)''', composée uniquement d'opérations '''ET''', '''OU''' et '''NON'''. Plus précisément : |
<code>SAT13</code> est un solveur qui accepte une '''formule logique en forme normale conjonctive (FNC)''', composée uniquement d'opérations '''ET''', '''OU''' et '''NON'''. Plus précisément : |
||
| Ligne 21 : | Ligne 22 : | ||
~A D |
~A D |
||
</pre> |
</pre> |
||
Cela correspond à : |
|||
<pre> |
<pre> |
||
(A ∨ B ∨ ¬C) ∧ (¬A ∨ D) |
(A ∨ B ∨ ¬C) ∧ (¬A ∨ D) |
||
| Ligne 31 : | Ligne 34 : | ||
# Une '''forme''' (ou grille) est décrite dans un fichier <code>tab.txt</code>, où les cases utilisables sont indiquées par le caractère <code>#</code>. |
# Une '''forme''' (ou grille) est décrite dans un fichier <code>tab.txt</code>, où les cases utilisables sont indiquées par le caractère <code>#</code>. |
||
# Une '''pièce''' est décrite par une liste de coordonnées relatives |
# Une '''pièce''' est décrite par une liste de coordonnées relatives, par exemple : <code>[[0,0], [0,1], [0,2], [1,2]]</code>. |
||
Nous générons alors toutes les clauses logiques qui modélisent : |
Nous générons alors toutes les clauses logiques qui modélisent : |
||
* les positions valides des pièces, |
* les positions valides des pièces, |
||
* la contrainte que chaque case soit couverte |
* la contrainte que chaque case soit couverte '''au moins une fois''', |
||
* la contrainte |
* la contrainte qu’elle ne soit couverte '''qu'une seule fois''', |
||
* l’implication logique entre une pièce placée et les cases couvertes. |
* l’implication logique entre une pièce placée et les cases couvertes. |
||
=== Lecture de la grille === |
=== Lecture de la grille === |
||
<syntaxhighlight lang="python"> |
|||
<pre> |
|||
def lecteur_tab(file: str) -> list: |
def lecteur_tab(file: str) -> list: |
||
... |
... |
||
</pre> |
|||
</syntaxhighlight> |
|||
Retourne la liste des coordonnées des cases utilisables dans la grille (les <code>#</code>). |
Retourne la liste des coordonnées des cases utilisables dans la grille (les <code>#</code>). |
||
=== Manipulation des pièces === |
=== Manipulation des pièces === |
||
* <code>trouve_origine(piece)</code> : Trouve le coin supérieur gauche de la pièce. |
* <code>trouve_origine(piece)</code> : Trouve le coin supérieur gauche de la pièce. |
||
* <code>placement_piece(origine, piece)</code> : Calcule la pièce translatée selon une origine. |
* <code>placement_piece(origine, piece)</code> : Calcule la pièce translatée selon une origine. |
||
| Ligne 55 : | Ligne 58 : | ||
=== Vérification de placements valides === |
=== Vérification de placements valides === |
||
<syntaxhighlight lang="python"> |
|||
<pre> |
|||
def verif_version(origine, pieces, tab) -> list: |
def verif_version(origine, pieces, tab) -> list: |
||
... |
... |
||
</pre> |
|||
</syntaxhighlight> |
|||
Retourne les versions valides de la pièce à une position donnée (qui restent dans la grille). |
Retourne les versions valides de la pièce à une position donnée (qui restent dans la grille). |
||
| Ligne 65 : | Ligne 69 : | ||
=== Clause de placement === |
=== Clause de placement === |
||
<syntaxhighlight lang="python"> |
|||
<pre> |
|||
def creation_clause_tab(piece, tab) -> str: |
def creation_clause_tab(piece, tab) -> str: |
||
... |
... |
||
</pre> |
|||
</syntaxhighlight> |
|||
Exemple de clause : |
Exemple de clause : |
||
<pre> |
<pre> |
||
~P0_2_1 C_3_1 |
~P0_2_1 C_3_1 |
||
</pre> |
</pre> |
||
(signifie : si la version 0 de la pièce est placée |
(signifie : si la version 0 de la pièce est placée en (2,1), alors la case (3,1) est couverte) |
||
=== Contrainte d’unicité === |
=== Contrainte d’unicité === |
||
Empêche que deux pièces différentes recouvrent la même case. |
Empêche que deux pièces différentes recouvrent la même case. |
||
<pre> |
|||
<syntaxhighlight lang="python"> |
|||
def creation_contrainte_unicite(tab, piece) -> str: |
def creation_contrainte_unicite(tab, piece) -> str: |
||
... |
... |
||
</pre> |
|||
</syntaxhighlight> |
|||
Exemple : |
Exemple : |
||
<pre> |
<pre> |
||
~P1_0_1 ~P2_1_1 |
~P1_0_1 ~P2_1_1 |
||
| Ligne 90 : | Ligne 99 : | ||
=== Contrainte de couverture === |
=== Contrainte de couverture === |
||
Impose qu’au moins une pièce couvre chaque case. |
Impose qu’au moins une pièce couvre chaque case. |
||
<pre> |
|||
<syntaxhighlight lang="python"> |
|||
def creation_contrainte_couverture(tab, piece) -> str: |
def creation_contrainte_couverture(tab, piece) -> str: |
||
... |
... |
||
</pre> |
|||
</syntaxhighlight> |
|||
Exemple : |
Exemple : |
||
<pre> |
<pre> |
||
P0_0_0 P1_1_0 |
P0_0_0 P1_1_0 |
||
| Ligne 103 : | Ligne 114 : | ||
=== Clause de couverture complète === |
=== Clause de couverture complète === |
||
<syntaxhighlight lang="python"> |
|||
<pre> |
|||
def creation_clause_complet(tab) -> str: |
def creation_clause_complet(tab) -> str: |
||
... |
... |
||
</pre> |
|||
</syntaxhighlight> |
|||
Assure que chaque case utile est bien prise en compte. |
Assure que chaque case utile est bien prise en compte. |
||
Exemple : |
Exemple : |
||
<pre> |
<pre> |
||
C_0_0 |
C_0_0 |
||
| Ligne 117 : | Ligne 130 : | ||
</pre> |
</pre> |
||
== Exemple de pièce == |
|||
Soit la pièce suivante : |
Soit la pièce suivante : |
||
<syntaxhighlight lang="python"> |
|||
<pre> |
|||
piece = [[0,0], [0,1], [0,2], [1,2]] |
piece = [[0,0], [0,1], [0,2], [1,2]] |
||
</pre> |
|||
</syntaxhighlight> |
|||
Et une grille donnée dans <code>tab.txt</code>. En exécutant : |
Et une grille donnée dans le fichier <code>tab.txt</code>. En exécutant : |
||
<syntaxhighlight lang="python"> |
|||
<pre> |
|||
tab = lecteur_tab("tab.txt") |
tab = lecteur_tab("tab.txt") |
||
generates_clauses(piece, tab) |
generates_clauses(piece, tab) |
||
</pre> |
|||
</syntaxhighlight> |
|||
| ⚫ | |||
Le code complet est disponible sur le [https://github.com/lasnelus/visi201 GitHub du projet]. |
|||
| ⚫ | |||
Dernière version du 11 mai 2025 à 21:59
Étudiant : MALABRE Étienne Chercheur : HYVERNAT Pierre
Introduction au problème
Quel que soit notre âge, nous avons tous connu des jeux basés sur des blocs ou des cases à placer : sous forme de jeux vidéo pour certains, sous forme de briques pour d'autres. Souvent, une question se pose : Puis-je remplir cette forme avec cette pièce ?
Le problème de pavage correspond précisément à cette interrogation : on nous donne un ou plusieurs types de pièces, ainsi qu’une forme (ou grille), et il s'agit de déterminer s’il est possible de remplir entièrement cette forme avec les pièces fournies.
Dans notre cas, pour résoudre ce problème, nous utilisons un solveur SAT (ici, SAT13). Celui-ci prend en entrée une suite d'instructions logiques composées uniquement d’opérateurs ET, OU et NON, plus particulièrement sous la forme normale conjonctive (FNC).
Utilisation de SAT13
SAT13 est un solveur qui accepte une formule logique en forme normale conjonctive (FNC), composée uniquement d'opérations ET, OU et NON. Plus précisément :
- Chaque ligne représente une clause (un OU logique entre plusieurs littéraux).
- L’ensemble des lignes est évalué comme un ET logique.
- Un littéral est soit une variable, soit sa négation (utilisant le symbole
~).
A B ~C ~A D
Cela correspond à :
(A ∨ B ∨ ¬C) ∧ (¬A ∨ D)
Représentation du problème
Pour représenter un problème de pavage :
- Une forme (ou grille) est décrite dans un fichier
tab.txt, où les cases utilisables sont indiquées par le caractère#. - Une pièce est décrite par une liste de coordonnées relatives, par exemple :
[[0,0], [0,1], [0,2], [1,2]].
Nous générons alors toutes les clauses logiques qui modélisent :
- les positions valides des pièces,
- la contrainte que chaque case soit couverte au moins une fois,
- la contrainte qu’elle ne soit couverte qu'une seule fois,
- l’implication logique entre une pièce placée et les cases couvertes.
Lecture de la grille
def lecteur_tab(file: str) -> list:
...
Retourne la liste des coordonnées des cases utilisables dans la grille (les #).
Manipulation des pièces
trouve_origine(piece): Trouve le coin supérieur gauche de la pièce.placement_piece(origine, piece): Calcule la pièce translatée selon une origine.version_piece(piece): Retourne les 8 versions (rotations et symétries) d’une pièce.
Vérification de placements valides
def verif_version(origine, pieces, tab) -> list:
...
Retourne les versions valides de la pièce à une position donnée (qui restent dans la grille).
Génération de clauses
Clause de placement
def creation_clause_tab(piece, tab) -> str:
...
Exemple de clause :
~P0_2_1 C_3_1
(signifie : si la version 0 de la pièce est placée en (2,1), alors la case (3,1) est couverte)
Contrainte d’unicité
Empêche que deux pièces différentes recouvrent la même case.
def creation_contrainte_unicite(tab, piece) -> str:
...
Exemple :
~P1_0_1 ~P2_1_1
Contrainte de couverture
Impose qu’au moins une pièce couvre chaque case.
def creation_contrainte_couverture(tab, piece) -> str:
...
Exemple :
P0_0_0 P1_1_0
Clause de couverture complète
def creation_clause_complet(tab) -> str:
...
Assure que chaque case utile est bien prise en compte.
Exemple :
C_0_0 C_1_0 C_2_0
Exemple de pièce
Soit la pièce suivante :
piece = [[0,0], [0,1], [0,2], [1,2]]
Et une grille donnée dans le fichier tab.txt. En exécutant :
tab = lecteur_tab("tab.txt")
generates_clauses(piece, tab)
On obtient le fichier clausepavage.txt contenant les contraintes.
Le code complet est disponible sur le GitHub du projet.