let open Printf in let debug = fprintf stderr in let checkpoint_ray = 600 in let module Vector = struct type t = { x : int; y : int } let to_string dst : string = (Printf.sprintf "{ x = %d ; y = %d }" dst.x dst.y) let create x y = { x ; y } let equal dst src = (dst.x = src.x) && (dst.y = src.y) let diff dst src = { x = (dst.x - src.x) ; y = (dst.y - src.y) } let mult src a = { x = src.x * a ; y = src.y * a } let add dst src = { x = (src.x + dst.x) ; y = (src.y + dst.y) } let distance (dst:t) (src:t) = (src.x - dst.x) * (src.x - dst.x) + (src.y - dst.y) * (src.y - dst.y) |> float_of_int |> sqrt |> int_of_float let is_touching dst src = (distance dst src) < (checkpoint_ray / 2) let is_near dst src = (distance dst src) < (checkpoint_ray * 2) let is_far dst src = ((distance dst src) >= checkpoint_ray * 6) end in let module Pod = struct type t = { pos : Vector.t ; dir : Vector.t ; } end in let module CheckpointList = struct type t = { mem: Vector.t list ; cur: Vector.t option } let add ck_li elem = match ck_li.cur with | None -> { mem = [] ; cur = Some elem } | Some cur_elem -> if (Vector.equal cur_elem elem) then ck_li else { mem = cur_elem :: ck_li.mem ; cur = Some elem } let create () = { mem = [] ; cur = None } let inc (ck_li:t) elem = (ck_li.mem) |> List.map (fun cur -> (Vector.equal elem cur)) |> List.fold_left (fun acc elem -> acc || elem) false end in let parse_line1 () = let line = input_line stdin in let build_results_fn = ( fun x y checkpointx checkpointy checkpointdist checkpointangle -> (Vector.create x y), (Vector.create checkpointx checkpointy), checkpointdist, checkpointangle ) in Scanf.sscanf line "%d %d %d %d %d %d" build_results_fn in let parse_line2 () = let line = input_line stdin in let build_results_fn = ( fun opponentx opponenty -> (Vector.create opponentx opponenty) ) in Scanf.sscanf line "%d %d" build_results_fn in let map_center = Vector.create (16000 / 2) (9000 / 2) in let first_turn = ref true in let old_pod = ref (Vector.create 0 0) in let tick = ref 0 in let checkpoint_list = ref (CheckpointList.create ()) in (* game loop *) while true do (* nextcheckpointdist: distance to the next checkpoint *) (* nextcheckpointangle: angle between your pod orientation and the direction of the next checkpoint *) let pod, checkpoint, checkpoint_dist, checkpoint_angle = parse_line1 () in let opponent = parse_line2 () in if !first_turn then begin old_pod := pod ; first_turn := false end ; if (CheckpointList.inc !checkpoint_list checkpoint) then begin prerr_endline "List already includes this checkpoint" ; end else begin checkpoint_list := (CheckpointList.add !checkpoint_list checkpoint) ; fprintf stderr "New checkpoint : %s\n%!" (Vector.to_string checkpoint); end ; (* output "x y thrust" : the target position + the power *) let is_aligned = checkpoint_angle > -2 && checkpoint_angle < 2 in let is_near_aligned = (checkpoint_angle > -15 && checkpoint_angle <= -2) || (checkpoint_angle >= 2 && checkpoint_angle < 15) in let is_wide_aligned = (checkpoint_angle > -45 && checkpoint_angle <= -15) || (checkpoint_angle >= 15 && checkpoint_angle < 45) in let is_aside = (checkpoint_angle > -85 && checkpoint_angle <= -45) || (checkpoint_angle >= 45 && checkpoint_angle < 85) in let is_behind = checkpoint_angle >= 85 || checkpoint_angle <= -85 in let use_boost = (!tick > 100) && is_aligned && (Vector.is_far pod checkpoint) in debug "angle = %d\n%!" checkpoint_angle ; let thrust = (* droit devant *) if is_behind && (Vector.is_touching pod opponent) then 20 else if is_aside && (Vector.is_touching pod opponent) then 20 else if is_behind then 6 else if is_aside && (Vector.is_near checkpoint pod) then 10 else if is_wide_aligned && (Vector.is_near checkpoint pod) then 20 else if is_near_aligned && (Vector.is_near checkpoint pod) then 40 else 100 in let power_str = match use_boost with | false -> string_of_int thrust | true -> "BOOST" in printf "%d %d %s\n%!" checkpoint.x checkpoint.y power_str ; tick := !tick + 1 ; old_pod := pod ; done;