Finally! I've completed day 19. It took a week (for part 2).
Naive version (that was passing the test case) of both part1 and part2 was done in 30 minutes the first day.
After that it took me the rest of the first day to add some short additional functions just to speed up the calculation. Functions like prune-towels, that removes useless towels (before starting a new match for each design string), and function can-match that collects only those towels (from already pruned) that can be the current prefix of a design string. By the end of first day I had the working (memoized) version for part1, that was accepted
The problem I had with part2 was that the function that calculated part2 was not purely functionl design. Althogh it was 99% identical to the part1 function, the base case, instead of returning #t (true) like for part1, was first setting the global count variable and then returning #f (false). And just because of that, I could not memoize it.
Both part1 and part2 were designed with one "and" inside the "or" that was forcing the backtracking. However for part2 this was always returning just #f, and therefore could not be memoized.
In the end, I changed the design to build a tree, instead of just backtracking on failure.
This is the function that does everything. It calculates simultaneously part1 (just take the length of returned list of matches that are not 0), and part2, just add all the numbers, after the tree function returns.And that's all there is to it!Considering that this is run on "banana" and from Emacs, and that the result is 700+ trillion, my hat is off to Chez Scheme.
Naive version (that was passing the test case) of both part1 and part2 was done in 30 minutes the first day.
After that it took me the rest of the first day to add some short additional functions just to speed up the calculation. Functions like prune-towels, that removes useless towels (before starting a new match for each design string), and function can-match that collects only those towels (from already pruned) that can be the current prefix of a design string. By the end of first day I had the working (memoized) version for part1, that was accepted
The problem I had with part2 was that the function that calculated part2 was not purely functionl design. Althogh it was 99% identical to the part1 function, the base case, instead of returning #t (true) like for part1, was first setting the global count variable and then returning #f (false). And just because of that, I could not memoize it.
Both part1 and part2 were designed with one "and" inside the "or" that was forcing the backtracking. However for part2 this was always returning just #f, and therefore could not be memoized.
In the end, I changed the design to build a tree, instead of just backtracking on failure.
This is the function that does everything. It calculates simultaneously part1 (just take the length of returned list of matches that are not 0), and part2, just add all the numbers, after the tree function returns.
Code:
(define (tree dsnt twls) (let* ((dsn (car dsnt)) (dl (string-length dsn))) (if (zero? dl)1(apply + (map (lambda (dt) (tree dt twls)) (map (chop dsn dl) (can-match dsn dl twls)))))))
Code:
;;; Advent of code 2024 - day19, part1 & part2, on BPI-F3 RISC-V;;; Chez code (load "utils.so")(define (can-match s sl twls) (filter (lambda (p) (string=? (substring s 0 (min (string-length p) sl)) p)) twls))(define (chop dsn dl) (lambda (pat) (list (substring dsn (string-length pat) dl))))(define (tree dsnt twls) (let* ((dsn (car dsnt)) (dl (string-length dsn))) (if (zero? dl)1(apply + (map (lambda (dt) (tree dt twls)) (map (chop dsn dl) (can-match dsn dl twls)))))))(define (prune-towels dsn twls) (let ((len (string-length dsn))) (filter (lambda (p) (let f ([i 0])(let ((pl (string-length p))) (cond ((> (+ i pl) len) #f) ((string=? (substring dsn i (+ i pl)) p)) (else (f (add1 i))))))) twls)))(define (day19 file) (let* ((rawl (read-lines file)) (towels (sort ; greedy algorithm (lambda (x y) (< (string-length x) (string-length y))) (string-split-n (car rawl) '(#\space #\,)))) (dsns (cddr rawl)) (pruned (map (lambda (d) (prune-towels d towels)) dsns)) (result (filter (compose not zero?) (map (lambda (t p) (tree (list t) p)) dsns pruned)))) (values (length result) (apply + result))))
Code:
> (time2 (lambda () (day19 "input.txt")))304705756472327497#<time-duration 1.483221209>
Statistics: Posted by hrvoje064 — Fri Dec 27, 2024 4:09 pm