add day 7, part 1

This commit is contained in:
Christian Ulrich 2022-12-07 17:49:31 +01:00
parent 04380e53a3
commit 8127688167
No known key found for this signature in database
GPG Key ID: 8241BE099775A097
4 changed files with 1266 additions and 0 deletions

112
day07/common.rs Normal file
View File

@ -0,0 +1,112 @@
// Copyright 2022 Christian Ulrich
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
use std::io;
use std::iter;
#[derive(Debug)]
pub enum Node {
Directory { name: String, children: Vec<Node> },
File { name: String, size: usize },
}
pub struct FileSystem {
root: Node,
}
impl Node {
pub fn name(&self) -> &str {
match self {
Node::File { name, size: _ } => name,
Node::Directory { name, children: _ } => name,
}
}
pub fn size(&self) -> usize {
match self {
Node::File { name: _, size } => *size,
Node::Directory { name: _, children } => {
children.iter().fold(0, |acc, c| acc + c.size())
}
}
}
pub fn walk(&self) -> Box<dyn Iterator<Item = &Node> + '_> {
match self {
Node::File { name: _, size: _ } => Box::new(iter::empty()),
Node::Directory { name: _, children } => Box::new(
children.iter().chain(
children
.iter()
.skip(1)
.fold(children[0].walk(), |acc, c| Box::new(acc.chain(c.walk()))),
),
),
}
}
}
impl FileSystem {
pub fn from_stdin() -> Result<FileSystem, &'static str> {
let mut line = String::new();
if let Ok(_) = io::stdin().read_line(&mut line) {
return Ok(FileSystem {
root: FileSystem::parse_dir(&line)?,
});
}
Err("input file is empty")
}
pub fn root(&self) -> &Node {
&self.root
}
fn parse_file(line: &str) -> Result<Node, &'static str> {
if let Some((size, name)) = line.trim().split_once(' ') {
return Ok(Node::File {
name: name.into(),
size: size.parse().map_err(|_| "failed to parse file")?,
});
}
Err("failed to parse file")
}
fn parse_dir(line: &str) -> Result<Node, &'static str> {
if !line.starts_with("$ cd ") {
return Err("cannot parse directory");
}
let name = line[5..].trim();
let mut children = vec![];
let mut line = String::new();
match io::stdin().read_line(&mut line) {
Ok(_) if { line == "$ ls\n" } => (),
_ => return Err("cannot parse directory"),
}
loop {
line.clear();
match io::stdin().read_line(&mut line) {
Ok(_) if { line.starts_with("dir ") } => (),
Ok(_) if { line.trim().is_empty() || line == "$ cd ..\n" } => break,
Ok(_) if { line.starts_with("$ cd ") } => children.push(Self::parse_dir(&line)?),
Ok(_) => children.push(Self::parse_file(&line)?),
_ => assert!(false),
}
}
Ok(Node::Directory {
name: name.into(),
children: children,
})
}
}

1092
day07/input Normal file

File diff suppressed because it is too large Load Diff

39
day07/part1.rs Normal file
View File

@ -0,0 +1,39 @@
// Copyright 2022 Christian Ulrich
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// usage: ./part1 < input
pub mod common;
use common::{FileSystem, Node};
fn main() -> Result<(), &'static str> {
let fs = FileSystem::from_stdin()?;
let mut result = 0;
for node in fs.root().walk() {
if let Node::Directory {
name: _,
children: _,
} = node
{
let size = node.size();
if size <= 100000 {
result += size;
}
}
}
println!("{result}");
Ok(())
}

23
day07/testinput Normal file
View File

@ -0,0 +1,23 @@
$ 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