(tried to) make advanced pathfinding more exausti(ng)ve

This commit is contained in:
Alexandre 2024-11-19 22:15:24 +01:00
parent 21f2b79a4b
commit 50a354ea94
9 changed files with 117 additions and 86 deletions

BIN
again

Binary file not shown.

BIN
again.cmi

Binary file not shown.

BIN
again.cmo

Binary file not shown.

BIN
again.cmx

Binary file not shown.

152
again.ml
View File

@ -98,7 +98,7 @@ exception ReturnBool of bool ;;
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) (* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) (* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
let order = [|(-1, 0); (0, 1); (1, 0); (0, -1)|] ;; let order = [|(-1, 0); (0, 1); (1, 0); (0, -1); (0, 0)|] ;;
let current_status = ref BlowUpCrates ;; let current_status = ref BlowUpCrates ;;
let action = ref 0 ;; let action = ref 0 ;;
@ -486,28 +486,52 @@ let simulate_bomb_deconstruct (dgs : danger_map) (bx : int) (by : int) (bsize :
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) (* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) (* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
let tile_distance (gd : game_data) (start_x : int) (start_y : int) (end_x : int) (end_y : int) = let tile_distance (gd : game_data) (x0 : int) (y0 : int) (end_x : int) (end_y : int) =
(* returns -1 if the 2 tiles cannot connect *) (* returns -1 if the 2 tiles cannot connect *)
let lines = Array.length gd.laby let lines = Array.length gd.laby
and cols = Array.length gd.laby.(0) in and cols = Array.length gd.laby.(0) in
let visited = Hashtbl.create 50 in let visited = Hashtbl.create 100 in
let rec aux x y depth = let q = Queue.create () in
if Hashtbl.find_opt visited (x, y) = None then begin
Hashtbl.add visited (x, y) 1; Queue.add (x0, y0, 0) q;
if (is_valid x y lines cols && gd.laby.(x).(y) <> 1 && gd.laby.(x).(y) <> 2 && not (Array.fold_left (fun acc (b : bomb) -> acc || (b.xy.x = x && b.xy.y = y)) false gd.bombs)) then begin
if x = end_x && y = end_y then
raise (ReturnInt depth) ;
for dir = 0 to 3 do
aux (x + fst order.(dir)) (y + snd order.(dir)) (depth+1)
done
end
end
in
try try
aux start_x start_y 0; 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 && not (Array.fold_left (fun acc (b : bomb) -> acc || (b.xy.x = x && b.xy.y = y)) false gd.bombs) 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 not (x0 == x && y0 == y) 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) ; (-1) ;
with with
| ReturnInt b -> b ;; | 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
)
) ;;
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) (* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) (* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
@ -517,26 +541,29 @@ let amt_free_adj_spaces (gd : game_data) (x : int) (y : int) =
and cols = Array.length gd.laby.(0) in and cols = Array.length gd.laby.(0) in
Array.fold_left Array.fold_left
(fun acc (ox, oy) -> (fun acc (ox, oy) ->
if (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 && b.xy.y = y)) false gd.bombs)) then acc+1 else acc if (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 0
order ;; order ;;
let max_depth = 4 ;; let max_depth = 12345 ;;
let max_spacing = 4 ;; let is_player_nearby (gd : game_data) (x0 : int) (y0 : int) (detect_dist : int) =
let is_player_nearby (gd : game_data) (res_x : int ref) (res_y : int ref) =
let pid = gd.player_id in let pid = gd.player_id in
let lines = Array.length gd.laby let lines = Array.length gd.laby
and cols = Array.length gd.laby.(0) in and cols = Array.length gd.laby.(0) in
(* DFS to find whether or not there are nearby players *) (* DFS to find whether or not there are nearby players *)
let visited = Hashtbl.create 40 in let visited = Hashtbl.create 40 in
Hashtbl.add visited ((gd.players.(pid).xy.x), (gd.players.(pid).xy.y)) 1 ; Hashtbl.add visited (x0, y0) 1 ;
let rec dfs x y depth = let rec dfs x y depth =
if Hashtbl.find_opt visited (x, y) = None && depth <= max_depth && (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) &&
(depth <= detect_dist) &&
(is_valid x y lines cols) &&
(gd.laby.(x).(y) <> 1 && gd.laby.(x).(y) <> 2) &&
(not (Array.fold_left (fun acc (b : bomb) -> acc || (b.xy.x = x && b.xy.y = y)) false gd.bombs))
then begin
Hashtbl.add visited (x, y) 1; Hashtbl.add visited (x, y) 1;
if Array.exists (fun (p : player) -> p.xy.x = x && p.xy.y = y) gd.players then begin if Array.exists (fun (p : player) -> p.xy.x = x && p.xy.y = y && p.id <> gd.player_id) gd.players then begin
res_x := x ;
res_y := y ;
raise (ReturnBool true) raise (ReturnBool true)
end end
else begin else begin
@ -559,7 +586,7 @@ let is_player_nearby (gd : game_data) (res_x : int ref) (res_y : int ref) =
| ReturnBool b -> b ;; | ReturnBool b -> b ;;
let is_dead_end (gd : game_data) (xstart : int) (ystart : int) (xban : int) (yban : int) = let is_dead_end (gd : game_data) (xstart : int) (ystart : int) (xban : int) (yban : int) =
if not (is_player_nearby gd fodder_x fodder_y) then if not (is_player_nearby gd gd.players.(gd.player_id).xy.x gd.players.(gd.player_id).xy.y max_depth) then
false (* if no one is nearby, it's safe to go there (hopefully) *) false (* if no one is nearby, it's safe to go there (hopefully) *)
else begin else begin
let lines = Array.length gd.laby let lines = Array.length gd.laby
@ -587,39 +614,48 @@ let is_dead_end (gd : game_data) (xstart : int) (ystart : int) (xban : int) (yba
end ;; end ;;
let has_multiple_escapes (gd : game_data) (xstart : int) (ystart : int) (xban : int) (yban : int) = let has_multiple_escapes (gd : game_data) (xstart : int) (ystart : int) (xban : int) (yban : int) =
let pl_x = ref 0 let lines = Array.length gd.laby
and pl_y = ref 0 in and cols = Array.length gd.laby.(0) in
if not (is_player_nearby gd pl_x pl_y) then if not (is_player_nearby gd gd.players.(gd.player_id).xy.x gd.players.(gd.player_id).xy.y max_depth) then
false (* if no one is nearby, it's safe to go there (hopefully) *) false (* if no one is nearby, it's safe to go there (hopefully) *)
else begin else begin
let lines = Array.length gd.laby let visited = Hashtbl.create 100 in
and cols = Array.length gd.laby.(0) in let q = Queue.create () in
let visited = Hashtbl.create 50 in
Hashtbl.add visited (xban, yban) 1 ; Queue.add (xstart, ystart, 0, false) q;
let rec aux x y =
if Hashtbl.find_opt visited (x, y) = None then begin
Hashtbl.add visited (x, y) 1;
if (is_valid x y lines cols && gd.laby.(x).(y) <> 1 && gd.laby.(x).(y) <> 2 && not (Array.fold_left (fun acc (b : bomb) -> acc || (b.xy.x = x && b.xy.y = y)) false gd.bombs)) then begin
match (amt_free_adj_spaces gd x y) with
| 0 -> failwith "wtf john"
| 1 | 2 -> for dir = 0 to 3 do
aux (x + fst order.(dir)) (y + snd order.(dir))
done
| _ ->
if tile_distance gd x y !pl_x !pl_y >= max_spacing then
raise (ReturnBool false) ;
end
end
in
try try
aux xstart ystart; while not (Queue.is_empty q) do
true ; let (x, y, depth, hasSafe) = Queue.pop q in
if is_valid x y lines cols && gd.laby.(x).(y) <> 1 && gd.laby.(x).(y) <> 2 && not (Array.fold_left (fun acc (b : bomb) -> acc || (b.xy.x = x && b.xy.y = y)) false gd.bombs) then begin
if Hashtbl.find_opt visited (x, y) = None then begin (* has not been visited yet *)
Hashtbl.add visited (x, y) 1 ;
if
(amt_free_adj_spaces gd x y >= 3) &&
(min_dist_from_player gd x y >= depth - d_len || hasSafe)
then begin
raise (ReturnBool true)
end
else if (amt_free_adj_spaces gd x y >= 3) then begin
for dir = 0 to 3 do
Queue.add (x + (fst order.(dir)), y + (snd order.(dir)), depth+1, true) q ;
done;
end
else if (amt_free_adj_spaces gd x y = 2) then begin
for dir = 0 to 3 do
Queue.add (x + (fst order.(dir)), y + (snd order.(dir)), depth+1, hasSafe) q ;
done;
end
end
end
done;
false ;
with with
| ReturnBool b -> b | ReturnBool k -> k
end ;; end ;;
let advanced_pathfind (gd : game_data) (xstart : int) (ystart : int) (xban : int) (yban : int) = let advanced_pathfind (gd : game_data) (dgs : danger_map) (xstart : int) (ystart : int) (xban : int) (yban : int) =
(is_dead_end gd xstart ystart xban yban) && (has_multiple_escapes gd xstart ystart xban yban) ;; (not (is_player_nearby gd gd.players.(gd.player_id).xy.x gd.players.(gd.player_id).xy.y max_depth)) || ((*is_dead_end gd xstart ystart xban yban) && *)(has_multiple_escapes gd xstart ystart xban yban)) ;;
let reverse_simulate_bomb (dgs : danger_map) (save : (int * int, float) Hashtbl.t) = let reverse_simulate_bomb (dgs : danger_map) (save : (int * int, float) Hashtbl.t) =
Hashtbl.iter Hashtbl.iter
@ -689,8 +725,8 @@ let goto_tile (gd : game_data) (dgs : danger_map) (x0 : int) (y0 : int) (end_x :
then begin (* is not lethal *) then begin (* is not lethal *)
if if
(is_empty_lst dgs.explosionTimes.(x).(y)) && (* safe *) (is_empty_lst dgs.explosionTimes.(x).(y)) && (* safe *)
(not (is_player_nearby gd fodder_x fodder_y && amt_free_adj_spaces gd x y = 1)) && (* is not a dead-end (==> ez kill) *) (not (is_player_nearby gd x y 3 && amt_free_adj_spaces gd (gd.players.(pid).xy.x + fst order.(direction)) (gd.players.(pid).xy.y + snd order.(direction)) = 1)) &&
(direction = 4 || not (advanced_pathfind gd (gd.players.(pid).xy.x + fst order.(direction)) (gd.players.(pid).xy.y + snd order.(direction)) gd.players.(pid).xy.x gd.players.(pid).xy.y)) && (direction = 4 || (advanced_pathfind gd dgs (gd.players.(pid).xy.x + fst order.(direction)) (gd.players.(pid).xy.y + snd order.(direction)) gd.players.(pid).xy.x gd.players.(pid).xy.y)) &&
(x = end_x && y = end_y) (x = end_x && y = end_y)
then begin then begin
raise (ReturnInt direction) raise (ReturnInt direction)
@ -802,8 +838,8 @@ let bfs_for_crate (gd : game_data) (dgs : danger_map) (x0 : int) (y0 : int) (sti
if if
(ct >= stime +. (float_of_int minDist) *. interval) && (* not too deep *) (ct >= stime +. (float_of_int minDist) *. interval) && (* not too deep *)
(is_empty_lst dgs.explosionTimes.(x).(y)) && (* safe *) (is_empty_lst dgs.explosionTimes.(x).(y)) && (* safe *)
(not (is_player_nearby gd fodder_x fodder_y && amt_free_adj_spaces gd x y = 1)) && (* is not a dead-end (==> ez kill) *) (not (is_player_nearby gd x y 3 && amt_free_adj_spaces gd (gd.players.(pid).xy.x + fst order.(direction)) (gd.players.(pid).xy.y + snd order.(direction)) = 1)) && (* is not a dead-end (==> ez kill) *)
(not placedBomb || direction = 4 || not (advanced_pathfind gd (gd.players.(pid).xy.x + fst order.(direction)) (gd.players.(pid).xy.y + snd order.(direction)) gd.players.(pid).xy.x gd.players.(pid).xy.y)) && ((advanced_pathfind gd dgs (gd.players.(pid).xy.x + fst order.(direction)) (gd.players.(pid).xy.y + snd order.(direction)) gd.players.(pid).xy.x gd.players.(pid).xy.y)) &&
(not searchCrate || (sees_a_crate gd dgs x y && not dgs.explodedCrates.(x).(y))) && (* sees a crate *) (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 *) (not searchBonus || dgs.bonusMap.(x).(y)) (* is a bonus *)
then begin then begin

BIN
again.o

Binary file not shown.

View File

@ -1 +1 @@
ocamlc again.ml -o again ocamlfind ocamlopt -linkpkg -package unix again.ml -o again

View File

@ -1,31 +1,26 @@
457.50401999999656 187.24208499999915
3 2
13 21 13 21
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 3 3 0 6 3 3 3 3 3 3 3 3 3 5 5 5 5 5 6 1 1 3 3 3 3 3 3 6 3 3 3 3 0 0 0 0 5 5 5 5 1
1 3 1 0 1 6 1 3 1 3 1 3 1 3 1 5 1 5 1 5 1 1 3 1 3 1 3 1 6 1 0 1 3 1 5 1 0 1 5 1 5 1
1 5 3 6 6 6 6 3 5 5 5 5 5 3 5 5 5 5 3 3 1 1 3 3 3 3 3 3 6 3 0 0 3 5 5 5 5 5 5 5 5 1
1 6 1 6 1 6 1 3 1 4 1 4 1 3 1 5 1 5 1 5 1 1 3 1 3 1 3 1 6 1 6 1 3 1 5 1 5 1 0 1 0 1
1 6 6 6 6 6 3 3 3 3 3 3 3 3 3 5 5 5 5 5 1 1 3 3 5 3 4 3 6 3 5 0 3 0 3 3 3 3 3 3 0 1
1 6 1 6 1 6 1 3 1 3 1 6 1 3 1 5 1 5 1 4 1 1 3 1 5 1 4 1 6 1 5 1 3 1 4 1 4 1 4 1 0 1
1 6 6 6 6 6 6 6 6 6 6 6 4 4 5 5 6 5 0 4 1 1 0 0 4 4 4 4 4 6 6 6 6 6 6 4 4 3 3 3 3 1
1 6 1 6 1 6 1 6 1 3 1 6 1 4 1 6 1 3 1 4 1 1 0 1 5 1 4 1 6 1 5 1 0 1 4 1 4 1 4 1 3 1
1 6 6 6 4 6 3 6 6 6 6 6 6 4 3 3 3 3 3 3 1 1 5 5 5 5 4 5 6 6 5 6 5 6 6 4 4 4 4 4 3 1
1 6 1 6 1 6 1 6 1 6 1 6 1 4 1 6 1 3 1 4 1 1 5 1 6 1 5 1 6 1 6 1 5 1 0 1 4 1 4 1 3 1
1 6 6 5 6 6 6 6 6 6 6 6 4 4 4 4 3 3 3 3 1 1 5 6 6 6 5 6 6 6 6 6 6 5 5 4 4 4 4 4 4 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
8 3
7 13 2 457.7330299999967 5 1 3 189.5
7 10 2 459.4610799999966 7 4 6 190.30000000000013
2 9 1 459.5 6 3 2 192.5
8 9 2 460.68547999999663
1 13 2 460.9700000000011
5 11 2 461.2325499999966
7 7 2 462.4569499999966
3 7 1 462.5
4 4
8 7 0 5 2 2 1 0 7 1 0 0 2 3 1 1
4 7 1 0 2 1 0 1 5 3 1 0 0 2 1 3
2 11 2 2 2 2 0 0 6 3 2 6 1 2 2 2
5 14 3 5 2 2 6 6 7 5 3 1 0 6 1 1
0 0

View File

@ -1 +1 @@
1 1 0 0