|
1 | 1 | use aoc::{common, io}; |
2 | 2 |
|
| 3 | +fn first_unordered_index(sequence: &[usize], page_orderings: &[[usize; 2]]) -> Option<usize> { |
| 4 | + let unordered_indices: Vec<usize> = sequence |
| 5 | + .windows(2) |
| 6 | + .enumerate() |
| 7 | + .filter(|(_, x)| !page_orderings.contains(&[x[0], x[1]])) |
| 8 | + .map(|(i, _)| i) |
| 9 | + .collect(); |
| 10 | + |
| 11 | + unordered_indices.first().copied() |
| 12 | +} |
| 13 | + |
3 | 14 | // Only works when the input page_orderings have ALL NxN relationships / or all relationships |
4 | 15 | // that occur in the page_sequences. Otherwise all transitive relationships, such as A->C |
5 | 16 | // given A->B and B->C should be additionally added to the page_orderings to make this algorithm work. |
6 | 17 | fn solve<const PART: usize>(input: &str) -> usize { |
7 | | - let mut page_orderings: Vec<(usize, usize)> = Vec::new(); |
8 | | - let mut page_sequences: Vec<Vec<usize>> = Vec::new(); |
9 | | - |
10 | | - for line in input.lines() { |
11 | | - if line.is_empty() { |
12 | | - continue; |
| 18 | + let batches = io::line_batches(input); |
| 19 | + let page_orderings: Vec<[usize; 2]> = batches[0].iter().fold(vec![], |mut acc, x| { |
| 20 | + if let Some((page1, page2)) = x.split_once('|') { |
| 21 | + acc.push([io::parse_num(page1), io::parse_num(page2)]); |
13 | 22 | } |
14 | | - if line.chars().any(|x| x == '|') { |
15 | | - let page_nums: Vec<usize> = io::tokenize_nums(line, "|"); |
16 | | - page_orderings.push((page_nums[0], page_nums[1])); |
17 | | - } else { |
18 | | - let seq: Vec<usize> = io::tokenize_nums(line, ","); |
19 | | - page_sequences.push(seq); |
20 | | - } |
21 | | - } |
| 23 | + acc |
| 24 | + }); |
| 25 | + let page_sequences: Vec<Vec<usize>> = batches[1].iter().fold(vec![], |mut acc, x| { |
| 26 | + acc.push(io::tokenize_nums(x, ",")); |
| 27 | + acc |
| 28 | + }); |
22 | 29 |
|
23 | | - let mut ans = 0; |
24 | | - for seq in page_sequences { |
25 | | - let l = seq.len(); |
26 | | - |
27 | | - let mut ordered = true; |
28 | | - for i in 1..l { |
29 | | - if !page_orderings.contains(&(seq[i - 1], seq[i])) { |
30 | | - ordered = false; |
31 | | - } |
32 | | - } |
33 | | - |
34 | | - if ordered { |
35 | | - if PART == 1 { |
36 | | - ans += seq[l / 2]; |
37 | | - } |
38 | | - } else if PART == 2 { |
39 | | - let mut new_seq = seq.clone(); |
40 | | - while !ordered { |
41 | | - ordered = true; |
42 | | - for i in 1..l { |
43 | | - if !page_orderings.contains(&(new_seq[i - 1], new_seq[i])) { |
44 | | - new_seq.swap(i - 1, i); |
45 | | - ordered = false; |
46 | | - break; |
47 | | - } |
| 30 | + page_sequences |
| 31 | + .iter() |
| 32 | + .map(|seq| { |
| 33 | + if first_unordered_index(seq, &page_orderings).is_none() { |
| 34 | + if PART == 1 { |
| 35 | + seq[seq.len() / 2] |
| 36 | + } else { |
| 37 | + 0 |
48 | 38 | } |
49 | | - |
50 | | - if ordered { |
51 | | - ans += new_seq[l / 2]; |
| 39 | + } else if PART == 2 { |
| 40 | + let mut new_seq = seq.clone(); |
| 41 | + while let Some(unordered_index) = first_unordered_index(&new_seq, &page_orderings) { |
| 42 | + new_seq.swap(unordered_index, unordered_index + 1); |
52 | 43 | } |
| 44 | + new_seq[seq.len() / 2] |
| 45 | + } else { |
| 46 | + 0 |
53 | 47 | } |
54 | | - } |
55 | | - } |
56 | | - |
57 | | - ans |
| 48 | + }) |
| 49 | + .sum() |
58 | 50 | } |
59 | 51 |
|
60 | 52 | fn main() { |
|
0 commit comments