Idiomatic Clojure implementation of maze generation algorithm - clojure

I am implementing algorithms to create and solve mazes in both Python and Clojure. I have experience with Python and am working to learn Clojure. I am likely doing too literal of a conversion from Python to Clojure and I am looking for input on a more idiomatic way to implement the code in Clojure.
First the working Python implementation
import random
N, S, E, W = 1, 2, 4, 8
DX = {E: 1, W: -1, N: 0, S: 0}
DY = {E: 0, W: 0, N: -1, S: 1}
OPPOSITE = {E: W, W: E, N: S, S: N}
def recursive_backtracker(current_x, current_y, grid):
directions = random_directions()
for direction in directions:
next_x, next_y = current_x + DX[direction], current_y + DY[direction]
if valid_unvisited_cell(next_x, next_y, grid):
grid = remove_walls(current_y, current_x, next_y, next_x, direction, grid)
recursive_backtracker(next_x, next_y, grid)
return grid
def random_directions():
directions = [N, S, E, W]
random.shuffle(directions)
return directions
def valid_unvisited_cell(x, y, grid):
return (0 <= y <= len(grid) - 1) and (0 <= x <= len(grid[y]) - 1) and grid[y][x] == 0
def remove_walls(cy, cx, ny, nx, direction, grid):
grid[cy][cx] |= direction
grid[ny][nx] |= OPPOSITE[direction]
return grid
Now the Clojure version that I have so far. Currently I believe it is not working because I am using the for macro which is passing a symbol into recur when it needs to be passing a vector. As I was trying to find a solution for this issue I felt like I was trying too hard to force the code to be Python which prompted this question. Any guidance is appreciated.
(ns maze.core)
(def DIRECTIONS { :N 1, :S 2, :E 4, :W 8})
(def DX { :E 1, :W -1, :N 0, :S 0})
(def DY { :E 0, :W 0, :N -1, :S 1})
(def OPPOSITE { :E 8, :W 4, :N 2, :S 1})
(defn make-empty-grid
[w h]
(vec (repeat w (vec (repeat h 0)))))
(defn valid-unvisited-cell?
[x y grid]
(and
(<= 0 y (- (count grid) 1)) ; within a column
(<= 0 x (- (count (nth grid y)) 1)) ; within a row
(= 0 (get-in grid [x y])))) ; unvisited
(defn remove-walls
[cy, cx, ny, nx, direction, grid]
(-> grid
(update-in [cy cx] bit-or (DIRECTIONS direction))
(update-in [ny nx] bit-or (OPPOSITE direction))))
(defn recursive-backtracker
[current-x current-y grid]
(loop [current-x current-x current-y current-x grid grid]
(let [directions (clojure.core/shuffle [:N :S :E :W])]
(for [direction directions]
(let [next-x (+ current-x (DX direction))
next-y (+ current-y (DY direction))]
(if (valid-unvisited-cell? next-x next-y grid)
(loop next-x next-y (remove-walls current-x current-y next-x next-y direction grid)))))
grid)))

This seems like a basically reasonable translation of the Python code into Clojure (including some stuff beginners often miss - nicely done)...until we get to recursive-backtracker, the heart of the problem. You can't just transliterate the Python here, because your algorithm assumes mutability of grid: you call yourself recursively four times inside the for loop, and you need changes made to the grid to be reflected. That's not how Clojure works, so this whole thing doesn't work. The actual error you're getting is an unrelated syntax error (double-check the interface to loop/recur), but it's not really relevant here since you have to rewrite the function anyway, so I'll leave it at that.
Now, how can you rewrite this function to work without mutating grid? As is so often the case, you can use reduce: for each of the four directions, you call recursive-backtracker, getting back a modified grid, and you make sure to use that modified grid for the next recursive call. The general outline will look like this:
(defn recursive-backtracker
[current-x current-y grid]
(reduce (fn [grid direction]
(let [next-x (+ current-x (DX direction))
next-y (+ current-y (DY direction))]
(if (valid-unvisited-cell? next-x next-y grid)
(recursive-backtracker next-x next-y
(remove-walls current-x current-y next-x next-y
direction grid))
grid)))
grid, (clojure.core/shuffle [:N :S :E :W])))
With that definition, (recursive-backtracker 0 0 (make-empty-grid 5 5)) produces [[2 5 6 3 5] [4 10 9 6 9] [14 3 1 12 4] [12 6 3 9 12] [10 11 3 3 9]] - is that a valid maze? It looks okay, but I don't know. You probably don't either. Which brings me to another point: using integers and bitwise arithmetic is an exercise in pointless optimization. Instead, make each entry in the grid be a map, or a set, containing keywords saying what directions are open for it. Then on inspection you can at least get a general idea for whether the maze is self-consistent.

Related

Extracting two map elements with the largest distance in Clojure

I am trying to extract two elements of a map with the largest distance. For that, I defined the function for calculating the distance and can obtain the distance between the first element (p1) and other elements of the map. But I need to calculate distances between the second item (p2) and the next ones (p3, p4, p5), the third item (p3) and (p4, p5), the fourth item (p4) and fifth item (p5). Then I need to identify the maximum amount between all distances and return the 2 items with the largest distance and the distance itself. Any help is highly appreciated.
Here is my code:
(defn eclid-dist
[u v]
(Math/sqrt (apply + (map #(* % %) (mapv - u v)))))
(def error
{:p1 [1 2 3]
:p2 [4 5 6]
:p3 [7 8 9]
:p4 [1 2 3]
:p5 [6 5 4]})
(dotimes [i (dec (count error))]
(let [dis (eclid-dist (second (nth (seq error) 0))
(second (nth (seq error) (+ i 1))))
max-error (max dis)]
(println [':dis' dis ':max-error' max-error])))
I tried to save each calculated distance as a vector element separately to prevent overwriting but it was not successful.
You could use the for macro for this. It let's you combine two nested loops to test for all pairs. Then you can use max-key to pick the pair with largest distance:
(defn find-largest-dist-pair [vec-map]
(apply max-key second
(for [[[k0 v0] & r] (iterate rest vec-map)
:while r
[k1 v1] r]
[[k0 k1] (eclid-dist v0 v1)])))
(find-largest-dist-pair error)
;; => [[:p3 :p4] 10.392304845413264]
There is nothing wrong with eclid-dist, you could just use the dedicated Clojure library clojure.math (and ->> thread-last macro for better readability) and rewrite it like this:
(:require [clojure.math :as m])
(defn distance [u v]
(->> (mapv - u v)
(mapv #(m/pow % 2))
(reduce +)
m/sqrt))
Your main problem is, how to create unique pairs of points from your data. You could write a recursive function for this:
(defn unique-pairs [point-seq]
(let [[f & r] point-seq]
(when (seq r)
(concat (map #(vector f %) r)
(unique-pairs r)))))
(def error {:p1 [1 2 3]
:p2 [4 5 6]
:p3 [7 8 9]
:p4 [1 2 3]
:p5 [6 5 4]})
(unique-pairs (vals error))
or use library clojure.math.combinatorics:
Dependency: [org.clojure/math.combinatorics "0.1.6"]
(:require [clojure.math.combinatorics :as combi])
(combi/combinations (vals error) 2)
Note that these functions have slightly different results- it doesn't affect the final result, but if you can, you should use combinations.
Now, you have to compute distance for all these pairs and return the pair with the largest one:
(defn max-distance [point-map]
(->> (combi/combinations (vals point-map) 2)
(map (fn [[u v]] {:u u :v v :distance (distance u v)}))
(apply max-key :distance)))
(max-distance error)
=> {:u [1 2 3], :v [7 8 9], :distance 10.392304845413264}

What's the functional version of a nested test?

I'm converting some C++ code to Clojure, and I want
to return a graph g with a bunch of edges added to it.
I pass in the the number of vertices, the graph, and
the test predicate (eg, a function that could depend on i, j, randomness, ...) something like this:
(defn addSomeEdges [v g test-p]
(doseq [i (range v)]
(doseq [j (range (dec i))]
(if test-p
(add-edges g [i j] )
)))
g)
the problem, of course, is that (add-edges) returns a new g. How can I capture this updated graph using best practices Clojure, please? It seems so simple and natural in C++.
Iterativly accumulating information looks like a reducing function if you split it into two parts:
Generate a bunch of edges to consider including.
Test each edge and if it passes, include it. Otherwise pass the result on unchanged
Which can be written using reduce
user> (defn add-edge [g i j]
(assoc g i j))
#'user/add-edge
user> (add-edge {1 2} 2 1)
{1 2, 2 1}
user> (defn addSomeEdges [v g test-p]
(reduce (fn [graph [i j]] ;; this takes the current graph, the points,
(if (test-p graph i j) ;; decides if the edge should be created.
(add-edge graph i j) ;; and returns the next graph
graph)) ;; or returns the graph unchanged.
g ;; This is the initial graph
(for [i (range v)
j (range (dec i))]
[i j]))) ;; this generates the candidate edges to check.
#'user/addSomeEdges
and let's run it!
user> (addSomeEdges 4 {1 2} (fn [g i j] (rand-nth [true false])))
{1 2, 2 0}
user> (addSomeEdges 4 {1 2} (fn [g i j] (rand-nth [true false])))
{1 2, 3 0}
user> (addSomeEdges 4 {1 2} (fn [g i j] (rand-nth [true false])))
{1 2, 2 0, 3 1}
When you think of other tests you can thread these calls together:
user> (as-> {1 2} g
(addSomeEdges 4 g (fn [g i j] (rand-nth [true false])))
(addSomeEdges 7 g (fn [g i j] (< i j)))
(addSomeEdges 9 g (fn [g i j] (contains? (set (keys g)) j))))
{1 2, 3 1, 4 1, 5 3, 6 4, 7 5, 8 6}
There is more than one solution to this. Sometimes, though, when you have a fundamentally mutable/imperative problem, you should just use a mutable/imperative solution:
; simplest version using mutation
(defn addSomeEdges [v g test-p]
(let [g-local (atom g)]
(doseq [i (range v)]
(doseq [j (range (dec i))]
(when (test-p i j ...) ; what other args does this need?
(swap! g-local add-edges [i j]))))
#g-local))
I was a little uncertain on the semtantics of test-p, so that part may need refinement.
Note the swap! will call add-edges like so:
(add-edges <curr val of g-local> [i j])
See the Clojure CheatSheet & ClojureDocs.org for more info.

Best practices for working with 2d arrays in clojure?

I am building a minesweeper where the gameboard is a 2d array.
To generate the board I need to get a 2d array, randomly place some bombs, calculate all neighboring bombs for each field, then pack all together with another value (is-revealed) into a Map that should be the final value of each field.
It seems that to do all of this, I need the help of functions like map, filter, nth or zip, but instead of working on lists, they should work on a 2d array. I already started building those, but it seems like the wrong path to go.
Is there some cool abstraction that helps me use the existing functions on the 2d array? Or are there any functions already existing, that deal with 2d arrays?
edit: The way I was doing it - before thinking to myself, that there should be a better way - is something like this:
(defn mapmap [f xxs]
(for [xs xxs]
(map f xs)))
(defn mapmap-coords [f xxs]
(for [[i xs] (map-indexed list xxs)]
(map-indexed (fn [j x] (f j i)) xs)))
(defn get-value [board x y]
(if (or (< x 0) (< y 0) (< (dec (count board)) y))
false
(let [xs (nth board y)]
(if (< (dec (count xs)) x)
false
(nth xs x)))))
for works for nested sequential data.
user> (def game-state
(let [game '[[_ _ _ _]
[1 1 _ _]
[! 1 _ _]
[1 1 _ _]]]
(for [[i row] (map-indexed list game)
[j cell] (map-indexed list row)
:when (not= '_ cell)]
{:x i :y j :value cell})))
#'user/game-state
user> (pprint game-state)
({:x 1, :y 0, :value 1}
{:x 1, :y 1, :value 1}
{:x 2, :y 0, :value !}
{:x 2, :y 1, :value 1}
{:x 3, :y 0, :value 1}
{:x 3, :y 1, :value 1})
nil
We can use reduce to build up the data structure again (of course any transformations to the state could have been done in between).
user> (let [empty-game (vec (repeat 4 '[_ _ _ _]))
fill-cell (fn [game, {:keys [x y value]}] (assoc-in game [x y] value))
game (reduce fill-cell empty-game game-state)]
(doseq [row game] (apply println row)))
_ _ _ _
1 1 _ _
! 1 _ _
1 1 _ _
nil
If you're willing to drop down into Java types for your implementation, consider using
clojure.core/to-array-2d to create your 2d array and then
clojure.core/aget to index into it.
aget will give you a more natural method for accessing the array, but you'll still need to build further abstractions to get neighbours and perform updates to (i.e., regenerate) this data structure.

How do I translate a complicated recurrence from clojure to maxima?

I think this little program:
(defn average [lst] (/ (reduce + lst) (count lst)))
(defn sqsum [lst] (reduce + (map #(* % %) lst)))
(defn tet [row col]
(cond (= [row col] [0 0]) 0
(= [row col] [1 0]) 1
(< row (inc col)) 0
(> row (inc col)) (average (for [i (range row)] (tet i col)))
(= row (inc col)) (Math/sqrt (- 1 (sqsum (for [i (range col)] (tet row i)))))))
gives me the coordinates of the vertices of generalised tetrahedra / euclidean simplices in various dimensions.
Unfortunately clojure will express things like sqrt(3/4) in floating point, whereas I'd like the answers in symbolic form.
Maxima would be ideal for this sort of thing, but I don't know how to express this relation in maxima.
Alternatively, solutions involving adding symbolic square roots to clojure would also be nice.
In Maxima, a memoizing function is defined by f[x, y] := ..., that is, with square brackets instead of parentheses for the arguments.
From what I can tell, this is a translation of the Clojure function:
average (lst) := apply ("+", lst) / length (lst);
sqsum (lst) := apply ("+", map (lambda ([x], x^2), lst));
tet [row, col] :=
if row < col + 1 then 0
else if row > col + 1 then average (makelist (tet [i, col], i, 0, row - 1))
else if row = col + 1 then sqrt (1 - sqsum (makelist (tet [row, i], i, 0, col - 1)));
tet [0, 0] : 0;
tet [1, 0] : 1;
E.g.:
radcan (tet[4, 3]);
=> sqrt(5)/2^(3/2)
radcan (tet[7, 6]);
=> 2/sqrt(7)
First one agrees with a[4, 3] above. Dunno about the second.
This does the business
a[0,0]:0;
a[1,0]:1;
for row:2 while row<=15 do (
(col:(row-1)),
for r:0 while r<=col do (a[r,col]:0),
for c:0 while c<col do (a[row,c]:(sum(a[i,c],i,0,row-1))/row),
a[row,col]:radcan(sqrt(1-sum(a[row,c]^2,c,0,col-1))),
disp(a[row,col]^2));
But is there anyway to express it as the original recursion and memoize it so it runs in finite time?
I've done the first few 'by hand' in maxima, like this, if anyone needs inspiration.
(This is the 2d iteration which is equivalent to the above recursion (once memoized))
So I guess my question now could be 'how do I express this as a for loop in maxima'
one-simplex
a[0,0]:0;
a[1,0]:1;
two-simplex (equilateral triangle)
a[0,1]:0;
a[1,1]:0;
a[2,0]:(a[0,0]+a[1,0])/2;
a[2,1]:sqrt(1-a[2,0]^2);
three-simplex (tetrahedron)
a[0,2]:0;
a[1,2]:0;
a[2,2]:0;
a[3,0]:(a[0,0]+a[1,0]+a[2,0])/3;
a[3,1]:(a[0,1]+a[1,1]+a[2,1])/3;
a[3,2]:sqrt(1-a[3,0]^2-a[3,1]^2);
four-simplex (tetrahedron)
col:3;
a[0,col]:0;
a[1,col]:0;
a[2,col]:0;
a[3,col]:0;
col:0;
a[4,col]:(a[0,col]+a[1,col]+a[2,col]+a[3,col])/4;
col:1;
a[4,col]:(a[0,col]+a[1,col]+a[2,col]+a[3,col])/4;
col:2;
a[4,col]:(a[0,col]+a[1,col]+a[2,col]+a[3,col])/4;
a[4,3]:sqrt(1-a[4,0]^2-a[4,1]^2-a[4,2]^2);
radcan(%);

How to (elegantly) iterate two lists at once?

I want to find better looking alternative to this code:
(def x (range 1 10))
(def y '(0 4 3 5 1 2 7 3 11))
(for [i (range 0 (count y))] [(nth x i) (nth y i)])
If I already have the result of previous I can simply
(def z (for [i (range 0 (count y))] [(nth x i) (nth y i)]))
(for [[x y] z] [x y])
Can you find some better looking alternative?
Example is made to be short and easilly to read. If you modify it to do something more complicated the first example can stop being readable.
You can use map:
(map vector x y)