mirror of
https://github.com/Ajetski/advent-of-code.git
synced 2025-09-30 09:23:17 -09:00
first attempts :(
This commit is contained in:
parent
1f15b9bc37
commit
e630119aef
@ -3,6 +3,9 @@ name = "advent-of-code-2022"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[profile.test]
|
||||||
|
opt-level = 2
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
54
2022/input/day_16.txt
Normal file
54
2022/input/day_16.txt
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
Valve VR has flow rate=11; tunnels lead to valves LH, KV, BP
|
||||||
|
Valve UV has flow rate=0; tunnels lead to valves GH, RO
|
||||||
|
Valve OH has flow rate=0; tunnels lead to valves AJ, NY
|
||||||
|
Valve GD has flow rate=0; tunnels lead to valves TX, PW
|
||||||
|
Valve NS has flow rate=0; tunnels lead to valves AJ, AA
|
||||||
|
Valve KZ has flow rate=18; tunnels lead to valves KO, VK, PJ
|
||||||
|
Valve AH has flow rate=0; tunnels lead to valves ZP, DI
|
||||||
|
Valve SA has flow rate=0; tunnels lead to valves VG, JF
|
||||||
|
Valve VK has flow rate=0; tunnels lead to valves RO, KZ
|
||||||
|
Valve GB has flow rate=0; tunnels lead to valves XH, AA
|
||||||
|
Valve AJ has flow rate=6; tunnels lead to valves IC, OH, ZR, NS, EM
|
||||||
|
Valve PJ has flow rate=0; tunnels lead to valves KZ, SP
|
||||||
|
Valve KO has flow rate=0; tunnels lead to valves KZ, LE
|
||||||
|
Valve AA has flow rate=0; tunnels lead to valves TW, GB, TI, NS, UL
|
||||||
|
Valve TW has flow rate=0; tunnels lead to valves TU, AA
|
||||||
|
Valve VG has flow rate=25; tunnel leads to valve SA
|
||||||
|
Valve BP has flow rate=0; tunnels lead to valves RO, VR
|
||||||
|
Valve XH has flow rate=0; tunnels lead to valves GB, RI
|
||||||
|
Valve TX has flow rate=0; tunnels lead to valves RI, GD
|
||||||
|
Valve IR has flow rate=10; tunnels lead to valves TN, NY, JF
|
||||||
|
Valve TU has flow rate=0; tunnels lead to valves JD, TW
|
||||||
|
Valve KC has flow rate=0; tunnels lead to valves SP, RO
|
||||||
|
Valve LN has flow rate=0; tunnels lead to valves EM, RI
|
||||||
|
Valve HD has flow rate=0; tunnels lead to valves FE, SC
|
||||||
|
Valve KE has flow rate=0; tunnels lead to valves OM, RI
|
||||||
|
Valve VY has flow rate=0; tunnels lead to valves PW, BS
|
||||||
|
Valve LH has flow rate=0; tunnels lead to valves OM, VR
|
||||||
|
Valve EM has flow rate=0; tunnels lead to valves AJ, LN
|
||||||
|
Valve SO has flow rate=22; tunnels lead to valves ZP, FE
|
||||||
|
Valve EC has flow rate=0; tunnels lead to valves OM, UL
|
||||||
|
Valve KV has flow rate=0; tunnels lead to valves SP, VR
|
||||||
|
Valve FE has flow rate=0; tunnels lead to valves SO, HD
|
||||||
|
Valve TI has flow rate=0; tunnels lead to valves AA, PW
|
||||||
|
Valve SC has flow rate=14; tunnel leads to valve HD
|
||||||
|
Valve ZP has flow rate=0; tunnels lead to valves SO, AH
|
||||||
|
Valve RO has flow rate=19; tunnels lead to valves UV, BP, VK, KC
|
||||||
|
Valve ZR has flow rate=0; tunnels lead to valves OM, AJ
|
||||||
|
Valve JL has flow rate=21; tunnels lead to valves GN, TN
|
||||||
|
Valve PW has flow rate=9; tunnels lead to valves TI, GN, VY, GD, IC
|
||||||
|
Valve UL has flow rate=0; tunnels lead to valves EC, AA
|
||||||
|
Valve GN has flow rate=0; tunnels lead to valves JL, PW
|
||||||
|
Valve TN has flow rate=0; tunnels lead to valves JL, IR
|
||||||
|
Valve NV has flow rate=0; tunnels lead to valves RI, JD
|
||||||
|
Valve DI has flow rate=23; tunnels lead to valves LE, AH
|
||||||
|
Valve IC has flow rate=0; tunnels lead to valves PW, AJ
|
||||||
|
Valve JF has flow rate=0; tunnels lead to valves SA, IR
|
||||||
|
Valve LE has flow rate=0; tunnels lead to valves DI, KO
|
||||||
|
Valve BS has flow rate=0; tunnels lead to valves JD, VY
|
||||||
|
Valve JD has flow rate=15; tunnels lead to valves NV, TU, BS
|
||||||
|
Valve SP has flow rate=24; tunnels lead to valves KC, KV, PJ
|
||||||
|
Valve NY has flow rate=0; tunnels lead to valves IR, OH
|
||||||
|
Valve OM has flow rate=7; tunnels lead to valves EC, GH, KE, ZR, LH
|
||||||
|
Valve GH has flow rate=0; tunnels lead to valves OM, UV
|
||||||
|
Valve RI has flow rate=3; tunnels lead to valves NV, KE, LN, XH, TX
|
10
2022/input/day_16_sample.txt
Normal file
10
2022/input/day_16_sample.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
Valve AA has flow rate=0; tunnels lead to valves DD, II, BB
|
||||||
|
Valve BB has flow rate=13; tunnels lead to valves CC, AA
|
||||||
|
Valve CC has flow rate=2; tunnels lead to valves DD, BB
|
||||||
|
Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE
|
||||||
|
Valve EE has flow rate=3; tunnels lead to valves FF, DD
|
||||||
|
Valve FF has flow rate=0; tunnels lead to valves EE, GG
|
||||||
|
Valve GG has flow rate=0; tunnels lead to valves FF, HH
|
||||||
|
Valve HH has flow rate=22; tunnel leads to valve GG
|
||||||
|
Valve II has flow rate=0; tunnels lead to valves AA, JJ
|
||||||
|
Valve JJ has flow rate=21; tunnel leads to valve II
|
1
2022/input/day_17.txt
Normal file
1
2022/input/day_17.txt
Normal file
File diff suppressed because one or more lines are too long
1
2022/input/day_17_sample.txt
Normal file
1
2022/input/day_17_sample.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
>>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>
|
2893
2022/input/day_18.txt
Normal file
2893
2022/input/day_18.txt
Normal file
File diff suppressed because it is too large
Load Diff
13
2022/input/day_18_sample.txt
Normal file
13
2022/input/day_18_sample.txt
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
2,2,2
|
||||||
|
1,2,2
|
||||||
|
3,2,2
|
||||||
|
2,1,2
|
||||||
|
2,3,2
|
||||||
|
2,2,1
|
||||||
|
2,2,3
|
||||||
|
2,2,4
|
||||||
|
2,2,6
|
||||||
|
1,2,5
|
||||||
|
3,2,5
|
||||||
|
2,1,5
|
||||||
|
2,3,5
|
30
2022/input/day_19.txt
Normal file
30
2022/input/day_19.txt
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
Blueprint 1: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 12 clay. Each geode robot costs 4 ore and 19 obsidian.
|
||||||
|
Blueprint 2: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 11 clay. Each geode robot costs 2 ore and 7 obsidian.
|
||||||
|
Blueprint 3: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 13 clay. Each geode robot costs 3 ore and 12 obsidian.
|
||||||
|
Blueprint 4: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 18 clay. Each geode robot costs 2 ore and 19 obsidian.
|
||||||
|
Blueprint 5: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 19 clay. Each geode robot costs 4 ore and 13 obsidian.
|
||||||
|
Blueprint 6: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 7 clay. Each geode robot costs 4 ore and 11 obsidian.
|
||||||
|
Blueprint 7: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 15 clay. Each geode robot costs 4 ore and 17 obsidian.
|
||||||
|
Blueprint 8: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 13 clay. Each geode robot costs 3 ore and 7 obsidian.
|
||||||
|
Blueprint 9: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 12 clay. Each geode robot costs 3 ore and 15 obsidian.
|
||||||
|
Blueprint 10: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 4 ore and 18 clay. Each geode robot costs 4 ore and 11 obsidian.
|
||||||
|
Blueprint 11: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 8 clay. Each geode robot costs 2 ore and 15 obsidian.
|
||||||
|
Blueprint 12: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 4 ore and 8 clay. Each geode robot costs 3 ore and 7 obsidian.
|
||||||
|
Blueprint 13: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 10 clay. Each geode robot costs 2 ore and 10 obsidian.
|
||||||
|
Blueprint 14: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 13 clay. Each geode robot costs 2 ore and 20 obsidian.
|
||||||
|
Blueprint 15: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 19 clay. Each geode robot costs 3 ore and 8 obsidian.
|
||||||
|
Blueprint 16: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 16 clay. Each geode robot costs 2 ore and 18 obsidian.
|
||||||
|
Blueprint 17: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 9 clay. Each geode robot costs 3 ore and 19 obsidian.
|
||||||
|
Blueprint 18: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 11 clay. Each geode robot costs 4 ore and 8 obsidian.
|
||||||
|
Blueprint 19: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 12 clay. Each geode robot costs 3 ore and 17 obsidian.
|
||||||
|
Blueprint 20: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 14 clay. Each geode robot costs 3 ore and 17 obsidian.
|
||||||
|
Blueprint 21: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 15 clay. Each geode robot costs 3 ore and 16 obsidian.
|
||||||
|
Blueprint 22: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 16 clay. Each geode robot costs 4 ore and 16 obsidian.
|
||||||
|
Blueprint 23: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 19 clay. Each geode robot costs 4 ore and 11 obsidian.
|
||||||
|
Blueprint 24: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 18 clay. Each geode robot costs 4 ore and 9 obsidian.
|
||||||
|
Blueprint 25: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 17 clay. Each geode robot costs 3 ore and 16 obsidian.
|
||||||
|
Blueprint 26: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 20 clay. Each geode robot costs 4 ore and 7 obsidian.
|
||||||
|
Blueprint 27: Each ore robot costs 2 ore. Each clay robot costs 2 ore. Each obsidian robot costs 2 ore and 8 clay. Each geode robot costs 2 ore and 14 obsidian.
|
||||||
|
Blueprint 28: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 20 clay. Each geode robot costs 3 ore and 14 obsidian.
|
||||||
|
Blueprint 29: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 4 ore and 20 clay. Each geode robot costs 4 ore and 8 obsidian.
|
||||||
|
Blueprint 30: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 18 clay. Each geode robot costs 3 ore and 13 obsidian.
|
2
2022/input/day_19_sample.txt
Normal file
2
2022/input/day_19_sample.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
Blueprint 1: Each ore robot costs 4 ore. Each clay robot costs 2 ore. Each obsidian robot costs 3 ore and 14 clay. Each geode robot costs 2 ore and 7 obsidian.
|
||||||
|
Blueprint 2: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 8 clay. Each geode robot costs 3 ore and 12 obsidian.
|
89
2022/src/day_16.rs
Normal file
89
2022/src/day_16.rs
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Node {
|
||||||
|
id: String,
|
||||||
|
rate: i64,
|
||||||
|
edges: Vec<String>,
|
||||||
|
}
|
||||||
|
type Data = (String, HashMap<String, Node>);
|
||||||
|
type Output = i64;
|
||||||
|
fn parse(input: &str) -> Data {
|
||||||
|
let start = input.lines().next().unwrap()[6..=7].to_string();
|
||||||
|
let map = input
|
||||||
|
.lines()
|
||||||
|
.map(|l| {
|
||||||
|
let id = l[6..=7].to_string();
|
||||||
|
|
||||||
|
let rate = l
|
||||||
|
.chars()
|
||||||
|
.skip_while(|c| *c != '=')
|
||||||
|
.skip(1)
|
||||||
|
.take_while(|c| *c != ';')
|
||||||
|
.collect::<String>()
|
||||||
|
.parse()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let edges_str = l
|
||||||
|
.chars()
|
||||||
|
.skip_while(|c| *c != ';')
|
||||||
|
.skip_while(|c| *c != 'v')
|
||||||
|
.skip_while(|c| *c != ' ')
|
||||||
|
.skip(1)
|
||||||
|
.collect::<String>();
|
||||||
|
let edges = edges_str.split(", ").map(str::to_owned).collect();
|
||||||
|
|
||||||
|
(id.clone(), Node { id, edges, rate })
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
(start, map)
|
||||||
|
}
|
||||||
|
fn part_one((start, mut graph): Data) -> Output {
|
||||||
|
fn solve(
|
||||||
|
graph: &mut HashMap<String, Node>,
|
||||||
|
curr: &str,
|
||||||
|
parent: &str,
|
||||||
|
amount_released: i64,
|
||||||
|
time_left: i64,
|
||||||
|
) -> Output {
|
||||||
|
if time_left == 0 {
|
||||||
|
return amount_released;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut max = 0;
|
||||||
|
let rate = graph.get(curr).unwrap().rate;
|
||||||
|
if rate > 0 {
|
||||||
|
graph.get_mut(curr).unwrap().rate = 0;
|
||||||
|
max = solve(
|
||||||
|
&mut *graph,
|
||||||
|
curr,
|
||||||
|
curr,
|
||||||
|
amount_released + rate * (time_left - 1),
|
||||||
|
time_left - 1,
|
||||||
|
);
|
||||||
|
graph.get_mut(curr).unwrap().rate = rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
for edge in &graph.get(curr).unwrap().edges.clone() {
|
||||||
|
if edge != parent {
|
||||||
|
max = std::cmp::max(
|
||||||
|
max,
|
||||||
|
solve(graph, edge, curr, amount_released, time_left - 1),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
max
|
||||||
|
}
|
||||||
|
solve(&mut graph, &start, "", 0, 30)
|
||||||
|
}
|
||||||
|
fn part_two(_data: Data) -> Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
advent_of_code_macro::generate_tests!(
|
||||||
|
day 16,
|
||||||
|
parse,
|
||||||
|
part_one,
|
||||||
|
part_two,
|
||||||
|
sample tests [1_651, 0],
|
||||||
|
star tests [0, 0]
|
||||||
|
);
|
258
2022/src/day_17.rs
Normal file
258
2022/src/day_17.rs
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
type Board = Vec<[bool; 7]>;
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
enum BlockType {
|
||||||
|
Square,
|
||||||
|
L,
|
||||||
|
Horizontal,
|
||||||
|
Vertical,
|
||||||
|
Cross,
|
||||||
|
}
|
||||||
|
impl BlockType {
|
||||||
|
fn height(&self) -> usize {
|
||||||
|
match *self {
|
||||||
|
Square => 2,
|
||||||
|
L => 3,
|
||||||
|
Horizontal => 1,
|
||||||
|
Vertical => 4,
|
||||||
|
Cross => 3,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use BlockType::*;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Position {
|
||||||
|
row: usize,
|
||||||
|
col: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Block {
|
||||||
|
pos: Position,
|
||||||
|
block_type: BlockType,
|
||||||
|
}
|
||||||
|
impl Block {
|
||||||
|
fn left(&mut self, board: &Board) {
|
||||||
|
let cond = match self.block_type {
|
||||||
|
Square => {
|
||||||
|
self.pos.col > 0
|
||||||
|
&& !board[self.pos.row][self.pos.col - 1]
|
||||||
|
&& !board[self.pos.row - 1][self.pos.col - 1]
|
||||||
|
}
|
||||||
|
L => {
|
||||||
|
self.pos.col > 0
|
||||||
|
&& !board[self.pos.row][self.pos.col + 1]
|
||||||
|
&& !board[self.pos.row - 1][self.pos.col + 1]
|
||||||
|
&& !board[self.pos.row - 2][self.pos.col - 1]
|
||||||
|
}
|
||||||
|
Cross => {
|
||||||
|
self.pos.col > 0
|
||||||
|
&& !board[self.pos.row][self.pos.col]
|
||||||
|
&& !board[self.pos.row - 1][self.pos.col - 1]
|
||||||
|
&& !board[self.pos.row - 2][self.pos.col]
|
||||||
|
}
|
||||||
|
Horizontal => self.pos.col > 0 && !board[self.pos.row][self.pos.col - 1],
|
||||||
|
Vertical => {
|
||||||
|
self.pos.col > 0
|
||||||
|
&& !board[self.pos.row][self.pos.col - 1]
|
||||||
|
&& !board[self.pos.row - 1][self.pos.col - 1]
|
||||||
|
&& !board[self.pos.row - 2][self.pos.col - 1]
|
||||||
|
&& !board[self.pos.row - 3][self.pos.col - 1]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if cond {
|
||||||
|
self.pos.col -= 1;
|
||||||
|
}
|
||||||
|
println!("left to {:?}, {:?}", self.pos, self.block_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn right(&mut self, board: &Board) {
|
||||||
|
let cond = match self.block_type {
|
||||||
|
Square => {
|
||||||
|
self.pos.col < 5
|
||||||
|
&& !board[self.pos.row][self.pos.col + 2]
|
||||||
|
&& !board[self.pos.row - 1][self.pos.col + 2]
|
||||||
|
}
|
||||||
|
L => {
|
||||||
|
self.pos.col < 4
|
||||||
|
&& !board[self.pos.row][self.pos.col + 3]
|
||||||
|
&& !board[self.pos.row - 1][self.pos.col + 3]
|
||||||
|
&& !board[self.pos.row - 2][self.pos.col + 3]
|
||||||
|
}
|
||||||
|
Cross => {
|
||||||
|
self.pos.col < 4
|
||||||
|
&& !board[self.pos.row][self.pos.col + 2]
|
||||||
|
&& !board[self.pos.row - 1][self.pos.col + 3]
|
||||||
|
&& !board[self.pos.row - 2][self.pos.col + 2]
|
||||||
|
}
|
||||||
|
Horizontal => self.pos.col < 3 && !board[self.pos.row][self.pos.col + 4],
|
||||||
|
Vertical => {
|
||||||
|
self.pos.col < 6
|
||||||
|
&& !board[self.pos.row][self.pos.col + 1]
|
||||||
|
&& !board[self.pos.row - 1][self.pos.col + 1]
|
||||||
|
&& !board[self.pos.row - 2][self.pos.col + 1]
|
||||||
|
&& !board[self.pos.row - 3][self.pos.col + 1]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if cond {
|
||||||
|
self.pos.col += 1;
|
||||||
|
}
|
||||||
|
println!("right to {:?}, {:?}", self.pos, self.block_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns if the block comes to rest (and can't move down)
|
||||||
|
/// board will only be mutated to insert the object if the block is at rest
|
||||||
|
fn down(&mut self, board: &mut Board) -> bool {
|
||||||
|
let is_falling = match self.block_type {
|
||||||
|
Square => {
|
||||||
|
self.pos.row > 1
|
||||||
|
&& !board[self.pos.row - 2][self.pos.col]
|
||||||
|
&& !board[self.pos.row - 2][self.pos.col + 1]
|
||||||
|
}
|
||||||
|
L => {
|
||||||
|
self.pos.row > 2
|
||||||
|
&& !board[self.pos.row - 3][self.pos.col]
|
||||||
|
&& !board[self.pos.row - 3][self.pos.col + 1]
|
||||||
|
&& !board[self.pos.row - 3][self.pos.col + 2]
|
||||||
|
}
|
||||||
|
Cross => {
|
||||||
|
self.pos.row > 2
|
||||||
|
&& !board[self.pos.row - 2][self.pos.col]
|
||||||
|
&& !board[self.pos.row - 3][self.pos.col + 1]
|
||||||
|
&& !board[self.pos.row - 2][self.pos.col + 2]
|
||||||
|
}
|
||||||
|
Horizontal => {
|
||||||
|
self.pos.row > 0
|
||||||
|
&& !board[self.pos.row - 1][self.pos.col]
|
||||||
|
&& !board[self.pos.row - 1][self.pos.col + 1]
|
||||||
|
&& !board[self.pos.row - 1][self.pos.col + 2]
|
||||||
|
&& !board[self.pos.row - 1][self.pos.col + 3]
|
||||||
|
}
|
||||||
|
Vertical => self.pos.row > 3 && !board[self.pos.row - 4][self.pos.col],
|
||||||
|
};
|
||||||
|
if is_falling {
|
||||||
|
self.pos.row -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"down to {:?}, is falling? {:?}, {:?}",
|
||||||
|
self.pos, is_falling, self.block_type
|
||||||
|
);
|
||||||
|
!is_falling
|
||||||
|
}
|
||||||
|
fn draw(&self, board: &mut Board) {
|
||||||
|
match self.block_type {
|
||||||
|
Square => {
|
||||||
|
board[self.pos.row][self.pos.col] = true;
|
||||||
|
board[self.pos.row][self.pos.col + 1] = true;
|
||||||
|
board[self.pos.row - 1][self.pos.col] = true;
|
||||||
|
board[self.pos.row - 1][self.pos.col + 1] = true;
|
||||||
|
}
|
||||||
|
L => {
|
||||||
|
board[self.pos.row][self.pos.col + 2] = true;
|
||||||
|
board[self.pos.row - 1][self.pos.col + 2] = true;
|
||||||
|
board[self.pos.row - 2][self.pos.col + 2] = true;
|
||||||
|
board[self.pos.row - 2][self.pos.col + 1] = true;
|
||||||
|
board[self.pos.row - 2][self.pos.col] = true;
|
||||||
|
}
|
||||||
|
Cross => {
|
||||||
|
board[self.pos.row][self.pos.col + 1] = true;
|
||||||
|
board[self.pos.row - 1][self.pos.col + 1] = true;
|
||||||
|
board[self.pos.row - 2][self.pos.col + 1] = true;
|
||||||
|
board[self.pos.row - 1][self.pos.col] = true;
|
||||||
|
board[self.pos.row - 1][self.pos.col + 2] = true;
|
||||||
|
}
|
||||||
|
Horizontal => {
|
||||||
|
board[self.pos.row][self.pos.col] = true;
|
||||||
|
board[self.pos.row][self.pos.col + 1] = true;
|
||||||
|
board[self.pos.row][self.pos.col + 2] = true;
|
||||||
|
board[self.pos.row][self.pos.col + 3] = true;
|
||||||
|
}
|
||||||
|
Vertical => {
|
||||||
|
board[self.pos.row][self.pos.col] = true;
|
||||||
|
board[self.pos.row - 1][self.pos.col] = true;
|
||||||
|
board[self.pos.row - 2][self.pos.col] = true;
|
||||||
|
board[self.pos.row - 3][self.pos.col] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Data = &'static str;
|
||||||
|
type Output = i32;
|
||||||
|
fn parse(input: &'static str) -> Data {
|
||||||
|
input
|
||||||
|
}
|
||||||
|
fn part_one(data: Data) -> Output {
|
||||||
|
let mut blocks = vec![Horizontal, Cross, L, Vertical, Square]
|
||||||
|
.into_iter()
|
||||||
|
.cycle();
|
||||||
|
let mut top = -1i32;
|
||||||
|
let block_type = blocks.next().unwrap();
|
||||||
|
let mut curr = Block {
|
||||||
|
pos: Position { row: 3, col: 2 },
|
||||||
|
block_type,
|
||||||
|
};
|
||||||
|
let mut board = vec![[false; 7]; 5];
|
||||||
|
let mut num_rocks = 0;
|
||||||
|
for c in data.chars().cycle() {
|
||||||
|
match c {
|
||||||
|
'>' => curr.right(&board),
|
||||||
|
'<' => curr.left(&board),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
if curr.down(&mut board) {
|
||||||
|
curr.draw(&mut board);
|
||||||
|
top = board
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.rev()
|
||||||
|
.find(|(_, el)| **el != [false; 7])
|
||||||
|
.map(|(idx, _)| idx as i32)
|
||||||
|
.unwrap();
|
||||||
|
num_rocks += 1;
|
||||||
|
|
||||||
|
println!();
|
||||||
|
for line in board.iter().rev() {
|
||||||
|
print!("|");
|
||||||
|
line.iter()
|
||||||
|
.map(|filled| if *filled { '#' } else { '.' })
|
||||||
|
.for_each(|c| print!("{c}"));
|
||||||
|
println!("|");
|
||||||
|
}
|
||||||
|
println!("+-------+");
|
||||||
|
println!("{:?}", top);
|
||||||
|
println!();
|
||||||
|
|
||||||
|
if num_rocks == 15 {
|
||||||
|
return top;
|
||||||
|
}
|
||||||
|
let block_type = blocks.next().unwrap();
|
||||||
|
let start_row = top + 3 + block_type.height() as i32;
|
||||||
|
while board.len() <= start_row as usize {
|
||||||
|
board.push([false; 7]);
|
||||||
|
}
|
||||||
|
curr = Block {
|
||||||
|
pos: Position {
|
||||||
|
row: start_row as usize,
|
||||||
|
col: 2,
|
||||||
|
},
|
||||||
|
block_type,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
fn part_two(_data: Data) -> Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
advent_of_code_macro::generate_tests!(
|
||||||
|
day 17,
|
||||||
|
parse,
|
||||||
|
part_one,
|
||||||
|
part_two,
|
||||||
|
sample tests [3068, 0],
|
||||||
|
star tests [0, 0]
|
||||||
|
);
|
201
2022/src/day_18.rs
Normal file
201
2022/src/day_18.rs
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
use std::collections::HashSet;
|
||||||
|
use Side::*;
|
||||||
|
|
||||||
|
type Point = (i32, i32, i32);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||||
|
enum Side {
|
||||||
|
/// positive z side
|
||||||
|
Top,
|
||||||
|
|
||||||
|
/// negative z side
|
||||||
|
Bottom,
|
||||||
|
|
||||||
|
/// negative x side
|
||||||
|
Left,
|
||||||
|
|
||||||
|
/// positive x side
|
||||||
|
Right,
|
||||||
|
|
||||||
|
/// positive y side
|
||||||
|
Front,
|
||||||
|
|
||||||
|
/// negative y side
|
||||||
|
Back,
|
||||||
|
}
|
||||||
|
impl Side {
|
||||||
|
fn inverse(&self) -> Self {
|
||||||
|
match *self {
|
||||||
|
Top => Bottom,
|
||||||
|
Bottom => Top,
|
||||||
|
Left => Right,
|
||||||
|
Right => Left,
|
||||||
|
Front => Back,
|
||||||
|
Back => Front,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Data = HashSet<Point>;
|
||||||
|
|
||||||
|
type Output = i32;
|
||||||
|
|
||||||
|
fn parse(input: &str) -> Data {
|
||||||
|
input
|
||||||
|
.lines()
|
||||||
|
.map(|l| l.split(',').map(str::parse).map(Result::unwrap))
|
||||||
|
.map(|mut iter| {
|
||||||
|
(
|
||||||
|
iter.next().unwrap(),
|
||||||
|
iter.next().unwrap(),
|
||||||
|
iter.next().unwrap(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_one(data: Data) -> Output {
|
||||||
|
data.iter()
|
||||||
|
.map(|(x, y, z)| {
|
||||||
|
let offsets = [
|
||||||
|
(0, 0, 1),
|
||||||
|
(0, 1, 0),
|
||||||
|
(1, 0, 0),
|
||||||
|
(0, 0, -1),
|
||||||
|
(0, -1, 0),
|
||||||
|
(-1, 0, 0),
|
||||||
|
];
|
||||||
|
offsets
|
||||||
|
.iter()
|
||||||
|
.filter(|(x_off, y_off, z_off)| !data.contains(&(x + x_off, y + y_off, z + z_off)))
|
||||||
|
.count() as Output
|
||||||
|
})
|
||||||
|
.sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_two(data: Data) -> Output {
|
||||||
|
let mut queue = vec![(
|
||||||
|
*data
|
||||||
|
.iter()
|
||||||
|
.max_by(|(x1, _, _), (x2, _, _)| x1.cmp(x2))
|
||||||
|
.unwrap(),
|
||||||
|
Top,
|
||||||
|
)];
|
||||||
|
let mut visited: HashSet<(Point, Side)> = queue.clone().into_iter().collect();
|
||||||
|
for i in 0.. {
|
||||||
|
if i >= queue.len() {
|
||||||
|
return visited.len() as Output;
|
||||||
|
}
|
||||||
|
let ((curr_x, curr_y, curr_z), curr_side) = queue[i];
|
||||||
|
let offsets = [(1, 0), (0, 1), (-1, 0), (0, -1)];
|
||||||
|
let positions = offsets.iter().map(|(a, b)| match curr_side {
|
||||||
|
Top | Bottom => (curr_x + a, curr_y + b, curr_z),
|
||||||
|
Left | Right => (curr_x, curr_y + a, curr_z + b),
|
||||||
|
Front | Back => (curr_x + a, curr_y, curr_z + b),
|
||||||
|
});
|
||||||
|
for (new_x, new_y, new_z) in positions {
|
||||||
|
let res = match curr_side {
|
||||||
|
Top | Bottom => {
|
||||||
|
let side = if curr_x > new_x {
|
||||||
|
Right
|
||||||
|
} else if curr_x < new_x {
|
||||||
|
Left
|
||||||
|
} else if curr_y > new_y {
|
||||||
|
Front
|
||||||
|
} else {
|
||||||
|
Back
|
||||||
|
};
|
||||||
|
if curr_side == Top {
|
||||||
|
if data.contains(&(new_x, new_y, new_z + 1)) {
|
||||||
|
((new_x, new_y, new_z + 1), side)
|
||||||
|
} else if data.contains(&(new_x, new_y, new_z)) {
|
||||||
|
((new_x, new_y, new_z), Top)
|
||||||
|
} else {
|
||||||
|
((curr_x, curr_y, curr_z), side.inverse())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if data.contains(&(new_x, new_y, new_z - 1)) {
|
||||||
|
((new_x, new_y, new_z - 1), side)
|
||||||
|
} else if data.contains(&(new_x, new_y, new_z)) {
|
||||||
|
((new_x, new_y, new_z), Bottom)
|
||||||
|
} else {
|
||||||
|
((curr_x, curr_y, curr_z), side.inverse())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Left | Right => {
|
||||||
|
let side = if curr_z > new_z {
|
||||||
|
Top
|
||||||
|
} else if curr_z < new_z {
|
||||||
|
Bottom
|
||||||
|
} else if curr_y > new_y {
|
||||||
|
Front
|
||||||
|
} else {
|
||||||
|
Back
|
||||||
|
};
|
||||||
|
if curr_side == Left {
|
||||||
|
if data.contains(&(new_x - 1, new_y, new_z)) {
|
||||||
|
((new_x - 1, new_y, new_z), side)
|
||||||
|
} else if data.contains(&(new_x, new_y, new_z)) {
|
||||||
|
((new_x, new_y, new_z), Left)
|
||||||
|
} else {
|
||||||
|
((curr_x, curr_y, curr_z), side.inverse())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if data.contains(&(new_x + 1, new_y, new_z)) {
|
||||||
|
((new_x + 1, new_y, new_z), side)
|
||||||
|
} else if data.contains(&(new_x, new_y, new_z)) {
|
||||||
|
((new_x, new_y, new_z), Right)
|
||||||
|
} else {
|
||||||
|
((curr_x, curr_y, curr_z), side.inverse())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Front | Back => {
|
||||||
|
let side = if curr_z > new_z {
|
||||||
|
Top
|
||||||
|
} else if curr_z < new_z {
|
||||||
|
Bottom
|
||||||
|
} else if curr_x > new_x {
|
||||||
|
Right
|
||||||
|
} else {
|
||||||
|
Left
|
||||||
|
};
|
||||||
|
if curr_side == Front {
|
||||||
|
if data.contains(&(new_x, new_y + 1, new_z)) {
|
||||||
|
((new_x, new_y + 1, new_z), side)
|
||||||
|
} else if data.contains(&(new_x, new_y, new_z)) {
|
||||||
|
((new_x, new_y, new_z), Front)
|
||||||
|
} else {
|
||||||
|
((curr_x, curr_y, curr_z), side.inverse())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if data.contains(&(new_x + 1, new_y, new_z)) {
|
||||||
|
((new_x + 1, new_y, new_z), side)
|
||||||
|
} else if data.contains(&(new_x, new_y, new_z)) {
|
||||||
|
((new_x, new_y, new_z), Back)
|
||||||
|
} else {
|
||||||
|
((curr_x, curr_y, curr_z), side.inverse())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if !visited.contains(&res) {
|
||||||
|
visited.insert(res);
|
||||||
|
println!("{:?}", res);
|
||||||
|
queue.push(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
advent_of_code_macro::generate_tests!(
|
||||||
|
day 18,
|
||||||
|
parse,
|
||||||
|
part_one,
|
||||||
|
part_two,
|
||||||
|
sample tests [64, 58],
|
||||||
|
star tests [4300, 0]
|
||||||
|
);
|
202
2022/src/day_19.rs
Normal file
202
2022/src/day_19.rs
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
use std::collections::{BinaryHeap, HashSet};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Blueprint {
|
||||||
|
id: i64,
|
||||||
|
ore_robot_cost: i64,
|
||||||
|
clay_robot_cost: i64,
|
||||||
|
obsidian_robot_cost: (i64, i64),
|
||||||
|
geode_robot_cost: (i64, i64),
|
||||||
|
}
|
||||||
|
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
|
||||||
|
struct Search {
|
||||||
|
time_left: i64,
|
||||||
|
ore: i64,
|
||||||
|
ore_robots: i64,
|
||||||
|
clay: i64,
|
||||||
|
clay_robots: i64,
|
||||||
|
obsidian: i64,
|
||||||
|
obsidian_robots: i64,
|
||||||
|
geode: i64,
|
||||||
|
geode_robots: i64,
|
||||||
|
}
|
||||||
|
impl std::cmp::Ord for Search {
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
(self.geode_robots * self.time_left + self.geode)
|
||||||
|
.cmp(&(other.geode_robots * other.time_left + other.geode))
|
||||||
|
.then_with(|| self.obsidian_robots.cmp(&other.obsidian_robots))
|
||||||
|
.then_with(|| self.clay_robots.cmp(&other.clay_robots))
|
||||||
|
.then_with(|| self.ore_robots.cmp(&other.ore_robots))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::cmp::PartialOrd for Search {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type Data = Vec<Blueprint>;
|
||||||
|
type Output = i64;
|
||||||
|
fn parse(input: &str) -> Data {
|
||||||
|
input
|
||||||
|
.lines()
|
||||||
|
.map(|l| Blueprint {
|
||||||
|
id: get_id(l),
|
||||||
|
ore_robot_cost: get_cost_one(l, "ore"),
|
||||||
|
clay_robot_cost: get_cost_one(l, "clay"),
|
||||||
|
obsidian_robot_cost: get_cost_two(l, "obsidian"),
|
||||||
|
geode_robot_cost: get_cost_two(l, "geode"),
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
fn max_geodes(bp: &Blueprint, initial_search: Search) -> Output {
|
||||||
|
let mut queue: BinaryHeap<Search> = BinaryHeap::new();
|
||||||
|
let mut visited: HashSet<Search> = HashSet::new();
|
||||||
|
queue.push(initial_search);
|
||||||
|
let mut max = 0;
|
||||||
|
while let Some(search) = queue.pop() {
|
||||||
|
if search.time_left == 0 {
|
||||||
|
println!("{:?}, {:?}", max, search);
|
||||||
|
max = std::cmp::max(search.geode, max);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let mut temp_search = search;
|
||||||
|
while temp_search.ore >= bp.ore_robot_cost {
|
||||||
|
temp_search.ore -= bp.ore_robot_cost;
|
||||||
|
temp_search.ore_robots += 1;
|
||||||
|
}
|
||||||
|
if !visited.contains(&temp_search) {
|
||||||
|
visited.insert(temp_search);
|
||||||
|
queue.push(temp_search);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let mut temp_search = search;
|
||||||
|
while temp_search.ore >= bp.clay_robot_cost {
|
||||||
|
temp_search.ore -= bp.clay_robot_cost;
|
||||||
|
temp_search.clay_robots += 1;
|
||||||
|
}
|
||||||
|
if !visited.contains(&temp_search) {
|
||||||
|
visited.insert(temp_search);
|
||||||
|
queue.push(temp_search);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let mut temp_search = search;
|
||||||
|
while temp_search.ore >= bp.obsidian_robot_cost.0
|
||||||
|
&& temp_search.clay >= bp.obsidian_robot_cost.1
|
||||||
|
{
|
||||||
|
temp_search.ore -= bp.obsidian_robot_cost.0;
|
||||||
|
temp_search.clay -= bp.obsidian_robot_cost.1;
|
||||||
|
temp_search.obsidian_robots += 1;
|
||||||
|
}
|
||||||
|
if !visited.contains(&temp_search) {
|
||||||
|
visited.insert(temp_search);
|
||||||
|
queue.push(temp_search);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let mut temp_search = search;
|
||||||
|
while temp_search.ore >= bp.geode_robot_cost.0
|
||||||
|
&& temp_search.obsidian >= bp.geode_robot_cost.1
|
||||||
|
{
|
||||||
|
temp_search.ore -= bp.geode_robot_cost.0;
|
||||||
|
temp_search.obsidian -= bp.geode_robot_cost.1;
|
||||||
|
temp_search.geode_robots += 1;
|
||||||
|
}
|
||||||
|
if !visited.contains(&temp_search) {
|
||||||
|
visited.insert(temp_search);
|
||||||
|
queue.push(temp_search);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let mut temp_search = search;
|
||||||
|
temp_search.ore += temp_search.ore_robots;
|
||||||
|
temp_search.clay += temp_search.clay_robots;
|
||||||
|
temp_search.obsidian += temp_search.obsidian_robots;
|
||||||
|
temp_search.geode += temp_search.geode_robots;
|
||||||
|
temp_search.time_left -= 1;
|
||||||
|
if !visited.contains(&temp_search) {
|
||||||
|
visited.insert(temp_search);
|
||||||
|
queue.push(temp_search);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
max
|
||||||
|
}
|
||||||
|
fn part_one(data: Data) -> Output {
|
||||||
|
for bp in data {
|
||||||
|
let res = max_geodes(
|
||||||
|
&bp,
|
||||||
|
Search {
|
||||||
|
time_left: 24,
|
||||||
|
ore: 0,
|
||||||
|
ore_robots: 1,
|
||||||
|
clay: 0,
|
||||||
|
clay_robots: 0,
|
||||||
|
obsidian: 0,
|
||||||
|
obsidian_robots: 0,
|
||||||
|
geode: 0,
|
||||||
|
geode_robots: 0,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
dbg!(res);
|
||||||
|
}
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
fn part_two(data: Data) -> Output {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
advent_of_code_macro::generate_tests!(
|
||||||
|
day 19,
|
||||||
|
parse,
|
||||||
|
part_one,
|
||||||
|
part_two,
|
||||||
|
sample tests [0, 0],
|
||||||
|
star tests [0, 0]
|
||||||
|
);
|
||||||
|
|
||||||
|
// helper funtions for parsing
|
||||||
|
fn get_cost_one(l: &str, t: &str) -> i64 {
|
||||||
|
l.split_once(&format!("{} robot costs ", t))
|
||||||
|
.unwrap()
|
||||||
|
.1
|
||||||
|
.split_once(' ')
|
||||||
|
.unwrap()
|
||||||
|
.0
|
||||||
|
.parse()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
fn get_cost_two(l: &str, t: &str) -> (i64, i64) {
|
||||||
|
(
|
||||||
|
l.split_once(&format!("{} robot costs ", t))
|
||||||
|
.unwrap()
|
||||||
|
.1
|
||||||
|
.split_once(' ')
|
||||||
|
.unwrap()
|
||||||
|
.0
|
||||||
|
.parse()
|
||||||
|
.unwrap(),
|
||||||
|
l.split_once(&format!("{} robot costs ", t))
|
||||||
|
.unwrap()
|
||||||
|
.1
|
||||||
|
.split_once("and ")
|
||||||
|
.unwrap()
|
||||||
|
.1
|
||||||
|
.split_once(' ')
|
||||||
|
.unwrap()
|
||||||
|
.0
|
||||||
|
.parse()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn get_id(l: &str) -> i64 {
|
||||||
|
l.split_once(' ')
|
||||||
|
.unwrap()
|
||||||
|
.1
|
||||||
|
.split_once(':')
|
||||||
|
.unwrap()
|
||||||
|
.0
|
||||||
|
.parse()
|
||||||
|
.unwrap()
|
||||||
|
}
|
@ -14,3 +14,7 @@ mod day_12;
|
|||||||
mod day_13;
|
mod day_13;
|
||||||
mod day_14;
|
mod day_14;
|
||||||
mod day_15;
|
mod day_15;
|
||||||
|
mod day_16;
|
||||||
|
mod day_17;
|
||||||
|
mod day_18;
|
||||||
|
mod day_19;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user