Idiomatic Clojure implementation of the maze generation algorithm

I implement algorithms for creating and solving mazes in both Python and Clojure. I have experience with Python and am learning Clojure. I'm most likely doing a too literal conversion from Python to Clojure, and I'm looking for input for a more idiomatic way to implement code in Clojure.

First 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 version of Clojure that I have so far. I currently believe that it does not work, because I use a for macro, which passes a character to recur when it needs to pass a vector. Since I was trying to find a solution to this problem, it seemed to me that I was trying too hard to get the code to be Python, which caused this question. Any recommendations are 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)))
+4
1

Python Clojure ( , ), recursive-backtracker, . Python , grid: for, , , . , Clojure, . , , - ( loop/recur), , , .

, grid? , reduce: recursive-backtracker, , , . :

(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])))

(recursive-backtracker 0 0 (make-empty-grid 5 5)) [[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]] - ? , . , , . : - . , , , . , .

+7

Source: https://habr.com/ru/post/1544838/


All Articles