summaryrefslogtreecommitdiffstats
path: root/src/util/parse.rs
blob: 5f42565a7f86fdf651e5c8aa6636eac46188a81d (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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use std::io::{BufRead as _, Read as _};

macro_rules! data {
    () => {{
        use anyhow::Context as _;
        let file = crate::util::parse::src_file_to_data_file(&std::file!());
        std::fs::File::open(file.clone())
            .with_context(|| format!("couldn't find data file {}", file))
    }};
}

macro_rules! data_lines {
    () => {
        data!().map(|fh| crate::util::parse::lines(fh))
    };
}

macro_rules! data_ints {
    () => {
        data!()
            .map(|fh| crate::util::parse::ints(crate::util::parse::lines(fh)))
    };
    ($sep:expr) => {
        data!().map(|fh| {
            crate::util::parse::ints(crate::util::parse::split(fh, $sep))
        })
    };
}

macro_rules! data_bytes {
    () => {
        data!().map(|fh| crate::util::parse::bytes(fh))
    };
}

macro_rules! data_str {
    () => {{
        data!().map(|fh| crate::util::parse::string(fh))
    }};
}

macro_rules! data_bool_grid {
    ($t:expr, $f:expr) => {{
        crate::util::parse::bool_grid(data_lines!().unwrap(), $t, $f)
    }};
}

macro_rules! data_digit_grid {
    () => {{
        crate::util::parse::digit_grid(data_lines!().unwrap())
    }};
}

pub fn src_file_to_data_file(file: &str) -> String {
    let parts: Vec<_> = file.split('/').collect();
    format!(
        "data/{}/{}.txt",
        parts[parts.len() - 3],
        parts[parts.len() - 2]
    )
}

pub fn lines(fh: std::fs::File) -> impl Iterator<Item = String> {
    let fh = std::io::BufReader::new(fh);
    fh.lines().map(|res| res.unwrap())
}

pub fn split(fh: std::fs::File, sep: u8) -> impl Iterator<Item = String> {
    let fh = std::io::BufReader::new(fh);
    fh.split(sep)
        .map(|res| String::from_utf8(res.unwrap()).unwrap())
}

pub fn ints(iter: impl Iterator<Item = String>) -> impl Iterator<Item = i64> {
    iter.map(|s| s.trim().parse().unwrap())
}

pub fn bytes(fh: std::fs::File) -> impl Iterator<Item = u8> {
    fh.bytes().map(|res| res.unwrap())
}

pub fn string(fh: std::fs::File) -> String {
    let bytes: Vec<_> = bytes(fh).collect();
    String::from_utf8(bytes).unwrap()
}

pub fn bool_grid(
    lines: impl Iterator<Item = String>,
    t: u8,
    f: u8,
) -> crate::util::grid::Grid<bool> {
    lines
        .map(|s| {
            s.as_bytes()
                .iter()
                .copied()
                .map(|b| {
                    if b == f {
                        false
                    } else if b == t {
                        true
                    } else {
                        panic!("unrecognized character {}", char::from(b))
                    }
                })
                .collect::<Vec<_>>()
        })
        .collect()
}

pub fn digit_grid(
    lines: impl Iterator<Item = String>,
) -> crate::util::grid::Grid<u8> {
    lines
        .map(|s| {
            s.as_bytes()
                .iter()
                .copied()
                .map(|b| b - b'0')
                .collect::<Vec<_>>()
        })
        .collect()
}