summaryrefslogtreecommitdiff
path: root/cube-conundrum/cc.scm
diff options
context:
space:
mode:
Diffstat (limited to 'cube-conundrum/cc.scm')
-rw-r--r--cube-conundrum/cc.scm110
1 files changed, 110 insertions, 0 deletions
diff --git a/cube-conundrum/cc.scm b/cube-conundrum/cc.scm
new file mode 100644
index 0000000..de62808
--- /dev/null
+++ b/cube-conundrum/cc.scm
@@ -0,0 +1,110 @@
+(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)))