added exploration function

This commit is contained in:
Alexandre 2024-11-07 20:13:35 +01:00
parent 1ed4d9b75b
commit a7da366a02
4 changed files with 115 additions and 5 deletions

BIN
bin/main

Binary file not shown.

BIN
main.cmi

Binary file not shown.

BIN
main.cmo

Binary file not shown.

120
main.ml
View File

@ -94,6 +94,8 @@ exception ReturnInt of int ;;
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
let current_status = ref BlowUpCrates ;;
let equal_pt (p1 : pt) (p2 : pt) =
p1.x = p2.x && p1.y = p2.y ;;
@ -269,6 +271,35 @@ let evaluate_dangers (gd : game_data) =
done
done ;
(* add players as warning (in case they bomb) *)
for p = 0 to gd.nplayers -1 do
if p <> gd.player_id then begin
let halt = ref false in
let bx = gd.players.(p).xy.x
and by = gd.players.(p).xy.y in
for dir = 0 to 3 do
for w = 0 to gd.players.(p).bomb_radius 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 then begin (* crate *)
halt := true ;
res.(cx).(cy) <- danger_priority res.(cx).(cy) Danger ;
end
else begin
res.(cx).(cy) <- danger_priority res.(cx).(cy) Danger ;
end
end
done;
halt := false ;
done
end
done;
(* sort bombs based on detonation time *)
for b = 0 to gd.nbombs -1 do
let m = ref gd.bombs.(b).det_time
@ -323,6 +354,7 @@ let is_safe = function
let move_safe (gd : game_data) (dgs : danger array array) =
(* use this whenever you are standing on a non-safe tile *)
(* Strat : find the closest safe tile (or warning tile if there are no reachable safe tile) *)
let pid = gd.player_id in
let lines = Array.length gd.laby
@ -330,12 +362,16 @@ let move_safe (gd : game_data) (dgs : danger array array) =
(* 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
raise (ReturnInt 4) ;
let q = Queue.create () in
let visited = Hashtbl.create 100 in
(* 1. try not to walk on fatal tiles *)
if debug then Printf.printf "Attempt 1/3...\n";
let (cx, cy) = (gd.players.(pid).xy.x, gd.players.(pid).xy.y) in
if debug then Printf.printf "[escape] Attempt 1/3...\n";
if cx <> 0 && is_safe dgs.(cx-1).(cy) then (* North *) Queue.add (cx-1, cy, 0) q ;
if cx <> lines -1 && is_safe dgs.(cx+1).(cy) then (* South *) Queue.add (cx+1, cy, 2) q ;
if cy <> 0 && is_safe dgs.(cx).(cy-1) then (* West *) Queue.add (cx, cy-1, 3) q ;
@ -356,7 +392,7 @@ let move_safe (gd : game_data) (dgs : danger array array) =
done;
(* 2. find the path that get you off fatal tiles ASAP *)
if debug then Printf.printf "Attempt 2/3...\n";
if debug then Printf.printf "[escape] Attempt 2/3...\n";
if cx <> 0 && dgs.(cx-1).(cy) <> Blocked then (* North *) Queue.add (cx-1, cy, 0) q ;
if cx <> lines -1 && dgs.(cx+1).(cy) <> Blocked then (* South *) Queue.add (cx+1, cy, 2) q ;
if cy <> 0 && dgs.(cx).(cy-1) <> Blocked then (* West *) Queue.add (cx, cy-1, 3) q ;
@ -377,7 +413,7 @@ let move_safe (gd : game_data) (dgs : danger array array) =
done;
(* 3. no safe tile within reach (very rare), look out for warning *)
if debug then Printf.printf "Attempt 3/3...\n";
if debug then Printf.printf "[escape] Attempt 3/3...\n";
if cx <> 0 && dgs.(cx-1).(cy) <> Blocked then (* North *) Queue.add (cx-1, cy, 0) q ;
if cx <> lines -1 && dgs.(cx+1).(cy) <> Blocked then (* South *) Queue.add (cx+1, cy, 2) q ;
if cy <> 0 && dgs.(cx).(cy-1) <> Blocked then (* West *) Queue.add (cx, cy-1, 3) q ;
@ -398,11 +434,85 @@ let move_safe (gd : game_data) (dgs : danger array array) =
done;
(* you're probably dead if the code reaches here *)
if debug then Printf.printf "Attempt F...\n";
if debug then Printf.printf "[escape] Attempt F...\n";
4
with
| ReturnInt k -> k ;;
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
let move_explore (gd: game_data) (dgs : danger array array) =
(* destroy crates *)
let pid = gd.player_id in
let lines = Array.length gd.laby
and cols = Array.length gd.laby.(0) in
(* find nearest crate and blow it up *)
try
let q = Queue.create () in
let visited = Hashtbl.create 100 in
let (cx, cy) = (gd.players.(pid).xy.x, gd.players.(pid).xy.y) in
(* O. if there's a crate right next to you, blow it up *)
if cx <> 0 && gd.laby.(cx-1).(cy) = 2 then (* North *) begin current_status := EscapeDeath; raise (ReturnInt 4) end ;
if cx <> lines -1 && gd.laby.(cx+1).(cy) = 2 then (* South *) begin current_status := EscapeDeath; raise (ReturnInt 4) end ;
if cy <> 0 && gd.laby.(cx).(cy-1) = 2 then (* West *) begin current_status := EscapeDeath; raise (ReturnInt 4) end ;
if cy <> cols -1 && gd.laby.(cx).(cy+1) = 2 then (* East *) begin current_status := EscapeDeath; raise (ReturnInt 4) end ;
(* 1. search without walking on dangerous tiles *)
if debug then Printf.printf "[explore] Attempt 1/2...\n";
if cx <> 0 && is_safe dgs.(cx-1).(cy) then (* North *) Queue.add (cx-1, cy, 0) q ;
if cx <> lines -1 && is_safe dgs.(cx+1).(cy) then (* South *) Queue.add (cx+1, cy, 2) q ;
if cy <> 0 && is_safe dgs.(cx).(cy-1) then (* West *) Queue.add (cx, cy-1, 3) q ;
if cy <> cols -1 && is_safe dgs.(cx).(cy+1) then (* East *) Queue.add (cx, cy+1, 1) q ;
while not (Queue.is_empty q) do
let (cx, cy, dir) = Queue.pop q in
Hashtbl.add visited (cx, cy, 1) 1 ;
if gd.laby.(cx).(cy) = 2 then
raise (ReturnInt dir)
else begin
(* add neighbors *)
if cx <> 0 && Hashtbl.find_opt visited (cx-1, cy, 1) = None && is_safe dgs.(cx-1).(cy) then (* North *) Queue.add (cx-1, cy, dir) q ;
if cx <> lines -1 && Hashtbl.find_opt visited (cx+1, cy, 1) = None && is_safe dgs.(cx+1).(cy) then (* South *) Queue.add (cx+1, cy, dir) q ;
if cy <> 0 && Hashtbl.find_opt visited (cx, cy-1, 1) = None && is_safe dgs.(cx).(cy-1) then (* West *) Queue.add (cx, cy-1, dir) q ;
if cy <> cols -1 && Hashtbl.find_opt visited (cx, cy+1, 1) = None && is_safe dgs.(cx).(cy+1) then (* East *) Queue.add (cx, cy+1, dir) q ;
end
done;
(* 2. search one anyway *)
if debug then Printf.printf "[explore] Attempt 2/2...\n";
let (cx, cy) = (gd.players.(pid).xy.x, gd.players.(pid).xy.y) in
if cx <> 0 && is_safe dgs.(cx-1).(cy) then (* North *) Queue.add (cx-1, cy, 0) q ;
if cx <> lines -1 && is_safe dgs.(cx+1).(cy) then (* South *) Queue.add (cx+1, cy, 2) q ;
if cy <> 0 && is_safe dgs.(cx).(cy-1) then (* West *) Queue.add (cx, cy-1, 3) q ;
if cy <> cols -1 && is_safe dgs.(cx).(cy+1) then (* East *) Queue.add (cx, cy+1, 1) q ;
while not (Queue.is_empty q) do
let (cx, cy, dir) = Queue.pop q in
Hashtbl.add visited (cx, cy, 2) 1 ;
if gd.laby.(cx).(cy) = 2 then
raise (ReturnInt dir)
else begin
(* add neighbors *)
if cx <> 0 && Hashtbl.find_opt visited (cx-1, cy, 2) = None && dgs.(cx-1).(cy) <> Blocked then (* North *) Queue.add (cx-1, cy, dir) q ;
if cx <> lines -1 && Hashtbl.find_opt visited (cx+1, cy, 2) = None && dgs.(cx+1).(cy) <> Blocked then (* South *) Queue.add (cx+1, cy, dir) q ;
if cy <> 0 && Hashtbl.find_opt visited (cx, cy-1, 2) = None && dgs.(cx).(cy-1) <> Blocked then (* West *) Queue.add (cx, cy-1, dir) q ;
if cy <> cols -1 && Hashtbl.find_opt visited (cx, cy+1, 2) = None && dgs.(cx).(cy+1) <> Blocked then (* East *) Queue.add (cx, cy+1, dir) q ;
end
done;
(* no crates ? Go for kills *)
if debug then Printf.printf "[explore] Attempt F...\n";
4
with
| ReturnInt k -> k ;;
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
let game_d = parse_input "input_test.txt" ;;
let dangers = evaluate_dangers game_d ;;
print_game_data game_d ;;