From fac478b89b59c025cd4deb29ad9596ba11f073be Mon Sep 17 00:00:00 2001 From: Christopher Bohn <bohn@unl.edu> Date: Wed, 7 Dec 2022 09:37:17 -0600 Subject: [PATCH] Completed Year 2022 Day 7 part 1 --- 2022/README.md | 25 +++ .../java/edu/unl/cse/bohn/year2022/Day7.java | 151 ++++++++++++++++++ 2 files changed, 176 insertions(+) create mode 100644 2022/src/main/java/edu/unl/cse/bohn/year2022/Day7.java diff --git a/2022/README.md b/2022/README.md index 79433ac..80c889b 100644 --- a/2022/README.md +++ b/2022/README.md @@ -183,5 +183,30 @@ This is straight-forward -- I just need to parameterize the helper method that l ## Day 7 +- [The problem](https://adventofcode.com/2022/day/7) +- [The solution](src/main/java/edu/unl/cse/bohn/year2022/Day7.java) + +### Part 1 + +The subproblems are +- Parse the input +- Based on the responses to commands, determine the size of each directory + - The size of a "leaf" directory that has no subdirectories is the sum of the sizes of its files + - The size of a non-leaf is the sum of the sizes of its files and the sizes of its directories +- Determine which directories' size is at most 100000 + +It is very tempting to create a model of the directory structure, but the concern of course is the memory usage. +Many of these problems can be mapped to a simpler problem. +I think the reason I'm so tempted to create a model of the directory structure is because the description of the +structure is coming in BFS, but determining the directory sizes would best be done DFS. +It looks like the puzzle input has fewer than 200 directories. YOLO. So, add to the subproblems: +- Build a model of the directory tree + +### Part 2 + +... + +## Day 8 + (coming soon) diff --git a/2022/src/main/java/edu/unl/cse/bohn/year2022/Day7.java b/2022/src/main/java/edu/unl/cse/bohn/year2022/Day7.java new file mode 100644 index 0000000..52404cb --- /dev/null +++ b/2022/src/main/java/edu/unl/cse/bohn/year2022/Day7.java @@ -0,0 +1,151 @@ +package edu.unl.cse.bohn.year2022; + +import edu.unl.cse.bohn.Puzzle; + +import java.util.*; + +@SuppressWarnings("unused") +public class Day7 extends Puzzle { + public Day7(boolean isProductionReady) { + super(isProductionReady); + sampleData = """ + $ 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"""; + } + + Directory rootDirectory = null; + public static final long THRESHOLD_DIRECTORY_SIZE = 100000; + + @Override + public long computePart1(List<String> data) { + if (rootDirectory == null) { + rootDirectory = buildDirectoryTree(data); + } + Set<Directory> directoriesBelowThreshold = getSmallDirectories(rootDirectory); + return directoriesBelowThreshold.stream().mapToLong(Directory::getSize).sum(); + } + + @Override + public long computePart2(List<String> data) { + if (rootDirectory == null) { + rootDirectory = buildDirectoryTree(data); + } + return 0; + } + + private Directory buildDirectoryTree(List<String> data) { + Directory root = null; + Directory workingDirectory = null; + for (String datum : data) { + if (datum.equals("$ cd /")) { + root = new Directory("/", null); + workingDirectory = root; + } else if (datum.equals("$ cd ..")) { + assert workingDirectory != null; + workingDirectory = workingDirectory.getParentDirectory(); + } else if (datum.startsWith("$ cd ")) { + assert workingDirectory != null; + workingDirectory = workingDirectory.getSubdirectory(datum.substring(5)); + } else if (datum.equals("$ ls")) { + System.out.print(""); // a convenient nop, since there's nothing to do + } else if (datum.startsWith("dir ")) { + assert workingDirectory != null; + workingDirectory.addDirectory(datum.substring(4)); + } else if (Character.isDigit(datum.charAt(0))) { + String[] tokens = datum.strip().split(" "); + long fileSize = Long.parseLong(tokens[0]); + String fileName = tokens[1]; + assert workingDirectory != null; + workingDirectory.addFile(fileName, fileSize); + } else { + throw new IllegalArgumentException("Unrecognized line in the data: " + datum); + } + } + return root; + } + + private Set<Directory> getSmallDirectories(Directory rootOfSubtree) { + Set<Directory> smallDirectories = new HashSet<>(); + if (rootOfSubtree.getSize() <= THRESHOLD_DIRECTORY_SIZE) { + smallDirectories.add(rootOfSubtree); + } + for (Directory subdirectory : rootOfSubtree.getSubdirectories()) { + smallDirectories.addAll(getSmallDirectories(subdirectory)); + } + return smallDirectories; + } + + private static class Directory { + String name; + Directory parentDirectory; + Map<String, Directory> subdirectories; + Map<String, Long> files; + Long cachedSize; // we're going to cache the directory size to avoid repeatedly diving into subdirectories + + public Directory(String name, Directory parentDirectory) { + this.name = name; + this.parentDirectory = parentDirectory; + subdirectories = new HashMap<>(); + files = new HashMap<>(); + cachedSize = null; + } + + public void addDirectory(String name) { + subdirectories.put(name, new Directory(name, this)); + cachedSize = null; // any existing cached size is now invalid + } + + public void addFile(String name, long size) { + files.put(name, size); + cachedSize = null; // any existing cached size is now invalid + } + + public String getName() { + return name; + } + + public Directory getParentDirectory() { + return parentDirectory; + } + + public Directory getSubdirectory(String name) { + return subdirectories.get(name); + } + + public Collection<Directory> getSubdirectories() { + return subdirectories.values(); + } + + public long getSize() { + if (cachedSize == null) { + long size = subdirectories.keySet().stream() + .mapToLong(directoryName -> subdirectories.get(directoryName).getSize()) + .sum(); + size += files.keySet().stream().mapToLong(fileName -> files.get(fileName)).sum(); + cachedSize = size; + } + return cachedSize; + } + } +} -- GitLab