From 9a6d9713678184657953e5a986f7211b82534742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Wed, 25 Oct 2023 22:34:01 -0700 Subject: [PATCH 1/2] Add clock exercise --- config.json | 8 + .../practice/clock/.docs/instructions.md | 7 + exercises/practice/clock/.meta/config.json | 18 ++ exercises/practice/clock/.meta/example.rkt | 46 ++++ exercises/practice/clock/.meta/tests.toml | 166 ++++++++++++ exercises/practice/clock/clock-test.rkt | 236 ++++++++++++++++++ exercises/practice/clock/clock.rkt | 19 ++ 7 files changed, 500 insertions(+) create mode 100644 exercises/practice/clock/.docs/instructions.md create mode 100644 exercises/practice/clock/.meta/config.json create mode 100644 exercises/practice/clock/.meta/example.rkt create mode 100644 exercises/practice/clock/.meta/tests.toml create mode 100644 exercises/practice/clock/clock-test.rkt create mode 100644 exercises/practice/clock/clock.rkt diff --git a/config.json b/config.json index 28eba6ab..b9514112 100644 --- a/config.json +++ b/config.json @@ -259,6 +259,14 @@ "prerequisites": [], "difficulty": 1 }, + { + "slug": "clock", + "name": "Clock", + "uuid": "5618c228-fa15-4450-9a61-b41369d7de06", + "practices": [], + "prerequisites": [], + "difficulty": 3 + }, { "slug": "etl", "name": "ETL", diff --git a/exercises/practice/clock/.docs/instructions.md b/exercises/practice/clock/.docs/instructions.md new file mode 100644 index 00000000..a1efc789 --- /dev/null +++ b/exercises/practice/clock/.docs/instructions.md @@ -0,0 +1,7 @@ +# Instructions + +Implement a clock that handles times without dates. + +You should be able to add and subtract minutes to it. + +Two clocks that represent the same time should be equal to each other. diff --git a/exercises/practice/clock/.meta/config.json b/exercises/practice/clock/.meta/config.json new file mode 100644 index 00000000..b26a9fe1 --- /dev/null +++ b/exercises/practice/clock/.meta/config.json @@ -0,0 +1,18 @@ +{ + "authors": [ + "BNAndras" + ], + "files": { + "solution": [ + "clock.rkt" + ], + "test": [ + "clock-test.rkt" + ], + "example": [ + ".meta/example.rkt" + ] + }, + "blurb": "Implement a clock that handles times without dates.", + "source": "Pairing session with Erin Drummond" +} diff --git a/exercises/practice/clock/.meta/example.rkt b/exercises/practice/clock/.meta/example.rkt new file mode 100644 index 00000000..e907066e --- /dev/null +++ b/exercises/practice/clock/.meta/example.rkt @@ -0,0 +1,46 @@ +#lang racket + +(provide (struct-out clock) + add + subtract + clock->string) + +(struct clock (hours minutes) + #:transparent + #:methods + gen:equal+hash + [(define (equal-proc self other rec) + (define normalized-self (normalize-clock self)) + (define normalized-other (normalize-clock other)) + (and (rec (clock-hours normalized-self) + (clock-hours normalized-other)) + (rec (clock-minutes normalized-self) + (clock-minutes normalized-other)))) + (define (hash-proc self rec) + (define normalized (normalize-clock self)) + (+ (* (rec (clock-hours normalized) 60) + (rec (clock-minutes normalized))))) + (define (hash2-proc self rec) + (define normalized (normalize-clock self)) + (+ (rec (clock-hours normalized)) + (/ (rec (clock-minutes normalized) 60))))]) + +(define (normalize-clock c) + (let* ([total-minutes (modulo (+ (* (clock-hours c) 60) (clock-minutes c)) 1440)] + [new-hours (modulo (quotient total-minutes 60) 24)] + [new-minutes (modulo (- total-minutes (* new-hours 60)) 60)]) + (clock new-hours new-minutes))) + +(define (clock->string c) + (define normalized (normalize-clock c)) + (~a (~a (clock-hours normalized) #:width 2 #:align 'right #:pad-string "0") + ":" + (~a (clock-minutes normalized) #:width 2 #:align 'right #:pad-string "0"))) + +(define (add c minutes) + (clock (clock-hours c) + (+ (clock-minutes c) minutes))) + +(define (subtract c minutes) + (clock (clock-hours c) + (- (clock-minutes c) minutes))) diff --git a/exercises/practice/clock/.meta/tests.toml b/exercises/practice/clock/.meta/tests.toml new file mode 100644 index 00000000..712c87bc --- /dev/null +++ b/exercises/practice/clock/.meta/tests.toml @@ -0,0 +1,166 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[a577bacc-106b-496e-9792-b3083ea8705e] +description = "Create a new clock with an initial time -> on the hour" + +[b5d0c360-3b88-489b-8e84-68a1c7a4fa23] +description = "Create a new clock with an initial time -> past the hour" + +[473223f4-65f3-46ff-a9f7-7663c7e59440] +description = "Create a new clock with an initial time -> midnight is zero hours" + +[ca95d24a-5924-447d-9a96-b91c8334725c] +description = "Create a new clock with an initial time -> hour rolls over" + +[f3826de0-0925-4d69-8ac8-89aea7e52b78] +description = "Create a new clock with an initial time -> hour rolls over continuously" + +[a02f7edf-dfd4-4b11-b21a-86de3cc6a95c] +description = "Create a new clock with an initial time -> sixty minutes is next hour" + +[8f520df6-b816-444d-b90f-8a477789beb5] +description = "Create a new clock with an initial time -> minutes roll over" + +[c75c091b-47ac-4655-8d40-643767fc4eed] +description = "Create a new clock with an initial time -> minutes roll over continuously" + +[06343ecb-cf39-419d-a3f5-dcbae0cc4c57] +description = "Create a new clock with an initial time -> hour and minutes roll over" + +[be60810e-f5d9-4b58-9351-a9d1e90e660c] +description = "Create a new clock with an initial time -> hour and minutes roll over continuously" + +[1689107b-0b5c-4bea-aad3-65ec9859368a] +description = "Create a new clock with an initial time -> hour and minutes roll over to exactly midnight" + +[d3088ee8-91b7-4446-9e9d-5e2ad6219d91] +description = "Create a new clock with an initial time -> negative hour" + +[77ef6921-f120-4d29-bade-80d54aa43b54] +description = "Create a new clock with an initial time -> negative hour rolls over" + +[359294b5-972f-4546-bb9a-a85559065234] +description = "Create a new clock with an initial time -> negative hour rolls over continuously" + +[509db8b7-ac19-47cc-bd3a-a9d2f30b03c0] +description = "Create a new clock with an initial time -> negative minutes" + +[5d6bb225-130f-4084-84fd-9e0df8996f2a] +description = "Create a new clock with an initial time -> negative minutes roll over" + +[d483ceef-b520-4f0c-b94a-8d2d58cf0484] +description = "Create a new clock with an initial time -> negative minutes roll over continuously" + +[1cd19447-19c6-44bf-9d04-9f8305ccb9ea] +description = "Create a new clock with an initial time -> negative sixty minutes is previous hour" + +[9d3053aa-4f47-4afc-bd45-d67a72cef4dc] +description = "Create a new clock with an initial time -> negative hour and minutes both roll over" + +[51d41fcf-491e-4ca0-9cae-2aa4f0163ad4] +description = "Create a new clock with an initial time -> negative hour and minutes both roll over continuously" + +[d098e723-ad29-4ef9-997a-2693c4c9d89a] +description = "Add minutes -> add minutes" + +[b6ec8f38-e53e-4b22-92a7-60dab1f485f4] +description = "Add minutes -> add no minutes" + +[efd349dd-0785-453e-9ff8-d7452a8e7269] +description = "Add minutes -> add to next hour" + +[749890f7-aba9-4702-acce-87becf4ef9fe] +description = "Add minutes -> add more than one hour" + +[da63e4c1-1584-46e3-8d18-c9dc802c1713] +description = "Add minutes -> add more than two hours with carry" + +[be167a32-3d33-4cec-a8bc-accd47ddbb71] +description = "Add minutes -> add across midnight" + +[6672541e-cdae-46e4-8be7-a820cc3be2a8] +description = "Add minutes -> add more than one day (1500 min = 25 hrs)" + +[1918050d-c79b-4cb7-b707-b607e2745c7e] +description = "Add minutes -> add more than two days" + +[37336cac-5ede-43a5-9026-d426cbe40354] +description = "Subtract minutes -> subtract minutes" + +[0aafa4d0-3b5f-4b12-b3af-e3a9e09c047b] +description = "Subtract minutes -> subtract to previous hour" + +[9b4e809c-612f-4b15-aae0-1df0acb801b9] +description = "Subtract minutes -> subtract more than an hour" + +[8b04bb6a-3d33-4e6c-8de9-f5de6d2c70d6] +description = "Subtract minutes -> subtract across midnight" + +[07c3bbf7-ce4d-4658-86e8-4a77b7a5ccd9] +description = "Subtract minutes -> subtract more than two hours" + +[90ac8a1b-761c-4342-9c9c-cdc3ed5db097] +description = "Subtract minutes -> subtract more than two hours with borrow" + +[2149f985-7136-44ad-9b29-ec023a97a2b7] +description = "Subtract minutes -> subtract more than one day (1500 min = 25 hrs)" + +[ba11dbf0-ac27-4acb-ada9-3b853ec08c97] +description = "Subtract minutes -> subtract more than two days" + +[f2fdad51-499f-4c9b-a791-b28c9282e311] +description = "Compare two clocks for equality -> clocks with same time" + +[5d409d4b-f862-4960-901e-ec430160b768] +description = "Compare two clocks for equality -> clocks a minute apart" + +[a6045fcf-2b52-4a47-8bb2-ef10a064cba5] +description = "Compare two clocks for equality -> clocks an hour apart" + +[66b12758-0be5-448b-a13c-6a44bce83527] +description = "Compare two clocks for equality -> clocks with hour overflow" + +[2b19960c-212e-4a71-9aac-c581592f8111] +description = "Compare two clocks for equality -> clocks with hour overflow by several days" + +[6f8c6541-afac-4a92-b0c2-b10d4e50269f] +description = "Compare two clocks for equality -> clocks with negative hour" + +[bb9d5a68-e324-4bf5-a75e-0e9b1f97a90d] +description = "Compare two clocks for equality -> clocks with negative hour that wraps" + +[56c0326d-565b-4d19-a26f-63b3205778b7] +description = "Compare two clocks for equality -> clocks with negative hour that wraps multiple times" + +[c90b9de8-ddff-4ffe-9858-da44a40fdbc2] +description = "Compare two clocks for equality -> clocks with minute overflow" + +[533a3dc5-59a7-491b-b728-a7a34fe325de] +description = "Compare two clocks for equality -> clocks with minute overflow by several days" + +[fff49e15-f7b7-4692-a204-0f6052d62636] +description = "Compare two clocks for equality -> clocks with negative minute" + +[605c65bb-21bd-43eb-8f04-878edf508366] +description = "Compare two clocks for equality -> clocks with negative minute that wraps" + +[b87e64ed-212a-4335-91fd-56da8421d077] +description = "Compare two clocks for equality -> clocks with negative minute that wraps multiple times" + +[822fbf26-1f3b-4b13-b9bf-c914816b53dd] +description = "Compare two clocks for equality -> clocks with negative hours and minutes" + +[e787bccd-cf58-4a1d-841c-ff80eaaccfaa] +description = "Compare two clocks for equality -> clocks with negative hours and minutes that wrap" + +[96969ca8-875a-48a1-86ae-257a528c44f5] +description = "Compare two clocks for equality -> full clock and zeroed clock" diff --git a/exercises/practice/clock/clock-test.rkt b/exercises/practice/clock/clock-test.rkt new file mode 100644 index 00000000..9fb7df62 --- /dev/null +++ b/exercises/practice/clock/clock-test.rkt @@ -0,0 +1,236 @@ +#lang racket/base + +(require "clock.rkt") + +(module+ test + (require rackunit rackunit/text-ui) + + (define suite + (test-suite + "clock tests" + + (test-equal? "Create a new clock with an initial time - on the hour" + (clock->string (clock 8 0)) + "08:00") + + (test-equal? "Create a new clock with an initial time - past the hour" + (clock->string (clock 11 9)) + "11:09") + + (test-equal? "Create a new clock with an initial time - midnight is zero hours" + (clock->string (clock 24 0)) + "00:00") + + (test-equal? "Create a new clock with an initial time - hour rolls over" + (clock->string (clock 25 0)) + "01:00") + + (test-equal? "Create a new clock with an initial time - hour rolls over continuously" + (clock->string (clock 100 0)) + "04:00") + + (test-equal? "Create a new clock with an initial time - sixty minutes is next hour" + (clock->string (clock 1 60)) + "02:00") + + (test-equal? "Create a new clock with an initial time - minutes roll over" + (clock->string (clock 0 160)) + "02:40") + + (test-equal? "Create a new clock with an initial time - minutes roll over continuously" + (clock->string (clock 0 1723)) + "04:43") + + (test-equal? "Create a new clock with an initial time - hour and minutes roll over" + (clock->string (clock 25 160)) + "03:40") + + (test-equal? "Create a new clock with an initial time - hour and minutes roll over continuously" + (clock->string (clock 201 3001)) + "11:01") + + (test-equal? "Create a new clock with an initial time - hour and minutes roll over to exactly midnight" + (clock->string (clock 72 8640)) + "00:00") + + (test-equal? "Create a new clock with an initial time - negative hour" + (clock->string (clock -1 15)) + "23:15") + + (test-equal? "Create a new clock with an initial time - negative hour rolls over" + (clock->string (clock -25 0)) + "23:00") + + (test-equal? "Create a new clock with an initial time - negative hour rolls over continuously" + (clock->string (clock -91 0)) + "05:00") + + (test-equal? "Create a new clock with an initial time - negative minutes" + (clock->string (clock 1 -40)) + "00:20") + + (test-equal? "Create a new clock with an initial time - negative minutes roll over" + (clock->string (clock 1 -160)) + "22:20") + + (test-equal? "Create a new clock with an initial time - negative minutes roll over continuously" + (clock->string (clock 1 -4820)) + "16:40") + + (test-equal? "Create a new clock with an initial time - negative sixty minutes is previous hour" + (clock->string (clock 2 -60)) + "01:00") + + (test-equal? "Create a new clock with an initial time - negative hour and minutes both roll over" + (clock->string (clock -25 -160)) + "20:20") + + (test-equal? "Create a new clock with an initial time - negative hour and minutes both roll over continuously" + (clock->string (clock -121 -5810)) + "22:10") + + (test-equal? "Add minutes - add minutes" + (clock->string (add (clock 10 0) + 3)) + "10:03") + + (test-equal? "Add minutes - add no minutes" + (clock->string (add (clock 6 41) + 0)) + "06:41") + + (test-equal? "Add minutes - add to next hour" + (clock->string (add (clock 0 45) + 40)) + "01:25") + + (test-equal? "Add minutes - add more than one hour" + (clock->string (add (clock 10 0) + 61)) + "11:01") + + (test-equal? "Add minutes - add more than two hours with carry" + (clock->string (add (clock 0 45) + 160)) + "03:25") + + (test-equal? "Add minutes - add across midnight" + (clock->string (add (clock 23 59) + 2)) + "00:01") + + (test-equal? "Add minutes - add more than one day (1500 min = 25 hrs)" + (clock->string (add (clock 5 32) + 1500)) + "06:32") + + (test-equal? "Add minutes - add more than two days" + (clock->string (add (clock 1 1) + 3500)) + "11:21") + + (test-equal? "Subtract minutes - subtract minutes" + (clock->string (subtract (clock 10 3) + 3)) + "10:00") + + (test-equal? "Subtract minutes - subtract to previous hour" + (clock->string (subtract (clock 10 3) + 30)) + "09:33") + + (test-equal? "Subtract minutes - subtract more than an hour" + (clock->string (subtract (clock 10 3) + 70)) + "08:53") + + (test-equal? "Subtract minutes - subtract across midnight" + (clock->string (subtract (clock 0 3) + 4)) + "23:59") + + (test-equal? "Subtract minutes - subtract more than two hours" + (clock->string (subtract (clock 0 0) + 160)) + "21:20") + + (test-equal? "Subtract minutes - subtract more than two hours with borrow" + (clock->string (subtract (clock 6 15) + 160)) + "03:35") + + (test-equal? "Subtract minutes - subtract more than one day (1500 min = 25 hrs)" + (clock->string (subtract (clock 5 32) + 1500)) + "04:32") + + (test-equal? "Subtract minutes - subtract more than two days" + (clock->string (subtract (clock 2 20) + 3000)) + "00:20") + + (test-equal? "Compare two clocks for equality - clocks with same time" + (clock 15 37) + (clock 15 37)) + + (test-case "Compare two clocks for equality - clocks a minute apart" + (check-not-equal? (clock 15 36) + (clock 15 37))) + + (test-case "Compare two clocks for equality - clocks an hour apart" + (check-not-equal? (clock 14 37) + (clock 15 37))) + + (test-equal? "Compare two clocks for equality - clocks with hour overflow" + (clock 10 37) + (clock 34 37)) + + (test-equal? "Compare two clocks for equality - clocks with hour overflow by several days" + (clock 3 11) + (clock 99 11)) + + (test-equal? "Compare two clocks for equality - clocks with negative hour" + (clock 22 40) + (clock -2 40)) + + (test-equal? "Compare two clocks for equality - clocks with negative hour that wraps" + (clock 17 3) + (clock -31 3)) + + (test-equal? "Compare two clocks for equality - clocks with negative hour that wraps multiple times" + (clock 13 49) + (clock -83 49)) + + (test-equal? "Compare two clocks for equality - clocks with minute overflow" + (clock 0 1) + (clock 0 1441)) + + (test-equal? "Compare two clocks for equality - clocks with minute overflow by several days" + (clock 2 2) + (clock 2 4322)) + + (test-equal? "Compare two clocks for equality - clocks with negative minute" + (clock 2 40) + (clock 3 -20)) + + (test-equal? "Compare two clocks for equality - clocks with negative minute that wraps" + (clock 4 10) + (clock 5 -1490)) + + (test-equal? "Compare two clocks for equality - clocks with negative minute that wraps multiple times" + (clock 6 15) + (clock 6 -4305)) + + (test-equal? "Compare two clocks for equality - clocks with negative hours and minutes" + (clock 7 32) + (clock -12 -268)) + + (test-equal? "Compare two clocks for equality - clocks with negative hours and minutes that wrap" + (clock 18 7) + (clock -54 -11513)) + + (test-equal? "Compare two clocks for equality - full clock and zeroed clock" + (clock 24 0) + (clock 0 0)))) + + (run-tests suite)) diff --git a/exercises/practice/clock/clock.rkt b/exercises/practice/clock/clock.rkt new file mode 100644 index 00000000..c6b6ac94 --- /dev/null +++ b/exercises/practice/clock/clock.rkt @@ -0,0 +1,19 @@ +#lang racket + +(provide (struct-out clock) + add + subtract + clock->string) + +(struct clock + ()) ; Add your implementation + + +(define (clock->string c) + (error "Not implemented yet")) + +(define (add c minutes) + (error "Not implemented yet")) + +(define (subtract c minutes) + (error "Not implemented yet")) From 99b9e7b9460d5eb63f92aec8e7bb56a66009e2d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20B=20Nagy?= <20251272+BNAndras@users.noreply.github.com> Date: Wed, 25 Oct 2023 22:48:20 -0700 Subject: [PATCH 2/2] Simplify stub --- exercises/practice/clock/clock.rkt | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/exercises/practice/clock/clock.rkt b/exercises/practice/clock/clock.rkt index c6b6ac94..1cce0782 100644 --- a/exercises/practice/clock/clock.rkt +++ b/exercises/practice/clock/clock.rkt @@ -1,13 +1,11 @@ #lang racket -(provide (struct-out clock) - add - subtract - clock->string) - -(struct clock - ()) ; Add your implementation +(provide clock + add + subtract + clock->string) +; We have provided stubs for add, subtract, and clock->string. The clock implementation is up to you. (define (clock->string c) (error "Not implemented yet"))