Compare commits
No commits in common. "e3bf22c10f4c61031f080b0c703598cf66143c1e" and "84de761c1af77ca804aaaeba13caa617ae1e4376" have entirely different histories.
e3bf22c10f
...
84de761c1a
1089
2022/data/day7.txt
1089
2022/data/day7.txt
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,4 @@
|
||||||
use nom::{self, bytes::complete::tag, character::complete, IResult};
|
use nom::{self, bytes::complete::tag, character::complete, sequence::separated_pair, IResult};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
const INPUT: &str = include_str!("../data/day4.txt");
|
const INPUT: &str = include_str!("../data/day4.txt");
|
||||||
|
|
543
2022/src/day7.rs
543
2022/src/day7.rs
|
@ -1,543 +0,0 @@
|
||||||
use nom::{
|
|
||||||
bytes::complete::tag,
|
|
||||||
character::{
|
|
||||||
complete::{line_ending, not_line_ending, u32},
|
|
||||||
streaming::space1,
|
|
||||||
},
|
|
||||||
combinator::eof,
|
|
||||||
multi::many0,
|
|
||||||
sequence::terminated,
|
|
||||||
IResult, Parser,
|
|
||||||
};
|
|
||||||
use std::{
|
|
||||||
collections::{HashMap, HashSet},
|
|
||||||
path::PathBuf,
|
|
||||||
};
|
|
||||||
|
|
||||||
const INPUT: &str = include_str!("../data/day7.txt");
|
|
||||||
|
|
||||||
pub fn part1() -> String {
|
|
||||||
format!("{}", tree_sizes_100k(&input(INPUT)))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn part2() -> String {
|
|
||||||
format!("{}", find_minimum_directory(&input(INPUT)).1)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
enum SessionLine {
|
|
||||||
Output(Node),
|
|
||||||
Command(Command),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
enum Node {
|
|
||||||
Dir(Dir),
|
|
||||||
File(File),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
struct Dir {
|
|
||||||
name: String,
|
|
||||||
children: Vec<PathBuf>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
struct File {
|
|
||||||
name: String,
|
|
||||||
size: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Node {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::Dir(Dir {
|
|
||||||
name: "/".to_owned(),
|
|
||||||
children: vec![],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tree_sizes_100k(filesystem: &Filesystem) -> usize {
|
|
||||||
filesystem
|
|
||||||
.find_dirs()
|
|
||||||
.iter()
|
|
||||||
.map(|path| filesystem.size(path))
|
|
||||||
.filter(|size| *size <= 100000)
|
|
||||||
.fold(0, |cur, size| cur + size)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_minimum_directory(filesystem: &Filesystem) -> (PathBuf, usize) {
|
|
||||||
let needed_space = 30000000 - filesystem.free_space();
|
|
||||||
let mut dir_sizes = filesystem
|
|
||||||
.find_dirs()
|
|
||||||
.iter()
|
|
||||||
.map(|path| (path.clone(), filesystem.size(path)))
|
|
||||||
.filter(|(_, size)| needed_space < (*size).try_into().unwrap())
|
|
||||||
.collect::<Vec<(PathBuf, usize)>>();
|
|
||||||
dir_sizes.sort_by(|(_, lsize), (_, rsize)| lsize.cmp(rsize));
|
|
||||||
dir_sizes[0].clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
enum Command {
|
|
||||||
CD(String),
|
|
||||||
LS,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
struct Filesystem(HashMap<PathBuf, Node>);
|
|
||||||
|
|
||||||
impl Filesystem {
|
|
||||||
fn insert(&mut self, path: PathBuf, node: Node) {
|
|
||||||
self.0.insert(path, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn paths(&self) -> HashSet<PathBuf> {
|
|
||||||
self.0.keys().cloned().collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get(&self, path: &PathBuf) -> Option<&Node> {
|
|
||||||
self.0.get(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_mut(&mut self, path: &PathBuf) -> Option<&mut Node> {
|
|
||||||
self.0.get_mut(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size(&self, path: &PathBuf) -> usize {
|
|
||||||
let node = self.0.get(path).unwrap();
|
|
||||||
match node {
|
|
||||||
Node::File(file) => file.size,
|
|
||||||
Node::Dir(dir) => dir
|
|
||||||
.children
|
|
||||||
.iter()
|
|
||||||
.fold(0, |sum, node| sum + self.size(node)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_dirs(&self) -> HashSet<PathBuf> {
|
|
||||||
self.paths()
|
|
||||||
.iter()
|
|
||||||
.filter(|path| match *self.get(path).unwrap() {
|
|
||||||
Node::Dir(_) => true,
|
|
||||||
_ => false,
|
|
||||||
})
|
|
||||||
.cloned()
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn free_space(&self) -> usize {
|
|
||||||
70000000 - self.size(&PathBuf::from("/"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Filesystem {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self(HashMap::new())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
struct State {
|
|
||||||
path: PathBuf,
|
|
||||||
filesystem: Filesystem,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for State {
|
|
||||||
fn default() -> Self {
|
|
||||||
let mut filesystem = Filesystem::default();
|
|
||||||
filesystem.insert(
|
|
||||||
PathBuf::from("/"),
|
|
||||||
Node::Dir(Dir {
|
|
||||||
name: "/".to_owned(),
|
|
||||||
children: vec![],
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
Self {
|
|
||||||
path: PathBuf::from("/"),
|
|
||||||
filesystem,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl State {
|
|
||||||
fn interpret_line(&mut self, line: SessionLine) {
|
|
||||||
match line {
|
|
||||||
SessionLine::Output(entry) => self.add_entry(entry),
|
|
||||||
SessionLine::Command(Command::CD(dest)) => self.change_dir(&dest),
|
|
||||||
SessionLine::Command(Command::LS) => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn change_dir(&mut self, dir: &str) {
|
|
||||||
match dir {
|
|
||||||
".." => {
|
|
||||||
self.path.pop();
|
|
||||||
}
|
|
||||||
"/" => {
|
|
||||||
self.path = PathBuf::from("/");
|
|
||||||
}
|
|
||||||
val => {
|
|
||||||
self.path.push(val);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_entry(&mut self, entry: Node) {
|
|
||||||
let mut path = self.path.clone();
|
|
||||||
match entry {
|
|
||||||
Node::Dir(ref dir) => path.push(dir.name.clone()),
|
|
||||||
Node::File(ref file) => path.push(file.name.clone()),
|
|
||||||
};
|
|
||||||
let parent = self.filesystem.get_mut(&self.path).unwrap();
|
|
||||||
match parent {
|
|
||||||
Node::Dir(dir) => dir.children.push(path.clone()),
|
|
||||||
Node::File(_) => panic!("adding a child to a file"),
|
|
||||||
}
|
|
||||||
self.filesystem.insert(path, entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn input(data: &str) -> Filesystem {
|
|
||||||
let (_, session) = parse_session(data).unwrap();
|
|
||||||
let mut state = State::default();
|
|
||||||
session
|
|
||||||
.into_iter()
|
|
||||||
.for_each(|line| state.interpret_line(line));
|
|
||||||
state.filesystem
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_session(input: &str) -> IResult<&str, Vec<SessionLine>> {
|
|
||||||
many0(
|
|
||||||
parse_command
|
|
||||||
.map(SessionLine::Command)
|
|
||||||
.or(parse_output.map(SessionLine::Output)),
|
|
||||||
)(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_command(input: &str) -> IResult<&str, Command> {
|
|
||||||
let (input, _) = tag("$ ")(input)?;
|
|
||||||
parse_cd
|
|
||||||
.map(|path| Command::CD(path))
|
|
||||||
.or(parse_ls.map(|_| Command::LS))
|
|
||||||
.parse(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_cd(input: &str) -> IResult<&str, String> {
|
|
||||||
let (input, _) = tag("cd ")(input)?;
|
|
||||||
let (input, path) = terminated(not_line_ending, line_ending.or(eof))(input)?;
|
|
||||||
|
|
||||||
Ok((input, path.to_owned()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_ls(input: &str) -> IResult<&str, ()> {
|
|
||||||
let (input, _) = terminated(tag("ls"), line_ending.or(eof))(input)?;
|
|
||||||
Ok((input, ()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_output(input: &str) -> IResult<&str, Node> {
|
|
||||||
parse_file_line
|
|
||||||
.map(|file| Node::File(file))
|
|
||||||
.or(parse_dir_line.map(|dir| Node::Dir(dir)))
|
|
||||||
.parse(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_file_line(input: &str) -> IResult<&str, File> {
|
|
||||||
let (input, size) = u32(input)?;
|
|
||||||
let (input, _) = space1(input)?;
|
|
||||||
let (input, name) = terminated(not_line_ending, line_ending.or(eof))(input)?;
|
|
||||||
|
|
||||||
Ok((
|
|
||||||
input,
|
|
||||||
File {
|
|
||||||
name: name.to_owned(),
|
|
||||||
size: size as usize,
|
|
||||||
},
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_dir_line(input: &str) -> IResult<&str, Dir> {
|
|
||||||
let (input, _) = tag("dir ")(input)?;
|
|
||||||
let (input, name) = terminated(not_line_ending, line_ending.or(eof))(input)?;
|
|
||||||
|
|
||||||
Ok((
|
|
||||||
input,
|
|
||||||
Dir {
|
|
||||||
name: name.to_owned(),
|
|
||||||
children: vec![],
|
|
||||||
},
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
const TEST_DATA: &str = "$ cd /
|
|
||||||
$ ls
|
|
||||||
dir a
|
|
||||||
14848514 b.txt
|
|
||||||
8504156 c.dat
|
|
||||||
dir d
|
|
||||||
$ cd a
|
|
||||||
$ ls
|
|
||||||
dir e
|
|
||||||
29116 f
|
|
||||||
2557 g
|
|
||||||
62596 h.lst
|
|
||||||
$ cd e
|
|
||||||
$ ls
|
|
||||||
584 i
|
|
||||||
$ cd ..
|
|
||||||
$ cd ..
|
|
||||||
$ cd d
|
|
||||||
$ ls
|
|
||||||
4060174 j
|
|
||||||
8033020 d.log
|
|
||||||
5626152 d.ext
|
|
||||||
7214296 k";
|
|
||||||
|
|
||||||
fn filesystem() -> Filesystem {
|
|
||||||
let mut filesystem = Filesystem::default();
|
|
||||||
|
|
||||||
filesystem.insert(
|
|
||||||
PathBuf::from("/"),
|
|
||||||
Node::Dir(Dir {
|
|
||||||
name: "/".to_owned(),
|
|
||||||
children: vec![
|
|
||||||
PathBuf::from("a"),
|
|
||||||
PathBuf::from("b.txt"),
|
|
||||||
PathBuf::from("c.dat"),
|
|
||||||
PathBuf::from("d"),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
filesystem.insert(
|
|
||||||
PathBuf::from("/a"),
|
|
||||||
Node::Dir(Dir {
|
|
||||||
name: "a".to_owned(),
|
|
||||||
children: vec![
|
|
||||||
PathBuf::from("e"),
|
|
||||||
PathBuf::from("f"),
|
|
||||||
PathBuf::from("g"),
|
|
||||||
PathBuf::from("h.lst"),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
filesystem.insert(
|
|
||||||
PathBuf::from("/a/e"),
|
|
||||||
Node::Dir(Dir {
|
|
||||||
name: "e".to_owned(),
|
|
||||||
children: vec![PathBuf::from("i")],
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
filesystem.insert(
|
|
||||||
PathBuf::from("/a/e/i"),
|
|
||||||
Node::File(File {
|
|
||||||
name: "i".to_owned(),
|
|
||||||
size: 584,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
filesystem.insert(
|
|
||||||
PathBuf::from("/a/f"),
|
|
||||||
Node::File(File {
|
|
||||||
name: "f".to_owned(),
|
|
||||||
size: 29116,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
filesystem.insert(
|
|
||||||
PathBuf::from("/a/g"),
|
|
||||||
Node::File(File {
|
|
||||||
name: "g".to_owned(),
|
|
||||||
size: 2557,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
filesystem.insert(
|
|
||||||
PathBuf::from("/a/h.lst"),
|
|
||||||
Node::File(File {
|
|
||||||
name: "h.lst".to_owned(),
|
|
||||||
size: 62596,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
filesystem.insert(
|
|
||||||
PathBuf::from("/b.txt"),
|
|
||||||
Node::File(File {
|
|
||||||
name: "b.txt".to_owned(),
|
|
||||||
size: 14848514,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
filesystem.insert(
|
|
||||||
PathBuf::from("/c.dat"),
|
|
||||||
Node::File(File {
|
|
||||||
name: "c.dat".to_owned(),
|
|
||||||
size: 8504156,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
filesystem.insert(
|
|
||||||
PathBuf::from("/d"),
|
|
||||||
Node::Dir(Dir {
|
|
||||||
name: "d".to_owned(),
|
|
||||||
children: vec![
|
|
||||||
PathBuf::from("j"),
|
|
||||||
PathBuf::from("d.log"),
|
|
||||||
PathBuf::from("d.ext"),
|
|
||||||
PathBuf::from("k"),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
filesystem.insert(
|
|
||||||
PathBuf::from("/d/j"),
|
|
||||||
Node::File(File {
|
|
||||||
name: "j".to_owned(),
|
|
||||||
size: 4060174,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
filesystem.insert(
|
|
||||||
PathBuf::from("/d/d.log"),
|
|
||||||
Node::File(File {
|
|
||||||
name: "d.log".to_owned(),
|
|
||||||
size: 8033020,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
filesystem.insert(
|
|
||||||
PathBuf::from("/d/d.ext"),
|
|
||||||
Node::File(File {
|
|
||||||
name: "d.ext".to_owned(),
|
|
||||||
size: 5626152,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
filesystem.insert(
|
|
||||||
PathBuf::from("/d/k"),
|
|
||||||
Node::File(File {
|
|
||||||
name: "k".to_owned(),
|
|
||||||
size: 7214296,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
filesystem
|
|
||||||
}
|
|
||||||
|
|
||||||
fn with_input<F>(test: F)
|
|
||||||
where
|
|
||||||
F: Fn(Filesystem) -> () + std::panic::UnwindSafe,
|
|
||||||
{
|
|
||||||
test(input(TEST_DATA));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_parses_command_lines() {
|
|
||||||
let (_, res) = parse_command("$ cd /").unwrap();
|
|
||||||
assert_eq!(Command::CD("/".to_owned()), res);
|
|
||||||
|
|
||||||
let (_, res) = parse_command("$ ls").unwrap();
|
|
||||||
assert_eq!(Command::LS, res);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_parses_output_lines() {
|
|
||||||
let (_, res) = parse_output("8033020 d.log").unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
Node::File(File {
|
|
||||||
name: "d.log".to_owned(),
|
|
||||||
size: 8033020
|
|
||||||
}),
|
|
||||||
res
|
|
||||||
);
|
|
||||||
|
|
||||||
let (_, res) = parse_output("dir e").unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
Node::Dir(Dir {
|
|
||||||
name: "e".to_owned(),
|
|
||||||
children: vec![],
|
|
||||||
}),
|
|
||||||
res
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_parses_a_session() {
|
|
||||||
let (_, res) = parse_session(TEST_DATA).unwrap();
|
|
||||||
assert_eq!(res[0], SessionLine::Command(Command::CD("/".to_owned())));
|
|
||||||
assert_eq!(res[1], SessionLine::Command(Command::LS));
|
|
||||||
assert_eq!(
|
|
||||||
res[2],
|
|
||||||
SessionLine::Output(Node::Dir(Dir {
|
|
||||||
name: "a".to_owned(),
|
|
||||||
children: vec![]
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
res[3],
|
|
||||||
SessionLine::Output(Node::File(File {
|
|
||||||
name: "b.txt".to_owned(),
|
|
||||||
size: 14848514
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
assert_eq!(res[6], SessionLine::Command(Command::CD("a".to_owned())));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_parses_the_tree() {
|
|
||||||
with_input(|fs| {
|
|
||||||
assert_eq!(fs.paths(), filesystem().paths());
|
|
||||||
assert_eq!(
|
|
||||||
fs.get(&PathBuf::from("/c.dat")).map(|c| c.clone()),
|
|
||||||
Some(Node::File(File {
|
|
||||||
name: "c.dat".to_owned(),
|
|
||||||
size: 8504156
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
fs.get(&PathBuf::from("/d")).map(|c| c.clone()),
|
|
||||||
Some(Node::Dir(Dir {
|
|
||||||
name: "d".to_owned(),
|
|
||||||
children: vec![
|
|
||||||
PathBuf::from("/d/j"),
|
|
||||||
PathBuf::from("/d/d.log"),
|
|
||||||
PathBuf::from("/d/d.ext"),
|
|
||||||
PathBuf::from("/d/k"),
|
|
||||||
]
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_scans_a_file_size() {
|
|
||||||
with_input(|fs| {
|
|
||||||
assert_eq!(fs.size(&PathBuf::from("/b.txt")), 14848514);
|
|
||||||
assert_eq!(fs.size(&PathBuf::from("/a/e")), 584);
|
|
||||||
assert_eq!(fs.size(&PathBuf::from("/a")), 94853);
|
|
||||||
assert_eq!(fs.size(&PathBuf::from("/d")), 24933642);
|
|
||||||
assert_eq!(fs.size(&PathBuf::from("/")), 48381165);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_finds_all_dirs_under_100000() {
|
|
||||||
with_input(|fs| {
|
|
||||||
assert_eq!(tree_sizes_100k(&fs), 95437);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_solves_part1() {
|
|
||||||
assert_eq!(tree_sizes_100k(&input(INPUT)), 1792222);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_measures_free_space() {
|
|
||||||
with_input(|fs| assert_eq!(fs.free_space(), 21618835));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_finds_smallest_needed_dir() {
|
|
||||||
with_input(|fs| assert_eq!(find_minimum_directory(&fs), (PathBuf::from("/d"), 24933642)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_solves_part2() {
|
|
||||||
assert_eq!(find_minimum_directory(&input(INPUT)).1, 1112963);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,7 +4,6 @@ mod day3;
|
||||||
mod day4;
|
mod day4;
|
||||||
mod day5;
|
mod day5;
|
||||||
mod day6;
|
mod day6;
|
||||||
mod day7;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let day = std::env::args().skip(1).next();
|
let day = std::env::args().skip(1).next();
|
||||||
|
@ -22,8 +21,6 @@ fn main() {
|
||||||
Some("5b") => day5::part2(),
|
Some("5b") => day5::part2(),
|
||||||
Some("6a") => day6::part1(),
|
Some("6a") => day6::part1(),
|
||||||
Some("6b") => day6::part2(),
|
Some("6b") => day6::part2(),
|
||||||
Some("7a") => day7::part1(),
|
|
||||||
Some("7b") => day7::part2(),
|
|
||||||
_ => panic!("unrecognized day"),
|
_ => panic!("unrecognized day"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue