aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad S Anwar <Mohammad.Anwar@yahoo.com>2021-03-13 08:29:57 +0000
committerGitHub <noreply@github.com>2021-03-13 08:29:57 +0000
commitd1438fe7cb03045f357c4e9ac389e16cea3c018c (patch)
tree2441d7916335d2e15d9d06e8bb4dddd49d9b9dbe
parent69182a0400e1559360606bc2dcc4e61d2e9d95f4 (diff)
parent3b18f59bca6f28ad739545b92970d232c81d2d44 (diff)
downloadperlweeklychallenge-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
-rw-r--r--challenge-103/tyler-wardhaugh/clojure/deps.edn6
-rw-r--r--challenge-103/tyler-wardhaugh/clojure/resources/stream.csv7
-rw-r--r--challenge-103/tyler-wardhaugh/clojure/src/tw/weekly/c103/core.clj12
-rw-r--r--challenge-103/tyler-wardhaugh/clojure/src/tw/weekly/c103/t1.clj59
-rw-r--r--challenge-103/tyler-wardhaugh/clojure/src/tw/weekly/c103/t2.clj48
-rw-r--r--challenge-103/tyler-wardhaugh/clojure/test/tw/weekly/c103_test.clj16
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)))))