#AoC 2023 | Day 1 | Solutions & Spoilers
1515 messages Β· Page 2 of 2 (latest)
im here but i dont want to really look at other solutions much until i figure out part 2
Oooh, I have loads of issues reading very loopy stuff π
This is scala but you can more or less replace every map with a list comprehension or so:
def part1Solution(rawInput: String): Int =
rawInput
.split("\n")
.map(_.filter(_.isDigit))
.map(line => (line.head.asDigit * 10) + line.last.asDigit)
.sum
thats super simple
Second one is harder tho, especially for a day 1 π
Yeah agreed, especially sincve they did people dirty by replace, replacing the first occurrence and breaking the actual first word.
idk if im gonna figure out the part 2
I used a hack that trivialises part 2 #1180009538544488478 message
@pseudo minnow ```py
print(*(v:=sorted(map(lambda s:sum(s),map(lambda x:map(int,x.split("\n")),open("inp.txt").split("\n\n")))),v[-1],sum(v[-3:]))[1:])
yeah I remember that one, considerably easier π
AOC 2022 start was pretty easy until they hit us with the crane and the stacked containers π
ppl def cheated by splitting the input in 2 in the txt.
It got really ugly for me there because I overengineered it
I wanted to get the crates with programming so this is what it turned out ```py
crates = [list(filter(lambda h: h != " ", k)) for k in list(zip(8[iter([z[1] for y in zip(*zip(9[iter(zip(4[iter(x)]))])) for z in y])]))]
After that it was pretty easy.
Reading golfed solutions give me a headache (in a good way!) π
I got into semi-golf solutions, they do learn myself new tricks and shortcuts that I actually use in production code.
Not stuff like eval or bitwise shifting with binary, that's too far.
@upper thicket two -> two2two
oh my god
lol
cleaned up my solution a bit
the slice assignment keeps the lists at a max of 2 elements```py
from pathlib import Path
with open(Path(file).parent / "input") as f:
data = f.read().rstrip()
from re import finditer, Match, compile
numbers = "zero, one, two, three, four, five, six, seven, eight, nine".split(", ")
py3.12 woo
pattern = compile(fr"(?=(\d|{"|".join(numbers)}))")
p1 = p2 = 0
for line in data.splitlines():
values_1 = []
values_2 = []
for m, in map(Match.groups, finditer(pattern, line)):
try:
v = int(m)
except ValueError:
values_2[1:] = numbers.index(m),
# values_2.append(numbers.index(m))
else:
values_1[1:] = values_2[1:] = v,
# values_1.append(v)
# values_2.append(v)
p1 += 10*values_1[0] + values_1[-1]
p2 += 10*values_2[0] + values_2[-1]
print(p1, p2)
though appending is probably much faster and easier to understand lol
is there a way to break up a string based on dictionary key matches
im trying to avoid regex. I thought just replace all instances of "one" with "1",etc
Complexity is negligible since each line is pretty short
my answer is incorrect yet every test case returns the right answer
do i have to scan al the 1000 strings ans answers now?π’
try ||oneight||, the result should be ||18||
yep it returned that
share your code in #aoc-solution-hints
that's what i thought at first. "it'd be trivial bc i can just ctrl + f replace everything!"
then i saw overlapping words :)
i gave up the mobile thing, not that masochistic lol
i'm not super well-versed in spreadsheet magic, so here's a clunky (but works!) nine nested substitutions solution:
https://docs.google.com/spreadsheets/d/1p0RXE_xMzGnM5gIPlGghr0uKjSwfVgQxdx1fWuSFDmc/edit?usp=sharing
posted it
I did code my thing on my phone
in a language I've never used before
not that bad at the end of the day π₯΄
oh hell naw π© how much pain were you in
with a decent phone keyboard it's quite fine
no
on screen keyboard
I've sworn by https://github.com/klausw/hackerskeyboard for ages π
full qwerty keyboard
looks sweet
i need to try this out sometime
what was the random language for today?
but overall that and then vim is actually quite alright
I guess in part because not a lot of mouse dependence
1seven8seven should return 17, not 18
groovy
never heard of it lol
istg one day you'll get a ping for malbolge
groovy is mainly used as a config language for java iirc
I'm hoping for a couple of esolangs in the first few days
(though maybe I'm thinking of something different there)
piet would be an interesting one
gradle?
I was thinking of something that was often used with gradle, but I'm probably misremembering
I'm curious why groovy didn't take off, but kotlin did
oh wait, are gradle config files groovy?
Gradle scripts are written in either Groovy DSL or Kotlin DSL (domain-specific language).
apparently it is, and I'm not entirely making stuff up
You've probably seen it by now, but if you put the word back in you can still use regex replace.
heh
just finished
couldn't do it earlier, because of school and other work π
oh huh, I didn't even consider regex
that was probably the way to go π
mine is sort of bad
aboo! :D
from more_itertools import substrings_indexes
def part_1(inp: str) -> int:
lines = inp.splitlines()
digits = ["".join(i for i in line if i.isdigit()) for line in lines]
return sum((int(d[0] + d[-1]) for d in digits))
def part_2(inp: str) -> int:
lines = inp.splitlines()
numbers = {
"one": "1",
"two": "2",
"three": "3",
"four": "4",
"five": "5",
"six": "6",
"seven": "7",
"eight": "8",
"nine": "9",
}
ret = 0
for line in lines:
substrings = (
"".join(i[0])
for i in sorted(substrings_indexes(line), key=lambda t: t[1])
if len(i) <= 5
)
digits = [i for i in substrings if i.isdigit() or i in numbers]
first = digits[0] if len(digits[0]) < 2 else numbers[digits[0]]
last = digits[-1] if len(digits[-1]) < 2 else numbers[digits[-1]]
ret += int(first + last)
return ret
hi π
i emerge from the vast dark to partake in aoc
heh
then i lurk again
π
trying to sm cool for every early day lol
I think this year's first puzzle was harder than last year's π
I want to do my solutions in agda
what's agda?
intead of regexes I thought "windows", and turns out more_itertools has a fancy substrings function
https://github.com/agda/agda a programming language π it's functional and dependently typed
you can also do proofs and stuff with it
that's not groovy
yeah what's up with that anyway
Was stumped about the overlapping numbers like a lot of people, before watching hyper-nutrino's video and realising the problem, as I am a noob, any obvious optimizations or things that indicate I don't know about some feature that I should?
import regex as re
with open('day1/input.txt','r') as f:
inputlines = f.read().splitlines()
def part1(inputlines):
ans = 0
for line in inputlines:
numline = []
for char in line:
if char.isdigit():
numline.append(int(char))
print(numline[-1])
ans += (int(f'{numline[0]}{numline[-1]}'))
return ans
def part2(inputlines):
wordstonum = {
'one':'1',
'two':'2',
'three':'3',
'four':'4',
'five':'5',
'six':'6',
'seven':'7',
'eight':'8',
'nine':'9'
}
def num(x: str):
if x.isdigit():
return x
return wordstonum[x]
pattern = "(?=(" + "|".join(wordstonum.keys()) + "|\\d))"
ans = 0
for line in inputlines:
digits = re.findall(pattern,line)
digits = [*map(num,digits)]
ans += (int(f'{digits[0]}{digits[-1]}'))
return (ans)
print(part1(inputlines))
print(part2(inputlines))```
Is this code working for you?
I didn't join the roulette leaderboard π₯Ί
I'll still do a solution in groovy, just after the other handful of languages on my list to do the solutions in
Yup!
I'm quite happy with this solution. A functional and recursive approach to doing Day 1 in Elixir. https://github.com/soupglasses/advent-of-code/blob/main/2023/day_01.exs
with open("day1.txt") as f:
puzzle = f.read().split("\n")
wordsToDigit = {
"one": "o1e",
"two": "t2o",
"three": "t3e",
"four": "f4r",
"five": "f5e",
"six": "s6x",
"seven": "s7n",
"eight": "e8t",
"nine": "n9e"
}
digits = []
windowSize = 5
words = wordsToDigit.keys()
for i in puzzle:
iterations = [i]
for n in range(len(i) - windowSize + 1):
smallS = iterations[-1][n: n+windowSize]
for word in words:
if word in smallS:
i = i.replace(word, str(wordsToDigit[word]), 1)
iterations.append(i)
digitized = "".join(filter(str.isdigit, iterations[-1]))
digits.append(int(f"{digitized[0]}{digitized[-1]}"))
print(sum(digits))```
tunnel vision: the puzzle
It is curious that you use third-party regex without the main reason to use it in this day's puzzle :)
But regardless the solution looks clean
oohkay, that might not happen anytime soon
from what I can tell, editor support for agda isn't amazing
at least, in terms of what I'm used to
overlapped=True? Yeah this was my first time using regex and I have no idea what I'm doing so I assumed regex and re were the same thing, didn't even realise I had the non built-in module until I read other people's solutions :P
crimes (groovy solution)
def part1(lines) {
lines.sum {
def digits = it.findAll(/\d/).collect { it.toInteger() }
digits[0] * 10 + digits[-1]
}
}
def part2(lines) {
def wordForm = ["", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"]
def fore_regex = /\d|one|two|three|four|five|six|seven|eight|nine/
def back_regex = /\d|eno|owt|eerht|ruof|evif|xis|neves|thgie|enin/
lines.sum {
def first = it.find(fore_regex)
def first_num = first.isNumber() ? first.toInteger() : wordForm.indexOf(first)
def second = it.reverse().find(back_regex)
def second_num = second.isNumber() ? second.toInteger() : wordForm.indexOf(second.reverse())
first_num * 10 + second_num
}
}
File input = new File("inputs/day1.txt")
def lines = input.readLines()
println "part 1: ${part1 lines}"
println "part 2: ${part2 lines}"
what language is this?
Groovy, the language roulette of the day (see the heading under #announcements message)
the syntax is interesting
ooh i see I did not know that was a thing
I'm too committed to doing it in my own, but sounds fun!
can i suggest my language as part of the roulette? π
you'd have to ask kat
I think they're all slightly more well-known ones though, and I believe the schedule is set?
source?
your mother
dawn I'm having a crisis
agda-mode is making me do emacs shortcuts in vscode
lovely
no.
i disagree
did you join the roulette leaderboard? π
uhhh no, i was not aware there was one
it's up there somewhere, I have to pin it still
I'm getting clowned on in the other leaderboards I'm in
we be growing
but I don't wanna stay up late
to me it's just nice to see collective progress
#advent-of-code message
ty
half the time I spent today was installing the language ngl
nix ftw
I already had sdkman installed from.... scala IIRC, so I just pasted in "sdkman install groovy", and away it went
Done in like three minutes
And then it took me 90 minutes to get a working solution 
flake.nix line 14
groovy # day 1```
Agda took like 20 minutes to install ;-;
I started using nixos as my main OS. Having never done functional programming like all you CS majors (presumably), I'm still lost by the nix language itself. But having every install and every system change being 100% undoable is worth it even if I'm not getting the most out of it yet.
my intention is to nuke my fedora install, reinstall, and then set up everything using nix π
Do you want some resources that helped me with the language?
I looked into silverblue, but Iβm not sure how well that plays with dual booting
I have https://nixcloud.io/tour/?id=1 on my list of things to go through as the nix discord channel recommended it since I wanted something with examples I could practice with, but if you have other resources that you liked. I went through the nix.dev manual and, I donno, some parts just aren't clicking and I think its because I'm just not used to functional languages.
Understandable. https://nixos.org/guides/nix-pills/ is also a nice digestible series of really short blog-post style articles, a couple of which touch on the language.
The real pain is working with nixpkgs and writing derivations π
I'm decent at the language at this point, but that is just beyond me for anything nontrivial
are you fully nixed, dawn?
Nah, I'm using it in wsl
I see
still need some software that exists only on or is better on windows
I started going through the pills at one point, but when I asked some follow up questions on the nix discord about nix-env, they told me thats out dated and not to use pills because its focus on an older style π€·ββοΈ . My whole system configuration is in a flake using home manager, so it seems like there are a lot of resources that aren't really targetted to a newer setup like that
I dual boot, which is nice with a drive dedicated each to windows and Linux
Why did Sir Lancebot react?
The word "flake"
Christmas reactions
Huh, interesting. I also use a Nix flake config, although it's quite minimal because I use WSL, as I said
I used to not know the home-manager option search existed, that made my config so much cleaner
oh woops, we've gotten wildly off topic
gpt4 can't get part 2 right!
i decided to give it a shot with dumb approaches. for whatever reason, i decided to check the str from both directions to get short circuiting, but then did the checks in the dumbest ways possible π
accumulator = 0
templates = {"o": ["one"],
"t": ["two", "three"],
"f": ["four", "five"],
"s": ["six", "seven"],
"e": ["eight"],
"n": ["nine"]}
mappings = {"one": "1", "two": "2", "three": "3", "four": "4", "five": "5", "six": "6",
"seven": "7", "eight": "8", "nine": "9",}
def check_digit(index, line, templates, mappings):
total_length = len(line)
char = line[index]
if char.isdigit():
return char
inventory = templates.get(char, [])
for item in inventory:
item_length = len(item)
if index + item_length - 1 < total_length:
chunk = line[index : index + item_length]
number = mappings.get(chunk)
if number is not None:
return number
return "F" # to pay respects
with open("inputs/input_day1_.txt", "r") as file:
for line in file:
number = ""
n = 0
while n < len(line):
digit = check_digit(n, line, templates, mappings)
if digit.isdigit():
number = digit
break
n += 1
n = len(line) - 1
while n >= 0:
digit = check_digit(n, line, templates, mappings)
if digit.isdigit():
number += digit
break
n -= 1
accumulator += int(number)
print(accumulator)
return "F" # to pay respects
i'm stealing this
Where can I get help with my day 1 solution?
Make a thread in #aoc-solution-hints and I might pop over and help
finally did it ```py
import aoc_lube
import re
LINES = aoc_lube.fetch(year=2023, day=1).splitlines()
LINES = ['1abc2', 'pqr3stu8vwx', 'a1b2c3d4e5f', 'treb7uchet']
lines = 0
index = 0
total_number = 0
ValueError_count = 0
nummers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
spelled_nummers = {
'zero': 0,
'one': 1,
'two': 2,
'three': 3,
'four': 4,
'five': 5,
'six': 6,
'seven': 7,
'eight': 8,
'nine': 9,
}
reverse_spelled_nummers = {
0: 'zero',
1: 'one',
2: 'two',
3: 'three',
4: 'four',
5: 'five',
6: 'six',
7: 'seven',
8: 'eight',
9: 'nine',
}
print(LINES)
for string in LINES:
index_list = []
index_library = {}
print(string)
for number in spelled_nummers.keys():
if number in string:
indexes = [m.start() for m in re.finditer(number, string)]
for item in indexes:
index_library[item] = spelled_nummers.get(number)
for number in reverse_spelled_nummers.keys():
if str(number) in string:
print(str(number))
indexes = [m.start() for m in re.finditer(str(number), string)]
for item in indexes:
index_library[item] = number
print(index_library)
index_list = []
for index in index_library.keys():
index_list.append(index)
index_list.sort()
print(index_list)
first_number = index_library.get(index_list[0])
last_number = index_library.get(index_list[-1])
number_to_add = int(f'{first_number}{last_number}')
total_number = total_number + number_to_add
print(number_to_add)
print(total_number)
mappings = {
"one": "1",
"two": "2",
"three": "3",
"four": "4",
"five": "5",
"six": "6",
"seven": "7",
"eight" : "8",
"nine": "9",
}
with open('day1.txt') as puzzle_file:
for line in puzzle_file:
line = line.strip()
reduce_one = reduce(lambda a, kv: a.replace(*kv), mappings.items(), line)
reduce_two = reduce(lambda a, kv: a.replace(*kv), reversed(list(mappings.items())), line)
numbers = []
final, final_reversed = zip(reduce_one, reduce_two), zip(reversed(reduce_one), reversed(reduce_two))
for r1, r2 in final:
if r1.isdigit():
sum += int(r1)*10
break
if r2.isdigit():
sum += int(r2)*10
break
for r1, r2 in final_reversed:
if r2.isdigit():
sum += int(r2)
break
if r1.isdigit():
sum += int(r1)
break
Non-Regex solution (because I forgot regex existsted)
Basically, just using .replace() twice - first time it replaces going down from 10->9->8 etc, second time 1->2->3
import re
f = open("input.txt", "r")
digit_pattern = r"\d|one|two|three|four|five|six|seven|eight|nine"
cor = {"one": "1", "two": "2", "three": "3", "four": "4", "five": "5", "six": "6", "seven": "7", "eight": "8", "nine": "9"}
items = f.readlines()
_sum = 0
for item in items:
reg = re.search(fr".*?({digit_pattern}).*({digit_pattern}).*", item)
nb = None
if reg is None:
reg = re.search(fr".*?({digit_pattern}).*", item).group(1)
nb = cor.get(reg, reg)*2
else:
nb = "".join(cor.get(i, i) for i in reg.groups())
_sum += int(nb)
print(_sum)
f.close()
``` everyone seems to be using findall, didn't even came to my mind
I aspire to write as clean code. Ultra performative
Raku:
my @lines = "day_01.input".IO.lines;
## Part 1
@lines>>.comb(/\d/)>>.[0, *-1]>>.join.sum.put;
## Part 2
my %digs = <one two three four five six seven eight nine> Z=> 1..9;
# Fast to write, slow to execute
@lines>>.match(/ \d | @(%digs.keys) /, :ex)>>.[0, *-1]>>.map({%digs{$_} // $_})>>.join.sum.put;
# Slow to write, fast to execute
@lines.map(-> \β { (.min({.value.min}).key, .max({.value.max}).key).join given (%digs{$_} // $_ => β.indices($_) for %digs.kv) }).sum.put;
initial d1p1 solution
lβββNGET'./day1.txt' 1
ββ+/{βv[1,β’vββ΅/β¨β΅ββd]}Β¨l
nums = {
"one": 1,
"two": 2,
"three": 3,
"four": 4,
"five": 5,
"six": 6,
"seven": 7,
"eight": 8,
"nine": 9,
}
with open("aoc/2023/input.txt") as file:
total = 0
for line in file.readlines():
ans = []
for iteration in (enumerate(line), reversed(list(enumerate(line)))):
for i, c in iteration:
if c.isdigit():
ans.append(int(c))
break
for numk, num in nums.items():
if line[i:].startswith(numk):
ans.append(num)
break
else:
continue
break
total += ans[0] * 10 + ans[1]
print(total)
shitass solution i spent an hour on because i was not breaking out of a nested loop, just remembered for else exists 
for-else exists but using an early return in a function is much nicer (and can break out of nested loops easily)
Who loves parsing?
I am actually really salty that this was the issue
Also somewhat disappointed in the fact that python's builtin re doesnt' have overlapping matches at all
Iβm quite annoyed this is a thing too
Normally AOC is good about catching these technical issues that you're not really expected to be searchign for on day one in the example...
They were meant to replace re with regex years ago - seems like that never happened
I was aware of the issue but I thought it wouldnβt count. I thought if a letter makes up a number word which counts as a βdigitβ then you canβt reuse it
Probably for good reasons, I should add
Not re. Only third party regex
AOC should have caught it
Python should've fixed it by now
I should have noticed
sigh
Well I guess it depends if you count ?= as overlapping support or not
I'd call that a hack
Not like whatever but
If I had to do that in production code
I'd comment it with #hack required because _insert reason here_
# hack required for job security 
I donβt want to be that guy whose Python looks like Morse code lol
I hacked some django theming code with
# I know why this was written this way, but it's wrong.
# So we actually do it differently. This is noted in the project readme, since the library documentation is now wrong.
# Speeds up page load times by 50%
lol π
The actual technical reasons is a conflict between two different use cases for the theming
between different themes for different pages and different theme "layers"
I do love coming across comments like that
A classic I enjoy is a comment saying βthis is temporaryβ
You just know that code is going to be there for the next 50 years
One of my favorite comments is
"this is technically like O(n^5) but it never runs on more than 15 items or outside of debug mode"
π
Actually solving the problem would be mentally hard and well, debug mode, not too slow, time to move on and whistle
it's part of a table layout engine
kind of proud of it, it makes pretty tables
If I were to go back and owrk on this code
I would probably un-nest it a bit and make the comments longer
code's 4 years old now
Weβre probably getting off topic for the channel, btw. But yeah, who cares about performance with small inputs - certainly not me :)
lol
Are non-Python solutions alright for this channel?
For part 1 I did
|| ```
Ax: input
Bx: =REGEX(Ax, "[0-9]")
Cx: =REGEX(Ax, "0-9")
Dx: =Bx*10 + Cx
E1: =SUM(D1:D99999)
For part 2 I did
|| ```
Ax: input
Bx: =SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(Ax, "nine", "n9e"), "eight", "e8t"), "seven", "s7n"), "six", "s6x"), "five", "f5e"), "four", "f4r"), "three", "t3e"), "two", "t2o"), "one", "o1e")
Cx: =REGEX(Bx, "[0-9]")
Dx: =REGEX(Bx, "[0-9](?!.*[0-9])")
Ex: =Cx*10 + Dx
G2: =SUM(E1:E99999)
``` ||
excel?
yeah
brave
idk why all the solutions are so long
maybe I am missing something
Basically the reason a naive .replace() chain doesn't work is overlapping digits. So something likeeightwo wouldn't work (it can't be an input because it wouldn't fit day 1, but whatever).
But if you replace eight with e8t instead of just 8, you get e8two which will work just fine
ok this one is even better and covers more edge cases theoretically (like if two letters can overlap, imagine if woops was a number and it overlapped with two)
Why ||substitute||?
Just ||check the indexes||
https://github.com/shenanigansd/scratchpad/tree/main/events/advent_of_code/2023/01/excel
Wait
Wait wait wait wait wait wait
Excel has REGEX !?!?
regexcel
you can fake it with lookahead assertions
does kinda suck it's not builtin
gaaaahhhhhhhhhhhhhh
I'm using LibreOffice Calc so it doesn't work for me
What is DIGIT_MAP?
i don't know what im doing anymore ```py
import re
import functools
with open("./input.txt") as file:
input = file.read().strip()
nums = lambda input: sum(
int(n[0] + n[-1]) for n in re.sub(r"[a-z]", "", input).split("\n")
)
nums = lambda input: sum(
int((match := re.findall(r"(\d)", line))[0] + match[-1])
for line in input.split("\n")
)
nums = lambda input: sum(
int((s := [*filter(str.isdigit, l)])[0] + s[-1]) for l in input.split("\n")
)
print(nums(input))
print(
nums(
functools.reduce(
lambda v, ie: v.replace((e := ie[1]), e + str(ie[0] + 1) + e),
enumerate("one two three four five six seven eight nine".split()),
input,
)
)
)
does this work?
they do
well actually you almost never want str.isdigit, use str.isdecimal instead
str.isdigit matches a whole bunch of characters that are not 0123456789
!e
print("ΰ―«".isdigit())
@fluid ivy :white_check_mark: Your 3.12 eval job has completed with return code 0.
True
!charinfo ΰ―«
\u0beb : TAMIL DIGIT FIVE - ΰ―«
same with \d in regex
I see.
I imagine thousands of projects have some inconsistency because of using \d in regex
!e ```py
import re
print(re.search(r"\d+", "xΰ―«d"))
@hidden schooner :white_check_mark: Your 3.12 eval job has completed with return code 0.
<re.Match object; span=(1, 2), match='ΰ―«'>
dam
oh thats bad
import re
with open('input.txt') as f:
calibration_document = f.read().splitlines()
def part1():
calibration_values = []
for line in calibration_document:
digits = re.findall(r'\d', line)
calibration_value = int(digits[0] + digits[-1])
calibration_values.append(calibration_value)
print(sum(calibration_values))
def part2():
digit_map = {
'one': 'o1e',
'two': 't2o',
'three': 't3e',
'four': 'f4r',
'five': 'f5e',
'six': 's6x',
'seven': 's7n',
'eight': 'e8',
'nine': 'n9e'
}
calibration_values = []
for line in calibration_document:
for digit in digit_map:
line = line.replace(digit, digit_map[digit])
digits = re.findall(r'\d', line)
calibration_value = int(digits[0] + digits[-1])
calibration_values.append(calibration_value)
print(sum(calibration_values))
if __name__ == '__main__':
part1()
part2()
ignore overlap issue by just letting it hang out, ya feel?>
it looks so dumb but it works
beats doing the ugly ass initial solution i had
Fair
import re
file = open('input.txt', 'r')
input = [i for i in file.read().strip('\n').split('\n')]
def part1(lines):
total = 0
for line in lines:
numbers = re.findall(r'[0-9]', line)
if len(numbers) == 1:
double = f'{numbers[0]}{numbers[0]}'
total += int(double)
else:
total += int(numbers[0] + numbers[-1])
return total
def part2(lines):
wordstonum = {
'one':'1',
'two':'2',
'three':'3',
'four':'4',
'five':'5',
'six':'6',
'seven':'7',
'eight':'8',
'nine':'9'
}
def num(x: str):
if x.isdigit():
return x
return wordstonum[x]
pattern = "(?=(" + "|".join(wordstonum.keys()) + "|\\d))"
ans = 0
for line in lines:
digits = re.findall(pattern,line)
digits = [*map(num,digits)]
ans += (int(f'{digits[0]}{digits[-1]}'))
return (ans)
print(part2(input))
print(part1(input))
overlapping matches has a tendency to blow up
e.g.
re.findall('a+', 'a'*10000)
and I suspect zero length matches complicate things as well
(it's kinda breaking how regex works)
Took me 3 hours to solve day 1 and man, I made a lot of mistakes. You can watch my dumbass on stream trying to tackle it here: https://www.youtube.com/watch?v=QbmDmoC1PS0
Or be spoiled and see the solution. Do note that the code is now broken for Part 1 of Day 1. I might reorganize it to accommodate Part 1 and Part 2 solution in a single Python file. And looking at other people's code made me realize how overcomplicated my code is. Dammit. https://github.com/Qoyyuum/adventofcode/blob/2023/2023/01/trebuchet.py
Powered by Restream https://restream.io
Coding late nights demands coffee. Buy me some at https://www.buymeacoffee.com/qoyyuum
You can join along or tackle the code challenges at https://adventofcode.com
The Github code repo for Advent of Code:
https://github.com/Qoyyuum/adventofcode
#Python #AdventOfCode #AOC
I did exactly the same lol #1180009538544488478 message
My Day1/Part 1
And youdont want to know how long it took me. a very Looooooooooooooooooooooooooooooooooooooonnnnnnnnnnnnnnnnnnnngggggggggggggggggggggggggggg time indeed. Though there were lot of iterations till arriving here. Thank you stackoverflow.
||```py
def get_integers(string):
# parse our string for integers
return [int(c) for c in string if c.isdigit()]
def count_sums():
sums = []
# loop through our data
result = [get_integers(item) for item in data]
for z in result:
# if we have more than one integer, we need to combine them
if len(z) > 1:
x = int(f"{z[0]}{z[-1]}")
# add our sum to our list
sums.append(x)
else:
# if we only have one integer, we need to double it
x = int(f"{z[0]}{z[0]}")
sums.append(x)
return sums
def main():
print(sum(count_sums()))
if name == "main":
main()
Congrats! Even if it took you long, nice job for sticking with it
Regarding your code, a style point - try to avoid naming variables as _ if you plan to use them. _ is a convention to label only variables that would be thrown away.
I have other code suggestions if you want to hear them :)
Allways open to a critiqu. Thats how you improve. I realised my mistake with the _ now, its a throwaway and i kept using it. should have used a name. what other points
Another point is that you donβt actually need the if statement, because even if the length of the list is 1, you can still access the same element through index 0 or index -1
Last comment is that count_sums and the sums list could be renamed because you arenβt actually summing the values until later.
so count_sums and sums should be different names for readability of code?
i dont see how i could have evaluated teh single digit or double digit unless i had the iff. can you show me what you mean?
which element is _[-1] if _ is a single element list?
I am appending a zero to the number if the length of the _ is 1, ( x = int(f"{[0]}{[-1]}"))
But I see your point having re-examined the actual input text, there are no single digits like there were in the test data.
wdym appending a zero?
im getting confused with day 4, scratchcards. Methinks comments might have been helpful
This is AOC - no one writes comments :P
haha, I just did. Ok so now that I know what im talking about and not scratchcards, I use the if to either output the number if its more than a single digit geting the fist and last figit from any number {0} or {-1} and if it is a single digit I convert it to two digits [0][0]
But you can do it the same way
You can do 0 and -1 for both cases
hey I wrote comments for day 5
:O
I need to look at the code for that
Iβll do that now even though I donβt have my IDE with me :(
file = open("day1_input.txt", "r")
cum_sum = 0
number_words = {
"one": "1",
"two": "2",
"three": "3",
"four": "4",
"five": "5",
"six": "6",
"seven": "7",
"eight": "8",
"nine": "9"
}
window_size = 5
def check_for_replace(line_to_replace):
for word in number_words.keys():
line_to_replace = line_to_replace.replace(word, number_words[word])
return line_to_replace
def check_word(word_to_check):
for i in range(len(word_to_check) - window_size + 1):
x = check_for_replace(word_to_check[i:i + window_size])
if x != word_to_check[i:i + window_size]:
word_to_check = word_to_check.replace(word_to_check[i:i+window_size], x)
return word_to_check
for line in file:
line = check_word(line)
nums = [i for i in line if i.isdigit()]
line_value = int(nums[0] + nums[-1])
cum_sum += line_value
break
print(cum_sum)
Does anyone know where i went wrong?
have you considered the oneight case?
yeah
!e
#file = open("day1_input.txt", "r")
cum_sum = 0
number_words = {
"one": "1",
"two": "2",
"three": "3",
"four": "4",
"five": "5",
"six": "6",
"seven": "7",
"eight": "8",
"nine": "9"
}
window_size = 5
def check_for_replace(line_to_replace):
for word in number_words.keys():
line_to_replace = line_to_replace.replace(word, number_words[word])
return line_to_replace
def check_word(word_to_check):
for i in range(len(word_to_check) - window_size + 1):
x = check_for_replace(word_to_check[i:i + window_size])
if x != word_to_check[i:i + window_size]:
word_to_check = word_to_check.replace(word_to_check[i:i+window_size], x)
return word_to_check
#for line in file:
line = "oneightwoneightwo"
line = check_word(line)
print(line)
nums = [i for i in line if i.isdigit()]
line_value = int(nums[0] + nums[-1])
cum_sum += line_value
print(cum_sum)
@gray timber :white_check_mark: Your 3.12 eval job has completed with return code 0.
12
no it should be 12
nope, 12 is correct because you still include overlaps
so oneightwoneightwo is 18282?
you could see it that way, yes
ah ok thx
as long as you're taking the "one" and "two" from the start and end respectively it's fine
wouldnt it be the easiest way to just put all the overlaps alos in my dict like "oneight": "18", etc.?
one workaround several people found was ||replacing one -> o1e, two -> t2o, etc. so the overlaps are preserved||
how about "oneightwo" then?
or "threeighthreeighthree..."
ah yeah i would have an infinite dict then if i want to check for each case
man i want to look at it but also dont xD
looks like you aren't handling the overlaps properly in the code still
ninesixmlfjxhscninehqcdvxf8nzfivetwonehhd
an example from my input - two is overwriting the o from one so you don't pick it up
yeah because i didnt think about the overlaps at first, but i managed to do it a while ago, but thx π
cool :)
I'm building up a for loop and trying to go through all of this. it's a bit of a head scratcher. This is where I gotten to:
for a in puzzle_input:
calibrated_1st_value = int(a[0][0].isdigit())
calibrated_2nd_value = int(a[0][-1].isdigit())
calibrated_values = calibrated_1st_value + calibrated_2nd_value
print(calibrated_values)```
Sigh. I'm a bit lost. I managed to convert puzzle input into the list so I could build a for loop out of it
What I understand from the day 1 site (https://adventofcode.com/2023/day/1)>
- I need to pull 1st and last numbers from a string that can be only be int.
- Add just 1st and last numbers as 1 number
Then make a sum of all the calibration values.
What doesn't make sense to me is that If I look at this example:
For example:
1abc2
pqr3stu8vwx
a1b2c3d4e5f
treb7uchet
that last line, 7. According to this site, the calibration would be 77, not 77. Is it because that 7 is a sole remaining number that it can be somehow turn into 77?
the 1st number in treb7uchet is 7
the last number in treb7uchet is 7
hence, the calibration is 77
doesn't matter if they're the same digits
Okay, fair enough, that makes sense.
Thanks STickie. Now to figuire out the rest.
I'm still working this out but is this output correct?
['186', '5713', '736', '716', '711', '1262', '9351', '342124', '998', '77', '75447']
Nvm, no. This output is incorrect. Back to work then.
thoughts on my solution?
import re
import time
def main() -> None:
with open(r"D:\01 Libraries\Documents\Coding\Advent of Code\Advent2023\Day 1\puzzle.txt",
"r", encoding="utf-8") as f:
puzzle: str = f.read()
puzzle: list = puzzle.split("\n")
total: int = 0
for line in puzzle:
digits = re.findall(r"\d", line)
if len(digits) == 0:
pass
else:
temp_digit = digits[0] + digits[-1]
total += int(temp_digit)
print(total)
if __name__ == "__main__":
start = time.perf_counter()
main()
end = time.perf_counter()
print('\n', end - start)
looks decent for p1!
if len(digits) == 0:
pass
was this because you are encountering empty strings in the split? if so consider
puzzle: list = puzzle.splitlines()
which will ditch the final newline by default
Also, nice type hinting but usually you wouldn't just typehint a list on its own - you'd indicate what was in that list. In this case it's a list of strings so you'd do list[str]
no, it was to skip lines with no digits
ah - fair but you won't likely have any such lines in the input - after all the puzzle does not tell you how to handle such cases
not a big deal though
there were
I was getting index errors until I put that exception π
really? I highly doubt that
again, are you sure it wasn't just an empty line?
left over from the last split?
let me check to be sure
yeah
apparently it was for the last line which is empty
the error I mean
yup - so that's where splitlines() helps
I just assumed there were lines without digits lol
ha fair :)
didn't know this, thanks
finally you can use timeit to time the solution easier
import timeit
print(timeit.timeit(main, number=1))
wouldn't that execute main twice?
no - as long as you didn't call main beforehand :)
so it would be like this?
if __name__ == "__main__":
print(timeit.timeit(main, number=1))
that's basically how I do it, yup
one more thing about typehinting as well - typically you don't need to typehint many individual vars
total: int = 0 - the type hint here probably isn't necessary because most tools will be able to infer that total is an int simply because you assigned 0 to it
alright
even if you were to run mypy on strict mode, it wouldn't insist that you type hint that var
more on this, what's the difference between subtracting two time.perfcounter(), subtracting two datetime.datetime.now(), and using timeit.timeit()?
timeit.timeit uses time.perfcounter internally - it's more of a convenience module so that you don't have to write out the calculating code
as for datetime.now, I suspect it's just not as precise
I see
anyhow - have a go at p2 now :)
oh - perhaps one other thing to mention - your regex solution is fine, and actually a good idea considering p2 coming up. But if you were only doing P1, jumping straight to regex probably is overkill for solving this
why is it overkill?
digits = [char for char in line if char.isdigit()] works just as well and is more readable
ah okay
to be honest
regex is my go to solution to anything that requires matching stuff
in the end, you do you - but I would suggest not to jump to regex immediately
it's a great tool, but used sparingly - when the occasion calls for it
just out of complexity sake or something else?
I think readability
regex patterns aren't always the most readable
in general, favour pure Python unless the resulting pure Python would be more complicated to express than the regex
ah okay
P2 is an example where regex becomes more viable as a solution
just because the resulting pure Python might be quite a bit less readable
I see
tbh, I have used regex as a primary tool for so long that I kind of can just read it lol
oh I understand. was jut giving my thoughts as well
@mortal siren code for the second part:
import re
import timeit
c_digs = {
'one': '1', 'two': '2', 'three': '3',
'four': '4', 'five': '5', 'six': '6',
'seven': '7', 'eight': '8', 'nine': '9'
}
def main() -> None:
with open(r"D:\01 Libraries\Documents\Coding\Advent of Code\Advent2023\Day 1\puzzle.txt",
"r", encoding="utf-8") as f:
puzzle: str = f.read()
puzzle: list[str] = puzzle.splitlines()
total = 0
for line in puzzle:
digits: list[str] = re.findall(r"\d|one|two|three|four|five|six|seven|eight|nine", line)
if digits[0].isdigit() and digits[-1].isdigit():
total += int(digits[0] + digits[-1])
elif digits[0].isdigit() and not digits[-1].isdigit():
total += int(digits[0] + c_digs[digits[-1]])
elif not digits[0].isdigit() and digits[-1].isdigit():
total += int(c_digs[digits[0]] + digits[-1])
elif not digits[0].isdigit() and not digits[-1].isdigit():
total += int(c_digs[digits[0]] + c_digs[digits[-1]])
print(total)
if __name__ == "__main__":
print(timeit.timeit(main, number=1))
I'm seing it flow in the debugger, and it should work, but AoC is saying that my resut is too low
Firstly - does your code work for test input?
(it looks like it should but do check that first)
so in the puzzle description they give you examples
and what result you should expect from the examples
right
whenever you have issues, the first thing to do is run your code over the examples and check that you get the result they say
I actually go to the trouble of writing automated tests for all example inputs, but that's generally overkill :)
ah okay
so check that out and report back whether it failed any or passed them all
so
apparently splitlines() is not ignoring the empty string
@mortal siren
also, yes
the code I wrote prints what the example says it's supposed to
How did you type in your input?
So you have an extra newline at the beginning and extra space at the end
To get rid of the extra newline at the beginning, type \ right after the opening triple quotes
or you could attach a .strip() to the end of the string
To get rid of the spaces at the end, remove the spaces at the end :) To the left of the closing triple quote
Yes but this way they learn the intricacies of triple quoted strings :)
fair
But yes you right they can strip() too ofc
Anyway this isnβt the main thing
The main thing is
gotcha
Have you considered the oneight case?
what about it?
ah
i see
but my logic still captured it appropriately
so what's the issue?
Did it?
If you test oneight on its own, do you get 18?
as you can see here, it captured everything exactly like the example
Right but you arenβt capturing eight
You need to capture both one and eight
ah
Or put another way, overlapping numbers count
Iβm completely with you on that one
I did consider this case and thought that overlapping should not count because one word counts as a digit, so if you count that as a unit it shouldnβt be allowed to share letters with neighbouring words
But it counts
So there
bs lol
I think this puzzle is the most BS of any in AOC, though others disagree
And the fact that itβs day 1 puzzle makes that even worse
btw
I disagree with you solely because day 8 exists
is that if/elif block the most elegant solution for the problem?
but yeah this was kinda bad too
I am aware of the existence of day 8 and still think this is worse
But there you go
elegant is subjective
is there a way to do it in less lines?
Thereβs better ways to write it - but you should focus on getting your code working first
there's almost always to do it in one line sure, but that usually isn't good looking nor well written so I wouldn't aim for it
Idk I think using dict.get would be good looking
for example?
dict.get(key, default)
If the key exists in the dictionary, retrieve it - else retrieve the default value
back to https://regex101.com I go lol
That is one approach - build a better regex
There is actually a way to make it work with your existing regex pattern
Let me know if you want to know about that
Alrighty!
last letter/first letter matching
just don't remember off the cuff, because it was literally only once lol
Thatβs not actually what I would suggest
You can make it work with literally your pattern unchanged
But change the code around it
Or change the pattern and donβt change the code
Both are viable options
ah okay
And yeah, the get. For example you can do c_digs.get(digits[0], digits[0])
Are you familiar with dict.get at all?
used once for a problem long time ago, didn't like and it didn't really fit my use, so no
yay
with reddit's spoilers I did it
I didn't know enough about regex operations to do this without spoilers
didn't even what lookahead or non-overlapping was
the lookahead is basically just there to avoid consuming the string as you match it
I didn't know that was a thing!
well, I guest htat's the point of the event after all
foce you to learn new things
well onto to day 2
@mortal siren if you wanna talk about better ways to do it than that if/elif block, I'm all ears
I went to sleep by this time but can still discuss this if you'd like
would love to. we can do it here, or if you don't mind, in DMs?
can do it here, but let's do it later - I want to finish day 16 first
np
Part 2 completed in Python 3 without regex:
https://github.com/TerraMonster5/Advent-of-Code/blob/main/2023/Day 1/day1.py
"oh this question is easy... there's a part two YOU SCOUNDRELS"
with open("input1.txt") as f:
data2 = f.read()
data2 = data2.splitlines()
list_of_matches = [
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"0",
"one",
"two",
"three",
"four",
"five",
"six",
"seven",
"eight",
"nine",
]
def str_num_to_int(stringnumber):
dct2 = {
"0": 0,
"1": 1,
"2": 2,
"3": 3,
"4": 4,
"5": 5,
"6": 6,
"7": 7,
"8": 8,
"9": 9,
"10": 10,
"one": 1,
"two": 2,
"three": 3,
"four": 4,
"five": 5,
"six": 6,
"seven": 7,
"eight": 8,
"nine": 9,
}
return dct2[stringnumber]
print(data2[0])
def bob(lst):
func_lst = []
for line in lst:
dct1 = {}
for word in list_of_matches:
if word in line:
index = line.index(word)
dct1[index] = word
print(dct1)
else:
pass
final_number = str(str_num_to_int(dct1[min(dct1)])) + str(
str_num_to_int(dct1[max(dct1)])
)
func_lst.append(int(final_number))
print(int(final_number))
test = sum(func_lst)
print(test)
bob(data2)
Apparently my day 1 part 2 solution returns +10 on the correct number, does anyone know why its returning 54540 instead of 54530 (the solution to the dataset of day1 part 2). Thanks.
one2eightwo654nine2 (expected answer 12) could be a helpful test case
answer: ||a match might appear multiple times||
Thank you, mine returns 19 which is obviously wrong, I'll work on it π
Is it cheating to use Perl for part 1?
# aoc day one part one
use v5.36;
open my $fh, '<', 'input.txt' or die;
my $total = 0;
while (my $line = <$fh>) {
my ($x) = ($line =~ /\D*(\d)/);
my ($y) = ((reverse $line) =~ /\D*(\d)/);
$total += "$x$y";
}
say $total;```
Not in the least. Use whatever it takes that makes you feel good about it.
I know this is pretty far past, but this is my first bit of code and I wanted to share it
check = 0
value = 0
#this function uses a for loop to iterate through a string and extract all numeric characters
def numextract(current):
extracted = ""
for char in current:
if char.isnumeric():
extracted += char
return extracted
#this function removes all numbers besides the outer two
def numslim(num):
final = 0
snum = str(num)
fir = snum[0:1]
firI = int(fir)
lisbac = snum[::-1]
sec = lisbac[0:1]
secI = int(sec)
hold = firI * 10 + secI
final = hold + final
return final
data = input("Dataset: ")
datalist = data.splitlines()
length = len(datalist)
while length != check:
current = datalist[check]
num = numextract(current)
digit = numslim(num)
value = value + digit
check = check + 1
print("Calibration Value", value)
Hey there - congrats on doing Day 1 Part 1 :) Would you be interested in feedback on your code?
Not right now! Thank you for asking though. I know there are tools I'm not aware of that I could have done much better if I had used them, but I used what I know, and I think that's enough to be proud of for now
Fair enough :) And yes, you should be proud of every completed problem :)
file = open("aoc1.txt", "r")
data = file.readlines()
number_strings = {"one": "1", "two": "2", "three": "3", "four": "4", "five": "5", "six": "6", "seven": "7",
"eight": "8", "nine": "9"}
calibration_sum = 0
def reverse_check(line):
temp_str = ""
for char in line:
if line[0].isnumeric():
line_numbers.append(line[0])
break
temp_str = line[0:3]
temp_str = temp_str[::-1]
if temp_str in number_strings:
line_numbers.append(number_strings[temp_str[0:3]])
break
temp_str = line[0:4]
temp_str = temp_str[::-1]
if temp_str in number_strings:
line_numbers.append(number_strings[temp_str[0:4]])
break
temp_str = line[0:5]
temp_str = temp_str[::-1]
if temp_str in number_strings:
line_numbers.append(number_strings[temp_str[0:5]])
break
else:
line = line[1:]
for line in data:
line_numbers = []
temp_string = ""
running = True
while running:
if len(line_numbers) > 1:
break
while line[0].isnumeric():
line_numbers.append(line[0])
line = line[::-1]
reverse_check(line)
if line[0:3] in number_strings:
line_numbers.append(number_strings[line[0:3]])
line = line[::-1]
reverse_check(line)
elif line[0:4] in number_strings:
line_numbers.append(number_strings[line[0:4]])
line = line[::-1]
reverse_check(line)
elif line[0:5] in number_strings:
line_numbers.append(number_strings[line[0:5]])
line = line[::-1]
reverse_check(line)
else:
line = line[1:]
calibration_sum += int(line_numbers[0] + line_numbers[len(line_numbers) - 1])
file.close()
print(calibration_sum)```
my full solution, im sure it's ugly but it works
this is similar to the other solution you posted where there is a lot of repeated code. You might want to think about how you could write a couple of functions that take in a parameter.



