y2024d21p1 this is hard

This commit is contained in:
Fabian Schmidt 2024-12-23 14:57:40 +01:00
parent 985b88f0aa
commit 911a60ab6c
4 changed files with 557 additions and 0 deletions

View File

@ -0,0 +1,5 @@
340A
149A
582A
780A
463A

27
y2024/src/bin/d21.rs Normal file
View File

@ -0,0 +1,27 @@
use std::{fs, time::Instant};
use utils::time::get_elapsed_string;
use y2024::days::d21;
fn main() {
let now = Instant::now();
println!("Part 1:");
part1();
println!("Ran in {}", get_elapsed_string(now.elapsed()));
let now = Instant::now();
println!("Part 2:");
part2();
println!("Ran in {}", get_elapsed_string(now.elapsed()));
}
fn part1() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/21_input.txt")).unwrap();
println!("{}", d21::process_part1(&content));
}
fn part2() {
let root = env!("CARGO_MANIFEST_DIR");
let content = fs::read_to_string(format!("{root}/resources/21_input.txt")).unwrap();
println!("{}", d21::process_part2(&content));
}

523
y2024/src/days/d21.rs Normal file
View File

@ -0,0 +1,523 @@
use core::panic;
use std::{char, error::Error};
use itertools::Itertools;
pub fn process_part1(input: &str) -> usize {
input
.lines()
.map(|line| {
let numpad = Numpad::from(line);
println!("first robot {}", numpad.sequence);
let _ = Numpad::revert_from(&numpad.sequence);
let keypad_1 = Keypad::from(numpad.sequence.as_str());
println!("second robot {}", keypad_1.sequence);
let _ = Keypad::revert_from(&keypad_1.sequence);
let keypad_2 = Keypad::from(keypad_1.sequence.as_str());
println!("me {}", keypad_2.sequence);
let _ = Keypad::revert_from(&keypad_2.sequence);
keypad_2.sequence.len() * numeric_part(line)
})
.sum()
}
pub fn process_part2(input: &str) -> usize {
0
}
fn numeric_part(code: &str) -> usize {
let code = &code[..code.len() - 1];
code.parse().unwrap()
}
#[derive(Debug, Clone, Copy)]
enum NumpadState {
Seven,
Eight,
Nine,
Four,
Five,
Six,
One,
Two,
Three,
Zero,
A,
}
impl NumpadState {
fn get_col(&self) -> i32 {
match self {
NumpadState::Seven | NumpadState::Four | NumpadState::One => 0,
NumpadState::Eight | NumpadState::Five | NumpadState::Two | NumpadState::Zero => 1,
NumpadState::Nine | NumpadState::Six | NumpadState::Three | NumpadState::A => 2,
}
}
fn get_row(&self) -> i32 {
match self {
NumpadState::Seven | NumpadState::Eight | NumpadState::Nine => 0,
NumpadState::Four | NumpadState::Five | NumpadState::Six => 1,
NumpadState::One | NumpadState::Two | NumpadState::Three => 2,
NumpadState::Zero | NumpadState::A => 3,
}
}
fn get_sequence(&self, goto: NumpadState) -> String {
let row = self.get_row();
let col = self.get_col();
let goto_row = goto.get_row();
let goto_col = goto.get_col();
if row == goto_row && col == goto_col {
return "A".to_string();
}
let row_diff = row.abs_diff(goto_row);
let col_diff = col.abs_diff(goto_col);
let mut sequence = String::new();
let row_seq = match goto_row.cmp(&row) {
std::cmp::Ordering::Less => vec!["^"; row_diff as usize].join(""),
std::cmp::Ordering::Equal => "".to_string(),
std::cmp::Ordering::Greater => vec!["v"; row_diff as usize].join(""),
};
let col_seq = match goto_col.cmp(&col) {
std::cmp::Ordering::Less => vec!["<"; col_diff as usize].join(""),
std::cmp::Ordering::Equal => "".to_string(),
std::cmp::Ordering::Greater => vec![">"; col_diff as usize].join(""),
};
if (goto_col < col && row < 3) || col == 0 {
sequence.push_str(&col_seq);
sequence.push_str(&row_seq);
} else {
sequence.push_str(&row_seq);
sequence.push_str(&col_seq);
}
sequence.push('A');
sequence
}
}
impl TryFrom<char> for NumpadState {
type Error = Box<dyn Error>;
fn try_from(value: char) -> Result<Self, Self::Error> {
match value {
'A' => Ok(NumpadState::A),
'0' => Ok(NumpadState::Zero),
'1' => Ok(NumpadState::One),
'2' => Ok(NumpadState::Two),
'3' => Ok(NumpadState::Three),
'4' => Ok(NumpadState::Four),
'5' => Ok(NumpadState::Five),
'6' => Ok(NumpadState::Six),
'7' => Ok(NumpadState::Seven),
'8' => Ok(NumpadState::Eight),
'9' => Ok(NumpadState::Nine),
_ => Err(Box::from("Unrecognised keystate")),
}
}
}
impl TryFrom<(usize, usize)> for NumpadState {
type Error = Box<dyn Error>;
fn try_from(value: (usize, usize)) -> Result<Self, Self::Error> {
match value {
(2, 3) => Ok(NumpadState::A),
(1, 3) => Ok(NumpadState::Zero),
(0, 2) => Ok(NumpadState::One),
(1, 2) => Ok(NumpadState::Two),
(2, 2) => Ok(NumpadState::Three),
(0, 1) => Ok(NumpadState::Four),
(1, 1) => Ok(NumpadState::Five),
(2, 1) => Ok(NumpadState::Six),
(0, 0) => Ok(NumpadState::Seven),
(1, 0) => Ok(NumpadState::Eight),
(2, 0) => Ok(NumpadState::Nine),
(0, 3) => Err(Box::from("Robot arm hovering over numpad gap")),
(x, y) => {
let err = format!("Unrecognised numpad key coord ({x}, {y})");
Err(err.into())
}
}
}
}
impl From<NumpadState> for char {
fn from(value: NumpadState) -> Self {
match value {
NumpadState::Seven => '7',
NumpadState::Eight => '8',
NumpadState::Nine => '9',
NumpadState::Four => '4',
NumpadState::Five => '5',
NumpadState::Six => '6',
NumpadState::One => '1',
NumpadState::Two => '2',
NumpadState::Three => '3',
NumpadState::Zero => '0',
NumpadState::A => 'A',
}
}
}
struct Numpad {
state: NumpadState,
sequence: String,
}
impl Numpad {
fn press_key(&mut self, goto: NumpadState) {
let sequence = self.state.get_sequence(goto);
self.state = goto;
self.sequence.push_str(&sequence);
}
#[allow(dead_code)]
fn revert_from(sequence: &str) -> String {
let mut state = NumpadState::A;
let mut col_idx = 2;
let mut row_idx = 3;
let mut reverted = String::new();
for movements in sequence.split_inclusive("A") {
for movement in movements.chars() {
match movement {
'<' => {
col_idx -= 1;
state = NumpadState::try_from((col_idx, row_idx)).unwrap()
}
'>' => {
col_idx += 1;
state = NumpadState::try_from((col_idx, row_idx)).unwrap()
}
'^' => {
row_idx -= 1;
state = NumpadState::try_from((col_idx, row_idx)).unwrap()
}
'v' => {
row_idx += 1;
state = NumpadState::try_from((col_idx, row_idx)).unwrap()
}
'A' => {
reverted.push(state.into());
}
_ => panic!("Impossible"),
}
}
}
reverted
}
}
impl From<&str> for Numpad {
fn from(value: &str) -> Self {
let mut numpad = Numpad {
state: NumpadState::A,
sequence: String::new(),
};
let keys = value
.chars()
.map(|numkey| NumpadState::try_from(numkey).unwrap())
.collect_vec();
for key in keys {
numpad.press_key(key);
}
numpad
}
}
#[derive(Debug, Clone, Copy)]
enum KeypadState {
Up,
A,
Left,
Down,
Right,
}
impl KeypadState {
fn get_col(&self) -> i32 {
match self {
KeypadState::Left => 0,
KeypadState::Up | KeypadState::Down => 1,
KeypadState::A | KeypadState::Right => 2,
}
}
fn get_row(&self) -> i32 {
match self {
KeypadState::Up | KeypadState::A => 0,
KeypadState::Left | KeypadState::Down | KeypadState::Right => 1,
}
}
fn get_sequence(&self, goto: KeypadState) -> String {
let row = self.get_row();
let col = self.get_col();
let goto_row = goto.get_row();
let goto_col = goto.get_col();
if row == goto_row && col == goto_col {
return "A".to_string();
}
let row_diff = row.abs_diff(goto_row);
let col_diff = col.abs_diff(goto_col);
let mut sequence = String::new();
let row_seq = match goto_row.cmp(&row) {
std::cmp::Ordering::Less => vec!["^"; row_diff as usize].join(""),
std::cmp::Ordering::Equal => "".to_string(),
std::cmp::Ordering::Greater => vec!["v"; row_diff as usize].join(""),
};
let col_seq = match goto_col.cmp(&col) {
std::cmp::Ordering::Less => vec!["<"; col_diff as usize].join(""),
std::cmp::Ordering::Equal => "".to_string(),
std::cmp::Ordering::Greater => vec![">"; col_diff as usize].join(""),
};
if (goto_col < col && row == 1) || col == 0 {
sequence.push_str(&col_seq);
sequence.push_str(&row_seq);
} else {
sequence.push_str(&row_seq);
sequence.push_str(&col_seq);
}
sequence.push('A');
sequence
}
}
impl TryFrom<char> for KeypadState {
type Error = Box<dyn Error>;
fn try_from(value: char) -> Result<Self, Self::Error> {
match value {
'A' => Ok(KeypadState::A),
'<' => Ok(KeypadState::Left),
'>' => Ok(KeypadState::Right),
'v' => Ok(KeypadState::Down),
'^' => Ok(KeypadState::Up),
_ => Err(Box::from("Unrecognised keystate")),
}
}
}
impl TryFrom<(usize, usize)> for KeypadState {
type Error = Box<dyn Error>;
fn try_from(value: (usize, usize)) -> Result<Self, Self::Error> {
match value {
(2, 0) => Ok(KeypadState::A),
(0, 1) => Ok(KeypadState::Left),
(2, 1) => Ok(KeypadState::Right),
(1, 1) => Ok(KeypadState::Down),
(1, 0) => Ok(KeypadState::Up),
(0, 0) => Err(Box::from("Robot arm hovering over keypad gap")),
(x, y) => {
let err = format!("Unrecognised key coord ({x}, {y})");
Err(err.into())
}
}
}
}
impl From<KeypadState> for char {
fn from(value: KeypadState) -> Self {
match value {
KeypadState::A => 'A',
KeypadState::Up => '^',
KeypadState::Left => '<',
KeypadState::Down => 'v',
KeypadState::Right => '>',
}
}
}
struct Keypad {
state: KeypadState,
sequence: String,
}
impl Keypad {
fn press_key(&mut self, goto: KeypadState) {
let sequence = self.state.get_sequence(goto);
self.state = goto;
self.sequence.push_str(&sequence);
}
#[allow(dead_code)]
fn revert_from(sequence: &str) -> String {
let mut state = KeypadState::A;
let mut col_idx = 2;
let mut row_idx = 0;
let mut reverted = String::new();
for movements in sequence.split_inclusive("A") {
for movement in movements.chars() {
match movement {
'<' => {
col_idx -= 1;
state = KeypadState::try_from((col_idx, row_idx)).unwrap()
}
'>' => {
col_idx += 1;
state = KeypadState::try_from((col_idx, row_idx)).unwrap()
}
'^' => {
row_idx -= 1;
state = KeypadState::try_from((col_idx, row_idx)).unwrap()
}
'v' => {
row_idx += 1;
state = KeypadState::try_from((col_idx, row_idx)).unwrap()
}
'A' => {
reverted.push(state.into());
}
_ => panic!("Impossible"),
}
}
}
reverted
}
}
impl From<&str> for Keypad {
fn from(value: &str) -> Self {
let mut numpad = Keypad {
state: KeypadState::A,
sequence: String::new(),
};
let keys = value
.chars()
.map(|numkey| KeypadState::try_from(numkey).unwrap())
.collect_vec();
for key in keys {
numpad.press_key(key);
}
numpad
}
}
#[cfg(test)]
mod tests {
use rayon::result;
use super::*;
const INPUT_1: &str = "029A";
const INPUT_2: &str = "980A";
const INPUT_3: &str = "179A";
const INPUT_4: &str = "456A";
const INPUT_5: &str = "379A";
//const INPUT_1_BACK: &str =
// "<vA<AA>>^AvAA<^A>A<v<A>>^AvA^A<vA>^A<v<A>^A>AAvA^A<v<A>A>^AAAvA<^A>A";
//const INPUT_2_BACK: &str = "<v<A>>^AAAvA^A<vA<AA>>^AvAA<^A>A<v<A>A>^AAAvA<^A>A<vA>^A<A>A";
//const INPUT_3_BACK: &str =
// "<v<A>>^A<vA<A>>^AAvAA<^A>A<v<A>>^AAvA^A<vA>^AA<A>A<v<A>A>^AAAvA<^A>A";
//const INPUT_4_BACK: &str = "<v<A>>^AA<vA<A>>^AAvAA<^A>A<vA>^A<A>A<vA>^A<A>A<v<A>A>^AAvA<^A>A";
const INPUT_5_BACK: &str = "<v<A>>^AvA^A<vA<AA>>^AAvA<^A>AAvA^A<vA>^AA<A>A<v<A>A>^AAAvA<^A>A";
#[test]
fn part1_full() {
let result = process_part1(&[INPUT_1, INPUT_2, INPUT_3, INPUT_4, INPUT_5].join("\n"));
assert_eq!(result, 126384);
}
#[test]
fn part1_1() {
let result = process_part1(INPUT_1);
assert_eq!(result, 29 * 68);
}
#[test]
fn part1_2() {
let result = process_part1(INPUT_2);
assert_eq!(result, 60 * 980);
}
#[test]
fn part1_3() {
let result = process_part1(INPUT_3);
assert_eq!(result, 68 * 179);
}
#[test]
fn part1_4() {
let result = process_part1(INPUT_4);
assert_eq!(result, 64 * 456);
}
#[test]
fn part1_5() {
let result = process_part1(INPUT_5);
assert_eq!(result, 64 * 379);
}
#[test]
fn part1_edge() {
let code = "1";
let numpad = Numpad::from(code);
let keypad_1 = Keypad::from(numpad.sequence.as_str());
assert_eq!(numpad.sequence, "^<<A");
assert_eq!(keypad_1.sequence, "<Av<AA>>^A");
}
//#[test]
//fn part1_1_back() {
// let result = Keypad::revert_from(INPUT_1_BACK);
// let result = Keypad::revert_from(&result);
// let result = Numpad::revert_from(&result);
// assert_eq!(result, "029A");
//}
//#[test]
//fn part1_2_back() {
// let result = Keypad::revert_from(INPUT_2_BACK);
// let result = Keypad::revert_from(&result);
// let result = Numpad::revert_from(&result);
// assert_eq!(result, "980A");
//}
//#[test]
//fn part1_3_back() {
// let result = Keypad::revert_from(INPUT_3_BACK);
// let result = Keypad::revert_from(&result);
// let result = Numpad::revert_from(&result);
// assert_eq!(result, "179A");
//}
//#[test]
//fn part1_4_back() {
// let result = Keypad::revert_from(INPUT_4_BACK);
// let result = Keypad::revert_from(&result);
// let result = Numpad::revert_from(&result);
// assert_eq!(result, "456A");
//}
#[test]
fn part1_5_back() {
let result = Keypad::revert_from(INPUT_5_BACK);
println!("back 1 {result}");
let result = Keypad::revert_from(&result);
println!("back 2 {result}");
let result = Numpad::revert_from(&result);
assert_eq!(result, "379A");
}
//#[test]
//fn part1_5_backnforth() {
// let numpad = Numpad::from(INPUT_5);
// let keypad_1 = Keypad::from(numpad.sequence.as_str());
// let keypad_2 = Keypad::from(keypad_1.sequence.as_str());
// let keypad_1_back = Keypad::revert_from(INPUT_5_BACK);
// let numpad_back = Keypad::revert_from(&keypad_1_back);
// let code = Numpad::revert_from(&numpad_back);
// //assert_eq!(code, INPUT_5);
// assert_eq!(numpad_back, numpad.sequence);
// //assert_eq!(keypad_1_back, keypad_1.sequence);
// //assert_eq!(INPUT_5_BACK, keypad_2.sequence);
//}
#[test]
fn part2() {
let result = process_part2(INPUT_1);
assert_eq!(result, 0);
}
}

View File

@ -29,3 +29,5 @@ pub mod d18;
pub mod d19;
pub mod d20;
pub mod d21;