Advent of Code 2022

Since this is not a numbered constraint or syntax rule, the compiler isn’t required to diagnose it. I’m a bit astonished that ifort could do so at all - it certainly can’t be done in all such cases. Whether it “works” or not is entirely accidental and subject to change at any time.

Been there, done that :joy:

Yes. No warning from gfortran(1) I could produce so far. I can get gfortran to not work for some I/O as well, although the initial case works fine with it (living up to “undefined”).

ifort(1) seems to reliably report an error if any part of LINE is actually written to LINE. So it is actually the rarer case where no I/O occurred from LINE to LINE. Ends up my test line is such a
case. If you assume (which seems to be the case) that LINE is wiped to all spaces before any other processing.;In that case there is no access of LINE because len_trim() returns zero and the implied do is not run.

Anything that actually extracts something from LINE appears to trip the warning rather reliably.
It all works fine if a second variable is written to instead of LINE with both the two compilers mentioned; and everything is living up to the “undefined” behavior (sort of a new puzzle trying to guess exactly how the output that comes out happens) In this case a
DO loop would be used in real applications because they have so much less overhead instead of invoking I/O statements but if it did work I could think of some uses for it because of the power of format descriptors (and it does work just fine using LINE2 instead of LINE for the internal file). Sort of like knowing what a 0 in column 6 does in fixed format fortran – not going to need to know this most of the time but it saves a lot of time knowing it when you do run into it. Thanks again.

Knowing something about dusty corners can come in handy. Where I work they were resurrecting some VERY old code and it was compiling (amazing by itself, as this was pre-77 code) but was getting the wrong answer. Knowing what some old F66 compilers did that did not make it into the standard, I knew what was wrong immediately when I saw the code. There was an integer array IARR and the statement

IARR=1

in the code. Completely standard f90+. But when this code was written there was no array syntax. That was a very old way to set the first element of an array, but now it sets all the elements of an array. A REALLY dusty corner case.

Day 5 starts to get a bit interesting. It’s obviously inspired by Towers of Hanoi but mixes it up a bit. I was pleased to see that my solution for part 1 needed just two changed executable lines for part 2.

As mentioned earlier by @jacobwilliams, reading the input file was more code than the problem solution. I agree it looks a lot like moves from a Towers of Hanoi game. One of the versions has priests moving 64 golden disks on three disks once a second, and it will take them something like 1/2 trillion years to finish the moves if they make no mistakes. I think I need to calculate how long a current computer would take to calculate all the moves; but the problem is the Universe is supposed to end when the Priests’ task is completed.

Reading the input, at least so far, is not a lot of code if you do it in Fortran rather than Python-in-Fortran, or similar. Play to Fortran’s strengths.

1 Like

I agree! I got the whole I/O setup in ~20 lines, almost a piece of cake!

1 Like

I actually did the Python-in-Fortran strategy, and it was indeed quite a lot of code… Looking at your solution, I would have probably to simplify mine :slight_smile:

Nine lines for me.

My respects! I don’t want to share more hints here but I’m going to upload my way to github.

Agreed, and going forward I probably will just read the input more simply, but to me part of the challenge was to be able to read the sample input problem input generically enough I did not need to know the number of columns or how tall the stacks were and to ignore columns of whitespace and blank lines, although I did not harden it all that much.

The program is about 100 lines and does both days and it has a few comment lines in there too; but probably just going to read things with a FORMAT on subsequent puzzles. Did also use a few fpm modules although they would be relatively easy to eliminate. A hard habit to break is making robust interfaces; need to treat these more as throw-away code.

I made part 2 of day 1 able to read the input even if you paragraph-filled it!

We do not have a lot of those throw-aways, so I find myself building way-to-general solutions :smile: . The irony is how often I suggest KISS to others :wink: . Just a game.

Still amazed at the number of players. I need to look up how many people regularly program. It must be far more than I thought. There are apparently nearly 200 000, players! Do some State school systems assign this as homework or something? If we all planted a tree instead of doing a puzzle how big would the forest be?

I looked at the AoC leaderbord and apparently people use wildly different approaches (some even testing their own languages lol). I took the challenge of over-engineering the task by trying to make Fortran as short as possible. That brought me down the F77 rabbithole!

For anything any more general than a simple script, I do agree that more and more general I/O libraries are needed nowadays.

If all the input files where NAMELIST group files most of the programs could be a few lines long :upside_down_face:

1 Like

Whether it’s AoC, or any other scientific / technical computing endeavor, libraries are crucial and this is what I had conveyed in this comment in another thread. Development of good libraries with Fortran is where it gets extremely, extremely difficult.

The extremely slow pace of certain compiler implementations when it comes to conforming with current standard facilities and the resultant slowing down of the language standard with minor revision after minor revision of miscellaneous items lacking a unifying vision, ostensibly for the sake of helping some compilers to “catch up”, is proving rather detrimental for Fortran.

6 Likes

OK, I have my second version now, thanks for the inspiration. It dynamically determines the nr. of stacks and is also able to cope with the sample input used in the task description, where some lines of the stack data were shorter than others (as the two outermost stacks were not the highest ones). I think, it is compact and Fortran-like enough now, than I can resist the temptation to optimize it further…

1 Like

A mixed message. Neptune’s stack looks quite impressive. However, in that episode Spongebob wins with his single patty because it is so much better as it “is made with Love” and Neptune becomes his Fry Cook trainee :grinning:

Definitely some similarities between the input and this old example of recursion from “FortranTools” …

Towers of Hanoi
program recursive_hanoi ! Fortran tools
! recursively solve Towers of Hanoi puzzle
implicit none
integer :: number_of_disks

   print *, "NUMBER_OF_DISKS:",  &
   read *, number_of_disks
   print *
   call hanoi (number_of_disks, 1, 3)

contains

recursive subroutine hanoi (number_of_disks,  &
      starting_post, goal_post)

integer, intent (in) ::  &
number_of_disks, starting_post, goal_post
integer :: free_post
integer, parameter :: all_posts = 6

   if (number_of_disks > 0) then
      free_post =  &
      all_posts - starting_post - goal_post
      call hanoi (number_of_disks - 1,  &
                  starting_post, free_post)

      print *, "Move disk", number_of_disks,  &
            "from post", starting_post,  &
            "to post", goal_post
      call hanoi (number_of_disks - 1,  &
                  free_post, goal_post)
   end if
end subroutine hanoi

end program recursive_hanoi

I have no remorse for what I did. :slight_smile:

    stacks(1)%str = 'GFVHPS'
    stacks(2)%str = 'GJFBVDZM'
    stacks(3)%str = 'GMLJN'
    stacks(4)%str = 'NGZVDWP'
    stacks(5)%str = 'VRCB'
    stacks(6)%str = 'VRSMPWLZ'
    stacks(7)%str = 'THP'
    stacks(8)%str = 'QRSNCHZV'
    stacks(9)%str = 'FLGPVQJ'
2 Likes

For day 6 (:santa:) I had too look up cshift, just to realize a little later, that my good old friend modulo allows again for a more elegant (and more efficient) solution, especially when combined with the power of Fortran array intrinsics. I think, this time I am satisfied with my I/O part as well…

Are we still needed at all? :grin:

There is an experimental AI Chat (https://chat.openai.com/chat - requires registration, free version has some constraints). I’ve given it a following input:

Solve the following problem in Fortran: One Elf has the important job of loading all of the rucksacks with supplies [… whole description from AoC day 3 page …]
Find the item type that appears in both compartments of each rucksack. What is the sum of the priorities of those item types?

After a while, it returned:

PROGRAM main
  IMPLICIT NONE
  CHARACTER(LEN=100) :: rucksacks(6) ! Array to store the rucksacks
  CHARACTER(LEN=50) :: comp1, comp2   ! Variables to store the compartments
  CHARACTER(LEN=1) :: c               ! Variable to store a character
  INTEGER :: i, j, k, n, sum          ! Loop variables and sum
  LOGICAL :: found                   ! Flag to indicate if a common item is found

  ! Input the rucksacks
  PRINT *, "Enter the rucksacks: "
  DO i = 1, 6
    READ *, rucksacks(i)
  END DO

  ! Loop through the rucksacks
  sum = 0
  DO i = 1, 6

    ! Split the rucksack into its compartments
    comp1 = rucksacks(i)(1:LEN_TRIM(rucksacks(i))/2)
    comp2 = rucksacks(i)(LEN_TRIM(rucksacks(i))/2+1:)

    ! Loop through the characters in the first compartment
    DO j = 1, LEN_TRIM(comp1)
      c = comp1(j:j)

      ! Check if the character appears in the second compartment
      found = .FALSE.
      DO k = 1, LEN_TRIM(comp2)
        IF (comp2(k:k) == c) THEN
          found = .TRUE.
          EXIT
        END IF
      END DO

      ! If the character is found, add its priority to the sum
      IF (found) THEN
        n = ASCII_CODE(c)
        IF (n >= 97) THEN
          n = n - 96
        ELSE
          n = n - 38
        END IF
        sum = sum + n
        EXIT
      END IF
    END DO
  END DO

  ! Print the result
  PRINT *, "The sum of the priorities of the common item types is: ", sum

END PROGRAM main

The only fix it required was changing ASCII_CODE to IACHAR. Fed with the sample data, returned 157 as the right example answer.

The code was accompanied by comments (cut in the middle of a sentence, probably due to free version constraints):

In this example, rucksacks is an array of strings that stores the input rucksacks, comp1 and comp2 are strings that store the compartments of each rucksack, c is a string that stores a character, i, j, and k are loop variables, n is a variable that stores the priority of a character, sum is an integer variable that stores the sum of the priorities, and found is a logical flag that indicates whether a common character is found.

The program first inputs the rucksacks using a DO loop and the READ statement. Then, it loops through the rucksacks and splits each one into its compartments using the / operator and the LEN_TRIM function. It then loops through the characters in the first compartment and checks if each character appears in the second compartment using another DO loop and an IF statement. If a common character is found, the program calculates its priority using the ASCII_CODE function and an IF statement, adds it to the sum, and exits the loop using the EXIT statement. Finally, the program prints

That’s really impressive!

5 Likes