aoc

My solutions for the Advent of Code
git clone https://git.tronto.net/aoc
Download | Log | Files | Refs | README

common.rs (3474B)


      1 use std::ops;
      2 
      3 pub enum FileType {
      4     File(usize),
      5     Directory(Vec<usize>)
      6 }
      7 
      8 pub struct File {
      9     pub kind: FileType,
     10     name: String
     11 }
     12 
     13 impl File {
     14     pub fn real_size(&self, fs: &FileSystem) -> usize {
     15         match &self.kind {
     16             FileType::File(s) => *s,
     17             FileType::Directory(c) =>
     18                 c.iter().map(|x: &usize| fs[*x].real_size(&fs)).sum()
     19         }
     20     }
     21 }
     22 
     23 pub struct FileSystem {
     24     files: Vec<File>
     25 }
     26 
     27 impl FileSystem {
     28     fn new() -> Self {
     29         Self {
     30             files: vec![File {
     31                 kind: FileType::Directory(Vec::<usize>::new()),
     32                 name: String::from("/")
     33             }]
     34         }
     35     }
     36 
     37     pub fn build_from_stdin() -> Self {
     38         let mut fs = FileSystem::new();
     39         let mut path = Path::new();
     40         let mut line = String::new();
     41         while std::io::stdin().read_line(&mut line).unwrap() > 0 {
     42             if &line[..5] == "$ cd " {
     43                 exec_cd(&line[5..], &mut path, &fs);
     44             } else if &line[..3] == "dir" {
     45                 fs.add_dir(&line[4..line.len()-1], path.last());
     46             } else if line.as_bytes()[0] != '$' as u8 {
     47                 let i = line.find(' ').unwrap();
     48                 let size = line[0..i].parse::<usize>().unwrap();
     49                 fs.add_file(&line[i+1..line.len()-1], size, path.last());
     50             }
     51             line.clear();
     52         }
     53         fs
     54     }
     55 
     56     fn make_parent(&mut self, id: usize, parent: usize) {
     57         let p = &mut self.files[parent];
     58         if let FileType::Directory(v) = &mut p.kind {
     59             v.push(id);
     60         } else {
     61             panic!("Parent is not a directory");
     62         }
     63     }
     64 
     65     fn add_dir(&mut self, name: &str, parent: usize) {
     66         let id = self.files.len();
     67         self.files.push(
     68             File {
     69                 kind: FileType::Directory(Vec::<usize>::new()),
     70                 name: String::from(name)
     71             }
     72         );
     73         self.make_parent(id, parent);
     74     }
     75 
     76     fn add_file(&mut self, name: &str, size: usize, parent: usize) {
     77         let id = self.files.len();
     78         self.files.push(
     79             File {
     80                 kind: FileType::File(size),
     81                 name: String::from(name)
     82             }
     83         );
     84         self.make_parent(id, parent);
     85     }
     86 
     87     pub fn iter(&self) -> impl Iterator<Item = &File>{
     88         self.files.iter()
     89     }
     90 }
     91 
     92 impl ops::Index<usize> for FileSystem {
     93     type Output = File;
     94     fn index(&self, i: usize) -> &File {
     95         &self.files[i]
     96     }
     97 }
     98 
     99 struct Path {
    100     stack: Vec<usize>
    101 }
    102 
    103 impl Path {
    104     fn new() -> Self { Self { stack: vec![0] } } // 0 is the id of "/"
    105     fn last(&self) -> usize { *self.stack.last().unwrap() }
    106     fn clear(&mut self) { self.stack.drain(1..); }
    107     fn pop(&mut self) { self.stack.pop(); }
    108     fn push(&mut self, dir_id: usize) { self.stack.push(dir_id); }
    109 }
    110 
    111 fn exec_cd(line: &str, path: &mut Path, fs: &FileSystem) {
    112     if line.as_bytes()[0] == '/' as u8 {
    113         path.clear();
    114     } else if &line[..2] == ".." {
    115         path.pop();
    116     } else {
    117         let current_dir = &fs[path.last()];
    118         if let FileType::Directory(children) = &current_dir.kind {
    119             for c in children {
    120                 if fs[*c].name == &line[..line.len()-1] {
    121                     path.push(*c);
    122                     return;
    123                 }
    124             }
    125         } else {
    126             panic!("Non-directory in path");
    127         }
    128         panic!("Directory not found in current path");
    129     }
    130 }