problem_10 Program

Uses

  • program~~problem_10~~UsesGraph program~problem_10 problem_10 iso_fortran_env iso_fortran_env program~problem_10->iso_fortran_env module~aoc_utilities aoc_utilities program~problem_10->module~aoc_utilities module~aoc_utilities->iso_fortran_env

Calls

program~~problem_10~~CallsGraph program~problem_10 problem_10 proc~clock_end aoc_utilities::clock%clock_end program~problem_10->proc~clock_end proc~clock_start aoc_utilities::clock%clock_start program~problem_10->proc~clock_start proc~locpt aoc_utilities::locpt program~problem_10->proc~locpt proc~move problem_10::move program~problem_10->proc~move proc~read_file_to_char_array aoc_utilities::read_file_to_char_array program~problem_10->proc~read_file_to_char_array proc~move->proc~move proc~pipe_info problem_10::pipe_info proc~move->proc~pipe_info proc~number_of_lines_in_file aoc_utilities::number_of_lines_in_file proc~read_file_to_char_array->proc~number_of_lines_in_file proc~read_line aoc_utilities::read_line proc~read_file_to_char_array->proc~read_line

Variables

Type Attributes Name Initial
integer :: i
integer :: j
integer :: nrows
integer :: ncols
integer :: imove
integer :: l
integer :: m
logical, dimension(:,:), allocatable :: icounts
character(len=1), dimension(:,:), allocatable :: array
integer, dimension(:,:), allocatable :: distance
integer, dimension(:,:), allocatable :: distance_reverse
logical, dimension(:,:), allocatable :: visited
real(kind=wp), dimension(:), allocatable :: x

path cooidinates

real(kind=wp), dimension(:), allocatable :: y

path cooidinates

integer, dimension(2) :: Sij

i,j of the S char in array


Functions

pure function pipe_info(p)

Arguments

Type IntentOptional Attributes Name
character(len=1), intent(in) :: p

Return Value character(len=2)


Subroutines

recursive subroutine move(i, j, direction, distance, save_path)

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: i
integer, intent(in) :: j
integer, intent(in) :: direction
integer, intent(inout), dimension(:,:) :: distance
logical, intent(in) :: save_path

to save the path coordinates

Source Code

program problem_10

use iso_fortran_env
use aoc_utilities

implicit none

integer :: i, j, nrows, ncols, imove, l , m
logical,dimension(:,:),allocatable :: icounts
character(len=1),dimension(:,:),allocatable :: array
integer,dimension(:,:),allocatable :: distance, distance_reverse
logical,dimension(:,:),allocatable :: visited
real(wp),dimension(:),allocatable :: x, y !! path cooidinates
integer,dimension(2) :: Sij !! i,j of the S char in array

call clk%tic()

array = read_file_to_char_array('inputs/day10.txt', '.') ! pad with . to simplify edge logic
nrows = size(array,1)
ncols = size(array,2)

allocate(distance(nrows,ncols)); distance = -1
allocate(distance_reverse(nrows,ncols)); distance_reverse = -1
allocate(visited(nrows,ncols))

! start at the S coordinate:
Sij = findloc(array, 'S')
x = [Sij(1)] ! to store the path for part b
y = [Sij(2)]

! traverse the maze:
visited = .false.; visited(Sij(1), Sij(2)) = .true.; distance(Sij(1), Sij(2)) = 0
do imove = 1, 4
    call move(Sij(1), Sij(2), imove, distance, .true.)
end do

! traverse the maze again in reverse:
visited = .false.; visited(Sij(1), Sij(2)) = .true.; distance_reverse(Sij(1), Sij(2)) = 0
do imove = 4, 1, -1
    call move(Sij(1), Sij(2), imove, distance_reverse, .false.)
end do
! where they match is the distance furthest away from the start
write(*,*) '10a: ', pack(distance, mask = (distance==distance_reverse .and. distance>0))

! for part b, use locpt to test all the points
! allow openmp to be used here to do each row in parallel
allocate(icounts(nrows,ncols)); icounts = .false.
!$OMP PARALLEL DO SHARED(icounts,x,y) PRIVATE(i,j,l,m)
do i = 2, nrows-1 ! we can skip the padding
    do j = 2, ncols-1
        if (any(i==x .and. j==y)) cycle ! skip if on path
        call locpt (real(i,wp), real(j,wp), x, y, size(x), l, m)
        if (l==1) icounts(i,j) = .true. ! if (i,j) is inside the polygonal path
    end do
end do
!$OMP END PARALLEL DO
write(*,*) '10b: ', count(icounts)

call clk%toc('10')

contains

    recursive subroutine move(i,j,direction,distance,save_path)
        integer,intent(in) :: i,j,direction
        integer,dimension(:,:),intent(inout) :: distance
        logical,intent(in) :: save_path !! to save the path coordinates

        integer :: inew, jnew, imove
        logical :: valid_move

        select case(direction)
        case(1); inew = i-1; jnew = j   ! north
        case(2); inew = i+1; jnew = j   ! south
        case(3); inew = i;   jnew = j+1 ! east
        case(4); inew = i;   jnew = j-1 ! west
        end select
        if (visited(inew,jnew) .or. array(inew,jnew)=='.') return

        ! can we move in this direction?
        valid_move = .false.
        associate (current_pipe     => array(i,j),      &
                   current_distance => distance(i,j),   &
                   move_to          => array(inew,jnew) )
            select case (current_pipe)
            case('S')
                ! don't know what the first pip is, so have to try them all
                select case(direction)
                case(1); valid_move = index(pipe_info(move_to),'S')>0  ! north
                case(2); valid_move = index(pipe_info(move_to),'N')>0  ! south
                case(3); valid_move = index(pipe_info(move_to),'W')>0 ! east
                case(4); valid_move = index(pipe_info(move_to),'E')>0 ! west
                end select
            case('|')
                select case(direction)
                case(1); valid_move = index(pipe_info(move_to),'S')>0  ! north
                case(2); valid_move = index(pipe_info(move_to),'N')>0  ! south
                end select
            case('-')
                select case(direction)
                case(3); valid_move = index(pipe_info(move_to),'W')>0 ! east
                case(4); valid_move = index(pipe_info(move_to),'E')>0 ! west
                end select
            case('L')
                select case(direction)
                case(1);  valid_move = index(pipe_info(move_to),'S')>0 ! north
                case(3);  valid_move = index(pipe_info(move_to),'W')>0 ! east
                end select
            case('J')
                select case(direction)
                case(1);  valid_move = index(pipe_info(move_to),'S')>0 ! north
                case(4);  valid_move = index(pipe_info(move_to),'E')>0! west
                end select
            case('7')
                select case(direction)
                case(2);  valid_move = index(pipe_info(move_to),'N')>0 ! south
                case(4);  valid_move = index(pipe_info(move_to),'E')>0 ! west
                end select
            case('F')
                select case(direction)
                case(2);  valid_move = index(pipe_info(move_to),'N')>0 ! south
                case(3);  valid_move = index(pipe_info(move_to),'W')>0 ! east
                end select
            end select

            if (valid_move) then
                distance(inew,jnew) = current_distance + 1
                visited(inew,jnew) = .true.
                do imove = 1, 4
                    call move(inew,jnew,imove,distance,save_path)
                end do
                if (save_path) then
                    x = [x, real(inew,wp)] ! save cordinates of point on the path
                    y = [y, real(jnew,wp)]
                end if
            end if

        end associate

    end subroutine move

    pure character(len=2) function pipe_info(p)
        character(len=1),intent(in) :: p
        select case (p)
        case('|'); pipe_info = 'NS'   ! | is a vertical pipe connecting north and south.
        case('-'); pipe_info = 'EW'   ! - is a horizontal pipe connecting east and west.
        case('L'); pipe_info = 'NE'   ! L is a 90-degree bend connecting north and east.
        case('J'); pipe_info = 'NW'   ! J is a 90-degree bend connecting north and west.
        case('7'); pipe_info = 'SW'   ! 7 is a 90-degree bend connecting south and west.
        case('F'); pipe_info = 'SE'   ! F is a 90-degree bend connecting south and east.
        end select
    end function pipe_info

end program problem_10