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