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 MENU    //
//

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(' ');
  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 couleure rouge est la grille du joueur dont ce n''est pas le tour.');
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('                     |___|');
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
  commentJouerCommandes();// lignes 52 à 77
  writeln('');
  writeln('                                 - Appuyez sur ECHAP ou RET. ARRIERE pour retourner au menu. -');
end;

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;

//
//                    //    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));//lignes 257 à 271
  if tourjoueur then TextColor(Red) else TextColor(White);
  LowVideo;
  writeln(grilBordHaut(taille));//lignes 257 à 271
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);//lignes 231 à 255
  writeln(grilBordHaut(tailletmp));//lignes 257 à 271
  for i := 0 to tailletmp[2]-1 do
  begin
      writeln(grilCaseBord(tailletmp,TRUE));//lignes 273 à 287
      writeln(grilCaseMilieu(grilchar,tailletmp,i));//lignes 289 à 301
      writeln(grilCaseBord(tailletmp,FALSE));//lignes 273 à 287
  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);//lignes 231 à 255
  convertgrille(grillejeu2,grilcharbot,taille);//lignes 231 à 255
  affichHautGrille(taille,tourjoueur);//lignes 303 à 324
  for line := 0 to taille[2]-1 do
  begin
      if tourjoueur then TextColor(White) else TextColor(Red);
      LowVideo;    
      write(grilCaseBord(taille,TRUE));//lignes 273 à 287
      if tourjoueur then TextColor(Red) else TextColor(White);
      LowVideo;
      writeln(grilCaseBord(taille,TRUE));//lignes 273 à 287
      if tourjoueur then TextColor(White) else TextColor(Red);
      LowVideo;    
      write(grilCaseMilieu(grilcharjr,taille,line));//lignes 289 à 301
      if tourjoueur then TextColor(Red) else TextColor(White);
      LowVideo;
      writeln(grilCaseMilieu(grilcharbot,taille,line));//lignes 289 à 301
      if tourjoueur then TextColor(White) else TextColor(Red);
      LowVideo;    
      write(grilCaseBord(taille,FALSE));//lignes 273 à 287
      if tourjoueur then TextColor(Red) else TextColor(White);
      LowVideo;
      writeln(grilCaseBord(taille,FALSE));//lignes 273 à 287
  end;
  TextColor(White);
  LowVideo;
end;

//
//                                                                 //    VERIFICATION DE LA GRILLE    //
//

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 extracGrille(var grille : matrix ; grilcoups : matrix ; loc : coord);
// INGOUFF Christian, 16/01/12
// Modélise le chemin obtenu avec algo Dijkstra. Part de trésor (case = nombre de coups) pour aller au départ (case = 0)
var
  direc : array_coord;
  i : integer;
begin
  arrayDirec(direc,loc);
  i := 1;
  if grille[loc[1],loc[2]] <> 10 then
      while i <= 4 do
          if grilcoups[direc[i,1],direc[i,2]] = grilcoups[loc[1],loc[2]] - 1 then
          begin
              grille[loc[1],loc[2]] := -1;
              extracGrille(grille,grilcoups,direc[i]);
              i := 5;
          end
          else
              i := i+1;
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 dijkstra(grille : matrix ; var grilcoups : matrix ; tresor, enter, taille : coord ; var nb_coups : integer);
// INGOUFF Christian, 16/01/12
// Test algorithme de Dijkstra (Chemin le plus court optimal, mais assez lourd en opérations)
// 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
  valide : boolean; // Sera FAUX si la grille s'avère ne pas être valide.
begin
  dist := 0;
  valide := TRUE;
  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 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;
  if not valide then nb_coups := -1 // Grille non valide
  else nb_coups := dist; // Nombre de coups optimal retourné
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 remiseZero(var grille, grille2 : 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 (grille2 va être une grille "tampon" qui va être remplie avec l'algorithme de Dijkstra (voir plus haut))
// k = 0 dans le cadre de l'initialisation des grilles vides (celles qui vont être affichées lors de la phase de jeu)
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
          begin
              grille2[i,j] := -42;
              grille[i,j] := -42;
          end
          else
          begin
              grille[i,j] := 0;
              grille2[i,j] := k;
          end;
end;

procedure iniGrilleOpt(var grille : matrix ; taille : coord ; var tresor, enter : coord ; min, max : integer);
// INGOUFF Christian
var
  nb_murs : integer;
  direc : array_coord;
  grilcoups : matrix;
begin
  setLength(grilcoups,taille[1],taille[2]);
  nb_murs := trunc(( 15 / 49 ) * ( (taille[1]-2) * (taille[2]-2) )); // Définit le nombre de murs
  remiseZero(grille,grilcoups,taille,-1);
  remplCase(grille,taille,42,tresor); // Trésor = 42
  remplCase(grille,taille,10,enter); // Porte d'entrée = 10
  grilcoups[enter[1],enter[2]] := 0; // Point d'entrée pour "dijkstra"
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
// 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;
  grilcoups : matrix; // Grille qui va gérer le vérificateur de grilles (nombre de coups)
begin
  setLength(grilcoups,taille[1],taille[2]);
  remiseZero(grille,grilcoups,taille,-1); // 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
  grilcoups[enter[1],enter[2]] := 0; // Point d'entrée pour "dijkstra"
  for i := 1 to nb_murs do
  begin
      remplCase(grille,taille,-42,tmp); // Mur = -42
      grilcoups[tmp[1],tmp[2]] := -42; // Reporte les murs sur la grille pour "dijkstra"
  end;
  dijkstra(grille,grilcoups,tresor,enter,taille,nb_coups); // Vérifie si la grille est valide ou non
  if (nb_coups <= min) then // 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)
  else
  begin
      extracGrille(grille,grilcoups,tresor);
      grille[tresor[1],tresor[2]] := 42;
      grille[enter[1],enter[2]] := 10;
  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) avec une phrase de congratulation!
begin
  clrscr;
  TextColor(White);
  LowVideo;
  titre(); //lignes 173 à 198
  writeln('');
  writeln('');
  victoryScreen();// lignes147 à 171
  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();//lignes 173 à 198
  writeln('');
  writeln('');
  defeatScreen();// lignes 116 à 145
  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 triche du joueur lorsqu'il a fait une grille invalide en version labyrinthe personnel
begin
  clrscr;
  TextColor(Red);
  LowVideo;
  titre();//lignes 173 à 198
  writeln('');
  writeln('');
  cheat();//lignes 92 à 114
  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 dijkstraCoup(grillejeu2 : matrix ; taille, enter, xbot, tresor : coord ; direc : array_coord):integer;
// INGOUFF Christian - 16/01/12
// Retourne la case que le bot devrait suivre pour suivre le chemin optimal (suivant l'algorithme de Dijkstra)
var
  i, j : integer;
    griltmp, griltmp2 : matrix;
begin
  setLength(griltmp,taille[1],taille[2]);
  setLength(griltmp2,taille[1],taille[2]);
  for i := 0 to taille[1]-1 do
      for j := 0 to taille[2]-1 do
          if grillejeu2[i,j] = -42 then griltmp[i,j] := -42
          else griltmp[i,j] := -1;
  griltmp[xbot[1],xbot[2]] := 0;
  dijkstra(grillejeu2,griltmp,tresor,xbot,taille,i);
  if i = -1 then dijkstraCoup := -1
  else
  begin
      extracGrille(griltmp2,griltmp,tresor);
      i := 1;
      repeat
          if griltmp2[direc[i,1],direc[i,2]] = -1 then
          begin
              dijkstraCoup := i;
              i := 5;
          end
          else i := i+1;
      until i > 4;
  end;
end;

function ecrireFlecheDroite(ok : boolean):string;// Retourne une flèche vers la droite(en ASCII) si le choix dans le menu principal correspond
//RODRIGUEZ Sébastien
forward;

procedure requeteBot(grillejeu1,grillejeu2 : matrix ; tailletmp : coord ; var valide : boolean);
// INGOUFF Christian
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=HAUT, #80=BAS, #75=GAUCHE, #77=DROITE}
              #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);
// INGOUFF Christian
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 := dijkstraCoup(grillejeu2,taille,enter,xbot,tresor,direc);
      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 dijkstraCoup(grillejeu2,taille,enter,xbot,tresor,direc) = -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;var choixH4:integer);
// 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,dijkstraCoup(grillejeu2,taille,enter,xbot,tresor,direc),valide);
      if ecran_gauche then affichGrille(grillejeu2,grillejeu1,tailletmp,TRUE)
      else affichGrille(grillejeu1,grillejeu2,tailletmp,FALSE);
      writeln('');
      delay(250*choixH4);
      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,choixH4);
      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  Ingouff Christian- 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
      else
      begin
             clrscr;
      if ecran_gauche then affichGrille(grillejeu1,grillejeu2,tailletmp,TRUE)
             else affichGrille(grillejeu2,grillejeu1,tailletmp,FALSE);
          writeln('     Vous avez rencontré un mur ! Appuyez sur ENTREE.');
          readln;
      end
  end;
end;

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

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 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 vers la gauche(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();//lignes 173 à 198
 writeln('                                                      UN JOUEUR'+ecrireFlecheDroite(choix=0));
 writeln('                                                      DEUX JOUEURS'+ecrireFlecheDroite(choix=1));
 writeln('                                                      PARAMETRES'+ecrireFlecheDroite(choix=2));
 writeln('                                                      COMMENT JOUER?'+ecrireFlecheDroite(choix=3));
 writeln('                                                      QUITTER'+ecrireFlecheDroite(choix=4));
end;

function grandeur(choixFormat:integer):string; // différents choix possibles pour l'option taille de la grille dans le menu paramètres
// RODRIGUEZ Sébastien
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; // différents choix possibles pour l'option difficulté de la grille dans le menu paramètre
// RODRIGUEZ Sébastien
begin
 case choixHard of
 0: difficulte:= 'Facile';
 1: difficulte:= 'Normal';
 2: difficulte:= 'Difficile';
 end;
end;

function carte(choixCarte:integer):string; // différents choix possibles pour l'option type de labyrinthe dans le menu paramètres
// RODRIGUEZ Sébastien
begin
 case choixCarte of
 0: carte:= 'Personnel';
 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('');
     end;
  1: begin
     writeln('                                         Détermine la difficulté du niveau généré pour le joueur.');
     writeln('');
       end;
  2:begin
    writeln('                                                Détermine l''origine du labyrinthe :');
     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('');
     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;

function quiCommence():boolean;
// INGOUFF Christian - 20/01/12
// Simulateur de pile ou face, retourne VRAI ou FAUX au hasard pour déterminer le joueur qui commence
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 choixH4:integer);
// INGOUFF Christian
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,choixH4);
      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);
// INGOUFF Christian
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);
// INGOUFF Christian
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=HAUT, #80=BAS, #75=GAUCHE, #77=DROITE}
              #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);
// INGOUFF Christian
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);
// INGOUFF Christian
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;
// INGOUFF Christian
begin
  case choixH2 of
      0 :    diffMin := nb_cases div 10; //Facile
      1 :    diffMin := nb_cases div 5; //Normal
      2 :    diffMin := nb_cases div 3; //Difficile
  end;
end;

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

procedure nouvellePartie(choixH1, choixH2, choixH3, choixH4 : integer ; multi : boolean);
// INGOUFF Christian - 20/01/12
// Procédure qui gère l'initialisation de la nouvelle partie
// choixH1 // taille
// choixH2 // difficulté
// choixH3 // labyrinthe
// choixH4 // vitesse du bot
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);
  writeln(nb_cases);
  writeln(diffMin(nb_cases,choixH2),',',diffMax(nb_cases,choixH2));
  readln;
  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,nb_cases)
  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,grillejeu2,taille,0); // Initialise les grilles de jeu
  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,choixH4);   
end;

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

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;
begin
 case choix of
     0:    nouvellePartie(choixH1,choixH2,choixH3,choixH4,FALSE); // Jeu solo, donc multi = FALSE
     1:    nouvellePartie(choixH1,choixH2,choixH3,choixH4,TRUE); // Jeu multi
     2:    menuParametre(choixH1,choixH2,choixH3,choixH4);{Procedure des Parametres}
     3:    begin
          clrscr;
          titre();//lignes 173 à 198
          commentJouer();
          repeat ch := ReadKey until (ch = #27) or (ch = #8);
      end;
 end;
end;

procedure encadrementChoix (var choixH1, choixH2, choixH3, choixH4:integer); // permet de ne pas sortir des possibilités de choix horizontaux dans le menu paramètre
// INGOUFF Christian
begin
   if choixH1<0 then choixH1 :=3;
   if choixH2<0 then choixH2 :=2;
   if choixH3<0 then choixH3 :=1;
   if choixH4<0 then choixH4 :=2;
   if choixH1>3 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 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:=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,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:=0; // taille 0= petit(5x5) 1=moyen (7x7) 2=grand(10x10) 3=très grand(15x15)
 choixH2:=0; // 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.
