From 17a34ec1fe2f23c60d3bdc870eaaa1bc04177e71 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 5 May 2023 16:28:26 +0200 Subject: [PATCH] Add gigasecond exercise --- config.json | 10 +++ .../practice/gigasecond/.docs/instructions.md | 8 +++ .../practice/gigasecond/.docs/introduction.md | 24 +++++++ .../practice/gigasecond/.meta/config.json | 19 +++++ .../gigasecond/.meta/src/example.cljs | 69 +++++++++++++++++++ .../practice/gigasecond/.meta/tests.toml | 18 +++++ exercises/practice/gigasecond/deps.edn | 10 +++ .../practice/gigasecond/src/gigasecond.cljs | 5 ++ .../gigasecond/test/gigasecond_test.cljs | 16 +++++ 9 files changed, 179 insertions(+) create mode 100644 exercises/practice/gigasecond/.docs/instructions.md create mode 100644 exercises/practice/gigasecond/.docs/introduction.md create mode 100644 exercises/practice/gigasecond/.meta/config.json create mode 100644 exercises/practice/gigasecond/.meta/src/example.cljs create mode 100644 exercises/practice/gigasecond/.meta/tests.toml create mode 100644 exercises/practice/gigasecond/deps.edn create mode 100644 exercises/practice/gigasecond/src/gigasecond.cljs create mode 100644 exercises/practice/gigasecond/test/gigasecond_test.cljs diff --git a/config.json b/config.json index 84014968..1f2ba88d 100644 --- a/config.json +++ b/config.json @@ -314,6 +314,16 @@ "prerequisites": [], "difficulty": 5, "topics": null + }, + { + "slug": "gigasecond", + "name": "Gigasecond", + "uuid": "3e8e9e3d-0999-4406-a46d-2a8e2cdfed45", + "practices": [], + "prerequisites": [ + "numbers" + ], + "difficulty": 3 } ] }, diff --git a/exercises/practice/gigasecond/.docs/instructions.md b/exercises/practice/gigasecond/.docs/instructions.md new file mode 100644 index 00000000..1e20f002 --- /dev/null +++ b/exercises/practice/gigasecond/.docs/instructions.md @@ -0,0 +1,8 @@ +# Instructions + +Your task is to determine the date and time one gigasecond after a certain date. + +A gigasecond is one thousand million seconds. +That is a one with nine zeros after it. + +If you were born on _January 24th, 2015 at 22:00 (10:00:00pm)_, then you would be a gigasecond old on _October 2nd, 2046 at 23:46:40 (11:46:40pm)_. diff --git a/exercises/practice/gigasecond/.docs/introduction.md b/exercises/practice/gigasecond/.docs/introduction.md new file mode 100644 index 00000000..18a3dc20 --- /dev/null +++ b/exercises/practice/gigasecond/.docs/introduction.md @@ -0,0 +1,24 @@ +# Introduction + +The way we measure time is kind of messy. +We have 60 seconds in a minute, and 60 minutes in an hour. +This comes from ancient Babylon, where they used 60 as the basis for their number system. +We have 24 hours in a day, 7 days in a week, and how many days in a month? +Well, for days in a month it depends not only on which month it is, but also on what type of calendar is used in the country you live in. + +What if, instead, we only use seconds to express time intervals? +Then we can use metric system prefixes for writing large numbers of seconds in more easily comprehensible quantities. + +- A food recipe might explain that you need to let the brownies cook in the oven for two kiloseconds (that's two thousand seconds). +- Perhaps you and your family would travel to somewhere exotic for two megaseconds (that's two million seconds). +- And if you and your spouse were married for _a thousand million_ seconds, you would celebrate your one gigasecond anniversary. + +~~~~exercism/note +If we ever colonize Mars or some other planet, measuring time is going to get even messier. +If someone says "year" do they mean a year on Earth or a year on Mars? + +The idea for this exercise came from the science fiction novel ["A Deepness in the Sky"][vinge-novel] by author Vernor Vinge. +In it the author uses the metric system as the basis for time measurements. + +[vinge-novel]: https://www.tor.com/2017/08/03/science-fiction-with-something-for-everyone-a-deepness-in-the-sky-by-vernor-vinge/ +~~~~ diff --git a/exercises/practice/gigasecond/.meta/config.json b/exercises/practice/gigasecond/.meta/config.json new file mode 100644 index 00000000..3133a1af --- /dev/null +++ b/exercises/practice/gigasecond/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "ErikSchierboom" + ], + "files": { + "solution": [ + "src/gigasecond.cljs" + ], + "test": [ + "test/gigasecond_test.cljs" + ], + "example": [ + ".meta/src/example.cljs" + ] + }, + "blurb": "Given a moment, determine the moment that would be after a gigasecond has passed.", + "source": "Chapter 9 in Chris Pine's online Learn to Program tutorial.", + "source_url": "https://pine.fm/LearnToProgram/?Chapter=09" +} diff --git a/exercises/practice/gigasecond/.meta/src/example.cljs b/exercises/practice/gigasecond/.meta/src/example.cljs new file mode 100644 index 00000000..71a14023 --- /dev/null +++ b/exercises/practice/gigasecond/.meta/src/example.cljs @@ -0,0 +1,69 @@ +(ns gigasecond) + +;; Given a moment, compute the moment that would be after an arbitrary number +;; of seconds has passed (one Gigasecond for this example). +;; +;; This function works is extreme cases like: +;; * Periods of any size (any positive number of seconds) +;; * Periods that include years like 1900 inside (oddly not leap year) +;; * Periods that start (or end), before (or after), the end of February in +;; years that are (or not) leap years +;; * Periods that start (or end), before (or after), the start (or end) of any +;; year +;; +;; Note: The number of seconds is embedded as `total-seconds` binding +(defn from [y m d] + ;; Steps: + ;; 1) Convert time period to days + ;; 2) Compute result thru 3 sections of the period (Start, Middle, End) + ;; 2a) Start: Remaining days in first month of the period + ;; 2b) Middle: Find last month of the period (loop through months/years) + ;; 2c) End: Days in the last month of the period + (letfn [;; Helper to compute boolean whether a year is leap or not + (leap-year? [year] + (cond + (zero? (mod year 400)) true + (zero? (mod year 100)) false + :else (zero? (mod year 4)))) + + ;; Helper to compute total number of days in a year's month + (days-in-month [year month] + (cond + (= month 2) (if (leap-year? year) 29 28) ; February + (some #(= month %) [4 6 9 11]) 30 ; Abril, June, ... + :else 31)) ; January, March, ... + + ;; Helper to compute the number of remaining days of a date's month + ;; Ex.: [2000 2 27] results in 3 days because 2000 is a leap year + ;; so day 27, day 28 and day 29 are 3 days in total. + ;; (To obtain the total days of a particular month, set day to 1) + (days-to-next-month [year month day] + (+ (days-in-month year month) (- day) 1))] + + (let [total-seconds 1e9 ;; Gigasecond (works with any positive number) + seconds-per-day 86400 ;; 24 x 60 x 60 + ;; Convert seconds to days + total-days (int (/ total-seconds seconds-per-day))] + + ;; Loop thru months decrementing the the total days remaining in period + (loop [;; Initialize date and total days in period + year y + month m + day d + remaining total-days] + (let [;; Compute amount to jump according to distance to next month + ;; First loop cycle computes from date's day (step 2a) + ;; Following cycles compute from 1st of current month (step 2b) + jump (days-to-next-month year month day)] + ;; Out of the loop when no more room for another month + (if-not (>= remaining jump) + ;; Result (step 2c) + [year month (+ day remaining)] + ;; Update to next month and increment year when necesary + (recur ;; Increment year when December jumps to January + (if (zero? (mod month 12)) (inc year) year) + ;; Circular month increment (December jumps to January) + (inc (mod month 12)) + 1 ;; 1st of month + ;; Decrement the the total days remaining in period + (- remaining jump)))))))) \ No newline at end of file diff --git a/exercises/practice/gigasecond/.meta/tests.toml b/exercises/practice/gigasecond/.meta/tests.toml new file mode 100644 index 00000000..18672327 --- /dev/null +++ b/exercises/practice/gigasecond/.meta/tests.toml @@ -0,0 +1,18 @@ +# This is an auto-generated file. Regular comments will be removed when this +# file is regenerated. Regenerating will not touch any manually added keys, +# so comments can be added in a "comment" key. + +[92fbe71c-ea52-4fac-bd77-be38023cacf7] +description = "date only specification of time" + +[6d86dd16-6f7a-47be-9e58-bb9fb2ae1433] +description = "second test for date only specification of time" + +[77eb8502-2bca-4d92-89d9-7b39ace28dd5] +description = "third test for date only specification of time" + +[c9d89a7d-06f8-4e28-a305-64f1b2abc693] +description = "full time specified" + +[09d4e30e-728a-4b52-9005-be44a58d9eba] +description = "full time with day roll-over" diff --git a/exercises/practice/gigasecond/deps.edn b/exercises/practice/gigasecond/deps.edn new file mode 100644 index 00000000..5c65da55 --- /dev/null +++ b/exercises/practice/gigasecond/deps.edn @@ -0,0 +1,10 @@ +{:deps + {org.clojure/clojure {:mvn/version "1.10.1"} + org.clojure/clojurescript {:mvn/version "1.10.773"}} + + :aliases + {:test + {:extra-paths ["test"] + :extra-deps + {olical/cljs-test-runner {:mvn/version "3.8.0"}} + :main-opts ["-m" "cljs-test-runner.main"]}}} diff --git a/exercises/practice/gigasecond/src/gigasecond.cljs b/exercises/practice/gigasecond/src/gigasecond.cljs new file mode 100644 index 00000000..aee6ff2c --- /dev/null +++ b/exercises/practice/gigasecond/src/gigasecond.cljs @@ -0,0 +1,5 @@ +(ns gigasecond) + +(defn from [] ;; <- arglist goes here + ;; your code goes here +) diff --git a/exercises/practice/gigasecond/test/gigasecond_test.cljs b/exercises/practice/gigasecond/test/gigasecond_test.cljs new file mode 100644 index 00000000..6cdf3f06 --- /dev/null +++ b/exercises/practice/gigasecond/test/gigasecond_test.cljs @@ -0,0 +1,16 @@ +(ns gigasecond-test + (:require [clojure.test :refer [deftest is]] + gigasecond)) + +(deftest from-apr-25-2011 + (is (= [2043 1 1] (gigasecond/from 2011 4 25)))) + +(deftest from-jun-13-1977 + (is (= [2009 2 19] (gigasecond/from 1977 6 13)))) + +(deftest from-jul-19-1959 + (is (= [1991 3 27] (gigasecond/from 1959 7 19)))) + +;; customize this to test your birthday and find your gigasecond date: +;; (deftest your-birthday +;; (is (= [year2 month2 day2] (gigasecond/from year1 month1 day1))))