Skip to content
This repository was archived by the owner on May 30, 2023. It is now read-only.

Commit 6fc89ae

Browse files
Add gigasecond exercise (#125)
1 parent eed9ed4 commit 6fc89ae

File tree

9 files changed

+179
-0
lines changed

9 files changed

+179
-0
lines changed

config.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,16 @@
315315
"difficulty": 5,
316316
"topics": null
317317
},
318+
{
319+
"slug": "gigasecond",
320+
"name": "Gigasecond",
321+
"uuid": "3e8e9e3d-0999-4406-a46d-2a8e2cdfed45",
322+
"practices": [],
323+
"prerequisites": [
324+
"numbers"
325+
],
326+
"difficulty": 3
327+
},
318328
{
319329
"slug": "flatten-array",
320330
"name": "Flatten Array",
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Instructions
2+
3+
Your task is to determine the date and time one gigasecond after a certain date.
4+
5+
A gigasecond is one thousand million seconds.
6+
That is a one with nine zeros after it.
7+
8+
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)_.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Introduction
2+
3+
The way we measure time is kind of messy.
4+
We have 60 seconds in a minute, and 60 minutes in an hour.
5+
This comes from ancient Babylon, where they used 60 as the basis for their number system.
6+
We have 24 hours in a day, 7 days in a week, and how many days in a month?
7+
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.
8+
9+
What if, instead, we only use seconds to express time intervals?
10+
Then we can use metric system prefixes for writing large numbers of seconds in more easily comprehensible quantities.
11+
12+
- A food recipe might explain that you need to let the brownies cook in the oven for two kiloseconds (that's two thousand seconds).
13+
- Perhaps you and your family would travel to somewhere exotic for two megaseconds (that's two million seconds).
14+
- And if you and your spouse were married for _a thousand million_ seconds, you would celebrate your one gigasecond anniversary.
15+
16+
~~~~exercism/note
17+
If we ever colonize Mars or some other planet, measuring time is going to get even messier.
18+
If someone says "year" do they mean a year on Earth or a year on Mars?
19+
20+
The idea for this exercise came from the science fiction novel ["A Deepness in the Sky"][vinge-novel] by author Vernor Vinge.
21+
In it the author uses the metric system as the basis for time measurements.
22+
23+
[vinge-novel]: https://www.tor.com/2017/08/03/science-fiction-with-something-for-everyone-a-deepness-in-the-sky-by-vernor-vinge/
24+
~~~~
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"authors": [
3+
"ErikSchierboom"
4+
],
5+
"files": {
6+
"solution": [
7+
"src/gigasecond.cljs"
8+
],
9+
"test": [
10+
"test/gigasecond_test.cljs"
11+
],
12+
"example": [
13+
".meta/src/example.cljs"
14+
]
15+
},
16+
"blurb": "Given a moment, determine the moment that would be after a gigasecond has passed.",
17+
"source": "Chapter 9 in Chris Pine's online Learn to Program tutorial.",
18+
"source_url": "https://pine.fm/LearnToProgram/?Chapter=09"
19+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
(ns gigasecond)
2+
3+
;; Given a moment, compute the moment that would be after an arbitrary number
4+
;; of seconds has passed (one Gigasecond for this example).
5+
;;
6+
;; This function works is extreme cases like:
7+
;; * Periods of any size (any positive number of seconds)
8+
;; * Periods that include years like 1900 inside (oddly not leap year)
9+
;; * Periods that start (or end), before (or after), the end of February in
10+
;; years that are (or not) leap years
11+
;; * Periods that start (or end), before (or after), the start (or end) of any
12+
;; year
13+
;;
14+
;; Note: The number of seconds is embedded as `total-seconds` binding
15+
(defn from [y m d]
16+
;; Steps:
17+
;; 1) Convert time period to days
18+
;; 2) Compute result thru 3 sections of the period (Start, Middle, End)
19+
;; 2a) Start: Remaining days in first month of the period
20+
;; 2b) Middle: Find last month of the period (loop through months/years)
21+
;; 2c) End: Days in the last month of the period
22+
(letfn [;; Helper to compute boolean whether a year is leap or not
23+
(leap-year? [year]
24+
(cond
25+
(zero? (mod year 400)) true
26+
(zero? (mod year 100)) false
27+
:else (zero? (mod year 4))))
28+
29+
;; Helper to compute total number of days in a year's month
30+
(days-in-month [year month]
31+
(cond
32+
(= month 2) (if (leap-year? year) 29 28) ; February
33+
(some #(= month %) [4 6 9 11]) 30 ; Abril, June, ...
34+
:else 31)) ; January, March, ...
35+
36+
;; Helper to compute the number of remaining days of a date's month
37+
;; Ex.: [2000 2 27] results in 3 days because 2000 is a leap year
38+
;; so day 27, day 28 and day 29 are 3 days in total.
39+
;; (To obtain the total days of a particular month, set day to 1)
40+
(days-to-next-month [year month day]
41+
(+ (days-in-month year month) (- day) 1))]
42+
43+
(let [total-seconds 1e9 ;; Gigasecond (works with any positive number)
44+
seconds-per-day 86400 ;; 24 x 60 x 60
45+
;; Convert seconds to days
46+
total-days (int (/ total-seconds seconds-per-day))]
47+
48+
;; Loop thru months decrementing the the total days remaining in period
49+
(loop [;; Initialize date and total days in period
50+
year y
51+
month m
52+
day d
53+
remaining total-days]
54+
(let [;; Compute amount to jump according to distance to next month
55+
;; First loop cycle computes from date's day (step 2a)
56+
;; Following cycles compute from 1st of current month (step 2b)
57+
jump (days-to-next-month year month day)]
58+
;; Out of the loop when no more room for another month
59+
(if-not (>= remaining jump)
60+
;; Result (step 2c)
61+
[year month (+ day remaining)]
62+
;; Update to next month and increment year when necesary
63+
(recur ;; Increment year when December jumps to January
64+
(if (zero? (mod month 12)) (inc year) year)
65+
;; Circular month increment (December jumps to January)
66+
(inc (mod month 12))
67+
1 ;; 1st of month
68+
;; Decrement the the total days remaining in period
69+
(- remaining jump))))))))
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# This is an auto-generated file. Regular comments will be removed when this
2+
# file is regenerated. Regenerating will not touch any manually added keys,
3+
# so comments can be added in a "comment" key.
4+
5+
[92fbe71c-ea52-4fac-bd77-be38023cacf7]
6+
description = "date only specification of time"
7+
8+
[6d86dd16-6f7a-47be-9e58-bb9fb2ae1433]
9+
description = "second test for date only specification of time"
10+
11+
[77eb8502-2bca-4d92-89d9-7b39ace28dd5]
12+
description = "third test for date only specification of time"
13+
14+
[c9d89a7d-06f8-4e28-a305-64f1b2abc693]
15+
description = "full time specified"
16+
17+
[09d4e30e-728a-4b52-9005-be44a58d9eba]
18+
description = "full time with day roll-over"
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{:deps
2+
{org.clojure/clojure {:mvn/version "1.10.1"}
3+
org.clojure/clojurescript {:mvn/version "1.10.773"}}
4+
5+
:aliases
6+
{:test
7+
{:extra-paths ["test"]
8+
:extra-deps
9+
{olical/cljs-test-runner {:mvn/version "3.8.0"}}
10+
:main-opts ["-m" "cljs-test-runner.main"]}}}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
(ns gigasecond)
2+
3+
(defn from [] ;; <- arglist goes here
4+
;; your code goes here
5+
)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
(ns gigasecond-test
2+
(:require [clojure.test :refer [deftest is]]
3+
gigasecond))
4+
5+
(deftest from-apr-25-2011
6+
(is (= [2043 1 1] (gigasecond/from 2011 4 25))))
7+
8+
(deftest from-jun-13-1977
9+
(is (= [2009 2 19] (gigasecond/from 1977 6 13))))
10+
11+
(deftest from-jul-19-1959
12+
(is (= [1991 3 27] (gigasecond/from 1959 7 19))))
13+
14+
;; customize this to test your birthday and find your gigasecond date:
15+
;; (deftest your-birthday
16+
;; (is (= [year2 month2 day2] (gigasecond/from year1 month1 day1))))

0 commit comments

Comments
 (0)