(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)

let debug_all = true ;;
let fatal_time = 1.0 ;;
let explosion_time = 1.0 ;;

(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)

type pt = {
  x : int ;
  y : int ;
}

type bomb = {
  xy : pt ;
  size : int ;
  det_time : float ;
}

type player = {
  id : int ;
  xy : pt ;
  nspeed : int ;
  nbomb_atonce : int ;
  bomb_radius : int ;
  ndash : int ;
  ntraps : int ;
}

type boost = {
  xy : pt ;
  spec : int ;
}

let default_point = {
  x = 0 ;
  y = 0 ;
}

let default_bomb = {
  xy = default_point ;
  size = 0 ;
  det_time = 0. ;
} 

and default_player = {
  id = 0 ;
  xy = default_point ;
  nspeed = 0 ;
  nbomb_atonce = 0 ;
  bomb_radius = 0 ;
  ndash = 0 ;
  ntraps = 0 ;
}

and default_boost = {
  xy = default_point ;
  spec = 0 ;
} 

and useless = ref 0 ;;

type game_data = {
  mutable dt : float ;
  mutable player_id : int ;
  mutable laby : int array array ;
  mutable nbombs : int ;
  mutable bombs : bomb array ;
  mutable nplayers : int ;
  mutable players : player array ;
  mutable nboosts : int ;
  mutable boosts : boost array ;
}

type danger = Safe | Danger of float | Fatal of float | Blocked ;;

let int_of_danger = function
  | Safe -> 0
  | Danger _ -> 1
  | Fatal _ -> 2
  | Blocked -> 3 ;;

let danger_of_int t = function
  | 0 -> Safe
  | 1 -> Danger t
  | 2 -> Fatal t
  | _ -> Blocked ;;

type moveType = EscapeDeath | BlowUpCrates | KillPlayers | ClaimLand ;;

exception ReturnInt of int ;;
exception ReturnBool of bool ;;

(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)

let current_status = ref BlowUpCrates ;;
let action = ref 0 ;;

let equal_pt (p1 : pt) (p2 : pt) =
  p1.x = p2.x && p1.y = p2.y ;;

let swap arr i j =
  let temp = arr.(i) in
  arr.(i) <- arr.(j) ;
  arr.(j) <- temp ;;

let is_valid i j len hei =
  i >= 0 && j >= 0 && i < len && j < hei ;;

let print_direction = function
  | 0 -> Printf.printf "NORTH "
  | 1 -> Printf.printf "EAST  "
  | 2 -> Printf.printf "SOUTH "
  | 3 -> Printf.printf "WEST  " 
  | 4 -> Printf.printf "STILL "
  | _-> failwith "ERROR : invalid direction" ;;

let level_of_danger = function
  | Danger k | Fatal k -> k
  | _ -> 32768. ;;

let delta i j =
  if i = j then 1 else 0 ;;

(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)

let print_game_data (gd : game_data) =
  Printf.printf "--------------------------------| Board data |--------------------------------\n" ;
  Printf.printf "Time : %f\n" gd.dt ;
  Printf.printf "ID   : %d\n" gd.player_id ;
  Printf.printf "Laby [of size %d %d]:\n" (Array.length gd.laby) (Array.length gd.laby.(0));
  for l = 0 to Array.length gd.laby -1 do
    Printf.printf "    " ;
    for c = 0 to Array.length gd.laby.(l) -1 do
      Printf.printf "%d " gd.laby.(l).(c) ;
    done;
    Printf.printf "\n"
  done ;
  Printf.printf "Bombs (%d) : \n" gd.nbombs ;
  for b = 0 to gd.nbombs -1 do
    Printf.printf "    [Bomb] (at %d %d) (of size %d) (blowing up at %f)\n" gd.bombs.(b).xy.x gd.bombs.(b).xy.y gd.bombs.(b).size gd.bombs.(b).det_time ;
  done;
  Printf.printf "Players (%d) : \n" gd.nplayers ;
  for b = 0 to gd.nplayers -1 do
    Printf.printf "    [Player %d] (at %d %d) (holding %d %d %d %d %d)\n" gd.players.(b).id gd.players.(b).xy.x gd.players.(b).xy.y gd.players.(b).nspeed gd.players.(b).nbomb_atonce  gd.players.(b).bomb_radius gd.players.(b).ndash gd.players.(b).ntraps ;
  done;
  Printf.printf "Boosts (%d) : \n" gd.nboosts ;
  for b = 0 to gd.nboosts -1 do
    Printf.printf "    [Boost] (at %d %d) (of type %d)\n" gd.boosts.(b).xy.x gd.boosts.(b).xy.y gd.boosts.(b).spec ;
  done;;

let print_danger_levels (map : danger array array) =
  Printf.printf "--------------------------------| Danger levels |--------------------------------\n" ;
  for l = 0 to (Array.length map -1) do
    for c = 0 to (Array.length map.(l) -1) do
      match map.(l).(c) with
        | Blocked -> Printf.printf "@ "
        | Safe -> Printf.printf ". "
        | Danger x -> Printf.printf "! "
        | Fatal x -> Printf.printf "X "
    done;
    Printf.printf "\n"
  done ;;

let print_gain_map (map : int array array) =
  Printf.printf "--------------------------------| Gain levels |--------------------------------\n" ;
  for l = 0 to (Array.length map -1) do
    for c = 0 to (Array.length map.(l) -1) do
      Printf.printf "%d " map.(l).(c) ;
    done;
    Printf.printf "\n"
  done ;;

(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)

let int_of_string (str : string) =
  String.fold_right (fun ch acc -> let cd = Char.code ch in if cd >= 48 || cd <= 57 then 10*acc + cd - 48 else failwith "not an integer\n") str 0 ;;

let int_n_of_string (str : string) (n : int) (nlast : int ref) =
  let res = Array.make n 0 in
  let rec aux idres idstr = match idstr with
    | k when k = String.length str || idres >= n -> 
      nlast := k
    | k ->
      if str.[k] = ' ' then
        aux (idres+1) (k+1)
      else begin
        let cd = Char.code str.[k] in
        if cd >= 48 && cd <= 57 then begin
          res.(idres) <- 10 * res.(idres) + cd - 48 ;
          aux (idres) (k+1)
        end
        else
          failwith "not an integer (n/n)\n"
      end
  in
  aux 0 0 ;
  res ;;

let parse_input (str : string) =
  let ptr = open_in str in
  let (res : game_data) = {dt = 0. ; player_id = 0 ; laby = [||] ; nbombs = 0 ; bombs = [||] ; nplayers = 0 ; players = [||] ; nboosts = 0 ; boosts = [||] ;} in
  try
    (* time *)
    if debug_all then Printf.printf "Time\n" ;
    res.dt <- Float.of_string (input_line ptr) ;

    (* player_id *)
    if debug_all then Printf.printf "PID\n" ;
    res.player_id <- int_of_string (input_line ptr) ;

    (* maze *)
    if debug_all then Printf.printf "Maze\n" ;
    let msize = int_n_of_string (input_line ptr) 2 useless in

    res.laby <- Array.make msize.(0) [||] ;
    for lane = 0 to msize.(0) -1 do
      let psd = input_line ptr in
      res.laby.(lane) <- int_n_of_string psd msize.(1) useless ;
    done;

    (* bombs *)
    if debug_all then Printf.printf "Boom\n" ;
    res.nbombs <- int_of_string (input_line ptr) ;

    res.bombs <- Array.make res.nbombs default_bomb ;
    for b = 0 to res.nbombs -1 do
      let psd = input_line ptr
      and last = ref 0 in
      let dat = int_n_of_string psd 3 last in
      let dtime = Float.of_string (String.init (String.length psd - !last) (fun i -> psd.[i + !last])) in
      res.bombs.(b) <- {xy = {x = dat.(0) ; y = dat.(1) ;} ; size = dat.(2) ; det_time = dtime ;
      }
    done;

    (* players *)
    if debug_all then Printf.printf "Players\n" ;
    res.nplayers <- int_of_string (input_line ptr) ;

    res.players <- Array.make res.nplayers default_player ;
    for p = 0 to res.nplayers -1 do
      let dat = int_n_of_string (input_line ptr) 8 useless in
      res.players.(p) <- {id = dat.(2) ; xy = {x = dat.(0) ; y = dat.(1) ;} ; nspeed = dat.(3) ; nbomb_atonce = dat.(4) ; bomb_radius = dat.(5) ; ndash = dat.(6) ; ntraps = dat.(7) ;}
    done;

    (* boosts *)
    if debug_all then Printf.printf "Boosts\n" ;
    res.nboosts <- int_of_string (input_line ptr) ;

    res.boosts <- Array.make res.nboosts default_boost ;
    for p = 0 to res.nboosts -1 do
      let dat = int_n_of_string (input_line ptr) 3 useless in
      res.boosts.(p) <- {xy = {x = dat.(0) ; y = dat.(1) ;} ; spec = dat.(2)}
    done;
        
    if debug_all then Printf.printf "Done!\n" ;
    close_in ptr ;
    res
  with
    | End_of_file ->
      close_in ptr ;
      failwith "cannot happen unless something is wrong" ;;

(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)

let warn_level (b : bomb) (ct : float) = match (b.det_time -. ct) with
  | k when k < fatal_time -> Fatal b.det_time ;
  | _ -> Danger b.det_time  ;;

let danger_priority (p1 : danger) (p2 : danger) = 
  danger_of_int (min (level_of_danger p1) (level_of_danger p2)) (max (int_of_danger p1) (int_of_danger p2)) ;;

let order = [|(1, 0); (-1, 0); (0, 1); (0, -1)|] ;;
let evaluate_dangers (gd : game_data) =
  let lines = Array.length gd.laby
  and cols = Array.length gd.laby.(0) in
  let res = Array.make_matrix lines cols Safe in
  
  (* add solid blocks *)
  for l = 0 to lines -1 do
    for c = 0 to cols -1 do
      if gd.laby.(l).(c) = 1 || gd.laby.(l).(c) = 2 then
        res.(l).(c) <- Blocked ;
    done
  done ;

  (* sort bombs based on detonation time *)
  for b = 0 to gd.nbombs -1 do
    let m = ref gd.bombs.(b).det_time
    and im = ref b in
    for j = b+1 to gd.nbombs -1 do
      if gd.bombs.(j).det_time < !m then begin
        m := gd.bombs.(j).det_time ;
        im := j ;
      end
    done;
    swap gd.bombs b (!im) ;
  done;

  (* add bomb tiles *)
  let exploded = Hashtbl.create 12 in
  for b = 0 to gd.nbombs -1 do
    let dgr = warn_level gd.bombs.(b) gd.dt in
    let halt = ref false in

    let bx = gd.bombs.(b).xy.x
    and by = gd.bombs.(b).xy.y in

    for dir = 0 to 3 do
      for w = 0 to gd.bombs.(b).size do
        let cx = bx + w*(fst order.(dir)) 
        and cy = by + w*(snd order.(dir)) in
        if not !halt && is_valid (cx) (cy) lines cols then begin
          if gd.laby.(cx).(cy) = 1 then (* bedrock *)
            halt := true ;
          if gd.laby.(cx).(cy) = 2 && Hashtbl.find_opt exploded (cx, cy) = None then begin (* unexploded crate *)
            halt := true ;
            res.(cx).(cy) <- danger_priority res.(cx).(cy) dgr ;
            Hashtbl.add exploded (cx, cy) 1 
          end
          else begin
            res.(cx).(cy) <- danger_priority res.(cx).(cy) dgr ;
          end
        end
      done;
      halt := false ;
    done
  done;

  res ;;

(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)

let cell_values (gd : game_data) =
  (* computes the net gain upon blowing up each cell *)
  let lines = Array.length gd.laby
  and cols = Array.length gd.laby.(0) in
  let res = Array.make_matrix lines cols 0 in

  let psize = gd.players.(gd.player_id).bomb_radius in

  for ln = 0 to lines -1 do
    for cl = 0 to cols -1 do
      if (gd.laby.(ln).(cl) >= 3 && gd.laby.(ln).(cl) <> 3 + gd.player_id) || gd.laby.(ln).(cl) = 0 then begin
        (* use a similar method than danger for bombs *)
        let halt = ref false in
    
        for dir = 0 to 3 do
          for w = 1 - delta dir 0 to psize do
            let cx = ln + w*(fst order.(dir)) 
            and cy = cl + w*(snd order.(dir)) in
            if not !halt && is_valid (cx) (cy) lines cols then begin
              if gd.laby.(cx).(cy) <> 1 && gd.laby.(cx).(cy) <> 2 then (* non-wall *)
                res.(cx).(cy) <- res.(cx).(cy) + 1 
              else
                halt := true ;
            end
          done;
          halt := false ;
        done
      end
    done
  done ;
  res ;;

(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)

let is_safe = function
  | Safe | Danger _ -> true
  | Fatal _ | Blocked -> false ;;

let move_safe (gd : game_data) (dgs : danger array array) =
  (* use this whenever you are standing on a non-safe tile *)
  (* Strat : find the shortest, safest path *)
  let pid = gd.player_id in
  let interval = Float.pow 0.9 (float_of_int gd.players.(pid).nspeed) in

  if debug_all then Printf.printf "I = %f\n" interval ;

  let lines = Array.length gd.laby
  and cols = Array.length gd.laby.(0) in

  (* BFS to find the nearest safe spot (if it exists) *)
  try
    (* 0. if you're standing on a safe tile, stay there *)
    let (cx, cy) = (gd.players.(pid).xy.x, gd.players.(pid).xy.y) in
    if dgs.(cx).(cy) = Safe then begin
      current_status := BlowUpCrates ;
      raise (ReturnInt 4) ;
    end;
    
    let visited = Hashtbl.create 100 in

    let has_a_safe_path (cx0 : int) (cy0 : int) (simt : float) =
      let q = Queue.create () in

      Hashtbl.add visited (cx0, cy0) 1 ;

      if is_valid (cx0+1) (cy0) lines cols && not ((simt +. interval) > (level_of_danger dgs.(cx0+1).(cy0)) && (simt  +. interval) < (level_of_danger dgs.(cx0+1).(cy0)) +. explosion_time) then begin (* South *)
        if debug_all then Printf.printf "[escape] +South\n" ;
        Queue.add (cx0+1, cy0, simt +. interval, 2) q ; 
      end;
      if is_valid (cx0-1) (cy0) lines cols && not ((simt +. interval) > (level_of_danger dgs.(cx0-1).(cy0)) && (simt  +. interval) < (level_of_danger dgs.(cx0-1).(cy0)) +. explosion_time) then begin (* North *)
        if debug_all then Printf.printf "[escape] +North\n" ;
        Queue.add (cx0-1, cy0, simt +. interval, 0) q ; 
      end;
      if is_valid (cx0) (cy0+1) lines cols && not ((simt +. interval) > (level_of_danger dgs.(cx0).(cy0+1)) && (simt  +. interval) < (level_of_danger dgs.(cx0).(cy0+1)) +. explosion_time) then begin (* East *)
        if debug_all then Printf.printf "[escape] +East\n" ;
        Queue.add (cx0, cy0+1, simt +. interval, 1) q ; 
      end;
      if is_valid (cx0) (cy0-1) lines cols && not ((simt +. interval) > (level_of_danger dgs.(cx0).(cy0-1)) && (simt  +. interval) < (level_of_danger dgs.(cx0).(cy0-1)) +. explosion_time) then begin (* West *)
        if debug_all then Printf.printf "[escape] +West\n" ;
        Queue.add (cx0, cy0-1, simt +. interval, 3) q ; 
      end;

      if debug_all then Printf.printf "[escape] Attempt 1/1...\n" ;
      try
        while not (Queue.is_empty q) do
          let (cx, cy, cur_t, direct) = Queue.pop q in
          if Hashtbl.find_opt visited (cx, cy) <> None then () else begin
            Hashtbl.add visited (cx, cy) 1 ;
            (*if debug_all then Printf.printf "dealing at (%d, %d) with dir %d\n" cx cy direct ;*)
            if dgs.(cx).(cy) = Safe then 
              raise (ReturnInt direct)
            else if dgs.(cx).(cy) = Blocked then 
              () 
            else begin (* either danger or fatal *)
              let dang_time = level_of_danger dgs.(cx).(cy) in
              for dir = 0 to 3 do
                let newx = cx + fst order.(dir)
                and newy = cy + snd order.(dir) 
                and newt = cur_t +. interval in
                if (is_valid newx newy lines cols) && not (newt > dang_time && newt < dang_time +. explosion_time) then
                  Queue.add (newx, newy, newt, direct) q
              done
            end
          end
        done;
        4
      with
        | ReturnInt b -> b
    in

    let result = has_a_safe_path (cx) (cy) gd.dt in

    if result <> 4 then result else begin
      (* you're probably dead if the code reaches here... *)
      if debug_all then Printf.printf "[escape] Attempt F...\n";
      4
    end
  with
    | ReturnInt k -> k ;;

(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)

let move_explore (gd: game_data) (dgs : danger array array) =
  (* destroy crates *)
  let pid = gd.player_id in
  let interval = Float.pow 0.9 (float_of_int gd.players.(pid).nspeed) in

  let lines = Array.length gd.laby
  and cols = Array.length gd.laby.(0) in

  (* find nearest crate and blow it up *)
  try
    let (cxi, cyi) = (gd.players.(pid).xy.x, gd.players.(pid).xy.y) in
    
    let visited = Hashtbl.create 100 in

    let has_a_safe_path (cx0 : int) (cy0 : int) (simt : float) =
      let q = Queue.create () in
      Hashtbl.add visited (cx0, cy0) 1 ;

      if is_valid (cx0+1) (cy0) lines cols && not ((simt +. interval) > (level_of_danger dgs.(cx0+1).(cy0)) && (simt  +. interval) < (level_of_danger dgs.(cx0+1).(cy0)) +. explosion_time) then begin (* South *)
        if debug_all then Printf.printf "[crates] +South\n" ;
        Queue.add (cx0+1, cy0, simt +. interval, 2) q ; 
      end;
      if is_valid (cx0-1) (cy0) lines cols && not ((simt +. interval) > (level_of_danger dgs.(cx0-1).(cy0)) && (simt  +. interval) < (level_of_danger dgs.(cx0-1).(cy0)) +. explosion_time) then begin (* North *)
        if debug_all then Printf.printf "[crates] +North\n" ;
        Queue.add (cx0-1, cy0, simt +. interval, 0) q ; 
      end;
      if is_valid (cx0) (cy0+1) lines cols && not ((simt +. interval) > (level_of_danger dgs.(cx0).(cy0+1)) && (simt  +. interval) < (level_of_danger dgs.(cx0).(cy0+1)) +. explosion_time) then begin (* East *)
        if debug_all then Printf.printf "[crates] +East\n" ;
        Queue.add (cx0, cy0+1, simt +. interval, 1) q ; 
      end;
      if is_valid (cx0) (cy0-1) lines cols && not ((simt +. interval) > (level_of_danger dgs.(cx0).(cy0-1)) && (simt  +. interval) < (level_of_danger dgs.(cx0).(cy0-1)) +. explosion_time) then begin (* West *)
        if debug_all then Printf.printf "[crates] +West\n" ;
        Queue.add (cx0, cy0-1, simt +. interval, 3) q ; 
      end;

      if debug_all then Printf.printf "[crates] Attempt 1/1...\n" ;
      try
        while not (Queue.is_empty q) do
          let (cx, cy, cur_t, direct) = Queue.pop q in
          if Hashtbl.find_opt visited (cx, cy) <> None then () else begin
            Hashtbl.add visited (cx, cy) 1 ;
            (*if debug_all then Printf.printf "[crates] exploring (%d, %d) at time %f for dir %d\n" cx cy cur_t direct ;*)
            if gd.laby.(cx).(cy) = 2 then (* crate *)
              raise (ReturnInt direct)
            else if dgs.(cx).(cy) = Blocked then 
              () 
            else begin (* we need to go deeper *)
              let dang_time = level_of_danger dgs.(cx).(cy) in
              for dir = 0 to 3 do
                let newx = cx + fst order.(dir)
                and newy = cy + snd order.(dir) 
                and newt = cur_t +. interval in
                if (is_valid newx newy lines cols) && not (newt > dang_time && newt < dang_time +. explosion_time) then
                  Queue.add (newx, newy, newt, direct) q
              done
            end
          end
        done;
        (-1)
      with
        | ReturnInt k -> k 
    in

    let move_with_caution (exit : bool) =
      let res = has_a_safe_path cxi cyi gd.dt in
      if res <> -1 then begin
        if debug_all then Printf.printf "[crates] success!\n" ;
        res
      end
      else begin
        if exit then
          current_status := ClaimLand ;
        4
      end
    in

    let safe_path_with_bomb (bx : int) (by : int) (bsize : int) =
      (* simulate the placement of a bomb, and test if that stills allows safe escape *)
      let bomb_hash = Hashtbl.create (4 * (bsize +1)) in
      let saved_dgs = Hashtbl.create (4 * (bsize +1)) in
      for dir = 0 to 3 do
        for w = 0 to bsize do
          Hashtbl.add bomb_hash (bx + w*(fst order.(dir)), by + w*(snd order.(dir))) (Danger 5.5) ;
        done
      done;
      Hashtbl.iter 
        (fun (kx, ky) v -> 
          if is_valid kx ky lines cols then begin 
            Hashtbl.add saved_dgs (kx, ky) dgs.(kx).(ky) ;
            dgs.(kx).(ky) <- danger_priority dgs.(kx).(ky) v
          end
        ) 
        bomb_hash ;
      let result = move_with_caution false in
      Hashtbl.iter (fun (k1, k2) v -> dgs.(k1).(k2) <- v) saved_dgs ;
      result
    in

    (* check if there's a crate next to the player, and if upon placing a bomb it won't softlock the player *)
    if is_valid (cxi+1) (cyi) lines cols && gd.laby.(cxi+1).(cyi) = 2 && (safe_path_with_bomb cxi cyi gd.players.(pid).bomb_radius <> 4) then begin (* Crate at South *)
      current_status := EscapeDeath ;
      action := 1;
      if debug_all then Printf.printf "Fire in the hole!\n" ;
      raise (ReturnInt 4) ;
    end;

    if is_valid (cxi-1) (cyi) lines cols && gd.laby.(cxi-1).(cyi) = 2 && (safe_path_with_bomb cxi cyi gd.players.(pid).bomb_radius <> 4) then begin (* Crate at North *)
      current_status := EscapeDeath ;
      action := 1;
      if debug_all then Printf.printf "Fire in the hole!\n" ;
      raise (ReturnInt 4) ;
    end;

    if is_valid (cxi) (cyi+1) lines cols && gd.laby.(cxi).(cyi+1) = 2 && (safe_path_with_bomb cxi cyi gd.players.(pid).bomb_radius <> 4) then begin (* Crate at East *)
      current_status := EscapeDeath ;
      action := 1;
      if debug_all then Printf.printf "Fire in the hole!\n" ;
      raise (ReturnInt 4) ;
    end;

    if is_valid (cxi) (cyi-1) lines cols && gd.laby.(cxi).(cyi-1) = 2 && (safe_path_with_bomb cxi cyi gd.players.(pid).bomb_radius <> 4) then begin (* Crate at West *)
      current_status := EscapeDeath ;
      action := 1;
      if debug_all then Printf.printf "Fire in the hole!\n" ;
      raise (ReturnInt 4) ;
    end;

    if debug_all then Printf.printf "[crates] Cannot bomb now, searching for a crate...\n";

    (* go to one without stepping into a dangerous tile *)
    raise (ReturnInt (move_with_caution true)) ;
  with
    | ReturnInt k -> k ;;

(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)

let game_d = parse_input "input_test.txt" ;;
let dangers = evaluate_dangers game_d ;;
let gains = cell_values game_d ;;

print_game_data game_d ;;
print_danger_levels dangers ;;
print_gain_map gains ;;

Printf.printf "move at\n";;
print_direction (move_explore game_d dangers) ;;
Printf.printf "\n" ;;