drools4: Conway示例分析 (转)

drools4: Conway示例分析 (转)
  1. 到的类比较多,这里简单说明一下每个类的用途,不再详细列举代码
  2. AbstractRunConway.java 建立GUI界面
  3. ConwayGUI.java 在这里定义好了界面,以及按钮相关事件
  4. CellGridCanvas.java 绘制界面
  5. ConwayRuleFlowGroupRun.java 继承AbstractRunConway,使用规则流模式启动程序
  6. ConwayAgendaGroupRun.java 继承AbstractRunConway,使用Agenda组模式启动程序,之前版本不推荐
  7. ConwayApplicationProperties.java 用于从conway.properties中读取预定义的属性
  8. ConwayRuleDelegate.java 作为Agenda和规则流两种模式的统一接口
  9. *RuleFlowDelegate.java 规则流模式行为响应代理,界面按钮的动作由该类转发给规则引擎,引起WorkingMemory中的变化
  10. 使用规则流控制规则执行时,针对应用的不同操作共使用了4组规则流如下:
  11. 初始化init - 规则流"register neighbor"
  12. 产生下一步的变化nextGeneration - 规则流"generation",连续变化通过重复调用该步骤进行
  13. 清除killAll - 规则流"kill all"
  14. 模式设置setPattern - 规则流"calculate"
  15. AgendaGroupDelegate.java Agenda模式行为响应代理,作用同上
  16. Cell.java 代表一个格子,有行列属性和状态属性
  17. CellGrid.java 控制表格的抽象接口
  18. *CellGridImpl.java 表格接口的实现,用于向规则引擎中插入数据,以及调用响应代理
  19. 数据的插入分为两种情况
  20. 1、初始化棋盘
  21. 将代表棋盘的CellGrid实例插入
  22. 将棋盘上的每一个格子产生一个Cell对象插入
  23. 2、设置初始模式
  24. 根据提供的模式数组长宽向棋盘中间对齐,对于True的数组数据
  25. 修改对应格子的Cell状态为Live
  26. CellState.java 格子状态(生/死)
  27. Phase.java 在规则中用于控制格子处理的阶段,间接影响格子的状态
  28. Neighbor.java 用于保存两个格子之间的邻居关系
  29. ConwayPattern.java 模型初始化数据读取接口
  30. Border.java 一种模型初始格式,实现ConwayPattern接口
  31. Hi.java 同上
  32. Pentadecathalon.java 同上
  33. Pulsar.java 同上
  34. SimpleGlider.java 同上
  35. 思路:
  36. 从元细胞自动机模型的规则中我们可以发现几个关键要点,
  37. 1、一个格子的状态由相邻格子的状态决定;因此在规则处理中我们要能够方便的确定每个格子的相邻格子情况
  38. 2、格子的状态变化是一次性完成计算的,格子状态的改变不会对本次变化产生影响;因此在规则处理时要注意
  39. 解决fact变化激活新的规则的问题
  40. 作者将所有规则按照规则流分组的方式分为下面几个组
  41. "register north east" - 建立格子间的邻居关系(再次提醒,规则引擎推理基于数据,应当将所有需要的数据事先准备好
  42. 数据模型的好坏直接影响规则的效率和质量)
  43. "evaluate" - 根据格子邻居的情况判定格子下一步的状态,并预设一个值;这里之所以没有直接改变格子
  44. 状态就是因为上面提到的一次性计算问题,如果直接改变状态会影响对其它邻居格子的判断
  45. Phase:只对Phase==EVALUATE的格子执行
  46. "calculate" - 遍历每一个格子,根据该格子的生存/死亡状态更新邻居格子的‘邻居’生存个数
  47. 这里留意的是,按照正常的编程思路,应当是找到格子后获得所有邻居状态,然后计算有多少
  48. 个邻居格子是生存状态的,然后更新本格子中的LiveNeighbors计数;但是要采用这样的
  49. 思路,必然涉及到对集合的处理以及一些循环语句,这样增加了规则的复杂度以及引入了过程
  50. 代码,这都是在规则中应当避免的问题;而换一个角度思考我们就会得到更为简单的规则。
  51. Phase:规则完成后将格子的Phase设为EVALUATE
  52. 注:使用规则引擎不只是掌握一门新技术,而是要求在编程思维上的改变。
  53. "reset calculate" - 取消"calculate"组激活的规则,因为每次格子重新设置pattern时,盘面上还有生存的格子
  54. 这时如果使用kill all规则来将格子设为死亡,如果之前的calcuate规则还起作用,那么就会
  55. 引起calcuate规则执行,建立新的生存格子,反过来又会引起kill all规则执行,造成无限循环
  56. "kill" - 将Phase为KILL的格子状态设为死亡
  57. "birth" - 将Phase为BIRTH的格子状态设为生存
  58. "kill all" - 将所有格子的状态设为死亡,是用在初始化棋盘时
  59. */
  60. package org.drools.examples
  61. import org.drools.examples.conway.Cell;
  62. import org.drools.examples.conway.CellGrid;
  63. import org.drools.examples.conway.Neighbor;
  64. import org.drools.examples.conway.Phase;
  65. import org.drools.examples.conway.CellState;
  66. import org.drools.WorkingMemory;
  67. import org.drools.common.InternalWorkingMemoryActions;
  68. import org.drools.RuleBase;
  69. /*
  70. 下面的四条规则都属于ruleflow-group:"register neighbor"
  71. 它们的作用是建立格子之间彼此的邻居关系。
  72. 我们知道每个格子会有8个相邻的格子,而规则建立关系时都是成对建立的,
  73. 因此只用四条规则即可完成所有邻居关系建立
  74. */
  75. # 建立格子与其右上角格子的邻居关系
  76. rule "register north east"
  77. ruleflow-group "register neighbor"
  78. when
  79. # 获得棋盘列数
  80. CellGrid( $numberOfColumns : numberOfColumns )
  81. # 获得棋盘内的每个格子,最右边除外,因为最右边没有右上角
  82. $cell: Cell( $row : row > 0, $col : col < ( $numberOfColumns - 1 ) )
  83. # 获得上面格子的东北角格子
  84. $northEast : Cell( row == ($row - 1), col == ( $col + 1 ) )
  85. then
  86. # 为这两个格子建立邻居关系
  87. insert( new Neighbor( $cell, $northEast ) );
  88. insert( new Neighbor( $northEast, $cell ) );
  89. end
  90. # 建立格子与其正上方格子的邻居关系
  91. rule "register north"
  92. ruleflow-group "register neighbor"
  93. when
  94. $cell: Cell( $row : row > 0, $col : col )
  95. $north : Cell( row == ($row - 1), col == $col )
  96. then
  97. insert( new Neighbor( $cell, $north ) );
  98. insert( new Neighbor( $north, $cell ) );
  99. end
  100. # 建立格子与其左上角格子的邻居关系
  101. rule "register north west"
  102. ruleflow-group "register neighbor"
  103. when
  104. $cell: Cell( $row : row > 0, $col : col > 0 )
  105. $northWest : Cell( row == ($row - 1), col == ( $col - 1 ) )
  106. then
  107. insert( new Neighbor( $cell, $northWest ) );
  108. insert( new Neighbor( $northWest, $cell ) );
  109. end
  110. # 建立格子与其左边格子的邻居关系
  111. rule "register west"
  112. ruleflow-group "register neighbor"
  113. when
  114. $cell: Cell( $row : row >= 0, $col : col > 0 )
  115. $west : Cell( row == $row, col == ( $col - 1 ) )
  116. then
  117. insert( new Neighbor( $cell, $west ) );
  118. insert( new Neighbor( $west, $cell ) );
  119. end
  120. /*
  121. 下面的三条规则都属于ruleflow-group:"evaluate"
  122. 它们是用在进行下一步的变化评估中的,这3个规则中并没有直接改变Cell.CellState,
  123. 因为CellState是用来进行评估用的,随意改变会造成无限的循环调用,因此规则使用了Phase字段来控制格子状态变化
  124. 在评估中只是改变Phase,最后根据Phase的状态完成所有格子CellState的设置,并将Phase设回EVALUATE状态
  125. */
  126. # 将格子的邻居中少于两个是生存状态的格子的状态设为死
  127. rule "Kill The Lonely"
  128. ruleflow-group "evaluate"
  129. no-loop
  130. when
  131. # A live cell has fewer than 2 live neighbors
  132. theCell: Cell(liveNeighbors < 2, cellState == CellState.LIVE, phase == Phase.EVALUATE)
  133. then
  134. theCell.setPhase(Phase.KILL);
  135. update( theCell );
  136. end
  137. # 将格子的邻居中超过3个状态是生存的格子状态设为死
  138. rule "Kill The Overcrowded"
  139. ruleflow-group "evaluate"
  140. no-loop
  141. when
  142. # A live cell has more than 3 live neighbors
  143. theCell: Cell(liveNeighbors > 3, cellState == CellState.LIVE, phase == Phase.EVALUATE)
  144. then
  145. theCell.setPhase(Phase.KILL);
  146. update( theCell );
  147. end
  148. # 将格子的邻居中正好有3个是生存状态的死亡格子变为生
  149. rule "Give Birth"
  150. ruleflow-group "evaluate"
  151. no-loop
  152. when
  153. # A dead cell has 3 live neighbors
  154. theCell: Cell(liveNeighbors == 3, cellState == CellState.DEAD, phase == Phase.EVALUATE)
  155. then
  156. theCell.setPhase(Phase.BIRTH);
  157. update( theCell );
  158. end
  159. # 取消ruleflow-group为"calculate"的所有激活规则
  160. # clearRuleFlowGroup - Clears the RuleFlow group, cancelling all its Activations
  161. # 因为在"generation"后,"calculate"组的规则还留在引擎中,如果不事先取消,就会引起无限循环
  162. rule "reset calculate"
  163. ruleflow-group "reset calculate"
  164. when
  165. then
  166. WorkingMemory wm = drools.getWorkingMemory();
  167. wm.clearRuleFlowGroup( "calculate" );
  168. end
  169. # 将所有格子的Phase为Kill的格子状态设置为死,并将处理阶段Phase设置为DONE
  170. rule "kill"
  171. ruleflow-group "kill"
  172. no-loop
  173. when
  174. theCell: Cell(phase == Phase.KILL)
  175. then
  176. theCell.setCellState(CellState.DEAD);
  177. theCell.setPhase(Phase.DONE);
  178. update( theCell );
  179. end
  180. # 将所有格子的Phase为Birth的格子状态设置为生,并将处理阶段Phase设置为完成
  181. rule "birth"
  182. ruleflow-group "birth"
  183. no-loop
  184. when
  185. theCell: Cell(phase == Phase.BIRTH)
  186. then
  187. theCell.setCellState(CellState.LIVE);
  188. theCell.setPhase(Phase.DONE);
  189. update( theCell );
  190. end
  191. # 根据格子的生存状态改变邻居格子中LiveNeighbors属性的计数
  192. rule "Calculate Live"
  193. ruleflow-group "calculate"
  194. lock-on-active # 本规则更新的数据在规则流处理完成前不激活新的规则
  195. when
  196. # 获得状态为生存的格子
  197. theCell: Cell(cellState == CellState.LIVE)
  198. # 找到该格子的每一个邻居
  199. Neighbor(cell == theCell, $neighbor : neighbor)
  200. then
  201. # 为这个格子的每一个邻居的LiveNeighbors属性加1
  202. $neighbor.setLiveNeighbors( $neighbor.getLiveNeighbors() + 1 );
  203. # 将邻居格子的处理阶段Phase设置为EVALUATE
  204. $neighbor.setPhase( Phase.EVALUATE );
  205. update( $neighbor );
  206. System.out.println( "--live--" );
  207. System.out.println( "theCell: row"+theCell.getRow()+"col"+theCell.getCol());
  208. System.out.println ( "Neighbor: row:"+$neighbor.getRow()+"col"+$neighbor.getCol()+";LiveNeighbors:"+ $neighbor.getLiveNeighbors()) ;
  209. end
  210. # 类似上一规则,只是进行递减操作
  211. # 对于这个规则,不太熟悉规则引擎的程序员可能会有所迷惑,所有的格子初始化状态都是DEAD
  212. # 那这样的话很多格子的LiveNeighbors就会变成负数了,有这样的想法是因为忽略了规则引擎不是从数据里找到规则合适的地方
  213. # 而是在数据插入或发生变化时找到规则,一开始初始化所有格子为DEAD时确实激活了"Calculate Dead"的很多实例,但是在
  214. # setPattern时首先执行了"reset calculate",这取消了之前的所有"Calculate Dead"的激活实例
  215. # 然后运行"kill all"规则,如果是第一次,该规则不改变任何数据也不会激发新的规则
  216. # 然后是根据数据设置格子的生存状态,此时上面的"Calculate Live"规则被激活
  217. # 在后面的规则运算中每次执行"evalaute"规则组都要运行"reset calculate"也是这个原因
  218. # 然后在运行了"birth""kill"规则后才执行"Calculate Live""Calculate Dead"规则
  219. rule "Calculate Dead"
  220. ruleflow-group "calculate"
  221. lock-on-active # 本规则更新的数据在规则流处理完成前不激活新的规则
  222. when
  223. theCell: Cell(cellState == CellState.DEAD)
  224. Neighbor(cell == theCell, $neighbor : neighbor )
  225. then
  226. $neighbor.setLiveNeighbors( $neighbor.getLiveNeighbors() - 1 );
  227. $neighbor.setPhase( Phase.EVALUATE );
  228. update( $neighbor );
  229. System.out.println( "--dead--" );
  230. System.out.println( "theCell: row"+theCell.getRow()+"col"+theCell.getCol());
  231. System.out.println ( "Neighbor: row:"+$neighbor.getRow()+"col"+$neighbor.getCol()+";LiveNeighbors:"+ $neighbor.getLiveNeighbors()) ;
  232. end
  233. # 将所有生存状态的格子设为死亡
  234. rule "Kill All"
  235. ruleflow-group "kill all"
  236. no-loop
  237. when
  238. theCell: Cell(cellState == CellState.LIVE)
  239. then
  240. theCell.setCellState(CellState.DEAD);
  241. update( theCell );
  242. end
请使用浏览器的分享功能分享到微信等