In Factor:
Here it is on GitHub with comments and imports.
: line>cards ( line -- winning-nums player-nums )
":|" split rest
[
[ CHAR: space = ] trim
split-words harvest [ string>number ] map
] map first2
;
: points ( winning-nums player-nums -- n )
intersect length
dup 0 > [ 1 - 2^ ] when
;
: part1 ( -- )
"vocab:aoc-2023/day04/input.txt" utf8 file-lines
[ line>cards points ] map-sum .
;
: follow-card ( i commons -- n )
[ 1 ] 2dip
2dup nth swapd
over + (a..b]
[ over follow-card ] map-sum
nip +
;
: part2 ( -- )
"vocab:aoc-2023/day04/input.txt" utf8 file-lines
[ line>cards intersect length ] map
dup length <iota> swap '[ _ follow-card ]
map-sum .
;