#Day 1 Trebuchet?!
1 messages · Page 1 of 1 (latest)
part 2 means i'll have to rewrite like, everything
this feels like the wrong way to solve this problem but I don't know OCaml well enough yet
the way to solve every problem is a recursive algorithm and a match statement
I collapsed the pattern match functions so it'd fit on one screen, but here's both parts solved
I used the Jane Street stdlib
bruh
Google Sheets one-liners
https://www.reddit.com/r/adventofcode/comments/1883ibu/comment/kbiho2e/?utm_source=share&utm_medium=web2x&context=3
🤔 consistent rank between parts 1 and 2
yup I definitely did this wrong
I was too lazy to do something proper for part 2 so I ||just reversed the input string and the list of needles to find the rightmost number||
Here's part 1 in Turing Complete. Part 2 should be easy but tedious, so I'll save it for the morning.
i think this counts as proper enough 😛
horrifying
The wiring could definitely be cleaned up. I was preparing for it to be much more complex and didn't put much focus in keeping it neat.

this is what I did and I stuck with it for part 2, you can see how it backfired in my first screenshot 😆
Oh lol you did it literally
||https://old.reddit.com/r/adventofcode/comments/1884fpl/2023_day_1for_those_who_stuck_on_part_2/||
|| I'm lucky that I accidentally accounted for this in my solution, I can imagine getting stuck on this specific case for a long time :\ ||
I said I'd do it in c++ but here's my (very naive) zig solution lol
Oh, I didn't even think of ||just replacing the words with digits||
Part 1 was like "oh a nice easy one to start with", then part 2 "oh no, this is gonna be a mess" and it was lol. Though in retrospect, I realize that all I did was try to adapt what I did for part 1, which wasn't the best choice.
Part 1. Yes I'm lame and this is C++ developed in replit on my phone
Ok thanks I now know what not to do 😅
Part 1
||```rust
fn part1() -> impl Display {
INPUT.lines()
.map(|line| {
let first = line.chars().find(|c| c.is_numeric()).unwrap();
let last = line.chars().rfind(|c| c.is_numeric()).unwrap();
format!("{first}{last}").parse::<usize>().unwrap()
})
.sum::<usize>()
}
My initial problem at part 2 was ||that I can't simply use `.find()` to say "if this char is number, OR some unknown length of chars matches one of a bunch of strings".|| The very ugly way I came up with, was to ||keep using `.find()` and check separately for numbers, and for matching words, and then determine which was the closest to the start/end of the data.||
Won't post my original part 2. But after reading about a certain issue that other people ran into, I figured out I could just do this:
||```rust
const PAT_REPLACE: [(&str, &str); 10] = [
("zero", "zero0zero"),
("one", "one1one"),
("two", "two2two"),
("three", "three3three"),
("four", "four4four"),
("five", "five5five"),
("six", "six6six"),
("seven", "seven7seven"),
("eight", "eight8eight"),
("nine", "nine9nine"),
];
fn part2() -> impl Display {
INPUT.lines()
.map(|line| {
let mut line = line.to_string();
for (pattern, replace) in PAT_REPLACE {
line = line.replace(pattern, replace);
}
let first = line.chars().find(|c| c.is_numeric()).unwrap();
let last = line.chars().rfind(|c| c.is_numeric()).unwrap();
format!("{first}{last}").parse::<usize>().unwrap()
})
.sum::<usize>()
}
Both parts, Kotlin
||
class Day1 : Puzzle(1) {
private val digitMap = mapOf(
"one" to 1, "two" to 2, "three" to 3, "four" to 4, "five" to 5,
"six" to 6, "seven" to 7, "eight" to 8, "nine" to 9
) + (1..9).map { it.toString() to it }
override fun part1() =
input.lines().asSequence()
.map { line ->
line.asSequence()
.filter { it.isDigit() }
.map { it.digitToInt() }
.let { it.first() * 10 + it.last() }
}.sum().toString()
override fun part2() =
input.lines().asSequence()
.mapNotNull { line ->
val first = line.findAnyOf(digitMap.keys)?.second
val last = line.findLastAnyOf(digitMap.keys)?.second
if (first == null |\| last == null) return@mapNotNull null
(digitMap[first]!! * 10) + digitMap[last]!!
}.sum().toString()
}
||
python solution
||
def find_num(s: str, rev: bool, p2: bool) -> int:
nums = {
"1": "one",
"2": "two",
"3": "three",
"4": "four",
"5": "five",
"6": "six",
"7": "seven",
"8": "eight",
"9": "nine",
}
if rev:
s = s[::-1]
nums = {k: v[::-1] for (k, v) in nums.items()}
for i in range(len(s)):
for k, v in nums.items():
if (s[i:].find(k) == 0) or (p2 and s[i:].find(v) == 0):
return int(k)
p1, p2 = 0, 0
for l in open("input.txt").read().splitlines():
p1 += find_num(l, 0, 0) * 10 + find_num(l, 1, 0)
p2 += find_num(l, 0, 1) * 10 + find_num(l, 1, 1)
print(p1, p2)
||
@silent quarry how did you get the colored syntax ?
after the three ``s` put the name of the language
@silent quarry thank you
Trigger warning: Java
lmao trigger warning
part 1 and 2 in factorio lmao
part 2 in vim key inputs
Looking at the subreddit, it seems like a lot people made it harder for themselves by using ||regex search and replace||
part2 haskell
yeah that's what i initially tried to do.
though you can make that work || by replacing "one" with "o1e" and the same for other numbers ||
Part 2 in Turing Complete. Props to anyone who can decipher this.
I don't think I have a Reddit account anymore.
bit of a weird one and in the end i ended up writing my own matching code but it could be worse
Still stuck in part 2. Can you guys give me confirmation that I'm understanding correctly: if there's only one digit in a line, it gets repeat into two, right?
yes, same as part one. if the line is like...
v4
the number would be 44
or vfourv or whatever, also 44
Dammit then I'm still stuck
are you using regex?
hmm
Also I'm printing all of my single nums and they seem to match, looking manually at the file
well what i'd suggest is doing a print statement that prints the line and the calculated first and second digits and then scrolling through it until you see one thats wrong
oh
Someone I know came up with an interesting solution
||He realized that the only characters that matter for overlapping are the first and last characters||
|| because of this, you can solve part two by replacing one with o1e, two with t2o, three with t3e etc, and then just run the solution from the first part||
|| I guess that’s quite similar to what bigbass did actually||
A colleague of mine came up with the same
I think there's two main ways people solve it.. this one and the one I used (why isn't this damn spoiler tag working now)
I feel like ||replacing text is overcomplicating it. For every character, I check if it’s a number or if it and the following characters match one of the 10 words.||
You can also || just check every possible substring || like I did
literally just what kellan said
It was less typing though 😛
What’s typing?
The thing you do on a keyboard
average javascript fan
I overcomplicated my life a lot I feel like
don't worry mine was crazy overcomplicated too 😆
Aight I give up
It's like this every year
Start doing AoC -> fixate for a day on solving a problem without succeeding -> feel stupid because you work as a programmer and have a working Nintendo 64 emulator but supposedly can't solve stupid problems while everyone else finished in about 5 minutes -> get angry at yourself and depressed
This isn't healthy for me
So i'm calling it quits
it's just for fun anyway
if you aren't having fun then there's no reason to do it imo
Exactly so yeah
I'm maybe going to try again tomorrow but yeah no
If it has to be string parsing fiasco every fucking time
I swear this guy just loves typing he should do web dev He does lmao
(Yeah I'm still salty)
Some people call it Advent of Parsing
Yeah it literally is
The puzzles get more fun and challenging than this though. But if it is not fun for you then maybe better not 🙂
I created a temp account and posted it.
I'm actually not that unique. The TC Discord server has a leaderboard running.
This happens every year to a lot of people. Even happened to me many times. I've spoken on it before, but AoC usually boils down to whether or not you already happen to know how to solve the problem, and then implementing it. The first few days can usually be worked through without knowing the best methodology to use, but even then it can feel frustrating.
AoC tends to make use of certain algorithms or ways of thinking that you don't need in a lot of other programming fields/scenarios. You could work on quantum computers but struggle with AoC because you've never parsed strings in arbitrarily complex ways before.
:/
I've gotten better over the years, and I take it much less seriously now, which helps reduce any frustration. If I get stuck, I head over to the Rust server, as there's people there that are really helpful.
Yeah, I mean, in the end it's about fun. I didn't finish most years but also if I get stuck on something for too long it helps to be able to ask for help. I guess people with a compsci or maths degree have an edge because you know all those algoritms you normally never use in practice 🙂
Also usually stuff from previous years is repeated sometimes so you definitely get better at it with time
I fucking did it
You rock
My solution sucks. I tried to use cool containers standard functions and shit but it wouldn't work and at this point I'm too tired to try and figure out a cleaner solution. ||I just went nuts with manual index searching||
wow
this is what they mean by thinking outside the box
i just did it the straightforward way and didn't have to deal with that 🤷♀️
I’m surprised we’re getting stuff like this on day 1
yeah, the first few days have been trivial in previous years
I think what would help AoC a lot, at least for me personally, is more thought out example input that will catch edge cases, or perhaps a different input file you can use for testing that is in a more manageable size for reading manually - “my code works on the example but not the real input” is far too common of a problem and just isn’t really very fun
The way that problems are described can also at times be a bit obtuse, and important details can be easy to miss because of how they’re written
for example how to parse “oneight “ today
i somewhat agree but i actually don't think the ambiguity in this problem was atypical or even difficult but unexpected for day 1 which is why people had problems with it. different mindset and stuff, if it was like day 7-10, sure people would still be like "ah didnt see the overlap coming" but no one would complain about the difficulty
also while i was annoyed by it being overlapping and it not being mentioned explicitely myself, i also kind of get the choice. technically the info is all there if you read it very carefully - the example is unfortunate but that might have also been intentional to throw people off. at that point its personal taste if people find that frustrating or challenging (and again, day 1 people assume the easiest way)
Yeah but too often an ambiguity has lead many people to misunderstanding the rules of the problem. On later days, the expectation for clear instructions should increase not decrease, as the complexity of the problems increase. When a significant number of people completely misinterpret what the expected behavior should be, then that's an issue that should be fixed.
Another way to think about it: Is AoC supposed to provide programming challenges, or english comprehension challenges?
Very true, there is a fine line between not giving the solution away and keeping it riddle-like or straight up not providing enough info to solve the problem
ig we'll see a trajectory for this year in about 6 hours
last year for the first time we saw llms/gpts take spots on the leaderboard,
i think this year the author slightly increased the difficulty in order to fight ais
No other help please, but ||can you have overlap between words? Does twone parse as 21 or 22?||
||yes. 21||
||or I guess as 11||
Thanks
||Alright, I used a regex to find the first match, then I reversed each line and ran a reverse regex eno|owt to find the last word.||
So earlier in the thread I'm seeing people ||replace one with o1e and then run the p1 parser on the result. which is a clever solution.|| But wouldn't you just need to do ||1e because you're only looking for overlap with the next possible word?||
Or wait no I see why that'd be required. ||I'm using a regex to find the words all at once, but if you're replacing one then two then three and you're not sure what order they go in, then that makes sense.||
i dont know how im gonna find time to do ts
while not hard as such, is it just me that thinks this day 1 puzzle is harder than usual for AoC? Straight into string parsing lol
I thought the same
bit late but i did part 1 in scratch
part 2 as well, the overlapping characters threw me for a loop :<
the way i handle the overlapping characters is by ||starting the string check with the last character of the most recently previously matched word||
well, that wasn't clear at all - finally done part 2 - those examples were misleading
|| I was reading four1eightwo as 418 instead of 4182 as nowhere does it say overlap is fine - unless I missed it ||
I'll spoiler it, but I think you've all done this by now
Indeed
it was probably mentioned on here, but I've avoided spoilers
there's mine anyway, boring c#
It doesn't. That's the main thing people were getting stuck on.
yeah, was annoying, spent like an hour printing stuff out lol
all I needed was || the -1 here: currentIndex += numberWord.Length - 1; ||
my code was right according to my understanding of the assignment lol
i redid my day 1... i'm not sure if i like this better or worse
I see people ||replacing the strings with the digits, does that really work? It looked to me like there could be two results if you replaced left to right and right to left. Unsure if that should matter, but some examples looked ambiguous||
The way people solved that was to ||replace only the middle of the words, rather than the whole thing. So twone->two1e->t2o1e, or eighthree->eight3e->e8t3e||
Why does this work?
||Because the words can at most overlap the first and final character||
Ah, interesting
I was confused in the other way when I saw it
I figured ||they only needed to keep the last char||, but my mistake there was thinking about it executing ||from left to right instead of in numeric replacement order||
I ||create a window going left to right and then right to left, check if the first (direction dependent) is a number, then if it is I return that, else I check if the window ends with one of the digit strings||
Yeah, I don't like this solution because it only works coincidentally due to the way ||numbers are spelled||
and because I just hate modifying strings for problems that don't need it.
Yeah but at the same time knowing the problem domain is a part of any puzzle solution
i just ||scan the input from left to right once|| and didn't have any issues
Yep that’s why I just ||used regex ||
I do dislike when problems require you to know the problem domain though
Especially true for competitive programming challenges where a naive approach is unfeasible
||Do you check at each char for a word match starting there?||
yes
I don’t feel that this one did though. That was only one solution, and there were plenty of other options that didn’t need to know the details
Ah no, this one was simple, I was referring to your comment
Fair
I guess one good thing that I like about AoC is that it only cares about the output, not how you found it 😄
am I the only one who doesn't enjoy string parsing? 😦
maybe it's cos I'm crap at it lol
doesn't interest me at all
I hate it too. Especially this year.
I normally don't like it but I needed practice tbh
I just cheat and use LinQ 
maybe for next year i'll finish my parser lib
i started making one but stopped bc i kept running into internal compiler errors in rustc
but that was a while ago and they've stabilized more nightly features now
do we still need spoilers for in here?
||Console.WriteLine(File.ReadLines("Day1Input").ToArray().Select(l => (First:new [] {"one", "two", "three", "four","five","six","seven","eight","nine", "1", "2","3","4","5","6","7","8","9"}.Select(p => (p,l.IndexOf(p))).Where(pair => pair.Item2 != -1).MinBy(p => p.Item2).p switch {"one" => 1, "two" => 2, "three" => 3, "four" => 4, "five" => 5, "six" => 6, "seven" => 7, "eight" => 8, "nine" => 9, var x => int.Parse(x)}, Second: new [] {"one", "two", "three", "four","five","six","seven","eight","nine", "1", "2","3","4","5","6","7","8","9"}.Select(p => (p,l.LastIndexOf(p))).Where(pair => pair.Item2 != -1).MaxBy(p => p.Item2).p switch {"one" => 1, "two" => 2, "three" => 3, "four" => 4, "five" => 5, "six" => 6, "seven" => 7, "eight" => 8, "nine" => 9, var x => int.Parse(x)}) ).Select(fnl => int.Parse($"{fnl.First}{fnl.Second}")).Sum());||
not my code, but 1 liner in linq 😄
I'm very late to the party but anyways here is my horrible solution written in good old C

has too many lines to show it in discord fuck me
carbon.now.sh is popular around here for code screenshots
@grand cedar i hope you're open to comments -
the switch statement has many blocks with very similar structure ..
i think you could use a table driven approach here 👍
yeah definitely! This is my first AoC and I'm also relatively new to C, so any feedback is very welcome
Yeah, I didn't want to do a whole wall of if, else if etc. so I tried to do it with a switch statement but that also didn't go that well...
I'll take a look at table driven approaches and try to rewrite it that way, thanks 👍
Do you intentionally want to do it in C? I would probably do it in C++ instead just for the little niceties, at some point C itself gets on your way because of string manip hell
yep, intentionally wanted to do it in C, but kinda made me realize why having actual strings and not char[] is useful... 
Lol yep. Can always just write C with classes, without going into the C++ insanity too deep
there is no classes in c
There is, it's called Objective C 
Yes I think Chiaki used that phrasing to say "write in C++ without any of the features except classes"
But it's also a way of sayi- yes what Simone said
oh i get it, ok then
i like c, it's kinda like a lingua franca amongst programmers;
someone who knows either one of: c++, java, javascript, php, golang will probably understand it
besides, it's extremely fast, there's a reason they use it to write operating systems
it's a cute little language, fun to write a compiler for
i like c too, but it's the worst choice for string manipulation
Now with a lookup table, thanks for the feedback asarandi
Khoi nice, much shorter 👍
|| you don't really need a struct, the int returned is just array index +1 ||
|| also, there are no zeros ||
I can't imagine asm is fine 😛
i mean you can call c functions from asm so it's just as fine as c is
no built in support, just like c!
you said worst choice, I was just pointing out that pure asm is probably worse
it's a figure of speech. i'm sure there's a lot worse choices available if you really try
I know someone last year did it all in x86 asm 👀 imagine doing it an AoC on GB/NES
string handling would be the least of your worries on that :p
I did day 1 of 2021 in x64
didn't even attempt the rest 😄
oh, it was 2020
was easy to be fair, and I cheated a bit
main proc
lea rsi, [values]
.for (r13d = 0 : r13d < 400 : r13d += 2)
mov ax, word ptr[rsi + r13]
movzx eax, ax
mov r12d, eax
.for (edx = r13d : edx < 400 : edx += 2)
mov bx, word ptr[rsi + rdx]
movzx ebx, bx
mov r15d, ebx
add ebx, eax
.if (ebx == 2020)
imul r15d
invoke printf, "2020 found, sum of %d and %d. Product is: %d\n", r15, r12, rax
.endif
.for (r8d = edx : r8d < 400 : r8d += 2)
mov r9w, word ptr[rsi + r8]
movzx r9d, r9w
mov r14d, r9d
add r9d, ebx
.if (r9d == 2020)
imul r14d
imul r15d
invoke printf, "2020 found, sum of %d, %d and %d. Product is: %d\n", r15, r12, r14, rax
.endif
.endfor
.endfor
.endfor
invoke exit, 0
main endp```
I used an assembler with HLL
Spec-Chum whats the name of the assembler ?
thank you, these macros look cool, i'll check this out
Can you refactor this more?
Could solve potentially use a map and sum?
Fair enough
This is just personal preference, but, read_from_file() feels unnecessary. There's no reason you need a vec of owned strings. But even just refactor-wise, you have a function that is only called once, and is effectively one line. solve() is similar, in that the body of the function could just go in main().
Though I agree with leina, using map() would cut out a lot of these extra functions.
fn main() {
let answer = std::fs::read_to_string("src/input.txt").unwrap()
.lines()
.map(|line| extract_number(line))
.sum();
println!("{answer}");
}
.map(|line| extract_number(line)) can be written as .map(extract_number)
Even better:
fn main() {
let answer = include_str!("input.txt")
.lines()
.map(extract_number)
.sum();
println!("{answer}");
}
true, I just don't like writing it that way.
Oh another note, as you used in extract_number, if you're returning something on the last line of a function (or closure) then you don't need to explicitly type return whatever;.
In the first function at lines 5-6, (without analyzing/changing the first line) I'd rewrite this like so:
if temp.is_empty() {
None
} else {
Some((first, last))
}
```(replacing `first` and `last` accordingly)
This entire block will be used as the return expression, and imo this makes the function easier to read.
Can also do temp.is_empty().then_some((first, last))
you forgot to negate temp.is_empty()
Hmm? Why would you need to negate it?
If you did, and the vec is empty, then .first().unwrap() would panic.
then_some makes a Some if the bool is true
but you want a Some if temp.is_empty() is false
going by that code snippet
Oh you meant in response to Chiaki, yeah that's true then, would need to negate that.
(this kind of confusion is why I gave the if-else block example instead; since it's much harder to mix up imo)
whoopsie
