summaryrefslogtreecommitdiff
path: root/12/src/part-2.rs
blob: aa14ef80d9b4304124ecf21ea4ea4df10a9606b7 (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
mod tensor;

use std::collections::{BinaryHeap};
use std::io::{BufRead};

use tensor::{Index, Shape, Tensor};

#[derive(Debug)]
struct Node {
    idx: [usize; 2],
    cost: usize
}

impl Node {
    fn new(idx: [usize; 2], cost: usize) -> Self {
        Self {
            idx: idx,
            cost: cost
        }
    }
}

impl PartialEq for Node {
    fn ne(self: & Self, other: & Self) -> bool {
        self.cost != other.cost
    }
    fn eq(self: & Self, other: & Self) -> bool {
        self.cost == other.cost
    }
}

impl Eq for Node {
}

impl PartialOrd for Node {
    fn partial_cmp(self: & Self, other: & Self) -> Option<std::cmp::Ordering> {
        other.cost.partial_cmp(& self.cost)
    }
}

impl Ord for Node {
    fn cmp(self: & Self, other: & Self) -> std::cmp::Ordering {
        other.cost.cmp(& self.cost)
    }
}

fn main() {
    let stdin = std::io::stdin();
    let mut handle = stdin.lock();

    let mut buf: Vec<u8> = Vec::new();

    let mut tmp: Vec<(u8, bool)> = Vec::new();
    let mut m: usize = 0;
    let mut n: usize = 0;
    let mut n_check: usize = 0;

    loop {
        let buf = handle.fill_buf().expect("IO error");
        let bytes_read = buf.len();
        if bytes_read == 0 { break; }

        for & b in buf.into_iter() {
            if b == b'\n' {
                m += 1;
                assert_eq!(n_check, n);
                n_check = 0;
            }
            else {
                tmp.push((b, false));
                if m == 0 {
                    n += 1;
                }
                n_check += 1;
            }
        }

        handle.consume(bytes_read);
    }
    let mut terrain: Tensor<(u8, bool), 2> = Tensor::new_from([m, n], tmp);

    let mut unvisited: BinaryHeap<Node> = BinaryHeap::new();
    let mut done: bool = false;
    let mut res: usize = usize::MAX;

    for i in 0..m {
        for j in 0..n {
            if terrain[[i, j]].0 == b'E' {
                unvisited.push(Node::new([i, j], 0));
            }
        }
    }

    while let Some(node) = unvisited.pop() {
        let idx = node.idx;
        if !terrain[idx].1 {
            let elev = if terrain[idx].0 == b'E' { b'z' } else { terrain[idx].0 };
            let neighbor_idxs = [[idx[0].wrapping_sub(1), idx[1]                ],
                                 [idx[0] + 1            , idx[1]                ],
                                 [idx[0]                , idx[1].wrapping_sub(1)],
                                 [idx[0]                , idx[1] + 1            ]];
            for neighbor_idx in neighbor_idxs.into_iter() {
                if let Some(& (x, v)) = terrain.el(& neighbor_idx) {
                    if (x == b'S' || x == b'a') && (elev == b'a' || elev == b'b') {
                        res = node.cost + 1;
                        done = true;
                        break;
                    }
                    if !v && (x > elev || elev - x <= 1) {
                        unvisited.push(Node::new(neighbor_idx.clone(), node.cost + 1));
                    }
                }
            }
            terrain[idx].1 = true;
        }
        if done { break; }
    }

    println!("{}", res);
}