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 orientation_t = | Behind | Aside | WideAligned | NearAligned | Aligned type distance_t = | Touching | Near | Anywhere | Far type t = { mutable id : int ; mutable pos : Vector.t ; mutable old_pos : Vector.t ; mutable dir : Vector.t ; mutable has_boost : bool ; mutable checkpoint_pos : Vector.t ; mutable checkpoint_dist : int ; mutable checkpoint_angle : int ; mutable output_str : string } let create () = { id = 0 ; pos = Vector.create 0 0 ; old_pos = Vector.create 0 0 ; dir = Vector.create 0 0 ; has_boost = true ; checkpoint_pos = Vector.create 0 0 ; checkpoint_dist = 0 ; checkpoint_angle = 0 ; output_str = "" } let use_boost pod = pod.has_boost <- false let update pod (pos, checkpoint_pos, checkpoint_dist, checkpoint_angle) = pod.pos <- pos ; pod.checkpoint_pos <- checkpoint_pos ; pod.checkpoint_dist <- checkpoint_dist ; pod.checkpoint_angle <- checkpoint_angle ; pod let movement pod = Vector.diff pod.pos pod.old_pos let is_aligned pod = pod.checkpoint_angle > -2 && pod.checkpoint_angle < 2 let is_near_aligned pod = (pod.checkpoint_angle > -15 && pod.checkpoint_angle <= -2) || (pod.checkpoint_angle >= 2 && pod.checkpoint_angle < 15) let is_wide_aligned pod = (pod.checkpoint_angle > -45 && pod.checkpoint_angle <= -15) || (pod.checkpoint_angle >= 15 && pod.checkpoint_angle < 45) let is_aside pod = (pod.checkpoint_angle > -85 && pod.checkpoint_angle <= -45) || (pod.checkpoint_angle >= 45 && pod.checkpoint_angle < 85) let is_behind pod = pod.checkpoint_angle >= 85 || pod.checkpoint_angle <= -85 let is_checkpoint_far pod = Vector.is_far pod.pos pod.checkpoint_pos let target_orientation pod = if is_aligned pod then Aligned else if is_near_aligned pod then NearAligned else if is_wide_aligned pod then WideAligned else if is_aside pod then Aside else Behind let target_distance pod = let dist = Vector.distance pod.pos pod.checkpoint_pos in if dist <= (checkpoint_ray) then Touching else if dist <= (checkpoint_ray * 3) then Near else if dist > (checkpoint_ray * 2 * 3) then Far else Anywhere 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 module Game = struct type t = { pods : Pod.t array ; opponents : Pod.t array ; mutable turn : int ; } let create () = { pods = Array.make 2 (Pod.create ()) ; opponents = Array.make 2 (Pod.create ()) ; turn = 0 } let is_first_turn game = game.turn < 2 let save_pods game = (* old_pod := pod ; *) ignore game let tick game = game.turn <- game.turn + 1 end in let module Strategy = struct let apply game pod = if Game.is_first_turn game then begin Game.save_pods game ; end ; let movement = Pod.movement in (* 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 ; *) let use_boost = (game.turn > 100) && (Pod.is_aligned pod) && (Pod.is_checkpoint_far pod) in let thrust = (* droit devant *) match (Pod.target_orientation pod, Pod.target_distance pod) with (* | (Behind, TouchingOpponent) -> 20 | (Aside, TouchingOpponent) -> 20 *) | (Behind, _) -> 6 | (Aside, Near) -> 10 | (WideAligned, Near) -> 20 | (NearAligned, Near) -> 40 | (_, _) -> 100 in let power_str = match use_boost with | false -> string_of_int thrust | true -> "BOOST" in let target = Vector.mult (Pod.movement pod) (-3) |> Vector.add pod.checkpoint_pos in printf "%d %d %s\n%!" target.x target.y power_str ; end in let parse_pod_line () = 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 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 (* laps : le nombre de tours à effectuer pour finir la course. *) let parse_init () = let laps = let line = input_line stdin in Scanf.sscanf line "%d" (fun x -> x) in let checkpoint_count = let line = input_line stdin in Scanf.sscanf line "%d" (fun x -> x) in let parse_checkpoint () = let line = input_line stdin in Scanf.sscanf line "%d %d" (fun x y -> Vector.create x y ) in for i = 1 to checkpoint_count do let checkpoint = parse_checkpoint () in checkpoint_list := CheckpointList.add !checkpoint_list checkpoint ; () done in let game = Game.create () in (* game loop *) while true do (* read pod1 line & update game data *) parse_pod_line () |> Pod.update game.pods.(0) |> ignore ; parse_pod_line () |> Pod.update game.pods.(1) |> ignore ; parse_pod_line () |> Pod.update game.opponents.(0) |> ignore ; parse_pod_line () |> Pod.update game.opponents.(1) |> ignore ; for i = 0 to 1 do game.pods.(i) (* |> Strategy.apply *) |> (fun (pod : Pod.t) -> pod.output_str) |> print_endline ; done ; Game.tick game ; done;