aboutsummaryrefslogtreecommitdiff
path: root/2021/day17/src/main.rs
blob: 641962e2c356bce26cf4c6c537fd9ab0f748526a (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
use regex::Regex;
use std::{fs::read_to_string, ops::Range};

#[derive(Debug, Clone, Copy)]
struct Coord(isize, isize);

#[derive(Debug, Clone)]
struct TargetArea(pub Range<isize>, pub Range<isize>);
impl TargetArea {
    fn contains(&self, c: Coord) -> bool {
        self.0.contains(&c.0) && self.1.contains(&c.1)
    }
}

fn parse_target_area(line: &str) -> TargetArea {
    let x_caps = Regex::new(r"x=([-\d]*)..([-\d]*)")
        .unwrap()
        .captures(line)
        .unwrap();
    let y_caps = Regex::new(r"y=([-\d]*)..([-\d]*)")
        .unwrap()
        .captures(line)
        .unwrap();

    TargetArea(
        x_caps[1].parse().unwrap()..x_caps[2].parse::<isize>().unwrap() + 1isize,
        y_caps[1].parse().unwrap()..y_caps[2].parse::<isize>().unwrap() + 1isize,
    )
}

fn does_intersect(mut vx: isize, mut vy: isize, area: &TargetArea) -> bool {
    let mut x = 0;
    let mut y = 0;
    for _ in 0.. {
        x += vx;
        y += vy;

        vx = if vx > 0 {
            vx - 1
        } else if vx < 0 {
            vx + 1
        } else {
            0
        };
        vy -= 1;
        if area.contains(Coord(x, y)) {
            return true;
        } else if x > area.0.end || y < area.1.start {
            return false;
        }
    }

    unreachable!()
}

fn max_y(mut vy: isize) -> isize {
    let mut y = 0;
    for _ in 0.. {
        y += vy;
        vy -= 1;

        if vy <= 0 {
            return y;
        }
    }

    unreachable!()
}

fn main() {
    let area = parse_target_area(&read_to_string("./input").unwrap());

    let mut max_y_found = 0;
    let mut max_y_vel = Coord(0, 0);
    let mut num_valid = 0;
    for vx in 0..=area.0.end * 2 {
        for vy in -area.1.start.abs() * 2..=area.1.start.abs() * 2 {
            if does_intersect(vx, vy, &area) {
                if max_y(vy) > max_y_found {
                    max_y_found = max_y(vy);
                    max_y_vel = Coord(vx, vy);
                }
                num_valid += 1;
            }
        }
    }

    println!("part 1: {} with velocity {:?}", max_y_found, max_y_vel);
    println!("part 2: {} possible velocities", num_valid);
}