Index: main/java/org/drools/examples/sudoku/Main.java
===================================================================
--- main/java/org/drools/examples/sudoku/Main.java	(revision 23682)
+++ main/java/org/drools/examples/sudoku/Main.java	(working copy)
@@ -11,6 +11,9 @@
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Iterator;
 
 import javax.swing.JButton;
 import javax.swing.JFileChooser;
@@ -21,11 +24,11 @@
 import javax.swing.JPanel;
 
 import org.drools.examples.sudoku.rules.DroolsSudokuGridModel;
-import org.drools.examples.sudoku.swing.SudokuGridSamples;
+import org.drools.examples.sudoku.swing.SudokuGridModelConstants;
 import org.drools.examples.sudoku.swing.SudokuGridView;
 
 /**
- * This example shows how Drools can be used to solve a 9x9 Sudoku Grid.
+ * This example shows how Drools can be used to solve a Sudoku Grid.
  * <p
  * This Class hooks together the GUI and the model and allows you to 
  * load different grids.
@@ -47,61 +50,115 @@
    private BorderLayout borderLayout = new BorderLayout();
    private FlowLayout flowLayout = new FlowLayout(FlowLayout.RIGHT);
    private JPanel buttonPanel = new JPanel(flowLayout);
-   private JButton solveButton = new JButton("Solve");
-   private JButton fireOneRuleButton = new JButton("Step");
+   private JButton solveButton = new JButton("Solve Grid");
+   private int numberOfSolvingPasses = 0;
    private JFileChooser fileChooser;
+   private JMenu gridMenu = new JMenu("Grid Size");
    
    public static void main(String[] args)
    {
-      @SuppressWarnings("unused")
-      Main main = new Main();
+	  Main main = new Main();
+	  main.run();
    }
    
    public Main()
    {
       mainFrame = new JFrame("Drools Sudoku Example");
-      for (String sampleName : SudokuGridSamples.getInstance().getSampleNames())
-      {
-         JMenuItem menuItem = new JMenuItem(sampleName);
-         menuItem.addActionListener(this);
-         samplesMenu.add(menuItem);
-      }
-      fileMenu.add(samplesMenu);
+
       openMenuItem.addActionListener(this);
-      // fileMenu.add(openMenuItem);
       exitMenuItem.addActionListener(this);
-      fileMenu.add(exitMenuItem);
-      menuBar.add(fileMenu);
+      setupGridSizeMenu();
+
+      setMenuBar();
       mainFrame.setJMenuBar(menuBar);
-      sudokuGridView = new SudokuGridView();
-      droolsSudokuGridModel = new DroolsSudokuGridModel(SudokuGridSamples.getInstance().getSample("Simple"));
       mainFrame.setLayout(borderLayout);
-      mainFrame.add(BorderLayout.CENTER, sudokuGridView);
-      // buttonPanel.add(fireOneRuleButton);
       buttonPanel.add(solveButton);
       solveButton.addActionListener(this);
       mainFrame.add(BorderLayout.SOUTH, buttonPanel);
       mainFrame.setSize(400,400);
       mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
-      mainFrame.setVisible(true);
-      sudokuGridView.setModel(droolsSudokuGridModel);
    }
 
+   private void clearMenuBar(){
+	      menuBar.remove(fileMenu);
+	      fileMenu = new JMenu("File");
+	   
+   }
+   
+private void setMenuBar() {
+	fileMenu.add(addSampleMenu());
+      fileMenu.add(gridMenu);
+      fileMenu.add(exitMenuItem);
+      menuBar.add(fileMenu);
+}
+
+private JMenu addSampleMenu() {
+	 Iterator<String> iter = SudokuGridModelConstants.getInstance().getSampleNames().iterator();
+	 samplesMenu = new JMenu("Samples");
+      while(iter.hasNext())
+      {
+         String sampleName = iter.next();
+         JMenuItem menuItem = new JMenuItem(sampleName);
+         menuItem.addActionListener(this);
+         samplesMenu.add(menuItem);
+      }
+      return samplesMenu;
+}
+
+private void setupGridSizeMenu()
+{
+	JMenuItem menuItem = new JMenuItem("4x4");
+    gridMenu.add(menuItem);
+    menuItem.addActionListener(this);
+    menuItem = new JMenuItem("6x6");
+    gridMenu.add(menuItem);
+    menuItem.addActionListener(this);
+    menuItem = new JMenuItem("9x9");
+    gridMenu.add(menuItem);
+    menuItem.addActionListener(this);
+}
+/**
+ * 
+ */
+private void run() {
+	  sudokuGridView = new SudokuGridView();
+      droolsSudokuGridModel = new DroolsSudokuGridModel(SudokuGridModelConstants.getInstance().getSample("Simple"));
+      sudokuGridView.setModel(droolsSudokuGridModel);
+      mainFrame.add(BorderLayout.CENTER, sudokuGridView);
+      mainFrame.setVisible(true);
+      }
+
    public void actionPerformed(ActionEvent ev)
    {
       if (ev.getSource().equals(solveButton))
       {
          long startTime = System.currentTimeMillis();
 
-         if (droolsSudokuGridModel.solve())
+         if ( numberOfSolvingPasses > 0)
          {
+             droolsSudokuGridModel.determineCellsByGuessing();        	 
+             droolsSudokuGridModel.solve();
+         }
+         else {
+             droolsSudokuGridModel.solve();        	 
+         }
+         numberOfSolvingPasses++;
+         
+         if ( droolsSudokuGridModel.isGridSolved())
+         {
             solveButton.setText("Solved ("+(System.currentTimeMillis()-startTime)+" ms)");
             solveButton.setEnabled(false);
          }
          else
          {
-            solveButton.setText("Unsolved ("+(System.currentTimeMillis()-startTime)+" ms)");
-            solveButton.setEnabled(false);            
+        	 if(droolsSudokuGridModel.isGridInError())
+        	 {
+        		 solveButton.setText("Not Solved ("+(System.currentTimeMillis()-startTime)+" ms)");
+                 solveButton.setEnabled(false);        		 
+        	 }
+        	 else{
+        		 solveButton.setText("Try guessing?");
+        	 }
          }
       }
       else if (ev.getSource().equals(openMenuItem))
@@ -129,15 +186,34 @@
       }
       else if (ev.getSource() instanceof JMenuItem)
       {
-         JMenuItem menuItem = (JMenuItem) ev.getSource();
-         droolsSudokuGridModel = new DroolsSudokuGridModel(SudokuGridSamples.getInstance().getSample(menuItem.getText()));
-         sudokuGridView.setModel(droolsSudokuGridModel);
+    	  JMenuItem menuItem = (JMenuItem) ev.getSource();
+    	  boolean sampleMatch = false;
+    		 Iterator<String> iter = SudokuGridModelConstants.getInstance().getSampleNames().iterator();
+    		 while(iter.hasNext())
+    	      {
+    	         String sampleName = iter.next();
+    	         if(sampleName.equals(menuItem.getText())){
+    	        	 sampleMatch = true;
+    	         }
+    	      }
+  	  
+    	  if (sampleMatch ){
+    		 droolsSudokuGridModel = new DroolsSudokuGridModel(SudokuGridModelConstants.getInstance().getSample(menuItem.getText()));
+             sudokuGridView.setModel(droolsSudokuGridModel);
+    	 }
+    	 else     		   
+    	 {
+    		 SudokuGridModelConstants.getInstance().setConstantType( menuItem.getText());
+    			 
+    	     // need to refresh the grid object
+    		 clearMenuBar();
+    		 setMenuBar();
+    	     mainFrame.remove(sudokuGridView);
+    	     run();
+    	 }
          solveButton.setText("Solve");
          solveButton.setEnabled(true);
+         numberOfSolvingPasses = 0;
       }
-      else
-      {
-         //
-      }
    }
 }
Index: main/java/org/drools/examples/sudoku/rules/AbstractCellValue.java
===================================================================
--- main/java/org/drools/examples/sudoku/rules/AbstractCellValue.java	(revision 23682)
+++ main/java/org/drools/examples/sudoku/rules/AbstractCellValue.java	(working copy)
@@ -6,7 +6,7 @@
  */
 package org.drools.examples.sudoku.rules;
 
-import org.drools.examples.sudoku.swing.SudokuGridModel;
+import org.drools.examples.sudoku.swing.SudokuGridModelConstants;
 
 /**
  * An abstract class which contains the methods common to both a PossibleCellValue
@@ -67,7 +67,7 @@
     */
    private int deriveZone(int row, int col)
    {
-      return SudokuGridModel.ZONE_LOOKUP[row][col];
+      return SudokuGridModelConstants.getInstance().getZoneLookup()[row][col];
    }
    
    /**
Index: main/java/org/drools/examples/sudoku/rules/BaseCell.java
===================================================================
--- main/java/org/drools/examples/sudoku/rules/BaseCell.java	(revision 0)
+++ main/java/org/drools/examples/sudoku/rules/BaseCell.java	(revision 0)
@@ -0,0 +1,31 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ * 
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.drools.examples.sudoku.rules;
+
+/**
+ * Represents a single cell location, used to ensure that all possible
+ * cell locations have a determined a cell value as it is possible to 
+ * to eliminate all values for a given row and column in a in error Grid.
+ * 
+ * @author <a href="">Ted Keenan</a>
+ * @version $Revision: 1.1 $
+ */
+public class BaseCell
+   extends AbstractCellValue
+{
+   /**
+    * Uses the constructor on the superclass to construct a new BaseCell
+    * 
+    * @param value the tested value in the cell from 1-9
+    * @param row the row index from 0-8
+    * @param col the column index from 0-8
+    */   
+   public BaseCell(int value, int row, int col)
+   {
+      super(value, row, col);
+   }
+}
Index: main/java/org/drools/examples/sudoku/rules/DroolsSudokuGridModel.java
===================================================================
--- main/java/org/drools/examples/sudoku/rules/DroolsSudokuGridModel.java	(revision 23682)
+++ main/java/org/drools/examples/sudoku/rules/DroolsSudokuGridModel.java	(working copy)
@@ -8,8 +8,11 @@
 
 import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
+
+import org.drools.FactException;
 import org.drools.RuleBase;
 import org.drools.StatefulSession;
 import org.drools.event.ObjectInsertedEvent;
@@ -17,16 +20,21 @@
 import org.drools.event.ObjectUpdatedEvent;
 import org.drools.event.WorkingMemoryEventListener;
 import org.drools.examples.sudoku.swing.AbstractSudokuGridModel;
+import org.drools.examples.sudoku.swing.GridModelConstants;
 import org.drools.examples.sudoku.swing.SudokuGridEvent;
-import org.drools.examples.sudoku.swing.SudokuGridModel;
+import org.drools.examples.sudoku.swing.SudokuGridModelInterface;
+import org.drools.examples.sudoku.swing.SudokuGridModelConstants;
 
 /**
  * An implementation of the SudokuGridModel interface which is backed by the Drools engine.
  * <p>
- * Two rule bases are used in this implementation. The first, defined at SUDOKU_SOLVER_DRL 
- * provides a set of rules that attempt to solve a partially completed Sudoku grid. The
- * second, defined at SUDOKU_VALIDATOR_DRL provides a set of rules which can validate 
+ * A single rule base with multiple agenda-groups is used in this implementation. 
+ * The first agenda-group, "BaseTest" provides a set of rules that attempt to solve 
+ * a partially completed Sudoku grid. 
+ * The second agenda-group, "validator" provides a set of rules which can validate  
  * whether the current state of the model represents a valid solution.
+ * Additional agenda-groups provide a guess and test agendas that can be used to identify
+ * possible values that can be eliminated because they end in error.
  * <p>
  * 
  * @author <a href="pbennett@redhat.com">Pete Bennett</a>
@@ -35,25 +43,20 @@
 @SuppressWarnings("unchecked")
 public class DroolsSudokuGridModel
    extends AbstractSudokuGridModel
-   implements SudokuGridModel
+   implements SudokuGridModelInterface 
 {
    /**
     * The location of the DRL file which defines the rule base for solving a Sudoku grid
     */
-   public final static String SUDOKU_SOLVER_DRL = "../sudokuSolver.drl";
+	public final static String SUDOKU_SOLVER_DRL = "../sudokuSolverValidatorWithGuess.drl";
    
-   /**
-    * The location of the DRL file which defines the rule base for validating the content of a Sudoku grid
-    */
-   public final static String SUDOKU_VALIDATOR_DRL = "../sudokuValidator.drl";
-   
    /** A set of AbtractCellValues capturing the current state of the grid */
    private Set<AbstractCellValue> allCellValues 
       = new HashSet<AbstractCellValue>();
    
    /** A index into the AbstractCellValues based on row and column */
    private Set<Integer>[][] cellValuesByRowAndCol 
-      = new HashSet[SudokuGridModel.NUM_ROWS][SudokuGridModel.NUM_COLS];
+      = new HashSet[SudokuGridModelConstants.getInstance().getNumRows()][SudokuGridModelConstants.getInstance().getNumCols()];
 
    /** The solver rule base */
    private RuleBase solverRuleBase;
@@ -63,8 +66,14 @@
 
    /** An inner class implementation listening to working memory events */
    private SudokuWorkingMemoryListener workingMemoryListener = new SudokuWorkingMemoryListener();
-   
+   /** A object to track the state of the model */
+   private DroolsSudokuGridModelState state = new DroolsSudokuGridModelState();
+
    /**
+    * Constants associated with setting up the grid which can be 4x4 or 9x9
+    */
+   protected GridModelConstants modelConstants = SudokuGridModelConstants.getInstance();
+   /**
     * Create a new DroolsSudokuGridModel with an empty grid.
     */
    public DroolsSudokuGridModel()
@@ -107,20 +116,25 @@
       if (solverStatefulSession != null)
       {
          solverStatefulSession.removeEventListener(workingMemoryListener);
+         solverStatefulSession.removeEventListener(state.getWorkingMemoryErrorListener());
       }
       
       solverStatefulSession = solverRuleBase.newStatefulSession();
       solverStatefulSession.addEventListener(workingMemoryListener);
-      
+      solverStatefulSession.addEventListener(state.getWorkingMemoryErrorListener());
+      // set up the facts that will be used in the memory
       for(int row=0; row<cellValues.length; row++)
       {
          for (int col=0; col<cellValues[row].length; col++)
          {
             cellValuesByRowAndCol[row][col] = new HashSet<Integer>();
+        	BaseCell cell = new BaseCell(0, row, col);
+        	addCellValue(cell);
             
+            // check if the cell row is set if not all are possible
             if(cellValues[row][col] == null)
             {
-               for(int value=1; value<10; value++)
+        	   for(int value=1; value<=cellValues.length; value++)
                {
                   PossibleCellValue cellValue = new PossibleCellValue(value, row, col);
                   addCellValue(cellValue);
@@ -129,12 +143,13 @@
             }
             else
             {
+            	// cell is resolved set it up that way
                ResolvedCellValue cellValue = new ResolvedCellValue(cellValues[row][col], row, col);
                addCellValue(cellValue);
             }
          }
       }
-      
+      // set up the memory with the cells
       insertAllCellValues(solverStatefulSession);
       System.out.println("Setting up working memory and inserting all cell value POJOs took "+(System.currentTimeMillis()-startTime)+"ms.");
    }
@@ -171,63 +186,15 @@
     * @return true if the current state represents a completely filled out
     *              and valid Sudoku solution, false otherwise
     */
+   
    public boolean isGridSolved()
    {
-      boolean solved = true;
-      
-      // TODO: move this logic into SUDOKU_VALIDATOR_DRL and out of Java code
-      for(int row=0; row<NUM_ROWS; row++)
-      {
-         for (int col=0; col<NUM_COLS; col++)
-         {
-            if(!isCellResolved(row, col))
-            {
-               System.out.print("("+row+","+col+") has not been resolved but has been narrowed down to ");
-               for (Integer possibleInt : getPossibleCellValues(row, col))
-               {
-                  System.out.print(possibleInt+" ");
-               }
-               System.out.println();
-               solved=false;
-            }
-         }
-      }
-      
-      if (solved)
-      {
-         try
-         {
-            RuleBase validatorRuleBase = DroolsUtil.getInstance().readRuleBase(SUDOKU_VALIDATOR_DRL);
-            
-            StatefulSession validatorStatefulSession = validatorRuleBase.newStatefulSession();
-            List issues = new ArrayList();
-            validatorStatefulSession.setGlobal("issues", issues);
-            insertAllCellValues(validatorStatefulSession);
-            validatorStatefulSession.fireAllRules();
-            
-            if (issues.isEmpty())
-            {
-               System.out.println("Sucessfully Validated Solution");
-            }
-            else
-            {
-               solved = false;
-               for (Object issue : issues)
-               {
-                  System.out.println(issue);
-               }
-            }
-         }
-         catch (Exception ex)
-         {
-            ex.printStackTrace();
-            throw new RuntimeException();
-         }
-      }
-      
-      return solved;
+	   return state.isSolved();
    }
    
+
+
+
    /**
     * Returns the possible values of the cell at a specific 
     * row and column in the Grid.
@@ -240,25 +207,187 @@
     */
    public Set<Integer> getPossibleCellValues(int row, int col)
    {
-      return cellValuesByRowAndCol[row][col];
+	   return cellValuesByRowAndCol[row][col];
    }
-   
    /**
-    * Attempt to solve the Sudoku puzzle from its current state by 
-    * firing all of the rules in SUDOKU_SOLVER_DRL against the 
-    * current state of the Grid then validate if we have solved the 
-    * Grid after this.
+    * Try to solve the grid using just the base solution
     * 
-    * @return true if the state after firing all rules 
-    *              represents a completely filled out
-    *              and valid Sudoku solution, false otherwise 
+    * @return true if the grid can be solved
     */
-   public boolean solve()
-   {
-      solverStatefulSession.fireAllRules();
-      
-      return isGridSolved();
+   public boolean solve(){
+	   try
+       {
+				baseSolution();
+
+				if (state.isInError()) {
+					System.out.println("First Pass with a logical error ");
+					return false;
+				} 
+			
+			if (state.isSolved()) {
+				System.out.println("Sucessfully Validated Solution");
+			} 
+		}
+       catch (Exception ex)
+       {
+          ex.printStackTrace();
+          throw new RuntimeException();
+       }
+	   return state.isSolved() ;
    }
+
+/**
+ * Try to limit one cell to a single possible value so the base test can be used
+ * 
+ * @return true when a cell has been identified that has a single possible value
+ *  
+ * @throws FactException
+ */
+public boolean determineCellsByGuessing() throws FactException {
+	// look to determine the solution to at least one cell
+	int numGuesses = 0;
+	int numErrors = 0;
+	
+	// remove the working memory listener so that it ignores the testing
+	solverStatefulSession.removeEventListener(workingMemoryListener);
+	
+	while((state.isUnSolved()) ){
+		numGuesses = setupGuesses();
+		if (numGuesses == 0 )
+			return false;
+		numErrors = numGuesses ;
+		for (int i = 0; i < numGuesses; i++) {
+			guessTesting();
+			if (state.isSolved())
+			{
+				solverStatefulSession.addEventListener(workingMemoryListener);
+				lastGuessWasRight();
+				break;
+			}				
+			else if (state.isInError()) {
+				numErrors--;
+				solverStatefulSession.addEventListener(workingMemoryListener);
+				lastGuessWasWrong(numErrors);
+				// if there is 1 value left then a cell has been determined
+				// Treat as if it was solved
+				if (numErrors == 1)
+				{
+					state.setIsSolved( DroolsSudokuGridModelState.SUDOKU_STATE_UNSOLVED);
+					return true;
+				}
+				solverStatefulSession.removeEventListener(workingMemoryListener);
+			}
+			else
+			{
+				lastGuessIndeterminate();
+			}
+		}
+	}
+	return true;	
+}
+
+/**
+ * BaseSolution does three things
+ * 1. Test the grid to find resolved cells and remove possible cells  
+ * 2. Remove any errors from previous passes
+ * 3. Validate the current solutions
+ * 
+ * @see DroolsSudokuGridModelState for error listneer
+ * note this uses agenda groups which are put on a stack last to fire goes first
+ *
+ * @throws FactException
+ */
+private void baseSolution() throws FactException {
+	solverStatefulSession.setFocus("Validator");
+	solverStatefulSession.setFocus("ReverseErrors");
+	solverStatefulSession.setFocus("BaseTest");
+  	solverStatefulSession.fireAllRules();
+}
+
+/**
+ * guessTesting does three things
+ * 1. In guess mode test the grid to find resolved cells and remove possible cells  
+ * 2. Remove any errors from previous passes
+ * 3. Validate the current solutions
+ * 
+ * @see DroolsSudokuGridModelState for error listneer
+ * Note the method uses agenda groups which are put on a stack last to fire goes first
+ *
+ * @throws FactException
+ */
+private void guessTesting() {
+	 // Reset solved issues
+	state.setIsSolved(DroolsSudokuGridModelState.SUDOKU_STATE_UNSOLVED);
+	 solverStatefulSession.setFocus("Validator");
+     solverStatefulSession.setFocus("ReverseErrors");
+	 solverStatefulSession.setFocus("GuessTesting");
+	 solverStatefulSession.fireAllRules();
+}
+
+/**
+ * Reverse the last guesses in 2 steps
+ * 1. Reverse the results of the tested guess 
+ * 2. Remove possible rows for the non-correct guess
+ * 
+ * Note the method uses agenda groups which are put on a stack last to fire goes first
+ * 
+ * @throws FactException
+ */
+private void lastGuessWasRight() throws FactException {
+	
+	solverStatefulSession.setFocus("CleanupCorrectGuess");
+	solverStatefulSession.setFocus("ReverseGuess");
+	solverStatefulSession.fireAllRules();
+}
+
+/**
+ * Set the opposite guess from the previous guess which caused an error
+ *  
+ * Note the method uses agenda groups which are put on a stack last to fire goes first
+ * 
+ * @throws FactException
+ */
+private void lastGuessWasWrong(int numErrors) throws FactException {
+	solverStatefulSession.setFocus("GuessSelectionError");
+	if (numErrors == 1)
+	{
+		solverStatefulSession.setFocus("GuessSelectionErrorOneCellRemains");
+	}
+	solverStatefulSession.setFocus("ReverseGuess");
+	solverStatefulSession.fireAllRules();
+	
+}
+/**
+ * The last guess was indeterminate reverse the actions of the guess so that the other
+ * guess can be made 
+ * 
+ * @throws FactException
+ */
+private void lastGuessIndeterminate() throws FactException 
+{
+	solverStatefulSession.setFocus("ReverseGuess");
+	solverStatefulSession.fireAllRules();
+}
+
+/**
+ * Set up the next guess items and return the number of guesses to set up
+ * 
+ * Note the method uses agenda groups which are put on a stack last to fire goes first
+ * 
+ * @return the number of guesses that have been set up
+ * @throws FactException
+ */
+private int setupGuesses() throws FactException {
+	 state.setNumGuesses(0);
+	 solverStatefulSession.setFocus("GuessSelection");
+	 solverStatefulSession.setFocus("GuessSetup");
+	 solverStatefulSession.setFocus("CleanupUnsolved");
+	 solverStatefulSession.setFocus("ReverseErrors");
+     solverStatefulSession.setFocus("ArchiveGuesses");
+     solverStatefulSession.setFocus("BasicRevGuess");
+	 solverStatefulSession.fireAllRules( );
+	 return state.getNumGuesses();
+}
    
    /**
     * Fire the next rule on the agenda and return
@@ -287,7 +416,7 @@
    {
       for (AbstractCellValue cellValue : allCellValues)
       {
-         statefulSession.insert(cellValue);
+          statefulSession.insert(cellValue);
       }
    }
 
@@ -300,7 +429,10 @@
    private void addCellValue(AbstractCellValue cellValue)
    {
       allCellValues.add(cellValue);
-      cellValuesByRowAndCol[cellValue.getRow()][cellValue.getCol()].add(cellValue.getValue());
+      if ( (cellValue instanceof PossibleCellValue)
+	     ||(cellValue instanceof ResolvedCellValue)){
+		        cellValuesByRowAndCol[cellValue.getRow()][cellValue.getCol()].add(cellValue.getValue());
+      }
    }
 
    /**
@@ -312,7 +444,10 @@
    private void removeCellValue(AbstractCellValue cellValue)
    {
       allCellValues.remove(cellValue);
-      cellValuesByRowAndCol[cellValue.getRow()][cellValue.getCol()].remove(cellValue.getValue());
+      if ((cellValue instanceof PossibleCellValue)
+    		  ||(cellValue instanceof ResolvedCellValue)){
+          cellValuesByRowAndCol[cellValue.getRow()][cellValue.getCol()].remove(cellValue.getValue());
+      }
    }
  
 
@@ -340,7 +475,8 @@
    
       public void objectRetracted(ObjectRetractedEvent ev)
       {
-         if (ev.getOldObject() instanceof AbstractCellValue)
+          if ((ev.getOldObject() instanceof PossibleCellValue)
+        		  ||(ev.getOldObject() instanceof ResolvedCellValue))
          {
             AbstractCellValue cellValue = (AbstractCellValue) ev.getOldObject();
             
@@ -355,7 +491,13 @@
          {
             ResolvedCellValue cellValue = (ResolvedCellValue) ev.getObject();
             fireCellUpdatedEvent(new SudokuGridEvent(this, cellValue.getRow(), cellValue.getCol(), cellValue.getValue()));
+   
          }     
       }
    }
+
+public boolean isGridInError()    {
+	   return state.isInError();
 }
+
+}
Index: main/java/org/drools/examples/sudoku/rules/DroolsSudokuGridModelState.java
===================================================================
--- main/java/org/drools/examples/sudoku/rules/DroolsSudokuGridModelState.java	(revision 0)
+++ main/java/org/drools/examples/sudoku/rules/DroolsSudokuGridModelState.java	(revision 0)
@@ -0,0 +1,110 @@
+package org.drools.examples.sudoku.rules;
+
+import org.drools.event.ObjectInsertedEvent;
+import org.drools.event.ObjectRetractedEvent;
+import org.drools.event.ObjectUpdatedEvent;
+import org.drools.event.WorkingMemoryEventListener;
+
+public class DroolsSudokuGridModelState {
+	/**
+	    * Mask for cases that haven't been completely solved
+	    */
+	   public final static int SUDOKU_STATE_SOLVED = 0;
+	/**
+	    * Mask for cases that haven't been completely solved
+	    */
+	   public final static int SUDOKU_STATE_UNSOLVED = 1;
+	   /**
+	    * Mask for cases that indicate a bad guess or an unsoluble puzzle
+	    */
+	   public final static int SUDOKU_STATE_ERROR = 2;
+
+	/** An inner class implementation listening to working memory error events */
+	private SudokuWorkingMemoryErrorListener workingMemoryErrorListener;
+	/**
+	    * Flag for tracking errors and the type of error
+	    */
+	private int isSolved;
+	/** 
+	    * Counter for the number of guesses
+	    */
+	private int numGuesses;
+
+	public DroolsSudokuGridModelState() {
+		this.workingMemoryErrorListener = new SudokuWorkingMemoryErrorListener();
+		this.isSolved = SUDOKU_STATE_UNSOLVED ;
+		this.numGuesses = 0;
+	}
+	public boolean isSolved()
+	{
+		return (isSolved == SUDOKU_STATE_SOLVED );
+	}
+	public boolean isUnSolved()
+	{
+		return (isSolved == SUDOKU_STATE_UNSOLVED );
+	}
+
+	public boolean isInError()
+	{
+		return (isSolved == SUDOKU_STATE_ERROR );
+	}
+
+	public WorkingMemoryEventListener getWorkingMemoryErrorListener() {
+		return (WorkingMemoryEventListener) workingMemoryErrorListener;
+	}
+
+/*	public int getIsSolved() {
+		return isSolved;
+	}
+*/
+	public void setIsSolved(int isSolved) {
+		this.isSolved = isSolved;
+	}
+
+	public int getNumGuesses() {
+		return numGuesses;
+	}
+
+	public void setNumGuesses(int numGuesses) {
+		this.numGuesses = numGuesses;
+	}
+	
+	   class SudokuWorkingMemoryErrorListener
+	   implements WorkingMemoryEventListener
+	{
+	   // Check for insert of any error
+	   public void objectInserted(ObjectInsertedEvent ev)
+	   {
+	      if (ev.getObject() instanceof SudokuStatusConflict) 
+	      {
+	    	  setIsSolved(SUDOKU_STATE_ERROR);
+	      }
+	      if ((ev.getObject() instanceof SudokuStatusUnresolved) && (!isInError()))
+	      {
+	    	  setIsSolved( SUDOKU_STATE_UNSOLVED);
+	      }
+	      if(ev.getObject() instanceof GuessedCellValue){
+	    	  setNumGuesses(getNumGuesses() + 1);
+	      }
+	      if(ev.getObject() instanceof SudokuStatusSolved){
+	    	  setIsSolved( SUDOKU_STATE_SOLVED );	    	  
+	      }
+	   }
+
+	      public void objectRetracted(ObjectRetractedEvent ev)
+	      {
+	         if (ev.getOldObject() instanceof GuessedCellValue)
+	         {
+		    	  setNumGuesses(getNumGuesses() - 1);
+	         }     
+	      }
+	   public void objectUpdated(ObjectUpdatedEvent ev)
+	   {
+		      if(ev.getObject() instanceof GuessedCellValue){
+		    	  setNumGuesses(getNumGuesses() + 0);
+		      }
+		   
+	   }
+	}
+
+}
\ No newline at end of file
Index: main/java/org/drools/examples/sudoku/rules/GuessedCellValue.java
===================================================================
--- main/java/org/drools/examples/sudoku/rules/GuessedCellValue.java	(revision 0)
+++ main/java/org/drools/examples/sudoku/rules/GuessedCellValue.java	(revision 0)
@@ -0,0 +1,111 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ * 
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.drools.examples.sudoku.rules;
+
+/**
+ * Object for tracking the testing of possible cells in a guess and 
+ * test scenario. Each guess is a single, possible value for a given cell,
+ * used when we are guessing what the value for this cell is, only a 
+ * single GuessedCellValue object should be associated with a 
+ * given row and column in a working Grid.
+ * Guessed cells extends RemovedCellBase which has the classes to track which
+ * possible cells were removed to create the guess
+ * 
+ * @author <a href="">Ted Keenan</a>
+ * @version $Revision: 1.1 $
+ */
+public class GuessedCellValue
+   extends RemovedCellBase
+{
+ /**
+  *  Constant for cells that you are planing to test during a guessing cycle
+  */
+   public static int GUESSING_STATUS_PLANED = 0;
+   /**
+    *  Constant for the active cell during a guessing cycle
+    */  
+   public static int GUESSING_STATUS_ACTIVE = 1;
+   /**
+    *  Constant for cells that have been tested during a guessing cycle
+    */  
+   public static int GUESSING_STATUS_TESTED = 2;
+   /**
+    *  Constant for the cell guessed during a previous guessing cycle
+    */  
+   public static int GUESSING_STATUS_PREVIOUS = 4;
+   /**
+    *  state of the cell guessed during the current guessing cycle
+    */  
+   private int state;
+
+   /**
+    * Uses the constructor on the superclass to construct a new GuessedCellValue
+    * from the possible cell being removed
+    * 
+    * @param cellValue possible cell being removed
+    */   
+   public GuessedCellValue(PossibleCellValue cellValue)
+   {
+      super(cellValue);
+      this.state = GUESSING_STATUS_PLANED;
+   }
+   /**
+    * Return the state stored in this cell
+    * 
+    * @return the cell's state
+    */
+   public int getState()
+   {
+      return state;
+   }
+   /**
+    * set the state stored in this cell
+    * 
+    * @param state the new state of the guessed cell
+    */
+   public void setState(int state)
+   {
+      this.state = state;
+   }
+   /**
+    * Return true if the cell is planned for guessing
+    * 
+    * @return state == GUESSING_STATUS_PLANED
+    */
+   public boolean getPlanned()
+   {
+      return (state == GUESSING_STATUS_PLANED);
+   }
+   
+   /**
+    * Return true if the cell is the active guess
+    * 
+    * @return state == GUESSING_STATUS_ACTIVE
+    */
+   public boolean getActive()
+   {
+      return (state == GUESSING_STATUS_ACTIVE);
+   }
+   /**
+    * Return true if the cell has been tested in the current cycle
+    * 
+    * @return state == GUESSING_STATUS_TESTED
+    */
+   public boolean getTested()
+   {
+      return (state == GUESSING_STATUS_TESTED);
+   }
+   /**
+    * Return true if the cell has been tested in a previous cycle
+    * 
+    * @return state == GUESSING_STATUS_PREVIOUS
+    */
+   public boolean getPrevious()
+   {
+      return (state == GUESSING_STATUS_PREVIOUS);
+   }
+}
Index: main/java/org/drools/examples/sudoku/rules/RemovedCellBase.java
===================================================================
--- main/java/org/drools/examples/sudoku/rules/RemovedCellBase.java	(revision 0)
+++ main/java/org/drools/examples/sudoku/rules/RemovedCellBase.java	(revision 0)
@@ -0,0 +1,74 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ * 
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.drools.examples.sudoku.rules;
+
+/**
+ * An abstract class which contains the methods common to both a GuessedCellValue
+ * and RemovedCellValue. Stores the possible cell that is removed by a guessing cycle
+ * and the resolved cell (if any) that was inserted in its place.
+ * It also overrides the methods of AbstractCellValue to return the location
+ * and value of the PossibleCellValue that was removed.
+ * 
+ * @author <a href="">Ted Keenan</a>
+ * @version $Revision: 1.1 $
+ */
+public abstract class RemovedCellBase
+   extends AbstractCellValue
+{
+	PossibleCellValue cellRemoved; 
+	ResolvedCellValue cellResolved;
+   /**
+    * Uses the constructor on the superclass to construct a new RemovedCellBase
+    * 
+    * @param cellValue the PossibleCellValue that was removed 
+    * @param resolvedCell the ResolvedCellValue that was inserted in its place, default = null
+    */   
+   public RemovedCellBase(PossibleCellValue cellValue , ResolvedCellValue  resolvedCell)
+   {
+      super(cellValue);
+      cellRemoved = cellValue;
+      this.cellResolved = resolvedCell;
+   }
+   /**
+    * Uses the constructor on the superclass to construct a new RemovedCellBase
+    * 
+    * @param cellValue the PossibleCellValue that was removed
+    */  
+   
+   public RemovedCellBase(PossibleCellValue cellValue )  
+   {
+	   this(cellValue,null);
+   }
+   /**
+    * The PossibleCellValue that was removed to create the cell
+    *  
+    * @return PossibleCellValue
+    */
+   public PossibleCellValue getPossibleCellRemoved()
+   {
+	      return  cellRemoved;	   
+   }
+   
+   /**
+    * The ResolvedCellValue that was created when the cell was removed
+    *  
+    * @return ResolvedCellValue 
+    */
+   public ResolvedCellValue getResolvedCell()
+   {
+	      return  cellResolved;	   
+   }
+   /**
+    * boolean to indicate if there was a resolved cell created when the removed
+    * cell was created
+    *  
+    * @return cellResolved != null
+    */
+   public boolean hasResolvedCell(){
+	   return (cellResolved != null);
+   }
+}
Index: main/java/org/drools/examples/sudoku/rules/RemovedCellValue.java
===================================================================
--- main/java/org/drools/examples/sudoku/rules/RemovedCellValue.java	(revision 0)
+++ main/java/org/drools/examples/sudoku/rules/RemovedCellValue.java	(revision 0)
@@ -0,0 +1,37 @@
+package org.drools.examples.sudoku.rules;
+
+/**
+ * Object for tracking cells removed during the logical testing of a guess. 
+ * Each removed cell is a single, possible value for a given cell,
+ * used when we are testing a guessing scenario.
+ * There is a single RemovedCellValue object associated with each removed possible
+ * Cell and potentially a resolved cell associated with the guessing rules.
+ * Guessed cells extends RemovedCellBase which has the classes to track which
+ * possible cells were removed to create the guess
+ * 
+ * @author <a href="">Ted Keenan</a>
+ * @version $Revision: 1.1 $
+ */
+public class RemovedCellValue extends RemovedCellBase {
+
+	   /**
+	    * Uses the constructor on the superclass to construct a new RemovedCellValue
+	    * 
+	    * @param cellValue the possible cell removed by the guessing rule
+	    * @param resolvedCell the resolve cell created by the guessing rule
+	    */
+	public RemovedCellValue(PossibleCellValue cellValue,
+			ResolvedCellValue resolvedCell) {
+		super(cellValue, resolvedCell);
+	}
+
+	   /**
+	    * Uses the constructor on the superclass to construct a new RemovedCellValue
+	    * 
+	    * @param cellValue the possible cell removed by the guessing rule
+	    */
+	public RemovedCellValue(PossibleCellValue cellValue) {
+		super(cellValue);
+	}
+
+}
Index: main/java/org/drools/examples/sudoku/rules/SudokuStatusConflict.java
===================================================================
--- main/java/org/drools/examples/sudoku/rules/SudokuStatusConflict.java	(revision 0)
+++ main/java/org/drools/examples/sudoku/rules/SudokuStatusConflict.java	(revision 0)
@@ -0,0 +1,20 @@
+package org.drools.examples.sudoku.rules;
+/**
+ * Represents a SudokuStatusMessage indicating a conflict.
+ * 
+ * @author 
+ * @version $Revision: 1.1 $
+ */
+
+public class SudokuStatusConflict extends SudokuStatusMessage {
+	 /**
+	    * Uses the constructor on the superclass to construct a new SudokuStatusConflict 
+	    * 
+	    * @param message the message associated with the issue
+	 */
+	public SudokuStatusConflict(String message) {
+		super(message);
+	}
+	
+
+}
Index: main/java/org/drools/examples/sudoku/rules/SudokuStatusMessage.java
===================================================================
--- main/java/org/drools/examples/sudoku/rules/SudokuStatusMessage.java	(revision 0)
+++ main/java/org/drools/examples/sudoku/rules/SudokuStatusMessage.java	(revision 0)
@@ -0,0 +1,51 @@
+/**
+ * 
+ */
+package org.drools.examples.sudoku.rules;
+
+/**
+ * An abstract class which contains the methods common objects used to 
+ * trace the status of the solution
+ * 
+ * @author 
+ * @version $Revision: 1.1 $
+ *
+ */
+public abstract class SudokuStatusMessage 
+{
+	   // The Status message
+	   private String message;
+	   
+	   
+	   /**
+	    * Create a new SudokuStatusMessage with the specified message.
+	    * 
+	    * @param message the message for the status
+	    */
+	   protected SudokuStatusMessage (String message)
+	   {
+	      this.message = message;
+	   }
+	   
+	   /**
+	    * Return the message
+	    * 
+	    * @return text of the message
+	    */
+	   public String getMessage()
+	   {
+	      return message;
+	   }
+	   /**
+	    * Return the type of message and the message
+	    * 
+	    * @return type and message
+	    */
+       public String toString()
+       {
+    	   Class<? extends SudokuStatusMessage> tmp = this.getClass();
+           String name = tmp.getName();
+       
+    	   return name + " : " + message;       
+       }
+}
Index: main/java/org/drools/examples/sudoku/rules/SudokuStatusSolved.java
===================================================================
--- main/java/org/drools/examples/sudoku/rules/SudokuStatusSolved.java	(revision 0)
+++ main/java/org/drools/examples/sudoku/rules/SudokuStatusSolved.java	(revision 0)
@@ -0,0 +1,19 @@
+package org.drools.examples.sudoku.rules;
+/**
+ * Represents a SudokuStatusMessage indicating the grid has been solved.
+ * 
+ * @author 
+ * @version $Revision: 1.1 $
+ */
+
+public class SudokuStatusSolved extends SudokuStatusMessage {
+	 /**
+	    * Uses the constructor on the superclass to construct a new SudokuStatusConflict 
+	    * 
+	    * @param message the message associated with the issue
+	 */
+	public SudokuStatusSolved(String message) {
+		super(message);
+	}
+
+}
Index: main/java/org/drools/examples/sudoku/rules/SudokuStatusUnresolved.java
===================================================================
--- main/java/org/drools/examples/sudoku/rules/SudokuStatusUnresolved.java	(revision 0)
+++ main/java/org/drools/examples/sudoku/rules/SudokuStatusUnresolved.java	(revision 0)
@@ -0,0 +1,51 @@
+package org.drools.examples.sudoku.rules;
+/**
+ * Represents a SudokuStatusMessage indicating a cell with multiple possible values.
+ * 
+ * @author 
+ * @version $Revision: 1.1 $
+ */
+
+public class SudokuStatusUnresolved extends SudokuStatusMessage {
+/**
+ * The cell that is unresolved
+ */
+	private BaseCell baseCell; 
+	
+	 /**
+	    * Uses the constructor on the superclass to construct a new SudokuStatusUnresolved
+	    * The cell that is unresolved 
+	    * 
+	    * @param message the message associated with the issue
+	 */
+	public SudokuStatusUnresolved(String message,BaseCell baseCell) {
+		super(message);
+		this.baseCell = baseCell;
+	}
+	/**
+	 * The cell that isn't resolved
+	 * @return
+	 */
+	public BaseCell getBase()
+	{
+		return baseCell;
+	}
+	/**
+	 * The id of the row that is unresolved
+	 * @return The id of the row that is unresolved
+	 */
+	public int getRow()
+	{
+		return baseCell.getRow();
+	}
+	/**
+	 * The id of the col that is unresolved
+	 * 
+	 * @return The id of the col that is unresolved
+	 */
+	public int getCol()
+	{
+		return baseCell.getCol();
+	}
+
+}
Index: main/java/org/drools/examples/sudoku/swing/GridModelConstants.java
===================================================================
--- main/java/org/drools/examples/sudoku/swing/GridModelConstants.java	(revision 0)
+++ main/java/org/drools/examples/sudoku/swing/GridModelConstants.java	(revision 0)
@@ -0,0 +1,23 @@
+package org.drools.examples.sudoku.swing;
+
+import java.util.Map;
+
+public interface GridModelConstants {
+
+	public abstract int getNumRows();
+
+	public abstract int getNumCols();
+
+	public abstract int getInnerGridHeight();
+
+	public abstract int getInnerGridWidth();
+
+	public abstract int[][] getZoneLookup();
+	
+	public abstract boolean isFourByFour();
+	public abstract boolean isSixBySix();
+	public abstract boolean isNineByNine();
+	public abstract Map<String, Integer[][]> getSamples();
+
+	
+}
\ No newline at end of file
Index: main/java/org/drools/examples/sudoku/swing/SudokuGridModelConstants.java
===================================================================
--- main/java/org/drools/examples/sudoku/swing/SudokuGridModelConstants.java	(revision 0)
+++ main/java/org/drools/examples/sudoku/swing/SudokuGridModelConstants.java	(revision 0)
@@ -0,0 +1,163 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ * 
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.drools.examples.sudoku.swing;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+
+/**
+ * A generic interface representing a 4x4 or a 9x9 Sudoku Grid of Cells.
+ * <p>
+ * In a solved Sudoku grid, each cell must contain an 
+ * integer from 1-grid width and the same integer must not be 
+ * repeated in the same row, in the same column or in 
+ * the same subsection of the grid.
+ * 
+ * @see SudokuGridListener
+ * @see SudokuGridEvent
+ * @see SudokuGridView
+ * @see AbstractSudokuGridModel
+ * @author <a href="pbennett@redhat.com">Pete Bennett</a>
+ * @version $Revision: 1.1 $
+ */
+public class SudokuGridModelConstants implements GridModelConstants 
+{ 	
+	protected static SudokuGridModelConstants INSTANCE;
+
+   /* (non-Javadoc)
+ * @see org.drools.examples.sudoku.swing.GridModelConstance#getNUM_ROWS()
+ */
+	protected GridModelConstants modelConstants;
+	   public static SudokuGridModelConstants getInstance()
+	   {
+	      if (INSTANCE == null)
+	      {
+	         INSTANCE = new SudokuGridModelConstants();
+	      }
+	      
+	      return INSTANCE;
+	   }
+
+	/**
+	 * Constructor for the constants that initializes either the 4x4 or 9x9
+	 * strategy   
+	 */
+	public SudokuGridModelConstants ()
+	{
+		modelConstants =  new SudokuGridModelConstants6x6();
+	}
+	public int getInnerGridHeight() {
+		return modelConstants.getInnerGridHeight();
+	}
+
+	@Override
+	public int getInnerGridWidth() {
+		return modelConstants.getInnerGridWidth();
+	}
+
+	@Override
+	public int getNumCols() {
+		return modelConstants.getNumCols();
+	}
+
+	@Override
+	public int getNumRows() {
+		return modelConstants.getNumRows();
+	}
+
+	@Override
+	public int[][] getZoneLookup() {
+		return modelConstants.getZoneLookup();
+	}
+	public boolean isFourByFour()
+	{
+		return modelConstants.isFourByFour();
+	}
+	   public boolean isSixBySix()
+		{
+			return modelConstants.isSixBySix();
+		}
+
+	public boolean isNineByNine()
+	{
+		return modelConstants.isNineByNine();
+	}
+	public int getTop(int row)
+	{
+		return (row % getInnerGridHeight() == 0 ? (getInnerGridHeight()-1) : 0); 
+	}
+	
+	public int getLeft(int col)
+	{
+		return (col % getInnerGridWidth () == 0 ? (getInnerGridWidth ()-1) : 0); 
+	}
+	
+	public int getBottom(int row)
+	{
+		return (row == getNumRows()-1 ? (getInnerGridHeight()-1) : 0); 
+	}
+	
+	public int getRight(int col)
+	{
+		return (col == getNumCols()-1 ? (getInnerGridWidth ()-1) : 0); 
+	}
+
+	public void setConstantType(String string){
+		 try {
+				Class cls ;
+		         Constructor ct ;
+	            Object retobj ;
+				cls = Class.forName("org.drools.examples.sudoku.swing.SudokuGridModelConstants" + string);
+		        ct = cls.getConstructor();
+	            retobj = ct.newInstance();
+	    		this.modelConstants = (GridModelConstants) retobj ;
+	        } catch (ClassNotFoundException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			} catch (SecurityException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			} catch (NoSuchMethodException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			} catch (IllegalArgumentException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			} catch (InstantiationException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			} catch (IllegalAccessException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			} catch (InvocationTargetException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+
+	}
+
+	@Override
+	public Map<String, Integer[][]> getSamples() {
+		// TODO Auto-generated method stub
+		return modelConstants.getSamples();
+	}
+
+	public Set<String> getSampleNames()
+	   {
+	      return modelConstants.getSamples().keySet();
+	   }
+	   
+	   public Integer[][] getSample(String name)
+	   {
+	      return modelConstants.getSamples().get(name);
+	   }
+
+ }
Index: main/java/org/drools/examples/sudoku/swing/SudokuGridModelConstants4x4.java
===================================================================
--- main/java/org/drools/examples/sudoku/swing/SudokuGridModelConstants4x4.java	(revision 0)
+++ main/java/org/drools/examples/sudoku/swing/SudokuGridModelConstants4x4.java	(revision 0)
@@ -0,0 +1,139 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ * 
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.drools.examples.sudoku.swing;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * An interface representing a 4x4 Sudoku Grid of Cells.
+ * <p>
+ * In a solved Sodoku grid, each cell must contain an 
+ * integer from 1-4 and the same integer must not be 
+ * repeated in the same row, in the same column or in 
+ * the same 2x2 subsection of the grid.
+ * 
+ * @see SudokuGridListener
+ * @see SudokuGridEvent
+ * @see SudokuGridView
+ * @see AbstractSudokuGridModel
+ * @author 
+ * @version $Revision: 1.1 $
+ */
+public class SudokuGridModelConstants4x4 implements GridModelConstants 
+{ 	
+	   private Map<String, Integer[][]> samples = new HashMap<String, Integer[][]>();
+
+   protected static int NUM_ROWS = 4;
+
+   /**
+    * The number of columns in the Grid, i.e. the width
+    */
+   protected static int NUM_COLS = 4;
+   
+   /**
+    * The number of cells in a column
+    */
+   protected static int INNER_GRID_HEIGHT = 2;
+   
+   /**
+    * The number of cells in a row
+    */
+   protected  static int INNER_GRID_WIDTH = 2;   
+   
+   /**
+    * A NUM_ROWSxNUM_COLS two dimensional array which maps from rows and columns
+    * to the 2x2 subzones in a Sudoku grid
+    */
+   protected  static int[][] ZONE_LOOKUP = 
+   { { 1 , 1 ,  2 , 2 },
+	 { 1 , 1 ,  2 , 2 },
+	 { 3 , 3 ,  4 , 4 },
+	 { 3 , 3 ,  4 , 4 },
+	 };  
+
+   public SudokuGridModelConstants4x4(){
+		super();
+		   /**
+		    * The number of rows in the Grid, i.e. the height
+		    */      // these are 4x4 samples
+		    samples.put
+		    (
+		      "Simple",
+		      new Integer[][] 
+		     {
+		      {4, null, 2, 3},
+		      {null, 2, 1, 4},
+		      {null, null, 4, null},
+		      {2, 4, 3, 1}
+		      }
+		    );
+		    samples.put
+		    (
+		  		  "!Indeterminate!",
+		  	       new Integer[][] 
+		 		       {
+		 		        {null, null, 4, null},
+		 		        {4, null, null, 3},
+		 		        {null, null, null, 4},
+		 		        {2, 4, 3, 1}
+		 		        }
+		    );
+		    
+		    samples.put
+		    (
+		  		  "!DELIBERATELY BROKEN!",
+		  	               new Integer[][] 
+		 		       {
+		 		        {null, null, 4, null},
+		 		        {4, null, 2, 3},
+		 		        {null, 2, 1, 4},
+		 		        {2, 4, 3, 1}
+		 		        }
+		    );
+		 
+	   
+   }
+   public int getNumRows() {
+   		return NUM_ROWS;
+   	}
+
+   public int getNumCols() {
+   		return NUM_COLS;
+   	}
+
+   	public int getInnerGridHeight() {
+   		return INNER_GRID_HEIGHT;
+   	}
+
+   	public int getInnerGridWidth() {
+   		return INNER_GRID_WIDTH;
+   	}
+
+   	public int[][] getZoneLookup() {
+   		return ZONE_LOOKUP;
+   	}
+
+   public boolean isFourByFour()
+	{
+		return true;
+	}
+   public boolean isSixBySix()
+	{
+		return false;
+	}
+   public boolean isNineByNine()
+	{
+		return false;
+	}
+
+@Override
+public Map<String, Integer[][]> getSamples() {
+	// TODO Auto-generated method stub
+	return samples;
+}
+}
Index: main/java/org/drools/examples/sudoku/swing/SudokuGridModelConstants6x6.java
===================================================================
--- main/java/org/drools/examples/sudoku/swing/SudokuGridModelConstants6x6.java	(revision 0)
+++ main/java/org/drools/examples/sudoku/swing/SudokuGridModelConstants6x6.java	(revision 0)
@@ -0,0 +1,159 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ * 
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.drools.examples.sudoku.swing;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * An interface representing a 6x6 Sudoku Grid of Cells.
+ * <p>
+ * In a solved Sodoku grid, each cell must contain an 
+ * integer from 1-6 and the same integer must not be 
+ * repeated in the same row, in the same column or in 
+ * the same 2x2 subsection of the grid.
+ * 
+ * @see SudokuGridListener
+ * @see SudokuGridEvent
+ * @see SudokuGridView
+ * @see AbstractSudokuGridModel
+ * @author 
+ * @version $Revision: 1.1 $
+ */
+public class SudokuGridModelConstants6x6 implements GridModelConstants 
+{ 	
+	   private Map<String, Integer[][]> samples = new HashMap<String, Integer[][]>();
+
+   protected static int NUM_ROWS = 6;
+
+   /**
+    * The number of columns in the Grid, i.e. the width
+    */
+   protected static int NUM_COLS = 6;
+   
+   /**
+    * The number of cells in a column
+    */
+   protected static int INNER_GRID_HEIGHT = 3;
+   
+   /**
+    * The number of cells in a row
+    */
+   protected  static int INNER_GRID_WIDTH = 2;   
+   
+   /**
+    * A NUM_ROWSxNUM_COLS two dimensional array which maps from rows and columns
+    * to the 2x2 subzones in a Sudoku grid
+    */
+   protected  static int[][] ZONE_LOOKUP = 
+   { { 1 , 1 ,  2 , 2 , 3 , 3 },
+	 { 1 , 1 ,  2 , 2 , 3 , 3 },
+	 { 1 , 1 ,  2 , 2 , 3 , 3 },
+	 { 4 , 4 , 5 , 5 ,  6 , 6 },
+	 { 4 , 4 , 5 , 5 ,  6 , 6 },
+	 { 4 , 4 , 5 , 5 ,  6 , 6 }
+	 };  
+
+   public SudokuGridModelConstants6x6(){
+		super();
+		   /**
+		    * The number of rows in the Grid, i.e. the height
+		    */      // these are 6x6 samples
+		    samples.put
+		    (
+			        "!DELIBERATELY BROKEN!",
+		      new Integer[][] 
+		     {
+		      {6, null, 2, 3,4,5},
+		      {4,5,null, 2, 1, 6},
+		      {null, null,null, null, null, null},
+		      {null, null,6,null, null,  null},
+		      {null, null,null, null,6, null},
+		      {2, 6, 4,5,3, 1}
+		      }
+		    );
+		    samples.put
+		    (
+		     "!Indeterminate!",
+		     new Integer[][] 
+		     {
+		      {6, null, 2, 3,4, null},
+		      {4,null,null, 5, null,  null},
+		      {null, null,null, 6,null,  null},
+		      {null, null,6,null, null,  null},
+		      {null, null,null,null, null, 4},
+		      {2, 6, null,4,null, null}
+		      }
+		    );
+		    samples.put
+		    (
+		      "Hard",
+		      new Integer[][] 
+		     {
+		      {6, null, 2, 3,4, null},
+		      {4,null,null, 5, null,  null},
+		      {null, null,null, 6,null,  null},
+		      {null, null,6,null, null,  null},
+		      {null, null,null,null, null, 4},
+		      {2, 6, null,4,5, null}
+		      }
+		    );
+		    samples.put
+		    (
+		      "Simple",
+		      new Integer[][] 
+		     {
+		      {6, 1, 2, 3,4, null},
+		      {4,null,null, 5, null,  null},
+		      {null, null,null, 6,null,  2},
+		      {null, null,6,1, null,  3},
+		      {1, null,null,null, null, 4},
+		      {2, 6, null,4,5, null}
+		      }
+		    );
+
+	   
+   }
+   public int getNumRows() {
+   		return NUM_ROWS;
+   	}
+
+   public int getNumCols() {
+   		return NUM_COLS;
+   	}
+
+   	public int getInnerGridHeight() {
+   		return INNER_GRID_HEIGHT;
+   	}
+
+   	public int getInnerGridWidth() {
+   		return INNER_GRID_WIDTH;
+   	}
+
+   	public int[][] getZoneLookup() {
+   		return ZONE_LOOKUP;
+   	}
+
+   public boolean isFourByFour()
+	{
+		return false;
+	}
+   public boolean isSixBySix()
+	{
+		return true;
+	}
+   public boolean isNineByNine()
+	{
+		return false;
+	}
+
+@Override
+public Map<String, Integer[][]> getSamples() {
+	// TODO Auto-generated method stub
+	return samples;
+}
+}
Index: main/java/org/drools/examples/sudoku/swing/SudokuGridModelConstants9x9.java
===================================================================
--- main/java/org/drools/examples/sudoku/swing/SudokuGridModelConstants9x9.java	(revision 0)
+++ main/java/org/drools/examples/sudoku/swing/SudokuGridModelConstants9x9.java	(revision 0)
@@ -0,0 +1,232 @@
+/*
+ * 
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.drools.examples.sudoku.swing;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * An interface representing a 9x9 Sudoku Grid of Cells.
+ * <p>
+ * In a solved Sodoku grid, each cell must contain an 
+ * integer from 1-9 and the same integer must not be 
+ * repeated in the same row, in the same column or in 
+ * the same 3x3 subsection of the grid.
+ * 
+ * @see SudokuGridListener
+ * @see SudokuGridEvent
+ * @see SudokuGridView
+ * @see AbstractSudokuGridModel
+ * @author <a href="pbennett@redhat.com">Pete Bennett</a>
+ * @version $Revision: 1.1 $
+ */
+public class SudokuGridModelConstants9x9 implements GridModelConstants
+{ 
+	   private Map<String, Integer[][]> samples = new HashMap<String, Integer[][]>();
+	   /**
+	    * The number of rows in the Grid, i.e. the height
+	    */
+	   public static int NUM_ROWS = 9;
+
+	   /**
+	    * The number of columns in the Grid, i.e. the width
+	    */
+	   public static int NUM_COLS = 9;
+	   
+	   /**
+	    * The number of cells in a column
+	    */
+	   protected static int INNER_GRID_HEIGHT = 3;
+	   
+	   /**
+	    * The number of cells in a row
+	    */
+	   public static int INNER_GRID_WIDTH = 3;   
+	   
+	   /**
+	    * A NUM_ROWSxNUM_COLS two dimensional array which maps from rows and columns
+	    * to the 3x3 subzones in a Sudoku grid
+	    */
+	   public static int[][] ZONE_LOOKUP = 
+	   { { 1 , 1 , 1 , 2 , 2 , 2 , 3 , 3 , 3},
+	     { 1 , 1 , 1 , 2 , 2 , 2 , 3 , 3 , 3},
+	     { 1 , 1 , 1 , 2 , 2 , 2 , 3 , 3 , 3},
+	     { 4 , 4 , 4 , 5 , 5 , 5 , 6 , 6 , 6},
+	     { 4 , 4 , 4 , 5 , 5 , 5 , 6 , 6 , 6},
+	     { 4 , 4 , 4 , 5 , 5 , 5 , 6 , 6 , 6},
+	     { 7 , 7 , 7 , 8 , 8 , 8 , 9 , 9 , 9},
+	     { 7 , 7 , 7 , 8 , 8 , 8 , 9 , 9 , 9},
+	     { 7 , 7 , 7 , 8 , 8 , 8 , 9 , 9 , 9} };
+	   public SudokuGridModelConstants9x9 (){
+		   samples.put
+		      (
+		        "Simple",
+		        new Integer[][] 
+		       {{null, 5, 6, 8, null, 1, 9, 4, null},
+		        {9, null, null, 6, null, 5, null, null, 3},
+		        {7, null, null, 4, 9, 3, null, null, 8},
+		        {8, 9, 7, null, 4, null, 6, 3, 5},
+		        {null, null, 3, 9, null, 6, 8, null, null},
+		        {4, 6, 5, null, 8, null, 2, 9, 1},
+		        {5, null, null, 2, 6, 9, null, null, 7},
+		        {6, null, null, 5, null, 4, null, null, 9},
+		        {null, 4, 9, 7, null, 8, 3, 5, null}}
+		      );
+		      
+		      samples.put
+		      (
+		        "Medium",
+		        new Integer[][] 
+		       {{8, 4, 7, null, null, null, 2, 5, 6},
+		               {5, null, null, null, 8, null, null, null, 4},
+		               {2, null, null, null, 7, null, null, null, 8},
+		               {null, null, null, 3, null, 8, null, null, null},
+		               {null, 5, 1, null, null, null, 8, 7, 2},
+		               {null, null, null, 5, null, 7, null, null, null},
+		               {4, null, null, null, 5, null, null, null, 7},
+		               {6, null, null, null, 3, null, null, null, 9},
+		               {1, 3, 2, null, null, null, 4, 8, 5}}
+		      );
+		      
+		      samples.put
+		      (
+		        "Hard 1",
+		        new Integer[][] 
+		       {{null, null, null, null, 5, 1, null, 8, null},
+		               {null, 8, null, null, 4, null, null, null, 5},
+		               {null, null, 3, null, null, null, 2, null, null},
+		               {null, null, null, null, 6, null, null, null, 9},
+		               {6, 7, null, 4, null, 9, null, 1, 3},
+		               {8, null, null, null, 3, null, null, null, null},
+		               {null, null, 2, null, null, null, 4, null, null},
+		               {5, null, null, null, 9, null, null, 2, null},
+		               {null, 9, null, 7, 1, null, null, null, null}}
+		      );
+		      
+		      samples.put
+		      (
+		        "Hard 2",
+		        new Integer[][] 
+		       {{null,null,null,6,null,null,1,null,null},
+		           {null,null,null,null,null,5,null,null,6},
+		           {5,null,7,null,null,null,2,3,null},
+		           {null,8,null,9,null,7,null,null,null},
+		           {9,3,null,null,null,null,null,6,7},
+		           {null,null,null,4,null,6,null,1,null},
+		           {null,7,4,null,null,null,9,null,1},
+		           {8,null,null,7,null,null,null,null,null},
+		           {null,null,3,null,null,8,null,null,null}}
+		      );
+
+		      samples.put
+		      (
+		        "Hard 3",
+		        new Integer[][] 
+		       {{null,8,null,null,null,6,null,null,5},
+		               {2,null,null,null,null,null,4,8,null},
+		               {null,null,9,null,null,8,null,1,null},
+		               {null,null,null,null,8,null,1,null,2},
+		               {null,null,null,3,null,1,null,null,null},
+		               {6,null,1,null,9,null,null,null,null},
+		               {null,9,null,4,null,null,8,null,null},
+		               {null,7,6,null,null,null,null,null,3},
+		               {1,null,null,7,null,null,null,5,null}}
+		      );
+		      
+		      samples.put
+		      (
+		        "Hard 4",
+		        new Integer[][] 
+		       {{null,null,null,null,null,4,null,9,5},
+		               {6,7,null,5,null,null,null,1,null},
+		               {null,null,null,6,null,9,null,null,null},
+		               {null,2,null,null,null,null,4,null,null},
+		               {8,1,null,null,null,null,null,7,2},
+		               {null,null,7,null,null,null,null,8,null},
+		               {null,null,null,3,null,5,null,null,null},
+		               {null,6,null,null,null,1,null,5,8},
+		               {7,3,null,9,null,null,null,null,null}}
+		      );    
+		      
+		      samples.put
+		      (
+		        "!DELIBERATELY BROKEN!",
+		        new Integer[][] 
+		       {{5,null,null,null,null,4,null,9,5},
+		               {6,7,null,5,null,null,null,1,null},
+		               {null,null,null,6,null,9,null,null,null},
+		               {null,2,null,null,null,null,4,null,null},
+		               {8,1,null,null,null,null,null,7,2},
+		               {null,null,7,null,null,null,null,8,null},
+		               {8,null,null,3,null,5,null,null,null},
+		               {null,6,null,null,null,1,null,5,8},
+		               {7,3,null,9,null,null,null,null,null}}
+			   
+		      );
+		      samples.put
+		      (
+		        "Today",
+		        new Integer[][] 
+		       {
+		        	{null,null,8,5,null,null,null,2,7},
+		        	{2,null,6,null,null,null,null,null,null},
+		        	{null,null,null,null,7,null,3,null,null},
+		        	{4,null,null,null,5,3,null,6,null},
+		        	{null,null,9,null,null,null,4,null,null},
+		        	{null,8,null,1,9,null,null,null,3},
+		        	{null,null,2,null,8,null,null,null,null},
+		        	{null,null,null,null,null,null,9,null,5},
+		        	{9,6,null,null,null,7,8,null,null}
+		               }
+			   
+		      );
+
+	   }
+
+	   public int getNumRows() {
+			return NUM_ROWS;
+		}
+
+	public int getNumCols() {
+			return NUM_COLS;
+		}
+
+
+	public int getInnerGridHeight() {
+			return INNER_GRID_HEIGHT;
+		}
+
+	public int getInnerGridWidth() {
+			return INNER_GRID_WIDTH;
+		}
+
+	public int[][] getZoneLookup() {
+			return ZONE_LOOKUP;
+		}
+
+
+
+   public boolean isFourByFour()
+	{
+		return false;
+	}
+   
+   public boolean isSixBySix()
+	{
+		return false;
+	}
+	public boolean isNineByNine()
+	{
+		return true;
+	}
+
+	@Override
+	public Map<String, Integer[][]> getSamples() {
+		// TODO Auto-generated method stub
+		return samples;
+	}
+
+}
Index: main/java/org/drools/examples/sudoku/swing/SudokuGridModelInterface.java
===================================================================
--- main/java/org/drools/examples/sudoku/swing/SudokuGridModelInterface.java	(revision 0)
+++ main/java/org/drools/examples/sudoku/swing/SudokuGridModelInterface.java	(revision 0)
@@ -0,0 +1,44 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ * 
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.drools.examples.sudoku.swing;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * An interface representing a 9x9 Sudoku Grid of Cells.
+ * <p>
+ * In a solved Sodoku grid, each cell must contain an 
+ * integer from 1-9 and the same integer must not be 
+ * repeated in the same row, in the same column or in 
+ * the same 3x3 subsection of the grid.
+ * 
+ * @see SudokuGridListener
+ * @see SudokuGridEvent
+ * @see SudokuGridView
+ * @see AbstractSudokuGridModel
+ * @author <a href="pbennett@redhat.com">Pete Bennett</a>
+ * @version $Revision: 1.1 $
+ */
+public interface SudokuGridModelInterface
+{ 
+   public void setCellValues(Integer[][] cellValues);
+   
+   public boolean isCellEditable(int row, int col);
+   
+   public boolean isCellResolved(int row, int col);
+   
+   public Set<Integer> getPossibleCellValues(int row, int col);
+   
+   public boolean solve();
+   
+   public boolean isGridSolved();
+   
+   public void addSudokuGridListener(SudokuGridListener l);   
+   
+   public void removeSudokuGridListener(SudokuGridListener l);
+}
Index: main/java/org/drools/examples/sudoku/swing/SudokuGridView.java
===================================================================
--- main/java/org/drools/examples/sudoku/swing/SudokuGridView.java	(revision 23682)
+++ main/java/org/drools/examples/sudoku/swing/SudokuGridView.java	(working copy)
@@ -25,15 +25,15 @@
 {
    /** The serialVersionUID */
    private static final long serialVersionUID = 1L;
-   private SudokuGridModel model;
+   private SudokuGridModelInterface model;
    private GridLayout gridLayout;
    private JTextField textFields[][];
    
    public SudokuGridView()
    {
-      gridLayout = new GridLayout(SudokuGridModel.NUM_ROWS, SudokuGridModel.NUM_COLS);
+      gridLayout = new GridLayout(SudokuGridModelConstants.getInstance().getNumRows(), SudokuGridModelConstants.getInstance().getNumCols());
       setLayout(gridLayout);
-      textFields = new JTextField[SudokuGridModel.NUM_ROWS][SudokuGridModel.NUM_COLS];
+      textFields = new JTextField[SudokuGridModelConstants.getInstance().getNumRows()][SudokuGridModelConstants.getInstance().getNumCols()];
       for (int row=0; row<textFields.length; row++)
       {
          for (int col=0; col<textFields[row].length; col++)
@@ -46,10 +46,10 @@
             }
             JPanel panel = new JPanel();
             
-            int top = row % SudokuGridModel.INNER_GRID_HEIGHT == 0 ? 2 : 0;
-            int left = col % SudokuGridModel.INNER_GRID_WIDTH == 0 ? 2 : 0;
-            int bottom = row == SudokuGridModel.NUM_ROWS-1 ? 2 : 0;
-            int right = col == SudokuGridModel.NUM_COLS-1 ? 2 : 0;
+            int top = SudokuGridModelConstants.getInstance().getTop(row );
+            int left = SudokuGridModelConstants.getInstance().getLeft(col );
+            int bottom = SudokuGridModelConstants.getInstance().getBottom(row );
+            int right = SudokuGridModelConstants.getInstance().getRight(col);
            
             panel.setBorder(BorderFactory.createMatteBorder( top, left, bottom, right, Color.BLACK ));
             panel.setLayout(new BorderLayout());
@@ -66,13 +66,13 @@
       }
    }
    
-   public SudokuGridView(SudokuGridModel model)
+   public SudokuGridView(SudokuGridModelInterface model)
    {
       this();
       setModel(model);
    }
    
-   public void setModel(SudokuGridModel model)
+   public void setModel(SudokuGridModelInterface model)
    {
       if (this.model != null  && this.model instanceof AbstractSudokuGridModel)
       {
@@ -88,7 +88,7 @@
       }
    }
    
-   public SudokuGridModel getModel()
+   public SudokuGridModelInterface getModel()
    {
       return model;
    }
Index: main/rules/org/drools/examples/sudoku/sudokuSolverValidatorWithGuess.drl
===================================================================
--- main/rules/org/drools/examples/sudoku/sudokuSolverValidatorWithGuess.drl	(revision 0)
+++ main/rules/org/drools/examples/sudoku/sudokuSolverValidatorWithGuess.drl	(revision 0)
@@ -0,0 +1,1026 @@
+package org.drools.examples.sudoku
+
+import org.drools.examples.sudoku.rules.RemovedCellValue;
+import org.drools.examples.sudoku.rules.GuessedCellValue;
+import org.drools.examples.sudoku.rules.PossibleCellValue;
+import org.drools.examples.sudoku.rules.ResolvedCellValue;
+import org.drools.examples.sudoku.rules.SudokuStatusUnresolved;
+import org.drools.examples.sudoku.rules.SudokuStatusConflict;
+import org.drools.examples.sudoku.rules.SudokuStatusSolved;
+import org.drools.examples.sudoku.rules.BaseCell;
+
+global org.drools.examples.sudoku.rules.ResolvedCellValue resolved;
+
+/**
+ * This rule package defines a set of rules that can be used to solve a partially filled Sudoku grid.
+ * It expects to have objects of type PossibleCellValue and ResolvedCellValue
+ * inserted into the working memory and will then work to remove PossibleCellValues and to 
+ * insert ResolvedCellValues until a single ResolvedCellValue is present for each row and column
+ * and not PossibleCellValues remain.
+ *
+ * Any issues discovered are inserted as Strings into the issues global.
+ *
+ * @author <a href="pbennett@redhat.com">Pete Bennett</a>
+ * @author <a href="mailto:michael.frandsen@syngenio.de">Michael Frandsen</a>
+ * @version $Revision: 1.1 $
+ */
+/**
+ * The 	agenda-group "BaseTest" is the basic set of rules needed to solve a sudoku problem
+ * that doesn't involve guessing-testing loops.
+ */
+ 
+
+/**
+ * This rule checks for the situation where a given Cell in the Sudoku Grid has been assigned 
+ * a definate ResolvedCellValue (i.e. we know what the value in this cell of the Grid is) and
+ * removes any other possible values from this cell (i.e. instances of PossibleCellValue 
+ * with the same row and column.
+ */
+rule "BaseTest: #01 once a specific cell has a ResolvedCellValue, remove all the other PossibleCellValues for the same cell"
+	# this rule requires a high salience so that, when it is activated it is executed, as soon as a 
+	# ResolvedCellValue is set, we need to clear out the PossibleCellValues for the same cell location, 
+	# otherwise other rules misfire - a good example of a valid use for salience
+	agenda-group "BaseTest"
+	salience 50 
+	when
+	    # matches all ResolvedCellValues (RCVs) in the grid, and stores them in the $resolved local variable
+	    # note that we also need to store the row and column for $resolved in $resolvedRow and $resolvedColum
+	    # so that the second part of the when clause can access them
+		$resolved : ResolvedCellValue($resolvedRow : row, $resolvedCol : col)
+		
+		# matches any PossibleCellValues (PCVs) in the grid with the same row and column as $resolved
+		$possible : PossibleCellValue(row == $resolvedRow, col == $resolvedCol)
+	then
+		# remove the matching PCVs stored in $possible
+		retract($possible);
+		
+		# trigger an update for the matched RCV stored in $resolved
+		update ($resolved); # this is done so that listeners can be triggered to know this cell is now resolved
+		
+		# insert a new String into the working memory describing in detail what we have done
+		insert ("BaseTest: rule #1 cleared the other PossibleCellValues for ("+$resolved.getRow()+","+$resolved.getCol()+") as a ResolvedCellValue of "+$resolved.getValue()+" exists for this cell.");
+end
+
+/** 
+ * This rule checks for the situation where a given Cell in the SudokuGrid only has 
+ * one PossibleCellValue assigned to its row and column. Once we have this situation, we 
+ * now that this must be the correct value for the cell so we remove the single PossibleCellValue
+ * and replace it with an equivalent ResolvedCellValue.
+ */
+rule "BaseTest: #02 If a cell has only a single PossibleCellValue, remove it and replace it with the equivalent ResolvedCellValue"
+	agenda-group "BaseTest"
+	salience 35
+	when
+		# macthes all PCVs in the Grid, stores them in $possible
+		$possible : PossibleCellValue ( $possibleRow : row, $possibleCol : col, $possibleValue : value )
+		
+		# the not operator only causes this when clause to resolve to true when there are not
+		# any other PCVs with the same row and column but different values to $possible
+		not ( PossibleCellValue ( row == $possibleRow, col == $possibleCol, value != $possibleValue ) )
+	then
+		# remove $possible from the working memory
+		retract($possible);
+		
+		# insert a new ResolvedCellValue with the same row, column and value into the working memory
+		insert (new ResolvedCellValue($possible));
+
+		# insert a new String into the working memory describing in detail what we have done
+		insert ("BaseTest: rule #2 changed the only PossibleCellValue at ("+$possible.getRow()+","+$possible.getCol()+") to a ResolvedCellValue with the value of "+$possible.getValue());
+end
+
+/**
+ * This rule checks for the situation where a row in the Grid has a ResolvedCellValue in it. In 
+ * this case we know that the value can not occur in any of the other cells in the same row in 
+ * the grid, so we look for any PossibleCellValues with the same row and remove them.
+ */
+rule "BaseTest: #03 If a row has a ResolvedCellValue in it, remove this value as a PossibleCellValue from all other cells in the same row"
+	agenda-group "BaseTest"
+  	salience 40
+  	when
+  		# matches all RCVs in the grid, and stores them in the $resolved local variable		
+		$resolved : ResolvedCellValue( $resolvedRow : row, $resolvedValue : value )
+		
+		# matches all the PCVs in the grid in the same row with the same value as $resolved
+		$possible : PossibleCellValue( row == $resolvedRow, value == $resolvedValue )
+	then
+		retract($possible);
+
+		# insert a new String into the working memory describing in detail what we have done
+		insert ("BaseTest: rule #3 determined the value at ("+$possible.getRow()+","+$possible.getCol()+") could not be "+$possible.getValue()+" as this value already exists in the same row at ("+$resolved.getRow()+","+$resolved.getCol()+")");
+end
+
+/**
+ * This rule checks for the situation where a column in the Grid has a ResolvedCellValue in it. In 
+ * this case we know that the value can not occur in any of the other cells in the same column in 
+ * the grid, so we look for any PossibleCellValues with the same column and remove them.
+ */
+rule "BaseTest: #04 If a column has a ResolvedCellValue in it, remove this value as a PossibleCellValue from all other cells in the same column"
+	agenda-group "BaseTest"
+  	salience 40
+    when		
+  		# matches all RCVs in the grid, and stores them in the $resolved local variable		
+		$resolved : ResolvedCellValue( $resolvedCol : col, $resolvedValue : value )
+
+		# matches all the PCVs in the grid in the same column with the same value as $resolved
+		$possible : PossibleCellValue( col == $resolvedCol, value == $resolvedValue )
+	then
+		retract($possible);
+
+		# insert a new String into the working memory describing in detail what we have done
+		insert ("BaseTest: rule #4 determined the value at ("+$possible.getRow()+","+$possible.getCol()+") could not be "+$possible.getValue()+" as this value already exists in the same column at ("+$resolved.getRow()+","+$resolved.getCol()+")");
+end
+
+/**
+ * This rule checks for the situation where a zone in the Grid has a ResolvedCellValue in it. In 
+ * this case we know that the value can not occur in any of the other cells in the same zone in 
+ * the grid, so we look for any PossibleCellValues with the same zone and remove them.
+ */
+rule "BaseTest: #05 If a zone has a ResolvedCellValue in it, remove this value as a PossibleCellValue from all other cells in the same zone"
+	agenda-group "BaseTest"
+  	salience 40
+ 	when		
+  		# matches all RCVs in the grid, and stores them in the $resolved local variable		
+		$resolved : ResolvedCellValue( $resolvedZone : zone, $resolvedValue : value )
+
+		# matches all the PCVs in the grid in the same zone with the same value as $resolved
+		$possible : PossibleCellValue( zone == $resolvedZone, value == $resolvedValue )
+	then
+		retract($possible);
+
+	    # insert a new String into the working memory describing in detail what we have done
+		insert ("BaseTest: rule #5 determined the value at ("+$possible.getRow()+","+$possible.getCol()+") could not be "+$possible.getValue()+" as this value already exists in the same zone at ("+$resolved.getRow()+","+$resolved.getCol()+")");
+end
+
+/**
+ * This rule checks for the situation when it is only possible for one cell of a row in the Grid to contain
+ * a particular value, i.e. there is exactly one PossibleCellValue with a given value and a given row.
+ * In this case, this cell must actually contain the value so we remove the single PossibleCellValue
+ * and replace it with an equivalent ResolvedCellValue.
+ */
+rule "BaseTest: #06 If a PossibleCellValue only appears once in a row, then this must be the ResolvedCellValue"
+	agenda-group "BaseTest"
+    salience 30
+	when
+		# matches all PCVs in the grid, and stores them in the $possible local variable		
+		$possible : PossibleCellValue( $zone : zone, $value : value, $col : col, $row : row)
+
+		# the not operator only causes this when clause to resolve to true when there are not
+		# any other PCVs with the same row and value as $possible
+		not (PossibleCellValue( row == $row, value == $value ))
+	then
+		retract($possible);
+		insert (new ResolvedCellValue($possible));
+
+		# insert a new String into the working memory describing in detail what we have done
+		insert ("BaseTest: rule #6 determined ("+$row+","+$col+") is "+$value+" as this is the only possible cell in the row that can have this value");
+end
+
+/**
+ * This rule checks for the situation when it is only possible for one cell of a column in the Grid to contain
+ * a particular value, i.e. there is exactly one PossibleCellValue with a given value and a given column.
+ * In this case, this cell must actually contain the value so we remove the single PossibleCellValue
+ * and replace it with an equivalent ResolvedCellValue.
+ */
+rule "BaseTest: #07 If a PossibleCellValue only appears once in a column, then this must be the ResolvedCellValue"
+	agenda-group "BaseTest"
+    salience 30
+  	when		
+		# matches all PCVs in the grid, and stores them in the $possible local variable		
+		$possible : PossibleCellValue( $zone : zone, $value : value, $col : col, $row : row)
+
+		# the not operator only causes this when clause to resolve to true when there are not
+		# any other PCVs with the same column and value as $possible
+		not (PossibleCellValue( col == $col, value == $value ))
+	then
+		retract($possible);
+		insert (new ResolvedCellValue($possible));
+
+		# insert a new String into the working memory describing in detail what we have done
+		insert ("BaseTest: rule #7 determined ("+$row+","+$col+") is "+$value+" as this is the only possible cell in the column that can have this value");
+end
+
+/**
+ * This rule checks for the situation when it is only possible for one cell of a zone in the Grid to contain
+ * a particular value, i.e. there is exactly one PossibleCellValue with a given zone and a given column.
+ * In this case, this cell must actually contain the value so we remove the single PossibleCellValue
+ * and replace it with an equivalent ResolvedCellValue.
+ */
+rule "BaseTest: #08 If a PossibleCellValue only appears once in a zone, then this must be the ResolvedCellValue"
+	agenda-group "BaseTest"
+    salience 30
+   	when		
+		# matches all PCVs in the grid, and stores them in the $possible local variable		
+		$possible : PossibleCellValue( $zone : zone, $value : value, $col : col, $row : row)
+
+		# the not operator only causes this when clause to resolve to true when there are not
+		# any other PCVs with the same column and value as $possible
+		not (PossibleCellValue( zone == $zone, value == $value ))
+	then
+		retract($possible);
+		insert (new ResolvedCellValue($possible));
+
+		# insert a new String into the working memory describing in detail what we have done
+		insert ("BaseTest: rule #8 determined ("+$row+","+$col+") is "+$value+" as this is the only possible cell in the zone that can have this value");
+end
+
+/**
+ * This rule looks for a situation where we have two cells in a zone of the grid which are in the 
+ * same column but different rows where each of the two cells contains exactly two possible values 
+ * and this pair of values is the same in both the cells. In this situation, while we do not 
+ * know which way round the two values should be assigned to the two cells, we do know that the 
+ * two values must be assigned to these two cells and therefore we remove the possibility of them 
+ * being present in any other cells in this zone.
+ */
+rule "BaseTest: #09 if a pair of cells exists in the same zone and the same column but different rows containing the same pair of possible values then elimnate these two possible values from anywhere else in the zone"
+	agenda-group "BaseTest"
+	salience 20
+	when
+	    # match all PCVs and store as $possible1
+		$possible1 : PossibleCellValue( $zone1 : zone, $val1 : value, $row1 : row, $col1 : col )
+		
+		# match any PCVs with the same value and in the same zone and column but in a different row to $possible1
+		$possible2 :PossibleCellValue( zone == $zone1, value == $val1, $row2 : row != $row1, $col2 : col)
+		
+		# match any PCV in the same location as $possible1 with a different value to $possible1
+		$possible3 : PossibleCellValue(row == $row1, col == $col1, $val3 : value )
+		
+		# match any PCV in the same location as $possible2 with the same value as $possible3
+		$possible4 : PossibleCellValue(row == $row2, col == $col2, value == $val3 )
+		
+		# check there is not a third PCV in the same location as $possible1 with a different value to $possible1 or $possible3
+		not ( PossibleCellValue( row == $row1, col == $col1, value != $val1, value != $val3 ) )
+		
+		# check there is not a third PCV in tne same location as $possible2 with a different value to $possible1 or $possible3
+		not ( PossibleCellValue( row == $row2, col == $col2, value != $val1, value != $val3 ) )
+		
+		# match any other PCVs in the same zone as $possible1 with the same value 
+		$possible : PossibleCellValue( zone == $zone1, value == $val1)
+	then
+		retract($possible);
+
+		# insert a new String into the working memory describing in detail what we have done
+		insert ("BaseTest: rule #9 fired, removing value "+$possible.getValue()+" as a possibility from "+$possible.getRow()+","+$possible.getCol()+" because the values of "+$val1+" and "+$val3+" must be in the cells "+$row1+","+$col1+" and "+$row2+","+$col2);
+end
+
+/**
+ * This rule looks for a situation where we have two cells in a zone of the grid which are in the 
+ * same row but different colums where each of the two cells contains exactly two possible values 
+ * and this pair of values is the same in both the cells. In this situation, while we do not 
+ * know which way round the two values should be assigned to the two cells, we do know that the 
+ * two values must be assigned to these two cells and therefore we remove the possibility of them 
+ * being present in any other cells in this zone.
+ */
+rule "BaseTest: #10 if a pair of cells exists in the same zone and the same row but different columns containing the same pair of possible values then elimnate these two possible values from anywhere else in the zone"
+	agenda-group "BaseTest"
+	salience 20
+	when
+	    # match all PCVs and store as $possible1
+		$possible1 : PossibleCellValue( $zone1 : zone, $val1 : value, $row1 : row, $col1 : col )
+		
+		# match any PCVs with the same value and in the same zone and column but in a different row to $possible1
+		$possible2 :PossibleCellValue( zone == $zone1, value == $val1, $row2 : row, $col2 : col != $col1)
+		
+		# match any PCV in the same location as $possible1 with a different value to $possible1
+		$possible3 : PossibleCellValue(row == $row1, col == $col1, $val3 : value )
+		
+		# match any PCV in the same location as $possible2 with the same value as $possible3
+		$possible4 : PossibleCellValue(row == $row2, col == $col2, value == $val3 )
+		
+		# check there is not a third PCV in the same location as $possible1 with a different value to $possible1 or $possible3
+		not ( PossibleCellValue( row == $row1, col == $col1, value != $val1, value != $val3 ) )
+		
+		# check there is not a third PCV in tne same location as $possible2 with a different value to $possible1 or $possible3
+		not ( PossibleCellValue( row == $row2, col == $col2, value != $val1, value != $val3 ) )
+		
+		# match any other PCVs in the same zone as $possible1 with the same value 
+		$possible : PossibleCellValue( zone == $zone1, value == $val1)
+	then
+		retract($possible);
+
+		# insert a new String into the working memory describing in detail what we have done
+		insert ("BaseTest: rule #10 fired, removing value "+$possible.getValue()+" as a possibility from "+$possible.getRow()+","+$possible.getCol()+" because the values of "+$val1+" and "+$val3+" must be in the cells "+$row1+","+$col1+" and "+$row2+","+$col2);
+end
+
+
+/**
+ * This rule cleans up any guesses left over from the guessing loop as the loop must have resolved 
+ * a cell which invalidates the previous potential guesses
+ */
+rule "BaseTest: Rule #00 Retract All Guesses"
+   agenda-group "BaseTest"
+   salience 100
+	when
+		$guess : GuessedCellValue( $value1 : value, $col1 : col, $row1 : row)
+	then
+		retract($guess);
+		insert ("BaseTest: retract all Guesses: V" + $guess.getValue() + ":R"+ $guess.getRow() + ":C"+ $guess.getCol());
+end
+
+
+/**
+ * The Validator agenda-group defines a set of rules that can be used to validate whether a valid Suoku solution
+ * has been produced or not. It expects to have objects of type BaseCell, PossibleCellValue and ResolvedCellValue
+ * inserted into the working memory and will then check that only a single ResolvedCellValue exists
+ * in a nxn Sudoku grid for each row, column and mxm zone.
+ *
+ * Any status conditions discovered are inserted into the working memeory.
+ *
+ */
+
+/**
+ * Checks for two ResolvedCellValues with both the same value and the same row property
+ * Enters a confilct status if there is one
+ */
+rule "Validator: #01 There should not be two ResolvedCellValues with the same value in the same row"
+   agenda-group "Validator"
+	when
+	    # Matches all ResolvedCellValues in the working memory and stores the row and the value for each in two local variables
+		$resolved1 : ResolvedCellValue($resolved1Row : row, $resolved1Value : value)
+		
+		# Matches any other ResolvedCellValues that have the same row and the same value as these two local variables
+		$resolved2 : ResolvedCellValue (row == $resolved1Row, value == $resolved1Value)
+	then
+	    # Enter a conflict
+		insert(new SudokuStatusConflict ("There are two cells on the same row with the same value " + $resolved1.getValue() + " at ("+$resolved1.getRow()+","+$resolved1.getCol()+") and ("+$resolved2.getRow()+","+$resolved2.getCol()+")"));
+     	insert("Validator " + "There are two cells on the same row with the same value " + $resolved1.getValue() + " at ("+$resolved1.getRow()+","+$resolved1.getCol()+") and ("+$resolved2.getRow()+","+$resolved2.getCol()+")");
+end
+
+/**
+ * Checks for two ResolvedCellValues with both the same value and the same column property
+ * Enters a confilct status if there is one
+ */
+rule "Validator: #02 There should not be two ResolvedCellValues with the same value in the same column"
+   agenda-group "Validator"
+	when
+	    # Matches all ResolvedCellValues in the working memory and stores the column and the value for each in two local variables
+		$resolved1 : ResolvedCellValue($resolved1Col : col, $resolved1Value : value)
+
+		# Matches any other ResolvedCellValues that have the same column and the same value as these two local variables
+		$resolved2 : ResolvedCellValue (col == $resolved1Col, value == $resolved1Value)
+	then
+	    # Enter a conflict
+		insert(new SudokuStatusConflict ("There are two cells on the same column with the same value at ("+$resolved1.getRow()+","+$resolved1.getCol()+") and ("+$resolved2.getRow()+","+$resolved2.getCol()+")"));
+		insert("Validator: There are two cells on the same column with the same value at ("+$resolved1.getRow()+","+$resolved1.getCol()+") and ("+$resolved2.getRow()+","+$resolved2.getCol()+")");
+end
+
+/**
+ * Checks for two ResolvedCellValues with both the same value and the same zone property
+ */
+rule "Validator: #03 There should not be two ResolvedCellValues with the same value in the same zone"
+   agenda-group "Validator"
+	when
+	    # Matches all ResolvedCellValues in the working memory and stores the zone and the value for each in two local variables
+		$resolved1 : ResolvedCellValue($resolved1Zone : zone, $resolved1Value : value)
+
+		# Matches any other ResolvedCellValues that have the same zone and the same value as these two local variables
+		$resolved2 : ResolvedCellValue (zone == $resolved1Zone, value == $resolved1Value)
+	then
+		insert(new SudokuStatusConflict ("There are two cells in the same zone " + $resolved1.getValue( ) + "with the same value at ("+$resolved1.getRow()+","+$resolved1.getCol()+") and ("+$resolved2.getRow()+","+$resolved2.getCol()+")"));
+		insert("Validator: There are two cells in the same zone with the same value " + $resolved1.getValue() + " at ("+$resolved1.getRow()+","+$resolved1.getCol()+") and ("+$resolved2.getRow()+","+$resolved2.getCol()+")");
+end
+/**
+ * Check for base cells have a possible cell value this is an indication of an 
+ * unresolved cell error 
+ */
+rule "Validator: #04 There should not be any basecells that have no resolved but still have possible cells"
+   agenda-group "Validator"
+	when
+	    # Run against all BaseCells in the working memory
+		$base : BaseCell($baseRow : row, $baseCol : col)
+		not (ResolvedCellValue (col == $baseCol, row==$baseRow))
+		PossibleCellValue (col == $baseCol, row==$baseRow)
+	then
+		insert(new SudokuStatusUnresolved ("Validator non-resolved row remains at ("+$base.getRow()+","+$base.getCol()+")" ,$base));
+     	insert("Validator non-resolved row remains at ("+$base.getRow()+","+$base.getCol()+")");
+end
+/**
+ * Check that all base cells have either a resolved or possible cell remaining
+ * If this is the case then the cell has no possible value which is a conflict error 
+ */
+rule "Validator: #01 Every basecells should  be resolved or possible cells"
+   agenda-group "Validator"
+	when
+	    # Run against all BaseCells in the working memory
+		$base : BaseCell($baseRow : row, $baseCol : col)
+		not (ResolvedCellValue (col == $baseCol, row==$baseRow)
+		|| PossibleCellValue (col == $baseCol, row==$baseRow))
+	then
+		insert(new SudokuStatusConflict("Validator: unresolveable row at ("+$base.getRow()+","+$base.getCol()+")"));
+     	insert("Validator: unresolveable row at ("+$base.getRow()+","+$base.getCol()+")");
+end
+/**
+ * Checks that there are no previous errors
+ * Enters a solved status row if this is the case to trigger the status listner
+ */
+rule "Validator: Final validation"
+   agenda-group "Validator"
+   salience -20
+	when
+		# No Conflicts in memory
+		 not ( SudokuStatusConflict())
+		# No unresolved cells in memory
+		 not( SudokuStatusUnresolved() )
+	then
+	    # We must be done
+		insert(new SudokuStatusSolved("Validator: No Errors at all"));
+		# track the action
+		insert("Validator: No errors at all " );
+end
+
+/**
+ * The 	agenda-group "GuessTesting" is a guess modifid case of the basic set of rules needed to solve a sudoku problem
+ * The set is modified to remember any deletes and inserts that occur so they can be reversed in the "ReverseGuess" agenda-group.
+ */
+
+/**
+ * This rule checks for the situation where a given Cell in the Sudoku Grid has been assigned 
+ * a definate ResolvedCellValue (i.e. we know what the value in this cell of the Grid is) and
+ * removes any other possible values from this cell (i.e. instances of PossibleCellValue 
+ * with the same row and column.
+ */
+rule "GuessTesting: #01 once a specific cell has a ResolvedCellValue, remove all the other PossibleCellValues for the same cell"
+	# this rule requires a high salience so that, when it is activated it is executed, as soon as a 
+	# ResolvedCellValue is set, we need to clear out the PossibleCellValues for the same cell location, 
+	# otherwise other rules misfire - a good example of a valid use for salience
+	agenda-group "GuessTesting"
+	salience 50 
+	when
+	    # matches all ResolvedCellValues (RCVs) in the grid, and stores them in the $resolved local variable
+	    # note that we also need to store the row and column for $resolved in $resolvedRow and $resolvedColum
+	    # so that the second part of the when clause can access them
+		$resolved : ResolvedCellValue($resolvedRow : row, $resolvedCol : col)
+		
+		# matches any PossibleCellValues (PCVs) in the grid with the same row and column as $resolved
+		$possible : PossibleCellValue(row == $resolvedRow, col == $resolvedCol)
+		(GuessedCellValue(active == true))
+	then
+      		# insert a new RemovedCellValue with the posible value recorded
+	    insert( new RemovedCellValue($possible));
+		# remove the matching PCVs stored in $possible
+		retract($possible);
+		
+		# insert a new String into the working memory describing in detail what we have done
+		insert ("GuessTesting: rule #1 cleared the other PossibleCellValues for ("+$resolved.getRow()+","+$resolved.getCol()+") as a ResolvedCellValue of "+$resolved.getValue()+" exists for this cell.");
+end
+
+/** 
+ * This rule checks for the situation where a given Cell in the SudokuGrid only has 
+ * one PossibleCellValue assigned to its row and column. Once we have this situation, we 
+ * now that this must be the correct value for the cell so we remove the single PossibleCellValue
+ * and replace it with an equivalent ResolvedCellValue.
+ */
+rule "GuessTesting: #02 If a cell has only a single PossibleCellValue, remove it and replace it with the equivalent ResolvedCellValue"
+	agenda-group "GuessTesting"
+	salience 35
+	when
+		# macthes all PCVs in the Grid, stores them in $possible
+		$possible : PossibleCellValue ( $possibleRow : row, $possibleCol : col, $possibleValue : value )
+		
+		# the not operator only causes this when clause to resolve to true when there are not
+		# any other PCVs with the same row and column but different values to $possible
+		not ( PossibleCellValue ( row == $possibleRow, col == $possibleCol, value != $possibleValue ) )
+		(GuessedCellValue(active == true))
+	then
+		# create a new ResolvedCellValue with the same row, column and value into the working memory
+	    resolved = new ResolvedCellValue( $possible);
+		# insert a new ResolvedCellValue with the same row, column and value into the working memory
+	    insert( resolved );
+      		# insert a new RemovedCellValue with the posible and resolved values recorded
+	    insert( new RemovedCellValue($possible , resolved ));
+		# remove $possible from the working memory
+		retract($possible);
+		
+		# insert a new String into the working memory describing in detail what we have done
+		insert ("GuessTesting: rule #2 changed the only PossibleCellValue at ("+$possible.getRow()+","+$possible.getCol()+") to a ResolvedCellValue with the value of "+$possible.getValue());
+end
+
+/**
+ * This rule checks for the situation where a row in the Grid has a ResolvedCellValue in it. In 
+ * this case we know that the value can not occur in any of the other cells in the same row in 
+ * the grid, so we look for any PossibleCellValues with the same row and remove them.
+ */
+rule "GuessTesting: #03 If a row has a ResolvedCellValue in it, remove this value as a PossibleCellValue from all other cells in the same row"
+	agenda-group "GuessTesting"
+  	salience 40
+  	when
+  		# matches all RCVs in the grid, and stores them in the $resolved local variable		
+		$resolved : ResolvedCellValue( $resolvedRow : row, $resolvedValue : value )
+		
+		# matches all the PCVs in the grid in the same row with the same value as $resolved
+		$possible : PossibleCellValue( row == $resolvedRow, value == $resolvedValue )
+		(GuessedCellValue(active == true))
+	then
+      		# insert a new RemovedCellValue with the posible value recorded
+	    insert( new RemovedCellValue($possible));
+		retract($possible);
+
+		# insert a new String into the working memory describing in detail what we have done
+		insert ("GuessTesting: rule #3 determined the value at ("+$possible.getRow()+","+$possible.getCol()+") could not be "+$possible.getValue()+" as this value already exists in the same row at ("+$resolved.getRow()+","+$resolved.getCol()+")");
+end
+
+/**
+ * This rule checks for the situation where a column in the Grid has a ResolvedCellValue in it. In 
+ * this case we know that the value can not occur in any of the other cells in the same column in 
+ * the grid, so we look for any PossibleCellValues with the same column and remove them.
+ */
+rule "GuessTesting: #04 If a column has a ResolvedCellValue in it, remove this value as a PossibleCellValue from all other cells in the same column"
+	agenda-group "GuessTesting"
+  	salience 40
+    when		
+  		# matches all RCVs in the grid, and stores them in the $resolved local variable		
+		$resolved : ResolvedCellValue( $resolvedCol : col, $resolvedValue : value )
+
+		# matches all the PCVs in the grid in the same column with the same value as $resolved
+		$possible : PossibleCellValue( col == $resolvedCol, value == $resolvedValue )
+		(GuessedCellValue(active == true))
+	then
+      		# insert a new RemovedCellValue with the posible value recorded
+	    insert( new RemovedCellValue($possible));
+		retract($possible);
+
+		# insert a new String into the working memory describing in detail what we have done
+		insert ("GuessTesting: rule #4 determined the value at ("+$possible.getRow()+","+$possible.getCol()+") could not be "+$possible.getValue()+" as this value already exists in the same column at ("+$resolved.getRow()+","+$resolved.getCol()+")");
+end
+
+/**
+ * This rule checks for the situation where a zone in the Grid has a ResolvedCellValue in it. In 
+ * this case we know that the value can not occur in any of the other cells in the same zone in 
+ * the grid, so we look for any PossibleCellValues with the same zone and remove them.
+ */
+rule "GuessTesting: #05 If a zone has a ResolvedCellValue in it, remove this value as a PossibleCellValue from all other cells in the same zone"
+	agenda-group "GuessTesting"
+  	salience 40
+ 	when		
+  		# matches all RCVs in the grid, and stores them in the $resolved local variable		
+		$resolved : ResolvedCellValue( $resolvedZone : zone, $resolvedValue : value )
+
+		# matches all the PCVs in the grid in the same zone with the same value as $resolved
+		$possible : PossibleCellValue( zone == $resolvedZone, value == $resolvedValue )
+		(GuessedCellValue(active == true))
+	then
+      		# insert a new RemovedCellValue with the posible value recorded
+	    insert( new RemovedCellValue($possible));
+		retract($possible);
+
+	    # insert a new String into the working memory describing in detail what we have done
+		insert ("GuessTesting: rule #5 determined the value at ("+$possible.getRow()+","+$possible.getCol()+") could not be "+$possible.getValue()+" as this value already exists in the same zone at ("+$resolved.getRow()+","+$resolved.getCol()+")");
+end
+
+/**
+ * This rule checks for the situation when it is only possible for one cell of a row in the Grid to contain
+ * a particular value, i.e. there is exactly one PossibleCellValue with a given value and a given row.
+ * In this case, this cell must actually contain the value so we remove the single PossibleCellValue
+ * and replace it with an equivalent ResolvedCellValue.
+ */
+rule "GuessTesting: #06 If a PossibleCellValue only appears once in a row, then this must be the ResolvedCellValue"
+	agenda-group "GuessTesting"
+    salience 30
+	when
+		# matches all PCVs in the grid, and stores them in the $possible local variable		
+		$possible : PossibleCellValue( $zone : zone, $value : value, $col : col, $row : row)
+
+		# the not operator only causes this when clause to resolve to true when there are not
+		# any other PCVs with the same row and value as $possible
+		not (PossibleCellValue( row == $row, value == $value ))
+		(GuessedCellValue(active == true))
+	then
+		# create a new ResolvedCellValue with the same row, column and value into the working memory
+	    resolved = new ResolvedCellValue( $possible);
+		# insert a new ResolvedCellValue with the same row, column and value into the working memory
+	    insert( resolved );
+      		# insert a new RemovedCellValue with the posible and resolved values recorded
+	    insert( new RemovedCellValue($possible , resolved ));
+		retract($possible);
+
+		# insert a new String into the working memory describing in detail what we have done
+		insert ("GuessTesting: rule #6 determined ("+$row+","+$col+") is "+$value+" as this is the only possible cell in the row that can have this value");
+end
+
+/**
+ * This rule checks for the situation when it is only possible for one cell of a column in the Grid to contain
+ * a particular value, i.e. there is exactly one PossibleCellValue with a given value and a given column.
+ * In this case, this cell must actually contain the value so we remove the single PossibleCellValue
+ * and replace it with an equivalent ResolvedCellValue.
+ */
+rule "GuessTesting: #07 If a PossibleCellValue only appears once in a column, then this must be the ResolvedCellValue"
+	agenda-group "GuessTesting"
+    salience 30
+  	when		
+		# matches all PCVs in the grid, and stores them in the $possible local variable		
+		$possible : PossibleCellValue( $zone : zone, $value : value, $col : col, $row : row)
+
+		# the not operator only causes this when clause to resolve to true when there are not
+		# any other PCVs with the same column and value as $possible
+		not (PossibleCellValue( col == $col, value == $value ))
+		(GuessedCellValue(active == true))
+	then
+		# create a new ResolvedCellValue with the same row, column and value into the working memory
+	    resolved = new ResolvedCellValue( $possible);
+		# insert a new ResolvedCellValue with the same row, column and value into the working memory
+	    insert( resolved );
+      		# insert a new RemovedCellValue with the posible and resolved values recorded
+	    insert( new RemovedCellValue($possible , resolved ));
+		retract($possible);
+
+		# insert a new String into the working memory describing in detail what we have done
+		insert ("GuessTesting: rule #7 determined ("+$row+","+$col+") is "+$value+" as this is the only possible cell in the column that can have this value");
+end
+
+/**
+ * This rule checks for the situation when it is only possible for one cell of a zone in the Grid to contain
+ * a particular value, i.e. there is exactly one PossibleCellValue with a given zone and a given column.
+ * In this case, this cell must actually contain the value so we remove the single PossibleCellValue
+ * and replace it with an equivalent ResolvedCellValue.
+ */
+rule "GuessTesting: #08 If a PossibleCellValue only appears once in a zone, then this must be the ResolvedCellValue"
+	agenda-group "GuessTesting"
+    salience 30
+   	when		
+		# matches all PCVs in the grid, and stores them in the $possible local variable		
+		$possible : PossibleCellValue( $zone : zone, $value : value, $col : col, $row : row)
+
+		# the not operator only causes this when clause to resolve to true when there are not
+		# any other PCVs with the same column and value as $possible
+		not (PossibleCellValue( zone == $zone, value == $value ))
+		(GuessedCellValue(active == true))
+	then
+		# create a new ResolvedCellValue with the same row, column and value into the working memory
+	    resolved = new ResolvedCellValue( $possible);
+		# insert a new ResolvedCellValue with the same row, column and value into the working memory
+	    insert( resolved );
+      		# insert a new RemovedCellValue with the posible and resolved values recorded
+	    insert( new RemovedCellValue($possible , resolved ));
+		retract($possible);
+
+		# insert a new String into the working memory describing in detail what we have done
+		insert ("GuessTesting: rule #8 determined ("+$row+","+$col+") is "+$value+" as this is the only possible cell in the zone that can have this value");
+end
+
+/**
+ * This rule looks for a situation where we have two cells in a zone of the grid which are in the 
+ * same column but different rows where each of the two cells contains exactly two possible values 
+ * and this pair of values is the same in both the cells. In this situation, while we do not 
+ * know which way round the two values should be assigned to the two cells, we do know that the 
+ * two values must be assigned to these two cells and therefore we remove the possibility of them 
+ * being present in any other cells in this zone.
+ */
+rule "GuessTesting: #09 if a pair of cells exists in the same zone and the same column but different rows containing the same pair of possible values then elimnate these two possible values from anywhere else in the zone"
+	agenda-group "GuessTesting"
+	salience 20
+	when
+	    # match all PCVs and store as $possible1
+		$possible1 : PossibleCellValue( $zone1 : zone, $val1 : value, $row1 : row, $col1 : col )
+		
+		# match any PCVs with the same value and in the same zone and column but in a different row to $possible1
+		$possible2 :PossibleCellValue( zone == $zone1, value == $val1, $row2 : row != $row1, $col2 : col)
+		
+		# match any PCV in the same location as $possible1 with a different value to $possible1
+		$possible3 : PossibleCellValue(row == $row1, col == $col1, $val3 : value )
+		
+		# match any PCV in the same location as $possible2 with the same value as $possible3
+		$possible4 : PossibleCellValue(row == $row2, col == $col2, value == $val3 )
+		
+		# check there is not a third PCV in the same location as $possible1 with a different value to $possible1 or $possible3
+		not ( PossibleCellValue( row == $row1, col == $col1, value != $val1, value != $val3 ) )
+		
+		# check there is not a third PCV in tne same location as $possible2 with a different value to $possible1 or $possible3
+		not ( PossibleCellValue( row == $row2, col == $col2, value != $val1, value != $val3 ) )
+		
+		# match any other PCVs in the same zone as $possible1 with the same value 
+		$possible : PossibleCellValue( zone == $zone1, value == $val1)
+		(GuessedCellValue(active == true))
+	then
+      		# insert a new RemovedCellValue with the posible value recorded
+	    insert( new RemovedCellValue($possible));
+		retract($possible);
+
+		# insert a new String into the working memory describing in detail what we have done
+		insert ("GuessTesting: rule #9 fired, removing value "+$possible.getValue()+" as a possibility from "+$possible.getRow()+","+$possible.getCol()+" because the values of "+$val1+" and "+$val3+" must be in the cells "+$row1+","+$col1+" and "+$row2+","+$col2);
+end
+
+/**
+ * This rule looks for a situation where we have two cells in a zone of the grid which are in the 
+ * same row but different colums where each of the two cells contains exactly two possible values 
+ * and this pair of values is the same in both the cells. In this situation, while we do not 
+ * know which way round the two values should be assigned to the two cells, we do know that the 
+ * two values must be assigned to these two cells and therefore we remove the possibility of them 
+ * being present in any other cells in this zone.
+ */
+rule "GuessTesting: #10 if a pair of cells exists in the same zone and the same row but different columns containing the same pair of possible values then elimnate these two possible values from anywhere else in the zone"
+	agenda-group "GuessTesting"
+	salience 20
+	when
+	    # match all PCVs and store as $possible1
+		$possible1 : PossibleCellValue( $zone1 : zone, $val1 : value, $row1 : row, $col1 : col )
+		
+		# match any PCVs with the same value and in the same zone and column but in a different row to $possible1
+		$possible2 :PossibleCellValue( zone == $zone1, value == $val1, $row2 : row, $col2 : col != $col1)
+		
+		# match any PCV in the same location as $possible1 with a different value to $possible1
+		$possible3 : PossibleCellValue(row == $row1, col == $col1, $val3 : value )
+		
+		# match any PCV in the same location as $possible2 with the same value as $possible3
+		$possible4 : PossibleCellValue(row == $row2, col == $col2, value == $val3 )
+		
+		# check there is not a third PCV in the same location as $possible1 with a different value to $possible1 or $possible3
+		not ( PossibleCellValue( row == $row1, col == $col1, value != $val1, value != $val3 ) )
+		
+		# check there is not a third PCV in tne same location as $possible2 with a different value to $possible1 or $possible3
+		not ( PossibleCellValue( row == $row2, col == $col2, value != $val1, value != $val3 ) )
+		
+		# match any other PCVs in the same zone as $possible1 with the same value 
+		$possible : PossibleCellValue( zone == $zone1, value == $val1)
+		(GuessedCellValue(active == true))
+	then
+      		# insert a new RemovedCellValue with the posible value recorded
+	    insert( new RemovedCellValue($possible));
+		retract($possible);
+
+		# insert a new String into the working memory describing in detail what we have done
+		insert ("GuessTesting: rule #10 fired, removing value "+$possible.getValue()+" as a possibility from "+$possible.getRow()+","+$possible.getCol()+" because the values of "+$val1+" and "+$val3+" must be in the cells "+$row1+","+$col1+" and "+$row2+","+$col2);
+end
+/**
+ * The 	agenda-group "GuessSetup" sets up the starting conditions for guess testing
+ * Which are as follows:
+ * Find a cell that has 2 or more possible cell values, and that hasn't been guessed
+ * Remove a possible value and insert a planned guess cell
+ * Replace all the other possibles with guesses.
+ */
+/**
+ * Find a cell that has exactly 2 possible cell values, and that hasn't been guessed
+ * set it up for testing
+ */
+rule "GuessSetup: rule #01 If there is a cell with only two possible values that hasn't been guessed, setup for guessing"
+   agenda-group "GuessSetup"
+   salience 20
+	when
+		$possible1 : PossibleCellValue( $value1 : value, $col1 : col, $row1 : row)
+		$possible2 : PossibleCellValue( $value2 : value, value != $value1
+		, col == $col1, row == $row1)
+		not (PossibleCellValue( value != $value2, value != $value1,col == $col1, row == $row1) )
+		not (GuessedCellValue(planned == true))
+		not (GuessedCellValue(value == $value1,col == $col1, row == $row1))
+	then
+		insert( new GuessedCellValue( $possible1) );
+	    retract($possible1);
+		insert("GuessSetup: Rule #01 fired" );
+end
+/**
+ * Find a cell that has more then 2 possible cell values, and that hasn't been guessed
+ * set it up for testing
+ */
+rule "GuessSetup: rule #02 If there is a cell with possible values and rule 01 didn't set up a guess, setup for guessing"
+   agenda-group "GuessSetup"
+   salience 10
+	when
+		$possible1 : PossibleCellValue( $value1 : value, $col1 : col, $row1 : row)
+		$possible2 : PossibleCellValue( $value2 : value, value != $value1
+		, col == $col1, row == $row1)
+		not (GuessedCellValue(planned == true))
+		not (GuessedCellValue(value == $value1,col == $col1, row == $row1))
+	then
+		insert( new GuessedCellValue( $possible1) );
+	    retract($possible1);
+		insert("GuessSetup: Rule #02 fired" );
+end
+/**
+ * Find a cell that has more then 2 possible cell values, and that hasn't been guessed
+ * set it up for testing
+ */
+rule "GuessSetup: rule #03 if you identified a cell to guess remove the other possible guesses"
+   agenda-group "GuessSetup"
+	when
+		$possible1 : PossibleCellValue( $zone1 : zone, $value1 : value, $col1 : col, $row1 : row)
+		$firstGuess : GuessedCellValue( zone == $zone1, col == $col1,  row == $row1,planned == true)
+	then
+		insert( new GuessedCellValue( $possible1) );
+	    retract($possible1);
+		
+		insert("GuessSetup: Rule #03 fired" );
+end
+/**
+ * The 	agenda-group "GuessSelection" identifies one of the planned guesses as the active guess
+ */
+/**
+ * Rule 1 pick a random planned guess when there is no active guess and make it active
+ * and add a resolve cell to the memory
+ */
+rule "GuessSelection: Rule #01 if you are guessing and have no active row pick one as the active row"
+   agenda-group "GuessSelection"
+   salience 20
+	when
+		$firstGuess : GuessedCellValue( $zone1 : zone, $value1 : value, $col1 : col, $row1 : row,planned == true, $possible : possibleCellRemoved)
+		not( GuessedCellValue( zone == $zone1, col == $col1,  row == $row1,value != $value1, active == true) )
+	then
+    	$firstGuess.setState( GuessedCellValue.GUESSING_STATUS_ACTIVE); 
+		update($firstGuess);
+		insert( $possible);
+		insert("GuessSelection: Rule #01 fired to activate guess :" + $value1+ ":" + $row1 + ":" + $col1 + ":");
+end
+/**
+ * The 	agenda-group "GuessSelectionError" cleans out the current active guess as it has been identified as an 
+ * Error. 
+ */
+/**
+ * "GuessSelectionError"  step 1. put in a possible row so that the listner can pick up its removal in step 2 
+ */
+
+rule "GuessSelectionError: Step #1 make sure a possible row exists for the guess to be reomved for the listener"
+   agenda-group "GuessSelectionError"
+   salience 20
+	when
+		$guess : GuessedCellValue( $possible : possibleCellRemoved , $value : value, $row : row, $col:col, active == true)
+		not(PossibleCellValue ( value == $value, row == $row, col == $col))
+	then
+		insert($possible );
+		insert("GuessSelectionError: Step #1 make sure a possible row exists for the guess to be reomved for the listener : added possible:"+ $guess.getValue() + ":R"+ $guess.getRow() + ":C"+ $guess.getCol());
+end
+/**
+ * "GuessSelectionError"  step 2. remove the guess and the associated possible row. 
+ */
+rule "GuessSelectionError: Step #2 retract the guess and the possible row"
+   agenda-group "GuessSelectionError"
+   salience 10
+	when
+		$guess : GuessedCellValue( $possible : possibleCellRemoved , $value : value, $row : row, $col:col, active == true)
+		PossibleCellValue ( value == $value, row == $row, col == $col)
+	then
+		retract($guess);
+		retract($possible );
+		insert("GuessSelectionError: Step #2 previous guess was wrong : removed guess V:"+ $guess.getValue() + ":R"+ $guess.getRow() + ":C"+ $guess.getCol());
+end
+/**
+ * The 	agenda-group "GuessSelectionErrorOneCellRemains" identifies the only remaining guess in the 
+ * cell currently being tested. When all other possiblities have been eliminated and sets it as possible
+ * so that the base loop can be rerun. 
+ */
+rule "GuessSelectionErrorOneCellRemains #1 but add both as possible"
+   agenda-group "GuessSelectionErrorOneCellRemains"
+    when
+		$guess : GuessedCellValue( $possible : possibleCellRemoved , previous == false)
+	then
+		insert($possible );
+		insert("GuessSelectionErrorOneCellRemains down to 1 put in possible guess V:"+ $guess.getValue() + ":R"+ $guess.getRow() + ":C"+ $guess.getCol());
+end
+
+/**
+ * The 	agenda-group "ReverseGuess" reverses the actions of "GuessTesting" 
+ */
+/**
+ * ReverseGuess: Step 01 reverse actions that just removed a possible cell because of a guess
+ */
+rule "ReverseGuess: Step #01 Reverse removed possible cells"
+   agenda-group "ReverseGuess"
+   salience 20
+	when
+   $removed : RemovedCellValue($possible: possibleCellRemoved, 
+   hasResolvedCell == false,
+   $row: row, $col: col, $value:value)
+	then
+	    retract($removed);
+	    insert($possible);
+	    update($possible);
+		insert("Reverse Guess: Step #02 Reversing the possible cell of value " + $possible.getValue() + ":R"+ $possible.getRow() + ":C"+ $possible.getCol());
+end
+
+/**
+ * ReverseGuess: Step 02 reverse actions that add a resolved cell and removed a possible cell because of a guess
+ */
+rule "ReverseGuess: Step #02 Reverse removed possible cells and added resolved cells"
+   agenda-group "ReverseGuess"
+   salience 20
+	when
+   $removed : RemovedCellValue($possible: possibleCellRemoved
+   		, hasResolvedCell == true
+   		, $resolved : resolvedCell)
+	then
+	    retract($removed);
+	    retract($resolved);
+	    insert($possible);
+	    update($possible);
+		insert("Reverse Guess: Step #02 Reversing the possible and the resolved with of V" + $possible.getValue() + ":R"+ $possible.getRow() + ":C"+ $possible.getCol());
+end
+
+/**
+ * The 	agenda-group "CleanupUnsolved" cleans up after an unsolved loop
+ */
+/**
+ * CleanupUnsolved: Step 01 mare all previous guesses as previous
+ * they are retained briefly to make sure that the same cell isn't repeatedly guessed
+ */
+rule "CleanupUnsolved: Step #01 update non-previous guesses as previous"
+   agenda-group "CleanupUnsolved"
+	when
+		$guess : GuessedCellValue( previous == false,$possible : possibleCellRemoved)
+	then
+	$guess.setState( GuessedCellValue.GUESSING_STATUS_PREVIOUS);
+		update($guess);
+		insert($possible );
+		insert("CleanupUnsolved: Step #01 update non-previous guesses as previous V" + $guess.getValue() + ":R"+ $guess.getRow() + ":C"+ $guess.getCol());
+end
+/**
+ * The 	agenda-group "CleanupCorrectGuess" cleans up after an guess that solves the puzzle
+ */
+/**
+ * Step #01 put back the possible cells for the current guesses
+ */
+ rule "CleanupCorrectGuess: Step #01 Reverse non-previous guess cells"
+   agenda-group "CleanupCorrectGuess"
+   salience 20
+	when
+    GuessedCellValue($possible: possibleCellRemoved, previous == false)
+	then
+	   insert($possible);
+	   insert("CleanupCorrectGuess: Step 1 Reversing the possible from Guess of V" + $possible.getValue() + ":R"+ $possible.getRow() + ":C"+ $possible.getCol());
+end
+/**
+ * Step #02 remove the possible cell for any guess that is tested and has a resolved value
+ */
+ 
+rule "CleanupCorrectGuess: Step 2 remove non active resolutions with resolved values"
+# This works because the the guess all ready is a possible 
+# and needs to be flipped again to be visible to the listener
+   agenda-group "CleanupCorrectGuess"
+	salience 10
+	when
+		$guess : GuessedCellValue( $value1 : value, $col1 : col, $row1 : row,tested == true,$possible : possibleCellRemoved)
+		$resolved : ResolvedCellValue( value == $value1, row == $row1, col == $col1)
+	then
+		insert($possible);
+		retract($resolved );
+		retract($guess);
+		insert("CleanupCorrectGuess: Step 2 Reverse Guess remove non active resolutions with resolved values: V" + $guess.getValue() + ":R"+ $guess.getRow() + ":C"+ $guess.getCol());
+end
+/**
+ * Step #03 remove the possible cell for any non active guesses 
+ */
+rule "CleanupCorrectGuess: Step #03 remove the possible for the non-active guesses in the current cell"
+# This works because the the guess all ready is a possible 
+# and needs to be flipped again to be visible to the listener
+   agenda-group "CleanupCorrectGuess"
+	when
+	    # ID the guessed value as it is right
+		GuessedCellValue( $value1 : value, $col1 : col, $row1 : row, active == true)
+		# ID the non-active guess and thier possible values in the same cell
+		$guess : GuessedCellValue(  value != $value1, col ==  $col1 , row == $row1 , active == false, $possible : possibleCellRemoved)
+	then
+	    # remove the non-active guess's possible fact which was added in step 01 so the listener is triggered by the removal
+		retract($possible);
+		# remove the non-active guess
+		retract($guess);
+		insert("CleanupCorrectGuess: Step 3 remove the possible for the non-active guesses in the current cell: V" + $guess.getValue() + ":R"+ $guess.getRow() + ":C"+ $guess.getCol());
+end
+/**
+ * The 	agenda-group "ReverseErrors" cleans up the state error messages from a previous validation run
+ * before running another set of tests
+ */
+ /**
+ * Remove all conflicts as these are identfied by the error which is being reversed
+ */
+rule "ReverseErrors: Step #01 Reverse Conflicts Errors"
+   agenda-group "ReverseErrors"
+    when
+		$conflict : SudokuStatusConflict()
+	then
+		retract($conflict );
+		insert("ReverseErrors: Step #01 Reversing a conflict error" + $conflict.toString());
+end
+ /**
+ * Remove all unresolved error if there is now a resolved row
+ */
+rule "ReverseErrors: Step #02 Reverse Unsolved Errors"
+   agenda-group "ReverseErrors"
+   salience -20
+	when
+		$unsolved : SudokuStatusUnresolved($base : base,$baseCol:col, $baseRow:row)
+		ResolvedCellValue (col == $baseCol, row==$baseRow)
+	then
+		retract($unsolved);
+		insert("ReverseErrors: Step #02 Reversing a unsolved error: V" +  ":R"+ $baseRow + ":C"+ + $baseCol);
+end
+/**
+ * The 	agenda-group "ArchiveGuesses" marks the current guesses as previous
+ */
+ /**
+ * Mark all current guessed cells previous as the previous guesses didn't remove a cell
+ */
+rule "ArchiveGuesses: Step #01 archive guesses"
+   agenda-group "ArchiveGuesses"
+	when
+		$guess : GuessedCellValue( previous == false)
+	then
+		$guess.setState( GuessedCellValue.GUESSING_STATUS_PREVIOUS); 
+		update($guess);		
+		insert("ArchiveGuesses: Step #01 archive guesses : V" + $guess.getValue() + ":R"+ $guess.getRow() + ":C"+ $guess.getCol());
+end
+/**
+ * The 	agenda-group "BasicRevGuess" puts the possible cells back for the current guesses 
+ */
+rule "BasicRevGuess: Step #01 put back all the possible cells"
+   agenda-group "BasicRevGuess"
+	when
+		$guess : GuessedCellValue( $possible:possibleCellRemoved, previous == false)
+	then
+		insert($possible);
+		insert("BasicRevGuess: Step #01  insert possible for guess : V" + $possible.getValue() + ":R"+ $possible.getRow() + ":C"+ $possible.getCol());
+end

