| 1 | module main |
| 2 | |
| 3 | import rand |
| 4 | import math |
| 5 | |
| 6 | struct Vector { |
| 7 | x f64 |
| 8 | y f64 |
| 9 | z f64 |
| 10 | } |
| 11 | |
| 12 | const boids_count = 10000 |
| 13 | const max_coordinate = 10000.0 |
| 14 | const cohesion_distance = 10.0 |
| 15 | const separation_distance = 5.0 |
| 16 | |
| 17 | @[direct_array_access] |
| 18 | fn main() { |
| 19 | mut positions := [boids_count]Vector{} |
| 20 | mut velocities := [boids_count]Vector{} |
| 21 | |
| 22 | for position_index in 0 .. positions.len { |
| 23 | positions[position_index] = Vector{ |
| 24 | x: rand.f64() * max_coordinate |
| 25 | y: rand.f64() * max_coordinate |
| 26 | z: rand.f64() * max_coordinate |
| 27 | } |
| 28 | } |
| 29 | |
| 30 | for boid_index in 0 .. positions.len { |
| 31 | position := positions[boid_index] |
| 32 | mut close_boids_ids := []int{} |
| 33 | |
| 34 | for other_boid_index in 0 .. positions.len { |
| 35 | if boid_index == other_boid_index { |
| 36 | continue |
| 37 | } |
| 38 | |
| 39 | other_position := positions[other_boid_index] |
| 40 | |
| 41 | difference_x := position.x - other_position.x |
| 42 | difference_y := position.y - other_position.y |
| 43 | difference_z := position.z - other_position.z |
| 44 | |
| 45 | distance := difference_x * difference_x + difference_y * difference_y + |
| 46 | difference_z * difference_z |
| 47 | |
| 48 | if distance <= cohesion_distance * cohesion_distance { |
| 49 | close_boids_ids << other_boid_index |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | if close_boids_ids.len == 0 { |
| 54 | continue |
| 55 | } |
| 56 | |
| 57 | mut cohesion := Vector{} |
| 58 | mut separation := Vector{} |
| 59 | mut separation_count := 0 |
| 60 | mut alignment := Vector{} |
| 61 | |
| 62 | for close_boid_id in close_boids_ids { |
| 63 | close_boid_position := positions[close_boid_id] |
| 64 | |
| 65 | cohesion = Vector{ |
| 66 | x: cohesion.x + close_boid_position.x |
| 67 | y: cohesion.y + close_boid_position.y |
| 68 | z: cohesion.z + close_boid_position.z |
| 69 | } |
| 70 | |
| 71 | difference_from_closest := Vector{ |
| 72 | x: position.x - close_boid_position.x |
| 73 | y: position.y - close_boid_position.y |
| 74 | z: position.z - close_boid_position.z |
| 75 | } |
| 76 | |
| 77 | difference_magnitude := math.sqrt( |
| 78 | difference_from_closest.x * difference_from_closest.x + |
| 79 | difference_from_closest.y * difference_from_closest.y + |
| 80 | difference_from_closest.z * difference_from_closest.z) |
| 81 | |
| 82 | if difference_magnitude <= separation_distance { |
| 83 | separation = Vector{ |
| 84 | x: separation.x + difference_from_closest.x / difference_magnitude |
| 85 | y: separation.y + difference_from_closest.y / difference_magnitude |
| 86 | z: separation.z + difference_from_closest.z / difference_magnitude |
| 87 | } |
| 88 | |
| 89 | separation_count += 1 |
| 90 | } |
| 91 | |
| 92 | close_boid_velocity := velocities[close_boid_id] |
| 93 | |
| 94 | alignment = Vector{ |
| 95 | x: alignment.x + close_boid_velocity.x |
| 96 | y: alignment.y + close_boid_velocity.y |
| 97 | z: alignment.z + close_boid_velocity.z |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | cohesion = Vector{ |
| 102 | x: cohesion.x / close_boids_ids.len |
| 103 | y: cohesion.y / close_boids_ids.len |
| 104 | z: cohesion.z / close_boids_ids.len |
| 105 | } |
| 106 | |
| 107 | cohesion_force := Vector{ |
| 108 | x: cohesion.x - position.x |
| 109 | y: cohesion.y - position.y |
| 110 | z: cohesion.z - position.z |
| 111 | } |
| 112 | |
| 113 | if separation_count > 0 { |
| 114 | separation = Vector{ |
| 115 | x: separation.x / separation_count |
| 116 | y: separation.y / separation_count |
| 117 | z: separation.z / separation_count |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | alignment = Vector{ |
| 122 | x: alignment.x / close_boids_ids.len |
| 123 | y: alignment.y / close_boids_ids.len |
| 124 | z: alignment.z / close_boids_ids.len |
| 125 | } |
| 126 | |
| 127 | current_velocity := velocities[boid_index] |
| 128 | |
| 129 | velocities[boid_index] = Vector{ |
| 130 | x: current_velocity.x + cohesion_force.x + separation.x + alignment.x |
| 131 | y: current_velocity.y + cohesion_force.y + separation.y + alignment.y |
| 132 | z: current_velocity.z + cohesion_force.z + separation.z + alignment.z |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | mut position_sum := Vector{} |
| 137 | mut velocity_sum := Vector{} |
| 138 | |
| 139 | for boid_index in 0 .. positions.len { |
| 140 | position := positions[boid_index] |
| 141 | velocity := velocities[boid_index] |
| 142 | |
| 143 | positions[boid_index] = Vector{ |
| 144 | x: position.x + velocity.x |
| 145 | y: position.y + velocity.y |
| 146 | z: position.z + velocity.z |
| 147 | } |
| 148 | |
| 149 | position_sum = Vector{ |
| 150 | x: position_sum.x + position.x |
| 151 | y: position_sum.y + position.y |
| 152 | z: position_sum.z + position.z |
| 153 | } |
| 154 | |
| 155 | velocity_sum = Vector{ |
| 156 | x: velocity_sum.x + velocity.x |
| 157 | y: velocity_sum.y + velocity.y |
| 158 | z: velocity_sum.z + velocity.z |
| 159 | } |
| 160 | } |
| 161 | |
| 162 | println('${position_sum.x} - ${position_sum.y} - ${position_sum.z}') |
| 163 | println('${velocity_sum.x} - ${velocity_sum.y} - ${velocity_sum.z}') |
| 164 | } |
| 165 | |