#open "windows";;
#open "camlwin";;


#open "morpdsgn";;
#open "morp_bw";;
#open "colmorp";;  


(*  
Define the possibility of a place *)
type case_type = Player
               | Computer
               | Empty 
;; 


let game_board = make_matrix 3 3 Empty;;




 

let WhichColor Place =
  match Place with
    Player   -> rond_player.el_color
  | Computer -> rond_caml.el_color
  | Empty    -> black
;;

let WhichFormPlayer Place =
  match Place with
    Player   -> black
  | Computer -> transp
  | Empty    -> white
;;

let WhichFormComputer Place =
  match Place with
    Player   -> transp
  | Computer -> black
  | Empty    -> white
;;

(* Met a jour l'affichage en fonction de la matrice 3x3 Game.
   Ensuite, l'ensemble des images sont reaffichees.
*)         
let UpdateBoard () =
  if gr_is_color_look ()
  then
  (
    rond_0_0.el_color <- WhichColor game_board.(0).(0);
    rond_0_1.el_color <- WhichColor game_board.(0).(1);
    rond_0_2.el_color <- WhichColor game_board.(0).(2);
    rond_1_0.el_color <- WhichColor game_board.(1).(0);
    rond_1_1.el_color <- WhichColor game_board.(1).(1);
    rond_1_2.el_color <- WhichColor game_board.(1).(2);
    rond_2_0.el_color <- WhichColor game_board.(2).(0);
    rond_2_1.el_color <- WhichColor game_board.(2).(1);
    rond_2_2.el_color <- WhichColor game_board.(2).(2)
  )
  else
  (
    rond_0_0.el_color <- WhichFormPlayer game_board.(0).(0);
    rond_0_1.el_color <- WhichFormPlayer game_board.(0).(1);
    rond_0_2.el_color <- WhichFormPlayer game_board.(0).(2);
    rond_1_0.el_color <- WhichFormPlayer game_board.(1).(0);
    rond_1_1.el_color <- WhichFormPlayer game_board.(1).(1);
    rond_1_2.el_color <- WhichFormPlayer game_board.(1).(2);
    rond_2_0.el_color <- WhichFormPlayer game_board.(2).(0);
    rond_2_1.el_color <- WhichFormPlayer game_board.(2).(1);
    rond_2_2.el_color <- WhichFormPlayer game_board.(2).(2);
    square_0_0.re_color <- WhichFormComputer game_board.(0).(0);
    square_0_1.re_color <- WhichFormComputer game_board.(0).(1);
    square_0_2.re_color <- WhichFormComputer game_board.(0).(2);
    square_1_0.re_color <- WhichFormComputer game_board.(1).(0);
    square_1_1.re_color <- WhichFormComputer game_board.(1).(1);
    square_1_2.re_color <- WhichFormComputer game_board.(1).(2);
    square_2_0.re_color <- WhichFormComputer game_board.(2).(0);
    square_2_1.re_color <- WhichFormComputer game_board.(2).(1);
    square_2_2.re_color <- WhichFormComputer game_board.(2).(2)
  );
  gr_draw_window MorpionWin_def.win_id
;;

(* Renvoie le coule (true,Computer) si l'ordinateur a 3 pionts alignes,
   (true,Player) si le joueur a 3 pionts alignes,
   (true,Empty) si 3 cases vides sont alignes,
   (false,Empty) si personne n'a 3 cases alignes.
*)
let Winner () =
  let result=ref (false,Empty) in
    for i=0 to 2 do
      if game_board.(i).(1)=game_board.(i).(0) & game_board.(i).(1)=game_board.(i).(2)
      then result := (true,game_board.(i).(1))
    done;
    for i=0 to 2 do
      if game_board.(1).(i)=game_board.(0).(i) & game_board.(1).(i)=game_board.(2).(i)
      then result := (true,game_board.(1).(i))
    done;
    if (game_board.(0).(0)=game_board.(1).(1) & game_board.(0).(0)=game_board.(2).(2)) or
       (game_board.(0).(2)=game_board.(1).(1) & game_board.(0).(2)=game_board.(2).(0))
    then result := (true,game_board.(1).(1));
    !result
;;
    
(* Renvoie les coordonnees (x,y) de la case vide si le joueur ou
   l'ordinateur a 2 pionts alignes horizontalement sur la i eme ligne 
   et que la troisieme case et vide. Renvoie (-1,-1) sinon.
*)
let TwoHorizontal i =
  match (game_board.(i).(0),game_board.(i).(1),game_board.(i).(2)) with
    (Player,Player,Empty ) -> (2,i)
  | (Player,Empty ,Player) -> (1,i)
  | (Empty ,Player,Player) -> (0,i)
  | (Computer,Computer,Empty ) -> (2,i)
  | (Computer,Empty ,Computer) -> (1,i)
  | (Empty ,Computer,Computer) -> (0,i)
  | _  -> (-1,-1)
;;
    
(* Renvoie les coordonnees (x,y) de la case vide si le joueur ou
   l'ordinateur a 2 pionts alignes verticalement sur la i eme colone 
   et que la troisieme case et vide. Renvoie (-1,-1) sinon.
*)
let TwoVertical i =
  match (game_board.(0).(i),game_board.(1).(i),game_board.(2).(i)) with
    (Player,Player,Empty ) -> (i,2)
  | (Player,Empty ,Player) -> (i,1)
  | (Empty ,Player,Player) -> (i,0)
  | (Computer,Computer,Empty ) -> (i,2)
  | (Computer,Empty ,Computer) -> (i,1)
  | (Empty ,Computer,Computer) -> (i,0)
  | _ -> (-1,-1)
;;

(* Renvoie les coordonnees (x,y) de la case vide si le joueur ou
   l'ordinateur a 2 pionts alignes sur la diagonale de pente negative 
   et que la troisieme case et vide. Renvoie (-1,-1) sinon.
*)
let TwoDiagonal1 () =
  match (game_board.(0).(0),game_board.(1).(1),game_board.(2).(2)) with
    (Player,Player,Empty ) -> (2,2)
  | (Player,Empty ,Player) -> (1,1)
  | (Empty ,Player,Player) -> (0,0)
  | (Computer,Computer,Empty ) -> (2,2)
  | (Computer,Empty ,Computer) -> (1,1)
  | (Empty ,Computer,Computer) -> (0,0)
  | _ -> (-1,-1)
;;

(* Renvoie les coordonnees (x,y) de la case vide si le joueur ou
   l'ordinateur a 2 pionts alignes sur la diagonale de pente positive 
   et que la troisieme case et vide. Renvoie (-1,-1) sinon.
*)
let TwoDiagonal2 () =
  match (game_board.(0).(2),game_board.(1).(1),game_board.(2).(0)) with
    (Player,Player,Empty ) -> (0,2)
  | (Player,Empty ,Player) -> (1,1)
  | (Empty ,Player,Player) -> (2,0)
  | (Computer,Computer,Empty ) -> (0,2)
  | (Computer,Empty ,Computer) -> (1,1)
  | (Empty ,Computer,Computer) -> (2,0)
  | _ -> (-1,-1)
;;

(* Renvoie les coordonnees (x,y) de la case vide si le joueur ou
   l'ordinateur a 2 pionts alignes horizontalement et que la 
   troisieme case et vide. Renvoie (-1,-1) sinon.
*)
let rec horizontal_loop i =
  let Pos=TwoHorizontal i in
    match ((fst Pos) > -1, i = 2) with
      (true,_) -> Pos
    | (false,false) -> horizontal_loop (i+1)
    | (false,true ) -> (-1,-1)
;;

(* Renvoie les coordonnees (x,y) de la case vide si le joueur ou
   l'ordinateur a 2 pionts alignes verticalement et que la 
   troisieme case et vide. Renvoie (-1,-1) sinon.
*)
let rec vertical_loop i =
  let pos=TwoVertical i in
    match (fst pos > -1, i = 2) with
      (true,_) -> pos
    | (false,false) -> vertical_loop (i+1)
    | (false,true ) -> (-1,-1)
;;


let rec empty_pos_loop x y =
  if game_board.(y).(x)=Empty
  then (x,y)
  else if x < 2
       then empty_pos_loop (x+1) y  
       else if y<2 
            then empty_pos_loop 0 (y+1)
            else (-1,-1)
;;

(* Renvoie les coordonnees (x,y) d'une case vide,
   (-1,-1) si il n'en reste pas. 
*)
let EmptyPos () =
  if game_board.(1).(1)=Empty
  then (1,1)
  else empty_pos_loop 0 0
;;

(* choisit une case et fait jouer l'ordinateur.
*)
let Play () =
  let win=Winner () in
    if fst win=true & not snd win=Empty
    then 
      gr_warning "You win..."
                 [| {warn_name="Ok";
                     warn_callback=gr_close_warning}
                 |]
    else
    (
      let pos1 = horizontal_loop 0
      and pos2 = vertical_loop 0 
      and pos3 = TwoDiagonal1 ()
      and pos4 = TwoDiagonal2 ()
      and pos5 = EmptyPos () in
        (
          match (fst pos1 > -1, fst pos2 > -1, fst pos3 > -1,fst pos4 > -1,fst pos5 > -1) with
            (_, _, _, _, false) -> gr_warning "Equality. No winner."
                                             [| {warn_name="Ok";
                                                 warn_callback=gr_close_warning}
                                             |]
          | (_, _, true, _, _) -> game_board.(snd pos3).(fst pos3) <- Computer
          | (_, _, _, true, _) -> game_board.(snd pos4).(fst pos4) <- Computer
          | (true, _, _, _, _) -> game_board.(snd pos1).(fst pos1) <- Computer
          | (_, true, _, _, _) -> game_board.(snd pos2).(fst pos2) <- Computer
          | (false,false,false,false,true) -> 
                                  game_board.(snd pos5).(fst pos5) <- Computer
        );
        UpdateBoard ();
        let win=Winner () in
          if fst win=true & not snd win=Empty
          then 
            gr_warning "I win!"
                       [| {warn_name="Ok";
                           warn_callback=gr_close_warning}
                       |]
    )
;;


(* Prend en compte le coup du joueur, et fait jouer l'ordinateur
   tout de suite derriere.
*)

let Pos_0_0_callback Obj Event =
  if game_board.(0).(0) = Empty
  then 
  (
     game_board.(0).(0) <- Player;
     Play ()
  );
  true
;;

let Pos_0_1_callback Obj Event =
  if game_board.(0).(1) = Empty
  then 
  (
    game_board.(0).(1) <- Player;
    Play ()
  );
  true
;;

let Pos_0_2_callback Obj Event =
  if game_board.(0).(2) = Empty
  then 
  (
    game_board.(0).(2) <- Player;
    Play ()
  );
  true
;;

let Pos_1_0_callback Obj Event =
  if game_board.(1).(0) = Empty
  then 
  (
    game_board.(1).(0) <- Player;
    Play ()
  );
  true
;;

let Pos_1_1_callback Obj Event =
  if game_board.(1).(1) = Empty
  then 
  (
    game_board.(1).(1) <- Player;
    Play ()
  );
  true
;;

let Pos_1_2_callback Obj Event =
  if game_board.(1).(2) = Empty
  then 
  (
    game_board.(1).(2) <- Player;
    Play ()
  );
  true
;;

let Pos_2_0_callback Obj Event =
  if game_board.(2).(0) = Empty
  then 
  (
    game_board.(2).(0) <- Player;
    Play ()
  );
  true
;;

let Pos_2_1_callback Obj Event =
  if game_board.(2).(1) = Empty
  then 
  (
    game_board.(2).(1) <- Player;
    Play ()
  );
  true
;;

let Pos_2_2_callback Obj Event =
  if game_board.(2).(2) = Empty
  then 
  (
    game_board.(2).(2) <- Player;
    Play ()
  );
  true
;;




(* Instancie les callbacks des bitmaps.
*)
place_0_0.bm_callback <- Pos_0_0_callback;;
place_1_0.bm_callback <- Pos_1_0_callback;;
place_2_0.bm_callback <- Pos_2_0_callback;;
place_0_1.bm_callback <- Pos_0_1_callback;;
place_1_1.bm_callback <- Pos_1_1_callback;;
place_2_1.bm_callback <- Pos_2_1_callback;;
place_0_2.bm_callback <- Pos_0_2_callback;;
place_1_2.bm_callback <- Pos_1_2_callback;;
place_2_2.bm_callback <- Pos_2_2_callback;;



(* Remplie le jeu avec des cases vides.
*)
let NewGame Obj Event =
  for i = 0 to 2 do
    for j = 0 to 2 do
      game_board.(i).(j) <- Empty
    done
  done;
  UpdateBoard ();
  true 
;;

new_game.it_callback <- NewGame;;

(* Renvoie la couleur qui est selectionnees dans la fenetre de choix 
   des couleurs.
*)
let selected_color () =
  match choose_color.gb_button with
    1 -> red
  | 2 -> white
  | 3 -> yellow
  | 4 -> green
  | 5 -> magenta
  | _ -> blue
;;

(* Change les couleurs des pionts du joueur et celles des pionts de
   l'ordinateur.
*)
let OpenColor Obj Event =
  color_title.pt_name <- "Yours";
  gr_block_loop ColorWin;
  rond_player.el_color <- selected_color ();
      
  color_title.pt_name <- "Mines";
  gr_block_loop ColorWin; 
  rond_caml.el_color <- selected_color ();

  UpdateBoard ();
  true
;;

config_color.it_callback <- OpenColor;;

(* Fait jouer l'ordinateur.
*)
let Turn Obj Event =
  Play ();
  true
;;

config_turn.it_callback <- Turn;;

(* Initialise les couleurs des pionts.
 *)
if gr_is_color_look () 
then
(
  rond_player.el_color <- red;
  rond_caml.el_color <- blue
);;

gr_main_loop [ if gr_is_color_look () then MorpionWin else MorpionWinBW  ];;



