432 lines
28 KiB
HTML
432 lines
28 KiB
HTML
<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 [get-cell get-num in-bounds? merge-cell]]
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
026 [taoensso.timbre :refer [info warn]]))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
027
|
|
</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 ;;;;
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
030 ;;;; mw-engine: the state/transition engine of MicroWorld.
|
|
</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 ;;;; This program is free software; you can redistribute it and/or
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
033 ;;;; modify it under the terms of the GNU General Public License
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
034 ;;;; as published by the Free Software Foundation; either version 2
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
035 ;;;; of the License, or (at your option) any later version.
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
036 ;;;;
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
037 ;;;; 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">
|
|
038 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
039 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
040 ;;;; GNU General Public License for more details.
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
041 ;;;;
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
042 ;;;; 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">
|
|
043 ;;;; along with this program; if not, write to the Free Software
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
044 ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
045 ;;;; USA.
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
046 ;;;;
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
047 ;;;; Copyright (C) 2014 Simon Brooke
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
048 ;;;;
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
049 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
050
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
051 (defn coordinate?
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
052 "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">
|
|
053 this `world`, else `false`. Assumes square worlds."
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
054 [o world]
|
|
</span><br/>
|
|
<span class="covered" title="2 out of 2 forms covered">
|
|
055 (try
|
|
</span><br/>
|
|
<span class="covered" title="14 out of 14 forms covered">
|
|
056 (and (or (zero? o) (pos-int? o))
|
|
</span><br/>
|
|
<span class="covered" title="3 out of 3 forms covered">
|
|
057 (< o (count world)))
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
058 (catch Exception e
|
|
</span><br/>
|
|
<span class="covered" title="20 out of 20 forms covered">
|
|
059 (warn (format "Not a valid coordinate: %s; %s" o (.getMessage e)))
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
060 false)))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
061
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
062 (defn location?
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
063 "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">
|
|
064 this `world`, else `false`."
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
065 [o world]
|
|
</span><br/>
|
|
<span class="partial" title="1 out of 2 forms covered">
|
|
066 (try
|
|
</span><br/>
|
|
<span class="partial" title="14 out of 16 forms covered">
|
|
067 (and (map? o)
|
|
</span><br/>
|
|
<span class="covered" title="5 out of 5 forms covered">
|
|
068 (integer? (:x o))
|
|
</span><br/>
|
|
<span class="covered" title="5 out of 5 forms covered">
|
|
069 (integer? (:y o))
|
|
</span><br/>
|
|
<span class="covered" title="8 out of 8 forms covered">
|
|
070 (in-bounds? world (:x o) (:y o)))
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
071 (catch Exception e
|
|
</span><br/>
|
|
<span class="not-covered" title="0 out of 20 forms covered">
|
|
072 (warn (format "Not a valid location: %s; %s" o (.getMessage e)))
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
073 false)))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
074
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
075 (defn flow?
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
076 "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">
|
|
077 this `world`, else `false`. Assumes square worlds."
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
078 [o world]
|
|
</span><br/>
|
|
<span class="partial" title="1 out of 2 forms covered">
|
|
079 (try
|
|
</span><br/>
|
|
<span class="partial" title="16 out of 20 forms covered">
|
|
080 (and (map? o)
|
|
</span><br/>
|
|
<span class="covered" title="6 out of 6 forms covered">
|
|
081 (location? (:source o) world)
|
|
</span><br/>
|
|
<span class="covered" title="6 out of 6 forms covered">
|
|
082 (location? (:destination o) world)
|
|
</span><br/>
|
|
<span class="covered" title="5 out of 5 forms covered">
|
|
083 (keyword? (:property o))
|
|
</span><br/>
|
|
<span class="covered" title="3 out of 3 forms covered">
|
|
084 (pos? (:quantity o)))
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
085 (catch Exception e
|
|
</span><br/>
|
|
<span class="not-covered" title="0 out of 20 forms covered">
|
|
086 (warn (format "Not a valid flow: %s; %s" o (.getMessage e)))
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
087 false)))
|
|
</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 execute
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
090 "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">
|
|
091 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">
|
|
092 to its destination."
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
093 [world flow]
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
094 (try
|
|
</span><br/>
|
|
<span class="covered" title="6 out of 6 forms covered">
|
|
095 (let [sx (-> flow :source :x)
|
|
</span><br/>
|
|
<span class="covered" title="5 out of 5 forms covered">
|
|
096 sy (-> flow :source :y)
|
|
</span><br/>
|
|
<span class="covered" title="5 out of 5 forms covered">
|
|
097 source (get-cell world sx sy)
|
|
</span><br/>
|
|
<span class="covered" title="5 out of 5 forms covered">
|
|
098 dx (-> flow :destination :x)
|
|
</span><br/>
|
|
<span class="covered" title="5 out of 5 forms covered">
|
|
099 dy (-> flow :destination :y)
|
|
</span><br/>
|
|
<span class="covered" title="5 out of 5 forms covered">
|
|
100 dest (get-cell world dx dy)
|
|
</span><br/>
|
|
<span class="covered" title="3 out of 3 forms covered">
|
|
101 p (:property flow)
|
|
</span><br/>
|
|
<span class="covered" title="8 out of 8 forms covered">
|
|
102 q (min (:quantity flow) (get-num source p))
|
|
</span><br/>
|
|
<span class="covered" title="9 out of 9 forms covered">
|
|
103 s' (assoc source p (- (source p) q))
|
|
</span><br/>
|
|
<span class="covered" title="10 out of 10 forms covered">
|
|
104 d' (assoc dest p (+ (get-num dest p) q))]
|
|
</span><br/>
|
|
<span class="covered" title="6 out of 6 forms covered">
|
|
105 (if (= q (:quantity flow))
|
|
</span><br/>
|
|
<span class="covered" title="18 out of 18 forms covered">
|
|
106 (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">
|
|
107 (float q) (name p) sx sy dx dy))
|
|
</span><br/>
|
|
<span class="covered" title="18 out of 18 forms covered">
|
|
108 (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">
|
|
109 (name p) sx sy dx dy (float (:quantity flow)) (float q))))
|
|
</span><br/>
|
|
<span class="covered" title="7 out of 7 forms covered">
|
|
110 (merge-cell (merge-cell world s') d'))
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
111 (catch Exception e
|
|
</span><br/>
|
|
<span class="not-covered" title="0 out of 20 forms covered">
|
|
112 (warn (format "Failed to execute flow %s: %s" flow (.getMessage e)))
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
113 ;; return the world unmodified.
|
|
</span><br/>
|
|
<span class="not-covered" title="0 out of 1 forms covered">
|
|
114 world)))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
115
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
116 (defn execute-flows
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
117 "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">
|
|
118 [world flows]
|
|
</span><br/>
|
|
<span class="covered" title="12 out of 12 forms covered">
|
|
119 (reduce execute world (filter #(flow? % world) flows)))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
120
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
121 ;; building blocks for compiled flow rules
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
122
|
|
</span><br/>
|
|
<span class="covered" title="32 out of 32 forms covered">
|
|
123 (defmacro create-location
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
124 [cell]
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
125 `(select-keys ~cell [:x :y]))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
126
|
|
</span><br/>
|
|
<span class="covered" title="56 out of 56 forms covered">
|
|
127 (defmacro create-flow-quantity
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
128 [source dest prop quantity]
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
129 `{:source (create-location ~source)
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
130 :destination (create-location ~dest)
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
131 :prop ~prop
|
|
</span><br/>
|
|
<span class="covered" title="1 out of 1 forms covered">
|
|
132 :quantity ~quantity})
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
133
|
|
</span><br/>
|
|
<span class="covered" title="48 out of 48 forms covered">
|
|
134 (defmacro create-flow-fraction
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
135 [source dest prop fraction]
|
|
</span><br/>
|
|
<span class="covered" title="3 out of 3 forms covered">
|
|
136 `(create-flow-quantity ~source ~dest ~prop
|
|
</span><br/>
|
|
<span class="covered" title="3 out of 3 forms covered">
|
|
137 (* ~fraction (get-num ~source ~prop))))
|
|
</span><br/>
|
|
<span class="blank" title="0 out of 0 forms covered">
|
|
138
|
|
</span><br/>
|
|
<span class="covered" title="36 out of 36 forms covered">
|
|
139 (defmacro create-flow-percent
|
|
</span><br/>
|
|
<span class="not-tracked" title="0 out of 0 forms covered">
|
|
140 [source dest prop percent]
|
|
</span><br/>
|
|
<span class="covered" title="4 out of 4 forms covered">
|
|
141 `(create-flow-fraction ~source ~dest ~prop (/ ~percent 100)))
|
|
</span><br/>
|
|
</body>
|
|
</html>
|