Add 2024 Quest 11
This commit is contained in:
parent
f7f796ed93
commit
9ad4df7eca
9 changed files with 291 additions and 0 deletions
6
2024/day11_biological_warfare/Cargo.toml
Normal file
6
2024/day11_biological_warfare/Cargo.toml
Normal file
|
@ -0,0 +1,6 @@
|
|||
[package]
|
||||
name = "day11_biological_warfare"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
34
2024/day11_biological_warfare/challenge.txt
Normal file
34
2024/day11_biological_warfare/challenge.txt
Normal file
|
@ -0,0 +1,34 @@
|
|||
Part I
|
||||
|
||||
The next tournament competition takes place in a very peculiar location, the Biological Weapons District. Unconventional and cunning warfare methods are a specialty of the Knights of the Order.
|
||||
One such method involves breeding Omnivorous Termites. Their strength lies not only in their ability to eat literally anything, including the enemy's weaponry, but also in their rapid population growth rate. Just a few suitable specimens sent near the enemy's castle can ensure that, within a short time, no trace of it will remain.
|
||||
However, for breeding purposes, it is crucial to consciously control the population size. Through years of work, the life cycle of the entire species has been identified. All individuals have been categorized, and for each category, the appearance of the next generation has been determined.
|
||||
Each individual converts into a new generation every day. You have noted down all conversions (your notes). The new individuals are also capable of converting the following day, so the overall population can grow extremely quickly, but it can also be very accurately predicted. This is precisely what the next tournament task involves. You start with a single A category termite, and you have to calculate the overall population after 4 days, based on the conversion notes.
|
||||
Example based on the following notes:
|
||||
A:B,C
|
||||
B:C,A
|
||||
C:A
|
||||
You start with a single A termite.
|
||||
After the first day, it converts into B and C category termites, so the population looks as follows: B,C
|
||||
After the second day, each termite converts again, so the population grows to 3: C,A,A
|
||||
After the third day, the population counts 5 termites: A,B,C,B,C, and after the fourth day, 8 termites: B,C,C,A,A,C,A,A.
|
||||
What will be the termite population count on the 4th day?
|
||||
|
||||
Part II
|
||||
|
||||
The second round takes place in an even more hostile environment, the Infestation Lab. This time, however, the Knights have perfected their Omnivorous Termites, and they come in a new strain with distinct conversion patterns. These new termites, starting from a single category Z termite, grow in a completely different way than the previous strain, but the general rules remain the same. Your goal is to predict the population count on the 10th day.
|
||||
What will be the termite population count on the 10th day?
|
||||
|
||||
Part III
|
||||
|
||||
The final round presents a new, intricate challenge. A newly engineered strain of termites has been developed for an upcoming combat mission. The knights must now investigate how the initial termite types affect the overall population after 20 days of growth.
|
||||
Your task is to determine which initial termite types will yield the largest and smallest populations on the 20th day, and then calculate the difference between these two population sizes.
|
||||
Example based on the following notes:
|
||||
A:B,C
|
||||
B:C,A,A
|
||||
C:A
|
||||
Starting with a single A termite results in a population of 330205 on day 20.
|
||||
Starting with a single B termite results in a population of 444092 on day 20.
|
||||
Starting with a single C termite results in a population of 175277 on day 20.
|
||||
You can calculate the population difference by subtracting the smallest number from the largest: 444092 - 175277 = 268815
|
||||
What is the population difference on the 20th day?
|
116
2024/day11_biological_warfare/src/lib.rs
Normal file
116
2024/day11_biological_warfare/src/lib.rs
Normal file
|
@ -0,0 +1,116 @@
|
|||
use core::fmt::Display;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum ParseError<'a> {
|
||||
LineMalformed(&'a str),
|
||||
}
|
||||
|
||||
impl Display for ParseError<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::LineMalformed(e) => write!(f, "Unable to parse malformed line: {e}\nShould be of format:\nA:B,C,D"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Termite=usize;
|
||||
|
||||
fn try_cycles_from(input: &str) -> Result<(Vec<Vec<Termite>>, HashMap<&str, Termite>), ParseError> {
|
||||
let mut names = HashMap::new();
|
||||
let mut res = Vec::new();
|
||||
for line in input.lines() {
|
||||
if let Some((from, to)) = line.split_once(':') {
|
||||
let next_idx = names.len();
|
||||
let from_idx = *names.entry(from).or_insert(next_idx);
|
||||
while res.len() <= from_idx {
|
||||
res.push(Vec::new());
|
||||
}
|
||||
res[from_idx] = to
|
||||
.split(',')
|
||||
.map(|name| {
|
||||
let next_idx = names.len();
|
||||
*names.entry(name).or_insert(next_idx)
|
||||
}).collect();
|
||||
} else {
|
||||
return Err(ParseError::LineMalformed(line));
|
||||
}
|
||||
}
|
||||
Ok((res, names))
|
||||
}
|
||||
|
||||
fn reproduce(cycles: &[Vec<Termite>], population: &mut Vec<usize>, days: usize) {
|
||||
let mut next_gen = Vec::with_capacity(cycles.len());
|
||||
(0..days).for_each(|_| {
|
||||
next_gen = vec![0; cycles.len()];
|
||||
population.iter().enumerate().for_each(|(category, count)| {
|
||||
let children = &cycles[category];
|
||||
children.iter().for_each(|child| {
|
||||
next_gen[*child] += count;
|
||||
});
|
||||
});
|
||||
std::mem::swap(population, &mut next_gen);
|
||||
next_gen.clear();
|
||||
});
|
||||
}
|
||||
|
||||
pub fn run(input: &str, part: usize) -> Result<usize, ParseError> {
|
||||
let (cycles, names) = try_cycles_from(input)?;
|
||||
let mut termites = vec![0; cycles.len()];
|
||||
match part {
|
||||
1 => {
|
||||
termites[*names.get("A").unwrap()] = 1;
|
||||
reproduce(&cycles, &mut termites, 4);
|
||||
Ok(termites.iter().sum())
|
||||
},
|
||||
2 => {
|
||||
termites[*names.get("Z").unwrap()] = 1;
|
||||
reproduce(&cycles, &mut termites, 10);
|
||||
Ok(termites.iter().sum())
|
||||
},
|
||||
3 => {
|
||||
let mut low = usize::MAX;
|
||||
let mut high = usize::MIN;
|
||||
|
||||
(0..cycles.len()).for_each(|c| {
|
||||
termites = vec![0; cycles.len()];
|
||||
termites[c] = 1;
|
||||
reproduce(&cycles, &mut termites, 20);
|
||||
let population = termites.iter().sum();
|
||||
low = low.min(population);
|
||||
high = high.max(population);
|
||||
});
|
||||
|
||||
Ok(high-low)
|
||||
},
|
||||
_ => 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 = [8, 144, 268815];
|
||||
for part in 1..=expected.len() {
|
||||
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 = [41, 213729, 896125189572];
|
||||
for part in 1..=expected.len() {
|
||||
let challenge_input = read_file(&format!("tests/challenge{part}"));
|
||||
assert_eq!(run(&challenge_input, part), Ok(expected[part-1]));
|
||||
}
|
||||
}
|
||||
}
|
6
2024/day11_biological_warfare/tests/challenge1
Normal file
6
2024/day11_biological_warfare/tests/challenge1
Normal file
|
@ -0,0 +1,6 @@
|
|||
A:O,Y,E
|
||||
I:U,U
|
||||
O:E,I,E
|
||||
E:O,I
|
||||
Y:U,O
|
||||
U:I,I,A
|
20
2024/day11_biological_warfare/tests/challenge2
Normal file
20
2024/day11_biological_warfare/tests/challenge2
Normal file
|
@ -0,0 +1,20 @@
|
|||
J:M,D,C,B
|
||||
M:H,W,T,B
|
||||
S:F,M,C,T
|
||||
Q:V,G,C
|
||||
R:Q,J,G,Z
|
||||
K:M,M,B
|
||||
T:R,G,F,M
|
||||
W:X,R,F
|
||||
L:S,W,W
|
||||
H:G,V,G
|
||||
V:Q,B,J
|
||||
D:W,N,T
|
||||
N:F,C,G
|
||||
G:K,L,H
|
||||
F:L,R,V
|
||||
B:G,J,H,X
|
||||
C:D,P,H,R
|
||||
P:T,C,Q,Q
|
||||
X:W,G,M,H
|
||||
Z:Q,L,L,H
|
100
2024/day11_biological_warfare/tests/challenge3
Normal file
100
2024/day11_biological_warfare/tests/challenge3
Normal file
|
@ -0,0 +1,100 @@
|
|||
KQW:JSC,JGW,WMZ
|
||||
PRV:KCG,NQJ,KRS
|
||||
RLJ:LMB,MFD,WMC,KTG,NPF
|
||||
CTT:WNW,RLS,FTS,SVZ,RLJ
|
||||
SRJ:KJS,MLJ,LMB,QSS,DBQ
|
||||
MFD:SNG,FMQ,GZR,WMC,KJS
|
||||
DJH:RGL,DJH,PGB,CNQ,WMZ
|
||||
JRT:RTJ,PNB,SRJ
|
||||
QTD:WSR,FWH,MSP,LPH,RGL
|
||||
VGX:KQW,WMZ,PGB,WMC,DHZ
|
||||
KNF:JWR,QSS,KRS
|
||||
NSQ:TCC,PNC,QSS
|
||||
SKR:GXP,CWP,TCC
|
||||
MLJ:NXZ,VGS,BWR,PGB,KQW
|
||||
SSP:KTL,CWP,HNZ
|
||||
PGB:JWR,RTJ,PFP
|
||||
HNZ:NPF,NDC,FZT
|
||||
TWC:HGD,MJR,NMF
|
||||
WSR:VGV,KTL,HNZ,RLS,RTJ
|
||||
CWP:MLJ,HNZ,WMV
|
||||
BWR:KVX,RGL,WMV
|
||||
DBQ:NXZ,FZT,VGS,NXZ,KJS
|
||||
RXB:QTD,NQJ,RTJ
|
||||
WRQ:NRW,KTG,KVX,KVX,SPC
|
||||
JCT:SVZ,NMF,TWC
|
||||
KRS:LMB,PGF,JFB,FNW,NDC
|
||||
NLB:RZF,VGH,NRW
|
||||
WNW:QSS,QTD,NSZ,MJR,WSR
|
||||
BBX:TWR,WRQ,MLJ
|
||||
FWD:PGF,LPH,LQT
|
||||
QSS:RLJ,FFZ,FNW,SNG,FWD
|
||||
KTL:JSC,SRJ,NDC
|
||||
FNW:DBQ,HGD,NSQ,NSQ,MJR
|
||||
KJS:QGG,JWR,RLS,MSP,VGS
|
||||
PGF:CNQ,NRW,XMM
|
||||
BSW:VFR,PGB,RLJ,KCG,TMT
|
||||
DHZ:JFV,BVF,JRT,WCS,HGD
|
||||
MSP:NSQ,PRV,NQJ
|
||||
PNB:NPF,QQP,KJS,NPF,DBQ
|
||||
RGL:KVX,TWC,FNW,TMT,SRJ
|
||||
FFZ:VGX,XLN,NPF,GDQ,JFV
|
||||
SVZ:KQW,VGH,WMC,MLJ,WMZ
|
||||
LQT:RXB,QSS,MJR,TMT,FFZ
|
||||
FZT:SVZ,WRQ,VLT,KQW,PNB
|
||||
FMQ:JWR,GXP,VGH
|
||||
WMC:JFV,RXB,XMM,JSC,SVZ
|
||||
PNC:TWC,WNW,NMF
|
||||
LMB:FMQ,VGX,NSZ,CNQ,PFP
|
||||
WCS:JSC,PNC,GZR
|
||||
TWR:NQJ,NXQ,SNG
|
||||
HGD:TWR,RLS,HNZ
|
||||
XMM:SNG,VLT,KNF,WNW,WMV
|
||||
WMZ:SPC,MND,KNF,NDC,NRW
|
||||
JSC:QTD,RGL,KGW,JWR,NQJ
|
||||
JWR:NXZ,MND,PGF
|
||||
NMF:KVX,NQJ,FZT
|
||||
RTJ:GDQ,LMB,RLS
|
||||
MJR:FZT,FMQ,BVF,LQT,QQP
|
||||
KTG:KTL,MND,WRQ,VGX,PNC
|
||||
NQJ:WCS,KTG,MFD,NPF,CNQ
|
||||
VGS:KTL,QSS,TCC,FNW,NRW
|
||||
SNG:BVF,NQJ,WMZ
|
||||
NXQ:PFP,JFV,HGD,NLB,RTJ
|
||||
KCG:WSR,VGH,NDC,CWP,MSP
|
||||
NXZ:FMQ,RXB,RXB,TWR,FMQ
|
||||
KGW:FNW,MFD,GXP
|
||||
FTS:GXP,JSC,KQW,QTD,NSQ
|
||||
NPF:KVX,TWC,FNW
|
||||
BTX:FWH,WSR,BWR
|
||||
NRW:FMQ,QQP,MJR,NPF,RXB
|
||||
PWG:RLS,JRT,SNG
|
||||
MND:BTX,GXP,WMV
|
||||
FWH:NWQ,NPF,MJR
|
||||
KVX:JRT,XLN,BVF
|
||||
TCC:BBX,RZF,PRV
|
||||
NWQ:KNF,RGL,KRS,MSP,NXZ
|
||||
LPH:NXZ,GDQ,FZT
|
||||
GDQ:TMT,NRW,NXQ
|
||||
VGH:KNF,LQT,DBQ
|
||||
PFP:JCT,NMF,PNC,NDC,PGB
|
||||
VFR:NWQ,NDC,FZT,LQT,JWR
|
||||
VLT:GXP,VGV,FWH,NDC,BVF
|
||||
RLS:SSP,HGD,NXZ
|
||||
NSZ:QGG,KCG,KTL
|
||||
TMT:XLN,KNF,LPH
|
||||
JFV:WMV,WRQ,PGF,XLN,DBQ
|
||||
VGV:RLS,DJH,FWD,KRS,WMZ
|
||||
JGW:DJH,FZT,SRJ
|
||||
NDC:TMT,PGB,FMQ
|
||||
GXP:XLN,BSW,LPH
|
||||
CNQ:MND,QGG,NLB,TCC,MND
|
||||
WMV:BWR,NPF,WRQ,QSS,JGW
|
||||
JFB:VGH,KNF,KQW,QGG,WRQ
|
||||
RZF:VGV,VLT,BBX,JGW,WNW
|
||||
SPC:BSW,PRV,SSP
|
||||
GZR:KNF,PWG,WNW
|
||||
BVF:KRS,KVX,WCS,JWR,VFR
|
||||
QGG:CNQ,QTD,VGS
|
||||
QQP:JFB,RXB,JWR,RLS,MLJ
|
||||
XLN:GXP,JCT,NSZ
|
3
2024/day11_biological_warfare/tests/sample1
Normal file
3
2024/day11_biological_warfare/tests/sample1
Normal file
|
@ -0,0 +1,3 @@
|
|||
A:B,C
|
||||
B:C,A
|
||||
C:A
|
3
2024/day11_biological_warfare/tests/sample2
Normal file
3
2024/day11_biological_warfare/tests/sample2
Normal file
|
@ -0,0 +1,3 @@
|
|||
Z:B,C
|
||||
B:C,Z
|
||||
C:Z
|
3
2024/day11_biological_warfare/tests/sample3
Normal file
3
2024/day11_biological_warfare/tests/sample3
Normal file
|
@ -0,0 +1,3 @@
|
|||
A:B,C
|
||||
B:C,A,A
|
||||
C:A
|
Loading…
Add table
Add a link
Reference in a new issue