0

Link to AOC: https://adventofcode.com/2022/day/7

I'm doing the aoc in Rust and I am stuck on day 7. The code works on example input but doesn't on normal. For some context, the file tree is:

.
├── example_input.txt
├── input.txt
├── src
    ├── bin
    │  └── part_1.rs
    └── lib.rs

input.txt contains this: kfkorulczyk.pl/aoc_d7_input

And example input is this:

$ 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

Output from the normal input should be 1501149 but is 1035695.

Here is the code:

lib.rs

#![allow(unused)]
use std::borrow::{Borrow, BorrowMut};
use std::cell::RefCell;
use std::fmt;

macro_rules! get_part {
    ($line:expr, $index:expr) => {
        $line.split(" ").nth($index).unwrap()
    };
}

#[derive(Debug)]
pub struct Dir<'a> {
    pub name: &'a str,
    pub files: Vec<File<'a>>,
    pub dirs: Vec<Dir<'a>>,
}


impl<'a> Dir<'a> {
    pub fn add_content_to_subdir(
        &mut self,
        destination_dir: &str,
        new_dir: &'a str,
        new_file: Option<File<'a>>,
    ) -> () {
        let destination_dir = self.find_dir(destination_dir).unwrap();
        match new_file {
            Some(expr) => destination_dir.files.push(expr),
            None => destination_dir.dirs.push(Dir {
                name: new_dir,
                files: Vec::new(),
                dirs: Vec::new(),
            }),
        }
    }

    pub fn find_dir<'b>(&'b mut self, name: &str) -> Option<&'b mut Dir<'a>> {
        if self.name == name {
            return Some(self);
        }
        self.dirs.iter_mut().find_map(|dir| dir.find_dir(name))
    }

    pub fn find_dir_not_mut<'b>(&'b self, name: &str) -> Option<&'b Dir<'a>> {
        if self.name == name {
            return Some(self);
        }

        self.dirs.iter().find_map(|dir| dir.find_dir_not_mut(name))
    }
}

fn calculate_size_of_folder<'a>(dir: &'a RefCell<Dir<'a>>, name: &str) -> Option<i64> {
    let mut sum = 0;
    let search_in = dir.borrow();
    let search_in = search_in.find_dir_not_mut(name).unwrap();
    
    for file in &search_in.files {
        sum += file.size;
    }
    if sum > 100000 {
        return None;
    }
    for subdir in &search_in.dirs {
        if let Some(size) = calculate_size_of_folder(dir, &subdir.name) {
            sum += size;
        }
    }
    if sum > 100000 {
        return None;
    }

    Some(sum)
}



#[derive(Debug)]
pub struct File<'a> {
    pub name: &'a str,
    pub size: i64,
}

fn read_input<'a>(
    input: &'a str,
    dir: &'a RefCell<Dir<'a>>,
) -> (&'a RefCell<Dir<'a>>, Vec<String>) {
    let mut file = File { name: "", size: 13 };
    let mut all_dirs = vec![];
    let mut dir_name = "";
    let mut found_dir = "";
    for line in input.lines() {
        match line {
            line if line.starts_with("$ ls") => {}
            line if line.starts_with("$ cd ..") => {}
            line if line.starts_with("$ cd ") => {
                dir_name = get_part!(line, 2);
                all_dirs.push(dir_name.to_string());
            }
            line if line.starts_with("dir ") => {
                found_dir = get_part!(line, 1);
                dir.borrow_mut()
                    .add_content_to_subdir(dir_name, found_dir, None);
            }
            _ => {
                let size: i64 = get_part!(line, 0).parse::<i64>().unwrap();
                let size: i64 = get_part!(line, 0).parse::<i64>().unwrap();
                let name = get_part!(line, 1);
                dir.borrow_mut().add_content_to_subdir(
                    dir_name,
                    "",
                    Some(File { size, name }),
                );
            }
        }
    }
    (dir, all_dirs)
}

pub fn part_one(input: &str) {
    let mut dir = RefCell::new(Dir {
        name: "/",
        files: vec![],
        dirs: vec![],
    });

    let (file_tree, mut all_dirs) = read_input(&input, &dir);

    let mut sum = 0;

    for dir in &all_dirs {
        let dir_size = calculate_size_of_folder(file_tree, &dir);
        match dir_size {
            Some(expr) => sum += expr,
            None => (),
        }
    }

    println!("{}", sum);
}


part_one.rs

use d7::*;
use std::fs;

fn main() {
    let input = fs::read_to_string("input.txt").unwrap();
    part_one(input);
}

You probably know but cargo install cargo-watch and cargo watch -x "run --bin part_1" helps a lot.

I tried redoing the calculate_size_of_folder function but it didn't work. Also, the return of a calculate_size_of_folder is an option and I am checking if the size is less than 100000 because if I won't I get a stack overflow error.

  • Nitpick: You don't need the `Box`es. – Chayim Friedman Jun 09 '23 at 12:57
  • "If I am stupid and AOC gives a different input for everyone" AOC does give different input to everyone. I don't have my AOC code available, but you're probably making assumptions which don't hold (from what I recall AOC day 7 was actually pretty relaxed as it didn't have traps like visiting the same directory twice or any such things), however the real input is a lot more complicated than the example. One thing you could do is go on the advent of code subreddit and run one of the top solutions to see what it tells you. – Masklinn Jun 09 '23 at 12:57
  • If you want readers to replicate your result, then posting your input data (ideally in the question) is a good idea. – halfer Jun 09 '23 at 12:58
  • Nitpick: [Don't take `&String`, take `&str`](https://stackoverflow.com/questions/40006219/why-is-it-discouraged-to-accept-a-reference-string-vec-or-box-as-a-function). – Chayim Friedman Jun 09 '23 at 12:59
  • Why are you doing nothing on `cd ..`? Just because they're seemingly not relevant in the example doesn't mean they aren't in the actual code... – Masklinn Jun 09 '23 at 13:02
  • You don't properly handle navigation in nested directories. – Chayim Friedman Jun 09 '23 at 13:02
  • Ok... I removed the boxes, posted my input if someone needed it, and changed String to str in function inputs(I hope I didn't miss any). Now the important thing, what should I do in cd ..? and what is wrong with my file navigation? I would really appreciate Chayim if you could explain a bit more the file navigation thing, is it just wrong because it is not efficient or is it wrong because it doesn't work? – grandkahuna Jun 09 '23 at 15:07
  • And I was looking at other's code but tbh it was just gibberish for me. Yes I know my code isn't beautiful but I couldn't understand a lot of things so I did it this way. – grandkahuna Jun 09 '23 at 15:16
  • And Masklinn, don't tell me it was pretty chill because I just got into programming and the 'easy' things are hard as hell for me. – grandkahuna Jun 09 '23 at 15:20
  • "`cd ..` moves out one level: it finds the directory that contains the current directory, then makes that directory the current directory." - the problem statement – cafce25 Jun 09 '23 at 17:12
  • Yeah, I know that, but I don't know why would I implement that. My program(not the most efficient way but I'm not thinking about that now) has a function that searches for the current directory, returns mutable reference, and does its thing. If I missed something I'm sorry but I don't see why would it help in this case, just asking for an explanation. – grandkahuna Jun 10 '23 at 06:44
  • You need to keep a tree of directories with parent and children links and navigate within it. But it is hard to do with Rust (though there are other ways). But really, if you just got into programming, Rust isn't exactly the best language to start with. Look at Python or JavaScript. – Chayim Friedman Jun 10 '23 at 19:45
  • Well, I 'can' program in Python javascript c++ HTML, and CSS but can I say I am intermediate? This is not a debate for comments on stack. I didn't find any information between 'just got into' 'beginner' and 'intermediate'. – grandkahuna Jun 13 '23 at 08:15

1 Answers1

0

The primary bug I see in your code is that you ignore cd ... The problem is asking you to model navigation through a directory tree; at all points in the simulation, your system has a "current directory" it occupies. When you see the command cd .., your system should move up one level, to the parent directory, and continue from there.

Lucretiel
  • 3,145
  • 1
  • 24
  • 52