Générateur de labyrinthe

Transcription

Générateur de labyrinthe
Option Informatique
Séance 10
Vendredi 2 décembre
TP : Générateur de labyrinthe
1) Génération aléatoire
1.a) Le module Random et son initialisation
Avant de créer automatiquement des labyrinthes, on va commencer par choisir des nombres
au hasard. Pour cela, on utilise le module Random, qui regroupe un certain nombre de
fonctions de génération aléatoire.
Pour commencer, utilisez la fonction Random.self_init : unit -> unit pour
initialiser votre générateur aléatoire (si vous oubliez cette étape, vous aurez tous la même
suite "aléatoire" au lancement de Caml).
1.b) Tirer un nombre entier au hasard
La fonction Random.int : int -> int permet de générer un nombre au hasard.
Selon vous, à quoi correspond l'entier passé en argument à cette fonction ?
1.c) Exercices
Ecrivez :



Une fonction d6 : unit -> int qui modélise le lancer d'un dé à 6 faces,
c'est-à-dire qui renvoie un nombre entre 1 et 6.
Une fonction pile_ou_face : unit -> string qui a une chance sur deux
de renvoyer "pile" et une change sur deux de renvoyer "face"
Une fonction semi_hasard : int -> bool telle que semi_hasard x
renvoit true dans x % des cas, et false sinon
2) Premiers labyrinthe
2.a) Structure de données utilisée
Dans cette première version, nous allons utiliser des tableaux de booléens à deux
dimensions : true si la case est vide (case accessible), et false si la case est pleine (mur):
j
v.(1).(4) = true
v.(3).(3) = false
i
Bonne nouvelle : Caml nous propose déjà la structure de données correspondante :
bool array array
1
Option Informatique
Séance 10
Vendredi 2 décembre
2.b) Premières fonctions
Pour créer un tableau à deux dimensions en Caml, le plus simple est d'utiliser la fonction
Array.make_matrix : int -> int -> 'a -> 'a array array, telle que
Array.make_matrix dimX dimY valInit renvoie un tableau de taille dimX par dimY
initialisé avec la valeur valInit.
Implémentez à partir de cette outil une fonction creer_laby_vide : int -> int ->
bool array array, qui créé un labyrinthe vide (dont toutes les cases sont vides).
Comment connaître après coup la hauteur et la largeur d'un labyrinthe ainsi généré ? Codez
les fonctions hauteur : 'a array -> int et largeur : 'a array array -> int
correspondantes
Indice : Regardez les types des fonctions en question.
2.c) Ajouter des murs
L'étape suivante consiste à ajouter des murs dans notre labyrinthe. Dans cette première
version, on va simplement tirer au hasard pour chaque case si cette case sera pleine (mur)
ou vide (case accessible).
Utilisez la fonction semi_hasard définie précédemment pour implémenter une fonction
ajouter_murs : bool array array -> int -> unit telle que ajouter_murs
lab p passe par chaque case de lab et laisse la case vide dans p% des cas (et sinon
ajoute un mur).
2.d) Affichage
De tels labyrinthes sont assez faciles à afficher : il suffit d'afficher un espace (" ") dans le
cas d'une case vide et un symbole dièse ("#") dans le cas d'un mur.
Ecrivez la fonction tracer_laby : bool array array -> unit correspondante.
Vous pouvez ensuite récupérer le fichier laby_affichage.ml disponible à l'adresse
suivante : http://andre.lovichi.free.fr/teaching/ea/2011-2012/cours/10/laby_affichage.ml, et
l'exécuter pour avoir à votre disposition la fonction tracer_laby_graphics : bool
array array -> unit qui utilise la librairie Graphics pour un affichage plus avancé.
3) Labyrinthes avancés
3.a) Nouvelle représentation
Pour construire de meilleurs labyrinthes (à la fois plus beaux et plus intéressants), on va
changer de représentation : désormais, les murs se situeront entre les cases voisines.
Plus exactement, chaque case contient deux informations :
 Est-ce qu'il y a un mur à gauche ?
 Est-ce qu'il y a un mur au-dessus ?
Selon vous, cela suffit-il pour coder un labyrinthe ?
Sinon, comment y remédier facilement ?
2
Option Informatique
Séance 10
Vendredi 2 décembre
3.b) Définition d'un nouveau type :
On va donc définir ce qu'on appelle un type enregistrement, c'est-à-dire un type composé de
différents éléments : type case = { gauche : bool ; dessus : bool };
La syntaxe pour créer un nouvel élément de type case sera alors
let x = { gauche = true ; dessus = false }
(ici, on créée une nouvelle case x avec un mur à gauche et pas de mur au-dessus).
Implémentez une fonction creer_case_vide : unit -> case qui renvoie une nouvelle
case sans mur ni à gauche, ni au-dessus.
3.c) Implémentation des labyrinthes
En vous inspirant de la première version, imaginez et écrivez les fonctions suivantes :


creer_laby_vide2 : int -> int -> case array array qui crée un
labyrinthe sans mur, dont les dimensions sont passées en argument
ajouter_murs2 : case array array -> int -> unit qui
3