Advent of Code 2024

https://adventofcode.com

Advent of Code is an annual set of Christmas-themed computer programming challenges that follow an Advent calendar.

Who wants to join this year? :slight_smile:

I am solving the puzzles in Fortran because I want to evaluate them for my Fortran course in February. On the last day of my last class, I let the students solve any puzzle from AoC23 to test their Fortran skills. In the entire two weeks of the course, they had never worked as hard or as ambitiously as they did on that day. :joy:

I removed some inactive members from the leaderboard, but feel free to (re-)join:
Go to Leaderboard - Advent of Code 2024 and enter 1510956-4380811b.

4 Likes

Note: you have to be logged in before you click this link; then you can enter the code. Took me a while to figure out.

1 Like

Day 5: We meet again, my old friend bubble sort.

I have no remorse for what I did.

1 Like

I always like doing these. I also don’t mind reinventing the wheel so every year I get to write new file reading, string parsing, and sorting utilities!

I reuse a module a various helper routines for things like that. (although I also do end up reinventing some wheels)

1 Like

I think it is a good way to test new fortran compilers, like flang-new,lfortran.
Because the solution usually contains intrinsic procedures, file I/O and some fortran magic tricks.

1 Like

@Euler-37 indeed, I discovered about 5 bugs yesterday related to IO, but most of them are now fixed. :slight_smile:

2 Likes

Did someone find a good way to read the input files?

There is no single best answer here. Some problems can be tackled line by line, in which case list-directed reads into a character variable or integer array can work well. Other times it will feel more natural to parse one character at a time. Yet other problems can be tackled in a very “matrix-y” way by reading the whole data into a 2D array.

If I had to recommend one most flexible way, I would say to work line-by-line. Read each line into a “big enough” character variable, parse it in whatever way makes sense for your solution approach, and stop when you hit the end of file (by checking the iostat of each read statement).

I have a read_line function that I use that returns an allocatable character string. That, with a simple string class and various routines like split, string_to_int, etc. are usually all you need for these, without having to mess around with any format statements, or assume “big enough” character strings.

3 Likes

As stated by others above, it depends on the problem. Some of them it’s best to read the line as text because you’re going to be searching for some pattern, perhaps across multiple lines, and other times you are dealing with more simple “there will be N integers, do something…”

The latest release of the Intel Fortran compiler supports split and tokenize in case you want to give them a try.

3 Likes

I generally use fpm and
general-purpose-fortran.
Some of the most common I/O related procedures that usually reduce the I/O to a few lines are

M_io:
   fileread       read (ie. slurp) a file into a string array
   filebyte       read (ie. slurp) a file into a character array
   get_next_char  read from a file one character at a time
   getline        read a line from specified LUN into allocatable string
   read_line      read a line from specified LUN into allocatable string cleaning up input line
   read_table     read a numeric table from a file

M_strings:
 CASE
   lower        changes a string to lowercase over specified range
   upper        changes a string to uppercase
 COMPARE
   glob         compare given string for match to a pattern which may contain globbing wildcard characters
 EDITING
   join           append CHARACTER variable array into a single CHARACTER variable with specified separator
   replace        function replaces one substring for another in string
   substitute     subroutine globally substitutes one substring for another in string
   transliterate  replace characters from old set with new set
 TOKENS
   delim        parse a string and store tokens into an array
   sep          function to parse string into an array using specified delimiters
   slice        parse string into an array using specified delimiters
   split        parse string into an array using specified delimiters
   split2020    parse a string into tokens using proposed f2023 method
                use M_strings, only: split=>split2020
                use M_strings, only : tokenize=>split2020
 TYPE
   getvals           read arbitrary number of REAL values from a character variable up to size of VALUES() array
   s2vs              given a string representing numbers return a numeric array
   string_to_values  read a string representing numbers into a numeric array
 WHITESPACE
   compact      converts contiguous whitespace to a single character (or nothing)

Note that a copy of split2020 by @milancurcic is included, so if you do not have the standard
split and tokenize you can use the USE statements shown to try them out as well. If you just
want these functions and not the entire GPF add these lines to the fpm manifest file fpm.toml:

[dependencies]
M_strings      = { git = "https://github.com/urbanjost/M_strings.git" }
M_io           = { git = "https://github.com/urbanjost/M_io.git" }

the source contains complete man-pages as comments as well as the documentation described in the repositories. The various regular expression modules available via fpm can be very useful as well.

4 Likes

@jacobwilliams your read_line function looks like a great candidate for stdlib or a standalone fpm package. @urbanjost is your read_line from M_io equivalent? If so, then maybe M_io is such an fpm package. :slight_smile:

1 Like

read_line from @jacobwilliams and getline from M_io are basically equivalent except a slight difference in that if an error occurs in getline the I/O message is returned as the value. the read_line in M_io is used in some specific codes that allow a backslash on the end to continue a long line, expands tabs, and removes DOS and GNU/Linux line terminators, etc. The General Purpose Fortran collection and the AOC module appear to have a good number of similiar functions, indicating such functionality might be good candidates for a shared library such as stdlib. Some is in stdlib already. But none of the GPF has a graphic as great as the one I see on the AOC site.

:smile: Nice!. The flames are just great.

2 Likes

agreed that @jacobwilliams read_line is very good, but could someone verify that it works with both gfortran and ifort (or latest ifx)? I more or less copied it at work today and ifort was consistently getting stuck at the end of file. Without looking too much into it, seemed that the version of gfortran I had (4.something ancient on RHEL8) would stop reading at end of file for advance='no' and report iostat_eof but would change to iostat=5001 if another read statement was encountered. The old version of ifort I had would just stay stuck at the iostat_eof forever and never report a bad read. Perhaps user error, but I didn’t see how a caller of read_line was supposed to know that a file was done other than getting a status_ok = .false..

1 Like

When was size= allowed in inquire!?
That would have saved me from so much bloat over the decades :sob:

It’s not even mentioned in my 2018 Metcalf-Reid-Cohen…

2 Likes

I didn’t know this, too. I just learned it exists when I asked ChatGPT about file reading a few days ago. :sweat_smile:

2 Likes

Apparently in F2003 (9.9.1.29 in N1601 Draft document). It seems not to be present in F95 (9.6.1 Inquiry specifiers in N1191 doc).

So it has been there for quite a while already :slight_smile:

1 Like

It is. Section 12.6 The Inquire statement, page 277. :slight_smile: