program Sphinx;

// Jeu du Sphinx, programmé dans le cadre du projet d'informatique du 1er semestre.
// Auteurs : INGOUFF Christian, RODRIGUEZ Sébastien
// Date de création : 11/01/12
// Version : 13.37 (26/01/12) : Bugfixes, finalisation du principal

uses crt, sysutils;
type
	matrix = array of array of integer; // Utilisé pour les grilles de données
	matstring = array of array of string; // Affichage de la grille à l'écran
	coord = array[1..2] of integer; // Coordonnées : coord[1] = abscisses (droite à gauche), coord[2] = ordonnées (haut en bas)
	array_coord = array[1..4] of coord; // 4 valeurs coordonnées : sert pour la définition des cases adjacentes (cf. arrayDirec)


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//                                                    //    DESIGN, INTERFACE TEXTUELLE ET ASCII ART    //
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


procedure cheat();//écran titre affiché lorsque le joueur a bloqué le trésor en mode labyrinthe personnel
//RODRIGUEZ Sébastien
begin
	  TextColor(Red + Blink);
	  writeln('     TTTTTTTTTTTTTTTTTTTTTTT RRRRRRRRRRRRRRRRR    IIIIIIIIII       CCCCCCCCCCCCC HHHHHHHHH     HHHHHHHHH EEEEEEEEEEEEEEEEEEEEEE');
	  writeln('     T:::::::::::::::::::::T R::::::::::::::::R   I::::::::I    CCC::::::::::::C H:::::::H     H:::::::H E::::::::::::::::::::E');
	  writeln('     T:::::::::::::::::::::T R::::::RRRRRR:::::R  I::::::::I  CC:::::::::::::::C H:::::::H     H:::::::H E::::::::::::::::::::E');
	  writeln('     T:::::TT:::::::TT:::::T RR:::::R     R:::::R II::::::II C:::::CCCCCCCC::::C HH::::::H     H::::::HH EE::::::EEEEEEEEE::::E');
	  writeln('     TTTTTT  T:::::T  TTTTTT   R::::R     R:::::R   I::::I  C:::::C       CCCCCC   H:::::H     H:::::H     E:::::E       EEEEEE');
	  writeln('             T:::::T           R::::R     R:::::R   I::::I C:::::C                 H:::::H     H:::::H     E:::::E             ');
	  writeln('             T:::::T           R::::RRRRRR:::::R    I::::I C:::::C                 H::::::HHHHH::::::H     E::::::EEEEEEEEEE   ');
	  writeln('             T:::::T           R:::::::::::::RR     I::::I C:::::C                 H:::::::::::::::::H     E:::::::::::::::E   ');
	  writeln('             T:::::T           R::::RRRRRR:::::R    I::::I C:::::C                 H:::::::::::::::::H     E:::::::::::::::E   ');
	  writeln('             T:::::T           R::::R     R:::::R   I::::I C:::::C                 H::::::HHHHH::::::H     E::::::EEEEEEEEEE   ');
	  writeln('             T:::::T           R::::R     R:::::R   I::::I C:::::C                 H:::::H     H:::::H     E:::::E             ');
	  writeln('             T:::::T           R::::R     R:::::R   I::::I  C:::::C       CCCCCC   H:::::H     H:::::H     E:::::E       EEEEEE');
	  writeln('           TT:::::::TT       RR:::::R     R:::::R II::::::II C:::::CCCCCCCC::::C HH::::::H     H::::::HH EE::::::EEEEEEEE:::::E');
	  writeln('           T:::::::::T       R::::::R     R:::::R I::::::::I  CC:::::::::::::::C H:::::::H     H:::::::H E::::::::::::::::::::E');
	  writeln('           T:::::::::T       R::::::R     R:::::R I::::::::I    CCC::::::::::::C H:::::::H     H:::::::H E::::::::::::::::::::E');
	  writeln('           TTTTTTTTTTT       RRRRRRRR     RRRRRRR IIIIIIIIII       CCCCCCCCCCCCC HHHHHHHHH     HHHHHHHHH EEEEEEEEEEEEEEEEEEEEEE');
	  TextColor(Red);
	  LowVideo;
end;

procedure defeatScreen(); //écran titre affiché lorsque le joueur a perdu contre le bot
// RODRIGUEZ Sébastien
// Illustration pour la défaite du joueur.
begin
	  writeln('                                                                           ,--. ');
	  writeln('                                                                          {    }');
	  writeln('                                                                          K,   }');
	  writeln('                                                                         /  ~Y` ');
	  writeln('                                                                    ,   /   /   ');
	  writeln('                                                                   {_"-K.__/    ');
	  writeln('                                                                     `/-.__L._  ');
	  writeln('                                                                     /  " /`\_} ');
	  writeln('                                                                    /  " /      ');
	  writeln('                                                            ____   /  " /       ');
	  writeln('                                                     ,-"~~~~    ~~/  " /_       ');
	  writeln('                                                   ,"             ``~~~  ",     ');
	  writeln('                                                  (                        Y    ');
	  writeln('                                                 {                         I    ');
	  writeln('                                                {      -                    `,  ');
	  writeln('                                                |       ",                   )  ');
	  writeln('                                                |        |   ,..__      __. Y   ');
	  writeln('                                                |    .,_./  Y " / ^Y   J   )|   ');
	  writeln('                                                \           |" /   |   |   ||   ');
	  writeln('                                                 \          L_/    . _ (_,."(   ');
	  writeln('                                                  \,   ,      ^^""" / |      )  ');
	  writeln('                                                    \_  \          /,L]     /   ');
	  writeln('                                                      "-_~-,       ` `   ./`    ');
	  writeln('                                                         `"{_            )      ');
	  writeln('                                                             ^^\..___,.--`      ');
end;

procedure victoryScreen(); //écran titre affiché lorsque le joueur a gagné
// RODRIGUEZ Sébastien
// Illustration pour la victoire du joueur.
begin
	  writeln('                       *******************************************************************************');
	  writeln('                                |                   |                  |                     |        ');
	  writeln('                       _________|________________.=""_;=.______________|_____________________|________');
	  writeln('                       |                   |  ,-"_,=""     `"=.|                  |                   ');
	  writeln('                       |___________________|__"=._o`"-._        `"=.______________|___________________');
	  writeln('                                 |                `"=._o`"=._      _`"=._                     |       ');
	  writeln('                        _________|_____________________:=._o "=._."_.-="""=.__________________|_______');
	  writeln('                       |                   |    __.--" , ; `"=._o." ,-"""-._ ".   |                   ');
	  writeln('                       |___________________|_._"  ,. .` ` `` ,  `"-._"-._   ". "__|___________________');
	  writeln('                                 |           |o`"=._` , "` `; .". ,  "-._"-._; ;              |       ');
	  writeln('                        _________|___________| ;`-.o`"=._; ." ` "`."\` . "-._ /_______________|_______');
	  writeln('                       |                   | |o;    `"-.o`"=._``  "` " ,__.--o;   |                   ');
	  writeln('                       |___________________|_| ;     (#) `-.o `"=.`_.--"_o.-; ;___|___________________');
	  writeln('                       ____/______/______/___|o;._    "      `".o|o_.--"    ;o;____/______/______/____');
	  writeln('                       /______/______/______/_"=._o--._        ; | ;        ; ;/______/______/______/_');
	  writeln('                       ____/______/______/______/__"=._o--._   ;o|o;     _._;o;____/______/______/____');
	  writeln('                       /______/______/______/______/____"=._o._; | ;_.--"o.--"_/______/______/______/_');
	  writeln('                       ____/______/______/______/______/_____"=.o|o_.--""___/______/______/______/____');
	  writeln('                       /______/______/______/______/______/______/______/______/______/______/______/_');
	  writeln('                       *******************************************************************************');
end;

procedure titre (); // écran titre affiché au démarage du jeu et dans les menus
// RODRIGUEZ Sébastien
begin
	  writeln('             SSSSSSSSSSSSSSS                     hhhhhh                iiii                                          ');
	  writeln('           SS:::::::::::::::S                    h::::h               i::::i                                         ');
	  writeln('          S:::::SSSSSS::::::S                    h::::h                iiii                                          ');
	  writeln('          S:::::S     SSSSSSS                    h::::h                                                              ');
	  writeln('          S:::::S            ppppp   ppppppppp    h::::h hhhhh        iiiiiii nnnn  nnnnnnnn     xxxxxxx      xxxxxxx');
	  writeln('          S:::::S            p::::ppp:::::::::p   h::::hh:::::hhh     i:::::i n:::nn::::::::nn    x:::::x    x:::::x ');
	  writeln('           S::::SSSS         p:::::::::::::::::p  h::::::::::::::hh    i::::i n::::::::::::::nn    x:::::x  x:::::x  ');
	  writeln('            SS::::::SSSSS    pp::::::ppppp::::::p h:::::::hhh::::::h   i::::i nn:::::::::::::::n    x:::::xx:::::x   ');
	  writeln('              SSS::::::::SS   p:::::p     p:::::p h::::::h   h::::::h  i::::i   n:::::nnnn:::::n     x::::::::::x    ');
	  writeln('                 SSSSSS::::S  p:::::p     p:::::p h:::::h     h:::::h  i::::i   n::::n    n::::n      x::::::::x     ');
	  writeln('                      S:::::S p:::::p     p:::::p h:::::h     h:::::h  i::::i   n::::n    n::::n      x::::::::x     ');
	  writeln('                      S:::::S p:::::p    p::::::p h:::::h     h:::::h  i::::i   n::::n    n::::n     x::::::::::x    ');
	  writeln('          SSSSSSS     S:::::S p:::::ppppp:::::::p h:::::h     h:::::h i::::::i  n::::n    n::::n    x:::::xx:::::x   ');
	  writeln('          S::::::SSSSSS:::::S p::::::::::::::::p  h:::::h     h:::::h i::::::i  n::::n    n::::n   x:::::x  x:::::x  ');
	  writeln('          S:::::::::::::::SS  p::::::::::::::pp   h:::::h     h:::::h i::::::i  n::::n    n::::n  x:::::x    x:::::x ');
	  writeln('           SSSSSSSSSSSSSSS    p::::::pppppppp     hhhhhhh     hhhhhhh iiiiiiii  nnnnnn    nnnnnn xxxxxxx      xxxxxxx');
	  writeln('                              p:::::p                                                                                ');
	  writeln('                              p:::::p                                                                                ');
	  writeln('                             p:::::::p                                                                               ');
	  writeln('                             p:::::::p                                                                               ');
	  writeln('                             p:::::::p                                                                               ');
	  writeln('                             ppppppppp                                                                               ');
end;

procedure logo();// écran titre affiché au démarage du jeu
// RODRIGUEZ Sébastien
// Illustration pour l'écran titre.
begin
	  writeln('                         .sSSSSSSSs                          ___                         sSSSSSSSs.                       ');
	  writeln('                         sSS=""^^^"s                       ."///".                       s"^^^""=SSs                      ');
	  writeln('              /\       , /  \_\_\|_/_)                    /|<> <>!\                     (_/_|/_/_/  \ ,       /\          ');
	  writeln('             /";;     /| \\\/.-. .-./                    /-|  ^  !-\                     \.-. .-.\/// |\     ;;"\         ');
	  writeln('            / \;|    /. \,S"  -   - |                   /-- \_=_/ --\                    | -   -  "S,/ .\    |;/ \        ');
	  writeln('           / -.;|    | ".SS     _|  ;                   )---| W |---(                    ;  |_     SS." |    |;.- \       ');
	  writeln('          ; "-.;\,   |"-.SS\   __  /S                  /-\--| W |--/-\                   S\  __   /SS.-"|   ,/;.-" ;      ');
	  writeln('          | _  ";\\.  \" SSS\_____/SS                 (_-_--|_-_|--___)                  SS\_____/SSS "/  .//;"  _ |      ');
	  writeln('          |  "- ";\\.  \_SSS[_____]SS                (-___  -_-- _-- -_)                 SS[_____]SSS_/  .//;" -"  |      ');
	  writeln('          \ "--.-";;-. __SSS/\    SSS                )-_ _--_ _ ___--__|                 SSS    /\SSS__ .-;;"-.--" /      ');
	  writeln('           \  .--" ";;.=SSS`\\_\_SSS                 (___ --__  __ __--(                 SSS_/_//`SSS=.";;" "--.  /       ');
	  writeln('            `._ .-"` _";;..=.=.=.\.=\               /-_  / __ -_ -__  \_\                /=./.=.=.=..;;"_ `"-. _.`        ');
	  writeln('               ;-._-"  _.;\.=.=.=.|.=|             _>/  -- /|___| _ \ -_ )              |=.|.=.=.=./;._  "-_.-;           ');
	  writeln('     ,     _.-"    `"=._  ;\=.=__/__/             /--  _ - _/   \>\ -  -- \              \__\__\=.=/;  _.="`   "-._     , ');
	  writeln('     )\ ."`   __        ".;|.=.=.=./             ( / / /   >     \   \ \ \_)              \.=.=.=./;."        __   `". /( ');
	  writeln('     (_\   .-`  ".   |    \/=.=.=/"              | |-" | |/       \| |   |_|               `\=.=.=\/    |   ."  `-.   /_) ');
	  writeln('      /\\         \-,|     |.--"|                L_|_|_|_/         L_L_|_l_)                  |"--.|    |,-/         //\  ');
	  writeln('     /  \`,       //  \    | |  |                                                             |  | |   /  \\       ,`/  \ ');
	  writeln('    ( (__) )  _.-"--,  \   | |  "--,                                                       ,--"  | |  /  ,(("-._  ( (__) )');
	  writeln('     ;----" -"--,__}}}  \  "--, __}}}                                                     {{{__ ,--" /  {{{__,--"- "----; ');
	  writeln('     \_________}}}       \___}}}                                                               {{{___/       {{{________/ ');
end;

procedure affichJoueur(joueur : integer);
begin
	clrscr;
	if joueur = 1 then
	begin
		writeln(#10,#13,#10,#13,#10,#13,#10,#13,#10,#13,#10,#13);
		writeln('             ___                                    __ ');
		writeln('            |_  |                                  /  |');
		writeln('              | |  ___   _   _   ___  _   _  _ __  `| |');
		writeln('              | | / _ \ | | | | / _ \| | | || `__|  | |');
		writeln('          /\__/ /| (_) || |_| ||  __/| |_| || |    _| |');
		writeln('          \____/  \___/  \__,_| \___| \__,_||_|    \___/');
	end
	else
	begin
		writeln(#10,#13,#10,#13,#10,#13,#10,#13,#10,#13,#10,#13);
		writeln('             ___                                    _____ ');
		writeln('            |_  |                                  / __  \');
		writeln('              | |  ___   _   _   ___  _   _  _ __  `` / /`');
		writeln('              | | / _ \ | | | | / _ \| | | || `__|   / / ');
		writeln('          /\__/ /| (_) || |_| ||  __/| |_| || |    ./ /___');
		writeln('          \____/  \___/  \__,_| \___| \__,_||_|    \_____/');
	end;
	readln;
end;

procedure commentJouerJeu(); //Procedure d'affichage de but du jeu
// RODRIGUEZ Sébastien
// Instructions pour le jeu.
begin
	writeln('                                                  ------ Jeu ------');
	writeln(' ');
	writeln('    Le but du jeu est d''atteindre le tresor du labyrinthe. Vous cherchez à l''aveugle, seul votre point de départ');
	writeln('     et le trésor vous sont indiqués. Mais faites vite! Votre rival cherche lui aussi le trésor dans le labyrinthe');
	writeln('           que vous avez dessiné pour lui. Trouvez votre trésor avant qu''il ne trouve le sien pour gagner!');
	writeln('');
	writeln('                                     Mur : ▓▓▓       Entrée : o       Trésor : X');
	writeln('');
	writeln('                                                Personnage : ▲ ▼ ◄ ►');
end;

procedure commentJouerRegles(); //Procedure d'affichage des règles du jeu
// RODRIGUEZ Sébastien
// Instructions pour le jeu.
begin
	writeln(' ');
	writeln(#10,#13,#10,#13,#10,#13,#10,#13,#10,#13);
	writeln('                                                 ------ Règles ------');
	writeln(' ');
	writeln('        Vous pouvez vous déplacer autant de fois que vous le souhaitez tant que vous ne rencontrez pas de mur.');
	writeln('         Lorsque vous rentrez dans un mur la main passe à votre rival jusqu''à ce qu''il trouve le trésor ou');
	writeln('                 qu''il rencontre lui même un mur. Le premier à atteindre le trésor remporte la partie.');
	writeln('         Vous jouez dans la grille 1, à gauche de l''écran, alors que votre rival se trouve dans la grille 2,');
	writeln('          droite de l''écran. La grille de couleur rouge est la grille du joueur dont ce n''est pas le tour.');
	writeln('');
	writeln('');
	writeln(#10,#13,#10,#13,#10,#13,#10,#13,#10,#13,#10,#13#10,#13,#10,#13);
end;

procedure commentJouerCommandes(); //Procedure d'affichage des commandes du jeu
// RODRIGUEZ Sébastien
// Instructions pour le jeu.
begin
	writeln('');
	writeln('');
	writeln('                                               ------ Commandes ------ ');
	writeln('');
	writeln('                     ___');
	writeln('                    |   |');
	writeln('                    | ▲ |');
	writeln('                 ___|___|___          Les flèches directionnelles pour vous diriger.');
	writeln('                |   |   |   |');
	writeln('                | ◄ | ▼ | ► |');
	writeln('                |___|___|___|');
	writeln('');
	writeln('                  ______');
	writeln('                 |Entrée|');
	writeln('                 |_<---┘|                   La touche Entrée pour valider.');
	writeln('                   |    |');
	writeln('                   |____|');
	writeln('');
	writeln('                    ___');
	writeln('                   |Esc|             La touche ECHAP pour quitter en pleine partie.');
	writeln('                   |___|');
	writeln('');
	writeln('');
	writeln('                            - Appuyez sur ECHAP ou RET. ARRIERE pour retourner au menu. -');
	writeln('                       - Appuyez sur ENTREE ou une flèche directionelle pour changer de page. -');
	writeln('');
	writeln('                                                                                                    Page:2/2.');
end;


procedure commentJouer();
// RODRIGUEZ Sébastien
// Instructions pour le jeu. Ce qui est retourné quand "Règles du jeu" est sélectionné dans le menu principal.
begin
	writeln(' ');
	commentJouerJeu(); //lignes 22 à 35
	commentJouerRegles(); //lignes 37 à 50
	writeln('');
	writeln('                            - Appuyez sur ECHAP ou RET. ARRIERE pour retourner au menu. -');
	writeln('                       - Appuyez sur ENTREE ou une flèche directionelle pour changer de page. -');
	writeln('');
	writeln('                                                                                                    Page:1/2.');
end;

procedure commentJouerModes();
// RODRIGUEZ Sébastien
// Instructions pour le jeu. Ce qui est retourné quand "Règles du jeu" est sélectionné dans le menu principal.
begin
	clrscr;
	titre();
	writeln('');
	writeln('                                                 ------ Modes ------ ');
	writeln('');
	writeln('                Le mode "Un joueur" consiste en un mode de jeu de Sphinx classique contre votre Rival.');
	writeln('         Le mode "Deux joueurs" vous oppose à un autre joueur "humain" dans le mode de jeu de Sphinx classique.');
	writeln('               Le mode "Mémoire" est jouable uniquement en monojoueur : il s''agit d''un mode personnalisé :');
	writeln('      la grille vous est dévoilé entièrement pendant une courte durée, vous devez alors retrouver le trésor en ayant');
	writeln('   mémorisé votre chemin auparavant. Si vous rencontrez un mur en mode mémoire vous recommencez à l''entrée du labyrinthe');
	writeln('                           et le chemin vous est dévoilé pendant un temps plus court encore.');
	writeln('               Le mode Démonstration permet de voir le déroulement d''une partie en faisant s''affronter');
	writeln('                             deux IA dans une grille définie d''après les paramètres choisis.');
	writeln('     Le mode "Contre la montre" vous oppose à vous même : vous devez trouvez le trésor en un certain nombre de coups.');
	writeln('');
end;

procedure victory(gagnant : string);
// RODRIGUEZ Sébastien - 16/01/12
// Affiche l'écran de victoire (du joueur) avec une phrase de congratulation!
begin
	clrscr;
	TextColor(White);
	LowVideo;
	titre();
	writeln('');
	writeln('');
	victoryScreen();
	writeln('');
	writeln('                                    $$$$     BRAVO, ',gagnant,' trouvé le trésor !     $$$$',#10,#13);
	writeln('                                           Appuyez sur ENTREE pour retourner au menu.');
	writeln('');
	repeat until ReadKey = #13;
	clrscr;
	
end;

procedure defeat(message : string);
// RODRIGUEZ Sébastien - 16/01/12
// Affiche l'écran de défaite (du joueur)
begin
	clrscr;
	TextColor(Red);
	LowVideo;
	titre();
	writeln('');
	writeln('');
	defeatScreen();
	writeln('');
	writeln('                             ††††     ',message,'     ††††',#10,#13);
	writeln('                                              Appuyez sur ENTREE pour retourner au menu');
	writeln('');
	repeat until ReadKey = #13;
	clrscr;
	TextColor(White);
	LowVideo;
end;

procedure defeatTriche();
// RODRIGUEZ Sébastien - 16/01/12
// Affiche l'écran de triche du joueur lorsqu'il a fait une grille invalide en version labyrinthe personnel
begin
	clrscr;
	TextColor(Red);
	LowVideo;
	titre();
	writeln('');
	writeln('');
	cheat();
	writeln('');
	writeln('                            #@%&     TRICHE ! Vous avez enfermé votre rival dans le labyrinthe !     &%@#',#10,#13);
	writeln('                                               Appuyez sur ENTREE pour retourner au menu.');
	writeln('');
	repeat until ReadKey = #13;
	clrscr;
	TextColor(White);
	LowVideo;
end;

procedure quiGagne(turn, multi : boolean);
// INGOUFF Christian, 16/01/12
// Opérations effectuées quand un joueur/bot gagne, selon le mode de jeu
begin
	if turn then
	begin
		if multi then victory('le joueur 1 a')
		else victory('vous avez');
	end
	else
		if multi then victory('le joueur 2 a')
		else defeat('   Dommage, votre rival a trouvé le trésor avant vous!');
end;


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//							// INTERFACE TEXTUELLE DES MENUS //
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


function ecrireFlecheDroite(ok : boolean):string;
// RODRIGUEZ Sébastien - 11/01/12
// Retourne une flèche vers la droite (en ASCII) si le choix dans le menu correspond
begin
	   if ok then
	       ecrireFlecheDroite:=(' <--')
	   else
	       ecrireFlecheDroite:=('');       
end;

function ecrireFlecheGauche(ok : boolean):string;
// RODRIGUEZ Sébastien - 11/01/12
// Retourne une flèche vers la gauche(en ASCII) si le choix dans le menu correspond
begin
	   if ok then
	       ecrireFlecheGauche:=('--> ')
	   else
	       ecrireFlecheGauche:=('    ');   
end;

procedure choixMenu(choix:integer);
// RODRIGUEZ Sébastien - 11/01/12
// Interface graphique/textuelle pour le menu principal
begin
	 clrscr;
	 titre();//lignes 173 à 198
	 writeln('                                                      UN JOUEUR'+ecrireFlecheDroite(choix=0));
	 writeln('                                                      DEUX JOUEURS'+ecrireFlecheDroite(choix=1));
	 writeln('                                                      MEMOIRE'+ecrireFlecheDroite(choix=2));
	 writeln('                                                      CONTRE LA MONTRE'+ecrireFlecheDroite(choix=3));
	 writeln('                                                      PARAMETRES'+ecrireFlecheDroite(choix=4));
	 writeln('                                                      COMMENT JOUER?'+ecrireFlecheDroite(choix=5));
	 writeln('                                                      DEMONSTRATION'+ecrireFlecheDroite(choix=6));
	 writeln('                                                      QUITTER'+ecrireFlecheDroite(choix=7));
end;

function grandeur(choixFormat:integer):string;
// RODRIGUEZ Sébastien - 24/01/12
// Choix de la taille de la grille
begin
	   case choixFormat of
	   0: grandeur:= 'Petit (5x5)';
	   1: grandeur:= 'Moyen (7x7)';
	   2: grandeur:= 'Grand (10x10)';
	   end;
end;

function difficulte(choixHard:integer):string;
// RODRIGUEZ Sébastien - 24/01/12
// Choix de la difficulté
begin
	   case choixHard of
	   0: difficulte:= 'Facile';
	   1: difficulte:= 'Normal';
	   2: difficulte:= 'Difficile';
	   end;
end;

function carte(choixCarte:integer):string;
// RODRIGUEZ Sébastien - 24/01/12
// Choix de la façon dont la grille (pour le bot) est générée
begin
	   case choixCarte of
	   0: carte:= 'Personnelle';
	   1: carte:= 'Aléatoire';
	   end;
end;

function vitesse(choixVitesse:integer):string;  // différents choix possibles pour l'option vitesse du bot dans le menu paramètres
// RODRIGUEZ Sébastien
begin
	  case choixVitesse of
	  2: vitesse:= 'Normale';
	  1: vitesse:= 'Rapide';
	  0: vitesse:= 'Instantanée';
	  end;
end;

procedure aideMenuParametre(choixParametre:integer); // différentes indications des choix possibles dans le menu paramètres
// RODRIGUEZ Sébastien
begin
	  case choixParametre of
	  0: begin
	     writeln('                                 Détermine la taille de la grille de jeu en nombre de lignes et de colonnes.');
	     writeln('',#10,#13);
	     end;
	  1: begin
	     writeln('                                         Détermine la difficulté du niveau généré pour le joueur.');
	     writeln('',#10,#13);
	       end;
	  2:begin
	    writeln('                                                Détermine l''origine du labyrinthe :',#10,#13);
	     writeln('    "Personelle" représente un labyrinthe dessiné par le joueur, "Aléatoire" représente un labyrinthe généré aléatoirement.');
	     end;
	  3: begin
	     writeln('                                                Détermine la vitesse de jeu du rival.');
	     writeln('',#10,#13);
	     end;
	  end;
end;

procedure choixMenuParametre(choixParametre,choixH1,choixH2,choixH3,choixH4:integer);
// RODRIGUEZ Sébastien - 11/01/12
// Interface graphique/textuelle pour le menu des parametres
begin
	 clrscr;
	 titre();//lignes 173 à 198
	 writeln('                                                  '+ecrireFlechegauche(choixParametre=0)+' TAILLE : ',grandeur(choixH1),ecrireFlecheDroite(choixParametre=0));
	 writeln('                                                  '+ecrireFlechegauche(choixParametre=1)+' DIFFICULTE : ',difficulte(choixH2),ecrireFlecheDroite(choixParametre=1));
	 writeln('                                                  '+ecrireFlechegauche(choixParametre=2)+' LABYRINTHE : ',carte(choixH3),ecrireFlecheDroite(choixParametre=2));
	 writeln('                                                  '+ecrireFlechegauche(choixParametre=3)+' VITESSE DE L''IA : ',vitesse(choixH4),ecrireFlecheDroite(choixParametre=3));
	 writeln('');
	 writeln('');
	 aideMenuParametre(choixParametre);
	 writeln('');
	 writeln('');
	 writeln('');
	 writeln('                                              ECHAP ou RET. ARRIERE pour revenir au menu.');
end;


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//               				     //    AFFICHAGE DE LA GRILLE        //
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


procedure convertGrille(grille : matrix ; var grilchar : matstring ; taille : coord);
// INGOUFF Christian, 11/01/12 - Version 1.0 ; 17/01/12 - Version 1.7 : caractères spéciaux
// Convertit la grille (array of array of integer) en grilchar (array of array of char) afin d'être affichée à l'utilisateur.
var
	i,j : integer;
begin
	setLength(grilchar,taille[1],taille[2]);
	for i := 0 to taille[1]-1 do
		for j := 0 to taille[2]-1 do
			case grille[i+1,j+1] of
				-66 : grilchar[i,j] := ' ▓@▓ '; // Mur + curseur (fabrication de la grille)
				-65 : grilchar[i,j] := ' (o) '; // Entrée + curseur (idem)
				-64 : grilchar[i,j] := ' (X) '; // Tresor + curseur (idem)
				-42 : grilchar[i,j] := ' ▓▓▓ '; // Mur
				-5 : grilchar[i,j] := '  ?  '; // Requête (jeu papier)
				10 : grilchar[i,j] := '  o  '; // Porte d'entrée
				0 : grilchar[i,j] := '     '; // Inconnu
				-1 : grilchar[i,j] := '  .  '; // Chemin
				15 : grilchar[i,j] := '  ▲  '; // Pions (faisant face à une direction donnée)
				16 : grilchar[i,j] := '  ▼  ';
				17 : grilchar[i,j] := '  ◄  ';
				18 : grilchar[i,j] := '  ►  ';
				42 : grilchar[i,j] := '  X  '; // Trésor
			end;
end;

function grilBordHaut(taille : coord):string;
// INGOUFF Christian, 20/01/12 - Version 1.0
// Retourne la bordure supérieure des grilles affichées à l'utilisateur.
var
	i : integer;
begin
	grilBordHaut := '   .';
	for i := 1 to taille[1]-1 do
	begin
		if i < 10 then grilBordHaut := grilBordHaut+'_';
		grilBordHaut := grilBordHaut+'_'+IntToStr(i)+'___';
	end;
	if i < 9 then grilBordHaut := grilBordHaut+'_';
		grilBordHaut := grilBordHaut+'_'+IntToStr(i+1)+'__.     ';
end;    

function grilCaseBord(taille : coord ; haut : boolean):string;
// INGOUFF Christian, 20/01/12 - Version 1.0
// Retourne la bordure supérieure ou inférieure des cases des grilles affichées à l'utilisateur.
var
	i : integer;
begin
	grilCaseBord := '   ';
	if haut then
	for i := 0 to taille[1]-1 do
		grilCaseBord := grilCaseBord+'|     '
	else
	for i := 0 to taille[1]-1 do
		grilCaseBord := grilCaseBord+'|_____';
	grilCaseBord := grilCaseBord+'|     ';
end;

function grilCaseMilieu(grilchar : matstring ; taille : coord ; line : integer):string;
// INGOUFF Christian, 20/01/12 - Version 1.0
// Retourne l'intérieur des cases des grilles affichées à l'utilisateur.
var
	i : integer;
begin
	grilCaseMilieu := ' ';
	if line < 9 then grilCaseMilieu := grilCaseMilieu+' ';
	grilCaseMilieu := grilCaseMilieu+IntToStr(line+1);
	for i := 0 to taille[1]-1 do
		grilCaseMilieu := grilCaseMilieu+'|'+grilchar[i,line];
	grilCaseMilieu := grilCaseMilieu+'|     ';
end;

procedure affichHautGrille(taille : coord ; tourjoueur : boolean);
// INGOUFF Christian, 20/01/12 - Version 1.0
// Retourne ce qui est affiché en haut de la grille.
var
	i : integer;
begin
	if tourjoueur then TextColor(White) else TextColor(Red);
	LowVideo;	
	for i := 1 to ((taille[2] div 2)) do write('    ');
	write(' ----- Grille n°1 -----');
	if tourjoueur then TextColor(Red) else TextColor(White);
	LowVideo;
	case taille[1] of
		5 : write('                ');
		7 : write('                              ');
		10 : write('                                                 ');
	end;
	writeln('----- Grille n°2 -----');
	writeln('');
	if tourjoueur then TextColor(White) else TextColor(Red);
	LowVideo;
	write(grilBordHaut(taille));
	if tourjoueur then TextColor(Red) else TextColor(White);
	LowVideo;
	writeln(grilBordHaut(taille));
end;

procedure affichSingleGrille(grille : matrix; taille : coord);
// INGOUFF Christian, 11/01/12 - Version 1.0
// Affiche la grille de jeu à l'écran
var
	i : integer;
	grilchar : matstring;
	tailletmp : coord;
begin
	tailletmp[1] := taille[1]-2; // Redéfinition de la taille dans le cadre de la création de grilles
	tailletmp[2] := taille[2]-2;
	convertgrille(grille,grilchar,tailletmp);
	writeln(grilBordHaut(tailletmp));
	for i := 0 to tailletmp[2]-1 do
	begin
		writeln(grilCaseBord(tailletmp,TRUE));
		writeln(grilCaseMilieu(grilchar,tailletmp,i));
		writeln(grilCaseBord(tailletmp,FALSE));
	end;
end;

procedure affichMultiGrilles(grillejeu1, grillejeu2 : matrix ; taille : coord ; tourjoueur : boolean);
// INGOUFF Christian, 11/01/12 - Version 1.0
// Affiche la grille de jeu à l'écran
var
  line : integer;
  grilcharjr, grilcharbot : matstring;
begin
	convertgrille(grillejeu1,grilcharjr,taille);
	convertgrille(grillejeu2,grilcharbot,taille);
	affichHautGrille(taille,tourjoueur);
	for line := 0 to taille[2]-1 do
	begin
		if tourjoueur then TextColor(White) else TextColor(Red);
		LowVideo;	
		write(grilCaseBord(taille,TRUE));
		if tourjoueur then TextColor(Red) else TextColor(White);
		LowVideo;
		writeln(grilCaseBord(taille,TRUE));
		if tourjoueur then TextColor(White) else TextColor(Red);
		LowVideo;	
		write(grilCaseMilieu(grilcharjr,taille,line));
		if tourjoueur then TextColor(Red) else TextColor(White);
		LowVideo;
		writeln(grilCaseMilieu(grilcharbot,taille,line));
		if tourjoueur then TextColor(White) else TextColor(Red);
		LowVideo;	
		write(grilCaseBord(taille,FALSE));
		if tourjoueur then TextColor(Red) else TextColor(White);
		LowVideo;
		writeln(grilCaseBord(taille,FALSE));
	end;
	TextColor(White);
	LowVideo;
end;


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//								   //	UTILITAIRES	//
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


function quiCommence():boolean;
// INGOUFF Christian - 20/01/12
// Simulateur de pile ou face, retourne VRAI ou FAUX au hasard
var
	test : integer;
begin
	test := random(2);
	quiCommence := test = 0;
end;

procedure arrayDirec(var direc : array_coord ; loc : coord);
// INGOUFF Christian, 15/01/12 - Version 1.0
// Retourne les coordonnées des cases environnantes (dans direc)
// (1,1),(1,2) : haut | (2,1),(2,2) : bas | (3,1),(3,2) : gauche | (4,1),(4,2) : droite
begin
	direc[1,1] := loc[1];	// Haut
	direc[1,2] := loc[2]-1;
  
	direc[2,1] := loc[1];	// Bas
	direc[2,2] := loc[2]+1;
  
	direc[3,1] := loc[1]-1;	// Gauche
	direc[3,2] := loc[2];
  
	direc[4,1] := loc[1]+1; // Droite
	direc[4,2] := loc[2];
end;

procedure bornes(var inf, sup : coord ; enter, taille : coord ; dist : integer);
// INGOUFF Christian, 16/01/12
// Définit inf et sup (bornes inférieure et supérieure) dans le cadre de "dijkstra"
var
	i : integer;
begin
	for i := 1 to 2 do
	begin
		inf[i] := enter[i]-dist+1;
		if inf[i] < 1 then inf[i] := 1;
		sup[i] := enter[i]+dist+1;
		if sup[i] > taille[i] then sup[i] := taille[i];
	end;
end;

procedure remiseZero(var grille : matrix ; taille : coord ; k : integer);
// INGOUFF Christian, 11/01/12
// Définit les murs aux bords de la zone de jeu valide (une grille 7x7 va être définie sous la forme d'une grille 9x9 entourée de murs)
// k désigne l'entier qui va être placé dans les cases libres
// k = -1 dans le cadre de l'initialisation de la grille valide (grille tampon pour "Dijkstra")
// k = 0 dans le cadre de l'initialisation des grilles vides
var
	i, j : integer;
begin
	for i := 0 to taille[1]-1 do
		for j := 0 to taille[2]-1 do
			if (i = 0) or (j = 0) or (i = taille[1]-1) or (j = taille[2]-1) then grille[i,j] := -42
			else grille[i,j] := k;
end;


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//                                             //    VERIFICATION DE LA GRILLE / CHEMIN OPTIMAL    //
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


procedure dijkstraGrille(grille : matrix ; var grilcoups : matrix ; tresor, enter, taille : coord ; var valide : boolean);
// INGOUFF Christian, 16/01/12
// Inspiré de l'algorithme de Dijkstra (Chemin le plus court optimal)
// Retournera la "grille des distances" (grilcoups) avec les cases libres marquées de leur distance par rapport au départ et la validité ou non de la grille.
// Les cases remplies auront comme nombre leur distance par rapport au départ. La distance enter/tresor avec les murs est ainsi obtenue.
var
	i, j, k, dist : integer; // dist = Distance par rapport au départ
	loc, inf, sup : coord; // inf et sup = valeurs qui augmenteront selon la distance au départ (recherche en "cercle")
	direc : array_coord; // Cases adjacentes à une case donnée
begin
	setLength(grilcoups,taille[1],taille[2]);
	remiseZero(grilcoups,taille,-1);
	grilcoups[enter[1],enter[2]] := 0; // Initialisation : l'algorithme va d'abord chercher cette case
	valide := TRUE; // Pour ne pas casser la boucle dès le début
	dist := 0;
	while valide and (grilcoups[tresor[1],tresor[2]] = -1) do // Boucle jusqu'à trésor trouvé ou impossible de continuer
	begin
		valide := FALSE; // Initialisation de "valide"
		bornes(inf,sup,enter,taille,dist); // Définition des bornes inférieure et supérieure
		for i := inf[1]-1 to sup[1]-1 do
			for j := inf[2]-1 to sup[2]-1 do // On parcourt le tableau d'abord en cercle (avec inf et sup) puis en entier quand dist > taille
				if (grilcoups[i,j] = dist) then // Si la case correspond à ce tour (dist)
				begin
					loc[1] := i;
					loc[2] := j; // On assigne les coordonnées de cette case à "loc"
					arrayDirec(direc,loc); // On obtient les coordonnées des cases adjacentes
					for k := 1 to 4 do // Pour chaque case adjacente
						if (grilcoups[direc[k,1],direc[k,2]] = -1) and (grille[direc[k,1],direc[k,2]] > -42) then // Si la case n'a pas été franchie et n'est pas un mur
						begin
							grilcoups[direc[k,1],direc[k,2]] := dist+1; // La remplir pour le tour suivant (dist+1)
							valide := TRUE; // Indique qu'au moins une case a été remplie pendant ce tour
						end;
				end;
		dist := dist+1; // On continue tant que le trésor n'a pas été marqué de sa distance par rapport au départ,
				// ou jusqu'à ce que toutes les cases accessibles soient marquées.
	end;
end;

function dijkstra(grille : matrix ; tresor, enter, taille : coord): integer;
// INGOUFF Christian, 16/01/12
// Retourne le nombre de coups minimum requis pour atteindre le trésor
// Principalement utilisé dans la définition de la difficulté de jeu.
var
	grilcoups : matrix;
	valide : boolean;
begin
	dijkstraGrille(grille,grilcoups,tresor,enter,taille,valide); // Création de la grille des distances
	if not valide then dijkstra := -1 // Si grille non valide
	else dijkstra := grilcoups[tresor[1],tresor[2]]; // Nombre de coups optimal
end;

function recurMeilleur(prec, loc : coord ; grilcoups : matrix):coord;
// INGOUFF Christian, 20/01/12
// Fonction récursive qui parcourt le chemin le plus court (tracé par Dijkstra) depuis le trésor jusqu'à un départ donné.
// (De la valeur "nombre de coups optimal" à 0 (le point donné))
// Retourne la coordonnée de la case la plus avantageuse.
var
	direc : array_coord;
	sens : integer;
begin
	arrayDirec(direc,loc); // On obtient les coordonnées des cases adjacentes
	sens := 1;
	if grilcoups[loc[1],loc[2]] <> 0 then // Jusqu'à ce qu'on soit au départ
		while sens < 5 do // Pour chaque sens
		begin
			if grilcoups[direc[sens,1],direc[sens,2]] = grilcoups[loc[1],loc[2]]-1 then // Vérifie si la case est sur le chemin (à l'envers)
			begin
				recurMeilleur := recurMeilleur(loc,direc[sens],grilcoups); // On continue le chemin
				sens := 5; // Fin boucle
			end
			else sens := sens+1; // Sinon, un autre sens
		end
	else recurMeilleur := prec; // Quand on est au départ, la coordonnée optimale est la précédente traitée.
end;

function meilleurCoup(grille : matrix ; tresor, depart : coord):integer;
// INGOUFF Christian, 20/01/12
// Fonction qui recherche la direction la plus avantageuse :
// 1 = Haut, 2 = Bas, 3 = Gauche, 4 = Droite
var
	direc : array_coord;
	objectif, taille_large : coord;
	i : integer;
	grilcoups : matrix;
	valide : boolean;
begin
	taille_large[1] := length(grille); // Taille réelle des grilles (jeu = x*x, réel = (x+2)*(x+2))
	taille_large[2] := length(grille[0]);
	meilleurCoup := -1;
	dijkstraGrille(grille,grilcoups,tresor,depart,taille_large,valide); // Création de la grille des distances
	if valide then // Si grille valide
	begin
		arrayDirec(direc,depart); // Cases adjacentes
		objectif := recurMeilleur(depart,tresor,grilcoups); // Le bot voudra aller sur cette case
		i := 1;
		repeat // Il cherche cette case
			if (direc[i,1] = objectif[1]) and (direc[i,2] = objectif[2]) then meilleurCoup := i; // Et en retourne le sens (cf description)
			i := i+1;
		until meilleurCoup > -1;
	end;
end;


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//                  				   //    INITIALISATION DE LA GRILLE    //
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


procedure remplCase(var grille : matrix ; taille : coord ; type_case : integer ; var coord_case : coord);
// INGOUFF Christian, 11/01/12
// Permet d'attribuer à une case au hasard d'une grille une valeur particulière (le type de case : trésor, entrée, murs) si elle est libre.
// Retourne la grille avec cette case remplie et les coordonnées de la case remplie.
var
  valide : boolean;
begin
	repeat
		coord_case[1] := random(taille[1]-1) + 1;
		coord_case[2] := random(taille[1]-1) + 1;
		valide := grille[coord_case[1],coord_case[2]] = 0; // Vérifie si la case n'est pas occupée par autre chose
		if valide then grille[coord_case[1],coord_case[2]] := type_case
	until valide;
end;

procedure iniGrille(var grille:matrix; taille : coord ; var tresor, enter : coord ; min, max : integer);
// Pré-condition : Reçoit un tableau vide de taille définie (non nulle) et la difficulté du jeu aussi définie (min, max)
// Post-condition : Renvoie la grille remplie et les coordonnées du trésor et de l'entrée.
// INGOUFF Christian, 11/01/12
var
	i, nb_coups, nb_murs : integer;
	tmp : coord;
	valide : boolean;
begin
	remiseZero(grille,taille,0); // Initialise la grille
	nb_murs := trunc(( 15 / 49 ) * ( (taille[1]-2) * (taille[2]-2) )); // Définit le nombre de murs
	remplCase(grille,taille,42,tresor); // Trésor = 42
	remplCase(grille,taille,10,enter); // Porte d'entrée = 10
	if dijkstra(grille,tresor,enter,taille) < 3 then iniGrille(grille,taille,tresor,enter,min,max) // S'ils ne sont pas assez éloignés
	else
	begin
		for i := 1 to nb_murs do // Placement des murs
			repeat
				remplCase(grille,taille,-42,tmp); // Mur = -42
				valide := dijkstra(grille,tresor,enter,taille) > -1;
				if not valide then grille[tmp[1],tmp[2]] := 0; // Si la grille n'est pas valide après placement du mur, recommencer
			until valide;
		nb_coups := dijkstra(grille,tresor,enter,taille); // Nombre de coups optimal
		if (nb_coups < min) or (nb_coups > max) then	// Si la grille ne vérifie pas les conditions de la difficulté de jeu
			iniGrille(grille,taille,tresor,enter,min,max); // Recommencer
	end;
end;


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//          				              //    DEPLACEMENT DU JOUEUR ET DU BOT        //
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


procedure deplacement(grille : matrix ; var grillejeu1 : matrix ; var joueur : coord ; enter : coord ; direc : array_coord ; sens : integer ; var valide : boolean);
// RODRIGUEZ Sébastien, INGOUFF Christian - 16/01/12
// Vérifie si une case est libre, si une case correspond à l'entrée et réagit correctement.
// Renvoie la grille de jeu correctement remplie et la coordonnée du joueur/bot
// Sens : 1 = haut, 2 = bas, 3 = gauche, 4 = droite
// Valide : Renvoie si le déplacement est valide ou non
begin
	valide := grille[direc[sens,1],direc[sens,2]] > -42; // Vérifie la case adjacente dans un sens donné
	if valide then // Si la case visée n'est pas un mur
	begin
		if (joueur[1] = enter[1]) and (joueur[2] = enter[2]) then
			grillejeu1[joueur[1],joueur[2]] := 10 // Pour ne pas effacer le point d'entrée sur la grille de jeu
		else
			grillejeu1[joueur[1],joueur[2]] := -1; // Sinon afficher un point là où le joueur était (chemin parcouru)
		joueur := direc[sens];
		grillejeu1[joueur[1],joueur[2]] := 14+sens; // Afficher le curseur joueur (avec la bonne direction) là où il est maintenant
	end
	else // S'il rencontre un mur
	begin
		grillejeu1[direc[sens,1],direc[sens,2]] := -42; // On affiche le mur rencontré
		grillejeu1[joueur[1],joueur[2]] := 14+sens; // Le joueur/bot fait face au mur (sur l'affichage)
	end;
end;

procedure requeteBot(grillejeu1,grillejeu2 : matrix ; taille : coord ; var valide : boolean);
// INGOUFF Christian, 16/01/12
// Le bot demande à l'utilisateur si la case (qu'il précisera) est un mur ou non.
var
	ch : char;
begin
	repeat
		clrscr;
		affichMultiGrilles(grillejeu1,grillejeu2,taille,FALSE); // Affiche les 2 grilles à l'écran
		writeln('Quel est le type de cette case ?');
		writeln('');
		writeln('     Mur          ',ecrireFlecheDroite(not valide)); // Avec la flèche de choix à droite
		writeln('     Case libre   ',ecrireFlecheDroite(valide));
		ch := ReadKey;
		if ch = #0 then
		begin
			ch := ReadKey; // Détecte les flèches du haut et du bas
			case ch of
				#72 :	valide := not valide;
				#80 :	valide := not valide;
			end;
		end;
	until ch = #13; // Jusqu'à validation (ENTREE)
end;

procedure botJeuPapier(grillejeu1 : matrix ; var grillejeu2 : matrix ; taille, enter, tresor : coord ; var xbot : coord ; var win : boolean ; var tmpstr : string);
// INGOUFF Christian, 16/01/12
// Gère l'intelligence artificielle pour un jeu avec grille "papier"
var
	direc : array_coord;
	sens_coup : integer;
	valide : boolean;
begin
	win := (xbot[1] = tresor[1]) and (xbot[2] = tresor[2]);
	if not win then // Si le bot n'est pas encore sur le trésor
	begin
		arrayDirec(direc,xbot); // Cases adjacentes
		sens_coup := meilleurCoup(grillejeu2,tresor,xbot); // Détermine le meilleur coup
		valide := (grillejeu2[direc[sens_coup,1],direc[sens_coup,2]] >= 10) or (grillejeu2[direc[sens_coup,1],direc[sens_coup,2]] = -1);
		if valide then // Si le bot connait le statut de la case
			deplacement(grillejeu2,grillejeu2,xbot,enter,direc,sens_coup,valide) // Déplacement automatique
		else
		begin
			grillejeu2[direc[sens_coup,1],direc[sens_coup,2]] := -5; 
			requeteBot(grillejeu1,grillejeu2,taille,valide); // Sinon, demande au joueur le statut de la case
		end;
		
		if not valide then // /!\ Pas le "même" valide : valide retourne la réponse donnée par l'utilisateur : VRAI si le chemin est libre, FAUX sinon.
		begin
			grillejeu2[direc[sens_coup,1],direc[sens_coup,2]] := -42;
			if meilleurCoup(grillejeu2,tresor,xbot) = -1 then tmpstr := 'TRICHERIE'; // Si le joueur a enfermé l'IA (vérification validité grille)
		end
		else
		begin
			deplacement(grillejeu2,grillejeu2,xbot,enter,direc,sens_coup,valide); // Si case libre, effectue le déplacement prévu
			clrscr;
			botJeuPapier(grillejeu1,grillejeu2,taille,enter,tresor,xbot,win,tmpstr); // Et recommence à jouer
		end;
	end;
end;

procedure bot(grille, grillejeu1 : matrix ; var grillejeu2 : matrix ; taille, enter, tresor : coord ; var xbot : coord ; var win : boolean ; ecran_gauche, auto : boolean ; choixH4 : integer);
// INGOUFF Christian - 16/01/12
// Procédure qui gère le déplacement du bot (pour une grille générée aléatoirement)
var
	direc : array_coord;
	valide : boolean;
begin
	win := (xbot[1] = tresor[1]) and (xbot[2] = tresor[2]);
	if not win then // Si le bot n'est pas encore sur le trésor
	begin
		arrayDirec(direc,xbot); // Cases adjacentes
		deplacement(grille,grillejeu2,xbot,enter,direc,meilleurCoup(grillejeu2,tresor,xbot),valide); // Effectue le meilleur coup d'après lui
		clrscr;
		if ecran_gauche then affichMultiGrilles(grillejeu2,grillejeu1,taille,ecran_gauche) // Si le bot qui joue est à gauche
		else affichMultiGrilles(grillejeu1,grillejeu2,taille,ecran_gauche); // Sinon, inversion des variables grilles (j'ai aussi cru à une tautologie)
		// ecran_gauche retourne VRAI si le bot est à gauche (donc la grille de gauche est en blanc), et FAUX sinon (celle-ci est donc rouge)
		writeln('');
		delay(250*choixH4); // Petit délai d'attente (histoire de voir le déplacement du bot)
		if not valide and not auto then // S'il prend un mur
		begin
			writeln('     Votre rival a rencontré un mur ! Appuyez sur ENTREE.');
			readln;
		end
		else if valide then bot(grille,grillejeu1,grillejeu2,taille,enter,tresor,xbot,win,ecran_gauche,auto,choixH4); // Sinon, recommence à jouer
	end; // Si auto = VRAI, passer le tour sans pause.
end;

procedure bouger(grille, grillejeu2 : matrix ; var grillejeu1 : matrix ; taille, enter, tresor : coord ; var joueur : coord ; var win : boolean ; var tmpstr : string ; ecran_gauche : boolean);
// RODRIGUEZ Sébastien - 16/01/12
// Procédure qui gère le déplacement du joueur
var
	direc : array_coord;
	ch : char;
	valide : boolean;
begin
	valide := TRUE;
	win := (joueur[1] = tresor[1]) and (joueur[2] = tresor[2]);
	if not win then // Si le joueur n'est pas encore sur le trésor
	begin
		clrscr;
		if ecran_gauche then affichMultiGrilles(grillejeu1,grillejeu2,taille,ecran_gauche)
		else affichMultiGrilles(grillejeu2,grillejeu1,taille,ecran_gauche); // Même chose qu'au dessus, selon la place du joueur
		writeln(#10,#13,'     Utilisez les flèches directionelles.',#10,#13);
		arrayDirec(direc,joueur); // On obtient les valeurs des cases environnantes
		repeat ch:=ReadKey until (ch = #0) or (ch = #27); // Jusqu'à ce que le joueur appuie sur une flèche ou ECHAP
		if ch = #27 then writeln('   Voulez-vous vraiment quitter ? Appuyez sur ECHAP encore une fois pour confirmer ou sur une autre touche pour annuler.');
		ch:=ReadKey; // Read ScanCode (appuyer sur une flèche retourne non seulement #0, mais aussi un autre caractère, qui est à relire)
		case ch of
			#72 :   deplacement(grille,grillejeu1,joueur,enter,direc,1,valide); // Haut
			#80 :   deplacement(grille,grillejeu1,joueur,enter,direc,2,valide); // Bas
			#75 :   deplacement(grille,grillejeu1,joueur,enter,direc,3,valide); // Gauche
			#77 :   deplacement(grille,grillejeu1,joueur,enter,direc,4,valide); // Droite
		end;
		if ch = #27 then tmpstr := 'QUITTER' // Si ECHAP 2 fois, on retourne au menu principal
		else if valide then bouger(grille,grillejeu2,grillejeu1,taille,enter,tresor,joueur,win,tmpstr,ecran_gauche) // Si c'est bon, on recommence
		else
		begin // Sinon on passe son tour
			clrscr;
			if ecran_gauche then affichMultiGrilles(grillejeu1,grillejeu2,taille,ecran_gauche)
			else affichMultiGrilles(grillejeu2,grillejeu1,taille,ecran_gauche);
			writeln(#10,#13,'     Vous avez rencontré un mur ! Appuyez sur ENTREE.');
			readln;
		end;
	end;
end;


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//							        // MODES BONUS //
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


// /!\ Il sera peut être préférable de lire les commentaires des fonctions du jeu normal afin de mieux comprendre les modes bonus...

procedure ordoBot(grille1, grille2 : matrix ; var grillejeu1, grillejeu2 : matrix ; taille, enter1, enter2, tresor1, tresor2 : coord ; choixH4 : integer);
// INGOUFF Christian, 26/01/12
// Jeu bot vs bot... une sorte de "demo mode"
var
	joueur1, joueur2 : coord;
	win, turn : boolean;
begin
	joueur1 := enter1; // On met les joueurs sur leurs points de départs
	joueur2 := enter2;
	clrscr;
	win := FALSE;
	turn := quiCommence(); // Qui va donc commencer ?
	affichMultiGrilles(grillejeu1,grillejeu2,taille,turn); // Affichage initial des grilles
	repeat
		if not win then
			if turn then bot(grille1,grillejeu2,grillejeu1,taille,enter1,tresor1,joueur1,win,turn,TRUE,choixH4) // Tour du bot 1
			else bot(grille2,grillejeu1,grillejeu2,taille,enter2,tresor2,joueur2,win,turn,TRUE,choixH4); // Tour du bot 2
		turn := not turn; // turn s'inverse soi-même après que le tour d'un joueur/bot se termine.
	until win; // On joue jusqu'à ce qu'on veut quitter, que quelqu'un gagne ou que quelqu'un triche.
	if win then quiGagne(not turn,TRUE) // not turn, car turn est inversé après que quelqu'un arrive au trésor !
end;

procedure bougerSolo(grille : matrix ; var grillejeu : matrix ; taille, enter, tresor : coord ; var joueur : coord ; var win, quit, bonus : boolean ; var nb_coups : integer ; a_battre : integer);
var
	direc : array_coord;
	ch : char;
	valide : boolean;
begin
		win := (joueur[1] = tresor[1]) and (joueur[2] = tresor[2]); // Condition de victoire
		clrscr;
		affichSingleGrille(grillejeu,taille); // Affichage 1 grille
		writeln(#10,#13,'     Utilisez les flèches directionelles. ECHAP pour quitter, B pour le bonus : afficher la grille temporairement.',#10,#13);
		if nb_coups > -666 then writeln('       Tour ',nb_coups,'/',a_battre,#10,#13); // -666 = mode memory. Positif = mode contre la montre
		if not win then
		begin
			arrayDirec(direc,joueur); // Cases adjacentes
			repeat ch:=ReadKey until (ch = #0) or (ch = #27) or (ch = #98); // Jusqu'à ce que le joueur appuie sur une flèche, ECHAP ou b (minuscule)
			if (nb_coups > -666) and (ch = #0) then nb_coups := nb_coups+1; // Si mode contre la montre et flèche appuyée, compteur up
			if ch = #27 then writeln('   Voulez-vous vraiment quitter ? Appuyez sur ECHAP encore une fois pour confirmer ou sur une autre touche pour annuler.')
			else if ch = #98 then
				if nb_coups = -666 then writeln('     Vous allez retourner à la case départ. Appuyez encore sur B pour confirmer, une autre touche pour annuler.')
				else writeln('     Vous allez utiliser un bonus qui va compter pour 3 coups. Appuyez encore sur B pour confirmer, une autre touche pour annuler.');
			ch:=ReadKey; // Read ScanCode (appuyer sur une flèche retourne non seulement #0, mais aussi un autre caractère, qui est à relire)
			case ch of
				#72 :   deplacement(grille,grillejeu,joueur,enter,direc,1,valide); // Haut
				#80 :   deplacement(grille,grillejeu,joueur,enter,direc,2,valide); // Bas
				#75 :   deplacement(grille,grillejeu,joueur,enter,direc,3,valide); // Gauche
				#77 :   deplacement(grille,grillejeu,joueur,enter,direc,4,valide); // Droite
				#98 :	if nb_coups > -666 then nb_coups := nb_coups+3;
			end;
			quit := ch = #27; // Si on veut quitter
			bonus := ch = #98; // Si on veut utiliser un bonus
			if valide and not quit and not bonus then bougerSolo(grille,grillejeu,taille,enter,tresor,joueur,win,quit,bonus,nb_coups,a_battre); // On recommence si c'est bon
		end;
end;

procedure memory(grille, grillejeu : matrix ; tresor, enter, taille : coord ; var win, quit, bonus : boolean);
// INGOUFF Christian, RODRIGUEZ Sébastien, 26/01/12
// Mémorisez la grille avant de tenter de la résoudre sans erreurs
var
	i, j : integer;
	griltmp : matrix;
	joueur : coord;
begin
	setLength(griltmp,length(grille),length(grille));
	joueur := enter;
	for i := 0 to taille[1]-1 do
		for j := 0 to taille[2]-2 do
			griltmp[i,j] := grillejeu[i,j]; // Création d'une nouvelle grille de jeu (réinitialisée à chaque erreur)
	j := -666; // Attribution de -666 à une variable pour bien utiliser "bougerSolo"
	bougerSolo(grille,griltmp,taille,enter,tresor,joueur,win,quit,bonus,j,0); // Déplacement jusqu'à erreur ou victoire
	clrscr;
	affichSingleGrille(griltmp,taille); // Affichage 1 grille
end;
	
procedure soloIni(var grille, grillejeu : matrix ; var enter, tresor, taille : coord ; choixH1 : integer);
// INGOUFF Christian, 26/01/12
// Génère une grille valide, et une grille de jeu. Renvoie aussi des coordonnées importantes.
begin
	case choixH1 of
		0 :	taille[1] := 7; // Petit (5x5)
		1 :	taille[1] := 9; // Normal (7x7)
		2 :	taille[1] := 12; // Grand (10x10)
	end;
	taille[2] := taille[1];
	setLength(grille,taille[1],taille[2]);
	setLength(grillejeu,taille[1],taille[2]);
	iniGrille(grille,taille,tresor,enter,trunc(taille[1]*1.5),100); // Grille valide crée à difficulté minimale constante
	remiseZero(grillejeu,taille,0);
	grillejeu[tresor[1],tresor[2]] := 42;
	grillejeu[enter[1],enter[2]] := 15;
end;


procedure affichMemory(grille : matrix ; taille : coord ; secs : integer);
// INGOUFF Christian, 26/01/12
// Affichage de la grille avec compteur à rebours.
var
	compteur : integer;
begin
	for compteur := 0 to secs-1 do
	begin
		clrscr;
		affichSingleGrille(grille,taille);
		writeln(#10,#13,'     Il vous reste ',secs-compteur,' secondes pour mémoriser la grille !');
		delay(1000);
	end;
end;
	

procedure memoryIni(choixH1, choixH2 : integer);
// INGOUFF Christian, RODRIGUEZ Sébastien, 26/01/12
// Mémorisez la grille avant de tenter de la résoudre sans erreurs
// Procédure d'initialisation de la grille, et gérance des bonus, des erreurs et de la redirection victoire.
var
	secs, essais, bonus : integer;
	grille, grillejeu : matrix;
	taille, enter, tresor : coord;
	win, quit, trigger_bonus : boolean;
begin
	essais := 1;
	bonus := 0;
	secs := 5-(choixH2*2);
	soloIni(grille,grillejeu,enter,tresor,taille,choixH1); // Initialisation d'une seule grille
	affichMemory(grille,taille,secs); // Affichage initial temporaire de la grille
	repeat
		memory(grille,grillejeu,tresor,enter,taille,win,quit,trigger_bonus); // Procédure de jeu
		if not win and not quit and not trigger_bonus then // Erreur
		begin
			writeln(#10,#13,'     Malheureux ! Vous avez rencontré un mur ! Vous retournez à la case départ, appuyez sur ENTREE.');
			essais := essais+1;
			readln;
		end
		else if trigger_bonus then // Bonus
		begin
			affichMemory(grille,taille,1);
			bonus := bonus+1;
		end; // Sinon, win = VRAI ou quit = VRAI, donc on termine la boucle sans opération supplémentaire.
	until win or quit; // Jusqu'à victoire ou envie de partir
	if win then
	begin
		writeln(#10,#13,'     Score : ',essais,' essais, ',bonus,' bonus utilisés. Appuyez sur ENTREE.');
		readln;
		victory('vous avez'); // Procédure victoire
	end;
end;

procedure timeAttack(choixH1, choixH2 : integer);
// INGOUFF Christian, 27/01/12
// Mode de jeu solo où on est limité par le nombre de coups
var
	score_a_battre, nb_coups, bonus : integer;
	grille, grillejeu : matrix;
	taille, enter, tresor, joueur : coord;
	win, quit, trigger_bonus : boolean;
begin
	nb_coups := 0;
	bonus := 0;
	soloIni(grille,grillejeu,enter,tresor,taille,choixH1);
	joueur := enter; // Initialisation position joueur
	score_a_battre := dijkstra(grille,tresor,enter,taille) + (2-choixH2)*5 + taille[1]-2;
	clrscr;
	affichSingleGrille(grillejeu,taille);
	writeln(#10,#13,'     Bienvenue ! Vous devrez trouver le trésor en ',score_a_battre,' coups. Appuyez sur ENTREE pour commencer.');
	readln;
	repeat
		bougerSolo(grille,grillejeu,taille,enter,tresor,joueur,win,quit,trigger_bonus,nb_coups,score_a_battre); // Déplacement jusqu'à bonus ou victoire
		if trigger_bonus then // Bonus
		begin
			affichMemory(grille,taille,1);
			bonus := bonus+1;
		end;
	until win or quit or (nb_coups >= score_a_battre); // Jusqu'à victoire, quitter ou "temps" écoulé
	if win then
	begin
		writeln(#10,#13,'     Score : ',score_a_battre-nb_coups,' coups restants. Appuyez sur ENTREE.');
		readln;
		victory('vous avez'); // Procédure victoire
	end
	else if nb_coups >= score_a_battre then defeat('    Dommage, vous n''avez pas réussi à trouver le trésor!');
end; // Sinon, quit = VRAI => Fin du jeu.
	

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//							  // ORDONNANCEUR, LANCEMENT DE PARTIES //
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


procedure ordonnanceur(grille1, grille2 : matrix ; var grillejeu1, grillejeu2 : matrix ; taille, enter1, enter2, tresor1, tresor2 : coord ; multi, papier : boolean ; choixH4 : integer);
// INGOUFF Christian, 20/01/12
// Procédure qui gère le déroulement du jeu
var
	joueur1, joueur2 : coord;
	win, turn : boolean;
	tmpstr : string;
begin
	joueur1 := enter1; // On met les joueurs sur leurs points de départs
	joueur2 := enter2;
	clrscr;
	win := FALSE;
	turn := quiCommence(); // Qui va donc commencer ?
	affichMultiGrilles(grillejeu1,grillejeu2,taille,turn); // Affichage initial des grilles
	if turn then writeln(#10,#13,'     Bienvenue ! Vous commencez. Appuyez sur ENTREE.')
	else writeln(#10,#13,'     Bienvenue ! Votre rival commence. Appuyez sur ENTREE.');
	readln;
	repeat
		if turn and not win then bouger(grille1,grillejeu2,grillejeu1,taille,enter1,tresor1,joueur1,win,tmpstr,turn) // Tour du joueur 1
		else if not win then // Tour du joueur 2 ou du bot
			if multi then bouger(grille2,grillejeu1,grillejeu2,taille,enter2,tresor2,joueur2,win,tmpstr,turn) // Joueur 2
			else if papier then botJeuPapier(grillejeu1,grillejeu2,taille,enter2,tresor2,joueur2,win,tmpstr) // Bot (jeu papier)
			else bot(grille2,grillejeu1,grillejeu2,taille,enter2,tresor2,joueur2,win,turn,FALSE,choixH4); // Bot (jeu normal)
		turn := not turn; // turn s'inverse soi-même après que le tour d'un joueur/bot se termine.
	until win or (tmpstr = 'QUITTER') or (tmpstr = 'TRICHERIE'); // On joue jusqu'à ce qu'on veut quitter, que quelqu'un gagne ou que quelqu'un triche.
	if win then quiGagne(not turn,multi) // not turn, car turn est inversé après que quelqu'un arrive au trésor !
	else if tmpstr = 'TRICHERIE' then defeatTriche();
end;

procedure deplaPapier(var grille : matrix ; var curseur : coord ; taille : coord ; direc : array_coord ; sens, type_case : integer);
// INGOUFF Christian, 24/01/12
// Gère le déplacement du curseur dans l'éditeur manuel de grilles
begin
	if (direc[sens,1] > 0) and (direc[sens,2] > 0) and (direc[sens,1] < taille[1]-1) and (direc[sens,2] < taille[2]-1) then // Si on dépasse pas les bornes
	begin
		case grille[curseur[1],curseur[2]] of // On modifie le statut de la case où on était
			-66 : grille[curseur[1],curseur[2]] := -42; // Murs sélectionnés redeviennent murs
			-65 : grille[curseur[1],curseur[2]] := 10; // Entrée sélectionnée redevient entrée
			-64 : grille[curseur[1],curseur[2]] := 42; // Trésor sélectionné redevient trésor
		else grille[curseur[1],curseur[2]] := 0; // Sinon redevient vide
		end;
		curseur := direc[sens]; // On passe à la case où on veut aller
		case grille[curseur[1],curseur[2]] of // On modifie le statut de la case où on veut aller
			-42 : grille[curseur[1],curseur[2]] := -66; // Murs deviennent sélectionnés
			10 : grille[curseur[1],curseur[2]] := -65; // Entrée devient sélectionnée
			42 : grille[curseur[1],curseur[2]] := -64; // Trésor devient sélectionné
		else grille[curseur[1],curseur[2]] := type_case; // Sinon devient type de case à placer
		end;
	end;
end;

procedure remplPapier(var grille : matrix ; taille : coord ; nb_murs : integer ; var curseur : coord ; type_case : integer ; var quit : boolean);
// INGOUFF Christian, 24/01/12
// Editeur manuel de grilles : place un type de case prédéfini
var
	ch : char;
	direc : array_coord;
begin
	repeat
		clrscr;
		affichSingleGrille(grille,taille); // Affiche la grille à remplir à l'écran
		if type_case = -42 then writeln(#10,#13,'Il vous reste ',nb_murs,' murs à placer. ECHAP pour quitter, ENTREE pour valide.',#10,#13) else writeln(#10,#13,'Il y aura ',nb_murs,' murs. ECHAP pour quitter, ENTREE pour valide.',#10,#13);
		case type_case of
			10 : writeln('Définissez la porte d''entrée.');
			42 : writeln('Définissez le trésor');
			-42 : writeln('Définissez les murs');
		end;
		arrayDirec(direc,curseur); // Cases adjacentes
		ch := ReadKey; // Détecteur de flèches directionnelles
		if ch = #0 then
			case ReadKey of
				#72 :   deplaPapier(grille,curseur,taille,direc,1,type_case); // Haut
				#80 :   deplaPapier(grille,curseur,taille,direc,2,type_case); // Bas
				#75 :   deplaPapier(grille,curseur,taille,direc,3,type_case); // Gauche
				#77 :   deplaPapier(grille,curseur,taille,direc,4,type_case); // Droite
			end;
	until (ch = #13) or (ch = #27) ; // Jusqu'à ENTREE ou ECHAP
	quit := ch = #27;
	if (grille[curseur[1],curseur[2]] < type_case) and not quit then // Si la case est déjà occupée par autre chose
	begin
		writeln('Cette case est déjà occupée ! Appuyez sur ENTREE pour replacer l''objet');
		readln;
		remplPapier(grille,taille,nb_murs,curseur,type_case,quit);
	end;
end;

procedure iniPapier(var grille : matrix ; taille : coord ; var tresor, enter : coord ; multi : boolean ; var murs, quit : boolean ; joueur : integer);
// INGOUFF Christian, 24/01/12
// Procédure qui gère la création manuelle de grilles
var
	i, nb_murs : integer;
	curseur : coord;
	ch : char;
begin
	affichJoueur(joueur);
	i := 0;
	ch := #0;
	nb_murs := trunc(( 15 / 49 ) * ( (taille[1]-2) * (taille[2]-2) )); // Définit le nombre de murs
	remiseZero(grille,taille,0); // Initialise la grille à remplir
	grille[1,1] := 10;
	curseur[1] := 1; // On place le curseur à la 1ère case
	curseur[2] := 1;
	remplPapier(grille,taille,nb_murs,curseur,10,quit); // Placement du point d'entrée
	enter := curseur;
	grille[curseur[1],curseur[2]] := -65;
	if not quit then remplPapier(grille,taille,nb_murs,curseur,42,quit); // Placement du trésor
	tresor := curseur;
	grille[curseur[1],curseur[2]] := -64;
	if not multi and not quit then // On laisse le choix : jeu papier, ou grille entièrement créee dans le programme
	begin
		writeln('Appuyez sur ECHAP si vous voulez conserver vos murs sur un papier ou sur ENTREE si vous voulez les placer ici');
		repeat ch := ReadKey until (ch = #13) or (ch = #27);
	end;
	murs := (multi or (ch = #13)) and not quit;
	if murs then
		while (i < nb_murs) and not quit do
		begin
			repeat
				remplPapier(grille,taille,nb_murs-i,curseur,-42,quit);
				murs := dijkstra(grille,enter,tresor,taille) > -1; // Placement des murs (avec vérification de la validité de la grille)
				if not murs and not quit then
				begin
					writeln('Le placement de ce mur rendrait la grille invalide !');
					readln;
				end;
			until murs or quit; // Placement des murs
			if i = nb_murs-1 then grille[curseur[1],curseur[2]] := -42
			else grille[curseur[1],curseur[2]] := -66;
			i := i+1;
		end;
end;

procedure setGrille(var grille1, grille2, grillejeu1, grillejeu2 : matrix ; var taille : coord ; choixH1 : integer);
// INGOUFF Christian, 21/01/12
// les setLength des différentes grilles nécessaires, selon la taille définie dans les paramètres.
begin
	case choixH1 of
		0 :	taille[1] := 7; // Petit (5x5)
		1 :	taille[1] := 9; // Normal (7x7)
		2 :	taille[1] := 12; // Grand (10x10)
	end;
	taille[2] := taille[1];
	setLength(grille1,taille[1],taille[2]);
	setLength(grille2,taille[1],taille[2]);
	setLength(grillejeu1,taille[1],taille[2]);
	setLength(grillejeu2,taille[1],taille[2]);
end;

function diffMin(taille, choixH2 : integer):integer;
// INGOUFF Christian, 21/01/12
// Nombre minimum de coups pour la création de la grille
begin
	case choixH2 of
		0 :	diffMin := trunc(taille / 1.5); // Facile
		1 :	diffMin := trunc(taille * 1.5); // Normal
		2 :	diffMin := trunc(taille * 2.5); // Difficile
	end;
end;

function diffMax(taille, choixH2 : integer):integer;
// INGOUFF Christian, 21/01/12
// Nombre maximum de coups pour la création de la grille
begin
	case choixH2 of
		0 :	diffMax := trunc(taille * 1.5); //Facile
		1 :	diffMax := trunc(taille * 2.5); //Normal
		2 :	diffMax := taille*taille; //Difficile
	end;
end;

procedure nouvellePartie(choixH1, choixH2, choixH3, choixH4 : integer ; multi, demo : boolean);
// INGOUFF Christian - 20/01/12
// Procédure qui gère l'initialisation de la nouvelle partie
// choixH1 // taille
// choixH2 // difficulté
// choixH3 // carte
// choixH4 // vitesse du bot
var
	grille1, grille2, grillejeu1, grillejeu2 : matrix;
	taille, enter1, enter2, tresor1, tresor2 : coord;
	murs, quit : boolean;
begin
	murs := FALSE;
	quit := FALSE;
	clrscr;
	setGrille(grille1,grille2,grillejeu1,grillejeu2,taille,choixH1); // Prépare les grilles en fonction de leur taille
	case choixH3 of
		0 : iniPapier(grille2,taille,tresor2,enter2,multi,murs,quit,1); //Personelle
		1 : if multi then iniGrille(grille2,taille,tresor2,enter2,diffMin(taille[1],choixH2),diffMax(taille[1],choixH2))
			else iniGrille(grille2,taille,tresor2,enter2,(taille[1]-2)*2,taille[1]*taille[1]); //Aléatoire
	end;
	if not quit then
	if not multi or (choixH3 = 1) then iniGrille(grille1,taille,tresor1,enter1,diffMin(taille[1],choixH2),diffMax(taille[1],choixH2))
	else iniPapier(grille1,taille,tresor1,enter1,multi,murs,quit,2); //Personelle
	if not quit then
	begin
		murs := murs or (choixH3 > 0);
		remiseZero(grillejeu1,taille,0); // Initialise les grilles de jeu
		remiseZero(grillejeu2,taille,0);
		taille[1] := taille[1]-2; // Recalibrage des tailles (de (x+2)*(x+2) on passe à x*x)
		taille[2] := taille[2]-2;
		grillejeu1[tresor1[1],tresor1[2]] := 42; // Placement du trésor...
		grillejeu2[tresor2[1],tresor2[2]] := 42;
		grillejeu1[enter1[1],enter1[2]] := 15; // et de l'entrée sur les grilles de jeu
		grillejeu2[enter2[1],enter2[2]] := 15;
		if demo then
			ordoBot(grille1,grille2,grillejeu1,grillejeu2,taille,enter1,enter2,tresor1,tresor2,choixH4)
		else
			ordonnanceur(grille1,grille2,grillejeu1,grillejeu2,taille,enter1,enter2,tresor1,tresor2,multi,not murs,choixH4); // Lance l'ordonnanceur
		// not murs : VRAI si l'utilisateur a placé ses murs lui même ou la grille a été générée aléatoirement. FAUX si jeu sur papier.
	end;
end;


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//							  // MENU PRINCIPAL, OPTIONS //
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


procedure menuPrincipal(var quit : boolean;var choixH1,choixH2,choixH3,choixH4: integer);
forward;
procedure menuParametre(var choixH1,choixH2,choixH3,choixH4: integer);
forward;

procedure encadrementChoix (var choixH1, choixH2, choixH3, choixH4:integer); // permet de ne pas sortir des possibilités de choix horizontaux dans le menu paramètre
// RODRIGUEZ Sébastien, 21/01/12
begin
   if choixH1<0 then choixH1 :=2;
   if choixH2<0 then choixH2 :=2;
   if choixH3<0 then choixH3 :=1;
   if choixH4<0 then choixH4 :=2;
   if choixH1>2 then choixH1 :=0;
   if choixH2>2 then choixH2 :=0;
   if choixH3>1 then choixH3 :=0;
   if choixH4>2 then choixH4 :=0;
end;

procedure modificationParametreH(var choixH1,choixH2,choixH3,choixH4:integer;choixParametre,modif:integer); //guide l'utilisateur dans les choix horizontaux du menu paramètre
//RODRIGUEZ Sébastien
begin
	   if choixParametre =0 then choixH1:=(choixH1 +modif)
	   else if choixParametre =1 then choixH2:=(choixH2 +modif)
	   else if choixParametre =2 then choixH3:=(choixH3 +modif)
	   else choixH4 := (choixH4 +modif);
end;

procedure destinationMenu(choix:integer;var choixH1,choixH2,choixH3,choixH4: integer);
// RODRIGUEZ Sébastien - 11/01/12
// Gère les destinations des choix effectués dans le menu principal
var
   ch : char;
   page : boolean;
begin
   case choix of
	0:	nouvellePartie(choixH1,choixH2,choixH3,choixH4,FALSE,FALSE); // Jeu solo, donc multi = FALSE (2ème FALSE = not demo mode)
	1:	nouvellePartie(choixH1,choixH2,choixH3,choixH4,TRUE,FALSE); // Jeu multi
	2:	memoryIni(choixH1,choixH2); // Memory mode
	3:	timeAttack(choixH1,choixH2); // contre la montre
	4:	menuParametre(choixH1,choixH2,choixH3,choixH4);{Procedure des Parametres}
	5:	begin
			page := TRUE;
			clrscr;
			titre();
			commentJouer();
			repeat
				ch:=ReadKey;
				if (ch=#13) or (ch=#72) or (ch=#75) or (ch=#80) or (ch=#77) then page:= (not page);
				if page then
				begin
					clrscr;
					titre();
					commentJouer();
				end
				else
				begin
					commentJouerModes();
					commentJouerCommandes();// lignes 52 à 77
				end;
			until (ch=#27) or (ch=#8);
		end;
	6:	nouvellePartie(choixH1,choixH2,choixH3,choixH4,TRUE,TRUE); // Démonstration : Bot vs Bot
   end;
end;

procedure menuParametre(var choixH1,choixH2,choixH3,choixH4: integer);
// RODRIGUEZ Sébastien - 11/01/12
// Procédure qui gère le déplacement dans le menu paramètre
var
 choixParametre: integer;
 ch: char;
begin
 choixParametre:=0;
 ch := '0';
 repeat
     choixMenuParametre(choixParametre,choixH1,choixH2,choixH3,choixH4);
         ch:=ReadKey;
         case ch of {#72=HAUT, #80=BAS, #75=GAUCHE, #77=DROITE}
             #72 :    begin
                     choixParametre := (choixParametre - 1); {monte dans le choix}
                     if (choixParametre <0) then choixParametre:=3;
                     end;    
             #75 :   begin
                     modificationParametreH(choixH1,choixH2,choixH3,choixH4,choixParametre,-1);
                     encadrementChoix(choixH1,choixH2,choixH3,choixH4);
                     end;
             #77 :    begin
                     modificationParametreH(choixH1,choixH2,choixH3,choixH4,choixParametre,+1);
                     encadrementChoix(choixH1,choixH2,choixH3,choixH4);
                     end;
             #80 :    begin
                     choixParametre := (choixParametre + 1);  {descend dans le choix}
                         if (choixParametre >3) then choixParametre:= 0;
                 end;
         end;
 until (ch=#27) or  (ch=#8);{= echap ou rett arr}
end;

procedure menuPrincipal(var quit : boolean;var choixH1,choixH2,choixH3,choixH4: integer);
// RODRIGUEZ Sébastien - 11/01/12
// Procédure qui gère le menu principal
var
	choix: integer;
	ch: char;
begin
	choix:=0;
	ch := '0';
	quit := FALSE;
	repeat
	     choixMenu(choix);
	     ch := ReadKey;
	     if ch = #0 then
	     begin
		 ch:=ReadKey; {Read ScanCode}
		 case ch of {#72=HAUT, #80=BAS, #75=GAUCHE, #77=DROITE}
		     #72 :    begin
		             choix := (choix - 1); {monte dans le choix}
		             if (choix <0) then choix:=7;
		             end;            
		     #80 :    begin
		             choix := (choix + 1);  {descend dans le choix}
		                 if (choix >7) then choix:= 0;
			      end;
		 end;
	     end;
	until (ch=#13);{#13=Entrée}
	quit := choix = 7;
	if (ch=#13) and not quit then
	     destinationMenu(choix,choixH1,choixH2,choixH3,choixH4)
	else clrscr;
end;

procedure debutMenu(var choixH1,choixH2,choixH3,choixH4: integer);
// RODRIGUEZ Sébastien - 11/01/12
// Initialise le menu principal.
var
 quit : boolean;
begin
	 clrscr;
	 writeln(' ');
	 writeln(' ');
	 menuPrincipal(quit,choixH1,choixH2,choixH3,choixH4);
	 if not quit then debutMenu(choixH1,choixH2,choixH3,choixH4);
end;

var
choixH1,choixH2,choixH3,choixH4: integer;

begin
	 choixH1:=1; // taille 0= petit(5x5) 1=moyen (7x7) 2=grand(10x10)
	 choixH2:=1; // difficulté 0=facile 1=moyen 2=difficile
	 choixH3:=0; // labyrinthe 0=personnel 1=aléatoire
	 choixH4:=2; // vitesse du bot 2=normale 1=rapide 0=instantanée
	 clrscr;
	 randomize;
	 titre();//lignes 173 à 198
	 writeln('');
	 writeln('');
	 logo(); // lignes 200 à 225
	 writeln('');
	 TextColor(White + Blink);
	 writeln('                                               Appuyez sur n''importe quelle touche.');
	 TextColor(White);
	 LowVideo;
	 repeat until ReadKey <> #0;
	 debutMenu(choixH1,choixH2,choixH3,choixH4);
end.
