While overengineering today’s AOC tasks, I stumbled into some limitations of Fortran (or maybe limitations of my Fortran skills?).
The task is to parse a list of integers, sum up each group and find the maximum. The way I tried to do it was a kind of parser. The general structure of function calls looks like this:
call graph
max_calories
-> get_next_sum
-> get_next_integer
-> get_next_line
-> intrinsic read
The first problem I had was the fact, that there is no straightforward way of handling exceptions. If the innermost read
hits eof
, this information has somehow to be handed back to the outermost function.
I tried to do this by returning allocatable
integers, where an unallocated integer would have meant, the file has reached eof
. Unfortunately, Fortran cannot return this kind of information, so I had to add an logical :: eof
to my reader class
. Similar to this, I needed a way to handle empty lines. In this case, I can simply return 0
, but I’m asking myself if there is a better solution, especially when the parser logic would be more complex. Would I require an eof
equivalent for each level of abstraction/function (or a more general status variable)?
Another problem I found is inheritance of class constructors. I use two classes, a task specific “calories parser” and a more general file reader (which can read integers). The file reader opens the file and stores the file unit in the constructor function. The calories parser extends the file reader with the next_calories
method, which basically returns the next sum of contiguous integer lines. Now if I want to create a new calories parser, I want to use the constructor of the file reader, but I didn’t manage to find a way that made me happy. My last approach is a member subroutine in the file reader, which acts as constructor and can be called by another constructor function, which has to be defined for each child class.
constructor diagram
type(calories_reader_t) :: cr
cr = calories_reader_t(filename)
-> interface calories_reader_t
-> calories_reader_constructor
-> call cr%constructor(filename)
-> file_reader%constructor(filename)
Funfact: In contrast to this highly overengineered Fortran solution, you can solve the puzzle with one line of “shell” or Python:
Shell and Python one-liner
cat input.txt | tr '\n' '+' | sed 's/++/\n/g;s/+$/\n/' | bc | sort --numeric-sort --reverse | head -3 | tr '\n' '+' | sed 's/+$/\n/' | bc
sum(sorted(map(lambda _:eval(_.replace('\n','+')),open("input.txt").read()[:-1].split(2*'\n')))[-3:])