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