Let's write β

プログラミング中にできたことか、思ったこととか

地面が雪によって平滑化されていく様子のシミュレーションがしたい

雪原を見ていると、地面の凹凸の大まかな部分が残されているものの表面は非常に平滑化されています。そんな感じの物が作れればなぁとおもいちょっとコードを書いています。

(ql:quickload :lispbuilder-sdl)
(ql:quickload :lispbuilder-sdl-gfx)

(defun brown (w val)
  (let* ((r (random w))
         (ng (random 2)))
    (if (zerop ng)
      (+ val r)
      (+ val (- r)))))

(defun gen-random-seq (init len &optional (w 2))
  (loop for v = init then (brown w v)
        collect v
        repeat len))

(defun rnth (idx list)
  (nth (mod idx (length list))
       list))

(defun smooth-list (width list)
  (loop for idx from 0 below (length list)
        collect 
        (/
          (loop for pad from (- width) upto width by 1
                sum (rnth (+ pad idx) list))
          (1+ (* width 2)))))

(defun smooth-snow (width &optional (p 2))
  (let* ((height (* width 0.8))
         (r-seq (gen-random-seq (floor (* height 0.8))
                               (1+ width) p)))
    (sdl:with-init ()
           (sdl:window width height :title-caption "Smooth Snow")
           (sdl:with-events ()
                    (:quit-event () t)
                    (:idle ()
                     (loop for idx from 0 below width
                           do
                           (sdl:draw-line-* 
                             idx (nth idx r-seq)
                             (1+ idx) (nth (1+ idx) r-seq)
                             :color sdl:*white*))
                     (loop for rep from 1 upto 10
                           for smooth-seq = (smooth-list 2 r-seq) then (smooth-list 2 smooth-seq)
                           do
                           (loop for idx from 0 below width
                                 do
                                 (sdl:draw-line-* 
                                   idx (round (-  (nth idx smooth-seq) (* rep 10)))
                                   (1+ idx) (round (-  (nth (1+ idx) smooth-seq)(* rep 10)))
                                   :color sdl:*blue*)))
                     (sdl:update-display))))))

原状は周囲の平均の値にどんどん近付いていくという方法をとっています。
すると徐々に平滑化されていくのが見えます。

しかし、実際はおそらく各点での傾きを計算して傾きがある程度水平でない点には雪がつもらない
とか、雪同士の結合などを考慮しなければならないでしょう。そこらへんも時間があったらやりたいです。