diff options
author | Ben Sima <ben@bsima.me> | 2022-11-19 13:00:30 -0500 |
---|---|---|
committer | Ben Sima <ben@bsima.me> | 2022-11-19 13:00:30 -0500 |
commit | 6100600fbf7d86218a71d735b2c08a61a520c02a (patch) | |
tree | 7dd9429cfbc9b8c63bb803045831484b8e1c0fff | |
parent | 49f60c2f36202fcdceb99e0ddf656681afa902d1 (diff) |
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | northwoods/.envrc | 1 | ||||
-rw-r--r-- | northwoods/guile.scm | 100 | ||||
-rw-r--r-- | northwoods/shell.nix | 5 |
4 files changed, 108 insertions, 1 deletions
@@ -1,3 +1,4 @@ client_session_key.aes .stack-work -state/
\ No newline at end of file +state/ +.direnv diff --git a/northwoods/.envrc b/northwoods/.envrc new file mode 100644 index 0000000..1d953f4 --- /dev/null +++ b/northwoods/.envrc @@ -0,0 +1 @@ +use nix diff --git a/northwoods/guile.scm b/northwoods/guile.scm new file mode 100644 index 0000000..8dea315 --- /dev/null +++ b/northwoods/guile.scm @@ -0,0 +1,100 @@ +#| +Babysitter Kata + +Background +---------- +This kata simulates a babysitter working and getting paid for one night. The rules are pretty straight forward: + +The babysitter +- starts no earlier than 5:00PM +- leaves no later than 4:00AM +- gets paid $12/hour from start-time to bedtime +- gets paid $8/hour from bedtime to midnight +- gets paid $16/hour from midnight to end of job +- gets paid for full hours (no fractional hours) + + +Feature: +As a babysitter +In order to get paid for 1 night of work +I want to calculate my nightly charge +|# + +;; doing this in guile scheme because they said i could use any language, and if +;; i'm gonna be writing code on saturday morning its gonna be lisp :P + +(import (only (rnrs base) assert)) + +(define +max+ 4) ;; can't work longer than 4am +(define +start+ 5) ;; can't start before 5pm + +;; times are represented as a pair of (hours . minutes) +(define (h time) (car time)) +(define (m time) (cdr time)) + +;; if hour is > 1 && < +max+, add 12h to account for midnight rollover +;; (always call this on end time) +(define (handle-midnight time) + (if (and (>= (h time) 1) (<= (h time) +max+)) + `(,(+ 12 (h time)) . ,(m time)) + time)) + +;; round-* functions return just the hour for simplicity, but ideally these +;; would operate on a <time> object that has + and - methods defined + +(define (round-down time) (h time)) + +(define (round-up time) + (if (> (m time) 0) + (+ (h time) 1) + (h time))) + +;; lookup table for pay rates +(define (payrate s) + (case s + ((prebed) 12) ;; before baby is asleep + ((postbed) 8) ;; after baby is asleep + ((postmidnight) 16) ;; from midnight until 4am or end of job + (else #f) ;; bad input, blowup + )) + +;; better way to do this would be with contracts, or parsing, or objects, but +;; base scheme doesn't have these so whatever +(define (valid-inputs? start end bedtime) + (and (pair? start) + (pair? end) + (pair? bedtime) + (or (>= (h start) +start+) + (error "cannot start before 5pm")) + (or (<= (h (handle-midnight end)) (h (handle-midnight `(,+max+ . 00)))) + (error "working hours must be between 5pm-4am (+start+ and +max+)")))) + +;; after validating and conforming the data, the core of the program is just +;; bucket the hours by payrate and sum them up +(define (charge start end bedtime) + (if (valid-inputs? start end bedtime) + (let ((hours-prebed (- (round-up bedtime) (round-down start))) + (hours-postbed (- 12 (round-up bedtime))) + (hours-postmidnight (- (round-up (handle-midnight end)) 12))) + (+ (* (payrate 'prebed) hours-prebed) + (* (payrate 'postbed) hours-postbed) + (* (payrate 'postmidnight) hours-postmidnight))) + #f)) + +;; simple tests +(define (test) + ;; happy path + ;; 3*12 + 4*8 + 3*12 = 116 + (assert (= 116 + (charge + '(5 . 34) + '(2 . 45) ;; late night! + '(8 . 00)))) + ;; 12*4 + 8*2 + 16*0 = 64 + (assert (= 64 + (charge + '(6 . 00) + '(11 . 30) ;; this is more my style + '(9 . 15)))) + ;; test bad inputs + (assert (equal? #f (charge '(60 . 60) "string" 1234)))) diff --git a/northwoods/shell.nix b/northwoods/shell.nix new file mode 100644 index 0000000..cae47b1 --- /dev/null +++ b/northwoods/shell.nix @@ -0,0 +1,5 @@ +with import <nixpkgs> {}; +mkShell { + name = "guile env"; + buildInputs = [ pkgs.guile_3_0 ]; +} |