From 43629fee61fd7620372cd7bbaa98bff2647a0bfe Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 18 Oct 2024 21:26:23 +0200 Subject: [PATCH] Add `clock` exercise (#379) --- config.json | 8 + .../practice/clock/.docs/instructions.md | 7 + exercises/practice/clock/.meta/config.json | 18 ++ exercises/practice/clock/.meta/example.R | 31 ++ exercises/practice/clock/.meta/tests.toml | 166 ++++++++++ exercises/practice/clock/clock.R | 15 + exercises/practice/clock/test_clock.R | 294 ++++++++++++++++++ 7 files changed, 539 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.R create mode 100644 exercises/practice/clock/.meta/tests.toml create mode 100644 exercises/practice/clock/clock.R create mode 100644 exercises/practice/clock/test_clock.R diff --git a/config.json b/config.json index 95f219b4..57b5646d 100644 --- a/config.json +++ b/config.json @@ -857,6 +857,14 @@ "prerequisites": [], "difficulty": 4 }, + { + "slug": "clock", + "name": "Clock", + "uuid": "31e35849-81fe-488a-b020-e6cd9c003a05", + "practices": [], + "prerequisites": [], + "difficulty": 4 + }, { "slug": "nth-prime", "name": "Nth Prime", 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..258f4d06 --- /dev/null +++ b/exercises/practice/clock/.meta/config.json @@ -0,0 +1,18 @@ +{ + "authors": [ + "erikschierboom" + ], + "files": { + "solution": [ + "clock.R" + ], + "test": [ + "test_clock.R" + ], + "example": [ + ".meta/example.R" + ] + }, + "blurb": "Implement a clock that handles times without dates.", + "source": "Pairing session with Erin Drummond" +} diff --git a/exercises/practice/clock/.meta/example.R b/exercises/practice/clock/.meta/example.R new file mode 100644 index 00000000..b0ca5d6b --- /dev/null +++ b/exercises/practice/clock/.meta/example.R @@ -0,0 +1,31 @@ +library(stringr) + +new_clock <- function(hours, minutes) { + total_minutes <- (hours * 60 + minutes) %% 1440 + + structure( + list( + hours = total_minutes %/% 60, + minutes = total_minutes %% 60 + ), + class = "Clock" + ) +} + +display <- function(clock) { + hours <- str_pad(as.character(clock$hours), 2, pad = "0") + minutes <- str_pad(as.character(clock$minutes), 2, pad = "0") + paste(hours, minutes, sep = ":") +} + +add <- function(clock, minutes) { + new_clock(clock$hours, clock$minutes + minutes) +} + +subtract <- function(clock, minutes) { + new_clock(clock$hours, clock$minutes - minutes) +} + +`==.Clock` <- function(clock1, clock2) { + clock1$hours == clock2$hours && clock1$minutes == clock2$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.R b/exercises/practice/clock/clock.R new file mode 100644 index 00000000..8b16d45b --- /dev/null +++ b/exercises/practice/clock/clock.R @@ -0,0 +1,15 @@ +new_clock <- function(hours, minutes) { + +} + +display <- function(clock) { + +} + +add <- function(clock, minutes) { + +} + +subtract <- function(clock, minutes) { + +} diff --git a/exercises/practice/clock/test_clock.R b/exercises/practice/clock/test_clock.R new file mode 100644 index 00000000..bfbbc9cf --- /dev/null +++ b/exercises/practice/clock/test_clock.R @@ -0,0 +1,294 @@ +source("./clock.R") +library(testthat) + +test_that("On the hour", { + clock <- new_clock(8, 0) + expect_equal(display(clock), "08:00") +}) + +test_that("Past the hour", { + clock <- new_clock(11, 9) + expect_equal(display(clock), "11:09") +}) + +test_that("Midnight is zero hours", { + clock <- new_clock(24, 0) + expect_equal(display(clock), "00:00") +}) + +test_that("Hour rolls over", { + clock <- new_clock(25, 0) + expect_equal(display(clock), "01:00") +}) + +test_that("Hour rolls over continuously", { + clock <- new_clock(100, 0) + expect_equal(display(clock), "04:00") +}) + +test_that("Sixty minutes is next hour", { + clock <- new_clock(1, 60) + expect_equal(display(clock), "02:00") +}) + +test_that("Minutes roll over", { + clock <- new_clock(0, 160) + expect_equal(display(clock), "02:40") +}) + +test_that("Minutes roll over continuously", { + clock <- new_clock(0, 1723) + expect_equal(display(clock), "04:43") +}) + +test_that("Hour and minutes roll over", { + clock <- new_clock(25, 160) + expect_equal(display(clock), "03:40") +}) + +test_that("Hour and minutes roll over continuously", { + clock <- new_clock(201, 3001) + expect_equal(display(clock), "11:01") +}) + +test_that("Hour and minutes roll over to exactly midnight", { + clock <- new_clock(72, 8640) + expect_equal(display(clock), "00:00") +}) + +test_that("Negative hour", { + clock <- new_clock(-1, 15) + expect_equal(display(clock), "23:15") +}) + +test_that("Negative hour rolls over", { + clock <- new_clock(-25, 0) + expect_equal(display(clock), "23:00") +}) + +test_that("Negative hour rolls over continuously", { + clock <- new_clock(-91, 0) + expect_equal(display(clock), "05:00") +}) + +test_that("Negative minutes", { + clock <- new_clock(1, -40) + expect_equal(display(clock), "00:20") +}) + +test_that("Negative minutes roll over", { + clock <- new_clock(1, -160) + expect_equal(display(clock), "22:20") +}) + +test_that("Negative minutes roll over continuously", { + clock <- new_clock(1, -4820) + expect_equal(display(clock), "16:40") +}) + +test_that("Negative sixty minutes is previous hour", { + clock <- new_clock(2, -60) + expect_equal(display(clock), "01:00") +}) + +test_that("Negative hour and minutes both roll over", { + clock <- new_clock(-25, -160) + expect_equal(display(clock), "20:20") +}) + +test_that("Negative hour and minutes both roll over continuously", { + clock <- new_clock(-121, -5810) + expect_equal(display(clock), "22:10") +}) + +test_that("Add minutes", { + clock <- new_clock(10, 0) + added_clock <- add(clock, 3) + expect_equal(display(added_clock), "10:03") +}) + +test_that("Add no minutes", { + clock <- new_clock(6, 41) + added_clock <- add(clock, 0) + expect_equal(display(added_clock), "06:41") +}) + +test_that("Add to next hour", { + clock <- new_clock(0, 45) + added_clock <- add(clock, 40) + expect_equal(display(added_clock), "01:25") +}) + +test_that("Add more than one hour", { + clock <- new_clock(10, 0) + added_clock <- add(clock, 61) + expect_equal(display(added_clock), "11:01") +}) + +test_that("Add more than two hours with carry", { + clock <- new_clock(0, 45) + added_clock <- add(clock, 160) + expect_equal(display(added_clock), "03:25") +}) + +test_that("Add across midnight", { + clock <- new_clock(23, 59) + added_clock <- add(clock, 2) + expect_equal(display(added_clock), "00:01") +}) + +test_that("Add more than one day (1500 min == 25 hrs)", { + clock <- new_clock(5, 32) + added_clock <- add(clock, 1500) + expect_equal(display(added_clock), "06:32") +}) + +test_that("Add more than two days", { + clock <- new_clock(1, 1) + added_clock <- add(clock, 3500) + expect_equal(display(added_clock), "11:21") +}) + +test_that("Subtract minutes", { + clock <- new_clock(10, 3) + subtracted_clock <- subtract(clock, 3) + expect_equal(display(subtracted_clock), "10:00") +}) + +test_that("Subtract to previous hour", { + clock <- new_clock(10, 3) + subtracted_clock <- subtract(clock, 30) + expect_equal(display(subtracted_clock), "09:33") +}) + +test_that("Subtract more than an hour", { + clock <- new_clock(10, 3) + subtracted_clock <- subtract(clock, 70) + expect_equal(display(subtracted_clock), "08:53") +}) + +test_that("Subtract across midnight", { + clock <- new_clock(0, 3) + subtracted_clock <- subtract(clock, 4) + expect_equal(display(subtracted_clock), "23:59") +}) + +test_that("Subtract more than two hours", { + clock <- new_clock(0, 0) + subtracted_clock <- subtract(clock, 160) + expect_equal(display(subtracted_clock), "21:20") +}) + +test_that("Subtract more than two hours with borrow", { + clock <- new_clock(6, 15) + subtracted_clock <- subtract(clock, 160) + expect_equal(display(subtracted_clock), "03:35") +}) + +test_that("Subtract more than one day (1500 min == 25 hrs)", { + clock <- new_clock(5, 32) + subtracted_clock <- subtract(clock, 1500) + expect_equal(display(subtracted_clock), "04:32") +}) + +test_that("Subtract more than two days", { + clock <- new_clock(2, 20) + subtracted_clock <- subtract(clock, 3000) + expect_equal(display(subtracted_clock), "00:20") +}) + +test_that("Clocks with same time", { + clock1 <- new_clock(15, 37) + clock2 <- new_clock(15, 37) + expect_equal(clock1, clock2) +}) + +test_that("Clocks a minute apart", { + clock1 <- new_clock(15, 36) + clock2 <- new_clock(15, 37) + expect_false(clock1 == clock2) +}) + +test_that("Clocks an hour apart", { + clock1 <- new_clock(14, 37) + clock2 <- new_clock(15, 37) + expect_false(clock1 == clock2) +}) + +test_that("Clocks with hour overflow", { + clock1 <- new_clock(10, 37) + clock2 <- new_clock(34, 37) + expect_equal(clock1, clock2) +}) + +test_that("Clocks with hour overflow by several days", { + clock1 <- new_clock(3, 11) + clock2 <- new_clock(99, 11) + expect_equal(clock1, clock2) +}) + +test_that("Clocks with negative hour", { + clock1 <- new_clock(22, 40) + clock2 <- new_clock(-2, 40) + expect_equal(clock1, clock2) +}) + +test_that("Clocks with negative hour that wraps", { + clock1 <- new_clock(17, 3) + clock2 <- new_clock(-31, 3) + expect_equal(clock1, clock2) +}) + +test_that("Clocks with negative hour that wraps multiple times", { + clock1 <- new_clock(13, 49) + clock2 <- new_clock(-83, 49) + expect_equal(clock1, clock2) +}) + +test_that("Clocks with minute overflow", { + clock1 <- new_clock(0, 1) + clock2 <- new_clock(0, 1441) + expect_equal(clock1, clock2) +}) + +test_that("Clocks with minute overflow by several days", { + clock1 <- new_clock(2, 2) + clock2 <- new_clock(2, 4322) + expect_equal(clock1, clock2) +}) + +test_that("Clocks with negative minute", { + clock1 <- new_clock(2, 40) + clock2 <- new_clock(3, -20) + expect_equal(clock1, clock2) +}) + +test_that("Clocks with negative minute that wraps", { + clock1 <- new_clock(4, 10) + clock2 <- new_clock(5, -1490) + expect_equal(clock1, clock2) +}) + +test_that("Clocks with negative minute that wraps multiple times", { + clock1 <- new_clock(6, 15) + clock2 <- new_clock(6, -4305) + expect_equal(clock1, clock2) +}) + +test_that("Clocks with negative hours and minutes", { + clock1 <- new_clock(7, 32) + clock2 <- new_clock(-12, -268) + expect_equal(clock1, clock2) +}) + +test_that("Clocks with negative hours and minutes that wrap", { + clock1 <- new_clock(18, 7) + clock2 <- new_clock(-54, -11513) + expect_equal(clock1, clock2) +}) + +test_that("Full clock and zeroed clock", { + clock1 <- new_clock(24, 0) + clock2 <- new_clock(0, 0) + expect_equal(clock1, clock2) +})