1117 lines
42 KiB
OCaml
1117 lines
42 KiB
OCaml
(*
|
|
TODO :
|
|
- deal with double bombing (DONE)
|
|
- well shit ==> dash
|
|
- deeper analysis on pathfinfing (n-1/n)
|
|
- correct fatal bug on player death (DONE)
|
|
- solve when player is on a bomb on an intersection
|
|
*)
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
Random.self_init () ;;
|
|
|
|
let debug_all = false ;;
|
|
let logg = true ;;
|
|
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
|
|
let fodder = ref 0 ;;
|
|
let bodder = ref false ;;
|
|
type pt = {
|
|
x : int ;
|
|
y : int ;
|
|
}
|
|
|
|
type bomb = {
|
|
xy : pt ;
|
|
size : int ;
|
|
det_time : float ;
|
|
}
|
|
|
|
type player = {
|
|
id : int ;
|
|
xy : pt ;
|
|
nspeed : int ;
|
|
bomb_to_place : 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 = -1 ;
|
|
xy = default_point ;
|
|
nspeed = 0 ;
|
|
bomb_to_place = 0 ;
|
|
bomb_radius = 0 ;
|
|
ndash = 0 ;
|
|
ntraps = 0 ;
|
|
}
|
|
|
|
and default_boost = {
|
|
xy = default_point ;
|
|
spec = 0 ;
|
|
}
|
|
|
|
and useless = ref 0 ;;
|
|
|
|
let fodder_x = ref 0
|
|
and fodder_y = 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_map = {
|
|
explosionTimes : (float list) array array ;
|
|
playersTimes : (float list) array array ;
|
|
bonusMap : bool array array ;
|
|
explodedCrates : bool array array ;
|
|
}
|
|
|
|
type moveType = EscapeDeath | BlowUpCrates | KillPlayers | ClaimLand ;;
|
|
|
|
exception ReturnInt of int ;;
|
|
exception ReturnBool of bool ;;
|
|
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
let order = [|(-1, 0); (0, 1); (1, 0); (0, -1); (0, 0)|] ;;
|
|
|
|
let current_status = ref BlowUpCrates ;;
|
|
let action = ref 0 ;;
|
|
|
|
let dash_left = 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.fprintf stderr "NORTH "
|
|
| 1 -> Printf.fprintf stderr "EAST "
|
|
| 2 -> Printf.fprintf stderr "SOUTH "
|
|
| 3 -> Printf.fprintf stderr "WEST "
|
|
| 4 -> Printf.fprintf stderr "STILL "
|
|
| _-> failwith "ERROR : invalid direction" ;;
|
|
|
|
let delta i j =
|
|
if i = j then 1 else 0 ;;
|
|
|
|
let overwrite_file (filename : string) =
|
|
let ptr = open_out filename in
|
|
close_out ptr ;;
|
|
|
|
let rec pop_list elt = function
|
|
| [] -> []
|
|
| h::t when h = elt -> t
|
|
| h::t -> h::(pop_list elt t) ;;
|
|
|
|
let is_empty_lst = function
|
|
| [] -> true
|
|
| _ -> false ;;
|
|
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
|
|
let get_player_id (gd : game_data) (raw_id : int) =
|
|
try
|
|
Array.fold_left (fun i (p : player) -> if p.id = raw_id then raise (ReturnInt i); i+1) 0 gd.players
|
|
with
|
|
| ReturnInt k -> k ;;
|
|
|
|
let print_game_data (gd : game_data) =
|
|
Printf.fprintf stderr "--------------------------------| Board data |--------------------------------\n" ;
|
|
Printf.fprintf stderr "Time : %f\n" gd.dt ;
|
|
Printf.fprintf stderr "ID : %d\n" gd.player_id ;
|
|
Printf.fprintf stderr "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.fprintf stderr " " ;
|
|
for c = 0 to Array.length gd.laby.(l) -1 do
|
|
Printf.fprintf stderr "%d " gd.laby.(l).(c) ;
|
|
done;
|
|
Printf.fprintf stderr "\n"
|
|
done ;
|
|
Printf.fprintf stderr "Bombs (%d) : \n" gd.nbombs ;
|
|
for b = 0 to gd.nbombs -1 do
|
|
Printf.fprintf stderr " [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.fprintf stderr "Players (%d) : \n" gd.nplayers ;
|
|
for b = 0 to gd.nplayers -1 do
|
|
Printf.fprintf stderr " [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).bomb_to_place gd.players.(b).bomb_radius gd.players.(b).ndash gd.players.(b).ntraps ;
|
|
done;
|
|
Printf.fprintf stderr "Boosts (%d) : \n" gd.nboosts ;
|
|
for b = 0 to gd.nboosts -1 do
|
|
Printf.fprintf stderr " [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_dangers (dgs : danger_map) =
|
|
for w = 0 to Array.length dgs.explosionTimes -1 do
|
|
for h = 0 to Array.length dgs.explosionTimes.(0) -1 do
|
|
Printf.fprintf stderr "%d " ((List.length dgs.explosionTimes.(w).(h)) + (List.length dgs.playersTimes.(w).(h))) ;
|
|
done ;
|
|
Printf.fprintf stderr "\n" ;
|
|
done ;;
|
|
|
|
let print_gain_map (map : int array array) =
|
|
Printf.fprintf stderr "--------------------------------| Gain levels |--------------------------------\n" ;
|
|
for l = 0 to (Array.length map -1) do
|
|
for c = 0 to (Array.length map.(l) -1) do
|
|
Printf.fprintf stderr "%d " map.(l).(c) ;
|
|
done;
|
|
Printf.fprintf stderr "\n"
|
|
done ;;
|
|
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
|
|
let rec ln_b b = function
|
|
| k when k < 0 -> failwith "are you sure about that ?"
|
|
| k when k < b -> 0
|
|
| k -> 1 + ln_b b (k/b) ;;
|
|
|
|
let int_of_bool = function
|
|
| false -> 0
|
|
| true -> 1 ;;
|
|
|
|
let get_meta_info (pid : int) =
|
|
let ptr = open_in ("main_"^(string_of_int pid)^".sav") in
|
|
let fct0 () = match (int_of_string (input_line ptr)) with
|
|
| 0 -> current_status := EscapeDeath
|
|
| 1 -> current_status := BlowUpCrates
|
|
| 2 -> current_status := ClaimLand
|
|
| 3 -> current_status := KillPlayers
|
|
| _ -> current_status := EscapeDeath
|
|
in
|
|
fct0 () ;
|
|
try
|
|
let resu = int_of_string (input_line ptr) in
|
|
dash_left := resu -1;
|
|
close_in ptr
|
|
with
|
|
| End_of_file -> close_in ptr ;;
|
|
|
|
let set_meta_info (pid : int) =
|
|
let ptr = open_out ("main_"^(string_of_int pid)^".sav") in
|
|
let fct0 () = match !current_status with
|
|
| EscapeDeath -> Printf.fprintf ptr "0"
|
|
| BlowUpCrates -> Printf.fprintf ptr "1"
|
|
| ClaimLand -> Printf.fprintf ptr "2"
|
|
| KillPlayers -> Printf.fprintf ptr "3"
|
|
in
|
|
fct0 () ;
|
|
if !dash_left > 0 then
|
|
Printf.fprintf ptr "\n%d" !dash_left ;
|
|
close_out ptr ;;
|
|
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
|
|
let int_of_string (str : string) =
|
|
String.fold_left (fun acc ch -> let cd = Char.code ch in if cd >= 48 || cd <= 57 then 10*acc + cd - 48 else failwith "not an integer\n") 0 str ;;
|
|
|
|
let string_of_int (k0 : int) =
|
|
String.make (1) (Char.chr (k0 + 48)) ;;
|
|
|
|
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.fprintf stderr "Time\n" ;
|
|
res.dt <- Float.of_string (input_line ptr) ;
|
|
|
|
(* player_id *)
|
|
if debug_all then Printf.fprintf stderr "PID\n" ;
|
|
res.player_id <- int_of_string (input_line ptr) ;
|
|
|
|
(* maze *)
|
|
if debug_all then Printf.fprintf stderr "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.fprintf stderr "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.fprintf stderr "Players\n" ;
|
|
res.nplayers <- int_of_string (input_line ptr) ;
|
|
|
|
res.players <- Array.make 4 default_player ;
|
|
for p = 0 to res.nplayers -1 do
|
|
let dat = int_n_of_string (input_line ptr) 8 useless in
|
|
res.players.(dat.(2)) <- {id = dat.(2) ; xy = {x = dat.(0) ; y = dat.(1) ;} ; nspeed = dat.(3) ; bomb_to_place = dat.(4) ; bomb_radius = dat.(5) ; ndash = dat.(6) ; ntraps = dat.(7) ;}
|
|
done;
|
|
|
|
(* boosts *)
|
|
if debug_all then Printf.fprintf stderr "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.fprintf stderr "Done!\n" ;
|
|
close_in ptr ;
|
|
res
|
|
with
|
|
| End_of_file ->
|
|
close_in ptr ;
|
|
failwith "cannot happen unless something is wrong" ;;
|
|
|
|
let build_danger_map (gd : game_data) =
|
|
let lines = Array.length gd.laby
|
|
and cols = Array.length gd.laby.(0) in
|
|
let (res : danger_map) = {
|
|
explosionTimes = Array.make lines [||] ;
|
|
playersTimes = Array.make lines [||] ;
|
|
bonusMap = Array.make lines [||] ;
|
|
explodedCrates = Array.make lines [||] ;
|
|
} in
|
|
for l = 0 to lines -1 do
|
|
res.explosionTimes.(l) <- Array.make cols [] ;
|
|
res.playersTimes.(l) <- Array.make cols [] ;
|
|
res.explodedCrates.(l) <- Array.make cols false ;
|
|
res.bonusMap.(l) <- Array.make cols false ;
|
|
done;
|
|
|
|
Array.sort
|
|
(
|
|
fun b1 b2 -> int_of_float (100. *. (b1.det_time -. b2.det_time))
|
|
)
|
|
gd.bombs ;
|
|
|
|
(*if gd.nbombs > 0 then
|
|
Printf.fprintf stderr "%f %f\n" (gd.bombs.(0).det_time) (gd.bombs.(Array.length gd.bombs -1).det_time) ;*)
|
|
|
|
(* add bombs *)
|
|
let halt = ref false in
|
|
for b = 0 to gd.nbombs -1 do
|
|
let bx = gd.bombs.(b).xy.x
|
|
and by = gd.bombs.(b).xy.y in
|
|
let bsize = gd.bombs.(b).size
|
|
and dtime = min (gd.bombs.(b).det_time) (List.fold_left min (gd.dt +. 1000.) res.explosionTimes.(bx).(by)) in
|
|
for dir = 0 to 3 do
|
|
for w = 0 to bsize do
|
|
if (not !halt) && (w > 0 || dir = 0) then begin
|
|
let nx = bx + w * (fst order.(dir))
|
|
and ny = by + w * (snd order.(dir)) in
|
|
if is_valid nx ny lines cols then begin
|
|
if (gd.laby.(nx).(ny) = 0 || gd.laby.(nx).(ny) >= 3) || (gd.laby.(nx).(ny) = 2 && res.explodedCrates.(nx).(ny)) then
|
|
res.explosionTimes.(nx).(ny) <- (dtime)::(res.explosionTimes.(nx).(ny))
|
|
else if gd.laby.(nx).(ny) = 1 then
|
|
halt := true
|
|
else if gd.laby.(nx).(ny) = 2 then begin
|
|
halt := true ;
|
|
res.explodedCrates.(nx).(ny) <- true ;
|
|
end
|
|
end
|
|
end
|
|
done;
|
|
halt := false ;
|
|
done
|
|
done;
|
|
|
|
(* add players *)
|
|
for p = 0 to gd.nplayers -1 do
|
|
if p <> gd.player_id then begin
|
|
let bx = gd.players.(p).xy.x
|
|
and by = gd.players.(p).xy.y in
|
|
let bsize = gd.players.(p).bomb_radius
|
|
and dtime = min (gd.dt +. 5.5) (min (List.fold_left min (gd.dt +. 1000.) res.explosionTimes.(bx).(by)) (List.fold_left min (gd.dt +. 1000.) res.playersTimes.(bx).(by))) in
|
|
if dtime <> gd.dt +. 5.5 then begin
|
|
for dir = 0 to 3 do
|
|
for w = 0 to bsize do
|
|
if (not !halt) && (w > 0 || dir = 0) then begin
|
|
let nx = bx + w * (fst order.(dir))
|
|
and ny = by + w * (snd order.(dir)) in
|
|
if is_valid nx ny lines cols then begin
|
|
if (gd.laby.(nx).(ny) = 0 || gd.laby.(nx).(ny) >= 3) || (gd.laby.(nx).(ny) = 2 && res.explodedCrates.(nx).(ny)) then
|
|
res.playersTimes.(nx).(ny) <- (dtime)::(res.playersTimes.(nx).(ny))
|
|
else if gd.laby.(nx).(ny) = 1 then
|
|
halt := true
|
|
else if gd.laby.(nx).(ny) = 2 then begin
|
|
halt := true ;
|
|
res.explodedCrates.(nx).(ny) <- true ;
|
|
end
|
|
end
|
|
end
|
|
done;
|
|
halt := false ;
|
|
done
|
|
end
|
|
end
|
|
done;
|
|
|
|
(* add bonuses *)
|
|
for b = 0 to gd.nboosts -1 do
|
|
res.bonusMap.(gd.boosts.(b).xy.x).(gd.boosts.(b).xy.y) <- true ;
|
|
done;
|
|
res ;;
|
|
|
|
let generate_gain_map (gd : game_data) =
|
|
let lines = Array.length gd.laby
|
|
and cols = Array.length gd.laby.(0) in
|
|
let bsize = gd.players.(gd.player_id).bomb_radius in
|
|
let res = Array.make_matrix lines cols 0 in
|
|
|
|
(* aim towards center by adding a bonus *)
|
|
for i = 0 to lines -1 do
|
|
for j = 0 to cols -1 do
|
|
res.(i).(j) <- res.(i).(j) + (min (min (i) (lines -1-i)) (min (j) (cols -1-j))) ;
|
|
done
|
|
done ;
|
|
|
|
(* add potential score *)
|
|
for l = 0 to lines -1 do
|
|
for c = 0 to cols -1 do
|
|
if (gd.laby.(l).(c) >= 3) || gd.laby.(l).(c) = 0 then begin
|
|
for dir = 0 to 3 do
|
|
for w = 0 to bsize do
|
|
if (w > 0) || dir = 0 then begin
|
|
let nx = l + w * (fst order.(dir))
|
|
and ny = c + w * (snd order.(dir)) in
|
|
if is_valid nx ny lines cols && gd.laby.(l).(c) <> 3+gd.player_id then begin
|
|
res.(nx).(ny) <- res.(nx).(ny) + 1;
|
|
if (gd.laby.(l).(c) >= 3) then
|
|
res.(nx).(ny) <- res.(nx).(ny) + 1;
|
|
end
|
|
end
|
|
done
|
|
done
|
|
end
|
|
done
|
|
done;
|
|
res ;;
|
|
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
|
|
let simulate_bomb_deconstruct (gd : game_data) (dgs : danger_map) (bx : int) (by : int) (bsize : int) (dtime0 : float) =
|
|
let saved_data = Hashtbl.create 40 in
|
|
let dtime = min dtime0 (List.fold_left min (32760.) dgs.explosionTimes.(bx).(by)) in
|
|
let lines = Array.length dgs.explosionTimes
|
|
and cols = Array.length dgs.explosionTimes.(0) in
|
|
for dir = 0 to 3 do
|
|
for w = 0 to bsize do
|
|
if (w > 0 || dir = 0) then begin
|
|
let nx = bx + w * (fst order.(dir))
|
|
and ny = by + w * (snd order.(dir)) in
|
|
if is_valid nx ny lines cols then begin
|
|
Hashtbl.add saved_data (nx, ny) dtime ;
|
|
dgs.explosionTimes.(nx).(ny) <- (dtime)::(dgs.explosionTimes.(nx).(ny))
|
|
end
|
|
end
|
|
done;
|
|
done;
|
|
let pid = gd.player_id in
|
|
Array.iter (fun (pl : player) ->
|
|
if pl.id <> pid then begin
|
|
let dtimep = min (gd.dt +. 5.5) (List.fold_left min (32760.) dgs.explosionTimes.(pl.xy.x).(pl.xy.y)) in
|
|
for dir = 0 to 3 do
|
|
for w = 0 to bsize do
|
|
if (w > 0 || dir = 0) then begin
|
|
let nx = pl.xy.x + w * (fst order.(dir))
|
|
and ny = pl.xy.y + w * (snd order.(dir)) in
|
|
if is_valid nx ny lines cols then begin
|
|
Hashtbl.add saved_data (nx, ny) dtimep ;
|
|
dgs.explosionTimes.(nx).(ny) <- (dtimep)::(dgs.explosionTimes.(nx).(ny))
|
|
end
|
|
end
|
|
done;
|
|
done;
|
|
end
|
|
)
|
|
gd.players ;
|
|
saved_data ;;
|
|
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
|
|
let tile_distance (gd : game_data) (x0 : int) (y0 : int) (end_x : int) (end_y : int) =
|
|
(* returns -1 if the 2 tiles cannot connect *)
|
|
let lines = Array.length gd.laby
|
|
and cols = Array.length gd.laby.(0) in
|
|
let visited = Hashtbl.create 100 in
|
|
let q = Queue.create () in
|
|
|
|
Queue.add (x0, y0, 0) q;
|
|
|
|
try
|
|
while not (Queue.is_empty q) do
|
|
let (x, y, depth) = Queue.pop q in
|
|
if is_valid x y lines cols && gd.laby.(x).(y) <> 1 && gd.laby.(x).(y) <> 2 then begin
|
|
if Hashtbl.find_opt visited (x, y) = None then begin (* has not been visited yet *)
|
|
Hashtbl.add visited (x, y) 1 ;
|
|
if (x = end_x && y = end_y) then begin
|
|
raise (ReturnInt depth)
|
|
end;
|
|
if true then begin
|
|
for dir = 0 to 3 do
|
|
Queue.add (x + (fst order.(dir)), y + (snd order.(dir)), depth+1) q ;
|
|
done;
|
|
end
|
|
end
|
|
end
|
|
done;
|
|
(-1) ;
|
|
with
|
|
| ReturnInt k -> k ;;
|
|
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
|
|
let d_len = 1 ;;
|
|
let min_dist_from_player (gd : game_data) (x : int) (y : int) =
|
|
Array.fold_left min 999999 (Array.init
|
|
(Array.length gd.players)
|
|
(fun i ->
|
|
if gd.player_id = gd.players.(i).id then
|
|
999999
|
|
else begin
|
|
let d = tile_distance gd x y (gd.players.(i).xy.x) (gd.players.(i).xy.y) in
|
|
if d = -1 then 999999 else d
|
|
end
|
|
)
|
|
) ;;
|
|
|
|
let min_dist_with_dash (gd : game_data) (x : int) (y : int) =
|
|
Array.fold_left min 999999 (Array.init
|
|
(Array.length gd.players)
|
|
(fun i ->
|
|
if gd.player_id = gd.players.(i).id then
|
|
999999
|
|
else begin
|
|
let d = tile_distance gd x y (gd.players.(i).xy.x) (gd.players.(i).xy.y) in
|
|
if d = 0 then 0 else
|
|
if d = -1 then 999999 else max 1 (d - 3*gd.players.(i).ndash)
|
|
end
|
|
)
|
|
) ;;
|
|
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
|
|
let amt_free_adj_spaces (gd : game_data) (x : int) (y : int) =
|
|
let lines = Array.length gd.laby
|
|
and cols = Array.length gd.laby.(0) in
|
|
Array.fold_left
|
|
(fun acc (ox, oy) ->
|
|
if not (ox = 0 && oy = 0) && (is_valid (x+ox) (y+oy) lines cols && gd.laby.(x+ox).(y+oy) <> 1 && gd.laby.(x+ox).(y+oy) <> 2 && not (Array.fold_left (fun acc (b : bomb) -> acc || (b.xy.x = x+ox && b.xy.y = y+oy)) false gd.bombs)) then acc+1 else acc
|
|
)
|
|
0
|
|
order ;;
|
|
|
|
let generate_dead_end_map (gd : game_data) =
|
|
(* links every cell that has at least 3 neighbors *)
|
|
|
|
let lines = Array.length gd.laby
|
|
and cols = Array.length gd.laby.(0) in
|
|
let res = Array.make_matrix lines cols 72727 in
|
|
(* distances for each tile to exit to a safe place (ie not a dead end) *)
|
|
|
|
let pid = gd.player_id in
|
|
let visited = Hashtbl.create (lines * cols) in
|
|
|
|
(* places 0s to connectable tiles *)
|
|
let rec dfs x y prev last_dir fpass =
|
|
if
|
|
(is_valid x y lines cols) &&
|
|
(Hashtbl.find_opt visited (x, y) = None) &&
|
|
(gd.laby.(x).(y) <> 1 && gd.laby.(x).(y) <> 2) &&
|
|
((x = gd.players.(pid).xy.x && y = gd.players.(pid).xy.y) || not (Array.fold_left (fun acc (b : bomb) -> acc || (b.xy.x = x && b.xy.y = y)) false gd.bombs))(*&&
|
|
(not (Array.fold_left (fun acc (p : player) -> acc || (p.xy.x = x && p.xy.y = y && p.id <> pid)) false gd.players))*)
|
|
then begin
|
|
if not (x = gd.players.(pid).xy.x && y = gd.players.(pid).xy.y) then
|
|
Hashtbl.add visited (x, y) 1 ;
|
|
if (amt_free_adj_spaces gd x y) >= 3 || (x = gd.players.(pid).xy.x && y = gd.players.(pid).xy.y) then begin
|
|
if prev <> [] then
|
|
Hashtbl.remove visited (x, y) ;
|
|
List.iter (fun (cx, cy) -> res.(cx).(cy) <- 0) ((x, y)::prev) ;
|
|
for dir = 0 to 3 do
|
|
if fpass <> 0 || (dir + 2) mod 4 <> last_dir then (* dont backtrack *)
|
|
dfs (x + fst (order.(dir))) (y + snd (order.(dir))) [] dir (max 0 (fpass-1))
|
|
done
|
|
end
|
|
else begin
|
|
for dir = 0 to 3 do
|
|
if (dir + 2) mod 4 <> last_dir then
|
|
dfs (x + fst (order.(dir))) (y + snd (order.(dir))) ((x, y)::prev) dir fpass
|
|
done
|
|
end
|
|
end
|
|
in
|
|
dfs gd.players.(pid).xy.x gd.players.(pid).xy.y [] 4 1;
|
|
|
|
(* fills remaining spaces with BFS *)
|
|
let bfs (x0 : int) (y0 : int) =
|
|
let q = Queue.create () in
|
|
let visit_mem = Hashtbl.create 100 in
|
|
Queue.add (x0, y0, 0) q ;
|
|
|
|
try
|
|
while not (Queue.is_empty q) do
|
|
let (x, y, d) = Queue.pop q in
|
|
if
|
|
(is_valid x y lines cols) &&
|
|
(Hashtbl.find_opt visit_mem (x, y) = None) &&
|
|
(gd.laby.(x).(y) <> 1 && gd.laby.(x).(y) <> 2) &&
|
|
((x = gd.players.(pid).xy.x && y = gd.players.(pid).xy.y) || not (Array.fold_left (fun acc (b : bomb) -> acc || (b.xy.x = x && b.xy.y = y)) false gd.bombs))(* &&
|
|
(not (Array.fold_left (fun acc (p : player) -> acc || (p.xy.x = x && p.xy.y = y && p.id <> pid)) false gd.players))*)
|
|
then begin
|
|
Hashtbl.add visit_mem (x, y) 1;
|
|
if res.(x).(y) = 0(* && not (x = gd.players.(pid).xy.x && y = gd.players.(pid).xy.y) *)then
|
|
raise (ReturnInt d) ;
|
|
for dir = 0 to 3 do
|
|
Queue.add (x + fst (order.(dir)), y + snd (order.(dir)), d+1) q
|
|
done
|
|
end
|
|
done;
|
|
()
|
|
with
|
|
| ReturnInt k -> res.(x0).(y0) <- k
|
|
in
|
|
for l = 0 to lines -1 do
|
|
for c = 0 to cols -1 do
|
|
if res.(l).(c) <> 0 then
|
|
bfs l c
|
|
done
|
|
done;
|
|
res ;;
|
|
|
|
let is_player_nearby (gd : game_data) (x0 : int) (y0 : int) (detect_dist : int) =
|
|
let mind = min_dist_from_player gd x0 y0 in
|
|
if x0 = gd.players.(gd.player_id).xy.x && y0 = gd.players.(gd.player_id).xy.y then Printf.fprintf stderr "[player %d] %d\n" gd.player_id mind ;
|
|
(mind <= detect_dist) ;;
|
|
|
|
let reverse_simulate_bomb (dgs : danger_map) (save : (int * int, float) Hashtbl.t) =
|
|
Hashtbl.iter
|
|
(fun (x, y) dt ->
|
|
dgs.explosionTimes.(x).(y) <- pop_list dt (dgs.explosionTimes.(x).(y))
|
|
)
|
|
save ;;
|
|
|
|
let is_dead (dgs : danger_map) (x : int) (y : int) (t : float) (dt : float) =
|
|
(List.fold_left (* bombs *)
|
|
(fun acc curtime ->
|
|
acc || (t >= curtime && t <= curtime +. dt)
|
|
)
|
|
false
|
|
dgs.explosionTimes.(x).(y)
|
|
) || (List.fold_left (* player-related bombs (only if in range of another bomb) *)
|
|
(fun acc curtime ->
|
|
acc || (t >= curtime && t <= curtime +. dt)
|
|
)
|
|
false
|
|
dgs.playersTimes.(x).(y)
|
|
) ;;
|
|
|
|
let is_dead_2 (dgs : danger_map) (x : int) (y : int) (t : float) (dt : float) =
|
|
(List.fold_left
|
|
(fun acc curtime ->
|
|
acc || (t >= curtime && t <= curtime +. dt)
|
|
)
|
|
false
|
|
dgs.explosionTimes.(x).(y)
|
|
) ;;
|
|
|
|
let is_dead_all (dgs : danger_map) (x : int) (y : int) (t : float) (dt : float) = function
|
|
| true -> is_dead_2 dgs x y t dt
|
|
| false -> is_dead dgs x y t dt ;;
|
|
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
|
|
let contains_crate (gd : game_data) =
|
|
Array.fold_left
|
|
(fun b1 lst -> b1 || (Array.fold_left (fun b2 tile -> b2 || (tile = 2)) false lst)) false gd.laby ;;
|
|
|
|
let is_a_crate_nearby (gd : game_data) (dgs : danger_map) =
|
|
let pid = gd.player_id
|
|
and lines = Array.length gd.laby
|
|
and cols = Array.length gd.laby.(0) in
|
|
try
|
|
let halt = ref false in
|
|
let res = ref false in
|
|
for dir = 0 to 3 do
|
|
for o = 1 to gd.players.(pid).bomb_radius do
|
|
if not !halt then begin
|
|
let nx = gd.players.(pid).xy.x + o * (fst order.(dir))
|
|
and ny = gd.players.(pid).xy.y + o * (snd order.(dir)) in
|
|
if is_valid nx ny lines cols then begin
|
|
if gd.laby.(nx).(ny) = 2 then begin
|
|
if not dgs.explodedCrates.(nx).(ny) then
|
|
res := true;
|
|
halt := true
|
|
end
|
|
else if gd.laby.(nx).(ny) = 1 then
|
|
halt := true
|
|
else if dgs.bonusMap.(nx).(ny) then
|
|
raise (ReturnBool false)
|
|
end
|
|
end
|
|
done;
|
|
halt := false ;
|
|
done;
|
|
!res
|
|
with
|
|
| ReturnBool b -> b ;;
|
|
|
|
let sees_a_crate (gd : game_data) (dgs : danger_map) (x : int) (y : int) =
|
|
let pid = gd.player_id
|
|
and lines = Array.length gd.laby
|
|
and cols = Array.length gd.laby.(0) in
|
|
try
|
|
let halt = ref false in
|
|
let res = ref false in
|
|
for dir = 0 to 3 do
|
|
for o = 1 to gd.players.(pid).bomb_radius do
|
|
if not !halt then begin
|
|
let nx = x + o * (fst order.(dir))
|
|
and ny = y + o * (snd order.(dir)) in
|
|
if is_valid nx ny lines cols then begin
|
|
if gd.laby.(nx).(ny) = 2 then begin
|
|
if not dgs.explodedCrates.(nx).(ny) then
|
|
res := true;
|
|
halt := true
|
|
end
|
|
else if gd.laby.(nx).(ny) = 1 then
|
|
halt := true
|
|
else if dgs.bonusMap.(nx).(ny) then
|
|
raise (ReturnBool false)
|
|
end
|
|
end
|
|
done;
|
|
halt := false ;
|
|
done;
|
|
!res
|
|
with
|
|
| ReturnBool b -> b ;;
|
|
|
|
let bfs_for_crate ?return_x:(retx=fodder) ?return_y:(rety=fodder) ?return_ok:(retfl=bodder) (gd : game_data) (dgs : danger_map) (x0 : int) (y0 : int) (stime : float) (searchCrate : bool) (searchBonus : bool) (placedBomb : bool) (minDist : int) (ignorePlayers : bool) (maxDist : int) =
|
|
let lines = Array.length gd.laby
|
|
and cols = Array.length gd.laby.(0) in
|
|
|
|
let visited = Hashtbl.create 100 in
|
|
let q = Queue.create () in
|
|
let interval = Float.pow (0.9) (float_of_int gd.players.(gd.player_id).nspeed) in
|
|
let pid = gd.player_id in
|
|
|
|
let needs_gtfo = not (is_empty_lst dgs.explosionTimes.(x0).(y0)) in
|
|
(*let nearest_player = min_dist_with_dash gd gd.players.(pid).xy.x gd.players.(pid).xy.y in*)
|
|
let nearest_player = min_dist_from_player gd gd.players.(pid).xy.x gd.players.(pid).xy.y in
|
|
|
|
let undead_end_tiles = generate_dead_end_map gd in
|
|
|
|
if gd.player_id = 4 then begin
|
|
for l = 0 to Array.length undead_end_tiles -1 do
|
|
for c = 0 to Array.length undead_end_tiles.(l) -1 do
|
|
if undead_end_tiles.(l).(c) >= 727 then
|
|
Printf.fprintf stderr "- "
|
|
else
|
|
Printf.fprintf stderr "%d " undead_end_tiles.(l).(c);
|
|
done;
|
|
Printf.fprintf stderr "\n";
|
|
done
|
|
end ;
|
|
|
|
Queue.add (x0, y0, stime +. interval, 4, 1) q ;
|
|
|
|
Queue.add (x0+1, y0, stime +. interval, 2, 1) q ;
|
|
Queue.add (x0-1, y0, stime +. interval, 0, 1) q ;
|
|
Queue.add (x0, y0+1, stime +. interval, 1, 1) q ;
|
|
Queue.add (x0, y0-1, stime +. interval, 3, 1) q ;
|
|
|
|
try
|
|
while not (Queue.is_empty q) do
|
|
let (x, y, ct, direction, polar) = Queue.pop q in
|
|
(*Printf.fprintf stderr "at (%d %d)\n" x y;*)
|
|
if is_valid x y lines cols && gd.laby.(x).(y) <> 1 && gd.laby.(x).(y) <> 2 then begin (* within the map *)
|
|
if Hashtbl.find_opt visited (x, y, polar) = None then begin (* has not been visited yet *)
|
|
Hashtbl.add visited (x, y, polar) 1 ;
|
|
if
|
|
not (is_dead_all dgs x y ct interval ignorePlayers) &&
|
|
ct < stime +. (float_of_int maxDist) *. interval &&
|
|
not (Array.fold_left (fun acc (b : bomb) -> acc || (b.xy.x = x && b.xy.y = y)) false gd.bombs) &&
|
|
polar <= 4
|
|
then begin (* is not lethal *)
|
|
if false && ct <= stime +. 3. *. interval then begin
|
|
Printf.fprintf stderr "(at %d %d) %b %b %b %b %b\n" x y
|
|
(ct >= stime +. (float_of_int minDist) *. interval) (* not too deep *)
|
|
(is_empty_lst dgs.explosionTimes.(x).(y)) (* safe *)
|
|
(needs_gtfo || undead_end_tiles.(x).(y) * 2 <= nearest_player) (* is not going to be an ez kill *)
|
|
(not searchCrate || (sees_a_crate gd dgs x y && not dgs.explodedCrates.(x).(y))) (* sees a crate *)
|
|
(not searchBonus || dgs.bonusMap.(x).(y)) (* is a bonus *)
|
|
end;
|
|
if
|
|
(ct >= stime +. (float_of_int minDist) *. interval) && (* not too deep *)
|
|
(is_empty_lst dgs.explosionTimes.(x).(y)) && (* safe *)
|
|
(needs_gtfo || undead_end_tiles.(x).(y) * 2 <= nearest_player) && (* is not going to be an ez kill *)
|
|
(not searchCrate || (sees_a_crate gd dgs x y && not dgs.explodedCrates.(x).(y))) && (* sees a crate *)
|
|
(not searchBonus || dgs.bonusMap.(x).(y)) (* is a bonus *)
|
|
then begin
|
|
retx := x ;
|
|
rety := y ;
|
|
raise (ReturnInt direction)
|
|
end;
|
|
if not (x0 = x && y0 = y) && (needs_gtfo || undead_end_tiles.(x).(y) * 2 <= nearest_player) then begin
|
|
for dir = 0 to 3 do
|
|
Queue.add (x + (fst order.(dir)), y + (snd order.(dir)), ct +. interval, direction, polar) q ;
|
|
done;
|
|
Queue.add (x, y, ct +. interval, direction, polar+1) q
|
|
end
|
|
end
|
|
end
|
|
end
|
|
done;
|
|
retfl := false ;
|
|
4 ;
|
|
with
|
|
| ReturnInt k ->
|
|
retfl := true ;
|
|
k ;;
|
|
|
|
let move_crate (gd : game_data) (dgs : danger_map) =
|
|
let pid = gd.player_id in
|
|
let cxi = gd.players.(pid).xy.x
|
|
and cyi = gd.players.(pid).xy.y in
|
|
try
|
|
(* send away a player standing right on top *)
|
|
if Array.exists (fun (p : player) -> p.id <> pid && p.xy.x = cxi && p.xy.y = cyi) gd.players && (is_empty_lst dgs.explosionTimes.(cxi).(cyi)) then begin
|
|
if gd.players.(pid).bomb_to_place > 0 then begin
|
|
if logg then Printf.fprintf stderr "oh no you dont\n" ;
|
|
let saved_p = simulate_bomb_deconstruct gd dgs cxi cyi gd.players.(pid).bomb_radius (gd.dt +. 5.5) in
|
|
|
|
let bonusres_2p = bfs_for_crate gd dgs cxi cyi gd.dt false true false 0 false 5 in
|
|
if bonusres_2p <> 4 then begin
|
|
if logg then Printf.fprintf stderr "mine\n" ;
|
|
raise (ReturnInt bonusres_2p) ;
|
|
end;
|
|
|
|
let resultp = bfs_for_crate gd dgs cxi cyi gd.dt false false true 1 false 80 in
|
|
if resultp <> 4 then begin
|
|
if logg then Printf.fprintf stderr "go away\n" ;
|
|
action := 1 ;
|
|
raise (ReturnInt resultp) ;
|
|
end;
|
|
reverse_simulate_bomb dgs saved_p ;
|
|
end
|
|
end;
|
|
if (is_a_crate_nearby gd dgs)(* && (is_empty_lst dgs.explosionTimes.(cxi).(cyi)) *)then begin
|
|
if gd.players.(pid).bomb_to_place > 0 then begin
|
|
if logg then Printf.fprintf stderr "trying...\n" ;
|
|
let saved = simulate_bomb_deconstruct gd dgs cxi cyi gd.players.(pid).bomb_radius (gd.dt +. 5.5) in
|
|
let bonus2_x = ref 0
|
|
and bonus2_y = ref 0 in
|
|
let bonusres_2 = bfs_for_crate ~return_x:bonus2_x ~return_y:bonus2_y gd dgs cxi cyi gd.dt false true false 0 false 5 in
|
|
if bonusres_2 <> 4 && (tile_distance gd cxi cyi !bonus2_x !bonus2_y <= min_dist_from_player gd cxi cyi) then begin
|
|
if logg then Printf.fprintf stderr "Bonus Spotted\n" ;
|
|
action := 1 ;
|
|
raise (ReturnInt bonusres_2) ;
|
|
end;
|
|
|
|
let result = bfs_for_crate gd dgs cxi cyi gd.dt false false true 1 false 80 in
|
|
if result <> 4 then begin
|
|
action := 1 ;
|
|
raise (ReturnInt result) ;
|
|
end;
|
|
reverse_simulate_bomb dgs saved ;
|
|
end
|
|
end;
|
|
if logg then Printf.fprintf stderr "bonusing...\n" ;
|
|
let bonus_x = ref 0
|
|
and bonus_y = ref 0 in
|
|
let bonusres = bfs_for_crate ~return_x:bonus_x ~return_y:bonus_y gd dgs cxi cyi gd.dt false true false 0 false 5 in
|
|
if bonusres <> 4 && (tile_distance gd cxi cyi !bonus_x !bonus_y <= min_dist_from_player gd cxi cyi) then begin
|
|
if logg then Printf.fprintf stderr "bonus spotted\n" ;
|
|
raise (ReturnInt bonusres) ;
|
|
end;
|
|
if logg then Printf.fprintf stderr "searching...\n" ;
|
|
let rescr = bfs_for_crate gd dgs cxi cyi gd.dt true false false 0 false 80 in
|
|
if logg then Printf.fprintf stderr "searching Done...\n" ;
|
|
if rescr <> 4 then
|
|
rescr
|
|
else begin
|
|
if logg then Printf.fprintf stderr "searching 2...\n" ;
|
|
let success = ref false in
|
|
let rescr2 = bfs_for_crate ~return_ok:success gd dgs cxi cyi gd.dt false false false 0 false 80 in
|
|
if logg then Printf.fprintf stderr "searching 2 Done...\n" ;
|
|
if !success then
|
|
rescr2
|
|
else begin
|
|
if logg then Printf.fprintf stderr "Needs dash lmao\n";
|
|
4
|
|
end
|
|
end
|
|
with
|
|
| ReturnInt k -> k ;;
|
|
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
|
|
let bfs_for_land ?return_x:(retx=fodder) ?return_y:(rety=fodder) ?return_ok:(retfl=bodder) (skip_near : bool) (gd : game_data) (dgs : danger_map) (x0 : int) (y0 : int) (target_x : int) (target_y : int) ?leniency:(lenc=1) (stime : float) (minDist : int) (maxDist : int) =
|
|
let lines = Array.length gd.laby
|
|
and cols = Array.length gd.laby.(0) in
|
|
|
|
let visited = Hashtbl.create 100 in
|
|
let q = Queue.create () in
|
|
let interval = Float.pow (0.9) (float_of_int gd.players.(gd.player_id).nspeed) in
|
|
let pid = gd.player_id in
|
|
|
|
let needs_gtfo = not (is_empty_lst dgs.explosionTimes.(x0).(y0)) in
|
|
(*let nearest_player = min_dist_with_dash gd gd.players.(pid).xy.x gd.players.(pid).xy.y in*)
|
|
let nearest_player = min_dist_from_player gd gd.players.(pid).xy.x gd.players.(pid).xy.y in
|
|
|
|
let undead_end_tiles = generate_dead_end_map gd in
|
|
|
|
if gd.player_id = 4 then begin
|
|
for l = 0 to Array.length undead_end_tiles -1 do
|
|
for c = 0 to Array.length undead_end_tiles.(l) -1 do
|
|
if undead_end_tiles.(l).(c) >= 727 then
|
|
Printf.fprintf stderr "- "
|
|
else
|
|
Printf.fprintf stderr "%d " undead_end_tiles.(l).(c);
|
|
done;
|
|
Printf.fprintf stderr "\n";
|
|
done
|
|
end ;
|
|
|
|
Queue.add (x0, y0, stime +. interval, 4, 1) q ;
|
|
|
|
Queue.add (x0+1, y0, stime +. interval, 2, 1) q ;
|
|
Queue.add (x0-1, y0, stime +. interval, 0, 1) q ;
|
|
Queue.add (x0, y0+1, stime +. interval, 1, 1) q ;
|
|
Queue.add (x0, y0-1, stime +. interval, 3, 1) q ;
|
|
|
|
try
|
|
while not (Queue.is_empty q) do
|
|
let (x, y, ct, direction, polar) = Queue.pop q in
|
|
(*Printf.fprintf stderr "at (%d %d)\n" x y;*)
|
|
if is_valid x y lines cols && gd.laby.(x).(y) <> 1 && gd.laby.(x).(y) <> 2 then begin (* within the map *)
|
|
if Hashtbl.find_opt visited (x, y, polar) = None then begin (* has not been visited yet *)
|
|
Hashtbl.add visited (x, y, polar) 1 ;
|
|
if
|
|
not (is_dead_all dgs x y ct interval false) &&
|
|
ct < stime +. (float_of_int maxDist) *. interval &&
|
|
not (Array.fold_left (fun acc (b : bomb) -> acc || (b.xy.x = x && b.xy.y = y)) false gd.bombs) &&
|
|
polar <= 4
|
|
then begin (* is not lethal *)
|
|
if false && ct <= stime +. 3. *. interval then begin
|
|
Printf.fprintf stderr "(at %d %d) %b %b %b\n" x y
|
|
(ct >= stime +. (float_of_int minDist) *. interval) (* not too deep *)
|
|
(is_empty_lst dgs.explosionTimes.(x).(y)) (* safe *)
|
|
(needs_gtfo || undead_end_tiles.(x).(y) * 2 <= nearest_player) (* is not going to be an ez kill *)
|
|
end;
|
|
if
|
|
(ct >= stime +. (float_of_int minDist) *. interval) && (* not too deep *)
|
|
(is_empty_lst dgs.explosionTimes.(x).(y)) && (* safe *)
|
|
(needs_gtfo || undead_end_tiles.(x).(y) * 2 <= nearest_player) && (* is not going to be an ez kill *)
|
|
(skip_near || tile_distance gd x y target_x target_y <= lenc) (* close enough to target *)
|
|
then begin
|
|
retx := x ;
|
|
rety := y ;
|
|
raise (ReturnInt direction)
|
|
end;
|
|
if not (x0 = x && y0 = y) && (needs_gtfo || undead_end_tiles.(x).(y) * 2 <= nearest_player) then begin
|
|
for dir = 0 to 3 do
|
|
Queue.add (x + (fst order.(dir)), y + (snd order.(dir)), ct +. interval, direction, polar) q ;
|
|
done;
|
|
Queue.add (x, y, ct +. interval, direction, polar+1) q
|
|
end
|
|
end
|
|
end
|
|
end
|
|
done;
|
|
retfl := false ;
|
|
4 ;
|
|
with
|
|
| ReturnInt k ->
|
|
retfl := true ;
|
|
k ;;
|
|
|
|
let move_land (gd : game_data) (dgs : danger_map) (gn : int array array) =
|
|
let max_cols = Array.mapi
|
|
(fun i lne ->
|
|
Array.fold_left
|
|
(fun acc (idc, sco) ->
|
|
if sco > snd acc then
|
|
(idc, sco)
|
|
else
|
|
acc
|
|
)
|
|
(0, 0)
|
|
(Array.mapi (fun j v -> (j, v)) lne)
|
|
)
|
|
gn
|
|
in
|
|
let (xmax, ymax, _) = Array.fold_left
|
|
(fun (cxm, cym, cvm) (nx, ny, nv) ->
|
|
if nv > cvm then
|
|
(nx, ny, nv)
|
|
else
|
|
(cxm, cym, cvm)
|
|
)
|
|
(0, 0, 0)
|
|
(Array.mapi (fun i (j, v) -> (i, j, v)) max_cols)
|
|
in
|
|
let pid = gd.player_id in
|
|
let cxi = gd.players.(pid).xy.x
|
|
and cyi = gd.players.(pid).xy.y in
|
|
|
|
if logg then Printf.fprintf stderr "going at (%d, %d) [score=%d]\n" xmax ymax gn.(xmax).(ymax);
|
|
|
|
(* try to place a bomb *)
|
|
let is_safe = is_empty_lst dgs.explosionTimes.(cxi).(cyi) in
|
|
let saved_p = simulate_bomb_deconstruct gd dgs cxi cyi gd.players.(pid).bomb_radius (gd.dt +. 5.5) in
|
|
let is_good = ref false in
|
|
|
|
let result_bomb = bfs_for_land ~return_ok:is_good true gd dgs cxi cyi xmax ymax gd.dt 1 80 in
|
|
if is_safe && gd.players.(pid).bomb_to_place > 0 && !is_good then begin
|
|
if logg then Printf.fprintf stderr "kaboom\n" ;
|
|
action := 1 ;
|
|
result_bomb
|
|
end
|
|
else begin
|
|
reverse_simulate_bomb dgs saved_p ;
|
|
|
|
let res = bfs_for_land ~return_ok:is_good false gd dgs cxi cyi xmax ymax gd.dt 1 80 in
|
|
if !is_good then begin
|
|
if logg then Printf.fprintf stderr "going to kaboom\n" ;
|
|
res
|
|
end
|
|
else begin
|
|
if logg then Printf.fprintf stderr "E\n" ;
|
|
let res = bfs_for_land ~leniency:20 false gd dgs cxi cyi xmax ymax gd.dt 1 80 in
|
|
res
|
|
end
|
|
end ;;
|
|
|
|
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
|
|
let exists_crate (gd : game_data) (dgs : danger_map) =
|
|
let lines = Array.length gd.laby
|
|
and cols = Array.length gd.laby.(0) in
|
|
for i = 0 to lines -1 do
|
|
for j = 0 to cols -1 do
|
|
if dgs.explodedCrates.(i).(j) then
|
|
gd.laby.(i).(j) <- -2 ;
|
|
done
|
|
done ;
|
|
let res = Array.exists
|
|
(fun line -> Array.exists (fun tile -> tile = 2) line)
|
|
gd.laby in
|
|
for i = 0 to lines -1 do
|
|
for j = 0 to cols -1 do
|
|
if dgs.explodedCrates.(i).(j) then
|
|
gd.laby.(i).(j) <- 2 ;
|
|
done
|
|
done ;
|
|
res ;;
|
|
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
|
|
|
let __start = Unix.gettimeofday() ;;
|
|
let game_map = parse_input "entrees.txt" ;;
|
|
if debug_all then print_game_data game_map ;;
|
|
let danger_data = build_danger_map game_map ;;
|
|
let gain_map = generate_gain_map game_map ;;
|
|
|
|
(*Printf.fprintf stderr "\n" ;;
|
|
print_dangers danger_data ;;*)
|
|
|
|
(*get_meta_info game_map.player_id ;;*)
|
|
(*Printf.fprintf stderr "\n" ;;
|
|
print_dangers danger_data ;;*)
|
|
let direction = ref 4 ;;
|
|
|
|
if exists_crate game_map danger_data then begin
|
|
if logg then Printf.fprintf stderr "Crates\n" ;
|
|
direction := move_crate game_map danger_data
|
|
end
|
|
else begin
|
|
if logg then Printf.fprintf stderr "No crates\n" ;
|
|
direction := move_land game_map danger_data gain_map
|
|
end ;;
|
|
|
|
Printf.printf "%d %d" !direction !action ;
|
|
if logg then Printf.fprintf stderr "[player %d] %d %d (at time %f)\n" game_map.player_id !direction !action game_map.dt;;
|
|
|
|
(*set_meta_info game_map.player_id ;;*)
|
|
let __end = Unix.gettimeofday() ;;
|
|
if logg then Printf.fprintf stderr "Time : %f\n" (__end -. __start) ;;
|
|
|