迷宫塔生成工具
1 简介
使用Clojure生成迷宫,然后把许多个迷宫的每一层解密路径作为zip密码,生成一个迷宫套娃。 迷宫生成的代码来自github。
主要是练习gui开发,使用cljfx库(包装了JavaFX)进行界面开发,使用起来还不是很顺手,与seesaw相比,没有seesaw与swing的配合方式用起来爽。不过响应式界面是现在的流行,有一些界面刷新的问题,使用了才知道,cljfx的事件处理方式不是很好用,也不能做到事件嵌套。用text-area实现一个日志输出窗口,折腾了很久也没弄好,滚动条逻辑不好实现。
图1 程序主界面
首先设置好一系列参数,点生成,就可以生成相应数量的迷宫图片。
再设置迷宫塔的生成参数,选择最顶层包含的文件,然后生成迷宫塔,注意迷宫塔文件的保存格式必须是图片:.png或.jpg后缀的文件,保存后会有一个同名的.pass.txt为解密密码文件,按照顺序每一层的zip密码与之对应。
整个项目的代码文件。
2 范围值的使用
因为要随机生成行数,列数,和路径长度等,需要提供范围值。范围值可以是一个数值(固定值),也可以是指定[min max]最小最大范围的区间值(取范围内一个随机整数),也可以是数值集合(随机从集合中取一个数值)。
(defn range? "range-v是否为一个范围值" [range-v] (or (number? range-v) (set? range-v) (and (seqable? range-v) (= 2 (count range-v)) (>= (second range-v) (first range-v))))) (defn range-value "获取一个范围数字 如果是数字n,则为固定的n 如果是[x y] 则为x-y之间的随机数,包含x和y 如果是#{a b ...} 集合,则为任意一个集合中的数字" [range-v] {:pre [(range? range-v)]} (cond (set? range-v) (rand-nth (vec range-v)) (seqable? range-v) (let [[x y] range-v] (+ x (rand-int (inc (- y x))))) :else range-v)) (defn in-range? "数字i是否在范围值range-v中 " [i range-v] {:pre [(int? i) (range? range-v)]} (cond (set? range-v) (range-v i) (seqable? range-v) (let [[x y] range-v] (<= x i y)) :else (= i range-v))) (defn parse-range "解析范围数字,可以是单个数字,或者是x-y之间的范围,或者是a,b,c数字集合" [s] (let [s (str/trim s)] (if-let [grps (re-matches #"\s*(\d+)\s*-\s*(\d+)\s*" s)] [(Integer/parseInt (second grps)) (Integer/parseInt (last grps))] (let [grps (str/split s #"\s*,\s*")] (if (> (count grps) 1) (-> (map #(Integer/parseInt %) grps) set) (-> (first grps) (Integer/parseInt))))))) (defn range->str "范围值转换为字符串表示" [range-v] {:pre [(range? range-v)]} (cond (set? range-v) (str/join "," range-v) (seqable? range-v) (str/join "-" range-v) :else (str range-v)))
通过界面设置范围值需要提供value-converter,在views中实现。
(def range-value-converter (proxy [StringConverter] [] (fromString [s] (util/parse-range s)) (toString [v] (util/range->str v))))
3 combo-box的value-converer
对于需要转换值和界面显示字符串的部分,JavaFX提供了StringValueConverter。 但是对于combo-box, converter处理的时候没有包含异常处理,如果输入值不合法就抛出异常。 需要自己进行包装。
(defn non-exception-long-converter "不抛出异常的转换器,可提供默认值,出现异常则使用默认值" ([] (non-exception-long-converter 0)) ([default] (proxy [StringConverter] [] (fromString [s] (try (Long/parseLong s) (catch Exception e default))) (toString [v] (str v)))))
4 项目打包
直接用lein uberjar打包后,发现在windows下执行会报错:
Graphics Device initialization failed for : d3d, sw Error initializing QuantumRenderer: no suitable pipeline found
原因是JavaFX的windows依赖没有添加,在project.clj中添加依赖即可提供对windows的支持,mac系统也类似:
;; 添加JavaFX的windows系统支持, mac如果要支持也需要添加依赖 [org.openjfx/javafx-graphics "13" :classifier "win"]
打包之后的jar文件有50M,已经包含了openjfx库,但是不包含jdk,加上jdk打包成独立可执行文件的话,也有80M左右了,Java写桌面GUI还是太巨大了,最后的可执行程序大小与Electron程序差不多。
提供一个打包好的release:微云下载,最低需要jdk 11才能正常运行,没有添加mac os支持,只能在windows或linux下运行。