论坛首页 Java企业应用论坛

drools4: Conway示例分析

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

跳转论坛:
Global site tag (gtag.js) - Google Analytics