Salut!
J'essaye d'écrire un solveur pour le jeu du solitaire en Haskell.
Vous savez, ce jeu ou des billes sont disposées en croix sur un plateau, le but étant de manger toutes les billes pour n'en avoir plus qu'une à la fin, si possible au milieu du plateau...
Je rencontre quelques problèmes de design, j'aimerais que vous me donniez votre avis!

Il me faut décrire le plateau, les coups possibles et l'arbre des jeux:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 
--les emplacements: bille, trou ou interdit
data Emplacement = B | T | I  deriving Eq
 
--le plateau 
data Plateau = Plateau { deconsPlat :: [[Emplacement]]}
 
--les coups possibles
newtype Coup = Coup { coup :: ([[Emplacement]], [[Emplacement]])}
newtype ListeCoups = ListeCoups { coups :: [Coup]}
 
--l'arbre des jeux
data Tree = Null | Node Plateau [Tree]
	deriving Eq
 
-- list of legal moves
coupsLegaux = ListeCoups [ Coup ([[B, B, T]], [[T, T, B]]),
			   Coup ([[T, B, B]], [[B, T, T]]),
                           Coup ([[B], [B], [T]], [[T], [T], [B]]),
                           Coup ([[T], [B], [B]], [[B], [T], [T]])]
 
--the initial board
initial = Plateau [[I, I, B, B, B, I, I],
                      [I, I, B, B, B, I, I],
                      [B, B, B, B, B, B, B],
                      [B, B, B, T, B, B, B],
                      [B, B, B, B, B, B, B],
                      [I, I, B, B, B, I, I],
                      [I, I, B, B, B, I, I]]
Ensuite, j'essaye de trouver tous les coups jouables à partir d'une position donnée.
Je souhaite écrire:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
listePlat :: Plateau -> Coup -> [Plateau]
qui me donne tous les plateaux possibles à partir d'un plateau et d'un coup donné.

Cette recherche ressemble au problème classique du rechercher/remplacer d'une sous-chaine dans une chaine...
J'ai donc écrit:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
--recherche la première occurence de "find" dans "s" et la remplace par "repl"
--si trouvé, retourne le résultat et le reste (pour application itérative)
replReste :: Eq a => [a] -> [a] -> [a] -> Maybe ([a], [a])
replReste _ _ [] = Nothing
replReste [] _ s = Just (s, [])
replReste find repl s =
    if take (length find) s == find
	 --si on trouve, on effectue le remplacement et on renvoie le reste
        then Just (repl ++ (drop (length find) s), drop (length find) s) 
	 --sinon on appelle récursivement en accumulant les caractères
        else case replReste find repl (tail s) of 
		Nothing -> Nothing
		Just (a, b) -> Just ([head s] ++ a, b)
 
--recherche les occurences de "find" dans "s" et les remplaces par "repl"
--retourne la liste des chaines résultats (un remplacement à chaque fois).
repls :: Eq a => [a] -> [a] -> [a] -> [[a]]
repls rech rempl s = unfoldr (compl . (replReste rech rempl))  s
   where compl Nothing = Nothing 
       -- on est obligé de compléter le début des chaines car sinon elles commencent par les caractères remplacés
      compl (Just (a,b)) = Just (take ((length s) - ((length a) + (length rech) -(length rempl))) s ++ a, b)
Ces deux fonctions me parraissent bien compliquées pour le résultat... Mais je n'ai pas trouvé plus simple après beaucoup beaucoup de grattage de tête!! D'autres idées?



Ensuite je voudrais écrire la fonction:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
listePlat :: Plateau -> Coup -> [Plateau]
Mais je bloque!
Il faudrais appliquer "repls" à chaque lignes du plateau et tout reconstituer... Je ne trouve pas de solution élégante.