BomberMan/main.ml

256 lines
7.8 KiB
OCaml

let debug = false ;;
type bomb = {
x : int ;
y : int ;
size : int ;
det_time : float ;
}
type player = {
id : int ;
x : int ;
y : int ;
nspeed : int ;
nbomb_atonce : int ;
bomb_radius : int ;
ndash : int ;
ntraps : int ;
}
type boost = {
x : int ;
y : int ;
spec : int ;
}
let default_bomb = {
x = 0 ;
y = 0 ;
size = 0 ;
det_time = 0. ;
}
and default_player = {
id = 0 ;
x = 0 ;
y = 0 ;
nspeed = 0 ;
nbomb_atonce = 0 ;
bomb_radius = 0 ;
ndash = 0 ;
ntraps = 0 ;
}
and default_boost = {
x = 0 ;
y = 0 ;
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 = Powerup | Safe | Danger | Fatal | Blocked ;;
let int_of_danger = function
| Safe -> 0
| Danger -> 1
| Powerup -> 2
| Fatal -> 3
| Blocked -> 4 ;;
let danger_of_int = function
| 0 -> Safe
| 1 -> Danger
| 2 -> Powerup
| 3 -> Fatal
| _ -> Blocked ;;
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
let print_game_data (gd : game_data) =
Printf.printf "--------------------------------| Board data |--------------------------------\n" ;
Printf.printf "Time : %f\n" gd.dt ;
Printf.printf "ID : %d\n" gd.player_id ;
Printf.printf "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.printf " " ;
for c = 0 to Array.length gd.laby.(l) -1 do
Printf.printf "%d " gd.laby.(l).(c) ;
done;
Printf.printf "\n"
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 ;
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 ;
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 ;
done;;
let print_danger_levels (map : danger array array) =
Printf.printf "--------------------------------| Danger levels |--------------------------------\n" ;
for l = 0 to (Array.length map -1) do
for c = 0 to (Array.length map.(l) -1) do
match map.(l).(c) with
| Blocked -> Printf.printf "@ "
| Safe -> Printf.printf ". "
| Danger -> Printf.printf "! "
| Fatal -> Printf.printf "X "
| Powerup -> Printf.printf "P "
done;
Printf.printf "\n"
done ;;
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
(* ---------------------------------------------------------------------------------------------------------------------------------------------------- *)
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 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 then Printf.printf "Time\n" ;
res.dt <- Float.of_string (input_line ptr) ;
(* player_id *)
if debug then Printf.printf "PID\n" ;
res.player_id <- int_of_string (input_line ptr) ;
(* maze *)
if debug then Printf.printf "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 then Printf.printf "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) <- {x = dat.(0) ; y = dat.(1) ; size = dat.(2) ; det_time = dtime ;
}
done;
(* players *)
if debug then Printf.printf "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) ; 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 then Printf.printf "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) <- {x = dat.(0) ; y = dat.(1) ; spec = dat.(2)}
done;
if debug then Printf.printf "Done!\n" ;
close_in ptr ;
res
with
| End_of_file ->
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 ;
| _ -> Danger ;;
let danger_priority (p1 : danger) (p2 : danger) =
danger_of_int (max (int_of_danger p1) (int_of_danger p2)) ;;
let evaluate_dangers (gd : game_data) =
let lines = Array.length gd.laby
and cols = Array.length gd.laby.(0) in
let res = Array.make_matrix lines cols Safe in
(* 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
res.(l).(c) <- Blocked ;
done
done ;
(* add bomb tiles *)
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 ;
done;
done;
(* add powerups *)
for p = 0 to gd.nboosts -1 do
res.(gd.boosts.(p).x).(gd.boosts.(p).y) <- Powerup ;
done;
res ;;
let game_d = parse_input "input_test.txt" ;;
print_game_data game_d ;;
print_danger_levels (evaluate_dangers game_d)