diff --git a/again b/again new file mode 100755 index 0000000..4aedcf8 Binary files /dev/null and b/again differ diff --git a/again.cmi b/again.cmi new file mode 100644 index 0000000..5855c1d Binary files /dev/null and b/again.cmi differ diff --git a/again.cmo b/again.cmo new file mode 100644 index 0000000..e9551c0 Binary files /dev/null and b/again.cmo differ diff --git a/again.ml b/again.ml new file mode 100644 index 0000000..7a17582 --- /dev/null +++ b/again.ml @@ -0,0 +1,670 @@ +(* +TODO : +- deal with double bombing (DONE) +- well shit ==> dash (DONE (needs dash to be fixed tho)) +- deeper analysis on pathfinfing +*) +(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) +(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) + +let debug_all = false ;; + +(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) +(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) + +type pt = { + x : int ; + y : int ; +} + +type bomb = { + xy : pt ; + size : int ; + det_time : float ; +} + +type player = { + id : int ; + xy : pt ; + nspeed : int ; + nbomb_atonce : int ; + bomb_radius : int ; + ndash : int ; + ntraps : int ; +} + +type boost = { + xy : pt ; + spec : int ; +} + +let default_point = { + x = 0 ; + y = 0 ; +} + +let default_bomb = { + xy = default_point ; + size = 0 ; + det_time = 0. ; +} + +and default_player = { + id = 0 ; + xy = default_point ; + nspeed = 0 ; + nbomb_atonce = 0 ; + bomb_radius = 0 ; + ndash = 0 ; + ntraps = 0 ; +} + +and default_boost = { + xy = default_point ; + spec = 0 ; +} + +and useless = ref 0 ;; + +type game_data = { + mutable dt : float ; + mutable player_id : int ; + mutable laby : int array array ; + mutable nbombs : int ; + mutable bombs : bomb array ; + mutable nplayers : int ; + mutable players : player array ; + mutable nboosts : int ; + mutable boosts : boost array ; +} + +type danger_map = { + explosionTimes : (float list) array array ; + bonusMap : bool array array ; + playersMap : (int * int * int) array ; + explodedCrates : bool array array ; +} + +type moveType = EscapeDeath | BlowUpCrates | KillPlayers | ClaimLand ;; + +exception ReturnInt of int ;; +exception ReturnBool of bool ;; + +(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) +(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) +let order = [|(1, 0); (-1, 0); (0, 1); (0, -1)|] ;; + +let current_status = ref BlowUpCrates ;; +let action = ref 0 ;; + +let dash_left = ref 0 ;; + +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.fprintf stderr "NORTH " + | 1 -> Printf.fprintf stderr "EAST " + | 2 -> Printf.fprintf stderr "SOUTH " + | 3 -> Printf.fprintf stderr "WEST " + | 4 -> Printf.fprintf stderr "STILL " + | _-> failwith "ERROR : invalid direction" ;; + +let delta i j = + if i = j then 1 else 0 ;; + +let overwrite_file (filename : string) = + let ptr = open_out filename in + close_out ptr ;; + +let rec pop_list elt = function + | [] -> [] + | h::t when h = elt -> t + | h::t -> h::(pop_list elt t) ;; + +let is_empty_lst = function + | [] -> true + | _ -> false ;; + +(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) +(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) + +let print_game_data (gd : game_data) = + Printf.fprintf stderr "--------------------------------| Board data |--------------------------------\n" ; + Printf.fprintf stderr "Time : %f\n" gd.dt ; + Printf.fprintf stderr "ID : %d\n" gd.player_id ; + Printf.fprintf stderr "Laby [of size %d %d]:\n" (Array.length gd.laby) (Array.length gd.laby.(0)); + for l = 0 to Array.length gd.laby -1 do + Printf.fprintf stderr " " ; + for c = 0 to Array.length gd.laby.(l) -1 do + Printf.fprintf stderr "%d " gd.laby.(l).(c) ; + done; + Printf.fprintf stderr "\n" + done ; + Printf.fprintf stderr "Bombs (%d) : \n" gd.nbombs ; + for b = 0 to gd.nbombs -1 do + Printf.fprintf stderr " [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.fprintf stderr "Players (%d) : \n" gd.nplayers ; + for b = 0 to gd.nplayers -1 do + Printf.fprintf stderr " [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.fprintf stderr "Boosts (%d) : \n" gd.nboosts ; + for b = 0 to gd.nboosts -1 do + Printf.fprintf stderr " [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_dangers (dgs : danger_map) = + for w = 0 to Array.length dgs.explosionTimes -1 do + for h = 0 to Array.length dgs.explosionTimes.(0) -1 do + Printf.fprintf stderr "%d " (List.length dgs.explosionTimes.(w).(h)) ; + done ; + Printf.fprintf stderr "\n" ; + done ;; + +let print_gain_map (map : int array array) = + Printf.fprintf stderr "--------------------------------| Gain levels |--------------------------------\n" ; + for l = 0 to (Array.length map -1) do + for c = 0 to (Array.length map.(l) -1) do + Printf.fprintf stderr "%d " map.(l).(c) ; + done; + Printf.fprintf stderr "\n" + done ;; + +(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) +(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) + +let rec ln_b b = function + | k when k < 0 -> failwith "are you sure about that ?" + | k when k < b -> 0 + | k -> 1 + ln_b b (k/b) ;; + +let get_meta_info (pid : int) = + let ptr = open_in ("main_"^(string_of_int pid)^".sav") in + let fct0 () = match (int_of_string (input_line ptr)) with + | 0 -> current_status := EscapeDeath + | 1 -> current_status := BlowUpCrates + | 2 -> current_status := ClaimLand + | 3 -> current_status := KillPlayers + | _ -> current_status := EscapeDeath + in + fct0 () ; + try + let resu = int_of_string (input_line ptr) in + dash_left := resu -1; + close_in ptr + with + | End_of_file -> close_in ptr ;; + +let set_meta_info (pid : int) = + let ptr = open_out ("main_"^(string_of_int pid)^".sav") in + let fct0 () = match !current_status with + | EscapeDeath -> Printf.fprintf ptr "0" + | BlowUpCrates -> Printf.fprintf ptr "1" + | ClaimLand -> Printf.fprintf ptr "2" + | KillPlayers -> Printf.fprintf ptr "3" + in + fct0 () ; + if !dash_left > 0 then + Printf.fprintf ptr "\n%d" !dash_left ; + close_out ptr ;; + +(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) +(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) + +let int_of_string (str : string) = + String.fold_right (fun ch acc -> let cd = Char.code ch in if cd >= 48 || cd <= 57 then 10*acc + cd - 48 else failwith "not an integer\n") str 0 ;; + +let string_of_int (k0 : int) = + String.make (1) (Char.chr (k0 + 48)) ;; + +let int_n_of_string (str : string) (n : int) (nlast : int ref) = + let res = Array.make n 0 in + let rec aux idres idstr = match idstr with + | k when k = String.length str || idres >= n -> + nlast := k + | k -> + if str.[k] = ' ' then + aux (idres+1) (k+1) + else begin + let cd = Char.code str.[k] in + if cd >= 48 && cd <= 57 then begin + res.(idres) <- 10 * res.(idres) + cd - 48 ; + aux (idres) (k+1) + end + else + failwith "not an integer (n/n)\n" + end + in + aux 0 0 ; + res ;; + +let parse_input (str : string) = + let ptr = open_in str in + let (res : game_data) = {dt = 0. ; player_id = 0 ; laby = [||] ; nbombs = 0 ; bombs = [||] ; nplayers = 0 ; players = [||] ; nboosts = 0 ; boosts = [||] ;} in + try + (* time *) + if debug_all then Printf.fprintf stderr "Time\n" ; + res.dt <- Float.of_string (input_line ptr) ; + + (* player_id *) + if debug_all then Printf.fprintf stderr "PID\n" ; + res.player_id <- int_of_string (input_line ptr) ; + + (* maze *) + if debug_all then Printf.fprintf stderr "Maze\n" ; + let msize = int_n_of_string (input_line ptr) 2 useless in + + res.laby <- Array.make msize.(0) [||] ; + for lane = 0 to msize.(0) -1 do + let psd = input_line ptr in + res.laby.(lane) <- int_n_of_string psd msize.(1) useless ; + done; + + (* bombs *) + if debug_all then Printf.fprintf stderr "Boom\n" ; + res.nbombs <- int_of_string (input_line ptr) ; + + res.bombs <- Array.make res.nbombs default_bomb ; + for b = 0 to res.nbombs -1 do + let psd = input_line ptr + 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) <- {xy = {x = dat.(0) ; y = dat.(1) ;} ; size = dat.(2) ; det_time = dtime ; + } + done; + + (* players *) + if debug_all then Printf.fprintf stderr "Players\n" ; + res.nplayers <- int_of_string (input_line ptr) ; + + 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) ; 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 *) + if debug_all then Printf.fprintf stderr "Boosts\n" ; + res.nboosts <- int_of_string (input_line ptr) ; + + 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) <- {xy = {x = dat.(0) ; y = dat.(1) ;} ; spec = dat.(2)} + done; + + if debug_all then Printf.fprintf stderr "Done!\n" ; + close_in ptr ; + res + with + | End_of_file -> + close_in ptr ; + failwith "cannot happen unless something is wrong" ;; + +let build_danger_map (gd : game_data) = + let lines = Array.length gd.laby + and cols = Array.length gd.laby.(0) in + let (res : danger_map) = { + explosionTimes = Array.make lines [||] ; + bonusMap = Array.make lines [||] ; + playersMap = Array.make (gd.nplayers) (0, 0, 0) ; + explodedCrates = Array.make lines [||] ; + } in + for l = 0 to lines -1 do + res.explosionTimes.(l) <- Array.make cols [] ; + res.explodedCrates.(l) <- Array.make cols false ; + res.bonusMap.(l) <- Array.make cols false ; + done; + + Array.sort + ( + fun b1 b2 -> int_of_float (100. *. (b1.det_time -. b2.det_time)) + ) + gd.bombs ; + + (* add bombs *) + let halt = ref false in + for b = 0 to gd.nbombs -1 do + let bx = gd.bombs.(b).xy.x + and by = gd.bombs.(b).xy.y in + let bsize = gd.bombs.(b).size + and dtime = min (gd.bombs.(b).det_time) (List.fold_left min (gd.dt +. 1000.) res.explosionTimes.(bx).(by)) in + for dir = 0 to 3 do + for w = 0 to bsize do + if (not !halt) && (w > 0 || dir = 0) then begin + let nx = bx + w * (fst order.(dir)) + and ny = by + w * (snd order.(dir)) in + if is_valid nx ny lines cols then begin + if (gd.laby.(nx).(ny) = 0 || gd.laby.(nx).(ny) >= 3) || (gd.laby.(nx).(ny) = 2 && res.explodedCrates.(nx).(ny)) then + res.explosionTimes.(nx).(ny) <- (dtime)::(res.explosionTimes.(nx).(ny)) + else if gd.laby.(nx).(ny) = 1 then + halt := true + else if gd.laby.(nx).(ny) = 2 then begin + halt := true ; + res.explodedCrates.(nx).(ny) <- true ; + end + end + end + done; + halt := false ; + done + done; + + (* add players *) + for p = 0 to gd.nplayers -1 do + if p <> gd.player_id then begin + let bx = gd.players.(p).xy.x + and by = gd.players.(p).xy.y in + let bsize = gd.players.(p).bomb_radius + (*and dtime = min (gd.dt +. 5.5) (List.fold_left min (gd.dt +. 1000.) res.explosionTimes.(bx).(by)) in*) + and dtime = (gd.dt +. 5.5) in + for dir = 0 to 3 do + for w = 0 to bsize do + if (not !halt) && (w > 0 || dir = 0) then begin + let nx = bx + w * (fst order.(dir)) + and ny = by + w * (snd order.(dir)) in + if is_valid nx ny lines cols then begin + if (gd.laby.(nx).(ny) = 0 || gd.laby.(nx).(ny) >= 3) || (gd.laby.(nx).(ny) = 2 && res.explodedCrates.(nx).(ny)) then + res.explosionTimes.(nx).(ny) <- (dtime)::(res.explosionTimes.(nx).(ny)) + else if gd.laby.(nx).(ny) = 1 then + halt := true + else if gd.laby.(nx).(ny) = 2 then begin + halt := true ; + res.explodedCrates.(nx).(ny) <- true ; + end + end + end + done; + halt := false ; + done + (*res.playersMap.(p) <- (gd.players.(p).xy.x, gd.players.(p).xy.y, gd.players.(p).bomb_radius) ;*) + end + done; + + (* add bonuses *) + for b = 0 to gd.nboosts -1 do + res.bonusMap.(gd.boosts.(b).xy.x).(gd.boosts.(b).xy.y) <- true ; + done; + res ;; + +(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) +(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) + +let simulate_bomb (dgs : danger_map) (b : bomb) = + let saved_data = Hashtbl.create 30 in + let bx = b.xy.x + and by = b.xy.y in + let bsize = b.size + and dtime = min (b.det_time) (List.fold_left min (32760.) dgs.explosionTimes.(bx).(by)) in + let lines = Array.length dgs.explosionTimes + and cols = Array.length dgs.explosionTimes.(0) in + for dir = 0 to 3 do + for w = 0 to bsize do + if (w > 0 || dir = 0) then begin + let nx = bx + w * (fst order.(dir)) + and ny = by + w * (snd order.(dir)) in + if is_valid nx ny lines cols then begin + Hashtbl.add saved_data (nx, ny) dtime ; + dgs.explosionTimes.(nx).(ny) <- (dtime)::(dgs.explosionTimes.(nx).(ny)) + end + end + done; + done; + saved_data ;; + +let simulate_bomb_deconstruct (dgs : danger_map) (bx : int) (by : int) (bsize : int) (dtime0 : float) = + let saved_data = Hashtbl.create 30 in + let dtime = min dtime0 (List.fold_left min (32760.) dgs.explosionTimes.(bx).(by)) in + let lines = Array.length dgs.explosionTimes + and cols = Array.length dgs.explosionTimes.(0) in + for dir = 0 to 3 do + for w = 0 to bsize do + if (w > 0 || dir = 0) then begin + let nx = bx + w * (fst order.(dir)) + and ny = by + w * (snd order.(dir)) in + if is_valid nx ny lines cols then begin + Hashtbl.add saved_data (nx, ny) dtime ; + dgs.explosionTimes.(nx).(ny) <- (dtime)::(dgs.explosionTimes.(nx).(ny)) + end + end + done; + done; + saved_data ;; + +let reverse_simulate_bomb (dgs : danger_map) (save : (int * int, float) Hashtbl.t) = + Hashtbl.iter + (fun (x, y) dt -> + dgs.explosionTimes.(x).(y) <- pop_list dt (dgs.explosionTimes.(x).(y)) + ) + save ;; + +let is_dead (dgs : danger_map) (x : int) (y : int) (t : float) (dt : float) = + List.fold_left + (fun acc curtime -> + acc || (t > curtime && t < curtime +. dt) + ) + false + dgs.explosionTimes.(x).(y) ;; + +(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) +(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) + +let contains_crate (gd : game_data) = + Array.fold_left + (fun b1 lst -> b1 || (Array.fold_left (fun b2 tile -> b2 || (tile = 2)) false lst)) false gd.laby ;; + +let is_a_crate_nearby (gd : game_data) (dgs : danger_map) = + let pid = gd.player_id + and lines = Array.length gd.laby + and cols = Array.length gd.laby.(0) in + try + let halt = ref false in + let res = ref false in + for dir = 0 to 3 do + for o = 1 to gd.players.(pid).bomb_radius do + if not !halt then begin + let nx = gd.players.(pid).xy.x + o * (fst order.(dir)) + and ny = gd.players.(pid).xy.y + o * (snd order.(dir)) in + if is_valid nx ny lines cols then begin + if gd.laby.(nx).(ny) = 2 then + res := true + else if gd.laby.(nx).(ny) = 1 then + halt := true + else if dgs.bonusMap.(nx).(ny) then + raise (ReturnBool false) + end + end + done; + halt := false ; + done; + !res + with + | ReturnBool b -> b ;; + +let sees_a_crate (gd : game_data) (dgs : danger_map) (x : int) (y : int) = + let pid = gd.player_id + and lines = Array.length gd.laby + and cols = Array.length gd.laby.(0) in + try + let halt = ref false in + let res = ref false in + for dir = 0 to 3 do + for o = 1 to gd.players.(pid).bomb_radius do + if not !halt then begin + let nx = x + o * (fst order.(dir)) + and ny = y + o * (snd order.(dir)) in + if is_valid nx ny lines cols then begin + if gd.laby.(nx).(ny) = 2 then + res := true + else if gd.laby.(nx).(ny) = 1 then + halt := true + else if dgs.bonusMap.(nx).(ny) then + raise (ReturnBool false) + end + end + done; + halt := false ; + done; + !res + with + | ReturnBool b -> b ;; + +let bfs_for_crate (gd : game_data) (dgs : danger_map) (x0 : int) (y0 : int) (stime : float) = + let lines = Array.length gd.laby + and cols = Array.length gd.laby.(0) in + + let visited = Hashtbl.create 100 in + let q = Queue.create () in + let interval = Float.pow (0.9) (float_of_int gd.players.(gd.player_id).nspeed) in + + Hashtbl.add visited (x0, y0) 1 ; + + Queue.add (x0+1, y0, stime +. interval, 2) q ; + Queue.add (x0-1, y0, stime +. interval, 0) q ; + Queue.add (x0, y0+1, stime +. interval, 1) q ; + Queue.add (x0, y0-1, stime +. interval, 3) q ; + + try + while not (Queue.is_empty q) do + let (x, y, ct, direction) = Queue.pop q in + if is_valid x y lines cols && gd.laby.(x).(y) <> 1 && gd.laby.(x).(y) <> 2 then begin (* within the map *) + if Hashtbl.find_opt visited (x, y) = None then begin (* has not been visited yet *) + Hashtbl.add visited (x, y) 1 ; + if not (is_dead dgs x y ct interval) then begin (* is not lethal *) + if (is_empty_lst dgs.explosionTimes.(x).(y)) && (sees_a_crate gd dgs x y && not dgs.explodedCrates.(x).(y)) then begin (* is a safe and valid tile *) + raise (ReturnInt direction) + end; + (*Printf.fprintf stderr "+4 (%b %b)\n" (is_empty_lst dgs.explosionTimes.(x).(y)) (sees_a_crate gd dgs x y) ;*) + for dir = 0 to 3 do + Queue.add (x + (fst order.(dir)), y + (snd order.(dir)), ct +. interval, direction) q ; + done + end + end + end + done; + 4 ; + with + | ReturnInt k -> k ;; + +let bfs_gtfo (gd : game_data) (dgs : danger_map) (x0 : int) (y0 : int) (stime : float) = + let lines = Array.length gd.laby + and cols = Array.length gd.laby.(0) in + + let visited = Hashtbl.create 100 in + let q = Queue.create () in + let interval = Float.pow (0.9) (float_of_int gd.players.(gd.player_id).nspeed) in + + Hashtbl.add visited (x0, y0) 1 ; + + Queue.add (x0+1, y0, stime +. interval, 2) q ; + Queue.add (x0-1, y0, stime +. interval, 0) q ; + Queue.add (x0, y0+1, stime +. interval, 1) q ; + Queue.add (x0, y0-1, stime +. interval, 3) q ; + + try + while not (Queue.is_empty q) do + let (x, y, ct, direction) = Queue.pop q in + if is_valid x y lines cols && gd.laby.(x).(y) <> 1 && gd.laby.(x).(y) <> 2 then begin (* within the map *) + if Hashtbl.find_opt visited (x, y) = None then begin (* has not been visited yet *) + Hashtbl.add visited (x, y) 1 ; + if not (is_dead dgs x y ct interval) then begin (* is not lethal *) + if (is_empty_lst dgs.explosionTimes.(x).(y)) then begin (* is a safe and valid tile *) + raise (ReturnInt direction) + end; + for dir = 0 to 3 do + Queue.add (x + (fst order.(dir)), y + (snd order.(dir)), ct +. interval, direction) q ; + done + end + end + end + done; + 4 ; + with + | ReturnInt k -> k ;; + +let bfs_bonus (gd : game_data) (dgs : danger_map) (x0 : int) (y0 : int) (stime : float) = + let lines = Array.length gd.laby + and cols = Array.length gd.laby.(0) in + + let visited = Hashtbl.create 100 in + let q = Queue.create () in + let interval = Float.pow (0.9) (float_of_int gd.players.(gd.player_id).nspeed) in + + Hashtbl.add visited (x0, y0) 1 ; + + Queue.add (x0+1, y0, stime +. interval, 2) q ; + Queue.add (x0-1, y0, stime +. interval, 0) q ; + Queue.add (x0, y0+1, stime +. interval, 1) q ; + Queue.add (x0, y0-1, stime +. interval, 3) q ; + + try + while not (Queue.is_empty q) do + let (x, y, ct, direction) = Queue.pop q in + if is_valid x y lines cols && gd.laby.(x).(y) <> 1 && gd.laby.(x).(y) <> 2 then begin (* within the map *) + if Hashtbl.find_opt visited (x, y) = None then begin (* has not been visited yet *) + Hashtbl.add visited (x, y) 1 ; + if not (is_dead dgs x y ct interval) && ct < stime +. 7. *. interval then begin (* is not lethal *) + if dgs.bonusMap.(x).(y) then begin (* is a safe and valid tile *) + raise (ReturnInt direction) + end; + for dir = 0 to 3 do + Queue.add (x + (fst order.(dir)), y + (snd order.(dir)), ct +. interval, direction) q ; + done + end + end + end + done; + 4 ; + with + | ReturnInt k -> k ;; + +let move_crate (gd : game_data) (dgs : danger_map) = + let pid = gd.player_id in + let cxi = gd.players.(pid).xy.x + and cyi = gd.players.(pid).xy.y in + try + let bonusres = bfs_bonus gd dgs cxi cyi gd.dt in + if bonusres <> 4 then raise (ReturnInt bonusres) ; + if (is_a_crate_nearby gd dgs) && (is_empty_lst dgs.explosionTimes.(cxi).(cyi)) then begin + Printf.fprintf stderr "trying...\n" ; + let saved = simulate_bomb_deconstruct dgs cxi cyi gd.players.(pid).bomb_radius (gd.dt +. 5.5) in + let result = bfs_gtfo gd dgs cxi cyi gd.dt in + if result <> 4 && gd.players.(pid).nbomb_atonce > 0 then begin + action := 1 ; + raise (ReturnInt result) ; + end + else + raise (ReturnInt 4) + end; + bfs_for_crate gd dgs cxi cyi gd.dt + with + | ReturnInt k -> k ;; + +(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) +(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) + +let game_map = parse_input "entrees.txt" ;; +if debug_all then print_game_data game_map ;; +let danger_data = build_danger_map game_map ;; + +get_meta_info game_map.player_id ;; +(*Printf.fprintf stderr "\n" ;; +print_dangers danger_data ;;*) + +let direction = move_crate game_map danger_data ;; + +Printf.printf "%d %d" direction !action ; +Printf.fprintf stderr "[player %d] %d %d (at time %f)\n" game_map.player_id direction !action game_map.dt; + +set_meta_info game_map.player_id ;; + diff --git a/compilZ.sh b/compilZ.sh new file mode 100644 index 0000000..1913351 --- /dev/null +++ b/compilZ.sh @@ -0,0 +1 @@ +ocamlc again.ml -o again \ No newline at end of file diff --git a/entrees.txt b/entrees.txt index 54a418b..65ba8d9 100644 --- a/entrees.txt +++ b/entrees.txt @@ -1,29 +1,27 @@ -107.60000000000014 +135.09900000000007 3 13 21 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 3 3 3 3 3 3 0 2 0 2 2 2 2 2 2 5 5 5 5 1 -1 3 1 3 1 3 1 2 1 2 1 0 1 2 1 2 1 5 1 5 1 -1 3 3 3 3 3 3 3 0 2 2 2 2 2 0 5 5 5 5 5 1 -1 3 1 3 1 3 1 2 1 2 1 2 1 0 1 5 1 5 1 5 1 -1 3 3 3 3 3 0 2 2 2 2 2 2 0 5 5 5 5 5 5 1 -1 0 1 3 1 3 1 2 1 2 1 0 1 2 1 5 1 4 1 5 1 -1 6 6 6 6 6 0 2 2 2 2 2 2 0 2 0 0 4 4 4 1 -1 6 1 3 1 6 1 0 1 2 1 2 1 2 1 0 1 4 1 5 1 -1 6 6 3 6 6 0 2 2 2 2 2 0 0 0 4 4 4 4 4 1 -1 6 1 6 1 6 1 0 1 2 1 2 1 2 1 4 1 4 1 4 1 -1 6 6 6 6 6 6 0 2 2 2 2 2 2 0 4 4 4 4 4 1 +1 3 3 3 3 0 2 2 2 2 2 2 2 0 5 5 5 5 5 5 1 +1 3 1 3 1 0 1 2 1 0 1 2 1 2 1 5 1 5 1 5 1 +1 3 3 3 3 3 3 0 2 0 2 2 0 0 5 5 5 5 5 5 1 +1 3 1 3 1 0 1 2 1 2 1 2 1 0 1 5 1 5 1 5 1 +1 0 0 3 0 0 2 2 2 2 2 2 0 4 4 5 5 5 5 5 1 +1 0 1 3 1 3 1 6 1 0 1 2 1 4 1 4 1 5 1 0 1 +1 3 6 3 3 3 3 6 2 6 2 0 0 4 4 4 4 5 4 4 1 +1 6 1 3 1 3 1 6 1 6 1 2 1 5 1 4 1 4 1 4 1 +1 6 6 6 6 6 3 6 3 3 0 2 0 5 5 5 4 4 4 4 1 +1 6 1 6 1 0 1 6 1 6 1 2 1 5 1 5 1 4 1 4 1 +1 6 6 6 6 6 6 6 6 6 6 0 2 5 5 5 5 5 4 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -5 -7 17 3 108.35799999999998 -11 15 2 109.5 -11 6 2 109.50000000000011 -3 6 3 109.64919999999982 -10 7 2 112.20000000000013 4 -1 7 0 4 3 3 0 0 -8 15 1 0 2 2 3 1 -9 17 2 3 3 3 0 2 -10 7 3 1 2 2 3 0 +9 5 5 137.68300000000002 +5 12 2 138.5 +3 12 1 139.70000000000022 +4 13 2 140.5 +3 +3 13 1 1 2 1 2 2 +3 13 2 0 4 2 0 2 +7 3 3 3 3 5 0 2 1 -5 13 1 +11 11 0 diff --git a/execZ.sh b/execZ.sh new file mode 100644 index 0000000..b663028 --- /dev/null +++ b/execZ.sh @@ -0,0 +1,2 @@ +ocamlc again.ml -o again +./again \ No newline at end of file diff --git a/iachallenge2024_bomberman_tkinter.py b/iachallenge2024_bomberman_tkinter.py index 155b976..851deb8 100644 --- a/iachallenge2024_bomberman_tkinter.py +++ b/iachallenge2024_bomberman_tkinter.py @@ -60,7 +60,7 @@ PU_NATURE = 2 from random import randrange from copy import deepcopy from tkinter import * -from os import system +import os def attente(vitesse): return TEMPS_BASE * 0.9**vitesse @@ -209,10 +209,10 @@ def execute_evenement(evenements, evenement, plateau, plateauCouleur, bombes, jo bombes.append([i,j,joueur[J_LONGUEURFLAMMES],indiceJoueur,evenement[0]+TEMPS_EXPLOSION]) ajoute_evenement(evenements, [evenement[0]+TEMPS_EXPLOSION, EVENEMENT_EXPLOSION_BOMBE, len(bombes)-1]) elif joueurs[indiceJoueur][J_DASHSRESTANTS]>0 and action == A_DASH: - joueurs[J_DASHSRESTANTS]-=1 - joueurs[J_TOURSDASH]+=3 + joueur[J_DASHSRESTANTS]-=1 + joueur[J_TOURSDASH]+=3 elif joueurs[indiceJoueur][J_PIEGESRESTANTS]>0 and action == A_PIEGE: - joueurs[J_PIEGESRESTANTS]-=1 + joueur[J_PIEGESRESTANTS]-=1 pieges.append([i,j,indiceJoueur]) ip,jp = prochain(i,j,direction) if plateau[ip][jp]==PLATEAU_VIDE and trouve_objet(ip, jp, bombes)==None: @@ -289,7 +289,7 @@ def execute_evenement(evenements, evenement, plateau, plateauCouleur, bombes, jo longueurFlammes = 0 # Si on est pas au bout de la flamme, on propage - if longueurFlammes>0: + elif longueurFlammes>0: ip, jp = prochain(i,j,direction) ajoute_evenement(evenements, [evenement[0]+TEMPS_PROPAGATION, EVENEMENT_PROPAGATION, ip, jp, direction, longueurFlammes-1, indJoueur]) @@ -322,9 +322,10 @@ def decision(programme, indiceJoueur, plateau, plateauCouleur, bombes, joueurs, print(len(powerups), file=entrees) for pu in powerups: print(pu[PU_LIGNE], pu[PU_COLONNE], pu[PU_NATURE], file=entrees) - - system("cat entrees.txt | "+programme+" > sortie.txt") - + if os.name == "posix": + os.system("cat entrees.txt | "+programme+" > sortie.txt") + elif os.name =="nt": + os.system('type entrees.txt | python '+programme[2:]+ ' >sortie.txt') with open("sortie.txt", "r") as sortie: direction, b = sortie.readline().split() action = int(b) @@ -332,7 +333,7 @@ def decision(programme, indiceJoueur, plateau, plateauCouleur, bombes, joueurs, def simulation(strategies): def pas_de_jeu(): - if len(joueurs) - joueurs.count(None) > 1: + if len(joueurs) - joueurs.count(None) > 0: evenement = evenements.pop(0) if evenement[0]>TEMPS_PARTIE: return @@ -366,7 +367,7 @@ def simulation(strategies): joueurs = [] for i in range(len(strategies)): - joueur = [positionsInitiales[i][0], positionsInitiales[i][1], strategies[i], 0, 1, 1, 1, 0, 0, 0] + joueur = [positionsInitiales[i][0], positionsInitiales[i][1], strategies[i], 0, 1, 1, 1, 0, 0, 0, 0] joueurs.append(joueur) ajoute_evenement(evenements, [0., EVENEMENT_TOUR_JOUEUR, i]) @@ -378,5 +379,4 @@ def simulation(strategies): fenetre.mainloop() return -from importlib import import_module -simulation(["./main", "./main", "./main", "./main"]) +simulation(["./again", "./again", "./again", "./again"]) diff --git a/main b/main index d1bb265..80304ee 100755 Binary files a/main and b/main differ diff --git a/main.cmi b/main.cmi index da3dca3..f288288 100644 Binary files a/main.cmi and b/main.cmi differ diff --git a/main.cmo b/main.cmo index d363de2..60247e7 100644 Binary files a/main.cmo and b/main.cmo differ diff --git a/main.ml b/main.ml index 8282a81..08d7eb4 100755 --- a/main.ml +++ b/main.ml @@ -12,6 +12,7 @@ let debug_all = false ;; let debug_data = false ;; let fatal_time = 1.0 ;; let explosion_time = 1.0 ;; +let logg = true ;; (* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) (* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) @@ -327,6 +328,8 @@ let parse_input (str : string) = (* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) (* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) +let exploded = Hashtbl.create 21 ;; + let warn_level (b : bomb) (ct : float) = match (b.det_time -. ct) with | k when k < fatal_time -> Fatal b.det_time ; | _ -> Danger b.det_time ;; @@ -367,7 +370,6 @@ let evaluate_dangers (gd : game_data) = done; (* add bomb tiles *) - let exploded = Hashtbl.create 12 in for b = 0 to gd.nbombs -1 do let bx = gd.bombs.(b).xy.x and by = gd.bombs.(b).xy.y in @@ -606,20 +608,33 @@ let move_explore (gd: game_data) (dgs : danger array array) = try let (cxi, cyi) = (gd.players.(pid).xy.x, gd.players.(pid).xy.y) in - let move_with_caution (exit : bool) = + let move_with_caution () = let res = has_a_safe_path_origin_2 cxi cyi lines cols gd.dt interval gd dgs [|Bonus|] [||] [|Blocked|] [||] 7 in if res <> 4 then begin if debug_all then Printf.fprintf stderr "[crates] success 1/2!\n" ; res end else begin - let res2 = has_a_safe_path_origin_2 cxi cyi lines cols gd.dt interval gd dgs [||] [|2|] [|Blocked|] [||] 80 in + for w = 0 to lines -1 do + for h = 0 to cols -1 do + if gd.laby.(w).(h) = 2 then begin + for dir = 0 to 3 do + let nx = w + fst order.(dir) + and ny = h + snd order.(dir) in + if is_valid nx ny lines cols && dgs.(nx).(ny) <> Blocked then + gd.laby.(nx).(ny) <- (-5) ; + done + end + done + done; + (* you dont want to stop INSIDE a crate, but rather right next to it *) + let res2 = has_a_safe_path_origin_2 cxi cyi lines cols gd.dt interval gd dgs [||] [|-5|] [|Blocked|] [||] 80 in if res2 <> 4 then begin if debug_all then Printf.fprintf stderr "[crates] success 2/2!\n" ; res2 end else begin - if exit then (* TODONE *) + if not (contains_crate gd) then (* TODONE *) current_status := ClaimLand ; Printf.fprintf stderr "Exited.\n" ; 4 @@ -645,25 +660,26 @@ let move_explore (gd: game_data) (dgs : danger array array) = end ) bomb_hash ; - let result = move_with_caution false in + let result = has_a_safe_path_origin_2 cxi cyi lines cols gd.dt interval gd dgs [|Bonus; Safe|] [||] [|Blocked|] [||] 10 in Hashtbl.iter (fun (k1, k2) v -> dgs.(k1).(k2) <- v) saved_dgs ; result in (* check if there's a crate next to the player, and if upon placing a bomb it won't softlock the player, and if you can place a bomb *) - if is_a_crate_nearby gd dgs && (safe_path_with_bomb cxi cyi gd.players.(pid).bomb_radius <> 4) then begin (* Crate at South *) + let spwb = safe_path_with_bomb cxi cyi gd.players.(pid).bomb_radius in + if is_a_crate_nearby gd dgs && (spwb <> 4) then begin (* Crate at South *) if dgs.(cxi).(cyi) = Safe && gd.players.(pid).nbomb_atonce > 0 then begin - current_status := EscapeDeath ; + (*current_status := EscapeDeath ;*) action := 1; if debug_all then Printf.fprintf stderr "Fire in the hole!\n" ; - raise (ReturnInt 4) ; + raise (ReturnInt spwb) ; end; end; if debug_all then Printf.fprintf stderr "[crates] Cannot bomb now, searching for a crate...\n"; (* go to one without stepping into a dangerous tile *) - raise (ReturnInt (move_with_caution true)) ; + raise (ReturnInt (move_with_caution ())) ; with | ReturnInt k -> k ;; @@ -671,7 +687,7 @@ let move_explore (gd: game_data) (dgs : danger array array) = (* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) let cell_profit (d_from_p : int) (gain : int) = - (100000 * gain * (1 + ln_b 7 gain)) / d_from_p ;; + (100 * gain * (1 + ln_b 7 gain)) (*/ d_from_p *);; let move_claim (gd : game_data) (dgs : danger array array) (gns : int array array) = let lines = Array.length gd.laby @@ -718,7 +734,14 @@ let move_claim (gd : game_data) (dgs : danger array array) (gns : int array arra (fun i lst -> Array.iteri ( fun j elt -> - if (distances.(i).(j) <> -1) then begin maxi_gain := max (!maxi_gain) (cell_profit distances.(i).(j) gns.(i).(j)); maxi_i := i ; maxi_j := j end + if (distances.(i).(j) <> -1) then begin + let cpft = cell_profit distances.(i).(j) gns.(i).(j) in + if !maxi_gain < cpft then begin + maxi_gain := cpft ; + maxi_i := i ; + maxi_j := j ; + end + end ) lst ) @@ -752,14 +775,14 @@ let move_claim (gd : game_data) (dgs : danger array array) (gns : int array arra if result0 <> 4 then begin action := 1 ; - current_status := EscapeDeath ; + (*current_status := EscapeDeath ;*) raise (ReturnInt result0) end end; raise (ReturnInt 4) end else if !maxi_i = (-1) then begin - current_status := EscapeDeath ; + (*current_status := EscapeDeath ;*) raise (ReturnInt (has_a_safe_path_origin_2 cxi cyi lines cols gd.dt interval gd dgs [|Bonus; Safe|] [||] [|Blocked|] [||] 80)) end else begin @@ -811,7 +834,7 @@ let move_safe (gd : game_data) (dgs : danger array array) (gns : int array array result2 else begin (* you're probably dead if the code reaches here, unless... *) - if (!dash_left > 0) || gd.players.(pid).ndash > 0 then begin + if false && ((!dash_left > 0) || gd.players.(pid).ndash > 0) then begin Printf.fprintf stderr "*teleports*\n" ; if (!dash_left = 0) then action := 2 ; @@ -831,6 +854,8 @@ let move_safe (gd : game_data) (dgs : danger array array) (gns : int array array (* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) let update_strat (gd : game_data) (dgs : danger array array) = match dgs.(gd.players.(gd.player_id).xy.x).(gd.players.(gd.player_id).xy.y) with + | _ when !current_status = BlowUpCrates -> () + | _ when !current_status = ClaimLand -> () | Safe -> () | Danger k when k < 3.0 -> current_status := EscapeDeath | Danger k -> () @@ -850,7 +875,7 @@ let debug_game_data (gd : game_data) = (* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) (* ---------------------------------------------------------------------------------------------------------------------------------------------------- *) -Printf.fprintf stderr "XXXXXXXX\n" ;; +if logg then Printf.fprintf stderr "XXXXXXXX\n" ;; let game_d = parse_input "entrees.txt" ;; let dangers = evaluate_dangers game_d ;; @@ -858,7 +883,7 @@ let gains = cell_values game_d ;; get_meta_info game_d.player_id ;; -Printf.fprintf stderr "[player %d started its turn]\n" game_d.player_id ;; +if logg then Printf.fprintf stderr "[player %d started its turn]\n" game_d.player_id ;; if debug_data then begin print_game_data game_d ; @@ -894,9 +919,10 @@ main_actions () ; Printf.printf "%d" !action ; (*debug_game_data game_d ;;*) - -Printf.fprintf stderr "[player %d went at direction " game_d.player_id ;; -print_direction !chosen ;; -Printf.fprintf stderr "with action %d] time at end : %f\n" !action game_d.dt ;; +if logg then begin + Printf.fprintf stderr "[player %d went at direction " game_d.player_id ; + print_direction !chosen ; + Printf.fprintf stderr "with action %d] time at end : %f\n" !action game_d.dt ; +end ;; set_meta_info game_d.player_id ;; \ No newline at end of file diff --git a/sortie.txt b/sortie.txt index 6ad1e30..e69de29 100644 --- a/sortie.txt +++ b/sortie.txt @@ -1 +0,0 @@ -2 2 \ No newline at end of file