added 1st movement algorithm
This commit is contained in:
parent
f5e5113e72
commit
1ed4d9b75b
|
@ -1,19 +1,19 @@
|
|||
3.7
|
||||
3
|
||||
0
|
||||
7 11
|
||||
0 0 0 0 0 0 0 0 0 0 0
|
||||
0 1 0 1 2 1 2 1 2 1 0
|
||||
0 0 0 0 2 0 2 0 2 0 0
|
||||
0 0 0 2 2 2 2 2 0 0 0
|
||||
0 1 2 1 2 1 2 1 2 1 2
|
||||
0 0 2 0 2 0 2 0 2 0 2
|
||||
3 3 3 0 0 0 2 2 4 4 0
|
||||
0 1 0 1 0 1 0 1 0 1 0
|
||||
0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 2 2 2 2 3 3 2 0
|
||||
3
|
||||
3 2 4 4.1
|
||||
4 4 2 4.3
|
||||
0 0 3 5.5
|
||||
5
|
||||
0 0 0 3 2 4 5 3
|
||||
2 2 0 3 2 4 5 3
|
||||
2 0 1 4 3 2 2 2
|
||||
10 5 2 0 2 3 2 3
|
||||
5 5 3 5 1 10 2 3
|
||||
|
|
235
main.ml
235
main.ml
|
@ -1,16 +1,26 @@
|
|||
let debug = false ;;
|
||||
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
||||
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
||||
|
||||
type bomb = {
|
||||
let debug = false ;;
|
||||
let fatal_time = 1.0 ;;
|
||||
|
||||
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
||||
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
||||
|
||||
type pt = {
|
||||
x : int ;
|
||||
y : int ;
|
||||
}
|
||||
|
||||
type bomb = {
|
||||
xy : pt ;
|
||||
size : int ;
|
||||
det_time : float ;
|
||||
}
|
||||
|
||||
type player = {
|
||||
id : int ;
|
||||
x : int ;
|
||||
y : int ;
|
||||
xy : pt ;
|
||||
nspeed : int ;
|
||||
nbomb_atonce : int ;
|
||||
bomb_radius : int ;
|
||||
|
@ -19,22 +29,24 @@ type player = {
|
|||
}
|
||||
|
||||
type boost = {
|
||||
x : int ;
|
||||
y : int ;
|
||||
xy : pt ;
|
||||
spec : int ;
|
||||
}
|
||||
|
||||
let default_bomb = {
|
||||
let default_point = {
|
||||
x = 0 ;
|
||||
y = 0 ;
|
||||
}
|
||||
|
||||
let default_bomb = {
|
||||
xy = default_point ;
|
||||
size = 0 ;
|
||||
det_time = 0. ;
|
||||
}
|
||||
|
||||
and default_player = {
|
||||
id = 0 ;
|
||||
x = 0 ;
|
||||
y = 0 ;
|
||||
xy = default_point ;
|
||||
nspeed = 0 ;
|
||||
nbomb_atonce = 0 ;
|
||||
bomb_radius = 0 ;
|
||||
|
@ -43,8 +55,7 @@ and default_player = {
|
|||
}
|
||||
|
||||
and default_boost = {
|
||||
x = 0 ;
|
||||
y = 0 ;
|
||||
xy = default_point ;
|
||||
spec = 0 ;
|
||||
}
|
||||
|
||||
|
@ -62,22 +73,46 @@ type game_data = {
|
|||
mutable boosts : boost array ;
|
||||
}
|
||||
|
||||
type danger = Powerup | Safe | Danger | Fatal | Blocked ;;
|
||||
type danger = Safe | Danger | Fatal | Blocked ;;
|
||||
|
||||
let int_of_danger = function
|
||||
| Safe -> 0
|
||||
| Danger -> 1
|
||||
| Powerup -> 2
|
||||
| Fatal -> 3
|
||||
| Blocked -> 4 ;;
|
||||
| Fatal -> 2
|
||||
| Blocked -> 3 ;;
|
||||
|
||||
let danger_of_int = function
|
||||
| 0 -> Safe
|
||||
| 1 -> Danger
|
||||
| 2 -> Powerup
|
||||
| 3 -> Fatal
|
||||
| 2 -> Fatal
|
||||
| _ -> Blocked ;;
|
||||
|
||||
type moveType = EscapeDeath | BlowUpCrates | KillPlayers | ClaimLand ;;
|
||||
|
||||
exception ReturnInt of int ;;
|
||||
|
||||
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
||||
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
||||
|
||||
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.printf "NORTH "
|
||||
| 1 -> Printf.printf "EAST "
|
||||
| 2 -> Printf.printf "SOUTH "
|
||||
| 3 -> Printf.printf "WEST "
|
||||
| 4 -> Printf.printf "STILL "
|
||||
| _-> failwith "ERROR : invalid direction" ;;
|
||||
|
||||
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
||||
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
||||
|
||||
|
@ -95,15 +130,15 @@ let print_game_data (gd : game_data) =
|
|||
done ;
|
||||
Printf.printf "Bombs (%d) : \n" gd.nbombs ;
|
||||
for b = 0 to gd.nbombs -1 do
|
||||
Printf.printf " [Bomb] (at %d %d) (of size %d) (blowing up at %f)\n" gd.bombs.(b).x gd.bombs.(b).y gd.bombs.(b).size gd.bombs.(b).det_time ;
|
||||
Printf.printf " [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.printf "Players (%d) : \n" gd.nplayers ;
|
||||
for b = 0 to gd.nplayers -1 do
|
||||
Printf.printf " [Player %d] (at %d %d) (holding %d %d %d %d %d)\n" gd.players.(b).id gd.players.(b).x gd.players.(b).y gd.players.(b).nspeed gd.players.(b).nbomb_atonce gd.players.(b).bomb_radius gd.players.(b).ndash gd.players.(b).ntraps ;
|
||||
Printf.printf " [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).nbomb_atonce gd.players.(b).bomb_radius gd.players.(b).ndash gd.players.(b).ntraps ;
|
||||
done;
|
||||
Printf.printf "Boosts (%d) : \n" gd.nboosts ;
|
||||
for b = 0 to gd.nboosts -1 do
|
||||
Printf.printf " [Boost] (at %d %d) (of type %d)\n" gd.boosts.(b).x gd.boosts.(b).y gd.boosts.(b).spec ;
|
||||
Printf.printf " [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_danger_levels (map : danger array array) =
|
||||
|
@ -115,7 +150,6 @@ let print_danger_levels (map : danger array array) =
|
|||
| Safe -> Printf.printf ". "
|
||||
| Danger -> Printf.printf "! "
|
||||
| Fatal -> Printf.printf "X "
|
||||
| Powerup -> Printf.printf "P "
|
||||
done;
|
||||
Printf.printf "\n"
|
||||
done ;;
|
||||
|
@ -179,7 +213,7 @@ let parse_input (str : string) =
|
|||
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) <- {x = dat.(0) ; y = dat.(1) ; size = dat.(2) ; det_time = dtime ;
|
||||
res.bombs.(b) <- {xy = {x = dat.(0) ; y = dat.(1) ;} ; size = dat.(2) ; det_time = dtime ;
|
||||
}
|
||||
done;
|
||||
|
||||
|
@ -190,7 +224,7 @@ let parse_input (str : string) =
|
|||
res.players <- Array.make res.nplayers default_player ;
|
||||
for p = 0 to res.nplayers -1 do
|
||||
let dat = int_n_of_string (input_line ptr) 8 useless in
|
||||
res.players.(p) <- {id = dat.(2) ; x = dat.(0) ; y = dat.(1) ; nspeed = dat.(3) ; nbomb_atonce = dat.(4) ; bomb_radius = dat.(5) ; ndash = dat.(6) ; ntraps = dat.(7) ;}
|
||||
res.players.(p) <- {id = dat.(2) ; xy = {x = dat.(0) ; y = dat.(1) ;} ; nspeed = dat.(3) ; nbomb_atonce = dat.(4) ; bomb_radius = dat.(5) ; ndash = dat.(6) ; ntraps = dat.(7) ;}
|
||||
done;
|
||||
|
||||
(* boosts *)
|
||||
|
@ -200,7 +234,7 @@ let parse_input (str : string) =
|
|||
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) <- {x = dat.(0) ; y = dat.(1) ; spec = dat.(2)}
|
||||
res.boosts.(p) <- {xy = {x = dat.(0) ; y = dat.(1) ;} ; spec = dat.(2)}
|
||||
done;
|
||||
|
||||
if debug then Printf.printf "Done!\n" ;
|
||||
|
@ -211,13 +245,17 @@ let parse_input (str : string) =
|
|||
close_in ptr ;
|
||||
failwith "cannot happen unless something is wrong" ;;
|
||||
|
||||
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
||||
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
||||
|
||||
let warn_level (b : bomb) (ct : float) = match (b.det_time -. ct) with
|
||||
| k when k < 1.0 -> Fatal ;
|
||||
| k when k < fatal_time -> Fatal ;
|
||||
| _ -> Danger ;;
|
||||
|
||||
let danger_priority (p1 : danger) (p2 : danger) =
|
||||
danger_of_int (max (int_of_danger p1) (int_of_danger p2)) ;;
|
||||
|
||||
let order = [|(1, 0); (-1, 0); (0, 1); (0, -1)|] ;;
|
||||
let evaluate_dangers (gd : game_data) =
|
||||
let lines = Array.length gd.laby
|
||||
and cols = Array.length gd.laby.(0) in
|
||||
|
@ -226,31 +264,150 @@ let evaluate_dangers (gd : game_data) =
|
|||
(* add solid blocks *)
|
||||
for l = 0 to lines -1 do
|
||||
for c = 0 to cols -1 do
|
||||
if gd.laby.(l).(c) = 1 || gd.laby.(l).(c) = 1 then
|
||||
if gd.laby.(l).(c) = 1 || gd.laby.(l).(c) = 2 then
|
||||
res.(l).(c) <- Blocked ;
|
||||
done
|
||||
done ;
|
||||
|
||||
(* add bomb tiles *)
|
||||
(* sort bombs based on detonation time *)
|
||||
for b = 0 to gd.nbombs -1 do
|
||||
let dgr = warn_level gd.bombs.(b) gd.dt in
|
||||
for off = -gd.bombs.(b).size to gd.bombs.(b).size do
|
||||
let ln = min (lines -1) (max 0 (gd.bombs.(b).x + off))
|
||||
and cl = min (cols -1) (max 0 (gd.bombs.(b).y + off)) in
|
||||
if res.(ln).(gd.bombs.(b).y) = Safe then
|
||||
res.(ln).(gd.bombs.(b).y) <- danger_priority (res.(ln).(gd.bombs.(b).y)) dgr ;
|
||||
if res.(gd.bombs.(b).x).(cl) = Safe then
|
||||
res.(gd.bombs.(b).x).(cl) <- danger_priority (res.(gd.bombs.(b).x).(cl)) dgr ;
|
||||
let m = ref gd.bombs.(b).det_time
|
||||
and im = ref b in
|
||||
for j = b+1 to gd.nbombs -1 do
|
||||
if gd.bombs.(j).det_time < !m then begin
|
||||
m := gd.bombs.(j).det_time ;
|
||||
im := j ;
|
||||
end
|
||||
done;
|
||||
swap gd.bombs b (!im) ;
|
||||
done;
|
||||
|
||||
(* add powerups *)
|
||||
for p = 0 to gd.nboosts -1 do
|
||||
res.(gd.boosts.(p).x).(gd.boosts.(p).y) <- Powerup ;
|
||||
(* add bomb tiles *)
|
||||
let exploded = Hashtbl.create 12 in
|
||||
for b = 0 to gd.nbombs -1 do
|
||||
let dgr = warn_level gd.bombs.(b) gd.dt in
|
||||
let halt = ref false in
|
||||
|
||||
let bx = gd.bombs.(b).xy.x
|
||||
and by = gd.bombs.(b).xy.y in
|
||||
|
||||
for dir = 0 to 3 do
|
||||
for w = 0 to gd.bombs.(b).size 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 && Hashtbl.find_opt exploded (cx, cy) = None then begin (* unexploded crate *)
|
||||
halt := true ;
|
||||
res.(cx).(cy) <- danger_priority res.(cx).(cy) dgr ;
|
||||
Hashtbl.add exploded (cx, cy) 1
|
||||
end
|
||||
else begin
|
||||
res.(cx).(cy) <- danger_priority res.(cx).(cy) dgr ;
|
||||
end
|
||||
end
|
||||
done;
|
||||
halt := false ;
|
||||
done
|
||||
done;
|
||||
|
||||
res ;;
|
||||
|
||||
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
||||
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
|
||||
|
||||
let is_safe = function
|
||||
| Safe | Danger -> true
|
||||
| Fatal | Blocked -> false ;;
|
||||
|
||||
let move_safe (gd : game_data) (dgs : danger array array) =
|
||||
(* use this whenever you are standing on a non-safe tile *)
|
||||
let pid = gd.player_id in
|
||||
|
||||
let lines = Array.length gd.laby
|
||||
and cols = Array.length gd.laby.(0) in
|
||||
|
||||
(* BFS to find the nearest safe spot (if it exists) *)
|
||||
try
|
||||
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 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 dgs.(cx).(cy) = Safe 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. find the path that get you off fatal tiles ASAP *)
|
||||
if debug then Printf.printf "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 ;
|
||||
if cy <> cols -1 && dgs.(cx).(cy+1) <> Blocked 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 dgs.(cx).(cy) = Safe 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-1).(cy) <> 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;
|
||||
|
||||
(* 3. no safe tile within reach (very rare), look out for warning *)
|
||||
if debug then Printf.printf "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 ;
|
||||
if cy <> cols -1 && dgs.(cx).(cy+1) <> Blocked 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, 3) 1 ;
|
||||
if dgs.(cx).(cy) = Danger then
|
||||
raise (ReturnInt dir)
|
||||
else begin
|
||||
(* add neighbors *)
|
||||
if cx <> 0 && Hashtbl.find_opt visited (cx-1, cy, 3) = 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, 3) = 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, 3) = None && dgs.(cx-1).(cy) <> Blocked then (* West *) Queue.add (cx, cy-1, dir) q ;
|
||||
if cy <> cols -1 && Hashtbl.find_opt visited (cx, cy+1, 3) = None && dgs.(cx).(cy+1) <> Blocked then (* East *) Queue.add (cx, cy+1, dir) q ;
|
||||
end
|
||||
done;
|
||||
|
||||
(* you're probably dead if the code reaches here *)
|
||||
if debug then Printf.printf "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 ;;
|
||||
print_danger_levels (evaluate_dangers game_d)
|
||||
print_danger_levels dangers ;;
|
||||
|
||||
Printf.printf "move at ";;
|
||||
print_direction (move_safe game_d dangers) ;;
|
||||
Printf.printf "\n" ;;
|
|
@ -0,0 +1,15 @@
|
|||
0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0
|
||||
3 3 3 0 0 0 0 0 4 4 0
|
||||
0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 3 3 0 0
|
||||
|
||||
0 0 0 0 0 0 0 0 0 0 0
|
||||
0 1 0 1 2 1 2 1 2 1 0
|
||||
0 0 0 2 2 2 2 2 0 0 0
|
||||
0 1 2 1 2 1 2 1 2 1 2
|
||||
3 3 3 0 0 0 2 2 4 4 0
|
||||
0 1 0 1 0 1 0 1 0 1 0
|
||||
0 0 0 2 2 2 2 3 3 2 0
|
Loading…
Reference in New Issue