diff --git a/README.md b/README.md index a11cb06..9375cea 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,140 @@ -# mw-ui +## What this is about -FIXME +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. -## Prerequisites +[Go and watch](world) it running for a few moments, then come back here. -You will need [Leiningen][1] 2.0 or above installed. +The demonstration world is a mountain, with snow at the top and the sea at the +bottom. as you watched, you probably saw the bright green of grass on the lower +slopes of the mountain turn to the darker green of forest. You may have seen +some forest fires break out. -## Running +That's all controlled by rules. You make the rules. To start Noah's flood, +[go to the rules page](rules) now, and add this rule at the very top: -To start a web server for the application, run: + if altitude is less than 200 then state should be water + +then, [go and watch the world](world) again. What happens? You should see water +spread across everywhere except the very top of the mountain. But after the +flood, the waters should drain away again. Go back to [rules](rules) and add +this rule at the very top: + + if altitude is more than 9 and state is water then state should be grassland + +Now the world alternates between *new* and *grassland*. That's no good! Go back to +[rules](rules) and delete the rule that you first added - the one that says + + if altitude is less than 200 then state should be water + +And see! The world starts growing again. + +## What you can do next + +### Change some rules + +Change some of the other rules and see what happens. Very likely, one of the +first things that will happen is that you will get a message like this: + + I did not understand 'if state is grassland then 1 chance in 10 state will be heath' + +That means that you changed a rule in a way that the engine could no longer +understand it. To find out what the engine will understand, have a look at the +[documentation](docs#grammar). + +### Invent some rules of your own! + +What happens when people come into the world? Where would they make their first +camp? Would they want to be near the water, so they could fish? Would they want +be near fertile grassland, to graze their sheep and cattle? + +__Write a rule which adds some camps to the world__ + +What happens to the land around a camp? Do the people burn down forest to make +new grassland? Do they convert the grassland into meadow, or into crop? + +Does growing crops reduce the soil fertility? What makes people decide that their +camp is a good enough place to build a proper house? + +__Write some rules which describe this__ + +How many squares of meadow or crop does it take to feed each house full of people? +What happens when there are too many houses and not enough fields? Can houses +catch fire? What happens to a house which is next to a fire? + +How many houses do you need for a market place? Where would people build a +harbour? + +### Change the rules completely + +I've provided rules which use the MicroWorld cellular automaton to make a simple +model of the changes to land in Europe after the ice age. But you don't have to +use it like that, at all. + +[Conway's Game of Life](http://en.wikipedia.org/wiki/Conway's_Game_of_Life) is one +of the famous uses of a cellular automaton. The rules for the Game of Life are +very simple. To set up your game of life you'll need some initialisation rules, +one for every cell you want to start live (we'll use _black_ for live, and +_white_ for dead): + + if x is equal to 4 and y is equal to 4 and state is new then state should be black + +Add as many of these as you need for your starting pattern. Then add a rule, after +all those: + + if state is new then state should be white + +I'll leave you to work out what the rules of life are for yourself, from the +Wiki page I linked to. + +### Change the engine + +If you want to modify the engine itself, you will need +[Leiningen](https://github.com/technomancy/leiningen) 2.0 or above installed on +your own computer, and you'll need to download the source, and unpack it. + +You will find that there are three packages: + ++ __mw-engine__ deals with creating worlds, and transforming them; ++ __mw-parser__ deals with turning the rule language into something the engine can work on; ++ __mw-ui__ is the web site which provides you with a user interface. + +For each of these packages, you need to run, in the root directory of the package, +the following command: + + lein install + +Once you've done that, you'll have everything built. To start a web server for +the application, run the following command in the _mw-ui_ directory: lein ring server +Now you have it working, you can start changing things. + +#### Add states + +Adding new states is easy: +just add new tiles in _mw-ui/resources/public/img/tiles_. The tiles should be +png (Portable Network Graphics) files, and should be 32 pixels square. The name +of the tile should be the name of your new state. It's good to also edit the file +_mw-ui/resources/public/css/states.css_ to add a class for your new state. + +#### Change the code + +Once you've done all that, you're ready to be really ambitious. Change the code. +Implement some new feature I haven't thought of, or fix bugs I've accidentally +left in. + +You'll need an editor. I recommend either [NightCode](https://nightcode.info/), +which is quite small and will run on a Raspberry Pi, or +[LightTable](http://www.lighttable.com/), which is extremely helpful but needs +a more powerful computer. + +Have fun! + ## License -Copyright © 2014 Simon Brooke +Copyright © 2014 [Simon Brooke](mailto:simon@journeyman.cc) -Distributed under the terms of the [GNU General Public License v2][2] - - -[1]: https://github.com/technomancy/leiningen -[2]: http://www.gnu.org/licenses/gpl-2.0.html \ No newline at end of file +Distributed under the terms of the [GNU General Public License v2](http://www.gnu.org/licenses/gpl-2.0.html) \ No newline at end of file diff --git a/resources/public/css/standard.css b/resources/public/css/standard.css index e60166e..0fd8ba0 100644 --- a/resources/public/css/standard.css +++ b/resources/public/css/standard.css @@ -35,8 +35,8 @@ body { width:100%; margin: -10px; padding: 0.25em 10%; - position: fixed; - z-index: 149; + position: fixed; + z-index: 149; background-color: black; background-repeat: no-repeat; color: white; diff --git a/resources/public/docs/mw-ui/uberdoc.html b/resources/public/docs/mw-ui/uberdoc.html index 2d2ec5b..4a5d41a 100644 --- a/resources/public/docs/mw-ui/uberdoc.html +++ b/resources/public/docs/mw-ui/uberdoc.html @@ -3029,7 +3029,7 @@ net.brehaut.ClojureTools = (function (SH) { }; })(SyntaxHighlighter); mw-ui -- Marginalia

mw-ui

0.1.0-SNAPSHOT


Web-based user interface for MicroWorld

-

dependencies

org.clojure/clojure
1.6.0
mw-engine
0.1.0-SNAPSHOT
mw-parser
0.1.0-SNAPSHOT
lib-noir
0.8.4
ring-server
0.3.1
selmer
0.6.8
com.taoensso/timbre
3.2.1
com.taoensso/tower
2.0.2
markdown-clj
0.9.44
environ
0.5.0
noir-exception
0.2.2



(this space intentionally left almost blank)
 
+

dependencies

org.clojure/clojure
1.6.0
mw-engine
0.1.0-SNAPSHOT
mw-parser
0.1.0-SNAPSHOT
lib-noir
0.8.4
ring-server
0.3.1
selmer
0.6.8
com.taoensso/timbre
3.2.1
com.taoensso/tower
2.0.2
markdown-clj
0.9.44
environ
0.5.0
noir-exception
0.2.2



(this space intentionally left almost blank)
 
(ns mw-ui.handler
   (:require [compojure.core :refer [defroutes]]
             [mw-ui.routes.home :refer [home-routes]]
@@ -3208,18 +3208,16 @@ net.brehaut.ClojureTools = (function (SH) {
   (.stop @server)
   (reset! server nil))
 
(ns mw-ui.routes.home
-  (:use compojure.core)
+  (:use compojure.core
+        [mw-ui.routes.rules :as rules])
   (:require [hiccup.core :refer [html]]
-            [mw-parser.bulk :as compiler]
             [mw-ui.layout :as layout]
             [mw-ui.util :as util]
             [mw-ui.render-world :as world]
             [noir.session :as session]))
(defn home-page []
-  (layout/render "world.html" {:title "Watch your world grow" 
-                               :content (html (world/render-world-table)) 
-                               :seconds (or (session/get :seconds) 5) 
-                               :maybe-refresh "refresh"}))
+ (layout/render "home.html" {:title "Welcome to MicroWorld" + :content (util/md->html "/md/mw-ui.md")}))
(defn world-page []
   (layout/render "world.html" {:title "Watch your world grow" 
                                :content (html (world/render-world-table)) 
@@ -3237,29 +3235,58 @@ net.brehaut.ClojureTools = (function (SH) {
                               :parser (util/md->html "/md/mw-parser.md")
                               :states (list-states)
                               :components ["mw-engine" "mw-parser" "mw-ui"]}))
-
(defn rules-page 
-  ([request]
-    (let [rule-text (:src request)
-          error 
-          (try 
-            (do
-              (if rule-text
-                (session/put! :rules (compiler/compile-string rule-text)))
-              (session/put! :rule-text rule-text)
-              nil)
-            (catch Exception e (.getMessage e)))]
-      (layout/render "rules.html" {:title "Edit Rules" 
-                                   :rule-text (or (session/get :rule-text) (slurp "resources/public/rulesets/basic.txt"))
-                                   :error error})))
-  ([]
-    (rules-page nil)))
(defroutes home-routes
   (GET "/" [] (home-page))
   (GET "/about" [] (about-page))
   (GET "/docs"  [] (docs-page))
   (GET "/world"  [] (world-page))
-  (GET "/rules" request (rules-page request))
-  (POST "/rules" request (rules-page request)))
 
+ (GET "/rules" request (rules/rules-page request)) + (POST "/rules" request (rules/rules-page request)))
 
+
(ns mw-ui.routes.rules
+  (:use clojure.walk
+        compojure.core)
+  (:require [hiccup.core :refer [html]]
+            [mw-parser.bulk :as compiler]
+            [mw-ui.layout :as layout]
+            [mw-ui.util :as util]
+            [mw-ui.render-world :as world]
+            [noir.session :as session]))
+
(defn process-rules-request
+  [request]
+  (let [src (:src (keywordize-keys (:form-params request)))]
+      (try 
+        (cond src 
+          (let [rules (compiler/compile-string src)]
+            {:rule-text src
+             :rules rules
+             :message (str "Successfully compiled " 
+                           (count rules) 
+                           " rules")           })
+          true {:rule-text (or 
+                             (session/get :rule-text) 
+                             (slurp "resources/rulesets/basic.txt"))
+                :message "No rules found in request; loading defaults"})
+        (catch Exception e 
+          {:rule-text src
+           :message "An error occurred during compilation"
+           :error (str (.getName (.getClass e)) ": " (.getMessage e))}))))

Request handler for the rules request. If the request contains a value + for :src, treat that as rule source and try to compile it. If compilation + succeeds, stash the compiled rules and the rule text on the session, and + provide feedback; if not, provide feedback.

+ +

If request doesn't contain a value for :src, load basic rule source from + the session or from resources/rulesets/basic.txt and pass that back.

+
(defn rules-page 
+  ([request]
+    (let [processed (process-rules-request request)]
+      (if (:rules processed)
+        (session/put! :rules (:rules processed)))
+      (if (:rule-text processed)
+        (session/put! :rule-text (:rule-text processed)))
+      (layout/render "rules.html" 
+                     (merge {:title "Edit Rules"} processed))))
+  ([]
+    (rules-page nil)))
 
(ns mw-ui.util
   (:require [noir.io :as io]
             [markdown.core :as md]))

reads a markdown file from public/md and returns an HTML string

diff --git a/resources/public/rulesets/basic.txt b/resources/rulesets/basic.txt similarity index 100% rename from resources/public/rulesets/basic.txt rename to resources/rulesets/basic.txt diff --git a/resources/templates/base.html b/resources/templates/base.html index 4191f0c..6b208f3 100644 --- a/resources/templates/base.html +++ b/resources/templates/base.html @@ -19,7 +19,7 @@ -