#AoC 2022 | Day 7 | Solutions & Spoilers
2275 messages ยท Page 3 of 3 (latest)
As I said before, when I was using treelib I got around that by just having a counter variable and tacking that on to the directory names then incrementing it so each one was unique
so instead of lmw, lmw, lmw you'd have 45 lmw, 83 lmw, 133 lmw
nope, i noticed after watching my visualization that each directory is only ever visited once, and in DFS order
Except for when you try to iterate over it
the same what? size?
if there's a chain of nested folders without any files inside of them then they would all have the same size
the same name I guess
yeah, i was looking at that and I added a uuid attribute to the folder, but im not really sure how i would use that to find the correct folder
they could have been cheeky about it and break the dfs algorithm a couple of times, they don't really tell you that that's what they are doing and you wouldn't notice unless you check the input looking for it
they can have the same name (their absolute path would be different)
!e
a = {0: "a", 1: "b", 2: "c"}
for i in range(len(a)):
print(a[i])
@vivid patrol :white_check_mark: Your 3.11 eval job has completed with return code 0.
001 | a
002 | b
003 | c
Yeah but a list doesn't have .values()
!e
a = {0: "a", 1: "b", 2: "c"}
for i in range(len(a)):
print(a[i])
@vivid patrol :white_check_mark: Your 3.11 eval job has completed with return code 0.
001 | a
002 | b
003 | c
yeah, i was comparing the names of the folders parents but that didnt end up working either
Lol
if it works it works
If you use something the wrong way twice, it cancels out
What if you use it three times?

Can you show your work?
because order of operations
Sigh
(-1) ** 3
!eval print((-1) ** 3)
@tough hinge :white_check_mark: Your 3.11 eval job has completed with return code 0.
-1
Checks out
And there you go
!e print(-1 ** 2)
@vivid patrol :white_check_mark: Your 3.11 eval job has completed with return code 0.
-1



@proven gyro :white_check_mark: Your 3.11 eval job has completed with return code 0.
1
yeah
pemdas ๐
though usually when you see -1 you assume there's parenthathese around it
Yeah that's quite true
i seriously can't speak english rn
anyone have something like this ready to copy and paste kek
Isn't that for day 6?
I just have my for line in lines loop ready
lmao
https://paste.pythondiscord.com/nehahaqaxa could someone look at this code for part 1, it works for the example input but not for mine and I have no idea why
from a quick look are you assuming each directory has a unique name?
because that's not the case
$ 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
dir a
$ cd a
$ ls
5 n```
TOTAL SIZE: 48381170
SIZE d: 24933647
probably better test cases
worked pre well for me but i dislike the double indentation
oop didnโt check timestamp
can anyone do this with a single seq[int]?
lowkey i'm surprised by the amount of people who assumed directories were unique
i mean, they are unique, but one should consider the full path
*unique names
mb
but yeah, are people just not that familiar with file systems? (not trying to judge if it's coming off like that idk)
yeah, my original solution did not depend on this pattern --- but once i saw it, i had to optimize!
is the seq a dictionary?
seq for "sequence"
It's just a list
(I'm assuming)
seems like going up and down the tree might be an issue, I don't know if all the instructions were in order such that you don't ever care about remembering subfolders after you're done with them.
Apparently inputs did a DFS
My code would work even if some things were repeated though because I spent way too long fixing every edge case because of a stupid typo :(
I suppose you could abuse that.
ok so ive finally implemented it with the actual paths in the dictionary instead of the directories names which could be repeated, but its still not giving the right answer. is anything im still missing?
from dataclasses import dataclass, field
@dataclass
class Directory:
size : int = 0
subdirs : list = field(default_factory=list)
def get_next_line(file):
return file.readline().rstrip("\n")
def get_path(current_path, dir):
path = f"{current_path}/{dir}"
return path if current_path == "/" else f"/{path.lstrip('/')}"
max_dir_sum = 100000
f = open("./puzzle_input.txt", "r")
dirs : dict[str, Directory] = {}
current_path = ""
line = get_next_line(f)
while(line != ""):
_, cmd, dir = line.split(" ")
if cmd == "cd":
if dir == "..": # remove the last dir from the path
current_path = current_path.rsplit("/", 1)[0]
else: # add the dir to the path
if current_path == "":
current_path = dir
else:
current_path = get_path(current_path, dir)
line = get_next_line(f)
cmd = line.split(" ")[1]
if cmd == "ls":
full_path = current_path
print(full_path)
dirs[full_path] = Directory()
while((line := get_next_line(f)) != "" and not line.startswith('$')):
val, name = line.split(" ")
if(val == "dir"): # directory
path = get_path(current_path, name)
dirs[full_path].subdirs.append(path)
else: # file
dirs[full_path].size += int(val)
f.close()
result = 0
for dir in dirs.values():
dir_sum = dir.size + sum(dirs[sub].size for sub in dir.subdirs if sub in dirs)
if dir_sum <= max_dir_sum:
result += dir_sum
print(result)
i love how the recent problems allow the usage of patma
proud of my solution yesterday when using match/case
yesterday's puzzle was pretty easy, im having a hard time with this one ๐
Your code confuses me. You get the next line in 3+ different places I'm not sure it's safe, what if it gets a command in the wrong order?
im assuming the order is always cd dir -> ls
but yeah its kinda confusing
kinda bad for someone who's been doing this for the past 5 hours
xD
ok so these last 6 directories are wrong since they arent even in the root directory, but i dont know why this is happening
I did it, finally
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
17 hours with some breaks
ugh
I should have gone to sleep five hours ago but I couldn't -_-;
Wrong channel Salt
or is it
you can also use dataclasses in newer versions of python, they're cool ๐
day=8
...or is it
Someone else suggested that. I had a look at them and didn't see the point of them for this
its just so you dont have to declare the init function in every class
but the regular ones are fine
Also typed with defaults
It just looks nicer
yea
They looked more confusing/obfuscated to me looking over
wrong channel ^^
wrong channel
oh no
also i did day 7 with regular stuff now https://paste.pythondiscord.com/yaqacehabu.py
If you want a class Foo that contains an int a and a str b, you can write
@dataclass
class Foo:
a: int
b: str
and it will generate an __init__ and a __repr__ for you
I think it also generates rich comparison methods but you might have to ask for that by using @dataclass(...), I don't remember
@dataclass
class Directory:
size : int = 0
subdirs : list = field(default_factory=list)
i really dont like this thing that i have to use to declare a mutable list in a data class tho
field(default_factory=list) seems so unnecessary
but doesnt work without it
Ah, mutable defaults. Fun
A) subdirs should probably be hinted with list["Directory"]
B) you could simply not provide a default and make it required on init
well didnt know about that ๐
thanks
wait
@dataclass
class Directory:
size : int = 0
subdirs : list["Directory"] = []
ValueError: mutable default <class 'list'> for field subdirs is not allowed: use default_factory
๐ฅฒ
Don't provide a default
Using default_factory or override __init__ yourself
Typical choice seems to be field
yup
FYI even if you override __init__ you can still get a decent amount of value out of a dataclass; you'll get a repr, an eq, a match_args, and a slots by default; by customising the settings (@dataclass(**settings)) you can also get total ordering and kw-only auto-init, frozen instances, and unsafe hashing (allowing hash despite mutability)
feels nice
indeed
I might have found a bug
if the cwd at the end is a subdir of the directory for part 2 it won't get the correct answer
what input?
I don't have one, I just know it can happen
I found it while I was writing a readable version of it
test input?
test input looks like it ends in /d/
oh true
yes
I like how this guy uses Github issues to document his thoughts and progress especially in using AI assistance to solve day 7. https://github.com/simonw/advent-of-code-2022-in-rust/issues/9
Amazing!
https://adventofcode.com/2022/day/7 Puzzle input looks like this: $ 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...
s=[];d=[]
for r in open(0):
a,*_,b=r.split()
if'/'>b:d+=s.pop(),
elif'$ d'>r:s+=0,
if'/'<a<':':s=[i+int(a)for i in s]
d+=s;print(sum(_*(1e5>_)for _ in d),min(_ for _ in d if _>max(d)-4e7))
``` 192 that actually works for all inputs
s=[];d=[]
for r in open(e:=0):
a,*_,b=r.split()
if'/'>b:*s,v=s;d+=v,;e+=v*(1e5>v)
elif'$ d'>r:s+=0,
if'/'<a<':':s=[i+int(a)for i in s]
print(e,min(_ for _ in d+s if _>max(s)-4e7))
``` 183
@narrow sail @viscid sail @queen breach any more ideas?
idk really
๐ซต โถ๏ธ ๐
all kinds of blind turns and wrong assumptions yesterday, to the point that I had a minor nightmare last night about there being an entire second independent root directory '\' , and I finish part B this morning before my coffee
but it's just 22:06 why should i have 6+ hours of sleep on a day with no school
Looks fine, except, make sure you create a different branch to work off of
They'll be able to use your PR fine, but it will break your fork after they merge the PR, because GitHub will try to update your fork to have commits that already exist
You can fix it with Git and force pushing and all that, but it's a huge pain
just create branches
I finally got day 7!
I wasn't taking into account directories possibly having the same name as other directories that are nested somewhere else ๐
Yeah, a lot of us fell for that 
s,d=[],[]
for r in open(e:=0):
a,*_,b=r.split()
if'/'>b:*s,v=s;d+=v,;e+=v*(v<1e5)
elif'$ d'>r:s+=0,
if'$'<a<'d':s=[i+int(a)for i in s]
print(e,min(_ for _ in d+s if-_<4e7-max(s)))
messed around a bit but couldn't get below 183
here's another version
with things flipped
guys, i made this code for the test data not knowing that for the real data, there would be repeated directory names
and i don't know how to change it so it takes this into account
i don't think this works
wrong answer on my input
text = open(r"C:\Users\ollys\Documents\AOC Files\2022 #7.txt", "r").read().splitlines()
curfolder = ""
tree = {}
for line in range(len(text)):
stepfd = 1
if text[line][0] == "$" and text[line][2] == "c":
#cd
if text[line][5] != ".":
#cd directory (not cd ..)
curfolder = text[line][5:]
if text[line][0] == "$" and text[line][2] == "l":
#ls
tree[curfolder] = []
array = []
while text[stepfd + line][0] != "$":
array.append(text[stepfd + line])
stepfd += 1
tree[curfolder] = array
def hasnodirs(dir):
for item in tree[dir]:
if not item[0].isdigit():
return False
return True
#directories that only contain files (no other directories)
def getfoldersize(folder):
total = 0
for file in folder:
for char in range(len(file)):
if file[char] == " ":
endofnum = char
break
total += int(file[:endofnum])
total = str(total) + " "
return total
def searchandreplace():
for dir in tree:
for item in range(len(tree[dir])):
if tree[dir][item].startswith("dir"):
dirname = tree[dir][item][4:]
for finaldir in range(len(finaldirs)):
if dirname == finaldirs[finaldir]:
tree[dir][item] = finaldirsizes[finaldir]
break
foldersizes = {}
while not hasnodirs("/"):
finaldirs = []
finaldirsizes = []
for dir in tree:
if hasnodirs(dir):
finaldirs.append(dir)
for finaldir in finaldirs:
finaldirsizes.append(getfoldersize(tree[finaldir]))
for i in range(len(finaldirs)):
foldersizes[finaldirs[i]] = finaldirsizes[i]
searchandreplace()
part1tot = 0
for dirsize in foldersizes:
if int(foldersizes[dirsize]) <= 100000:
part1tot += int(foldersizes[dirsize])
print(part1tot)
here is the code
the 192 did work though
guys, i made this code for the test data not knowing that for the real data, there would be repeated directory names
and i don't know how to change it so it takes this into account
it basically finds all of the folders that contain only files
and then changes the names of them in their parent folders to a file name of the amount of storage they take up
use paths instead of folder names
paths will not be repeated, otherwise it's the same folder
actually wait
i probably pasted the wrong thing
for part one:
code returns test input correct, directories and sizes all seem correct.
why does this return the wrong output?
commands = []
x = input()
while x != "":
commands.append(x.split())
x = input()
current_directory = "/"
directory_dict = {"/": []}
size_dic = {}
for i in commands:
if i[0] == "$":
if i[1] == "cd":
if i[2] == "..":
for key, values in directory_dict.items():
if current_directory in values:
current_directory = key
else:
current_directory = i[2]
if i[0] == "dir":
directory_dict[current_directory].append(i[1])
directory_dict[directory_dict[current_directory][-1]] = []
if i[0].isnumeric():
size_dic[i[1]] = int(i[0])
directory_dict[current_directory].append(i[1])
def size(node):
if node in size_dic:
return size_dic[node]
else:
count = 0
for i in directory_dict[node]:
count += size(i)
size_dic[node] = count
return size_dic[node]
total_size = 0
for i in directory_dict:
x = size(i)
if x <= 100000:
total_size+=x
print(total_size)
who's gonna solve day 7 in bash
in the whole puzzle input, two directories can have the same name
It looks like your code uses the directory names as dictionary keys. That won't work unless you add something to them to make them unique
that would actually be hilarious, create all the files and then just query using du
You can't do it with du, you have to use find
du rounds up to the next block I think
OKay - here is my code so far - hold on a sec while I get it up.
a meh input to test it against is:
$ 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
dir a
$ cd a
$ ls
5 n```
TOTAL SIZE: 48381170
SIZE d: 24933647
Where do I post code snippets if there are too long for Discord?
!paste
Pasting large amounts of code
If your code is too long to fit in a codeblock in Discord, you can paste your code here:
https://paste.pythondiscord.com/
After pasting your code, save it by clicking the floppy disk icon in the top right, or by typing ctrl + S. After doing that, the URL should change. Copy the URL and post it here so others can see it.
wow
i'm just impressed that you wanted to write a nice looking solution
are you sure you're doing directory shennanings right
it's kinda weird how you did it but maybe fine? ๐คทโโ๏ธ
are you assuming directory names are unique? because it isn't
I was, but I wrote the whole lookup table thing to account for that.
Each file and directory goes into the tree with a unique id as the name.
looks like your tree is working and fine
probably an issue of where you do number calculations
Thats what I suspect - but I have no idea what it might be
That all happens right at the bottom.
not sure how anytree works
are you sure you're recursively getting files
i.e. in directory a
it sums up files i, f, g, h.lst
Yes, and then adds them to the directory attribute length of the parent node.
to the length of a, in your example.
weird
i don't have anytree installed, can't test personally ๐คทโโ๏ธ
you can try to replace with paths and test against input
oh thats such a silly reason -_-
It's a pretty simple fix though tbh
My first go at day 7 I used a module called treelib that threw errors immediately when I tried to create multiple nodes with the same name
Lmao rip
What I did was just put some code in my main for loop that incremented a counter each time it went through and then appended that as a string to the name of each directory node when I made it.
Thus ensuring that every directory had a unique name
I eventually had to go back to the drawing board because it was too difficult to extract the information I needed from the output, but that at least was a good idea lol
That's another solution. It didn't occur to me for some reason, even though I was recording the paths in that version of the script.
wait if they can have the same name when you call "$ cd x" how would you know which to choose
because when you call $ cd it can only go to subfolders of the current folder
just like when you use it on a regular shell
(which is one reason why I was tracking the path)
I kept track of it with a cursor stack, appending a directory on every cd foo and popping it with each cd ... With a function that could convert that stack to a single string to use as a dict key when adding files and sizes.
Assigning total size per directory, I would just recursively add the file size to the total for every key of the current cursor back to the root.
Once that was all set up, totalling everything was pretty straightforward.
would something like this work?
starting in my code at line 20
else:
for dire in directory_dict[current_directory]:
if dire == current_directory + "_" + i[2]:
current_directory = dire
if i[0] == "dir":
directory_dict[current_directory].append(current_directory + "_" + i[1])
directory_dict[directory_dict[current_directory][-1]] = []
I struggle so much with recursion, it took me more than half a day to solve Day 7, and I ended up getting a lot of help with people. I barely understand my own code for it ๐
lmao rip
I am STILL working on Day 7 - if I don't figure this out soon I'm giving up this year cause I can't take this level of frustration during my christmas vacation lol
Hello
Am bad at recursion
Does this seem like it'd do what I expect it to? (Recursively sum the sizes of a directory)
def _recursive_size(entry: FileSystemEntry, sum) -> int:
if entry.type == EntryType.FILE:
return entry.size
for e in entry.entries:
sum += _recursive_size(e)
return sum
FileSystemEntry is a custom class meant to mockup a file or folder. Only files have sizes. Folder sizes need to be calculated from summing all their nested file sizes
I'm too sleepy for recursion right now. But... You're defining the total as a parameter, and then you're not actually passing it into the recursive call. You'll only get the result of the first return, AFAIU. Have you tried it yet?
Also you're overriding the built-in sum
Right. Got an error that I was missing the required parameter. Passed it in and it worked like a charm
As for overriding sum, I'll have to on an epic journey through the mountains and valleys to find out where I asked
Well ๐you too then birdo, 
(I'll probably be back later asking why int is not a callable)
Only if you try to use it in a shadowed scope, as long as you constrain it to that function you're fine
Don't encourage him!!!
Anyone know whats wrong with this? Works for test input but not actual input (part one)
from collections import defaultdict
with open('day7\input.txt', 'r') as f:
data = f.read().split('\n')
path = []
sizes = defaultdict(int)
sums = 0
for line in data:
words = line.split()
if words[0] == '$':
if words[1] == 'cd':
if words[2] == '..':
path.pop()
else:
path.append(words[2])
elif words[0].isnumeric():
for i in range(len(path)):
sizes[path[i]] += int(words[0])
print(sizes, i, path)
for keys, values in sizes.items():
if values <= 100000:
sums += values
print(sums)```
This doesn't produce enough folders, maybe duplicates?
yeah that's probably it
wdym?
oh, so there could be file sphbzn inside of a folder called sphbzn? or something along those lines? Like there are duplicate file/folder names?
exactly and you'd be counting them as the same
Hm, do you see an easy way to fix that with my code?
sorry for the late reply
for path in accumulate(current_path): # current_path = ['/', 'folder1/', 'folder2/']
sizes[path] += size``` this is what a lot of people did
!docs itertools.accumulate
itertools.accumulate(iterable[, func, *, initial=None])```
Make an iterator that returns accumulated sums, or accumulated results of other binary functions (specified via the optional *func* argument).
If *func* is supplied, it should be a function of two arguments. Elements of the input *iterable* may be any type that can be accepted as arguments to *func*. (For example, with the default operation of addition, elements may be any addable type including [`Decimal`](https://docs.python.org/3/library/decimal.html#decimal.Decimal "decimal.Decimal") or [`Fraction`](https://docs.python.org/3/library/fractions.html#fractions.Fraction "fractions.Fraction").)
Usually, the number of elements output matches the input iterable. However, if the keyword argument *initial* is provided, the accumulation leads off with the *initial* value so that the output has one more element than the input iterable.
Roughly equivalent to:
Ah interesting, ty!