I'm using cargo-aoc to download my inputs and generate runners.
There was a little "gotcha" with the second part, that I had to search through my input to figure out.
Part 2 Hint
The spelled out digits can overlap, so if you're using a non-overlapping regex iterator, it'll miss things.
The furthest I've gotten in AOC before being distracted by something else is day 10, lets see how far I get this year. :D
EDIT: Went back and did part 1 with nom to refresh myself on it in case it's needed later on.
I quickly remembered how annoyingly opaque its errors are and have decided not to bother with it for future puzzles unless I absolutely need to.
I'll stick to regex and logos otherwise.
welp, I'm doing Google Sheets again because I have done fuck all to learn anything. I think I did it basically the same way as everyone else... ish. Part 1 =ARRAYFORMULA( LET(...
welp, I'm doing Google Sheets again because I have done fuck all to learn anything. I think I did it basically the same way as everyone else... ish.
Gasp! I forgot it was December 1. This is why I never get and sleep in December. Is anyone running a Tildes leaderboard? Edit to add: Got the solutions, my repo is here:...
Gasp! I forgot it was December 1. This is why I never get and sleep in December. Is anyone running a Tildes leaderboard?
I think I did something a little different than most people for part 2...
Part 2 spoilers
Unlike many of the solutions I've seen people post, I did not use regexes. I have a function that looks for a match at the beginning of the string and returns the remaining string if it finds one. I hit the problem that most people hit (overlapping number names), but it was a simple as tweaking the algorithm to only consume the first letter of the name when it matches on it, leaving the others to match for the second letter.
The year went by so quick, but here we are again! As usual I am using Python: Part 1 #!/usr/bin/env pypy3 total = 0 for line in open(0): digits = [*filter(str.isdigit, line.strip())] calibration =...
The year went by so quick, but here we are again! As usual I am using Python:
Bonus: I wrote a little script so I don't have to remember how to write out these comments with <details> and all.
tildes-aoc-comment.py
#!/usr/bin/env python3importpathlibimportdatetimenow=datetime.datetime.now()path=pathlib.Path(f'~/src/advent-of-code-{now.year}/day{now.day:02}').expanduser()part1=open(path/'1.py').read()part2=open(path/'2.py').read()input_blue=lambdas:input(f'\033[34m{s}\033[0m')part1_remarks=input_blue('Any remarks before part one?: ')part2_remarks=input_blue('Any remarks before part two?: ')final_remarks=input_blue('Any final remarks?: ')print(f'''\{part1_remarks}<details><summary>Part 1</summary>```python{part1}```</details>{part2_remarks}<details><summary>Part 2</summary>```python{part2}```</details>{final_remarks}''')
If other people have pointers about my somewhat rudimentary Spring Boot webapp layout, I would love feedback on that, too.
Everything I've done so far with Java has been spring boot, so my AoC this year is a web app using Spring Boot.
Java
packagecom.michaeleisemann.aoc23.services;importcom.michaeleisemann.aoc23.interfaces.DayInterface;importorg.apache.commons.lang3.ArrayUtils;importorg.springframework.stereotype.Service;// https://adventofcode.com/2023/day/1@ServicepublicclassDay1ServiceimplementsDayInterface{privatefinalString[]wordToNumbers={"zero","one","two","three","four","five","six","seven","eight","nine"};// Fundamentally, we have to just get the first and last digit of the String.// The first and last number can be the same. e.g. asdf1asdf produces the first and last number as 1.publicStringday1Part1(StringpuzzleInput){logger.info("Day 1 Part 1");logger.debug("Puzzle Input:\n{}",puzzleInput);intsum=0;for(Stringline:puzzleInput.split("\n")){// remove all non-digitsStringdigits=line.replaceAll("\\D+","");intcalibrationValue=getFirstAndLastDigits(digits);logger.debug("Calibration Value: {}",calibrationValue);sum+=calibrationValue;}returnString.valueOf(sum);}publicStringday1Part2(StringpuzzleInput){logger.info("Day 1 Part 2");logger.debug("Puzzle Input:\n{}",puzzleInput);intsum=0;for(Stringline:puzzleInput.split("\n")){// search through the line for either a digit or the word for a digitStringBuilderrealDigits=newStringBuilder();StringBuildertempString=newStringBuilder();for(Stringletter:line.split("")){if(letter.matches("\\d")){realDigits.append(letter);tempString=newStringBuilder();continue;}tempString.append(letter);for(StringwordNumber:wordToNumbers){if(tempString.toString().contains(wordNumber)){realDigits.append(ArrayUtils.indexOf(wordToNumbers,wordNumber));tempString=newStringBuilder();tempString.append(letter);break;}}}Stringdigits=realDigits.toString();intcalibrationValue=getFirstAndLastDigits(digits);logger.debug("Calibration Value: {}",calibrationValue);sum+=calibrationValue;}returnString.valueOf(sum);}privateintgetFirstAndLastDigits(Stringdigits){StringfirstDigit=String.valueOf(digits.charAt(0));StringlastDigit=String.valueOf(digits.charAt(digits.length()-1));returnInteger.parseInt(firstDigit+lastDigit);}}
I am doing the same thing (trying to force myself to use Go). It's hard because Python is just so fast and flexible. But my golang has improved enough this past year that I think I can complete...
I am doing the same thing (trying to force myself to use Go). It's hard because Python is just so fast and flexible. But my golang has improved enough this past year that I think I can complete it, even if I don't win any prizes for speed.
Once again, I'm doing it in Python: Repo Link Part 1 This was pretty straightforward: just used a list comprehension to extract the digits. def read_values(stream=sys.stdin) -> list[list[str]]:...
This was pretty straightforward: just used a list comprehension to extract the digits.
def read_values(stream=sys.stdin) -> list[list[str]]:
return [
list(filter(str.isdigit, line))
for line in stream
]
def main(stream=sys.stdin) -> None:
values = read_values(stream)
total = sum(
int(digits[0] + digits[-1]) for digits in values
)
print(total)
Part 2
This was trickier than expected as you had to account for overlapping words such as eightwo. Fortunately, I only had to change my read_values function.
def read_values(stream=sys.stdin) -> list[list[str]]:
values = []
for line in stream:
letters = line.strip()
digits = []
for index, letter in enumerate(letters):
if letter.isdigit():
digits.append(letter)
for value, digit in enumerate(DIGITS, 1):
if letters[index:].startswith(digit):
digits.append(str(value))
break
values.append(digits)
return values
Part 2 (Update)
While showering, I thought of a way to make Part 2 more functional by using map to convert the words to digits before filtering as I did in Part 1:
def word_to_digit(s: str, index: int) -> str:
for value, digit in enumerate(DIGITS, 1):
if s[index:].startswith(digit):
return str(value)
return s[index]
def read_values(stream=sys.stdin) -> list[list[str]]:
return [
list(filter(str.isdigit, map(lambda p: word_to_digit(line, p[0]), enumerate(line))))
for line in stream
]
Part 2 was much trickier than I expected. As usual, here's my hacky AWK solutions. Part 1 #!/usr/bin/awk -f { gsub(/[^0-9]/, "") total += substr($0, 1, 1) substr($0, length($0 - 1)) } END { print...
Part 2 was much trickier than I expected. As usual, here's my hacky AWK solutions.
After spotting the overlapping problem, I initially just decided to parse it from left to right for some reason. The worst part is that it worked perfectly for the sample but not for my input... made things a lot harder for myself.
What a tricky Day 1 compared to previous years! Plus, as somebody using this year to try and brush up a bit on my old beloved C, it feels like today's second part was designed to make me sad :(...
What a tricky Day 1 compared to previous years! Plus, as somebody using this year to try and brush up a bit on my old beloved C, it feels like today's second part was designed to make me sad :( While I completed today, I didn't get the second star thanks to a misinterpretation that I hope that I'm not alone in having read: given the input 6eightwo, my reading of the challenge led me to believe that the expected value therefor was 68, and not 62, and so that caused my final solution to be wrong. To change that I'd need to totally reïmplement, so I suppose that that's that.
Anyway, as I haven't seen anybody else having a crack at C, I thought I'd post mine here!
Advent of Code Day 1 C implementation
```c
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
// replace a substring at a given index with another
void insertNumeral(char* srcString, int startIndex, int endIndex, char num) {
char builtString[MAX_STR_LENGTH];
// load up the leadin...
strncpy(
builtString,
srcString,
startIndex
);
// ...sneak in our little numeral package...
builtString[startIndex] = num;
// ...and then top off with the rest!
strncpy(
&builtString[startIndex + 1],
srcString + endIndex,
MAX_STR_LENGTH - endIndex
);
// donezo; now just copy back to the source :)
strcpy(srcString, builtString);
}
// pass through a given string, replacing spelled numbers with numerals
void sanitiseDigits(char* srcString) {
for (int start = 0; start < (MAX_STR_LENGTH-5); start++ )
for (int numLen = 0; numLen < 3; numLen++) {
if (!isalnum(srcString[start+numLen+2]))
break;
// get current substring to query
char* srcSubstr = (char*) malloc( (numLen+3) * sizeof(char) );
memcpy(
srcSubstr,
srcString + start * sizeof(char),
(numLen + 3) * sizeof(char)
);
// check for numeral hits
for (int i = 0; i < 3; i++)
if (!strcmp(srcSubstr, DIGIT_NAMES[numLen][i][0]))
insertNumeral(
srcString,
start,
(start + numLen + 3),
DIGIT_NAMES[numLen][i][1][0]
);
free(srcSubstr);
}
}
int main(int argc, char* argv[]) {
// first, let's open up our input file...
char const* const fn = argv[1];
FILE* f = fopen(fn, "r");
char curLine[MAX_STR_LENGTH];
// ..and finally we can iterate through its lines!
int noOfDigits;
char curTerminals[2];
int runningTotal = 0;
while ( fgets(curLine, sizeof(curLine), f) ) {
// firstly let's sanitise our spelled digits as a first pass
printf("raw str is %s...", curLine);
sanitiseDigits(curLine);
printf(" and sanitised str is %s!\n", curLine);
// now all there is to do is to extract the digits...
int* curDigits = (int*) malloc(MAX_STR_LENGTH * sizeof(int));
noOfDigits = 0;
for (int i = 0; i < (int)sizeof(curLine); i++) {
if (!isalnum(curLine[i]))
break;
if (curLine[i]>='0' && curLine[i]<='9') {
// (treat as single-character int by subtracting 0 literal)
curDigits[noOfDigits] = (curLine[i] - '0');
noOfDigits++;
}
}
// ...and build the calibrators!
curTerminals[0] = '0' + curDigits[0];
curTerminals[1] = '0' + curDigits[noOfDigits-1];
runningTotal += atoi(curTerminals);
free(curDigits);
}
fclose(f);
// lovely stuff. :)
printf("FINAL TOTAL IS %d. End.", runningTotal);
return 0;
You inspired me to take a crack at a C solution myself. It's pretty much a port of my Python solution, but I think it's pretty efficient? I'm not entirely sure, I'm not the most experienced with...
You inspired me to take a crack at a C solution myself. It's pretty much a port of my Python solution, but I think it's pretty efficient? I'm not entirely sure, I'm not the most experienced with C.
Solution
// Advent of Code 2023// Day 1: Trebuchet?!#include<ctype.h>#include<stdio.h>#include<string.h>intmain(void){FILE*file=fopen("inputs/day_1.txt","r");if(file==NULL){puts("Couldn't read file!");return1;}intresult_part_1=0;intresult_part_2=0;for(charline[64];fgets(line,64,file);){intfirst_digit_part_1=-1;intlast_digit_part_1=-1;intfirst_digit_part_2=-1;intlast_digit_part_2=-1;for(size_ti=0;line[i]!='\n';++i){intdigit=-1;if(isdigit(line[i])){digit=line[i]-'0';if(digit!=-1){if(first_digit_part_1==-1){first_digit_part_1=digit;}last_digit_part_1=digit;}}else{charcheck[5];strncpy(check,line+i,5);if(strncmp(check,"one",3)==0){digit=1;}elseif(strncmp(check,"two",3)==0){digit=2;}elseif(strncmp(check,"three",5)==0){digit=3;}elseif(strncmp(check,"four",4)==0){digit=4;}elseif(strncmp(check,"five",4)==0){digit=5;}elseif(strncmp(check,"six",3)==0){digit=6;}elseif(strncmp(check,"seven",5)==0){digit=7;}elseif(strncmp(check,"eight",5)==0){digit=8;}elseif(strncmp(check,"nine",4)==0){digit=9;}}if(digit!=-1){if(first_digit_part_2==-1){first_digit_part_2=digit;}last_digit_part_2=digit;}}result_part_1+=first_digit_part_1*10+last_digit_part_1;result_part_2+=first_digit_part_2*10+last_digit_part_2;}printf("Part 1: %i\nPart 2: %i\n",result_part_1,result_part_2);}
As usual for me, I do my solutions in Common Lisp. Here's my code for today. I started the problem at midnight EST and did more from the REPL than from writing and running functions. I...
I started the problem at midnight EST and did more from the REPL than from writing and running functions. I accidentally submitted the wrong answer for part one twice in a row, so I ended up getting a recorded solution at 00:14 or so. The code linked above is a more formalized version of what I was typing by hand in the REPL.
My solution, as with many other peoples', involved regexes. So part two bit me, as with many others, by having overlapping digit names. My quick and dirty solution was to reverse all of the regex string except the \d, match against the reversed string, and then re-reverse the match for parsing.
Rust Rust use std::env; use std::io::{self, prelude::*, BufReader}; use std::fs::File; extern crate regex; use regex::Regex; fn calibration_value(input: &str) -> usize { let re =...
Rust
Rust
usestd::env;usestd::io::{self,prelude::*,BufReader};usestd::fs::File;externcrateregex;useregex::Regex;fncalibration_value(input: &str)-> usize{letre=Regex::new(r"(\d)").unwrap();letmatches: Vec<_>=re.find_iter(input).map(|x|x.as_str().parse::<usize>().ok()).collect();10*matches[0].unwrap()+matches[matches.len()-1].unwrap()}fncalibration_value_2(input: &str)-> usize{letre=Regex::new(r"(\d|one|two|three|four|five|six|seven|eight|nine)").unwrap();letmatches: Vec<_>=re.find_iter(input).map(|x|x.as_str()).collect();10*actual_value(matches[0])+actual_value(matches[matches.len()-1])}fnactual_value(input: &str)-> usize{matchinput{"1"|"one"=>1,"2"|"two"=>2,"3"|"three"=>3,"4"|"four"=>4,"5"|"five"=>5,"6"|"six"=>6,"7"|"seven"=>7,"8"|"eight"=>8,"9"|"nine"=>9,_=>panic!("Unexpected input to actual_value: {input}"),}}fnsolve(input: &str)-> io::Result<()>{letfile=File::open(input).expect("Input file not found.");letreader=BufReader::new(file);// Inputletinput: Vec<String>=matchreader.lines().collect(){Err(err)=>panic!("Unknown error reading input: {}",err),Ok(result)=>result,};// Part 1letpart1=input.iter().map(|x|calibration_value(x)).sum::<usize>();println!("Part 1: {part1}");// 54561// Part 2letpart2=input.iter().map(|x|calibration_value_2(x)).sum::<usize>();println!("Part 2: {part2}");// 54076Ok(())}fnmain(){letargs: Vec<String>=env::args().collect();letfilename=&args[1];solve(&filename).unwrap();}
Decided to use Kotlin and see how far I get this year. I got tripped up on part 2 and had to switch from simple replacement to regex: import java.util.regex.Pattern fun main() { /* For each line,...
Decided to use Kotlin and see how far I get this year. I got tripped up on part 2 and had to switch from simple replacement to regex:
importjava.util.regex.Patternfunmain(){/* For each line, filter the digits, concatenate the first and last digits, and then add it to the result. */funpart1(input:List<String>):Int{varresult=0for(lineininput){valdigits=line.filter{it.isDigit()}.map{it.digitToInt()}result+=digits[0]*10+digits[digits.size-1]}returnresult}check(part1(readExample(1,1))==142)valoutput1=part1(readInput(1))println(output1)check(output1==53334)/* For each line, generate digits using a map, concatenate the first and last digits, and then add it to the result. */funpart2(input:List<String>):Int{varresult=0valmap=mapOf("one"to1,"two"to2,"three"to3,"four"to4,"five"to5,"six"to6,"seven"to7,"eight"to8,"nine"to9).plus((0until10).map{it.toString()toit})valpattern=Pattern.compile(map.keys.joinToString("|"))for(lineininput){valdigits=arrayListOf<Int>()valmatcher=pattern.matcher(line)while(matcher.find()){digits.addLast(map[matcher.group()])}result+=digits[0]*10+digits[digits.size-1]}returnresult}check(part2(readExample(1,2))==281)valoutput2=part2(readInput(1))println(output2)check(output2==52834)}
Here's my code in Rust. It's not particularly elegant (or fast, or good, or idiomatic, or...), but it gets the job done. I'm going on a work trip/vacation for the next 8 days so I probably won't...
Here's my code in Rust. It's not particularly elegant (or fast, or good, or idiomatic, or...), but it gets the job done. I'm going on a work trip/vacation for the next 8 days so I probably won't be able to keep up but can't wait to come check out these threads after the fact.
I solved it with Typescript and Deno, using my aocd library for handling fetching the inputs and submitting answers. Part 1 was very straight forward by using a regex to remove all non-numeric...
I solved it with Typescript and Deno, using my aocd library for handling fetching the inputs and submitting answers. Part 1 was very straight forward by using a regex to remove all non-numeric characters from the line. Part 2 required me to throw that out and iterate character by character to see if it was a digit or was the position a digit's name started.
My first attempt at part 2 passed the test but failed on the real data because as an optimization I skipped to the end of the digit's name in the line when I recognized a digit's name, but it turns out some of the lines actually have the digit names overlapping, like in "eightwothree" where you're meant to read both "eight" and "two" despite them sharing a letter. I deleted the line I had that advanced i by the word's length and then my code worked fine.
Wrote about the first problem on my blog. Dunno if I can keep up lol. First part I did with a text editor with regex, and then an Excel file. Second part was tricky. I gave up on Excel and whipped...
Wrote about the first problem on my blog. Dunno if I can keep up lol.
First part I did with a text editor with regex, and then an Excel file.
Second part was tricky. I gave up on Excel and whipped out my trusty Python.
Invested time on a function that finds the first recognized digit then copy pasted that into the same function but with the relevant strings reversed.
I know what you meant, but .... if you got the answer with the second meaning of this phrase, that would be truly impressive. And yes, part of me apparently is still 12.
whipped out my trusty Python
I know what you meant, but .... if you got the answer with the second meaning of this phrase, that would be truly impressive. And yes, part of me apparently is still 12.
AoC is routinely my favorite event of the year. Day 1 had some fun edge cases, but nothing too crazy. If anyone gets stuck (not necessarily today, but at some point in here), I'll be posting...
AoC is routinely my favorite event of the year. Day 1 had some fun edge cases, but nothing too crazy.
If anyone gets stuck (not necessarily today, but at some point in here), I'll be posting explanations of each puzzle and my Python solution on my website: https://advent-of-code.xavd.id/writeups/2023/day/1/
I'm trying out Guile Scheme, this year. Didn't get to it yesterday, sadly, but such is life. I wrote a "utils.scm" library, to do things I'll have to do over and over again: utils.scm For now,...
I'm trying out Guile Scheme, this year.
Didn't get to it yesterday, sadly, but such is life.
I wrote a "utils.scm" library, to do things I'll have to do over and over again:
utils.scm
For now, it's just a function that reads in the input-file line by line, hands back a list of lines.
Elixir Breaking out the binary pattern matching on day 1, hoo-wee 🤠Parts 1 and 2 I got tripped up by the fact that spelled-out digits can overlap in part 2. At first, I had my code jump ahead by...
Elixir
Breaking out the binary pattern matching on day 1, hoo-wee ðŸ¤
Parts 1 and 2
I got tripped up by the fact that spelled-out digits can overlap in part 2. At first, I had my code jump ahead by length(digit_string) every time I found one, so I was missing any spelled-out digits that started within that first one. Annoyingly, this issue only came up in the real puzzle input and not the examples.
defmoduleAdventOfCode.Solution.Year2023.Day01dodefpart1(input),do:solve(input,&digits_part1/1)defpart2(input),do:solve(input,&digits_part2/1)defpsolve(input,get_digits_fn)doinput|>String.split("\n",trim:true)|>Enum.map(&(&1|>get_digits_fn.()|>Integer.undigits()))|>Enum.sum()enddefguardpis_digit(char)whencharin?0..?9defpdigits_part1(line,acc\\[])defpdigits_part1("",acc),do:[List.first(acc),List.last(acc)]defpdigits_part1(<<char,rest::binary>>,acc)whenis_digit(char)dodigits_part1(rest,put_digit(acc,char-?0))enddefpdigits_part1(<<_,rest::binary>>,acc)dodigits_part1(rest,acc)end###defpdigits_part2(line,acc\\[])defpdigits_part2("",acc),do:[List.first(acc),List.last(acc)]defpdigits_part2(<<char,rest::binary>>,acc)whenis_digit(char)dodigits_part2(rest,put_digit(acc,char-?0))enddefpdigits_part2(<<_,rest::binary>>=line,acc)doacc=casefind_leading_word_digit(line)do{:ok,digit}->put_digit(acc,digit):error->accenddigits_part2(rest,acc)enddefpput_digit([],first_digit),do:[first_digit]defpput_digit([first_digit|_],digit),do:[first_digit,digit]for{str,n}<-Enum.zip(~w[one two three four five six seven eight nine],1..9)dodefpfind_leading_word_digit(unquote(str)<>_),do:{:ok,unquote(n)}enddefpfind_leading_word_digit(_),do::errorend
P.S. This is the cleaned up version of my solution—my initial code was a big ol' mess
Edit
Shorter and (in certain cases) faster solution
I realized you don't need to search through the entirety of each line—you can look for the first digit from the left end and the first digit from the right end, and potentially skip a large amount of text in the middle of the line.
Seems like the Erlang VM is optimized for parsing through binary data from left to right though, so even though this does "less work" by stopping as soon as it finds a digit on either end, instead of always iterating through the whole line, the code that works backward from the end of the string tends to run slowly enough to almost cancel out the benefit. In fact, part 1 now runs a few hundred μs slower!
However I still like this approach better because it's a bit easier to understand what the code is doing.
defmoduleAdventOfCode.Solution.Year2023.Day01dodefpart1(input),do:solve(input,&find_digit_part1/1)defpart2(input),do:solve(input,&find_digit_part2/1)defpsolve(input,finder_fn)doinput|>String.split("\n",trim:true)|>Enum.map(fnline->[find_first_digit(line,finder_fn),find_last_digit(line,finder_fn)]|>Integer.undigits()end)|>Enum.sum()enddefguardpis_digit(char)whencharin?0..?9defpfind_first_digit(<<_,rest::binary>>=str,finder_fn)docasefinder_fn.(str)do{:ok,d}->d:error->find_first_digit(rest,finder_fn)endenddefpfind_last_digit(line,finder_fn),do:find_last_digit(line,finder_fn,byte_size(line)-1)defpfind_last_digit(line,finder_fn,drop_from_front)do<<_::binary-size(drop_from_front),str::binary>>=linecasefinder_fn.(str)do{:ok,d}->d:error->find_last_digit(line,finder_fn,drop_from_front-1)endenddefpfind_digit_part1(<<char,_::binary>>)whenis_digit(char),do:{:ok,char-?0}defpfind_digit_part1(_),do::errordefpfind_digit_part2(<<char,_::binary>>)whenis_digit(char),do:{:ok,char-?0}for{str,n}<-Enum.zip(~w[one two three four five six seven eight nine],1..9)dodefpfind_digit_part2(<<unquote(str),_::binary>>),do:{:ok,unquote(n)}enddefpfind_digit_part2(_),do::errorend
Rust, with the aim being pure speed - my repo is here. According to Criterion, on a Macbook Pro with M2, I'm getting around 18 µs for part one, and 28 µs for part two, which I'm fairly happy with....
Rust, with the aim being pure speed - my repo is here.
According to Criterion, on a Macbook Pro with M2, I'm getting around 18 µs for part one, and 28 µs for part two, which I'm fairly happy with.
Notes
I started by just parsing all the values I could see and then returning the first and last ones, which seems to be a common solution. (I also got stuck on the overlapping numbers issue and was really confused for a long time why all my tests were working but the main solution kept on showing up as wrong. The subreddit definitely helped today! 😅)
Then I realised I didn't need to do all that parsing, and it was only the first and last numbers that were interesting, which meant I could skip all the overlapping stuff, and made the parsing a lot easier, although I did end up needing to do it twice to handle the forwards case and the backwards case.
If I were going to improve this, I'd probably look at the regex crate, or better yet some of its internals. The full power of regex is probably overkill in this situation, but Burntsushi knows his way around string matching, so maybe there's something there that'll handle the parsing better. But I think I'm happy for now.
My Rust solution. Seems that many people are advocating that the intended solution is you stop scanning once you hit the first number, and I should've done that instead of find & replace approach...
My Rust solution. Seems that many people are advocating that the intended solution is you stop scanning once you hit the first number, and I should've done that instead of find & replace approach that I did. It might be even simplier. The Rust code also have a bug that it should've use is_digit(10) instead of is_numeric() which make the app crash when encountering non-ascii number.
Maybe I'll try different language tomorrow.
usestd::io;usestd::io::Read;// The newly-improved calibration document consists of lines of text// each line originally contained a specific calibration value that the Elves now need to recover// On each line, the calibration value can be found by combining the first digit and the last digit (in that order) to form a single two-digit number.fnsolve(text: &str)-> u32{text.lines().map(|v|{letfirst_digit=v.chars().find(|c|c.is_numeric()).map(|c|c.to_digit(10)).flatten().unwrap();letlast_digit=v.chars().rfind(|c|c.is_numeric()).map(|c|c.to_digit(10)).flatten().unwrap();(first_digit*10)+last_digit}).fold(0u32,|a,b|a+b)}structReplacement{len: usize,text: &'static[u8;5],replacement: &'static[u8;1],}constNUMBERS: [Replacement;9]=[Replacement{len: 3,text: b"one ",replacement: b"1"},Replacement{len: 3,text: b"two ",replacement: b"2"},Replacement{len: 5,text: b"three",replacement: b"3"},Replacement{len: 4,text: b"four ",replacement: b"4"},Replacement{len: 4,text: b"five ",replacement: b"5"},Replacement{len: 3,text: b"six ",replacement: b"6"},Replacement{len: 5,text: b"seven",replacement: b"7"},Replacement{len: 5,text: b"eight",replacement: b"8"},Replacement{len: 4,text: b"nine ",replacement: b"9"},];fnsolve2(text: &str)-> u32{text.lines().map(|v|{letmutnew_v=Vec::<u8>::new();letraw=v.as_bytes();letmuti=0;letmutlast_covered=0;'outer: whilei<raw.len(){forpatternin&NUMBERS{ifi+pattern.len>raw.len(){continue;}ifraw[i..i+pattern.len]==pattern.text[0..pattern.len]{last_covered=i+pattern.len;new_v.extend_from_slice(pattern.replacement);i+=1;continue'outer;}}iflast_covered<=i{new_v.push(raw[i]);}i+=1;}letnew_v=unsafe{String::from_utf8_unchecked(new_v)};letfirst_digit=new_v.chars().find(|c|c.is_numeric()).map(|c|c.to_digit(10)).flatten().unwrap();letlast_digit=new_v.chars().rfind(|c|c.is_numeric()).map(|c|c.to_digit(10)).flatten().unwrap();(first_digit*10)+last_digit}).fold(0u32,|a,b|a+b)}fnmain(){letmutstdin=io::stdin();letmutinput=String::new();stdin.read_to_string(&mutinput).unwrap();println!("{}",solve2(&input));}#[cfg(test)]modtests{usecrate::*;#[test]fntest_example(){letinput="1abc2pqr3stu8vwxa1b2c3d4e5ftreb7uchet";assert_eq!(solve(input),142);}#[test]fntest_example2(){letinput="two1nineeightwothreeabcone2threexyzxtwone3four4nineeightseven2zoneight2347pqrstsixteen";assert_eq!(solve2(input),281);}#[test]fntest_example2_reddit(){letinput="eighthreesevenine";assert_eq!(solve2(input),83+79);}}
Back to Ruby for this year, I want to see if I can get further this time than I have the last couple. Day 1 - Ruby #!/usr/bin/env ruby require 'benchmark' require 'minitest' require 'pry-byebug'...
Back to Ruby for this year, I want to see if I can get further this time than I have the last couple.
Day 1 - Ruby
#!/usr/bin/env rubyrequire'benchmark'require'minitest'require'pry-byebug'TEST_STR="\1abc2pqr3stu8vwxa1b2c3d4e5ftreb7uchet"TEST_STR_2="\two1nineeightwothreeabcone2threexyzxtwone3four4nineeightseven2zoneight2347pqrstsixteen"classTest<MiniTest::Testdeftest_p1assert_equal(142,compute_p1(TEST_STR))enddeftest_p2assert_equal(281,compute_p2(TEST_STR_2))enddeftest_p2_overlapassert_equal(51,compute_p2("jjhxddmg5mqxqbgfivextlcpnvtwothreetwonerzk"))endenddefcompute_p1(input)input.lines.map{|line|numbers=line.chars.filter{|c|c.match(/[[:digit:]]/)}[numbers.first,numbers.last].join.to_i}.sumenddefcompute_p2(input)input.lines.map{|line|numbers=line.scan(/(?=(\d|one|two|three|four|five|six|seven|eight|nine))/).flatten.map{|num|casenumwhen"one"1when"two"2when"three"3when"four"4when"five"5when"six"6when"seven"7when"eight"8when"nine"9elsenumend}[numbers.first,numbers.last].join.to_i}.sumendifMiniTest.runputs'Test case OK, running...'@input=File.read(ARGV[0]||'input')do_p2=defined?(compute_p2)Benchmark.bmdo|bm|bm.report('Part 1:'){@p1=compute_p1(@input)}bm.report('Part 2:'){@p2=compute_p2(@input)}ifdo_p2endputs"\nResults:"puts'Part 1: %i'%@p1puts'Part 2: %i'%@p2ifdo_p2elseputs'Test case ERR'end
Should've posted this earlier, but I didn't realize there was a thread here. We're certainly off to a tricky start this year - I was hoping for a leaderboard spot, but was a couple minutes off for...
Should've posted this earlier, but I didn't realize there was a thread here. We're certainly off to a tricky start this year - I was hoping for a leaderboard spot, but was a couple minutes off for part 1 and even further away for part 2. Enjoyable problem, though! Looking forward to tonight's.
Solution
# Advent of Code 2023# Day 1: Trebuchet?!spelled_digits={"one":1,"two":2,"three":3,"four":4,"five":5,"six":6,"seven":7,"eight":8,"nine":9,"ten":10}result_part_1=0result_part_2=0withopen("inputs/day_1.txt")asfile:forlineinfile:digits_part_1=[]digits_part_2=[]forposinrange(len(line)):ifline[pos].isdigit():digit=int(line[pos])digits_part_1.append(digit)digits_part_2.append(digit)forspelledinspelled_digits:ifline[pos:].startswith(spelled):digits_part_2.append(spelled_digits[spelled])result_part_1+=digits_part_1[0]*10+digits_part_1[-1]result_part_2+=digits_part_2[0]*10+digits_part_2[-1]print(f"Part 1: {result_part_1}")print(f"Part 2: {result_part_2}")
This is my first year doing AoC after hearing about it from coworkers for a while. Curious to see how long I can stick with it! Here's my Elixir solution for part 2. Day 1 - Elixir defmodule...
This is my first year doing AoC after hearing about it from coworkers for a while. Curious to see how long I can stick with it! Here's my Elixir solution for part 2.
Part 1 was straight forward, but had to rely on a really hacky solution for day 2. Doing it in rust again this year, its the language that I find fun....
Part 1 was straight forward, but had to rely on a really hacky solution for day 2. Doing it in rust again this year, its the language that I find fun.
Always running behind on these. 19 loc in F# for part 1. Didn't want to use regex because I suck at it and I like to future proof against part 2 which sometimes is much harder to do in regex. Part...
Always running behind on these. 19 loc in F# for part 1. Didn't want to use regex because I suck at it and I like to future proof against part 2 which sometimes is much harder to do in regex.
Annnd i was wrong, regex would've been fine, but I'm stubborn and lazy so rather than spend 5 minutes on regexr i'll spend 20 mocking this up. Got it in under 50 lines ignoring my rage debugging.
Part 2
openSystem.IOopenSystemletinputData=File.ReadLines@".\input.txt"letnumberWords=["one",1"two",2"three",3"four",4"five",5"six",6"seven",7"eight",8"nine",9]typeNumberIndex={Index:intValue:string}letgetNumberFromWord(input:string)=numberWords|>List.collect(fun(number,value)->letfirst=input.IndexOfnumberletlast=input.LastIndexOfnumber[{Index=first;Value=value.ToString()}{Index=last;Value=value.ToString()}])|>List.filter(funindexes->indexes.Index>=0)|>List.sortBy(funindex->index.Value)letgetNumberFromCharacter(input:string)=input|>Seq.mapi(funic->matchChar.IsNumbercwith|true->Some{Index=i;Value=c.ToString()}|false->None)|>Seq.chooseid|>Seq.toListletresult=inputData|>Seq.map(funline->getNumberFromWordline@getNumberFromCharacterline|>List.sortBy_.Index|>funindexes->(List.headindexes).Value+(List.lastindexes).Value|>int)|>Seq.toList|>Seq.sum// Ye ole fashion debugging.// result // |> Seq.map _.ToString()// |> fun data -> File.WriteAllLines(@".\test.txt", data)
I'm already behind, but got Part 1 done in Bash. An arbitrary goal I've set is pure GNU/Bash, since bash is fairly limited in what it can do, but has fairly robust logic. I used sed and awk for...
I'm already behind, but got Part 1 done in Bash. An arbitrary goal I've set is pure GNU/Bash, since bash is fairly limited in what it can do, but has fairly robust logic. I used sed and awk for this, for example, to extract the data, and the arithmetic was fairly simple to get work, like any other language.
Here we go again! I'll try to remember to post my solution in the morning, but for now I'll just say - wow that was a trickier Day 1 than I expected
Rust
I'm using cargo-aoc to download my inputs and generate runners.
There was a little "gotcha" with the second part, that I had to search through my input to figure out.
Part 2 Hint
The spelled out digits can overlap, so if you're using a non-overlapping regex iterator, it'll miss things.The furthest I've gotten in AOC before being distracted by something else is day 10, lets see how far I get this year. :D
EDIT: Went back and did part 1 with nom to refresh myself on it in case it's needed later on.
I quickly remembered how annoyingly opaque its errors are and have decided not to bother with it for future puzzles unless I absolutely need to.
I'll stick to regex and logos otherwise.
Rust - Nom Part 1
welp, I'm doing Google Sheets again because I have done fuck all to learn anything. I think I did it basically the same way as everyone else... ish.
Part 1
Part 2
Gasp! I forgot it was December 1. This is why I never get and sleep in December. Is anyone running a Tildes leaderboard?
Edit to add: Got the solutions, my repo is here: https://github.com/firstmustburn/aoc
I think I did something a little different than most people for part 2...
Part 2 spoilers
Unlike many of the solutions I've seen people post, I did not use regexes. I have a function that looks for a match at the beginning of the string and returns the remaining string if it finds one. I hit the problem that most people hit (overlapping number names), but it was a simple as tweaking the algorithm to only consume the first letter of the name when it matches on it, leaving the others to match for the second letter.
I made one
https://tildes.net/~comp/1cke/join_the_tildes_advent_of_code_leaderboard
The year went by so quick, but here we are again! As usual I am using Python:
Part 1
Part 2
Bonus: I wrote a little script so I don't have to remember how to write out these comments with
<details>
and all.tildes-aoc-comment.py
I started using Java since the last year, so this year I did them in Java. Other people have posted a repo, so here's mine: https://michaeleisemann.com/source/aoc23/browse/master/src/main/java/com/michaeleisemann/aoc23/services/
If other people have pointers about my somewhat rudimentary Spring Boot webapp layout, I would love feedback on that, too.
Everything I've done so far with Java has been spring boot, so my AoC this year is a web app using Spring Boot.
Java
I am doing the same thing (trying to force myself to use Go). It's hard because Python is just so fast and flexible. But my golang has improved enough this past year that I think I can complete it, even if I don't win any prizes for speed.
Once again, I'm doing it in Python: Repo Link
Part 1
This was pretty straightforward: just used a list comprehension to extract the digits.
Part 2
This was trickier than expected as you had to account for overlapping words such as
eightwo
. Fortunately, I only had to change myread_values
function.Part 2 (Update)
While showering, I thought of a way to make Part 2 more functional by using
map
to convert the words to digits before filtering as I did in Part 1:Part 2 was much trickier than I expected. As usual, here's my hacky AWK solutions.
Part 1
Part 2
After spotting the overlapping problem, I initially just decided to parse it from left to right for some reason. The worst part is that it worked perfectly for the sample but not for my input... made things a lot harder for myself.
What a tricky Day 1 compared to previous years! Plus, as somebody using this year to try and brush up a bit on my old beloved C, it feels like today's second part was designed to make me sad :( While I completed today, I didn't get the second star thanks to a misinterpretation that I hope that I'm not alone in having read: given the input
6eightwo
, my reading of the challenge led me to believe that the expected value therefor was 68, and not 62, and so that caused my final solution to be wrong. To change that I'd need to totally reïmplement, so I suppose that that's that.Anyway, as I haven't seen anybody else having a crack at C, I thought I'd post mine here!
Advent of Code Day 1 C implementation
```c #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <string.h>#define MAX_STR_LENGTH 128
// a lookup table of number spellings and numerals, grouped by spelling length
char* const DIGIT_NAMES[3][9][2] = {
{
{ "one", "1" },
{ "two", "2" },
{ "six", "6" },
}, {
{ "four", "4" },
{ "five", "5" },
{ "nine", "9" },
}, {
{ "three", "3" },
{. "seven", "7" },
{ "eight", "8" }
}
};
// replace a substring at a given index with another
void insertNumeral(char* srcString, int startIndex, int endIndex, char num) {
}
// pass through a given string, replacing spelled numbers with numerals
void sanitiseDigits(char* srcString) {
}
int main(int argc, char* argv[]) {
}
But you can still get a second star right? Even despite giving a wrong answer initially.
Absolutely.
You inspired me to take a crack at a C solution myself. It's pretty much a port of my Python solution, but I think it's pretty efficient? I'm not entirely sure, I'm not the most experienced with C.
Solution
As usual for me, I do my solutions in Common Lisp. Here's my code for today.
I started the problem at midnight EST and did more from the REPL than from writing and running functions. I accidentally submitted the wrong answer for part one twice in a row, so I ended up getting a recorded solution at 00:14 or so. The code linked above is a more formalized version of what I was typing by hand in the REPL.
My solution, as with many other peoples', involved regexes. So part two bit me, as with many others, by having overlapping digit names. My quick and dirty solution was to reverse all of the regex string except the
\d
, match against the reversed string, and then re-reverse the match for parsing.Rust
Rust
Decided to use Kotlin and see how far I get this year. I got tripped up on part 2 and had to switch from simple replacement to regex:
Here's my code in Rust. It's not particularly elegant (or fast, or good, or idiomatic, or...), but it gets the job done. I'm going on a work trip/vacation for the next 8 days so I probably won't be able to keep up but can't wait to come check out these threads after the fact.
I solved it with Typescript and Deno, using my aocd library for handling fetching the inputs and submitting answers. Part 1 was very straight forward by using a regex to remove all non-numeric characters from the line. Part 2 required me to throw that out and iterate character by character to see if it was a digit or was the position a digit's name started.
My first attempt at part 2 passed the test but failed on the real data because as an optimization I skipped to the end of the digit's name in the line when I recognized a digit's name, but it turns out some of the lines actually have the digit names overlapping, like in "eightwothree" where you're meant to read both "eight" and "two" despite them sharing a letter. I deleted the line I had that advanced
i
by the word's length and then my code worked fine.Typescript
Wrote about the first problem on my blog. Dunno if I can keep up lol.
First part I did with a text editor with regex, and then an Excel file.
Second part was tricky. I gave up on Excel and whipped out my trusty Python.
Invested time on a function that finds the first recognized digit then copy pasted that into the same function but with the relevant strings reversed.
More info here:
https://guissmo.com/blog/advent-of-code-2023-day-1/
I know what you meant, but .... if you got the answer with the second meaning of this phrase, that would be truly impressive. And yes, part of me apparently is still 12.
AoC is routinely my favorite event of the year. Day 1 had some fun edge cases, but nothing too crazy.
If anyone gets stuck (not necessarily today, but at some point in here), I'll be posting explanations of each puzzle and my Python solution on my website: https://advent-of-code.xavd.id/writeups/2023/day/1/
Should be a fun year!
I'm trying out Guile Scheme, this year.
Didn't get to it yesterday, sadly, but such is life.
I wrote a "utils.scm" library, to do things I'll have to do over and over again:
utils.scm
For now, it's just a function that reads in the input-file line by line, hands back a list of lines.
Part 1
Nothing particularly fancy, just regex-ing it.
Second part was, as everyone already mentioned, a bit trickier.
Still regex-ing it, though.
Part 2
The solutions don't feel particularly... scheme-y, but then again, I don't know what that would feel like, exactly. xD
Elixir
Breaking out the binary pattern matching on day 1, hoo-wee ðŸ¤
Parts 1 and 2
I got tripped up by the fact that spelled-out digits can overlap in part 2. At first, I had my code jump ahead by
length(digit_string)
every time I found one, so I was missing any spelled-out digits that started within that first one. Annoyingly, this issue only came up in the real puzzle input and not the examples.P.S. This is the cleaned up version of my solution—my initial code was a big ol' mess
Edit
Shorter and (in certain cases) faster solution
I realized you don't need to search through the entirety of each line—you can look for the first digit from the left end and the first digit from the right end, and potentially skip a large amount of text in the middle of the line.
Seems like the Erlang VM is optimized for parsing through binary data from left to right though, so even though this does "less work" by stopping as soon as it finds a digit on either end, instead of always iterating through the whole line, the code that works backward from the end of the string tends to run slowly enough to almost cancel out the benefit. In fact, part 1 now runs a few hundred μs slower!
However I still like this approach better because it's a bit easier to understand what the code is doing.
Rust, with the aim being pure speed - my repo is here.
According to Criterion, on a Macbook Pro with M2, I'm getting around 18 µs for part one, and 28 µs for part two, which I'm fairly happy with.
Notes
I started by just parsing all the values I could see and then returning the first and last ones, which seems to be a common solution. (I also got stuck on the overlapping numbers issue and was really confused for a long time why all my tests were working but the main solution kept on showing up as wrong. The subreddit definitely helped today! 😅)Then I realised I didn't need to do all that parsing, and it was only the first and last numbers that were interesting, which meant I could skip all the overlapping stuff, and made the parsing a lot easier, although I did end up needing to do it twice to handle the forwards case and the backwards case.
If I were going to improve this, I'd probably look at the regex crate, or better yet some of its internals. The full power of regex is probably overkill in this situation, but Burntsushi knows his way around string matching, so maybe there's something there that'll handle the parsing better. But I think I'm happy for now.
My Rust solution. Seems that many people are advocating that the intended solution is you stop scanning once you hit the first number, and I should've done that instead of find & replace approach that I did. It might be even simplier. The Rust code also have a bug that it should've use
is_digit(10)
instead ofis_numeric()
which make the app crash when encountering non-ascii number.Maybe I'll try different language tomorrow.
Back to Ruby for this year, I want to see if I can get further this time than I have the last couple.
Day 1 - Ruby
Should've posted this earlier, but I didn't realize there was a thread here. We're certainly off to a tricky start this year - I was hoping for a leaderboard spot, but was a couple minutes off for part 1 and even further away for part 2. Enjoyable problem, though! Looking forward to tonight's.
Solution
This is my first year doing AoC after hearing about it from coworkers for a while. Curious to see how long I can stick with it! Here's my Elixir solution for part 2.
Day 1 - Elixir
Part 1 was straight forward, but had to rely on a really hacky solution for day 2. Doing it in rust again this year, its the language that I find fun.
https://github.com/gabevenberg/advent-of-code-2023
Always running behind on these. 19 loc in F# for part 1. Didn't want to use regex because I suck at it and I like to future proof against part 2 which sometimes is much harder to do in regex.
Part 1
Part 2
I'm already behind, but got Part 1 done in Bash. An arbitrary goal I've set is pure GNU/Bash, since bash is fairly limited in what it can do, but has fairly robust logic. I used sed and awk for this, for example, to extract the data, and the arithmetic was fairly simple to get work, like any other language.
Part 1
````bash#!/bin/bash
INPUT=$(sed ./input.txt -e 's/[a-z]//g' | awk '{print substr($0,0,1) substr($0,length($0),1)}')
declare -a NUMS=()
NUM=0
#echo -e "$INPUT"
for LINE in $INPUT; do
#echo $LINE
let NUM+=$LINE
done
echo "$NUM"