Compare commits
31 commits
Author | SHA1 | Date | |
---|---|---|---|
|
29d9c2e549 | ||
|
a44e9548a2 | ||
|
716eb9442e | ||
|
c739dd7094 | ||
|
e19ce2e5f7 | ||
|
93dab8067b | ||
|
3e1e3052d1 | ||
|
4b1472d311 | ||
|
85d66208b9 | ||
|
ac25969f90 | ||
|
ff6bbad14c | ||
|
321e6edd9a | ||
|
68298cf9c1 | ||
|
866c00bea0 | ||
|
4f35557b38 | ||
|
8b3639edd5 | ||
|
f60fdb944b | ||
|
5ef93ef4df | ||
|
f4d4e9b694 | ||
|
67a43279f6 | ||
|
630309719e | ||
|
2cb3a6af6f | ||
|
1cb613e6e6 | ||
|
2f2463da0e | ||
|
519ca4e3bd | ||
|
3ca247e471 | ||
|
47caea3eb8 | ||
|
39b7cd608c | ||
|
f1b35dc948 | ||
|
944b54fc89 | ||
|
21cdff764f |
.gitignoreREADME.mdbuildall.shuberdoc.htmlproject.clj
docs
cloverage
codox
css
index.htmlintro.htmljs
mw-engine.core.htmlmw-engine.display.htmlmw-engine.drainage.htmlmw-engine.flow.htmlmw-engine.heightmap.htmlmw-engine.natural-rules.htmlmw-engine.render.htmlmw-engine.utils.htmlmw-engine.world.htmlresources
src
cljc/mw_engine
mw_engine
test/mw_engine
19
.gitignore
vendored
Normal file
19
.gitignore
vendored
Normal 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
|
|
@ -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
|
||||
|
|
236
buildall.sh
236
buildall.sh
|
@ -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
|
||||
|
||||
|
||||
|
|
40
docs/cloverage/coverage.css
Normal file
40
docs/cloverage/coverage.css
Normal 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
172
docs/cloverage/index.html
Normal 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>
|
443
docs/cloverage/mw_engine/core.clj.html
Normal file
443
docs/cloverage/mw_engine/core.clj.html
Normal 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 (ns ^{:doc "Functions to transform a world and run rules.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
002
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
003 Every rule is a function of two arguments, a cell and a world. If the rule
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
004 fires, it returns a new cell, which should have the same values for `:x` and
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
005 `:y` as the old cell. Anything else can be modified.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
006
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
007 While any function of two arguments can be used as a rule, a special high
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
008 level rule language is provided by the `mw-parser` package, which compiles
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
009 rules expressed in a subset of English rules into suitable functions.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
010
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
011 A cell is a map containing at least values for the keys :x, :y, and :state;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
012 a transformation should not alter the values of :x or :y, and should not
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
013 return a cell without a keyword as the value of :state. Anything else is
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
014 legal.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
015
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
016 A world is a two dimensional matrix (sequence of sequences) of cells, such
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
017 that every cell's `:x` and `:y` properties reflect its place in the matrix.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
018 See `world.clj`.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
019
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
020 Each time the world is transformed (see `transform-world`), for each cell,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
021 rules are applied in turn until one matches. Once one rule has matched no
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
022 further rules can be applied to that cell."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
023 :author "Simon Brooke"}
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
024 mw-engine.core
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
025 (:require [mw-engine.flow :refer [flow-world]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
026 [mw-engine.utils :refer [add-history-event get-int-or-zero map-world rule-type]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
027 [taoensso.timbre :as l]))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
028
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
029 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
030 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
031 ;;;; mw-engine: the state/transition engine of MicroWorld.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
032 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
033 ;;;; This program is free software; you can redistribute it and/or
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
034 ;;;; modify it under the terms of the GNU General Public License
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
035 ;;;; as published by the Free Software Foundation; either version 2
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
036 ;;;; of the License, or (at your option) any later version.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
037 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
038 ;;;; This program is distributed in the hope that it will be useful,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
039 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
040 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
041 ;;;; GNU General Public License for more details.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
042 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
043 ;;;; You should have received a copy of the GNU General Public License
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
044 ;;;; along with this program; if not, write to the Free Software
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
045 ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
046 ;;;; USA.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
047 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
048 ;;;; Copyright (C) 2014 Simon Brooke
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
049 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
050 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
051
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
052 (def ^:dynamic *with-history*
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
053 "I suspect that caching history on the cells is greatly worsening the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
054 memory problems. Make it optional, but by default false."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
055 false)
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
056
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
057 (defn apply-rule
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
058 "Apply a single `rule` to a `cell`. What this is about is that I want to be able,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
059 for debugging purposes, to tag a cell with the rule text of the rule which
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
060 fired (and especially so when an exception is thrown). "
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
061 ;; as of version 0-3-0, metadata for rules is now passed around on the metadata
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
062 ;; of the rule function itself. Yes, I know, this is obvious; but I'll confess
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
063 ;; I didn't think of it before.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
064 [world cell rule]
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
065 (let [result (try
|
||||
</span><br/>
|
||||
<span class="covered" title="7 out of 7 forms covered">
|
||||
066 (apply rule (list cell world))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
067 (catch Exception e
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 16 forms covered">
|
||||
068 (l/warn e
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
069 (format
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
070 "Error in `apply-rule`: `%s` (%s) while executing rule `%s` on cell `%s`"
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
071 e
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
072 (.getMessage e)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
073 (-> rule meta :lisp)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
074 cell))))]
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
075 (if *with-history*
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
076 (add-history-event result rule)
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
077 result)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
078
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
079 (defn- apply-rules
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
080 "Derive a cell from this `cell` of this `world` by applying these `rules`."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
081 [world cell rules]
|
||||
</span><br/>
|
||||
<span class="partial" title="4 out of 5 forms covered">
|
||||
082 (or
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
083 (first
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
084 (remove
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
085 nil?
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
086 (try
|
||||
</span><br/>
|
||||
<span class="covered" title="9 out of 9 forms covered">
|
||||
087 (map #(apply-rule world cell %) rules)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
088 (catch Exception e
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 16 forms covered">
|
||||
089 (l/warn e
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
090 (format
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
091 "Error in `apply-rules`: `%s` (%s) while executing rules on cell `%s`"
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
092 (-> e .getClass .getName)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
093 (.getMessage e)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
094 cell))))))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
095 cell))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
096
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
097 (defn- transform-cell
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
098 "Derive a cell from this `cell` of this `world` by applying these `rules`. If an
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
099 exception is thrown, cache its message on the cell and set it's state to error"
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
100 [world cell rules]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
101 (try
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
102 (merge
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
103 (apply-rules world cell rules)
|
||||
</span><br/>
|
||||
<span class="covered" title="8 out of 8 forms covered">
|
||||
104 {:generation (+ (get-int-or-zero cell :generation) 1)})
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
105 (catch Exception e
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
106 (let [narrative (format "Error in `transform-cell`: `%s` (%s) at generation %d when in state %s;"
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
107 (-> e .getClass .getName)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
108 (.getMessage e)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
109 (:generation cell)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
110 (:state cell))]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 17 forms covered">
|
||||
111 (l/warn e narrative)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
112 cell))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
113
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
114 (defn transform-world
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
115 "Return a world derived from this `world` by applying the production rules
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
116 found among these `rules` to each cell."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
117 [world rules]
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
118 (map-world world transform-cell
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
119 ;; Yes, that `list` is there for a reason!
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
120 (list
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
121 (filter
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
122 #(= :production (rule-type %))
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
123 rules))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
124
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
125 (defn run-world
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
126 "Run this world with these rules for this number of generations.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
127
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
128 * `world` a world as discussed above;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
129 * `init-rules` a sequence of rules as defined above, to be run once to initialise the world;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
130 * `rules` a sequence of rules as defined above, to be run iteratively for each generation;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
131 * `generations` an (integer) number of generations.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
132
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
133 **NOTE THAT** all rules **must** be tagged with `rule-type` metadata, or thet **will not**
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
134 be executed.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
135
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
136 Return the final generation of the world."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
137 ([world rules generations]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 7 forms covered">
|
||||
138 (run-world world rules rules (dec generations)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
139 ([world init-rules rules generations]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
140 (reduce (fn [world iteration]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 17 forms covered">
|
||||
141 (l/info "Running iteration " iteration)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
142 (let [w' (transform-world world rules)]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
143 (flow-world w' rules)))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
144 (transform-world world init-rules)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
145 (range generations))))
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
203
docs/cloverage/mw_engine/display.clj.html
Normal file
203
docs/cloverage/mw_engine/display.clj.html
Normal 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 (ns ^{:doc "Simple functions to allow a world to be visualised."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
002 :author "Simon Brooke"}
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
003 mw-engine.display)
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
004
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
005 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
006 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
007 ;;;; mw-engine: the state/transition engine of MicroWorld.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
008 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
009 ;;;; This program is free software; you can redistribute it and/or
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
010 ;;;; modify it under the terms of the GNU General Public License
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
011 ;;;; as published by the Free Software Foundation; either version 2
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
012 ;;;; of the License, or (at your option) any later version.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
013 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
014 ;;;; This program is distributed in the hope that it will be useful,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
015 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
016 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
017 ;;;; GNU General Public License for more details.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
018 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
019 ;;;; You should have received a copy of the GNU General Public License
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
020 ;;;; along with this program; if not, write to the Free Software
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
021 ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
022 ;;;; USA.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
023 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
024 ;;;; Copyright (C) 2014 Simon Brooke
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
025 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
026 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
027
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
028 (def ^:dynamic *image-base*
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
029 "Base url (i.e., url of directory) from which to load tile images."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
030 "img/tiles")
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
031
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
032 (defn format-css-class
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
033 "Format this `state`, assumed to be a keyword indicating a state in the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
034 world, into a CSS class"
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
035 [state]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
036 (subs (str state) 1))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
037
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
038 (defn format-image-path
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
039 "Render this `state`, assumed to be a keyword indicating a state in the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
040 world, into a path which should recover the corresponding image file."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
041 [state]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 7 forms covered">
|
||||
042 (format "%s/%s.png" *image-base* (format-css-class state)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
043
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
044 (defn format-mouseover [cell]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
045 (str cell))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
046
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
047 (defn render-cell
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
048 "Render this world cell as a Hiccup table cell."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
049 [cell]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
050 (let [state (:state cell)]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 11 forms covered">
|
||||
051 [:td {:class (format-css-class state) :title (format-mouseover cell)}
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 13 forms covered">
|
||||
052 [:a {:href (format "inspect?x=%d&y=%d" (:x cell) (:y cell))}
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 15 forms covered">
|
||||
053 [:img {:alt (:state cell) :width 32 :height 32 :src (format-image-path state)}]]]))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
054
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
055 (defn render-world-row
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
056 "Render this world `row` as a Hiccup table row."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
057 [row]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 10 forms covered">
|
||||
058 (apply vector (cons :tr (map render-cell row))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
059
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
060 (defn render-world-table
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
061 "Render this `world` as a Hiccup table."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
062 [world]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
063 (apply vector
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
064 (cons :table
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
065 (map render-world-row world))))
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
659
docs/cloverage/mw_engine/drainage.clj.html
Normal file
659
docs/cloverage/mw_engine/drainage.clj.html
Normal 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 (ns ^{:doc "Experimental, probably of no interest to anyone else; attempt to
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
002 compute drainage on a world, assumed to have altitudes already set
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
003 from a heightmap."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
004 :author "Simon Brooke"}
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
005 mw-engine.drainage
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
006 (:require [mw-engine.core :refer [run-world]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
007 [mw-engine.heightmap :as heightmap]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
008 [mw-engine.utils :refer [get-int-or-zero get-least-cell get-neighbours
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
009 get-neighbours-with-property-value
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
010 map-world]]))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
011
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
012 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
013 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
014 ;;;; mw-engine: the state/transition engine of MicroWorld.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
015 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
016 ;;;; This program is free software; you can redistribute it and/or
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
017 ;;;; modify it under the terms of the GNU General Public License
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
018 ;;;; as published by the Free Software Foundation; either version 2
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
019 ;;;; of the License, or (at your option) any later version.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
020 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
021 ;;;; This program is distributed in the hope that it will be useful,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
022 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
023 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
024 ;;;; GNU General Public License for more details.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
025 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
026 ;;;; You should have received a copy of the GNU General Public License
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
027 ;;;; along with this program; if not, write to the Free Software
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
028 ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
029 ;;;; USA.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
030 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
031 ;;;; Copyright (C) 2014 Simon Brooke
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
032 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
033 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
034
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
035
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
036 (def ^:dynamic *sealevel* 10)
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
037
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
038 ;; forward declaration of flow, to allow for a wee bit of mutual recursion.
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
039 (declare flow)
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
040
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
041 (defn rainfall
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
042 "Compute rainfall for a cell with this `gradient` west-east, given
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
043 `remaining` drops to distribute, and this overall map width."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
044 [gradient remaining map-width]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 7 forms covered">
|
||||
045 (cond
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
046 ;; if there's no rain left in the cloud, it can't fall;
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
047 (zero? remaining)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
048 0
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
049 (pos? gradient)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
050 ;; rain, on prevailing westerly wind, falls preferentially on rising ground;
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
051 (int (rand gradient))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
052 ;; rain falls randomly across the width of the map...
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
053 (zero? (int (rand map-width))) 1
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
054 :else
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
055 0))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
056
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
057 (defn rain-row
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
058 "Return a row like this `row`, across which rainfall has been distributed;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
059 if `rain-probability` is specified, it is the probable rainfall on a cell
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
060 with no gradient."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
061 ([row]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
062 (rain-row row 1))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
063 ([row rain-probability]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 11 forms covered">
|
||||
064 (rain-row row (count row) 0 (int (* (count row) rain-probability))))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
065 ([row map-width previous-altitude drops-in-cloud]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
066 (cond
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
067 (empty? row) nil
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
068 (pos? drops-in-cloud)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
069 (let [cell (first row)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 8 forms covered">
|
||||
070 alt (or (:altitude cell) 0)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
071 rising (- alt previous-altitude)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
072 fall (rainfall rising drops-in-cloud map-width)]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
073 (cons
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
074 (assoc cell :rainfall fall)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 10 forms covered">
|
||||
075 (rain-row (rest row) map-width alt (- drops-in-cloud fall))))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
076 :else
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
077 (map
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
078 #(assoc % :rainfall 0)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
079 row))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
080
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
081
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
082 (defn rain-world
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
083 "Simulate rainfall on this `world`. TODO: Doesn't really work just now - should
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
084 rain more on west-facing slopes, and less to the east of high ground"
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
085 [world]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
086 (map
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
087 rain-row
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
088 world))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
089
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
090
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
091 (defn flow-contributors
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
092 "Return a list of the cells in this `world` which are higher than this
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
093 `cell` and for which this cell is the lowest neighbour, or which are at the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
094 same altitude and have greater flow"
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
095 [cell world]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
096 (filter #(map? %)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
097 (map
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
098 (fn [n]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
099 (cond
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 10 forms covered">
|
||||
100 (= cell (get-least-cell (get-neighbours world n) :altitude)) n
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 12 forms covered">
|
||||
101 (and (= (:altitude cell) (:altitude n))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 17 forms covered">
|
||||
102 (> (or (:flow n) 0) (or (:flow cell) 0))) n))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
103 (get-neighbours-with-property-value
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 7 forms covered">
|
||||
104 world (:x cell) (:y cell) 1 :altitude
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 9 forms covered">
|
||||
105 (or (:altitude cell) 0) >=))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
106
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
107
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
108 (defn is-hollow
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
109 "Detects point hollows - that is, individual cells all of whose neighbours
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
110 are higher. Return true if this `cell` has an altitude lower than any of
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
111 its neighbours in this `world`"
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
112 [world cell]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
113 ;; quicker to count the elements of the list and compare equality of numbers
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
114 ;; than recursive equality check on members, I think. But worth benchmarking.
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
115 (let [neighbours (get-neighbours world cell)
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
116 altitude (get-int-or-zero cell :altitude)]
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
117 (= (count neighbours)
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
118 (count (get-neighbours-with-property-value
|
||||
</span><br/>
|
||||
<span class="covered" title="9 out of 9 forms covered">
|
||||
119 world (:x cell) (:y cell) 1 :altitude altitude >)))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
120
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
121
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
122 (defn flood-hollow
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
123 "Raise the altitude of a copy of this `cell` of this `world` to the altitude
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
124 of the lowest of its `neighbours`."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
125 ([_world cell neighbours]
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
126 (let [lowest (get-least-cell neighbours :altitude)]
|
||||
</span><br/>
|
||||
<span class="covered" title="10 out of 10 forms covered">
|
||||
127 (merge cell {:state :water :altitude (:altitude lowest)})))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
128 ([world cell]
|
||||
</span><br/>
|
||||
<span class="covered" title="8 out of 8 forms covered">
|
||||
129 (flood-hollow world cell (get-neighbours world cell))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
130
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
131
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
132 (defn flood-hollows
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
133 "Flood all local hollows in this `world`. At this stage only floods single
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
134 cell hollows."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
135 [world]
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
136 (map-world world
|
||||
</span><br/>
|
||||
<span class="covered" title="10 out of 10 forms covered">
|
||||
137 #(if (is-hollow %1 %2) (flood-hollow %1 %2) %2)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
138
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
139
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
140 (def max-altitude 255)
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
141
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
142 (defn flow-nr
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
143 "Experimental non recursive flow algorithm, needs to be run on a world as
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
144 many times as there are distinct altitude values. This algorithm works only
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
145 if applied sequentially from the highest altitude to the lowest, see
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
146 `flow-world-nr`."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
147 [cell world]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 9 forms covered">
|
||||
148 (when (= (- max-altitude (get-int-or-zero cell :generation))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
149 (get-int-or-zero cell :altitude))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
150 (merge cell
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
151 {:flow (reduce +
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
152 (map
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
153 #(+ (get-int-or-zero % :rainfall)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
154 (get-int-or-zero % :flow))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
155 (flow-contributors cell world)))})))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
156
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
157
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
158 (def flow
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
159 "Compute the total flow upstream of this `cell` in this `world`, and return a cell identical
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
160 to this one but having a value of its flow property set from that computation. The function is
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
161 memoised because the consequence of mapping a recursive function across an array is that many
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
162 cells will be revisited - potentially many times.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
163
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
164 Flow comes from a higher cell to a lower only if the lower is the lowest neighbour of the higher."
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
165 (memoize
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
166 (fn [cell world]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
167 (cond
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 8 forms covered">
|
||||
168 (not (nil? (:flow cell))) cell
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 11 forms covered">
|
||||
169 (<= (or (:altitude cell) 0) *sealevel*) cell
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
170 :else
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
171 (merge cell
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
172 {:flow (+ (:rainfall cell)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
173 (apply +
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 9 forms covered">
|
||||
174 (map (fn [neighbour] (:flow (flow neighbour world)))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
175 (flow-contributors cell world))))})))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
176
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
177
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
178 (defn flow-world-nr
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
179 "Experimental non-recursive flow-world algorithm"
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
180 [world]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 8 forms covered">
|
||||
181 (run-world world nil (list flow-nr) max-altitude))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
182
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
183 (defn flow-world
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
184 "Return a world like this `world`, but with cells tagged with the amount of
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
185 water flowing through them."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
186 [world]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
187 (map-world (rain-world world) flow))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
188
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
189 (defn explore-lake
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
190 "Return a sequence of cells starting with this `cell` in this `world` which
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
191 form a contiguous lake"
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
192 [_world _cell]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
193 )
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
194
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
195 (defn is-lake?
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
196 "If this `cell` in this `world` is not part of a lake, return nil. If it is,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
197 return a cell like this `cell` tagged as part of a lake."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
198 [world cell]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
199 (if
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
200 ;; if it's already tagged as a lake, it's a lake
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
201 (:lake cell) cell
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
202 (let
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 10 forms covered">
|
||||
203 [outflow (apply min (map :altitude (get-neighbours world cell)))]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
204 (when-not
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
205 (> (:altitude cell) outflow)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
206 (assoc cell :lake true)))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
207
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
208
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
209 (defn find-lakes
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
210 [_world]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
211 )
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
212
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
213 (defn run-drainage
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
214 "Create a world from the heightmap `hmap`, rain on it, and then compute river
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
215 flows."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
216 [hmap]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 9 forms covered">
|
||||
217 (flow-world (rain-world (flood-hollows (heightmap/apply-heightmap hmap)))))
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
545
docs/cloverage/mw_engine/flow.clj.html
Normal file
545
docs/cloverage/mw_engine/flow.clj.html
Normal 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 (ns mw-engine.flow
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
002 "Allow flows of values between cells in the world.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
003
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
004 The design here is: a flow object is a map with the following properties:
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
005
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
006 1. `:source`, whose value is a location;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
007 2. `:destination`, whose value is a location;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
008 3. `:property`, whose value is a keyword;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
009 4. `:quantity`, whose value is a positive real number.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
010
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
011 A location object is a map with the following properties:
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
012
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
013 1. `:x`, whose value is a natural number not greater than the extent of the world;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
014 2. `:y`, whose value is a natural number not greater than the extent of the world.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
015
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
016 To execute a flow is transfer the quantity specified of the property specified
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
017 from the cell at the source specified to the cell at the destination specified;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
018 if the source doesn't have sufficient of the property, then all it has should
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
019 be transferred, but no more: properties to be flowed cannot be pulled negative.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
020
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
021 Flowing values through the world is consequently a two stage process: firstly
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
022 there's a planning stage, in which all the flows to be executed are computed
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
023 without changing the world, and then an execution stage, where they're all
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
024 executed. This namespace deals with mainly with execution."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
025 (:require [mw-engine.utils :refer [add-history-event get-cell get-num
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
026 in-bounds? map-world merge-cell rule-type]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
027 [taoensso.timbre :refer [info warn]]))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
028
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
029 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
030 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
031 ;;;; mw-engine: the state/transition engine of MicroWorld.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
032 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
033 ;;;; This program is free software; you can redistribute it and/or
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
034 ;;;; modify it under the terms of the GNU General Public License
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
035 ;;;; as published by the Free Software Foundation; either version 2
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
036 ;;;; of the License, or (at your option) any later version.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
037 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
038 ;;;; This program is distributed in the hope that it will be useful,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
039 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
040 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
041 ;;;; GNU General Public License for more details.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
042 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
043 ;;;; You should have received a copy of the GNU General Public License
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
044 ;;;; along with this program; if not, write to the Free Software
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
045 ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
046 ;;;; USA.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
047 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
048 ;;;; Copyright (C) 2014 Simon Brooke
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
049 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
050 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
051
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
052 (defn coordinate?
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
053 "Return `true` if this object `o` is a valid coordinate with respect to
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
054 this `world`, else `false`. Assumes square worlds."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
055 [o world]
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
056 (try
|
||||
</span><br/>
|
||||
<span class="covered" title="14 out of 14 forms covered">
|
||||
057 (and (or (zero? o) (pos-int? o))
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
058 (< o (count world)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
059 (catch Exception e
|
||||
</span><br/>
|
||||
<span class="covered" title="20 out of 20 forms covered">
|
||||
060 (warn (format "Not a valid coordinate: %s; %s" o (.getMessage e)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
061 false)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
062
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
063 (defn location?
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
064 "Return `true` if this object `o` is a location as defined above with respect to
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
065 this `world`, else `false`."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
066 [o world]
|
||||
</span><br/>
|
||||
<span class="partial" title="1 out of 2 forms covered">
|
||||
067 (try
|
||||
</span><br/>
|
||||
<span class="partial" title="14 out of 16 forms covered">
|
||||
068 (and (map? o)
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
069 (integer? (:x o))
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
070 (integer? (:y o))
|
||||
</span><br/>
|
||||
<span class="covered" title="8 out of 8 forms covered">
|
||||
071 (in-bounds? world (:x o) (:y o)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
072 (catch Exception e
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 20 forms covered">
|
||||
073 (warn (format "Not a valid location: %s; %s" o (.getMessage e)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
074 false)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
075
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
076 (defn flow?
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
077 "Return `true` if this object `o` is a flow as defined above with respect to
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
078 this `world`, else `false`. Assumes square worlds."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
079 [o world]
|
||||
</span><br/>
|
||||
<span class="partial" title="1 out of 2 forms covered">
|
||||
080 (try
|
||||
</span><br/>
|
||||
<span class="partial" title="16 out of 20 forms covered">
|
||||
081 (and (map? o)
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
082 (location? (:source o) world)
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
083 (location? (:destination o) world)
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
084 (keyword? (:property o))
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
085 (pos? (:quantity o)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
086 (catch Exception e
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 20 forms covered">
|
||||
087 (warn (format "Not a valid flow: %s; %s" o (.getMessage e)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
088 false)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
089
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
090 (defn execute
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
091 "Return a world like this `world`, except with the quantity of the property
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
092 described in this `flow` object transferred from the source of that flow
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
093 to its destination."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
094 [world flow]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
095 (try
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
096 (let [sx (-> flow :source :x)
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
097 sy (-> flow :source :y)
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
098 source (get-cell world sx sy)
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
099 dx (-> flow :destination :x)
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
100 dy (-> flow :destination :y)
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
101 dest (get-cell world dx dy)
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
102 p (:property flow)
|
||||
</span><br/>
|
||||
<span class="partial" title="16 out of 22 forms covered">
|
||||
103 q (min (:quantity flow) (get-num source p))
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
104 s' (add-history-event
|
||||
</span><br/>
|
||||
<span class="covered" title="9 out of 9 forms covered">
|
||||
105 (assoc source p (- (source p) q))
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
106 (:rule flow)
|
||||
</span><br/>
|
||||
<span class="covered" title="13 out of 13 forms covered">
|
||||
107 {:direction :sent :other {:x dx :y dy} :property p :quantity q})
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
108 d' (add-history-event
|
||||
</span><br/>
|
||||
<span class="partial" title="20 out of 24 forms covered">
|
||||
109 (assoc dest p (+ (get-num dest p) q))
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
110 (:rule flow)
|
||||
</span><br/>
|
||||
<span class="covered" title="13 out of 13 forms covered">
|
||||
111 {:direction :received :other {:x sx :y sy} :property p :quantity q})]
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
112 (if (= q (:quantity flow))
|
||||
</span><br/>
|
||||
<span class="covered" title="18 out of 18 forms covered">
|
||||
113 (info (format "Moving %f units of %s from %d,%d to %d,%d"
|
||||
</span><br/>
|
||||
<span class="covered" title="9 out of 9 forms covered">
|
||||
114 (float q) (name p) sx sy dx dy))
|
||||
</span><br/>
|
||||
<span class="covered" title="18 out of 18 forms covered">
|
||||
115 (warn (format "Moving %s from %d,%d to %d,%d; %f units ordered but only %f available"
|
||||
</span><br/>
|
||||
<span class="covered" title="13 out of 13 forms covered">
|
||||
116 (name p) sx sy dx dy (float (:quantity flow)) (float q))))
|
||||
</span><br/>
|
||||
<span class="covered" title="7 out of 7 forms covered">
|
||||
117 (merge-cell (merge-cell world s') d'))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
118 (catch Exception e
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 20 forms covered">
|
||||
119 (warn (format "Failed to execute flow %s: %s" flow (.getMessage e)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
120 ;; return the world unmodified.
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
121 world)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
122
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
123 (defn execute-flows
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
124 "Return a world like this `world`, but with each of these flows executed."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
125 [world flows]
|
||||
</span><br/>
|
||||
<span class="covered" title="12 out of 12 forms covered">
|
||||
126 (reduce execute world (filter #(flow? % world) flows)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
127
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
128 (defn- plan-cell-flows
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
129 [world cell rules]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
130 (map ;; across all the rules
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
131 (fn [rule] (let [r (try
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 7 forms covered">
|
||||
132 (apply rule (list cell world))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
133 (catch Exception any
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
134 (throw (ex-info "Planning of flows failed"
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 8 forms covered">
|
||||
135 (merge (meta rule) {:cell cell})
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
136 any))))]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 12 forms covered">
|
||||
137 (when r (map #(assoc % :rule rule) r))))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
138 rules))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
139
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
140 (defn plan-flows
|
||||
</span><br/>
|
||||
<span class="partial" title="3 out of 4 forms covered">
|
||||
141 "Plan, but do not execute, all the flows in this `world` implied by those of
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
142 these `rules` (which are expected to be pre-compiled) which are
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
143 flow rules. Return the list of plans, as flow objects."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
144 [world rules]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
145 (remove nil?
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
146 (flatten
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
147 (map-world
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
148 world
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
149 plan-cell-flows
|
||||
</span><br/>
|
||||
<span class="partial" title="4 out of 17 forms covered">
|
||||
150 (list (filter #(= :flow (rule-type %)) rules))))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
151
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
152 (defn flow-world
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
153 "Return a world derived from this `world` by applying the flow rules
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
154 found among these `rules` to each cell, and executing all the flows
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
155 planned."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
156 [world rules]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 7 forms covered">
|
||||
157 (execute-flows world (plan-flows world rules)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
158
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
159 ;; building blocks for compiled flow rules
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
160
|
||||
</span><br/>
|
||||
<span class="covered" title="32 out of 32 forms covered">
|
||||
161 (defmacro create-location
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
162 [cell]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
163 `(select-keys ~cell [:x :y]))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
164
|
||||
</span><br/>
|
||||
<span class="covered" title="56 out of 56 forms covered">
|
||||
165 (defmacro create-flow-quantity
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
166 [source dest prop quantity]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
167 `{:source (create-location ~source)
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
168 :destination (create-location ~dest)
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
169 :prop ~prop
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
170 :quantity ~quantity})
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
171
|
||||
</span><br/>
|
||||
<span class="covered" title="48 out of 48 forms covered">
|
||||
172 (defmacro create-flow-fraction
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
173 [source dest prop fraction]
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
174 `(create-flow-quantity ~source ~dest ~prop
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
175 (* ~fraction (get-num ~source ~prop))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
176
|
||||
</span><br/>
|
||||
<span class="covered" title="36 out of 36 forms covered">
|
||||
177 (defmacro create-flow-percent
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
178 [source dest prop percent]
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
179 `(create-flow-fraction ~source ~dest ~prop (/ ~percent 100)))
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
407
docs/cloverage/mw_engine/heightmap.clj.html
Normal file
407
docs/cloverage/mw_engine/heightmap.clj.html
Normal 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 (ns ^{:doc "Functions to apply a heightmap to a world.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
002
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
003 Heightmaps are considered only as greyscale images, so colour is redundent
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
004 (will be ignored). Darker shades are higher."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
005 :author "Simon Brooke"}
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
006 mw-engine.heightmap
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
007 (:require [mikera.image.core :refer [load-image filter-image]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
008 [mikera.image.filters :as filters]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
009 [mw-engine.utils :refer [get-int get-neighbours map-world]]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
010 [mw-engine.world :refer [make-world]]))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
011
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
012 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
013 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
014 ;;;; mw-engine: the state/transition engine of MicroWorld.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
015 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
016 ;;;; This program is free software; you can redistribute it and/or
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
017 ;;;; modify it under the terms of the GNU General Public License
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
018 ;;;; as published by the Free Software Foundation; either version 2
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
019 ;;;; of the License, or (at your option) any later version.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
020 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
021 ;;;; This program is distributed in the hope that it will be useful,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
022 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
023 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
024 ;;;; GNU General Public License for more details.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
025 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
026 ;;;; You should have received a copy of the GNU General Public License
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
027 ;;;; along with this program; if not, write to the Free Software
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
028 ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
029 ;;;; USA.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
030 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
031 ;;;; Copyright (C) 2014 Simon Brooke
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
032 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
033 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
034
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
035 (defn abs
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
036 "Prior to Clojure 1.11, there is no native `abs` function. Afterwards, there
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
037 is."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
038 [n]
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
039 (Math/abs n))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
040
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
041 (defn tag-property
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
042 "Set the value of this `property` of this cell from the corresponding pixel of this `heightmap`.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
043 If the heightmap you supply is smaller than the world, this will break.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
044
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
045 * `world` not actually used, but present to enable this function to be
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
046 passed as an argument to `mw-engine.utils/map-world`, q.v.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
047 * `cell` a cell, as discussed in world.clj, q.v. Alternatively, a map;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
048 * `property` the property (normally a keyword) whose value will be set on the cell.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
049 * `heightmap` an (ideally) greyscale image, whose x and y dimensions should
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
050 exceed those of the world of which the `cell` forms part."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
051 ([_ cell property heightmap]
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
052 (tag-property cell property heightmap))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
053 ([cell property heightmap]
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
054 (merge cell
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
055 {property
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
056 (+ (get-int cell property)
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
057 (- 256
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
058 (abs
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
059 (mod
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
060 (.getRGB heightmap
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
061 (get-int cell :x)
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
062 (get-int cell :y)) 256))))})))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
063
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
064 (defn tag-gradient
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
065 "Set the `gradient` property of this `cell` of this `world` to the difference in
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
066 altitude between its highest and lowest neghbours."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
067 [world cell]
|
||||
</span><br/>
|
||||
<span class="covered" title="11 out of 11 forms covered">
|
||||
068 (let [heights (remove nil? (map :altitude (get-neighbours world cell)))
|
||||
</span><br/>
|
||||
<span class="partial" title="5 out of 6 forms covered">
|
||||
069 highest (cond (empty? heights) 0 ;; shouldn't happen
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
070 :else (apply max heights))
|
||||
</span><br/>
|
||||
<span class="partial" title="5 out of 6 forms covered">
|
||||
071 lowest (cond (empty? heights) 0 ;; shouldn't
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
072 :else (apply min heights))
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
073 gradient (- highest lowest)]
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
074 (merge cell {:gradient gradient})))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
075
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
076 (defn tag-gradients
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
077 "Set the `gradient` property of each cell in this `world` to the difference in
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
078 altitude between its highest and lowest neghbours."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
079 [world]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
080 (map-world world tag-gradient))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
081
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
082 (defn tag-altitude
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
083 "Set the altitude of this cell from the corresponding pixel of this heightmap.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
084 If the heightmap you supply is smaller than the world, this will break.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
085
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
086 * `world` not actually used, but present to enable this function to be
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
087 passed as an argument to `mw-engine.utils/map-world`, q.v.;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
088 * `cell` a cell, as discussed in world.clj, q.v. Alternatively, a map;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
089 * `heightmap` an (ideally) greyscale image, whose x and y dimensions should
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
090 exceed those of the world of which the `cell` forms part."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
091 ([_ cell heightmap]
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
092 (tag-property cell :altitude heightmap))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
093 ([cell heightmap]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
094 (tag-property cell :altitude heightmap)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
095
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
096 (defn apply-heightmap
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
097 "Apply the image file loaded from this path to this world, and return a world whose
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
098 altitudes are modified (added to) by the altitudes in the heightmap. It is assumed that
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
099 the heightmap is at least as large in x and y dimensions as the world. Note that, in
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
100 addition to setting the `:altitude` of each cell, this function also sets the `:gradient`.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
101
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
102 * `world` a world, as defined in `world.clj`, q.v.; if world is not supplied,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
103 a world the size of the heightmap will be created;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
104 * `imagepath` a file path or URL which indicates an (ideally greyscale) image file."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
105 ([world imagepath]
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
106 (let [heightmap (filter-image
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
107 (load-image imagepath)
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
108 (filters/grayscale))]
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
109 (map-world
|
||||
</span><br/>
|
||||
<span class="covered" title="7 out of 7 forms covered">
|
||||
110 (map-world world tag-altitude (list heightmap))
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
111 tag-gradient)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
112 ([imagepath]
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
113 (let [heightmap (filter-image
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
114 (load-image imagepath)
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
115 (filters/grayscale))
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
116 world (make-world (.getWidth heightmap) (.getHeight heightmap))]
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
117 (map-world
|
||||
</span><br/>
|
||||
<span class="covered" title="7 out of 7 forms covered">
|
||||
118 (map-world world tag-altitude (list heightmap))
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
119 tag-gradient))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
120
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
121 (defn apply-valuemap
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
122 "Generalised from apply-heightmap, set an arbitrary property on each cell
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
123 of this `world` from the values in this (ideally greyscale) heightmap.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
124
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
125 * `world` a world, as defined in `world.clj`, q.v.;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
126 * `imagepath` a file path or URL which indicates an (ideally greyscale) image file;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
127 * `property` the property of each cell whose value should be added to from the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
128 intensity of the corresponding cell of the image."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
129 [world imagepath property]
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
130 (let [heightmap (filter-image
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
131 (load-image imagepath)
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
132 (filters/grayscale))]
|
||||
</span><br/>
|
||||
<span class="covered" title="8 out of 8 forms covered">
|
||||
133 (map-world world tag-property (list property heightmap))))
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
560
docs/cloverage/mw_engine/natural_rules.clj.html
Normal file
560
docs/cloverage/mw_engine/natural_rules.clj.html
Normal 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 (ns ^{:doc "A set of MicroWorld rules describing a simplified natural ecosystem.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
002
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
003 Since the completion of the rule language this is more or less obsolete -
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
004 there are still a few things that you can do with rules written in Clojure
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
005 that you can't do in the rule language, but not many and I doubt they're
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
006 important. "
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
007 :author " Simon Brooke "}
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
008 mw-engine.natural-rules
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
009 (:require [mw-engine.utils :refer [get-int get-neighbours get-neighbours-with-state member?]]))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
010
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
011 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
012 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
013 ;;;; mw-engine: the state/transition engine of MicroWorld.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
014 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
015 ;;;; This program is free software; you can redistribute it and/or
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
016 ;;;; modify it under the terms of the GNU General Public License
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
017 ;;;; as published by the Free Software Foundation; either version 2
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
018 ;;;; of the License, or (at your option) any later version.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
019 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
020 ;;;; This program is distributed in the hope that it will be useful,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
021 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
022 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
023 ;;;; GNU General Public License for more details.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
024 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
025 ;;;; You should have received a copy of the GNU General Public License
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
026 ;;;; along with this program; if not, write to the Free Software
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
027 ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
028 ;;;; USA.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
029 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
030 ;;;; Copyright (C) 2014 Simon Brooke
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
031 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
032 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
033
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
034 ;; treeline at arbitrary altitude.
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
035 (def treeline 150)
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
036
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
037 ;; waterline also at arbitrary altitude.
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
038 (def waterline 10)
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
039
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
040 ;; and finally snowline is also arbitrary.
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
041 (def snowline 200)
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
042
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
043 ;; Rare chance of lightning strikes
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
044 (def lightning-probability 500)
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
045
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
046 ;; rules describing vegetation
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
047 (def vegetation-rules
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
048 (list
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
049 ;; Randomly, birds plant tree seeds into grassland.
|
||||
</span><br/>
|
||||
<span class="partial" title="1 out of 23 forms covered">
|
||||
050 (fn [cell _] (cond (and (= (:state cell) :grassland)(< (rand 10) 1))(merge cell {:state :heath})))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
051 ;; heath below the treeline grows gradually into forest, providing browsing pressure is not to high
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
052 (fn [cell _]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 11 forms covered">
|
||||
053 (cond (and
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
054 (= (:state cell) :heath)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
055 ;; browsing limit really ought to vary with soil fertility, but...
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 11 forms covered">
|
||||
056 (< (+ (get-int cell :deer)(get-int cell :sheep)) 6)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
057 (< (get-int cell :altitude) treeline))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
058 (merge cell {:state :scrub})))
|
||||
</span><br/>
|
||||
<span class="partial" title="1 out of 14 forms covered">
|
||||
059 (fn [cell _] (cond (= (:state cell) :scrub) (merge cell {:state :forest})))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
060 ;; Forest on fertile land grows to climax
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
061 (fn [cell _]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
062 (cond
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
063 (and
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
064 (= (:state cell) :forest)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
065 (> (get-int cell :fertility) 10))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
066 (merge cell {:state :climax})))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
067 ;; Climax forest occasionally catches fire (e.g. lightning strikes)
|
||||
</span><br/>
|
||||
<span class="partial" title="1 out of 23 forms covered">
|
||||
068 (fn [cell _] (cond (and (= (:state cell) :climax)(< (rand lightning-probability) 1)) (merge cell {:state :fire})))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
069 ;; Climax forest neighbouring fires is likely to catch fire
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
070 (fn [cell world]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
071 (cond
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 14 forms covered">
|
||||
072 (and (= (:state cell) :climax)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
073 (< (rand 3) 1)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 14 forms covered">
|
||||
074 (not (empty? (get-neighbours-with-state world (:x cell) (:y cell) 1 :fire))))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
075 (merge cell {:state :fire})))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
076 ;; After fire we get waste
|
||||
</span><br/>
|
||||
<span class="partial" title="1 out of 14 forms covered">
|
||||
077 (fn [cell _] (cond (= (:state cell) :fire) (merge cell {:state :waste})))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
078 ;; And after waste we get pioneer species; if there's a woodland seed
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
079 ;; source, it's going to be heath, otherwise grassland.
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
080 (fn [cell world]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
081 (cond
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 10 forms covered">
|
||||
082 (and (= (:state cell) :waste)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
083 (not
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
084 (empty?
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
085 (flatten
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
086 (list
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 11 forms covered">
|
||||
087 (get-neighbours-with-state world (:x cell) (:y cell) 1 :scrub)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 11 forms covered">
|
||||
088 (get-neighbours-with-state world (:x cell) (:y cell) 1 :forest)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 11 forms covered">
|
||||
089 (get-neighbours-with-state world (:x cell) (:y cell) 1 :climax))))))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
090 (merge cell {:state :heath})))
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
091 (fn [cell _]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 7 forms covered">
|
||||
092 (cond (= (:state cell) :waste)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
093 (merge cell {:state :grassland})))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
094 ;; Forest increases soil fertility
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
095 (fn [cell _]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 8 forms covered">
|
||||
096 (cond (member? (:state cell) '(:forest :climax))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 11 forms covered">
|
||||
097 (merge cell {:fertility (+ (get-int cell :fertility) 1)})))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
098
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
099
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
100 ;; rules describing herbivore behaviour
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
101 (def herbivore-rules
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
102 (list
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
103 ;; if there are too many deer for the fertility of the area to sustain,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
104 ;; some die or move on.
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
105 (fn [cell _]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 11 forms covered">
|
||||
106 (cond (> (get-int cell :deer) (get-int cell :fertility))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 9 forms covered">
|
||||
107 (merge cell {:deer (get-int cell :fertility)})))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
108 ;; deer arrive occasionally at the edge of the map.
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
109 (fn [cell world]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 23 forms covered">
|
||||
110 (cond (and (< (count (get-neighbours world cell)) 8)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
111 (< (rand 50) 1)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
112 (> (get-int cell :fertility) 0)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
113 (= (get-int cell :deer) 0))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
114 (merge cell {:deer 2})))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
115 ;; deer gradually spread through the world by breeding or migrating.
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
116 (fn [cell world]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 15 forms covered">
|
||||
117 (let [n (apply + (map #(get-int % :deer) (get-neighbours world cell)))]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 12 forms covered">
|
||||
118 (cond (and
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
119 (> (get-int cell :fertility) 0)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
120 (= (get-int cell :deer) 0)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
121 (>= n 2))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 9 forms covered">
|
||||
122 (merge cell {:deer (int (/ n 2))}))))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
123 ;; deer breed.
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
124 (fn [cell _]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
125 (cond
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
126 (>= (get-int cell :deer) 2)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 11 forms covered">
|
||||
127 (merge cell {:deer (int (* (:deer cell) 2))})))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
128
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
129 ;; rules describing predator behaviour
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
130 (def predator-rules
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
131 (list
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
132 ;; wolves eat deer
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
133 (fn [cell _]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
134 (cond
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
135 (>= (get-int cell :wolves) 1)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 16 forms covered">
|
||||
136 (merge cell {:deer (max 0 (- (get-int cell :deer) (get-int cell :wolves)))})))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
137 ;; ;; not more than eight wolves in a pack, for now (hack because wolves are not dying)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
138 ;; (fn [cell world]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
139 ;; (cond (> (get-int cell :wolves) 8) (merge cell {:wolves 8})))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
140 ;; if there are not enough deer to sustain the get-int of wolves,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
141 ;; some wolves die or move on. (doesn't seem to be working?)
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
142 (fn [cell _]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 11 forms covered">
|
||||
143 (cond (> (get-int cell :wolves) (get-int cell :deer))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
144 (merge cell {:wolves 0})))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
145 ;; wolves arrive occasionally at the edge of the map.
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
146 (fn [cell world]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 23 forms covered">
|
||||
147 (cond (and (< (count (get-neighbours world cell)) 8)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
148 (< (rand 50) 1)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 7 forms covered">
|
||||
149 (not (= (:state cell) :water))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
150 (= (get-int cell :wolves) 0))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
151 (merge cell {:wolves 2})))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
152 ;; wolves gradually spread through the world by breeding or migrating.
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
153 (fn [cell world]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 15 forms covered">
|
||||
154 (let [n (apply + (map #(get-int % :wolves) (get-neighbours world cell)))]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 12 forms covered">
|
||||
155 (cond (and
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 7 forms covered">
|
||||
156 (not (= (:state cell) :water))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
157 (= (get-int cell :wolves) 0)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
158 (>= n 2))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
159 (merge cell {:wolves 2}))))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
160 ;; wolves breed.
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
161 (fn [cell _]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
162 (cond
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
163 (>= (get-int cell :wolves) 2)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 11 forms covered">
|
||||
164 (merge cell {:wolves (int (* (:wolves cell) 2))})))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
165
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
166
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
167 ;; rules which initialise the world
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
168 (def init-rules
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
169 (list
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
170 ;; below the waterline, we have water.
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
171 (fn [cell _]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 23 forms covered">
|
||||
172 (cond (and (= (:state cell) :new) (< (get-int cell :altitude) waterline)) (merge cell {:state :water})))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
173 ;; above the snowline, we have snow.
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
174 (fn [cell _]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 23 forms covered">
|
||||
175 (cond (and (= (:state cell) :new) (> (get-int cell :altitude) snowline)) (merge cell {:state :snow})))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
176 ;; in between, we have a wasteland.
|
||||
</span><br/>
|
||||
<span class="partial" title="1 out of 14 forms covered">
|
||||
177 (fn [cell _] (cond (= (:state cell) :new) (merge cell {:state :grassland})))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
178
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
179
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
180 (def natural-rules (flatten
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
181 (list
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
182 vegetation-rules
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
183 herbivore-rules
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
184 predator-rules)))
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
302
docs/cloverage/mw_engine/render.clj.html
Normal file
302
docs/cloverage/mw_engine/render.clj.html
Normal 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 (ns mw-engine.render
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
002 "Render a world as HTML.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
003
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
004 Adapted (simplified) from mw-ui.render-world; this is for visualisation, not
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
005 interaction."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
006 ;; TODO: but possibly it would be better if there is to be a newer version of
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
007 ;; mw-ui, to base it on this.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
008 (:require [hiccup2.core :refer [html]])
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
009 )
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
010
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
011 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
012 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
013 ;;;; This program is free software; you can redistribute it and/or
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
014 ;;;; modify it under the terms of the GNU General Public License
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
015 ;;;; as published by the Free Software Foundation; either version 2
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
016 ;;;; of the License, or (at your option) any later version.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
017 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
018 ;;;; This program is distributed in the hope that it will be useful,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
019 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
020 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
021 ;;;; GNU General Public License for more details.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
022 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
023 ;;;; You should have received a copy of the GNU General Public License
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
024 ;;;; along with this program; if not, write to the Free Software
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
025 ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
026 ;;;; USA.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
027 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
028 ;;;; Copyright (C) 2024 Simon Brooke
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
029 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
030 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
031
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
032 (def ^:dynamic *state-images-relative-path* "img/tiles/")
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
033
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
034 (defn format-css-class
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
035 "Format this statekey, assumed to be a keyword indicating a state in the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
036 world, into a CSS class"
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
037 [statekey]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
038 (name statekey))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
039
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
040 (defn format-image-path
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
041 "Render this statekey, assumed to be a keyword indicating a state in the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
042 world, into a path which should recover the corresponding image file."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
043 [statekey]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 7 forms covered">
|
||||
044 (format "%s%s.png" *state-images-relative-path* (format-css-class statekey)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
045
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
046 (defn format-mouseover [cell]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
047 (str cell))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
048
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
049 (defn render-cell
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
050 "Render this world cell as a Hiccup table cell."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
051 [cell]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
052 (let [state (:state cell)]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 11 forms covered">
|
||||
053 [:td {:class (format-css-class state) :title (format-mouseover cell)}
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
054
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 11 forms covered">
|
||||
055 [:img {:alt (:state cell) :src (format-image-path state)}]]))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
056
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
057
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
058 (defn render-world-row
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
059 "Render this world row as a Hiccup table row."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
060 [row]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 10 forms covered">
|
||||
061 (apply vector (cons :tr (map render-cell row))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
062
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
063 (defn render-world-table
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
064 "Render this `world` as a complete HTML table in a DIV. If
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
065 `state-images-relative-path` is passed, use that to override the default path."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
066 ([world]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
067 [:div {:class "world"}
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
068 (apply vector
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
069 (cons :table
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
070 (map render-world-row world)))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
071 [:p
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 10 forms covered">
|
||||
072 (str "Generation " (:generation (first (flatten world))))]])
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
073 ([world state-images-relative-path]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 10 forms covered">
|
||||
074 (binding [*state-images-relative-path* state-images-relative-path]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
075 (render-world-table world))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
076
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
077 (defn render-world-page
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
078 ([world]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
079 [:html
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
080 [:head
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
081 [:title "Rendered world"]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
082 [:style "div.world table, div.world table tr td {
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
083 padding: 0;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
084 margin: 0;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
085 border-collapse: collapse;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
086 border: none;}"]]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
087 [:body
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
088 (render-world-table world)]])
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
089 ([world state-images-relative-path]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 10 forms covered">
|
||||
090 (binding [*state-images-relative-path* state-images-relative-path]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
091 (render-world-page world))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
092
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
093 (defn world->html-file
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
094 ([world output-path]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 18 forms covered">
|
||||
095 (spit output-path (str (html (render-world-page world)))))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
096 ([world output-path state-images-relative-path]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 10 forms covered">
|
||||
097 (binding [*state-images-relative-path* state-images-relative-path]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
098 (world->html-file world output-path))))
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
1145
docs/cloverage/mw_engine/utils.clj.html
Normal file
1145
docs/cloverage/mw_engine/utils.clj.html
Normal file
File diff suppressed because it is too large
Load diff
341
docs/cloverage/mw_engine/world.clj.html
Normal file
341
docs/cloverage/mw_engine/world.clj.html
Normal 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 (ns ^{:doc "Functions to create and to print two dimensional cellular automata.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
002
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
003 Nothing in this namespace should determine what states are possible within
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
004 the automaton, except for the initial state, :new.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
005
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
006 A cell is a map containing at least values for the keys `:x`, `:y`, and `:state`.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
007
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
008 A world is a two dimensional matrix (sequence of sequences) of cells, such
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
009 that every cell's `:x` and `:y` properties reflect its place in the matrix."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
010 :author "Simon Brooke"}
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
011 mw-engine.world
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
012 (:require [clojure.string :as string]
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
013 [mw-engine.utils :refer [population]]))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
014
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
015 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
016 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
017 ;;;; mw-engine: the state/transition engine of MicroWorld.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
018 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
019 ;;;; This program is free software; you can redistribute it and/or
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
020 ;;;; modify it under the terms of the GNU General Public License
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
021 ;;;; as published by the Free Software Foundation; either version 2
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
022 ;;;; of the License, or (at your option) any later version.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
023 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
024 ;;;; This program is distributed in the hope that it will be useful,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
025 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
026 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
027 ;;;; GNU General Public License for more details.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
028 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
029 ;;;; You should have received a copy of the GNU General Public License
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
030 ;;;; along with this program; if not, write to the Free Software
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
031 ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
032 ;;;; USA.
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
033 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
034 ;;;; Copyright (C) 2014 Simon Brooke
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
035 ;;;;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
036 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
037
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
038 (defn cell?
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
039 "Return `true` if `obj` is a cell, as understood by MicroWorld, else `false`."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
040 [obj]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 16 forms covered">
|
||||
041 (and (map? obj) ;; it's a map...
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
042 ;; TODO: it's worth checking (and this does not) that cells have the
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
043 ;; right co-ordinates!
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
044 (pos-int? (:x obj)) ;; with an x co-ordinate...
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
045 (pos-int? (:y obj)) ;; and a y co-ordinate...
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
046 (keyword? (:state obj)))) ;; and a state which is a keyword.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
047
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
048 (defn world?
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
049 "Return `true` if `obj` is a world, as understood by MicroWorld, else `false`."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
050 [obj]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 16 forms covered">
|
||||
051 (and (coll? obj) ;; it's a collection...
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
052 (every? coll? obj) ;; of collections...
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 9 forms covered">
|
||||
053 (= 1 (count (set (map count obj)))) ;; all of which are the same length...
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
054 (every? cell? (flatten obj)))) ;; and every element of each of those is a cell.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
055
|
||||
</span><br/>
|
||||
<span class="covered" title="30 out of 30 forms covered">
|
||||
056 (defmacro make-cell
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
057 "Create a minimal default cell at x, y
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
058
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
059 * `x` the x coordinate at which this cell is created;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
060 * `y` the y coordinate at which this cell is created."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
061 [x y]
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
062 `{:x ~x :y ~y :state :new})
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
063
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
064 (defn make-world
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
065 "Make a world width cells from east to west, and height cells from north to
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
066 south.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
067
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
068 * `width` a natural number representing the width of the matrix to be created;
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
069 * `height` a natural number representing the height of the matrix to be created."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
070 [width height]
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
071 (apply vector
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
072 (map (fn [h]
|
||||
</span><br/>
|
||||
<span class="covered" title="16 out of 16 forms covered">
|
||||
073 (apply vector (map #(make-cell % h) (range width))))
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
074 (range height))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
075
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
076 (defn truncate-state
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
077 "Truncate the print name of the state of this cell to at most limit characters."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
078 [cell limit]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
079 (let [s (:state cell)]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
080 (try
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 15 forms covered">
|
||||
081 (cond (> (count (str s)) limit) (subs (name s) 0 limit)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
082 :else s)
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
083 (catch Exception any
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
084 (throw (ex-info (.getMessage any)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 5 forms covered">
|
||||
085 {:cell cell
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
086 :limit limit
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
087 :exception-class (.getClass any)}))))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
088
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
089 (defn format-cell
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
090 "Return a formatted string summarising the current state of this cell."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
091 [cell]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
092 (format "%10s"
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 4 forms covered">
|
||||
093 (truncate-state cell 10)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
094
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
095 (defn- format-world-row
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
096 "Format one row in the state of a world for printing."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
097 [row]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 6 forms covered">
|
||||
098 (string/join (map format-cell row)))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
099
|
||||
</span><br/>
|
||||
<span class="partial" title="1 out of 2 forms covered">
|
||||
100 (defn print-world
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
101 "Print the current state of this world, and return nil.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
102
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
103 * `world` a world as defined above."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
104 [world]
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
105 (println)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
106 (dorun
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
107 (map
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 2 forms covered">
|
||||
108 #(println
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
109 (format-world-row %))
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
110 world))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
111 nil)
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
551
docs/codox/css/default.css
Normal file
551
docs/codox/css/default.css
Normal 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;
|
||||
}
|
97
docs/codox/css/highlight.css
Normal file
97
docs/codox/css/highlight.css
Normal 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
12
docs/codox/index.html
Normal 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->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
5
docs/codox/intro.html
Normal 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
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
4
docs/codox/js/jquery.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
112
docs/codox/js/page_effects.js
Normal file
112
docs/codox/js/page_effects.js
Normal 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)
|
||||
})
|
22
docs/codox/mw-engine.core.html
Normal file
22
docs/codox/mw-engine.core.html
Normal 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 cell’s <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>
|
11
docs/codox/mw-engine.display.html
Normal file
11
docs/codox/mw-engine.display.html
Normal 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>
|
22
docs/codox/mw-engine.drainage.html
Normal file
22
docs/codox/mw-engine.drainage.html
Normal file
File diff suppressed because one or more lines are too long
29
docs/codox/mw-engine.flow.html
Normal file
29
docs/codox/mw-engine.flow.html
Normal 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 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.</p>
|
||||
<p>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.</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>
|
31
docs/codox/mw-engine.heightmap.html
Normal file
31
docs/codox/mw-engine.heightmap.html
Normal 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>
|
14
docs/codox/mw-engine.natural-rules.html
Normal file
14
docs/codox/mw-engine.natural-rules.html
Normal 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 can’t do in the rule language, but not many and I doubt they’re 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>
|
14
docs/codox/mw-engine.render.html
Normal file
14
docs/codox/mw-engine.render.html
Normal 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->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->html-file</h3><div class="usage"><code>(world->html-file world output-path)</code><code>(world->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>
|
82
docs/codox/mw-engine.utils.html
Normal file
82
docs/codox/mw-engine.utils.html
Normal file
File diff suppressed because one or more lines are too long
25
docs/codox/mw-engine.world.html
Normal file
25
docs/codox/mw-engine.world.html
Normal 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 cell’s <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
4092
docs/uberdoc.html
Normal file
File diff suppressed because one or more lines are too long
45
project.clj
45
project.clj
|
@ -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/")
|
||||
|
|
BIN
resources/heightmaps/20x20/crucible.png
Normal file
BIN
resources/heightmaps/20x20/crucible.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 1.3 KiB |
BIN
resources/heightmaps/20x20/crucible.xcf
Normal file
BIN
resources/heightmaps/20x20/crucible.xcf
Normal file
Binary file not shown.
1
resources/test.edn
Normal file
1
resources/test.edn
Normal file
|
@ -0,0 +1 @@
|
|||
{:hello "goodbye"}
|
160
src/cljc/mw_engine/core.clj
Normal file
160
src/cljc/mw_engine/core.clj
Normal 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})))))))
|
65
src/cljc/mw_engine/display.clj
Normal file
65
src/cljc/mw_engine/display.clj
Normal 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))))
|
288
src/cljc/mw_engine/drainage.clj
Normal file
288
src/cljc/mw_engine/drainage.clj
Normal 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) " ")]))
|
||||
%))
|
||||
world))]]))
|
||||
"&"
|
||||
"&"))))
|
||||
|
||||
;; (visualise-drainage (run-drainage "resources/heightmaps/20x20/crucible.png") "test.html")
|
179
src/cljc/mw_engine/flow.clj
Normal file
179
src/cljc/mw_engine/flow.clj
Normal 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)))
|
|
@ -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))))
|
|
@ -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)))
|
96
src/cljc/mw_engine/render.clj
Normal file
96
src/cljc/mw_engine/render.clj
Normal 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))))
|
||||
|
383
src/cljc/mw_engine/utils.clj
Normal file
383
src/cljc/mw_engine/utils.clj
Normal 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)))))
|
112
src/cljc/mw_engine/world.clj
Normal file
112
src/cljc/mw_engine/world.clj
Normal 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)
|
|
@ -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)))
|
||||
|
||||
|
|
@ -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))))
|
|
@ -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)))))
|
|
@ -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))
|
|
@ -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 ))
|
|
@ -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)
|
|
@ -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)))))
|
|
@ -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"
|
||||
|
|
85
test/mw_engine/flow_test.clj
Normal file
85
test/mw_engine/flow_test.clj
Normal 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))))))))
|
|
@ -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")
|
||||
|
|
|
@ -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"))))
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue