summaryrefslogtreecommitdiff
path: root/2020/src/bin/day_9.rs
blob: b5a02e6d6c4a735a89e2d5f7c1f3674fa2e7feeb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use bevy::{app::AppExit, prelude::*};
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_system(read_input_file.system())
        .add_stage("add")
        .add_system_to_stage("add", check_next_num.system())
        .add_stage("remove")
        .add_system_to_stage("remove", remove_oldest_line.system())
        .add_stage("find_range")
        .add_system_to_stage("find_range", find_contiguous_range.system())
        .add_plugins(DefaultPlugins)
        .run();
}

fn setup_camera(mut commands: Commands) {
    commands.spawn(Camera2dComponents::default());
}

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
struct LineNum(usize);
#[derive(Clone)]
struct Num(i64);
struct Active;
struct Invalid;
struct Done;

fn read_input_file(mut commands: Commands) {
    let f = File::open("./inputs/day_9.txt").unwrap();

    for (line_num, line) in BufReader::new(f).lines().enumerate() {
        let line = line.unwrap();
        let line = line.trim();
        let num = line.parse().unwrap();
        commands.spawn((LineNum(line_num), Num(num)));
        if line_num < 25 {
            commands.with(Active);
        }
    }
}

fn check_next_num(
    mut commands: Commands,
    active: Query<With<Active, &Num>>,
    next: Query<Without<Done, Without<Active, (Entity, &LineNum, &Num)>>>,
) {
    if let Some((min_entity, line, num)) = next.iter().min_by_key(|(_, line, _)| line.0) {
        let mut is_sum = false;
        for active_1 in active.iter() {
            for active_2 in active.iter() {
                is_sum = is_sum || (num.0 == active_1.0 + active_2.0)
            }
        }
        commands.insert_one(min_entity, Active);

        if !is_sum {
            commands.insert_one(min_entity, Invalid);
            println!(
                "{} on line {} was not a sum of the previous lot!",
                num.0, line.0
            );
        }
    }
}

fn remove_oldest_line(
    mut commands: Commands,
    line_nums: Query<Without<Done, With<Active, (Entity, &LineNum)>>>,
) {
    if let Some((min_entity, _)) = line_nums.iter().min_by_key(|(_, line)| line.0) {
        commands.remove_one::<Active>(min_entity);
        commands.insert_one(min_entity, Done);
    } else {
        println!("All numbers cleared");
    }
}

fn find_contiguous_range(
    mut exit_events: ResMut<Events<AppExit>>,
    line_nums: Query<(&LineNum, &Num)>,
    invalid: Query<With<Invalid, &Num>>,
) {
    for invalid in invalid.iter() {
        let mut nums: Vec<(LineNum, Num)> = line_nums
            .iter()
            .map(|(line, num)| (line.clone(), num.clone()))
            .collect();

        nums.sort_by_key(|(line, _num)| line.clone());
        let nums: Vec<i64> = nums.into_iter().map(|(_line, num)| num.0).collect();

        for min in 0..nums.len() {
            for max in min + 2..nums.len() + 1 {
                let sum: i64 = nums[min..max].iter().sum();
                if sum == invalid.0 {
                    let min_in_range = nums[min..max].iter().min().unwrap();
                    let max_in_range = nums[min..max].iter().max().unwrap();
                    println!(
                        "Range found! {} + {} = {}",
                        min_in_range,
                        max_in_range,
                        min_in_range + max_in_range
                    );
                }
            }
        }

        exit_events.send(AppExit);
    }
}