-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
537 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
use aoc::common; | ||
use aoc::io; | ||
|
||
fn solve<const PART: usize>(input: &str) -> usize { | ||
let mut lst1 = Vec::new(); | ||
let mut lst2 = Vec::new(); | ||
for line in input.lines() { | ||
let nums = io::tokenize(line, " "); | ||
let a: usize = io::parse_num(nums[0]); | ||
let b: usize = io::parse_num(nums[1]); | ||
lst1.push(a); | ||
lst2.push(b); | ||
} | ||
lst1.sort(); | ||
lst2.sort(); | ||
let mut ans = 0; | ||
if PART == 1 { | ||
for (a, b) in lst1.iter().zip(lst2.iter()) { | ||
ans += a.max(b) - a.min(b); | ||
} | ||
} else { | ||
ans = lst1 | ||
.iter() | ||
.map(|n| lst2.iter().filter(|x| *x == n).count() * n) | ||
.sum(); | ||
} | ||
|
||
ans | ||
} | ||
|
||
fn main() { | ||
let input = common::get_input(); | ||
common::timed(&input, solve::<1>, true); | ||
common::timed(&input, solve::<2>, false); | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
#[test] | ||
fn test_samples() { | ||
let sample_input = "3 4\n4 3\n2 5\n1 3\n3 9\n3 3"; | ||
assert_eq!(solve::<1>(sample_input), 11); | ||
assert_eq!(solve::<2>(sample_input), 31); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
use aoc::common; | ||
use aoc::io; | ||
|
||
fn diff_vec(seq: &[usize]) -> Vec<i32> { | ||
let mut num_diffs: Vec<i32> = Vec::new(); | ||
for i in 1..seq.len() { | ||
num_diffs.push(seq[i] as i32 - seq[i - 1] as i32); | ||
} | ||
num_diffs | ||
} | ||
|
||
fn good_difference(seq: &[usize]) -> bool { | ||
let diff_seq = diff_vec(seq); | ||
const ALLOWED_DIFF_POS: [i32; 3] = [1, 2, 3]; | ||
const ALLOWED_DIFF_NEG: [i32; 3] = [-1, -2, -3]; | ||
diff_seq.iter().all(|x| ALLOWED_DIFF_POS.contains(x)) | ||
|| diff_seq.iter().all(|x| ALLOWED_DIFF_NEG.contains(x)) | ||
} | ||
|
||
fn good_sequence<const PART: usize>(seq: &[usize]) -> bool { | ||
if good_difference(seq) { | ||
return true; | ||
} else if PART == 2 { | ||
for drop_idx in 0..seq.len() { | ||
let mut seq_new = seq.to_vec(); | ||
seq_new.remove(drop_idx); | ||
if good_difference(&seq_new) { | ||
return true; | ||
} | ||
} | ||
} | ||
false | ||
} | ||
|
||
fn solve<const PART: usize>(input: &str) -> usize { | ||
let mut ans = 0; | ||
for report in input.lines() { | ||
let sequence_str = io::tokenize(report, " "); | ||
let sequence = sequence_str | ||
.iter() | ||
.map(|x| io::parse_num(x)) | ||
.collect::<Vec<usize>>(); | ||
ans += if good_sequence::<PART>(&sequence) { | ||
1 | ||
} else { | ||
0 | ||
}; | ||
} | ||
ans | ||
} | ||
|
||
fn main() { | ||
let input = common::get_input(); | ||
//println!("{input:?}"); | ||
common::timed(&input, solve::<1>, true); | ||
common::timed(&input, solve::<2>, false); | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
#[test] | ||
fn test_samples() { | ||
let sample_input = "7 6 4 2 1\n1 2 7 8 9\n9 7 6 2 1\n1 3 2 4 5\n8 6 4 4 1\n1 3 6 7 9"; | ||
assert_eq!(solve::<1>(sample_input), 2); | ||
assert_eq!(solve::<2>(sample_input), 4); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
use aoc::common; | ||
use aoc::io; | ||
use itertools::Itertools; | ||
|
||
fn is_num(s: &str) -> bool { | ||
s.chars().all(|x| x.is_ascii_digit()) | ||
} | ||
|
||
// the ....mul(X,Y)...... part | ||
fn solve_muls(input: &str) -> usize { | ||
let mut ans = 0; | ||
for pattern in io::tokenize(input, "mul(") { | ||
let tokens1 = io::tokenize(pattern, ","); | ||
let num1 = tokens1.first().unwrap(); | ||
// check if num1 has all digits | ||
if is_num(num1) { | ||
let n1: usize = io::parse_num(num1); | ||
let tokens2 = io::tokenize(tokens1[1], ")"); | ||
let num2 = tokens2.first().unwrap(); | ||
if is_num(num2) { | ||
let n2: usize = io::parse_num(num2); | ||
ans += n1 * n2; | ||
} | ||
} | ||
} | ||
ans | ||
} | ||
|
||
fn solve<const PART: usize>(input: &str) -> usize { | ||
let mut ans = 0; | ||
|
||
if PART == 1 { | ||
ans = solve_muls(input); | ||
} else { | ||
let indices = input | ||
.match_indices("do()") | ||
.chain(input.match_indices("don't()")) | ||
.sorted_by_key(|x| x.0); | ||
|
||
let mut last_idx = 0; | ||
let mut yes: bool = true; | ||
for (idx, ins) in indices { | ||
if yes { | ||
ans += solve_muls(&input[last_idx..idx]); | ||
} | ||
last_idx = idx; | ||
yes = ins == "do()"; | ||
} | ||
|
||
if yes { | ||
ans += solve_muls(&input[last_idx..]); | ||
} | ||
} | ||
|
||
ans | ||
} | ||
|
||
fn main() { | ||
let input = common::get_input(); | ||
println!("{input:?}"); | ||
common::timed(&input, solve::<1>, true); | ||
common::timed(&input, solve::<2>, false); | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
#[test] | ||
fn test_samples() { | ||
let sample_input1 = | ||
"xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))"; | ||
let sample_input2 = | ||
"xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))"; | ||
assert_eq!(solve::<1>(sample_input1), 161); | ||
assert_eq!(solve::<2>(sample_input2), 48); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
use aoc::{common, grid::Grid}; | ||
|
||
fn solve2(input: &str) -> usize { | ||
let mut ans = 0; | ||
let grid = Grid::from_str(input, |c| c); | ||
|
||
const DIRS: [(i32, i32); 4] = [(1, 1), (-1, 1), (-1, -1), (1, -1)]; | ||
const ADJ_DIRS: [(usize, usize); 4] = [(0, 1), (1, 2), (2, 3), (3, 0)]; | ||
|
||
let a_positions = grid.positions('A'); | ||
|
||
for a_pos in a_positions.iter() { | ||
for (i1, i2) in ADJ_DIRS.iter() { | ||
let m_pos = [DIRS[*i1], DIRS[*i2]]; | ||
let s_pos = [DIRS[(*i1 + 2) % 4], DIRS[(*i2 + 2) % 4]]; | ||
|
||
let num_desired_m_pos = grid | ||
.adjacent_in_dir(a_pos, &m_pos) | ||
.iter() | ||
.filter(|x| grid.get(x) == 'M') | ||
.count(); | ||
let num_desired_s_pos = grid | ||
.adjacent_in_dir(a_pos, &s_pos) | ||
.iter() | ||
.filter(|x| grid.get(x) == 'S') | ||
.count(); | ||
|
||
if num_desired_m_pos == 2 && num_desired_s_pos == 2 { | ||
ans += 1; | ||
} | ||
} | ||
} | ||
|
||
ans | ||
} | ||
|
||
fn solve1(input: &str) -> usize { | ||
let mut ans = 0; | ||
let grid = Grid::from_str(input, |c| c); | ||
|
||
const DIRS: [(i32, i32); 8] = [ | ||
(-1, 0), | ||
(0, -1), | ||
(1, 0), | ||
(0, 1), | ||
(-1, 1), | ||
(1, -1), | ||
(1, 1), | ||
(-1, -1), | ||
]; | ||
|
||
for x_pos in grid.positions('X').iter() { | ||
for dir in DIRS { | ||
let mut pos = vec![*x_pos]; | ||
let mut count = 0; | ||
for ch in ['M', 'A', 'S'] { | ||
pos = grid.adjacent_in_dir(&pos[0], &[dir]); | ||
if pos.is_empty() || grid.get(&pos[0]) != ch { | ||
break; | ||
} | ||
count += 1; | ||
} | ||
|
||
if count == 3 { | ||
ans += 1; | ||
} | ||
} | ||
} | ||
|
||
ans | ||
} | ||
|
||
fn main() { | ||
let input = common::get_input(); | ||
//println!("{input:?}"); | ||
common::timed(&input, solve1, true); | ||
common::timed(&input, solve2, false); | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
#[test] | ||
fn test_samples() { | ||
let sample_input = | ||
"MMMSXXMASM\nMSAMXMSMSA\nAMXSXMAAMM\nMSAMASMSMX\nXMASAMXAMM\nXXAMMXXAMA\nSMSMSASXSS\nSAXAMASAAA\nMAMMMXMMMM\nMXMXAXMASX"; | ||
assert_eq!(solve1(sample_input), 18); | ||
assert_eq!(solve2(sample_input), 9); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
use aoc::{common, io}; | ||
|
||
// Only works when the input page_orderings have ALL NxN relationships / or all relationships | ||
// that occur in the page_sequences. Otherwise all transitive relationships, such as A->C | ||
// given A->B and B->C should be additionally added to the page_orderings to make this algorithm work. | ||
fn solve<const PART: usize>(input: &str) -> usize { | ||
let mut page_orderings: Vec<(usize, usize)> = Vec::new(); | ||
let mut page_sequences: Vec<Vec<usize>> = Vec::new(); | ||
|
||
for line in input.lines() { | ||
if line.is_empty() { | ||
continue; | ||
} | ||
if line.chars().any(|x| x == '|') { | ||
let page_nums: Vec<usize> = io::tokenize(line, "|") | ||
.into_iter() | ||
.map(io::parse_num) | ||
.collect(); | ||
page_orderings.push((page_nums[0], page_nums[1])); | ||
} else { | ||
let seq: Vec<usize> = io::tokenize(line, ",") | ||
.into_iter() | ||
.map(io::parse_num) | ||
.collect(); | ||
page_sequences.push(seq); | ||
} | ||
} | ||
|
||
let mut ans = 0; | ||
for seq in page_sequences { | ||
let l = seq.len(); | ||
|
||
let mut ordered = true; | ||
for i in 1..l { | ||
if !page_orderings.contains(&(seq[i - 1], seq[i])) { | ||
ordered = false; | ||
} | ||
} | ||
|
||
if ordered { | ||
if PART == 1 { | ||
ans += seq[l / 2]; | ||
} | ||
} else if PART == 2 { | ||
let mut new_seq = seq.clone(); | ||
while !ordered { | ||
ordered = true; | ||
for i in 1..l { | ||
if !page_orderings.contains(&(new_seq[i - 1], new_seq[i])) { | ||
new_seq.swap(i - 1, i); | ||
ordered = false; | ||
break; | ||
} | ||
} | ||
|
||
if ordered { | ||
ans += new_seq[l / 2]; | ||
} | ||
} | ||
} | ||
} | ||
|
||
ans | ||
} | ||
|
||
fn main() { | ||
let input = common::get_input(); | ||
//println!("{input:?}"); | ||
common::timed(&input, solve::<1>, true); | ||
common::timed(&input, solve::<2>, false); | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
#[test] | ||
fn test_samples() { | ||
let sample_input = | ||
"47|53\n97|13\n97|61\n97|47\n75|29\n61|13\n75|53\n29|13\n97|29\n53|29\n61|53\n97|53\n61|29\n47|13\n75|47\n97|75\n47|61\n75|61\n47|29\n75|13\n53|13\n\n75,47,61,53,29\n97,61,53,29,13\n75,29,13\n75,97,47,61,53\n61,13,29\n97,13,75,29,47"; | ||
assert_eq!(solve::<1>(sample_input), 143); | ||
assert_eq!(solve::<2>(sample_input), 123); | ||
} | ||
} |
Oops, something went wrong.