summaryrefslogtreecommitdiff
path: root/2020/src/bin/day_3.rs
diff options
context:
space:
mode:
Diffstat (limited to '2020/src/bin/day_3.rs')
-rw-r--r--2020/src/bin/day_3.rs205
1 files changed, 205 insertions, 0 deletions
diff --git a/2020/src/bin/day_3.rs b/2020/src/bin/day_3.rs
new file mode 100644
index 0000000..5e6f0bd
--- /dev/null
+++ b/2020/src/bin/day_3.rs
@@ -0,0 +1,205 @@
+use bevy::app::AppExit;
+use bevy::prelude::*;
+use bevy::render::camera::Camera;
+use std::fs::File;
+use std::io::{BufRead, BufReader};
+
+fn main() {
+ App::build()
+ .add_resource(WindowDescriptor {
+ title: "Advent of Code".to_string(),
+ width: 1920,
+ height: 1080,
+ ..Default::default()
+ })
+ .add_resource(ClearColor(Color::rgb(0., 0., 0.)))
+ .add_startup_system(setup_camera.system())
+ .add_startup_stage("game_entities")
+ .add_startup_system_to_stage("game_entities", read_input_file.system())
+ .add_system(move_tobogganist.system())
+ .add_system(collide_with_trees.system())
+ .add_system(clear_finished_tobogganists.system())
+ .add_system(end_of_slope.system())
+ .add_system(translate_positions.system())
+ .add_system(tobogganist_cam.system())
+ .add_plugins(DefaultPlugins)
+ .run();
+}
+
+fn setup_camera(mut commands: Commands, mut materials: ResMut<Assets<ColorMaterial>>) {
+ commands.spawn(Camera2dComponents::default());
+
+ commands.insert_resource(Materials {
+ tobogganist_material: materials.add(Color::rgb(0., 0., 255.).into()),
+ tree_material: materials.add(Color::rgb(0., 255., 0.).into()),
+ });
+}
+
+struct Materials {
+ tobogganist_material: Handle<ColorMaterial>,
+ tree_material: Handle<ColorMaterial>,
+}
+
+struct Tobogganist;
+
+struct Tree;
+#[derive(PartialEq, Eq)]
+struct Position {
+ x: usize,
+ y: usize,
+}
+struct Velocity {
+ x: usize,
+ y: usize,
+}
+struct MapSize {
+ width: usize,
+ height: usize,
+}
+struct TreeHitCount(usize);
+struct Score(usize);
+
+fn read_input_file(mut commands: Commands, materials: Res<Materials>) {
+ commands
+ .spawn(SpriteComponents {
+ sprite: Sprite::new(Vec2::new(10., 10.)),
+ material: materials.tobogganist_material.clone(),
+ ..Default::default()
+ })
+ .with(Tobogganist)
+ .with(Position { x: 0, y: 0 })
+ .with(Velocity { x: 1, y: 1 })
+ .with(TreeHitCount(0));
+
+ commands
+ .spawn(SpriteComponents {
+ sprite: Sprite::new(Vec2::new(10., 10.)),
+ material: materials.tobogganist_material.clone(),
+ ..Default::default()
+ })
+ .with(Tobogganist)
+ .with(Position { x: 0, y: 0 })
+ .with(Velocity { x: 3, y: 1 })
+ .with(TreeHitCount(0));
+
+ commands
+ .spawn(SpriteComponents {
+ sprite: Sprite::new(Vec2::new(10., 10.)),
+ material: materials.tobogganist_material.clone(),
+ ..Default::default()
+ })
+ .with(Tobogganist)
+ .with(Position { x: 0, y: 0 })
+ .with(Velocity { x: 5, y: 1 })
+ .with(TreeHitCount(0));
+
+ commands
+ .spawn(SpriteComponents {
+ sprite: Sprite::new(Vec2::new(10., 10.)),
+ material: materials.tobogganist_material.clone(),
+ ..Default::default()
+ })
+ .with(Tobogganist)
+ .with(Position { x: 0, y: 0 })
+ .with(Velocity { x: 7, y: 1 })
+ .with(TreeHitCount(0));
+
+ commands
+ .spawn(SpriteComponents {
+ sprite: Sprite::new(Vec2::new(10., 10.)),
+ material: materials.tobogganist_material.clone(),
+ ..Default::default()
+ })
+ .with(Tobogganist)
+ .with(Position { x: 0, y: 0 })
+ .with(Velocity { x: 1, y: 2 })
+ .with(TreeHitCount(0));
+
+ let f = File::open("./inputs/day_3.txt").expect("Failed to read file"); // TODO: Use the asset loading system to load this rather?
+ let mut width = 0;
+ let mut height = 0;
+ for (y, line) in BufReader::new(f).lines().enumerate() {
+ let line = line.expect("Error reading file");
+ let line = line.trim();
+ width = width.max(line.len());
+ for (x, c) in line.chars().enumerate() {
+ if c == '#' {
+ commands
+ .spawn(SpriteComponents {
+ sprite: Sprite::new(Vec2::new(10., 10.)),
+ material: materials.tree_material.clone(),
+ ..Default::default()
+ })
+ .with(Tree)
+ .with(Position { x, y })
+ .with(TreeHitCount(0));
+ }
+ }
+ height = y + 1;
+ }
+ commands.insert_resource(MapSize { width, height });
+ commands.insert_resource(Score(1));
+}
+
+fn translate_positions(mut transform: Mut<Transform>, position: &Position) {
+ transform.translation = Vec3::new(position.x as f32 * 10., position.y as f32 * -10., 0.);
+}
+
+fn tobogganist_cam(
+ tobogganist: Query<With<Tobogganist, &Transform>>,
+ mut camera: Query<With<Camera, &mut Transform>>,
+) {
+ for mut camera_transform in camera.iter_mut() {
+ if let Some(tobogganist_transform) = tobogganist.iter().next() {
+ camera_transform.translation = Vec3::new(0., tobogganist_transform.translation.y(), 0.);
+ }
+ }
+}
+
+fn move_tobogganist(map_size: Res<MapSize>, mut position: Mut<Position>, velocity: &Velocity) {
+ position.x += velocity.x;
+ position.x %= map_size.width;
+ position.y += velocity.y;
+}
+
+fn collide_with_trees(
+ mut tobogganists: Query<With<Tobogganist, (&Position, &mut TreeHitCount)>>,
+ trees: Query<With<Tree, &Position>>,
+) {
+ for (tobogganist_position, mut tree_hit_count) in tobogganists.iter_mut() {
+ for tree_position in trees.iter() {
+ if *tree_position == *tobogganist_position {
+ tree_hit_count.0 += 1;
+ }
+ }
+ }
+}
+
+fn clear_finished_tobogganists(
+ mut commands: Commands,
+ map_size: Res<MapSize>,
+ mut score: ResMut<Score>,
+ tobogganists: Query<With<Tobogganist, (Entity, &Position, &Velocity, &TreeHitCount)>>,
+) {
+ for (entity, position, velocity, tree_hit_count) in tobogganists.iter() {
+ if position.y >= map_size.height {
+ println!(
+ "A tobogganist finished heading at incline {} x {}, after hitting {} trees",
+ velocity.x, velocity.y, tree_hit_count.0
+ );
+ score.0 *= tree_hit_count.0;
+ commands.despawn(entity);
+ }
+ }
+}
+
+fn end_of_slope(
+ score: Res<Score>,
+ mut exit_events: ResMut<Events<AppExit>>,
+ tobogganists: Query<&Tobogganist>,
+) {
+ if tobogganists.iter().count() == 0 {
+ println!("All tobogganists finished. Total score: {}", score.0);
+ exit_events.send(AppExit);
+ }
+}