(define-module (cc) #:use-module (srfi srfi-1) #:export (cc filter-possible-games games->at-least game->seen draw->colors take-max-instances)) (define (cc str red green blue) "Given STR, a list of games and their corresponding draws, as well as RED, GREEN, and BLUE, the total amount of cubes actually possessed, return the sum of the possible game ids, as well as the total power." (let ((games (games->at-least str))) (cons (apply + (map car (filter-possible-games games (list red green blue)))) (calculate-total-power games)))) (define (calculate-total-power games) "Given an alist of games, calculates the total 'power'. The power of one game is product the minimum number of cubes required to make the game possible." (apply + (map (lambda (x) (apply * (cdr x))) games))) (define (filter-possible-games games have-rgb) (filter (lambda (x) (list<=? (cdr x) have-rgb)) games)) (define (list<=? lst1 lst2) (cond ((null? lst1) #t) ((null? lst2) #f) ((< (car lst2) (car lst1)) #f) (#t (list<=? (cdr lst1) (cdr lst2))))) (define (games->at-least str) "Given STR containing a new-line separated list of games and their corresponding draws, returns an alist containing the game identifiers as keys and a list numbers of each cube that must be present for the game to be possible." (let ((ret '())) (map (lambda (line) (unless (string-null? line) (let* ((gd-pair (string-split line #\:)) (num (string->number (substring (car gd-pair) 5))) (draws (cadr gd-pair))) (set! ret (acons num (game->seen draws) ret))))) (string-split (string-trim-both str char-set:whitespace) #\newline)) ret)) (define (game->seen str) "Given a single round of draws: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red Produces a list of numbers representing the maximum amount of each color seen at a time: '(20 13 6)" (let loop ((draws (string-split str #\;)) (cur-rgb '(0 0 0))) (if (null? draws) cur-rgb (loop (cdr draws) (take-max-instances cur-rgb (draw->colors (car draws))))))) (define (draw->colors str) "Given a string of a single draw, i.e.: 3 blue, 4 red returns a list of numbers representing the corresponding RGB: '(4 0 3)" (let loop ((colors (string-split str #\,)) (red 0) (green 0) (blue 0)) (if (or (null? colors) (zero? (string-length (car colors)))) (list red green blue) (let* ((nc-pair (string-split (string-trim (car colors)) #\space)) (num (string->number (car nc-pair))) (color (cadr nc-pair))) (cond ((equal? color "red") (set! red num)) ((equal? color "green") (set! green num)) ((equal? color "blue") (set! blue num))) (loop (cdr colors) red green blue))))) (define (take-max-instances cur-rgb new-rgb) "Given two lists representing a count of RGB cubes, return a new list that is the max of each element-wise." (map (lambda (c-pair) (max (car c-pair) (cadr c-pair))) (zip cur-rgb new-rgb)))