Mad Pod Racing solution in rust

By NicknamedTwice
 avatar
unknown
rust
a year ago
9.7 kB
5
Indexable
use std::{cmp, io};

macro_rules! parse_input {
    ($x:expr, $t:ident) => ($x.trim().parse::<$t>().unwrap())
}

struct GameInput {
    player_position: Position,
    speed: Speed,
    next_checkpoint_id: i32,
    next_checkpoint_dist: i32,
    next_checkpoint_angle: i32,
}

struct Pod {
    thrust: i32,
    correction_angle: i32,
    min_correction_speed: i32,
    max_correction_speed: i32,
    multiplier_correction_speed: f32,
    boost_angle: i32,
    min_boost_distance: i32,
    checkpoint_close_proximity_range: i32,
    checkpoint_close_proximity_correction_angle: i32,
    checkpoint_close_proximity_correction_speed: i32,
    checkpoint_target_offset_multiplier: i32,
}

struct Speed(i32, i32);

#[derive(Clone, Copy, Debug)]
struct Position(i32, i32);

#[derive(Clone, Copy, Debug)]
struct Checkpoint {
    checkpoint_id: i32,
    position: Position,
    distance_prev_checkpoint: Option<i32>,
}

impl GameInput {
    /// determines the target to aim for with regard to the current pods speed
    fn get_target_coordinates(
        &self,
        pod_parameters: &Pod,
        pod_speed: &Speed,
        next_checkpoint: &Checkpoint
    ) -> (i32, i32) {
        (
            (
                next_checkpoint.position.0 +
                    (-pod_parameters.checkpoint_target_offset_multiplier
                        * pod_speed.0)
            ),
            (
                next_checkpoint.position.1 +
                    (-pod_parameters.checkpoint_target_offset_multiplier
                        * pod_speed.1)
            ),
        )
    }

    /// checking if were on the longest straight to the next checkpoint
    fn should_boost(
        &self,
        pod_parameters: &Pod,
        next_checkpoint: &Checkpoint
    ) -> bool {
        if self.next_checkpoint_dist > pod_parameters.min_boost_distance
            && self.next_checkpoint_angle < pod_parameters.boost_angle
            && self.next_checkpoint_angle > -pod_parameters.boost_angle
            && next_checkpoint.distance_prev_checkpoint.unwrap() != 0
            && next_checkpoint.checkpoint_id == self.next_checkpoint_id {
            return true;
        }
        false
    }

    /// function that determines the speed used while adjusting rotation
    fn get_target_speed(
        &self,
        pod_parameters: &Pod,
    ) -> i32 {
        let mut speed =
            (((1 - self.next_checkpoint_angle / 90) as f32)
                * 100_f32)
                .round() as i32;
        if speed == 200 {
            speed = 100;
        }
        cmp::max(
            cmp::min(
                (speed as f32 * pod_parameters.multiplier_correction_speed) as i32,
                pod_parameters.min_correction_speed,
            ),
            pod_parameters.max_correction_speed,
        )
    }
}

/// calculates the pythagorean theorem
/// c^2 = a^2 + b^2 => c = sqrt(a^2 + b^2)
fn pythagorean_theorem(a: i32, b: i32) -> i32 {
    ((a.pow(2) + b.pow(2)) as f32).sqrt() as i32
}

/// determines the checkpoint with the highest distance to the previous one
fn get_max_distance_checkpoint(checkpoints: &Vec<Checkpoint>) -> Option<&Checkpoint> {
    if checkpoints.len() < 2 || checkpoints[0].distance_prev_checkpoint.unwrap() == 0 { return None; }
    let highest_distance = checkpoints.iter().max_by_key(|p| p.distance_prev_checkpoint);
    highest_distance
}

/// determines the speed of the pod in the current epoch.
fn get_pod_speed(game_parameters: &GameInput, last_pod_position: (i32, i32)) -> (i32, i32) {
    let delta_x = game_parameters.player_position.0 - last_pod_position.0;
    let delta_y = game_parameters.player_position.1 - last_pod_position.1;
    eprintln!("Speed: {:?}", (delta_x, delta_y));
    (delta_x, delta_y)
}

/**
 * Auto-generated code below aims at helping you parse
 * the standard input according to the problem statement.
 **/
fn main() {
    let mut input_line = String::new();
    io::stdin().read_line(&mut input_line).unwrap();
    let laps = parse_input!(input_line, i32);
    let mut input_line = String::new();
    io::stdin().read_line(&mut input_line).unwrap();
    let checkpoint_count = parse_input!(input_line, i32);
    let mut checkpoints: Vec<Checkpoint> = vec![];
    for i in 0..checkpoint_count as usize {
        let mut input_line = String::new();
        io::stdin().read_line(&mut input_line).unwrap();
        let inputs = input_line.split(" ").collect::<Vec<_>>();
        let checkpoint_x = parse_input!(inputs[0], i32);
        let checkpoint_y = parse_input!(inputs[1], i32);
        if i == 0 {
            checkpoints.extend([Checkpoint {
                checkpoint_id: i as i32,
                position: Position(checkpoint_x, checkpoint_y),
                distance_prev_checkpoint: None,
            }]);
        } else {
            checkpoints.extend([Checkpoint {
                checkpoint_id: i as i32,
                position: Position(checkpoint_x, checkpoint_y),
                distance_prev_checkpoint: Option::from(pythagorean_theorem(checkpoints[i - 1].position.0, checkpoints[i - 1].position.1)),
            }]);
        }
    }
    checkpoints[0].distance_prev_checkpoint = Option::from(pythagorean_theorem(
        (checkpoints[0].position.0 - checkpoints[checkpoints.len() - 1].position.0).abs(),
        (checkpoints[0].position.1 - checkpoints[checkpoints.len() - 1].position.1)).abs()
    );

    // game loop
    loop {
        let mut pod_inputs: Vec<GameInput> = vec![];
        let mut enemy_pod_inputs: Vec<GameInput> = vec![];
        for i in 0..2 as usize {
            let mut input_line = String::new();
            io::stdin().read_line(&mut input_line).unwrap();
            let inputs = input_line.split(" ").collect::<Vec<_>>();
            let x = parse_input!(inputs[0], i32); // x position of your pod
            let y = parse_input!(inputs[1], i32); // y position of your pod
            let vx = parse_input!(inputs[2], i32); // x speed of your pod
            let vy = parse_input!(inputs[3], i32); // y speed of your pod
            let angle = parse_input!(inputs[4], i32); // angle of your pod
            let next_check_point_id = parse_input!(inputs[5], i32); // next check point id of your pod
            eprintln!("input {} {:?}", i, inputs);

            let target_checkpoint = checkpoints.get(next_check_point_id as usize);
            let pod_input = GameInput {
                player_position: Position(x, y),
                speed: Speed(vx, vy),
                next_checkpoint_id: next_check_point_id,
                next_checkpoint_dist: target_checkpoint.unwrap().distance_prev_checkpoint.unwrap(),
                next_checkpoint_angle: angle,
            };
            pod_inputs.extend([pod_input]);
        }
        for i in 0..2 as usize {
            let mut input_line = String::new();
            io::stdin().read_line(&mut input_line).unwrap();
            let inputs = input_line.split(" ").collect::<Vec<_>>();
            let x_2 = parse_input!(inputs[0], i32); // x position of the opponent's pod
            let y_2 = parse_input!(inputs[1], i32); // y position of the opponent's pod
            let vx_2 = parse_input!(inputs[2], i32); // x speed of the opponent's pod
            let vy_2 = parse_input!(inputs[3], i32); // y speed of the opponent's pod
            let angle_2 = parse_input!(inputs[4], i32); // angle of the opponent's pod
            let next_check_point_id_2 = parse_input!(inputs[5], i32); // next check point id of the opponent's pod
            eprintln!("input enemy {} {:?}", i, inputs);

            let target_checkpoint = checkpoints.get(next_check_point_id_2 as usize);
            let pod_input = GameInput {
                player_position: Position(x_2, y_2),
                speed: Speed(vx_2, vy_2),
                next_checkpoint_id: next_check_point_id_2,
                next_checkpoint_dist: target_checkpoint.unwrap().distance_prev_checkpoint.unwrap(),
                next_checkpoint_angle: angle_2,
            };
            enemy_pod_inputs.extend([pod_input]);
        }

        // Write an action using println!("message...");
        // To debug: eprintln!("Debug message...");

        for pod in pod_inputs.iter() {
            let pod_parameters = Pod {
                thrust: 100,
                correction_angle: 45,
                min_correction_speed: 20,
                max_correction_speed: 100,
                multiplier_correction_speed: 0.5,
                boost_angle: 20,
                min_boost_distance: 0,
                checkpoint_close_proximity_range: 2000,
                checkpoint_close_proximity_correction_angle: 25,
                checkpoint_close_proximity_correction_speed: 15,
                checkpoint_target_offset_multiplier: 3,
            };
            let next_checkpoint = checkpoints.get(pod.next_checkpoint_id as usize);

            let (target_x, target_y) = pod.get_target_coordinates(
                &pod_parameters,
                &pod.speed,
                next_checkpoint.unwrap()
            );
            let thrust = pod.get_target_speed(&pod_parameters);
            // boost
            if pod.should_boost(&pod_parameters, next_checkpoint.unwrap()) {
                println!("{} {} BOOST", target_x, target_y);
                continue;
            }
            println!(
                "{} {} {}",
                target_x,
                target_y,
                thrust
            );
        }
    }
}

Editor is loading...
Leave a Comment