Compare commits

...

31 commits

Author SHA1 Message Date
Simon Brooke 29d9c2e549 Allow zero coordinates in cells (d'oh!) 2024-05-04 14:36:19 +01:00
Simon Brooke a44e9548a2 comment out test code we don't want run every time the library is loaded! 2024-04-07 22:13:59 +01:00
Simon Brooke 716eb9442e More work on drainage and rendering. 2024-04-06 23:37:55 +01:00
Simon Brooke c739dd7094 Drainage is now *mostly* working...
not sure about rivers flowing out of lakes.
2024-04-06 16:54:10 +01:00
Simon Brooke e19ce2e5f7 drainage/flow-world-nr now works; drainage/flow-world still doesn't 2024-04-06 09:41:52 +01:00
Simon Brooke 93dab8067b Work in support of new development in the-great-game, q.v. 2024-04-05 22:13:13 +01:00
Simon Brooke 3e1e3052d1 More on history; more error trapping on flows. 2023-07-26 07:25:02 +01:00
Simon Brooke 4b1472d311 New cell history feature 2023-07-22 21:16:33 +01:00
Simon Brooke 85d66208b9 Much better error logging on rule execution. 2023-07-21 23:53:08 +01:00
Simon Brooke ac25969f90 Major overhaul of rule metadata, so upversioned to 0.3.0
Many tests do not pass at this stage
2023-07-21 09:35:14 +01:00
Simon Brooke ff6bbad14c Major overhaul of rule metadata, so upversioned to 0.3.0
Many tests do not pass at this stage
2023-07-19 20:35:19 +01:00
Simon Brooke 321e6edd9a Logging rule errors. 2023-07-18 22:27:27 +01:00
Simon Brooke 68298cf9c1 More work on flow rules. All rules must now have metadata
Better error capturing!
2023-07-18 22:15:19 +01:00
Simon Brooke 866c00bea0 Some work on flow, but mainly tidyup. 2023-07-11 08:22:54 +01:00
Simon Brooke 4f35557b38 Upversioning whole system to 0.2.0, for flow feature 2023-07-10 13:48:07 +01:00
Simon Brooke 8b3639edd5 Logging of flows; better member? 2023-07-10 10:44:33 +01:00
Simon Brooke f60fdb944b Executing flows now works. 2023-07-10 08:15:09 +01:00
Simon Brooke 5ef93ef4df Work on flows, close to complete but no cigar. 2023-07-09 22:27:20 +01:00
Simon Brooke f4d4e9b694 Upgraded everything. This may be a mistake! 2023-07-08 10:21:41 +01:00
Simon Brooke 67a43279f6
Fix linting issues 2021-12-09 21:20:31 +00:00
Simon Brooke 630309719e
Merge branch 'feature/2' into develop 2021-12-09 20:03:21 +00:00
Simon Brooke 2cb3a6af6f
Trying to address bit-rot 2021-12-09 20:02:33 +00:00
Simon Brooke 1cb613e6e6
: Minor preparatory changes. 2020-06-06 12:21:54 +01:00
Simon Brooke 2f2463da0e
Sweep up of minor changes 2020-06-03 10:47:28 +01:00
simon 519ca4e3bd Upversioned from 0.1.5 to 0.1.6-SNAPSHOT 2016-12-27 16:18:38 +00:00
simon 3ca247e471 Upversioned from 0.1.5-SNAPSHOT to 0.1.5 for release 2016-12-27 16:18:10 +00:00
simon 47caea3eb8 Don't do anything with mw-explore during buildall - it contains unreliable junk. 2016-12-27 15:44:57 +00:00
simon 39b7cd608c Added Docker stuff; corrected usage message. 2016-12-27 15:22:41 +00:00
simon f1b35dc948 Standardised header documentation in line with current best practice. 2016-08-21 14:17:30 +01:00
simon 944b54fc89 Deleted version.clj, which did not work anyway. 2016-08-13 17:41:53 +01:00
simon 21cdff764f Added namespace documentation conforming to better practice; added GPL
declaration; changed 'use' to 'require' passim. All tests pass but that's
not proof we're all good yet.
2016-08-13 17:39:07 +01:00
56 changed files with 11673 additions and 855 deletions

19
.gitignore vendored Normal file
View file

@ -0,0 +1,19 @@
.calva/
target/
pom.xml
.lein-repl-history
.lein-failures
eastwood.txt
.clj-kondo/
.lsp/
.project
.settings/
.nrepl-port
.classpath
test.html

View file

@ -13,6 +13,13 @@ You can see MicroWorld in action [here](http://www.journeyman.cc/microworld/) -
but please don't be mean to my poor little server. If you want to run big maps
or complex rule-sets, please run it on your own machines.
### Version compatibility
There are substantial changes in how rule functions are evaluated between 0.1.x
versions of MicroWorld libraries and 0.3.x versions. In particular, in 0.3.x
metadata is held on rule functions which is essential to the functioning of the
engine. Consequently, you cannot mix 0.1.x and 0.3.x libraries: it will not work.
## Usage
Primary entry points are make-world and run-world, both in mw-engine.core. See

View file

@ -72,8 +72,9 @@ if [ $# -lt 1 ]
then
cat <<-EOF 1>&2
Usage:
-archive Create a tar archive of the current state of the source.
-build Build all components and commit to master.
-archive Create a tar archive of the current state of the source.
-build Build all components, commit and push to origin.
-docker Build and push a Docker image.
-email [ADDRESS] Your email address, to be recorded in the build signature.
-fullname [NAME] Your full name, to be recorded in the build signature.
-pull Pull from remote git repository
@ -87,12 +88,14 @@ fi
while (( "$#" ))
do
case $1 in
-a|-archive)
archive="TRUE";;
-a|-archive)
archive="TRUE";;
-b|-build)
# 'build' is the expected normal case.
trial="FALSE";
;;
-d|-docker)
docker="TRUE";;
-e|-email)
shift;
email=$1;;
@ -126,7 +129,7 @@ do
shift
done
echo "Trial: ${trial}; email: ${email}; fullname ${fullname}; release: ${release}; webapps: $webappsdir"
echo "Trial: ${trial}; docker: ${docker}; email: ${email}; fullname ${fullname}; release: ${release}; webapps: $webappsdir"
ls mw-* > /dev/null 2>&1
if [ $? -ne 0 ]
@ -137,132 +140,141 @@ fi
for dir in mw-*
do
pushd ${dir}
if [ "${dir}" != "mw-explore" ]
then
pushd ${dir}
# Make a temporary directory to keep the work-in-progress files.
if [ ! -d "${tmp}" ]
then
rm -f "${tmp}"
mkdir "${tmp}"
fi
# Make a temporary directory to keep the work-in-progress files.
if [ ! -d "${tmp}" ]
then
rm -f "${tmp}"
mkdir "${tmp}"
fi
cat project.clj > ${tmp}/project.bak.1
old=`cat project.clj | grep 'defproject mw' | sed 's/.*defproject mw-[a-z]* "\([A-Za-z0-9_.-]*\)".*/\1/'`
cat project.clj > ${tmp}/project.bak.1
old=`cat project.clj | grep 'defproject mw' | sed 's/.*defproject mw-[a-z]* "\([A-Za-z0-9_.-]*\)".*/\1/'`
if [ "${release}" != "" ]
then
message="Preparing ${old} for release"
if [ "${release}" != "" ]
then
message="Preparing ${old} for release"
# Does the 'old' version tag end with the token "-SNAPSHOT"? it probably does!
echo "${old}" | grep 'SNAPSHOT'
if [ $? -eq 0 ]
then
# It does...
interim=`echo ${old} | sed 's/\([A-Za-z0-9_.-]*\)-SNAPSHOT.*/\1/'`
if [ "${interim}" = "" ]
then
echo "Failed to compute interim version tag from '${old}'" 1>&2
exit 1;
fi
setup-build-sig "${old}" "${interim}" "${fullname}" "${email}"
message="Upversioned from ${old} to ${interim} for release"
old=${interim}
else
setup-build-sig "unset" "${old}" "${fullname}" "${email}"
fi
else
setup-build-sig "unset" "${old}" "${fullname}" "${email}"
fi
# Does the 'old' version tag end with the token "-SNAPSHOT"? it probably does!
echo "${old}" | grep 'SNAPSHOT'
if [ $? -eq 0 ]
then
# It does...
interim=`echo ${old} | sed 's/\([A-Za-z0-9_.-]*\)-SNAPSHOT.*/\1/'`
if [ "${interim}" = "" ]
then
echo "Failed to compute interim version tag from '${old}'" 1>&2
exit 1;
fi
setup-build-sig "${old}" "${interim}" "${fullname}" "${email}"
message="Upversioned from ${old} to ${interim} for release"
old=${interim}
else
setup-build-sig "unset" "${old}" "${fullname}" "${email}"
fi
else
setup-build-sig "unset" "${old}" "${fullname}" "${email}"
fi
sed -f ${tmp}/manifest.sed ${tmp}/project.bak.1 > project.clj
sed -f ${tmp}/manifest.sed ${tmp}/project.bak.1 > project.clj
echo $message
echo $message
lein clean
lein compile
if [ $? -ne 0 ]
then
echo "Sub-project ${dir} failed in compile" 1>&2
exit 1
fi
lein clean
lein compile
if [ $? -ne 0 ]
then
echo "Sub-project ${dir} failed in compile" 1>&2
exit 1
fi
lein test
if [ $? -ne 0 ]
then
echo "Sub-project ${dir} failed in test" 1>&2
exit 1
fi
lein test
if [ $? -ne 0 ]
then
echo "Sub-project ${dir} failed in test" 1>&2
exit 1
fi
lein marg
lein install
lein marg
lein install
# If we're in the UI project, build the uberwar - and should
# probably deploy it to local Tomcat for test
if [ "${dir}" = "mw-ui" -a "${webappsdir}" != "" ]
then
lein ring uberwar
sudo cp target/microworld.war "${webappsdir}"
echo "Deployed new WAR file to local Tomcat at ${webappsdir}"
fi
# If we're in the UI project, build the uberwar - and should
# probably deploy it to local Tomcat for test
if [ "${dir}" = "mw-ui" -a "${webappsdir}" != "" ]
then
lein ring uberwar
sudo cp target/microworld.war "${webappsdir}"
echo "Deployed new WAR file to local Tomcat at ${webappsdir}"
fi
# Then unset manifest properties prior to committing.
cat project.clj > ${tmp}/project.bak.2
setup-build-sig
sed -f ${tmp}/manifest.sed ${tmp}/project.bak.2 > project.clj
if [ "${dir}" = "mw-ui" -a "${docker}" = "TRUE" ]
then
lein docker build
lein docker push
fi
if [ "${trial}" = "FALSE" ]
then
if [ "${message}" = "" ]
then
git commit -a
else
git commit -a -m "$message"
fi
git push origin master
fi
# Then unset manifest properties prior to committing.
cat project.clj > ${tmp}/project.bak.2
setup-build-sig
sed -f ${tmp}/manifest.sed ${tmp}/project.bak.2 > project.clj
if [ "${release}" != "" ]
then
branch="${old}_MAINTENANCE"
if [ "${trial}" = "FALSE" ]
then
git branch "${branch}"
git push origin "${branch}"
fi
if [ "${trial}" = "FALSE" ]
then
if [ "${message}" = "" ]
then
git commit -a
else
git commit -a -m "$message"
fi
git push origin master
fi
cat project.clj > ${tmp}/project.bak.3
setup-build-sig "${old}" "${release}-SNAPSHOT" "${fullname}" "${email}"
sed -f ${tmp}/manifest.sed ${tmp}/project.bak.3 > project.clj
message="Upversioned from ${interim} to ${release}-SNAPSHOT"
if [ "${release}" != "" ]
then
branch="${old}_MAINTENANCE"
if [ "${trial}" = "FALSE" ]
then
git branch "${branch}"
git push origin "${branch}"
fi
echo $message
cat project.clj > ${tmp}/project.bak.3
setup-build-sig "${old}" "${release}-SNAPSHOT" "${fullname}" "${email}"
sed -f ${tmp}/manifest.sed ${tmp}/project.bak.3 > project.clj
message="Upversioned from ${interim} to ${release}-SNAPSHOT"
lein clean
lein compile
if [ $? -ne 0 ]
then
echo "Sub-project ${dir} failed in compile after branch to ${release}!" 1>&2
exit 1
fi
lein marg
lein install
echo $message
# Then unset manifest properties prior to committing.
cat project.clj > ${tmp}/project.bak.4
setup-build-sig
sed -f ${tmp}/manifest.sed ${tmp}/project.bak.4 > project.clj
lein clean
lein compile
if [ $? -ne 0 ]
then
echo "Sub-project ${dir} failed in compile after branch to ${release}!" 1>&2
exit 1
fi
lein marg
lein install
if [ "${trial}" = "FALSE" ]
then
git commit -a -m "${message}"
echo ${message}
git push origin master
fi
fi
# Then unset manifest properties prior to committing.
cat project.clj > ${tmp}/project.bak.4
setup-build-sig
sed -f ${tmp}/manifest.sed ${tmp}/project.bak.4 > project.clj
# if nothing broke so far, clean up...
rm -rf "${tmp}"
popd
if [ "${trial}" = "FALSE" ]
then
git commit -a -m "${message}"
echo ${message}
git push origin master
fi
fi
# if nothing broke so far, clean up...
rm -rf "${tmp}"
popd
fi
done

View file

@ -0,0 +1,40 @@
.covered {
font-family: 'Bitstream Vera Sans Mono', 'Courier', monospace;
background-color: #558B55;
}
.not-covered {
font-family: 'Bitstream Vera Sans Mono', 'Courier', monospace;
background-color: red;
}
.partial {
font-family: 'Bitstream Vera Sans Mono', 'Courier', monospace;
background-color: orange;
}
.not-tracked {
font-family: 'Bitstream Vera Sans Mono', 'Courier', monospace;
}
.blank {
font-family: 'Bitstream Vera Sans Mono', 'Courier', monospace;
}
td {
padding-right: 10px;
}
td.with-bar {
width: 250px;
text-align: center;
}
td.with-number {
text-align: right;
}
td.ns-name {
min-width: 150px;
padding-right: 25px;
}

172
docs/cloverage/index.html Normal file
View file

@ -0,0 +1,172 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="./coverage.css"/>
<title>Coverage Summary</title>
</head>
<body>
<table>
<thead><tr>
<td class="ns-name"> Namespace </td>
<td class="with-bar"> Forms </td>
<td class="with-number">Forms %</td>
<td class="with-bar"> Lines </td>
<td class="with-number">Lines %</td>
<td class="with-number">Total</td><td class="with-number">Blank</td><td class="with-number">Instrumented</td>
</tr></thead>
<tr>
<td><a href="mw_engine/core.clj.html">mw-engine.core</a></td><td class="with-bar"><div class="covered"
style="width:37.185929648241206%;
float:left;"> 74 </div><div class="not-covered"
style="width:62.814070351758794%;
float:left;"> 125 </div></td>
<td class="with-number">37.19 %</td>
<td class="with-bar"><div class="covered"
style="width:50.0%;
float:left;"> 26 </div><div class="partial"
style="width:1.9230769230769231%;
float:left;"> 1 </div><div class="not-covered"
style="width:48.07692307692308%;
float:left;"> 25 </div></td>
<td class="with-number">51.92 %</td>
<td class="with-number">145</td><td class="with-number">13</td><td class="with-number">52</td>
</tr>
<tr>
<td><a href="mw_engine/display.clj.html">mw-engine.display</a></td><td class="with-bar"><div class="covered"
style="width:10.227272727272727%;
float:left;"> 9 </div><div class="not-covered"
style="width:89.77272727272727%;
float:left;"> 79 </div></td>
<td class="with-number">10.23 %</td>
<td class="with-bar"><div class="covered"
style="width:42.10526315789474%;
float:left;"> 8 </div><div class="not-covered"
style="width:57.89473684210526%;
float:left;"> 11 </div></td>
<td class="with-number">42.11 %</td>
<td class="with-number">65</td><td class="with-number">8</td><td class="with-number">19</td>
</tr>
<tr>
<td><a href="mw_engine/drainage.clj.html">mw-engine.drainage</a></td><td class="with-bar"><div class="covered"
style="width:22.62210796915167%;
float:left;"> 88 </div><div class="not-covered"
style="width:77.37789203084833%;
float:left;"> 301 </div></td>
<td class="with-number">22.62 %</td>
<td class="with-bar"><div class="covered"
style="width:34.44444444444444%;
float:left;"> 31 </div><div class="not-covered"
style="width:65.55555555555556%;
float:left;"> 59 </div></td>
<td class="with-number">34.44 %</td>
<td class="with-number">217</td><td class="with-number">30</td><td class="with-number">90</td>
</tr>
<tr>
<td><a href="mw_engine/flow.clj.html">mw-engine.flow</a></td><td class="with-bar"><div class="covered"
style="width:77.65957446808511%;
float:left;"> 511 </div><div class="not-covered"
style="width:22.340425531914892%;
float:left;"> 147 </div></td>
<td class="with-number">77.66 %</td>
<td class="with-bar"><div class="covered"
style="width:67.5%;
float:left;"> 54 </div><div class="partial"
style="width:10.0%;
float:left;"> 8 </div><div class="not-covered"
style="width:22.5%;
float:left;"> 18 </div></td>
<td class="with-number">77.50 %</td>
<td class="with-number">179</td><td class="with-number">18</td><td class="with-number">80</td>
</tr>
<tr>
<td><a href="mw_engine/heightmap.clj.html">mw-engine.heightmap</a></td><td class="with-bar"><div class="covered"
style="width:92.71523178807946%;
float:left;"> 140 </div><div class="not-covered"
style="width:7.28476821192053%;
float:left;"> 11 </div></td>
<td class="with-number">92.72 %</td>
<td class="with-bar"><div class="covered"
style="width:91.30434782608695%;
float:left;"> 42 </div><div class="partial"
style="width:4.3478260869565215%;
float:left;"> 2 </div><div class="not-covered"
style="width:4.3478260869565215%;
float:left;"> 2 </div></td>
<td class="with-number">95.65 %</td>
<td class="with-number">133</td><td class="with-number">12</td><td class="with-number">46</td>
</tr>
<tr>
<td><a href="mw_engine/natural_rules.clj.html">mw-engine.natural-rules</a></td><td class="with-bar"><div class="covered"
style="width:7.774390243902439%;
float:left;"> 51 </div><div class="not-covered"
style="width:92.22560975609755%;
float:left;"> 605 </div></td>
<td class="with-number">7.77 %</td>
<td class="with-bar"><div class="covered"
style="width:33.0188679245283%;
float:left;"> 35 </div><div class="partial"
style="width:4.716981132075472%;
float:left;"> 5 </div><div class="not-covered"
style="width:62.264150943396224%;
float:left;"> 66 </div></td>
<td class="with-number">37.74 %</td>
<td class="with-number">184</td><td class="with-number">14</td><td class="with-number">106</td>
</tr>
<tr>
<td><a href="mw_engine/render.clj.html">mw-engine.render</a></td><td class="with-bar"><div class="covered"
style="width:6.875%;
float:left;"> 11 </div><div class="not-covered"
style="width:93.125%;
float:left;"> 149 </div></td>
<td class="with-number">6.88 %</td>
<td class="with-bar"><div class="covered"
style="width:27.77777777777778%;
float:left;"> 10 </div><div class="not-covered"
style="width:72.22222222222223%;
float:left;"> 26 </div></td>
<td class="with-number">27.78 %</td>
<td class="with-number">98</td><td class="with-number">11</td><td class="with-number">36</td>
</tr>
<tr>
<td><a href="mw_engine/utils.clj.html">mw-engine.utils</a></td><td class="with-bar"><div class="covered"
style="width:65.87395957193817%;
float:left;"> 554 </div><div class="not-covered"
style="width:34.126040428061835%;
float:left;"> 287 </div></td>
<td class="with-number">65.87 %</td>
<td class="with-bar"><div class="covered"
style="width:64.93506493506493%;
float:left;"> 100 </div><div class="partial"
style="width:0.6493506493506493%;
float:left;"> 1 </div><div class="not-covered"
style="width:34.41558441558441%;
float:left;"> 53 </div></td>
<td class="with-number">65.58 %</td>
<td class="with-number">379</td><td class="with-number">41</td><td class="with-number">154</td>
</tr>
<tr>
<td><a href="mw_engine/world.clj.html">mw-engine.world</a></td><td class="with-bar"><div class="covered"
style="width:34.57446808510638%;
float:left;"> 65 </div><div class="not-covered"
style="width:65.42553191489361%;
float:left;"> 123 </div></td>
<td class="with-number">34.57 %</td>
<td class="with-bar"><div class="covered"
style="width:33.333333333333336%;
float:left;"> 13 </div><div class="partial"
style="width:2.5641025641025643%;
float:left;"> 1 </div><div class="not-covered"
style="width:64.1025641025641%;
float:left;"> 25 </div></td>
<td class="with-number">35.90 %</td>
<td class="with-number">111</td><td class="with-number">14</td><td class="with-number">39</td>
</tr>
<tr><td>Totals:</td>
<td class="with-bar"></td>
<td class="with-number">45.14 %</td>
<td class="with-bar"></td>
<td class="with-number">54.18 %</td>
</tr>
</table>
</body>
</html>

View file

@ -0,0 +1,443 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="../coverage.css"/> <title> mw_engine/core.clj </title>
</head>
<body>
<span class="covered" title="1 out of 1 forms covered">
001&nbsp;&nbsp;(ns&nbsp;^{:doc&nbsp;&quot;Functions&nbsp;to&nbsp;transform&nbsp;a&nbsp;world&nbsp;and&nbsp;run&nbsp;rules.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
002&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
003&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Every&nbsp;rule&nbsp;is&nbsp;a&nbsp;function&nbsp;of&nbsp;two&nbsp;arguments,&nbsp;a&nbsp;cell&nbsp;and&nbsp;a&nbsp;world.&nbsp;If&nbsp;the&nbsp;rule
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
004&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fires,&nbsp;it&nbsp;returns&nbsp;a&nbsp;new&nbsp;cell,&nbsp;which&nbsp;should&nbsp;have&nbsp;the&nbsp;same&nbsp;values&nbsp;for&nbsp;`:x`&nbsp;and
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
005&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`:y`&nbsp;as&nbsp;the&nbsp;old&nbsp;cell.&nbsp;Anything&nbsp;else&nbsp;can&nbsp;be&nbsp;modified.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
006&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
007&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;While&nbsp;any&nbsp;function&nbsp;of&nbsp;two&nbsp;arguments&nbsp;can&nbsp;be&nbsp;used&nbsp;as&nbsp;a&nbsp;rule,&nbsp;a&nbsp;special&nbsp;high
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;level&nbsp;rule&nbsp;language&nbsp;is&nbsp;provided&nbsp;by&nbsp;the&nbsp;`mw-parser`&nbsp;package,&nbsp;which&nbsp;compiles
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
009&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rules&nbsp;expressed&nbsp;in&nbsp;a&nbsp;subset&nbsp;of&nbsp;English&nbsp;rules&nbsp;into&nbsp;suitable&nbsp;functions.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
010&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
011&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;A&nbsp;cell&nbsp;is&nbsp;a&nbsp;map&nbsp;containing&nbsp;at&nbsp;least&nbsp;values&nbsp;for&nbsp;the&nbsp;keys&nbsp;:x,&nbsp;:y,&nbsp;and&nbsp;:state;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
012&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a&nbsp;transformation&nbsp;should&nbsp;not&nbsp;alter&nbsp;the&nbsp;values&nbsp;of&nbsp;:x&nbsp;or&nbsp;:y,&nbsp;and&nbsp;should&nbsp;not
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
013&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;a&nbsp;cell&nbsp;without&nbsp;a&nbsp;keyword&nbsp;as&nbsp;the&nbsp;value&nbsp;of&nbsp;:state.&nbsp;Anything&nbsp;else&nbsp;is
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
014&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;legal.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
015&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
016&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;A&nbsp;world&nbsp;is&nbsp;a&nbsp;two&nbsp;dimensional&nbsp;matrix&nbsp;(sequence&nbsp;of&nbsp;sequences)&nbsp;of&nbsp;cells,&nbsp;such
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
017&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;that&nbsp;every&nbsp;cell&#x27;s&nbsp;`:x`&nbsp;and&nbsp;`:y`&nbsp;properties&nbsp;reflect&nbsp;its&nbsp;place&nbsp;in&nbsp;the&nbsp;matrix.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
018&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;See&nbsp;`world.clj`.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
019&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
020&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Each&nbsp;time&nbsp;the&nbsp;world&nbsp;is&nbsp;transformed&nbsp;(see&nbsp;`transform-world`),&nbsp;for&nbsp;each&nbsp;cell,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
021&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rules&nbsp;are&nbsp;applied&nbsp;in&nbsp;turn&nbsp;until&nbsp;one&nbsp;matches.&nbsp;Once&nbsp;one&nbsp;rule&nbsp;has&nbsp;matched&nbsp;no
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
022&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;further&nbsp;rules&nbsp;can&nbsp;be&nbsp;applied&nbsp;to&nbsp;that&nbsp;cell.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
023&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:author&nbsp;&quot;Simon&nbsp;Brooke&quot;}
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
024&nbsp;&nbsp;&nbsp;mw-engine.core
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
025&nbsp;&nbsp;&nbsp;&nbsp;(:require&nbsp;[mw-engine.flow&nbsp;:refer&nbsp;[flow-world]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
026&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[mw-engine.utils&nbsp;:refer&nbsp;[add-history-event&nbsp;get-int-or-zero&nbsp;map-world&nbsp;rule-type]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
027&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[taoensso.timbre&nbsp;:as&nbsp;l]))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
028&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
029&nbsp;&nbsp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
030&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
031&nbsp;&nbsp;;;;;&nbsp;mw-engine:&nbsp;the&nbsp;state&#x2F;transition&nbsp;engine&nbsp;of&nbsp;MicroWorld.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
032&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
033&nbsp;&nbsp;;;;;&nbsp;This&nbsp;program&nbsp;is&nbsp;free&nbsp;software;&nbsp;you&nbsp;can&nbsp;redistribute&nbsp;it&nbsp;and&#x2F;or
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
034&nbsp;&nbsp;;;;;&nbsp;modify&nbsp;it&nbsp;under&nbsp;the&nbsp;terms&nbsp;of&nbsp;the&nbsp;GNU&nbsp;General&nbsp;Public&nbsp;License
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
035&nbsp;&nbsp;;;;;&nbsp;as&nbsp;published&nbsp;by&nbsp;the&nbsp;Free&nbsp;Software&nbsp;Foundation;&nbsp;either&nbsp;version&nbsp;2
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
036&nbsp;&nbsp;;;;;&nbsp;of&nbsp;the&nbsp;License,&nbsp;or&nbsp;(at&nbsp;your&nbsp;option)&nbsp;any&nbsp;later&nbsp;version.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
037&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
038&nbsp;&nbsp;;;;;&nbsp;This&nbsp;program&nbsp;is&nbsp;distributed&nbsp;in&nbsp;the&nbsp;hope&nbsp;that&nbsp;it&nbsp;will&nbsp;be&nbsp;useful,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
039&nbsp;&nbsp;;;;;&nbsp;but&nbsp;WITHOUT&nbsp;ANY&nbsp;WARRANTY;&nbsp;without&nbsp;even&nbsp;the&nbsp;implied&nbsp;warranty&nbsp;of
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
040&nbsp;&nbsp;;;;;&nbsp;MERCHANTABILITY&nbsp;or&nbsp;FITNESS&nbsp;FOR&nbsp;A&nbsp;PARTICULAR&nbsp;PURPOSE.&nbsp;&nbsp;See&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
041&nbsp;&nbsp;;;;;&nbsp;GNU&nbsp;General&nbsp;Public&nbsp;License&nbsp;for&nbsp;more&nbsp;details.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
042&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
043&nbsp;&nbsp;;;;;&nbsp;You&nbsp;should&nbsp;have&nbsp;received&nbsp;a&nbsp;copy&nbsp;of&nbsp;the&nbsp;GNU&nbsp;General&nbsp;Public&nbsp;License
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
044&nbsp;&nbsp;;;;;&nbsp;along&nbsp;with&nbsp;this&nbsp;program;&nbsp;if&nbsp;not,&nbsp;write&nbsp;to&nbsp;the&nbsp;Free&nbsp;Software
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
045&nbsp;&nbsp;;;;;&nbsp;Foundation,&nbsp;Inc.,&nbsp;51&nbsp;Franklin&nbsp;Street,&nbsp;Fifth&nbsp;Floor,&nbsp;Boston,&nbsp;MA&nbsp;&nbsp;02110-1301,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
046&nbsp;&nbsp;;;;;&nbsp;USA.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
047&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
048&nbsp;&nbsp;;;;;&nbsp;Copyright&nbsp;(C)&nbsp;2014&nbsp;Simon&nbsp;Brooke
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
049&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
050&nbsp;&nbsp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
051&nbsp;&nbsp;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
052&nbsp;&nbsp;(def&nbsp;^:dynamic&nbsp;*with-history*
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
053&nbsp;&nbsp;&nbsp;&nbsp;&quot;I&nbsp;suspect&nbsp;that&nbsp;caching&nbsp;history&nbsp;on&nbsp;the&nbsp;cells&nbsp;is&nbsp;greatly&nbsp;worsening&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
054&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memory&nbsp;problems.&nbsp;Make&nbsp;it&nbsp;optional,&nbsp;but&nbsp;by&nbsp;default&nbsp;false.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
055&nbsp;&nbsp;&nbsp;&nbsp;false)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
056&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
057&nbsp;&nbsp;(defn&nbsp;apply-rule
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
058&nbsp;&nbsp;&nbsp;&nbsp;&quot;Apply&nbsp;a&nbsp;single&nbsp;`rule`&nbsp;to&nbsp;a&nbsp;`cell`.&nbsp;What&nbsp;this&nbsp;is&nbsp;about&nbsp;is&nbsp;that&nbsp;I&nbsp;want&nbsp;to&nbsp;be&nbsp;able,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
059&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;debugging&nbsp;purposes,&nbsp;to&nbsp;tag&nbsp;a&nbsp;cell&nbsp;with&nbsp;the&nbsp;rule&nbsp;text&nbsp;of&nbsp;the&nbsp;rule&nbsp;which
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
060&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fired&nbsp;(and&nbsp;especially&nbsp;so&nbsp;when&nbsp;an&nbsp;exception&nbsp;is&nbsp;thrown).&nbsp;&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
061&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;as&nbsp;of&nbsp;version&nbsp;0-3-0,&nbsp;metadata&nbsp;for&nbsp;rules&nbsp;is&nbsp;now&nbsp;passed&nbsp;around&nbsp;on&nbsp;the&nbsp;metadata
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
062&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;of&nbsp;the&nbsp;rule&nbsp;function&nbsp;itself.&nbsp;Yes,&nbsp;I&nbsp;know,&nbsp;this&nbsp;is&nbsp;obvious;&nbsp;but&nbsp;I&#x27;ll&nbsp;confess
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
063&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;I&nbsp;didn&#x27;t&nbsp;think&nbsp;of&nbsp;it&nbsp;before.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
064&nbsp;&nbsp;&nbsp;&nbsp;[world&nbsp;cell&nbsp;rule]
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
065&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[result&nbsp;(try
</span><br/>
<span class="covered" title="7 out of 7 forms covered">
066&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(apply&nbsp;rule&nbsp;(list&nbsp;cell&nbsp;world))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
067&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(catch&nbsp;Exception&nbsp;e
</span><br/>
<span class="not-covered" title="0 out of 16 forms covered">
068&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(l&#x2F;warn&nbsp;e
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
069&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(format
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
070&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;Error&nbsp;in&nbsp;`apply-rule`:&nbsp;`%s`&nbsp;(%s)&nbsp;while&nbsp;executing&nbsp;rule&nbsp;`%s`&nbsp;on&nbsp;cell&nbsp;`%s`&quot;
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
071&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
072&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(.getMessage&nbsp;e)
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
073&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(-&gt;&nbsp;rule&nbsp;meta&nbsp;:lisp)
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
074&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cell))))]
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
075&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;*with-history*
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
076&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(add-history-event&nbsp;result&nbsp;rule)
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
077&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
078&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
079&nbsp;&nbsp;(defn-&nbsp;apply-rules
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
080&nbsp;&nbsp;&nbsp;&nbsp;&quot;Derive&nbsp;a&nbsp;cell&nbsp;from&nbsp;this&nbsp;`cell`&nbsp;of&nbsp;this&nbsp;`world`&nbsp;by&nbsp;applying&nbsp;these&nbsp;`rules`.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
081&nbsp;&nbsp;&nbsp;&nbsp;[world&nbsp;cell&nbsp;rules]
</span><br/>
<span class="partial" title="4 out of 5 forms covered">
082&nbsp;&nbsp;&nbsp;&nbsp;(or
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
083&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(first
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
084&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(remove
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
085&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nil?
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
086&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(try
</span><br/>
<span class="covered" title="9 out of 9 forms covered">
087&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map&nbsp;#(apply-rule&nbsp;world&nbsp;cell&nbsp;%)&nbsp;rules)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
088&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(catch&nbsp;Exception&nbsp;e
</span><br/>
<span class="not-covered" title="0 out of 16 forms covered">
089&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(l&#x2F;warn&nbsp;e
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
090&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(format
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
091&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;Error&nbsp;in&nbsp;`apply-rules`:&nbsp;`%s`&nbsp;(%s)&nbsp;while&nbsp;executing&nbsp;rules&nbsp;on&nbsp;cell&nbsp;`%s`&quot;
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
092&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(-&gt;&nbsp;e&nbsp;.getClass&nbsp;.getName)
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
093&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(.getMessage&nbsp;e)
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
094&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cell))))))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
095&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cell))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
096&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
097&nbsp;&nbsp;(defn-&nbsp;transform-cell
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
098&nbsp;&nbsp;&nbsp;&nbsp;&quot;Derive&nbsp;a&nbsp;cell&nbsp;from&nbsp;this&nbsp;`cell`&nbsp;of&nbsp;this&nbsp;`world`&nbsp;by&nbsp;applying&nbsp;these&nbsp;`rules`.&nbsp;If&nbsp;an
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
099&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exception&nbsp;is&nbsp;thrown,&nbsp;cache&nbsp;its&nbsp;message&nbsp;on&nbsp;the&nbsp;cell&nbsp;and&nbsp;set&nbsp;it&#x27;s&nbsp;state&nbsp;to&nbsp;error&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
100&nbsp;&nbsp;&nbsp;&nbsp;[world&nbsp;cell&nbsp;rules]
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
101&nbsp;&nbsp;&nbsp;&nbsp;(try
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
102&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(merge
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
103&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(apply-rules&nbsp;world&nbsp;cell&nbsp;rules)
</span><br/>
<span class="covered" title="8 out of 8 forms covered">
104&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{:generation&nbsp;(+&nbsp;(get-int-or-zero&nbsp;cell&nbsp;:generation)&nbsp;1)})
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
105&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(catch&nbsp;Exception&nbsp;e
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
106&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[narrative&nbsp;(format&nbsp;&quot;Error&nbsp;in&nbsp;`transform-cell`:&nbsp;`%s`&nbsp;(%s)&nbsp;at&nbsp;generation&nbsp;%d&nbsp;when&nbsp;in&nbsp;state&nbsp;%s;&quot;
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
107&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(-&gt;&nbsp;e&nbsp;.getClass&nbsp;.getName)
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
108&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(.getMessage&nbsp;e)
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
109&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:generation&nbsp;cell)
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
110&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:state&nbsp;cell))]
</span><br/>
<span class="not-covered" title="0 out of 17 forms covered">
111&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(l&#x2F;warn&nbsp;e&nbsp;narrative)
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
112&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cell))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
113&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
114&nbsp;&nbsp;(defn&nbsp;transform-world
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
115&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;a&nbsp;world&nbsp;derived&nbsp;from&nbsp;this&nbsp;`world`&nbsp;by&nbsp;applying&nbsp;the&nbsp;production&nbsp;rules&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
116&nbsp;&nbsp;&nbsp;&nbsp;found&nbsp;among&nbsp;these&nbsp;`rules`&nbsp;to&nbsp;each&nbsp;cell.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
117&nbsp;&nbsp;&nbsp;&nbsp;[world&nbsp;rules]
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
118&nbsp;&nbsp;&nbsp;&nbsp;(map-world&nbsp;world&nbsp;transform-cell
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
119&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;Yes,&nbsp;that&nbsp;`list`&nbsp;is&nbsp;there&nbsp;for&nbsp;a&nbsp;reason!&nbsp;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
120&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(list
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
121&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(filter
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
122&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(=&nbsp;:production&nbsp;(rule-type&nbsp;%))
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
123&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rules))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
124&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
125&nbsp;&nbsp;(defn&nbsp;run-world
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
126&nbsp;&nbsp;&nbsp;&nbsp;&quot;Run&nbsp;this&nbsp;world&nbsp;with&nbsp;these&nbsp;rules&nbsp;for&nbsp;this&nbsp;number&nbsp;of&nbsp;generations.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
127&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
128&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`world`&nbsp;a&nbsp;world&nbsp;as&nbsp;discussed&nbsp;above;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
129&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`init-rules`&nbsp;a&nbsp;sequence&nbsp;of&nbsp;rules&nbsp;as&nbsp;defined&nbsp;above,&nbsp;to&nbsp;be&nbsp;run&nbsp;once&nbsp;to&nbsp;initialise&nbsp;the&nbsp;world;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
130&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`rules`&nbsp;a&nbsp;sequence&nbsp;of&nbsp;rules&nbsp;as&nbsp;defined&nbsp;above,&nbsp;to&nbsp;be&nbsp;run&nbsp;iteratively&nbsp;for&nbsp;each&nbsp;generation;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
131&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`generations`&nbsp;an&nbsp;(integer)&nbsp;number&nbsp;of&nbsp;generations.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
132&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
133&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;**NOTE&nbsp;THAT**&nbsp;all&nbsp;rules&nbsp;**must**&nbsp;be&nbsp;tagged&nbsp;with&nbsp;`rule-type`&nbsp;metadata,&nbsp;or&nbsp;thet&nbsp;**will&nbsp;not**
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
134&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;be&nbsp;executed.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
135&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
136&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Return&nbsp;the&nbsp;final&nbsp;generation&nbsp;of&nbsp;the&nbsp;world.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
137&nbsp;&nbsp;&nbsp;&nbsp;([world&nbsp;rules&nbsp;generations]
</span><br/>
<span class="not-covered" title="0 out of 7 forms covered">
138&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(run-world&nbsp;world&nbsp;rules&nbsp;rules&nbsp;(dec&nbsp;generations)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
139&nbsp;&nbsp;&nbsp;&nbsp;([world&nbsp;init-rules&nbsp;rules&nbsp;generations]
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
140&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(reduce&nbsp;(fn&nbsp;[world&nbsp;iteration]
</span><br/>
<span class="not-covered" title="0 out of 17 forms covered">
141&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(l&#x2F;info&nbsp;&quot;Running&nbsp;iteration&nbsp;&quot;&nbsp;iteration)
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
142&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[w&#x27;&nbsp;(transform-world&nbsp;world&nbsp;rules)]
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
143&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(flow-world&nbsp;w&#x27;&nbsp;rules)))
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
144&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(transform-world&nbsp;world&nbsp;init-rules)
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
145&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(range&nbsp;generations))))
</span><br/>
</body>
</html>

View file

@ -0,0 +1,203 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="../coverage.css"/> <title> mw_engine/display.clj </title>
</head>
<body>
<span class="covered" title="1 out of 1 forms covered">
001&nbsp;&nbsp;(ns&nbsp;^{:doc&nbsp;&quot;Simple&nbsp;functions&nbsp;to&nbsp;allow&nbsp;a&nbsp;world&nbsp;to&nbsp;be&nbsp;visualised.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
002&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:author&nbsp;&quot;Simon&nbsp;Brooke&quot;}
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
003&nbsp;&nbsp;&nbsp;&nbsp;mw-engine.display)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
004&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
005&nbsp;&nbsp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
006&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
007&nbsp;&nbsp;;;;;&nbsp;mw-engine:&nbsp;the&nbsp;state&#x2F;transition&nbsp;engine&nbsp;of&nbsp;MicroWorld.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
008&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
009&nbsp;&nbsp;;;;;&nbsp;This&nbsp;program&nbsp;is&nbsp;free&nbsp;software;&nbsp;you&nbsp;can&nbsp;redistribute&nbsp;it&nbsp;and&#x2F;or
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
010&nbsp;&nbsp;;;;;&nbsp;modify&nbsp;it&nbsp;under&nbsp;the&nbsp;terms&nbsp;of&nbsp;the&nbsp;GNU&nbsp;General&nbsp;Public&nbsp;License
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
011&nbsp;&nbsp;;;;;&nbsp;as&nbsp;published&nbsp;by&nbsp;the&nbsp;Free&nbsp;Software&nbsp;Foundation;&nbsp;either&nbsp;version&nbsp;2
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
012&nbsp;&nbsp;;;;;&nbsp;of&nbsp;the&nbsp;License,&nbsp;or&nbsp;(at&nbsp;your&nbsp;option)&nbsp;any&nbsp;later&nbsp;version.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
013&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
014&nbsp;&nbsp;;;;;&nbsp;This&nbsp;program&nbsp;is&nbsp;distributed&nbsp;in&nbsp;the&nbsp;hope&nbsp;that&nbsp;it&nbsp;will&nbsp;be&nbsp;useful,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
015&nbsp;&nbsp;;;;;&nbsp;but&nbsp;WITHOUT&nbsp;ANY&nbsp;WARRANTY;&nbsp;without&nbsp;even&nbsp;the&nbsp;implied&nbsp;warranty&nbsp;of
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
016&nbsp;&nbsp;;;;;&nbsp;MERCHANTABILITY&nbsp;or&nbsp;FITNESS&nbsp;FOR&nbsp;A&nbsp;PARTICULAR&nbsp;PURPOSE.&nbsp;&nbsp;See&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
017&nbsp;&nbsp;;;;;&nbsp;GNU&nbsp;General&nbsp;Public&nbsp;License&nbsp;for&nbsp;more&nbsp;details.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
018&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
019&nbsp;&nbsp;;;;;&nbsp;You&nbsp;should&nbsp;have&nbsp;received&nbsp;a&nbsp;copy&nbsp;of&nbsp;the&nbsp;GNU&nbsp;General&nbsp;Public&nbsp;License
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
020&nbsp;&nbsp;;;;;&nbsp;along&nbsp;with&nbsp;this&nbsp;program;&nbsp;if&nbsp;not,&nbsp;write&nbsp;to&nbsp;the&nbsp;Free&nbsp;Software
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
021&nbsp;&nbsp;;;;;&nbsp;Foundation,&nbsp;Inc.,&nbsp;51&nbsp;Franklin&nbsp;Street,&nbsp;Fifth&nbsp;Floor,&nbsp;Boston,&nbsp;MA&nbsp;&nbsp;02110-1301,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
022&nbsp;&nbsp;;;;;&nbsp;USA.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
023&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
024&nbsp;&nbsp;;;;;&nbsp;Copyright&nbsp;(C)&nbsp;2014&nbsp;Simon&nbsp;Brooke
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
025&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
026&nbsp;&nbsp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
027&nbsp;&nbsp;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
028&nbsp;&nbsp;(def&nbsp;^:dynamic&nbsp;*image-base*
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
029&nbsp;&nbsp;&nbsp;&nbsp;&quot;Base&nbsp;url&nbsp;(i.e.,&nbsp;url&nbsp;of&nbsp;directory)&nbsp;from&nbsp;which&nbsp;to&nbsp;load&nbsp;tile&nbsp;images.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
030&nbsp;&nbsp;&nbsp;&nbsp;&quot;img&#x2F;tiles&quot;)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
031&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
032&nbsp;&nbsp;(defn&nbsp;format-css-class
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
033&nbsp;&nbsp;&nbsp;&nbsp;&quot;Format&nbsp;this&nbsp;`state`,&nbsp;assumed&nbsp;to&nbsp;be&nbsp;a&nbsp;keyword&nbsp;indicating&nbsp;a&nbsp;state&nbsp;in&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
034&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;world,&nbsp;into&nbsp;a&nbsp;CSS&nbsp;class&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
035&nbsp;&nbsp;&nbsp;&nbsp;[state]
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
036&nbsp;&nbsp;&nbsp;&nbsp;(subs&nbsp;(str&nbsp;state)&nbsp;1))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
037&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
038&nbsp;&nbsp;(defn&nbsp;format-image-path
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
039&nbsp;&nbsp;&nbsp;&nbsp;&quot;Render&nbsp;this&nbsp;`state`,&nbsp;assumed&nbsp;to&nbsp;be&nbsp;a&nbsp;keyword&nbsp;indicating&nbsp;a&nbsp;state&nbsp;in&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
040&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;world,&nbsp;into&nbsp;a&nbsp;path&nbsp;which&nbsp;should&nbsp;recover&nbsp;the&nbsp;corresponding&nbsp;image&nbsp;file.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
041&nbsp;&nbsp;&nbsp;&nbsp;[state]
</span><br/>
<span class="not-covered" title="0 out of 7 forms covered">
042&nbsp;&nbsp;&nbsp;&nbsp;(format&nbsp;&quot;%s&#x2F;%s.png&quot;&nbsp;*image-base*&nbsp;(format-css-class&nbsp;state)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
043&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
044&nbsp;&nbsp;(defn&nbsp;format-mouseover&nbsp;[cell]
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
045&nbsp;&nbsp;&nbsp;&nbsp;(str&nbsp;cell))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
046&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
047&nbsp;&nbsp;(defn&nbsp;render-cell
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
048&nbsp;&nbsp;&nbsp;&nbsp;&quot;Render&nbsp;this&nbsp;world&nbsp;cell&nbsp;as&nbsp;a&nbsp;Hiccup&nbsp;table&nbsp;cell.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
049&nbsp;&nbsp;&nbsp;&nbsp;[cell]
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
050&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[state&nbsp;(:state&nbsp;cell)]
</span><br/>
<span class="not-covered" title="0 out of 11 forms covered">
051&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[:td&nbsp;{:class&nbsp;(format-css-class&nbsp;state)&nbsp;:title&nbsp;(format-mouseover&nbsp;cell)}
</span><br/>
<span class="not-covered" title="0 out of 13 forms covered">
052&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[:a&nbsp;{:href&nbsp;(format&nbsp;&quot;inspect?x=%d&amp;y=%d&quot;&nbsp;(:x&nbsp;cell)&nbsp;(:y&nbsp;cell))}
</span><br/>
<span class="not-covered" title="0 out of 15 forms covered">
053&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[:img&nbsp;{:alt&nbsp;(:state&nbsp;cell)&nbsp;:width&nbsp;32&nbsp;:height&nbsp;32&nbsp;:src&nbsp;(format-image-path&nbsp;state)}]]]))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
054&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
055&nbsp;&nbsp;(defn&nbsp;render-world-row
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
056&nbsp;&nbsp;&nbsp;&nbsp;&quot;Render&nbsp;this&nbsp;world&nbsp;`row`&nbsp;as&nbsp;a&nbsp;Hiccup&nbsp;table&nbsp;row.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
057&nbsp;&nbsp;&nbsp;&nbsp;[row]
</span><br/>
<span class="not-covered" title="0 out of 10 forms covered">
058&nbsp;&nbsp;&nbsp;&nbsp;(apply&nbsp;vector&nbsp;(cons&nbsp;:tr&nbsp;(map&nbsp;render-cell&nbsp;row))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
059&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
060&nbsp;&nbsp;(defn&nbsp;render-world-table
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
061&nbsp;&nbsp;&nbsp;&nbsp;&quot;Render&nbsp;this&nbsp;`world`&nbsp;as&nbsp;a&nbsp;Hiccup&nbsp;table.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
062&nbsp;&nbsp;&nbsp;&nbsp;[world]
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
063&nbsp;&nbsp;&nbsp;&nbsp;(apply&nbsp;vector
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
064&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cons&nbsp;:table
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
065&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map&nbsp;render-world-row&nbsp;world))))
</span><br/>
</body>
</html>

View file

@ -0,0 +1,659 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="../coverage.css"/> <title> mw_engine/drainage.clj </title>
</head>
<body>
<span class="covered" title="1 out of 1 forms covered">
001&nbsp;&nbsp;(ns&nbsp;^{:doc&nbsp;&quot;Experimental,&nbsp;probably&nbsp;of&nbsp;no&nbsp;interest&nbsp;to&nbsp;anyone&nbsp;else;&nbsp;attempt&nbsp;to
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
002&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;compute&nbsp;drainage&nbsp;on&nbsp;a&nbsp;world,&nbsp;assumed&nbsp;to&nbsp;have&nbsp;altitudes&nbsp;already&nbsp;set
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
003&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from&nbsp;a&nbsp;heightmap.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
004&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:author&nbsp;&quot;Simon&nbsp;Brooke&quot;}
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
005&nbsp;&nbsp;&nbsp;&nbsp;mw-engine.drainage
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
006&nbsp;&nbsp;&nbsp;&nbsp;(:require&nbsp;[mw-engine.core&nbsp;:refer&nbsp;[run-world]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
007&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[mw-engine.heightmap&nbsp;:as&nbsp;heightmap]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[mw-engine.utils&nbsp;:refer&nbsp;[get-int-or-zero&nbsp;get-least-cell&nbsp;get-neighbours
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
009&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;get-neighbours-with-property-value
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
010&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;map-world]]))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
011&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
012&nbsp;&nbsp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
013&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
014&nbsp;&nbsp;;;;;&nbsp;mw-engine:&nbsp;the&nbsp;state&#x2F;transition&nbsp;engine&nbsp;of&nbsp;MicroWorld.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
015&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
016&nbsp;&nbsp;;;;;&nbsp;This&nbsp;program&nbsp;is&nbsp;free&nbsp;software;&nbsp;you&nbsp;can&nbsp;redistribute&nbsp;it&nbsp;and&#x2F;or
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
017&nbsp;&nbsp;;;;;&nbsp;modify&nbsp;it&nbsp;under&nbsp;the&nbsp;terms&nbsp;of&nbsp;the&nbsp;GNU&nbsp;General&nbsp;Public&nbsp;License
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
018&nbsp;&nbsp;;;;;&nbsp;as&nbsp;published&nbsp;by&nbsp;the&nbsp;Free&nbsp;Software&nbsp;Foundation;&nbsp;either&nbsp;version&nbsp;2
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
019&nbsp;&nbsp;;;;;&nbsp;of&nbsp;the&nbsp;License,&nbsp;or&nbsp;(at&nbsp;your&nbsp;option)&nbsp;any&nbsp;later&nbsp;version.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
020&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
021&nbsp;&nbsp;;;;;&nbsp;This&nbsp;program&nbsp;is&nbsp;distributed&nbsp;in&nbsp;the&nbsp;hope&nbsp;that&nbsp;it&nbsp;will&nbsp;be&nbsp;useful,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
022&nbsp;&nbsp;;;;;&nbsp;but&nbsp;WITHOUT&nbsp;ANY&nbsp;WARRANTY;&nbsp;without&nbsp;even&nbsp;the&nbsp;implied&nbsp;warranty&nbsp;of
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
023&nbsp;&nbsp;;;;;&nbsp;MERCHANTABILITY&nbsp;or&nbsp;FITNESS&nbsp;FOR&nbsp;A&nbsp;PARTICULAR&nbsp;PURPOSE.&nbsp;&nbsp;See&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
024&nbsp;&nbsp;;;;;&nbsp;GNU&nbsp;General&nbsp;Public&nbsp;License&nbsp;for&nbsp;more&nbsp;details.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
025&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
026&nbsp;&nbsp;;;;;&nbsp;You&nbsp;should&nbsp;have&nbsp;received&nbsp;a&nbsp;copy&nbsp;of&nbsp;the&nbsp;GNU&nbsp;General&nbsp;Public&nbsp;License
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
027&nbsp;&nbsp;;;;;&nbsp;along&nbsp;with&nbsp;this&nbsp;program;&nbsp;if&nbsp;not,&nbsp;write&nbsp;to&nbsp;the&nbsp;Free&nbsp;Software
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
028&nbsp;&nbsp;;;;;&nbsp;Foundation,&nbsp;Inc.,&nbsp;51&nbsp;Franklin&nbsp;Street,&nbsp;Fifth&nbsp;Floor,&nbsp;Boston,&nbsp;MA&nbsp;&nbsp;02110-1301,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
029&nbsp;&nbsp;;;;;&nbsp;USA.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
030&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
031&nbsp;&nbsp;;;;;&nbsp;Copyright&nbsp;(C)&nbsp;2014&nbsp;Simon&nbsp;Brooke
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
032&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
033&nbsp;&nbsp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
034&nbsp;&nbsp;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
035&nbsp;&nbsp;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
036&nbsp;&nbsp;(def&nbsp;^:dynamic&nbsp;*sealevel*&nbsp;10)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
037&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
038&nbsp;&nbsp;;;&nbsp;forward&nbsp;declaration&nbsp;of&nbsp;flow,&nbsp;to&nbsp;allow&nbsp;for&nbsp;a&nbsp;wee&nbsp;bit&nbsp;of&nbsp;mutual&nbsp;recursion.
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
039&nbsp;&nbsp;(declare&nbsp;flow)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
040&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
041&nbsp;&nbsp;(defn&nbsp;rainfall
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
042&nbsp;&nbsp;&nbsp;&nbsp;&quot;Compute&nbsp;rainfall&nbsp;for&nbsp;a&nbsp;cell&nbsp;with&nbsp;this&nbsp;`gradient`&nbsp;west-east,&nbsp;given
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
043&nbsp;&nbsp;&nbsp;&nbsp;`remaining`&nbsp;drops&nbsp;to&nbsp;distribute,&nbsp;and&nbsp;this&nbsp;overall&nbsp;map&nbsp;width.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
044&nbsp;&nbsp;&nbsp;&nbsp;[gradient&nbsp;remaining&nbsp;map-width]
</span><br/>
<span class="not-covered" title="0 out of 7 forms covered">
045&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
046&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;if&nbsp;there&#x27;s&nbsp;no&nbsp;rain&nbsp;left&nbsp;in&nbsp;the&nbsp;cloud,&nbsp;it&nbsp;can&#x27;t&nbsp;fall;
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
047&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(zero?&nbsp;remaining)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
048&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
049&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(pos?&nbsp;gradient)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
050&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;rain,&nbsp;on&nbsp;prevailing&nbsp;westerly&nbsp;wind,&nbsp;falls&nbsp;preferentially&nbsp;on&nbsp;rising&nbsp;ground;
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
051&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(int&nbsp;(rand&nbsp;gradient))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
052&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;rain&nbsp;falls&nbsp;randomly&nbsp;across&nbsp;the&nbsp;width&nbsp;of&nbsp;the&nbsp;map...
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
053&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(zero?&nbsp;(int&nbsp;(rand&nbsp;map-width)))&nbsp;1
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
054&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:else
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
055&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
056&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
057&nbsp;&nbsp;(defn&nbsp;rain-row
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
058&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;a&nbsp;row&nbsp;like&nbsp;this&nbsp;`row`,&nbsp;across&nbsp;which&nbsp;rainfall&nbsp;has&nbsp;been&nbsp;distributed;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
059&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;`rain-probability`&nbsp;is&nbsp;specified,&nbsp;it&nbsp;is&nbsp;the&nbsp;probable&nbsp;rainfall&nbsp;on&nbsp;a&nbsp;cell
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
060&nbsp;&nbsp;&nbsp;&nbsp;with&nbsp;no&nbsp;gradient.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
061&nbsp;&nbsp;&nbsp;&nbsp;([row]
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
062&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(rain-row&nbsp;row&nbsp;1))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
063&nbsp;&nbsp;&nbsp;&nbsp;([row&nbsp;rain-probability]
</span><br/>
<span class="not-covered" title="0 out of 11 forms covered">
064&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(rain-row&nbsp;row&nbsp;(count&nbsp;row)&nbsp;0&nbsp;(int&nbsp;(*&nbsp;(count&nbsp;row)&nbsp;rain-probability))))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
065&nbsp;&nbsp;&nbsp;&nbsp;([row&nbsp;map-width&nbsp;previous-altitude&nbsp;drops-in-cloud]
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
066&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
067&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(empty?&nbsp;row)&nbsp;nil
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
068&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(pos?&nbsp;drops-in-cloud)
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
069&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[cell&nbsp;(first&nbsp;row)
</span><br/>
<span class="not-covered" title="0 out of 8 forms covered">
070&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alt&nbsp;(or&nbsp;(:altitude&nbsp;cell)&nbsp;0)
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
071&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rising&nbsp;(-&nbsp;alt&nbsp;previous-altitude)
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
072&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fall&nbsp;(rainfall&nbsp;rising&nbsp;drops-in-cloud&nbsp;map-width)]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
073&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cons
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
074&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assoc&nbsp;cell&nbsp;:rainfall&nbsp;fall)
</span><br/>
<span class="not-covered" title="0 out of 10 forms covered">
075&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(rain-row&nbsp;(rest&nbsp;row)&nbsp;map-width&nbsp;alt&nbsp;(-&nbsp;drops-in-cloud&nbsp;fall))))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
076&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:else
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
077&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
078&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(assoc&nbsp;%&nbsp;:rainfall&nbsp;0)
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
079&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;row))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
080&nbsp;&nbsp;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
081&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
082&nbsp;&nbsp;(defn&nbsp;rain-world
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
083&nbsp;&nbsp;&nbsp;&nbsp;&quot;Simulate&nbsp;rainfall&nbsp;on&nbsp;this&nbsp;`world`.&nbsp;TODO:&nbsp;Doesn&#x27;t&nbsp;really&nbsp;work&nbsp;just&nbsp;now&nbsp;-&nbsp;should
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
084&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rain&nbsp;more&nbsp;on&nbsp;west-facing&nbsp;slopes,&nbsp;and&nbsp;less&nbsp;to&nbsp;the&nbsp;east&nbsp;of&nbsp;high&nbsp;ground&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
085&nbsp;&nbsp;&nbsp;&nbsp;[world]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
086&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
087&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rain-row
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
088&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;world))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
089&nbsp;&nbsp;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
090&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
091&nbsp;&nbsp;(defn&nbsp;flow-contributors
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
092&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;a&nbsp;list&nbsp;of&nbsp;the&nbsp;cells&nbsp;in&nbsp;this&nbsp;`world`&nbsp;which&nbsp;are&nbsp;higher&nbsp;than&nbsp;this
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
093&nbsp;&nbsp;&nbsp;&nbsp;`cell`&nbsp;and&nbsp;for&nbsp;which&nbsp;this&nbsp;cell&nbsp;is&nbsp;the&nbsp;lowest&nbsp;neighbour,&nbsp;or&nbsp;which&nbsp;are&nbsp;at&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
094&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;same&nbsp;altitude&nbsp;and&nbsp;have&nbsp;greater&nbsp;flow&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
095&nbsp;&nbsp;&nbsp;&nbsp;[cell&nbsp;world]
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
096&nbsp;&nbsp;&nbsp;&nbsp;(filter&nbsp;#(map?&nbsp;%)
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
097&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
098&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[n]
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
099&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond
</span><br/>
<span class="not-covered" title="0 out of 10 forms covered">
100&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(=&nbsp;cell&nbsp;(get-least-cell&nbsp;(get-neighbours&nbsp;world&nbsp;n)&nbsp;:altitude))&nbsp;n
</span><br/>
<span class="not-covered" title="0 out of 12 forms covered">
101&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and&nbsp;(=&nbsp;(:altitude&nbsp;cell)&nbsp;(:altitude&nbsp;n))
</span><br/>
<span class="not-covered" title="0 out of 17 forms covered">
102&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;&nbsp;(or&nbsp;(:flow&nbsp;n)&nbsp;0)&nbsp;(or&nbsp;(:flow&nbsp;cell)&nbsp;0)))&nbsp;n))
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
103&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(get-neighbours-with-property-value
</span><br/>
<span class="not-covered" title="0 out of 7 forms covered">
104&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;world&nbsp;(:x&nbsp;cell)&nbsp;(:y&nbsp;cell)&nbsp;1&nbsp;:altitude
</span><br/>
<span class="not-covered" title="0 out of 9 forms covered">
105&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(or&nbsp;(:altitude&nbsp;cell)&nbsp;0)&nbsp;&gt;=))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
106&nbsp;&nbsp;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
107&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
108&nbsp;&nbsp;(defn&nbsp;is-hollow
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
109&nbsp;&nbsp;&nbsp;&nbsp;&quot;Detects&nbsp;point&nbsp;hollows&nbsp;-&nbsp;that&nbsp;is,&nbsp;individual&nbsp;cells&nbsp;all&nbsp;of&nbsp;whose&nbsp;neighbours
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
110&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;are&nbsp;higher.&nbsp;Return&nbsp;true&nbsp;if&nbsp;this&nbsp;`cell`&nbsp;has&nbsp;an&nbsp;altitude&nbsp;lower&nbsp;than&nbsp;any&nbsp;of
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
111&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;its&nbsp;neighbours&nbsp;in&nbsp;this&nbsp;`world`&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
112&nbsp;&nbsp;&nbsp;&nbsp;[world&nbsp;cell]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
113&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;quicker&nbsp;to&nbsp;count&nbsp;the&nbsp;elements&nbsp;of&nbsp;the&nbsp;list&nbsp;and&nbsp;compare&nbsp;equality&nbsp;of&nbsp;numbers
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
114&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;than&nbsp;recursive&nbsp;equality&nbsp;check&nbsp;on&nbsp;members,&nbsp;I&nbsp;think.&nbsp;But&nbsp;worth&nbsp;benchmarking.
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
115&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[neighbours&nbsp;(get-neighbours&nbsp;world&nbsp;cell)
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
116&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;altitude&nbsp;(get-int-or-zero&nbsp;cell&nbsp;:altitude)]
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
117&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(=&nbsp;(count&nbsp;neighbours)
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
118&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(count&nbsp;(get-neighbours-with-property-value
</span><br/>
<span class="covered" title="9 out of 9 forms covered">
119&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;world&nbsp;(:x&nbsp;cell)&nbsp;(:y&nbsp;cell)&nbsp;1&nbsp;:altitude&nbsp;altitude&nbsp;&gt;)))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
120&nbsp;&nbsp;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
121&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
122&nbsp;&nbsp;(defn&nbsp;flood-hollow
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
123&nbsp;&nbsp;&nbsp;&nbsp;&quot;Raise&nbsp;the&nbsp;altitude&nbsp;of&nbsp;a&nbsp;copy&nbsp;of&nbsp;this&nbsp;`cell`&nbsp;of&nbsp;this&nbsp;`world`&nbsp;to&nbsp;the&nbsp;altitude
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
124&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;of&nbsp;the&nbsp;lowest&nbsp;of&nbsp;its&nbsp;`neighbours`.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
125&nbsp;&nbsp;&nbsp;&nbsp;([_world&nbsp;cell&nbsp;neighbours]
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
126&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[lowest&nbsp;(get-least-cell&nbsp;neighbours&nbsp;:altitude)]
</span><br/>
<span class="covered" title="10 out of 10 forms covered">
127&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(merge&nbsp;cell&nbsp;{:state&nbsp;:water&nbsp;:altitude&nbsp;(:altitude&nbsp;lowest)})))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
128&nbsp;&nbsp;&nbsp;&nbsp;([world&nbsp;cell]
</span><br/>
<span class="covered" title="8 out of 8 forms covered">
129&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(flood-hollow&nbsp;world&nbsp;cell&nbsp;(get-neighbours&nbsp;world&nbsp;cell))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
130&nbsp;&nbsp;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
131&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
132&nbsp;&nbsp;(defn&nbsp;flood-hollows
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
133&nbsp;&nbsp;&nbsp;&nbsp;&quot;Flood&nbsp;all&nbsp;local&nbsp;hollows&nbsp;in&nbsp;this&nbsp;`world`.&nbsp;At&nbsp;this&nbsp;stage&nbsp;only&nbsp;floods&nbsp;single
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
134&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cell&nbsp;hollows.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
135&nbsp;&nbsp;&nbsp;&nbsp;[world]
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
136&nbsp;&nbsp;&nbsp;&nbsp;(map-world&nbsp;world
</span><br/>
<span class="covered" title="10 out of 10 forms covered">
137&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(if&nbsp;(is-hollow&nbsp;%1&nbsp;%2)&nbsp;(flood-hollow&nbsp;%1&nbsp;%2)&nbsp;%2)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
138&nbsp;&nbsp;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
139&nbsp;&nbsp;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
140&nbsp;&nbsp;(def&nbsp;max-altitude&nbsp;255)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
141&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
142&nbsp;&nbsp;(defn&nbsp;flow-nr
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
143&nbsp;&nbsp;&nbsp;&nbsp;&quot;Experimental&nbsp;non&nbsp;recursive&nbsp;flow&nbsp;algorithm,&nbsp;needs&nbsp;to&nbsp;be&nbsp;run&nbsp;on&nbsp;a&nbsp;world&nbsp;as
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
144&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;many&nbsp;times&nbsp;as&nbsp;there&nbsp;are&nbsp;distinct&nbsp;altitude&nbsp;values.&nbsp;This&nbsp;algorithm&nbsp;works&nbsp;only
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
145&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;applied&nbsp;sequentially&nbsp;from&nbsp;the&nbsp;highest&nbsp;altitude&nbsp;to&nbsp;the&nbsp;lowest,&nbsp;see
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
146&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`flow-world-nr`.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
147&nbsp;&nbsp;&nbsp;&nbsp;[cell&nbsp;world]
</span><br/>
<span class="not-covered" title="0 out of 9 forms covered">
148&nbsp;&nbsp;&nbsp;&nbsp;(when&nbsp;(=&nbsp;(-&nbsp;max-altitude&nbsp;(get-int-or-zero&nbsp;cell&nbsp;:generation))
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
149&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(get-int-or-zero&nbsp;cell&nbsp;:altitude))
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
150&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(merge&nbsp;cell
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
151&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{:flow&nbsp;(reduce&nbsp;+
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
152&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
153&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(+&nbsp;(get-int-or-zero&nbsp;%&nbsp;:rainfall)
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
154&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(get-int-or-zero&nbsp;%&nbsp;:flow))
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
155&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(flow-contributors&nbsp;cell&nbsp;world)))})))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
156&nbsp;&nbsp;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
157&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
158&nbsp;&nbsp;(def&nbsp;flow
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
159&nbsp;&nbsp;&nbsp;&nbsp;&quot;Compute&nbsp;the&nbsp;total&nbsp;flow&nbsp;upstream&nbsp;of&nbsp;this&nbsp;`cell`&nbsp;in&nbsp;this&nbsp;`world`,&nbsp;and&nbsp;return&nbsp;a&nbsp;cell&nbsp;identical
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
160&nbsp;&nbsp;&nbsp;&nbsp;to&nbsp;this&nbsp;one&nbsp;but&nbsp;having&nbsp;a&nbsp;value&nbsp;of&nbsp;its&nbsp;flow&nbsp;property&nbsp;set&nbsp;from&nbsp;that&nbsp;computation.&nbsp;The&nbsp;function&nbsp;is
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
161&nbsp;&nbsp;&nbsp;&nbsp;memoised&nbsp;because&nbsp;the&nbsp;consequence&nbsp;of&nbsp;mapping&nbsp;a&nbsp;recursive&nbsp;function&nbsp;across&nbsp;an&nbsp;array&nbsp;is&nbsp;that&nbsp;many
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
162&nbsp;&nbsp;&nbsp;&nbsp;cells&nbsp;will&nbsp;be&nbsp;revisited&nbsp;-&nbsp;potentially&nbsp;many&nbsp;times.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
163&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
164&nbsp;&nbsp;&nbsp;&nbsp;Flow&nbsp;comes&nbsp;from&nbsp;a&nbsp;higher&nbsp;cell&nbsp;to&nbsp;a&nbsp;lower&nbsp;only&nbsp;if&nbsp;the&nbsp;lower&nbsp;is&nbsp;the&nbsp;lowest&nbsp;neighbour&nbsp;of&nbsp;the&nbsp;higher.&quot;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
165&nbsp;&nbsp;&nbsp;&nbsp;(memoize
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
166&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[cell&nbsp;world]
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
167&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond
</span><br/>
<span class="not-covered" title="0 out of 8 forms covered">
168&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(not&nbsp;(nil?&nbsp;(:flow&nbsp;cell)))&nbsp;cell
</span><br/>
<span class="not-covered" title="0 out of 11 forms covered">
169&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&lt;=&nbsp;(or&nbsp;(:altitude&nbsp;cell)&nbsp;0)&nbsp;*sealevel*)&nbsp;cell
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
170&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:else
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
171&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(merge&nbsp;cell
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
172&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{:flow&nbsp;(+&nbsp;(:rainfall&nbsp;cell)
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
173&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(apply&nbsp;+
</span><br/>
<span class="not-covered" title="0 out of 9 forms covered">
174&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map&nbsp;(fn&nbsp;[neighbour]&nbsp;(:flow&nbsp;(flow&nbsp;neighbour&nbsp;world)))
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
175&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(flow-contributors&nbsp;cell&nbsp;world))))})))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
176&nbsp;&nbsp;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
177&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
178&nbsp;&nbsp;(defn&nbsp;flow-world-nr
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
179&nbsp;&nbsp;&nbsp;&nbsp;&quot;Experimental&nbsp;non-recursive&nbsp;flow-world&nbsp;algorithm&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
180&nbsp;&nbsp;&nbsp;&nbsp;[world]
</span><br/>
<span class="not-covered" title="0 out of 8 forms covered">
181&nbsp;&nbsp;&nbsp;&nbsp;(run-world&nbsp;world&nbsp;nil&nbsp;(list&nbsp;flow-nr)&nbsp;max-altitude))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
182&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
183&nbsp;&nbsp;(defn&nbsp;flow-world
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
184&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;a&nbsp;world&nbsp;like&nbsp;this&nbsp;`world`,&nbsp;but&nbsp;with&nbsp;cells&nbsp;tagged&nbsp;with&nbsp;the&nbsp;amount&nbsp;of
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
185&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;water&nbsp;flowing&nbsp;through&nbsp;them.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
186&nbsp;&nbsp;&nbsp;&nbsp;[world]
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
187&nbsp;&nbsp;&nbsp;&nbsp;(map-world&nbsp;(rain-world&nbsp;world)&nbsp;flow))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
188&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
189&nbsp;&nbsp;(defn&nbsp;explore-lake
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
190&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;a&nbsp;sequence&nbsp;of&nbsp;cells&nbsp;starting&nbsp;with&nbsp;this&nbsp;`cell`&nbsp;in&nbsp;this&nbsp;`world`&nbsp;which
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
191&nbsp;&nbsp;&nbsp;&nbsp;form&nbsp;a&nbsp;contiguous&nbsp;lake&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
192&nbsp;&nbsp;&nbsp;&nbsp;[_world&nbsp;_cell]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
193&nbsp;&nbsp;&nbsp;&nbsp;)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
194&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
195&nbsp;&nbsp;(defn&nbsp;is-lake?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
196&nbsp;&nbsp;&nbsp;&nbsp;&quot;If&nbsp;this&nbsp;`cell`&nbsp;in&nbsp;this&nbsp;`world`&nbsp;is&nbsp;not&nbsp;part&nbsp;of&nbsp;a&nbsp;lake,&nbsp;return&nbsp;nil.&nbsp;If&nbsp;it&nbsp;is,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
197&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;a&nbsp;cell&nbsp;like&nbsp;this&nbsp;`cell`&nbsp;tagged&nbsp;as&nbsp;part&nbsp;of&nbsp;a&nbsp;lake.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
198&nbsp;&nbsp;&nbsp;&nbsp;[world&nbsp;cell]
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
199&nbsp;&nbsp;&nbsp;&nbsp;(if
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
200&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;if&nbsp;it&#x27;s&nbsp;already&nbsp;tagged&nbsp;as&nbsp;a&nbsp;lake,&nbsp;it&#x27;s&nbsp;a&nbsp;lake
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
201&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:lake&nbsp;cell)&nbsp;cell
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
202&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let
</span><br/>
<span class="not-covered" title="0 out of 10 forms covered">
203&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[outflow&nbsp;(apply&nbsp;min&nbsp;(map&nbsp;:altitude&nbsp;(get-neighbours&nbsp;world&nbsp;cell)))]
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
204&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(when-not
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
205&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;&nbsp;(:altitude&nbsp;cell)&nbsp;outflow)
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
206&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assoc&nbsp;cell&nbsp;:lake&nbsp;true)))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
207&nbsp;&nbsp;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
208&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
209&nbsp;&nbsp;(defn&nbsp;find-lakes
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
210&nbsp;&nbsp;&nbsp;&nbsp;[_world]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
211&nbsp;&nbsp;&nbsp;&nbsp;)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
212&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
213&nbsp;&nbsp;(defn&nbsp;run-drainage
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
214&nbsp;&nbsp;&nbsp;&nbsp;&quot;Create&nbsp;a&nbsp;world&nbsp;from&nbsp;the&nbsp;heightmap&nbsp;`hmap`,&nbsp;rain&nbsp;on&nbsp;it,&nbsp;and&nbsp;then&nbsp;compute&nbsp;river
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
215&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flows.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
216&nbsp;&nbsp;&nbsp;&nbsp;[hmap]
</span><br/>
<span class="not-covered" title="0 out of 9 forms covered">
217&nbsp;&nbsp;&nbsp;&nbsp;(flow-world&nbsp;(rain-world&nbsp;(flood-hollows&nbsp;(heightmap&#x2F;apply-heightmap&nbsp;hmap)))))
</span><br/>
</body>
</html>

View file

@ -0,0 +1,545 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="../coverage.css"/> <title> mw_engine/flow.clj </title>
</head>
<body>
<span class="covered" title="1 out of 1 forms covered">
001&nbsp;&nbsp;(ns&nbsp;mw-engine.flow
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
002&nbsp;&nbsp;&nbsp;&nbsp;&quot;Allow&nbsp;flows&nbsp;of&nbsp;values&nbsp;between&nbsp;cells&nbsp;in&nbsp;the&nbsp;world.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
003&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
004&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The&nbsp;design&nbsp;here&nbsp;is:&nbsp;a&nbsp;flow&nbsp;object&nbsp;is&nbsp;a&nbsp;map&nbsp;with&nbsp;the&nbsp;following&nbsp;properties:
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
005&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
006&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1.&nbsp;`:source`,&nbsp;whose&nbsp;value&nbsp;is&nbsp;a&nbsp;location;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
007&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2.&nbsp;`:destination`,&nbsp;whose&nbsp;value&nbsp;is&nbsp;a&nbsp;location;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3.&nbsp;`:property`,&nbsp;whose&nbsp;value&nbsp;is&nbsp;a&nbsp;keyword;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
009&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4.&nbsp;`:quantity`,&nbsp;whose&nbsp;value&nbsp;is&nbsp;a&nbsp;positive&nbsp;real&nbsp;number.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
010&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
011&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;A&nbsp;location&nbsp;object&nbsp;is&nbsp;a&nbsp;map&nbsp;with&nbsp;the&nbsp;following&nbsp;properties:
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
012&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
013&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1.&nbsp;`:x`,&nbsp;whose&nbsp;value&nbsp;is&nbsp;a&nbsp;natural&nbsp;number&nbsp;not&nbsp;greater&nbsp;than&nbsp;the&nbsp;extent&nbsp;of&nbsp;the&nbsp;world;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
014&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2.&nbsp;`:y`,&nbsp;whose&nbsp;value&nbsp;is&nbsp;a&nbsp;natural&nbsp;number&nbsp;not&nbsp;greater&nbsp;than&nbsp;the&nbsp;extent&nbsp;of&nbsp;the&nbsp;world.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
015&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
016&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;To&nbsp;execute&nbsp;a&nbsp;flow&nbsp;is&nbsp;transfer&nbsp;the&nbsp;quantity&nbsp;specified&nbsp;of&nbsp;the&nbsp;property&nbsp;specified
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
017&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from&nbsp;the&nbsp;cell&nbsp;at&nbsp;the&nbsp;source&nbsp;specified&nbsp;to&nbsp;the&nbsp;cell&nbsp;at&nbsp;the&nbsp;destination&nbsp;specified;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
018&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;the&nbsp;source&nbsp;doesn&#x27;t&nbsp;have&nbsp;sufficient&nbsp;of&nbsp;the&nbsp;property,&nbsp;then&nbsp;all&nbsp;it&nbsp;has&nbsp;should
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
019&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;be&nbsp;transferred,&nbsp;but&nbsp;no&nbsp;more:&nbsp;properties&nbsp;to&nbsp;be&nbsp;flowed&nbsp;cannot&nbsp;be&nbsp;pulled&nbsp;negative.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
020&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
021&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Flowing&nbsp;values&nbsp;through&nbsp;the&nbsp;world&nbsp;is&nbsp;consequently&nbsp;a&nbsp;two&nbsp;stage&nbsp;process:&nbsp;firstly
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
022&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;there&#x27;s&nbsp;a&nbsp;planning&nbsp;stage,&nbsp;in&nbsp;which&nbsp;all&nbsp;the&nbsp;flows&nbsp;to&nbsp;be&nbsp;executed&nbsp;are&nbsp;computed
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
023&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;without&nbsp;changing&nbsp;the&nbsp;world,&nbsp;and&nbsp;then&nbsp;an&nbsp;execution&nbsp;stage,&nbsp;where&nbsp;they&#x27;re&nbsp;all&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
024&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;executed.&nbsp;This&nbsp;namespace&nbsp;deals&nbsp;with&nbsp;mainly&nbsp;with&nbsp;execution.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
025&nbsp;&nbsp;&nbsp;&nbsp;(:require&nbsp;[mw-engine.utils&nbsp;:refer&nbsp;[add-history-event&nbsp;get-cell&nbsp;get-num
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
026&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;in-bounds?&nbsp;map-world&nbsp;merge-cell&nbsp;rule-type]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
027&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[taoensso.timbre&nbsp;:refer&nbsp;[info&nbsp;warn]]))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
028&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
029&nbsp;&nbsp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
030&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
031&nbsp;&nbsp;;;;;&nbsp;mw-engine:&nbsp;the&nbsp;state&#x2F;transition&nbsp;engine&nbsp;of&nbsp;MicroWorld.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
032&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
033&nbsp;&nbsp;;;;;&nbsp;This&nbsp;program&nbsp;is&nbsp;free&nbsp;software;&nbsp;you&nbsp;can&nbsp;redistribute&nbsp;it&nbsp;and&#x2F;or
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
034&nbsp;&nbsp;;;;;&nbsp;modify&nbsp;it&nbsp;under&nbsp;the&nbsp;terms&nbsp;of&nbsp;the&nbsp;GNU&nbsp;General&nbsp;Public&nbsp;License
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
035&nbsp;&nbsp;;;;;&nbsp;as&nbsp;published&nbsp;by&nbsp;the&nbsp;Free&nbsp;Software&nbsp;Foundation;&nbsp;either&nbsp;version&nbsp;2
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
036&nbsp;&nbsp;;;;;&nbsp;of&nbsp;the&nbsp;License,&nbsp;or&nbsp;(at&nbsp;your&nbsp;option)&nbsp;any&nbsp;later&nbsp;version.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
037&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
038&nbsp;&nbsp;;;;;&nbsp;This&nbsp;program&nbsp;is&nbsp;distributed&nbsp;in&nbsp;the&nbsp;hope&nbsp;that&nbsp;it&nbsp;will&nbsp;be&nbsp;useful,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
039&nbsp;&nbsp;;;;;&nbsp;but&nbsp;WITHOUT&nbsp;ANY&nbsp;WARRANTY;&nbsp;without&nbsp;even&nbsp;the&nbsp;implied&nbsp;warranty&nbsp;of
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
040&nbsp;&nbsp;;;;;&nbsp;MERCHANTABILITY&nbsp;or&nbsp;FITNESS&nbsp;FOR&nbsp;A&nbsp;PARTICULAR&nbsp;PURPOSE.&nbsp;&nbsp;See&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
041&nbsp;&nbsp;;;;;&nbsp;GNU&nbsp;General&nbsp;Public&nbsp;License&nbsp;for&nbsp;more&nbsp;details.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
042&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
043&nbsp;&nbsp;;;;;&nbsp;You&nbsp;should&nbsp;have&nbsp;received&nbsp;a&nbsp;copy&nbsp;of&nbsp;the&nbsp;GNU&nbsp;General&nbsp;Public&nbsp;License
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
044&nbsp;&nbsp;;;;;&nbsp;along&nbsp;with&nbsp;this&nbsp;program;&nbsp;if&nbsp;not,&nbsp;write&nbsp;to&nbsp;the&nbsp;Free&nbsp;Software
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
045&nbsp;&nbsp;;;;;&nbsp;Foundation,&nbsp;Inc.,&nbsp;51&nbsp;Franklin&nbsp;Street,&nbsp;Fifth&nbsp;Floor,&nbsp;Boston,&nbsp;MA&nbsp;&nbsp;02110-1301,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
046&nbsp;&nbsp;;;;;&nbsp;USA.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
047&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
048&nbsp;&nbsp;;;;;&nbsp;Copyright&nbsp;(C)&nbsp;2014&nbsp;Simon&nbsp;Brooke
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
049&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
050&nbsp;&nbsp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
051&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
052&nbsp;&nbsp;(defn&nbsp;coordinate?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
053&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;`true`&nbsp;if&nbsp;this&nbsp;object&nbsp;`o`&nbsp;is&nbsp;a&nbsp;valid&nbsp;coordinate&nbsp;with&nbsp;respect&nbsp;to
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
054&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this&nbsp;`world`,&nbsp;else&nbsp;`false`.&nbsp;Assumes&nbsp;square&nbsp;worlds.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
055&nbsp;&nbsp;&nbsp;&nbsp;[o&nbsp;world]
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
056&nbsp;&nbsp;&nbsp;&nbsp;(try
</span><br/>
<span class="covered" title="14 out of 14 forms covered">
057&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and&nbsp;(or&nbsp;(zero?&nbsp;o)&nbsp;(pos-int?&nbsp;o))
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
058&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&lt;&nbsp;o&nbsp;(count&nbsp;world)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
059&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(catch&nbsp;Exception&nbsp;e
</span><br/>
<span class="covered" title="20 out of 20 forms covered">
060&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(warn&nbsp;(format&nbsp;&quot;Not&nbsp;a&nbsp;valid&nbsp;coordinate:&nbsp;%s;&nbsp;%s&quot;&nbsp;o&nbsp;(.getMessage&nbsp;e)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
061&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;false)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
062&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
063&nbsp;&nbsp;(defn&nbsp;location?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
064&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;`true`&nbsp;if&nbsp;this&nbsp;object&nbsp;`o`&nbsp;is&nbsp;a&nbsp;location&nbsp;as&nbsp;defined&nbsp;above&nbsp;with&nbsp;respect&nbsp;to
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
065&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this&nbsp;`world`,&nbsp;else&nbsp;`false`.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
066&nbsp;&nbsp;&nbsp;&nbsp;[o&nbsp;world]
</span><br/>
<span class="partial" title="1 out of 2 forms covered">
067&nbsp;&nbsp;&nbsp;&nbsp;(try
</span><br/>
<span class="partial" title="14 out of 16 forms covered">
068&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and&nbsp;(map?&nbsp;o)
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
069&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(integer?&nbsp;(:x&nbsp;o))
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
070&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(integer?&nbsp;(:y&nbsp;o))
</span><br/>
<span class="covered" title="8 out of 8 forms covered">
071&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(in-bounds?&nbsp;world&nbsp;(:x&nbsp;o)&nbsp;(:y&nbsp;o)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
072&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(catch&nbsp;Exception&nbsp;e
</span><br/>
<span class="not-covered" title="0 out of 20 forms covered">
073&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(warn&nbsp;(format&nbsp;&quot;Not&nbsp;a&nbsp;valid&nbsp;location:&nbsp;%s;&nbsp;%s&quot;&nbsp;o&nbsp;(.getMessage&nbsp;e)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
074&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;false)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
075&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
076&nbsp;&nbsp;(defn&nbsp;flow?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
077&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;`true`&nbsp;if&nbsp;this&nbsp;object&nbsp;`o`&nbsp;is&nbsp;a&nbsp;flow&nbsp;as&nbsp;defined&nbsp;above&nbsp;with&nbsp;respect&nbsp;to
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
078&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this&nbsp;`world`,&nbsp;else&nbsp;`false`.&nbsp;Assumes&nbsp;square&nbsp;worlds.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
079&nbsp;&nbsp;&nbsp;&nbsp;[o&nbsp;world]
</span><br/>
<span class="partial" title="1 out of 2 forms covered">
080&nbsp;&nbsp;&nbsp;&nbsp;(try
</span><br/>
<span class="partial" title="16 out of 20 forms covered">
081&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and&nbsp;(map?&nbsp;o)
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
082&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(location?&nbsp;(:source&nbsp;o)&nbsp;world)
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
083&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(location?&nbsp;(:destination&nbsp;o)&nbsp;world)
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
084&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(keyword?&nbsp;(:property&nbsp;o))
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
085&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(pos?&nbsp;(:quantity&nbsp;o)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
086&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(catch&nbsp;Exception&nbsp;e
</span><br/>
<span class="not-covered" title="0 out of 20 forms covered">
087&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(warn&nbsp;(format&nbsp;&quot;Not&nbsp;a&nbsp;valid&nbsp;flow:&nbsp;%s;&nbsp;%s&quot;&nbsp;o&nbsp;(.getMessage&nbsp;e)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
088&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;false)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
089&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
090&nbsp;&nbsp;(defn&nbsp;execute
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
091&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;a&nbsp;world&nbsp;like&nbsp;this&nbsp;`world`,&nbsp;except&nbsp;with&nbsp;the&nbsp;quantity&nbsp;of&nbsp;the&nbsp;property
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
092&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;described&nbsp;in&nbsp;this&nbsp;`flow`&nbsp;object&nbsp;transferred&nbsp;from&nbsp;the&nbsp;source&nbsp;of&nbsp;that&nbsp;flow
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
093&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;to&nbsp;its&nbsp;destination.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
094&nbsp;&nbsp;&nbsp;&nbsp;[world&nbsp;flow]
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
095&nbsp;&nbsp;&nbsp;&nbsp;(try
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
096&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[sx&nbsp;(-&gt;&nbsp;flow&nbsp;:source&nbsp;:x)
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
097&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sy&nbsp;(-&gt;&nbsp;flow&nbsp;:source&nbsp;:y)
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
098&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;source&nbsp;(get-cell&nbsp;world&nbsp;sx&nbsp;sy)
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
099&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dx&nbsp;(-&gt;&nbsp;flow&nbsp;:destination&nbsp;:x)
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
100&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dy&nbsp;(-&gt;&nbsp;flow&nbsp;:destination&nbsp;:y)
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
101&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dest&nbsp;(get-cell&nbsp;world&nbsp;dx&nbsp;dy)
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
102&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p&nbsp;(:property&nbsp;flow)
</span><br/>
<span class="partial" title="16 out of 22 forms covered">
103&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;q&nbsp;(min&nbsp;(:quantity&nbsp;flow)&nbsp;(get-num&nbsp;source&nbsp;p))
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
104&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s&#x27;&nbsp;(add-history-event&nbsp;
</span><br/>
<span class="covered" title="9 out of 9 forms covered">
105&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assoc&nbsp;source&nbsp;p&nbsp;(-&nbsp;(source&nbsp;p)&nbsp;q))&nbsp;
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
106&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:rule&nbsp;flow)&nbsp;
</span><br/>
<span class="covered" title="13 out of 13 forms covered">
107&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{:direction&nbsp;:sent&nbsp;:other&nbsp;{:x&nbsp;dx&nbsp;:y&nbsp;dy}&nbsp;:property&nbsp;p&nbsp;:quantity&nbsp;q})
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
108&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d&#x27;&nbsp;(add-history-event
</span><br/>
<span class="partial" title="20 out of 24 forms covered">
109&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(assoc&nbsp;dest&nbsp;p&nbsp;(+&nbsp;(get-num&nbsp;dest&nbsp;p)&nbsp;q))
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
110&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(:rule&nbsp;flow)
</span><br/>
<span class="covered" title="13 out of 13 forms covered">
111&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{:direction&nbsp;:received&nbsp;:other&nbsp;{:x&nbsp;sx&nbsp;:y&nbsp;sy}&nbsp;:property&nbsp;p&nbsp;:quantity&nbsp;q})]
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
112&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(if&nbsp;(=&nbsp;q&nbsp;(:quantity&nbsp;flow))
</span><br/>
<span class="covered" title="18 out of 18 forms covered">
113&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(info&nbsp;(format&nbsp;&quot;Moving&nbsp;%f&nbsp;units&nbsp;of&nbsp;%s&nbsp;from&nbsp;%d,%d&nbsp;to&nbsp;%d,%d&quot;
</span><br/>
<span class="covered" title="9 out of 9 forms covered">
114&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(float&nbsp;q)&nbsp;(name&nbsp;p)&nbsp;sx&nbsp;sy&nbsp;dx&nbsp;dy))
</span><br/>
<span class="covered" title="18 out of 18 forms covered">
115&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(warn&nbsp;(format&nbsp;&quot;Moving&nbsp;%s&nbsp;from&nbsp;%d,%d&nbsp;to&nbsp;%d,%d;&nbsp;%f&nbsp;units&nbsp;ordered&nbsp;but&nbsp;only&nbsp;%f&nbsp;available&quot;
</span><br/>
<span class="covered" title="13 out of 13 forms covered">
116&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(name&nbsp;p)&nbsp;sx&nbsp;sy&nbsp;dx&nbsp;dy&nbsp;(float&nbsp;(:quantity&nbsp;flow))&nbsp;(float&nbsp;q))))
</span><br/>
<span class="covered" title="7 out of 7 forms covered">
117&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(merge-cell&nbsp;(merge-cell&nbsp;world&nbsp;s&#x27;)&nbsp;d&#x27;))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
118&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(catch&nbsp;Exception&nbsp;e
</span><br/>
<span class="not-covered" title="0 out of 20 forms covered">
119&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(warn&nbsp;(format&nbsp;&quot;Failed&nbsp;to&nbsp;execute&nbsp;flow&nbsp;%s:&nbsp;%s&quot;&nbsp;flow&nbsp;(.getMessage&nbsp;e)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
120&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;return&nbsp;the&nbsp;world&nbsp;unmodified.
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
121&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;world)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
122&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
123&nbsp;&nbsp;(defn&nbsp;execute-flows
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
124&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;a&nbsp;world&nbsp;like&nbsp;this&nbsp;`world`,&nbsp;but&nbsp;with&nbsp;each&nbsp;of&nbsp;these&nbsp;flows&nbsp;executed.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
125&nbsp;&nbsp;&nbsp;&nbsp;[world&nbsp;flows]
</span><br/>
<span class="covered" title="12 out of 12 forms covered">
126&nbsp;&nbsp;&nbsp;&nbsp;(reduce&nbsp;execute&nbsp;world&nbsp;(filter&nbsp;#(flow?&nbsp;%&nbsp;world)&nbsp;flows)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
127&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
128&nbsp;&nbsp;(defn-&nbsp;plan-cell-flows&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
129&nbsp;&nbsp;&nbsp;&nbsp;[world&nbsp;cell&nbsp;rules]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
130&nbsp;&nbsp;&nbsp;&nbsp;(map&nbsp;;;&nbsp;across&nbsp;all&nbsp;the&nbsp;rules
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
131&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[rule]&nbsp;(let&nbsp;[r&nbsp;(try&nbsp;
</span><br/>
<span class="not-covered" title="0 out of 7 forms covered">
132&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(apply&nbsp;rule&nbsp;(list&nbsp;cell&nbsp;world))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
133&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(catch&nbsp;Exception&nbsp;any
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
134&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw&nbsp;(ex-info&nbsp;&quot;Planning&nbsp;of&nbsp;flows&nbsp;failed&quot;
</span><br/>
<span class="not-covered" title="0 out of 8 forms covered">
135&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(merge&nbsp;(meta&nbsp;rule)&nbsp;{:cell&nbsp;cell})
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
136&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;any))))]&nbsp;
</span><br/>
<span class="not-covered" title="0 out of 12 forms covered">
137&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(when&nbsp;r&nbsp;(map&nbsp;#(assoc&nbsp;%&nbsp;:rule&nbsp;rule)&nbsp;r))))
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
138&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rules))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
139&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
140&nbsp;&nbsp;(defn&nbsp;plan-flows
</span><br/>
<span class="partial" title="3 out of 4 forms covered">
141&nbsp;&nbsp;&nbsp;&nbsp;&quot;Plan,&nbsp;but&nbsp;do&nbsp;not&nbsp;execute,&nbsp;all&nbsp;the&nbsp;flows&nbsp;in&nbsp;this&nbsp;`world`&nbsp;implied&nbsp;by&nbsp;those&nbsp;of&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
142&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;these&nbsp;`rules`&nbsp;(which&nbsp;are&nbsp;expected&nbsp;to&nbsp;be&nbsp;pre-compiled)&nbsp;which&nbsp;are
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
143&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flow&nbsp;rules.&nbsp;Return&nbsp;the&nbsp;list&nbsp;of&nbsp;plans,&nbsp;as&nbsp;flow&nbsp;objects.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
144&nbsp;&nbsp;&nbsp;&nbsp;[world&nbsp;rules]
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
145&nbsp;&nbsp;&nbsp;&nbsp;(remove&nbsp;nil?
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
146&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(flatten
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
147&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map-world
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
148&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;world
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
149&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;plan-cell-flows
</span><br/>
<span class="partial" title="4 out of 17 forms covered">
150&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(list&nbsp;(filter&nbsp;#(=&nbsp;:flow&nbsp;(rule-type&nbsp;%))&nbsp;rules))))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
151&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
152&nbsp;&nbsp;(defn&nbsp;flow-world
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
153&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;a&nbsp;world&nbsp;derived&nbsp;from&nbsp;this&nbsp;`world`&nbsp;by&nbsp;applying&nbsp;the&nbsp;flow&nbsp;rules&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
154&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;found&nbsp;among&nbsp;these&nbsp;`rules`&nbsp;to&nbsp;each&nbsp;cell,&nbsp;and&nbsp;executing&nbsp;all&nbsp;the&nbsp;flows
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
155&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;planned.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
156&nbsp;&nbsp;&nbsp;&nbsp;[world&nbsp;rules]
</span><br/>
<span class="not-covered" title="0 out of 7 forms covered">
157&nbsp;&nbsp;&nbsp;&nbsp;(execute-flows&nbsp;world&nbsp;(plan-flows&nbsp;world&nbsp;rules)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
158&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
159&nbsp;&nbsp;;;&nbsp;building&nbsp;blocks&nbsp;for&nbsp;compiled&nbsp;flow&nbsp;rules
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
160&nbsp;&nbsp;
</span><br/>
<span class="covered" title="32 out of 32 forms covered">
161&nbsp;&nbsp;(defmacro&nbsp;create-location
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
162&nbsp;&nbsp;&nbsp;&nbsp;[cell]
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
163&nbsp;&nbsp;&nbsp;&nbsp;`(select-keys&nbsp;~cell&nbsp;[:x&nbsp;:y]))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
164&nbsp;&nbsp;
</span><br/>
<span class="covered" title="56 out of 56 forms covered">
165&nbsp;&nbsp;(defmacro&nbsp;create-flow-quantity
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
166&nbsp;&nbsp;&nbsp;&nbsp;[source&nbsp;dest&nbsp;prop&nbsp;quantity]
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
167&nbsp;&nbsp;&nbsp;&nbsp;`{:source&nbsp;(create-location&nbsp;~source)
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
168&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:destination&nbsp;(create-location&nbsp;~dest)
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
169&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:prop&nbsp;~prop
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
170&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:quantity&nbsp;~quantity})
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
171&nbsp;&nbsp;
</span><br/>
<span class="covered" title="48 out of 48 forms covered">
172&nbsp;&nbsp;(defmacro&nbsp;create-flow-fraction
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
173&nbsp;&nbsp;&nbsp;&nbsp;[source&nbsp;dest&nbsp;prop&nbsp;fraction]
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
174&nbsp;&nbsp;&nbsp;&nbsp;`(create-flow-quantity&nbsp;~source&nbsp;~dest&nbsp;~prop
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
175&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(*&nbsp;~fraction&nbsp;(get-num&nbsp;~source&nbsp;~prop))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
176&nbsp;&nbsp;
</span><br/>
<span class="covered" title="36 out of 36 forms covered">
177&nbsp;&nbsp;(defmacro&nbsp;create-flow-percent
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
178&nbsp;&nbsp;&nbsp;&nbsp;[source&nbsp;dest&nbsp;prop&nbsp;percent]
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
179&nbsp;&nbsp;&nbsp;&nbsp;`(create-flow-fraction&nbsp;~source&nbsp;~dest&nbsp;~prop&nbsp;(&#x2F;&nbsp;~percent&nbsp;100)))
</span><br/>
</body>
</html>

View file

@ -0,0 +1,407 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="../coverage.css"/> <title> mw_engine/heightmap.clj </title>
</head>
<body>
<span class="covered" title="1 out of 1 forms covered">
001&nbsp;&nbsp;(ns&nbsp;^{:doc&nbsp;&quot;Functions&nbsp;to&nbsp;apply&nbsp;a&nbsp;heightmap&nbsp;to&nbsp;a&nbsp;world.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
002&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
003&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Heightmaps&nbsp;are&nbsp;considered&nbsp;only&nbsp;as&nbsp;greyscale&nbsp;images,&nbsp;so&nbsp;colour&nbsp;is&nbsp;redundent
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
004&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(will&nbsp;be&nbsp;ignored).&nbsp;Darker&nbsp;shades&nbsp;are&nbsp;higher.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
005&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:author&nbsp;&quot;Simon&nbsp;Brooke&quot;}
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
006&nbsp;&nbsp;&nbsp;&nbsp;mw-engine.heightmap
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
007&nbsp;&nbsp;&nbsp;&nbsp;(:require&nbsp;[mikera.image.core&nbsp;:refer&nbsp;[load-image&nbsp;filter-image]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[mikera.image.filters&nbsp;:as&nbsp;filters]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
009&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[mw-engine.utils&nbsp;:refer&nbsp;[get-int&nbsp;get-neighbours&nbsp;map-world]]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
010&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[mw-engine.world&nbsp;:refer&nbsp;[make-world]]))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
011&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
012&nbsp;&nbsp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
013&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
014&nbsp;&nbsp;;;;;&nbsp;mw-engine:&nbsp;the&nbsp;state&#x2F;transition&nbsp;engine&nbsp;of&nbsp;MicroWorld.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
015&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
016&nbsp;&nbsp;;;;;&nbsp;This&nbsp;program&nbsp;is&nbsp;free&nbsp;software;&nbsp;you&nbsp;can&nbsp;redistribute&nbsp;it&nbsp;and&#x2F;or
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
017&nbsp;&nbsp;;;;;&nbsp;modify&nbsp;it&nbsp;under&nbsp;the&nbsp;terms&nbsp;of&nbsp;the&nbsp;GNU&nbsp;General&nbsp;Public&nbsp;License
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
018&nbsp;&nbsp;;;;;&nbsp;as&nbsp;published&nbsp;by&nbsp;the&nbsp;Free&nbsp;Software&nbsp;Foundation;&nbsp;either&nbsp;version&nbsp;2
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
019&nbsp;&nbsp;;;;;&nbsp;of&nbsp;the&nbsp;License,&nbsp;or&nbsp;(at&nbsp;your&nbsp;option)&nbsp;any&nbsp;later&nbsp;version.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
020&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
021&nbsp;&nbsp;;;;;&nbsp;This&nbsp;program&nbsp;is&nbsp;distributed&nbsp;in&nbsp;the&nbsp;hope&nbsp;that&nbsp;it&nbsp;will&nbsp;be&nbsp;useful,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
022&nbsp;&nbsp;;;;;&nbsp;but&nbsp;WITHOUT&nbsp;ANY&nbsp;WARRANTY;&nbsp;without&nbsp;even&nbsp;the&nbsp;implied&nbsp;warranty&nbsp;of
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
023&nbsp;&nbsp;;;;;&nbsp;MERCHANTABILITY&nbsp;or&nbsp;FITNESS&nbsp;FOR&nbsp;A&nbsp;PARTICULAR&nbsp;PURPOSE.&nbsp;&nbsp;See&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
024&nbsp;&nbsp;;;;;&nbsp;GNU&nbsp;General&nbsp;Public&nbsp;License&nbsp;for&nbsp;more&nbsp;details.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
025&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
026&nbsp;&nbsp;;;;;&nbsp;You&nbsp;should&nbsp;have&nbsp;received&nbsp;a&nbsp;copy&nbsp;of&nbsp;the&nbsp;GNU&nbsp;General&nbsp;Public&nbsp;License
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
027&nbsp;&nbsp;;;;;&nbsp;along&nbsp;with&nbsp;this&nbsp;program;&nbsp;if&nbsp;not,&nbsp;write&nbsp;to&nbsp;the&nbsp;Free&nbsp;Software
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
028&nbsp;&nbsp;;;;;&nbsp;Foundation,&nbsp;Inc.,&nbsp;51&nbsp;Franklin&nbsp;Street,&nbsp;Fifth&nbsp;Floor,&nbsp;Boston,&nbsp;MA&nbsp;&nbsp;02110-1301,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
029&nbsp;&nbsp;;;;;&nbsp;USA.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
030&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
031&nbsp;&nbsp;;;;;&nbsp;Copyright&nbsp;(C)&nbsp;2014&nbsp;Simon&nbsp;Brooke
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
032&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
033&nbsp;&nbsp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
034&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
035&nbsp;&nbsp;(defn&nbsp;abs&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
036&nbsp;&nbsp;&nbsp;&nbsp;&quot;Prior&nbsp;to&nbsp;Clojure&nbsp;1.11,&nbsp;there&nbsp;is&nbsp;no&nbsp;native&nbsp;`abs`&nbsp;function.&nbsp;Afterwards,&nbsp;there
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
037&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;is.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
038&nbsp;&nbsp;&nbsp;&nbsp;[n]&nbsp;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
039&nbsp;&nbsp;&nbsp;&nbsp;(Math&#x2F;abs&nbsp;n))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
040&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
041&nbsp;&nbsp;(defn&nbsp;tag-property
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
042&nbsp;&nbsp;&nbsp;&nbsp;&quot;Set&nbsp;the&nbsp;value&nbsp;of&nbsp;this&nbsp;`property`&nbsp;of&nbsp;this&nbsp;cell&nbsp;from&nbsp;the&nbsp;corresponding&nbsp;pixel&nbsp;of&nbsp;this&nbsp;`heightmap`.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
043&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;If&nbsp;the&nbsp;heightmap&nbsp;you&nbsp;supply&nbsp;is&nbsp;smaller&nbsp;than&nbsp;the&nbsp;world,&nbsp;this&nbsp;will&nbsp;break.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
044&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
045&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`world`&nbsp;not&nbsp;actually&nbsp;used,&nbsp;but&nbsp;present&nbsp;to&nbsp;enable&nbsp;this&nbsp;function&nbsp;to&nbsp;be
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
046&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;passed&nbsp;as&nbsp;an&nbsp;argument&nbsp;to&nbsp;`mw-engine.utils&#x2F;map-world`,&nbsp;q.v.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
047&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`cell`&nbsp;a&nbsp;cell,&nbsp;as&nbsp;discussed&nbsp;in&nbsp;world.clj,&nbsp;q.v.&nbsp;Alternatively,&nbsp;a&nbsp;map;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
048&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`property`&nbsp;the&nbsp;property&nbsp;(normally&nbsp;a&nbsp;keyword)&nbsp;whose&nbsp;value&nbsp;will&nbsp;be&nbsp;set&nbsp;on&nbsp;the&nbsp;cell.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
049&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`heightmap`&nbsp;an&nbsp;(ideally)&nbsp;greyscale&nbsp;image,&nbsp;whose&nbsp;x&nbsp;and&nbsp;y&nbsp;dimensions&nbsp;should
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
050&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exceed&nbsp;those&nbsp;of&nbsp;the&nbsp;world&nbsp;of&nbsp;which&nbsp;the&nbsp;`cell`&nbsp;forms&nbsp;part.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
051&nbsp;&nbsp;&nbsp;&nbsp;([_&nbsp;cell&nbsp;property&nbsp;heightmap]
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
052&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(tag-property&nbsp;cell&nbsp;property&nbsp;heightmap))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
053&nbsp;&nbsp;&nbsp;&nbsp;([cell&nbsp;property&nbsp;heightmap]
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
054&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(merge&nbsp;cell
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
055&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{property
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
056&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(+&nbsp;(get-int&nbsp;cell&nbsp;property)
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
057&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(-&nbsp;256
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
058&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(abs
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
059&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(mod
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
060&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(.getRGB&nbsp;heightmap
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
061&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(get-int&nbsp;cell&nbsp;:x)
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
062&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(get-int&nbsp;cell&nbsp;:y))&nbsp;256))))})))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
063&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
064&nbsp;&nbsp;(defn&nbsp;tag-gradient
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
065&nbsp;&nbsp;&nbsp;&nbsp;&quot;Set&nbsp;the&nbsp;`gradient`&nbsp;property&nbsp;of&nbsp;this&nbsp;`cell`&nbsp;of&nbsp;this&nbsp;`world`&nbsp;to&nbsp;the&nbsp;difference&nbsp;in
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
066&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;altitude&nbsp;between&nbsp;its&nbsp;highest&nbsp;and&nbsp;lowest&nbsp;neghbours.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
067&nbsp;&nbsp;&nbsp;&nbsp;[world&nbsp;cell]
</span><br/>
<span class="covered" title="11 out of 11 forms covered">
068&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[heights&nbsp;(remove&nbsp;nil?&nbsp;(map&nbsp;:altitude&nbsp;(get-neighbours&nbsp;world&nbsp;cell)))
</span><br/>
<span class="partial" title="5 out of 6 forms covered">
069&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;highest&nbsp;(cond&nbsp;(empty?&nbsp;heights)&nbsp;0&nbsp;;;&nbsp;shouldn&#x27;t&nbsp;happen
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
070&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:else&nbsp;(apply&nbsp;max&nbsp;heights))
</span><br/>
<span class="partial" title="5 out of 6 forms covered">
071&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lowest&nbsp;(cond&nbsp;(empty?&nbsp;heights)&nbsp;0&nbsp;;;&nbsp;shouldn&#x27;t
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
072&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:else&nbsp;(apply&nbsp;min&nbsp;heights))
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
073&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gradient&nbsp;(-&nbsp;highest&nbsp;lowest)]
</span><br/>
<span class="covered" title="6 out of 6 forms covered">
074&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(merge&nbsp;cell&nbsp;{:gradient&nbsp;gradient})))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
075&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
076&nbsp;&nbsp;(defn&nbsp;tag-gradients
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
077&nbsp;&nbsp;&nbsp;&nbsp;&quot;Set&nbsp;the&nbsp;`gradient`&nbsp;property&nbsp;of&nbsp;each&nbsp;cell&nbsp;in&nbsp;this&nbsp;`world`&nbsp;to&nbsp;the&nbsp;difference&nbsp;in
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
078&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;altitude&nbsp;between&nbsp;its&nbsp;highest&nbsp;and&nbsp;lowest&nbsp;neghbours.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
079&nbsp;&nbsp;&nbsp;&nbsp;[world]
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
080&nbsp;&nbsp;&nbsp;&nbsp;(map-world&nbsp;world&nbsp;tag-gradient))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
081&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
082&nbsp;&nbsp;(defn&nbsp;tag-altitude
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
083&nbsp;&nbsp;&nbsp;&nbsp;&quot;Set&nbsp;the&nbsp;altitude&nbsp;of&nbsp;this&nbsp;cell&nbsp;from&nbsp;the&nbsp;corresponding&nbsp;pixel&nbsp;of&nbsp;this&nbsp;heightmap.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
084&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;If&nbsp;the&nbsp;heightmap&nbsp;you&nbsp;supply&nbsp;is&nbsp;smaller&nbsp;than&nbsp;the&nbsp;world,&nbsp;this&nbsp;will&nbsp;break.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
085&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
086&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`world`&nbsp;not&nbsp;actually&nbsp;used,&nbsp;but&nbsp;present&nbsp;to&nbsp;enable&nbsp;this&nbsp;function&nbsp;to&nbsp;be
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
087&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;passed&nbsp;as&nbsp;an&nbsp;argument&nbsp;to&nbsp;`mw-engine.utils&#x2F;map-world`,&nbsp;q.v.;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
088&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`cell`&nbsp;a&nbsp;cell,&nbsp;as&nbsp;discussed&nbsp;in&nbsp;world.clj,&nbsp;q.v.&nbsp;Alternatively,&nbsp;a&nbsp;map;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
089&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`heightmap`&nbsp;an&nbsp;(ideally)&nbsp;greyscale&nbsp;image,&nbsp;whose&nbsp;x&nbsp;and&nbsp;y&nbsp;dimensions&nbsp;should
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
090&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exceed&nbsp;those&nbsp;of&nbsp;the&nbsp;world&nbsp;of&nbsp;which&nbsp;the&nbsp;`cell`&nbsp;forms&nbsp;part.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
091&nbsp;&nbsp;&nbsp;&nbsp;([_&nbsp;cell&nbsp;heightmap]
</span><br/>
<span class="covered" title="5 out of 5 forms covered">
092&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(tag-property&nbsp;cell&nbsp;:altitude&nbsp;heightmap))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
093&nbsp;&nbsp;&nbsp;&nbsp;([cell&nbsp;heightmap]
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
094&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(tag-property&nbsp;cell&nbsp;:altitude&nbsp;heightmap)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
095&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
096&nbsp;&nbsp;(defn&nbsp;apply-heightmap
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
097&nbsp;&nbsp;&nbsp;&nbsp;&quot;Apply&nbsp;the&nbsp;image&nbsp;file&nbsp;loaded&nbsp;from&nbsp;this&nbsp;path&nbsp;to&nbsp;this&nbsp;world,&nbsp;and&nbsp;return&nbsp;a&nbsp;world&nbsp;whose
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
098&nbsp;&nbsp;&nbsp;&nbsp;altitudes&nbsp;are&nbsp;modified&nbsp;(added&nbsp;to)&nbsp;by&nbsp;the&nbsp;altitudes&nbsp;in&nbsp;the&nbsp;heightmap.&nbsp;It&nbsp;is&nbsp;assumed&nbsp;that
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
099&nbsp;&nbsp;&nbsp;&nbsp;the&nbsp;heightmap&nbsp;is&nbsp;at&nbsp;least&nbsp;as&nbsp;large&nbsp;in&nbsp;x&nbsp;and&nbsp;y&nbsp;dimensions&nbsp;as&nbsp;the&nbsp;world.&nbsp;Note&nbsp;that,&nbsp;in
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
100&nbsp;&nbsp;&nbsp;&nbsp;addition&nbsp;to&nbsp;setting&nbsp;the&nbsp;`:altitude`&nbsp;of&nbsp;each&nbsp;cell,&nbsp;this&nbsp;function&nbsp;also&nbsp;sets&nbsp;the&nbsp;`:gradient`.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
101&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
102&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`world`&nbsp;a&nbsp;world,&nbsp;as&nbsp;defined&nbsp;in&nbsp;`world.clj`,&nbsp;q.v.;&nbsp;if&nbsp;world&nbsp;is&nbsp;not&nbsp;supplied,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
103&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a&nbsp;world&nbsp;the&nbsp;size&nbsp;of&nbsp;the&nbsp;heightmap&nbsp;will&nbsp;be&nbsp;created;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
104&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`imagepath`&nbsp;a&nbsp;file&nbsp;path&nbsp;or&nbsp;URL&nbsp;which&nbsp;indicates&nbsp;an&nbsp;(ideally&nbsp;greyscale)&nbsp;image&nbsp;file.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
105&nbsp;&nbsp;&nbsp;&nbsp;([world&nbsp;imagepath]
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
106&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[heightmap&nbsp;(filter-image
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
107&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(load-image&nbsp;imagepath)
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
108&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(filters&#x2F;grayscale))]
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
109&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map-world
</span><br/>
<span class="covered" title="7 out of 7 forms covered">
110&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map-world&nbsp;world&nbsp;tag-altitude&nbsp;(list&nbsp;heightmap))
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
111&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tag-gradient)))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
112&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;([imagepath]
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
113&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[heightmap&nbsp;(filter-image
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
114&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(load-image&nbsp;imagepath)
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
115&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(filters&#x2F;grayscale))
</span><br/>
<span class="covered" title="4 out of 4 forms covered">
116&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;world&nbsp;(make-world&nbsp;(.getWidth&nbsp;heightmap)&nbsp;(.getHeight&nbsp;heightmap))]
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
117&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map-world
</span><br/>
<span class="covered" title="7 out of 7 forms covered">
118&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map-world&nbsp;world&nbsp;tag-altitude&nbsp;(list&nbsp;heightmap))
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
119&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tag-gradient))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
120&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
121&nbsp;&nbsp;(defn&nbsp;apply-valuemap
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
122&nbsp;&nbsp;&nbsp;&nbsp;&quot;Generalised&nbsp;from&nbsp;apply-heightmap,&nbsp;set&nbsp;an&nbsp;arbitrary&nbsp;property&nbsp;on&nbsp;each&nbsp;cell
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
123&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;of&nbsp;this&nbsp;`world`&nbsp;from&nbsp;the&nbsp;values&nbsp;in&nbsp;this&nbsp;(ideally&nbsp;greyscale)&nbsp;heightmap.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
124&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
125&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`world`&nbsp;a&nbsp;world,&nbsp;as&nbsp;defined&nbsp;in&nbsp;`world.clj`,&nbsp;q.v.;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
126&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`imagepath`&nbsp;a&nbsp;file&nbsp;path&nbsp;or&nbsp;URL&nbsp;which&nbsp;indicates&nbsp;an&nbsp;(ideally&nbsp;greyscale)&nbsp;image&nbsp;file;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
127&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`property`&nbsp;the&nbsp;property&nbsp;of&nbsp;each&nbsp;cell&nbsp;whose&nbsp;value&nbsp;should&nbsp;be&nbsp;added&nbsp;to&nbsp;from&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
128&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;intensity&nbsp;of&nbsp;the&nbsp;corresponding&nbsp;cell&nbsp;of&nbsp;the&nbsp;image.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
129&nbsp;&nbsp;&nbsp;&nbsp;[world&nbsp;imagepath&nbsp;property]
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
130&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[heightmap&nbsp;(filter-image
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
131&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(load-image&nbsp;imagepath)
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
132&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(filters&#x2F;grayscale))]
</span><br/>
<span class="covered" title="8 out of 8 forms covered">
133&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map-world&nbsp;world&nbsp;tag-property&nbsp;(list&nbsp;property&nbsp;heightmap))))
</span><br/>
</body>
</html>

View file

@ -0,0 +1,560 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="../coverage.css"/> <title> mw_engine/natural_rules.clj </title>
</head>
<body>
<span class="covered" title="1 out of 1 forms covered">
001&nbsp;&nbsp;(ns&nbsp;^{:doc&nbsp;&quot;A&nbsp;set&nbsp;of&nbsp;MicroWorld&nbsp;rules&nbsp;describing&nbsp;a&nbsp;simplified&nbsp;natural&nbsp;ecosystem.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
002&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
003&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Since&nbsp;the&nbsp;completion&nbsp;of&nbsp;the&nbsp;rule&nbsp;language&nbsp;this&nbsp;is&nbsp;more&nbsp;or&nbsp;less&nbsp;obsolete&nbsp;-
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
004&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;there&nbsp;are&nbsp;still&nbsp;a&nbsp;few&nbsp;things&nbsp;that&nbsp;you&nbsp;can&nbsp;do&nbsp;with&nbsp;rules&nbsp;written&nbsp;in&nbsp;Clojure
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
005&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;that&nbsp;you&nbsp;can&#x27;t&nbsp;do&nbsp;in&nbsp;the&nbsp;rule&nbsp;language,&nbsp;but&nbsp;not&nbsp;many&nbsp;and&nbsp;I&nbsp;doubt&nbsp;they&#x27;re
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
006&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;important.&nbsp;&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
007&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:author&nbsp;&quot;&nbsp;Simon&nbsp;Brooke&nbsp;&quot;}
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
008&nbsp;&nbsp;&nbsp;&nbsp;mw-engine.natural-rules
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
009&nbsp;&nbsp;&nbsp;&nbsp;(:require&nbsp;[mw-engine.utils&nbsp;:refer&nbsp;[get-int&nbsp;get-neighbours&nbsp;get-neighbours-with-state&nbsp;member?]]))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
010&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
011&nbsp;&nbsp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
012&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
013&nbsp;&nbsp;;;;;&nbsp;mw-engine:&nbsp;the&nbsp;state&#x2F;transition&nbsp;engine&nbsp;of&nbsp;MicroWorld.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
014&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
015&nbsp;&nbsp;;;;;&nbsp;This&nbsp;program&nbsp;is&nbsp;free&nbsp;software;&nbsp;you&nbsp;can&nbsp;redistribute&nbsp;it&nbsp;and&#x2F;or
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
016&nbsp;&nbsp;;;;;&nbsp;modify&nbsp;it&nbsp;under&nbsp;the&nbsp;terms&nbsp;of&nbsp;the&nbsp;GNU&nbsp;General&nbsp;Public&nbsp;License
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
017&nbsp;&nbsp;;;;;&nbsp;as&nbsp;published&nbsp;by&nbsp;the&nbsp;Free&nbsp;Software&nbsp;Foundation;&nbsp;either&nbsp;version&nbsp;2
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
018&nbsp;&nbsp;;;;;&nbsp;of&nbsp;the&nbsp;License,&nbsp;or&nbsp;(at&nbsp;your&nbsp;option)&nbsp;any&nbsp;later&nbsp;version.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
019&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
020&nbsp;&nbsp;;;;;&nbsp;This&nbsp;program&nbsp;is&nbsp;distributed&nbsp;in&nbsp;the&nbsp;hope&nbsp;that&nbsp;it&nbsp;will&nbsp;be&nbsp;useful,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
021&nbsp;&nbsp;;;;;&nbsp;but&nbsp;WITHOUT&nbsp;ANY&nbsp;WARRANTY;&nbsp;without&nbsp;even&nbsp;the&nbsp;implied&nbsp;warranty&nbsp;of
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
022&nbsp;&nbsp;;;;;&nbsp;MERCHANTABILITY&nbsp;or&nbsp;FITNESS&nbsp;FOR&nbsp;A&nbsp;PARTICULAR&nbsp;PURPOSE.&nbsp;&nbsp;See&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
023&nbsp;&nbsp;;;;;&nbsp;GNU&nbsp;General&nbsp;Public&nbsp;License&nbsp;for&nbsp;more&nbsp;details.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
024&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
025&nbsp;&nbsp;;;;;&nbsp;You&nbsp;should&nbsp;have&nbsp;received&nbsp;a&nbsp;copy&nbsp;of&nbsp;the&nbsp;GNU&nbsp;General&nbsp;Public&nbsp;License
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
026&nbsp;&nbsp;;;;;&nbsp;along&nbsp;with&nbsp;this&nbsp;program;&nbsp;if&nbsp;not,&nbsp;write&nbsp;to&nbsp;the&nbsp;Free&nbsp;Software
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
027&nbsp;&nbsp;;;;;&nbsp;Foundation,&nbsp;Inc.,&nbsp;51&nbsp;Franklin&nbsp;Street,&nbsp;Fifth&nbsp;Floor,&nbsp;Boston,&nbsp;MA&nbsp;&nbsp;02110-1301,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
028&nbsp;&nbsp;;;;;&nbsp;USA.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
029&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
030&nbsp;&nbsp;;;;;&nbsp;Copyright&nbsp;(C)&nbsp;2014&nbsp;Simon&nbsp;Brooke
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
031&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
032&nbsp;&nbsp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
033&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
034&nbsp;&nbsp;;;&nbsp;treeline&nbsp;at&nbsp;arbitrary&nbsp;altitude.
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
035&nbsp;&nbsp;(def&nbsp;treeline&nbsp;150)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
036&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
037&nbsp;&nbsp;;;&nbsp;waterline&nbsp;also&nbsp;at&nbsp;arbitrary&nbsp;altitude.
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
038&nbsp;&nbsp;(def&nbsp;waterline&nbsp;10)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
039&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
040&nbsp;&nbsp;;;&nbsp;and&nbsp;finally&nbsp;snowline&nbsp;is&nbsp;also&nbsp;arbitrary.
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
041&nbsp;&nbsp;(def&nbsp;snowline&nbsp;200)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
042&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
043&nbsp;&nbsp;;;&nbsp;Rare&nbsp;chance&nbsp;of&nbsp;lightning&nbsp;strikes
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
044&nbsp;&nbsp;(def&nbsp;lightning-probability&nbsp;500)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
045&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
046&nbsp;&nbsp;;;&nbsp;rules&nbsp;describing&nbsp;vegetation
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
047&nbsp;&nbsp;(def&nbsp;vegetation-rules
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
048&nbsp;&nbsp;&nbsp;&nbsp;(list
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
049&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;Randomly,&nbsp;birds&nbsp;plant&nbsp;tree&nbsp;seeds&nbsp;into&nbsp;grassland.
</span><br/>
<span class="partial" title="1 out of 23 forms covered">
050&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[cell&nbsp;_]&nbsp;(cond&nbsp;(and&nbsp;(=&nbsp;(:state&nbsp;cell)&nbsp;:grassland)(&lt;&nbsp;(rand&nbsp;10)&nbsp;1))(merge&nbsp;cell&nbsp;{:state&nbsp;:heath})))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
051&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;heath&nbsp;below&nbsp;the&nbsp;treeline&nbsp;grows&nbsp;gradually&nbsp;into&nbsp;forest,&nbsp;providing&nbsp;browsing&nbsp;pressure&nbsp;is&nbsp;not&nbsp;to&nbsp;high
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
052&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[cell&nbsp;_]
</span><br/>
<span class="not-covered" title="0 out of 11 forms covered">
053&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond&nbsp;(and
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
054&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(=&nbsp;(:state&nbsp;cell)&nbsp;:heath)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
055&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;browsing&nbsp;limit&nbsp;really&nbsp;ought&nbsp;to&nbsp;vary&nbsp;with&nbsp;soil&nbsp;fertility,&nbsp;but...
</span><br/>
<span class="not-covered" title="0 out of 11 forms covered">
056&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&lt;&nbsp;(+&nbsp;(get-int&nbsp;cell&nbsp;:deer)(get-int&nbsp;cell&nbsp;:sheep))&nbsp;6)
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
057&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&lt;&nbsp;(get-int&nbsp;cell&nbsp;:altitude)&nbsp;treeline))
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
058&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(merge&nbsp;cell&nbsp;{:state&nbsp;:scrub})))
</span><br/>
<span class="partial" title="1 out of 14 forms covered">
059&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[cell&nbsp;_]&nbsp;(cond&nbsp;(=&nbsp;(:state&nbsp;cell)&nbsp;:scrub)&nbsp;(merge&nbsp;cell&nbsp;{:state&nbsp;:forest})))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
060&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;Forest&nbsp;on&nbsp;fertile&nbsp;land&nbsp;grows&nbsp;to&nbsp;climax
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
061&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[cell&nbsp;_]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
062&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
063&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
064&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(=&nbsp;(:state&nbsp;cell)&nbsp;:forest)
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
065&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;&nbsp;(get-int&nbsp;cell&nbsp;:fertility)&nbsp;10))
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
066&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(merge&nbsp;cell&nbsp;{:state&nbsp;:climax})))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
067&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;Climax&nbsp;forest&nbsp;occasionally&nbsp;catches&nbsp;fire&nbsp;(e.g.&nbsp;lightning&nbsp;strikes)
</span><br/>
<span class="partial" title="1 out of 23 forms covered">
068&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[cell&nbsp;_]&nbsp;(cond&nbsp;(and&nbsp;(=&nbsp;(:state&nbsp;cell)&nbsp;:climax)(&lt;&nbsp;(rand&nbsp;lightning-probability)&nbsp;1))&nbsp;(merge&nbsp;cell&nbsp;{:state&nbsp;:fire})))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
069&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;Climax&nbsp;forest&nbsp;neighbouring&nbsp;fires&nbsp;is&nbsp;likely&nbsp;to&nbsp;catch&nbsp;fire
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
070&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[cell&nbsp;world]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
071&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond
</span><br/>
<span class="not-covered" title="0 out of 14 forms covered">
072&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and&nbsp;(=&nbsp;(:state&nbsp;cell)&nbsp;:climax)
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
073&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&lt;&nbsp;(rand&nbsp;3)&nbsp;1)
</span><br/>
<span class="not-covered" title="0 out of 14 forms covered">
074&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(not&nbsp;(empty?&nbsp;(get-neighbours-with-state&nbsp;world&nbsp;(:x&nbsp;cell)&nbsp;(:y&nbsp;cell)&nbsp;1&nbsp;:fire))))
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
075&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(merge&nbsp;cell&nbsp;{:state&nbsp;:fire})))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
076&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;After&nbsp;fire&nbsp;we&nbsp;get&nbsp;waste
</span><br/>
<span class="partial" title="1 out of 14 forms covered">
077&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[cell&nbsp;_]&nbsp;(cond&nbsp;(=&nbsp;(:state&nbsp;cell)&nbsp;:fire)&nbsp;(merge&nbsp;cell&nbsp;{:state&nbsp;:waste})))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
078&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;And&nbsp;after&nbsp;waste&nbsp;we&nbsp;get&nbsp;pioneer&nbsp;species;&nbsp;if&nbsp;there&#x27;s&nbsp;a&nbsp;woodland&nbsp;seed
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
079&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;source,&nbsp;it&#x27;s&nbsp;going&nbsp;to&nbsp;be&nbsp;heath,&nbsp;otherwise&nbsp;grassland.
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
080&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[cell&nbsp;world]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
081&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond
</span><br/>
<span class="not-covered" title="0 out of 10 forms covered">
082&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(and&nbsp;(=&nbsp;(:state&nbsp;cell)&nbsp;:waste)
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
083&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(not
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
084&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(empty?
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
085&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(flatten
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
086&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(list
</span><br/>
<span class="not-covered" title="0 out of 11 forms covered">
087&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(get-neighbours-with-state&nbsp;world&nbsp;(:x&nbsp;cell)&nbsp;(:y&nbsp;cell)&nbsp;1&nbsp;:scrub)
</span><br/>
<span class="not-covered" title="0 out of 11 forms covered">
088&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(get-neighbours-with-state&nbsp;world&nbsp;(:x&nbsp;cell)&nbsp;(:y&nbsp;cell)&nbsp;1&nbsp;:forest)
</span><br/>
<span class="not-covered" title="0 out of 11 forms covered">
089&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(get-neighbours-with-state&nbsp;world&nbsp;(:x&nbsp;cell)&nbsp;(:y&nbsp;cell)&nbsp;1&nbsp;:climax))))))
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
090&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(merge&nbsp;cell&nbsp;{:state&nbsp;:heath})))
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
091&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[cell&nbsp;_]
</span><br/>
<span class="not-covered" title="0 out of 7 forms covered">
092&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond&nbsp;(=&nbsp;(:state&nbsp;cell)&nbsp;:waste)
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
093&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(merge&nbsp;cell&nbsp;{:state&nbsp;:grassland})))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
094&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;Forest&nbsp;increases&nbsp;soil&nbsp;fertility
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
095&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[cell&nbsp;_]
</span><br/>
<span class="not-covered" title="0 out of 8 forms covered">
096&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond&nbsp;(member?&nbsp;(:state&nbsp;cell)&nbsp;&#x27;(:forest&nbsp;:climax))
</span><br/>
<span class="not-covered" title="0 out of 11 forms covered">
097&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(merge&nbsp;cell&nbsp;{:fertility&nbsp;(+&nbsp;(get-int&nbsp;cell&nbsp;:fertility)&nbsp;1)})))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
098&nbsp;&nbsp;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
099&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
100&nbsp;&nbsp;;;&nbsp;rules&nbsp;describing&nbsp;herbivore&nbsp;behaviour
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
101&nbsp;&nbsp;(def&nbsp;herbivore-rules
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
102&nbsp;&nbsp;&nbsp;&nbsp;(list
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
103&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;if&nbsp;there&nbsp;are&nbsp;too&nbsp;many&nbsp;deer&nbsp;for&nbsp;the&nbsp;fertility&nbsp;of&nbsp;the&nbsp;area&nbsp;to&nbsp;sustain,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
104&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;some&nbsp;die&nbsp;or&nbsp;move&nbsp;on.
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
105&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[cell&nbsp;_]
</span><br/>
<span class="not-covered" title="0 out of 11 forms covered">
106&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond&nbsp;(&gt;&nbsp;(get-int&nbsp;cell&nbsp;:deer)&nbsp;(get-int&nbsp;cell&nbsp;:fertility))
</span><br/>
<span class="not-covered" title="0 out of 9 forms covered">
107&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(merge&nbsp;cell&nbsp;{:deer&nbsp;(get-int&nbsp;cell&nbsp;:fertility)})))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
108&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;deer&nbsp;arrive&nbsp;occasionally&nbsp;at&nbsp;the&nbsp;edge&nbsp;of&nbsp;the&nbsp;map.
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
109&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[cell&nbsp;world]
</span><br/>
<span class="not-covered" title="0 out of 23 forms covered">
110&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond&nbsp;(and&nbsp;(&lt;&nbsp;(count&nbsp;(get-neighbours&nbsp;world&nbsp;cell))&nbsp;8)
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
111&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&lt;&nbsp;(rand&nbsp;50)&nbsp;1)
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
112&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;&nbsp;(get-int&nbsp;cell&nbsp;:fertility)&nbsp;0)
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
113&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(=&nbsp;(get-int&nbsp;cell&nbsp;:deer)&nbsp;0))
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
114&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(merge&nbsp;cell&nbsp;{:deer&nbsp;2})))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
115&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;deer&nbsp;gradually&nbsp;spread&nbsp;through&nbsp;the&nbsp;world&nbsp;by&nbsp;breeding&nbsp;or&nbsp;migrating.
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
116&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[cell&nbsp;world]
</span><br/>
<span class="not-covered" title="0 out of 15 forms covered">
117&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[n&nbsp;(apply&nbsp;+&nbsp;(map&nbsp;#(get-int&nbsp;%&nbsp;:deer)&nbsp;(get-neighbours&nbsp;world&nbsp;cell)))]
</span><br/>
<span class="not-covered" title="0 out of 12 forms covered">
118&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond&nbsp;(and
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
119&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;&nbsp;(get-int&nbsp;cell&nbsp;:fertility)&nbsp;0)
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
120&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(=&nbsp;(get-int&nbsp;cell&nbsp;:deer)&nbsp;0)
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
121&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;=&nbsp;n&nbsp;2))
</span><br/>
<span class="not-covered" title="0 out of 9 forms covered">
122&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(merge&nbsp;cell&nbsp;{:deer&nbsp;(int&nbsp;(&#x2F;&nbsp;n&nbsp;2))}))))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
123&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;deer&nbsp;breed.
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
124&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[cell&nbsp;_]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
125&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
126&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;=&nbsp;(get-int&nbsp;cell&nbsp;:deer)&nbsp;2)
</span><br/>
<span class="not-covered" title="0 out of 11 forms covered">
127&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(merge&nbsp;cell&nbsp;{:deer&nbsp;(int&nbsp;(*&nbsp;(:deer&nbsp;cell)&nbsp;2))})))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
128&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
129&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;rules&nbsp;describing&nbsp;predator&nbsp;behaviour
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
130&nbsp;&nbsp;&nbsp;&nbsp;(def&nbsp;predator-rules
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
131&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(list
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
132&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;wolves&nbsp;eat&nbsp;deer
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
133&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[cell&nbsp;_]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
134&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
135&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;=&nbsp;(get-int&nbsp;cell&nbsp;:wolves)&nbsp;1)
</span><br/>
<span class="not-covered" title="0 out of 16 forms covered">
136&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(merge&nbsp;cell&nbsp;{:deer&nbsp;(max&nbsp;0&nbsp;(-&nbsp;(get-int&nbsp;cell&nbsp;:deer)&nbsp;(get-int&nbsp;cell&nbsp;:wolves)))})))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
137&nbsp;&nbsp;;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;not&nbsp;more&nbsp;than&nbsp;eight&nbsp;wolves&nbsp;in&nbsp;a&nbsp;pack,&nbsp;for&nbsp;now&nbsp;(hack&nbsp;because&nbsp;wolves&nbsp;are&nbsp;not&nbsp;dying)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
138&nbsp;&nbsp;;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[cell&nbsp;world]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
139&nbsp;&nbsp;;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond&nbsp;(&gt;&nbsp;(get-int&nbsp;cell&nbsp;:wolves)&nbsp;8)&nbsp;(merge&nbsp;cell&nbsp;{:wolves&nbsp;8})))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
140&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;if&nbsp;there&nbsp;are&nbsp;not&nbsp;enough&nbsp;deer&nbsp;to&nbsp;sustain&nbsp;the&nbsp;get-int&nbsp;of&nbsp;wolves,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
141&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;some&nbsp;wolves&nbsp;die&nbsp;or&nbsp;move&nbsp;on.&nbsp;(doesn&#x27;t&nbsp;seem&nbsp;to&nbsp;be&nbsp;working?)
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
142&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[cell&nbsp;_]
</span><br/>
<span class="not-covered" title="0 out of 11 forms covered">
143&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond&nbsp;(&gt;&nbsp;(get-int&nbsp;cell&nbsp;:wolves)&nbsp;(get-int&nbsp;cell&nbsp;:deer))
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
144&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(merge&nbsp;cell&nbsp;{:wolves&nbsp;0})))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
145&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;wolves&nbsp;arrive&nbsp;occasionally&nbsp;at&nbsp;the&nbsp;edge&nbsp;of&nbsp;the&nbsp;map.
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
146&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[cell&nbsp;world]
</span><br/>
<span class="not-covered" title="0 out of 23 forms covered">
147&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond&nbsp;(and&nbsp;(&lt;&nbsp;(count&nbsp;(get-neighbours&nbsp;world&nbsp;cell))&nbsp;8)
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
148&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&lt;&nbsp;(rand&nbsp;50)&nbsp;1)
</span><br/>
<span class="not-covered" title="0 out of 7 forms covered">
149&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(not&nbsp;(=&nbsp;(:state&nbsp;cell)&nbsp;:water))
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
150&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(=&nbsp;(get-int&nbsp;cell&nbsp;:wolves)&nbsp;0))
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
151&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(merge&nbsp;cell&nbsp;{:wolves&nbsp;2})))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
152&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;wolves&nbsp;gradually&nbsp;spread&nbsp;through&nbsp;the&nbsp;world&nbsp;by&nbsp;breeding&nbsp;or&nbsp;migrating.
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
153&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[cell&nbsp;world]
</span><br/>
<span class="not-covered" title="0 out of 15 forms covered">
154&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[n&nbsp;(apply&nbsp;+&nbsp;(map&nbsp;#(get-int&nbsp;%&nbsp;:wolves)&nbsp;(get-neighbours&nbsp;world&nbsp;cell)))]
</span><br/>
<span class="not-covered" title="0 out of 12 forms covered">
155&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond&nbsp;(and
</span><br/>
<span class="not-covered" title="0 out of 7 forms covered">
156&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(not&nbsp;(=&nbsp;(:state&nbsp;cell)&nbsp;:water))
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
157&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(=&nbsp;(get-int&nbsp;cell&nbsp;:wolves)&nbsp;0)
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
158&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;=&nbsp;n&nbsp;2))
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
159&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(merge&nbsp;cell&nbsp;{:wolves&nbsp;2}))))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
160&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;wolves&nbsp;breed.
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
161&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[cell&nbsp;_]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
162&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
163&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&gt;=&nbsp;(get-int&nbsp;cell&nbsp;:wolves)&nbsp;2)
</span><br/>
<span class="not-covered" title="0 out of 11 forms covered">
164&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(merge&nbsp;cell&nbsp;{:wolves&nbsp;(int&nbsp;(*&nbsp;(:wolves&nbsp;cell)&nbsp;2))})))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
165&nbsp;&nbsp;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
166&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
167&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;rules&nbsp;which&nbsp;initialise&nbsp;the&nbsp;world
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
168&nbsp;&nbsp;&nbsp;&nbsp;(def&nbsp;init-rules
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
169&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(list
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
170&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;below&nbsp;the&nbsp;waterline,&nbsp;we&nbsp;have&nbsp;water.
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
171&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[cell&nbsp;_]
</span><br/>
<span class="not-covered" title="0 out of 23 forms covered">
172&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond&nbsp;(and&nbsp;(=&nbsp;(:state&nbsp;cell)&nbsp;:new)&nbsp;(&lt;&nbsp;(get-int&nbsp;cell&nbsp;:altitude)&nbsp;waterline))&nbsp;(merge&nbsp;cell&nbsp;{:state&nbsp;:water})))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
173&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;above&nbsp;the&nbsp;snowline,&nbsp;we&nbsp;have&nbsp;snow.
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
174&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[cell&nbsp;_]
</span><br/>
<span class="not-covered" title="0 out of 23 forms covered">
175&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond&nbsp;(and&nbsp;(=&nbsp;(:state&nbsp;cell)&nbsp;:new)&nbsp;(&gt;&nbsp;(get-int&nbsp;cell&nbsp;:altitude)&nbsp;snowline))&nbsp;(merge&nbsp;cell&nbsp;{:state&nbsp;:snow})))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
176&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;in&nbsp;between,&nbsp;we&nbsp;have&nbsp;a&nbsp;wasteland.
</span><br/>
<span class="partial" title="1 out of 14 forms covered">
177&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(fn&nbsp;[cell&nbsp;_]&nbsp;(cond&nbsp;(=&nbsp;(:state&nbsp;cell)&nbsp;:new)&nbsp;(merge&nbsp;cell&nbsp;{:state&nbsp;:grassland})))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
178&nbsp;&nbsp;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
179&nbsp;&nbsp;
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
180&nbsp;&nbsp;(def&nbsp;natural-rules&nbsp;(flatten
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
181&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(list
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
182&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vegetation-rules
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
183&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;herbivore-rules
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
184&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;predator-rules)))
</span><br/>
</body>
</html>

View file

@ -0,0 +1,302 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="../coverage.css"/> <title> mw_engine/render.clj </title>
</head>
<body>
<span class="covered" title="1 out of 1 forms covered">
001&nbsp;&nbsp;(ns&nbsp;mw-engine.render
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
002&nbsp;&nbsp;&nbsp;&nbsp;&quot;Render&nbsp;a&nbsp;world&nbsp;as&nbsp;HTML.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
003&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
004&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Adapted&nbsp;(simplified)&nbsp;from&nbsp;mw-ui.render-world;&nbsp;this&nbsp;is&nbsp;for&nbsp;visualisation,&nbsp;not
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
005&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;interaction.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
006&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;TODO:&nbsp;but&nbsp;possibly&nbsp;it&nbsp;would&nbsp;be&nbsp;better&nbsp;if&nbsp;there&nbsp;is&nbsp;to&nbsp;be&nbsp;a&nbsp;newer&nbsp;version&nbsp;of
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
007&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;mw-ui,&nbsp;to&nbsp;base&nbsp;it&nbsp;on&nbsp;this.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
008&nbsp;&nbsp;&nbsp;&nbsp;(:require&nbsp;[hiccup2.core&nbsp;:refer&nbsp;[html]])
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
009&nbsp;&nbsp;&nbsp;&nbsp;)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
010&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
011&nbsp;&nbsp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
012&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
013&nbsp;&nbsp;;;;;&nbsp;This&nbsp;program&nbsp;is&nbsp;free&nbsp;software;&nbsp;you&nbsp;can&nbsp;redistribute&nbsp;it&nbsp;and&#x2F;or
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
014&nbsp;&nbsp;;;;;&nbsp;modify&nbsp;it&nbsp;under&nbsp;the&nbsp;terms&nbsp;of&nbsp;the&nbsp;GNU&nbsp;General&nbsp;Public&nbsp;License
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
015&nbsp;&nbsp;;;;;&nbsp;as&nbsp;published&nbsp;by&nbsp;the&nbsp;Free&nbsp;Software&nbsp;Foundation;&nbsp;either&nbsp;version&nbsp;2
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
016&nbsp;&nbsp;;;;;&nbsp;of&nbsp;the&nbsp;License,&nbsp;or&nbsp;(at&nbsp;your&nbsp;option)&nbsp;any&nbsp;later&nbsp;version.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
017&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
018&nbsp;&nbsp;;;;;&nbsp;This&nbsp;program&nbsp;is&nbsp;distributed&nbsp;in&nbsp;the&nbsp;hope&nbsp;that&nbsp;it&nbsp;will&nbsp;be&nbsp;useful,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
019&nbsp;&nbsp;;;;;&nbsp;but&nbsp;WITHOUT&nbsp;ANY&nbsp;WARRANTY;&nbsp;without&nbsp;even&nbsp;the&nbsp;implied&nbsp;warranty&nbsp;of
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
020&nbsp;&nbsp;;;;;&nbsp;MERCHANTABILITY&nbsp;or&nbsp;FITNESS&nbsp;FOR&nbsp;A&nbsp;PARTICULAR&nbsp;PURPOSE.&nbsp;&nbsp;See&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
021&nbsp;&nbsp;;;;;&nbsp;GNU&nbsp;General&nbsp;Public&nbsp;License&nbsp;for&nbsp;more&nbsp;details.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
022&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
023&nbsp;&nbsp;;;;;&nbsp;You&nbsp;should&nbsp;have&nbsp;received&nbsp;a&nbsp;copy&nbsp;of&nbsp;the&nbsp;GNU&nbsp;General&nbsp;Public&nbsp;License
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
024&nbsp;&nbsp;;;;;&nbsp;along&nbsp;with&nbsp;this&nbsp;program;&nbsp;if&nbsp;not,&nbsp;write&nbsp;to&nbsp;the&nbsp;Free&nbsp;Software
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
025&nbsp;&nbsp;;;;;&nbsp;Foundation,&nbsp;Inc.,&nbsp;51&nbsp;Franklin&nbsp;Street,&nbsp;Fifth&nbsp;Floor,&nbsp;Boston,&nbsp;MA&nbsp;&nbsp;02110-1301,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
026&nbsp;&nbsp;;;;;&nbsp;USA.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
027&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
028&nbsp;&nbsp;;;;;&nbsp;Copyright&nbsp;(C)&nbsp;2024&nbsp;Simon&nbsp;Brooke
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
029&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
030&nbsp;&nbsp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
031&nbsp;&nbsp;
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
032&nbsp;&nbsp;(def&nbsp;^:dynamic&nbsp;*state-images-relative-path*&nbsp;&quot;img&#x2F;tiles&#x2F;&quot;)
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
033&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
034&nbsp;&nbsp;(defn&nbsp;format-css-class
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
035&nbsp;&nbsp;&nbsp;&nbsp;&quot;Format&nbsp;this&nbsp;statekey,&nbsp;assumed&nbsp;to&nbsp;be&nbsp;a&nbsp;keyword&nbsp;indicating&nbsp;a&nbsp;state&nbsp;in&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
036&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;world,&nbsp;into&nbsp;a&nbsp;CSS&nbsp;class&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
037&nbsp;&nbsp;&nbsp;&nbsp;[statekey]
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
038&nbsp;&nbsp;&nbsp;&nbsp;(name&nbsp;statekey))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
039&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
040&nbsp;&nbsp;(defn&nbsp;format-image-path
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
041&nbsp;&nbsp;&nbsp;&nbsp;&quot;Render&nbsp;this&nbsp;statekey,&nbsp;assumed&nbsp;to&nbsp;be&nbsp;a&nbsp;keyword&nbsp;indicating&nbsp;a&nbsp;state&nbsp;in&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
042&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;world,&nbsp;into&nbsp;a&nbsp;path&nbsp;which&nbsp;should&nbsp;recover&nbsp;the&nbsp;corresponding&nbsp;image&nbsp;file.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
043&nbsp;&nbsp;&nbsp;&nbsp;[statekey]
</span><br/>
<span class="not-covered" title="0 out of 7 forms covered">
044&nbsp;&nbsp;&nbsp;&nbsp;(format&nbsp;&quot;%s%s.png&quot;&nbsp;*state-images-relative-path*&nbsp;(format-css-class&nbsp;statekey)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
045&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
046&nbsp;&nbsp;(defn&nbsp;format-mouseover&nbsp;[cell]
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
047&nbsp;&nbsp;&nbsp;&nbsp;(str&nbsp;cell))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
048&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
049&nbsp;&nbsp;(defn&nbsp;render-cell
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
050&nbsp;&nbsp;&nbsp;&nbsp;&quot;Render&nbsp;this&nbsp;world&nbsp;cell&nbsp;as&nbsp;a&nbsp;Hiccup&nbsp;table&nbsp;cell.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
051&nbsp;&nbsp;&nbsp;&nbsp;[cell]
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
052&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[state&nbsp;(:state&nbsp;cell)]
</span><br/>
<span class="not-covered" title="0 out of 11 forms covered">
053&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[:td&nbsp;{:class&nbsp;(format-css-class&nbsp;state)&nbsp;:title&nbsp;(format-mouseover&nbsp;cell)}
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
054&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span><br/>
<span class="not-covered" title="0 out of 11 forms covered">
055&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[:img&nbsp;{:alt&nbsp;(:state&nbsp;cell)&nbsp;:src&nbsp;(format-image-path&nbsp;state)}]]))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
056&nbsp;&nbsp;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
057&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
058&nbsp;&nbsp;(defn&nbsp;render-world-row
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
059&nbsp;&nbsp;&nbsp;&nbsp;&quot;Render&nbsp;this&nbsp;world&nbsp;row&nbsp;as&nbsp;a&nbsp;Hiccup&nbsp;table&nbsp;row.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
060&nbsp;&nbsp;&nbsp;&nbsp;[row]
</span><br/>
<span class="not-covered" title="0 out of 10 forms covered">
061&nbsp;&nbsp;&nbsp;&nbsp;(apply&nbsp;vector&nbsp;(cons&nbsp;:tr&nbsp;(map&nbsp;render-cell&nbsp;row))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
062&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
063&nbsp;&nbsp;(defn&nbsp;render-world-table
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
064&nbsp;&nbsp;&nbsp;&nbsp;&quot;Render&nbsp;this&nbsp;`world`&nbsp;as&nbsp;a&nbsp;complete&nbsp;HTML&nbsp;table&nbsp;in&nbsp;a&nbsp;DIV.&nbsp;If&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
065&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`state-images-relative-path`&nbsp;is&nbsp;passed,&nbsp;use&nbsp;that&nbsp;to&nbsp;override&nbsp;the&nbsp;default&nbsp;path.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
066&nbsp;&nbsp;&nbsp;&nbsp;([world]&nbsp;
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
067&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[:div&nbsp;{:class&nbsp;&quot;world&quot;}
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
068&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(apply&nbsp;vector
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
069&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cons&nbsp;:table
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
070&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map&nbsp;render-world-row&nbsp;world)))
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
071&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[:p
</span><br/>
<span class="not-covered" title="0 out of 10 forms covered">
072&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(str&nbsp;&quot;Generation&nbsp;&quot;&nbsp;(:generation&nbsp;(first&nbsp;(flatten&nbsp;world))))]])
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
073&nbsp;&nbsp;&nbsp;&nbsp;([world&nbsp;state-images-relative-path]
</span><br/>
<span class="not-covered" title="0 out of 10 forms covered">
074&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(binding&nbsp;[*state-images-relative-path*&nbsp;state-images-relative-path]
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
075&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(render-world-table&nbsp;world))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
076&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
077&nbsp;&nbsp;(defn&nbsp;render-world-page
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
078&nbsp;&nbsp;&nbsp;&nbsp;([world]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
079&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[:html
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
080&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[:head
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
081&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[:title&nbsp;&quot;Rendered&nbsp;world&quot;]
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
082&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[:style&nbsp;&quot;div.world&nbsp;table,&nbsp;div.world&nbsp;table&nbsp;tr&nbsp;td&nbsp;{
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
083&nbsp;&nbsp; padding:&nbsp;0;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
084&nbsp;&nbsp; margin:&nbsp;0;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
085&nbsp;&nbsp; border-collapse:&nbsp;collapse;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
086&nbsp;&nbsp; border:&nbsp;none;}&quot;]]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
087&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[:body
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
088&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(render-world-table&nbsp;world)]])
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
089&nbsp;&nbsp;&nbsp;&nbsp;([world&nbsp;state-images-relative-path]
</span><br/>
<span class="not-covered" title="0 out of 10 forms covered">
090&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(binding&nbsp;[*state-images-relative-path*&nbsp;state-images-relative-path]
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
091&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(render-world-page&nbsp;world))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
092&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
093&nbsp;&nbsp;(defn&nbsp;world-&gt;html-file
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
094&nbsp;&nbsp;&nbsp;&nbsp;([world&nbsp;output-path]
</span><br/>
<span class="not-covered" title="0 out of 18 forms covered">
095&nbsp;&nbsp;&nbsp;&nbsp;(spit&nbsp;output-path&nbsp;(str&nbsp;(html&nbsp;(render-world-page&nbsp;world)))))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
096&nbsp;&nbsp;&nbsp;&nbsp;([world&nbsp;output-path&nbsp;state-images-relative-path]
</span><br/>
<span class="not-covered" title="0 out of 10 forms covered">
097&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(binding&nbsp;[*state-images-relative-path*&nbsp;state-images-relative-path]
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
098&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(world-&gt;html-file&nbsp;world&nbsp;output-path))))
</span><br/>
</body>
</html>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,341 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="../coverage.css"/> <title> mw_engine/world.clj </title>
</head>
<body>
<span class="covered" title="1 out of 1 forms covered">
001&nbsp;&nbsp;(ns&nbsp;^{:doc&nbsp;&quot;Functions&nbsp;to&nbsp;create&nbsp;and&nbsp;to&nbsp;print&nbsp;two&nbsp;dimensional&nbsp;cellular&nbsp;automata.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
002&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
003&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Nothing&nbsp;in&nbsp;this&nbsp;namespace&nbsp;should&nbsp;determine&nbsp;what&nbsp;states&nbsp;are&nbsp;possible&nbsp;within
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
004&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;the&nbsp;automaton,&nbsp;except&nbsp;for&nbsp;the&nbsp;initial&nbsp;state,&nbsp;:new.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
005&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
006&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;A&nbsp;cell&nbsp;is&nbsp;a&nbsp;map&nbsp;containing&nbsp;at&nbsp;least&nbsp;values&nbsp;for&nbsp;the&nbsp;keys&nbsp;`:x`,&nbsp;`:y`,&nbsp;and&nbsp;`:state`.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
007&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
008&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;A&nbsp;world&nbsp;is&nbsp;a&nbsp;two&nbsp;dimensional&nbsp;matrix&nbsp;(sequence&nbsp;of&nbsp;sequences)&nbsp;of&nbsp;cells,&nbsp;such
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
009&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;that&nbsp;every&nbsp;cell&#x27;s&nbsp;`:x`&nbsp;and&nbsp;`:y`&nbsp;properties&nbsp;reflect&nbsp;its&nbsp;place&nbsp;in&nbsp;the&nbsp;matrix.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
010&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:author&nbsp;&quot;Simon&nbsp;Brooke&quot;}
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
011&nbsp;&nbsp;&nbsp;mw-engine.world
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
012&nbsp;&nbsp;&nbsp;&nbsp;(:require&nbsp;[clojure.string&nbsp;:as&nbsp;string]
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
013&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[mw-engine.utils&nbsp;:refer&nbsp;[population]]))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
014&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
015&nbsp;&nbsp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
016&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
017&nbsp;&nbsp;;;;;&nbsp;mw-engine:&nbsp;the&nbsp;state&#x2F;transition&nbsp;engine&nbsp;of&nbsp;MicroWorld.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
018&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
019&nbsp;&nbsp;;;;;&nbsp;This&nbsp;program&nbsp;is&nbsp;free&nbsp;software;&nbsp;you&nbsp;can&nbsp;redistribute&nbsp;it&nbsp;and&#x2F;or
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
020&nbsp;&nbsp;;;;;&nbsp;modify&nbsp;it&nbsp;under&nbsp;the&nbsp;terms&nbsp;of&nbsp;the&nbsp;GNU&nbsp;General&nbsp;Public&nbsp;License
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
021&nbsp;&nbsp;;;;;&nbsp;as&nbsp;published&nbsp;by&nbsp;the&nbsp;Free&nbsp;Software&nbsp;Foundation;&nbsp;either&nbsp;version&nbsp;2
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
022&nbsp;&nbsp;;;;;&nbsp;of&nbsp;the&nbsp;License,&nbsp;or&nbsp;(at&nbsp;your&nbsp;option)&nbsp;any&nbsp;later&nbsp;version.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
023&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
024&nbsp;&nbsp;;;;;&nbsp;This&nbsp;program&nbsp;is&nbsp;distributed&nbsp;in&nbsp;the&nbsp;hope&nbsp;that&nbsp;it&nbsp;will&nbsp;be&nbsp;useful,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
025&nbsp;&nbsp;;;;;&nbsp;but&nbsp;WITHOUT&nbsp;ANY&nbsp;WARRANTY;&nbsp;without&nbsp;even&nbsp;the&nbsp;implied&nbsp;warranty&nbsp;of
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
026&nbsp;&nbsp;;;;;&nbsp;MERCHANTABILITY&nbsp;or&nbsp;FITNESS&nbsp;FOR&nbsp;A&nbsp;PARTICULAR&nbsp;PURPOSE.&nbsp;&nbsp;See&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
027&nbsp;&nbsp;;;;;&nbsp;GNU&nbsp;General&nbsp;Public&nbsp;License&nbsp;for&nbsp;more&nbsp;details.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
028&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
029&nbsp;&nbsp;;;;;&nbsp;You&nbsp;should&nbsp;have&nbsp;received&nbsp;a&nbsp;copy&nbsp;of&nbsp;the&nbsp;GNU&nbsp;General&nbsp;Public&nbsp;License
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
030&nbsp;&nbsp;;;;;&nbsp;along&nbsp;with&nbsp;this&nbsp;program;&nbsp;if&nbsp;not,&nbsp;write&nbsp;to&nbsp;the&nbsp;Free&nbsp;Software
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
031&nbsp;&nbsp;;;;;&nbsp;Foundation,&nbsp;Inc.,&nbsp;51&nbsp;Franklin&nbsp;Street,&nbsp;Fifth&nbsp;Floor,&nbsp;Boston,&nbsp;MA&nbsp;&nbsp;02110-1301,
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
032&nbsp;&nbsp;;;;;&nbsp;USA.
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
033&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
034&nbsp;&nbsp;;;;;&nbsp;Copyright&nbsp;(C)&nbsp;2014&nbsp;Simon&nbsp;Brooke
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
035&nbsp;&nbsp;;;;;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
036&nbsp;&nbsp;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
037&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
038&nbsp;&nbsp;(defn&nbsp;cell?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
039&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;`true`&nbsp;if&nbsp;`obj`&nbsp;is&nbsp;a&nbsp;cell,&nbsp;as&nbsp;understood&nbsp;by&nbsp;MicroWorld,&nbsp;else&nbsp;`false`.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
040&nbsp;&nbsp;&nbsp;&nbsp;[obj]
</span><br/>
<span class="not-covered" title="0 out of 16 forms covered">
041&nbsp;&nbsp;&nbsp;&nbsp;(and&nbsp;(map?&nbsp;obj)&nbsp;;;&nbsp;it&#x27;s&nbsp;a&nbsp;map...
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
042&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;TODO:&nbsp;it&#x27;s&nbsp;worth&nbsp;checking&nbsp;(and&nbsp;this&nbsp;does&nbsp;not)&nbsp;that&nbsp;cells&nbsp;have&nbsp;the
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
043&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;;&nbsp;right&nbsp;co-ordinates!
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
044&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(pos-int?&nbsp;(:x&nbsp;obj))&nbsp;;;&nbsp;with&nbsp;an&nbsp;x&nbsp;co-ordinate...
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
045&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(pos-int?&nbsp;(:y&nbsp;obj))&nbsp;;;&nbsp;and&nbsp;a&nbsp;y&nbsp;co-ordinate...
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
046&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(keyword?&nbsp;(:state&nbsp;obj))))&nbsp;;;&nbsp;and&nbsp;a&nbsp;state&nbsp;which&nbsp;is&nbsp;a&nbsp;keyword.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
047&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
048&nbsp;&nbsp;(defn&nbsp;world?
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
049&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;`true`&nbsp;if&nbsp;`obj`&nbsp;is&nbsp;a&nbsp;world,&nbsp;as&nbsp;understood&nbsp;by&nbsp;MicroWorld,&nbsp;else&nbsp;`false`.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
050&nbsp;&nbsp;&nbsp;&nbsp;[obj]
</span><br/>
<span class="not-covered" title="0 out of 16 forms covered">
051&nbsp;&nbsp;&nbsp;&nbsp;(and&nbsp;(coll?&nbsp;obj)&nbsp;;;&nbsp;it&#x27;s&nbsp;a&nbsp;collection...
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
052&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(every?&nbsp;coll?&nbsp;obj)&nbsp;;;&nbsp;of&nbsp;collections...
</span><br/>
<span class="not-covered" title="0 out of 9 forms covered">
053&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(=&nbsp;1&nbsp;(count&nbsp;(set&nbsp;(map&nbsp;count&nbsp;obj))))&nbsp;;;&nbsp;all&nbsp;of&nbsp;which&nbsp;are&nbsp;the&nbsp;same&nbsp;length...
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
054&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(every?&nbsp;cell?&nbsp;(flatten&nbsp;obj))))&nbsp;;;&nbsp;and&nbsp;every&nbsp;element&nbsp;of&nbsp;each&nbsp;of&nbsp;those&nbsp;is&nbsp;a&nbsp;cell.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
055&nbsp;&nbsp;
</span><br/>
<span class="covered" title="30 out of 30 forms covered">
056&nbsp;&nbsp;(defmacro&nbsp;make-cell
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
057&nbsp;&nbsp;&nbsp;&nbsp;&quot;Create&nbsp;a&nbsp;minimal&nbsp;default&nbsp;cell&nbsp;at&nbsp;x,&nbsp;y
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
058&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
059&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`x`&nbsp;the&nbsp;x&nbsp;coordinate&nbsp;at&nbsp;which&nbsp;this&nbsp;cell&nbsp;is&nbsp;created;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
060&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`y`&nbsp;the&nbsp;y&nbsp;coordinate&nbsp;at&nbsp;which&nbsp;this&nbsp;cell&nbsp;is&nbsp;created.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
061&nbsp;&nbsp;&nbsp;&nbsp;[x&nbsp;y]
</span><br/>
<span class="covered" title="2 out of 2 forms covered">
062&nbsp;&nbsp;&nbsp;&nbsp;`{:x&nbsp;~x&nbsp;:y&nbsp;~y&nbsp;:state&nbsp;:new})
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
063&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
064&nbsp;&nbsp;(defn&nbsp;make-world
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
065&nbsp;&nbsp;&nbsp;&nbsp;&quot;Make&nbsp;a&nbsp;world&nbsp;width&nbsp;cells&nbsp;from&nbsp;east&nbsp;to&nbsp;west,&nbsp;and&nbsp;height&nbsp;cells&nbsp;from&nbsp;north&nbsp;to
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
066&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;south.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
067&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
068&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`width`&nbsp;a&nbsp;natural&nbsp;number&nbsp;representing&nbsp;the&nbsp;width&nbsp;of&nbsp;the&nbsp;matrix&nbsp;to&nbsp;be&nbsp;created;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
069&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`height`&nbsp;a&nbsp;natural&nbsp;number&nbsp;representing&nbsp;the&nbsp;height&nbsp;of&nbsp;the&nbsp;matrix&nbsp;to&nbsp;be&nbsp;created.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
070&nbsp;&nbsp;&nbsp;&nbsp;[width&nbsp;height]
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
071&nbsp;&nbsp;&nbsp;&nbsp;(apply&nbsp;vector
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
072&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map&nbsp;(fn&nbsp;[h]
</span><br/>
<span class="covered" title="16 out of 16 forms covered">
073&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(apply&nbsp;vector&nbsp;(map&nbsp;#(make-cell&nbsp;%&nbsp;h)&nbsp;(range&nbsp;width))))
</span><br/>
<span class="covered" title="3 out of 3 forms covered">
074&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(range&nbsp;height))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
075&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
076&nbsp;&nbsp;(defn&nbsp;truncate-state
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
077&nbsp;&nbsp;&nbsp;&nbsp;&quot;Truncate&nbsp;the&nbsp;print&nbsp;name&nbsp;of&nbsp;the&nbsp;state&nbsp;of&nbsp;this&nbsp;cell&nbsp;to&nbsp;at&nbsp;most&nbsp;limit&nbsp;characters.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
078&nbsp;&nbsp;&nbsp;&nbsp;[cell&nbsp;limit]
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
079&nbsp;&nbsp;&nbsp;&nbsp;(let&nbsp;[s&nbsp;(:state&nbsp;cell)]
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
080&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(try
</span><br/>
<span class="not-covered" title="0 out of 15 forms covered">
081&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond&nbsp;(&gt;&nbsp;(count&nbsp;(str&nbsp;s))&nbsp;limit)&nbsp;(subs&nbsp;(name&nbsp;s)&nbsp;0&nbsp;limit)
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
082&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:else&nbsp;s)
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
083&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(catch&nbsp;Exception&nbsp;any&nbsp;
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
084&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(throw&nbsp;(ex-info&nbsp;(.getMessage&nbsp;any)&nbsp;
</span><br/>
<span class="not-covered" title="0 out of 5 forms covered">
085&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{:cell&nbsp;cell
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
086&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:limit&nbsp;limit
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
087&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:exception-class&nbsp;(.getClass&nbsp;any)}))))))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
088&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
089&nbsp;&nbsp;(defn&nbsp;format-cell
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
090&nbsp;&nbsp;&nbsp;&nbsp;&quot;Return&nbsp;a&nbsp;formatted&nbsp;string&nbsp;summarising&nbsp;the&nbsp;current&nbsp;state&nbsp;of&nbsp;this&nbsp;cell.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
091&nbsp;&nbsp;&nbsp;&nbsp;[cell]
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
092&nbsp;&nbsp;&nbsp;&nbsp;(format&nbsp;&quot;%10s&quot;
</span><br/>
<span class="not-covered" title="0 out of 4 forms covered">
093&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(truncate-state&nbsp;cell&nbsp;10)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
094&nbsp;&nbsp;
</span><br/>
<span class="covered" title="1 out of 1 forms covered">
095&nbsp;&nbsp;(defn-&nbsp;format-world-row
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
096&nbsp;&nbsp;&nbsp;&nbsp;&quot;Format&nbsp;one&nbsp;row&nbsp;in&nbsp;the&nbsp;state&nbsp;of&nbsp;a&nbsp;world&nbsp;for&nbsp;printing.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
097&nbsp;&nbsp;&nbsp;&nbsp;[row]
</span><br/>
<span class="not-covered" title="0 out of 6 forms covered">
098&nbsp;&nbsp;&nbsp;&nbsp;(string&#x2F;join&nbsp;(map&nbsp;format-cell&nbsp;row)))
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
099&nbsp;&nbsp;
</span><br/>
<span class="partial" title="1 out of 2 forms covered">
100&nbsp;&nbsp;(defn&nbsp;print-world
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
101&nbsp;&nbsp;&nbsp;&nbsp;&quot;Print&nbsp;the&nbsp;current&nbsp;state&nbsp;of&nbsp;this&nbsp;world,&nbsp;and&nbsp;return&nbsp;nil.
</span><br/>
<span class="blank" title="0 out of 0 forms covered">
102&nbsp;&nbsp;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
103&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;`world`&nbsp;a&nbsp;world&nbsp;as&nbsp;defined&nbsp;above.&quot;
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
104&nbsp;&nbsp;&nbsp;&nbsp;[world]
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
105&nbsp;&nbsp;&nbsp;&nbsp;(println)
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
106&nbsp;&nbsp;&nbsp;&nbsp;(dorun
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
107&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(map
</span><br/>
<span class="not-covered" title="0 out of 2 forms covered">
108&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#(println
</span><br/>
<span class="not-covered" title="0 out of 3 forms covered">
109&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(format-world-row&nbsp;%))
</span><br/>
<span class="not-covered" title="0 out of 1 forms covered">
110&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;world))
</span><br/>
<span class="not-tracked" title="0 out of 0 forms covered">
111&nbsp;&nbsp;&nbsp;&nbsp;nil)
</span><br/>
</body>
</html>

551
docs/codox/css/default.css Normal file
View file

@ -0,0 +1,551 @@
body {
font-family: Helvetica, Arial, sans-serif;
font-size: 15px;
}
pre, code {
font-family: Monaco, DejaVu Sans Mono, Consolas, monospace;
font-size: 9pt;
margin: 15px 0;
}
h1 {
font-weight: normal;
font-size: 29px;
margin: 10px 0 2px 0;
padding: 0;
}
h2 {
font-weight: normal;
font-size: 25px;
}
h5.license {
margin: 9px 0 22px 0;
color: #555;
font-weight: normal;
font-size: 12px;
font-style: italic;
}
.document h1, .namespace-index h1 {
font-size: 32px;
margin-top: 12px;
}
#header, #content, .sidebar {
position: fixed;
}
#header {
top: 0;
left: 0;
right: 0;
height: 22px;
color: #f5f5f5;
padding: 5px 7px;
}
#content {
top: 32px;
right: 0;
bottom: 0;
overflow: auto;
background: #fff;
color: #333;
padding: 0 18px;
}
.sidebar {
position: fixed;
top: 32px;
bottom: 0;
overflow: auto;
}
.sidebar.primary {
background: #e2e2e2;
border-right: solid 1px #cccccc;
left: 0;
width: 250px;
}
.sidebar.secondary {
background: #f2f2f2;
border-right: solid 1px #d7d7d7;
left: 251px;
width: 200px;
}
#content.namespace-index, #content.document {
left: 251px;
}
#content.namespace-docs {
left: 452px;
}
#content.document {
padding-bottom: 10%;
}
#header {
background: #3f3f3f;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.4);
z-index: 100;
}
#header h1 {
margin: 0;
padding: 0;
font-size: 18px;
font-weight: lighter;
text-shadow: -1px -1px 0px #333;
}
#header h1 .project-version {
font-weight: normal;
}
.project-version {
padding-left: 0.15em;
}
#header a, .sidebar a {
display: block;
text-decoration: none;
}
#header a {
color: #f5f5f5;
}
.sidebar a {
color: #333;
}
#header h2 {
float: right;
font-size: 9pt;
font-weight: normal;
margin: 4px 3px;
padding: 0;
color: #bbb;
}
#header h2 a {
display: inline;
}
.sidebar h3 {
margin: 0;
padding: 10px 13px 0 13px;
font-size: 19px;
font-weight: lighter;
}
.sidebar h3 a {
color: #444;
}
.sidebar h3.no-link {
color: #636363;
}
.sidebar ul {
padding: 7px 0 6px 0;
margin: 0;
}
.sidebar ul.index-link {
padding-bottom: 4px;
}
.sidebar li {
display: block;
vertical-align: middle;
}
.sidebar li a, .sidebar li .no-link {
border-left: 3px solid transparent;
padding: 0 10px;
white-space: nowrap;
}
.sidebar li .no-link {
display: block;
color: #777;
font-style: italic;
}
.sidebar li .inner {
display: inline-block;
padding-top: 7px;
height: 24px;
}
.sidebar li a, .sidebar li .tree {
height: 31px;
}
.depth-1 .inner { padding-left: 2px; }
.depth-2 .inner { padding-left: 6px; }
.depth-3 .inner { padding-left: 20px; }
.depth-4 .inner { padding-left: 34px; }
.depth-5 .inner { padding-left: 48px; }
.depth-6 .inner { padding-left: 62px; }
.sidebar li .tree {
display: block;
float: left;
position: relative;
top: -10px;
margin: 0 4px 0 0;
padding: 0;
}
.sidebar li.depth-1 .tree {
display: none;
}
.sidebar li .tree .top, .sidebar li .tree .bottom {
display: block;
margin: 0;
padding: 0;
width: 7px;
}
.sidebar li .tree .top {
border-left: 1px solid #aaa;
border-bottom: 1px solid #aaa;
height: 19px;
}
.sidebar li .tree .bottom {
height: 22px;
}
.sidebar li.branch .tree .bottom {
border-left: 1px solid #aaa;
}
.sidebar.primary li.current a {
border-left: 3px solid #a33;
color: #a33;
}
.sidebar.secondary li.current a {
border-left: 3px solid #33a;
color: #33a;
}
.namespace-index h2 {
margin: 30px 0 0 0;
}
.namespace-index h3 {
font-size: 16px;
font-weight: bold;
margin-bottom: 0;
}
.namespace-index .topics {
padding-left: 30px;
margin: 11px 0 0 0;
}
.namespace-index .topics li {
padding: 5px 0;
}
.namespace-docs h3 {
font-size: 18px;
font-weight: bold;
}
.public h3 {
margin: 0;
float: left;
}
.usage {
clear: both;
}
.public {
margin: 0;
border-top: 1px solid #e0e0e0;
padding-top: 14px;
padding-bottom: 6px;
}
.public:last-child {
margin-bottom: 20%;
}
.members .public:last-child {
margin-bottom: 0;
}
.members {
margin: 15px 0;
}
.members h4 {
color: #555;
font-weight: normal;
font-variant: small-caps;
margin: 0 0 5px 0;
}
.members .inner {
padding-top: 5px;
padding-left: 12px;
margin-top: 2px;
margin-left: 7px;
border-left: 1px solid #bbb;
}
#content .members .inner h3 {
font-size: 12pt;
}
.members .public {
border-top: none;
margin-top: 0;
padding-top: 6px;
padding-bottom: 0;
}
.members .public:first-child {
padding-top: 0;
}
h4.type,
h4.dynamic,
h4.added,
h4.deprecated {
float: left;
margin: 3px 10px 15px 0;
font-size: 15px;
font-weight: bold;
font-variant: small-caps;
}
.public h4.type,
.public h4.dynamic,
.public h4.added,
.public h4.deprecated {
font-size: 13px;
font-weight: bold;
margin: 3px 0 0 10px;
}
.members h4.type,
.members h4.added,
.members h4.deprecated {
margin-top: 1px;
}
h4.type {
color: #717171;
}
h4.dynamic {
color: #9933aa;
}
h4.added {
color: #508820;
}
h4.deprecated {
color: #880000;
}
.namespace {
margin-bottom: 30px;
}
.namespace:last-child {
margin-bottom: 10%;
}
.index {
padding: 0;
font-size: 80%;
margin: 15px 0;
line-height: 16px;
}
.index * {
display: inline;
}
.index p {
padding-right: 3px;
}
.index li {
padding-right: 5px;
}
.index ul {
padding-left: 0;
}
.type-sig {
clear: both;
color: #088;
}
.type-sig pre {
padding-top: 10px;
margin: 0;
}
.usage code {
display: block;
color: #008;
margin: 2px 0;
}
.usage code:first-child {
padding-top: 10px;
}
p {
margin: 15px 0;
}
.public p:first-child, .public pre.plaintext {
margin-top: 12px;
}
.doc {
margin: 0 0 26px 0;
clear: both;
}
.public .doc {
margin: 0;
}
.namespace-index .doc {
margin-bottom: 20px;
}
.namespace-index .namespace .doc {
margin-bottom: 10px;
}
.markdown p, .markdown li, .markdown dt, .markdown dd, .markdown td {
line-height: 22px;
}
.markdown li {
padding: 2px 0;
}
.markdown h2 {
font-weight: normal;
font-size: 25px;
margin: 30px 0 10px 0;
}
.markdown h3 {
font-weight: normal;
font-size: 20px;
margin: 30px 0 0 0;
}
.markdown h4 {
font-size: 15px;
margin: 22px 0 -4px 0;
}
.doc, .public, .namespace .index {
max-width: 680px;
overflow-x: visible;
}
.markdown pre > code {
display: block;
padding: 10px;
}
.markdown pre > code, .src-link a {
border: 1px solid #e4e4e4;
border-radius: 2px;
}
.markdown code:not(.hljs), .src-link a {
background: #f6f6f6;
}
pre.deps {
display: inline-block;
margin: 0 10px;
border: 1px solid #e4e4e4;
border-radius: 2px;
padding: 10px;
background-color: #f6f6f6;
}
.markdown hr {
border-style: solid;
border-top: none;
color: #ccc;
}
.doc ul, .doc ol {
padding-left: 30px;
}
.doc table {
border-collapse: collapse;
margin: 0 10px;
}
.doc table td, .doc table th {
border: 1px solid #dddddd;
padding: 4px 6px;
}
.doc table th {
background: #f2f2f2;
}
.doc dl {
margin: 0 10px 20px 10px;
}
.doc dl dt {
font-weight: bold;
margin: 0;
padding: 3px 0;
border-bottom: 1px solid #ddd;
}
.doc dl dd {
padding: 5px 0;
margin: 0 0 5px 10px;
}
.doc abbr {
border-bottom: 1px dotted #333;
font-variant: none;
cursor: help;
}
.src-link {
margin-bottom: 15px;
}
.src-link a {
font-size: 70%;
padding: 1px 4px;
text-decoration: none;
color: #5555bb;
}

View file

@ -0,0 +1,97 @@
/*
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
color: #333;
background: #f8f8f8;
}
.hljs-comment,
.hljs-quote {
color: #998;
font-style: italic;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-subst {
color: #333;
font-weight: bold;
}
.hljs-number,
.hljs-literal,
.hljs-variable,
.hljs-template-variable,
.hljs-tag .hljs-attr {
color: #008080;
}
.hljs-string,
.hljs-doctag {
color: #d14;
}
.hljs-title,
.hljs-section,
.hljs-selector-id {
color: #900;
font-weight: bold;
}
.hljs-subst {
font-weight: normal;
}
.hljs-type,
.hljs-class .hljs-title {
color: #458;
font-weight: bold;
}
.hljs-tag,
.hljs-name,
.hljs-attribute {
color: #000080;
font-weight: normal;
}
.hljs-regexp,
.hljs-link {
color: #009926;
}
.hljs-symbol,
.hljs-bullet {
color: #990073;
}
.hljs-built_in,
.hljs-builtin-name {
color: #0086b3;
}
.hljs-meta {
color: #999;
font-weight: bold;
}
.hljs-deletion {
background: #fdd;
}
.hljs-addition {
background: #dfd;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

12
docs/codox/index.html Normal file
View file

@ -0,0 +1,12 @@
<!DOCTYPE html PUBLIC ""
"">
<html><head><meta charset="UTF-8" /><title>Mw-engine 0.3.0-SNAPSHOT</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Mw-engine</span> <span class="project-version">0.3.0-SNAPSHOT</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1 current"><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1"><a href="intro.html"><div class="inner"><span>Introduction to mw-engine</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>mw-engine</span></div></div></li><li class="depth-2 branch"><a href="mw-engine.core.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>core</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.display.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>display</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.drainage.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>drainage</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.flow.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>flow</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.heightmap.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>heightmap</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.natural-rules.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>natural-rules</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.render.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>render</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.utils.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>utils</span></div></a></li><li class="depth-2"><a href="mw-engine.world.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>world</span></div></a></li></ul></div><div class="namespace-index" id="content"><h1><span class="project-title"><span class="project-name">Mw-engine</span> <span class="project-version">0.3.0-SNAPSHOT</span></span></h1><h5 class="license">Released under the <a href="http://www.gnu.org/licenses/gpl-2.0.html">GNU General Public License v2</a></h5><div class="doc"><p>Cellular automaton world builder.</p></div><h2>Installation</h2><p>To install, add the following dependency to your project or build file:</p><pre class="deps">[mw-engine "0.3.0-SNAPSHOT"]</pre><h2>Topics</h2><ul class="topics"><li><a href="intro.html">Introduction to mw-engine</a></li></ul><h2>Namespaces</h2><div class="namespace"><h3><a href="mw-engine.core.html">mw-engine.core</a></h3><div class="doc"><div class="markdown"><p>Functions to transform a world and run rules.</p>
</div></div><div class="index"><p>Public variables and functions:</p><ul><li> <a href="mw-engine.core.html#var-*with-history*">*with-history*</a> </li><li> <a href="mw-engine.core.html#var-apply-rule">apply-rule</a> </li><li> <a href="mw-engine.core.html#var-known-rule-types">known-rule-types</a> </li><li> <a href="mw-engine.core.html#var-run-world">run-world</a> </li><li> <a href="mw-engine.core.html#var-transform-world">transform-world</a> </li></ul></div></div><div class="namespace"><h3><a href="mw-engine.display.html">mw-engine.display</a></h3><div class="doc"><div class="markdown"><p>Simple functions to allow a world to be visualised.</p>
</div></div><div class="index"><p>Public variables and functions:</p><ul><li> <a href="mw-engine.display.html#var-*image-base*">*image-base*</a> </li><li> <a href="mw-engine.display.html#var-format-css-class">format-css-class</a> </li><li> <a href="mw-engine.display.html#var-format-image-path">format-image-path</a> </li><li> <a href="mw-engine.display.html#var-format-mouseover">format-mouseover</a> </li><li> <a href="mw-engine.display.html#var-render-cell">render-cell</a> </li><li> <a href="mw-engine.display.html#var-render-world-row">render-world-row</a> </li><li> <a href="mw-engine.display.html#var-render-world-table">render-world-table</a> </li></ul></div></div><div class="namespace"><h3><a href="mw-engine.drainage.html">mw-engine.drainage</a></h3><div class="doc"><div class="markdown"><p>Experimental, probably of no interest to anyone else; attempt to compute drainage on a world, assumed to have altitudes already set from a heightmap.</p>
</div></div><div class="index"><p>Public variables and functions:</p><ul><li> <a href="mw-engine.drainage.html#var-*sealevel*">*sealevel*</a> </li><li> <a href="mw-engine.drainage.html#var-explore-lake">explore-lake</a> </li><li> <a href="mw-engine.drainage.html#var-find-lakes">find-lakes</a> </li><li> <a href="mw-engine.drainage.html#var-flood-hollow">flood-hollow</a> </li><li> <a href="mw-engine.drainage.html#var-flood-hollows">flood-hollows</a> </li><li> <a href="mw-engine.drainage.html#var-flow">flow</a> </li><li> <a href="mw-engine.drainage.html#var-flow-contributors">flow-contributors</a> </li><li> <a href="mw-engine.drainage.html#var-flow-nr">flow-nr</a> </li><li> <a href="mw-engine.drainage.html#var-flow-world">flow-world</a> </li><li> <a href="mw-engine.drainage.html#var-flow-world-nr">flow-world-nr</a> </li><li> <a href="mw-engine.drainage.html#var-is-hollow">is-hollow</a> </li><li> <a href="mw-engine.drainage.html#var-is-lake.3F">is-lake?</a> </li><li> <a href="mw-engine.drainage.html#var-max-altitude">max-altitude</a> </li><li> <a href="mw-engine.drainage.html#var-rain-row">rain-row</a> </li><li> <a href="mw-engine.drainage.html#var-rain-world">rain-world</a> </li><li> <a href="mw-engine.drainage.html#var-rainfall">rainfall</a> </li><li> <a href="mw-engine.drainage.html#var-run-drainage">run-drainage</a> </li></ul></div></div><div class="namespace"><h3><a href="mw-engine.flow.html">mw-engine.flow</a></h3><div class="doc"><div class="markdown"><p>Allow flows of values between cells in the world.</p>
</div></div><div class="index"><p>Public variables and functions:</p><ul><li> <a href="mw-engine.flow.html#var-coordinate.3F">coordinate?</a> </li><li> <a href="mw-engine.flow.html#var-create-flow-fraction">create-flow-fraction</a> </li><li> <a href="mw-engine.flow.html#var-create-flow-percent">create-flow-percent</a> </li><li> <a href="mw-engine.flow.html#var-create-flow-quantity">create-flow-quantity</a> </li><li> <a href="mw-engine.flow.html#var-create-location">create-location</a> </li><li> <a href="mw-engine.flow.html#var-execute">execute</a> </li><li> <a href="mw-engine.flow.html#var-execute-flows">execute-flows</a> </li><li> <a href="mw-engine.flow.html#var-flow-world">flow-world</a> </li><li> <a href="mw-engine.flow.html#var-flow.3F">flow?</a> </li><li> <a href="mw-engine.flow.html#var-location.3F">location?</a> </li><li> <a href="mw-engine.flow.html#var-plan-flows">plan-flows</a> </li></ul></div></div><div class="namespace"><h3><a href="mw-engine.heightmap.html">mw-engine.heightmap</a></h3><div class="doc"><div class="markdown"><p>Functions to apply a heightmap to a world.</p>
</div></div><div class="index"><p>Public variables and functions:</p><ul><li> <a href="mw-engine.heightmap.html#var-apply-heightmap">apply-heightmap</a> </li><li> <a href="mw-engine.heightmap.html#var-apply-valuemap">apply-valuemap</a> </li><li> <a href="mw-engine.heightmap.html#var-tag-altitude">tag-altitude</a> </li><li> <a href="mw-engine.heightmap.html#var-tag-gradient">tag-gradient</a> </li><li> <a href="mw-engine.heightmap.html#var-tag-gradients">tag-gradients</a> </li><li> <a href="mw-engine.heightmap.html#var-tag-property">tag-property</a> </li></ul></div></div><div class="namespace"><h3><a href="mw-engine.natural-rules.html">mw-engine.natural-rules</a></h3><div class="doc"><div class="markdown"><p>A set of MicroWorld rules describing a simplified natural ecosystem.</p>
</div></div><div class="index"><p>Public variables and functions:</p><ul><li> <a href="mw-engine.natural-rules.html#var-herbivore-rules">herbivore-rules</a> </li><li> <a href="mw-engine.natural-rules.html#var-init-rules">init-rules</a> </li><li> <a href="mw-engine.natural-rules.html#var-lightning-probability">lightning-probability</a> </li><li> <a href="mw-engine.natural-rules.html#var-natural-rules">natural-rules</a> </li><li> <a href="mw-engine.natural-rules.html#var-predator-rules">predator-rules</a> </li><li> <a href="mw-engine.natural-rules.html#var-snowline">snowline</a> </li><li> <a href="mw-engine.natural-rules.html#var-treeline">treeline</a> </li><li> <a href="mw-engine.natural-rules.html#var-vegetation-rules">vegetation-rules</a> </li><li> <a href="mw-engine.natural-rules.html#var-waterline">waterline</a> </li></ul></div></div><div class="namespace"><h3><a href="mw-engine.render.html">mw-engine.render</a></h3><div class="doc"><div class="markdown"><p>Render a world as HTML.</p>
</div></div><div class="index"><p>Public variables and functions:</p><ul><li> <a href="mw-engine.render.html#var-*state-images-relative-path*">*state-images-relative-path*</a> </li><li> <a href="mw-engine.render.html#var-format-css-class">format-css-class</a> </li><li> <a href="mw-engine.render.html#var-format-image-path">format-image-path</a> </li><li> <a href="mw-engine.render.html#var-format-mouseover">format-mouseover</a> </li><li> <a href="mw-engine.render.html#var-render-cell">render-cell</a> </li><li> <a href="mw-engine.render.html#var-render-world-page">render-world-page</a> </li><li> <a href="mw-engine.render.html#var-render-world-row">render-world-row</a> </li><li> <a href="mw-engine.render.html#var-render-world-table">render-world-table</a> </li><li> <a href="mw-engine.render.html#var-world-.3Ehtml-file">world-&gt;html-file</a> </li></ul></div></div><div class="namespace"><h3><a href="mw-engine.utils.html">mw-engine.utils</a></h3><div class="doc"><div class="markdown"><p>Utility functions needed by MicroWorld and, specifically, in the interpretation of MicroWorld rule.</p>
</div></div><div class="index"><p>Public variables and functions:</p><ul><li> <a href="mw-engine.utils.html#var-add-history-event">add-history-event</a> </li><li> <a href="mw-engine.utils.html#var-get-cell">get-cell</a> </li><li> <a href="mw-engine.utils.html#var-get-int">get-int</a> </li><li> <a href="mw-engine.utils.html#var-get-int-or-zero">get-int-or-zero</a> </li><li> <a href="mw-engine.utils.html#var-get-least-cell">get-least-cell</a> </li><li> <a href="mw-engine.utils.html#var-get-most-cell">get-most-cell</a> </li><li> <a href="mw-engine.utils.html#var-get-neighbours">get-neighbours</a> </li><li> <a href="mw-engine.utils.html#var-get-neighbours-with-property-value">get-neighbours-with-property-value</a> </li><li> <a href="mw-engine.utils.html#var-get-neighbours-with-state">get-neighbours-with-state</a> </li><li> <a href="mw-engine.utils.html#var-get-num">get-num</a> </li><li> <a href="mw-engine.utils.html#var-history-string">history-string</a> </li><li> <a href="mw-engine.utils.html#var-in-bounds">in-bounds</a> </li><li> <a href="mw-engine.utils.html#var-in-bounds.3F">in-bounds?</a> </li><li> <a href="mw-engine.utils.html#var-init-generation">init-generation</a> </li><li> <a href="mw-engine.utils.html#var-map-world">map-world</a> </li><li> <a href="mw-engine.utils.html#var-map-world-n-n">map-world-n-n</a> </li><li> <a href="mw-engine.utils.html#var-map-world-p-p">map-world-p-p</a> </li><li> <a href="mw-engine.utils.html#var-member.3F">member?</a> </li><li> <a href="mw-engine.utils.html#var-memo-get-neighbours">memo-get-neighbours</a> </li><li> <a href="mw-engine.utils.html#var-merge-cell">merge-cell</a> </li><li> <a href="mw-engine.utils.html#var-population">population</a> </li><li> <a href="mw-engine.utils.html#var-rule-type">rule-type</a> </li><li> <a href="mw-engine.utils.html#var-set-property">set-property</a> </li><li> <a href="mw-engine.utils.html#var-summarise-history">summarise-history</a> </li></ul></div></div><div class="namespace"><h3><a href="mw-engine.world.html">mw-engine.world</a></h3><div class="doc"><div class="markdown"><p>Functions to create and to print two dimensional cellular automata.</p>
</div></div><div class="index"><p>Public variables and functions:</p><ul><li> <a href="mw-engine.world.html#var-cell.3F">cell?</a> </li><li> <a href="mw-engine.world.html#var-format-cell">format-cell</a> </li><li> <a href="mw-engine.world.html#var-make-cell">make-cell</a> </li><li> <a href="mw-engine.world.html#var-make-world">make-world</a> </li><li> <a href="mw-engine.world.html#var-print-world">print-world</a> </li><li> <a href="mw-engine.world.html#var-truncate-state">truncate-state</a> </li><li> <a href="mw-engine.world.html#var-world.3F">world?</a> </li></ul></div></div></div></body></html>

5
docs/codox/intro.html Normal file
View file

@ -0,0 +1,5 @@
<!DOCTYPE html PUBLIC ""
"">
<html><head><meta charset="UTF-8" /><title>Introduction to mw-engine</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Mw-engine</span> <span class="project-version">0.3.0-SNAPSHOT</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1"><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1 current"><a href="intro.html"><div class="inner"><span>Introduction to mw-engine</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>mw-engine</span></div></div></li><li class="depth-2 branch"><a href="mw-engine.core.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>core</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.display.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>display</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.drainage.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>drainage</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.flow.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>flow</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.heightmap.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>heightmap</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.natural-rules.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>natural-rules</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.render.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>render</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.utils.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>utils</span></div></a></li><li class="depth-2"><a href="mw-engine.world.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>world</span></div></a></li></ul></div><div class="document" id="content"><div class="doc"><div class="markdown"><h1><a href="#introduction-to-mw-engine" id="introduction-to-mw-engine"></a>Introduction to mw-engine</h1>
<p>TODO: write <a href="http://jacobian.org/writing/great-documentation/what-to-write/">great documentation</a></p>
</div></div></div></body></html>

2
docs/codox/js/highlight.min.js vendored Normal file

File diff suppressed because one or more lines are too long

4
docs/codox/js/jquery.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,112 @@
function visibleInParent(element) {
var position = $(element).position().top
return position > -50 && position < ($(element).offsetParent().height() - 50)
}
function hasFragment(link, fragment) {
return $(link).attr("href").indexOf("#" + fragment) != -1
}
function findLinkByFragment(elements, fragment) {
return $(elements).filter(function(i, e) { return hasFragment(e, fragment)}).first()
}
function scrollToCurrentVarLink(elements) {
var elements = $(elements);
var parent = elements.offsetParent();
if (elements.length == 0) return;
var top = elements.first().position().top;
var bottom = elements.last().position().top + elements.last().height();
if (top >= 0 && bottom <= parent.height()) return;
if (top < 0) {
parent.scrollTop(parent.scrollTop() + top);
}
else if (bottom > parent.height()) {
parent.scrollTop(parent.scrollTop() + bottom - parent.height());
}
}
function setCurrentVarLink() {
$('.secondary a').parent().removeClass('current')
$('.anchor').
filter(function(index) { return visibleInParent(this) }).
each(function(index, element) {
findLinkByFragment(".secondary a", element.id).
parent().
addClass('current')
});
scrollToCurrentVarLink('.secondary .current');
}
var hasStorage = (function() { try { return localStorage.getItem } catch(e) {} }())
function scrollPositionId(element) {
var directory = window.location.href.replace(/[^\/]+\.html$/, '')
return 'scroll::' + $(element).attr('id') + '::' + directory
}
function storeScrollPosition(element) {
if (!hasStorage) return;
localStorage.setItem(scrollPositionId(element) + "::x", $(element).scrollLeft())
localStorage.setItem(scrollPositionId(element) + "::y", $(element).scrollTop())
}
function recallScrollPosition(element) {
if (!hasStorage) return;
$(element).scrollLeft(localStorage.getItem(scrollPositionId(element) + "::x"))
$(element).scrollTop(localStorage.getItem(scrollPositionId(element) + "::y"))
}
function persistScrollPosition(element) {
recallScrollPosition(element)
$(element).scroll(function() { storeScrollPosition(element) })
}
function sidebarContentWidth(element) {
var widths = $(element).find('.inner').map(function() { return $(this).innerWidth() })
return Math.max.apply(Math, widths)
}
function calculateSize(width, snap, margin, minimum) {
if (width == 0) {
return 0
}
else {
return Math.max(minimum, (Math.ceil(width / snap) * snap) + (margin * 2))
}
}
function resizeSidebars() {
var primaryWidth = sidebarContentWidth('.primary')
var secondaryWidth = 0
if ($('.secondary').length != 0) {
secondaryWidth = sidebarContentWidth('.secondary')
}
// snap to grid
primaryWidth = calculateSize(primaryWidth, 32, 13, 160)
secondaryWidth = calculateSize(secondaryWidth, 32, 13, 160)
$('.primary').css('width', primaryWidth)
$('.secondary').css('width', secondaryWidth).css('left', primaryWidth + 1)
if (secondaryWidth > 0) {
$('#content').css('left', primaryWidth + secondaryWidth + 2)
}
else {
$('#content').css('left', primaryWidth + 1)
}
}
$(window).ready(resizeSidebars)
$(window).ready(setCurrentVarLink)
$(window).ready(function() { persistScrollPosition('.primary')})
$(window).ready(function() {
$('#content').scroll(setCurrentVarLink)
$(window).resize(setCurrentVarLink)
})

View file

@ -0,0 +1,22 @@
<!DOCTYPE html PUBLIC ""
"">
<html><head><meta charset="UTF-8" /><title>mw-engine.core documentation</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Mw-engine</span> <span class="project-version">0.3.0-SNAPSHOT</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1"><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1"><a href="intro.html"><div class="inner"><span>Introduction to mw-engine</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>mw-engine</span></div></div></li><li class="depth-2 branch current"><a href="mw-engine.core.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>core</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.display.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>display</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.drainage.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>drainage</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.flow.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>flow</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.heightmap.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>heightmap</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.natural-rules.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>natural-rules</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.render.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>render</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.utils.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>utils</span></div></a></li><li class="depth-2"><a href="mw-engine.world.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>world</span></div></a></li></ul></div><div class="sidebar secondary"><h3><a href="#top"><span class="inner">Public Vars</span></a></h3><ul><li class="depth-1"><a href="mw-engine.core.html#var-*with-history*"><div class="inner"><span>*with-history*</span></div></a></li><li class="depth-1"><a href="mw-engine.core.html#var-apply-rule"><div class="inner"><span>apply-rule</span></div></a></li><li class="depth-1"><a href="mw-engine.core.html#var-known-rule-types"><div class="inner"><span>known-rule-types</span></div></a></li><li class="depth-1"><a href="mw-engine.core.html#var-run-world"><div class="inner"><span>run-world</span></div></a></li><li class="depth-1"><a href="mw-engine.core.html#var-transform-world"><div class="inner"><span>transform-world</span></div></a></li></ul></div><div class="namespace-docs" id="content"><h1 class="anchor" id="top">mw-engine.core</h1><div class="doc"><div class="markdown"><p>Functions to transform a world and run rules.</p>
<p>Every rule is a function of two arguments, a cell and a world. If the rule fires, it returns a new cell, which should have the same values for <code>:x</code> and <code>:y</code> as the old cell. Anything else can be modified.</p>
<p>While any function of two arguments can be used as a rule, a special high level rule language is provided by the <code>mw-parser</code> package, which compiles rules expressed in a subset of English rules into suitable functions.</p>
<p>A cell is a map containing at least values for the keys :x, :y, and :state; a transformation should not alter the values of :x or :y, and should not return a cell without a keyword as the value of :state. Anything else is legal.</p>
<p>A world is a two dimensional matrix (sequence of sequences) of cells, such that every cells <code>:x</code> and <code>:y</code> properties reflect its place in the matrix. See <code>world.clj</code>.</p>
<p>Each time the world is transformed (see <code>transform-world</code>), for each cell, rules are applied in turn until one matches. Once one rule has matched no further rules can be applied to that cell.</p>
</div></div><div class="public anchor" id="var-*with-history*"><h3>*with-history*</h3><h4 class="dynamic">dynamic</h4><div class="usage"></div><div class="doc"><div class="markdown"><p>I suspect that caching history on the cells is greatly worsening the memory problems. Make it optional, but by default false.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/core.clj#L53">view source</a></div></div><div class="public anchor" id="var-apply-rule"><h3>apply-rule</h3><div class="usage"><code>(apply-rule world cell rule)</code></div><div class="doc"><div class="markdown"><p>Apply a single <code>rule</code> to a <code>cell</code>. What this is about is that I want to be able, for debugging purposes, to tag a cell with the rule text of the rule which fired (and especially so when an exception is thrown).</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/core.clj#L62">view source</a></div></div><div class="public anchor" id="var-known-rule-types"><h3>known-rule-types</h3><div class="usage"></div><div class="doc"><div class="markdown"><p>Types of rules we know about.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/core.clj#L58">view source</a></div></div><div class="public anchor" id="var-run-world"><h3>run-world</h3><div class="usage"><code>(run-world world rules generations)</code><code>(run-world world init-rules rules generations)</code></div><div class="doc"><div class="markdown"><p>Run this <code>world</code> with these <code>rules</code> for this number of <code>generations</code>.</p>
<ul>
<li><code>world</code> a world as discussed above;</li>
<li><code>init-rules</code> a sequence of rules as defined above, to be run once to initialise the world;</li>
<li><code>rules</code> a sequence of rules as defined above, to be run iteratively for each generation;</li>
<li><code>generations</code> an (integer) number of generations.</li>
</ul>
<p><strong>NOTE THAT</strong> all rules <strong>must</strong> be tagged with <code>rule-type</code> metadata, or they <strong>will not</strong> be executed.</p>
<p>Return the final generation of the world.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/core.clj#L130">view source</a></div></div><div class="public anchor" id="var-transform-world"><h3>transform-world</h3><div class="usage"><code>(transform-world world rules)</code></div><div class="doc"><div class="markdown"><p>Return a world derived from this <code>world</code> by applying the production rules found among these <code>rules</code> to each cell.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/core.clj#L119">view source</a></div></div></div></body></html>

View file

@ -0,0 +1,11 @@
<!DOCTYPE html PUBLIC ""
"">
<html><head><meta charset="UTF-8" /><title>mw-engine.display documentation</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Mw-engine</span> <span class="project-version">0.3.0-SNAPSHOT</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1"><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1"><a href="intro.html"><div class="inner"><span>Introduction to mw-engine</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>mw-engine</span></div></div></li><li class="depth-2 branch"><a href="mw-engine.core.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>core</span></div></a></li><li class="depth-2 branch current"><a href="mw-engine.display.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>display</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.drainage.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>drainage</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.flow.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>flow</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.heightmap.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>heightmap</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.natural-rules.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>natural-rules</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.render.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>render</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.utils.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>utils</span></div></a></li><li class="depth-2"><a href="mw-engine.world.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>world</span></div></a></li></ul></div><div class="sidebar secondary"><h3><a href="#top"><span class="inner">Public Vars</span></a></h3><ul><li class="depth-1"><a href="mw-engine.display.html#var-*image-base*"><div class="inner"><span>*image-base*</span></div></a></li><li class="depth-1"><a href="mw-engine.display.html#var-format-css-class"><div class="inner"><span>format-css-class</span></div></a></li><li class="depth-1"><a href="mw-engine.display.html#var-format-image-path"><div class="inner"><span>format-image-path</span></div></a></li><li class="depth-1"><a href="mw-engine.display.html#var-format-mouseover"><div class="inner"><span>format-mouseover</span></div></a></li><li class="depth-1"><a href="mw-engine.display.html#var-render-cell"><div class="inner"><span>render-cell</span></div></a></li><li class="depth-1"><a href="mw-engine.display.html#var-render-world-row"><div class="inner"><span>render-world-row</span></div></a></li><li class="depth-1"><a href="mw-engine.display.html#var-render-world-table"><div class="inner"><span>render-world-table</span></div></a></li></ul></div><div class="namespace-docs" id="content"><h1 class="anchor" id="top">mw-engine.display</h1><div class="doc"><div class="markdown"><p>Simple functions to allow a world to be visualised.</p>
</div></div><div class="public anchor" id="var-*image-base*"><h3>*image-base*</h3><h4 class="dynamic">dynamic</h4><div class="usage"></div><div class="doc"><div class="markdown"><p>Base url (i.e., url of directory) from which to load tile images.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/display.clj#L28">view source</a></div></div><div class="public anchor" id="var-format-css-class"><h3>format-css-class</h3><div class="usage"><code>(format-css-class state)</code></div><div class="doc"><div class="markdown"><p>Format this <code>state</code>, assumed to be a keyword indicating a state in the world, into a CSS class</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/display.clj#L32">view source</a></div></div><div class="public anchor" id="var-format-image-path"><h3>format-image-path</h3><div class="usage"><code>(format-image-path state)</code></div><div class="doc"><div class="markdown"><p>Render this <code>state</code>, assumed to be a keyword indicating a state in the world, into a path which should recover the corresponding image file.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/display.clj#L38">view source</a></div></div><div class="public anchor" id="var-format-mouseover"><h3>format-mouseover</h3><div class="usage"><code>(format-mouseover cell)</code></div><div class="doc"><div class="markdown"><p><strong>TODO</strong>: write docs</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/display.clj#L44">view source</a></div></div><div class="public anchor" id="var-render-cell"><h3>render-cell</h3><div class="usage"><code>(render-cell cell)</code></div><div class="doc"><div class="markdown"><p>Render this world cell as a Hiccup table cell.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/display.clj#L47">view source</a></div></div><div class="public anchor" id="var-render-world-row"><h3>render-world-row</h3><div class="usage"><code>(render-world-row row)</code></div><div class="doc"><div class="markdown"><p>Render this world <code>row</code> as a Hiccup table row.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/display.clj#L55">view source</a></div></div><div class="public anchor" id="var-render-world-table"><h3>render-world-table</h3><div class="usage"><code>(render-world-table world)</code></div><div class="doc"><div class="markdown"><p>Render this <code>world</code> as a Hiccup table.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/display.clj#L60">view source</a></div></div></div></body></html>

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,29 @@
<!DOCTYPE html PUBLIC ""
"">
<html><head><meta charset="UTF-8" /><title>mw-engine.flow documentation</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Mw-engine</span> <span class="project-version">0.3.0-SNAPSHOT</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1"><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1"><a href="intro.html"><div class="inner"><span>Introduction to mw-engine</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>mw-engine</span></div></div></li><li class="depth-2 branch"><a href="mw-engine.core.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>core</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.display.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>display</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.drainage.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>drainage</span></div></a></li><li class="depth-2 branch current"><a href="mw-engine.flow.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>flow</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.heightmap.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>heightmap</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.natural-rules.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>natural-rules</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.render.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>render</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.utils.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>utils</span></div></a></li><li class="depth-2"><a href="mw-engine.world.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>world</span></div></a></li></ul></div><div class="sidebar secondary"><h3><a href="#top"><span class="inner">Public Vars</span></a></h3><ul><li class="depth-1"><a href="mw-engine.flow.html#var-coordinate.3F"><div class="inner"><span>coordinate?</span></div></a></li><li class="depth-1"><a href="mw-engine.flow.html#var-create-flow-fraction"><div class="inner"><span>create-flow-fraction</span></div></a></li><li class="depth-1"><a href="mw-engine.flow.html#var-create-flow-percent"><div class="inner"><span>create-flow-percent</span></div></a></li><li class="depth-1"><a href="mw-engine.flow.html#var-create-flow-quantity"><div class="inner"><span>create-flow-quantity</span></div></a></li><li class="depth-1"><a href="mw-engine.flow.html#var-create-location"><div class="inner"><span>create-location</span></div></a></li><li class="depth-1"><a href="mw-engine.flow.html#var-execute"><div class="inner"><span>execute</span></div></a></li><li class="depth-1"><a href="mw-engine.flow.html#var-execute-flows"><div class="inner"><span>execute-flows</span></div></a></li><li class="depth-1"><a href="mw-engine.flow.html#var-flow-world"><div class="inner"><span>flow-world</span></div></a></li><li class="depth-1"><a href="mw-engine.flow.html#var-flow.3F"><div class="inner"><span>flow?</span></div></a></li><li class="depth-1"><a href="mw-engine.flow.html#var-location.3F"><div class="inner"><span>location?</span></div></a></li><li class="depth-1"><a href="mw-engine.flow.html#var-plan-flows"><div class="inner"><span>plan-flows</span></div></a></li></ul></div><div class="namespace-docs" id="content"><h1 class="anchor" id="top">mw-engine.flow</h1><div class="doc"><div class="markdown"><p>Allow flows of values between cells in the world.</p>
<p>The design here is: a flow object is a map with the following properties:</p>
<ol>
<li><code>:source</code>, whose value is a location;</li>
<li><code>:destination</code>, whose value is a location;</li>
<li><code>:property</code>, whose value is a keyword;</li>
<li><code>:quantity</code>, whose value is a positive real number.</li>
</ol>
<p>A location object is a map with the following properties:</p>
<ol>
<li><code>:x</code>, whose value is a natural number not greater than the extent of the world;</li>
<li><code>:y</code>, whose value is a natural number not greater than the extent of the world.</li>
</ol>
<p>To execute a flow is transfer the quantity specified of the property specified from the cell at the source specified to the cell at the destination specified; if the source doesnt have sufficient of the property, then all it has should be transferred, but no more: properties to be flowed cannot be pulled negative.</p>
<p>Flowing values through the world is consequently a two stage process: firstly theres a planning stage, in which all the flows to be executed are computed without changing the world, and then an execution stage, where theyre all executed. This namespace deals with mainly with execution.</p>
</div></div><div class="public anchor" id="var-coordinate.3F"><h3>coordinate?</h3><div class="usage"><code>(coordinate? o world)</code></div><div class="doc"><div class="markdown"><p>Return <code>true</code> if this object <code>o</code> is a valid coordinate with respect to this <code>world</code>, else <code>false</code>. Assumes square worlds.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/flow.clj#L52">view source</a></div></div><div class="public anchor" id="var-create-flow-fraction"><h3>create-flow-fraction</h3><h4 class="type">macro</h4><div class="usage"><code>(create-flow-fraction source dest prop fraction)</code></div><div class="doc"><div class="markdown"><p><strong>TODO</strong>: write docs</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/flow.clj#L172">view source</a></div></div><div class="public anchor" id="var-create-flow-percent"><h3>create-flow-percent</h3><h4 class="type">macro</h4><div class="usage"><code>(create-flow-percent source dest prop percent)</code></div><div class="doc"><div class="markdown"><p><strong>TODO</strong>: write docs</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/flow.clj#L177">view source</a></div></div><div class="public anchor" id="var-create-flow-quantity"><h3>create-flow-quantity</h3><h4 class="type">macro</h4><div class="usage"><code>(create-flow-quantity source dest prop quantity)</code></div><div class="doc"><div class="markdown"><p><strong>TODO</strong>: write docs</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/flow.clj#L165">view source</a></div></div><div class="public anchor" id="var-create-location"><h3>create-location</h3><h4 class="type">macro</h4><div class="usage"><code>(create-location cell)</code></div><div class="doc"><div class="markdown"><p><strong>TODO</strong>: write docs</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/flow.clj#L161">view source</a></div></div><div class="public anchor" id="var-execute"><h3>execute</h3><div class="usage"><code>(execute world flow)</code></div><div class="doc"><div class="markdown"><p>Return a world like this <code>world</code>, except with the quantity of the property described in this <code>flow</code> object transferred from the source of that flow to its destination.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/flow.clj#L90">view source</a></div></div><div class="public anchor" id="var-execute-flows"><h3>execute-flows</h3><div class="usage"><code>(execute-flows world flows)</code></div><div class="doc"><div class="markdown"><p>Return a world like this <code>world</code>, but with each of these flows executed.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/flow.clj#L123">view source</a></div></div><div class="public anchor" id="var-flow-world"><h3>flow-world</h3><div class="usage"><code>(flow-world world rules)</code></div><div class="doc"><div class="markdown"><p>Return a world derived from this <code>world</code> by applying the flow rules found among these <code>rules</code> to each cell, and executing all the flows planned.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/flow.clj#L152">view source</a></div></div><div class="public anchor" id="var-flow.3F"><h3>flow?</h3><div class="usage"><code>(flow? o world)</code></div><div class="doc"><div class="markdown"><p>Return <code>true</code> if this object <code>o</code> is a flow as defined above with respect to this <code>world</code>, else <code>false</code>. Assumes square worlds.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/flow.clj#L76">view source</a></div></div><div class="public anchor" id="var-location.3F"><h3>location?</h3><div class="usage"><code>(location? o world)</code></div><div class="doc"><div class="markdown"><p>Return <code>true</code> if this object <code>o</code> is a location as defined above with respect to this <code>world</code>, else <code>false</code>.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/flow.clj#L63">view source</a></div></div><div class="public anchor" id="var-plan-flows"><h3>plan-flows</h3><div class="usage"><code>(plan-flows world rules)</code></div><div class="doc"><div class="markdown"><p>Plan, but do not execute, all the flows in this <code>world</code> implied by those of these <code>rules</code> (which are expected to be pre-compiled) which are flow rules. Return the list of plans, as flow objects.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/flow.clj#L140">view source</a></div></div></div></body></html>

View file

@ -0,0 +1,31 @@
<!DOCTYPE html PUBLIC ""
"">
<html><head><meta charset="UTF-8" /><title>mw-engine.heightmap documentation</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Mw-engine</span> <span class="project-version">0.3.0-SNAPSHOT</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1"><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1"><a href="intro.html"><div class="inner"><span>Introduction to mw-engine</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>mw-engine</span></div></div></li><li class="depth-2 branch"><a href="mw-engine.core.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>core</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.display.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>display</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.drainage.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>drainage</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.flow.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>flow</span></div></a></li><li class="depth-2 branch current"><a href="mw-engine.heightmap.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>heightmap</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.natural-rules.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>natural-rules</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.render.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>render</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.utils.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>utils</span></div></a></li><li class="depth-2"><a href="mw-engine.world.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>world</span></div></a></li></ul></div><div class="sidebar secondary"><h3><a href="#top"><span class="inner">Public Vars</span></a></h3><ul><li class="depth-1"><a href="mw-engine.heightmap.html#var-apply-heightmap"><div class="inner"><span>apply-heightmap</span></div></a></li><li class="depth-1"><a href="mw-engine.heightmap.html#var-apply-valuemap"><div class="inner"><span>apply-valuemap</span></div></a></li><li class="depth-1"><a href="mw-engine.heightmap.html#var-tag-altitude"><div class="inner"><span>tag-altitude</span></div></a></li><li class="depth-1"><a href="mw-engine.heightmap.html#var-tag-gradient"><div class="inner"><span>tag-gradient</span></div></a></li><li class="depth-1"><a href="mw-engine.heightmap.html#var-tag-gradients"><div class="inner"><span>tag-gradients</span></div></a></li><li class="depth-1"><a href="mw-engine.heightmap.html#var-tag-property"><div class="inner"><span>tag-property</span></div></a></li></ul></div><div class="namespace-docs" id="content"><h1 class="anchor" id="top">mw-engine.heightmap</h1><div class="doc"><div class="markdown"><p>Functions to apply a heightmap to a world.</p>
<p>Heightmaps are considered only as greyscale images, so colour is redundent (will be ignored). Darker shades are higher.</p>
</div></div><div class="public anchor" id="var-apply-heightmap"><h3>apply-heightmap</h3><div class="usage"><code>(apply-heightmap world imagepath)</code><code>(apply-heightmap imagepath)</code></div><div class="doc"><div class="markdown"><p>Apply the image file loaded from this path to this world, and return a world whose altitudes are modified (added to) by the altitudes in the heightmap. It is assumed that the heightmap is at least as large in x and y dimensions as the world. Note that, in addition to setting the <code>:altitude</code> of each cell, this function also sets the <code>:gradient</code>.</p>
<ul>
<li><code>world</code> a world, as defined in <code>world.clj</code>, q.v.; if world is not supplied, a world the size of the heightmap will be created;</li>
<li><code>imagepath</code> a file path or URL which indicates an (ideally greyscale) image file.</li>
</ul>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/heightmap.clj#L90">view source</a></div></div><div class="public anchor" id="var-apply-valuemap"><h3>apply-valuemap</h3><div class="usage"><code>(apply-valuemap world imagepath property)</code></div><div class="doc"><div class="markdown"><p>Generalised from apply-heightmap, set an arbitrary property on each cell of this <code>world</code> from the values in this (ideally greyscale) heightmap.</p>
<ul>
<li><code>world</code> a world, as defined in <code>world.clj</code>, q.v.;</li>
<li><code>imagepath</code> a file path or URL which indicates an (ideally greyscale) image file;</li>
<li><code>property</code> the property of each cell whose value should be added to from the intensity of the corresponding cell of the image.</li>
</ul>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/heightmap.clj#L115">view source</a></div></div><div class="public anchor" id="var-tag-altitude"><h3>tag-altitude</h3><div class="usage"><code>(tag-altitude _ cell heightmap)</code><code>(tag-altitude cell heightmap)</code></div><div class="doc"><div class="markdown"><p>Set the altitude of this cell from the corresponding pixel of this heightmap. If the heightmap you supply is smaller than the world, this will break.</p>
<ul>
<li><code>world</code> not actually used, but present to enable this function to be passed as an argument to <code>mw-engine.utils/map-world</code>, q.v.;</li>
<li><code>cell</code> a cell, as discussed in world.clj, q.v. Alternatively, a map;</li>
<li><code>heightmap</code> an (ideally) greyscale image, whose x and y dimensions should exceed those of the world of which the <code>cell</code> forms part.</li>
</ul>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/heightmap.clj#L76">view source</a></div></div><div class="public anchor" id="var-tag-gradient"><h3>tag-gradient</h3><div class="usage"><code>(tag-gradient world cell)</code></div><div class="doc"><div class="markdown"><p>Set the <code>gradient</code> property of this <code>cell</code> of this <code>world</code> to the difference in altitude between its highest and lowest neghbours.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/heightmap.clj#L58">view source</a></div></div><div class="public anchor" id="var-tag-gradients"><h3>tag-gradients</h3><div class="usage"><code>(tag-gradients world)</code></div><div class="doc"><div class="markdown"><p>Set the <code>gradient</code> property of each cell in this <code>world</code> to the difference in altitude between its highest and lowest neghbours.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/heightmap.clj#L70">view source</a></div></div><div class="public anchor" id="var-tag-property"><h3>tag-property</h3><div class="usage"><code>(tag-property _ cell property heightmap)</code><code>(tag-property cell property heightmap)</code></div><div class="doc"><div class="markdown"><p>Set the value of this <code>property</code> of this cell from the corresponding pixel of this <code>heightmap</code>. If the heightmap you supply is smaller than the world, this will break.</p>
<ul>
<li><code>world</code> not actually used, but present to enable this function to be passed as an argument to <code>mw-engine.utils/map-world</code>, q.v.</li>
<li><code>cell</code> a cell, as discussed in world.clj, q.v. Alternatively, a map;</li>
<li><code>property</code> the property (normally a keyword) whose value will be set on the cell.</li>
<li><code>heightmap</code> an (ideally) greyscale image, whose x and y dimensions should exceed those of the world of which the <code>cell</code> forms part.</li>
</ul>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/heightmap.clj#L35">view source</a></div></div></div></body></html>

View file

@ -0,0 +1,14 @@
<!DOCTYPE html PUBLIC ""
"">
<html><head><meta charset="UTF-8" /><title>mw-engine.natural-rules documentation</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Mw-engine</span> <span class="project-version">0.3.0-SNAPSHOT</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1"><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1"><a href="intro.html"><div class="inner"><span>Introduction to mw-engine</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>mw-engine</span></div></div></li><li class="depth-2 branch"><a href="mw-engine.core.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>core</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.display.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>display</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.drainage.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>drainage</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.flow.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>flow</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.heightmap.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>heightmap</span></div></a></li><li class="depth-2 branch current"><a href="mw-engine.natural-rules.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>natural-rules</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.render.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>render</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.utils.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>utils</span></div></a></li><li class="depth-2"><a href="mw-engine.world.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>world</span></div></a></li></ul></div><div class="sidebar secondary"><h3><a href="#top"><span class="inner">Public Vars</span></a></h3><ul><li class="depth-1"><a href="mw-engine.natural-rules.html#var-herbivore-rules"><div class="inner"><span>herbivore-rules</span></div></a></li><li class="depth-1"><a href="mw-engine.natural-rules.html#var-init-rules"><div class="inner"><span>init-rules</span></div></a></li><li class="depth-1"><a href="mw-engine.natural-rules.html#var-lightning-probability"><div class="inner"><span>lightning-probability</span></div></a></li><li class="depth-1"><a href="mw-engine.natural-rules.html#var-natural-rules"><div class="inner"><span>natural-rules</span></div></a></li><li class="depth-1"><a href="mw-engine.natural-rules.html#var-predator-rules"><div class="inner"><span>predator-rules</span></div></a></li><li class="depth-1"><a href="mw-engine.natural-rules.html#var-snowline"><div class="inner"><span>snowline</span></div></a></li><li class="depth-1"><a href="mw-engine.natural-rules.html#var-treeline"><div class="inner"><span>treeline</span></div></a></li><li class="depth-1"><a href="mw-engine.natural-rules.html#var-vegetation-rules"><div class="inner"><span>vegetation-rules</span></div></a></li><li class="depth-1"><a href="mw-engine.natural-rules.html#var-waterline"><div class="inner"><span>waterline</span></div></a></li></ul></div><div class="namespace-docs" id="content"><h1 class="anchor" id="top">mw-engine.natural-rules</h1><div class="doc"><div class="markdown"><p>A set of MicroWorld rules describing a simplified natural ecosystem.</p>
<p>Since the completion of the rule language this is more or less obsolete - there are still a few things that you can do with rules written in Clojure that you cant do in the rule language, but not many and I doubt theyre important.</p>
</div></div><div class="public anchor" id="var-herbivore-rules"><h3>herbivore-rules</h3><div class="usage"></div><div class="doc"><div class="markdown"><p><strong>TODO</strong>: write docs</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/natural_rules.clj#L101">view source</a></div></div><div class="public anchor" id="var-init-rules"><h3>init-rules</h3><div class="usage"></div><div class="doc"><div class="markdown"><p><strong>TODO</strong>: write docs</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/natural_rules.clj#L168">view source</a></div></div><div class="public anchor" id="var-lightning-probability"><h3>lightning-probability</h3><div class="usage"></div><div class="doc"><div class="markdown"><p><strong>TODO</strong>: write docs</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/natural_rules.clj#L44">view source</a></div></div><div class="public anchor" id="var-natural-rules"><h3>natural-rules</h3><div class="usage"></div><div class="doc"><div class="markdown"><p><strong>TODO</strong>: write docs</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/natural_rules.clj#L180">view source</a></div></div><div class="public anchor" id="var-predator-rules"><h3>predator-rules</h3><div class="usage"></div><div class="doc"><div class="markdown"><p><strong>TODO</strong>: write docs</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/natural_rules.clj#L130">view source</a></div></div><div class="public anchor" id="var-snowline"><h3>snowline</h3><div class="usage"></div><div class="doc"><div class="markdown"><p><strong>TODO</strong>: write docs</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/natural_rules.clj#L41">view source</a></div></div><div class="public anchor" id="var-treeline"><h3>treeline</h3><div class="usage"></div><div class="doc"><div class="markdown"><p><strong>TODO</strong>: write docs</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/natural_rules.clj#L35">view source</a></div></div><div class="public anchor" id="var-vegetation-rules"><h3>vegetation-rules</h3><div class="usage"></div><div class="doc"><div class="markdown"><p><strong>TODO</strong>: write docs</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/natural_rules.clj#L47">view source</a></div></div><div class="public anchor" id="var-waterline"><h3>waterline</h3><div class="usage"></div><div class="doc"><div class="markdown"><p><strong>TODO</strong>: write docs</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/natural_rules.clj#L38">view source</a></div></div></div></body></html>

View file

@ -0,0 +1,14 @@
<!DOCTYPE html PUBLIC ""
"">
<html><head><meta charset="UTF-8" /><title>mw-engine.render documentation</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Mw-engine</span> <span class="project-version">0.3.0-SNAPSHOT</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1"><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1"><a href="intro.html"><div class="inner"><span>Introduction to mw-engine</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>mw-engine</span></div></div></li><li class="depth-2 branch"><a href="mw-engine.core.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>core</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.display.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>display</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.drainage.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>drainage</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.flow.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>flow</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.heightmap.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>heightmap</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.natural-rules.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>natural-rules</span></div></a></li><li class="depth-2 branch current"><a href="mw-engine.render.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>render</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.utils.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>utils</span></div></a></li><li class="depth-2"><a href="mw-engine.world.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>world</span></div></a></li></ul></div><div class="sidebar secondary"><h3><a href="#top"><span class="inner">Public Vars</span></a></h3><ul><li class="depth-1"><a href="mw-engine.render.html#var-*state-images-relative-path*"><div class="inner"><span>*state-images-relative-path*</span></div></a></li><li class="depth-1"><a href="mw-engine.render.html#var-format-css-class"><div class="inner"><span>format-css-class</span></div></a></li><li class="depth-1"><a href="mw-engine.render.html#var-format-image-path"><div class="inner"><span>format-image-path</span></div></a></li><li class="depth-1"><a href="mw-engine.render.html#var-format-mouseover"><div class="inner"><span>format-mouseover</span></div></a></li><li class="depth-1"><a href="mw-engine.render.html#var-render-cell"><div class="inner"><span>render-cell</span></div></a></li><li class="depth-1"><a href="mw-engine.render.html#var-render-world-page"><div class="inner"><span>render-world-page</span></div></a></li><li class="depth-1"><a href="mw-engine.render.html#var-render-world-row"><div class="inner"><span>render-world-row</span></div></a></li><li class="depth-1"><a href="mw-engine.render.html#var-render-world-table"><div class="inner"><span>render-world-table</span></div></a></li><li class="depth-1"><a href="mw-engine.render.html#var-world-.3Ehtml-file"><div class="inner"><span>world-&gt;html-file</span></div></a></li></ul></div><div class="namespace-docs" id="content"><h1 class="anchor" id="top">mw-engine.render</h1><div class="doc"><div class="markdown"><p>Render a world as HTML.</p>
<p>Adapted (simplified) from mw-ui.render-world; this is for visualisation, not interaction.</p>
</div></div><div class="public anchor" id="var-*state-images-relative-path*"><h3>*state-images-relative-path*</h3><h4 class="dynamic">dynamic</h4><div class="usage"></div><div class="doc"><div class="markdown"><p><strong>TODO</strong>: write docs</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/render.clj#L32">view source</a></div></div><div class="public anchor" id="var-format-css-class"><h3>format-css-class</h3><div class="usage"><code>(format-css-class statekey)</code></div><div class="doc"><div class="markdown"><p>Format this statekey, assumed to be a keyword indicating a state in the world, into a CSS class</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/render.clj#L34">view source</a></div></div><div class="public anchor" id="var-format-image-path"><h3>format-image-path</h3><div class="usage"><code>(format-image-path statekey)</code></div><div class="doc"><div class="markdown"><p>Render this statekey, assumed to be a keyword indicating a state in the world, into a path which should recover the corresponding image file.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/render.clj#L40">view source</a></div></div><div class="public anchor" id="var-format-mouseover"><h3>format-mouseover</h3><div class="usage"><code>(format-mouseover cell)</code></div><div class="doc"><div class="markdown"><p><strong>TODO</strong>: write docs</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/render.clj#L46">view source</a></div></div><div class="public anchor" id="var-render-cell"><h3>render-cell</h3><div class="usage"><code>(render-cell cell)</code></div><div class="doc"><div class="markdown"><p>Render this world cell as a Hiccup table cell.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/render.clj#L49">view source</a></div></div><div class="public anchor" id="var-render-world-page"><h3>render-world-page</h3><div class="usage"><code>(render-world-page world)</code><code>(render-world-page world state-images-relative-path)</code></div><div class="doc"><div class="markdown"><p><strong>TODO</strong>: write docs</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/render.clj#L77">view source</a></div></div><div class="public anchor" id="var-render-world-row"><h3>render-world-row</h3><div class="usage"><code>(render-world-row row)</code></div><div class="doc"><div class="markdown"><p>Render this world row as a Hiccup table row.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/render.clj#L58">view source</a></div></div><div class="public anchor" id="var-render-world-table"><h3>render-world-table</h3><div class="usage"><code>(render-world-table world)</code><code>(render-world-table world state-images-relative-path)</code></div><div class="doc"><div class="markdown"><p>Render this <code>world</code> as a complete HTML table in a DIV. If <code>state-images-relative-path</code> is passed, use that to override the default path.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/render.clj#L63">view source</a></div></div><div class="public anchor" id="var-world-.3Ehtml-file"><h3>world-&gt;html-file</h3><div class="usage"><code>(world-&gt;html-file world output-path)</code><code>(world-&gt;html-file world output-path state-images-relative-path)</code></div><div class="doc"><div class="markdown"><p><strong>TODO</strong>: write docs</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/render.clj#L93">view source</a></div></div></div></body></html>

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,25 @@
<!DOCTYPE html PUBLIC ""
"">
<html><head><meta charset="UTF-8" /><title>mw-engine.world documentation</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Mw-engine</span> <span class="project-version">0.3.0-SNAPSHOT</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1"><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1"><a href="intro.html"><div class="inner"><span>Introduction to mw-engine</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>mw-engine</span></div></div></li><li class="depth-2 branch"><a href="mw-engine.core.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>core</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.display.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>display</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.drainage.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>drainage</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.flow.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>flow</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.heightmap.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>heightmap</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.natural-rules.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>natural-rules</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.render.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>render</span></div></a></li><li class="depth-2 branch"><a href="mw-engine.utils.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>utils</span></div></a></li><li class="depth-2 current"><a href="mw-engine.world.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>world</span></div></a></li></ul></div><div class="sidebar secondary"><h3><a href="#top"><span class="inner">Public Vars</span></a></h3><ul><li class="depth-1"><a href="mw-engine.world.html#var-cell.3F"><div class="inner"><span>cell?</span></div></a></li><li class="depth-1"><a href="mw-engine.world.html#var-format-cell"><div class="inner"><span>format-cell</span></div></a></li><li class="depth-1"><a href="mw-engine.world.html#var-make-cell"><div class="inner"><span>make-cell</span></div></a></li><li class="depth-1"><a href="mw-engine.world.html#var-make-world"><div class="inner"><span>make-world</span></div></a></li><li class="depth-1"><a href="mw-engine.world.html#var-print-world"><div class="inner"><span>print-world</span></div></a></li><li class="depth-1"><a href="mw-engine.world.html#var-truncate-state"><div class="inner"><span>truncate-state</span></div></a></li><li class="depth-1"><a href="mw-engine.world.html#var-world.3F"><div class="inner"><span>world?</span></div></a></li></ul></div><div class="namespace-docs" id="content"><h1 class="anchor" id="top">mw-engine.world</h1><div class="doc"><div class="markdown"><p>Functions to create and to print two dimensional cellular automata.</p>
<p>Nothing in this namespace should determine what states are possible within the automaton, except for the initial state, :new.</p>
<p>A cell is a map containing at least values for the keys <code>:x</code>, <code>:y</code>, and <code>:state</code>.</p>
<p>A world is a two dimensional matrix (sequence of sequences) of cells, such that every cells <code>:x</code> and <code>:y</code> properties reflect its place in the matrix.</p>
</div></div><div class="public anchor" id="var-cell.3F"><h3>cell?</h3><div class="usage"><code>(cell? obj)</code></div><div class="doc"><div class="markdown"><p>Return <code>true</code> if <code>obj</code> is a cell, as understood by MicroWorld, else <code>false</code>.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/world.clj#L38">view source</a></div></div><div class="public anchor" id="var-format-cell"><h3>format-cell</h3><div class="usage"><code>(format-cell cell)</code></div><div class="doc"><div class="markdown"><p>Return a formatted string summarising the current state of this cell.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/world.clj#L89">view source</a></div></div><div class="public anchor" id="var-make-cell"><h3>make-cell</h3><h4 class="type">macro</h4><div class="usage"><code>(make-cell x y)</code></div><div class="doc"><div class="markdown"><p>Create a minimal default cell at x, y</p>
<ul>
<li><code>x</code> the x coordinate at which this cell is created;</li>
<li><code>y</code> the y coordinate at which this cell is created.</li>
</ul>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/world.clj#L56">view source</a></div></div><div class="public anchor" id="var-make-world"><h3>make-world</h3><div class="usage"><code>(make-world width height)</code></div><div class="doc"><div class="markdown"><p>Make a world width cells from east to west, and height cells from north to south.</p>
<ul>
<li><code>width</code> a natural number representing the width of the matrix to be created;</li>
<li><code>height</code> a natural number representing the height of the matrix to be created.</li>
</ul>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/world.clj#L64">view source</a></div></div><div class="public anchor" id="var-print-world"><h3>print-world</h3><div class="usage"><code>(print-world world)</code></div><div class="doc"><div class="markdown"><p>Print the current state of this world, and return nil.</p>
<ul>
<li><code>world</code> a world as defined above.</li>
</ul>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/world.clj#L100">view source</a></div></div><div class="public anchor" id="var-truncate-state"><h3>truncate-state</h3><div class="usage"><code>(truncate-state cell limit)</code></div><div class="doc"><div class="markdown"><p>Truncate the print name of the state of this cell to at most limit characters.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/world.clj#L76">view source</a></div></div><div class="public anchor" id="var-world.3F"><h3>world?</h3><div class="usage"><code>(world? obj)</code></div><div class="doc"><div class="markdown"><p>Return <code>true</code> if <code>obj</code> is a world, as understood by MicroWorld, else <code>false</code>.</p>
</div></div><div class="src-link"><a href="https://github.com/simon-brooke/mw-engine/blob/master/src/cljc/mw_engine/world.clj#L48">view source</a></div></div></div></body></html>

4092
docs/uberdoc.html Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,21 +1,32 @@
(defproject mw-engine "0.1.5-SNAPSHOT"
(defproject mw-engine "0.3.0-SNAPSHOT"
:cloverage {:output "docs/cloverage"}
:codox {:metadata {:doc "**TODO**: write docs"
:doc/format :markdown}
:output-path "docs/codox"
:source-uri "https://github.com/simon-brooke/mw-engine/blob/master/{filepath}#L{line}"}
:dependencies [[com.github.pmonks/embroidery "0.1.20"] ;; better pmap?
[distributions "0.1.2"] ;; mainly for investigating drainage
[org.clojure/clojure "1.11.1"]
[org.clojure/clojurescript "1.11.60" :scope "provided"]
[org.clojure/math.combinatorics "0.2.0"]
[org.clojure/tools.trace "0.7.11"]
[org.clojure/tools.namespace "1.4.4"]
[com.taoensso/timbre "6.2.1"]
[fivetonine/collage "0.3.0"]
;; [hiccup "1.0.5"]
[hiccup "2.0.0-RC3"]
[net.mikera/imagez "0.12.0"]]
:description "Cellular automaton world builder."
:url "http://www.journeyman.cc/microworld/"
:manifest {
"build-signature-version" "unset"
"build-signature-user" "unset"
"build-signature-email" "unset"
"build-signature-timestamp" "unset"
"Implementation-Version" "unset"
}
:jvm-opts ["-Xmx4g"]
:license {:name "GNU General Public License v2"
:url "http://www.gnu.org/licenses/gpl-2.0.html"}
:plugins [[lein-marginalia "0.7.1"]]
:dependencies [[org.clojure/clojure "1.6.0"]
[org.clojure/math.combinatorics "0.0.7"]
[org.clojure/tools.trace "0.7.8"]
[org.clojure/tools.namespace "0.2.4"]
[hiccup "1.0.5"]
[net.mikera/imagez "0.3.1"]
[fivetonine/collage "0.2.0"]])
:min-lein-version "2.0.0"
:plugins [[lein-cljsbuild "1.1.7"]
[lein-cloverage "1.2.2"]
[lein-codox "0.10.8"]
[lein-kibit "0.1.2"]
[lein-marginalia "0.7.1"]]
:resource-paths ["resources" "target/cljsbuild"]
:source-paths ["src/clj" "src/cljs" "src/cljc"]
:url "http://www.journeyman.cc/microworld/")

Binary file not shown.

After

(image error) Size: 1.3 KiB

Binary file not shown.

1
resources/test.edn Normal file
View file

@ -0,0 +1 @@
{:hello "goodbye"}

160
src/cljc/mw_engine/core.clj Normal file
View file

@ -0,0 +1,160 @@
(ns ^{:doc "Functions to transform a world and run rules.
Every rule is a function of two arguments, a cell and a world. If the rule
fires, it returns a new cell, which should have the same values for `:x` and
`:y` as the old cell. Anything else can be modified.
While any function of two arguments can be used as a rule, a special high
level rule language is provided by the `mw-parser` package, which compiles
rules expressed in a subset of English rules into suitable functions.
A cell is a map containing at least values for the keys :x, :y, and :state;
a transformation should not alter the values of :x or :y, and should not
return a cell without a keyword as the value of :state. Anything else is
legal.
A world is a two dimensional matrix (sequence of sequences) of cells, such
that every cell's `:x` and `:y` properties reflect its place in the matrix.
See `world.clj`.
Each time the world is transformed (see `transform-world`), for each cell,
rules are applied in turn until one matches. Once one rule has matched no
further rules can be applied to that cell."
:author "Simon Brooke"}
mw-engine.core
(:require [clojure.set :refer [difference]]
[mw-engine.flow :refer [flow-world]]
[mw-engine.utils :refer [add-history-event get-int-or-zero map-world rule-type]]
[taoensso.timbre :as l]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;
;;;; mw-engine: the state/transition engine of MicroWorld.
;;;;
;;;; This program is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU General Public License
;;;; as published by the Free Software Foundation; either version 2
;;;; of the License, or (at your option) any later version.
;;;;
;;;; This program is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;;; GNU General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU General Public License
;;;; along with this program; if not, write to the Free Software
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
;;;; USA.
;;;;
;;;; Copyright (C) 2014 Simon Brooke
;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def ^:dynamic *with-history*
"I suspect that caching history on the cells is greatly worsening the
memory problems. Make it optional, but by default false."
false)
(def known-rule-types
"Types of rules we know about."
#{:ad-hoc :flow :production})
(defn apply-rule
"Apply a single `rule` to a `cell`. What this is about is that I want to be able,
for debugging purposes, to tag a cell with the rule text of the rule which
fired (and especially so when an exception is thrown). "
;; as of version 0-3-0, metadata for rules is now passed around on the metadata
;; of the rule function itself. Yes, I know, this is obvious; but I'll confess
;; I didn't think of it before.
[world cell rule]
(let [result (try
(apply rule (list cell world))
(catch Exception e
(l/warn e
(format
"Error in `apply-rule`: `%s` (%s) while executing rule `%s` on cell `%s`"
e
(.getMessage e)
(-> rule meta :lisp)
cell))))]
(if *with-history*
(add-history-event result rule)
result)))
(defn- apply-rules
"Derive a cell from this `cell` of this `world` by applying these `rules`."
[world cell rules]
(or
(first
(remove
nil?
(try
(map #(apply-rule world cell %) rules)
(catch Exception e
(l/warn e
(format
"Error in `apply-rules`: `%s` (%s) while executing rules on cell `%s`"
(-> e .getClass .getName)
(.getMessage e)
cell))))))
cell))
(defn- transform-cell
"Derive a cell from this `cell` of this `world` by applying these `rules`. If an
exception is thrown, cache its message on the cell and set it's state to error"
[world cell rules]
(try
(merge
(apply-rules world cell rules)
{:generation (+ (get-int-or-zero cell :generation) 1)})
(catch Exception e
(let [narrative (format "Error in `transform-cell`: `%s` (%s) at generation %d when in state %s;"
(-> e .getClass .getName)
(.getMessage e)
(:generation cell)
(:state cell))]
(l/warn e narrative)
cell))))
(defn transform-world
"Return a world derived from this `world` by applying the production rules
found among these `rules` to each cell."
[world rules]
(map-world world transform-cell
;; Yes, that `list` is there for a reason!
(list
(filter
#(#{:ad-hoc :production} (rule-type %))
rules))))
(defn run-world
"Run this `world` with these `rules` for this number of `generations`.
* `world` a world as discussed above;
* `init-rules` a sequence of rules as defined above, to be run once to initialise the world;
* `rules` a sequence of rules as defined above, to be run iteratively for each generation;
* `generations` an (integer) number of generations.
**NOTE THAT** all rules **must** be tagged with `rule-type` metadata, or they **will not**
be executed.
Return the final generation of the world."
([world rules generations]
(run-world world rules rules (dec generations)))
([world init-rules rules generations]
(let [found-types (map rule-type (concat init-rules rules))]
(if (every? known-rule-types found-types)
(reduce (fn [world iteration]
(l/info "Running iteration " iteration)
(let [w' (transform-world world rules)]
(flow-world w' rules)))
(transform-world world init-rules)
(range generations))
(let [unexpected (difference (set found-types) known-rule-types)]
(throw
(ex-info (format
"Unexpected rule type(s) %s found. Expected types are %s"
unexpected
known-rule-types)
{:types unexpected})))))))

View file

@ -0,0 +1,65 @@
(ns ^{:doc "Simple functions to allow a world to be visualised."
:author "Simon Brooke"}
mw-engine.display)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;
;;;; mw-engine: the state/transition engine of MicroWorld.
;;;;
;;;; This program is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU General Public License
;;;; as published by the Free Software Foundation; either version 2
;;;; of the License, or (at your option) any later version.
;;;;
;;;; This program is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;;; GNU General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU General Public License
;;;; along with this program; if not, write to the Free Software
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
;;;; USA.
;;;;
;;;; Copyright (C) 2014 Simon Brooke
;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def ^:dynamic *image-base*
"Base url (i.e., url of directory) from which to load tile images."
"img/tiles")
(defn format-css-class
"Format this `state`, assumed to be a keyword indicating a state in the
world, into a CSS class"
[state]
(subs (str state) 1))
(defn format-image-path
"Render this `state`, assumed to be a keyword indicating a state in the
world, into a path which should recover the corresponding image file."
[state]
(format "%s/%s.png" *image-base* (format-css-class state)))
(defn format-mouseover [cell]
(str cell))
(defn render-cell
"Render this world cell as a Hiccup table cell."
[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))}
[:img {:alt (:state cell) :width 32 :height 32 :src (format-image-path state)}]]]))
(defn render-world-row
"Render this world `row` as a Hiccup table row."
[row]
(apply vector (cons :tr (map render-cell row))))
(defn render-world-table
"Render this `world` as a Hiccup table."
[world]
(apply vector
(cons :table
(map render-world-row world))))

View file

@ -0,0 +1,288 @@
(ns ^{:doc "Experimental, probably of no interest to anyone else; attempt to
compute drainage on a world, assumed to have altitudes already set
from a heightmap."
:author "Simon Brooke"}
mw-engine.drainage
(:require [clojure.string :refer [replace]]
[hiccup2.core :refer [html]]
[mw-engine.core :refer [run-world]]
[mw-engine.heightmap :refer [apply-heightmap]]
[mw-engine.utils :refer [get-int-or-zero get-least-cell get-neighbours
get-neighbours-with-property-value
map-world]]
[taoensso.timbre :refer [info]]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;
;;;; mw-engine: the state/transition engine of MicroWorld.
;;;;
;;;; This program is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU General Public License
;;;; as published by the Free Software Foundation; either version 2
;;;; of the License, or (at your option) any later version.
;;;;
;;;; This program is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;;; GNU General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU General Public License
;;;; along with this program; if not, write to the Free Software
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
;;;; USA.
;;;;
;;;; Copyright (C) 2014 Simon Brooke
;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def ^:dynamic *sealevel* 10)
;; forward declaration of flow, to allow for a wee bit of mutual recursion.
(declare flow)
(defn rainfall
"Compute rainfall for a cell with this `gradient` west-east, given
`remaining` drops to distribute, and this overall map width."
[gradient remaining map-width]
(cond
;; if there's no rain left in the cloud, it can't fall;
(zero? remaining)
0
(pos? gradient)
;; rain, on prevailing westerly wind, falls preferentially on rising ground;
(int (rand gradient))
;; rain falls randomly across the width of the map...
(zero? (int (rand map-width))) 1
:else
0))
(defn rain-row
"Return a row like this `row`, across which rainfall has been distributed;
if `rain-probability` is specified, it is the probable rainfall on a cell
with no gradient."
([row]
(rain-row row 1))
([row rain-probability]
(rain-row row (count row) 0 (int (* (count row) rain-probability))))
([row map-width previous-altitude drops-in-cloud]
(cond
(empty? row) nil
(pos? drops-in-cloud)
(let [cell (first row)
alt (or (:altitude cell) 0)
rising (- alt previous-altitude)
fall (rainfall rising drops-in-cloud map-width)]
(cons
(assoc cell :rainfall fall)
(rain-row (rest row) map-width alt (- drops-in-cloud fall))))
:else
(map
#(assoc % :rainfall 0)
row))))
(defn rain-world
"Simulate rainfall on this `world`. TODO: Doesn't really work just now - should
rain more on west-facing slopes, and less to the east of high ground"
[world]
(info "rain-world started.")
(let [w' (into [] (map #(apply vector (rain-row %)) world))]
(info "rain-world completed")
w'))
(defn flow-contributors
"Return a list of the cells in this `world` which are higher than this
`cell` and for which this cell is the lowest neighbour, or which are at the
same altitude and have greater flow"
[cell world]
(filter #(map? %)
(map
(fn [n]
(cond
(= cell (get-least-cell (get-neighbours world n) :altitude)) n
(and (= (:altitude cell) (:altitude n))
(> (or (:flow n) 0) (or (:flow cell) 0))) n))
(get-neighbours-with-property-value
world (:x cell) (:y cell) 1 :altitude
(or (:altitude cell) 0) >=))))
(defn is-hollow
"Detects point hollows - that is, individual cells all of whose neighbours
are higher. Return true if this `cell` has an altitude lower than any of
its neighbours in this `world`"
[world cell]
;; quicker to count the elements of the list and compare equality of numbers
;; than recursive equality check on members, I think. But worth benchmarking.
(let [neighbours (get-neighbours world cell)
altitude (get-int-or-zero cell :altitude)]
(= (count neighbours)
(count (get-neighbours-with-property-value
world (:x cell) (:y cell) 1 :altitude altitude >)))))
(defn flood-hollow
"Raise the altitude of a copy of this `cell` of this `world` to the altitude
of the lowest of its `neighbours`."
([_world cell neighbours]
(let [lowest (get-least-cell neighbours :altitude)]
(merge cell {:state :water :altitude (:altitude lowest)})))
([world cell]
(flood-hollow world cell (get-neighbours world cell))))
(defn flood-hollows
"Flood all local hollows in this `world`. At this stage only floods single
cell hollows."
[world]
(info "flood-hollows started.")
(let [w' (map-world world
#(if (is-hollow %1 %2) (flood-hollow %1 %2) %2))]
(info "flood-hollows completed")
w'))
(def max-altitude 255)
(defn flow-nr
"Experimental non recursive flow algorithm, needs to be run on a world as
many times as there are distinct altitude values. This algorithm works only
if applied sequentially from the highest altitude to the lowest, see
`flow-world-nr`."
[cell world]
(when (= (- max-altitude (get-int-or-zero cell :generation))
(get-int-or-zero cell :altitude))
(let [contributors (flow-contributors cell world)]
(when contributors
(merge cell
{:flow (reduce +
(map
#(+ (get-int-or-zero % :rainfall)
(get-int-or-zero % :flow))
contributors))})))))
(def flow
"Compute the total flow upstream of this `cell` in this `world`, and return a cell identical
to this one but having a value of its flow property set from that computation. The function is
memoised because the consequence of mapping a recursive function across an array is that many
cells will be revisited - potentially many times.
Flow comes from a higher cell to a lower only if the lower is the lowest neighbour of the higher."
(memoize
(fn [cell world]
(cond
(not (nil? (:flow cell))) cell
(<= (or (:altitude cell) 0) *sealevel*) cell
:else
(merge cell
{:flow (+ (:rainfall cell)
(apply +
(map (fn [neighbour] (:flow (flow neighbour world)))
(flow-contributors cell world))))})))))
(defn flow-world-nr
"Experimental non-recursive flow-world algorithm"
[world]
(info "Non recursive flow-world started.")
(let [w' (run-world world (list (vary-meta flow-nr assoc :rule-type :ad-hoc)) max-altitude)]
(info "Non recursive flow-world completed")
w'))
(defn flow-world
"Return a world like this `world`, but with cells tagged with the amount of
water flowing through them."
[world]
(info "Recursive flow-world started.")
(let [w' (map-world (rain-world world) flow)]
(info "Recursive flow-world completed")
w'))
(defn explore-lake
"Return a sequence of cells starting with this `cell` in this `world` which
form a contiguous lake"
[_world _cell])
(defn is-lake?
"If this `cell` in this `world` is not part of a lake, return nil. If it is,
return a cell like this `cell` tagged as part of a lake."
[world cell]
(cond
;; if it's already tagged as a lake, it's a lake
(:lake cell) cell
(#{:lake :sea :water} (:state cell)) cell ;; if it's already tagged as
;; wet, no need for change
(and (integer? (:x cell)) (integer? (:y cell)))
(let
[outflow (apply min (map :altitude (get-neighbours world cell)))]
(when-not
(> (:altitude cell) outflow)
(do
(info (format "tagging cell at %d, %d as lake" (:x cell) (:y cell)))
(assoc cell :lake true :state :lake))))
:else (throw (ex-info "Invalid cell?"
{:cell cell}))))
(defn identify-lake
[world cell]
(or (is-lake? world cell) cell))
(defn find-lakes
"Identify cells in this `world` which are lakes."
[world]
(info "find-lakes started.")
(let [w' (map-world world identify-lake)]
(info "find-lakes completed.")
w'))
(defn run-drainage
"Create a world from the heightmap `hmap`, rain on it, and then compute river
flows."
[hmap]
(find-lakes (flow-world-nr (rain-world (flood-hollows (apply-heightmap hmap))))))
(defn visualise-drainage
[world html-file]
(let [mxf (apply max (map :flow (flatten world)))
scf (/ 128 mxf)
mxa (apply max (map :altitude (flatten world)))
sca (/ 128 mxa)]
(spit
html-file
(replace
(str
(html [:html
[:head
[:title "Drainage visualisation"]
[:style "table, table tr td {
padding: 0.5em;
margin: 0.2em;
width: 2em;
height: 2em;
border-collapse: collapse;
border: none;}"]]
[:body
(into [:table]
(map
#(into [:tr]
(map
(fn [c]
(let [g (- 255 (int (* sca (:altitude c))))]
[:td {:style (if (> (:altitude c) 1)
(let [blue (int (* scf (or (:flow c) 0)))
o (- g blue)]
(format "background-color: rgb(%d, %d, %d)"
o
o
(+ g blue)))
"background-color: cornflower-blue")
:title (format "state %s, x %d, y %d, rainfall %d, flow %d"
(:state c) (:x c) (:y c) (:rainfall c) (:flow c))}
(or (:rainfall c) "&nbsp;")]))
%))
world))]]))
"&amp;"
"&"))))
;; (visualise-drainage (run-drainage "resources/heightmaps/20x20/crucible.png") "test.html")

179
src/cljc/mw_engine/flow.clj Normal file
View file

@ -0,0 +1,179 @@
(ns mw-engine.flow
"Allow flows of values between cells in the world.
The design here is: a flow object is a map with the following properties:
1. `:source`, whose value is a location;
2. `:destination`, whose value is a location;
3. `:property`, whose value is a keyword;
4. `:quantity`, whose value is a positive real number.
A location object is a map with the following properties:
1. `:x`, whose value is a natural number not greater than the extent of the world;
2. `:y`, whose value is a natural number not greater than the extent of the world.
To execute a flow is transfer the quantity specified of the property specified
from the cell at the source specified to the cell at the destination specified;
if the source doesn't have sufficient of the property, then all it has should
be transferred, but no more: properties to be flowed cannot be pulled negative.
Flowing values through the world is consequently a two stage process: firstly
there's a planning stage, in which all the flows to be executed are computed
without changing the world, and then an execution stage, where they're all
executed. This namespace deals with mainly with execution."
(:require [mw-engine.utils :refer [add-history-event get-cell get-num
in-bounds? map-world merge-cell rule-type]]
[taoensso.timbre :refer [info warn]]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;
;;;; mw-engine: the state/transition engine of MicroWorld.
;;;;
;;;; This program is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU General Public License
;;;; as published by the Free Software Foundation; either version 2
;;;; of the License, or (at your option) any later version.
;;;;
;;;; This program is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;;; GNU General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU General Public License
;;;; along with this program; if not, write to the Free Software
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
;;;; USA.
;;;;
;;;; Copyright (C) 2014 Simon Brooke
;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn coordinate?
"Return `true` if this object `o` is a valid coordinate with respect to
this `world`, else `false`. Assumes square worlds."
[o world]
(try
(and (or (zero? o) (pos-int? o))
(< o (count world)))
(catch Exception e
(warn (format "Not a valid coordinate: %s; %s" o (.getMessage e)))
false)))
(defn location?
"Return `true` if this object `o` is a location as defined above with respect to
this `world`, else `false`."
[o world]
(try
(and (map? o)
(integer? (:x o))
(integer? (:y o))
(in-bounds? world (:x o) (:y o)))
(catch Exception e
(warn (format "Not a valid location: %s; %s" o (.getMessage e)))
false)))
(defn flow?
"Return `true` if this object `o` is a flow as defined above with respect to
this `world`, else `false`. Assumes square worlds."
[o world]
(try
(and (map? o)
(location? (:source o) world)
(location? (:destination o) world)
(keyword? (:property o))
(pos? (:quantity o)))
(catch Exception e
(warn (format "Not a valid flow: %s; %s" o (.getMessage e)))
false)))
(defn execute
"Return a world like this `world`, except with the quantity of the property
described in this `flow` object transferred from the source of that flow
to its destination."
[world flow]
(try
(let [sx (-> flow :source :x)
sy (-> flow :source :y)
source (get-cell world sx sy)
dx (-> flow :destination :x)
dy (-> flow :destination :y)
dest (get-cell world dx dy)
p (:property flow)
q (min (:quantity flow) (get-num source p))
s' (add-history-event
(assoc source p (- (source p) q))
(:rule flow)
{:direction :sent :other {:x dx :y dy} :property p :quantity q})
d' (add-history-event
(assoc dest p (+ (get-num dest p) q))
(:rule flow)
{:direction :received :other {:x sx :y sy} :property p :quantity q})]
(if (= q (:quantity flow))
(info (format "Moving %f units of %s from %d,%d to %d,%d"
(float q) (name p) sx sy dx dy))
(warn (format "Moving %s from %d,%d to %d,%d; %f units ordered but only %f available"
(name p) sx sy dx dy (float (:quantity flow)) (float q))))
(merge-cell (merge-cell world s') d'))
(catch Exception e
(warn (format "Failed to execute flow %s: %s" flow (.getMessage e)))
;; return the world unmodified.
world)))
(defn execute-flows
"Return a world like this `world`, but with each of these flows executed."
[world flows]
(reduce execute world (filter #(flow? % world) flows)))
(defn- plan-cell-flows
[world cell rules]
(map ;; across all the rules
(fn [rule] (let [r (try
(apply rule (list cell world))
(catch Exception any
(throw (ex-info "Planning of flows failed"
(merge (meta rule) {:cell cell})
any))))]
(when r (map #(assoc % :rule rule) r))))
rules))
(defn plan-flows
"Plan, but do not execute, all the flows in this `world` implied by those of
these `rules` (which are expected to be pre-compiled) which are
flow rules. Return the list of plans, as flow objects."
[world rules]
(remove nil?
(flatten
(map-world
world
plan-cell-flows
(list (filter #(= :flow (rule-type %)) rules))))))
(defn flow-world
"Return a world derived from this `world` by applying the flow rules
found among these `rules` to each cell, and executing all the flows
planned."
[world rules]
(execute-flows world (plan-flows world rules)))
;; building blocks for compiled flow rules
(defmacro create-location
[cell]
`(select-keys ~cell [:x :y]))
(defmacro create-flow-quantity
[source dest prop quantity]
`{:source (create-location ~source)
:destination (create-location ~dest)
:prop ~prop
:quantity ~quantity})
(defmacro create-flow-fraction
[source dest prop fraction]
`(create-flow-quantity ~source ~dest ~prop
(* ~fraction (get-num ~source ~prop))))
(defmacro create-flow-percent
[source dest prop percent]
`(create-flow-fraction ~source ~dest ~prop (/ ~percent 100)))

View file

@ -1,16 +1,36 @@
;; Functions to apply a heightmap to a world.
;;
;; Heightmaps are considered only as greyscale images, so colour is redundent (will be
;; ignored). Darker shades are higher.
(ns mw-engine.heightmap
(:import [java.awt.image BufferedImage])
(:use mw-engine.utils
mw-engine.world)
(:require [fivetonine.collage.util :as collage :only [load-image]]
[mikera.image.core :as imagez :only [filter-image get-pixels]]
[mikera.image.filters :as filters]))
(ns ^{:doc "Functions to apply a heightmap to a world.
Heightmaps are considered only as greyscale images, so colour is redundent
(will be ignored). Darker shades are higher."
:author "Simon Brooke"}
mw-engine.heightmap
(:require [mikera.image.core :refer [load-image filter-image]]
[mikera.image.filters :as filters]
[mw-engine.utils :refer [get-int get-neighbours map-world]]
[mw-engine.world :refer [make-world]]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;
;;;; mw-engine: the state/transition engine of MicroWorld.
;;;;
;;;; This program is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU General Public License
;;;; as published by the Free Software Foundation; either version 2
;;;; of the License, or (at your option) any later version.
;;;;
;;;; This program is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;;; GNU General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU General Public License
;;;; along with this program; if not, write to the Free Software
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
;;;; USA.
;;;;
;;;; Copyright (C) 2014 Simon Brooke
;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn tag-property
"Set the value of this `property` of this cell from the corresponding pixel of this `heightmap`.
@ -22,7 +42,7 @@
* `property` the property (normally a keyword) whose value will be set on the cell.
* `heightmap` an (ideally) greyscale image, whose x and y dimensions should
exceed those of the world of which the `cell` forms part."
([world cell property heightmap]
([_ cell property heightmap]
(tag-property cell property heightmap))
([cell property heightmap]
(merge cell
@ -41,9 +61,9 @@
[world cell]
(let [heights (remove nil? (map :altitude (get-neighbours world cell)))
highest (cond (empty? heights) 0 ;; shouldn't happen
true (apply max heights))
:else (apply max heights))
lowest (cond (empty? heights) 0 ;; shouldn't
true (apply min heights))
:else (apply min heights))
gradient (- highest lowest)]
(merge cell {:gradient gradient})))
@ -62,7 +82,7 @@
* `cell` a cell, as discussed in world.clj, q.v. Alternatively, a map;
* `heightmap` an (ideally) greyscale image, whose x and y dimensions should
exceed those of the world of which the `cell` forms part."
([world cell heightmap]
([_ cell heightmap]
(tag-property cell :altitude heightmap))
([cell heightmap]
(tag-property cell :altitude heightmap)))
@ -77,16 +97,16 @@
a world the size of the heightmap will be created;
* `imagepath` a file path or URL which indicates an (ideally greyscale) image file."
([world imagepath]
(let [heightmap (imagez/filter-image
(filters/grayscale)
(collage/load-image imagepath))]
(let [heightmap (filter-image
(load-image imagepath)
(filters/grayscale))]
(map-world
(map-world world tag-altitude (list heightmap))
tag-gradient)))
([imagepath]
(let [heightmap (imagez/filter-image
(filters/grayscale)
(collage/load-image imagepath))
(let [heightmap (filter-image
(load-image imagepath)
(filters/grayscale))
world (make-world (.getWidth heightmap) (.getHeight heightmap))]
(map-world
(map-world world tag-altitude (list heightmap))
@ -101,7 +121,7 @@
* `property` the property of each cell whose value should be added to from the
intensity of the corresponding cell of the image."
[world imagepath property]
(let [heightmap (imagez/filter-image
(filters/grayscale)
(collage/load-image imagepath))]
(let [heightmap (filter-image
(load-image imagepath)
(filters/grayscale))]
(map-world world tag-property (list property heightmap))))

View file

@ -1,13 +1,35 @@
;; A set of MicroWorld rules describing a simplified natural ecosystem.
;;
;; Since the completion of the rule language this is more or less obsolete -
;; there are still a few things that you can do with rules written in Clojure
;; that you can't do in the rule language, but not many and I doubt they're
;; important.
(ns ^{:doc "A set of MicroWorld rules describing a simplified natural ecosystem.
(ns mw-engine.natural-rules
(:use mw-engine.utils
mw-engine.world))
Since the completion of the rule language this is more or less obsolete -
there are still a few things that you can do with rules written in Clojure
that you can't do in the rule language, but not many and I doubt they're
important. "
:author " Simon Brooke "}
mw-engine.natural-rules
(:require [mw-engine.utils :refer [get-int get-neighbours get-neighbours-with-state member?]]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;
;;;; mw-engine: the state/transition engine of MicroWorld.
;;;;
;;;; This program is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU General Public License
;;;; as published by the Free Software Foundation; either version 2
;;;; of the License, or (at your option) any later version.
;;;;
;;;; This program is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;;; GNU General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU General Public License
;;;; along with this program; if not, write to the Free Software
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
;;;; USA.
;;;;
;;;; Copyright (C) 2014 Simon Brooke
;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; treeline at arbitrary altitude.
(def treeline 150)
@ -25,25 +47,25 @@
(def vegetation-rules
(list
;; Randomly, birds plant tree seeds into grassland.
(fn [cell world] (cond (and (= (:state cell) :grassland)(< (rand 10) 1))(merge cell {:state :heath})))
(fn [cell _] (cond (and (= (:state cell) :grassland)(< (rand 10) 1))(merge cell {:state :heath})))
;; heath below the treeline grows gradually into forest, providing browsing pressure is not to high
(fn [cell world]
(fn [cell _]
(cond (and
(= (:state cell) :heath)
;; browsing limit really ought to vary with soil fertility, but...
(< (+ (get-int cell :deer)(get-int cell :sheep)) 6)
(< (get-int cell :altitude) treeline))
(merge cell {:state :scrub})))
(fn [cell world] (cond (= (:state cell) :scrub) (merge cell {:state :forest})))
(fn [cell _] (cond (= (:state cell) :scrub) (merge cell {:state :forest})))
;; Forest on fertile land grows to climax
(fn [cell world]
(fn [cell _]
(cond
(and
(= (:state cell) :forest)
(> (get-int cell :fertility) 10))
(merge cell {:state :climax})))
;; Climax forest occasionally catches fire (e.g. lightning strikes)
(fn [cell world] (cond (and (= (:state cell) :climax)(< (rand lightning-probability) 1)) (merge cell {:state :fire})))
(fn [cell _] (cond (and (= (:state cell) :climax)(< (rand lightning-probability) 1)) (merge cell {:state :fire})))
;; Climax forest neighbouring fires is likely to catch fire
(fn [cell world]
(cond
@ -52,7 +74,7 @@
(not (empty? (get-neighbours-with-state world (:x cell) (:y cell) 1 :fire))))
(merge cell {:state :fire})))
;; After fire we get waste
(fn [cell world] (cond (= (:state cell) :fire) (merge cell {:state :waste})))
(fn [cell _] (cond (= (:state cell) :fire) (merge cell {:state :waste})))
;; And after waste we get pioneer species; if there's a woodland seed
;; source, it's going to be heath, otherwise grassland.
(fn [cell world]
@ -66,21 +88,21 @@
(get-neighbours-with-state world (:x cell) (:y cell) 1 :forest)
(get-neighbours-with-state world (:x cell) (:y cell) 1 :climax))))))
(merge cell {:state :heath})))
(fn [cell world]
(fn [cell _]
(cond (= (:state cell) :waste)
(merge cell {:state :grassland})))
;; Forest increases soil fertility
(fn [cell world]
(fn [cell _]
(cond (member? (:state cell) '(:forest :climax))
(merge cell {:fertility (+ (get-int cell :fertility) 1)})))
))
(merge cell {:fertility (+ (get-int cell :fertility) 1)})))))
;; rules describing herbivore behaviour
(def herbivore-rules
(list
;; if there are too many deer for the fertility of the area to sustain,
;; some die or move on.
(fn [cell world]
(fn [cell _]
(cond (> (get-int cell :deer) (get-int cell :fertility))
(merge cell {:deer (get-int cell :fertility)})))
;; deer arrive occasionally at the edge of the map.
@ -99,7 +121,7 @@
(>= n 2))
(merge cell {:deer (int (/ n 2))}))))
;; deer breed.
(fn [cell world]
(fn [cell _]
(cond
(>= (get-int cell :deer) 2)
(merge cell {:deer (int (* (:deer cell) 2))})))))
@ -108,7 +130,7 @@
(def predator-rules
(list
;; wolves eat deer
(fn [cell world]
(fn [cell _]
(cond
(>= (get-int cell :wolves) 1)
(merge cell {:deer (max 0 (- (get-int cell :deer) (get-int cell :wolves)))})))
@ -117,7 +139,7 @@
;; (cond (> (get-int cell :wolves) 8) (merge cell {:wolves 8})))
;; if there are not enough deer to sustain the get-int of wolves,
;; some wolves die or move on. (doesn't seem to be working?)
(fn [cell world]
(fn [cell _]
(cond (> (get-int cell :wolves) (get-int cell :deer))
(merge cell {:wolves 0})))
;; wolves arrive occasionally at the edge of the map.
@ -136,28 +158,27 @@
(>= n 2))
(merge cell {:wolves 2}))))
;; wolves breed.
(fn [cell world]
(fn [cell _]
(cond
(>= (get-int cell :wolves) 2)
(merge cell {:wolves (int (* (:wolves cell) 2))})))
))
(merge cell {:wolves (int (* (:wolves cell) 2))})))))
;; rules which initialise the world
(def init-rules
(list
;; below the waterline, we have water.
(fn [cell world]
(fn [cell _]
(cond (and (= (:state cell) :new) (< (get-int cell :altitude) waterline)) (merge cell {:state :water})))
;; above the snowline, we have snow.
(fn [cell world]
(fn [cell _]
(cond (and (= (:state cell) :new) (> (get-int cell :altitude) snowline)) (merge cell {:state :snow})))
;; in between, we have a wasteland.
(fn [cell world] (cond (= (:state cell) :new) (merge cell {:state :grassland}))
)))
(fn [cell _] (cond (= (:state cell) :new) (merge cell {:state :grassland})))))
(def natural-rules (flatten
(list
vegetation-rules
herbivore-rules
;; predator-rules
)))
predator-rules)))

View file

@ -0,0 +1,96 @@
(ns mw-engine.render
"Render a world as HTML.
Adapted (simplified) from mw-ui.render-world; this is for visualisation, not
interaction."
;; TODO: but possibly it would be better if there is to be a newer version of
;; mw-ui, to base it on this.
(:require [hiccup2.core :refer [html]])
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;
;;;; This program is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU General Public License
;;;; as published by the Free Software Foundation; either version 2
;;;; of the License, or (at your option) any later version.
;;;;
;;;; This program is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;;; GNU General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU General Public License
;;;; along with this program; if not, write to the Free Software
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
;;;; USA.
;;;;
;;;; Copyright (C) 2024 Simon Brooke
;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def ^:dynamic *state-images-relative-path* "img/tiles/")
(defn format-css-class
"Format this statekey, assumed to be a keyword indicating a state in the
world, into a CSS class"
[statekey]
(when statekey (name statekey)))
(defn format-image-path
"Render this statekey, assumed to be a keyword indicating a state in the
world, into a path which should recover the corresponding image file."
[statekey]
(format "%s%s.png" *state-images-relative-path* (format-css-class statekey)))
(defn format-mouseover [cell]
(str cell))
(defn render-cell
"Render this world cell as a Hiccup table cell."
[cell]
(let [state (:state cell)]
[:td {:class (format-css-class state) :title (format-mouseover cell)}
[:img {:alt (:state cell) :src (format-image-path state)}]]))
(defn render-world-row
"Render this world row as a Hiccup table row."
[row]
(into [:tr] (map render-cell row)))
(defn render-world-table
"Render this `world` as a complete HTML table in a DIV. If
`state-images-relative-path` is passed, use that to override the default path."
([world]
[:div {:class "world"}
(into [:table] (map render-world-row world))
[:p
(str "Generation " (:generation (first (flatten world))))]])
([world state-images-relative-path]
(binding [*state-images-relative-path* state-images-relative-path]
(render-world-table world))))
(defn render-world-page
([world]
[:html
[:head
[:title "Rendered world"]
[:style "div.world table, div.world table tr td {
padding: 0;
margin: 0;
border-collapse: collapse;
border: none;}"]]
[:body
(render-world-table world)]])
([world state-images-relative-path]
(binding [*state-images-relative-path* state-images-relative-path]
(render-world-page world))))
(defn world->html-file
([world output-path]
(spit output-path (str (html (render-world-page world)))))
([world output-path state-images-relative-path]
(binding [*state-images-relative-path* state-images-relative-path]
(world->html-file world output-path))))

View file

@ -0,0 +1,383 @@
(ns ^{:doc " Utility functions needed by MicroWorld and, specifically, in the
interpretation of MicroWorld rule."
:author "Simon Brooke"}
mw-engine.utils
(:require [clojure.math.combinatorics :as combo]
[clojure.string :refer [join]]
[embroidery.api :refer [pmap*]]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;
;;;; mw-engine: the state/transition engine of MicroWorld.
;;;;
;;;; This program is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU General Public License
;;;; as published by the Free Software Foundation; either version 2
;;;; of the License, or (at your option) any later version.
;;;;
;;;; This program is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;;; GNU General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU General Public License
;;;; along with this program; if not, write to the Free Software
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
;;;; USA.
;;;;
;;;; Copyright (C) 2014 Simon Brooke
;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn member?
"Return 'true' if elt is a member of col, else 'false'."
[elt col]
(contains? (set col) elt))
(defn get-int-or-zero
"Return the value of this `property` from this `map` if it is a integer;
otherwise return zero."
[map property]
(let [value (map property)]
(if (integer? value) value 0)))
(defn init-generation
"Return a cell like this `cell`, but having a value for :generation, zero if
the cell passed had no integer value for generation, otherwise the value
taken from the cell passed. The `world` argument is present only for
consistency with the rule engine and is ignored."
[_ cell]
(merge cell {:generation (get-int-or-zero cell :generation)}))
(defn in-bounds
"True if x, y are in bounds for this world (i.e., there is a cell at x, y)
else false. *DEPRECATED*: it's a predicate, prefer `in-bounds?`.
* `world` a world as defined in [world.clj](mw-engine.world.html);
* `x` a number which may or may not be a valid x coordinate within that world;
* `y` a number which may or may not be a valid y coordinate within that world."
{:deprecated "1.1.7"}
[world x y]
(and (>= x 0) (>= y 0) (< y (count world)) (< x (count (first world)))))
(defn in-bounds?
"True if x, y are in bounds for this world (i.e., there is a cell at x, y)
else false.
* `world` a world as defined in [world.clj](mw-engine.world.html);
* `x` a number which may or may not be a valid x coordinate within that world;
* `y` a number which may or may not be a valid y coordinate within that world."
{:added "1.1.7"}
[world x y]
(and (>= x 0) (>= y 0) (< y (count world)) (< x (count (first world)))))
(defn map-world-n-n
"Wholly non-parallel map world implementation; see documentation for `map-world`."
([world function]
(map-world-n-n world function nil))
([world function additional-args]
(into []
(map (fn [row]
(into [] (map
#(apply function
(cons world (cons % additional-args)))
row)))
world))))
(defn map-world-p-p
"Wholly parallel map-world implementation; see documentation for `map-world`."
([world function]
(map-world-p-p world function nil))
([world function additional-args]
(into []
(pmap (fn [row]
(into [] (pmap
#(apply function
(cons world (cons % additional-args)))
row)))
world))))
(defn map-world
"Apply this `function` to each cell in this `world` to produce a new world.
the arguments to the function will be the world, the cell, and any
`additional-args` supplied. Note that we parallel map over rows but
just map over cells within a row. That's because it isn't worth starting
a new thread for each cell, but there may be efficiency gains in
running rows in parallel."
([world function]
(map-world world function nil))
([world function additional-args]
(into []
(pmap* (fn [row]
(into [] (map
#(apply function
(cons world (cons % additional-args)))
row)))
world))))
(defn get-cell
"Return the cell a x, y in this world, if any.
* `world` a world as defined in [world.clj](mw-engine.world.html);
* `x` a number which may or may not be a valid x coordinate within that world;
* `y` a number which may or may not be a valid y coordinate within that world."
[world x y]
(when (in-bounds? world x y)
(nth (nth world y) x)))
(defn get-int
"Get the value of a property expected to be an integer from a map; if not
present (or not an integer) return 0.
* `map` a map;
* `key` a symbol or keyword, presumed to be a key into the `map`."
[map key]
(if (map? map)
(let [v (map key)]
(cond (and v (integer? v)) v
:else 0))
(throw (Exception. "No map passed?"))))
(defmacro get-num
"Get the value of a property expected to be a number from a map; if not
present (or not a number) return 0.
* `map` a map;
* `key` a symbol or keyword, presumed to be a key into the `map`."
[map key]
`(if (map? ~map)
(let [~'v (~map ~key)]
(cond (and ~'v (number? ~'v)) ~'v
:else 0))
(throw (Exception. "No map passed?"))))
(defn population
"Return the population of this species in this cell. Currently a synonym for
`get-int`, but may not always be (depending whether species are later
implemented as actors)
* `cell` a map;
* `species` a keyword representing a species which may populate that cell."
[cell species]
(get-int cell species))
(def memo-get-neighbours
"Memoised get neighbours is more efficient when running deeply recursive
algorithms on the same world. But it's less efficient when running the
engine in its normal iterative style, because then we will rarely call
get naighbours on the same cell of the same world twice."
(memoize
(fn [world x y depth]
(remove nil?
(map #(get-cell world (first %) (first (rest %)))
(remove #(= % (list x y))
(combo/cartesian-product
(range (- x depth) (+ x depth 1))
(range (- y depth) (+ y depth 1)))))))))
(defn get-neighbours
"Get the neighbours to distance depth of a cell in this world.
Several overloads:
* `world` a world, as described in [world.clj](mw-engine.world.html);
* `cell` a cell within that world
Gets immediate neighbours of the specified cell.
* `world` a world, as described in[world.clj](mw-engine.world.html);
* `cell` a cell within that world
* `depth` an integer representing the depth to search from the
`cell`
Gets neighbours within the specified distance of the cell.
* `world` a world, as described in[world.clj](mw-engine.world.html);
* `x` an integer representing an x coordinate in that world;
* `y` an integer representing an y coordinate in that world;
* `depth` an integer representing the distance from [x,y] that
should be searched
Gets the neighbours within the specified distance of the cell at
coordinates [x,y] in this world."
([world x y depth]
(if (and (integer? x) (integer? y) (integer? depth))
(memo-get-neighbours world x y depth)
(throw (ex-info "get-neighbours: integer arguments expected."
{:x x :y y :depth depth}))))
([world cell depth]
(memo-get-neighbours world (:x cell) (:y cell) depth))
([world cell]
(memo-get-neighbours world (:x cell) (:y cell) 1)))
(defn get-neighbours-with-property-value
"Get the neighbours to distance depth of the cell at x, y in this world which
have this value for this property.
* `world` a world, as described in [world.clj](mw-engine.world.html);
* `cell` a cell within that world;
* `depth` an integer representing the distance from [x,y] that
should be searched (optional);
* `property` a keyword representing a property of the neighbours;
* `value` a value of that property (or, possibly, the name of another);
* `op` a comparator function to use in place of `=` (optional).
It gets messy."
([world x y depth property value op]
(filter
#(eval
(list op
(or (get % property) (get-int % property))
value))
(get-neighbours world x y depth)))
([world x y depth property value]
(get-neighbours-with-property-value world x y depth property value =))
([world cell depth property value]
(get-neighbours-with-property-value world (:x cell) (:y cell) depth
property value))
([world cell property value]
(get-neighbours-with-property-value world cell 1
property value)))
(defn get-neighbours-with-state
"Get the neighbours to distance depth of the cell at x, y in this world which
have this state.
* `world` a world, as described in [world.clj](mw-engine.world.html);
* `cell` a cell within that world;
* `depth` an integer representing the distance from [x,y] that
should be searched;
* `state` a keyword representing a state in the world."
([world x y depth state]
(filter #(= (:state %) state) (get-neighbours world x y depth)))
([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)))
(defn get-least-cell
"Return the cell from among these `cells` which has the lowest numeric value
for this `property`."
[cells property]
(first (sort-by property (filter #(number? (property %)) cells))))
(defn get-most-cell
"Return the cell from among these `cells` which has the highest numeric value
for this `property`."
[cells property]
(last (sort-by property (filter #(number? (property %)) cells))))
(defn- set-cell-property
"If this `cell`s x and y properties are equal to these `x` and `y` values,
return a cell like this cell but with the value of this `property` set to
this `value`. Otherwise, just return this `cell`."
[cell x y property value]
(cond
(and (= x (:x cell)) (= y (:y cell)))
(merge cell {property value :rule "Set by user"})
:else cell))
(defn set-property
"Return a world like this `world` but with the value of exactly one `property`
of one `cell` changed to this `value`"
([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))))
(defn merge-cell
"Return a world like this `world`, but merge the values from this `cell` with
those from the cell in the world with the same co-ordinates"
[world cell]
(if (in-bounds? world (:x cell) (:y cell))
(map-world world
#(if
(and
(= (:x cell) (:x %2))
(= (:y cell) (:y %2)))
(merge %2 cell)
%2))
world))
(defn rule-type
"Return the rule-type of this compiled `rule`."
[rule]
(:rule-type (meta rule)))
(defn add-history-event
"If `cell` is non-nil, expect it to be a map representing a cell; add
to its history an an event recording the firing of this rule. If
`detail` is passed, treat it as a map of additional data to be
added to the event."
([cell rule]
(when cell (add-history-event cell rule {})))
([result rule detail]
(when result
(let [rule-meta (meta rule)
event {:rule (:source rule-meta)
:rule-type (:rule-type rule-meta)
:generation (get-int-or-zero
result
:generation)}
event' (if detail (merge event detail) event)]
(merge result
{:history (concat
(:history result)
(list event'))})))))
(defn- event-narrative [event]
(case (:rule-type event)
:production (:rule event)
:flow (format "%s %f units of %s %s %d,%d:\n %s"
(name (:direction event))
(:quantity event)
(:property event)
(if (= :sent (:direction event)) "to" "from")
(:x (:other event))
(:y (:other event))
(:rule event))))
(defn history-string
"Return the history of this `cell` as a string for presentation to the user."
[cell]
(join "\n"
(map #(format "%6d: %s" (:generation %) (event-narrative %))
(:history cell))))
(defn- extend-summary [summary rs rl event]
(str summary
(if rs (format "%d-%d (%d occurances): %s\n" rs
(:generation event)
rl
(event-narrative event))
(format "%d: %s\n" (:generation event)
(event-narrative event)))))
(defn summarise-history
"Return, as a string, a shorter summary of the history of this cell"
[cell]
(loop [history (rest (:history cell))
event (first (:history cell))
prev nil
rs nil
rl 0
summary ""]
(cond (nil? event) (extend-summary summary rs rl prev)
(= (:rule event) (:rule prev)) (recur
(rest history)
(first history)
event
(or rs (:generation event))
(inc rl)
summary)
:else (recur (rest history)
(first history)
event
nil
0
(extend-summary summary rs (inc rl) event)))))

View file

@ -0,0 +1,112 @@
(ns ^{:doc "Functions to create and to print two dimensional cellular automata.
Nothing in this namespace should determine what states are possible within
the automaton, except for the initial state, :new.
A cell is a map containing at least values for the keys `:x`, `:y`, and `:state`.
A world is a two dimensional matrix (sequence of sequences) of cells, such
that every cell's `:x` and `:y` properties reflect its place in the matrix."
:author "Simon Brooke"}
mw-engine.world
(:require [clojure.string :as string]
[mw-engine.utils :refer [population]]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;
;;;; mw-engine: the state/transition engine of MicroWorld.
;;;;
;;;; This program is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU General Public License
;;;; as published by the Free Software Foundation; either version 2
;;;; of the License, or (at your option) any later version.
;;;;
;;;; This program is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;;; GNU General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU General Public License
;;;; along with this program; if not, write to the Free Software
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
;;;; USA.
;;;;
;;;; Copyright (C) 2014 Simon Brooke
;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn cell?
"Return `true` if `obj` is a cell, as understood by MicroWorld, else `false`."
[obj]
(let [x (:x obj)
y (:y obj)]
(and (map? obj) ;; it's a map...
;; TODO: it's worth checking (and this does not) that cells have the
;; right co-ordinates!
(or (zero? x)(pos-int? x)) ;; with an x co-ordinate...
(or (zero? y)(pos-int? y)) ;; and a y co-ordinate...
(keyword? (:state obj))))) ;; and a state which is a keyword.
(defn world?
"Return `true` if `obj` is a world, as understood by MicroWorld, else `false`."
[obj]
(and (coll? obj) ;; it's a collection...
(every? coll? obj) ;; of collections...
(every? cell? (flatten obj)))) ;; and every element of each of those is a cell.
(defmacro make-cell
"Create a minimal default cell at x, y
* `x` the x coordinate at which this cell is created;
* `y` the y coordinate at which this cell is created."
[x y]
`{:x ~x :y ~y :state :new})
(defn make-world
"Make a world width cells from east to west, and height cells from north to
south.
* `width` a natural number representing the width of the matrix to be created;
* `height` a natural number representing the height of the matrix to be created."
[width height]
(apply vector
(map (fn [h]
(apply vector (map #(make-cell % h) (range width))))
(range height))))
(defn truncate-state
"Truncate the print name of the state of this cell to at most limit characters."
[cell limit]
(let [s (:state cell)]
(try
(cond (> (count (str s)) limit) (subs (name s) 0 limit)
:else s)
(catch Exception any
(throw (ex-info (.getMessage any)
{:cell cell
:limit limit
:exception-class (.getClass any)}))))))
(defn format-cell
"Return a formatted string summarising the current state of this cell."
[cell]
(format "%10s"
(truncate-state cell 10)))
(defn- format-world-row
"Format one row in the state of a world for printing."
[row]
(string/join (map format-cell row)))
(defn print-world
"Print the current state of this world, and return nil.
* `world` a world as defined above."
[world]
(println)
(dorun
(map
#(println
(format-world-row %))
world))
nil)

View file

@ -1,102 +0,0 @@
;; Functions to transform a world and run rules.
(ns mw-engine.core
(:use mw-engine.utils)
(:require [clojure.core.reducers :as r]
[mw-engine.world :as world])
(:gen-class))
;; Every rule is a function of two arguments, a cell and a world. If the rule
;; fires, it returns a new cell, which should have the same values for :x and
;; :y as the old cell. Anything else can be modified.
;;
;; While any function of two arguments can be used as a rule, a special high
;; level rule language is provided by the `mw-parser` package, which compiles
;; rules expressed in a subset of English rules into suitable functions.
;;
;; A cell is a map containing at least values for the keys :x, :y, and :state;
;; a transformation should not alter the values of :x or :y, and should not
;; return a cell without a keyword as the value of :state. Anything else is
;; legal.
;;
;; A world is a two dimensional matrix (sequence of sequences) of cells, such
;; that every cell's :x and :y properties reflect its place in the matrix.
;; See `world.clj`.
;;
;; Each time the world is transformed (see `transform-world`, for each cell,
;; rules are applied in turn until one matches. Once one rule has matched no
;; further rules can be applied.
(defn apply-rule
"Apply a single `rule` to a `cell`. What this is about is that I want to be able,
for debugging purposes, to tag a cell with the rule text of the rule which
fired (and especially so when an exception is thrown. So a rule may be either
an ifn, or a list (ifn source-text). This function deals with despatching
on those two possibilities. `world` is also passed in in order to be able
to access neighbours."
([world cell rule]
(cond
(ifn? rule) (apply-rule cell world rule nil)
(seq? rule) (let [[afn src] rule] (apply-rule cell world afn src))))
([cell world rule source]
(let [result (apply rule (list cell world))]
(cond
(and result source) (merge result {:rule source})
true result))))
(defn- apply-rules
"Derive a cell from this `cell` of this `world` by applying these `rules`."
[world cell rules]
(cond (empty? rules) cell
true (let [result (apply-rule world cell (first rules))]
(cond result result
true (apply-rules world cell (rest rules))))))
(defn- transform-cell
"Derive a cell from this `cell` of this `world` by applying these `rules`. If an
exception is thrown, cache its message on the cell and set it's state to error"
[world cell rules]
(try
(merge
(apply-rules world cell rules)
{:generation (+ (get-int-or-zero cell :generation) 1)})
(catch Exception e
(merge cell {:error
(format "%s at generation %d when in state %s"
(.getMessage e)
(:generation cell)
(:state cell))
:state :error}))))
(defn transform-world
"Return a world derived from this `world` by applying these `rules` to each cell."
[world rules]
(map-world world transform-cell (list rules)))
(defn- transform-world-state
"Consider this single argument as a map of `:world` and `:rules`; apply the rules
to transform the world, and return a map of the new, transformed `:world` and
these `:rules`. As a side effect, print the world."
[state]
(let [world (transform-world (:world state) (:rules state))]
;;(world/print-world world)
{:world world :rules (:rules state)}))
(defn run-world
"Run this world with these rules for this number of generations.
* `world` a world as discussed above;
* `init-rules` a sequence of rules as defined above, to be run once to initialise the world;
* `rules` a sequence of rules as defined above, to be run iteratively for each generation;
* `generations` an (integer) number of generations.
Return the final generation of the world."
[world init-rules rules generations]
(reduce (fn [world _iteration]
(transform-world world rules))
(transform-world world init-rules)
(range generations)))

View file

@ -1,38 +0,0 @@
(ns mw-engine.display
(:use mw-engine.utils
mw-engine.world)
(:require [hiccup.core :refer [html]]))
(defn format-css-class [state]
"Format this `state`, assumed to be a keyword indicating a state in the
world, into a CSS class"
(subs (str state) 1))
(defn format-image-path
"Render this `state`, assumed to be a keyword indicating a state in the
world, into a path which should recover the corresponding image file."
[state]
(format "img/tiles/%s.png" (format-css-class state)))
(defn format-mouseover [cell]
(str cell))
(defn render-cell
"Render this world cell as a Hiccup table cell."
[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))}
[:img {:alt (:state cell) :width 32 :height 32 :src (format-image-path state)}]]]))
(defn render-world-row
"Render this world `row` as a Hiccup table row."
[row]
(apply vector (cons :tr (map render-cell row))))
(defn render-world-table
"Render this `world` as a Hiccup table."
[world]
(apply vector
(cons :table
(map render-world-row world))))

View file

@ -1,117 +0,0 @@
;; Experimental, probably of no interest to anyone else; attempt to compute drainage on a world,
;; assumed to have altitudes already set from a heighmap.
(ns mw-engine.drainage
(:use mw-engine.utils
mw-engine.world
mw-engine.core)
(:require [mw-engine.heightmap :as heightmap]))
(def ^:dynamic *sealevel* 10)
;; forward declaration of flow, to allow for a wee bit of mutual recursion.
(declare flow)
(defn rain-world
"Simulate rainfall on this `world`. TODO: Doesn't really work just now - should
rain more on west-facing slopes, and less to the east of high ground"
[world]
(map-world world (fn [world cell] (merge cell {:rainfall 1}))))
(defn flow-contributors
"Return a list of the cells in this `world` which are higher than this
`cell` and for which this cell is the lowest neighbour, or which are at the
same altitude and have greater flow"
[cell world]
(filter #(map? %)
(map
(fn [n]
(cond
(= cell (get-least-cell (get-neighbours world n) :altitude)) n
(and (= (:altitude cell) (:altitude n))
(> (or (:flow n) 0) (or (:flow cell) 0))) n))
(get-neighbours-with-property-value
world (:x cell) (:y cell) 1 :altitude
(or (:altitude cell) 0) >=))))
(defn is-hollow
"Detects point hollows - that is, individual cells all of whose neighbours
are higher. Return true if this `cell` has an altitude lower than any of
its neighbours in this `world`"
[world cell]
;; quicker to count the elements of the list and compare equality of numbers
;; than recursive equality check on members, I think. But worth benchmarking.
(let [neighbours (get-neighbours world cell)
altitude (get-int-or-zero cell :altitude)]
(= (count neighbours)
(count (get-neighbours-with-property-value
world (:x cell) (:y cell) 1 :altitude altitude >)))))
(defn flood-hollow
"Raise the altitude of a copy of this `cell` of this `world` to the altitude
of the lowest of its `neighbours`."
([world cell neighbours]
(let [lowest (get-least-cell neighbours :altitude)]
(merge cell {:state :water :altitude (:altitude lowest)})))
([world cell]
(flood-hollow world cell (get-neighbours world cell))))
(defn flood-hollows
"Flood all local hollows in this `world`. At this stage only floods single
cell hollows."
[world]
(map-world world
#(if (is-hollow %1 %2) (flood-hollow %1 %2) %2)))
(def max-altitude 255)
(defn flow-nr
"Experimental non recursive flow algorithm, needs to be run on a world as
many times as there are distinct altitude values. This algorithm works only
if applied sequentially from the highest altitude to the lowest, see
`flow-world-nr`."
[cell world]
(if (= (- max-altitude (get-int-or-zero cell :generation))
(get-int-or-zero cell :altitude))
(merge cell
{:flow (reduce +
(map
#(+ (get-int-or-zero % :rainfall)
(get-int-or-zero % :flow))
(flow-contributors cell world)))})))
(def flow
"Compute the total flow upstream of this `cell` in this `world`, and return a cell identical
to this one but having a value of its flow property set from that computation. The function is
memoised because the consequence of mapping a recursive function across an array is that many
cells will be revisited - potentially many times.
Flow comes from a higher cell to a lower only if the lower is the lowest neighbour of the higher."
(memoize
(fn [cell world]
(cond
(not (nil? (:flow cell))) cell
(<= (or (:altitude cell) 0) *sealevel*) cell
true
(merge cell
{:flow (+ (:rainfall cell)
(apply +
(map (fn [neighbour] (:flow (flow neighbour world)))
(flow-contributors cell world))))})))))
(defn flow-world-nr
"Experimental non-recursive flow-world algorithm"
[world]
(run-world world nil (list flow-nr) max-altitude))
(defn flow-world
"Return a world like this `world`, but with cells tagged with the amount of
water flowing through them."
[world]
(map-world (rain-world world) flow))
(defn run-drainage
[hmap]
"Create a world from the heightmap `hmap`, rain on it, and then compute river
flows."
(flow-world (rain-world (flood-hollows (heightmap/apply-heightmap hmap)))))

View file

@ -1,273 +0,0 @@
;; Utility functions needed by MicroWorld and, specifically, in the
;; interpretation of MicroWorld rule.
(ns mw-engine.utils
(:require
;; [clojure.core.reducers :as r]
[clojure.math.combinatorics :as combo]))
(defn abs
"Surprisingly, Clojure doesn't seem to have an abs function, or else I've
missed it. So here's one of my own. Maps natural numbers onto themselves,
and negative integers onto natural numbers. Also maps negative real numbers
onto positive real numbers.
* `n` a number, on the set of real numbers."
[n]
(if (neg? n) (- 0 n) n))
(defn member?
"True if elt is a member of col."
[elt col] (some #(= elt %) col))
(defn get-int-or-zero
"Return the value of this `property` from this `map` if it is a integer;
otherwise return zero."
[map property]
(let [value (map property)]
(if (integer? value) value 0)))
(defn init-generation
"Return a cell like this `cell`, but having a value for :generation, zero if
the cell passed had no integer value for generation, otherwise the value
taken from the cell passed. The `world` argument is present only for
consistency with the rule engine and is ignored."
[world cell]
(merge cell {:generation (get-int-or-zero cell :generation)}))
(defn in-bounds
"True if x, y are in bounds for this world (i.e., there is a cell at x, y)
else false.
* `world` a world as defined above;
* `x` a number which may or may not be a valid x coordinate within that world;
* `y` a number which may or may not be a valid y coordinate within that world."
[world x y]
(and (>= x 0)(>= y 0)(< y (count world))(< x (count (first world)))))
(defn map-world-n-n
"Wholly non-parallel map world implementation"
([world function]
(map-world-n-n world function nil))
([world function additional-args]
(into []
(map (fn [row]
(into [] (map
#(apply function
(cons world (cons % additional-args)))
row)))
world))))
(defn map-world-p-p
"Wholly parallel map world implementation"
([world function]
(map-world-p-p world function nil))
([world function additional-args]
(into []
(pmap (fn [row]
(into [] (pmap
#(apply function
(cons world (cons % additional-args)))
row)))
world))))
(defn map-world
"Apply this `function` to each cell in this `world` to produce a new world.
the arguments to the function will be the world, the cell, and any
`additional-args` supplied. Note that we parallel map over rows but
just map over cells within a row. That's because it isn't worth starting
a new thread for each cell, but there may be efficiency gains in
running rows in parallel."
([world function]
(map-world world function nil))
([world function additional-args]
(into []
(pmap (fn [row]
(into [] (map
#(apply function
(cons world (cons % additional-args)))
row)))
world))))
(defn get-cell
"Return the cell a x, y in this world, if any.
* `world` a world as defined above;
* `x` a number which may or may not be a valid x coordinate within that world;
* `y` a number which may or may not be a valid y coordinate within that world."
[world x y]
(cond (in-bounds world x y)
(nth (nth world y) x)))
(defn get-int
"Get the value of a property expected to be an integer from a map; if not present (or not an integer) return 0.
* `map` a map;
* `key` a symbol or keyword, presumed to be a key into the `map`."
[map key]
(cond (map? map)
(let [v (map key)]
(cond (and v (integer? v)) v
true 0))
true (throw (Exception. "No map passed?"))))
(defn population
"Return the population of this species in this cell. Currently a synonym for
`get-int`, but may not always be (depending whether species are later
implemented as actors)
* `cell` a map;
* `species` a keyword representing a species which may populate that cell."
[cell species]
(get-int cell species))
(def memo-get-neighbours
"Memoised get neighbours is more efficient when running deeply recursive
algorithms on the same world. But it's less efficient when running the
engine in its normal iterative style, because then we will rarely call
get naighbours on the same cell of the same world twice."
(memoize
(fn [world x y depth]
(remove nil?
(map #(get-cell world (first %) (first (rest %)))
(remove #(= % (list x y))
(combo/cartesian-product
(range (- x depth) (+ x depth 1))
(range (- y depth) (+ y depth 1)))))))))
(defn get-neighbours
"Get the neighbours to distance depth of a cell in this world.
Several overloads:
* `world` a world, as described in world.clj;
* `cell` a cell within that world
Gets immediate neighbours of the specified cell.
* `world` a world, as described in world.clj;
* `cell` a cell within that world
* `depth` an integer representing the depth to search from the
`cell`
Gets neighbours within the specified distance of the cell.
* `world` a world, as described in world.clj;
* `x` an integer representing an x coordinate in that world;
* `y` an integer representing an y coordinate in that world;
* `depth` an integer representing the distance from [x,y] that
should be searched
Gets the neighbours within the specified distance of the cell at
coordinates [x,y] in this world."
([world x y depth]
(remove nil?
(map #(get-cell world (first %) (first (rest %)))
(remove #(= % (list x y))
(combo/cartesian-product
(range (- x depth) (+ x depth 1))
(range (- y depth) (+ y depth 1)))))))
([world cell depth]
(memo-get-neighbours world (:x cell) (:y cell) depth))
([world cell]
(get-neighbours world cell 1)))
(defn get-neighbours-with-property-value
"Get the neighbours to distance depth of the cell at x, y in this world which
have this value for this property.
* `world` a world, as described in `world.clj`;
* `cell` a cell within that world;
* `depth` an integer representing the distance from [x,y] that
should be searched (optional);
* `property` a keyword representing a property of the neighbours;
* `value` a value of that property (or, possibly, the name of another);
* `op` a comparator function to use in place of `=` (optional).
It gets messy."
([world x y depth property value op]
(filter
#(eval
(list op
(or (get % property) (get-int % property))
value))
(get-neighbours world x y depth)))
([world x y depth property value]
(get-neighbours-with-property-value world x y depth property value =))
([world cell depth property value]
(get-neighbours-with-property-value world (:x cell) (:y cell) depth
property value))
([world cell property value]
(get-neighbours-with-property-value world cell 1
property value)))
(defn get-neighbours-with-state
"Get the neighbours to distance depth of the cell at x, y in this world which
have this state.
* `world` a world, as described in `world.clj`;
* `cell` a cell within that world;
* `depth` an integer representing the distance from [x,y] that
should be searched;
* `state` a keyword representing a state in the world."
([world x y depth state]
(filter #(= (:state %) state) (get-neighbours world x y depth)))
([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)))
(defn get-least-cell
"Return the cell from among these `cells` which has the lowest numeric value
for this `property`; if the property is absent or not a number, use this
`default`"
([cells property default]
(cond
(empty? cells) nil
true (let [downstream (get-least-cell (rest cells) property default)]
(cond (<
(or (property (first cells)) default)
(or (property downstream) default)) (first cells)
true downstream))))
([cells property]
(get-least-cell cells property (Integer/MAX_VALUE))))
(defn- set-cell-property
"If this `cell`s x and y properties are equal to these `x` and `y` values,
return a cell like this cell but with the value of this `property` set to
this `value`. Otherwise, just return this `cell`."
[cell x y property value]
(cond
(and (= x (:x cell)) (= y (:y cell)))
(merge cell {property value :rule "Set by user"})
true
cell))
(defn set-property
"Return a world like this `world` but with the value of exactly one `property`
of one `cell` changed to this `value`"
([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))))
(defn merge-cell
"Return a world like this `world`, but merge the values from this `cell` with
those from the cell in the world with the same co-ordinates"
[world cell]
(if (in-bounds world (:x cell) (:y cell))
(map-world world
#(if
(and
(= (:x cell)(:x %2))
(= (:y cell)(:y %2)))
(merge %2 cell)
%2))
world))

View file

@ -1,16 +0,0 @@
(ns mw-engine.version
(:gen-class))
(defn get-implementation-version
"Get the implementation version from the package of this namespace, which must
be compiled into a class (see clojure.java.interop). See
http://stackoverflow.com/questions/12599889/how-to-get-runtime-access-to-version-number-of-a-running-clojure-application
TODO: doesn't work yet."
[]
(try
(.getImplementationVersion (.getPackage (eval 'mw-engine.version)))
(catch Exception any "Unknown")
))
(defn -main []
(get-implementation-version ))

View file

@ -1,85 +0,0 @@
;; 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.
;;
;; A cell is a map containing at least values for the keys :x, :y, and :state.
;;
;; A world is a two dimensional matrix (sequence of sequences) of cells, such
;; that every cell's :x and :y properties reflect its place in the matrix.
(ns mw-engine.world
(:use mw-engine.utils)
(:require [clojure.string :as string :only [join]]))
(defn- make-cell
"Create a minimal default cell at x, y
* `x` the x coordinate at which this cell is created;
* `y` the y coordinate at which this cell is created."
[x y]
{:x x :y y :state :new})
(defn- make-world-row
"Make the (remaining) cells in a row at this height in a world of this width.
* `index` x coordinate of the next cell to be created;
* `width` total width of the matrix, in cells;
* `height` y coordinate of the next cell to be created."
[index width height]
(cond (= index width) nil
true (cons (make-cell index height)
(make-world-row (inc index) width height))))
(defn- make-world-rows
"Make the (remaining) rows in a world of this width and height, from this
index.
* `index` y coordinate of the next row to be created;
* `width` total width of the matrix, in cells;
* `height` total height of the matrix, in cells."
[index width height]
(cond (= index height) nil
true (cons (apply vector (make-world-row 0 width index))
(make-world-rows (inc index) width height))))
(defn make-world
"Make a world width cells from east to west, and height cells from north to
south.
* `width` a natural number representing the width of the matrix to be created;
* `height` a natural number representing the height of the matrix to be created."
[width height]
(apply vector (make-world-rows 0 width height)))
(defn truncate-state
"Truncate the print name of the state of this cell to at most limit characters."
[cell limit]
(let [s (:state cell)]
(cond (> (count (str s)) limit) (subs s 0 limit)
true s)))
(defn format-cell
"Return a formatted string summarising the current state of this cell."
[cell]
(format "%10s(%2d/%2d)"
(truncate-state cell 10)
(population cell :deer)
(population cell :wolves)))
(defn- format-world-row
"Format one row in the state of a world for printing."
[row]
(string/join (map format-cell row)))
(defn print-world
"Print the current state of this world, and return nil.
* `world` a world as defined above."
[world]
(println)
(dorun
(map
#(println
(format-world-row %))
world))
nil)

View file

@ -1,24 +1,54 @@
(ns mw-engine.core-test
(:require [clojure.test :refer :all]
[mw-engine.core :refer :all]))
(:require [clojure.test :refer [deftest is testing]]
[mw-engine.core :refer [*with-history* apply-rule transform-world]]
[mw-engine.utils :refer [map-world]]
[mw-engine.world :refer [make-world]]))
(deftest apply-rule-test
(testing "Application of a single rule"
(let [afn (eval
(fn [cell world]
(cond
(= (:state cell) :new)
(merge cell {:state :grassland}))))
pair (list afn "Test source")]
(is (nil? (apply-rule nil {:state :water} afn))
"Rule shouldn't fire when state is wrong")
(is (nil? (apply-rule nil {:state :water} pair))
"Rule shouldn't fire when state is wrong")
(is (= (:state (apply-rule nil {:state :new} afn)) :grassland)
"Rule should fire when state is correct")
(is (= (:state (apply-rule nil {:state :new} pair)) :grassland)
"Rule should fire when state is correct")
(is (nil? (:rule (apply-rule nil {:state :new} afn)))
"No rule text if not provided")
(is (= (:rule (apply-rule nil {:state :new} pair)) "Test source")
"Rule text cached on cell if provided"))))
(binding [*with-history* true]
(let [afn (vary-meta
(eval
(fn [cell _world]
(cond
(= (:state cell) :new)
(merge cell {:state :grassland}))))
merge {:rule-type :production
:rule "Test source"})]
(is (nil? (apply-rule nil {:state :water} afn))
"Rule shouldn't fire when state is wrong")
(is (= (:state (apply-rule nil {:state :new} afn)) :grassland)
"Rule should fire when state is correct")
(is (seq? (:history (apply-rule nil {:state :new} afn)))
"Event cached on history of cell")))
(binding [*with-history* false]
(let [afn (vary-meta
(eval
(fn [cell _world]
(cond
(= (:state cell) :new)
(merge cell {:state :grassland}))))
merge {:rule-type :production
:rule "Test source"})
modified-cell (apply-rule nil {:state :new} afn)]
(is (= (:state modified-cell) :grassland)
"Rule should fire when state is correct")
(is (nil? (:history modified-cell))
"No event cached on history of cell")))))
(deftest transform-world-tests
(testing "Application of a single rule"
(let [afn (vary-meta
(eval
(fn [cell _world]
(cond
(= (:state cell) :new)
(merge cell {:state :grassland}))))
merge {:rule-type :production
:rule "Test source"})
world (make-world 3 3)
expected [[{:y 0, :state :grassland, :x 0} {:y 0, :state :grassland, :x 1} {:y 0, :state :grassland, :x 2}]
[{:y 1, :state :grassland, :x 0} {:y 1, :state :grassland, :x 1} {:y 1, :state :grassland, :x 2}]
[{:y 2, :state :grassland, :x 0} {:y 2, :state :grassland, :x 1} {:y 2, :state :grassland, :x 2}]]
actual (map-world (transform-world world (list afn)) (fn [_ c] (select-keys c [:x :y :state])))]
(is (= actual expected)))))

View file

@ -1,8 +1,8 @@
(ns mw-engine.drainage-test
(:require [clojure.test :refer :all]
[mw-engine.world :as world]
(:require [clojure.test :refer [deftest is testing]]
[mw-engine.drainage :refer [flood-hollow flood-hollows is-hollow]]
[mw-engine.utils :as utils]
[mw-engine.drainage :refer :all]))
[mw-engine.world :as world]))
(deftest is-hollow-test
(testing "detection of hollows"

View file

@ -0,0 +1,85 @@
(ns mw-engine.flow-test
(:require [clojure.test :refer [deftest is testing]]
[mw-engine.flow :refer [coordinate? create-flow-percent
create-location execute execute-flows flow?
location?]]
[mw-engine.utils :refer [get-cell merge-cell]]
[mw-engine.world :refer [make-world]]))
(deftest coordinate-tests
(testing "coordinates"
(let [world (make-world 3 3)]
(is (not (coordinate? -1 world)) "Not a coordinate: negative")
(is (not (coordinate? 4 world)) "Not a coordinate: out of bounds")
(is (not (coordinate? 3 world)) "Not a coordinate: boundary")
(is (not (coordinate? :three world)) "Not a coordinate: keyword")
(is (not (coordinate? 3.14 world)) "Not a coordinate: floating point")
(is (coordinate? 0 world) "should be a coordinate: zero")
(is (coordinate? 1 world) "should be a coordinate: middle"))))
(deftest location-tests
(testing "locations"
(let [world (make-world 3 3)
in1 {:x 0 :y 0}
in2 {:x 1 :y 2}
out1 {:p 0 :q 0}
out2 {:x -1 :y 2}]
(is (location? in1 world) "should be a location: top left")
(is (location? in2 world) "should be a location: middle bottom")
(is (not (location? out1 world)) "should not be a location: wrong keys")
(is (not (location? out2 world)) "should not be a location: negative coordinate"))))
(deftest flow-tests
(testing "flows"
(let [world (make-world 3 3)
world' (merge-cell world {:x 0, :y 0, :state :new :q 5.3})
valid {:source {:x 0 :y 0}
:destination {:x 1 :y 1}
:property :q
:quantity 2.4}]
(is (flow? valid world))
(let [transferred (execute world' valid)
source-q (:q (get-cell transferred 0 0))
dest-q (:q (get-cell transferred 1 1))]
(is (= source-q 2.9))
(is (= dest-q 2.4)))
(let [valid2 {:source {:x 1 :y 1}
:destination {:x 0 :y 1}
:property :q
:quantity 1}
transferred (execute-flows world' (list valid valid2))
source-q (:q (get-cell transferred 0 0))
inter-q (:q (get-cell transferred 1 1))
dest-q (:q (get-cell transferred 0 1))]
(is (= source-q 2.9))
(is (= inter-q 1.4))
(is (= dest-q 1))))
(let [world (make-world 3 3)
world' (merge-cell world {:x 0, :y 0, :state :new :q 5.3})
highdemand {:source {:x 0 :y 0}
:destination {:x 1 :y 1}
:property :q
:quantity 7.4}
transferred (execute world' highdemand)
source-q (:q (get-cell transferred 0 0))
dest-q (:q (get-cell transferred 1 1))
sx 0.0
dx 5.3]
(is (= source-q sx) "The entire stock should have gone;")
(is (= dest-q dx) "Only as much as was available should have arrived."))))
(deftest creator-macro-tests
(testing "Creator macros"
(let [source {:x 1 :y 2 :q 5.7 :state :house}
dest {:x 3 :y 3 :q 1 :state :house}
prop :q]
(let [expected {:x 1, :y 2}
actual (create-location source)]
(is (= actual expected)))
(let [expected {:source {:x 1, :y 2},
:prop :q,
:quantity 1.425,
:destination {:x 3, :y 3}}
actual (create-flow-percent source dest prop 25)]
(is (= actual expected))
(is (= (:quantity actual) (* 0.25 (:q source))))))))

View file

@ -1,9 +1,8 @@
(ns mw-engine.heightmap-test
(:use clojure.java.io)
(:require [clojure.test :refer :all]
[mw-engine.heightmap :refer :all]
[mw-engine.world :as world :only [make-world]]
[clojure.math.combinatorics :as combo]))
(:require [clojure.java.io :refer [as-file]]
[clojure.test :refer [deftest is testing]]
[mw-engine.heightmap :refer [apply-heightmap apply-valuemap]]
[mw-engine.world :refer [make-world]]))
(deftest apply-heightmap-test
(testing "Heightmap functionality"
@ -22,7 +21,7 @@
(is (> (apply + gradients) 0)
"At least some gradients must be positive, none should be negative"))
;; alternate means of making the world, same tests.
(let [world (apply-heightmap (world/make-world 9 9) (as-file "resources/heightmaps/test9x9.png"))
(let [world (apply-heightmap (make-world 9 9) (as-file "resources/heightmaps/test9x9.png"))
altitudes (map #(:altitude %) (flatten world))
gradients (map #(:gradient %) (flatten world))]
(is (= (count world) 9) "World should be 9x9")

View file

@ -1,8 +1,11 @@
(ns mw-engine.utils-test
(:use [mw-engine.world :as world])
(:require [clojure.test :refer :all]
[clojure.math.combinatorics :as combo]
[mw-engine.utils :refer :all]))
(:require [clojure.math.combinatorics :as combo]
[clojure.test :refer [deftest is testing]]
[mw-engine.utils :refer [get-cell get-least-cell get-most-cell
get-neighbours
get-neighbours-with-property-value
map-world merge-cell set-property]]
[mw-engine.world :refer [make-world]]))
(deftest abs-test
(testing "Absolute value function"
@ -116,8 +119,8 @@
(let [w1a (make-world 3 3)
w2b (set-property w1a (get-cell w1a 1 1) :location :centre)
w3c (set-property w2b 0 0 :location :top-left)]
(is (= (:location (get-cell w3c 0 0) :top-left)))
(is (= (:location (get-cell w3c 1 1) :centre)))
(is (= (:location (get-cell w3c 0 0)) :top-left))
(is (= (:location (get-cell w3c 1 1)) :centre))
(is (nil? (:location (get-cell w3c 2 2)))
"Cell at 2,2 should not have location set")
(is (= (count (remove nil? (map #(:location %) (flatten w3c)))) 2)
@ -178,4 +181,20 @@
(is (:test (get-cell w3c 2 2))
"The cell with :test set is at 2, 2"))))
(deftest most-least-tests
(let [cells [{:x 0, :y 0, :state :new, :prop 0.4406204774301924}
{:x 1, :y 0, :state :new, :prop 0.26475629405490275}
{:x 2, :y 0, :state :new, :prop 0.34018209505715813}
{:x 0, :y 1, :state :new, :prop 0.35104719397171424}
{:x 1, :y 1, :state :new, :prop 0.6009298123397215} ;; <- max
{:x 2, :y 1, :state :new, :prop 0.5580383897506066}
{:x 0, :y 2, :state :new, :prop 0.1780241365266907} ;; <- min
{:x 1, :y 2, :state :new, :prop 0.3255028139128574}
{:x 2, :y 2, :state :new, :prop 0.3449965660347397}]]
(let [expected {:x 1, :y 1, :state :new, :prop 0.6009298123397215}
actual (get-most-cell cells :prop)]
(is (= actual expected) "get-most-cell failed")
)
(let [expected {:x 0, :y 2, :state :new, :prop 0.1780241365266907}
actual (get-least-cell cells :prop)]
(is (= actual expected) "get-least-cell failed"))))

View file

@ -1,6 +1,6 @@
(ns mw-engine.world-test
(:require [clojure.test :refer :all]
[mw-engine.world :refer :all]
(:require [clojure.test :refer [deftest is testing]]
[mw-engine.world :refer [make-world]]
[clojure.math.combinatorics :as combo]))
(deftest genesis-test