;; caesar.hs — Caesar cipher.
;; Source: https://rosettacode.org/wiki/Caesar_cipher#Haskell (adapted).
;;
;; Exercises chr, ord, isUpper, isLower, mod, string pattern matching
;; (x:xs) over a String (which is now a [Char] string view), and map
;; from the Phase 7 string=[Char] foundation.

(define
  hk-prog-val
  (fn
    (src name)
    (hk-deep-force (get (hk-eval-program (hk-core src)) name))))

(define
  hk-as-list
  (fn
    (xs)
    (cond
      ((and (list? xs) (= (first xs) "[]")) (list))
      ((and (list? xs) (= (first xs) ":"))
        (cons (nth xs 1) (hk-as-list (nth xs 2))))
      (:else xs))))

(define
  hk-caesar-source
  "shift n c = if isUpper c\n              then chr (mod ((ord c) - 65 + n) 26 + 65)\n              else if isLower c\n                     then chr (mod ((ord c) - 97 + n) 26 + 97)\n                     else chr c\n\ncaesarRec n []     = []\ncaesarRec n (x:xs) = shift n x : caesarRec n xs\n\ncaesarMap n s = map (shift n) s\n")

(hk-test
  "caesar.hs — caesarRec 3 \"ABC\" = DEF"
  (hk-as-list
    (hk-prog-val (str hk-caesar-source "r = caesarRec 3 \"ABC\"\n") "r"))
  (list "D" "E" "F"))

(hk-test
  "caesar.hs — caesarRec 13 \"Hello\" = Uryyb"
  (hk-as-list
    (hk-prog-val (str hk-caesar-source "r = caesarRec 13 \"Hello\"\n") "r"))
  (list "U" "r" "y" "y" "b"))

(hk-test
  "caesar.hs — caesarRec 1 \"AZ\" wraps to BA"
  (hk-as-list
    (hk-prog-val (str hk-caesar-source "r = caesarRec 1 \"AZ\"\n") "r"))
  (list "B" "A"))

(hk-test
  "caesar.hs — caesarRec 0 \"World\" identity"
  (hk-as-list
    (hk-prog-val (str hk-caesar-source "r = caesarRec 0 \"World\"\n") "r"))
  (list "W" "o" "r" "l" "d"))

(hk-test
  "caesar.hs — caesarRec preserves punctuation"
  (hk-as-list
    (hk-prog-val (str hk-caesar-source "r = caesarRec 3 \"Hi!\"\n") "r"))
  (list "K" "l" "!"))

(hk-test
  "caesar.hs — caesarMap 3 \"abc\" via map"
  (hk-as-list
    (hk-prog-val (str hk-caesar-source "r = caesarMap 3 \"abc\"\n") "r"))
  (list "d" "e" "f"))

(hk-test
  "caesar.hs — caesarMap 13 round-trips with caesarMap 13"
  (hk-as-list
    (hk-prog-val
      (str
        hk-caesar-source
        "r = caesarMap 13 (foldr (\\c acc -> c : acc) [] (caesarMap 13 \"Hello\"))\n")
      "r"))
  (list "H" "e" "l" "l" "o"))

(hk-test
  "caesar.hs — caesarRec 25 \"AB\" = ZA"
  (hk-as-list
    (hk-prog-val (str hk-caesar-source "r = caesarRec 25 \"AB\"\n") "r"))
  (list "Z" "A"))

{:fails hk-test-fails :pass hk-test-pass :fail hk-test-fail}
