Advent of Code 2021

2 days left until the Advent of Code 2021 starts.
If some of you want to participate, feel free to join the leader board I created for our Fortran Family:

  1. Register/Login at https://adventofcode.com/
  2. Go to Leaderboard - Advent of Code 2021
  3. Enter this code: 1510956-4380811b

Feel free to share your repository / discuss your solutions in this thread.
Happy coding!

6 Likes

Got my first two stars. A generic comment I will make, based on the couple of years past I have participated, is to try to avoid storing all of the input in a single array and then processing it, as often the input data is structured to make that difficult. Most of the problems can be solved incrementally. Some of them require you to build a linked structure dynamically.

4 Likes

Thank you for this hint, because this is exactly what I did for the first day. I even wrote a module to add more of these “input-to-array” parsers.

1 Like

Ugh, I found Day 3 Part 2 to to be pretty tedious. It took me several read-throughs to understand what it was asking for. I took a pretty simplistic approach to it using an iteratively updating mask array. I’ll be curious if people came up with something more clever.

2 Likes

I think this is clever enough, at least I also implemented it that way. :smiley:
What made it hard for me is when all bits of a column are equal and you want to select the entries with the least common bit, because then obviously you are left with an empty set.

2 Likes

The main problem I had with Part 2 of Day 3 was that I failed to read the description carefully. In particular I missed that I needed to recompute the ones and zeroes count after each pass. Once I realized that, I got the right answer. I didn’t use a mask, just kept writing the selected values to one of two alternating temp files until a pass completed with a count of 1.

1 Like

As has sometimes been the case in the past, part 2 of Day 4 was just adding a few lines to my part 1. I got to use FINDLOC, SUM, ALL and MERGE.

1 Like

I also got use out of FINDLOC, SUM, ALL, and ANY. My strategy involved basically simulating the actual bingo game, drawing a number, then checking each board, then checking for bingos. Now I realize that you can just as well go board by board and see how many turns it would take each board to win. Probably more efficient that way!

1 Like

On Day 4 I made use of elemental functions to cross numbers and check if a board has won. I made a datatype bingo_board_t with two 5x5 fields, one for the numbers and the second to mark numbers. Checking if a board has won is as easy as calling sum(count(...))==5 for rows and for columns.
The trickiest part was to read in the data. But in the end it came down to counting the numbers in the first line and the amount of boards. After that I could use read(fileunit, *) bingo_board(i). I didn’t know fmt=* is that flexible.

2 Likes

Day 5 was another easy one. The key realization here was that you just need to track the number of cells whose count reaches 2 - any more than that can be ignored..

2 Likes

Are you folks posting your solutions anywhere? Mine are at: GitHub - jacobwilliams/AoC-2021: Advent of Code 2021 with Fortran

Not my finest work…just trying to get the answers! :slight_smile:

2 Likes

I like the fact, that sometimes the second part of a task makes you realise that your first approach was way too complicated

Edit:
Imagine what my work mate did: Just like me he made an array with entries for each fish, to simulate each fish separately. When he saw, that problem 2 might get out of control with Python on a ThinkPad, his first approach was to run the code on a supercomputer node. Obviously that didn’t work out, too. :smiley:

3 Likes

Here is my repository. Not that clean either, but at least I try to write readable and fast code. :sweat_smile:

2 Likes

I’m putting my solutions up here: GitHub - awvwgk/AoC-2021: questionable code quality is guaranteed. Not a Fortran only advent of code, however.

3 Likes

Now we’re into 64-bit integer territory! You need only keep track of how many fish have n days left before spawning (0:8). Each day, create a “tomorrow” array with updated counts, assign to “today”, repeat.

4 Likes

I was waiting for a day like Day 6. Good fun! Did it a very naive way for part 1 (wastefully using allocate-on-assign and array concatenation to emulate a linked list). Then came to nearly the same solution as Steve to make part 2 feasible. Here’s my solution:

Day 6 Part 2

Rather than maintain two arrays, I use EOSHIFT. But it’s likely that creates a temp array anyway. I also learned EOSHIFT actually works the opposite direction to what I thought

subroutine part2
    use, intrinsic :: iso_fortran_env, only: int64
    integer, allocatable :: fish(:)
    integer :: i, t
    integer(int64) :: counts(-1:8)

    call load('data\input_day6.txt', fish)

    counts = 0
    do i = 1, size(fish)
        counts(fish(i)) = counts(fish(i)) + 1 
    end do

    do t = 1, 256
       counts = eoshift(counts, 1) 
       counts(6) = counts(6) + counts(-1) ! fish that give birth reset to 6 days
       counts(8) = counts(-1)             ! newly born fish have 8 days
    end do
    print *, sum(counts(0:))
end subroutine part2
2 Likes

I even tried to get rid of shifting the numbers in the array by calculating the “index of zero” with mod(day, 7) but in the end this was two times slower and I don’t know why.

1 Like

Here is my Day 6 Part 2 solution (same as part 1, just change the end day number.) It does depend on an implementation-specific behavior in one place.

Summary
    program AOC06
    implicit none

    integer(8) :: today(0:8), tomorrow(0:8), count
    integer :: input(500), day, ios, i
    
    open (unit=1, file='input.txt', form='formatted', status='old')
    input = 0
    read (1,*,iostat=ios) input
    
    today = 0
    do count=1,size(input)
        if (input(count) == 0) exit
        today(input(count)) = today(input(count)) + 1
    end do
    count = count - 1
    
    day = 0
    dayloop: do
        print *, "Day ", day, " count=", count
        if (day == 256) exit dayloop
        tomorrow(0:7) = today(1:8)
        tomorrow(6) = tomorrow(6) + today(0)
        tomorrow(8) = today(0)
        count = count + tomorrow(8)
        today = tomorrow
        day = day + 1
        end do dayloop
    
    end program AOC06
1 Like

Yes - I post mine online too when I remember to run the git push command! Added the URL below, just in case you want to have a look.

As a newbie to Fortran I have found it very useful to learn new techniques and better ways to achieve the answers etc. Or even get me going again when I am completely stuck - which is quite a frequent occurrence I can assure you. Certainly having fun and learning a lot thanks to others Fortran code, which they are kind enough to share :slight_smile:

I noticed if you join the ‘Fortran AOC 2021 Leader Board’ (ie see the very first post above), some people are linked to their code repos via that as well, which is a handy to see where people have got too.

All good fun :+1:

1 Like

I found that a matrix population model works nicely for day 6, here is a Fortran version of it:

implicit none
integer, parameter :: i8 = selected_int_kind(18), &
   & max_n = 1000, t0 = 1, t1 = 80, t2 = 256
integer :: input(max_n), io, stat, n, i
character(len=64) :: arg
integer(i8), parameter :: grow(9, 9) = reshape([&
   & 0, 0, 0, 0, 0, 0, 1, 0, 1, &
   & 1, 0, 0, 0, 0, 0, 0, 0, 0, &
   & 0, 1, 0, 0, 0, 0, 0, 0, 0, &
   & 0, 0, 1, 0, 0, 0, 0, 0, 0, &
   & 0, 0, 0, 1, 0, 0, 0, 0, 0, &
   & 0, 0, 0, 0, 1, 0, 0, 0, 0, &
   & 0, 0, 0, 0, 0, 1, 0, 0, 0, &
   & 0, 0, 0, 0, 0, 0, 1, 0, 0, &
   & 0, 0, 0, 0, 0, 0, 0, 1, 0],&
   & shape(grow))
integer(i8) :: pop(9)

pop(:) = 0
input(:) = 0
call get_command_argument(1, arg)
open(newunit=io, file=arg, status='old')
read(io, *, iostat=stat) input
close(io)

n = count(input > 0)
pop(input(:n)) = pop(input(:n)) + 1

do i = t0, t1-1
   pop = matmul(grow, pop)
end do
print '(a, 1x, i0)', "[1]:", sum(pop)

do i = t1, t2-1
   pop = matmul(grow, pop)
end do
print '(a, 1x, i0)', "[2]:", sum(pop)
end
2 Likes