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