Added some moderately-real tests.
This commit is contained in:
parent
723a23e3dc
commit
2dc5e394cc
93
README.md
93
README.md
|
@ -4,8 +4,8 @@ A rule parser for MicroWorld
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Main entry point is (parse-rule <string>), where string takes a form detailed
|
Main entry point is (parse-rule _string_), where string takes a form detailed
|
||||||
in **grammar**, below. If the rule is interpretted correctly the result will
|
in __grammar__, below. If the rule is interpretted correctly the result will
|
||||||
be a Clojure anonymous function; if the rule is not interpretted, currently nil
|
be a Clojure anonymous function; if the rule is not interpretted, currently nil
|
||||||
is returned and there's no helpful error message.
|
is returned and there's no helpful error message.
|
||||||
|
|
||||||
|
@ -13,71 +13,76 @@ is returned and there's no helpful error message.
|
||||||
|
|
||||||
The generated function is a function of two arguments
|
The generated function is a function of two arguments
|
||||||
|
|
||||||
* **cell** a cell in a world as defined in mw-engine.world, q.v.;
|
_ __cell__ a cell in a world as defined in mw-engine.world, q.v.;
|
||||||
* **world** the world of which that cell forms part.
|
_ __world__ the world of which that cell forms part.
|
||||||
|
|
||||||
It returns a new cell, based on the cell passed.
|
It returns a new cell, based on the cell passed.
|
||||||
|
|
||||||
Actions of the rule will (can only) modify properties of the cell; there are two
|
Actions of the rule will (can only) modify properties of the cell; there are two
|
||||||
properties which are special and SHOULD NOT be modified, namely the properties
|
properties which are special and SHOULD NOT be modified, namely the properties
|
||||||
**x** and **y**. Currently there is no policing that these properties are not
|
__x__ and __y__. Currently there is no policing that these properties are not
|
||||||
modified.
|
modified.
|
||||||
|
|
||||||
### Grammar
|
### Grammar
|
||||||
|
|
||||||
A rule comprises:
|
A rule comprises:
|
||||||
|
|
||||||
* if *conditions* then *actions*
|
+ if _conditions_ then _actions_
|
||||||
|
|
||||||
#### Conditions
|
#### Conditions
|
||||||
|
|
||||||
where *conditions* is:
|
where _conditions_ is:
|
||||||
|
|
||||||
* *condition*
|
+ _condition_
|
||||||
|
+ _condition_ and _conditions_
|
||||||
|
+ _condition_ or _conditions_
|
||||||
|
|
||||||
or
|
Note that 'and' takes precedence over or, so
|
||||||
* *condition* and *conditions*
|
|
||||||
|
|
||||||
A *condition* is one of:
|
conditionA and conditionB or conditionC and conditionD
|
||||||
|
|
||||||
* *property* is *value*
|
is interpreted as
|
||||||
* *property* is not *value*
|
|
||||||
* *property* is in *values*
|
(conditionA and (conditionB or (conditionC and conditionD)))
|
||||||
* *property* is not in *values*
|
|
||||||
* *property* is more than *numeric-value*
|
A _condition_ is one of:
|
||||||
* *property* is less than *numeric-value*
|
|
||||||
* *number* neighbours have *property* equal to *value*
|
+ _property_ is _value_
|
||||||
* more than *number* neighbours have *property* equal to *value*
|
+ _property_ is not _value_
|
||||||
* fewer than *number* neighbours have *property* equal to *value*
|
+ _property_ is in _values_
|
||||||
|
+ _property_ is not in _values_
|
||||||
|
+ _property_ is more than _numeric-value_
|
||||||
|
+ _property_ is less than _numeric-value_
|
||||||
|
+ _number_ neighbours have _property_ equal to _value_
|
||||||
|
+ more than _number_ neighbours have _property_ equal to _value_
|
||||||
|
+ fewer than _number_ neighbours have _property_ equal to _value_
|
||||||
|
|
||||||
#### Actions
|
#### Actions
|
||||||
|
|
||||||
Where *actions* is:
|
Where _actions_ is:
|
||||||
|
|
||||||
* *action*
|
+ _action_
|
||||||
|
+ _action_ and _actions_
|
||||||
|
|
||||||
or
|
and _action_ is:
|
||||||
* *action* and *actions*
|
|
||||||
|
|
||||||
and *action* is:
|
+ _property_ should be _value_
|
||||||
|
|
||||||
* *property* should be *value*
|
|
||||||
|
|
||||||
#### Properties
|
#### Properties
|
||||||
|
|
||||||
In the above, *property* is the name of any property of a cell. Any alpha-numeric
|
In the above, _property_ is the name of any property of a cell. Any alpha-numeric
|
||||||
string of characters can form the name of a property. Actions should NOT refer
|
string of characters can form the name of a property. Actions should NOT refer
|
||||||
to the reserved properties **x** and **y**.
|
to the reserved properties __x__ and __y__.
|
||||||
|
|
||||||
#### Values in Conditions
|
#### Values in Conditions
|
||||||
|
|
||||||
Values in conditions and actions are considered slightly differently. In a
|
Values in conditions and actions are considered slightly differently. In a
|
||||||
condition, a value is one of
|
condition, a value is one of
|
||||||
|
|
||||||
* *symbolic-value*
|
+ _symbolic-value_
|
||||||
* *numeric-value*
|
+ _numeric-value_
|
||||||
|
|
||||||
The '...more than...' and '...less than...' conditions imply a *numeric-value*.
|
The '...more than...' and '...less than...' conditions imply a _numeric-value_.
|
||||||
Thus "if altitude is more than fertility..." is interpreted as meaning "if the value
|
Thus "if altitude is more than fertility..." is interpreted as meaning "if the value
|
||||||
of the property of the current cell called 'altitude' is greater than the value
|
of the property of the current cell called 'altitude' is greater than the value
|
||||||
of the property of the current cell called 'fertility'", whereas the apparently
|
of the property of the current cell called 'fertility'", whereas the apparently
|
||||||
|
@ -85,29 +90,29 @@ similar condition 'if altitude is fertility...' is interpreted as meaning
|
||||||
"if the value of the property of the current cell called 'altitude' is the symbol
|
"if the value of the property of the current cell called 'altitude' is the symbol
|
||||||
'fertility'".
|
'fertility'".
|
||||||
|
|
||||||
Thus *symbolic-value* is any sequence of alphanumeric characters, whereas
|
Thus _symbolic-value_ is any sequence of alphanumeric characters, whereas
|
||||||
*numeric-value* is one of:
|
_numeric-value_ is one of:
|
||||||
|
|
||||||
* *number*
|
+ _number_
|
||||||
* *property*
|
+ _property_
|
||||||
|
|
||||||
and *number* is any sequence of the decimal digits 0...9, the minus character
|
and _number_ is any sequence of the decimal digits 0...9, the minus character
|
||||||
'-' and the period character '.', provided that the minus character can only be
|
'-' and the period character '.', provided that the minus character can only be
|
||||||
in the first position, and the period character can only appear once.
|
in the first position, and the period character can only appear once.
|
||||||
|
|
||||||
#### Values in Actions
|
#### Values in Actions
|
||||||
|
|
||||||
A *value* in an action is one of
|
A _value_ in an action is one of
|
||||||
|
|
||||||
* *symbolic-value*
|
+ _symbolic-value_
|
||||||
* *arithmetic-value*
|
+ _arithmetic-value_
|
||||||
* *number*
|
+ _number_
|
||||||
|
|
||||||
where *arithmetic-value* is:
|
where _arithmetic-value_ is:
|
||||||
|
|
||||||
* *property* *operator* *numeric-value*
|
+ _property_ _operator_ _numeric-value_
|
||||||
|
|
||||||
and *operator* is one of the simple arithmetic operators '+', '-', '*' and '/'.
|
and _operator_ is one of the simple arithmetic operators '+', '-', '*' and '/'.
|
||||||
|
|
||||||
### Shorthand
|
### Shorthand
|
||||||
|
|
||||||
|
|
|
@ -5,16 +5,22 @@
|
||||||
|
|
||||||
|
|
||||||
(deftest rules-tests
|
(deftest rules-tests
|
||||||
(testing "if altitude is less than 100 and state is forest then state should be climax and deer should be 3"
|
(testing "Rule parser - does not test whether generated functions actually work, just that something is generated!"
|
||||||
(is (parse-rule "if altitude is less than 100 and state is forest then state should be climax and deer should be 3"))
|
(is (parse-rule "if altitude is less than 100 and state is forest then state should be climax and deer should be 3"))
|
||||||
(is (let [cell (apply (eval (parse-rule "if altitude is less than 100 and state is forest then state should be climax and deer should be 3"))
|
(is (parse-rule "if altitude is less than 100 and state is forest then state should be climax and deer should be 3"))
|
||||||
(list {:state :forest :altitude 99} nil))]
|
(is (parse-rule "if altitude is 100 or fertility is 25 then state should be heath and fertility should be 24.3"))
|
||||||
(and (= (:state cell) :climax) (= (:deer cell) 3))))
|
(is (parse-rule "if altitude is 100 or fertility is 25 then state should be heath"))
|
||||||
|
(is (parse-rule "if deer is more than 2 and wolves is 0 and fertility is more than 20 then deer should be deer + 2"))
|
||||||
|
(is (parse-rule "if deer is more than 1 and wolves is more than 1 then deer should be deer - wolves"))
|
||||||
|
(is (parse-rule "if state is grassland and 4 neighbours have state equal to water then state should be village"))
|
||||||
|
(is (parse-rule "if state is forest and fertility is between 55 and 75 then state should be climax"))
|
||||||
|
(is (parse-rule "if 6 neighbours have state equal to water then state should be village"))
|
||||||
|
(is (parse-rule "if state is in grassland or pasture or heath and 4 neighbours are water then state should be village"))
|
||||||
|
|
||||||
|
;; ideally should also test that the rule works, but I haven't worked out how to make mw-engine.utils available
|
||||||
|
;; during eval
|
||||||
|
;; (is (let [cell (apply (eval (parse-rule "if altitude is less than 100 and state is forest then state should be climax and deer should be 3"))
|
||||||
|
;; (list {:state :forest :altitude 99} nil))]
|
||||||
|
;; (and (= (:state cell) :climax) (= (:deer cell) 3))))
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
;; * "if altitude is 100 or fertility is 25 then state should be heath and fertility should be 24.3"
|
|
||||||
;; * "if altitude is 100 or fertility is 25 then state should be heath"
|
|
||||||
;; * "if deer is more than 2 and wolves is 0 and fertility is more than 20 then deer should be deer + 2"
|
|
||||||
;; * "if deer is more than 1 and wolves is more than 1 then deer should be deer - wolves"
|
|
||||||
;;
|
|
Loading…
Reference in a new issue