Skip to content

Instantly share code, notes, and snippets.

@ericnormand
Created January 17, 2022 23:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ericnormand/3154b336534ec8de911b0e99501584ab to your computer and use it in GitHub Desktop.
Save ericnormand/3154b336534ec8de911b0e99501584ab to your computer and use it in GitHub Desktop.
459 PurelyFunctional.tv Newsletter

Paul Cipher

Here's an interesting cipher.

  • Treat all letters as uppercase, and convert them to uppercase if needed.
  • The first alphabetical character of the string will not change.
  • All subsequent alphabetical characters are shifted toward Z by the alphabetical position of the preceding alphabetical character.
  • Non-alphabetical characters are left as-is.

Your task is to write an encoder and decoder for this cipher

Examples

(encode "") ;=> ""
(encode "a") ;=> "A"
(encode "hello") ;=> "HMQXA"
(encode "newsletter") ;=> "NSBPEQYNYW"
(encode "1 hug") ;=> "1 HCB"

(decode "") ;=> ""
(decode "1") ;=> "1"
(decode "HMQXA") ;=> "HELLO"

Note that you should always be able to decode a string that was encoded and get back the original string uppercased.

Thanks to this site for the problem idea, where it is rated Very Hard in Java. The problem has been modified.

Please submit your solutions as comments on this gist.

To subscribe: https://purelyfunctional.tv/newsletter/

@KingCode
Copy link

KingCode commented May 28, 2022

The more interesting part consisted (for me) of separating the 'glue code' from the specifics of calculating indexes
and choosing translation targets.

(def alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
(def getpos (->> (range) (map vector alphabet) (into {})))
(def getchar (->> getpos (map #(-> % reverse vec)) (into {})))

(defn perhaps-translate1 [prv c f]
  (let [ppos (getpos prv)
        cpos (getpos c)]
    (if (and ppos cpos)
      (f (inc ppos) cpos)
      c)))

(defn translate [msg translator choose]
  (->> msg 
       (partition 2 1)
       (reduce (fn [[acc [prvt :as memo]] [prv c]]
                 (let [c' (perhaps-translate1 
                           (choose [prvt prv])
                           c translator)]
                   [(conj acc c') (conj memo c')]))
               [[(first msg)] (list (first msg))])
       first
       (apply str)))

(defn encode1 [offset cpos]
  (-> offset (+ cpos) (rem 26) getchar))

(defn decode1 [offset cpos]
  (-> 26 (- offset) (+ cpos) (rem 26) getchar))

(defn encode [msg]
  (-> msg clojure.string/upper-case
      (translate encode1 last)))

(defn decode [txt]
  (translate txt decode1 first))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment