Wednesday, May 20, 2015

Exercism: "Queen Attack in Clojure"

I solved the Queen Attack problem in Clojure.

This is my solution:

(ns queen-attack
(:require [clojure.string :as clj-str]))
(def ^:private empty-board
(vec (repeat 8 (vec (repeat 8 "O")))))
(defn- add-to-board [position representation board]
(if position
(assoc-in board position representation)
board))
(defn- board [{white-queen-position :w black-queen-position :b}]
(->> empty-board
(add-to-board white-queen-position "W")
(add-to-board black-queen-position "B")))
(defn board-string [queens]
(str (clj-str/join
"\n"
(map #(clj-str/join " " %) (board queens)))
"\n"))
(defn- in-same-rank? [[white-queen-rank _] [black-queen-rank _]]
(= white-queen-rank black-queen-rank))
(defn- in-same-column? [[_ white-queen-col] [_ black-queen-col]]
(= white-queen-col black-queen-col))
(defn- in-same-diagonal? [[white-queen-rank white-queen-col]
[black-queen-rank black-queen-col]]
(= 1 (quot (- white-queen-rank black-queen-rank)
(- white-queen-col black-queen-col))))
(defn can-attack [{white-queen-pos :w black-queen-pos :b}]
(or (in-same-column? white-queen-pos black-queen-pos)
(in-same-rank? white-queen-pos black-queen-pos)
(in-same-diagonal? white-queen-pos black-queen-pos)))
view raw queen-atack.clj hosted with ❤ by GitHub
I think that the can-attack function should be called can-attack?. I've kept its original name because it's being exercised from the tests given by Exercism.

You can nitpick the solution here and/or see all the exercises I've done so far in this repository.

Exercism: "Robot Simulator in Clojure"

I solved the Robot Simulator problem in Clojure.

This is my solution:

(ns robot-simulator)
(defn robot [coordinates bearing]
{:coordinates coordinates
:bearing bearing})
(def ^:private turns
{:right {:north :east
:east :south
:south :west
:west :north}
:left {:north :west
:east :north
:south :east
:west :south}})
(defn- turn [direction current-bearing]
(get-in turns [direction current-bearing]))
(defn turn-right [bearing]
(turn :right bearing))
(defn turn-left [bearing]
(turn :left bearing))
(def ^:private displacements
{:north [0 1]
:east [1 0]
:south [0 -1]
:west [-1 0]})
(defn- advance [{{:keys [x y]} :coordinates bearing :bearing}]
(let [displacement (get displacements bearing [0 0])
[x y] (map + [x y] displacement)]
(robot {:x x :y y} bearing)))
(defn- right [{bearing :bearing :as rb}]
(assoc rb :bearing (turn-right bearing)))
(defn- left [{bearing :bearing :as rb}]
(assoc rb :bearing (turn-left bearing)))
(def ^:private commands
{\R right
\A advance
\L left})
(defn simulate [[first-msg & rest-msg] rb]
(if-let [comm (get commands first-msg)]
(recur rest-msg (comm rb))
rb))
I think that the turn-right and turn-left functions aren't necessary. I've kept them because they are being exercised from the tests given by Exercism.

You can nitpick the solution here and/or see all the exercises I've done so far in this repository.

Tuesday, May 19, 2015

Exercism: "Kindergarten Garden in Clojure"

I solved the Kindergarten Garden problem in Clojure.

This is my solution:

(ns kindergarten-garden)
(def ^:private plants
{\R :radishes \C :clover \G :grass \V :violets})
(def ^:private default-children
[:alice :bob :charlie :david
:eve :fred :ginny :harriet
:ileana :joseph :kincaid :larry])
(def ^:private get-plants
(partial map #(get plants %)))
(defn- plants-rows [diagram]
(map #(vec (get-plants %))
(clojure.string/split diagram #"\n")))
(defn- plants-per-child-in-rows [child-index rows]
(vec
(flatten
(map #(vector (get % child-index) (get % (inc child-index)))
rows))))
(defn- plants-per-child [diagram]
(let [num-cols (.indexOf diagram "\n")]
(map #(plants-per-child-in-rows (* 2 %) (plants-rows diagram))
(range 0 (quot num-cols 2)))))
(def ^:private lowercase-all
(partial map #(clojure.string/lower-case %)))
(def ^:private strs->keys
(partial map #(keyword %)))
(defn- children-keys [children-strs]
(->> children-strs
lowercase-all
sort
strs->keys))
(defn- make-garden [children diagram]
(zipmap children (plants-per-child diagram)))
(defn garden
([diagram]
(make-garden default-children diagram))
([diagram children-strs]
(make-garden (children-keys children-strs) diagram)))
You can nitpick this solution here and/or see all the exercises I've done so far in this repository.

Saturday, May 16, 2015

Exercism: "Crypto Square in Clojure"

I solved the Crypto Square problem in Clojure.

This is my solution:

(ns crypto-square
(:require [clojure.string :as clj-str]))
(defn- no-punctuation [c]
(or (Character/isLetter c)
(Character/isDigit c)))
(defn- remove-punctuation [text]
(clj-str/join "" (filter no-punctuation text)))
(defn normalize-plaintext [text]
(clj-str/lower-case (remove-punctuation text)))
(defn square-size [text]
(int (Math/ceil (Math/sqrt (count text)))))
(defn plaintext-segments [text]
(let [normalized-text (normalize-plaintext text)
segment-size (square-size normalized-text)]
(map clj-str/join (partition-all segment-size normalized-text))))
(defn- pad-segments [segments segments-size]
(map #(format (str "%-" segments-size "s") %) segments))
(defn- segments-in-columns [text]
(let [segments (plaintext-segments text)
segment-size (count (first segments))]
(apply map
#(clj-str/trim (apply str %&))
(pad-segments segments segment-size))))
(defn- remove-spaces [text]
(clj-str/replace text " " ""))
(defn normalize-ciphertext [text]
(->> text
segments-in-columns
(clj-str/join " ")))
(defn ciphertext [text]
(remove-spaces (normalize-ciphertext text)))
You can nitpick this solution here or see all the exercises I've done so far in this repository.

Wednesday, May 13, 2015

Exercism: "Bank Account in Clojure"

In the last event of Clojure Developers Barcelona, we practiced mob programming to solve the Bank Account problem in Clojure.

This is our solution:

(ns bank-account)
(defn open-account []
(atom 0))
(defn close-account [_])
(defn get-balance [acct]
@acct)
(defn update-balance [account amount]
(swap! account + amount))
You can nitpick our solution here or see all the exercises I've done so far in this repository.

Interesting Talk: "Outside-In TDD"

I've just watched this great series of talks by Sandro Mancuso:

Friday, May 8, 2015

Tuesday, May 5, 2015

Kata: String Calculator in Clojure

Last week we started working on the String Calculator kata at the Clojure Developers Barcelona meetup.

Finally, this week I found some time to finish it.

These are the tests using Midje:

(ns string-calculator.core-test
(:use midje.sweet)
(:use [string-calculator.core]))
(facts
"about string-calculator"
(fact
"It returns 0 for an empty string"
(add "") => 0)
(fact
"It returns the number itself when the string contains only a number"
(add "1") => 1
(add "2") => 2)
(fact
"It adds strings containing several numbers separated by commas"
(add "1,2") => 3
(add "1,2,3") => 6)
(fact
"It adds numbers separated by new lines and/or commas"
(add "1\n2,3") => 6)
(fact
"It can also use any given delimiter"
(add "//;\n1;2,3") => 6)
(fact
"It throws and exception when trying to add negative numbers"
(add "1,-2,3,-4") => (throws Exception
"Detected negative numbers: -2, -4"))
(fact
"It ignores any number greater than 1000"
(add "4,5,1001,3") => 12)
(fact
"It can use delimiters of any length"
(add "//[***]\n1***2***3") => 6)
(fact
"It can use multiple delimiters of any length"
(add "//[***][%%]\n1***2%%3,4") => 10))
The resulting code which is divided in several name spaces.

The string-calculator.core name space:

(ns string-calculator.core
(:require [string-calculator.numbers-parser :as numbers-parser]
[string-calculator.numbers-validation :as numbers-validation]
[string-calculator.numbers-filter :as numbers-filter]))
(def ^:private sum (partial apply +))
(defn add [input-str]
(-> input-str
numbers-parser/parse
numbers-validation/validate
numbers-filter/remove-too-big-numbers
sum))
The string-calculator.numbers-parser which is where most of the logic lives:

(ns string-calculator.numbers-parser
(:require [clojure.string :as string]))
(def ^:private default-delimiters ["," "\n"])
(def ^:private escaped-chars-by-metachar
(let [esc-chars "()*&^%$#!"]
(zipmap esc-chars
(map #(str "\\" %) esc-chars))))
(defn- escape-meta-characters [delimiters-str]
(reduce str (map #(get escaped-chars-by-metachar % %)
delimiters-str)))
(defn- get-matches [pattern string]
(mapcat (partial drop 1) (re-seq pattern string)))
(defn- extract-delimiters [delimiters-str]
(let [delimiters (get-matches #"\[(.*?)\]" delimiters-str)]
(if (empty? delimiters)
delimiters-str
delimiters)))
(defn- create-delimiters-pattern [delimiters-str]
(->> delimiters-str
extract-delimiters
(concat default-delimiters)
(string/join "|")
escape-meta-characters
re-pattern))
(defn- numbers-and-delimiters-pattern [input]
(let [delimiters-and-numbers (get-matches #"//(.+)\n(.*)" input)]
[(or (second delimiters-and-numbers) input)
(create-delimiters-pattern
(or (first delimiters-and-numbers) ""))]))
(defn- extract-nums-str [input-str]
(apply string/split
(numbers-and-delimiters-pattern input-str)))
(defn parse [input-str]
(if (string/blank? input-str)
[0]
(map #(Integer/parseInt %)
(extract-nums-str input-str))))
The string-calculator.numbers-validation name space:

(ns string-calculator.numbers-validation)
(def ^:private any-negative?
(partial not-every? #(>= % 0)))
(defn- throw-negative-numbers-exception [numbers]
(throw
(Exception.
(str "Detected negative numbers: "
(clojure.string/join ", " (filter neg? numbers))))))
(defn validate [numbers]
(if (any-negative? numbers)
(throw-negative-numbers-exception numbers)
numbers))
Finally, the string-calculator.numbers-filter name space:

(ns string-calculator.numbers-filter)
(defn remove-too-big-numbers [numbers]
(remove #(> % 1000) numbers))
I used a mix of TDD and REPL-driven development to code it.

To document the process I committed the code after every passing test and every refactoring.

This time I didn't commit the REPL history because I used Cursive and I didn't find how to save it. Apart from that, I really enjoyed the experience of using Cursive.

You can find the commits step by step here and the code in this repository in GitHub.