added exploration function
This commit is contained in:
parent
1ed4d9b75b
commit
a7da366a02
120
main.ml
120
main.ml
|
@ -94,6 +94,8 @@ exception ReturnInt of int ;;
|
||||||
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
||||||
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
||||||
|
|
||||||
|
let current_status = ref BlowUpCrates ;;
|
||||||
|
|
||||||
let equal_pt (p1 : pt) (p2 : pt) =
|
let equal_pt (p1 : pt) (p2 : pt) =
|
||||||
p1.x = p2.x && p1.y = p2.y ;;
|
p1.x = p2.x && p1.y = p2.y ;;
|
||||||
|
|
||||||
|
@ -269,6 +271,35 @@ let evaluate_dangers (gd : game_data) =
|
||||||
done
|
done
|
||||||
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 *)
|
(* sort bombs based on detonation time *)
|
||||||
for b = 0 to gd.nbombs -1 do
|
for b = 0 to gd.nbombs -1 do
|
||||||
let m = ref gd.bombs.(b).det_time
|
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) =
|
let move_safe (gd : game_data) (dgs : danger array array) =
|
||||||
(* use this whenever you are standing on a non-safe tile *)
|
(* 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 pid = gd.player_id in
|
||||||
|
|
||||||
let lines = Array.length gd.laby
|
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) *)
|
(* BFS to find the nearest safe spot (if it exists) *)
|
||||||
try
|
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 q = Queue.create () in
|
||||||
let visited = Hashtbl.create 100 in
|
let visited = Hashtbl.create 100 in
|
||||||
|
|
||||||
(* 1. try not to walk on fatal tiles *)
|
(* 1. try not to walk on fatal tiles *)
|
||||||
if debug then Printf.printf "Attempt 1/3...\n";
|
if debug then Printf.printf "[escape] Attempt 1/3...\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 <> 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 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 <> 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;
|
done;
|
||||||
|
|
||||||
(* 2. find the path that get you off fatal tiles ASAP *)
|
(* 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 <> 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 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 ;
|
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;
|
done;
|
||||||
|
|
||||||
(* 3. no safe tile within reach (very rare), look out for warning *)
|
(* 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 <> 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 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 ;
|
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;
|
done;
|
||||||
|
|
||||||
(* you're probably dead if the code reaches here *)
|
(* 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
|
4
|
||||||
with
|
with
|
||||||
| ReturnInt k -> k ;;
|
| 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 game_d = parse_input "input_test.txt" ;;
|
||||||
let dangers = evaluate_dangers game_d ;;
|
let dangers = evaluate_dangers game_d ;;
|
||||||
print_game_data game_d ;;
|
print_game_data game_d ;;
|
||||||
|
|
Loading…
Reference in New Issue