[rules-users] conways game of life

Michael Neale michael.neale at gmail.com
Tue Apr 17 01:57:46 EDT 2007


Its interesting, Conways game of life was created to demonstrate a
"determinisitc universe" - if you think as the little "critters" as life
forms its pretty cool. A good example of how very very simple rules (and
only a small number) can create complex behaviour.



On 4/17/07, Mark Proctor <mproctor at redhat.com> wrote:
>
> I have just moved Jeff Brown's "Conways Game of Life" to a stateful
> example, this is now the best place to look to understand jboss rules.
> It's also good to compare this stateful implementation to the old
> stateless version. Trunk introduces a new feature to help deal with
> recursion "lock-on-active" which stops a rule being able to create
> activations while it's agenda-group/rule-flow-group has focus - so it's
> a much stronger no-loop. Probably the most important thing this example
> shows is how to think relationally, the old example used nested
> properties and sets to maintain the "neighbour" information; this
> example shows how to achieve the same but expressing it relationally,
> using the Neighbor relation class, further it shows how we can exploit
> the the cross-product relational information to drive the engine without
> us having to write loops. Currently the example is using agenda-groups
> to drive execution flow, I'm now in the process of moving this to
> rule-flow-groups.
>
> You'll need trunk to be able to run this, so checkout:
> http://anonsvn.labs.jboss.com/labs/jbossrules/trunk/
> Make sure you have maven 2.0.6 installed and then type the following
> from the root directory:
> mvn clean install -Declipse=true
> The eclipse plugin will now be built in the drools-eclipse/target
> directory, so open that up and unzip into your eclipse install (make
> sure you use -clean to start eclipse). Then import drools-examples and
> "run as application" the ConwayGUI class.
>
> I plan to do a blog or two on how this exampe works, and my next
> challenge will be to migrate the pacman game to jboss rules.
>
> Mark
>
> --
> Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod
> Street, Windsor, Berkshire,
> SI4 1TE, United Kingdom.
> Registered in UK and Wales under Company Registration No. 3798903
> Directors: Michael Cunningham (USA), Charlie Peters (USA) and David
> Owens (Ireland)
>
>
>
> package org.drools.examples
>
> import org.drools.examples.conway.Cell;
> import org.drools.examples.conway.CellGrid;
> import org.drools.examples.conway.Neighbor;
> import org.drools.examples.conway.Phase;
> import org.drools.examples.conway.CellState;
>
> import org.drools.WorkingMemory;
> import org.drools.common.InternalWorkingMemoryActions;
> import org.drools.RuleBase;
>
>
> rule "register north east"
>         agenda-group "register neighbor"
> when
>     CellGrid( $numberOfColumns : numberOfColumns )
>         $cell: Cell( $row : row > 0, $col : col < ( $numberOfColumns - 1 )
> )
>         $northEast : Cell( row  == ($row - 1), col == $col )
> then
>         assert( new Neighbor( $cell, $northEast ) );
>         assert( new Neighbor( $northEast, $cell ) );
> end
>
> rule "register north"
>         agenda-group "register neighbor"
> when
>         $cell: Cell( $row : row > 0, $col : col )
>         $north : Cell( row  == ($row - 1), col == $col )
> then
>         assert( new Neighbor( $cell, $north ) );
>         assert( new Neighbor( $north, $cell ) );
> end
>
> rule "register north west"
>         agenda-group "register neighbor"
> when
>         $cell: Cell( $row : row > 0, $col : col > 0 )
>         $northWest : Cell( row  == ($row - 1), col == ( $col - 1 ) )
> then
>         assert( new Neighbor( $cell, $northWest ) );
>         assert( new Neighbor( $northWest, $cell ) );
> end
>
> rule "register west"
>         agenda-group "register neighbor"
> when
>         $cell: Cell( $row : row > 0, $col : col > 0 )
>         $west : Cell( row  == $row, col == ( $col - 1 ) )
> then
>         assert( new Neighbor( $cell, $west ) );
>         assert( new Neighbor( $west, $cell ) );
> end
>
> rule "Kill The Lonely"
>         agenda-group "evaluate"
>         no-loop
> when
> #       A live cell has fewer than 2 live neighbors
>         theCell: Cell(liveNeighbors < 2, cellState == CellState.LIVE,
> phase == Phase.EVALUATE)
> then
>         theCell.setPhase(Phase.KILL);
>         modify( theCell );
> end
>
> rule "Kill The Overcrowded"
>         agenda-group "evaluate"
>         no-loop
> when
> #       A live cell has more than 3 live neighbors
>         theCell: Cell(liveNeighbors > 3, cellState == CellState.LIVE,
> phase == Phase.EVALUATE)
> then
>         theCell.setPhase(Phase.KILL);
>         modify( theCell );
> end
>
> rule "Give Birth"
>         agenda-group "evaluate"
>         no-loop
> when
> #       A dead cell has 3 live neighbors
>         theCell: Cell(liveNeighbors == 3, cellState == CellState.DEAD,
> phase == Phase.EVALUATE)
> then
>         theCell.setPhase(Phase.BIRTH);
>         modify( theCell );
> end
>
> rule "reset calculate"
>         agenda-group "reset calculate"
> when
> then
>         WorkingMemory wm = drools.getWorkingMemory();
>         wm.getAgenda().clearAgendaGroup( "calculate" );
> end
>
> rule "kill"
>         agenda-group "kill"
>         no-loop
> when
>         theCell: Cell(phase == Phase.KILL)
> then
>         theCell.setCellState(CellState.DEAD);
>         theCell.setPhase(Phase.DONE);
>         modify( theCell );
> end
>
> rule "birth"
>         agenda-group "birth"
>         no-loop
> when
>         theCell: Cell(phase == Phase.BIRTH)
> then
>         theCell.setCellState(CellState.LIVE);
>         theCell.setPhase(Phase.DONE);
>         modify( theCell );
> end
>
> rule "Calculate Live"
>         agenda-group "calculate"
>         lock-on-active
> when
>         theCell: Cell(cellState == CellState.LIVE)
>         Neighbor(cell == theCell, $neighbor : neighbor)
> then
>         $neighbor.setLiveNeighbors( $neighbor.getLiveNeighbors() + 1 );
>         $neighbor.setPhase( Phase.EVALUATE );
>         modify( $neighbor );
> end
>
> rule "Calculate Dead"
>         agenda-group "calculate"
>         lock-on-active
> when
>         theCell: Cell(cellState == CellState.DEAD)
>     Neighbor(cell == theCell, $neighbor : neighbor )
> then
>         $neighbor.setLiveNeighbors( $neighbor.getLiveNeighbors() - 1 );
>         $neighbor.setPhase( Phase.EVALUATE );
>         modify( $neighbor );
> end
>
> rule "Kill All"
>         agenda-group "kill all"
>         no-loop
> when
>         theCell: Cell(cellState == CellState.LIVE)
> then
>         theCell.setCellState(CellState.DEAD);
>         modify( theCell );
> end
> package org.drools.examples.conway;
>
> /**
> * A <code>Cell</code> represents a single cell within a
> <code>CellGrid</code>.
> * A cell may be either live or dead. <p/>
> *
> * @author <a href="mailto:brown_j at ociweb.com">Jeff Brown</a>
> * @see CellState
> * @see CellGrid
> */
> public class Cell {
>
>     private CellState cellState = CellState.DEAD;
>
>     private int       phase     = Phase.DONE;
>
>     private int       liveNeighbors;
>
>     private int       col;
>
>     private int       row;
>
>     public Cell(int col,
>                 int row) {
>         this.col = col;
>         this.row = row;
>     }
>
>     public int getCol() {
>         return col;
>     }
>
>     public int getRow() {
>         return row;
>     }
>
>     public int getPhase() {
>         return this.phase;
>     }
>
>     public void setPhase(int phase) {
>         this.phase = phase;
>     }
>
>     public int getLiveNeighbors() {
>         return this.liveNeighbors;
>     }
>
>     public void setLiveNeighbors(int liveNeighbors) {
>         this.liveNeighbors = liveNeighbors;
>     }
>
>     /**
>      * @return this cell's current life state
>      * @see #queueNextCellState(org.drools.examples.conway.CellState)
>      * @see CellState
>      */
>     public CellState getCellState() {
>         return this.cellState;
>     }
>
>     /**
>      * Sets this cells state
>      *
>      * @param newState
>      *            new state for this cell
>      * @see CellState
>      */
>     public void setCellState(final CellState newState) {
>         this.cellState = newState;
>     }
>
>     public String toString() {
>         return cellState + " col=" + this.col + " row=" + this.row + "
> phase '" + phase + "' liveNeighbors '" + liveNeighbors + "'";
>     }
> }
>
>
> package org.drools.examples.conway;
>
> import org.drools.RuleBase;
> import org.drools.WorkingMemory;
> import org.drools.event.AgendaGroupPoppedEvent;
> import org.drools.event.DefaultAgendaEventListener;
> import org.drools.examples.conway.patterns.ConwayPattern;
>
> /**
> * A <code>CellGrid</code> represents a grid of <code>Cell</code> objects.
> * <p/>
> *
> * @author <a href="mailto:brown_j at ociweb.com">Jeff Brown</a>
> * @see Cell
> */
> public class CellGrid {
>
>     private final Cell[][] cells;
>
>     private WorkingMemory  workingMemory;
>
>     /**
>      * Constructs a CellGrid
>      *
>      * @param rows
>      *            number of rows in the grid
>      * @param columns
>      *            number of columns in the grid
>      */
>     public CellGrid(final int rows,
>                     final int columns) {
>         this.cells = new Cell[rows][columns];
>
>         final RuleBase ruleBase = ConwayRuleBaseFactory.getRuleBase();
>         this.workingMemory = ruleBase.newWorkingMemory();
>
>         DefaultAgendaEventListener listener = new
> DefaultAgendaEventListener() {
>             public void agendaGroupPopped(AgendaGroupPoppedEvent event,
>                                           WorkingMemory workingMemory) {
>                 System.out.println( "popped AgendaGroup = '" +
> event.getAgendaGroup().getName() + "'" );
>                 System.out.println( CellGrid.this.toString() );
>                 System.out.println( "" );
>             }
>         };
>
>         this.workingMemory.addEventListener( listener );
>
>         this.workingMemory.assertObject( this );
>
>         // populate the array of Cells and hook each
>         // cell up with its neighbors...
>         for ( int row = 0; row < rows; row++ ) {
>             for ( int column = 0; column < columns; column++ ) {
>                 final Cell newCell = new Cell( column,
>                                                row );
>                 this.cells[row][column] = newCell;
>                 this.workingMemory.assertObject( newCell );
>             }
>         }
>         this.workingMemory.setFocus( "register neighbor" );
>         this.workingMemory.fireAllRules();
>     }
>
>     /**
>      * @param row
>      *            row of the requested cell
>      * @param column
>      *            column of the requested cell
>      * @return the cell at the specified coordinates
>      * @see Cell
>      */
>     public Cell getCellAt(final int row,
>                           final int column) {
>         return this.cells[row][column];
>     }
>
>     /**
>      * @return the number of rows in this grid
>      * @see #getNumberOfColumns()
>      */
>     public int getNumberOfRows() {
>         return this.cells.length;
>     }
>
>     /**
>      * @return the number of columns in this grid
>      * @see #getNumberOfRows()
>      */
>     public int getNumberOfColumns() {
>         return this.cells[0].length;
>     }
>
>     /**
>      * Moves this grid to its next generation
>      *
>      * @return <code>true</code> if the state changed, otherwise false
>      * @see #transitionState()
>      */
>     public boolean nextGeneration() {
>         System.out.println( "next generation" );
>         workingMemory.setFocus( "calculate" );
>         workingMemory.setFocus( "kill" );
>         workingMemory.setFocus( "birth" );
>         workingMemory.setFocus( "reset calculate" );
>         workingMemory.setFocus( "rest" );
>         workingMemory.setFocus( "evaluate" );
>         workingMemory.fireAllRules();
>         return workingMemory.getAgenda().getAgendaGroup( "evaluate"
> ).size() != 0;
>     }
>
>     /**
>      * kills all cells in the grid
>      */
>     public void killAll() {
>         this.workingMemory.setFocus( "calculate" );
>         this.workingMemory.setFocus( "kill all" );
>         this.workingMemory.setFocus( "reset calculate" );
>         this.workingMemory.fireAllRules();
>     }
>
>     /**
>      * Populates the grid with a <code>ConwayPattern</code>
>      *
>      * @param pattern
>      *            pattern to populate the grid with
>      * @see ConwayPattern
>      */
>     public void setPattern(final ConwayPattern pattern) {
>         final boolean[][] gridData = pattern.getPattern();
>         int gridWidth = gridData[0].length;
>         int gridHeight = gridData.length;
>
>         int columnOffset = 0;
>         int rowOffset = 0;
>
>         if ( gridWidth > getNumberOfColumns() ) {
>             gridWidth = getNumberOfColumns();
>         } else {
>             columnOffset = (getNumberOfColumns() - gridWidth) / 2;
>         }
>
>         if ( gridHeight > getNumberOfRows() ) {
>             gridHeight = getNumberOfRows();
>         } else {
>             rowOffset = (getNumberOfRows() - gridHeight) / 2;
>         }
>
>         killAll();
>
>         for ( int column = 0; column < gridWidth; column++ ) {
>             for ( int row = 0; row < gridHeight; row++ ) {
>                 if ( gridData[row][column] ) {
>                     final Cell cell = getCellAt( row + rowOffset,
>                                                  column + columnOffset );
>                     cell.setCellState( CellState.LIVE );
>                     this.workingMemory.modifyObject(
> this.workingMemory.getFactHandle( cell ),
>                                                      cell );
>                 }
>             }
>         }
>         workingMemory.setFocus( "calculate" );
>         workingMemory.fireAllRules();
>         System.out.println( "" );
>     }
>
>     public String toString() {
>         StringBuffer buf = new StringBuffer();
>
>         for ( int i = 0; i < this.cells.length; i++ ) {
>             for ( int j = 0; j < this.cells[i].length; j++ ) {
>                 Cell cell = this.cells[i][j];
>                 System.out.print( cell.getLiveNeighbors() + ((
> cell.getCellState() == CellState.DEAD) ? "D" : "L") + " " );
>             }
>             System.out.println( "" );
>         }
>
>         return buf.toString();
>     }
> }
>
>
> package org.drools.examples.conway;
>
> public class Neighbor {
>     private Cell cell;
>     private Cell neighbor;
>
>     public Neighbor(Cell cell, Cell neighbor) {
>         this.cell = cell;
>         this.neighbor = neighbor;
>     }
>
>     public Cell getCell() {
>         return cell;
>     }
>
>     public Cell getNeighbor() {
>         return neighbor;
>     }
>
>     public String toString() {
>         return "cell '"+ this.cell + "' neighbour '" + this.neighbor +
> "'";
>     }
>
> }
>
>
> _______________________________________________
> rules-users mailing list
> rules-users at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/rules-users
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/rules-users/attachments/20070417/8ba56f3c/attachment.html 


More information about the rules-users mailing list