summaryrefslogtreecommitdiff
path: root/src/bin/day8.rs
blob: 725f129d107c249b3909c68284f70be00fc1fa18 (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
fn main() {
    let input = advent::read_lines(8);
    println!("8a: {}", count_chars_decoding(&input));
    println!("8b: {}", count_chars_encoding(&input));
}

fn decode_string(word: &str) -> Vec<u8> {
    let mut decoded = Vec::new();

    let mut chars = word.chars();
    // drop " at beginning
    assert_eq!(chars.next(), Some('"'));

    while let Some(c) = chars.next() {
        if c == '\\' {
            let next = chars.next().unwrap();
            if next == 'x' {
                let digit1 = chars.next().unwrap().to_digit(16).unwrap();
                let digit2 = chars.next().unwrap().to_digit(16).unwrap();
                let code = 16 * digit1 + digit2;
                decoded.push(char::from_u32(code).unwrap() as u8);
            } else {
                decoded.push(next as u8);
            }
        } else {
            decoded.push(c as u8);
        }
    }

    // drop " at end
    assert_eq!(decoded.pop(), Some(34));

    decoded
}

fn count_chars_decoding<T: AsRef<str>>(input: &[T]) -> usize {
    let mut code = 0;
    let mut values = 0;

    for line in input {
        code += line.as_ref().len();
        values += decode_string(line.as_ref()).len();
    }
    code - values
}

fn encode_string(word: &str) -> String {
    let mut encoded = String::new();
    encoded.push('"');

    for c in word.chars() {
        match c {
            '"' => encoded += "\\\"",
            '\\' => encoded += "\\\\",
            rest => encoded.push(rest),
        }
    }

    encoded.push('"');
    encoded
}

fn count_chars_encoding<T: AsRef<str>>(input: &[T]) -> usize {
    let mut code = 0;
    let mut values = 0;

    for line in input {
        code += line.as_ref().len();
        values += encode_string(line.as_ref()).len();
    }
    values - code
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test() {
        let input = [
            "\"\"",
            "\"abc\"",
            "\"aaa\\\"aaa\"",
            "\"\\x27\"",
        ];
        assert_eq!(count_chars_decoding(&input), 12);
        assert_eq!(count_chars_encoding(&input), 19);
    }
}