Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save vdt/fc2fe3213034d548832c to your computer and use it in GitHub Desktop.

Select an option

Save vdt/fc2fe3213034d548832c to your computer and use it in GitHub Desktop.
Learning try-and-diy: how can I simplify this example?
(ns firstshot.chessknightmove
(:refer-clojure :exclude [== >= <= > < =])
(:use clojure.core.logic
clojure.core.logic.arithmetic))
(defn knight-moves
"Returns the available moves for a knight (on a 8x8 grid) given its current position."
[x y]
(let [xmax 8 ymax 8]
(run* [q]
(fresh [a b]
(conde
[(< (+ x 1) xmax) (< (+ y 2) ymax) (== a (+ x 1)) (== b (+ y 2))]
[(< (+ x 2) xmax) (< (+ y 1) ymax) (== a (+ x 2)) (== b (+ y 1))]
[(< (+ x 2) xmax) (>= (- y 1) 0) (== a (+ x 2)) (== b (- y 1))]
[(< (+ x 1) xmax) (>= (- y 2) 0) (== a (+ x 1)) (== b (- y 2))]
[(>= (- x 1) 0) (>= (- y 2) 0) (== a (- x 1)) (== b (- y 2))]
[(>= (- x 2) 0) (>= (- y 1) 0) (== a (- x 2)) (== b (- y 1))]
[(>= (- x 2) 0) (< (+ y 1) ymax) (== a (- x 2)) (== b (+ y 1))]
[(>= (- x 1) 0) (< (+ y 2) ymax) (== a (- x 1)) (== b (+ y 2))])
(== q [a b])))))
;; This instruction
(knight-moves 4 4)
;; will give the following result
([5 6] [6 5] [6 3] [5 2] [3 2] [2 3] [2 5] [3 6])
;; Now let's try to go beyond that verbose way.
;; First, let's define an helper function
(defn distance
[a b]
"Returns the distance between two numbers"
(let [diff (- a b)]
(max diff (- diff))))
(defn knight-moves-smaller
"Returns the available moves for a knight and aims at cleaning the code."
[x y]
(let [xmax 8 ymax 8]
(run* [q]
(fresh [a b]
(== 3 (+ (distance a x) (distance b y)))
(>= a 0) (< a xmax)
(>= b 0) (< b ymax)
(== q [a b])))))
;; But we've got a problem with the arithmetic part then this doesn't work:
(knight-moves-smaller 4 4)
;; => Unhandled java.lang.ClassCastException, clojure.core.logic.LVar cannot be cast to java.lang.Number
;; I'm new to core.logic (and Clojure in general) so I'll like to understand how we can do to factorise the previous into something similar to the latter.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment