From 6883260603435b8349f727e4bab090069da98f5d Mon Sep 17 00:00:00 2001 From: "whatthedev.eth" Date: Thu, 20 Jul 2023 20:26:57 -0700 Subject: [PATCH 01/14] add test_filter_positions, test_raystrait_new --- src/math.cairo | 22 +++++ src/racer.cairo | 247 ++++++++++++++++++++++++++++++++++++++++++------ src/rays.cairo | 236 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 474 insertions(+), 31 deletions(-) diff --git a/src/math.cairo b/src/math.cairo index af15bfe..344e83f 100644 --- a/src/math.cairo +++ b/src/math.cairo @@ -105,6 +105,28 @@ fn distance(p1: Vec2, p2: Vec2, q2: Vec2, cos_ray: Fixed, sin_ray: Fixed) -> Fix } } +// similar to assert_precise which works for Fixed type only +use debug::PrintTrait; +const DEFAULT_PRECISION: u128 = 1844674407370; // 1e-7 +// To use `DEFAULT_PRECISION`, final arg is: `Option::None(())`. +// To use `custom_precision` of 184467440737_u128: `Option::Some(184467440737_u128)`. +fn assert_precise_u128(result: u128, expected: u128, msg: felt252, custom_precision: Option) { + let precision = match custom_precision { + Option::Some(val) => val, + Option::None(_) => DEFAULT_PRECISION, + }; + + let mut diff = result - expected; + if result < expected { + diff = expected - result; + } + + if (diff > precision) { + result.print(); + assert(diff <= precision, msg); + } +} + #[cfg(test)] mod tests { use traits::Into; diff --git a/src/racer.cairo b/src/racer.cairo index 0fb8bd6..4ae87c4 100644 --- a/src/racer.cairo +++ b/src/racer.cairo @@ -1,3 +1,4 @@ +use debug::PrintTrait; use traits::Into; use cubit::types::vec2::{Vec2, Vec2Trait}; use cubit::types::fixed::{Fixed, FixedTrait, ONE_u128}; @@ -44,7 +45,7 @@ fn compute_sensors(vehicle: Vehicle, mut enemies: Array) -> Sensors { // All sensors (ray segments) for this vehicle let ray_segments = RaysTrait::new(vehicle.position, vehicle.steer).segments; - let filter_dist = FixedTrait::new(CAR_WIDTH + RAY_LENGTH, false); // Is this used? + // let filter_dist = FixedTrait::new(CAR_WIDTH + RAY_LENGTH, false); // Is this used here? // Distances of each sensor to wall, if wall is near let mut wall_sensors = match near_wall(vehicle) { @@ -118,26 +119,22 @@ fn filter_positions(vehicle: Vehicle, mut positions: Array) -> Array

{ - // Option 1: Box - This may be cheaper than distance calculation in option 2, - // but may include unneeded positions near corners of box, which could be more expensive - if (FixedTrait::new(position.x, false) - vehicle.position.x).abs() <= max_dist - && (FixedTrait::new(position.y, false) - vehicle.position.y).abs() <= max_dist { + if (FixedTrait::new(position.x, false) - vehicle.position.x).abs() <= filter_dist_x + && (FixedTrait::new(position.y, false) - vehicle.position.y) + .abs() <= filter_dist_y { near.append(position); } - // // Option 2: Semi-circle - This may eliminate some positions near corners of box in option 2, - // // but may include (probably fewer) unneeded positions at the sides where max distance reduces - // // to as low as CAR_WIDTH + RAY_LENGTH - // let delta_x_squared = pow_int(position.x - vehicle.position.x, 2, false); - // let delta_y_squared = pow_int(position.y - vehicle.position.y, 2, false); - // let distance = sqrt(delta_x_squared + delta_y_squared); - // if distance <= max_dist { - // near.append(enemy_idx); - // } }, Option::None(_) => { break (); @@ -441,44 +438,214 @@ mod drive { #[cfg(test)] mod tests { use debug::PrintTrait; + use array::{ArrayTrait, SpanTrait}; use cubit::types::vec2::{Vec2, Vec2Trait}; use cubit::types::fixed::{Fixed, FixedTrait, FixedPrint, ONE_u128}; use cubit::math::trig; use cubit::test::helpers::assert_precise; - use array::SpanTrait; - use drive_ai::{Vehicle, VehicleTrait}; - use drive_ai::rays::{RAY_LENGTH}; + use drive_ai::vehicle::{Vehicle, VehicleTrait}; + use drive_ai::rays::{Rays, RaysTrait, Ray, RayTrait, NUM_RAYS, RAY_LENGTH}; + use drive_ai::enemy::{Position, PositionTrait}; + use drive_ai::math::assert_precise_u128; use super::{ compute_sensors, filter_positions, closest_position, near_wall, distances_to_wall, collision_check, Wall }; - use super::{CAR_WIDTH, GRID_WIDTH}; + use super::{GRID_HEIGHT, GRID_WIDTH, CAR_HEIGHT, CAR_WIDTH}; const TWO: u128 = 36893488147419103232; + const FOUR: u128 = 73786976294838206464; const TEN: u128 = 184467440737095516160; + const FIFTY: u128 = 922337203685477580800; const HUNDRED: u128 = 1844674407370955161600; + const TWO_HUNDRED: u128 = 3689348814741910323200; + const THREE_HUNDRED: u128 = 5534023222112865484800; + const THREE_FIFTY: u128 = 6456360425798343065600; + const DEG_25_IN_RADS: u128 = 8048910508974580935; + + #[test] + #[available_gas(20000000)] + fn test_compute_sensors() {// let vehicle = Vehicle { + // position: Vec2Trait::new( + // FixedTrait::new(CAR_WIDTH, false), FixedTrait::new(TEN, false) + // ), + // steer: FixedTrait::new(0, false), + // speed: FixedTrait::new(0, false) + // }; + } + // TODO #[test] #[available_gas(20000000)] - fn test_compute_sensors() { - let vehicle = Vehicle { + fn test_filter_positions() { + let vehicle_1 = Vehicle { position: Vec2Trait::new( - FixedTrait::new(CAR_WIDTH, false), FixedTrait::new(TEN, false) + FixedTrait::new(HUNDRED, false), FixedTrait::new(TWO_HUNDRED, false) ), steer: FixedTrait::new(0, false), speed: FixedTrait::new(0, false) }; - } - // TODO - #[test] - #[available_gas(20000000)] - fn test_filter_positions() {} + // Spawn enemies, spaced evenly horizontally, a little ahead of vehicle + // Use scaled u128 for Position + let enemies_nb = FOUR; + // position.x of first enemy (center), so left edge is `CAR_WIDTH` (half-width) from left wall + let enemy_min_dist_from_wall = 2 * CAR_WIDTH; + let enemy_horiz_spacing = (GRID_WIDTH - 2 * enemy_min_dist_from_wall) + / (enemies_nb - ONE_u128); + + let mut enemies_1 = ArrayTrait::::new(); + let mut i = 0_u128; + loop { + if i == enemies_nb { + break (); + } + let x = enemy_min_dist_from_wall + i * enemy_horiz_spacing; + let y = THREE_HUNDRED; + enemies_1.append(Position { x: x, y: y }); + i += ONE_u128; + }; + + // values calculated in spreadsheet "drive_ai tests" + let filtered_enemies_1 = filter_positions(vehicle_1, enemies_1); + assert(filtered_enemies_1.len() == 3_usize, 'invalid filtered_enemies_1'); + assert_precise_u128( + *(filtered_enemies_1.at(0).x), + 590295810358704000000, + 'invalid filtered_enemies_1 0 x', + Option::None(()) + ); + assert_precise_u128( + *(filtered_enemies_1.at(0).y), + 5534023222112850000000, + 'invalid filtered_enemies_1 0 y', + Option::None(()) + ); + assert_precise_u128( + *(filtered_enemies_1.at(1).x), + 2656331146614170000000, + 'invalid filtered_enemies_1 1 x', + Option::None(()) + ); + assert_precise_u128( + *(filtered_enemies_1.at(1).y), + 5534023222112850000000, + 'invalid filtered_enemies_1 1 y', + Option::None(()) + ); + assert_precise_u128( + *(filtered_enemies_1.at(2).x), + 4722366482869630000000, + 'invalid filtered_enemies_1 2 x', + Option::None(()) + ); + assert_precise_u128( + *(filtered_enemies_1.at(2).y), + 5534023222112850000000, + 'invalid filtered_enemies_1 2 y', + Option::None(()) + ); + + let vehicle_2 = Vehicle { + position: Vec2Trait::new( + FixedTrait::new(THREE_FIFTY, false), FixedTrait::new(TWO_HUNDRED, false) + ), + steer: FixedTrait::new(DEG_25_IN_RADS, false), + speed: FixedTrait::new(0, false) + }; + + // Could not figure out how to reuse enemies_1 here + let mut enemies_2 = ArrayTrait::::new(); + i = 0_u128; + loop { + if i == enemies_nb { + break (); + } + let x = enemy_min_dist_from_wall + i * enemy_horiz_spacing; + let y = THREE_HUNDRED; + enemies_2.append(Position { x: x, y: y }); + i += ONE_u128; + }; + + let filtered_enemies_2 = filter_positions(vehicle_2, enemies_2); + assert(filtered_enemies_2.len() == 2_usize, 'invalid filtered_enemies_2'); + assert_precise_u128( + *(filtered_enemies_2.at(0).x), + 4722366482869630000000, + 'invalid filtered_enemies_2 0 x', + Option::None(()) + ); + assert_precise_u128( + *(filtered_enemies_2.at(0).y), + 5534023222112850000000, + 'invalid filtered_enemies_2 0 y', + Option::None(()) + ); + assert_precise_u128( + *(filtered_enemies_2.at(1).x), + 6788401819125100000000, + 'invalid filtered_enemies_2 1 x', + Option::None(()) + ); + assert_precise_u128( + *(filtered_enemies_2.at(1).y), + 5534023222112850000000, + 'invalid filtered_enemies_2 1 y', + Option::None(()) + ); + } // TODO - #[test] - #[available_gas(20000000)] - fn test_closest_position() {} + // #[test] + // #[available_gas(20000000)] + // fn test_closest_position() { + // let vehicle_1 = Vehicle { + // position: Vec2Trait::new( + // FixedTrait::new(HUNDRED, false), FixedTrait::new(TWO_HUNDRED, false) + // ), + // steer: FixedTrait::new(0, false), + // speed: FixedTrait::new(0, false) + // }; + + // // Spawn enemies, spaced evenly horizontally, a little ahead of vehicle + // // Use scaled u128 for Position + // let enemies_nb = FOUR; + // // position.x of first enemy (center), so left edge is `CAR_WIDTH` (half-width) from left wall + // let enemy_min_dist_from_wall = 2 * CAR_WIDTH; + // let enemy_horiz_spacing = (GRID_WIDTH - 2 * enemy_min_dist_from_wall) + // / (enemies_nb - ONE_u128); + + // let mut enemies_1 = ArrayTrait::::new(); + // let mut i = 0_u128; + // loop { + // if i == enemies_nb { + // break (); + // } + // let x = enemy_min_dist_from_wall + i * enemy_horiz_spacing; + // let y = THREE_HUNDRED; + // enemies_1.append(Position { x: x, y: y }); + // i += ONE_u128; + // }; + + // let filtered_enemies_1 = filter_positions(vehicle_1, enemies_1); + + // // Distances of each sensor to its closest intersecting edge of all filtered enemies + // // (If sensor does not intersect an enemy edge, sensor's distance = 0) + // let mut enemy_sensors = ArrayTrait::::new(); + // let mut ray_idx = 0; + // loop { + // if (ray_idx == NUM_RAYS) { + // break (); + // } + + // enemy_sensors + // .append(closest_position(ray_segments.at(ray_idx), filtered_enemies.span())); + + // ray_idx += 1; + // }; + // // Asserted values need to be updated if/when NUM_RAYS = 5 changes value + // values calculated in spreadsheet "drive_ai tests" + // } #[test] #[available_gas(20000000)] @@ -518,7 +685,25 @@ mod tests { // TODO #[test] #[available_gas(20000000)] - fn test_distances_to_wall() {} + fn test_distances_to_wall() { // + // All sensors (ray segments) for this vehicle + // let ray_segments = RaysTrait::new(vehicle.position, vehicle.steer).segments; + + // let filter_dist = FixedTrait::new(CAR_WIDTH + RAY_LENGTH, false); // Is this used? + + // // Distances of each sensor to wall, if wall is near + // let mut wall_sensors = match near_wall(vehicle) { + // Wall::None(()) => { + // ArrayTrait::::new() + // }, + // Wall::Left(()) => { + // distances_to_wall(vehicle, Wall::Left(()), ray_segments) + // }, + // Wall::Right(()) => { + // distances_to_wall(vehicle, Wall::Right(()), ray_segments) + // }, + // }; + } // TODO #[test] diff --git a/src/rays.cairo b/src/rays.cairo index a7bdf10..609816f 100644 --- a/src/rays.cairo +++ b/src/rays.cairo @@ -86,3 +86,239 @@ impl RayImpl of RayTrait { distance(*self.p, p, q, *self.cos_theta, *self.sin_theta) } } + + +#[cfg(test)] +mod tests { + use debug::PrintTrait; + use array::{ArrayTrait, SpanTrait}; + use cubit::types::vec2::{Vec2, Vec2Trait}; + use cubit::types::fixed::{Fixed, FixedTrait, FixedPrint, ONE_u128}; + use cubit::math::trig; + use cubit::test::helpers::assert_precise; + use drive_ai::vehicle::{Vehicle, VehicleTrait}; + use drive_ai::enemy::{Position, PositionTrait}; + use drive_ai::racer::{ + compute_sensors, filter_positions, closest_position, near_wall, distances_to_wall, + collision_check, Wall + }; + use drive_ai::racer::{GRID_HEIGHT, GRID_WIDTH, CAR_HEIGHT, CAR_WIDTH}; + use super::{Rays, RaysTrait, Ray, RayTrait, NUM_RAYS, RAY_LENGTH}; + + const TWO: u128 = 36893488147419103232; + const FOUR: u128 = 73786976294838206464; + const TEN: u128 = 184467440737095516160; + const FIFTY: u128 = 922337203685477580800; + const HUNDRED: u128 = 1844674407370955161600; + const TWO_HUNDRED: u128 = 3689348814741910323200; + const THREE_HUNDRED: u128 = 5534023222112865484800; + const THREE_FIFTY: u128 = 6456360425798343065600; + const DEG_25_IN_RADS: u128 = 8048910508974580935; + + #[test] + #[available_gas(20000000)] + fn test_raystrait_new() { + // Vehicle 1 + let vehicle_1 = Vehicle { + position: Vec2Trait::new( + FixedTrait::new(HUNDRED, false), FixedTrait::new(TWO_HUNDRED, false) + ), + steer: FixedTrait::new(0, false), + speed: FixedTrait::new(0, false) + }; + let ray_segments_1 = RaysTrait::new(vehicle_1.position, vehicle_1.steer).segments; + assert(ray_segments_1.len() == NUM_RAYS, 'invalid ray_segments_1'); + + // values calculated in spreadsheet "drive_ai tests" + // ray_segments_1.at(0) + assert_precise( + *(ray_segments_1.at(0).theta), + -16097821017949100000, + 'invalid ray_segments_1 0 theta', + // use custom_precision of 1e-04, lower because of "fast" trig functions + Option::Some(1844674407370950) + ); + assert_precise( + *(ray_segments_1.at(0).cos_theta), + 11857338529639100000, + 'invalid ray_segments_1 0 cos', + Option::Some(1844674407370950) // 1e-04 + ); + assert_precise( + *(ray_segments_1.at(0).sin_theta), + -14131025791303100000, + 'invalid ray_segments_1 0 sin', + Option::Some(1844674407370950) // 1e-04 + ); + // p & q are less precise due to propagation of error above + assert_precise( + *(ray_segments_1.at(0).p.x), + 1844674407370950000000, + 'invalid ray_segments_1 0 p.x', + // + Option::Some(18446744073709500) // 1e-03 + ); + assert_precise( + *(ray_segments_1.at(0).p.y), + 3689348814741900000000, + 'invalid ray_segments_1 0 p.y', + Option::Some(18446744073709500) // 1e-03 + ); + assert_precise( + *(ray_segments_1.at(0).q.x), + -274979461324515000000, + 'invalid ray_segments_1 0 q.x', + Option::Some(184467440737095000) // 1e-02 + ); + assert_precise( + *(ray_segments_1.at(0).q.y), + 5467949594187760000000, + 'invalid ray_segments_1 0 q.y', + Option::Some(184467440737095000) // 1e-02 + ); + // ray_segments_1.at(3) + assert_precise( + *(ray_segments_1.at(3).theta), + 9658692610769470000, + 'invalid ray_segments_1 3 theta', + Option::Some(1844674407370950) // 1e-04 + ); + assert_precise( + *(ray_segments_1.at(3).cos_theta), + 15975348984942500000, + 'invalid ray_segments_1 3 cos', + Option::Some(1844674407370950) // 1e-04 + ); + assert_precise( + *(ray_segments_1.at(3).sin_theta), + 9223372036854750000, + 'invalid ray_segments_1 3 sin', + Option::Some(1844674407370950) // 1e-04 + ); + assert_precise( + *(ray_segments_1.at(3).p.x), + 1844674407370950000000, + 'invalid ray_segments_1 3 p.x', + // + Option::Some(18446744073709500) // 1e-03 + ); + assert_precise( + *(ray_segments_1.at(3).p.y), + 3689348814741900000000, + 'invalid ray_segments_1 3 p.y', + Option::Some(18446744073709500) // 1e-03 + ); + assert_precise( + *(ray_segments_1.at(3).q.x), + 3228180212899160000000, + 'invalid ray_segments_1 3 q.x', + Option::Some(184467440737095000) // 1e-02 + ); + assert_precise( + *(ray_segments_1.at(3).q.y), + 6085651162483270000000, + 'invalid ray_segments_1 3 q.y', + Option::Some(184467440737095000) // 1e-02 + ); + + // Vehicle 2 + let vehicle_2 = Vehicle { + position: Vec2Trait::new( + FixedTrait::new(THREE_FIFTY, false), FixedTrait::new(TWO_HUNDRED, false) + ), + steer: FixedTrait::new(DEG_25_IN_RADS, false), + speed: FixedTrait::new(0, false) + }; + let ray_segments_2 = RaysTrait::new(vehicle_2.position, vehicle_2.steer).segments; + assert(ray_segments_2.len() == NUM_RAYS, 'invalid ray_segments_2'); + + // ray_segments_2.at(0) + assert_precise( + *(ray_segments_2.at(0).theta), + -8048910508974560000, + 'invalid ray_segments_2 0 theta', + Option::Some(1844674407370950) // 1e-04 + ); + assert_precise( + *(ray_segments_2.at(0).cos_theta), + 16718427799475100000, + 'invalid ray_segments_2 0 cos', + Option::Some(1844674407370950) // 1e-04 + ); + assert_precise( + *(ray_segments_2.at(0).sin_theta), + -7795930915206660000, + 'invalid ray_segments_2 0 sin', + Option::Some(1844674407370950) // 1e-04 + ); + assert_precise( + *(ray_segments_2.at(0).p.x), + 6456360425798330000000, + 'invalid ray_segments_2 0 p.x', + // + Option::Some(18446744073709500) // 1e-03 + ); + assert_precise( + *(ray_segments_2.at(0).p.y), + 3689348814741900000000, + 'invalid ray_segments_2 0 p.y', + Option::Some(18446744073709500) // 1e-03 + ); + assert_precise( + *(ray_segments_2.at(0).q.x), + 5286970788517330000000, + 'invalid ray_segments_2 0 q.x', + Option::Some(184467440737095000) // 1e-02 + ); + assert_precise( + *(ray_segments_2.at(0).q.y), + 6197112984663160000000, + 'invalid ray_segments_2 0 q.y', + Option::Some(184467440737095000) // 1e-02 + ); + // ray_segments_2.at(3) + assert_precise( + *(ray_segments_2.at(3).theta), + 17707603119744000000, + 'invalid ray_segments_2 3 theta', + Option::Some(1844674407370950) // 1e-04 + ); + assert_precise( + *(ray_segments_2.at(3).cos_theta), + 10580617728078100000, + 'invalid ray_segments_2 3 cos', + Option::Some(1844674407370950) // 1e-04 + ); + assert_precise( + *(ray_segments_2.at(3).sin_theta), + 15110688118455000000, + 'invalid ray_segments_2 3 sin', + Option::Some(1844674407370950) // 1e-04 + ); + assert_precise( + *(ray_segments_2.at(3).p.x), + 6456360425798330000000, + 'invalid ray_segments_2 3 p.x', + // + Option::Some(18446744073709500) // 1e-03 + ); + assert_precise( + *(ray_segments_2.at(3).p.y), + 3689348814741900000000, + 'invalid ray_segments_2 3 p.y', + Option::Some(18446744073709500) // 1e-03 + ); + assert_precise( + *(ray_segments_2.at(3).q.x), + 8722963643566570000000, + 'invalid ray_segments_2 3 q.x', + Option::Some(184467440737095000) // 1e-02 + ); + assert_precise( + *(ray_segments_2.at(3).q.y), + 5276441473953610000000, + 'invalid ray_segments_2 3 q.y', + Option::Some(184467440737095000) // 1e-02 + ); + } +} From f5e449085849775ab9d277aba60c3f076cd758fe Mon Sep 17 00:00:00 2001 From: "whatthedev.eth" Date: Thu, 20 Jul 2023 22:32:36 -0700 Subject: [PATCH 02/14] add test_raytrait_intersects, test_raytrait_dist --- src/math.cairo | 12 ++--- src/racer.cairo | 54 ++++++++++++++++++++-- src/rays.cairo | 116 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+), 9 deletions(-) diff --git a/src/math.cairo b/src/math.cairo index 344e83f..32b3b33 100644 --- a/src/math.cairo +++ b/src/math.cairo @@ -248,7 +248,7 @@ mod tests { let mut p2 = Vec2Trait::new(FixedTrait::new(TEN, false), FixedTrait::new(FORTY, false)); let mut q2 = Vec2Trait::new(FixedTrait::new(THIRTY, false), FixedTrait::new(0, false)); let mut intersect = intersects(p1, q1, p2, q2); - assert(intersect == true, 'invalid intersection'); + assert(intersect, 'invalid intersection'); // Switch only p1,q1 p1 = Vec2Trait::new(FixedTrait::new(0, false), FixedTrait::new(TEN, false)); @@ -256,7 +256,7 @@ mod tests { p2 = Vec2Trait::new(FixedTrait::new(TEN, false), FixedTrait::new(FORTY, false)); q2 = Vec2Trait::new(FixedTrait::new(THIRTY, false), FixedTrait::new(0, false)); intersect = intersects(p1, q1, p2, q2); - assert(intersect == true, 'invalid intersection'); + assert(intersect, 'invalid intersection'); // Switch only p2,q2 p1 = Vec2Trait::new(FixedTrait::new(FORTY, false), FixedTrait::new(THIRTY, false)); @@ -264,7 +264,7 @@ mod tests { p2 = Vec2Trait::new(FixedTrait::new(THIRTY, false), FixedTrait::new(0, false)); q2 = Vec2Trait::new(FixedTrait::new(TEN, false), FixedTrait::new(FORTY, false)); intersect = intersects(p1, q1, p2, q2); - assert(intersect == true, 'invalid intersection'); + assert(intersect, 'invalid intersection'); // Switch both p1,q1 and p2,q2 p1 = Vec2Trait::new(FixedTrait::new(0, false), FixedTrait::new(TEN, false)); @@ -272,19 +272,19 @@ mod tests { p2 = Vec2Trait::new(FixedTrait::new(THIRTY, false), FixedTrait::new(0, false)); q2 = Vec2Trait::new(FixedTrait::new(TEN, false), FixedTrait::new(FORTY, false)); intersect = intersects(p1, q1, p2, q2); - assert(intersect == true, 'invalid intersection'); + assert(intersect, 'invalid intersection'); // Now shorter line 2 so no intersection q2 = Vec2Trait::new(FixedTrait::new(TEN, false), FixedTrait::new(TEN, false)); intersect = intersects(p1, q1, p2, q2); - assert(intersect == false, 'invalid non-intersection'); + assert(!intersect, 'invalid non-intersection'); // Colinear segments q1 = Vec2Trait::new(FixedTrait::new(THIRTY, false), FixedTrait::new(TEN, false)); p2 = Vec2Trait::new(FixedTrait::new(TWENTY, false), FixedTrait::new(TEN, false)); q2 = Vec2Trait::new(FixedTrait::new(FORTY, false), FixedTrait::new(TEN, false)); intersect = intersects(p1, q1, p2, q2); - assert(intersect == true, 'invalid colinear intersection'); + assert(intersect, 'invalid colinear intersection'); } #[test] diff --git a/src/racer.cairo b/src/racer.cairo index 4ae87c4..5c484f9 100644 --- a/src/racer.cairo +++ b/src/racer.cairo @@ -465,7 +465,7 @@ mod tests { #[test] #[available_gas(20000000)] - fn test_compute_sensors() {// let vehicle = Vehicle { + fn test_compute_sensors() { // let vehicle = Vehicle { // position: Vec2Trait::new( // FixedTrait::new(CAR_WIDTH, false), FixedTrait::new(TEN, false) // ), @@ -599,6 +599,7 @@ mod tests { // #[test] // #[available_gas(20000000)] // fn test_closest_position() { + // // Vehicle 1 // let vehicle_1 = Vehicle { // position: Vec2Trait::new( // FixedTrait::new(HUNDRED, false), FixedTrait::new(TWO_HUNDRED, false) @@ -643,8 +644,55 @@ mod tests { // ray_idx += 1; // }; - // // Asserted values need to be updated if/when NUM_RAYS = 5 changes value - // values calculated in spreadsheet "drive_ai tests" + + // // Values calculated in spreadsheet "drive_ai tests" + // // Asserted values need to be updated if/when NUM_RAYS = 5 is changed to new value + + // // Vehicle 2 + // let vehicle_2 = Vehicle { + // position: Vec2Trait::new( + // FixedTrait::new(HUNDRED, false), FixedTrait::new(TWO_HUNDRED, false) + // ), + // steer: FixedTrait::new(0, false), + // speed: FixedTrait::new(0, false) + // }; + + // // Spawn enemies, spaced evenly horizontally, a little ahead of vehicle + // // Use scaled u128 for Position + // let enemies_nb = FOUR; + // // position.x of first enemy (center), so left edge is `CAR_WIDTH` (half-width) from left wall + // let enemy_min_dist_from_wall = 2 * CAR_WIDTH; + // let enemy_horiz_spacing = (GRID_WIDTH - 2 * enemy_min_dist_from_wall) + // / (enemies_nb - ONE_u128); + + // let mut enemies_2 = ArrayTrait::::new(); + // let mut i = 0_u128; + // loop { + // if i == enemies_nb { + // break (); + // } + // let x = enemy_min_dist_from_wall + i * enemy_horiz_spacing; + // let y = THREE_HUNDRED; + // enemies_2.append(Position { x: x, y: y }); + // i += ONE_u128; + // }; + + // let filtered_enemies_2 = filter_positions(vehicle_2, enemies_2); + + // // Distances of each sensor to its closest intersecting edge of all filtered enemies + // // (If sensor does not intersect an enemy edge, sensor's distance = 0) + // let mut enemy_sensors = ArrayTrait::::new(); + // let mut ray_idx = 0; + // loop { + // if (ray_idx == NUM_RAYS) { + // break (); + // } + + // enemy_sensors + // .append(closest_position(ray_segments.at(ray_idx), filtered_enemies.span())); + + // ray_idx += 1; + // }; // } #[test] diff --git a/src/rays.cairo b/src/rays.cairo index 609816f..8099523 100644 --- a/src/rays.cairo +++ b/src/rays.cairo @@ -321,4 +321,120 @@ mod tests { Option::Some(184467440737095000) // 1e-02 ); } + + #[test] + #[available_gas(20000000)] + fn test_raytrait_intersects() { + // From vehicle 2 above, only ray 2 intersects enemy edges + let ray_2_2 = Ray { + theta: FixedTrait::new(8048910508974560000, false), + cos_theta: FixedTrait::new(16718427799475100000, false), + sin_theta: FixedTrait::new(7795930915206660000, false), + p: Vec2Trait::new( + FixedTrait::new(6456360425798330000000, false), + FixedTrait::new(3689348814741900000000, false) + ), + q: Vec2Trait::new( + FixedTrait::new(7625750063079320000000, false), + FixedTrait::new(6197112984663160000000, false) + ), + }; + + // ray_2_2 intersects only edges 2 & 3 of enemy 3 + // Enemy 3 edge 0 (horizontal, top) + let p_3_0 = Vec2Trait::new( + FixedTrait::new(6493253913945740000000, false), + FixedTrait::new(6124319032471550000000, false) + ); + let q_3_0 = Vec2Trait::new( + FixedTrait::new(7083549724304450000000, false), + FixedTrait::new(6124319032471550000000, false) + ); + let intersects = ray_2_2.intersects(p_3_0, q_3_0); + assert(!intersects, 'invalid RayTrait intersects'); + + // Enemy 3 edge 1 (vertical, left) + let p_3_1 = Vec2Trait::new( + FixedTrait::new(6493253913945740000000, false), + FixedTrait::new(4943727411754150000000, false) + ); + let q_3_1 = Vec2Trait::new( + FixedTrait::new(6493253913945740000000, false), + FixedTrait::new(6124319032471550000000, false) + ); + let intersects = ray_2_2.intersects(p_3_1, q_3_1); + assert(!intersects, 'invalid RayTrait intersects'); + + // Enemy 3 edge 2 (horizontal, bottom) + let p_3_2 = Vec2Trait::new( + FixedTrait::new(6493253913945740000000, false), + FixedTrait::new(4943727411754150000000, false) + ); + let q_3_2 = Vec2Trait::new( + FixedTrait::new(7083549724304450000000, false), + FixedTrait::new(4943727411754150000000, false) + ); + let intersects = ray_2_2.intersects(p_3_2, q_3_2); + assert(intersects, 'invalid RayTrait intersects'); + + // Enemy 3 edge 3 (vertical, right) + let p_3_3 = Vec2Trait::new( + FixedTrait::new(7083549724304450000000, false), + FixedTrait::new(4943727411754150000000, false) + ); + let q_3_3 = Vec2Trait::new( + FixedTrait::new(7083549724304450000000, false), + FixedTrait::new(6124319032471550000000, false) + ); + let intersects = ray_2_2.intersects(p_3_3, q_3_3); + assert(intersects, 'invalid RayTrait intersects'); + } + + #[test] + #[available_gas(20000000)] + fn test_raytrait_dist() { + // From vehicle 2 above, only ray 2 intersects enemy edges + let ray_2_2 = Ray { + theta: FixedTrait::new(8048910508974560000, false), + cos_theta: FixedTrait::new(16718427799475100000, false), + sin_theta: FixedTrait::new(7795930915206660000, false), + p: Vec2Trait::new( + FixedTrait::new(6456360425798330000000, false), + FixedTrait::new(3689348814741900000000, false) + ), + q: Vec2Trait::new( + FixedTrait::new(7625750063079320000000, false), + FixedTrait::new(6197112984663160000000, false) + ), + }; + + // ray_2_2 intersects only edges 2 & 3 of enemy 3 + // Enemy 3 edge 2 (horizontal, bottom) + let p_3_2 = Vec2Trait::new( + FixedTrait::new(6493253913945740000000, false), + FixedTrait::new(4943727411754150000000, false) + ); + let q_3_2 = Vec2Trait::new( + FixedTrait::new(7083549724304450000000, false), + FixedTrait::new(4943727411754150000000, false) + ); + let distance_2 = ray_2_2.dist(p_3_2, q_3_2); + assert_precise( + distance_2, 1384053645962460000000, 'invalid RayTrait distance 2', Option::None(()) + ); + + // Enemy 3 edge 3 (vertical, right) + let p_3_3 = Vec2Trait::new( + FixedTrait::new(7083549724304450000000, false), + FixedTrait::new(4943727411754150000000, false) + ); + let q_3_3 = Vec2Trait::new( + FixedTrait::new(7083549724304450000000, false), + FixedTrait::new(6124319032471550000000, false) + ); + let distance_3 = ray_2_2.dist(p_3_3, q_3_3); + assert_precise( + distance_3, 1484056311061490000000, 'invalid RayTrait distance 3', Option::None(()) + ); + } } From 2f8338c55b355537b9a94770b8a985054e11b3ea Mon Sep 17 00:00:00 2001 From: "whatthedev.eth" Date: Fri, 21 Jul 2023 00:32:42 -0700 Subject: [PATCH 03/14] add to rays tests --- src/rays.cairo | 266 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 235 insertions(+), 31 deletions(-) diff --git a/src/rays.cairo b/src/rays.cairo index 8099523..a6ae211 100644 --- a/src/rays.cairo +++ b/src/rays.cairo @@ -325,8 +325,131 @@ mod tests { #[test] #[available_gas(20000000)] fn test_raytrait_intersects() { + // From vehicle 1 above, only rays 1 & 3 intersect enemy edges + // Ray 1 + let ray_11 = Ray { + theta: FixedTrait::new(9658692610769470000, true), + cos_theta: FixedTrait::new(15975348984942500000, false), + sin_theta: FixedTrait::new(9223372036854750000, true), + p: Vec2Trait::new( + FixedTrait::new(1844674407370950000000, false), + FixedTrait::new(3689348814741900000000, false) + ), + q: Vec2Trait::new( + FixedTrait::new(461168601842738000000, false), + FixedTrait::new(6085651162483270000000, false) + ), + }; + + // ray_11 intersects only enemy 0 edge 3 + // Enemy 0 edge 0 (horizontal, top) + let p_00 = Vec2Trait::new( + FixedTrait::new(885443715538056000000, false), + FixedTrait::new(6124319032471550000000, false) + ); + let q_00 = Vec2Trait::new( + FixedTrait::new(295147905179352000000, false), + FixedTrait::new(6124319032471550000000, false) + ); + let intersect_1100 = ray_11.intersects(p_00, q_00); + assert(!intersect_1100, 'invalid RayTrait intersect 1100'); + // Enemy 0 edge 1 (vertical, left) + let p_01 = Vec2Trait::new( + FixedTrait::new(295147905179352000000, false), + FixedTrait::new(6124319032471550000000, false) + ); + let q_01 = Vec2Trait::new( + FixedTrait::new(295147905179352000000, false), + FixedTrait::new(4943727411754150000000, false) + ); + let intersect_1101 = ray_11.intersects(p_01, q_01); + assert(!intersect_1101, 'invalid RayTrait intersect 1101'); + // Enemy 0 edge 2 (horizontal, bottom) + let p_02 = Vec2Trait::new( + FixedTrait::new(295147905179352000000, false), + FixedTrait::new(4943727411754150000000, false) + ); + let q_02 = Vec2Trait::new( + FixedTrait::new(885443715538056000000, false), + FixedTrait::new(4943727411754150000000, false) + ); + let intersect_1102 = ray_11.intersects(p_02, q_02); + assert(!intersect_1102, 'invalid RayTrait intersect 1102'); + // Enemy 0 edge 3 (vertical, right) + let p_03 = Vec2Trait::new( + FixedTrait::new(885443715538056000000, false), + FixedTrait::new(4943727411754150000000, false) + ); + let q_03 = Vec2Trait::new( + FixedTrait::new(885443715538056000000, false), + FixedTrait::new(6124319032471550000000, false) + ); + let intersect_1103 = ray_11.intersects(p_03, q_03); + assert(intersect_1103, 'invalid RayTrait intersect 1103'); + + // Ray 3 + let ray_13 = Ray { + theta: FixedTrait::new(9658692610769470000, false), + cos_theta: FixedTrait::new(15975348984942500000, false), + sin_theta: FixedTrait::new(9223372036854750000, false), + p: Vec2Trait::new( + FixedTrait::new(1844674407370950000000, false), + FixedTrait::new(3689348814741900000000, false) + ), + q: Vec2Trait::new( + FixedTrait::new(3228180212899160000000, false), + FixedTrait::new(6085651162483270000000, false) + ), + }; + + // ray_13 intersects only enemy 1 edges 2 & 3 + // Enemy 1 edge 0 (horizontal, bottom) + let p_10 = Vec2Trait::new( + FixedTrait::new(2951479051793520000000, false), + FixedTrait::new(6124319032471550000000, false) + ); + let q_10 = Vec2Trait::new( + FixedTrait::new(2361183241434820000000, false), + FixedTrait::new(6124319032471550000000, false) + ); + let intersect_1310 = ray_13.intersects(p_10, q_10); + assert(!intersect_1310, 'invalid RayTrait intersect_1310'); + // Enemy 1 edge 1 (vertical, left) + let p_11 = Vec2Trait::new( + FixedTrait::new(2361183241434820000000, false), + FixedTrait::new(6124319032471550000000, false) + ); + let q_11 = Vec2Trait::new( + FixedTrait::new(2361183241434820000000, false), + FixedTrait::new(4943727411754150000000, false) + ); + let intersect_1311 = ray_13.intersects(p_11, q_11); + assert(!intersect_1311, 'invalid RayTrait intersect 1311'); + // Enemy 1 edge 2 (horizontal, bottom) + let p_12 = Vec2Trait::new( + FixedTrait::new(2361183241434820000000, false), + FixedTrait::new(4943727411754150000000, false) + ); + let q_12 = Vec2Trait::new( + FixedTrait::new(2951479051793520000000, false), + FixedTrait::new(4943727411754150000000, false) + ); + let intersect_1312 = ray_13.intersects(p_12, q_12); + assert(intersect_1312, 'invalid RayTrait intersect_1312'); + // Enemy 1 edge 3 (vertical, right) + let p_13 = Vec2Trait::new( + FixedTrait::new(2951479051793520000000, false), + FixedTrait::new(4943727411754150000000, false) + ); + let q_13 = Vec2Trait::new( + FixedTrait::new(2951479051793520000000, false), + FixedTrait::new(6124319032471550000000, false) + ); + let intersect_1313 = ray_13.intersects(p_13, q_13); + assert(intersect_1313, 'invalid RayTrait intersect 1313'); + // From vehicle 2 above, only ray 2 intersects enemy edges - let ray_2_2 = Ray { + let ray_22 = Ray { theta: FixedTrait::new(8048910508974560000, false), cos_theta: FixedTrait::new(16718427799475100000, false), sin_theta: FixedTrait::new(7795930915206660000, false), @@ -340,61 +463,142 @@ mod tests { ), }; - // ray_2_2 intersects only edges 2 & 3 of enemy 3 + // ray_22 intersects only enemy 3 edges 2 & 3 // Enemy 3 edge 0 (horizontal, top) - let p_3_0 = Vec2Trait::new( + let p_30 = Vec2Trait::new( FixedTrait::new(6493253913945740000000, false), FixedTrait::new(6124319032471550000000, false) ); - let q_3_0 = Vec2Trait::new( + let q_30 = Vec2Trait::new( FixedTrait::new(7083549724304450000000, false), FixedTrait::new(6124319032471550000000, false) ); - let intersects = ray_2_2.intersects(p_3_0, q_3_0); - assert(!intersects, 'invalid RayTrait intersects'); - + let intersect_2230 = ray_22.intersects(p_30, q_30); + assert(!intersect_2230, 'invalid RayTrait intersect_2230'); // Enemy 3 edge 1 (vertical, left) - let p_3_1 = Vec2Trait::new( + let p_31 = Vec2Trait::new( FixedTrait::new(6493253913945740000000, false), FixedTrait::new(4943727411754150000000, false) ); - let q_3_1 = Vec2Trait::new( + let q_31 = Vec2Trait::new( FixedTrait::new(6493253913945740000000, false), FixedTrait::new(6124319032471550000000, false) ); - let intersects = ray_2_2.intersects(p_3_1, q_3_1); - assert(!intersects, 'invalid RayTrait intersects'); - + let intersect_2231 = ray_22.intersects(p_31, q_31); + assert(!intersect_2231, 'invalid RayTrait intersect_2231'); // Enemy 3 edge 2 (horizontal, bottom) - let p_3_2 = Vec2Trait::new( + let p_32 = Vec2Trait::new( FixedTrait::new(6493253913945740000000, false), FixedTrait::new(4943727411754150000000, false) ); - let q_3_2 = Vec2Trait::new( + let q_32 = Vec2Trait::new( FixedTrait::new(7083549724304450000000, false), FixedTrait::new(4943727411754150000000, false) ); - let intersects = ray_2_2.intersects(p_3_2, q_3_2); - assert(intersects, 'invalid RayTrait intersects'); - + let intersect_2232 = ray_22.intersects(p_32, q_32); + assert(intersect_2232, 'invalid RayTrait intersect_2232'); // Enemy 3 edge 3 (vertical, right) - let p_3_3 = Vec2Trait::new( + let p_33 = Vec2Trait::new( FixedTrait::new(7083549724304450000000, false), FixedTrait::new(4943727411754150000000, false) ); - let q_3_3 = Vec2Trait::new( + let q_33 = Vec2Trait::new( FixedTrait::new(7083549724304450000000, false), FixedTrait::new(6124319032471550000000, false) ); - let intersects = ray_2_2.intersects(p_3_3, q_3_3); - assert(intersects, 'invalid RayTrait intersects'); + let intersect_2233 = ray_22.intersects(p_33, q_33); + assert(intersect_2233, 'invalid RayTrait intersect_2233'); } #[test] #[available_gas(20000000)] fn test_raytrait_dist() { + // From vehicle 1 above, only rays 1 & 3 intersect enemy edges + // Ray 1 + let ray_11 = Ray { + theta: FixedTrait::new(9658692610769470000, true), + cos_theta: FixedTrait::new(15975348984942500000, false), + sin_theta: FixedTrait::new(9223372036854750000, true), + p: Vec2Trait::new( + FixedTrait::new(1844674407370950000000, false), + FixedTrait::new(3689348814741900000000, false) + ), + q: Vec2Trait::new( + FixedTrait::new(461168601842738000000, false), + FixedTrait::new(6085651162483270000000, false) + ), + }; + + // ray_11 intersects only enemy 0 edge 3 + // Enemy 0 edge 3 (vertical, right) + let p_03 = Vec2Trait::new( + FixedTrait::new(885443715538056000000, false), + FixedTrait::new(4943727411754150000000, false) + ); + let q_03 = Vec2Trait::new( + FixedTrait::new(885443715538056000000, false), + FixedTrait::new(6124319032471550000000, false) + ); + let distance_1103 = ray_11.dist(p_03, q_03); + assert_precise( + distance_1103, + 1918461383665790000000, + 'invalid RayTrait distance 1103', + Option::None(()) + ); + + // Ray 3 + let ray_13 = Ray { + theta: FixedTrait::new(9658692610769470000, false), + cos_theta: FixedTrait::new(15975348984942500000, false), + sin_theta: FixedTrait::new(9223372036854750000, false), + p: Vec2Trait::new( + FixedTrait::new(1844674407370950000000, false), + FixedTrait::new(3689348814741900000000, false) + ), + q: Vec2Trait::new( + FixedTrait::new(3228180212899160000000, false), + FixedTrait::new(6085651162483270000000, false) + ), + }; + + // ray_13 intersects only enemy 1 edges 2 & 3 + // Enemy 1 edge 2 (horizontal, bottom) + let p_12 = Vec2Trait::new( + FixedTrait::new(2361183241434820000000, false), + FixedTrait::new(4943727411754150000000, false) + ); + let q_12 = Vec2Trait::new( + FixedTrait::new(2951479051793520000000, false), + FixedTrait::new(4943727411754150000000, false) + ); + let distance_1312 = ray_11.dist(p_12, q_12); + assert_precise( + distance_1312, + 1448431641301450000000, + 'invalid RayTrait distance 1312', + Option::None(()) + ); + + // Enemy 1 edge 3 (vertical, right) + let p_13 = Vec2Trait::new( + FixedTrait::new(2951479051793520000000, false), + FixedTrait::new(4943727411754150000000, false) + ); + let q_13 = Vec2Trait::new( + FixedTrait::new(2951479051793520000000, false), + FixedTrait::new(6124319032471550000000, false) + ); + let distance_1313 = ray_11.dist(p_13, q_13); + assert_precise( + distance_1313, + 2213609288845140000000, + 'invalid RayTrait distance 1313', + Option::None(()) + ); + // From vehicle 2 above, only ray 2 intersects enemy edges - let ray_2_2 = Ray { + let ray_22 = Ray { theta: FixedTrait::new(8048910508974560000, false), cos_theta: FixedTrait::new(16718427799475100000, false), sin_theta: FixedTrait::new(7795930915206660000, false), @@ -408,33 +612,33 @@ mod tests { ), }; - // ray_2_2 intersects only edges 2 & 3 of enemy 3 + // ray_22 intersects only enemy 3 edges 2 & 3 // Enemy 3 edge 2 (horizontal, bottom) - let p_3_2 = Vec2Trait::new( + let p_32 = Vec2Trait::new( FixedTrait::new(6493253913945740000000, false), FixedTrait::new(4943727411754150000000, false) ); - let q_3_2 = Vec2Trait::new( + let q_32 = Vec2Trait::new( FixedTrait::new(7083549724304450000000, false), FixedTrait::new(4943727411754150000000, false) ); - let distance_2 = ray_2_2.dist(p_3_2, q_3_2); + let distance_2232 = ray_22.dist(p_32, q_32); assert_precise( - distance_2, 1384053645962460000000, 'invalid RayTrait distance 2', Option::None(()) + distance_2232, 1384053645962460000000, 'invalid RayTrait dist 2232', Option::None(()) ); // Enemy 3 edge 3 (vertical, right) - let p_3_3 = Vec2Trait::new( + let p_33 = Vec2Trait::new( FixedTrait::new(7083549724304450000000, false), FixedTrait::new(4943727411754150000000, false) ); - let q_3_3 = Vec2Trait::new( + let q_33 = Vec2Trait::new( FixedTrait::new(7083549724304450000000, false), FixedTrait::new(6124319032471550000000, false) ); - let distance_3 = ray_2_2.dist(p_3_3, q_3_3); + let distance_2233 = ray_22.dist(p_33, q_33); assert_precise( - distance_3, 1484056311061490000000, 'invalid RayTrait distance 3', Option::None(()) + distance_2233, 1484056311061490000000, 'invalid RayTrait dist 2233', Option::None(()) ); } } From 67bf4158a8edeb727a6b3f98eb30a2e7aae5e607 Mon Sep 17 00:00:00 2001 From: "whatthedev.eth" Date: Fri, 21 Jul 2023 00:59:57 -0700 Subject: [PATCH 04/14] add to tests in rays.cairo --- src/rays.cairo | 270 +++++++++++++++++++++++++++---------------------- 1 file changed, 148 insertions(+), 122 deletions(-) diff --git a/src/rays.cairo b/src/rays.cairo index a6ae211..efa5fd7 100644 --- a/src/rays.cairo +++ b/src/rays.cairo @@ -130,6 +130,7 @@ mod tests { assert(ray_segments_1.len() == NUM_RAYS, 'invalid ray_segments_1'); // values calculated in spreadsheet "drive_ai tests" + // Asserted values need to be updated if/when NUM_RAYS = 5 is changed to new value // ray_segments_1.at(0) assert_precise( *(ray_segments_1.at(0).theta), @@ -325,128 +326,153 @@ mod tests { #[test] #[available_gas(20000000)] fn test_raytrait_intersects() { - // From vehicle 1 above, only rays 1 & 3 intersect enemy edges - // Ray 1 - let ray_11 = Ray { - theta: FixedTrait::new(9658692610769470000, true), - cos_theta: FixedTrait::new(15975348984942500000, false), - sin_theta: FixedTrait::new(9223372036854750000, true), - p: Vec2Trait::new( - FixedTrait::new(1844674407370950000000, false), - FixedTrait::new(3689348814741900000000, false) - ), - q: Vec2Trait::new( - FixedTrait::new(461168601842738000000, false), - FixedTrait::new(6085651162483270000000, false) - ), - }; - - // ray_11 intersects only enemy 0 edge 3 - // Enemy 0 edge 0 (horizontal, top) - let p_00 = Vec2Trait::new( - FixedTrait::new(885443715538056000000, false), - FixedTrait::new(6124319032471550000000, false) - ); - let q_00 = Vec2Trait::new( - FixedTrait::new(295147905179352000000, false), - FixedTrait::new(6124319032471550000000, false) - ); - let intersect_1100 = ray_11.intersects(p_00, q_00); - assert(!intersect_1100, 'invalid RayTrait intersect 1100'); - // Enemy 0 edge 1 (vertical, left) - let p_01 = Vec2Trait::new( - FixedTrait::new(295147905179352000000, false), - FixedTrait::new(6124319032471550000000, false) - ); - let q_01 = Vec2Trait::new( - FixedTrait::new(295147905179352000000, false), - FixedTrait::new(4943727411754150000000, false) - ); - let intersect_1101 = ray_11.intersects(p_01, q_01); - assert(!intersect_1101, 'invalid RayTrait intersect 1101'); - // Enemy 0 edge 2 (horizontal, bottom) - let p_02 = Vec2Trait::new( - FixedTrait::new(295147905179352000000, false), - FixedTrait::new(4943727411754150000000, false) - ); - let q_02 = Vec2Trait::new( - FixedTrait::new(885443715538056000000, false), - FixedTrait::new(4943727411754150000000, false) - ); - let intersect_1102 = ray_11.intersects(p_02, q_02); - assert(!intersect_1102, 'invalid RayTrait intersect 1102'); - // Enemy 0 edge 3 (vertical, right) - let p_03 = Vec2Trait::new( - FixedTrait::new(885443715538056000000, false), - FixedTrait::new(4943727411754150000000, false) - ); - let q_03 = Vec2Trait::new( - FixedTrait::new(885443715538056000000, false), - FixedTrait::new(6124319032471550000000, false) - ); - let intersect_1103 = ray_11.intersects(p_03, q_03); - assert(intersect_1103, 'invalid RayTrait intersect 1103'); - - // Ray 3 - let ray_13 = Ray { - theta: FixedTrait::new(9658692610769470000, false), - cos_theta: FixedTrait::new(15975348984942500000, false), - sin_theta: FixedTrait::new(9223372036854750000, false), - p: Vec2Trait::new( - FixedTrait::new(1844674407370950000000, false), - FixedTrait::new(3689348814741900000000, false) - ), - q: Vec2Trait::new( - FixedTrait::new(3228180212899160000000, false), - FixedTrait::new(6085651162483270000000, false) - ), - }; - - // ray_13 intersects only enemy 1 edges 2 & 3 - // Enemy 1 edge 0 (horizontal, bottom) - let p_10 = Vec2Trait::new( - FixedTrait::new(2951479051793520000000, false), - FixedTrait::new(6124319032471550000000, false) - ); - let q_10 = Vec2Trait::new( - FixedTrait::new(2361183241434820000000, false), - FixedTrait::new(6124319032471550000000, false) - ); - let intersect_1310 = ray_13.intersects(p_10, q_10); - assert(!intersect_1310, 'invalid RayTrait intersect_1310'); - // Enemy 1 edge 1 (vertical, left) - let p_11 = Vec2Trait::new( - FixedTrait::new(2361183241434820000000, false), - FixedTrait::new(6124319032471550000000, false) - ); - let q_11 = Vec2Trait::new( - FixedTrait::new(2361183241434820000000, false), - FixedTrait::new(4943727411754150000000, false) - ); - let intersect_1311 = ray_13.intersects(p_11, q_11); - assert(!intersect_1311, 'invalid RayTrait intersect 1311'); - // Enemy 1 edge 2 (horizontal, bottom) - let p_12 = Vec2Trait::new( - FixedTrait::new(2361183241434820000000, false), - FixedTrait::new(4943727411754150000000, false) - ); - let q_12 = Vec2Trait::new( - FixedTrait::new(2951479051793520000000, false), - FixedTrait::new(4943727411754150000000, false) - ); - let intersect_1312 = ray_13.intersects(p_12, q_12); - assert(intersect_1312, 'invalid RayTrait intersect_1312'); - // Enemy 1 edge 3 (vertical, right) - let p_13 = Vec2Trait::new( - FixedTrait::new(2951479051793520000000, false), - FixedTrait::new(4943727411754150000000, false) - ); - let q_13 = Vec2Trait::new( - FixedTrait::new(2951479051793520000000, false), - FixedTrait::new(6124319032471550000000, false) - ); - let intersect_1313 = ray_13.intersects(p_13, q_13); - assert(intersect_1313, 'invalid RayTrait intersect 1313'); + // // From vehicle 1 above, rays 0, 1, & 3 intersect enemy edges + // // Ray 0 + // let ray_10 = Ray { + // theta: FixedTrait::new(16097821017949100000, true), + // cos_theta: FixedTrait::new(11857338529639100000, false), + // sin_theta: FixedTrait::new(14131025791303100000, true), + // p: Vec2Trait::new( + // FixedTrait::new(1844674407370950000000, false), + // FixedTrait::new(3689348814741900000000, false) + // ), + // q: Vec2Trait::new( + // FixedTrait::new(274979461324515000000, true), + // FixedTrait::new(5467949594187760000000, false) + // ), + // }; + + // // ray_10 intersects only enemy 0 edges 1 & 2 + // // Enemy 0 edge 0 (horizontal, top) + // let p_00 = Vec2Trait::new( + // FixedTrait::new(885443715538056000000, false), + // FixedTrait::new(6124319032471550000000, false) + // ); + // let q_00 = Vec2Trait::new( + // FixedTrait::new(295147905179352000000, false), + // FixedTrait::new(6124319032471550000000, false) + // ); + // let intersect_1000 = ray_10.intersects(p_00, q_00); + // assert(!intersect_1000, 'invalid RayTrait intersect 1000'); + // // Enemy 0 edge 1 (vertical, left) + // let p_01 = Vec2Trait::new( + // FixedTrait::new(295147905179352000000, false), + // FixedTrait::new(6124319032471550000000, false) + // ); + // let q_01 = Vec2Trait::new( + // FixedTrait::new(295147905179352000000, false), + // FixedTrait::new(4943727411754150000000, false) + // ); + // let intersect_1001 = ray_10.intersects(p_01, q_01); + // assert(intersect_1001, 'invalid RayTrait intersect 1001'); + // // Enemy 0 edge 2 (horizontal, bottom) + // let p_02 = Vec2Trait::new( + // FixedTrait::new(295147905179352000000, false), + // FixedTrait::new(4943727411754150000000, false) + // ); + // let q_02 = Vec2Trait::new( + // FixedTrait::new(885443715538056000000, false), + // FixedTrait::new(4943727411754150000000, false) + // ); + // let intersect_1002 = ray_10.intersects(p_02, q_02); + // assert(intersect_1002, 'invalid RayTrait intersect 1002'); + // // Enemy 0 edge 3 (vertical, right) + // let p_03 = Vec2Trait::new( + // FixedTrait::new(885443715538056000000, false), + // FixedTrait::new(4943727411754150000000, false) + // ); + // let q_03 = Vec2Trait::new( + // FixedTrait::new(885443715538056000000, false), + // FixedTrait::new(6124319032471550000000, false) + // ); + // let intersect_1003 = ray_10.intersects(p_03, q_03); + // assert(!intersect_1003, 'invalid RayTrait intersect 1003'); + + // // Ray 1 + // let ray_11 = Ray { + // theta: FixedTrait::new(9658692610769470000, true), + // cos_theta: FixedTrait::new(15975348984942500000, false), + // sin_theta: FixedTrait::new(9223372036854750000, true), + // p: Vec2Trait::new( + // FixedTrait::new(1844674407370950000000, false), + // FixedTrait::new(3689348814741900000000, false) + // ), + // q: Vec2Trait::new( + // FixedTrait::new(461168601842738000000, false), + // FixedTrait::new(6085651162483270000000, false) + // ), + // }; + + // // ray_11 intersects only enemy 0 edge 3 + // let intersect_1100 = ray_11.intersects(p_00, q_00); + // assert(!intersect_1100, 'invalid RayTrait intersect 1100'); + // let intersect_1101 = ray_11.intersects(p_01, q_01); + // assert(!intersect_1101, 'invalid RayTrait intersect 1101'); + // let intersect_1102 = ray_11.intersects(p_02, q_02); + // assert(!intersect_1102, 'invalid RayTrait intersect 1102'); + // let intersect_1103 = ray_11.intersects(p_03, q_03); + // assert(intersect_1103, 'invalid RayTrait intersect 1103'); + + // // Ray 3 + // let ray_13 = Ray { + // theta: FixedTrait::new(9658692610769470000, false), + // cos_theta: FixedTrait::new(15975348984942500000, false), + // sin_theta: FixedTrait::new(9223372036854750000, false), + // p: Vec2Trait::new( + // FixedTrait::new(1844674407370950000000, false), + // FixedTrait::new(3689348814741900000000, false) + // ), + // q: Vec2Trait::new( + // FixedTrait::new(3228180212899160000000, false), + // FixedTrait::new(6085651162483270000000, false) + // ), + // }; + + // // ray_13 intersects only enemy 1 edges 2 & 3 + // // Enemy 1 edge 0 (horizontal, bottom) + // let p_10 = Vec2Trait::new( + // FixedTrait::new(2951479051793520000000, false), + // FixedTrait::new(6124319032471550000000, false) + // ); + // let q_10 = Vec2Trait::new( + // FixedTrait::new(2361183241434820000000, false), + // FixedTrait::new(6124319032471550000000, false) + // ); + // let intersect_1310 = ray_13.intersects(p_10, q_10); + // assert(!intersect_1310, 'invalid RayTrait intersect_1310'); + // // Enemy 1 edge 1 (vertical, left) + // let p_11 = Vec2Trait::new( + // FixedTrait::new(2361183241434820000000, false), + // FixedTrait::new(6124319032471550000000, false) + // ); + // let q_11 = Vec2Trait::new( + // FixedTrait::new(2361183241434820000000, false), + // FixedTrait::new(4943727411754150000000, false) + // ); + // let intersect_1311 = ray_13.intersects(p_11, q_11); + // assert(!intersect_1311, 'invalid RayTrait intersect 1311'); + // // Enemy 1 edge 2 (horizontal, bottom) + // let p_12 = Vec2Trait::new( + // FixedTrait::new(2361183241434820000000, false), + // FixedTrait::new(4943727411754150000000, false) + // ); + // let q_12 = Vec2Trait::new( + // FixedTrait::new(2951479051793520000000, false), + // FixedTrait::new(4943727411754150000000, false) + // ); + // let intersect_1312 = ray_13.intersects(p_12, q_12); + // assert(intersect_1312, 'invalid RayTrait intersect_1312'); + // // Enemy 1 edge 3 (vertical, right) + // let p_13 = Vec2Trait::new( + // FixedTrait::new(2951479051793520000000, false), + // FixedTrait::new(4943727411754150000000, false) + // ); + // let q_13 = Vec2Trait::new( + // FixedTrait::new(2951479051793520000000, false), + // FixedTrait::new(6124319032471550000000, false) + // ); + // let intersect_1313 = ray_13.intersects(p_13, q_13); + // assert(intersect_1313, 'invalid RayTrait intersect 1313'); // From vehicle 2 above, only ray 2 intersects enemy edges let ray_22 = Ray { From 3fa743d1d681fa658cc524c099ec34dab0259766 Mon Sep 17 00:00:00 2001 From: "whatthedev.eth" Date: Fri, 21 Jul 2023 01:42:16 -0700 Subject: [PATCH 05/14] add to test_raytrait_dist --- src/rays.cairo | 54 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/src/rays.cairo b/src/rays.cairo index efa5fd7..ef6d028 100644 --- a/src/rays.cairo +++ b/src/rays.cairo @@ -136,8 +136,7 @@ mod tests { *(ray_segments_1.at(0).theta), -16097821017949100000, 'invalid ray_segments_1 0 theta', - // use custom_precision of 1e-04, lower because of "fast" trig functions - Option::Some(1844674407370950) + Option::Some(1844674407370950) // use custom_precision of 1e-04 ); assert_precise( *(ray_segments_1.at(0).cos_theta), @@ -539,7 +538,56 @@ mod tests { #[test] #[available_gas(20000000)] fn test_raytrait_dist() { - // From vehicle 1 above, only rays 1 & 3 intersect enemy edges + // From vehicle 1 above, rays 0, 1, & 3 intersect enemy edges + // Ray 0 + let ray_10 = Ray { + theta: FixedTrait::new(16097821017949100000, true), + cos_theta: FixedTrait::new(11857338529639100000, false), + sin_theta: FixedTrait::new(14131025791303100000, true), + p: Vec2Trait::new( + FixedTrait::new(1844674407370950000000, false), + FixedTrait::new(3689348814741900000000, false) + ), + q: Vec2Trait::new( + FixedTrait::new(274979461324515000000, true), + FixedTrait::new(5467949594187760000000, false) + ), + }; + + // ray_10 intersects only enemy 0 edges 1 & 2 + // Enemy 0 edge 1 (vertical, left) + let p_01 = Vec2Trait::new( + FixedTrait::new(295147905179352000000, false), + FixedTrait::new(6124319032471550000000, false) + ); + let q_01 = Vec2Trait::new( + FixedTrait::new(295147905179352000000, false), + FixedTrait::new(4943727411754150000000, false) + ); + let distance_1001 = ray_10.dist(p_01, q_01); + assert_precise( + distance_1001, + 2022763190974460000000, + 'invalid RayTrait distance 1001', + Option::None(()) + ); + // Enemy 0 edge 2 (horizontal, bottom) + let p_02 = Vec2Trait::new( + FixedTrait::new(295147905179352000000, false), + FixedTrait::new(4943727411754150000000, false) + ); + let q_02 = Vec2Trait::new( + FixedTrait::new(885443715538056000000, false), + FixedTrait::new(4943727411754150000000, false) + ); + let distance_1002 = ray_10.dist(p_02, q_02); + assert_precise( + distance_1002, + 1951466671275690000000, + 'invalid RayTrait distance 1002', + Option::None(()) + ); + // Ray 1 let ray_11 = Ray { theta: FixedTrait::new(9658692610769470000, true), From d9fe26b87e3e132cdb50c85fb3060b94fc96003f Mon Sep 17 00:00:00 2001 From: "whatthedev.eth" Date: Fri, 21 Jul 2023 09:30:41 -0700 Subject: [PATCH 06/14] add method vertices_scaled --- src/enemy.cairo | 90 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/src/enemy.cairo b/src/enemy.cairo index 822a8f5..c884a1d 100644 --- a/src/enemy.cairo +++ b/src/enemy.cairo @@ -26,7 +26,8 @@ struct Position { trait PositionTrait { // Returns the vertices of the enemy at given position - fn vertices(self: @Position) -> Span; + fn vertices(self: @Position) -> Span; // Position has unscaled members + fn vertices_scaled(self: @Position) -> Span; // Position has scaled members } impl PostionImpl of PositionTrait { @@ -58,6 +59,34 @@ impl PostionImpl of PositionTrait { vertices.append(Vec2 { x: FixedTrait::new_unscaled(*self.x + CAR_WIDTH, false), y: y1 }); vertices.span() } + + fn vertices_scaled(self: @Position) -> Span { + let mut vertices = ArrayTrait::new(); + vertices + .append( + Vec2 { + x: FixedTrait::new(*self.x + CAR_WIDTH_SCALED, false), + y: FixedTrait::new(*self.y + CAR_HEIGHT_SCALED, false) + } + ); + + let x1 = if *self.x < CAR_WIDTH_SCALED { + FixedTrait::new(0, false) + } else { + FixedTrait::new(*self.x - CAR_WIDTH_SCALED, false) + }; + + let y1 = if *self.y < CAR_HEIGHT_SCALED { + FixedTrait::new(0, false) + } else { + FixedTrait::new(*self.y - CAR_HEIGHT_SCALED, false) + }; + + vertices.append(Vec2 { x: x1, y: FixedTrait::new(*self.y + CAR_HEIGHT_SCALED, false) }); + vertices.append(Vec2 { x: x1, y: y1 }); + vertices.append(Vec2 { x: FixedTrait::new(*self.x + CAR_WIDTH_SCALED, false), y: y1 }); + vertices.span() + } } #[system] @@ -498,4 +527,63 @@ mod tests { Option::None(()) ); } + + #[test] + #[available_gas(2000000)] + fn test_vertices_scaled() { + let position = Position { x: HUNDRED, y: HUNDRED }; + let vertices = position.vertices_scaled(); + + assert_precise( + *(vertices.at(0).x), + (HUNDRED + CAR_WIDTH_SCALED).into(), + 'invalid vertex_0', + Option::None(()) + ); + assert_precise( + *(vertices.at(0).y), + (HUNDRED + CAR_HEIGHT_SCALED).into(), + 'invalid vertex_0', + Option::None(()) + ); + + assert_precise( + *(vertices.at(1).x), + (HUNDRED - CAR_WIDTH_SCALED).into(), + 'invalid vertex_1', + Option::None(()) + ); + assert_precise( + *(vertices.at(1).y), + (HUNDRED + CAR_HEIGHT_SCALED).into(), + 'invalid vertex_1', + Option::None(()) + ); + + assert_precise( + *(vertices.at(2).x), + (HUNDRED - CAR_WIDTH_SCALED).into(), + 'invalid vertex_x2', + Option::None(()) + ); + assert_precise( + *(vertices.at(2).y), + (HUNDRED - CAR_HEIGHT_SCALED).into(), + 'invalid vertex_y2', + Option::None(()) + ); + + assert_precise( + *(vertices.at(3).x), + (HUNDRED + CAR_WIDTH_SCALED).into(), + 'invalid vertex_3', + Option::None(()) + ); + assert_precise( + *(vertices.at(3).y), + (HUNDRED - CAR_HEIGHT_SCALED).into(), + 'invalid vertex_3', + Option::None(()) + ); + } } From 39bd29a438915a1f6b3710a4a6c8cb2b1e6696ce Mon Sep 17 00:00:00 2001 From: "whatthedev.eth" Date: Fri, 21 Jul 2023 09:31:06 -0700 Subject: [PATCH 07/14] add test_closest_position --- src/racer.cairo | 254 +++++++++++++++++++++++++----------------------- 1 file changed, 135 insertions(+), 119 deletions(-) diff --git a/src/racer.cairo b/src/racer.cairo index 5c484f9..36a7374 100644 --- a/src/racer.cairo +++ b/src/racer.cairo @@ -148,25 +148,18 @@ fn filter_positions(vehicle: Vehicle, mut positions: Array) -> Array

) -> Fixed { - // Return value if sensor does not intersect any edges - let mut closest = FixedTrait::new(0, false); - // Max possible intersection distance - let ray_length = FixedTrait::new(RAY_LENGTH, false); - + // Set to max possible intersection distance before outer loop + let mut closest = FixedTrait::new(RAY_LENGTH, false); loop { match positions.pop_front() { Option::Some(position) => { - closest = ray_length; let mut edge_idx: usize = 0; - let vertices = position.vertices(); + let vertices = position.vertices_scaled(); // TODO: Only check visible edges loop { - if edge_idx == 3 { - if closest == ray_length { // No intersection - closest == FixedTrait::new(0, false); - } + if edge_idx == 4 { break (); } @@ -189,6 +182,10 @@ fn closest_position(ray: @Ray, mut positions: Span) -> Fixed { } }, Option::None(_) => { + if closest == FixedTrait::new(RAY_LENGTH, false) { + // No intersection found for ray + closest = FixedTrait::new(0, false); + } break (); } }; @@ -312,7 +309,7 @@ fn collision_check(vehicle: Vehicle, mut enemies: Array) { Option::Some(position) => { let mut enemy_edge_idx: usize = 0; - let vertices = position.vertices(); + let vertices = position.vertices_scaled(); // For each enemy edge // TODO: Only check visible edges @@ -454,7 +451,6 @@ mod tests { use super::{GRID_HEIGHT, GRID_WIDTH, CAR_HEIGHT, CAR_WIDTH}; const TWO: u128 = 36893488147419103232; - const FOUR: u128 = 73786976294838206464; const TEN: u128 = 184467440737095516160; const FIFTY: u128 = 922337203685477580800; const HUNDRED: u128 = 1844674407370955161600; @@ -474,7 +470,6 @@ mod tests { // }; } - // TODO #[test] #[available_gas(20000000)] fn test_filter_positions() { @@ -488,11 +483,10 @@ mod tests { // Spawn enemies, spaced evenly horizontally, a little ahead of vehicle // Use scaled u128 for Position - let enemies_nb = FOUR; + let enemies_nb = 4_u128; // position.x of first enemy (center), so left edge is `CAR_WIDTH` (half-width) from left wall let enemy_min_dist_from_wall = 2 * CAR_WIDTH; - let enemy_horiz_spacing = (GRID_WIDTH - 2 * enemy_min_dist_from_wall) - / (enemies_nb - ONE_u128); + let enemy_horiz_spacing = (GRID_WIDTH - 2 * enemy_min_dist_from_wall) / (enemies_nb - 1); let mut enemies_1 = ArrayTrait::::new(); let mut i = 0_u128; @@ -503,7 +497,7 @@ mod tests { let x = enemy_min_dist_from_wall + i * enemy_horiz_spacing; let y = THREE_HUNDRED; enemies_1.append(Position { x: x, y: y }); - i += ONE_u128; + i += 1; }; // values calculated in spreadsheet "drive_ai tests" @@ -554,7 +548,7 @@ mod tests { speed: FixedTrait::new(0, false) }; - // Could not figure out how to reuse enemies_1 here + // Could not figure out how to reuse enemies_1 here, not copyable let mut enemies_2 = ArrayTrait::::new(); i = 0_u128; loop { @@ -564,7 +558,7 @@ mod tests { let x = enemy_min_dist_from_wall + i * enemy_horiz_spacing; let y = THREE_HUNDRED; enemies_2.append(Position { x: x, y: y }); - i += ONE_u128; + i += 1; }; let filtered_enemies_2 = filter_positions(vehicle_2, enemies_2); @@ -595,105 +589,127 @@ mod tests { ); } - // TODO - // #[test] - // #[available_gas(20000000)] - // fn test_closest_position() { - // // Vehicle 1 - // let vehicle_1 = Vehicle { - // position: Vec2Trait::new( - // FixedTrait::new(HUNDRED, false), FixedTrait::new(TWO_HUNDRED, false) - // ), - // steer: FixedTrait::new(0, false), - // speed: FixedTrait::new(0, false) - // }; - - // // Spawn enemies, spaced evenly horizontally, a little ahead of vehicle - // // Use scaled u128 for Position - // let enemies_nb = FOUR; - // // position.x of first enemy (center), so left edge is `CAR_WIDTH` (half-width) from left wall - // let enemy_min_dist_from_wall = 2 * CAR_WIDTH; - // let enemy_horiz_spacing = (GRID_WIDTH - 2 * enemy_min_dist_from_wall) - // / (enemies_nb - ONE_u128); - - // let mut enemies_1 = ArrayTrait::::new(); - // let mut i = 0_u128; - // loop { - // if i == enemies_nb { - // break (); - // } - // let x = enemy_min_dist_from_wall + i * enemy_horiz_spacing; - // let y = THREE_HUNDRED; - // enemies_1.append(Position { x: x, y: y }); - // i += ONE_u128; - // }; - - // let filtered_enemies_1 = filter_positions(vehicle_1, enemies_1); - - // // Distances of each sensor to its closest intersecting edge of all filtered enemies - // // (If sensor does not intersect an enemy edge, sensor's distance = 0) - // let mut enemy_sensors = ArrayTrait::::new(); - // let mut ray_idx = 0; - // loop { - // if (ray_idx == NUM_RAYS) { - // break (); - // } - - // enemy_sensors - // .append(closest_position(ray_segments.at(ray_idx), filtered_enemies.span())); - - // ray_idx += 1; - // }; - - // // Values calculated in spreadsheet "drive_ai tests" - // // Asserted values need to be updated if/when NUM_RAYS = 5 is changed to new value - - // // Vehicle 2 - // let vehicle_2 = Vehicle { - // position: Vec2Trait::new( - // FixedTrait::new(HUNDRED, false), FixedTrait::new(TWO_HUNDRED, false) - // ), - // steer: FixedTrait::new(0, false), - // speed: FixedTrait::new(0, false) - // }; - - // // Spawn enemies, spaced evenly horizontally, a little ahead of vehicle - // // Use scaled u128 for Position - // let enemies_nb = FOUR; - // // position.x of first enemy (center), so left edge is `CAR_WIDTH` (half-width) from left wall - // let enemy_min_dist_from_wall = 2 * CAR_WIDTH; - // let enemy_horiz_spacing = (GRID_WIDTH - 2 * enemy_min_dist_from_wall) - // / (enemies_nb - ONE_u128); - - // let mut enemies_2 = ArrayTrait::::new(); - // let mut i = 0_u128; - // loop { - // if i == enemies_nb { - // break (); - // } - // let x = enemy_min_dist_from_wall + i * enemy_horiz_spacing; - // let y = THREE_HUNDRED; - // enemies_2.append(Position { x: x, y: y }); - // i += ONE_u128; - // }; - - // let filtered_enemies_2 = filter_positions(vehicle_2, enemies_2); - - // // Distances of each sensor to its closest intersecting edge of all filtered enemies - // // (If sensor does not intersect an enemy edge, sensor's distance = 0) - // let mut enemy_sensors = ArrayTrait::::new(); - // let mut ray_idx = 0; - // loop { - // if (ray_idx == NUM_RAYS) { - // break (); - // } - - // enemy_sensors - // .append(closest_position(ray_segments.at(ray_idx), filtered_enemies.span())); - - // ray_idx += 1; - // }; - // } + #[test] + #[available_gas(200000000)] // Made gas 10x + fn test_closest_position() { + // Vehicle 1 + let vehicle_1 = Vehicle { + position: Vec2Trait::new( + FixedTrait::new(HUNDRED, false), FixedTrait::new(TWO_HUNDRED, false) + ), + steer: FixedTrait::new(0, false), + speed: FixedTrait::new(0, false) + }; + + let ray_segments_1 = RaysTrait::new(vehicle_1.position, vehicle_1.steer).segments; + + // Spawn enemies, spaced evenly horizontally, a little ahead of vehicle + // Use scaled u128 for Position + let enemies_nb = 4_u128; + // position.x of first enemy (center), so left edge is `CAR_WIDTH` (half-width) from left wall + let enemy_min_dist_from_wall = 2 * CAR_WIDTH; + let enemy_horiz_spacing = (GRID_WIDTH - 2 * enemy_min_dist_from_wall) / (enemies_nb - 1); + + let mut enemies_1 = ArrayTrait::::new(); + let mut i = 0_u128; + loop { + if i == enemies_nb { + break (); + } + let x = enemy_min_dist_from_wall + i * enemy_horiz_spacing; + let y = THREE_HUNDRED; + enemies_1.append(Position { x: x, y: y }); + i += 1; + }; + + let filtered_enemies_1 = filter_positions(vehicle_1, enemies_1); + + let mut enemy_sensors_1 = ArrayTrait::::new(); + let mut ray_idx = 0; + loop { + if (ray_idx == NUM_RAYS) { + break (); + } + + enemy_sensors_1 + .append(closest_position(ray_segments_1.at(ray_idx), filtered_enemies_1.span())); + + ray_idx += 1; + }; + // Values calculated in spreadsheet "drive_ai tests" + // Asserted values need to be updated if/when NUM_RAYS = 5 is changed to new value + assert(enemy_sensors_1.len() == NUM_RAYS, 'invalid enemy_sensors_1'); + assert_precise( + *(enemy_sensors_1.at(0)), + 1951466671275690000000, + 'invalid v1 closest pos ray 0', + Option::Some(184467440737095000) // 1e-02 + ); + assert_precise( + *(enemy_sensors_1.at(1)), + 1918461383665790000000, + 'invalid v1 closest pos ray 1', + Option::Some(184467440737095000) // 1e-02 + ); + assert(*(enemy_sensors_1.at(2).mag) == 0, 'invalid v1 closest pos ray 2'); + assert_precise( + *(enemy_sensors_1.at(3)), + 1448431641301450000000, + 'invalid v1 closest pos ray 3', + Option::Some(184467440737095000) // 1e-02 + ); + assert(*(enemy_sensors_1.at(4).mag) == 0, 'invalid v1 closest pos ray 4'); + + // Vehicle 2 + let vehicle_2 = Vehicle { + position: Vec2Trait::new( + FixedTrait::new(THREE_FIFTY, false), FixedTrait::new(TWO_HUNDRED, false) + ), + steer: FixedTrait::new(DEG_25_IN_RADS, false), + speed: FixedTrait::new(0, false) + }; + + let ray_segments_2 = RaysTrait::new(vehicle_2.position, vehicle_2.steer).segments; + + // Could not figure out how to reuse enemies_1 here, not copyable + let mut enemies_2 = ArrayTrait::::new(); + i = 0_u128; + loop { + if i == enemies_nb { + break (); + } + let x = enemy_min_dist_from_wall + i * enemy_horiz_spacing; + let y = THREE_HUNDRED; + enemies_2.append(Position { x: x, y: y }); + i += 1; + }; + + let filtered_enemies_2 = filter_positions(vehicle_2, enemies_2); + + let mut enemy_sensors_2 = ArrayTrait::::new(); + ray_idx = 0; + loop { + if (ray_idx == NUM_RAYS) { + break (); + } + + enemy_sensors_2 + .append(closest_position(ray_segments_2.at(ray_idx), filtered_enemies_2.span())); + + ray_idx += 1; + }; + assert(enemy_sensors_2.len() == NUM_RAYS, 'invalid enemy_sensors_2'); + assert(*(enemy_sensors_2.at(0).mag) == 0, 'invalid v2 closest pos ray 0'); + assert(*(enemy_sensors_2.at(1).mag) == 0, 'invalid v2 closest pos ray 1'); + assert_precise( + *(enemy_sensors_2.at(2)), + 1384053645962460000000, + 'invalid v2 closest pos ray 2', + Option::Some(184467440737095000) // 1e-02 + ); + assert(*(enemy_sensors_2.at(3).mag) == 0, 'invalid v2 closest pos ray 3'); + assert(*(enemy_sensors_2.at(4).mag) == 0, 'invalid v2 closest pos ray 4'); + } #[test] #[available_gas(20000000)] From c55e5400741ad801da971a9849fe33495f654173 Mon Sep 17 00:00:00 2001 From: "whatthedev.eth" Date: Fri, 21 Jul 2023 10:15:11 -0700 Subject: [PATCH 08/14] convert some arrays to spans --- src/racer.cairo | 102 +++++++++++++++++++----------------------------- 1 file changed, 40 insertions(+), 62 deletions(-) diff --git a/src/racer.cairo b/src/racer.cairo index 36a7374..c65f557 100644 --- a/src/racer.cairo +++ b/src/racer.cairo @@ -61,7 +61,7 @@ fn compute_sensors(vehicle: Vehicle, mut enemies: Array) -> Sensors { }; // Positions of only filtered (near) enemies - let filtered_enemies = filter_positions(vehicle, enemies); + let filtered_enemies = filter_positions(vehicle, enemies.span()); // Distances of each sensor to its closest intersecting edge of all filtered enemies // (If sensor does not intersect an enemy edge, sensor's distance = 0) @@ -115,7 +115,7 @@ fn compute_sensors(vehicle: Vehicle, mut enemies: Array) -> Sensors { Sensors { rays: TensorTrait::new(shape.span(), sensors.span(), extra) } } -fn filter_positions(vehicle: Vehicle, mut positions: Array) -> Array { +fn filter_positions(vehicle: Vehicle, mut positions: Span) -> Array { // Will hold near position values let mut near = ArrayTrait::new(); @@ -130,10 +130,10 @@ fn filter_positions(vehicle: Vehicle, mut positions: Array) -> Array

{ - if (FixedTrait::new(position.x, false) - vehicle.position.x).abs() <= filter_dist_x - && (FixedTrait::new(position.y, false) - vehicle.position.y) + if (FixedTrait::new(*position.x, false) - vehicle.position.x).abs() <= filter_dist_x + && (FixedTrait::new(*position.y, false) - vehicle.position.y) .abs() <= filter_dist_y { - near.append(position); + near.append(*position); } }, Option::None(_) => { @@ -286,7 +286,7 @@ fn collision_check(vehicle: Vehicle, mut enemies: Array) { /// Enemy collision check // Get array of only near enemies positions - let mut filtered_enemies = filter_positions(vehicle, enemies); + let mut filtered_enemies = filter_positions(vehicle, enemies.span()); // For each vehicle edge... let mut vehicle_edge_idx: usize = 0; @@ -473,22 +473,14 @@ mod tests { #[test] #[available_gas(20000000)] fn test_filter_positions() { - let vehicle_1 = Vehicle { - position: Vec2Trait::new( - FixedTrait::new(HUNDRED, false), FixedTrait::new(TWO_HUNDRED, false) - ), - steer: FixedTrait::new(0, false), - speed: FixedTrait::new(0, false) - }; - - // Spawn enemies, spaced evenly horizontally, a little ahead of vehicle + // Spawn enemies, spaced evenly horizontally, a little ahead of vehicles at y = TWO_HUNDRED // Use scaled u128 for Position let enemies_nb = 4_u128; // position.x of first enemy (center), so left edge is `CAR_WIDTH` (half-width) from left wall let enemy_min_dist_from_wall = 2 * CAR_WIDTH; let enemy_horiz_spacing = (GRID_WIDTH - 2 * enemy_min_dist_from_wall) / (enemies_nb - 1); - let mut enemies_1 = ArrayTrait::::new(); + let mut enemies = ArrayTrait::::new(); let mut i = 0_u128; loop { if i == enemies_nb { @@ -496,12 +488,22 @@ mod tests { } let x = enemy_min_dist_from_wall + i * enemy_horiz_spacing; let y = THREE_HUNDRED; - enemies_1.append(Position { x: x, y: y }); + enemies.append(Position { x: x, y: y }); i += 1; }; - // values calculated in spreadsheet "drive_ai tests" - let filtered_enemies_1 = filter_positions(vehicle_1, enemies_1); + // Vehicle 1 + let vehicle_1 = Vehicle { + position: Vec2Trait::new( + FixedTrait::new(HUNDRED, false), FixedTrait::new(TWO_HUNDRED, false) + ), + steer: FixedTrait::new(0, false), + speed: FixedTrait::new(0, false) + }; + + let filtered_enemies_1 = filter_positions(vehicle_1, enemies.span()); + + // Values calculated in spreadsheet "drive_ai tests" assert(filtered_enemies_1.len() == 3_usize, 'invalid filtered_enemies_1'); assert_precise_u128( *(filtered_enemies_1.at(0).x), @@ -540,6 +542,7 @@ mod tests { Option::None(()) ); + // Vehicle 2 let vehicle_2 = Vehicle { position: Vec2Trait::new( FixedTrait::new(THREE_FIFTY, false), FixedTrait::new(TWO_HUNDRED, false) @@ -548,20 +551,7 @@ mod tests { speed: FixedTrait::new(0, false) }; - // Could not figure out how to reuse enemies_1 here, not copyable - let mut enemies_2 = ArrayTrait::::new(); - i = 0_u128; - loop { - if i == enemies_nb { - break (); - } - let x = enemy_min_dist_from_wall + i * enemy_horiz_spacing; - let y = THREE_HUNDRED; - enemies_2.append(Position { x: x, y: y }); - i += 1; - }; - - let filtered_enemies_2 = filter_positions(vehicle_2, enemies_2); + let filtered_enemies_2 = filter_positions(vehicle_2, enemies.span()); assert(filtered_enemies_2.len() == 2_usize, 'invalid filtered_enemies_2'); assert_precise_u128( *(filtered_enemies_2.at(0).x), @@ -592,25 +582,14 @@ mod tests { #[test] #[available_gas(200000000)] // Made gas 10x fn test_closest_position() { - // Vehicle 1 - let vehicle_1 = Vehicle { - position: Vec2Trait::new( - FixedTrait::new(HUNDRED, false), FixedTrait::new(TWO_HUNDRED, false) - ), - steer: FixedTrait::new(0, false), - speed: FixedTrait::new(0, false) - }; - - let ray_segments_1 = RaysTrait::new(vehicle_1.position, vehicle_1.steer).segments; - - // Spawn enemies, spaced evenly horizontally, a little ahead of vehicle + // Spawn enemies, spaced evenly horizontally, a little ahead of vehicles at y = TWO_HUNDRED // Use scaled u128 for Position let enemies_nb = 4_u128; // position.x of first enemy (center), so left edge is `CAR_WIDTH` (half-width) from left wall let enemy_min_dist_from_wall = 2 * CAR_WIDTH; let enemy_horiz_spacing = (GRID_WIDTH - 2 * enemy_min_dist_from_wall) / (enemies_nb - 1); - let mut enemies_1 = ArrayTrait::::new(); + let mut enemies = ArrayTrait::::new(); let mut i = 0_u128; loop { if i == enemies_nb { @@ -618,11 +597,22 @@ mod tests { } let x = enemy_min_dist_from_wall + i * enemy_horiz_spacing; let y = THREE_HUNDRED; - enemies_1.append(Position { x: x, y: y }); + enemies.append(Position { x: x, y: y }); i += 1; }; - let filtered_enemies_1 = filter_positions(vehicle_1, enemies_1); + // Vehicle 1 + let vehicle_1 = Vehicle { + position: Vec2Trait::new( + FixedTrait::new(HUNDRED, false), FixedTrait::new(TWO_HUNDRED, false) + ), + steer: FixedTrait::new(0, false), + speed: FixedTrait::new(0, false) + }; + + let ray_segments_1 = RaysTrait::new(vehicle_1.position, vehicle_1.steer).segments; + + let filtered_enemies_1 = filter_positions(vehicle_1, enemies.span()); let mut enemy_sensors_1 = ArrayTrait::::new(); let mut ray_idx = 0; @@ -636,6 +626,7 @@ mod tests { ray_idx += 1; }; + // Values calculated in spreadsheet "drive_ai tests" // Asserted values need to be updated if/when NUM_RAYS = 5 is changed to new value assert(enemy_sensors_1.len() == NUM_RAYS, 'invalid enemy_sensors_1'); @@ -671,20 +662,7 @@ mod tests { let ray_segments_2 = RaysTrait::new(vehicle_2.position, vehicle_2.steer).segments; - // Could not figure out how to reuse enemies_1 here, not copyable - let mut enemies_2 = ArrayTrait::::new(); - i = 0_u128; - loop { - if i == enemies_nb { - break (); - } - let x = enemy_min_dist_from_wall + i * enemy_horiz_spacing; - let y = THREE_HUNDRED; - enemies_2.append(Position { x: x, y: y }); - i += 1; - }; - - let filtered_enemies_2 = filter_positions(vehicle_2, enemies_2); + let filtered_enemies_2 = filter_positions(vehicle_2, enemies.span()); let mut enemy_sensors_2 = ArrayTrait::::new(); ray_idx = 0; From 1437c183ba27d9daafd17c6fb07f240c50c9e060 Mon Sep 17 00:00:00 2001 From: "whatthedev.eth" Date: Mon, 24 Jul 2023 19:04:38 -0700 Subject: [PATCH 09/14] optimize , add --- src/math.cairo | 4 +- src/racer.cairo | 206 +++++++++++++++++++++++++++++++++--------------- src/rays.cairo | 14 ++-- 3 files changed, 153 insertions(+), 71 deletions(-) diff --git a/src/math.cairo b/src/math.cairo index 32b3b33..11e0b5b 100644 --- a/src/math.cairo +++ b/src/math.cairo @@ -89,14 +89,14 @@ fn orientation(a: Vec2, b: Vec2, c: Vec2) -> u8 { // Finds distance from p1 to intersection of segments p1q1 and p2q2 fn distance(p1: Vec2, p2: Vec2, q2: Vec2, cos_ray: Fixed, sin_ray: Fixed) -> Fixed { - // All enemy edges are either vertical or horizontal + // All enemy edges are either vertical or horizontal; all walls are vertical if p2.y == q2.y { // Enemy edge is horizontal if p2.y == p1.y { // Ray is colinear with enemy edge return min((p2.x - p1.x).abs(), (q2.x - p1.x).abs()); } else { return ((p2.y - p1.y) / cos_ray).abs(); } - } else { // Enemy edge is vertical + } else { // Enemy edge or wall is vertical if p2.x == p1.x { // Ray is colinear with enemy edge return min((p2.y - p1.y).abs(), (q2.y - p1.y).abs()); } else { diff --git a/src/racer.cairo b/src/racer.cairo index c65f557..b9e7796 100644 --- a/src/racer.cairo +++ b/src/racer.cairo @@ -45,26 +45,26 @@ fn compute_sensors(vehicle: Vehicle, mut enemies: Array) -> Sensors { // All sensors (ray segments) for this vehicle let ray_segments = RaysTrait::new(vehicle.position, vehicle.steer).segments; - // let filter_dist = FixedTrait::new(CAR_WIDTH + RAY_LENGTH, false); // Is this used here? - - // Distances of each sensor to wall, if wall is near + // Distances along each sensor ray to near wall + // If ray does not intersect wall, sensor's distance is 0 + // If no near wall, array is empty let mut wall_sensors = match near_wall(vehicle) { Wall::None(()) => { ArrayTrait::::new() }, Wall::Left(()) => { - distances_to_wall(vehicle, Wall::Left(()), ray_segments) + distances_to_wall(Wall::Left(()), ray_segments) }, Wall::Right(()) => { - distances_to_wall(vehicle, Wall::Right(()), ray_segments) + distances_to_wall(Wall::Right(()), ray_segments) }, }; // Positions of only filtered (near) enemies let filtered_enemies = filter_positions(vehicle, enemies.span()); - // Distances of each sensor to its closest intersecting edge of all filtered enemies - // (If sensor does not intersect an enemy edge, sensor's distance = 0) + // Distances along each sensor ray to nearest intersection of ray w/edge of filtered enemy + // If sensor does not intersect an enemy edge, sensor's distance = 0 let mut enemy_sensors = ArrayTrait::::new(); let mut ray_idx = 0; loop { @@ -203,39 +203,60 @@ fn near_wall(vehicle: Vehicle) -> Wall { return Wall::None(()); } -fn distances_to_wall(vehicle: Vehicle, near_wall: Wall, mut rays: Span) -> Array { +// Distances along each sensor ray to near wall +// If ray does not intersect wall, sensor's distance is 0 +// If no near wall, array is empty +fn distances_to_wall(near_wall: Wall, mut rays: Span) -> Array { let mut sensors = ArrayTrait::::new(); - let ray_length = FixedTrait::new(RAY_LENGTH, false); - - let wall_position_x = match near_wall { + match near_wall { Wall::None(()) => { return sensors; }, - Wall::Left(()) => FixedTrait::new(0, false), - Wall::Right(()) => FixedTrait::new(GRID_WIDTH, false), - }; - - let p2 = Vec2 { x: wall_position_x, y: FixedTrait::new(0, false) }; - let q2 = Vec2 { x: wall_position_x, y: FixedTrait::new(GRID_HEIGHT, false) }; - - // TODO: We can exit early on some conditions here, since, for example, if the left most ray math::intersects, the right most can't - loop { - match rays.pop_front() { - Option::Some(ray) => { - // Endpoints of Ray - if ray.intersects(p2, q2) { - sensors.append(ray.dist(p2, q2)); - } else { - sensors.append(FixedTrait::new(0, false)); - } - }, - Option::None(_) => { - break (); - } - }; + Wall::Left(()) => { + // Wall endpoints + let p2 = Vec2 { x: FixedTrait::new(0, false), y: FixedTrait::new(0, false) }; + let q2 = Vec2 { x: FixedTrait::new(0, false), y: FixedTrait::new(GRID_HEIGHT, false) }; + loop { + match rays.pop_front() { + Option::Some(ray) => { + // If ray.q.x is negative or zero, ray intersects with Left wall + // Cheaper than ray.intersects(p2, q2)? + if *(ray.q.x.sign) || *(ray.q.x.mag) == 0_u128 { + sensors.append(ray.dist(p2, q2)); + } else { + sensors.append(FixedTrait::new(0, false)); + } + }, + Option::None(_) => { + break (); + } + }; + }; + }, + Wall::Right(()) => { + // Wall endpoints + let p2 = Vec2 { x: FixedTrait::new(GRID_WIDTH, false), y: FixedTrait::new(0, false) }; + let q2 = Vec2 { + x: FixedTrait::new(GRID_WIDTH, false), y: FixedTrait::new(GRID_HEIGHT, false) + }; + loop { + match rays.pop_front() { + Option::Some(ray) => { + // If ray.q.x is >= GRID_WIDTH, ray intersects with Right wall + if !*(ray.q.x.sign) && *(ray.q.x.mag) >= GRID_WIDTH { + sensors.append(ray.dist(p2, q2)); + } else { + sensors.append(FixedTrait::new(0, false)); + } + }, + Option::None(_) => { + break (); + } + }; + }; + }, }; - sensors } @@ -441,7 +462,7 @@ mod tests { use cubit::math::trig; use cubit::test::helpers::assert_precise; use drive_ai::vehicle::{Vehicle, VehicleTrait}; - use drive_ai::rays::{Rays, RaysTrait, Ray, RayTrait, NUM_RAYS, RAY_LENGTH}; + use drive_ai::rays::{Rays, RaysTrait, Ray, RayTrait, RAY_LENGTH}; use drive_ai::enemy::{Position, PositionTrait}; use drive_ai::math::assert_precise_u128; use super::{ @@ -450,6 +471,7 @@ mod tests { }; use super::{GRID_HEIGHT, GRID_WIDTH, CAR_HEIGHT, CAR_WIDTH}; + const NUM_RAYS: usize = 5; // Asserted values below are only for NUM_RAYS = 5 const TWO: u128 = 36893488147419103232; const TEN: u128 = 184467440737095516160; const FIFTY: u128 = 922337203685477580800; @@ -461,14 +483,7 @@ mod tests { #[test] #[available_gas(20000000)] - fn test_compute_sensors() { // let vehicle = Vehicle { - // position: Vec2Trait::new( - // FixedTrait::new(CAR_WIDTH, false), FixedTrait::new(TEN, false) - // ), - // steer: FixedTrait::new(0, false), - // speed: FixedTrait::new(0, false) - // }; - } + fn test_compute_sensors() {} #[test] #[available_gas(20000000)] @@ -628,7 +643,7 @@ mod tests { }; // Values calculated in spreadsheet "drive_ai tests" - // Asserted values need to be updated if/when NUM_RAYS = 5 is changed to new value + // Asserted values below are only for NUM_RAYS = 5 assert(enemy_sensors_1.len() == NUM_RAYS, 'invalid enemy_sensors_1'); assert_precise( *(enemy_sensors_1.at(0)), @@ -724,27 +739,92 @@ mod tests { assert(right_wall == Wall::Right(()), 'invalid near right wall'); } - // TODO #[test] #[available_gas(20000000)] - fn test_distances_to_wall() { // - // All sensors (ray segments) for this vehicle - // let ray_segments = RaysTrait::new(vehicle.position, vehicle.steer).segments; - - // let filter_dist = FixedTrait::new(CAR_WIDTH + RAY_LENGTH, false); // Is this used? - - // // Distances of each sensor to wall, if wall is near - // let mut wall_sensors = match near_wall(vehicle) { - // Wall::None(()) => { - // ArrayTrait::::new() - // }, - // Wall::Left(()) => { - // distances_to_wall(vehicle, Wall::Left(()), ray_segments) - // }, - // Wall::Right(()) => { - // distances_to_wall(vehicle, Wall::Right(()), ray_segments) - // }, - // }; + fn test_distances_to_wall() { + // Vehicle 1 to test Wall::Left(()) + let vehicle_1 = Vehicle { + position: Vec2Trait::new( + FixedTrait::new(HUNDRED, false), FixedTrait::new(TWO_HUNDRED, false) + ), + steer: FixedTrait::new(0, false), + speed: FixedTrait::new(0, false) + }; + let near_wall_1 = near_wall(vehicle_1); + assert(near_wall_1 == Wall::Left(()), 'invalid near_wall_1'); + + let ray_segments_1 = RaysTrait::new(vehicle_1.position, vehicle_1.steer).segments; + let distances_to_wall_1 = distances_to_wall(near_wall_1, ray_segments_1); + + // Values calculated in spreadsheet "drive_ai tests" + // Asserted values below are only for NUM_RAYS = 5 + // Vehicle 1 only ray 0 intersects with Left wall + assert(distances_to_wall_1.len() == NUM_RAYS, 'invalid distances_to_wall_1'); + assert_precise( + *(distances_to_wall_1.at(0)), + 2408051417826740000000, + 'invalid v1 dist to wall ray 0', + Option::Some(184467440737095000) // 1e-02 + ); + assert(*(distances_to_wall_1.at(1).mag) == 0, 'invalid v1 dist to wall ray 1'); + assert(*(distances_to_wall_1.at(2).mag) == 0, 'invalid v1 dist to wall ray 2'); + assert(*(distances_to_wall_1.at(3).mag) == 0, 'invalid v1 dist to wall ray 3'); + assert(*(distances_to_wall_1.at(4).mag) == 0, 'invalid v1 dist to wall ray 4'); + + // Vehicle 2 to test Wall::Right(()) + let vehicle_2 = Vehicle { + position: Vec2Trait::new( + FixedTrait::new(THREE_FIFTY, false), FixedTrait::new(TWO_HUNDRED, false) + ), + steer: FixedTrait::new(DEG_25_IN_RADS, false), + speed: FixedTrait::new(0, false) + }; + + let near_wall_2 = near_wall(vehicle_2); + assert(near_wall_2 == Wall::Right(()), 'invalid near_wall_2'); + + let ray_segments_2 = RaysTrait::new(vehicle_2.position, vehicle_2.steer).segments; + let distances_to_wall_2 = distances_to_wall(near_wall_2, ray_segments_2); + + // Vehicle 2 rays 2,3,4 each intersect with Right wall + assert(distances_to_wall_2.len() == NUM_RAYS, 'invalid distances_to_wall_2'); + assert(*(distances_to_wall_2.at(0).mag) == 0, 'invalid v2 dist to wall ray 0'); + assert(*(distances_to_wall_2.at(1).mag) == 0, 'invalid v2 dist to wall ray 1'); + assert_precise( + *(distances_to_wall_2.at(2)), + 2182435751561020000000, + 'invalid v2 dist to wall ray 2', + Option::Some(184467440737095000) // 1e-02 + ); + assert_precise( + *(distances_to_wall_2.at(3)), + 1125965820528530000000, + 'invalid v2 dist to wall ray 3', + Option::Some(184467440737095000) // 1e-02 + ); + assert_precise( + *(distances_to_wall_2.at(4)), + 954873737281615000000, + 'invalid v2 dist to wall ray 4', + Option::Some(184467440737095000) // 1e-02 + ); + + // Vehicle 3 to test Wall::None(()) + let vehicle_3 = Vehicle { + position: Vec2Trait::new( + FixedTrait::new(TWO_HUNDRED, false), FixedTrait::new(TWO_HUNDRED, false) + ), + steer: FixedTrait::new(0, false), + speed: FixedTrait::new(0, false) + }; + + let near_wall_3 = near_wall(vehicle_3); + assert(near_wall_3 == Wall::None(()), 'invalid near_wall_3'); + + let ray_segments_3 = RaysTrait::new(vehicle_3.position, vehicle_3.steer).segments; + let distances_to_wall_3 = distances_to_wall(near_wall_3, ray_segments_3); + + assert(distances_to_wall_3.len() == 0, 'invalid distances_to_wall_3'); } // TODO diff --git a/src/rays.cairo b/src/rays.cairo index ef6d028..fe49dd5 100644 --- a/src/rays.cairo +++ b/src/rays.cairo @@ -103,8 +103,9 @@ mod tests { collision_check, Wall }; use drive_ai::racer::{GRID_HEIGHT, GRID_WIDTH, CAR_HEIGHT, CAR_WIDTH}; - use super::{Rays, RaysTrait, Ray, RayTrait, NUM_RAYS, RAY_LENGTH}; + use super::{Rays, RaysTrait, Ray, RayTrait, RAY_LENGTH}; + const NUM_RAYS: usize = 5; // Asserted values below are only for NUM_RAYS = 5 const TWO: u128 = 36893488147419103232; const FOUR: u128 = 73786976294838206464; const TEN: u128 = 184467440737095516160; @@ -129,8 +130,8 @@ mod tests { let ray_segments_1 = RaysTrait::new(vehicle_1.position, vehicle_1.steer).segments; assert(ray_segments_1.len() == NUM_RAYS, 'invalid ray_segments_1'); - // values calculated in spreadsheet "drive_ai tests" - // Asserted values need to be updated if/when NUM_RAYS = 5 is changed to new value + // Values calculated in spreadsheet "drive_ai tests" + // Asserted values below are only for NUM_RAYS = 5 // ray_segments_1.at(0) assert_precise( *(ray_segments_1.at(0).theta), @@ -539,7 +540,7 @@ mod tests { #[available_gas(20000000)] fn test_raytrait_dist() { // From vehicle 1 above, rays 0, 1, & 3 intersect enemy edges - // Ray 0 + // Vehicle 1 ray 0 let ray_10 = Ray { theta: FixedTrait::new(16097821017949100000, true), cos_theta: FixedTrait::new(11857338529639100000, false), @@ -588,7 +589,7 @@ mod tests { Option::None(()) ); - // Ray 1 + // Vehicle 1 ray 1 let ray_11 = Ray { theta: FixedTrait::new(9658692610769470000, true), cos_theta: FixedTrait::new(15975348984942500000, false), @@ -621,7 +622,7 @@ mod tests { Option::None(()) ); - // Ray 3 + // Vehicle 1 ray 3 let ray_13 = Ray { theta: FixedTrait::new(9658692610769470000, false), cos_theta: FixedTrait::new(15975348984942500000, false), @@ -672,6 +673,7 @@ mod tests { ); // From vehicle 2 above, only ray 2 intersects enemy edges + // Vehicle 2 ray 2 let ray_22 = Ray { theta: FixedTrait::new(8048910508974560000, false), cos_theta: FixedTrait::new(16718427799475100000, false), From 307cd378fad8b6c265be90befd1431b2857b2775 Mon Sep 17 00:00:00 2001 From: "whatthedev.eth" Date: Mon, 24 Jul 2023 19:53:52 -0700 Subject: [PATCH 10/14] cleanup some imports --- src/rays.cairo | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/rays.cairo b/src/rays.cairo index fe49dd5..e3a7ee9 100644 --- a/src/rays.cairo +++ b/src/rays.cairo @@ -98,11 +98,6 @@ mod tests { use cubit::test::helpers::assert_precise; use drive_ai::vehicle::{Vehicle, VehicleTrait}; use drive_ai::enemy::{Position, PositionTrait}; - use drive_ai::racer::{ - compute_sensors, filter_positions, closest_position, near_wall, distances_to_wall, - collision_check, Wall - }; - use drive_ai::racer::{GRID_HEIGHT, GRID_WIDTH, CAR_HEIGHT, CAR_WIDTH}; use super::{Rays, RaysTrait, Ray, RayTrait, RAY_LENGTH}; const NUM_RAYS: usize = 5; // Asserted values below are only for NUM_RAYS = 5 From a96378cce0a1f1fae2bb33a6b147428c3374e60b Mon Sep 17 00:00:00 2001 From: "whatthedev.eth" Date: Tue, 25 Jul 2023 01:41:14 -0700 Subject: [PATCH 11/14] fix compute_sensors, add test_compute_sensors --- src/math.cairo | 55 ++++----- src/racer.cairo | 312 +++++++++++++++++++++++++++--------------------- 2 files changed, 205 insertions(+), 162 deletions(-) diff --git a/src/math.cairo b/src/math.cairo index 11e0b5b..6561245 100644 --- a/src/math.cairo +++ b/src/math.cairo @@ -105,9 +105,9 @@ fn distance(p1: Vec2, p2: Vec2, q2: Vec2, cos_ray: Fixed, sin_ray: Fixed) -> Fix } } -// similar to assert_precise which works for Fixed type only use debug::PrintTrait; const DEFAULT_PRECISION: u128 = 1844674407370; // 1e-7 +// Similar to cubit's assert_precise which works for Fixed type only, but here for u128 // To use `DEFAULT_PRECISION`, final arg is: `Option::None(())`. // To use `custom_precision` of 184467440737_u128: `Option::Some(184467440737_u128)`. fn assert_precise_u128(result: u128, expected: u128, msg: felt252, custom_precision: Option) { @@ -116,14 +116,18 @@ fn assert_precise_u128(result: u128, expected: u128, msg: felt252, custom_precis Option::None(_) => DEFAULT_PRECISION, }; - let mut diff = result - expected; if result < expected { - diff = expected - result; - } - - if (diff > precision) { - result.print(); - assert(diff <= precision, msg); + let diff = expected - result; + if (diff > precision) { + result.print(); + assert(diff <= precision, msg); + } + } else { + let diff = result - expected; + if (diff > precision) { + result.print(); + assert(diff <= precision, msg); + } } } @@ -184,17 +188,17 @@ mod tests { let mut vertices = vertices(position, width, height, theta); - assert_precise(*(vertices.at(0).x), TWENTY.into(), 'invalid vertex_0', Option::None(())); - assert_precise(*(vertices.at(0).y), FORTY.into(), 'invalid vertex_0', Option::None(())); + assert_precise(*vertices.at(0).x, TWENTY.into(), 'invalid vertex_0', Option::None(())); + assert_precise(*vertices.at(0).y, FORTY.into(), 'invalid vertex_0', Option::None(())); - assert_precise(*(vertices.at(1).x), 0, 'invalid vertex_1', Option::None(())); - assert_precise(*(vertices.at(1).y), FORTY.into(), 'invalid vertex_1', Option::None(())); + assert_precise(*vertices.at(1).x, 0, 'invalid vertex_1', Option::None(())); + assert_precise(*vertices.at(1).y, FORTY.into(), 'invalid vertex_1', Option::None(())); - assert_precise(*(vertices.at(2).x), 0, 'invalid vertex_2', Option::None(())); - assert_precise(*(vertices.at(2).y), 0, 'invalid vertex_2', Option::None(())); + assert_precise(*vertices.at(2).x, 0, 'invalid vertex_2', Option::None(())); + assert_precise(*vertices.at(2).y, 0, 'invalid vertex_2', Option::None(())); - assert_precise(*(vertices.at(3).x), TWENTY.into(), 'invalid vertex_3', Option::None(())); - assert_precise(*(vertices.at(3).y), 0, 'invalid vertex_3', Option::None(())); + assert_precise(*vertices.at(3).x, TWENTY.into(), 'invalid vertex_3', Option::None(())); + assert_precise(*vertices.at(3).y, 0, 'invalid vertex_3', Option::None(())); let position = Vec2Trait::new(FixedTrait::new(TEN, false), FixedTrait::new(TWENTY, false)); let width = FixedTrait::new(TEN, false); @@ -205,37 +209,34 @@ mod tests { // x: ~8.66025403784439, y: ~42.32050807568880 assert_precise( - *(vertices.at(0).x), 159753090305067335160, 'invalid rotated vertex_0', Option::None(()) + *vertices.at(0).x, 159753090305067335160, 'invalid rotated vertex_0', Option::None(()) ); assert_precise( - *(vertices.at(0).y), 780673828410437532220, 'invalid rotated vertex_0', Option::None(()) + *vertices.at(0).y, 780673828410437532220, 'invalid rotated vertex_0', Option::None(()) ); // x: ~-8.66025403784439, y: ~32.32050807568880 assert_precise( - *(vertices.at(1).x), - -159752327071118592360, - 'invalid rotated vertex_1', - Option::None(()) + *vertices.at(1).x, -159752327071118592360, 'invalid rotated vertex_1', Option::None(()) ); assert_precise( - *(vertices.at(1).y), 596206769290316387460, 'invalid rotated vertex_1', Option::None(()) + *vertices.at(1).y, 596206769290316387460, 'invalid rotated vertex_1', Option::None(()) ); // x: ~11.33974596215560, y: ~-2.32050807568877 assert_precise( - *(vertices.at(2).x), 209181791169123697160, 'invalid rotated vertex_2', Option::None(()) + *vertices.at(2).x, 209181791169123697160, 'invalid rotated vertex_2', Option::None(()) ); assert_precise( - *(vertices.at(2).y), -42804065462055467580, 'invalid rotated vertex_2', Option::None(()) + *vertices.at(2).y, -42804065462055467580, 'invalid rotated vertex_2', Option::None(()) ); // x: ~28.66025403784440, y: ~7.67949192431123 assert_precise( - *(vertices.at(3).x), 528687208545309624680, 'invalid rotated vertex_3', Option::None(()) + *vertices.at(3).x, 528687208545309624680, 'invalid rotated vertex_3', Option::None(()) ); assert_precise( - *(vertices.at(3).y), 141662993658065677180, 'invalid rotated vertex_3', Option::None(()) + *vertices.at(3).y, 141662993658065677180, 'invalid rotated vertex_3', Option::None(()) ); } diff --git a/src/racer.cairo b/src/racer.cairo index b9e7796..fb64411 100644 --- a/src/racer.cairo +++ b/src/racer.cairo @@ -41,11 +41,13 @@ const HALF_GRID_WIDTH: u128 = 3689348814741910323200; // 200 const CAR_HEIGHT: u128 = 590295810358705651712; // 32 const CAR_WIDTH: u128 = 295147905179352825856; // 16 +// Shortest distances along each sensor ray to intersection with either near wall or enemy edge +// If ray does not intersect either wall or enemy edge, sensor's distance is 0 fn compute_sensors(vehicle: Vehicle, mut enemies: Array) -> Sensors { // All sensors (ray segments) for this vehicle let ray_segments = RaysTrait::new(vehicle.position, vehicle.steer).segments; - // Distances along each sensor ray to near wall + // Distances along each sensor ray to nearest intersection of ray w/near wall // If ray does not intersect wall, sensor's distance is 0 // If no near wall, array is empty let mut wall_sensors = match near_wall(vehicle) { @@ -77,10 +79,11 @@ fn compute_sensors(vehicle: Vehicle, mut enemies: Array) -> Sensors { ray_idx += 1; }; + // Distances along each sensor ray to nearest intersection of ray w/either wall or edge of enemy let mut sensors = ArrayTrait::::new(); let mut idx = 0; - if wall_sensors.len() > 0 { + if wall_sensors.len() > 0 { // Vehicle near either Left or Right wall loop { if idx == NUM_RAYS { break (); @@ -89,15 +92,20 @@ fn compute_sensors(vehicle: Vehicle, mut enemies: Array) -> Sensors { let wall_sensor = *wall_sensors.at(idx); let enemy_sensor = *enemy_sensors.at(idx); - if wall_sensor < enemy_sensor { + if wall_sensor.mag == 0 { + // Sensor ray does not intersect wall + sensors.append(orion_fp::FixedTrait::new(enemy_sensor.mag, false)); + } else if enemy_sensor.mag == 0 || wall_sensor < enemy_sensor { + // Sensor ray does not intersect an enemy edge OR vehicle closer to wall sensors.append(orion_fp::FixedTrait::new(wall_sensor.mag, false)); } else { + // Vehicle closer to enemy edge sensors.append(orion_fp::FixedTrait::new(enemy_sensor.mag, false)); }; idx += 1; } - } else { + } else { // Vehicle near no wall loop { if idx == NUM_RAYS { break (); @@ -110,7 +118,7 @@ fn compute_sensors(vehicle: Vehicle, mut enemies: Array) -> Sensors { } let mut shape = ArrayTrait::::new(); - shape.append(5); + shape.append(5); // Can this be `shape.append(NUM_RAYS);` ? let extra = Option::::None(()); Sensors { rays: TensorTrait::new(shape.span(), sensors.span(), extra) } } @@ -122,9 +130,9 @@ fn filter_positions(vehicle: Vehicle, mut positions: Span) -> Array) -> Array) -> Fixed { // Set to max possible intersection distance before outer loop let mut closest = FixedTrait::new(RAY_LENGTH, false); @@ -203,7 +211,7 @@ fn near_wall(vehicle: Vehicle) -> Wall { return Wall::None(()); } -// Distances along each sensor ray to near wall +// Distances along each sensor ray to nearest intersection of ray w/near wall // If ray does not intersect wall, sensor's distance is 0 // If no near wall, array is empty fn distances_to_wall(near_wall: Wall, mut rays: Span) -> Array { @@ -222,7 +230,7 @@ fn distances_to_wall(near_wall: Wall, mut rays: Span) -> Array { Option::Some(ray) => { // If ray.q.x is negative or zero, ray intersects with Left wall // Cheaper than ray.intersects(p2, q2)? - if *(ray.q.x.sign) || *(ray.q.x.mag) == 0_u128 { + if *ray.q.x.sign || *ray.q.x.mag == 0_u128 { sensors.append(ray.dist(p2, q2)); } else { sensors.append(FixedTrait::new(0, false)); @@ -244,7 +252,7 @@ fn distances_to_wall(near_wall: Wall, mut rays: Span) -> Array { match rays.pop_front() { Option::Some(ray) => { // If ray.q.x is >= GRID_WIDTH, ray intersects with Right wall - if !*(ray.q.x.sign) && *(ray.q.x.mag) >= GRID_WIDTH { + if !*ray.q.x.sign && *ray.q.x.mag >= GRID_WIDTH { sensors.append(ray.dist(p2, q2)); } else { sensors.append(FixedTrait::new(0, false)); @@ -471,7 +479,10 @@ mod tests { }; use super::{GRID_HEIGHT, GRID_WIDTH, CAR_HEIGHT, CAR_WIDTH}; - const NUM_RAYS: usize = 5; // Asserted values below are only for NUM_RAYS = 5 + // Set these two values here (instead of import) + const NUM_RAYS: usize = 5; // Many asserted values below are valid only for NUM_RAYS = 5 + const ENEMIES_NB: u128 = 4; // Many asserted values below are valid only for ENEMIES_NB = 4 + const TWO: u128 = 36893488147419103232; const TEN: u128 = 184467440737095516160; const FIFTY: u128 = 922337203685477580800; @@ -482,112 +493,138 @@ mod tests { const DEG_25_IN_RADS: u128 = 8048910508974580935; #[test] - #[available_gas(20000000)] - fn test_compute_sensors() {} + #[available_gas(200000000)] // Made gas 10x + fn test_compute_sensors() { + // Vehicle 1 + let vehicle_1 = vehicle_for_tests(TestVehicle::Vehicle1(())); + let mut enemies_1 = enemies_for_tests(); + let sensors_1 = compute_sensors(vehicle_1, enemies_1); + assert(sensors_1.rays.data.len() == 5, 'invalid sensors_1'); + assert_precise_u128( + *sensors_1.rays.data.at(0).mag, + // Ray 0 intersects enemy 0 edge 2 (before it intersects edge 1, then Left wall) + 1951466671275690000000, + 'invalid sensors_1 ray 0', + Option::Some(184467440737095000) // 1e-02 + ); + assert_precise_u128( + *sensors_1.rays.data.at(1).mag, + 1918461383665790000000, // Ray 1 intersects enemy 0 edge 3 + 'invalid sensors_1 ray 1', + Option::Some(184467440737095000) // 1e-02 + ); + assert(*sensors_1.rays.data.at(2).mag == 0, 'invalid sensors_1 ray 2'); + assert_precise_u128( + *sensors_1.rays.data.at(3).mag, + 1448431641301450000000, // Ray 3 intersects enemy 1 edge 2 + 'invalid sensors_1 ray 3', + Option::Some(184467440737095000) // 1e-02 + ); + assert(*sensors_1.rays.data.at(4).mag == 0, 'invalid sensors_1 ray 4'); + + // Vehicle 2 + let vehicle_2 = vehicle_for_tests(TestVehicle::Vehicle2(())); + let mut enemies_2 = enemies_for_tests(); + let sensors_2 = compute_sensors(vehicle_2, enemies_2); + assert(sensors_2.rays.data.len() == 5, 'invalid sensors_2'); + assert(*sensors_2.rays.data.at(0).mag == 0, 'invalid sensors_2 ray 0'); + assert(*sensors_2.rays.data.at(1).mag == 0, 'invalid sensors_2 ray 1'); + assert_precise_u128( + *sensors_2.rays.data.at(2).mag, + 1384053645962460000000, // Ray 2 intersects enemy 3 edge 2 (before it intersects Right wall) + 'invalid sensors_2 ray 2', + Option::Some(184467440737095000) // 1e-02 + ); + assert_precise_u128( + *sensors_2.rays.data.at(3).mag, + 1125965820528530000000, // Ray 3 intersects Right wall + 'invalid sensors_2 ray 3', + Option::Some(184467440737095000) // 1e-02 + ); + assert_precise_u128( + *sensors_2.rays.data.at(4).mag, + 954873737281615000000, // Ray 4 intersects Right wall + 'invalid sensors_2 ray 4', + Option::Some(184467440737095000) // 1e-02 + ); + } #[test] #[available_gas(20000000)] fn test_filter_positions() { - // Spawn enemies, spaced evenly horizontally, a little ahead of vehicles at y = TWO_HUNDRED - // Use scaled u128 for Position - let enemies_nb = 4_u128; - // position.x of first enemy (center), so left edge is `CAR_WIDTH` (half-width) from left wall - let enemy_min_dist_from_wall = 2 * CAR_WIDTH; - let enemy_horiz_spacing = (GRID_WIDTH - 2 * enemy_min_dist_from_wall) / (enemies_nb - 1); - - let mut enemies = ArrayTrait::::new(); - let mut i = 0_u128; - loop { - if i == enemies_nb { - break (); - } - let x = enemy_min_dist_from_wall + i * enemy_horiz_spacing; - let y = THREE_HUNDRED; - enemies.append(Position { x: x, y: y }); - i += 1; - }; + let mut enemies = enemies_for_tests(); // Vehicle 1 - let vehicle_1 = Vehicle { - position: Vec2Trait::new( - FixedTrait::new(HUNDRED, false), FixedTrait::new(TWO_HUNDRED, false) - ), - steer: FixedTrait::new(0, false), - speed: FixedTrait::new(0, false) - }; + let vehicle_1 = vehicle_for_tests(TestVehicle::Vehicle1(())); let filtered_enemies_1 = filter_positions(vehicle_1, enemies.span()); + // Vehicle 1 is near 3 enemies (0, 1, & 2) // Values calculated in spreadsheet "drive_ai tests" assert(filtered_enemies_1.len() == 3_usize, 'invalid filtered_enemies_1'); assert_precise_u128( - *(filtered_enemies_1.at(0).x), + *filtered_enemies_1.at(0).x, 590295810358704000000, 'invalid filtered_enemies_1 0 x', Option::None(()) ); assert_precise_u128( - *(filtered_enemies_1.at(0).y), + *filtered_enemies_1.at(0).y, 5534023222112850000000, 'invalid filtered_enemies_1 0 y', Option::None(()) ); assert_precise_u128( - *(filtered_enemies_1.at(1).x), + *filtered_enemies_1.at(1).x, 2656331146614170000000, 'invalid filtered_enemies_1 1 x', Option::None(()) ); assert_precise_u128( - *(filtered_enemies_1.at(1).y), + *filtered_enemies_1.at(1).y, 5534023222112850000000, 'invalid filtered_enemies_1 1 y', Option::None(()) ); assert_precise_u128( - *(filtered_enemies_1.at(2).x), + *filtered_enemies_1.at(2).x, 4722366482869630000000, 'invalid filtered_enemies_1 2 x', Option::None(()) ); assert_precise_u128( - *(filtered_enemies_1.at(2).y), + *filtered_enemies_1.at(2).y, 5534023222112850000000, 'invalid filtered_enemies_1 2 y', Option::None(()) ); // Vehicle 2 - let vehicle_2 = Vehicle { - position: Vec2Trait::new( - FixedTrait::new(THREE_FIFTY, false), FixedTrait::new(TWO_HUNDRED, false) - ), - steer: FixedTrait::new(DEG_25_IN_RADS, false), - speed: FixedTrait::new(0, false) - }; + let vehicle_2 = vehicle_for_tests(TestVehicle::Vehicle2(())); + // Vehicle 2 is near 2 enemies (2 & 3) let filtered_enemies_2 = filter_positions(vehicle_2, enemies.span()); assert(filtered_enemies_2.len() == 2_usize, 'invalid filtered_enemies_2'); assert_precise_u128( - *(filtered_enemies_2.at(0).x), + *filtered_enemies_2.at(0).x, 4722366482869630000000, 'invalid filtered_enemies_2 0 x', Option::None(()) ); assert_precise_u128( - *(filtered_enemies_2.at(0).y), + *filtered_enemies_2.at(0).y, 5534023222112850000000, 'invalid filtered_enemies_2 0 y', Option::None(()) ); assert_precise_u128( - *(filtered_enemies_2.at(1).x), + *filtered_enemies_2.at(1).x, 6788401819125100000000, 'invalid filtered_enemies_2 1 x', Option::None(()) ); assert_precise_u128( - *(filtered_enemies_2.at(1).y), + *filtered_enemies_2.at(1).y, 5534023222112850000000, 'invalid filtered_enemies_2 1 y', Option::None(()) @@ -595,38 +632,13 @@ mod tests { } #[test] - #[available_gas(200000000)] // Made gas 10x + #[available_gas(200000000)] // Made gas 10x fn test_closest_position() { - // Spawn enemies, spaced evenly horizontally, a little ahead of vehicles at y = TWO_HUNDRED - // Use scaled u128 for Position - let enemies_nb = 4_u128; - // position.x of first enemy (center), so left edge is `CAR_WIDTH` (half-width) from left wall - let enemy_min_dist_from_wall = 2 * CAR_WIDTH; - let enemy_horiz_spacing = (GRID_WIDTH - 2 * enemy_min_dist_from_wall) / (enemies_nb - 1); - - let mut enemies = ArrayTrait::::new(); - let mut i = 0_u128; - loop { - if i == enemies_nb { - break (); - } - let x = enemy_min_dist_from_wall + i * enemy_horiz_spacing; - let y = THREE_HUNDRED; - enemies.append(Position { x: x, y: y }); - i += 1; - }; + let mut enemies = enemies_for_tests(); // Vehicle 1 - let vehicle_1 = Vehicle { - position: Vec2Trait::new( - FixedTrait::new(HUNDRED, false), FixedTrait::new(TWO_HUNDRED, false) - ), - steer: FixedTrait::new(0, false), - speed: FixedTrait::new(0, false) - }; - + let vehicle_1 = vehicle_for_tests(TestVehicle::Vehicle1(())); let ray_segments_1 = RaysTrait::new(vehicle_1.position, vehicle_1.steer).segments; - let filtered_enemies_1 = filter_positions(vehicle_1, enemies.span()); let mut enemy_sensors_1 = ArrayTrait::::new(); @@ -646,37 +658,29 @@ mod tests { // Asserted values below are only for NUM_RAYS = 5 assert(enemy_sensors_1.len() == NUM_RAYS, 'invalid enemy_sensors_1'); assert_precise( - *(enemy_sensors_1.at(0)), + *enemy_sensors_1.at(0), 1951466671275690000000, 'invalid v1 closest pos ray 0', Option::Some(184467440737095000) // 1e-02 ); assert_precise( - *(enemy_sensors_1.at(1)), + *enemy_sensors_1.at(1), 1918461383665790000000, 'invalid v1 closest pos ray 1', Option::Some(184467440737095000) // 1e-02 ); - assert(*(enemy_sensors_1.at(2).mag) == 0, 'invalid v1 closest pos ray 2'); + assert(*enemy_sensors_1.at(2).mag == 0, 'invalid v1 closest pos ray 2'); assert_precise( - *(enemy_sensors_1.at(3)), + *enemy_sensors_1.at(3), 1448431641301450000000, 'invalid v1 closest pos ray 3', Option::Some(184467440737095000) // 1e-02 ); - assert(*(enemy_sensors_1.at(4).mag) == 0, 'invalid v1 closest pos ray 4'); + assert(*enemy_sensors_1.at(4).mag == 0, 'invalid v1 closest pos ray 4'); // Vehicle 2 - let vehicle_2 = Vehicle { - position: Vec2Trait::new( - FixedTrait::new(THREE_FIFTY, false), FixedTrait::new(TWO_HUNDRED, false) - ), - steer: FixedTrait::new(DEG_25_IN_RADS, false), - speed: FixedTrait::new(0, false) - }; - + let vehicle_2 = vehicle_for_tests(TestVehicle::Vehicle2(())); let ray_segments_2 = RaysTrait::new(vehicle_2.position, vehicle_2.steer).segments; - let filtered_enemies_2 = filter_positions(vehicle_2, enemies.span()); let mut enemy_sensors_2 = ArrayTrait::::new(); @@ -692,16 +696,16 @@ mod tests { ray_idx += 1; }; assert(enemy_sensors_2.len() == NUM_RAYS, 'invalid enemy_sensors_2'); - assert(*(enemy_sensors_2.at(0).mag) == 0, 'invalid v2 closest pos ray 0'); - assert(*(enemy_sensors_2.at(1).mag) == 0, 'invalid v2 closest pos ray 1'); + assert(*enemy_sensors_2.at(0).mag == 0, 'invalid v2 closest pos ray 0'); + assert(*enemy_sensors_2.at(1).mag == 0, 'invalid v2 closest pos ray 1'); assert_precise( - *(enemy_sensors_2.at(2)), + *enemy_sensors_2.at(2), 1384053645962460000000, 'invalid v2 closest pos ray 2', Option::Some(184467440737095000) // 1e-02 ); - assert(*(enemy_sensors_2.at(3).mag) == 0, 'invalid v2 closest pos ray 3'); - assert(*(enemy_sensors_2.at(4).mag) == 0, 'invalid v2 closest pos ray 4'); + assert(*enemy_sensors_2.at(3).mag == 0, 'invalid v2 closest pos ray 3'); + assert(*enemy_sensors_2.at(4).mag == 0, 'invalid v2 closest pos ray 4'); } #[test] @@ -743,13 +747,7 @@ mod tests { #[available_gas(20000000)] fn test_distances_to_wall() { // Vehicle 1 to test Wall::Left(()) - let vehicle_1 = Vehicle { - position: Vec2Trait::new( - FixedTrait::new(HUNDRED, false), FixedTrait::new(TWO_HUNDRED, false) - ), - steer: FixedTrait::new(0, false), - speed: FixedTrait::new(0, false) - }; + let vehicle_1 = vehicle_for_tests(TestVehicle::Vehicle1(())); let near_wall_1 = near_wall(vehicle_1); assert(near_wall_1 == Wall::Left(()), 'invalid near_wall_1'); @@ -761,24 +759,18 @@ mod tests { // Vehicle 1 only ray 0 intersects with Left wall assert(distances_to_wall_1.len() == NUM_RAYS, 'invalid distances_to_wall_1'); assert_precise( - *(distances_to_wall_1.at(0)), + *distances_to_wall_1.at(0), 2408051417826740000000, 'invalid v1 dist to wall ray 0', Option::Some(184467440737095000) // 1e-02 ); - assert(*(distances_to_wall_1.at(1).mag) == 0, 'invalid v1 dist to wall ray 1'); - assert(*(distances_to_wall_1.at(2).mag) == 0, 'invalid v1 dist to wall ray 2'); - assert(*(distances_to_wall_1.at(3).mag) == 0, 'invalid v1 dist to wall ray 3'); - assert(*(distances_to_wall_1.at(4).mag) == 0, 'invalid v1 dist to wall ray 4'); + assert(*distances_to_wall_1.at(1).mag == 0, 'invalid v1 dist to wall ray 1'); + assert(*distances_to_wall_1.at(2).mag == 0, 'invalid v1 dist to wall ray 2'); + assert(*distances_to_wall_1.at(3).mag == 0, 'invalid v1 dist to wall ray 3'); + assert(*distances_to_wall_1.at(4).mag == 0, 'invalid v1 dist to wall ray 4'); // Vehicle 2 to test Wall::Right(()) - let vehicle_2 = Vehicle { - position: Vec2Trait::new( - FixedTrait::new(THREE_FIFTY, false), FixedTrait::new(TWO_HUNDRED, false) - ), - steer: FixedTrait::new(DEG_25_IN_RADS, false), - speed: FixedTrait::new(0, false) - }; + let vehicle_2 = vehicle_for_tests(TestVehicle::Vehicle2(())); let near_wall_2 = near_wall(vehicle_2); assert(near_wall_2 == Wall::Right(()), 'invalid near_wall_2'); @@ -788,35 +780,29 @@ mod tests { // Vehicle 2 rays 2,3,4 each intersect with Right wall assert(distances_to_wall_2.len() == NUM_RAYS, 'invalid distances_to_wall_2'); - assert(*(distances_to_wall_2.at(0).mag) == 0, 'invalid v2 dist to wall ray 0'); - assert(*(distances_to_wall_2.at(1).mag) == 0, 'invalid v2 dist to wall ray 1'); + assert(*distances_to_wall_2.at(0).mag == 0, 'invalid v2 dist to wall ray 0'); + assert(*distances_to_wall_2.at(1).mag == 0, 'invalid v2 dist to wall ray 1'); assert_precise( - *(distances_to_wall_2.at(2)), + *distances_to_wall_2.at(2), 2182435751561020000000, 'invalid v2 dist to wall ray 2', Option::Some(184467440737095000) // 1e-02 ); assert_precise( - *(distances_to_wall_2.at(3)), + *distances_to_wall_2.at(3), 1125965820528530000000, 'invalid v2 dist to wall ray 3', Option::Some(184467440737095000) // 1e-02 ); assert_precise( - *(distances_to_wall_2.at(4)), + *distances_to_wall_2.at(4), 954873737281615000000, 'invalid v2 dist to wall ray 4', Option::Some(184467440737095000) // 1e-02 ); // Vehicle 3 to test Wall::None(()) - let vehicle_3 = Vehicle { - position: Vec2Trait::new( - FixedTrait::new(TWO_HUNDRED, false), FixedTrait::new(TWO_HUNDRED, false) - ), - steer: FixedTrait::new(0, false), - speed: FixedTrait::new(0, false) - }; + let vehicle_3 = vehicle_for_tests(TestVehicle::Vehicle3(())); let near_wall_3 = near_wall(vehicle_3); assert(near_wall_3 == Wall::None(()), 'invalid near_wall_3'); @@ -831,4 +817,60 @@ mod tests { #[test] #[available_gas(20000000)] fn test_collision_check() {} + + // Helper functions for tests + #[derive(Serde, Drop, Copy)] + enum TestVehicle { + Vehicle1: (), + Vehicle2: (), + Vehicle3: (), + } + + fn vehicle_for_tests(test_vehicle: TestVehicle) -> Vehicle { + let vehicle = match test_vehicle { + TestVehicle::Vehicle1(()) => Vehicle { + position: Vec2Trait::new( + FixedTrait::new(HUNDRED, false), FixedTrait::new(TWO_HUNDRED, false) + ), + steer: FixedTrait::new(0, false), + speed: FixedTrait::new(0, false) + }, + TestVehicle::Vehicle2(()) => Vehicle { + position: Vec2Trait::new( + FixedTrait::new(THREE_FIFTY, false), FixedTrait::new(TWO_HUNDRED, false) + ), + steer: FixedTrait::new(DEG_25_IN_RADS, false), + speed: FixedTrait::new(0, false) + }, + TestVehicle::Vehicle3(()) => Vehicle { + position: Vec2Trait::new( + FixedTrait::new(TWO_HUNDRED, false), FixedTrait::new(TWO_HUNDRED, false) + ), + steer: FixedTrait::new(0, false), + speed: FixedTrait::new(0, false) + }, + }; + vehicle + } + + fn enemies_for_tests() -> Array { + // Spawn enemies, spaced evenly horizontally, at y = THREE_HUNDRED + // Use scaled u128 for Position + // position.x (center) of first enemy, so left edge is `CAR_WIDTH` (half-width) from Left wall + let enemy_min_dist_from_wall = 2 * CAR_WIDTH; + let enemy_horiz_spacing = (GRID_WIDTH - 2 * enemy_min_dist_from_wall) / (ENEMIES_NB - 1); + + let mut enemies = ArrayTrait::::new(); + let mut i = 0_u128; + loop { + if i == ENEMIES_NB { + break (); + } + let x = enemy_min_dist_from_wall + i * enemy_horiz_spacing; + let y = THREE_HUNDRED; + enemies.append(Position { x: x, y: y }); + i += 1; + }; + enemies + } } From e99aea45d23bfcd36fc81a4a0285b9272859110a Mon Sep 17 00:00:00 2001 From: "whatthedev.eth" Date: Tue, 25 Jul 2023 01:42:52 -0700 Subject: [PATCH 12/14] cleanup tests --- src/enemy.cairo | 32 +++++++++++----------- src/rays.cairo | 73 +++++++++++++++++++++---------------------------- 2 files changed, 47 insertions(+), 58 deletions(-) diff --git a/src/enemy.cairo b/src/enemy.cairo index c884a1d..82d58e6 100644 --- a/src/enemy.cairo +++ b/src/enemy.cairo @@ -476,52 +476,52 @@ mod tests { let vertices = position.vertices(); assert_precise( - *(vertices.at(0).x), + *vertices.at(0).x, (HUNDRED + CAR_WIDTH_SCALED).into(), 'invalid vertex_0', Option::None(()) ); assert_precise( - *(vertices.at(0).y), + *vertices.at(0).y, (HUNDRED + CAR_HEIGHT_SCALED).into(), 'invalid vertex_0', Option::None(()) ); assert_precise( - *(vertices.at(1).x), + *vertices.at(1).x, (HUNDRED - CAR_WIDTH_SCALED).into(), 'invalid vertex_1', Option::None(()) ); assert_precise( - *(vertices.at(1).y), + *vertices.at(1).y, (HUNDRED + CAR_HEIGHT_SCALED).into(), 'invalid vertex_1', Option::None(()) ); assert_precise( - *(vertices.at(2).x), + *vertices.at(2).x, (HUNDRED - CAR_WIDTH_SCALED).into(), 'invalid vertex_x2', Option::None(()) ); assert_precise( - *(vertices.at(2).y), + *vertices.at(2).y, (HUNDRED - CAR_HEIGHT_SCALED).into(), 'invalid vertex_y2', Option::None(()) ); assert_precise( - *(vertices.at(3).x), + *vertices.at(3).x, (HUNDRED + CAR_WIDTH_SCALED).into(), 'invalid vertex_3', Option::None(()) ); assert_precise( - *(vertices.at(3).y), + *vertices.at(3).y, (HUNDRED - CAR_HEIGHT_SCALED).into(), 'invalid vertex_3', Option::None(()) @@ -535,52 +535,52 @@ mod tests { let vertices = position.vertices_scaled(); assert_precise( - *(vertices.at(0).x), + *vertices.at(0).x, (HUNDRED + CAR_WIDTH_SCALED).into(), 'invalid vertex_0', Option::None(()) ); assert_precise( - *(vertices.at(0).y), + *vertices.at(0).y, (HUNDRED + CAR_HEIGHT_SCALED).into(), 'invalid vertex_0', Option::None(()) ); assert_precise( - *(vertices.at(1).x), + *vertices.at(1).x, (HUNDRED - CAR_WIDTH_SCALED).into(), 'invalid vertex_1', Option::None(()) ); assert_precise( - *(vertices.at(1).y), + *vertices.at(1).y, (HUNDRED + CAR_HEIGHT_SCALED).into(), 'invalid vertex_1', Option::None(()) ); assert_precise( - *(vertices.at(2).x), + *vertices.at(2).x, (HUNDRED - CAR_WIDTH_SCALED).into(), 'invalid vertex_x2', Option::None(()) ); assert_precise( - *(vertices.at(2).y), + *vertices.at(2).y, (HUNDRED - CAR_HEIGHT_SCALED).into(), 'invalid vertex_y2', Option::None(()) ); assert_precise( - *(vertices.at(3).x), + *vertices.at(3).x, (HUNDRED + CAR_WIDTH_SCALED).into(), 'invalid vertex_3', Option::None(()) ); assert_precise( - *(vertices.at(3).y), + *vertices.at(3).y, (HUNDRED - CAR_HEIGHT_SCALED).into(), 'invalid vertex_3', Option::None(()) diff --git a/src/rays.cairo b/src/rays.cairo index e3a7ee9..a31d77a 100644 --- a/src/rays.cairo +++ b/src/rays.cairo @@ -98,6 +98,7 @@ mod tests { use cubit::test::helpers::assert_precise; use drive_ai::vehicle::{Vehicle, VehicleTrait}; use drive_ai::enemy::{Position, PositionTrait}; + use drive_ai::racer::tests::{TestVehicle, vehicle_for_tests}; use super::{Rays, RaysTrait, Ray, RayTrait, RAY_LENGTH}; const NUM_RAYS: usize = 5; // Asserted values below are only for NUM_RAYS = 5 @@ -115,13 +116,7 @@ mod tests { #[available_gas(20000000)] fn test_raystrait_new() { // Vehicle 1 - let vehicle_1 = Vehicle { - position: Vec2Trait::new( - FixedTrait::new(HUNDRED, false), FixedTrait::new(TWO_HUNDRED, false) - ), - steer: FixedTrait::new(0, false), - speed: FixedTrait::new(0, false) - }; + let vehicle_1 = vehicle_for_tests(TestVehicle::Vehicle1(())); let ray_segments_1 = RaysTrait::new(vehicle_1.position, vehicle_1.steer).segments; assert(ray_segments_1.len() == NUM_RAYS, 'invalid ray_segments_1'); @@ -129,189 +124,183 @@ mod tests { // Asserted values below are only for NUM_RAYS = 5 // ray_segments_1.at(0) assert_precise( - *(ray_segments_1.at(0).theta), + *ray_segments_1.at(0).theta, -16097821017949100000, 'invalid ray_segments_1 0 theta', Option::Some(1844674407370950) // use custom_precision of 1e-04 ); assert_precise( - *(ray_segments_1.at(0).cos_theta), + *ray_segments_1.at(0).cos_theta, 11857338529639100000, 'invalid ray_segments_1 0 cos', Option::Some(1844674407370950) // 1e-04 ); assert_precise( - *(ray_segments_1.at(0).sin_theta), + *ray_segments_1.at(0).sin_theta, -14131025791303100000, 'invalid ray_segments_1 0 sin', Option::Some(1844674407370950) // 1e-04 ); // p & q are less precise due to propagation of error above assert_precise( - *(ray_segments_1.at(0).p.x), + *ray_segments_1.at(0).p.x, 1844674407370950000000, 'invalid ray_segments_1 0 p.x', // Option::Some(18446744073709500) // 1e-03 ); assert_precise( - *(ray_segments_1.at(0).p.y), + *ray_segments_1.at(0).p.y, 3689348814741900000000, 'invalid ray_segments_1 0 p.y', Option::Some(18446744073709500) // 1e-03 ); assert_precise( - *(ray_segments_1.at(0).q.x), + *ray_segments_1.at(0).q.x, -274979461324515000000, 'invalid ray_segments_1 0 q.x', Option::Some(184467440737095000) // 1e-02 ); assert_precise( - *(ray_segments_1.at(0).q.y), + *ray_segments_1.at(0).q.y, 5467949594187760000000, 'invalid ray_segments_1 0 q.y', Option::Some(184467440737095000) // 1e-02 ); // ray_segments_1.at(3) assert_precise( - *(ray_segments_1.at(3).theta), + *ray_segments_1.at(3).theta, 9658692610769470000, 'invalid ray_segments_1 3 theta', Option::Some(1844674407370950) // 1e-04 ); assert_precise( - *(ray_segments_1.at(3).cos_theta), + *ray_segments_1.at(3).cos_theta, 15975348984942500000, 'invalid ray_segments_1 3 cos', Option::Some(1844674407370950) // 1e-04 ); assert_precise( - *(ray_segments_1.at(3).sin_theta), + *ray_segments_1.at(3).sin_theta, 9223372036854750000, 'invalid ray_segments_1 3 sin', Option::Some(1844674407370950) // 1e-04 ); assert_precise( - *(ray_segments_1.at(3).p.x), + *ray_segments_1.at(3).p.x, 1844674407370950000000, 'invalid ray_segments_1 3 p.x', // Option::Some(18446744073709500) // 1e-03 ); assert_precise( - *(ray_segments_1.at(3).p.y), + *ray_segments_1.at(3).p.y, 3689348814741900000000, 'invalid ray_segments_1 3 p.y', Option::Some(18446744073709500) // 1e-03 ); assert_precise( - *(ray_segments_1.at(3).q.x), + *ray_segments_1.at(3).q.x, 3228180212899160000000, 'invalid ray_segments_1 3 q.x', Option::Some(184467440737095000) // 1e-02 ); assert_precise( - *(ray_segments_1.at(3).q.y), + *ray_segments_1.at(3).q.y, 6085651162483270000000, 'invalid ray_segments_1 3 q.y', Option::Some(184467440737095000) // 1e-02 ); // Vehicle 2 - let vehicle_2 = Vehicle { - position: Vec2Trait::new( - FixedTrait::new(THREE_FIFTY, false), FixedTrait::new(TWO_HUNDRED, false) - ), - steer: FixedTrait::new(DEG_25_IN_RADS, false), - speed: FixedTrait::new(0, false) - }; + let vehicle_2 = vehicle_for_tests(TestVehicle::Vehicle2(())); let ray_segments_2 = RaysTrait::new(vehicle_2.position, vehicle_2.steer).segments; assert(ray_segments_2.len() == NUM_RAYS, 'invalid ray_segments_2'); // ray_segments_2.at(0) assert_precise( - *(ray_segments_2.at(0).theta), + *ray_segments_2.at(0).theta, -8048910508974560000, 'invalid ray_segments_2 0 theta', Option::Some(1844674407370950) // 1e-04 ); assert_precise( - *(ray_segments_2.at(0).cos_theta), + *ray_segments_2.at(0).cos_theta, 16718427799475100000, 'invalid ray_segments_2 0 cos', Option::Some(1844674407370950) // 1e-04 ); assert_precise( - *(ray_segments_2.at(0).sin_theta), + *ray_segments_2.at(0).sin_theta, -7795930915206660000, 'invalid ray_segments_2 0 sin', Option::Some(1844674407370950) // 1e-04 ); assert_precise( - *(ray_segments_2.at(0).p.x), + *ray_segments_2.at(0).p.x, 6456360425798330000000, 'invalid ray_segments_2 0 p.x', // Option::Some(18446744073709500) // 1e-03 ); assert_precise( - *(ray_segments_2.at(0).p.y), + *ray_segments_2.at(0).p.y, 3689348814741900000000, 'invalid ray_segments_2 0 p.y', Option::Some(18446744073709500) // 1e-03 ); assert_precise( - *(ray_segments_2.at(0).q.x), + *ray_segments_2.at(0).q.x, 5286970788517330000000, 'invalid ray_segments_2 0 q.x', Option::Some(184467440737095000) // 1e-02 ); assert_precise( - *(ray_segments_2.at(0).q.y), + *ray_segments_2.at(0).q.y, 6197112984663160000000, 'invalid ray_segments_2 0 q.y', Option::Some(184467440737095000) // 1e-02 ); // ray_segments_2.at(3) assert_precise( - *(ray_segments_2.at(3).theta), + *ray_segments_2.at(3).theta, 17707603119744000000, 'invalid ray_segments_2 3 theta', Option::Some(1844674407370950) // 1e-04 ); assert_precise( - *(ray_segments_2.at(3).cos_theta), + *ray_segments_2.at(3).cos_theta, 10580617728078100000, 'invalid ray_segments_2 3 cos', Option::Some(1844674407370950) // 1e-04 ); assert_precise( - *(ray_segments_2.at(3).sin_theta), + *ray_segments_2.at(3).sin_theta, 15110688118455000000, 'invalid ray_segments_2 3 sin', Option::Some(1844674407370950) // 1e-04 ); assert_precise( - *(ray_segments_2.at(3).p.x), + *ray_segments_2.at(3).p.x, 6456360425798330000000, 'invalid ray_segments_2 3 p.x', // Option::Some(18446744073709500) // 1e-03 ); assert_precise( - *(ray_segments_2.at(3).p.y), + *ray_segments_2.at(3).p.y, 3689348814741900000000, 'invalid ray_segments_2 3 p.y', Option::Some(18446744073709500) // 1e-03 ); assert_precise( - *(ray_segments_2.at(3).q.x), + *ray_segments_2.at(3).q.x, 8722963643566570000000, 'invalid ray_segments_2 3 q.x', Option::Some(184467440737095000) // 1e-02 ); assert_precise( - *(ray_segments_2.at(3).q.y), + *ray_segments_2.at(3).q.y, 5276441473953610000000, 'invalid ray_segments_2 3 q.y', Option::Some(184467440737095000) // 1e-02 From 60272a60359dad8f561c87555e4e97456aa369da Mon Sep 17 00:00:00 2001 From: "whatthedev.eth" Date: Mon, 31 Jul 2023 21:33:15 -0700 Subject: [PATCH 13/14] fix collision_check, add tests for collision_check --- src/enemy.cairo | 36 +++---- src/math.cairo | 3 +- src/racer.cairo | 254 ++++++++++++++++++++++++++++++++++++++++-------- src/rays.cairo | 7 +- 4 files changed, 239 insertions(+), 61 deletions(-) diff --git a/src/enemy.cairo b/src/enemy.cairo index 82d58e6..1ef2691 100644 --- a/src/enemy.cairo +++ b/src/enemy.cairo @@ -467,7 +467,7 @@ mod tests { use drive_ai::racer::{CAR_HEIGHT as CAR_HEIGHT_SCALED, CAR_WIDTH as CAR_WIDTH_SCALED}; use super::{Position, PositionTrait}; - const HUNDRED: u128 = 1844674407370955161600; + const ONE_HUNDRED: u128 = 1844674407370955161600; #[test] #[available_gas(2000000)] @@ -477,52 +477,52 @@ mod tests { assert_precise( *vertices.at(0).x, - (HUNDRED + CAR_WIDTH_SCALED).into(), + (ONE_HUNDRED + CAR_WIDTH_SCALED).into(), 'invalid vertex_0', Option::None(()) ); assert_precise( *vertices.at(0).y, - (HUNDRED + CAR_HEIGHT_SCALED).into(), + (ONE_HUNDRED + CAR_HEIGHT_SCALED).into(), 'invalid vertex_0', Option::None(()) ); assert_precise( *vertices.at(1).x, - (HUNDRED - CAR_WIDTH_SCALED).into(), + (ONE_HUNDRED - CAR_WIDTH_SCALED).into(), 'invalid vertex_1', Option::None(()) ); assert_precise( *vertices.at(1).y, - (HUNDRED + CAR_HEIGHT_SCALED).into(), + (ONE_HUNDRED + CAR_HEIGHT_SCALED).into(), 'invalid vertex_1', Option::None(()) ); assert_precise( *vertices.at(2).x, - (HUNDRED - CAR_WIDTH_SCALED).into(), + (ONE_HUNDRED - CAR_WIDTH_SCALED).into(), 'invalid vertex_x2', Option::None(()) ); assert_precise( *vertices.at(2).y, - (HUNDRED - CAR_HEIGHT_SCALED).into(), + (ONE_HUNDRED - CAR_HEIGHT_SCALED).into(), 'invalid vertex_y2', Option::None(()) ); assert_precise( *vertices.at(3).x, - (HUNDRED + CAR_WIDTH_SCALED).into(), + (ONE_HUNDRED + CAR_WIDTH_SCALED).into(), 'invalid vertex_3', Option::None(()) ); assert_precise( *vertices.at(3).y, - (HUNDRED - CAR_HEIGHT_SCALED).into(), + (ONE_HUNDRED - CAR_HEIGHT_SCALED).into(), 'invalid vertex_3', Option::None(()) ); @@ -531,57 +531,57 @@ mod tests { #[test] #[available_gas(2000000)] fn test_vertices_scaled() { - let position = Position { x: HUNDRED, y: HUNDRED }; + let position = Position { x: ONE_HUNDRED, y: ONE_HUNDRED }; let vertices = position.vertices_scaled(); assert_precise( *vertices.at(0).x, - (HUNDRED + CAR_WIDTH_SCALED).into(), + (ONE_HUNDRED + CAR_WIDTH_SCALED).into(), 'invalid vertex_0', Option::None(()) ); assert_precise( *vertices.at(0).y, - (HUNDRED + CAR_HEIGHT_SCALED).into(), + (ONE_HUNDRED + CAR_HEIGHT_SCALED).into(), 'invalid vertex_0', Option::None(()) ); assert_precise( *vertices.at(1).x, - (HUNDRED - CAR_WIDTH_SCALED).into(), + (ONE_HUNDRED - CAR_WIDTH_SCALED).into(), 'invalid vertex_1', Option::None(()) ); assert_precise( *vertices.at(1).y, - (HUNDRED + CAR_HEIGHT_SCALED).into(), + (ONE_HUNDRED + CAR_HEIGHT_SCALED).into(), 'invalid vertex_1', Option::None(()) ); assert_precise( *vertices.at(2).x, - (HUNDRED - CAR_WIDTH_SCALED).into(), + (ONE_HUNDRED - CAR_WIDTH_SCALED).into(), 'invalid vertex_x2', Option::None(()) ); assert_precise( *vertices.at(2).y, - (HUNDRED - CAR_HEIGHT_SCALED).into(), + (ONE_HUNDRED - CAR_HEIGHT_SCALED).into(), 'invalid vertex_y2', Option::None(()) ); assert_precise( *vertices.at(3).x, - (HUNDRED + CAR_WIDTH_SCALED).into(), + (ONE_HUNDRED + CAR_WIDTH_SCALED).into(), 'invalid vertex_3', Option::None(()) ); assert_precise( *vertices.at(3).y, - (HUNDRED - CAR_HEIGHT_SCALED).into(), + (ONE_HUNDRED - CAR_HEIGHT_SCALED).into(), 'invalid vertex_3', Option::None(()) ); diff --git a/src/math.cairo b/src/math.cairo index 6561245..cf95794 100644 --- a/src/math.cairo +++ b/src/math.cairo @@ -37,6 +37,7 @@ fn vertices(position: Vec2, width: Fixed, height: Fixed, theta: Fixed) -> Span bool { let orientation_a = orientation(p1, q1, p2); @@ -151,7 +152,7 @@ mod tests { const FIFTY: u128 = 922337203685477580800; const SIXTY: u128 = 1106804644422573096960; const EIGHTY: u128 = 1475739525896764129280; - const HUNDRED: u128 = 1844674407370955161600; + const ONE_HUNDRED: u128 = 1844674407370955161600; const DEG_30_IN_RADS: u128 = 9658715196994321226; const DEG_90_IN_RADS: u128 = 28976077338029890953; diff --git a/src/racer.cairo b/src/racer.cairo index fb64411..ef94891 100644 --- a/src/racer.cairo +++ b/src/racer.cairo @@ -271,14 +271,16 @@ fn distances_to_wall(near_wall: Wall, mut rays: Span) -> Array { fn collision_check(vehicle: Vehicle, mut enemies: Array) { let vertices = vehicle.vertices(); + // TODO make narrower filters (near_wall and filter_positions) for collision checks + /// Wall collision check match near_wall(vehicle) { Wall::None(()) => {}, - Wall::Left(()) => { // not 100% sure of syntax here at end + Wall::Left(()) => { let cos_theta = trig::cos_fast(vehicle.steer); let sin_theta = trig::sin_fast(vehicle.steer); - // Check only left edge (vertex 1 to 2) + // Left edge (1) or vertex (1 & 2) must be involved in collision w/Left wall let closest_edge = Ray { theta: vehicle.steer, cos_theta: cos_theta, @@ -286,16 +288,17 @@ fn collision_check(vehicle: Vehicle, mut enemies: Array) { p: *vertices.at(1), q: *vertices.at(2), }; + // Left wall let p2 = Vec2 { x: FixedTrait::new(0, false), y: FixedTrait::new(0, false) }; let q2 = Vec2 { x: FixedTrait::new(0, false), y: FixedTrait::new(GRID_HEIGHT, false) }; assert(!closest_edge.intersects(p2, q2), 'hit left wall'); }, - Wall::Right(()) => { // not 100% sure of syntax here at end + Wall::Right(()) => { let cos_theta = trig::cos_fast(vehicle.steer); let sin_theta = trig::sin_fast(vehicle.steer); - // Check only right edge (vertex 3 to 0) + // Right edge (3) or vertices (3 & 0) must be involved in collision w/Right wall let closest_edge = Ray { theta: vehicle.steer, cos_theta: cos_theta, @@ -303,7 +306,7 @@ fn collision_check(vehicle: Vehicle, mut enemies: Array) { p: *vertices.at(3), q: *vertices.at(0), }; - + // Right wall let p2 = Vec2 { x: FixedTrait::new(GRID_WIDTH, false), y: FixedTrait::new(0, false) }; let q2 = Vec2 { x: FixedTrait::new(GRID_WIDTH, false), y: FixedTrait::new(GRID_HEIGHT, false) @@ -320,7 +323,7 @@ fn collision_check(vehicle: Vehicle, mut enemies: Array) { // For each vehicle edge... let mut vehicle_edge_idx: usize = 0; loop { - if (vehicle_edge_idx == 3) { + if (vehicle_edge_idx > 3) { break (); } @@ -329,12 +332,14 @@ fn collision_check(vehicle: Vehicle, mut enemies: Array) { q1_idx = 0; } // Endpoints of vehicle edge - let p1 = vertices.at(vehicle_edge_idx); - let q1 = vertices.at(q1_idx); + let p1 = *vertices.at(vehicle_edge_idx); + let q1 = *vertices.at(q1_idx); + + let mut filtered_enemies_this_edge = filtered_enemies.span(); // ..., check for collision with each near enemy loop { - match filtered_enemies.pop_front() { + match filtered_enemies_this_edge.pop_front() { Option::Some(position) => { let mut enemy_edge_idx: usize = 0; @@ -343,7 +348,7 @@ fn collision_check(vehicle: Vehicle, mut enemies: Array) { // For each enemy edge // TODO: Only check visible edges loop { - if enemy_edge_idx == 3 { + if enemy_edge_idx > 3 { break (); } @@ -353,10 +358,10 @@ fn collision_check(vehicle: Vehicle, mut enemies: Array) { } // Endpoints of enemy edge - let p2 = vertices.at(enemy_edge_idx); - let q2 = vertices.at(q2_idx); + let p2 = *vertices.at(enemy_edge_idx); + let q2 = *vertices.at(q2_idx); - assert(!intersects(*p1, *q1, *p2, *q2), 'hit enemy'); + assert(!intersects(p1, q1, p2, q2), 'hit enemy'); enemy_edge_idx += 1; } @@ -472,7 +477,7 @@ mod tests { use drive_ai::vehicle::{Vehicle, VehicleTrait}; use drive_ai::rays::{Rays, RaysTrait, Ray, RayTrait, RAY_LENGTH}; use drive_ai::enemy::{Position, PositionTrait}; - use drive_ai::math::assert_precise_u128; + use drive_ai::math::{intersects, assert_precise_u128}; use super::{ compute_sensors, filter_positions, closest_position, near_wall, distances_to_wall, collision_check, Wall @@ -486,17 +491,23 @@ mod tests { const TWO: u128 = 36893488147419103232; const TEN: u128 = 184467440737095516160; const FIFTY: u128 = 922337203685477580800; - const HUNDRED: u128 = 1844674407370955161600; + const SEVENTY_FIVE: u128 = 1383505805528216371200; + const ONE_HUNDRED: u128 = 1844674407370955161600; + const ONE_HUNDRED_FIFTY: u128 = 2767011611056432742400; const TWO_HUNDRED: u128 = 3689348814741910323200; + const TWO_HUNDRED_FIFTY: u128 = 4611686018427387904000; + const TWO_HUNDRED_NINETY: u128 = 5349555781375769968640; const THREE_HUNDRED: u128 = 5534023222112865484800; - const THREE_FIFTY: u128 = 6456360425798343065600; + const THREE_HUNDRED_FIFTY: u128 = 6456360425798343065600; const DEG_25_IN_RADS: u128 = 8048910508974580935; + const DEG_40_IN_RADS: u128 = 12878256814359329497; + const DEG_70_IN_RADS: u128 = 22536949425128826620; #[test] #[available_gas(200000000)] // Made gas 10x fn test_compute_sensors() { // Vehicle 1 - let vehicle_1 = vehicle_for_tests(TestVehicle::Vehicle1(())); + let vehicle_1 = vehicle_for_tests(TestVehicle::Vehicle_1(())); let mut enemies_1 = enemies_for_tests(); let sensors_1 = compute_sensors(vehicle_1, enemies_1); assert(sensors_1.rays.data.len() == 5, 'invalid sensors_1'); @@ -523,7 +534,7 @@ mod tests { assert(*sensors_1.rays.data.at(4).mag == 0, 'invalid sensors_1 ray 4'); // Vehicle 2 - let vehicle_2 = vehicle_for_tests(TestVehicle::Vehicle2(())); + let vehicle_2 = vehicle_for_tests(TestVehicle::Vehicle_2(())); let mut enemies_2 = enemies_for_tests(); let sensors_2 = compute_sensors(vehicle_2, enemies_2); assert(sensors_2.rays.data.len() == 5, 'invalid sensors_2'); @@ -555,8 +566,7 @@ mod tests { let mut enemies = enemies_for_tests(); // Vehicle 1 - let vehicle_1 = vehicle_for_tests(TestVehicle::Vehicle1(())); - + let vehicle_1 = vehicle_for_tests(TestVehicle::Vehicle_1(())); let filtered_enemies_1 = filter_positions(vehicle_1, enemies.span()); // Vehicle 1 is near 3 enemies (0, 1, & 2) @@ -600,10 +610,10 @@ mod tests { ); // Vehicle 2 - let vehicle_2 = vehicle_for_tests(TestVehicle::Vehicle2(())); + let vehicle_2 = vehicle_for_tests(TestVehicle::Vehicle_2(())); + let filtered_enemies_2 = filter_positions(vehicle_2, enemies.span()); // Vehicle 2 is near 2 enemies (2 & 3) - let filtered_enemies_2 = filter_positions(vehicle_2, enemies.span()); assert(filtered_enemies_2.len() == 2_usize, 'invalid filtered_enemies_2'); assert_precise_u128( *filtered_enemies_2.at(0).x, @@ -637,7 +647,7 @@ mod tests { let mut enemies = enemies_for_tests(); // Vehicle 1 - let vehicle_1 = vehicle_for_tests(TestVehicle::Vehicle1(())); + let vehicle_1 = vehicle_for_tests(TestVehicle::Vehicle_1(())); let ray_segments_1 = RaysTrait::new(vehicle_1.position, vehicle_1.steer).segments; let filtered_enemies_1 = filter_positions(vehicle_1, enemies.span()); @@ -679,7 +689,7 @@ mod tests { assert(*enemy_sensors_1.at(4).mag == 0, 'invalid v1 closest pos ray 4'); // Vehicle 2 - let vehicle_2 = vehicle_for_tests(TestVehicle::Vehicle2(())); + let vehicle_2 = vehicle_for_tests(TestVehicle::Vehicle_2(())); let ray_segments_2 = RaysTrait::new(vehicle_2.position, vehicle_2.steer).segments; let filtered_enemies_2 = filter_positions(vehicle_2, enemies.span()); @@ -747,7 +757,7 @@ mod tests { #[available_gas(20000000)] fn test_distances_to_wall() { // Vehicle 1 to test Wall::Left(()) - let vehicle_1 = vehicle_for_tests(TestVehicle::Vehicle1(())); + let vehicle_1 = vehicle_for_tests(TestVehicle::Vehicle_1(())); let near_wall_1 = near_wall(vehicle_1); assert(near_wall_1 == Wall::Left(()), 'invalid near_wall_1'); @@ -770,7 +780,7 @@ mod tests { assert(*distances_to_wall_1.at(4).mag == 0, 'invalid v1 dist to wall ray 4'); // Vehicle 2 to test Wall::Right(()) - let vehicle_2 = vehicle_for_tests(TestVehicle::Vehicle2(())); + let vehicle_2 = vehicle_for_tests(TestVehicle::Vehicle_2(())); let near_wall_2 = near_wall(vehicle_2); assert(near_wall_2 == Wall::Right(()), 'invalid near_wall_2'); @@ -802,7 +812,7 @@ mod tests { ); // Vehicle 3 to test Wall::None(()) - let vehicle_3 = vehicle_for_tests(TestVehicle::Vehicle3(())); + let vehicle_3 = vehicle_for_tests(TestVehicle::Vehicle_3(())); let near_wall_3 = near_wall(vehicle_3); assert(near_wall_3 == Wall::None(()), 'invalid near_wall_3'); @@ -813,42 +823,210 @@ mod tests { assert(distances_to_wall_3.len() == 0, 'invalid distances_to_wall_3'); } - // TODO #[test] #[available_gas(20000000)] - fn test_collision_check() {} + fn test_collision_check_123() { + // Vehicle 1, no collision + let vehicle_1 = vehicle_for_tests(TestVehicle::Vehicle_1(())); + let mut enemies_1 = enemies_for_tests(); + collision_check(vehicle_1, enemies_1); + // Vehicle 2, no collision + let vehicle_2 = vehicle_for_tests(TestVehicle::Vehicle_2(())); + let mut enemies_2 = enemies_for_tests(); + collision_check(vehicle_2, enemies_2); + // Vehicle 3, no collision + let vehicle_3 = vehicle_for_tests(TestVehicle::Vehicle_3(())); + let mut enemies_3 = enemies_for_tests(); + collision_check(vehicle_3, enemies_3); + } + + #[test] + #[available_gas(20000000)] + #[should_panic(expected: ('hit left wall', ))] + fn test_collision_check_4() { + // Vehicle 4, collision w/Left wall + let vehicle = vehicle_for_tests(TestVehicle::Vehicle_4(())); + let mut enemies = enemies_for_tests(); + collision_check(vehicle, enemies); + } + + #[test] + #[available_gas(20000000)] + #[should_panic(expected: ('hit right wall', ))] + fn test_collision_check_5() { + // Vehicle 5, collision w/Left wall + let vehicle = vehicle_for_tests(TestVehicle::Vehicle_5(())); + let mut enemies = enemies_for_tests(); + collision_check(vehicle, enemies); + } + + #[test] + #[available_gas(20000000)] + #[should_panic(expected: ('hit enemy', ))] + fn test_collision_check_6() { + let vehicle = vehicle_for_tests(TestVehicle::Vehicle_6(())); + let mut enemies = enemies_for_tests(); + + // Vehicle_6 edge 1 collision w/enemy 1 edge 2 + let p1 = vehicle.vertices().at(1); + let q1 = vehicle.vertices().at(2); + let p2 = enemies.at(1).vertices_scaled().at(2); + let q2 = enemies.at(1).vertices_scaled().at(3); + assert(intersects(*p1, *q1, *p2, *q2), 'Vehicle 6 invalid collision'); - // Helper functions for tests + // Should panic + collision_check(vehicle, enemies); + } + + #[test] + #[available_gas(20000000)] + #[should_panic(expected: ('hit enemy', ))] + fn test_collision_check_7() { + let vehicle = vehicle_for_tests(TestVehicle::Vehicle_7(())); + let mut enemies = enemies_for_tests(); + + // Vehicle_7 edge 2 collision w/enemy 2 edge 0 + let p1 = vehicle.vertices().at(2); + let q1 = vehicle.vertices().at(3); + let p2 = enemies.at(2).vertices_scaled().at(0); + let q2 = enemies.at(2).vertices_scaled().at(1); + assert(intersects(*p1, *q1, *p2, *q2), 'Vehicle 7 invalid collision'); + + // Should panic + collision_check(vehicle, enemies); + } + + #[test] + #[available_gas(20000000)] + #[should_panic(expected: ('hit enemy', ))] + fn test_collision_check_8() { + let vehicle = vehicle_for_tests(TestVehicle::Vehicle_8(())); + let mut enemies = enemies_for_tests(); + + // Vehicle_8 edge 3 collision w/enemy 3 edge 1 + let p1 = vehicle.vertices().at(3); + let q1 = vehicle.vertices().at(0); + let p2 = enemies.at(3).vertices_scaled().at(1); + let q2 = enemies.at(3).vertices_scaled().at(2); + assert(intersects(*p1, *q1, *p2, *q2), 'Vehicle 8 invalid collision'); + + // Should panic + collision_check(vehicle, enemies); + } + + + #[test] + #[available_gas(20000000)] + #[should_panic(expected: ('hit enemy', ))] + fn test_collision_check_9() { + let vehicle = vehicle_for_tests(TestVehicle::Vehicle_9(())); + let mut enemies = enemies_for_tests(); + + // Vehicle_9 edge 0 collision w/enemy 0 edge 3 + let p1 = vehicle.vertices().at(0); + let q1 = vehicle.vertices().at(1); + let p2 = enemies.at(0).vertices_scaled().at(3); + let q2 = enemies.at(0).vertices_scaled().at(0); + assert(intersects(*p1, *q1, *p2, *q2), 'Vehicle 9 invalid collision'); + + // Should panic + collision_check(vehicle, enemies); + } + + // + // Helpers for tests + // #[derive(Serde, Drop, Copy)] enum TestVehicle { - Vehicle1: (), - Vehicle2: (), - Vehicle3: (), + Vehicle_1: (), + Vehicle_2: (), + Vehicle_3: (), + Vehicle_4: (), + Vehicle_5: (), + Vehicle_6: (), + Vehicle_7: (), + Vehicle_8: (), + Vehicle_9: (), } fn vehicle_for_tests(test_vehicle: TestVehicle) -> Vehicle { let vehicle = match test_vehicle { - TestVehicle::Vehicle1(()) => Vehicle { + // Vehicle_1 near Left wall & some enemies, no collision + TestVehicle::Vehicle_1(()) => Vehicle { position: Vec2Trait::new( - FixedTrait::new(HUNDRED, false), FixedTrait::new(TWO_HUNDRED, false) + FixedTrait::new(ONE_HUNDRED, false), FixedTrait::new(TWO_HUNDRED, false) ), steer: FixedTrait::new(0, false), speed: FixedTrait::new(0, false) }, - TestVehicle::Vehicle2(()) => Vehicle { + // Vehicle_2 near Right wall & some enemies, no collision + TestVehicle::Vehicle_2(()) => Vehicle { position: Vec2Trait::new( - FixedTrait::new(THREE_FIFTY, false), FixedTrait::new(TWO_HUNDRED, false) + FixedTrait::new(THREE_HUNDRED_FIFTY, false), FixedTrait::new(TWO_HUNDRED, false) ), steer: FixedTrait::new(DEG_25_IN_RADS, false), speed: FixedTrait::new(0, false) }, - TestVehicle::Vehicle3(()) => Vehicle { + // Vehicle_3 near no wall, near some enemies, no collision + TestVehicle::Vehicle_3(()) => Vehicle { position: Vec2Trait::new( FixedTrait::new(TWO_HUNDRED, false), FixedTrait::new(TWO_HUNDRED, false) ), steer: FixedTrait::new(0, false), speed: FixedTrait::new(0, false) }, + // Vehicle_4 collision w/Left wall + TestVehicle::Vehicle_4(()) => Vehicle { + position: Vec2Trait::new( + FixedTrait::new(CAR_HEIGHT, false), FixedTrait::new(TWO_HUNDRED, false) + ), + steer: FixedTrait::new(DEG_70_IN_RADS, true), + speed: FixedTrait::new(0, false) + }, + // Vehicle_5 collision w/Right wall + TestVehicle::Vehicle_5(()) => Vehicle { + position: Vec2Trait::new( + FixedTrait::new(GRID_WIDTH - CAR_WIDTH, false), + FixedTrait::new(TWO_HUNDRED, false) + ), + steer: FixedTrait::new(DEG_25_IN_RADS, false), + speed: FixedTrait::new(0, false) + }, + // Vehicle_6 edge 1 collision w/enemy 1 edge 2 + TestVehicle::Vehicle_6(()) => Vehicle { + position: Vec2Trait::new( + FixedTrait::new(ONE_HUNDRED_FIFTY, false), + FixedTrait::new(TWO_HUNDRED_FIFTY, false) + ), + steer: FixedTrait::new(DEG_70_IN_RADS, false), + speed: FixedTrait::new(0, false) + }, + // Vehicle_7 edge 2 collision w/enemy 2 edge 0 + TestVehicle::Vehicle_7(()) => Vehicle { + position: Vec2Trait::new( + FixedTrait::new(TWO_HUNDRED_NINETY, false), + FixedTrait::new(THREE_HUNDRED_FIFTY, false) + ), + steer: FixedTrait::new(DEG_70_IN_RADS, false), + speed: FixedTrait::new(0, false) + }, + // Vehicle_8 edge 3 collision w/enemy 3 edge 1 + TestVehicle::Vehicle_8(()) => Vehicle { + position: Vec2Trait::new( + FixedTrait::new(THREE_HUNDRED_FIFTY, false), + FixedTrait::new(TWO_HUNDRED_FIFTY, false) + ), + steer: FixedTrait::new(DEG_40_IN_RADS, true), + speed: FixedTrait::new(0, false) + }, + // Vehicle_9 edge 0 collision w/enemy 0 edge 3 + TestVehicle::Vehicle_9(()) => Vehicle { + position: Vec2Trait::new( + FixedTrait::new(SEVENTY_FIVE, false), FixedTrait::new(THREE_HUNDRED, false) + ), + steer: FixedTrait::new(DEG_40_IN_RADS, true), + speed: FixedTrait::new(0, false) + }, }; vehicle } diff --git a/src/rays.cairo b/src/rays.cairo index a31d77a..3a998d7 100644 --- a/src/rays.cairo +++ b/src/rays.cairo @@ -106,17 +106,16 @@ mod tests { const FOUR: u128 = 73786976294838206464; const TEN: u128 = 184467440737095516160; const FIFTY: u128 = 922337203685477580800; - const HUNDRED: u128 = 1844674407370955161600; + const ONE_HUNDRED: u128 = 1844674407370955161600; const TWO_HUNDRED: u128 = 3689348814741910323200; const THREE_HUNDRED: u128 = 5534023222112865484800; - const THREE_FIFTY: u128 = 6456360425798343065600; const DEG_25_IN_RADS: u128 = 8048910508974580935; #[test] #[available_gas(20000000)] fn test_raystrait_new() { // Vehicle 1 - let vehicle_1 = vehicle_for_tests(TestVehicle::Vehicle1(())); + let vehicle_1 = vehicle_for_tests(TestVehicle::Vehicle_1(())); let ray_segments_1 = RaysTrait::new(vehicle_1.position, vehicle_1.steer).segments; assert(ray_segments_1.len() == NUM_RAYS, 'invalid ray_segments_1'); @@ -213,7 +212,7 @@ mod tests { ); // Vehicle 2 - let vehicle_2 = vehicle_for_tests(TestVehicle::Vehicle2(())); + let vehicle_2 = vehicle_for_tests(TestVehicle::Vehicle_2(())); let ray_segments_2 = RaysTrait::new(vehicle_2.position, vehicle_2.steer).segments; assert(ray_segments_2.len() == NUM_RAYS, 'invalid ray_segments_2'); From fb502a444be8c78375833bbeb030073e5646396d Mon Sep 17 00:00:00 2001 From: "whatthedev.eth" Date: Thu, 3 Aug 2023 15:23:30 -0700 Subject: [PATCH 14/14] fix fn move --- src/enemy.cairo | 2 +- src/racer.cairo | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/enemy.cairo b/src/enemy.cairo index 1ef2691..4fa2e0c 100644 --- a/src/enemy.cairo +++ b/src/enemy.cairo @@ -300,7 +300,7 @@ mod move_enemies { let new_y = if y <= velocity + height { GRID_HEIGHT + y + height - velocity } else { - y - (velocity + height) + y - velocity }; Position { diff --git a/src/racer.cairo b/src/racer.cairo index ef94891..eb2e823 100644 --- a/src/racer.cairo +++ b/src/racer.cairo @@ -824,7 +824,7 @@ mod tests { } #[test] - #[available_gas(20000000)] + #[available_gas(200000000)] // Made 10x fn test_collision_check_123() { // Vehicle 1, no collision let vehicle_1 = vehicle_for_tests(TestVehicle::Vehicle_1(()));