迷宫塔生成工具

迷宫塔生成工具

迷宫塔生成工具

1 简介

使用Clojure生成迷宫,然后把许多个迷宫的每一层解密路径作为zip密码,生成一个迷宫套娃。 迷宫生成的代码来自github

主要是练习gui开发,使用cljfx库(包装了JavaFX)进行界面开发,使用起来还不是很顺手,与seesaw相比,没有seesaw与swing的配合方式用起来爽。不过响应式界面是现在的流行,有一些界面刷新的问题,使用了才知道,cljfx的事件处理方式不是很好用,也不能做到事件嵌套。用text-area实现一个日志输出窗口,折腾了很久也没弄好,滚动条逻辑不好实现。

https://img2018.cnblogs.com/blog/1545892/202002/1545892-20200207000202889-1626391481.jpg

图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"]
[org.openjfx/javafx-graphics "13" :classifier "mac"]

打包之后的jar文件有50M,已经包含了openjfx库,但是不包含jdk,加上jdk打包成独立可执行文件的话,也有80M左右了,Java写桌面GUI还是太巨大了,最后的可执行程序大小与Electron程序差不多。

通过去掉没有使用的openjfx依赖,主要是webkit,使打包后的文件体积从50M降到20M,主要是webkit太大了,就是内嵌一个浏览器。

提供一个打包好的release:微云下载,最低需要jdk 11才能正常运行,已添加windows、mac下的依赖包,可直接运行。

作者: ntestoc

Created: 2020-02-07 五 00:01

原文地址:https://www.cnblogs.com/ntestoc/p/12271251.html