diff options
| author | Mohammad S Anwar <Mohammad.Anwar@yahoo.com> | 2021-03-13 08:29:57 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-03-13 08:29:57 +0000 |
| commit | d1438fe7cb03045f357c4e9ac389e16cea3c018c (patch) | |
| tree | 2441d7916335d2e15d9d06e8bb4dddd49d9b9dbe | |
| parent | 69182a0400e1559360606bc2dcc4e61d2e9d95f4 (diff) | |
| parent | 3b18f59bca6f28ad739545b92970d232c81d2d44 (diff) | |
| download | perlweeklychallenge-club-d1438fe7cb03045f357c4e9ac389e16cea3c018c.tar.gz perlweeklychallenge-club-d1438fe7cb03045f357c4e9ac389e16cea3c018c.tar.bz2 perlweeklychallenge-club-d1438fe7cb03045f357c4e9ac389e16cea3c018c.zip | |
Merge pull request #3709 from tylerw/tw/challenge-103
Ch103 (Clojure): Tasks 1 & 2
6 files changed, 147 insertions, 1 deletions
diff --git a/challenge-103/tyler-wardhaugh/clojure/deps.edn b/challenge-103/tyler-wardhaugh/clojure/deps.edn index 072d0028a0..17f4f62bb1 100644 --- a/challenge-103/tyler-wardhaugh/clojure/deps.edn +++ b/challenge-103/tyler-wardhaugh/clojure/deps.edn @@ -1,6 +1,10 @@ {:paths ["src" "resources"] :deps {org.clojure/clojure {:mvn/version "1.10.1"} - clj-http/clj-http {:mvn/version "3.12.1"}} + org.clojure/data.finger-tree {:mvn/version "0.0.3"} + org.clojure/data.csv {:mvn/version "1.0.0"} + clojure.java-time/clojure.java-time {:mvn/version "0.3.2"} + net.time4j/time4j-base {:mvn/version "5.7"} +} :aliases {:test {:extra-paths ["test"] :extra-deps {org.clojure/test.check {:mvn/version "1.0.0"}}} diff --git a/challenge-103/tyler-wardhaugh/clojure/resources/stream.csv b/challenge-103/tyler-wardhaugh/clojure/resources/stream.csv new file mode 100644 index 0000000000..9428b93004 --- /dev/null +++ b/challenge-103/tyler-wardhaugh/clojure/resources/stream.csv @@ -0,0 +1,7 @@ +1709363,"Les Miserables Episode 1: The Bishop (broadcast date: 1937-07-23)" +1723781,"Les Miserables Episode 2: Javert (broadcast date: 1937-07-30)" +1723781,"Les Miserables Episode 3: The Trial (broadcast date: 1937-08-06)" +1678356,"Les Miserables Episode 4: Cosette (broadcast date: 1937-08-13)" +1646043,"Les Miserables Episode 5: The Grave (broadcast date: 1937-08-20)" +1714640,"Les Miserables Episode 6: The Barricade (broadcast date: 1937-08-27)" +1714640,"Les Miserables Episode 7: Conclusion (broadcast date: 1937-09-03)" diff --git a/challenge-103/tyler-wardhaugh/clojure/src/tw/weekly/c103/core.clj b/challenge-103/tyler-wardhaugh/clojure/src/tw/weekly/c103/core.clj new file mode 100644 index 0000000000..ae62f7f638 --- /dev/null +++ b/challenge-103/tyler-wardhaugh/clojure/src/tw/weekly/c103/core.clj @@ -0,0 +1,12 @@ +(ns tw.weekly.c103.core + (:require [tw.weekly.c103.t1 :as t1]) + (:require [tw.weekly.c103.t2 :as t2]) + (:gen-class)) + +(defn -main + "Run all tasks" + [& _] + (println "Task #1:") + (t1/-main) + (println "\nTask #2:") + (t2/-main)) diff --git a/challenge-103/tyler-wardhaugh/clojure/src/tw/weekly/c103/t1.clj b/challenge-103/tyler-wardhaugh/clojure/src/tw/weekly/c103/t1.clj new file mode 100644 index 0000000000..1807978094 --- /dev/null +++ b/challenge-103/tyler-wardhaugh/clojure/src/tw/weekly/c103/t1.clj @@ -0,0 +1,59 @@ +(ns tw.weekly.c103.t1 + (:require [clojure.edn :as edn] + [clojure.string :as str] + [clojure.data.finger-tree :as ft] + [clojure.pprint :refer [cl-format]]) + (:import (java.util Locale) + (net.time4j.calendar ChineseCalendar) + (net.time4j PlainDate))) + +;;; +; Task description for TASK #1 › Chinese Zodiac +;;; +(def DEFAULT-INPUT 2017) + +;; A counted-double-list is a type of finger tree that provides: +;; O(n) left/right access +;; O(n) count +;; O(log n) nth +(def ANIMALS (into ft/empty-counted-double-list + ["Rat" "Ox" "Tiger" "Rabbit" "Dragon" "Snake" "Horse" "Goat" + "Monkey" "Rooster" "Dog" "Pig"])) +(def ELEMENTS (into ft/empty-counted-double-list + ["Wood" "Fire" "Earth" "Metal" "Water"])) + +; First "Wood Rat" year in CE +(def BASE-YEAR 4) + +(defn chinese-zodiac-simple + "Determine the Chinese Zodiac name for the given year, using a + simple, but slightly naïve algorithm." + [year] + (let [indexes ((juxt #(mod (quot % 2) (count ELEMENTS)) + #(mod % (count ANIMALS))) + (- year BASE-YEAR)) + [element animal] (map #(apply nth %&) [ELEMENTS ANIMALS] indexes)] + (str element " " animal))) + +(defn chinese-zodiac-time4j + "Determine the Chinese Zodiac name for the given year, using a + library." + [year] + (let [cyear (-> (PlainDate/of year 12 31) + (.transform (ChineseCalendar/axis)) + (.getYear)) + element (-> (.name (.getStem cyear)) + (str/split #"_") + (nth 2) + str/capitalize) + animal (.getZodiac cyear Locale/ENGLISH)] + (str element " " animal))) + +(defn -main + "Run Task 1 using a YEAR, defaulting to the example given in the task + description." + [& args] + (let [YEAR (or (some-> args first edn/read-string) DEFAULT-INPUT)] + (cl-format true "Zodiac:~%~:{~10@a: ~a~%~}" + [["Simple" (chinese-zodiac-simple YEAR)] + ["Time4J" (chinese-zodiac-time4j YEAR)]]))) diff --git a/challenge-103/tyler-wardhaugh/clojure/src/tw/weekly/c103/t2.clj b/challenge-103/tyler-wardhaugh/clojure/src/tw/weekly/c103/t2.clj new file mode 100644 index 0000000000..a4894c884c --- /dev/null +++ b/challenge-103/tyler-wardhaugh/clojure/src/tw/weekly/c103/t2.clj @@ -0,0 +1,48 @@ +(ns tw.weekly.c103.t2 + (:require [clojure.edn :as edn] + [clojure.java.io :as io] + [clojure.pprint :refer [cl-format]] + [java-time :as j] + [clojure.data.csv :as csv])) + +;;; +; Task description for TASK #2 › What's playing? +;;; + +(def DEFAULT-INPUT [1606134123 1614591276 (io/resource "stream.csv")]) + +(defn parse-csv + "Parse the CSV file as specified in the task description, with two fields + representing playtime and song title." + [file] + (with-open [reader (io/reader file)] + (into [] + (map (fn [[track-time title]] [(Long/parseLong track-time) title])) + (csv/read-csv reader)))) + +(defn currently-playing + "Determine which song is currently playing." + [start-time current-time filename] + (let [source (parse-csv filename) + playlist-duration (transduce (map first) + 0 source) + pos (rem (* (- current-time start-time) 1000) playlist-duration) + f (fn [pos [track-time title]] + (let [new-pos (- pos track-time)] + (if (pos? new-pos) + new-pos + (reduced [title pos]))))] + (reduce f pos source))) + +(defn -main + "Run Task 2 with a start time, current timestamp, and data file defaulting + to the example given in the task description." + [& args] + (let [[start-time current-time filename] + (or (some->> args (take 3) (map edn/read-string)) DEFAULT-INPUT) + [current-title current-position] + (currently-playing start-time current-time filename) + duration (j/duration current-position) + [h m s] (map #(j/as duration %) [:hours :minutes :seconds]) + m (- m (* h 60)) + s (- s (* h 60) (* m 60))] + (cl-format true "~s~%~2,'0d:~2,'0d:~2,'0d~%" current-title h m s))) diff --git a/challenge-103/tyler-wardhaugh/clojure/test/tw/weekly/c103_test.clj b/challenge-103/tyler-wardhaugh/clojure/test/tw/weekly/c103_test.clj new file mode 100644 index 0000000000..a29c9b27d8 --- /dev/null +++ b/challenge-103/tyler-wardhaugh/clojure/test/tw/weekly/c103_test.clj @@ -0,0 +1,16 @@ +(ns tw.weekly.c103-test + (:require [clojure.test :refer [deftest is testing]] + [tw.weekly.c103.t1 :refer [chinese-zodiac-simple chinese-zodiac-time4j]] + [tw.weekly.c103.t2 :refer [currently-playing DEFAULT-INPUT]])) + +(deftest task-1 + (testing "Task 1, Chinese Zodiac" + (let [both (juxt chinese-zodiac-simple chinese-zodiac-time4j)] + (is (apply = "Fire Rooster" (both 2017))) + (is (apply = "Earth Tiger" (both 1938)))))) + +(deftest task-2 + (testing "Task 2, What's playing?" + (is (= ["Les Miserables Episode 1: The Bishop (broadcast date: 1937-07-23)" + 624160] + (apply currently-playing DEFAULT-INPUT))))) |
