diff --git a/bin/main b/bin/main index f5e98d6..39de58c 100755 Binary files a/bin/main and b/bin/main differ diff --git a/main.cmi b/main.cmi index dee3dc1..116a3ad 100644 Binary files a/main.cmi and b/main.cmi differ diff --git a/main.cmo b/main.cmo index 4db212b..fb2bd70 100644 Binary files a/main.cmo and b/main.cmo differ diff --git a/main.ml b/main.ml index 234bc4a..c446b9b 100644 --- a/main.ml +++ b/main.ml @@ -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 ;;