problem_03.f90 Source File


This file depends on

sourcefile~~problem_03.f90~~EfferentGraph sourcefile~problem_03.f90 problem_03.f90 sourcefile~aoc_utilities.f90 aoc_utilities.F90 sourcefile~problem_03.f90->sourcefile~aoc_utilities.f90

Source Code

program problem_3

use iso_fortran_env
use aoc_utilities

implicit none

integer :: n_lines, i, j, n_cols, jstart, jend
logical :: adjacent, tmp
integer(ip) :: isum
character(len=1),dimension(:,:),allocatable :: array
integer(ip),dimension(:),allocatable :: ivals

call clk%tic()

! read file:
! pad around with blanks to simplify logic below
array = read_file_to_char_array('inputs/day3.txt', border = '.')
n_lines = size(array,1)
n_cols  = size(array,2)

!----------------- part 1 -----------------

isum = 0
do i = 1, n_lines
    ! is this character adjacent to a symbol?
    jend = 0
    do j = 1, n_cols
        if (is_not_number(array(i,j))) cycle
        if (j<=jend) cycle   ! skip the cols that we already have
        jend = 0
        adjacent =  is_symbol(array(i-1,j)  ) .or. &
                    is_symbol(array(i-1,j-1)) .or. &
                    is_symbol(array(i-1,j+1)) .or. &
                    is_symbol(array(i,j-1)  ) .or. &
                    is_symbol(array(i,j+1)  ) .or. &
                    is_symbol(array(i+1,j)  ) .or. &
                    is_symbol(array(i+1,j-1)) .or. &
                    is_symbol(array(i+1,j+1))
        if (adjacent) isum = isum + get_number(i,j) ! note: this sets jend
    end do
end do
write(*,*) '3a: sum :', isum

!----------------- part 2 -----------------

! now look for '*' and find adjacent numbers ....
isum = 0
do i = 1, n_lines
    do j = 1, n_cols
        if (array(i,j) == '*') then
            ! look for 2 adjacent numbers.
            if (allocated(ivals)) deallocate(ivals); allocate(ivals(0))
            ! above
            tmp = check(i-1,j) ! if only one on top
            if (.not. tmp) then
                tmp = check(i-1,j-1)
                tmp = check(i-1,j+1)
            end if
            tmp = check(i,j-1)    ! left and right
            tmp = check(i,j+1)
            ! below
            tmp = check(i+1,j) ! if only one below
            if (.not. tmp) then
                tmp = check(i+1,j-1)
                tmp = check(i+1,j+1)
            end if
            if (size(ivals) == 2) isum = isum + product(ivals) ! sum gear ratio
        end if
    end do

end do
write(*,*) '3b: result :', isum

call clk%toc('3')

contains

    logical function check(i,j)
        !! if the char is part of a number, then get it and append to ivals
        integer,intent(in) :: i,j
        check = is_number(array(i,j))
        if (check) ivals = [ivals, get_number(i,j)]
    end function check

    logical function is_symbol(c)
        character(len=1),intent(in) :: c
        is_symbol = is_not_number(c) .and. c /= '.'
    end function is_symbol

    integer(ip) function get_number(i,j)
        !! get the full number contining the character at i,j
        integer,intent(in) :: i,j
        jstart = j
        jend = j
        do
            if (array(i,jstart-1)=='.' .or. is_symbol(array(i,jstart-1))) exit
            jstart = jstart - 1
        end do
        do
            if (array(i,jend+1)=='.' .or. is_symbol(array(i,jend+1))) exit
            jend = jend + 1
        end do
        get_number = int(array(i, jstart:jend))
    end function get_number

end program problem_3