We use some essential cookies to make our website work.

We use optional cookies, as detailed in our cookie policy, to remember your settings and understand how you use our website.

ejolson
Posts: 13950
Joined: Tue Mar 18, 2014 11:47 am

Advent of Code 2025

Sat Nov 29, 2025 7:43 pm

ejolson wrote:
Wed May 07, 2025 5:18 pm
Looking through the forum there have been threads for Advent of Code starting in 2020.

viewtopic.php?t=293084

viewtopic.php?t=325236

viewtopic.php?t=343515

viewtopic.php?t=360011

viewtopic.php?t=380295
This is a thread to discuss solutions to Advent of Code 2025. As mentioned in

viewtopic.php?p=2347868#p2347868

there will only be twelve puzzles to pass the time until Christmas this year. That is good because other years I nearly missed Christmas on account of still working the puzzles.

Speaking of missing things, that Raspberry Pi 5 from last Christmas is still not a NAS and I just missed a sale for 24 TB hard disks. Fortunately, the Pi 5 is currently nailed to a piece of wood, running off the Pi 4 power supply and ready for the code produced by Scratchy, Purr, Shy and myself.

I'll miss Fido this Advent.

Is anyone else planning to do Advent of Code with a Raspberry Pi this year?

ejolson
Posts: 13950
Joined: Tue Mar 18, 2014 11:47 am

Re: Advent of Code 2025

Sun Nov 30, 2025 5:13 am

ejolson wrote:
Sat Nov 29, 2025 7:43 pm
Fortunately, the Pi 5 is currently nailed to a piece of wood, running off the Pi 4 power supply and ready for the code produced by Scratchy, Purr, Shy and myself.
The hardware is ready. There are 24 hours before the first puzzle unlocks, so I thought I'd check the software. Software is always more difficult.

Scratchy suggested doing the puzzles in C. Purr blinked but Shy was too shy to blink.

That's great, I said, then everything is ready to go. At this Purr pounced on Scratchy who fell off the cat tree onto Shy who started to mew.

I think some additional software will be required.

ejolson
Posts: 13950
Joined: Tue Mar 18, 2014 11:47 am

Re: Advent of Code 2025

Sun Nov 30, 2025 6:17 pm

ejolson wrote:
Sun Nov 30, 2025 5:13 am
I think some additional software will be required.
Shy looked shyly up from underneath the pileup of kittens and mewed shyly, IBM Fortran G, Microsoft Power Automate and Kotlin?

Those were hard choices, but after what happened I felt compelled to agree. Although Fortran G runs only on System/360 mainframes, Hercules runs on a Pi and can emulate 50-year-old hardware.

After reflecting on the likely outcome of a chatbot powered code review, I questioned a lack of string handling. Shy crawled out from under the other kittens and looked shyly at the ground, clearly thinking about four-character Hollerith constants lovingly stored in 32-bit integer variables.

As Power Automate is an expensive software-as-a-service low-code solution, I suggested Kotlin. At this Shy happily rolled on the ground feet kicking into the air. If the Java virtual machine is too slow can I switch to Fortran? Suddenly I felt shy.

I hope Purr asks for a language easily installed by an operating system package.

ejolson
Posts: 13950
Joined: Tue Mar 18, 2014 11:47 am

Re: Advent of Code 2025

Sun Nov 30, 2025 8:01 pm

ejolson wrote:
Sun Nov 30, 2025 6:17 pm
ejolson wrote:
Sun Nov 30, 2025 5:13 am
I think some additional software will be required.
I hope Purr asks for a language easily installed by an operating system package.
Purr obviously did not think C was purrfect.

Rather than wait for another impractical request, I decided to negotiate. That constant purring must have distracted me from the danger.

There's a nice kitty, I began, how about Rust. Purr blinked, continued purring and replied Hare.

Image
https://harelang.org/

It looked interesting, especially as it does not use the LLVM or GCC backends. However, I suspected an ulterior motive and feared for that cute bunny.

Excellent choice I continued, I think Free Pascal is similar and the mascot is a cat like you.

Image
https://www.freepascal.org/

The purring stopped and Purr blinked again.

I tried one more time. How about Go?

Image
https://go.dev/

Luckily Purr started purring again. The kitten went on for a time and then replied Swift.

Image
https://www.swift.org/

I should have known kittens would be attracted to birds. I worried that the next choice would have a seafood mascot, but then remembered my first suggestion had been Rust.

Considering how much trouble there was building the Swift runtime a few years ago, Hare started to look more reasonable. So I gave in.

I wonder what the chatbots will say about Hare in the code reviews.
Last edited by ejolson on Mon Dec 01, 2025 12:27 am, edited 3 times in total.

ejolson
Posts: 13950
Joined: Tue Mar 18, 2014 11:47 am

Re: Advent of Code 2025

Mon Dec 01, 2025 12:02 am

ejolson wrote:
Sun Nov 30, 2025 8:01 pm
I reflected on the moral "hare today goon tomorrow" and gave in.
With only 5 hours before the first puzzle opens
I worked on bootstrapping Hare from source while the kittens played a game and sang:

Little bunny Foo Foo
hopping through the datacenter,
scooping up the computer mice
and clicking them on the buttons.

Out came the Unix greybeard who said,
little bunny Foo Foo I don't want to see you
scooping up the computer mice
and clicking them on the buttons.
I'll give you three more chances
and then compile you into a goon.

Little bunny Foo Foo
hopping through the datacenter,
scooping up the computer mice
and clicking them on the buttons.

Out came the Unix greybeard who said,
little bunny Foo Foo I don't want to see you
scooping up the computer mice
and clicking them on the buttons.
I'll give you two more chances
and then compile you into a goon.

Little bunny Foo Foo
hopping through the datacenter,
scooping up the computer mice
and clicking them on the buttons.

Out came the Unix greybeard who said,
little bunny Foo Foo I don't want to see you
scooping up the computer mice
and clicking them on the buttons.
I'll give you one more chance
and then compile you into a goon.

Little bunny Foo Foo
hopping through the datacenter,
scooping up the computer mice
and clicking them on the buttons.

Out came the Unix greybeard who said,
that was your last chance.
The greybeard logged into a terminal and said,
now I'll compile you into a goon.
And the moral of the story is
Hare today goon tomorrow.

During the above commotion I managed to identify the QBE backend was generating AMD64 rather than ARM64 assembly and fixed it. Not counting the debugging, a full bootstrap of the compiler and runtime using the packaged version of QBE took less than a minute on the Pi 5.

After installing Hare today, next up is Kotlin.
Last edited by ejolson on Tue Dec 02, 2025 7:16 pm, edited 3 times in total.

ejolson
Posts: 13950
Joined: Tue Mar 18, 2014 11:47 am

Re: Advent of Code 2025

Mon Dec 01, 2025 5:17 am

ejolson wrote:
Mon Dec 01, 2025 12:02 am
Next up is Kotlin.
Kotlin was even easier. All I did was download version 2.2.21 from

https://github.com/JetBrains/kotlin/releases

unzip it into /usr/local and create links from /usr/local/kotlinc/bin to /usr/local/bin. It just worked after that. Moreover, Shy seems very happy.

I now have templates in C, Kotlin, Hare and Go which do nothing

Code: Select all

Advent of Code 2025 Day 1 (c)
Total execution time 1.11e-07 seconds.
when run. The sizes of each executable

Code: Select all

-rwxr-xr-x 1 ejolson users 74160 Dec 1 05:13 day01-c
-rwxr-xr-x 1 ejolson users 2298509 Dec 1 05:13 day01-go
-rwxr-xr-x 1 ejolson users 841616 Dec 1 05:12 day01-ha
-rw-r--r-- 1 ejolson users 5125643 Dec 1 05:13 day01.jar
span almost 2 decimal orders of magnitude.

The day 1 puzzle has opened, but the mice are nonfunctional after the singing and everyone is tired. I'll post solutions as they come in.

Has anyone else started?
Last edited by ejolson on Mon Dec 01, 2025 10:52 am, edited 1 time in total.

ejolson
Posts: 13950
Joined: Tue Mar 18, 2014 11:47 am

Re: Advent of Code 2025

Mon Dec 01, 2025 10:10 am

ejolson wrote:
Mon Dec 01, 2025 5:17 am
The day 1 puzzle has opened, but the mice are nonfunctional after the singing and everyone is tired. I'll post solutions as they come in.
Scratchy finished first, but admittedly needed 6 tries to get the right answer to part 2.

Code: Select all

$ ./day01-c
Advent of Code 2025 Day 1 Secret Entrance (c)
Part 1 The actual password is 997
Part 2 Following method 0x434C49434B gives 5978
Total execution time 0.000571019 seconds.
For reference the code was

Code: Select all

/* Advent of Code 2025 Day 1 Secret Entrance (c)
 Written December 2025 by Eric Olson */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
static struct timespec tic_start;
void tic(){
 clock_gettime(CLOCK_MONOTONIC_RAW,&tic_start);
}
double toc(){
 struct timespec tic_stop;
 clock_gettime(CLOCK_MONOTONIC_RAW,&tic_stop);
 double sec=tic_stop.tv_sec-tic_start.tv_sec;
 return sec+(tic_stop.tv_nsec-tic_start.tv_nsec)*1.0e-9;
}
void dowork(){
 FILE *fp=fopen("day01.txt","r");
 int p1=0,p2=0;
 int d=50;
 while(!feof(fp)){
 char c; int x;
 if(fscanf(fp,"%c%d\n",&c,&x)!=2) break;
 int r;
 switch(c){
case 'L':
 if(d>0){
 d-=x;
 r=(100-d)/100;
 } else {
 d-=x;
 r=-d/100;
 }
 d=(d%100+100)%100;
 break;
case 'R':
 d+=x;
 r=d/100;
 d%=100;
 break;
default:
 fprintf(stderr,"Unknown direction %c!\n",c);
 exit(1);
 }
 if(d==0) p1++;
 p2+=r;
 }
 fclose(fp);
 printf("Part 1 The actual password is %d\n",p1);
 printf("Part 2 Following method 0x434C49434B gives %d\n",p2);
}
int main(){
 printf("Advent of Code 2025 Day 1 Secret Entrance (c)\n\n");
 tic();
 dowork();
 double t=toc();
 printf("\nTotal execution time %g seconds.\n",t);
 exit(0);
} 
Purr and Shy are still sleeping. I've got an idea to remove the conditional in the loop, but sleeping seems like the better idea.

ejolson
Posts: 13950
Joined: Tue Mar 18, 2014 11:47 am

Re: Advent of Code 2025

Mon Dec 01, 2025 12:52 pm

ejolson wrote:
Mon Dec 01, 2025 10:10 am
I've got an idea to remove the conditional in the loop, but sleeping seems like the better idea.
I couldn't sleep because my nose is plugged, so I finished the Go template.

Code: Select all

$ ./day01-go # Pi 
Advent of Code Day 01 (go)
Part 1 The actual password is 997
Part 2 Following method 0x434C49434B gives 5978
Total execution time 0.00258147 seconds.
The runtime is 4.5 times slower than C.

The code is

Code: Select all

/* Advent of Code 2025 Day 01 Secret Entrance (go)
 Written December 2025 by Eric Olson */
package main
import("fmt"; "os"; "time"; "bufio")
var tictime time.Time
func tic(){
 tictime=time.Now()
}
func toc() float64 {
 now:=time.Now()
 elapsed:=now.Sub(tictime)
 return elapsed.Seconds()
}
func dowork(){
 fd,err:=os.Open("day01.txt")
 if err!=nil {
 fmt.Fprintf(os.Stderr,"Unable to open file input file!\n")
 os.Exit(0)
 }
 defer fd.Close()
 fp:=bufio.NewReader(fd)
 p1:=0; p2:=0; d:=50
 for {
 var (c rune; x int)
 r,err:=fmt.Fscanf(fp,"%c%d\n",&c,&x)
 if r!=2||err!=nil { break }
 switch c {
case 'L':
 d=(d-100)%100
 d-=x
 r=-d/100
case 'R':
 d=(d+100)%100
 d+=x
 r=d/100
default:
 fmt.Fprintf(os.Stderr,"Unknown direction %c!\n",c)
 os.Exit(1)
 }
 d%=100
 if d==0 { p1++ }
 p2+=r
 }
 fmt.Printf("Part 1 The actual password is %d\n",p1);
 fmt.Printf("Part 2 Following method 0x434C49434B gives %d\n",p2);
}
func main(){
 fmt.Printf("Advent of Code Day 01 Secret Entrance (go)\n\n")
 tic()
 dowork()
 t:=toc()
 fmt.Printf("\nTotal execution time %.6g seconds.\n",t)
 os.Exit(0)
}
I copied Scratchy's program but made the cases between the left and right more symmetric.

Surprisingly, it is not possible to write

Code: Select all

 p1+=int(d==0)
to increment p1 when d is equal to zero. Go allows one to index an array using a bool datatype with the meaning false=0 and true=1 but does not allow one to cast a bool to an integer type directly. Every time I use Go something annoying happens. However, bounds checking with stack traces are useful when debugging.

I thought about trying zig

https://ziglang.org/

but it looked like too much syntax.

RogerW
Posts: 439
Joined: Sat Dec 20, 2014 12:15 pm

Re: Advent of Code 2025

Mon Dec 01, 2025 3:16 pm

My version is a bit more long winded but got me two starrs.

Code: Select all

#include <iostream>
#include <chrono>
#include <fstream>
int main()
{
 // file must not have blank line at end
 const char* filename = "data.txt";
 std::chrono::time_point<std::chrono::system_clock> start,stop;
 start = std::chrono::system_clock::now();
 std::cout << "Advent of code 2025 day 1" << "\n";
 std::ifstream file(filename);
 int dial = 50; // dial position
 const int num = 100; // number of dial positions
 int part1 = 0; // answer fo part 1
 int extras = 0; // extras due to "method 0x434C49434B"
 if(file)
 {
 while(!file.eof())
 {
 int i;
 char c;
 file >> c >> i;
 // i maybe > 100
 int turns = i / num;
 if(turns)
 {
 extras += turns;
 i -= num * turns;
 }
 // do not bump extras if dial is zero before or after change
 bool doextras = (dial != 0);
 // move the dial
 if(c == 'R')
 {
 dial += i;
 if(dial > num - 1)
 {
 dial -= num ;
 if(doextras && dial)
 extras++;
 }
 }
 else
 {
 dial -= i;
 if(dial < 0)
 {
 dial += num;
 if(doextras && dial)
 extras++;
 }
 }
 if(dial == 0)
 part1 += 1;
 }
 }
 std::cout << "Part 1 " << part1 << "\n";
 std::cout << "Part 2 " << part1 + extras << "\n";
 stop = std::chrono::system_clock::now();
 std::chrono::duration<double> elapsed = stop - start;
 std::cout << "Elapsed time " << elapsed.count() << " seconds" << "\n";
 return 0;
}

ejolson
Posts: 13950
Joined: Tue Mar 18, 2014 11:47 am

Re: Advent of Code 2025

Mon Dec 01, 2025 7:41 pm

RogerW wrote:
Mon Dec 01, 2025 3:16 pm
My version is a bit more long winded but got me two starrs.
Woohoo! Welcome to the party!

I think it's interesting how you avoided using the % modulo operator.

Purr just finished the Hare solution:

Code: Select all

$ ./day01-ha # Pi 5
Advent of Code 2025 Day 01 Secret Entrance (ha)
Part 1 The actual password is 997
Part 2 Following method 0x434C49434B gives 5978
Total execution time 2.07877e-3 seconds.
The program was

Code: Select all

// Advent of Code 2025 Day 1 Secret Entrance (ha)
// Written December 2025 by Eric Olson
use fmt;
use os;
use time;
use io;
use bufio;
use types;
use strconv;
use strings;
use fs;
let tic_start:time::instant=time::INSTANT_ZERO;
fn tic() void = {
 tic_start=time::now(time::clock::MONOTONIC);
};
fn toc() f64 = {
 const tic_stop=time::now(time::clock::MONOTONIC);
 return time::diff(tic_start,tic_stop):f64*1e-9;
};
// Routine read_file generated by Claude from the prompt
//
// I am writing a program in the Hare programming language and
// want to read a text file line by line. The file consists
// of natural numbers with a prefix 'L' or 'R' that indicates
// whether the number following should be counted as positive
// or negative. 'L' means negative and 'R' means positive. Could
// you write a routine to read the file day01.txt and store the
// resulting signed integers in an array? The routine should
// handle all errors internally by printing an error message and
// exiting with an appropriate error code, rather than returning
// error types to the caller.
//
// plus lots of back and forth to fix errors.
//
fn read_file(path: str) []int = {
 // Open the file
 const file = match (os::open(path)) {
 case let f: io::file =>
 yield f;
 case let err: fs::error =>
 fmt::fatalf("Error opening file: {}", fs::strerror(err));
 };
 defer io::close(file)!;
 // Create buffered reader
 const scanner = bufio::newscanner(file, types::SIZE_MAX);
 defer bufio::finish(&scanner);
 // Dynamic array to store results
 let numbers: []int = [];
 for (true) {
 const line = match (bufio::scan_line(&scanner)) {
 case io::EOF =>
 break;
 case let err: io::error =>
 fmt::fatalf("Error reading file: {}", io::strerror(err));
 case let line: const str =>
 yield line;
 };
 // Skip empty lines
 if (len(line) == 0) {
 continue;
 };
 // Parse the line
 const prefix = strings::sub(line, 0, 1);
 const num_str = strings::sub(line, 1, strings::end);
 // Parse the number
 const num = match (strconv::stoi(num_str)) {
 case let n: int =>
 yield n;
 case =>
 fmt::fatalf("Error parsing number: '{}'", num_str);
 };
 // Apply sign based on prefix
 const signed_num = switch (prefix) {
 case "L" =>
 yield -num;
 case "R" =>
 yield num;
 case =>
 fmt::fatalf("Invalid prefix '{}' on line: {}", prefix, line);
 };
 match (append(numbers, signed_num)) {
 case void =>
 yield;
 case =>
 fmt::fatalf("Error: Out of memory");
 };
 };
 return numbers;
};
fn part1(numbers: []int) int = {
 let p1 = 0, dial = 50;
 for (let i = 0z; i < len(numbers); i += 1) {
 dial = (dial+numbers[i])%100;
 if (dial==0) p1 += 1;
 };
 return p1;
};
fn part2(numbers: []int) int = {
 let p2 = 0, dial = 50;
 for (let i = 0z; i < len(numbers); i += 1) {
 if (numbers[i]<0) {
 dial = (dial-100)%100 + numbers[i];
 p2 += -dial/100;
 } else {
 dial = (dial+100)%100 + numbers[i];
 p2 += dial/100;
 };
 dial %= 100;
 };
 return p2;
};
fn dowork() void = {
 const numbers = read_file("day01.txt");
 const p1 = part1(numbers);
 fmt::printfln("Part 1 The actual password is {}",p1)!;
 const p2 = part2(numbers);
 fmt::printfln("Part 2 Following method 0x434C49434B gives {}",p2)!;
 free(numbers);
};
export fn main() void = {
 fmt::print("Advent of Code 2025 Day 01 Secret Entrance (ha)\n\n")!;
 tic();
 dowork();
 const t = toc();
 fmt::printf("\nTotal execution time {:.6g} seconds.\n",t)!;
 os::exit(0);
};
The read_file routine was generated by Claude after quite a bit of back and forth. Sometimes Claude would write comments and sometimes not. Code generation was not fully syntactical, perhaps due to lack of training data.

For example, the line

Code: Select all

 const prefix = strings::sub(line, 0, 1);
originally appeared as

Code: Select all

 const prefix = line[0];
which doesn't parse because strings are not arrays. Surprisingly, Claude had difficulty finding a simple work around even though strings::sub was used on the following line.

Shy looked at the all the semicolons and shyly asked, did the rabbit leave those?
Last edited by ejolson on Tue Dec 02, 2025 12:52 am, edited 1 time in total.

ejolson
Posts: 13950
Joined: Tue Mar 18, 2014 11:47 am

Re: Advent of Code 2025

Mon Dec 01, 2025 9:19 pm

ejolson wrote:
Mon Dec 01, 2025 12:52 pm
I thought about trying zig

https://ziglang.org/

but it looked like too much syntax.
Avoiding zig was a fortunate accident as it's on the list of software incompatible with the 16K kernel page size used by Raspberry Pi OS on the Pi 5.

viewtopic.php?p=2351173#p2351173

In other news, the kitten named Shy is working on a solution to Day 1 in Kotlin. As coding assistants seem popular, I'm expecting a request for IntelliJ IDEA as soon as the mice are fixed.
Last edited by ejolson on Tue Dec 02, 2025 6:32 pm, edited 2 times in total.

ejolson
Posts: 13950
Joined: Tue Mar 18, 2014 11:47 am

Re: Advent of Code 2025

Mon Dec 01, 2025 9:54 pm

ejolson wrote:
Mon Dec 01, 2025 9:19 pm
ejolson wrote:
Mon Dec 01, 2025 12:52 pm
I thought about trying zig

https://ziglang.org/

but it looked like too much syntax.
Avoiding zig was a fortunate accident as it's on the list of software incompatible with the 16K kernel page size used by Raspberry Pi OS on the Pi 5.

viewtopic.php?p=2351173#p2351173

In other news, the kitten named Shy is now working on a solution to Day 1 in Kotlin. As AI coding assistants seem popular, I'm expecting a request for IntelliJ IDEA as soon as the mice are fixed.
Shy shyly mewed the puzzle is done.

Code: Select all

$ ./day01-kt # Pi 5
Advent of Code 2025 Day 01 (kt)
Part 1 The actual password is 997
Part 2 Following method 0x434C49434B gives 5978
Total execution time 0.0553859 seconds.
Here day01-kt is a shell script containing

Code: Select all

#!/bin/bash
exec java -jar day01.jar "$@"
and the code is

Code: Select all

/* Advent of Code 2025 Day 01 Secret Entrance (kt)
 Written December 2025 by Eric Olson */
import java.io.File
var tic_time=0.0
fun tic() {
 tic_time=System.nanoTime()*1e-9
}
fun toc(): Double {
 return System.nanoTime()*1e-9-tic_time
}
fun dowork(){
 val data=File("day01.txt").readLines()
 var p1=0; var p2=0; var d=50
 for(s in data){
 val x=s.substring(1).toInt()
 when(s[0]){
 'R'->{
 d=(d+100)%100+x
 p2+=d/100
 }
 'L'->{
 d=(d-100)%100-x
 p2-=d/100
 }
 }
 d%=100
 if(d==0) p1++
 }
 println("Part 1 The actual password is %d".format(p1))
 println("Part 2 Following method 0x434C49434B gives %d".format(p2))
 return
}
fun main(){
 print("Advent of Code 2025 Day 01 (kt)\n\n")
 tic()
 dowork()
 var t=toc()
 println("\nTotal execution time %.6g seconds.\n".format(t))
 return
}
Shy hid under the cat tree waiting. I didn't see any AI generated code, but the arithmetic looked similar to what I wrote in Go. The next post will compare the solutions.

ejolson
Posts: 13950
Joined: Tue Mar 18, 2014 11:47 am

Re: Advent of Code 2025

Mon Dec 01, 2025 10:40 pm

ejolson wrote:
Mon Dec 01, 2025 7:41 pm
RogerW wrote:
Mon Dec 01, 2025 3:16 pm
My version is a bit more long winded but got me two starrs.
Woohoo! Welcome to the party! I think it's interesting how you avoided using the % modulo operator.
I fixed the difficulty with a trailing newline in the input file by changing

Code: Select all

 file >> c >> i;
to

Code: Select all

 if(!(file >> c >> i)) break;
After this I obtain

Code: Select all

$ ./day01-cpp
Advent of code 2025 day 1
Part 1 997
Part 2 5978
Elapsed time 0.000432798 seconds
for my input which is correct and faster than any of the other runtimes so far.

Scratchy meowed, include the C++ code with the others. I wasn't sure. Purr purred, it's perfect. Shy still hid under the cat tree. If it were big enough, I'd hide under there too.

ejolson
Posts: 13950
Joined: Tue Mar 18, 2014 11:47 am

Re: Advent of Code 2025

Mon Dec 01, 2025 10:48 pm

ejolson wrote:
Mon Dec 01, 2025 10:40 pm
If it were big enough, I'd hide under there too.
Before moving on to a chatbot-powered code review, here are some quantitative results:

Compile times are

Code: Select all

$ for i in day01-ha day01-kt day01-go day01-c day01-cpp
 do time make $i
 done
hare build -o day01-ha day01.ha
real 0m0.046s
user 0m0.034s
sys 0m0.012s
kotlinc day01.kt -include-runtime -d day01.jar
./mkjarun day01.jar
real 0m7.396s
user 0m15.800s
sys 0m0.654s
go build -o day01-go day01.go
real 0m0.180s
user 0m0.227s
sys 0m0.044s
gcc -O2 -Wall -fwrapv -o day01-c day01.c
real 0m0.091s
user 0m0.061s
sys 0m0.030s
g++ -O2 -Wall -fwrapv -o day01-cpp day01.cpp
real 0m0.691s
user 0m0.625s
sys 0m0.065s
where the Makefile was given by

Code: Select all

.SUFFIXES: .ha .jar .kt
TARGETS=day01-ha day01-kt day01-go day01-c day01-cpp
all: $(TARGETS)
clean:
	rm -f $(TARGETS)
	rm -f *.jar
%-go: %.go
	go build -o $@ $<
%-c: %.c
	gcc -O2 -Wall -fwrapv -o $@ $<
%-cpp: %.cpp
	g++ -O2 -Wall -fwrapv -o $@ $<
%-ha: %.ha
	hare build -o $@ $<
%-kt: %.kt
	kotlinc $< -include-runtime -d $*.jar
	./mkjarun $*.jar
and I typed "make clean" then "make" followed by "make clean" to prime the cache before timing.

Sizes of the source codes are

Code: Select all

$ wc day01.ha day01.kt day01.go day01.c day01.cpp
 142 531 3928 day01.ha
 44 98 974 day01.kt
 59 134 1311 day01.go
 62 127 1447 day01.c
 77 230 1932 day01.cpp
 384 1120 9592 total
The sizes of the executables are

Code: Select all

$ ls -l day01-ha day01.jar day01-go day01-c day01-cpp
-rwxr-xr-x 1 ejolson users 74440 Dec 1 22:21 day01-c
-rwxr-xr-x 1 ejolson users 74856 Dec 1 22:21 day01-cpp
-rwxr-xr-x 1 ejolson users 2479193 Dec 1 22:21 day01-go
-rwxr-xr-x 1 ejolson users 850128 Dec 1 22:21 day01-ha
-rw-r--r-- 1 ejolson users 5126318 Dec 1 22:21 day01.jar
The speeds of execution were

Code: Select all

$ for i in day01-ha day01-kt day01-go day01-c day01-cpp
 do time ./$i
 done
Advent of Code 2025 Day 01 Secret Entrance (ha)
Part 1 The actual password is 997
Part 2 Following method 0x434C49434B gives 5978
Total execution time 2.10695e-3 seconds.
real 0m0.003s
user 0m0.003s
sys 0m0.000s
Advent of Code 2025 Day 01 (kt)
Part 1 The actual password is 997
Part 2 Following method 0x434C49434B gives 5978
Total execution time 0.0539526 seconds.
real 0m0.152s
user 0m0.184s
sys 0m0.032s
Advent of Code Day 01 Secret Entrance (go)
Part 1 The actual password is 997
Part 2 Following method 0x434C49434B gives 5978
Total execution time 0.00256284 seconds.
real 0m0.004s
user 0m0.000s
sys 0m0.004s
Advent of Code 2025 Day 1 Secret Entrance (c)
Part 1 The actual password is 997
Part 2 Following method 0x434C49434B gives 5978
Total execution time 0.00057187 seconds.
real 0m0.001s
user 0m0.001s
sys 0m0.000s
Advent of code 2025 day 1
Part 1 997
Part 2 5978
Elapsed time 0.000433001 seconds
real 0m0.002s
user 0m0.002s
sys 0m0.000s
Scratchy yowled, where are the graphs? That's a good idea, I replied, who will volunteer?

Purr silently climbed down from top of the cat tree and hid where Shy was hiding.

ejolson
Posts: 13950
Joined: Tue Mar 18, 2014 11:47 am

Re: Advent of Code 2025

Tue Dec 02, 2025 2:55 am

ejolson wrote:
Mon Dec 01, 2025 10:48 pm
ejolson wrote:
Mon Dec 01, 2025 10:40 pm
If it were big enough, I'd hide under there too.
Before moving on to a chatbot-powered code review, here are some quantitative results:
In graph form the results from the Pi 5 are

Image

Note that the first two groups of bar charts are measured in seconds on the left while the last two are keyed to bytes on the right. With respect to runtime the Hare and Go results are friends, the C and C++ results are friends but Kotlin is too shy to have any friends. I wonder if things will change when solving a more complicated puzzle.
Last edited by ejolson on Wed Dec 03, 2025 5:24 am, edited 2 times in total.

RogerW
Posts: 439
Joined: Sat Dec 20, 2014 12:15 pm

Re: Advent of Code 2025

Tue Dec 02, 2025 9:40 am

>> Woohoo! Welcome to the party! I think it's interesting how you avoided using the % modulo operator.

I did use it for part 1 but then I needed the number of full revolutions for part 2 so kept it simple.
I have used a similar solution to the end of file problem in the past. I now just use mousepad to write the data files because that does not insist on adding a newline at the end.

Glad you found it quick.

ejolson
Posts: 13950
Joined: Tue Mar 18, 2014 11:47 am

Re: Advent of Code 2025

Tue Dec 02, 2025 5:48 pm

ejolson wrote:
Tue Dec 02, 2025 2:55 am
Kotlin is too shy to have any friends.
The problem with being Shy meowed the kitten programming in Kotlin is you end up with too many friends. I looked and all the kittens were crowded together under the cat tree hiding.

They began to sing:

Three little kittens
with coding were smitten
and they began to cry.
Oh greybeard dear we greatly fear
our program we did erase.
Meow, meow, meow, me-ow.

What naughty kittens
to lose what you've written,
the greybeard did reply.
Meow, meow, meow, me-ow.
No more Raspberry Pi.

Then three little kittens
they looked for a smidgeon
a thumb drive they did spy.
Oh greybeard dear look here look here
a backup we did find.
Meow, meow, meow, me-ow.

What clever kittens
to save what you've written,
the greybeard gave a sigh.
Meow, meow, meow, me-ow.
Have some Raspberry Pi.

Then three little kittens
restored what they'd written
and powered up the Pi.
Oh greybeard dear it does appear
our program has a bug.
Meow, meow, meow, me-ow.

What naughty kittens
you saved the wrong version,
the greybeard swatted a fly.
Meow, meow, meow, me-ow.
No more bugs there did lie.

Then three little kittens
ran the code they'd written
on the Raspberry Pi.
Oh greybeard dear they gave a cheer
our program now does work.
Meow, meow, meow, me-ow.

What good little kittens...

At that point I sneezed and the singing stopped. It seems my cold is worse. Aside from the song, no progress has been made on Day 2.
Last edited by ejolson on Thu Dec 04, 2025 6:20 pm, edited 4 times in total.

jalih
Posts: 287
Joined: Mon Apr 15, 2019 3:54 pm

Re: Advent of Code 2025

Tue Dec 02, 2025 8:45 pm

ejolson wrote:
Tue Dec 02, 2025 5:48 pm
At that point I sneezed and the singing stopped. It seems my cold is worse. Aside from the song, no progress has been made on Day 2.
I wrote a simple brute force solution for Day 2 Part 1 using 8th programming language:

Code: Select all

"2.txt" f:slurp ( "," s:/ ( "-" s:/ ' >n a:map ) a:map ) s:eachline constant ranges 
a:new ( >s dup s:+ >n a:push ) 1 99999 loop constant doubles
: app:main
 ranges ( >r doubles ( r@ a:open n:between ) a:filter rdrop ) a:map a:squash
 ' n:+ 0 a:reduce . cr ;
 

ejolson
Posts: 13950
Joined: Tue Mar 18, 2014 11:47 am

Re: Advent of Code 2025

Wed Dec 03, 2025 3:33 am

jalih wrote:
Tue Dec 02, 2025 8:45 pm
ejolson wrote:
Tue Dec 02, 2025 5:48 pm
At that point I sneezed and the singing stopped. It seems my cold is worse. Aside from the song, no progress has been made on Day 2.
I wrote a simple brute force solution for Day 2 Part 1 using 8th programming language:

Code: Select all

"2.txt" f:slurp ( "," s:/ ( "-" s:/ ' >n a:map ) a:map ) s:eachline constant ranges 
a:new ( >s dup s:+ >n a:push ) 1 99999 loop constant doubles
: app:main
 ranges ( >r doubles ( r@ a:open n:between ) a:filter rdrop ) a:map a:squash
 ' n:+ 0 a:reduce . cr ;
 
I always find it amazing how concise 8th code is compared to what I'm used to.

I now have one star for Day 2.

Part 2 seems similar except I have to refactor (of course) and avoid double counting.

ejolson
Posts: 13950
Joined: Tue Mar 18, 2014 11:47 am

Re: Advent of Code 2025

Wed Dec 03, 2025 5:17 am

ejolson wrote:
Tue Dec 02, 2025 5:48 pm
I looked and all the kittens were crowded together under the cat tree hiding.
Purr was asleep. Scratchy was asleep. But the last kitten was awake. However, instead of working on the puzzle which just opened, Shy was watching television. Luckily, before saying something snarky I noticed it was the Advent of Code channel

https://blog.jetbrains.com/kotlin/2025/ ... tlin-2025/

Now I understand why Shy asked for Kotlin.

jalih
Posts: 287
Joined: Mon Apr 15, 2019 3:54 pm

Re: Advent of Code 2025

Wed Dec 03, 2025 12:49 pm

Here is a simple 8th programming language solution for the Day 3 Part 1. Anyone figured some clever solution for this task?

Code: Select all

: build-table
 a:new ( >r ( r@ swap 2 a:close a:push ) r@ n:1+ 99 loop rdrop ) 0 98 loop ;
build-table constant indices
: app:main
 a:new "3.txt" f:slurp
 ( "" s:/ indices ( a:@ "" a:join >n ) a:map nip ' n:cmp a:sort -1 a:_@ a:push ) s:eachline
 ' n:+ 0 a:reduce . cr ;
 

ejolson
Posts: 13950
Joined: Tue Mar 18, 2014 11:47 am

Re: Advent of Code 2025

Thu Dec 04, 2025 4:55 am

ejolson wrote:
Wed Dec 03, 2025 3:33 am
I now have one star for Day 2.

Part 2 seems similar except I have to refactor (of course) and avoid double counting.
To avoid double counting I used a priority queue--essentially a unique sort that avoids consuming O(n) storage where n is the number of invalid IDs.

The refactoring was more extensive than I had expected. In the process I deleted the code from part 1 which found the correct starting point for the pattern based on the lower endpoint of the interval. I also removed the recursive bit which handled integer ranges spanning a different orders of magnitude. I liked the recursion, but never mind.

The result was

Code: Select all

$ ./day02-go # Pi 5
Advent of Code Day 02 Gift Shop (go)
Part 1 The invalid ID sum is 24747430309
Part 2 The corrected ID sum is 30962646823
Total execution time 0.00399479 seconds.
so it seems fast enough. I think Shy is planning to retain the original algorithm and use associative arrays to avoid double counting. Purr and Scratchy have been discussing the difference between anarchy and freedom in open source

viewtopic.php?p=2351556#p2351556

and consequently made no progress. It's almost always a bad idea to argue with a cat, so I've left them alone for now.

For reference the Go code for Day 2 is

Code: Select all

/* Advent of Code 2025 Day 02 Gift Shop (go)
 Written December 2025 by Eric Olson */
package main
import("fmt"; "os"; "time"; "bufio")
var tictime time.Time
func tic(){
 tictime=time.Now()
}
func toc() float64 {
 now:=time.Now()
 elapsed:=now.Sub(tictime)
 return elapsed.Seconds()
}
type abspec struct {
 a,b int64
}
func mkidrange(fn string)[]abspec {
 fd,err:=os.Open(fn)
 if err!=nil {
 fmt.Fprintf(os.Stderr,"Unable to open %s for input!\n",fn)
 os.Exit(1)
 }
 defer fd.Close()
 fp:=bufio.NewReader(fd)
 idrange:=make([]abspec,0,128)
 for {
 var a,b int64
 r,err:=fmt.Fscanf(fp,"%d-%d",&a,&b)
 if r!=2||err!=nil { break }
 idrange=append(idrange,abspec{a,b})
 _,err=fmt.Fscanf(fp,",")
 if err!=nil { break }
 }
 return idrange
}
type patspec struct {
 x,d,s int64
 n int
}
var heap=make([]patspec,0,100)
func enqueue(p patspec){
 var r=len(heap)
 heap=append(heap,p)
 for {
 s:=(r+1)/2-1
 if s<0 { break }
 if heap[s].x<=p.x{
 break
 }
 heap[r]=heap[s]
 r=s
 }
 heap[r]=p
}
func dequeue()patspec {
 if len(heap)==0 {
 fmt.Printf("Tried to remove nonexistent point!\n")
 os.Exit(1)
 } 
 t:=heap[len(heap)-1]; heap=heap[:len(heap)-1]
 if len(heap)==0 { return t }
 p:=heap[0]
 s0:=0
 for {
 r1:=2*(s0+1); r0:=r1-1
 if r0>=len(heap){ break }
 s1:=r0
 if r1<len(heap){
 if heap[r0].x>heap[r1].x{
 s1=r1
 }
 }
 if t.x<=heap[s1].x {
 break;
 }
 heap[s0]=heap[s1]
 s0=s1
 }
 heap[s0]=t
 return p
}
func mkpat(d,s int64, n int)int64 {
 r:=d
 for i:=1;i<n;i++ { r=r*s+d }
 return r
}
func tallyn(x abspec)(int64,int64){
 s:=int64(10)
 for i:=0;i<9;i++ {
 var pat patspec
 n:=2; s2:=s*s
 for {
 if x.a<s2-1 {
 pat.d=s/10
 pat.s=s
 pat.n=n
 pat.x=mkpat(pat.d,pat.s,pat.n)
 if pat.x>x.b { break }
 enqueue(pat)
 }
 n+=1; s2*=s
 }
 s*=10
 }
 p1:=int64(0); x1:=int64(0)
 p2:=int64(0); x2:=int64(0)
 for len(heap)>0 {
 pat:=dequeue()
 if pat.x>=x.a {
 if x1!=pat.x&&pat.n==2 {
 x1=pat.x
 p1+=x1
 }
 if x2!=pat.x {
 x2=pat.x
 p2+=x2
 }
 }
 pat.d+=1
 if pat.d<pat.s {
 pat.x=mkpat(pat.d,pat.s,pat.n)
 if pat.x<=x.b {
 enqueue(pat)
 }
 }
 }
 return p1,p2
}
func dowork(){
 p1:=int64(0); p2:=int64(0)
 idrange:=mkidrange("day02.txt")
 for _,x:=range idrange {
 r1,r2:=tallyn(x)
 p1+=r1; p2+=r2
 }
 fmt.Printf("Part 1 The invalid ID sum is %d\n",p1)
 fmt.Printf("Part 2 The corrected ID sum is %d\n",p2)
}
func main(){
 fmt.Printf("Advent of Code Day 02 Gift Shop (go)\n\n")
 tic()
 dowork()
 t:=toc()
 fmt.Printf("\nTotal execution time %.6g seconds.\n",t)
 os.Exit(0)
}
By tomorrow I expect to not understand how the code works. Maybe I should've added comments like Claude but I couldn't think of anything useful to write.

RogerW
Posts: 439
Joined: Sat Dec 20, 2014 12:15 pm

Re: Advent of Code 2025

Thu Dec 04, 2025 10:47 am

Finally made day 2. I suspect a more elegant solution is possible and it could certainly be more efficient.

Code: Select all

#include <iostream>
#include <chrono>
#include <fstream>
#include <set>
const char* filename = "data.txt";
const int tens[] = {1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};
inline bool isodd(int i)
{
 return i & 1;
}
int digits(long num)
{
 int ret = 0;
 while(num)
 {
 num /= 10;
 ret++;
 }
 return ret;
}
long checkrange(long r1, long r2, int d, int num, std::set<long>& found)
{
 // check range for repeated patterns of num digits;
 // r1 and r2 are assumed to have the same number of digits
 // d is the number of digits in ranges
 // num is the number of digits of the pattern to check
 if(d % num)
 return 0;
 // s is the number of repeats of the pattern
 int s = d / num;
 long ret = 0;
 int p = tens[num];
 long x = 1; // this could be improved
 while(x < (p * s))
 {
 // make t the repeated pattern
 long t = x;
 for(int i = 0; i < s - 1; i++)
 t = (t * p) + x;
 // check if repeated pattern is in range
 if((r1 <= t) && (r2 >= t))
 {
 // avoid duplicates
 if(found.find(t) == found.cend())
 {
 ret += t;
 found.insert(t);
 }
 }
 if(t > r2)
 break;
 x++;
 }
 return ret;
}
long checkpatterns(long r1, long r2, int digits)
{
 // my data has at most 10 digits
 // we need to look for sequences of 2,3,4,5 digits
 // some calls will be invalid but checkrange will sort
 // set found set stops repeats e.g 11 4 times and 1111 twice
 long ret = 0;
 std::set<long> found;
 for(int p = 1; p <= digits/2; p++)
 ret += checkrange(r1, r2, digits, p, found);
 return ret;
}
long check2(long r1, long r2)
{
 // if neccessary split range so limits have same digits
 // call checkrange for all possible pattern sizes
 long ret = 0;
 int d1 = digits(r1);
 int d2 = digits(r2);
 if(d1 != d2)
 {
 ret += checkpatterns(r1,tens[d1] -1, d1);
 ret += checkpatterns(tens[d2 - 1],r2, d2);
 }
 else
 ret += checkpatterns(r1,r2,d1);
 return ret;
}
long check1(long r1, long r2)
{
 // some range limits have different number of digits
 // invalid id must have even number of digits
 int d1 = digits(r1);
 int d2 = digits(r2);
 int d;
 // r1 and r2 must be even
 // in my data range limits differ by at most one digit in size
 if(d1 != d2)
 {
 if(isodd(d1))
 {
 r1 = tens[d1];
 d = d2;
 }
 else
 {
 r2 = tens[d2 - 1];
 d = d1;
 }
 }
 else
 d = d1;
 if(isodd(d))
 return 0;
 // generate numbers ofthe form xyzxyz
 // and then test if in range;
 long ret = 0;
 int p = tens[d/2];
 long x = r1 / p;
 while(x < p)
 {
 long t = x + x*p;
 if(r1 <= t && t <= r2)
 ret += t;
 if(t > r2)
 break;
 x++;
 }
 return ret;
}
int main()
{
 std::chrono::time_point<std::chrono::system_clock> start,stop;
 start = std::chrono::system_clock::now();
 std::cout << "Advent of code 2025 day 2 \n";
 std::ifstream file(filename);
 long part1 = 0;
 long part2 = 0;
 if(file)
 {
 while(!file.eof())
 {
 long l1,l2;
 char c;
 file >> l1 >> l2 >> c;
 //std::cout << l1 << " " << -l2 << " " << digits(-l2) << std::endl;
 part1 += check1(l1, -l2);
 part2 += check2(l1, -l2);
 }
 }
 std::cout << "Part 1 " << part1 << "\n";
 std::cout << "Part 2 " << part2 << "\n";
 stop = std::chrono::system_clock::now();
 std::chrono::duration<double> elapsed = stop - start;
 std::cout << "Elapsed time " << elapsed.count() << " seconds" << "\n";
 return 0;
}
When run in release mode (-O2)

Code: Select all

Advent of code 2025 day 2 
Part 1 21139440284
Part 2 38731915928
Elapsed time 0.000861608 seconds

jalih
Posts: 287
Joined: Mon Apr 15, 2019 3:54 pm

Re: Advent of Code 2025

Thu Dec 04, 2025 11:54 am

For Day 4, I though about using a graph to do all the work. Luckily 8th supports graph but I think, I found a bug with 'gr:connect' word. It works fine with smaller amount of data but crashes with the actual puzzle input.

Idea is simple, build and traverse a graph. Part 2 can be solved by marking nodes for paper roll removal when traversing and removing paper rolls from marked nodes afterwards. Just repeat this until no more paper rolls can be removed.

Code: Select all

137 constant COLS
a:new "4.txt" f:slurp ( "." "0" s:replace! "@" "1" s:replace! a:push ) s:eachline "" a:join "" s:/ ' >n a:map constant data
: index> \ n1 n2 -- [row,col]
 n:/mod swap 2 a:close ;
: build-graph \ a cols -- gr
 >r a:new 2 a:close ["nodes", "edges"] swap m:zip gr:new
 \ connect and filter edges
 gr:connect gr:edges
 ( [0,1] a:_@ ( r@ index> ) a:map a:open ( n:- n:abs 2 n:< ) a:2map a:open and ) a:filter rdrop
 gr:edges! ;
: app:main
 data COLS build-graph
 0 >r false 0 ( swap if gr:neighbors data swap a:_@ ' n:+ 0 a:reduce 4 n:< if 1 n:r+ then else drop then ) gr:traverse
 r> . cr ;
 

ejolson
Posts: 13950
Joined: Tue Mar 18, 2014 11:47 am

Re: Advent of Code 2025

Fri Dec 05, 2025 1:10 am

jalih wrote:
Wed Dec 03, 2025 12:49 pm
Here is a simple 8th programming language solution for the Day 3 Part 1. Anyone figured some clever solution for this task?
The Shy kitten just finished Day 3 part 1. I asked about part 2, but not a single meow in reply.

Return to "Teaching and learning resources"

AltStyle によって変換されたページ (->オリジナル) /