summaryrefslogtreecommitdiffstats
path: root/src/2020/5/mod.rs
blob: b824e603252f883c2f287404ed31313411951a04 (plain) (blame)
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
use anyhow::Context as _;
use std::convert::TryInto as _;

pub fn parse(fh: std::fs::File) -> anyhow::Result<impl Iterator<Item = i64>> {
    Ok(crate::util::parse::lines(fh).map(|line| seat_id(&line).unwrap()))
}

pub fn part1(ids: impl Iterator<Item = i64>) -> anyhow::Result<i64> {
    let mut max = 0;
    for id in ids {
        if id > max {
            max = id;
        }
    }
    Ok(max)
}

pub fn part2(ids: impl Iterator<Item = i64>) -> anyhow::Result<i64> {
    let mut seats = vec![false; 1024];
    for id in ids {
        seats[id as usize] = true;
    }
    let first = seats
        .iter()
        .position(|b| *b)
        .context("failed to find taken seat")?;
    let seat = seats
        .iter()
        .skip(first)
        .position(|b| !*b)
        .context("failed to find free seat")?
        + first;
    if !seats[seat - 1] || seats[seat] || !seats[seat + 1] {
        return Err(anyhow::anyhow!("invalid seat found"));
    }
    Ok(seat.try_into()?)
}

fn seat_id(desc: &str) -> anyhow::Result<i64> {
    if desc.len() != 10 {
        return Err(anyhow::anyhow!("invalid desc {}", desc));
    }
    let row_desc = &desc[0..7];
    let col_desc = &desc[7..10];

    let mut min_row = 0;
    let mut max_row = 127;
    for c in row_desc.chars() {
        let mid = (max_row + min_row) / 2;
        match c {
            'F' => {
                max_row = mid;
            }
            'B' => {
                min_row = mid + 1;
            }
            _ => return Err(anyhow::anyhow!("invalid desc {}", desc)),
        }
    }
    if min_row != max_row {
        return Err(anyhow::anyhow!("bug"));
    }
    let row = min_row;

    let mut min_col = 0;
    let mut max_col = 7;
    for c in col_desc.chars() {
        let mid = (max_col + min_col) / 2;
        match c {
            'L' => {
                max_col = mid;
            }
            'R' => {
                min_col = mid + 1;
            }
            _ => return Err(anyhow::anyhow!("invalid desc {}", desc)),
        }
    }
    if min_col != max_col {
        return Err(anyhow::anyhow!("bug"));
    }
    let col = min_col;

    Ok(row * 8 + col)
}

#[test]
fn test() {
    assert_eq!(
        part1(parse(crate::util::data(2020, 5).unwrap()).unwrap()).unwrap(),
        978
    );
    assert_eq!(
        part2(parse(crate::util::data(2020, 5).unwrap()).unwrap()).unwrap(),
        727
    );
}