Add 2024 Quest 5

This commit is contained in:
Chris Alge 2024-11-09 16:55:37 +01:00
parent f4153f6135
commit 22d0b8bea7
9 changed files with 539 additions and 0 deletions

View file

@ -0,0 +1,6 @@
[package]
name = "day05_pseudo-random_clap_dance"
version = "0.1.0"
edition = "2021"
[dependencies]

View file

@ -0,0 +1,232 @@
Part I
No grand tournament is complete without lively music and spirited dancing! As evening falls, crowds gather in the main square to partake in the whimsical Pseudo-Random Clap Dance. Each participant receives a number from the Master of Ceremonies which is then prominently displayed on their chest. Then, they choose their places in one of four columns, standing one behind the other, forming long lines.
With everyone in position, the dance begins. It unfolds in rounds, with each round featuring one person designated as the Clapper. In the first round, the Clapper is the first person in the first column. In the second round, it's the first person in the second column, followed by the first person in the third column in the third round, and finally, the first person in the fourth column in the fourth round.
The Clapper moves to the beginning of the column to their right, facing its members. If the Clapper is from the fourth column, they move to the start of the first column. All members of that column extend their arms to the sides. The Clapper then dances around the column from the left, high-fiving each extended hand. Upon reaching the end of the column, they switch to the right side and continue in the opposite direction. The crowd counts each clap out loud, starting from one. When the shouted number matches the Clapper's chest number, an absorption occurs.
A Clapper can be absorbed into the column in two ways. If they are circling from the left side, they are absorbed in front of the person they are high-fiving. If on the right side, they are absorbed behind that person.
After absorption, the first person from each column combines their numbers into a single large number, shouting it out loud before the next round begins.
Just before the start, the king delivers a brief speech, concluding with a caution to the knights participating in the tournament to remain vigilant! You decide to practice predicting the flow of the dance, so you note down all columns as seen from above.
Example based on the following notes:
2 3 4 5
3 4 5 2
4 5 2 3
5 2 3 4
The first Clapper is the person marked with 2 on the top left side. After the initial move to the next column, it looks like this:
2
3 3 4 5
4 4 5 2
5 5 2 3
2 3 4
Clapping time! The Clapper's number is 2, so there will be only 2 claps.
"ONE!"
323 4 5
4 4 5 2
5 5 2 3
2 3 4 "TWO!"
3 3 4 5
424 5 2
5 5 2 3
2 3 4
The Clapper is on the left side of the target column, so absorption results in them taking the place in front of the last high-fived dancer.
3 3 4 5
4 2 5 2
5 4 2 3
5 3 4
2
The people in the front combine their numbers and shout:
"3345!"
3 3 4 5
4 2 5 2
5 4 2 3
5 3 4
2
The result of the first round is 3345.
The second round goes like this:
3 3 4 5
4 2 5 2
5 4 2 3
5 3 4
2 3
3 2 4 5
4 4 5 2
5 5 2 3
2 3 4
"ONE!"
3 234 5
4 4 5 2
5 5 2 3
2 3 4
"TWO!"
3 2 4 5
4 435 2
5 5 2 3
2 3 4
"THREE!"
3 2 4 5
4 4 5 2
5 532 3
2 3 4
3 2 4 5
4 4 5 2
5 5 3 3
2 2 4
3 "3245!"
3 2 4 5
4 4 5 2
5 5 3 3
2 2 4
3
The third round:
3 2 4 5
4 4 5 2
5 5 3 3
2 2 4
3 4
3 2 5 5
4 4 3 2
5 5 2 3
2 3 4
"ONE!"
3 2 545
4 4 3 2
5 5 2 3
2 3 4
"TWO!"
3 2 5 5
4 4 342
5 5 2 3
2 3 4
"THREE!"
3 2 5 5
4 4 3 2
5 5 243
2 3 4
"FOUR!"
3 2 5 5
4 4 3 2
5 5 2 3
2 344
3 2 5 5
4 4 3 2
5 5 2 3
2 3 4
4 "3255!"
3 2 5 5
4 4 3 2
5 5 2 3
2 3 4
4
The following round:
3 2 5 5
4 4 3 2
5 5 2 3
2 3 4
4 5
3 2 5 2
4 4 3 3
5 5 2 4
2 3 4
"ONE!"
53 2 5 2
4 4 3 3
5 5 2 4
2 3 4
"TWO!"
3 2 5 2
54 4 3 3
5 5 2 4
2 3 4
"THREE!"
3 2 5 2
4 4 3 3
55 5 2 4
2 3 4
"FOUR!"
3 2 5 2
4 4 3 3
555 2 4
2 3 4
"FIVE!"
3 2 5 2
454 3 3
5 5 2 4
2 3 4
3 2 5 2
4 4 3 3
5 5 2 4
5 2 3 4
"3252!"
3 2 5 2
4 4 3 3
5 5 2 4
5 2 3 4
Note that the Clapper ends on the right side of the column, so the target place in this case is behind the last high-fived person.
For this example, the numbers shouted at the end of each round are as follows:
Round Number
1: 3345
2: 3245
3: 3255
4: 3252
5: 4252
6: 4452
7: 4422
8: 4423
9: 2423
10: 2323
What is the number shouted at the end of the 10th round?
Part II
The first dance went exactly as you predicted, so you feel ready for the real challenge.
For the upcoming dance, the master of ceremonies meticulously assigns numbers and personally positions the participants in columns. The king takes the stage once more:
As you know, in our traditional dance some of the numbers shouted at the end of each round
can eventually repeat. The next dance will conclude in the round where one of the numbers
at the end of the round is shouted for the 2024th time! Your task, my dear knights,
is to predict this number and the duration of the dance. Multiply the final number
by the round in which it was shouted for the 2024th time to get your final answer.
Good luck!
Example based on the following notes:
2 3 4 5
6 7 8 9
In this example, the dance unfolds as follows:
Round Number Shouts
1: 6345 1
2: 6245 1
3: 6285 1
4: 5284 1
5: 6584 1
6: 6254 1
7: 6285 2
8: 5284 2
9: 6584 2
10: 6254 2
...
8095: 6285 2024
After 10 rounds, some numbers were shouted twice already: 6285, 5284, 6584, and 6254. By continuing further, the first number shouted for the 2024th time is 6285, and this happens at the end of round 8095.
Multiplying 6285 by 8095 gives the final answer: 50877075.
What do you get if you multiply the first number shouted for the 2024th time by the total number of dance rounds?
Part III
Time for the final dance! The Master of Ceremonies once again arranges everyone with the utmost care.
The king presents another riddle:
Sadly, every good time must come to an end eventually,
but what if our next dance were to go on forever?
Can you predict what would be the highest number that could be shouted?
Example based on the following notes:
2 3 4 5
6 7 8 9
Assuming this dance would never end, the highest number shouted would be: 6584.
What is the highest possible number that can appear at the end of a round in the final dance?

View file

@ -0,0 +1,139 @@
use core::fmt::{Display, Write};
use std::collections::{BTreeMap, HashMap, VecDeque};
#[derive(Debug, PartialEq, Eq)]
pub enum ParseError {
GridMalformed(usize, usize, usize),
ParseIntError(String),
}
impl Display for ParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::GridMalformed(first, idx, len) => write!(f, "Grid is not rectangular: First line has {first} items, but line {idx} has {len}."),
Self::ParseIntError(e) => write!(f, "Unable to parse into a number: {e}"),
}
}
}
struct Dancers {
dancers: Vec<VecDeque<usize>>,
columns: usize,
round: usize,
}
impl TryFrom<&str> for Dancers {
type Error = ParseError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let columns = value.lines().next().unwrap_or_default().split_whitespace().count();
let mut dancers = vec![VecDeque::new(); columns];
for (y, l) in value.lines().enumerate() {
let numbers: Vec<_> = l.split_whitespace().map(|c| c.parse::<usize>().map_err(|_| ParseError::ParseIntError(c.to_string()))).collect::<Result<Vec<_>, _>>()?;
if numbers.len() != columns {
return Err(Self::Error::GridMalformed(columns, y, numbers.len()));
}
numbers.iter().enumerate().for_each(|(x, n)| dancers[x].push_back(*n));
}
Ok(Self { dancers, columns, round: 0 })
}
}
impl Dancers {
fn dance(&mut self) -> usize {
let clapper = self.dancers[self.round % self.columns].pop_front().unwrap();
self.round += 1;
let column = &mut self.dancers[self.round % self.columns];
let direction = (clapper-1) / column.len();
let residual = clapper % column.len();
if direction & 1 == 0 {
// left side
if residual == 0 {
column.insert(column.len()-1, clapper);
} else {
column.insert(residual-1, clapper);
}
} else {
//right side
if residual == 0 {
column.insert(1, clapper)
} else {
column.insert(column.len()-residual+1, clapper)
}
}
self.dancers.iter().fold(String::new(), |mut output, c| {
let _ = write!(output, "{}", c.front().unwrap());
output
}).parse().unwrap()
}
}
pub fn run(input: &str, part: usize) -> Result<usize, ParseError> {
let mut dancers = Dancers::try_from(input)?;
match part {
1 => {
for _ in 0..9 { dancers.dance(); }
Ok(dancers.dance())
},
2 => {
// There are probably loops in the results to be exploited here, but I don't see how
// to spot them algorithmically and saving the entire state after each dance, just
// to look for repetitions, seems excessive.
let mut numbers = HashMap::new();
loop {
let this = dancers.dance();
let repetitions: usize = *numbers.get(&this).unwrap_or(&0);
if repetitions == 2023 {
return Ok(this * dancers.round);
} else {
numbers.insert(this, repetitions+1);
}
}
},
3 => {
// Admittedly, there is no proof that no more higher numbers will appear later.
// But I simply hope that at the point at which a number repeats itself for the
// 10th time, no more new ones will appear.
let mut numbers = BTreeMap::new();
loop {
let this = dancers.dance();
let repetitions: usize = *numbers.get(&this).unwrap_or(&0);
if repetitions == 9 {
return Ok(numbers.pop_last().unwrap().0);
} else {
numbers.insert(this, repetitions+1);
}
}
},
_ => panic!("Illegal part number"),
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::read_to_string;
fn read_file(name: &str) -> String {
read_to_string(name).expect(&format!("Unable to read file: {name}")[..]).trim().to_string()
}
#[test]
fn test_sample() {
let expected = [2323, 50877075, 6584];
for part in 1..=3 {
let sample_input = read_file(&format!("tests/sample{part}"));
assert_eq!(run(&sample_input, part), Ok(expected[part-1]));
}
}
#[test]
fn test_challenge() {
let expected = [2232, 14029502980017, 8265100210021008];
for part in 1..=3 {
let challenge_input = read_file(&format!("tests/challenge{part}"));
assert_eq!(run(&challenge_input, part), Ok(expected[part-1]));
}
}
}

View file

@ -0,0 +1,5 @@
5 2 3 2
3 4 3 5
2 2 4 3
5 5 4 4
4 2 3 5

View file

@ -0,0 +1,99 @@
72 36 76 28
73 14 38 86
30 89 31 61
12 26 35 75
63 93 54 64
76 65 79 50
17 95 61 94
71 29 75 47
64 66 31 80
48 22 20 12
72 46 81 11
33 73 25 42
53 79 45 80
83 11 26 74
41 98 92 69
98 94 89 84
15 59 35 87
53 45 14 26
69 35 78 62
96 82 39 67
69 51 67 46
62 44 70 90
81 48 65 76
78 97 29 92
92 82 20 68
37 45 67 63
40 97 94 56
19 15 55 91
50 40 84 29
46 95 59 27
31 23 48 42
74 13 91 61
18 30 28 33
72 12 25 38
59 34 30 58
28 91 37 34
48 16 27 10
49 83 19 39
59 15 87 69
88 30 86 37
96 82 11 16
32 13 73 49
89 53 75 10
84 42 70 52
17 98 77 17
14 11 93 50
21 86 26 63
12 81 54 70
61 68 55 99
28 26 22 43
91 94 36 78
57 23 31 28
81 66 96 58
71 56 30 74
95 99 52 38
21 40 86 93
32 96 13 21
60 31 99 34
20 55 19 95
13 85 34 84
64 32 85 21
76 12 88 47
27 13 40 77
51 58 90 15
22 24 72 67
10 60 42 40
39 79 89 64
60 41 37 80
50 45 54 90
90 83 68 23
57 55 46 82
41 52 65 43
35 56 62 36
79 65 36 33
88 46 39 20
51 60 73 53
75 14 88 83
47 10 24 92
37 17 44 63
77 18 56 20
23 16 11 29
19 71 52 98
22 44 33 47
74 41 57 87
29 62 35 43
43 15 68 39
80 27 99 49
32 18 32 43
24 45 44 54
77 18 34 17
71 25 16 57
27 38 70 66
19 16 21 87
66 97 49 97
58 24 22 33
24 78 18 25
85 14 36 41
51 44 23 38
93 25 85 42

View file

@ -0,0 +1,50 @@
1003 1009 1000 3274
1008 1002 1000 1008
1005 1002 1008 1006
1002 1002 1005 1002
1001 1003 1009 8363
8265 1003 1005 1000
1008 1005 7661 1009
1001 1003 9870 1004
1009 1000 3352 1001
1009 1003 1007 1003
1007 6665 1008 1005
1000 1005 1009 1005
1009 8236 1003 1002
1002 8094 1000 1004
7033 1005 1004 1004
1001 5397 1003 1000
1006 1001 1003 1003
1008 1009 1008 1004
1000 1005 1006 1007
1003 1003 5343 1003
1003 1009 1008 1009
1002 1002 1001 1006
1000 1000 1004 1009
1002 1009 1003 1004
1002 1008 8579 1006
1002 1009 1000 1005
1008 1002 1008 1007
4614 1003 1003 1006
1008 1005 1005 1000
1007 1006 1009 1008
1006 1008 1003 1005
1003 1006 1001 1001
1006 1005 3367 1006
1001 1009 1002 1006
1009 1007 1000 1006
1006 1007 1004 7305
1000 1004 8332 1004
4128 1005 1009 1000
1007 1003 1000 1001
1008 1002 1001 1002
1003 1005 1001 1003
1005 1009 1003 1009
1001 1002 1006 1003
1002 1002 1008 1003
1009 1009 1002 1001
1008 1007 1000 1009
1002 1001 1004 1001
2412 1006 1001 1000
7178 1001 1000 1003
1008 1004 1005 1008

View file

@ -0,0 +1,4 @@
2 3 4 5
3 4 5 2
4 5 2 3
5 2 3 4

View file

@ -0,0 +1,2 @@
2 3 4 5
6 7 8 9

View file

@ -0,0 +1,2 @@
2 3 4 5
6 7 8 9