Feature complete for version 1; some refactoring still needed.
This commit is contained in:
parent
a0f59ac2dd
commit
98e43dbe8f
|
@ -1,5 +1,6 @@
|
|||
## What this is about
|
||||
|
||||
<img alt="Screenshot" id="screenshot" style="float: left; padding-right: 2em;" src="img/screenshot_med.png"/>
|
||||
MicroWorld is a rule driven cellular automaton. What does that mean? Well, it's
|
||||
a two dimensional world made up of squares called **cells**. The world develops
|
||||
in steps, and at each step, each cell is modified by applying the rules.
|
||||
|
|
|
@ -72,9 +72,10 @@ li.nav-item a:active { background: gray; color: white; }
|
|||
}
|
||||
|
||||
.widget {
|
||||
margin: 0;
|
||||
padding: 0.25em 1em;
|
||||
background-color: silver;
|
||||
border: thin solid white;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.world {
|
||||
|
@ -86,8 +87,6 @@ div.error {
|
|||
}
|
||||
|
||||
form {
|
||||
width: 100%;
|
||||
background-color: silver;
|
||||
border: thin solid silver;
|
||||
}
|
||||
|
||||
|
@ -100,7 +99,7 @@ h1, h2, h3, h4, h5 {
|
|||
color: white;
|
||||
}
|
||||
|
||||
p, pre, ul, ol, dl, menu, h1, h2, h3, h4, h5 {
|
||||
div.content, form, p, pre, ul, ol, dl, menu, h1, h2, h3, h4, h5 {
|
||||
padding: 0.25em 10%;
|
||||
}
|
||||
|
||||
|
@ -118,15 +117,8 @@ input.required:after {
|
|||
}
|
||||
|
||||
label {
|
||||
min-width: 35%;
|
||||
}
|
||||
|
||||
label, input {
|
||||
padding: 0.25em 1em;
|
||||
margin: 0 0.5em;
|
||||
}
|
||||
|
||||
label {
|
||||
width: 30em;
|
||||
min-width: 20em;
|
||||
border-right: thin solid gray;
|
||||
}
|
||||
|
||||
|
@ -138,9 +130,19 @@ menu li::before {
|
|||
content: "|| ";
|
||||
}
|
||||
|
||||
div.world table, div.world tr td {
|
||||
div.world table, div.world table tr td {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border-collapse: collapse;
|
||||
border: none;
|
||||
}
|
||||
|
||||
table.music-ruled tr:nth-child(odd) {
|
||||
background-color: silver;
|
||||
}
|
||||
|
||||
th, td {
|
||||
text-align: left;
|
||||
padding: 0 0.25em;
|
||||
}
|
||||
|
||||
|
|
|
@ -3441,7 +3441,30 @@ important.</p>
|
|||
([world cell depth state]
|
||||
(get-neighbours-with-state world (:x cell) (:y cell) depth state))
|
||||
([world cell state]
|
||||
(get-neighbours-with-state world cell 1 state)))</pre></td></tr><tr><td class="spacer docs"> </td><td class="codes" /></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#mw-engine.world" name="mw-engine.world"><h1 class="project-name">mw-engine.world</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs"><p>Functions to create and to print two dimensional cellular automata. Nothing in this
|
||||
(get-neighbours-with-state world cell 1 state)))</pre></td></tr><tr><td class="docs"><p>If this <code>cell</code>s x and y properties are equal to these <code>x</code> and <code>y</code> values,
|
||||
return a cell like this cell but with the value of this <code>property</code> set to
|
||||
this <code>value</code>. Otherwise, just return this <code>cell</code>.</p>
|
||||
</td><td class="codes"><pre class="brush: clojure">(defn- set-cell-property
|
||||
[cell x y property value]
|
||||
(cond
|
||||
(and (= x (:x cell)) (= y (:y cell)))
|
||||
(merge cell {property value})
|
||||
true
|
||||
cell))</pre></td></tr><tr><td class="docs"><p>Return a world like this <code>world</code> but with the value of exactly one <code>property</code>
|
||||
of one <code>cell</code> changed to this <code>value</code></p>
|
||||
</td><td class="codes"><pre class="brush: clojure">(defn set-property
|
||||
([world cell property value]
|
||||
(set-property world (:x cell) (:y cell) property value))
|
||||
([world x y property value]
|
||||
(apply
|
||||
vector ;; we want a vector of vectors, not a list of lists, for efficiency
|
||||
(map
|
||||
(fn [row]
|
||||
(apply
|
||||
vector
|
||||
(map #(set-cell-property % x y property value)
|
||||
row)))
|
||||
world))))</pre></td></tr><tr><td class="spacer docs"> </td><td class="codes" /></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#mw-engine.world" name="mw-engine.world"><h1 class="project-name">mw-engine.world</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs"><p>Functions to create and to print two dimensional cellular automata. Nothing in this
|
||||
file should determine what states are possible within the automaton, except for the
|
||||
initial state, :new.</p>
|
||||
|
||||
|
|
|
@ -3126,6 +3126,7 @@ net.brehaut.ClojureTools = (function (SH) {
|
|||
[mw-engine.natural-rules :as rules]
|
||||
[mw-parser.bulk :as compiler]
|
||||
[hiccup.core :refer [html]]
|
||||
[noir.io :as io]
|
||||
[noir.session :as session]))</pre></td></tr><tr><td class="docs">
|
||||
</td><td class="codes"><pre class="brush: clojure">(defn format-css-class [statekey]
|
||||
"Format this statekey, assumed to be a keyword indicating a state in the
|
||||
|
@ -3141,7 +3142,7 @@ net.brehaut.ClojureTools = (function (SH) {
|
|||
[cell]
|
||||
(let [state (:state cell)]
|
||||
[:td {:class (format-css-class state) :title (format-mouseover cell)}
|
||||
[:a {:href (format "inspect?x=%d&amp;y=%d" (:x cell) (:y cell))}
|
||||
[:a {:href (format "inspect?x=%d&y=%d" (:x cell) (:y cell))}
|
||||
[:img {:alt (:state cell) :src (format-image-path state)}]]]))</pre></td></tr><tr><td class="docs"><p>Render this world row as a Hiccup table row.</p>
|
||||
</td><td class="codes"><pre class="brush: clojure">(defn render-world-row
|
||||
[row]
|
||||
|
@ -3151,11 +3152,13 @@ net.brehaut.ClojureTools = (function (SH) {
|
|||
(let [world (or (session/get :world)
|
||||
(engine/transform-world
|
||||
(heightmap/apply-heightmap
|
||||
"resources/public/img/heightmaps/small_hill.png"
|
||||
(io/get-resource "/img/heightmaps/small_hill.png")
|
||||
;; "resources/public/img/heightmaps/great_britain_and_ireland_small.png")
|
||||
rules/init-rules))
|
||||
rules (or (session/get :rules)
|
||||
(do (session/put! :rules (compiler/compile-file "resources/rulesets/basic.txt"))
|
||||
(do (session/put! :rules
|
||||
(compiler/compile-file
|
||||
(io/get-resource "/rulesets/basic.txt")))
|
||||
(session/get :rules)))
|
||||
generation (+ (or (session/get :generation) 0) 1)
|
||||
w2 (engine/transform-world world rules)
|
||||
|
@ -3166,22 +3169,17 @@ net.brehaut.ClojureTools = (function (SH) {
|
|||
(apply vector
|
||||
(cons :table
|
||||
(map render-world-row w2)))
|
||||
[:p (str "Generation " generation)]]))</pre></td></tr><tr><td class="docs"><p>Render the world implied by the session as a complete HTML page.</p>
|
||||
</td><td class="codes"><pre class="brush: clojure">(defn render-world
|
||||
[]
|
||||
(html
|
||||
[:html
|
||||
[:head
|
||||
[:title "MicroWorld demo"]
|
||||
[:link {:media "only screen and (max-device-width: 480px)" :href "css/phone.css" :type "text/css" :rel "stylesheet"}]
|
||||
[:link {:media "only screen and (min-device-width: 481px) and (max-device-width: 1024px)" :href "css/tablet.css" :type "text/css" :rel "stylesheet"}]
|
||||
[:link {:media "screen and (min-device-width: 1025px)" :href "css/standard.css" :type "text/css" :rel "stylesheet"}]
|
||||
[:link {:media "print" :href "css/print.css" :type "text/css" :rel "stylesheet"}]
|
||||
[:link {:href "css/states.css" :type "text/css" :rel "stylesheet"}]
|
||||
[:meta {:http-equiv "refresh" :content "5"}]]
|
||||
[:body
|
||||
(render-world-table)
|
||||
]]))</pre></td></tr><tr><td class="spacer docs"> </td><td class="codes" /></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#mw-ui.repl" name="mw-ui.repl"><h1 class="project-name">mw-ui.repl</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs">
|
||||
[:p (str "Generation " generation)]]))</pre></td></tr><tr><td class="docs">
|
||||
</td><td class="codes"><pre class="brush: clojure">(defn render-inspector
|
||||
[cell table]
|
||||
[:table {:class "music-ruled"}
|
||||
[:tr
|
||||
[:td {:colspan 2 :style "text-align: center;"}
|
||||
[:img {:src (str "img/tiles/" (name (:state cell)) ".png")
|
||||
:width 64
|
||||
:height 64}]]]
|
||||
[:tr [:th "Key"][:th "Value"]]
|
||||
(map #(vector :tr (vector :th %)(vector :td (cell %))) (keys cell))])</pre></td></tr><tr><td class="spacer docs"> </td><td class="codes" /></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#mw-ui.repl" name="mw-ui.repl"><h1 class="project-name">mw-ui.repl</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs">
|
||||
</td><td class="codes"><pre class="brush: clojure">(ns mw-ui.repl
|
||||
(:use mw-ui.handler
|
||||
ring.server.standalone
|
||||
|
@ -3214,16 +3212,40 @@ net.brehaut.ClojureTools = (function (SH) {
|
|||
</td><td class="codes"><pre class="brush: clojure">(ns mw-ui.routes.home
|
||||
(:use clojure.walk
|
||||
compojure.core
|
||||
[mw-engine.utils :as engine-utils]
|
||||
[mw-ui.routes.rules :as rules]
|
||||
[mw-ui.routes.params :as params])
|
||||
(:require [hiccup.core :refer [html]]
|
||||
[mw-ui.layout :as layout]
|
||||
[mw-ui.util :as util]
|
||||
[mw-ui.render-world :as world]
|
||||
[noir.session :as session]))</pre></td></tr><tr><td class="docs">
|
||||
[noir.session :as session]
|
||||
[ring.util.response :as response]))</pre></td></tr><tr><td class="docs">
|
||||
</td><td class="codes"><pre class="brush: clojure">(defn home-page []
|
||||
(layout/render "trusted-content.html" {:title "Welcome to MicroWorld"
|
||||
:content (util/md->html "/md/mw-ui.md")}))</pre></td></tr><tr><td class="docs">
|
||||
</td><td class="codes"><pre class="brush: clojure">(defn inspect-page [request]
|
||||
(let [params (keywordize-keys (:params request))
|
||||
xs (:x params)
|
||||
ys (:y params)
|
||||
x (if (not (empty? xs)) (read-string xs) 0)
|
||||
y (if (not (empty? ys)) (read-string ys) 0)
|
||||
world (session/get :world)
|
||||
cell (engine-utils/get-cell world x y)
|
||||
state (:state params)]
|
||||
(cond state
|
||||
(do
|
||||
(session/put! :world (engine-utils/set-property world cell :state (keyword state)))
|
||||
(response/redirect "world"))
|
||||
true
|
||||
(layout/render "inspector.html"
|
||||
{:title (format "Inspect cell at %d, %d" x y)
|
||||
:content (html (world/render-inspector cell world))
|
||||
:cell cell
|
||||
:x (:x cell)
|
||||
:y (:y cell)
|
||||
:states (util/list-resources
|
||||
"/img/tiles" #"([0-9a-z-_]+).png")}))))</pre></td></tr><tr><td class="docs">
|
||||
</td><td class="codes"><pre class="brush: clojure">(defn world-page []
|
||||
(layout/render "trusted-content.html"
|
||||
{:title "Watch your world grow"
|
||||
|
@ -3250,8 +3272,8 @@ net.brehaut.ClojureTools = (function (SH) {
|
|||
</td><td class="codes"><pre class="brush: clojure">(defn docs-page []
|
||||
(layout/render "docs.html" {:title "Documentation"
|
||||
:parser (util/md->html "/md/mw-parser.md" )
|
||||
:states (util/list-resources "resources/public/img/tiles" #"([0-9a-z-_]+).png")
|
||||
:lessons (util/list-resources "resources/public/md/lesson-plans" #"([0-9a-z-_]+).md")
|
||||
:states (util/list-resources "/img/tiles" #"([0-9a-z-_]+).png")
|
||||
:lessons (util/list-resources "/md/lesson-plans" #"([0-9a-z-_]+).md")
|
||||
:components ["mw-engine" "mw-parser" "mw-ui"]}))</pre></td></tr><tr><td class="docs">
|
||||
</td><td class="codes"><pre class="brush: clojure">(defroutes home-routes
|
||||
(GET "/" [] (home-page))
|
||||
|
@ -3262,9 +3284,12 @@ net.brehaut.ClojureTools = (function (SH) {
|
|||
(GET "/md" request (md-page request))
|
||||
(POST "/params" request (params/params-page request))
|
||||
(GET "/rules" request (rules/rules-page request))
|
||||
(POST "/rules" request (rules/rules-page request)))</pre></td></tr><tr><td class="spacer docs"> </td><td class="codes" /></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#mw-ui.routes.params" name="mw-ui.routes.params"><h1 class="project-name">mw-ui.routes.params</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs">
|
||||
(POST "/rules" request (rules/rules-page request))
|
||||
(GET "/inspect" request (inspect-page request))
|
||||
(POST "/inspect" request (inspect-page request)))</pre></td></tr><tr><td class="spacer docs"> </td><td class="codes" /></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#mw-ui.routes.params" name="mw-ui.routes.params"><h1 class="project-name">mw-ui.routes.params</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs">
|
||||
</td><td class="codes"><pre class="brush: clojure">(ns mw-ui.routes.params
|
||||
(:use clojure.walk
|
||||
clojure.java.io
|
||||
compojure.core)
|
||||
(:require [hiccup.core :refer [html]]
|
||||
[mw-engine.heightmap :as heightmap]
|
||||
|
@ -3272,12 +3297,13 @@ net.brehaut.ClojureTools = (function (SH) {
|
|||
[mw-ui.layout :as layout]
|
||||
[mw-ui.util :as util]
|
||||
[mw-ui.render-world :as world]
|
||||
[noir.io :as io]
|
||||
[noir.session :as session]))</pre></td></tr><tr><td class="docs">
|
||||
</td><td class="codes"><pre class="brush: clojure">(defn- send-params []
|
||||
{:title "Choose your world"
|
||||
:heightmaps (util/list-resources "resources/public/img/heightmaps" #"([0-9a-z-_]+).png")
|
||||
:heightmaps (util/list-resources "/img/heightmaps" #"([0-9a-z-_]+).png")
|
||||
:pause (or (session/get :pause) 5)
|
||||
:rulesets (util/list-resources "resources/rulesets" #"([0-9a-z-_]+).txt")
|
||||
:rulesets (util/list-resources "/rulesets" #"([0-9a-z-_]+).txt")
|
||||
})</pre></td></tr><tr><td class="docs"><p>Handler for params request. If no <code>request</code> passed, show empty params form.
|
||||
If <code>request</code> is passed, put parameters from request into session and show
|
||||
the world page.</p>
|
||||
|
@ -3290,15 +3316,15 @@ net.brehaut.ClojureTools = (function (SH) {
|
|||
map (:heightmap params)
|
||||
pause (:pause params)
|
||||
rulefile (:ruleset params)
|
||||
rulepath (str "resources/rulesets/" rulefile ".txt")]
|
||||
rulepath (str "/rulesets/" rulefile ".txt")]
|
||||
(if (not (= map ""))
|
||||
(session/put! :world
|
||||
(heightmap/apply-heightmap
|
||||
(str "resources/public/img/heightmaps/" map ".png"))))
|
||||
(io/get-resource (str "/img/heightmaps/" map ".png")))))
|
||||
(if (not (= rulefile ""))
|
||||
(do
|
||||
(session/put! :rule-text (slurp rulepath))
|
||||
(session/put! :rules (compiler/compile-file rulepath))))
|
||||
(session/put! :rule-text (io/slurp-resource rulepath))
|
||||
(session/put! :rules (compiler/compile-file (io/get-resource rulepath)))))
|
||||
(if (not (= pause ""))
|
||||
(session/put! :pause pause))
|
||||
(layout/render "params.html"
|
||||
|
@ -3323,6 +3349,7 @@ net.brehaut.ClojureTools = (function (SH) {
|
|||
[mw-ui.layout :as layout]
|
||||
[mw-ui.util :as util]
|
||||
[mw-ui.render-world :as world]
|
||||
[noir.io :as io]
|
||||
[noir.session :as session]))</pre></td></tr><tr><td class="docs">
|
||||
</td><td class="codes"><pre class="brush: clojure">(defn process-rules-request
|
||||
[request]
|
||||
|
@ -3337,7 +3364,7 @@ net.brehaut.ClojureTools = (function (SH) {
|
|||
" rules") })
|
||||
true {:rule-text (or
|
||||
(session/get :rule-text)
|
||||
(slurp "resources/rulesets/basic.txt"))
|
||||
(io/slurp-resource "/rulesets/basic.txt"))
|
||||
:message "No rules found in request; loading defaults"})
|
||||
(catch Exception e
|
||||
{:rule-text src
|
||||
|
@ -3362,6 +3389,7 @@ net.brehaut.ClojureTools = (function (SH) {
|
|||
(rules-page nil)))</pre></td></tr><tr><td class="spacer docs"> </td><td class="codes" /></tr><tr><td class="docs"><div class="docs-header"><a class="anchor" href="#mw-ui.util" name="mw-ui.util"><h1 class="project-name">mw-ui.util</h1><a class="toc-link" href="#toc">toc</a></a></div></td><td class="codes" /></tr><tr><td class="docs">
|
||||
</td><td class="codes"><pre class="brush: clojure">(ns mw-ui.util
|
||||
(:require [noir.io :as io]
|
||||
[noir.session :as session]
|
||||
[markdown.core :as md]))</pre></td></tr><tr><td class="docs"><p>reads a markdown file from public/md and returns an HTML string</p>
|
||||
</td><td class="codes"><pre class="brush: clojure">(defn md->html
|
||||
[filename]
|
||||
|
@ -3370,8 +3398,11 @@ net.brehaut.ClojureTools = (function (SH) {
|
|||
(md/md-to-html-string)))</pre></td></tr><tr><td class="docs">
|
||||
</td><td class="codes"><pre class="brush: clojure">(defn list-resources [directory pattern]
|
||||
"List resource files matching `pattern` in `directory`."
|
||||
(let
|
||||
[path (str (io/resource-path) directory)]
|
||||
(session/put! :list-resources-path path)
|
||||
(sort
|
||||
(filter #(not (nil? %))
|
||||
(map #(first (rest (re-matches pattern (.getName %))))
|
||||
(file-seq (clojure.java.io/file directory))))))</pre></td></tr><tr><td class="spacer docs"> </td><td class="codes" /></tr></table><div class="footer">Generated by <a href="https://github.com/fogus/marginalia">Marginalia</a>. Syntax highlighting provided by Alex Gorbatchev's <a href="http://alexgorbatchev.com/SyntaxHighlighter/">SyntaxHighlighter</a></div><script type="text/javascript">SyntaxHighlighter.defaults['gutter'] = false;
|
||||
(file-seq (clojure.java.io/file path)))))))</pre></td></tr><tr><td class="spacer docs"> </td><td class="codes" /></tr></table><div class="footer">Generated by <a href="https://github.com/fogus/marginalia">Marginalia</a>. Syntax highlighting provided by Alex Gorbatchev's <a href="http://alexgorbatchev.com/SyntaxHighlighter/">SyntaxHighlighter</a></div><script type="text/javascript">SyntaxHighlighter.defaults['gutter'] = false;
|
||||
SyntaxHighlighter.all()</script></body></html>
|
Binary file not shown.
Before Width: | Height: | Size: 198 B After Width: | Height: | Size: 192 B |
|
@ -15,7 +15,10 @@ if state is in grassland or heath and more than 2 neighbours are pasture then st
|
|||
if state is pasture and more than 3 neighbours are pasture and fewer than 1 neighbours are camp and fewer than 1 neighbours within 2 are house then state should be camp
|
||||
|
||||
;; the idea of agriculture spreads
|
||||
if state is in grassland or heath and some neighbours are pasture and some neighbours within 3 are house then state should be pasture
|
||||
if state is in grassland or heath and some neighbours within 3 are house then state should be pasture
|
||||
|
||||
;; nomads don't move on while the have crops growing. That would be silly!
|
||||
if state is camp and some neighbours are ploughland then state should be camp
|
||||
|
||||
;; nomads move on
|
||||
if state is camp then 1 chance in 5 state should be waste
|
||||
|
@ -82,8 +85,8 @@ if state is forest and fertility is more than 5 and altitude is less than 70 the
|
|||
|
||||
if state is climax then 1 chance in 500 state should be fire
|
||||
|
||||
;; Climax forest neighbouring fires is likely to catch fire. So are buildings.
|
||||
if state is in climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire
|
||||
;; Forest neighbouring fires is likely to catch fire. So are buildings.
|
||||
if state is in forest or climax or camp or house or inn and some neighbours are fire then 1 chance in 3 state should be fire
|
||||
|
||||
;; Climax forest near to settlement may be cleared for timber
|
||||
if state is in climax and more than 3 neighbours within 2 are house then state should be scrub
|
||||
|
@ -123,4 +126,3 @@ if state is new and altitude is more than 200 then state should be snow
|
|||
|
||||
;; otherwise, we have grassland.
|
||||
if state is new then state should be grassland
|
||||
|
||||
|
|
|
@ -93,12 +93,15 @@
|
|||
user interface is a web browser. It would be possible to arrange a
|
||||
classroom with one copy of MicroWorld on a single server, and each child's
|
||||
machine running MicroWorld from that single server.</p>
|
||||
<p>However, performance isn't very good, and unless you have an unusually
|
||||
powerful server you may find that when a full class of pupils are running
|
||||
MicroWorld from a single server performance may be frustratingly poor.
|
||||
Check your performance before introducing a class to it, and if in doubt,
|
||||
<p>However, many users accessing the same server at the same time may
|
||||
lead to poor performance.
|
||||
Check performance on your system before introducing a class to it, and if in doubt,
|
||||
running a separate copy on each machine used by children may well be more
|
||||
satisfactory.</p>
|
||||
<p>If many users are using the same shared machine, you should make sure
|
||||
that they don't use the 'original' or 'med' versions of the Great Britain
|
||||
and Ireland map - both of these are big, and performance will inevitably
|
||||
be poor.</p>
|
||||
|
||||
<h3>Subject areas</h3>
|
||||
<p>One of my main objectives in writing MicroWorld was to create a system
|
||||
|
@ -148,15 +151,34 @@
|
|||
class projects. Writing rules will enable discussion of why castles, or
|
||||
mills, are positioned where they are, and what the social consequences of
|
||||
these developments are.</p>
|
||||
<p>You might also want to explore the conditions for the spread of epidemic
|
||||
disease - such as the black death - I've provided a state for this,
|
||||
but no rules.</p>
|
||||
<h4>IT/Informatics</h4>
|
||||
<p>Obviously, any of the rulesets but particularly the <em>gameoflife</em>
|
||||
<p>Obviously, any of the rulesets but particularly the <em>life</em>
|
||||
ruleset are good introduction points to informatics lessons. The rule
|
||||
language is sufficiently simple that introducing children to writing
|
||||
their own rules can begin almost as soon as basic literacy is
|
||||
established.</p>
|
||||
<p>In more advanced IT lessons, at the upper end of primary school or in
|
||||
secondary schools, I would encourage you to explore modifying the engine
|
||||
itself in your classes.</p>
|
||||
itself in your classes. Also, it would be interesting to write an
|
||||
export program which would export MicroWorld maps to Minecraft, or
|
||||
render them as explorable three dimensional spaces using
|
||||
<a href="http://jmonkeyengine.org/">JMonkeyEngine</a>
|
||||
or <a href="https://nightmod.net/">NightMod</a>.</p>
|
||||
<h4>Art and design</h4>
|
||||
<p>A number of projects, progressively more ambitious, are possible in
|
||||
art and design.</p>
|
||||
<ol>
|
||||
<li>The tiles I've drawn are pretty basic - again, that's
|
||||
intentional, children can easily produce better ones. They don't have to
|
||||
be 32x32, but they do all have to be the same size.</li>
|
||||
<li>The stylesheets providing the overall look and feel of the system
|
||||
could be modified</li>
|
||||
<li>If you have an IT project to render a 3d world, you will need 3d
|
||||
models of each of the states, instead of tiles. That might be a job for
|
||||
<a href="http://blender.org">Blender</a>.</li></ol>
|
||||
|
||||
<h3>Lesson plans</h3>
|
||||
<ul>
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
[cell]
|
||||
(let [state (:state cell)]
|
||||
[:td {:class (format-css-class state) :title (format-mouseover cell)}
|
||||
[:a {:href (format "inspect?x=%d&y=%d" (:x cell) (:y cell))}
|
||||
[:a {:href (format "inspect?x=%d&y=%d" (:x cell) (:y cell))}
|
||||
[:img {:alt (:state cell) :src (format-image-path state)}]]]))
|
||||
|
||||
(defn render-world-row
|
||||
|
@ -63,19 +63,16 @@
|
|||
(map render-world-row w2)))
|
||||
[:p (str "Generation " generation)]]))
|
||||
|
||||
(defn render-world
|
||||
"Render the world implied by the session as a complete HTML page."
|
||||
[]
|
||||
(html
|
||||
[:html
|
||||
[:head
|
||||
[:title "MicroWorld demo"]
|
||||
[:link {:media "only screen and (max-device-width: 480px)" :href "css/phone.css" :type "text/css" :rel "stylesheet"}]
|
||||
[:link {:media "only screen and (min-device-width: 481px) and (max-device-width: 1024px)" :href "css/tablet.css" :type "text/css" :rel "stylesheet"}]
|
||||
[:link {:media "screen and (min-device-width: 1025px)" :href "css/standard.css" :type "text/css" :rel "stylesheet"}]
|
||||
[:link {:media "print" :href "css/print.css" :type "text/css" :rel "stylesheet"}]
|
||||
[:link {:href "css/states.css" :type "text/css" :rel "stylesheet"}]
|
||||
[:meta {:http-equiv "refresh" :content "5"}]]
|
||||
[:body
|
||||
(render-world-table)
|
||||
]]))
|
||||
(defn render-inspector
|
||||
[cell table]
|
||||
[:table {:class "music-ruled"}
|
||||
[:tr
|
||||
[:td {:colspan 2 :style "text-align: center;"}
|
||||
[:img {:src (str "img/tiles/" (name (:state cell)) ".png")
|
||||
:width 64
|
||||
:height 64}]]]
|
||||
[:tr [:th "Key"][:th "Value"]]
|
||||
(map #(vector :tr (vector :th %)(vector :td (cell %))) (keys cell))])
|
||||
|
||||
|
||||
|
|
@ -1,18 +1,43 @@
|
|||
(ns mw-ui.routes.home
|
||||
(:use clojure.walk
|
||||
compojure.core
|
||||
[mw-engine.utils :as engine-utils]
|
||||
[mw-ui.routes.rules :as rules]
|
||||
[mw-ui.routes.params :as params])
|
||||
(:require [hiccup.core :refer [html]]
|
||||
[mw-ui.layout :as layout]
|
||||
[mw-ui.util :as util]
|
||||
[mw-ui.render-world :as world]
|
||||
[noir.session :as session]))
|
||||
[noir.session :as session]
|
||||
[ring.util.response :as response]))
|
||||
|
||||
(defn home-page []
|
||||
(layout/render "trusted-content.html" {:title "Welcome to MicroWorld"
|
||||
:content (util/md->html "/md/mw-ui.md")}))
|
||||
|
||||
(defn inspect-page [request]
|
||||
(let [params (keywordize-keys (:params request))
|
||||
xs (:x params)
|
||||
ys (:y params)
|
||||
x (if (not (empty? xs)) (read-string xs) 0)
|
||||
y (if (not (empty? ys)) (read-string ys) 0)
|
||||
world (session/get :world)
|
||||
cell (engine-utils/get-cell world x y)
|
||||
state (:state params)]
|
||||
(cond state
|
||||
(do
|
||||
(session/put! :world (engine-utils/set-property world cell :state (keyword state)))
|
||||
(response/redirect "world"))
|
||||
true
|
||||
(layout/render "inspector.html"
|
||||
{:title (format "Inspect cell at %d, %d" x y)
|
||||
:content (html (world/render-inspector cell world))
|
||||
:cell cell
|
||||
:x (:x cell)
|
||||
:y (:y cell)
|
||||
:states (util/list-resources
|
||||
"/img/tiles" #"([0-9a-z-_]+).png")}))))
|
||||
|
||||
(defn world-page []
|
||||
(layout/render "trusted-content.html"
|
||||
{:title "Watch your world grow"
|
||||
|
@ -43,8 +68,8 @@
|
|||
(defn docs-page []
|
||||
(layout/render "docs.html" {:title "Documentation"
|
||||
:parser (util/md->html "/md/mw-parser.md" )
|
||||
:states (util/list-resources "resources/public/img/tiles" #"([0-9a-z-_]+).png")
|
||||
:lessons (util/list-resources "resources/public/md/lesson-plans" #"([0-9a-z-_]+).md")
|
||||
:states (util/list-resources "/img/tiles" #"([0-9a-z-_]+).png")
|
||||
:lessons (util/list-resources "/md/lesson-plans" #"([0-9a-z-_]+).md")
|
||||
:components ["mw-engine" "mw-parser" "mw-ui"]}))
|
||||
|
||||
(defroutes home-routes
|
||||
|
@ -56,4 +81,7 @@
|
|||
(GET "/md" request (md-page request))
|
||||
(POST "/params" request (params/params-page request))
|
||||
(GET "/rules" request (rules/rules-page request))
|
||||
(POST "/rules" request (rules/rules-page request)))
|
||||
(POST "/rules" request (rules/rules-page request))
|
||||
(GET "/inspect" request (inspect-page request))
|
||||
(POST "/inspect" request (inspect-page request))
|
||||
)
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
;; Test file specifically to test the helper function in rules handler
|
||||
(deftest test-rules-processor
|
||||
(testing "Rules processor"
|
||||
(let [request {:src "if state is new and altitude is less than 10 then state should be water"}
|
||||
(let [request {:form-params {:src "if state is new and altitude is less than 10 then state should be water"}}
|
||||
response (process-rules-request request)]
|
||||
(is (= (:message response) "Successfully compiled 1 rules"))
|
||||
(is (= (count (:rules response)) 1))
|
||||
(is (= (:rule-text response) (:src request))))))
|
||||
(is (= (:rule-text response) (:src (:form-params request)))))))
|
||||
|
|
Loading…
Reference in a new issue