Compare commits
27
Commits
1cf168ec71
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1670ffc8d7 | ||
|
|
9f353660f1 | ||
|
|
9c0653f39e | ||
|
|
ce521e996a | ||
|
|
9fab2616c5 | ||
|
|
60ef7ce843 | ||
|
|
7a65f1431c | ||
|
|
f8633a07c4 | ||
|
|
06e554c53e | ||
|
|
350f6ef6eb | ||
|
|
728a14855a | ||
|
|
c8a2ebffc4 | ||
|
|
afba7f543c | ||
|
|
1f4e5be195 | ||
|
|
aead1786ba | ||
|
|
95122bb4ca | ||
|
|
576547bfc8 | ||
|
|
143dabb6f2 | ||
|
|
c60d0bf3f6 | ||
|
|
d3c1c39a68 | ||
|
|
27501c65ee | ||
|
|
4614df8845 | ||
|
|
c32121a4b2 | ||
|
|
cd4dab86c8 | ||
|
|
f29621d4ca | ||
|
|
c046c78f08 | ||
|
|
d13f519c9e |
No files matched your search
+15
-15
@@ -4,21 +4,21 @@ pub mod d3;
|
|||||||
pub mod d4;
|
pub mod d4;
|
||||||
pub mod d5;
|
pub mod d5;
|
||||||
pub mod d6;
|
pub mod d6;
|
||||||
// pub mod d7;
|
pub mod d7;
|
||||||
// pub mod d8;
|
pub mod d8;
|
||||||
// pub mod d9;
|
pub mod d9;
|
||||||
// pub mod d10;
|
pub mod d10;
|
||||||
// pub mod d11;
|
pub mod d11;
|
||||||
// pub mod d12;
|
pub mod d12;
|
||||||
// pub mod d13;
|
pub mod d13;
|
||||||
// pub mod d14;
|
pub mod d14;
|
||||||
// pub mod d15;
|
pub mod d15;
|
||||||
// pub mod d16;
|
pub mod d16;
|
||||||
// pub mod d17;
|
pub mod d17;
|
||||||
// pub mod d18;
|
pub mod d18;
|
||||||
// pub mod d19;
|
pub mod d19;
|
||||||
// pub mod d20;
|
pub mod d20;
|
||||||
// pub mod d21;
|
pub mod d21;
|
||||||
// pub mod d22;
|
// pub mod d22;
|
||||||
// pub mod d23;
|
// pub mod d23;
|
||||||
// pub mod d24;
|
// pub mod d24;
|
||||||
+124
@@ -0,0 +1,124 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub type I = (M<SS, Vec<u32>>, M<SS, (SS, SS)>);
|
||||||
|
pub type O = SS;
|
||||||
|
|
||||||
|
fn _parse (data: &'static str) -> I {
|
||||||
|
let mut initial: M<SS, Vec<u32>> = M::new();
|
||||||
|
let mut maps = M::new();
|
||||||
|
|
||||||
|
for line in data.lines() {
|
||||||
|
if let Some(sfx) = line.strip_prefix("value ") {
|
||||||
|
let (val, out) = sfx.split_once(" goes to bot ").map(|(v, b)| (v.parse().unwrap(), b)).unwrap();
|
||||||
|
initial.entry(out).or_default().push(val);
|
||||||
|
} else {
|
||||||
|
let line = line.trim_start_matches("bot ");
|
||||||
|
let (source, dests) = line.split_once(" gives low to ").unwrap();
|
||||||
|
let (l, h) = dests.split_once(" and high to ").unwrap();
|
||||||
|
|
||||||
|
let l = l.strip_prefix("bot ").unwrap_or(l);
|
||||||
|
let h = h.strip_prefix("bot ").unwrap_or(h);
|
||||||
|
|
||||||
|
maps.insert(source, (l, h));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(initial, maps)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(suspicious_double_ref_op)]
|
||||||
|
fn _silver ((mut state, map): I) -> O {
|
||||||
|
let mut cur = state.iter().find(|e| e.1.len() == 2).unwrap().0.clone();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let chips = state.entry(cur).or_default();
|
||||||
|
|
||||||
|
let a = chips[0];
|
||||||
|
let b = chips[1];
|
||||||
|
|
||||||
|
chips.clear();
|
||||||
|
|
||||||
|
if (a == 17 && b == 61) || (b == 17 && a == 61) { return cur; }
|
||||||
|
|
||||||
|
let (low, high) = map.get(cur).unwrap();
|
||||||
|
|
||||||
|
let l_entry = state.entry(low).or_default();
|
||||||
|
l_entry.push(if a > b { b } else { a });
|
||||||
|
let l_len = l_entry.len();
|
||||||
|
|
||||||
|
let h_entry = state.entry(high).or_default();
|
||||||
|
h_entry.push(if a > b { a } else { b });
|
||||||
|
let h_len = h_entry.len();
|
||||||
|
|
||||||
|
|
||||||
|
cur = if l_len == 2 {
|
||||||
|
low
|
||||||
|
} else if h_len == 2 {
|
||||||
|
high
|
||||||
|
} else {
|
||||||
|
state.iter().find(|e| e.1.len() == 2).unwrap().0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(suspicious_double_ref_op)]
|
||||||
|
fn _gold ((mut state, map): I) -> u32 {
|
||||||
|
let mut cur = state.iter().find(|e| e.1.len() == 2).unwrap().0.clone();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let chips = state.entry(cur).or_default();
|
||||||
|
|
||||||
|
let a = chips[0];
|
||||||
|
let b = chips[1];
|
||||||
|
|
||||||
|
chips.clear();
|
||||||
|
|
||||||
|
let (low, high) = map.get(cur).unwrap();
|
||||||
|
|
||||||
|
let l_entry = state.entry(low).or_default();
|
||||||
|
l_entry.push(if a > b { b } else { a });
|
||||||
|
let l_len = l_entry.len();
|
||||||
|
|
||||||
|
let h_entry = state.entry(high).or_default();
|
||||||
|
h_entry.push(if a > b { a } else { b });
|
||||||
|
let h_len = h_entry.len();
|
||||||
|
|
||||||
|
if let Some(a) = state.get("output 0") && let Some(b) = state.get("output 1") && let Some(c) = state.get("output 2") {
|
||||||
|
return a[0] * b[0] * c[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = if l_len == 2 {
|
||||||
|
low
|
||||||
|
} else if h_len == 2 {
|
||||||
|
high
|
||||||
|
} else {
|
||||||
|
state.iter().find(|e| e.1.len() == 2).unwrap().0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn read () -> I {
|
||||||
|
let data = inc!(10);
|
||||||
|
_parse(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn silver () {
|
||||||
|
let data = read();
|
||||||
|
let ans = _silver(data);
|
||||||
|
|
||||||
|
assert_eq!(ans, s!(116))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gold () {
|
||||||
|
let data = read();
|
||||||
|
let ans = _gold(data);
|
||||||
|
|
||||||
|
assert_eq!(ans, 23903)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
#![allow(dead_code)]
|
||||||
|
#![allow(unused_variables)]
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub type I = Vec<Vec<char>>;
|
||||||
|
pub type O = i64;
|
||||||
|
|
||||||
|
fn _parse (data: &str) -> I {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _solve (data: &I) -> O {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _silver (data: &I) -> O {
|
||||||
|
|
||||||
|
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _gold (data: &I) -> O {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
type St = [Vec<char>; 4];
|
||||||
|
|
||||||
|
fn is_final_state (state: &St) -> bool {
|
||||||
|
state[1..].iter().all(|e| e.is_empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_valid_state (state: &St) -> bool {
|
||||||
|
state.iter().all(|level| level.len() < 2 || level.iter().all(|e| e.is_lowercase()) || {
|
||||||
|
let mut chips = level.iter().filter(|e| e.is_uppercase());
|
||||||
|
while let Some(chip) = chips.next() {
|
||||||
|
if level.iter().find(|&v| chip.to_ascii_lowercase() == *v).is_none() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn state_discriminant (state: &St) -> [(usize, usize); 4] {
|
||||||
|
state.iter().map(|s| (
|
||||||
|
s.iter().filter(|e| e.is_lowercase()).count(),
|
||||||
|
s.iter().filter(|e| e.is_uppercase()).count()
|
||||||
|
)).collect_vec().try_into().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
fn read () -> I {
|
||||||
|
vec![vec!['a', 'b', 'c', 'd', 'e', 'A', 'B', 'C'], vec!['D', 'E'], vec![], vec![]]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn silver () {
|
||||||
|
let data = read();
|
||||||
|
let ans = _silver(&data);
|
||||||
|
|
||||||
|
assert_eq!(ans, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gold () {
|
||||||
|
let data = read();
|
||||||
|
let ans = _gold(&data);
|
||||||
|
|
||||||
|
assert_eq!(ans, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
+121
@@ -0,0 +1,121 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub type I = Vec<Inst>;
|
||||||
|
pub type O = i64;
|
||||||
|
|
||||||
|
pub enum Val {
|
||||||
|
Register (char),
|
||||||
|
Literal (i64),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
impl Val {
|
||||||
|
fn new (i: &str) -> Self {
|
||||||
|
match i.parse::<i64>() {
|
||||||
|
Ok(s) => Self::Literal(s),
|
||||||
|
Err(_) => Self::Register(i.chars().next().unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Inst {
|
||||||
|
Jnz (Val, isize),
|
||||||
|
Cpy (Val, char),
|
||||||
|
Inc (char),
|
||||||
|
Dec (char)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fn _parse (data: &str) -> I {
|
||||||
|
data.trim().lines().map(|line| {
|
||||||
|
let mut split = line.split_ascii_whitespace();
|
||||||
|
match split.next().unwrap() {
|
||||||
|
"jnz" => {
|
||||||
|
Inst::Jnz(Val::new(split.next().unwrap()), split.next().unwrap().parse().unwrap())
|
||||||
|
},
|
||||||
|
"cpy" => {
|
||||||
|
Inst::Cpy(Val::new(split.next().unwrap()), split.next().unwrap().chars().next().unwrap())
|
||||||
|
},
|
||||||
|
"inc" => {
|
||||||
|
Inst::Inc(split.next().unwrap().chars().next().unwrap())
|
||||||
|
},
|
||||||
|
"dec" => {
|
||||||
|
Inst::Dec(split.next().unwrap().chars().next().unwrap())
|
||||||
|
},
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _solve (data: I, r: &mut M<char, i64>) {
|
||||||
|
let mut ptr = 0;
|
||||||
|
|
||||||
|
while ptr < data.len() {
|
||||||
|
let i = &data[ptr];
|
||||||
|
|
||||||
|
match i {
|
||||||
|
Inst::Inc(reg) => *r.entry(*reg).or_default() += 1,
|
||||||
|
Inst::Dec(reg) => *r.entry(*reg).or_default() -= 1,
|
||||||
|
Inst::Cpy(val, reg) => {
|
||||||
|
match val {
|
||||||
|
Val::Literal(val) => *r.entry(*reg).or_default() = *val,
|
||||||
|
Val::Register(r2) => *r.entry(*reg).or_default() = *r.get(r2).unwrap(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Inst::Jnz(val, dest) => {
|
||||||
|
let val = match val {
|
||||||
|
Val::Literal(val) => *val,
|
||||||
|
Val::Register(r2) => *r.get(r2).unwrap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if val != 0 {
|
||||||
|
ptr = ptr.checked_add_signed(*dest).unwrap_or(0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
ptr += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _silver (data: I) -> O {
|
||||||
|
let mut state = M::from([('a', 0), ('b', 0), ('c', 0), ('d', 0)]);
|
||||||
|
_solve(data, &mut state);
|
||||||
|
*state.get(&'a').unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _gold (data: I) -> O {
|
||||||
|
let mut state = M::from([('a', 0), ('b', 0), ('c', 1), ('d', 0)]);
|
||||||
|
_solve(data, &mut state);
|
||||||
|
*state.get(&'a').unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn read () -> I {
|
||||||
|
let data = inc!(12);
|
||||||
|
_parse(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn silver () {
|
||||||
|
let data = read();
|
||||||
|
let ans = _silver(data);
|
||||||
|
|
||||||
|
assert_eq!(ans, 318007)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gold () {
|
||||||
|
let data = read();
|
||||||
|
let ans = _gold(data);
|
||||||
|
|
||||||
|
assert_eq!(ans, 9227661)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
#![allow(dead_code)]
|
||||||
|
#![allow(non_upper_case_globals)]
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub type O = usize;
|
||||||
|
|
||||||
|
const INPUT: usize = 1358;
|
||||||
|
|
||||||
|
|
||||||
|
fn is_wall (y: usize, x: usize) -> bool {
|
||||||
|
((x*x + 3*x + 2*x*y + y + y*y) + INPUT).count_ones() % 2 != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next ((y, x, len): (usize, usize, usize)) -> Vec<(usize, usize, usize)> {
|
||||||
|
const cand: [(isize, isize); 4] = [(0, -1), (0, 1), (-1, 0), (1, 0)];
|
||||||
|
|
||||||
|
cand.into_iter().filter_map(|(dy, dx)| {
|
||||||
|
let ny = y.checked_add_signed(dy);
|
||||||
|
let nx = x.checked_add_signed(dx);
|
||||||
|
|
||||||
|
match (ny, nx) {
|
||||||
|
(Some(y), Some(x)) => if is_wall(y, x) { None } else { Some((y, x, len + 1)) },
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn solve (visited: &mut M<(usize, usize), usize>) {
|
||||||
|
let mut stack = vec![(1, 1, 0)];
|
||||||
|
while !stack.is_empty() {
|
||||||
|
let c @ (y, x, len) = stack.pop().unwrap();
|
||||||
|
|
||||||
|
*visited.entry((y, x)).or_default() = len;
|
||||||
|
for n @ (ny, nx, nl) in next(c) {
|
||||||
|
if !visited.contains_key(&(ny, nx)) || visited.get(&(ny, nx)).is_some_and(|&old| old > nl) {
|
||||||
|
stack.push(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _silver () -> O {
|
||||||
|
let mut visited = M::new();
|
||||||
|
solve(&mut visited);
|
||||||
|
*visited.get(&(39, 31)).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _gold () -> O {
|
||||||
|
let mut visited = M::new();
|
||||||
|
solve(&mut visited);
|
||||||
|
visited.values().filter(|&&e| e <= 50).count()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn silver () {
|
||||||
|
let ans = _silver();
|
||||||
|
|
||||||
|
assert_eq!(ans, 96)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gold () {
|
||||||
|
let ans = _gold();
|
||||||
|
|
||||||
|
assert_eq!(ans, 141)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub type O = usize;
|
||||||
|
|
||||||
|
pub const INPUT: &'static str = "qzyelonm";
|
||||||
|
|
||||||
|
fn _solve (extra: u32) -> O {
|
||||||
|
let mut candidates: M<char, Vec<usize>> = M::new();
|
||||||
|
let mut done: Vec<usize> = vec![];
|
||||||
|
|
||||||
|
for i in 0.. {
|
||||||
|
let s = format!("{INPUT}{i}");
|
||||||
|
let mut hash = md5::compute(s);
|
||||||
|
let mut repr = format!("{:x}", hash);
|
||||||
|
|
||||||
|
for _ in 0..extra {
|
||||||
|
hash = md5::compute(repr);
|
||||||
|
repr = format!("{:x}", hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
let three = repr.chars().tuple_windows().find(|&(a, b, c)| a == b && b == c);
|
||||||
|
|
||||||
|
if let Some((c, _, _)) = three {
|
||||||
|
if !candidates.is_empty() {
|
||||||
|
let five = repr.chars().tuple_windows().find(|&(a, b, c, d, e)| a == b && a == c && a == d && a == e);
|
||||||
|
if let Some((c, _, _, _, _)) = five {
|
||||||
|
if let Some(candidates) = candidates.get_mut(&c) {
|
||||||
|
let pos = candidates.iter().position(|pos| pos + 1000 > i);
|
||||||
|
if let Some(pos) = pos {
|
||||||
|
done.extend(candidates.drain(pos..));
|
||||||
|
candidates.clear();
|
||||||
|
if done.len() >= 100 { // should be pretty solid, but not sure if I can prove this!
|
||||||
|
done.sort();
|
||||||
|
return done[63];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
candidates.entry(c).or_default().push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _silver () -> O {
|
||||||
|
_solve(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _gold () -> O {
|
||||||
|
_solve(2016)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn silver () {
|
||||||
|
let ans = _silver();
|
||||||
|
|
||||||
|
assert_eq!(ans, 15168)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gold () {
|
||||||
|
let ans = _gold();
|
||||||
|
|
||||||
|
assert_eq!(ans, 20864)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#![allow(unused_imports)]
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub type I = Vec<(usize, usize)>;
|
||||||
|
pub type O = usize;
|
||||||
|
|
||||||
|
fn _parse (data: &str) -> I {
|
||||||
|
data.lines()
|
||||||
|
.map(|e| e.trim().trim_matches('.')
|
||||||
|
.split_once(" has ")
|
||||||
|
.map(|(_, r)|
|
||||||
|
r.split_once(" positions; at time=0, it is at position ")
|
||||||
|
.map(|(n, p)| (n.parse().unwrap(), p.parse().unwrap()))
|
||||||
|
)
|
||||||
|
.flatten()
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _solve (data: &I) -> O {
|
||||||
|
let d = |time, (size, position)| (time + position) % size == 0;
|
||||||
|
(0..).into_iter().find(|t| data.iter().enumerate().all(|(i, &df)| d(t + i + 1, df))).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _silver (data: I) -> O {
|
||||||
|
_solve(&data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _gold (mut data: I) -> O {
|
||||||
|
data.push((11, 0));
|
||||||
|
_solve(&data)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn read () -> I {
|
||||||
|
let data = inc!(15);
|
||||||
|
_parse(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn silver () {
|
||||||
|
let data = read();
|
||||||
|
let ans = _silver(data);
|
||||||
|
|
||||||
|
assert_eq!(ans, 122318)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gold () {
|
||||||
|
let data = read();
|
||||||
|
let ans = _gold(data);
|
||||||
|
|
||||||
|
assert_eq!(ans, 3208583)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
#![allow(non_upper_case_globals)]
|
||||||
|
#![allow(unused_imports)]
|
||||||
|
#![allow(dead_code)]
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub type I = &'static str;
|
||||||
|
pub type O = String;
|
||||||
|
|
||||||
|
fn checksum (data: &str) -> String {
|
||||||
|
data.chars().array_chunks().map(|[a, b]| if a == b { '1' } else { '0' }).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _solve (data: I, disk: usize) -> O {
|
||||||
|
let mut s = data.to_owned();
|
||||||
|
while s.len() < disk {
|
||||||
|
s = format!("{}0{}", &s, s.chars().rev().map(|e| if e == '1' { '0' } else { '1' }).collect::<String>());
|
||||||
|
}
|
||||||
|
s = (&s[..disk]).to_owned();
|
||||||
|
let mut chk = checksum(&s);
|
||||||
|
while chk.len() % 2 == 0 {
|
||||||
|
chk = checksum(&chk);
|
||||||
|
}
|
||||||
|
chk
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const input: &'static str = "01110110101001000";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn silver () {
|
||||||
|
let ans = _solve(input, 272);
|
||||||
|
assert_eq!(ans, s!("11100111011101111"))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gold () {
|
||||||
|
let ans = _solve(input, 35651584);
|
||||||
|
|
||||||
|
assert_eq!(ans, s!("10001110010000110"))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
#![allow(non_upper_case_globals)]
|
||||||
|
#![allow(unused_imports)]
|
||||||
|
|
||||||
|
use md5::Digest;
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub type I = &'static str;
|
||||||
|
pub type O = String;
|
||||||
|
pub type O2 = usize;
|
||||||
|
|
||||||
|
const _cand: [(isize, isize, char); 4] = [(-1, 0, 'U'), (1, 0, 'D'), (0, -1, 'L'), (0, 1, 'R')];
|
||||||
|
|
||||||
|
fn _open_doors ((y, x): (usize, usize), digest: Digest) -> Vec<(usize, usize, char)> {
|
||||||
|
let repr = format!("{:x}", digest);
|
||||||
|
let access: [char; 4] = repr.chars().take(4).collect_vec().try_into().unwrap();
|
||||||
|
|
||||||
|
_cand.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(i, &(dy, dx, n))| match (y.checked_add_signed(dy), x.checked_add_signed(dx)) {
|
||||||
|
(Some(y), Some(x)) => if y <= 3 && x <= 3 { Some((y, x, n, i)) } else { None },
|
||||||
|
_ => None
|
||||||
|
})
|
||||||
|
.filter(|(_, _, _, idx)| ('b'..='f').contains(&access[*idx]))
|
||||||
|
.map(|(a, b, c, _)| (a, b, c))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _digest (pass: &'static str, i: &str) -> Digest {
|
||||||
|
let full = format!("{pass}{i}");
|
||||||
|
md5::compute(full)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _dfs (cur: (usize, usize), path: &mut String, pass: &'static str) -> bool {
|
||||||
|
if cur == (3, 3) { return true; } else {
|
||||||
|
let digest = _digest(pass, &path);
|
||||||
|
let doors = _open_doors(cur, digest);
|
||||||
|
for (ny, nx, p) in doors {
|
||||||
|
path.push(p);
|
||||||
|
if _dfs((ny, nx), path, pass) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
path.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _dfs_max (cur: (usize, usize), path: &mut String, pass: &'static str, max: &mut usize) {
|
||||||
|
if cur == (3, 3) {
|
||||||
|
*max = (*max).max(path.len());
|
||||||
|
} else {
|
||||||
|
let digest = _digest(pass, &path);
|
||||||
|
let doors = _open_doors(cur, digest);
|
||||||
|
for (ny, nx, p) in doors {
|
||||||
|
path.push(p);
|
||||||
|
_dfs_max((ny, nx), path, pass, max);
|
||||||
|
path.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _silver (data: I) -> O {
|
||||||
|
let mut path = String::new();
|
||||||
|
_dfs((0, 0), &mut path, data);
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _gold (data: I) -> O2 {
|
||||||
|
let mut path = String::new();
|
||||||
|
let mut max = 0;
|
||||||
|
_dfs_max((0, 0), &mut path, data, &mut max);
|
||||||
|
max
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const pass: &'static str = "edjrjqaa";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn silver () {
|
||||||
|
let ans = _silver(pass);
|
||||||
|
assert_eq!(ans, s!("DUDRDLRRRD"))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gold () {
|
||||||
|
let ans = _gold(pass);
|
||||||
|
assert_eq!(ans, 502)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub type I = &'static str;
|
||||||
|
pub type O = usize;
|
||||||
|
|
||||||
|
// @TODO: try bit mask approach
|
||||||
|
fn _solve (data: I, rows: usize) -> O {
|
||||||
|
let w = data.len();
|
||||||
|
let mut v = vec![data.to_owned()];
|
||||||
|
|
||||||
|
while v.len() < rows {
|
||||||
|
let mut v2 = String::new();
|
||||||
|
let prev = &v[v.len() - 1].chars().collect_vec();
|
||||||
|
|
||||||
|
for i in 0..w {
|
||||||
|
let next = match (
|
||||||
|
i.checked_sub(1).map(|i| prev.get(i)).flatten().unwrap_or(&'.'),
|
||||||
|
prev.get(i).unwrap_or(&'.'),
|
||||||
|
prev.get(i+1).unwrap_or(&'.')
|
||||||
|
) {
|
||||||
|
('^', '^', '.') | ('.', '^', '^') | ('^', '.', '.') | ('.', '.', '^') => '^',
|
||||||
|
_ => '.'
|
||||||
|
};
|
||||||
|
|
||||||
|
v2.push(next);
|
||||||
|
}
|
||||||
|
v.push(v2);
|
||||||
|
}
|
||||||
|
v.concat().chars().filter(|&c| c == '.').count()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn read () -> I {
|
||||||
|
inc!(18).trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example () {
|
||||||
|
let data = ".^^.^.^^^^";
|
||||||
|
let ans = _solve(data, 10);
|
||||||
|
assert_eq!(ans, 38);
|
||||||
|
|
||||||
|
let data = "..^^.";
|
||||||
|
let ans = _solve(data, 3);
|
||||||
|
assert_eq!(ans, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn silver () {
|
||||||
|
let data = read();
|
||||||
|
let ans = _solve(data, 40);
|
||||||
|
assert_eq!(ans, 1982)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gold () {
|
||||||
|
let data = read();
|
||||||
|
let ans = _solve(data, 400_000);
|
||||||
|
assert_eq!(ans, 20005203)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub type I = u32;
|
||||||
|
pub type O = u32;
|
||||||
|
|
||||||
|
fn _silver (data: I) -> O {
|
||||||
|
2 * (data - (1 << (32 - data.leading_zeros() - 1))) + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _gold (data: I) -> O {
|
||||||
|
let mut left = D::from_iter(0..data/2);
|
||||||
|
let mut right = D::from_iter(data/2..data);
|
||||||
|
|
||||||
|
while !left.is_empty() && !right.is_empty() {
|
||||||
|
if left.len() > right.len() {
|
||||||
|
left.pop_back();
|
||||||
|
} else {
|
||||||
|
right.pop_back();
|
||||||
|
}
|
||||||
|
right.push_front(left.pop_front().unwrap());
|
||||||
|
left.push_back(right.pop_back().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
left[0] + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn silver () {
|
||||||
|
let ans = _silver(3005290);
|
||||||
|
assert_eq!(ans, 1816277)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gold () {
|
||||||
|
let ans = _gold(3005290);
|
||||||
|
assert_eq!(ans, 1410967)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,10 +13,6 @@ fn _parse (data: &str) -> I {
|
|||||||
}).collect()).collect()
|
}).collect()).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _solve (data: &I) -> O {
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn _silver (data: &I) -> O {
|
fn _silver (data: &I) -> O {
|
||||||
let mut out = format!("");
|
let mut out = format!("");
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
#![allow(unused_imports)]
|
||||||
|
use std::ops::RangeInclusive;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub type I = Vec<RangeInclusive<u64>>;
|
||||||
|
pub type O = u64;
|
||||||
|
|
||||||
|
fn _parse (data: &str) -> I {
|
||||||
|
data.trim().lines().map(|e| e.trim().split_once('-').map(|(a, b)| a.parse().unwrap()..=b.parse().unwrap()).unwrap()).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _silver (mut data: I) -> O {
|
||||||
|
data.sort_by_key(|d| *d.start());
|
||||||
|
let mut start = data[0].end() + 1;
|
||||||
|
|
||||||
|
for d in &data[1..] {
|
||||||
|
if *d.start() <= start {
|
||||||
|
start = start.max(d.end() + 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _gold (mut data: I) -> O {
|
||||||
|
data.sort_by_key(|d| *d.start());
|
||||||
|
let mut start = data[0].end() + 1;
|
||||||
|
let mut gaps = 0;
|
||||||
|
|
||||||
|
for d in &data[1..] {
|
||||||
|
if *d.start() <= start {
|
||||||
|
start = start.max(d.end() + 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let l = d.start() - start;
|
||||||
|
gaps += l;
|
||||||
|
start = d.end() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// doesn't matter in my input, but for a general case where there's a gap between last
|
||||||
|
// blocked ip and last possible ip will matter. check is here to ensure it won't overflow
|
||||||
|
if start <= u32::MAX as u64 {
|
||||||
|
gaps += u32::MAX as u64 - start;
|
||||||
|
}
|
||||||
|
gaps
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn read () -> I {
|
||||||
|
let data = inc!(20);
|
||||||
|
_parse(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn silver () {
|
||||||
|
let data = read();
|
||||||
|
let ans = _silver(data);
|
||||||
|
assert_eq!(ans, 17348574)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gold () {
|
||||||
|
let data = read();
|
||||||
|
let ans = _gold(data);
|
||||||
|
assert_eq!(ans, 104)
|
||||||
|
}
|
||||||
|
}
|
||||||
+151
@@ -0,0 +1,151 @@
|
|||||||
|
#![allow(non_upper_case_globals)]
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub type I = Vec<Inst>;
|
||||||
|
pub type O = String;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Inst {
|
||||||
|
SwapPos (usize, usize),
|
||||||
|
SwapLetter (char, char),
|
||||||
|
RotateLeft (usize),
|
||||||
|
RotateRight (usize),
|
||||||
|
RotatePos (char),
|
||||||
|
Reverse (usize, usize),
|
||||||
|
Move (usize, usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
// const _rotations: [usize; 8] = [1,2,3,4,6,7,0,1];
|
||||||
|
// ↓
|
||||||
|
const _rotations: [usize; 8] = [1,1,6,2,7,3,0,4];
|
||||||
|
|
||||||
|
|
||||||
|
impl Inst {
|
||||||
|
fn from_str (i: &str) -> Self {
|
||||||
|
let i = i.trim();
|
||||||
|
if let Some(sfx) = i.strip_prefix("swap position ") {
|
||||||
|
let (l, r) = sfx.split_once(" with position ").unwrap();
|
||||||
|
Inst::SwapPos(p!(l), p!(r))
|
||||||
|
} else if let Some(sfx) = i.strip_prefix("swap letter ") {
|
||||||
|
let (l, r) = sfx.split_once(" with letter ").unwrap();
|
||||||
|
Inst::SwapLetter(l.trim().chars().next().unwrap(), r.trim().chars().next().unwrap())
|
||||||
|
} else if let Some(sfx) = i.strip_prefix("rotate left ") {
|
||||||
|
let (l, _) = sfx.split_once(' ').unwrap();
|
||||||
|
Inst::RotateLeft(p!(l))
|
||||||
|
} else if let Some(sfx) = i.strip_prefix("rotate right ") {
|
||||||
|
let (l, _) = sfx.split_once(' ').unwrap();
|
||||||
|
Inst::RotateRight(p!(l))
|
||||||
|
} else if let Some(sfx) = i.strip_prefix("rotate based on position of letter ") {
|
||||||
|
Inst::RotatePos(sfx.chars().next().unwrap())
|
||||||
|
} else if let Some(sfx) = i.strip_prefix("reverse positions ") {
|
||||||
|
let (l, r) = sfx.split_once(" through ").unwrap();
|
||||||
|
Inst::Reverse(p!(l), p!(r))
|
||||||
|
} else if let Some(sfx) = i.strip_prefix("move position ") {
|
||||||
|
let (l, r) = sfx.split_once(" to position ").unwrap();
|
||||||
|
Inst::Move(p!(l), p!(r))
|
||||||
|
} else {
|
||||||
|
panic!("unknown instruction")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply (self, target: &mut Vec<char>) {
|
||||||
|
use Inst as I;
|
||||||
|
match self {
|
||||||
|
I::SwapPos(l, r) => target.swap(l, r),
|
||||||
|
I::SwapLetter(l, r) => {
|
||||||
|
let lpos = target.iter().position(|&c| c == l);
|
||||||
|
let rpos = target.iter().position(|&c| c == r);
|
||||||
|
if let Some(lpos) = lpos && let Some(rpos) = rpos {
|
||||||
|
target.swap(lpos, rpos);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
I::RotateLeft(times) => target.rotate_left(times),
|
||||||
|
I::RotateRight(times) => target.rotate_right(times),
|
||||||
|
I::RotatePos(needle) => {
|
||||||
|
let pos = target.iter().position(|&c| c == needle);
|
||||||
|
if let Some(pos) = pos {
|
||||||
|
let rotations = pos + 1 + if pos >= 4 { 1 } else { 0 };
|
||||||
|
let len = target.len(); // % len is useless in my input but needed for the general correctness of the algorithm
|
||||||
|
target.rotate_right(rotations % len);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
I::Reverse(from, to) => (&mut target[from..=to]).reverse(),
|
||||||
|
I::Move(from, to) => {
|
||||||
|
let val = target.remove(from);
|
||||||
|
target.insert(to, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn undo (self, target: &mut Vec<char>) {
|
||||||
|
use Inst as I;
|
||||||
|
match self {
|
||||||
|
I::SwapPos(l, r) => target.swap(l, r),
|
||||||
|
I::SwapLetter(l, r) => {
|
||||||
|
let lpos = target.iter().position(|&c| c == l);
|
||||||
|
let rpos = target.iter().position(|&c| c == r);
|
||||||
|
if let Some(lpos) = lpos && let Some(rpos) = rpos {
|
||||||
|
target.swap(lpos, rpos);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
I::RotateLeft(times) => target.rotate_right(times),
|
||||||
|
I::RotateRight(times) => target.rotate_left(times),
|
||||||
|
I::RotatePos(needle) => {
|
||||||
|
let pos = target.iter().position(|&c| c == needle);
|
||||||
|
if let Some(pos) = pos {
|
||||||
|
target.rotate_left(_rotations[pos]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
I::Reverse(from, to) => (&mut target[from..=to]).reverse(),
|
||||||
|
I::Move(from, to) => {
|
||||||
|
let val = target.remove(to);
|
||||||
|
target.insert(from, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _parse (data: &str) -> I {
|
||||||
|
data.trim().lines().map(Inst::from_str).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _silver (start: &'static str, list: I) -> O {
|
||||||
|
let mut state = start.chars().collect_vec();
|
||||||
|
list.into_iter().for_each(|i| i.apply(&mut state));
|
||||||
|
state.into_iter().collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _gold (start: &'static str, mut list: I) -> O {
|
||||||
|
list.reverse();
|
||||||
|
let mut state = start.chars().collect_vec();
|
||||||
|
list.into_iter().for_each(|i| i.undo(&mut state));
|
||||||
|
state.into_iter().collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn read () -> I {
|
||||||
|
let data = inc!(21);
|
||||||
|
_parse(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn silver () {
|
||||||
|
let data = read();
|
||||||
|
let ans = _silver("abcdefgh", data);
|
||||||
|
|
||||||
|
assert_eq!(ans, s!("bfheacgd"))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gold () {
|
||||||
|
let data = read();
|
||||||
|
let ans = _gold("fbgdceah", data);
|
||||||
|
|
||||||
|
assert_eq!(ans, s!("gcehdbfa"))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub type I = Vec<(SS, Vec<SS>, Vec<SS>)>;
|
||||||
|
pub type O = usize;
|
||||||
|
|
||||||
|
fn _parse (data: &'static str) -> I {
|
||||||
|
data.lines().map(|line| {
|
||||||
|
let line = line.trim();
|
||||||
|
let mut out = vec![];
|
||||||
|
let mut _in = vec![];
|
||||||
|
let mut pos = false;
|
||||||
|
|
||||||
|
let mut l = 0;
|
||||||
|
let mut r = 0;
|
||||||
|
|
||||||
|
for (idx, c) in line.char_indices() {
|
||||||
|
|
||||||
|
match c {
|
||||||
|
'[' | ']' => {
|
||||||
|
let v = if pos { &mut _in } else { &mut out };
|
||||||
|
v.push(&line[l..r]);
|
||||||
|
pos = !pos;
|
||||||
|
l = idx + 1;
|
||||||
|
r = l;
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
r += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let v = if pos { &mut _in } else { &mut out };
|
||||||
|
v.push(&line[l..r]);
|
||||||
|
|
||||||
|
(line, _in, out)
|
||||||
|
}).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _silver (data: &I) -> O {
|
||||||
|
let abba = |(a, b, c, d)| a == d && b == c && b != a;
|
||||||
|
data.into_iter().filter(|(_, _in, out)| {
|
||||||
|
!_in.into_iter().any(|part| part.chars().tuple_windows().any(abba)) &&
|
||||||
|
out.into_iter().any(|part| part.chars().tuple_windows().any(abba))
|
||||||
|
}).count()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _gold (data: &I) -> O {
|
||||||
|
let aba = |(a, b, c)| a == c && b != a;
|
||||||
|
data.into_iter().filter(|(_, _in, out)| {
|
||||||
|
let mut abas = S::new();
|
||||||
|
out.into_iter().for_each(|part| part.chars().tuple_windows().for_each(|x| if aba(x) { abas.insert(x); }));
|
||||||
|
_in.into_iter().any(|part| part.chars().tuple_windows().any(|x @ (a, b, _)| aba(x) && abas.contains(&(b, a, b))))
|
||||||
|
}).count()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn read () -> I {
|
||||||
|
let data = inc!(7);
|
||||||
|
_parse(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn silver () {
|
||||||
|
let data = read();
|
||||||
|
let ans = _silver(&data);
|
||||||
|
|
||||||
|
assert_eq!(ans, 105)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gold () {
|
||||||
|
let data = read();
|
||||||
|
let ans = _gold(&data);
|
||||||
|
|
||||||
|
assert_eq!(ans, 258)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub type I = Vec<Inst>;
|
||||||
|
pub type O = usize;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum Inst {
|
||||||
|
Rect(usize, usize),
|
||||||
|
RotateY(usize, usize),
|
||||||
|
RotateX(usize, usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
impl Inst {
|
||||||
|
fn from_line (data: &str) -> Self {
|
||||||
|
if let Some(suffix) = data.strip_prefix("rotate row y=") && let Some((y, rotation)) = suffix.split_once(" by ") {
|
||||||
|
Self::RotateY(y.parse().unwrap(), rotation.parse().unwrap())
|
||||||
|
} else if let Some(suffix) = data.strip_prefix("rotate column x=") && let Some((x, rotation)) = suffix.split_once(" by ") {
|
||||||
|
Self::RotateX(x.parse().unwrap(), rotation.parse().unwrap())
|
||||||
|
} else {
|
||||||
|
let (a, b) = data.strip_prefix("rect ").unwrap().split_once('x').unwrap();
|
||||||
|
Self::Rect(a.parse().unwrap(), b.parse().unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _parse (data: &str) -> I {
|
||||||
|
data.lines().map(Inst::from_line).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _solve (data: &I) -> Vec<Vec<bool>> {
|
||||||
|
let mut state = vec![vec![false; 50]; 6];
|
||||||
|
|
||||||
|
for i in data {
|
||||||
|
match i {
|
||||||
|
Inst::Rect(a, b) => {
|
||||||
|
for y in 0..*b {
|
||||||
|
for x in 0..*a {
|
||||||
|
state[y][x] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Inst::RotateY(y, r) => {
|
||||||
|
state[*y].rotate_right(*r);
|
||||||
|
},
|
||||||
|
Inst::RotateX(x, r) => {
|
||||||
|
let mut view = state.iter().map(|e| e[*x]).collect_vec();
|
||||||
|
view.rotate_right(*r);
|
||||||
|
|
||||||
|
for (y, n) in view.into_iter().enumerate() {
|
||||||
|
state[y][*x] = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _silver (data: &I) -> O {
|
||||||
|
_solve(data).into_iter().flatten().filter(|e| *e).count()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _gold (data: &I) -> () {
|
||||||
|
let data = _solve(data).into_iter().map(|line| line.into_iter().map(|f| if f { 'X' } else { '.' }).collect::<String>()).collect_vec();
|
||||||
|
println!("{:#?}", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn read () -> I {
|
||||||
|
let data = inc!(8);
|
||||||
|
_parse(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn silver () {
|
||||||
|
let data = read();
|
||||||
|
let ans = _silver(&data);
|
||||||
|
|
||||||
|
assert_eq!(ans, 115)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gold () {
|
||||||
|
let data = read();
|
||||||
|
let ans = _gold(&data);
|
||||||
|
// EFEYKFRFIJ
|
||||||
|
assert_eq!(ans, ())
|
||||||
|
}
|
||||||
|
}
|
||||||
+108
@@ -0,0 +1,108 @@
|
|||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
pub type I = SS;
|
||||||
|
pub type O = usize;
|
||||||
|
|
||||||
|
fn _expand (mut data: impl Iterator<Item = char>) -> O {
|
||||||
|
let mut stack = 0;
|
||||||
|
|
||||||
|
data.by_ref().take_while(|e| *e != '(').for_each(|_| stack += 1);
|
||||||
|
|
||||||
|
let a = data.by_ref().take_while(|c| *c != ')').collect::<String>();
|
||||||
|
let Some((len, times)) = a.split_once('x') else { return stack };
|
||||||
|
let len = len.parse::<usize>().unwrap();
|
||||||
|
let taken = data.by_ref().take(len).filter(|e| !e.is_control() && !e.is_whitespace()).collect::<String>();
|
||||||
|
|
||||||
|
let t = if let Some(p) = taken.find("(") {
|
||||||
|
p + _expand(taken[p..].chars())
|
||||||
|
} else {
|
||||||
|
taken.len()
|
||||||
|
};
|
||||||
|
|
||||||
|
let times = times.parse::<usize>().unwrap();
|
||||||
|
stack += t * times;
|
||||||
|
stack += _expand(data);
|
||||||
|
|
||||||
|
stack
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _silver (data: I) -> O {
|
||||||
|
let mut stack = String::new();
|
||||||
|
let mut cs = data.trim().chars();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let Some(cur) = cs.next() else { break; };
|
||||||
|
|
||||||
|
match cur {
|
||||||
|
'(' => {
|
||||||
|
let a = cs.by_ref().take_while(|c| *c != ')').collect::<String>();
|
||||||
|
let (len, times) = a.split_once('x').unwrap();
|
||||||
|
let len = len.parse::<usize>().unwrap();
|
||||||
|
let times = times.parse::<usize>().unwrap();
|
||||||
|
let taken = cs.by_ref().take(len).filter(|e| !e.is_control() && !e.is_whitespace()).collect::<String>();
|
||||||
|
|
||||||
|
stack.push_str(&taken.repeat(times));
|
||||||
|
},
|
||||||
|
e => stack.push(e),
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
stack.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _gold (data: I) -> O {
|
||||||
|
let stack = _expand(data.trim().chars());
|
||||||
|
stack
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn read () -> I {
|
||||||
|
inc!(9)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sample () {
|
||||||
|
|
||||||
|
let cases = [
|
||||||
|
("ADVENT", 6),
|
||||||
|
("X(8x2)(3x3)ABCY", 18),
|
||||||
|
("A(1x5)BC", 7),
|
||||||
|
("(3x3)XYZ", 9),
|
||||||
|
("A(2x2)BCD(2x2)EFG", 11),
|
||||||
|
("(6x1)(1x3)A", 6),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (i, o) in cases {
|
||||||
|
assert_eq!(_silver(i), o)
|
||||||
|
}
|
||||||
|
|
||||||
|
let cases_gold = [
|
||||||
|
("X(8x2)(3x3)ABCY", 20),
|
||||||
|
("(25x3)(3x3)ABC(2x3)XY(5x2)PQRSTX(18x9)(3x2)TWO(5x7)SEVEN", 445),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (i, o) in cases_gold {
|
||||||
|
assert_eq!(_gold(i), o)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn silver () {
|
||||||
|
let data = read();
|
||||||
|
let ans = _silver(&data);
|
||||||
|
|
||||||
|
assert_eq!(ans, 74532)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn gold () {
|
||||||
|
let data = read();
|
||||||
|
let ans = _gold(&data);
|
||||||
|
|
||||||
|
assert_eq!(ans, 11558231665)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
#![feature(decl_macro)]
|
#![feature(decl_macro)]
|
||||||
|
#![feature(iter_array_chunks)]
|
||||||
|
|
||||||
pub mod days;
|
pub mod days;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|||||||
+3
-1
@@ -2,6 +2,8 @@ pub use crate::utils::*;
|
|||||||
pub use anyhow::Error;
|
pub use anyhow::Error;
|
||||||
pub use itertools::Itertools;
|
pub use itertools::Itertools;
|
||||||
pub use std::{
|
pub use std::{
|
||||||
collections::{ HashMap as M, HashSet as S },
|
collections::{ HashMap as M, HashSet as S, VecDeque as D },
|
||||||
cmp::Ordering as Or,
|
cmp::Ordering as Or,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub type SS = &'static str;
|
||||||
@@ -9,3 +9,16 @@ pub macro s {
|
|||||||
format!("{}", $s)
|
format!("{}", $s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub macro p {
|
||||||
|
($s: expr) => {
|
||||||
|
$s.parse().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub macro n {
|
||||||
|
($s: expr) => {
|
||||||
|
$s.next().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user