001 (ns ^{:doc "Functions to create and to print two dimensional cellular automata.
002
003 Nothing in this namespace should determine what states are possible within
004 the automaton, except for the initial state, :new.
005
006 A cell is a map containing at least values for the keys `:x`, `:y`, and `:state`.
007
008 A world is a two dimensional matrix (sequence of sequences) of cells, such
009 that every cell's `:x` and `:y` properties reflect its place in the matrix."
010 :author "Simon Brooke"}
011 mw-engine.world
012 (:require [clojure.string :as string]
013 [mw-engine.utils :refer [population]]))
014
015 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
016 ;;;;
017 ;;;; mw-engine: the state/transition engine of MicroWorld.
018 ;;;;
019 ;;;; This program is free software; you can redistribute it and/or
020 ;;;; modify it under the terms of the GNU General Public License
021 ;;;; as published by the Free Software Foundation; either version 2
022 ;;;; of the License, or (at your option) any later version.
023 ;;;;
024 ;;;; This program is distributed in the hope that it will be useful,
025 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
026 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
027 ;;;; GNU General Public License for more details.
028 ;;;;
029 ;;;; You should have received a copy of the GNU General Public License
030 ;;;; along with this program; if not, write to the Free Software
031 ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
032 ;;;; USA.
033 ;;;;
034 ;;;; Copyright (C) 2014 Simon Brooke
035 ;;;;
036 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
037
038 (defmacro make-cell
039 "Create a minimal default cell at x, y
040
041 * `x` the x coordinate at which this cell is created;
042 * `y` the y coordinate at which this cell is created."
043 [x y]
044 `{:x ~x :y ~y :state :new})
045
046 (defn make-world
047 "Make a world width cells from east to west, and height cells from north to
048 south.
049
050 * `width` a natural number representing the width of the matrix to be created;
051 * `height` a natural number representing the height of the matrix to be created."
052 [width height]
053 (apply vector
054 (map (fn [h]
055 (apply vector (map #(make-cell % h) (range width))))
056 (range height))))
057
058 (defn truncate-state
059 "Truncate the print name of the state of this cell to at most limit characters."
060 [cell limit]
061 (let [s (:state cell)]
062 (cond (> (count (str s)) limit) (subs s 0 limit)
063 :else s)))
064
065 (defn format-cell
066 "Return a formatted string summarising the current state of this cell."
067 [cell]
068 (format "%10s(%2d/%2d)"
069 (truncate-state cell 10)
070 (population cell :deer)
071 (population cell :wolves)))
072
073 (defn- format-world-row
074 "Format one row in the state of a world for printing."
075 [row]
076 (string/join (map format-cell row)))
077
078 (defn print-world
079 "Print the current state of this world, and return nil.
080
081 * `world` a world as defined above."
082 [world]
083 (println)
084 (dorun
085 (map
086 #(println
087 (format-world-row %))
088 world))
089 nil)