In Factor:
Here it is on GitHub with comments and imports.
: symbol-indices ( line -- seq )
[ ".0123456789" member? not ] find-all [ first ] map
;
: num-spans ( line -- seq )
>array [ over digit? [ nip ] [ 2drop f ] if ] map-index
{ f } split harvest
[ [ first ] [ last ] bi 2array ] map
;
: adjacent? ( num-span symbol-indices -- ? )
swap [ first 1 - ] [ last 1 + ] bi [a,b]
'[ _ interval-contains? ] any?
;
: part-numbers ( line nearby-symbol-indices -- seq )
[ dup num-spans ] dip
'[ _ adjacent? ] filter
swap '[ first2 1 + _ subseq string>number ] map
;
: part1 ( -- )
"vocab:aoc-2023/day03/input.txt" utf8 file-lines
[ [ symbol-indices ] map ] keep
[
pick swap [ 1 - ?nth-of ] [ nth-of ] [ 1 + ?nth-of ] 2tri
3append part-numbers sum
] map-index sum nip .
;
: star-indices ( line -- seq )
[ CHAR: * = ] find-all [ first ] map
;
: gears ( line prev-line next-line -- seq-of-pairs )
pick star-indices
[ 1array '[ _ part-numbers ] [ 3dup ] dip tri@ 3append ]
[ length 2 = ] map-filter [ 3drop ] dip
;
: part2 ( -- )
"vocab:aoc-2023/day03/input.txt" utf8 file-lines
dup [
pick swap [ 1 - ?nth-of ] [ 1 + ?nth-of ] 2bi
gears [ product ] map-sum
] map-index sum nip .
;