Clojure——学习迷宫生成
背景
初学clojure,想着看一些算法来熟悉clojure语法及相关算法实现。
找到一个各种语言生成迷宫的网站:http://rosettacode.org/wiki/Maze_generation
在上述网站可以看到clojure的实现版,本文就是以初学者的视角解读改程序。
小试牛刀
先看一些简单的示例,以帮助我们理解迷宫生成程序。
绑定符号x++
(defn f [x]
(let [x++ (+ x 5)]
#{[x x++]}))
(println (f 1))
=> #'sinlov.clojure.base-learn/f
#{[1 6]}
=> nil
Tips: 上述程序将x++
绑定为x+5
,不同于c语言中的自增运算符。
集合过滤
(select odd? (set [1 2 3 4 5]))
=> #{1 3 5}
(select (partial odd?) (set [1 2 3 4 5]))
=> #{1 3 5}
select
语法参考文档:http://clojuredocs.org/clojure.set/select
partial
解释见下文
vec交叉合并
(interleave [0 1 2] ['a 'b 'c])
=> (0 a 1 b 2 c)
(interleave [0 1 2] ['a 'b 'c] ['b])
=> (0 a b)
(interleave [0 1 2] ['a 'b 'c] (repeat 'z))
=> (0 a z 1 b z 2 c z)
文档:http://clojuredocs.org/clojure.core/interleave
transduce
transducer是clojure里面的一种编程思想,使用transducer可以简化很多语法。
可以参考这篇文章链接,帮助理解
文档:http://clojuredocs.org/clojure.core/transduce
思路
笔者阅读了迷宫生成算法,将思路整理如下
坐标点与符号映射关系
比如迷宫的左上角┌
是如何生成的,不同大小的迷宫如何确定?
经过阅读源码发现,一个坐标点的符号与其周围4个临接点相关,如果按照坐标点表示,5个点排序顺序是一致的。
比如,上述坐标点(5,5),和其4个临界点。可以看到在该坐标系内,一个点与其临界点做成的集合排序一定是下面的顺序:
比如迷宫左上角坐标是(0, 0),该点五元组应该是
不在迷宫,不在迷宫,(0, 0), (0, 1), (1, 0)
假设不在迷宫或者该位置为空,记为0
;如果是墙记为1
那么上述五元组可以换算为11100
。
再比如迷宫右上角,五元组为
(n-1, 0), 不在迷宫, (n, 0), (n, 1), 不在迷宫
可换算为10110
。
按照如上规则可以生成如下表:
[" " " " " " " " "· " "╵ " "╴ " "┘ "
" " " " " " " " "╶─" "└─" "──" "┴─"
" " " " " " " " "╷ " "│ " "┐ " "┤ "
" " " " " " " " "┌─" "├─" "┬─" "┼─"]
程序代码
(ns maze.core
(:require [clojure.set :refer [intersection
select]]
[clojure.string :as str]))
;; 得到周围临界点
(defn neighborhood
([] (neighborhood [0 0]))
([coord] (neighborhood coord 1))
([[y x] r]
(let [y-- (- y r) y++ (+ y r)
x-- (- x r) x++ (+ x r)]
#{[y++ x] [y-- x] [y x--] [y x++]})))
;; 判断位置是否为空
(defn cell-empty? [maze coords]
(= :empty (get-in maze coords)))
;; 判断位置是否为墙
(defn wall? [maze coords]
(= :wall (get-in maze coords)))
;; 过滤迷宫中指定类型的点的集合
(defn filter-maze
([pred maze coords]
(select (partial pred maze) (set coords)))
([pred maze]
(filter-maze
pred
maze
(for [y (range (count maze))
x (range (count (nth maze y)))]
[y x]))))
;; 创建新迷宫
(defn create-empty-maze [width height]
(let [width (inc (* 2 width))
height (inc (* 2 height))]
(vec (take height
(interleave
(repeat (vec (take width (repeat :wall))))
(repeat (vec (take width (cycle [:wall :empty])))))))))
(defn next-step [possible-steps]
(rand-nth (vec possible-steps)))
;; 核心算法,深度优先递归
(defn create-random-maze [width height]
(loop [maze (create-empty-maze width height)
stack []
nonvisited (filter-maze cell-empty? maze)
visited #{}
coords (next-step nonvisited)]
(if (empty? nonvisited)
maze
(let [nonvisited-neighbors (intersection (neighborhood coords 2) nonvisited)]
(cond
(seq nonvisited-neighbors)
(let [next-coords (next-step nonvisited-neighbors)
wall-coords (map #(+ %1 (/ (- %2 %1) 2)) coords next-coords)]
(recur (assoc-in maze wall-coords :empty)
(conj stack coords)
(disj nonvisited next-coords)
(conj visited next-coords)
next-coords))
(seq stack)
(recur maze (pop stack) nonvisited visited (last stack)))))))
;; 迷宫坐标与字符映射
(def cell-code->str
[" " " " " " " " "· " "╵ " "╴ " "┘ "
" " " " " " " " "╶─" "└─" "──" "┴─"
" " " " " " " " "╷ " "│ " "┐ " "┤ "
" " " " " " " " "┌─" "├─" "┬─" "┼─"])
;; 获取迷宫坐标的类型
;; 使用5 bit表示一个点对应的字符映射
;; 例如:00111对应┘
(defn cell-code [maze coord]
(transduce
(comp
(map (partial wall? maze))
(keep-indexed (fn [idx el] (when el idx)))
(map (partial bit-shift-left 1)))
(completing bit-or)
0
(sort (cons coord (neighborhood coord)))))
(defn cell->str [maze coord]
(get cell-code->str (cell-code maze coord)))
;; 将迷宫坐标转换为字符
(defn maze->str [maze]
(->> (for [y (range (count maze))]
(for [x (range (count (nth maze y)))]
(cell->str maze [y x])))
(map str/join)
(str/join \newline)))
;; 生成迷宫
(println (maze->str (create-random-maze 10 10)))
上述程序输出:
Clojure——学习迷宫生成的更多相关文章
- ICML 2018 | 从强化学习到生成模型:40篇值得一读的论文
https://blog.csdn.net/y80gDg1/article/details/81463731 感谢阅读腾讯AI Lab微信号第34篇文章.当地时间 7 月 10-15 日,第 35 届 ...
- O(n)线性空间的迷宫生成算法
之前所有的迷宫生成算法,空间都是O(mn),时间同样是O(mn),时间上已经不可能更优化, 于是,我就从空间优化上着手,研究一个仅用O(n)空间的生成算法. 我初步的想法是,每次生成一行,生成后立即输 ...
- NASNet学习笔记—— 核心一:延续NAS论文的核心机制使得能够自动产生网络结构; 核心二:采用resnet和Inception重复使用block结构思想; 核心三:利用迁移学习将生成的网络迁移到大数据集上提出一个new search space。
from:https://blog.csdn.net/xjz18298268521/article/details/79079008 NASNet总结 论文:<Learning Transfer ...
- [迷宫中的算法实践]迷宫生成算法——递归分割算法
Recursive division method Mazes can be created with recursive division, an algorithm which wo ...
- MySQL学习记录--生成时间日期数据
时间数据格式组件: 组件 定义 范围 YYYY 年份,包括世纪 1000~9999 MM 月份 01(January)~12(December) DD 日 01~31 HH 小时 00~23 HHH ...
- Clojure学习笔记(一)——介绍、安装和语法
什么是Clojure Clojure是一种动态的.强类型的.寄居在JVM上的语言. Clojure的特性: 函数式编程基础,包括一套性能可以和典型可变数据结构媲美的持久性数据结构 由JVM提供的成熟的 ...
- [ExtJS5学习笔记]第三节 sencha cmd学习笔记 生成应用程序构建的内部细节
本文地址: http://blog.csdn.net/sushengmiyan/article/details/38316829本文作者:sushengmiyan------------------- ...
- Clojure学习资料
以下大部分收藏自博客:http://blog.csdn.net/ithomer/article/details/17225813 官方文档: http://clojure.org/documentat ...
- Clojure 学习入门(19)—— 数组
1.创建数组 1.1 从集合创建数组 into-array into-array (into-array aseq) (into-array type aseq) 演示样例: user=> (i ...
随机推荐
- 简单易学的SSM(Spring+SpringMVC+MyBatis)整合
SSM(Spring+SpringMVC+MyBatis)的整合: 具体执行过程:1.用户在页面向后台发送一个请求 2.请求由DispatcherServlet 前端控制器拦截交给SpringMVC管 ...
- spring整合mybatis错误:Caused by: org.xml.sax.SAXParseException; lineNumber: 5; columnNumber: 62; 文档根元素 "mapper" 必须匹配 DOCTYPE 根 "configuration"。
运行环境:jdk1.7.0_17+tomcat 7 + spring:3.2.0 +mybatis:3.2.7+ eclipse 错误:Caused by: org.xml.sax.SAXParseE ...
- 探索 Java 热部署
在 JAVA 开发领域,热部署一直是一个难以解决的问题,目前的 JAVA 虚拟机只能实现方法体的修改热部署,对于整个类的结构修改,仍然需要重启虚拟机,对类重新加载才能完成更新操作.对于某些大型的应用来 ...
- Java基础学习 —— io
/** 解决数据与数据之间的传输问题. 字节流: 输入字节流: -------| InputStream 所有输入字节流的基类.抽象类. -----------| FileInputStream 读取 ...
- 非空与 jquery.each
return :只能跳出each方法 ,无法跳出aaa() function aaa{ var result = false; //非空 $("i ...
- nodejs本地服务器自动重启
在我们开发node 应用的时候,一但你的应用已经启动了,这个时候如果你修改了服务端的文件,那么要是这个修改起作用,你必须手动停止服务然后再重新启动,这在开发过程中无疑是很烦人的一件事,最好是有一个能够 ...
- stable_sort()与sort
stable_sort与sort()都是c++库函数,调用<algorithm>库,但区别是sort是不稳定的排序,而stable_sort是稳定的,有时候stable_sort比sort ...
- 使用 LVS 实现负载均衡原理及安装配置详解
负载均衡集群是 load balance 集群的简写,翻译成中文就是负载均衡集群.常用的负载均衡开源软件有nginx.lvs.haproxy,商业的硬件负载均衡设备F5.Netscale.这里主要是学 ...
- 结对编程1----基于java的四则运算生成器
小组成员:王震(201421123054).王杰(201421123055) Coding地址:https://git.coding.net/a506504661/sssss.git 一.题目描述 我 ...
- 201521123040《Java程序设计》第7周学习总结
1. 本周学习总结 以你喜欢的方式(思维导图或其他)归纳总结集合相关内容. 参考资料: XMind 2. 书面作业 1.ArrayList代码分析 1.1 解释ArrayList的contains源代 ...