mirror of
https://github.com/wezm/advent-of-code.git
synced 2024-12-18 18:29:55 +00:00
Day 7 part 1
This commit is contained in:
parent
a6ed0b6306
commit
b4840fd176
4 changed files with 1246 additions and 0 deletions
7
2022/Cargo.lock
generated
Normal file
7
2022/Cargo.lock
generated
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "advent-of-code"
|
||||||
|
version = "0.1.0"
|
8
2022/Cargo.toml
Normal file
8
2022/Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "advent-of-code"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
1044
2022/input/day_7.txt
Normal file
1044
2022/input/day_7.txt
Normal file
File diff suppressed because it is too large
Load diff
187
2022/src/bin/day7.rs
Normal file
187
2022/src/bin/day7.rs
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::io::{self};
|
||||||
|
use std::ops::DerefMut;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
const LIMIT: usize = 100_000;
|
||||||
|
|
||||||
|
type Node<'a> = Rc<RefCell<FsNode<'a>>>;
|
||||||
|
|
||||||
|
struct FsNode<'a> {
|
||||||
|
parent: Option<Node<'a>>,
|
||||||
|
data: FsNodeData<'a>,
|
||||||
|
}
|
||||||
|
enum FsNodeData<'a> {
|
||||||
|
Dir(Dir<'a>),
|
||||||
|
File(File<'a>),
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Dir<'a> {
|
||||||
|
name: &'a str,
|
||||||
|
size: usize,
|
||||||
|
children: Vec<Node<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct File<'a> {
|
||||||
|
name: &'a str,
|
||||||
|
size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> io::Result<()> {
|
||||||
|
let input = std::fs::read_to_string("input/day_7.txt")?;
|
||||||
|
let root = new_node(None, FsNodeData::Dir(Dir::new("/")));
|
||||||
|
let mut pwd = Rc::clone(&root);
|
||||||
|
|
||||||
|
for line in input.lines() {
|
||||||
|
match line.chars().next() {
|
||||||
|
Some('$') => pwd = execute_cmd(&line[1..], Rc::clone(&pwd), &root)?,
|
||||||
|
Some('d') => add_dir(line, Rc::clone(&pwd))?,
|
||||||
|
Some(c) if c.is_ascii_digit() => add_file(line, Rc::clone(&pwd))?,
|
||||||
|
c => panic!("unexpected character: {:?}", c),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Traverse the filesystem tree looking for large dirs
|
||||||
|
let sum_of_large_dirs = traverse(&root.borrow());
|
||||||
|
println!("{}", sum_of_large_dirs);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn traverse(node: &FsNode<'_>) -> usize {
|
||||||
|
let mut sum = 0;
|
||||||
|
match &node.data {
|
||||||
|
FsNodeData::Dir(Dir { size, children, .. }) => {
|
||||||
|
if *size <= LIMIT {
|
||||||
|
sum += size
|
||||||
|
}
|
||||||
|
for child in children {
|
||||||
|
sum += traverse(&child.borrow())
|
||||||
|
}
|
||||||
|
sum
|
||||||
|
}
|
||||||
|
FsNodeData::File(_) => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Execute a command, returning the new pwd
|
||||||
|
fn execute_cmd<'a, 'b>(line: &'a str, pwd: Node<'b>, root: &'a Node<'b>) -> io::Result<Node<'b>> {
|
||||||
|
let mut words = line.trim().split(' ');
|
||||||
|
let cmd = words.next();
|
||||||
|
let arg = words.next();
|
||||||
|
match (cmd, arg) {
|
||||||
|
(Some("ls"), None) => Ok(pwd),
|
||||||
|
(Some("cd"), Some("..")) => pwd
|
||||||
|
.borrow()
|
||||||
|
.parent
|
||||||
|
.as_ref()
|
||||||
|
.map(Rc::clone)
|
||||||
|
.ok_or_else(|| err("node has no parent")),
|
||||||
|
(Some("cd"), Some("/")) => Ok(Rc::clone(root)),
|
||||||
|
(Some("cd"), Some(dir)) => {
|
||||||
|
let pwd = pwd.borrow();
|
||||||
|
let FsNode { data: FsNodeData::Dir(pwd), .. } = &*pwd else {
|
||||||
|
return Err(err("pwd is not a dir"))
|
||||||
|
};
|
||||||
|
pwd.children
|
||||||
|
.iter()
|
||||||
|
.find(|child| {
|
||||||
|
matches!(
|
||||||
|
*child.borrow(),
|
||||||
|
FsNode {
|
||||||
|
data: FsNodeData::Dir(Dir { name, .. }),
|
||||||
|
..
|
||||||
|
} if name == dir
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.ok_or_else(|| err("node has no parent"))
|
||||||
|
.cloned()
|
||||||
|
}
|
||||||
|
_ => Err(err("unexpected command")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_dir<'a>(line: &'a str, pwd: Node<'a>) -> io::Result<()> {
|
||||||
|
let mut words = line.trim().split(' ');
|
||||||
|
let Some("dir") = words.next() else {
|
||||||
|
return Err(err("didn't get dir"))
|
||||||
|
};
|
||||||
|
let Some(name) = words.next() else {
|
||||||
|
return Err(err("missing dir name"))
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut dir = pwd.borrow_mut();
|
||||||
|
let FsNode { data: FsNodeData::Dir(dir), .. } = dir.deref_mut() else {
|
||||||
|
return Err(err("pwd is not a dir"))
|
||||||
|
};
|
||||||
|
dir.children.push(new_node(
|
||||||
|
Some(Rc::clone(&pwd)),
|
||||||
|
FsNodeData::Dir(Dir::new(name)),
|
||||||
|
));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_file<'a>(line: &'a str, pwd: Node<'a>) -> io::Result<()> {
|
||||||
|
let mut words = line.trim().split(' ');
|
||||||
|
let size = words
|
||||||
|
.next()
|
||||||
|
.and_then(|size| size.parse::<usize>().ok())
|
||||||
|
.ok_or_else(|| err("file missing size"))?;
|
||||||
|
let Some(name) = words.next() else {
|
||||||
|
return Err(err("missing file name"))
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut dir = pwd.borrow_mut();
|
||||||
|
let FsNode { data: FsNodeData::Dir(dir), parent, .. } = dir.deref_mut() else {
|
||||||
|
return Err(err("pwd is not a dir"))
|
||||||
|
};
|
||||||
|
dir.children.push(new_node(
|
||||||
|
Some(Rc::clone(&pwd)),
|
||||||
|
FsNodeData::File(File::new(name, size)),
|
||||||
|
));
|
||||||
|
dir.size += size;
|
||||||
|
if let Some(parent) = parent {
|
||||||
|
update_size(size, &mut parent.borrow_mut());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_size(size: usize, node: &mut FsNode<'_>) {
|
||||||
|
let FsNode { data: FsNodeData::Dir(dir), parent, .. } = node else {
|
||||||
|
panic!("node is not a dir")
|
||||||
|
};
|
||||||
|
dir.size += size;
|
||||||
|
if let Some(parent) = parent {
|
||||||
|
update_size(size, &mut parent.borrow_mut())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_node<'a>(parent: Option<Node<'a>>, data: FsNodeData<'a>) -> Node<'a> {
|
||||||
|
Rc::new(RefCell::new(FsNode::new(parent, data)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn err(msg: &str) -> io::Error {
|
||||||
|
io::Error::new(io::ErrorKind::Other, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> FsNode<'a> {
|
||||||
|
fn new(parent: Option<Node<'a>>, data: FsNodeData<'a>) -> Self {
|
||||||
|
FsNode { parent, data }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Dir<'a> {
|
||||||
|
fn new(name: &'a str) -> Self {
|
||||||
|
Dir {
|
||||||
|
size: 0,
|
||||||
|
name,
|
||||||
|
children: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> File<'a> {
|
||||||
|
fn new(name: &'a str, size: usize) -> Self {
|
||||||
|
File { name, size }
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue