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 : 7.1 (21/01/12)
// Version : 8.0 (23/01/12) : Bot vs. bot et joueur vs. joueur

uses crt, sysutils;
type
	matrix = array of array of integer;
	matstring = array of array of string;
	coord = array[1..2] of integer;
	array_coord = array[1..4] of coord;
	array_itg = array[1..4] of integer;
	array_bool = array[1..4] of boolean;

//
//                                                                 //    DESIGN ET ASCII ART    //
//

procedure commentJouerJeu();
// 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();
// RODRIGUEZ Sébastien
// Instructions pour le jeu.
begin
	writeln(' ');
	writeln(' ');
	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.');
end;

procedure commentJouerCommandes();
// 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('                     |___|');
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();
	commentJouerRegles();
	commentJouerCommandes();
	writeln('');
	writeln('                                 - Appuyez sur ECHAP ou RET. ARRIERE pour retourner au menu. -');
end;

procedure cheat();
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();
// 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();
// 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 ();
// 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();
// 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;

//
//                    //    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
				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;
	for i := 1 to (taille[2]-1) do write('     ');
	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;
	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 affichGrille(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	//
//

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
// k = -1 dans le cadre de l'initialisation de la grille valide (grille tampon)
// 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 tampon (grilcoups) avec les cases libres marquées de leur distance par rapport au départ, ainsi que le nombre de coups optimal.
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
	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;
var
	grilcoups : matrix;
	valide : boolean;
begin
	setLength(grilcoups,taille[1],taille[2]);
	remiseZero(grilcoups,taille,-1);
	grilcoups[enter[1],enter[2]] := 0;
	valide := TRUE;
	dijkstraGrille(grille,grilcoups,tresor,enter,taille,valide);
	if not valide then dijkstra := -1 // Grille non valide
	else dijkstra := grilcoups[tresor[1],tresor[2]]; // Nombre de coups optimal
end;

function recurMeilleur(prec, loc : coord ; grilcoups : matrix):coord;
// Fonction récursive qui parcourt le chemin le plus court (tracé par Dijkstra) depuis le trésor jusqu'au point 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);
	sens := 1;
	if grilcoups[loc[1],loc[2]] <> 0 then
		while sens < 5 do
		begin
			if grilcoups[direc[sens,1],direc[sens,2]] = grilcoups[loc[1],loc[2]]-1 then
			begin
				recurMeilleur := recurMeilleur(loc,direc[sens],grilcoups);
				sens := 5;
			end
			else sens := sens+1;
		end
	else recurMeilleur := prec;
end;

function meilleurCoup(grille : matrix ; tresor, depart, taille : coord):integer;
// Fonction qui recherche la direction la plus avantageuse
// 1 = Haut, 2 = Bas, 3 = Gauche, 4 = Droite
var
	direc : array_coord;
	objectif : coord;
	i : integer;
	grilcoups : matrix;
	valide : boolean;
begin
	meilleurCoup := -1;
	setLength(grilcoups,taille[1],taille[2]);
	remiseZero(grilcoups,taille,-1);
	grilcoups[depart[1],depart[2]] := 0;
	valide := TRUE;
	dijkstraGrille(grille,grilcoups,tresor,depart,taille,valide);
	if valide then
	begin
		arrayDirec(direc,depart);
		objectif := recurMeilleur(depart,tresor,grilcoups);
		i := 1;
		repeat
			if (direc[i,1] = objectif[1]) and (direc[i,2] = objectif[2]) then meilleurCoup := i;
			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;
		if valide then grille[coord_case[1],coord_case[2]] := type_case
	until valide;
end;

procedure deplacement(grille : matrix ; var grillejeu1 : matrix ; var joueur : coord ; enter : coord ; direc : array_coord ; sens : integer ; var valide : boolean);
forward;
	
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
// 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;
	direc : array_coord;
	valide : boolean;
begin
	remiseZero(grille,taille,0); // Initialise les grilles
	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) < (taille[1]*taille[2]) div 20 then iniGrille(grille,taille,tresor,enter,min,max)
	else
	begin
		arrayDirec(direc,enter);
		for i := 1 to nb_murs do
			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;
			until valide;
		nb_coups := dijkstra(grille,tresor,enter,taille); // Vérifie si la grille est valide ou non
		if (nb_coups < min) or (nb_coups > max) then	// Si la grille n'est valide ou ne vérifie pas les conditions de la difficulté de jeu
			iniGrille(grille,taille,tresor,enter,min,max);
	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.
// Sens : 1 = haut, 2 = bas, 3 = gauche, 4 = droite (cf. procédure "bouger")
// Valide : Renvoie si le déplacement est valide ou non
begin
	valide := grille[direc[sens,1],direc[sens,2]] > -42;
	if valide then
	begin
		if (joueur[1] = enter[1]) and (joueur[2] = enter[2]) then
			grillejeu1[joueur[1],joueur[2]] := 10
		else
			grillejeu1[joueur[1],joueur[2]] := -1;
		joueur := direc[sens];
		grillejeu1[joueur[1],joueur[2]] := 14+sens;
	end
	else
	begin
		grillejeu1[direc[sens,1],direc[sens,2]] := -42;
		grillejeu1[joueur[1],joueur[2]] := 14+sens;
	end;
end;

procedure victory(gagnant : string);
// RODRIGUEZ Sébastien - 16/01/12
// Affiche l'écran de victoire (du joueur)
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();
// 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('                                ††††     Dommage, votre rival a trouvé le trésor avant vous!     ††††',#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 défaite (du joueur)
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;

function ecrireFlecheDroite(ok : boolean):string;
forward;

procedure requeteBot(grillejeu1,grillejeu2 : matrix ; tailletmp : coord ; var valide : boolean);
var
	ch : char;
begin
	repeat
		clrscr;
		affichGrille(grillejeu1,grillejeu2,tailletmp,FALSE);
		writeln('Quel est le type de cette case ?');
		writeln('');
		writeln('     Mur          ',ecrireFlecheDroite(not valide));
		writeln('     Case libre   ',ecrireFlecheDroite(valide));
		ch := ReadKey;
		if ch = #0 then
		begin
			ch := ReadKey;
			case ch of
				#72 :	valide := not valide;
				#80 :	valide := not valide;
			end;
		end;
	until ch = #13;
end;

procedure botJeuPapier(grillejeu1 : matrix ; var grillejeu2 : matrix ; taille, enter, tresor : coord ; var xbot : coord ; var win : boolean ; var tmpstr : string);
var
	direc : array_coord;
	sens_coup : integer;
	tailletmp : coord;
	valide : boolean;
begin
	win := (xbot[1] = tresor[1]) and (xbot[2] = tresor[2]);
	if not win then
	begin
		tailletmp[1] := taille[1]-2;
		tailletmp[2] := taille[2]-2;
		arrayDirec(direc,xbot);
		sens_coup := meilleurCoup(grillejeu2,tresor,xbot,taille);
		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
			deplacement(grillejeu2,grillejeu2,xbot,enter,direc,sens_coup,valide)
		else
		begin
			grillejeu2[direc[sens_coup,1],direc[sens_coup,2]] := -5;
			requeteBot(grillejeu1,grillejeu2,tailletmp,valide);
		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
			tmpstr := 'Votre rival a rencontré un mur ! C''est à votre tour.';
			grillejeu2[direc[sens_coup,1],direc[sens_coup,2]] := -42;
			if meilleurCoup(grillejeu2,tresor,xbot,taille) = -1 then tmpstr := 'TRICHERIE';
		end
		else
		begin
			deplacement(grillejeu2,grillejeu2,xbot,enter,direc,sens_coup,valide);
			clrscr;
			botJeuPapier(grillejeu1,grillejeu2,taille,enter,tresor,xbot,win,tmpstr);
		end;
	end;
end;

procedure bot(grille, grillejeu1 : matrix ; var grillejeu2 : matrix ; taille, enter, tresor : coord ; var xbot : coord ; var win : boolean ; ecran_gauche : boolean);
// INGOUFF Christian - 16/01/12
// Procédure qui gère le déplacement du bot
var
	direc : array_coord;
	tailletmp : coord;
	valide : boolean;
begin
	win := (xbot[1] = tresor[1]) and (xbot[2] = tresor[2]);
	if not win then
	begin
		tailletmp[1] := taille[1]-2;
		tailletmp[2] := taille[2]-2;
		arrayDirec(direc,xbot);
		deplacement(grille,grillejeu2,xbot,enter,direc,meilleurCoup(grillejeu2,tresor,xbot,taille),valide);
		if ecran_gauche then affichGrille(grillejeu2,grillejeu1,tailletmp,TRUE)
		else affichGrille(grillejeu1,grillejeu2,tailletmp,FALSE);
		writeln('');
		delay(500);
		if not valide then
		begin
			writeln('     Votre rival a rencontré un mur ! Appuyez sur ENTREE.');
			readln;
		end
		else
		begin
			clrscr;
			bot(grille,grillejeu1,grillejeu2,taille,enter,tresor,xbot,win,ecran_gauche);
		end;
	end;
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;
	tailletmp : coord;
begin
	win := (joueur[1] = tresor[1]) and (joueur[2] = tresor[2]);
	if not win then
	begin
		tailletmp[1] := taille[1]-2;
		tailletmp[2] := taille[2]-2;
		if ecran_gauche then affichGrille(grillejeu1,grillejeu2,tailletmp,TRUE)
		else affichGrille(grillejeu2,grillejeu1,tailletmp,FALSE);
		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);
		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}
		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'
		else if valide then
		begin
			clrscr;
			bouger(grille,grillejeu2,grillejeu1,taille,enter,tresor,joueur,win,tmpstr,ecran_gauche);
		end;
	end;
end;

//
//                  						  //    MENU PRINCIPAL    //
//

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

function ecrireFlecheGauche(ok : boolean):string;
// RODRIGUEZ Sébastien - 11/01/12
// Retourne une flèche (en ASCII) si le choix dans le menu principal 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();
   writeln('                                                      UN JOUEUR'+ecrireFlecheDroite(choix=0));
   writeln('                                                      DEUX JOUEURS'+ecrireFlecheDroite(choix=1));
   writeln('                                                      COMMENT JOUER?'+ecrireFlecheDroite(choix=2));
   writeln('                                                      PARAMETRES'+ecrireFlecheDroite(choix=3));
   writeln('                                                      QUITTER'+ecrireFlecheDroite(choix=4));
end;

function grandeur(choixFormat:integer):string;
begin
   case choixFormat of
   0: grandeur:= 'Petit (5x5)';
   1: grandeur:= 'Moyen (7x7)';
   2: grandeur:= 'Grand (10x10)';
   3: grandeur:= 'Très grand (15x15)';
   end;
end;

function difficulte(choixHard:integer):string;
begin
   case choixHard of
   0: difficulte:= 'Facile';
   1: difficulte:= 'Normal';
   2: difficulte:= 'Difficile';
   end;
end;

function carte(choixCarte:integer):string;
begin
   case choixCarte of
   0: carte:= 'Personnelle';
   1: carte:= 'Aléatoire';
   end;
end;

procedure choixMenuParametre(choixParametre,choixH1,choixH2,choixH3:integer);
// RODRIGUEZ Sébastien - 11/01/12
// Interface graphique/textuelle pour le menu des parametres
begin
   clrscr;
   titre();
   writeln('                                                  '+ecrireFlechegauche(choixParametre=0)+' TAILLE : ',grandeur(choixH1),ecrireFlecheDroite(choixParametre=0));
   writeln('                                                  '+ecrireFlechegauche(choixParametre=1)+' DIFFICULTE : ',difficulte(choixH2),ecrireFlecheDroite(choixParametre=1));
   writeln('                                                  '+ecrireFlechegauche(choixParametre=2)+' CARTE : ',carte(choixH3),ecrireFlecheDroite(choixParametre=2));
   writeln('');
   writeln('');
   writeln('                                                  ECHAP ou RET. ARRIERE.');
end;

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 quiGagne(turn, multi : boolean);
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();
end;

procedure ordonnanceur(grille1, grille2 : matrix ; var grillejeu1, grillejeu2 : matrix ; taille, enter1, enter2, tresor1, tresor2 : coord ; multi, papier : boolean);
var
	joueur1, joueur2 : coord;
	win, turn : boolean;
	tmpstr : string;
begin
	joueur1 := enter1;
	joueur2 := enter2;
	clrscr;
	win := FALSE;
	turn := quiCommence();
	if turn then tmpstr := 'Bienvenue ! Vous commencez, utilisez les flèches directionelles.'
	else tmpstr := 'Bienvenue ! Votre rival commence.';
	repeat
		clrscr;
		if turn and not win then bouger(grille1,grillejeu2,grillejeu1,taille,enter1,tresor1,joueur1,win,tmpstr,turn)
		else if not win then
			if multi then bouger(grille2,grillejeu1,grillejeu2,taille,enter2,tresor2,joueur2,win,tmpstr,turn)
			else if papier then botJeuPapier(grillejeu1,grillejeu2,taille,enter2,tresor2,joueur2,win,tmpstr)
			else bot(grille2,grillejeu1,grillejeu2,taille,enter2,tresor2,joueur2,win,turn);
		turn := not turn;
	until win or (tmpstr = 'QUITTER') or (tmpstr = 'TRICHERIE');
	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);
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
	begin
		case grille[curseur[1],curseur[2]] of
			-66 : grille[curseur[1],curseur[2]] := -42;// Murs
			-65 : grille[curseur[1],curseur[2]] := 10;// Entrée
			-64 : grille[curseur[1],curseur[2]] := 42;// Trésor
		else grille[curseur[1],curseur[2]] := 0;
		end;
		curseur := direc[sens];
		case grille[curseur[1],curseur[2]] of
			-42 : grille[curseur[1],curseur[2]] := -66;// Murs
			10 : grille[curseur[1],curseur[2]] := -65;// Entrée
			42 : grille[curseur[1],curseur[2]] := -64;// Trésor
		else grille[curseur[1],curseur[2]] := type_case;
		end;
	end;
end;

procedure remplPapier(var grille : matrix ; taille : coord ; nb_murs : integer ; var curseur : coord ; type_case : integer);
var
	ch : char;
	direc : array_coord;
begin
	repeat
		clrscr;
		affichSingleGrille(grille,taille);
		writeln('');
		if type_case = -42 then writeln('Il vous reste ',nb_murs,' murs à placer') else writeln('Il y aura ',nb_murs,' murs');
		writeln('');
		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);
		ch := ReadKey;
		if ch = #0 then
		begin
			ch := ReadKey;
			case ch 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;
		end;
	until ch = #13;
	if grille[curseur[1],curseur[2]] < type_case then
	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);
	end;
end;

procedure iniPapier(var grille : matrix ; taille : coord ; var tresor, enter : coord ; multi : boolean ; var murs : boolean);
var
	i, j, nb_murs : integer;
	curseur : coord;
	ch : char;
begin
	ch := #0;
	nb_murs := trunc(( 15 / 49 ) * ( (taille[1]-2) * (taille[2]-2) )); // Définit le nombre de murs
	for i := 0 to taille[1]-1 do
		for j := 0 to taille[2]-1 do
			if (i = 0) or (i = taille[1]-1) or (j = 0) or (j = taille[2]-1) then grille[i,j] := -42
			else grille[i,j] := 0;
	grille[1,1] := 10;
	curseur[1] := 1;
	curseur[2] := 1;
	remplPapier(grille,taille,nb_murs,curseur,10);
	enter := curseur;
	grille[curseur[1],curseur[2]] := -65;
	remplPapier(grille,taille,nb_murs,curseur,42);
	tresor := curseur;
	grille[curseur[1],curseur[2]] := -64;
	if not multi then
	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);
	if murs then
		for i := 0 to nb_murs-1 do
		begin
			remplPapier(grille,taille,nb_murs-i,curseur,-42);		
			if i = nb_murs-1 then grille[curseur[1],curseur[2]] := -42 else grille[curseur[1],curseur[2]] := -66;
		end;
end;

procedure setGrille(var grille1, grille2, grillejeu1, grillejeu2 : matrix ; var taille : coord ; choixH1 : integer);
begin
	case choixH1 of
		0 :	taille[1] := 7; // Petit (5x5)
		1 :	taille[1] := 9; // Normal (7x7)
		2 :	taille[1] := 12; // Grand (10x10)
		3 :	taille[1] := 17; // Très grand (15x15)
	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(nb_cases, choixH2 : integer):integer;
begin
	case choixH2 of
		0 :	diffMin := nb_cases div 10; //Facile
		1 :	diffMin := nb_cases div 5; //Normal
		2 :	diffMin := trunc(nb_cases/2.5); //Difficile
	end;
end;

function diffMax(nb_cases, choixH2 : integer):integer;
begin
	case choixH2 of
		0 :	diffMax := nb_cases div 5; //Facile
		1 :	diffMax := trunc(nb_cases/2.5); //Normal
		2 :	diffMax := trunc(nb_cases/1.5); //Difficile
	end;
end;

procedure nouvellePartie(choixH1, choixH2, choixH3 : integer ; multi : boolean);
// INGOUFF Christian - 20/01/12
// Procédure qui gère l'initialisation de la nouvelle partie
// choixH1 // taille
// choixH2 // difficulté
// choixH3 // carte
var
	nb_cases : integer;
	grille1, grille2, grillejeu1, grillejeu2 : matrix;
	taille, enter1, enter2, tresor1, tresor2 : coord;
	murs : boolean;
begin
	murs := FALSE;
	clrscr;
	setGrille(grille1,grille2,grillejeu1,grillejeu2,taille,choixH1); // Prépare les grilles en fonction de leur taille
	nb_cases := (taille[1]-2) * (taille[2]-2);
	case choixH3 of
		0 : iniPapier(grille2,taille,tresor2,enter2,multi,murs); //Personelle
		1 : iniGrille(grille2,taille,tresor2,enter2,diffMin(nb_cases,choixH2),diffMax(nb_cases,choixH2)); //Aléatoire
	end;
	if not multi then iniGrille(grille1,taille,tresor1,enter1,nb_cases div 4,trunc(nb_cases/1.5))
	else
	case choixH3 of
		0 : iniPapier(grille1,taille,tresor1,enter1,multi,murs); //Personelle
		1 : iniGrille(grille1,taille,tresor1,enter1,diffMin(nb_cases,choixH2),diffMax(nb_cases,choixH2)); //Aléatoire
	end;
	murs := murs or (choixH3 > 0);
	remiseZero(grillejeu1,taille,0); // Initialise les grilles de jeu
	remiseZero(grillejeu2,taille,0);
	grillejeu1[tresor1[1],tresor1[2]] := 42;
	grillejeu2[tresor2[1],tresor2[2]] := 42;
	grillejeu1[enter1[1],enter1[2]] := 15;
	grillejeu2[enter2[1],enter2[2]] := 15;
	ordonnanceur(grille1,grille2,grillejeu1,grillejeu2,taille,enter1,enter2,tresor1,tresor2,multi,not murs);
end;

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

procedure destinationMenu(choix:integer;var choixH1,choixH2,choixH3: integer);
// RODRIGUEZ Sébastien - 11/01/12
// Gère les destinations des choix effectués dans le menu principal
var
   ch : char;
begin
   case choix of
       0:	nouvellePartie(choixH1,choixH2,choixH3,FALSE); // Jeu solo, donc multi = FALSE
       1:	nouvellePartie(choixH1,choixH2,choixH3,TRUE); // Jeu multi
       2:	begin
			clrscr;
			titre();
			commentJouer();
			writeln('');
			writeln('');
			repeat ch := ReadKey until (ch = #27) or (ch = #8);
		end;
       3:	menuParametre(choixH1,choixH2,choixH3){Procedure des Parametres}
   end;
end;

procedure menuParametre(var choixH1,choixH2,choixH3: integer);
// RODRIGUEZ Sébastien - 11/01/12
// Procédure qui gère le menu principal
var
   choixParametre: integer;
   ch: char;
begin
   choixParametre:=0;
   ch := '0';
   repeat
       choixMenuParametre(choixParametre,choixH1,choixH2,choixH3);
           ch:=ReadKey; {Read ScanCode}
           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:=2;
                       end;    
               #75 :    begin
                       if choixParametre =0 then choixH1:=choixH1 -1
                       else if choixParametre =1 then choixH2:=choixH2 -1
                       else choixH3:=choixH3 -1;
                       if choixH1<0 then choixH1 :=3;
                       if choixH2<0 then choixH2 :=2;
                       if choixH3<0 then choixH3 :=1;
                       end;
               #77 :    begin
                       if choixParametre =0 then choixH1:=choixH1 +1
                       else if choixParametre =1 then choixH2:=choixH2 +1
                       else choixH3:=choixH3 +1;
                       if choixH1>3 then choixH1 :=0;
                       if choixH2>2 then choixH2 :=0;
                       if choixH3>1 then choixH3 :=0;
                       end;
               #80 :    begin
                       choixParametre := (choixParametre + 1);  {descend dans le choix}
                           if (choixParametre >2) 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: 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:=4;
                       end;            
               #80 :    begin
                       choix := (choix + 1);  {descend dans le choix}
                           if (choix >4) then choix:= 0;
                   end;
           end;
       end;
   until (ch=#13);{#13=Entrée}
   quit := choix = 4;
   if (ch=#13) and not quit then
       destinationMenu(choix,choixH1,choixH2,choixH3)
   else clrscr;
end;

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

begin
   choixH1:=0; // taille
   choixH2:=0; // difficulté
   choixH3:=0; // carte
   clrscr;
   randomize;
   titre();
   writeln('');
   writeln('');
   logo();
   writeln('');
   TextColor(White + Blink);
   writeln('                                               Appuyez sur n''importe quelle touche.');
   TextColor(White);
   LowVideo;
   repeat until ReadKey <> #0;
   debutMenu(choixH1,choixH2,choixH3);
end.
