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

use std::io::{BufRead};
use std::collections::{HashMap, HashSet};
use std::ops::{IndexMut};

pub type Matrix = tensor::Tensor<(bool, u64), 2>;
pub type Index = tensor::Index<2>;

fn read_board(handle: &mut std::io::StdinLock) -> Option<Matrix> {
    let mut lines = handle.lines();
    let first_line = lines.next()?.ok()?;
    let mut words = first_line.split_whitespace();
    let mut data: Vec<(bool, u64)> = words.map(|x| (false, x.parse().expect("Malformed input"))).collect();
    let n = data.len();
    for i in 1..n {
        let line = lines.next().expect("Malformed input").expect("IO error");
        let mut words = line.split_whitespace();
        data.extend(words.map(|x| (false, x.parse::<u64>().expect("Malformed input"))));
    }
    lines.next();
    Some(Matrix::new_from([n, n], data))
}

fn is_board_winning(board: & Matrix, pivot: Index) -> bool {
    let mut win_row = true;
    for j in 0..board.shape()[1] {
        if !board[[pivot[0], j]].0 { win_row = false; break; }
    }
    if win_row { return true; }
    let mut win_col = true;
    for i in 0..board.shape()[0] {
        if !board[[i, pivot[1]]].0 { win_col = false; break; }
    }
    win_col
}

fn board_score(board: & Matrix) -> u64 {
    board.data().into_iter().filter(|x| !x.0).map(|x| x.1).sum()
}

pub fn main() {
    let mut stdin = std::io::stdin();
    
    let numbers: Vec<u64> = {
        let mut handle = stdin.lock();
        let mut lines = handle.lines();
        let line = lines.next().expect("Malformed input").expect("IO error");
        let mut words = line.split(',');
        words.map(|s| s.parse().expect("Malformed input")).collect()
    };

    {
        let mut handle = stdin.lock();
        let mut lines = handle.lines();
        lines.next();
    }
    let mut handle = stdin.lock();

    let mut boards: Vec<Matrix> = Vec::new();
    let mut inverse: HashMap<u64, Vec<(usize, Index)>> = HashMap::new();
    
    while let Some(mat) = read_board(&mut handle) {
        let shape = mat.shape();
        for i in 0..shape[0] {
            for j in 0..shape[1] {
                let x = mat[[i, j]].1;
                if let Some(k) = inverse.get_mut(&x) {
                    k.push((boards.len(), [i, j]));
                }
                else { inverse.insert(x, vec![(boards.len(), [i, j])]); }
            }
        }
        boards.push(mat);
    }

    //println!("Got {} boards and {} inv maps elements.", boards.len(), inverse.len());
    let mut boards_not_yet_won: HashSet<usize> = HashSet::new();
    boards_not_yet_won.extend(0..boards.len());
    for x in numbers.into_iter() {
        for (board_num, idx) in inverse.get(&x).unwrap().into_iter() {
            //println!("Marking ({}, {}) on board {}", idx[0], idx[1], board_num);
            let board: &mut Matrix = boards.index_mut(*board_num);
            board[idx].0 = true;
            if is_board_winning(board, *idx) {
                boards_not_yet_won.remove(board_num);
                if boards_not_yet_won.is_empty() {
                    println!("{}", board_score(board)*x);
                    return;
                }
                //winning_boards.push((*board_num, board_score(board)*x));
            }
        }
    }
}