org.drools.examples.sudoku.sudokuSolver.drl Maven / Gradle / Ivy
The newest version!
package org.drools.examples.sudoku
import org.drools.examples.sudoku.rules.PossibleCellValue;
import org.drools.examples.sudoku.rules.ResolvedCellValue;
/**
* 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 no PossibleCellValues remain.
*
* After each rule fires, it inserts a String object into the working memoru detailing the action that
* the fired rule has taken.
*
* @see org.drools.examples.sudoku.rules.PossibleCellValue
* @see org.drools.examples.sudoku.rules.ResolvedCellValue
* @author Pete Bennett
* @author Michael Frandsen
* @version $Revision: 1.1 $
*/
/**
* 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 "#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
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 ("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 "#02 If a cell has only a single PossibleCellValue, remove it and replace it with the equivalent ResolvedCellValue"
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 ("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 "#03 If a row has a ResolvedCellValue in it, remove this value as a PossibleCellValue from all other cells in the same row"
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 ("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 "#04 If a column has a ResolvedCellValue in it, remove this value as a PossibleCellValue from all other cells in the same column"
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 ("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 "#05 If a zone has a ResolvedCellValue in it, remove this value as a PossibleCellValue from all other cells in the same zone"
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 ("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 "#06 If a PossibleCellValue only appears once in a row, then this must be the ResolvedCellValue"
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 ("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 "#07 If a PossibleCellValue only appears once in a column, then this must be the ResolvedCellValue"
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 ("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 "#08 If a PossibleCellValue only appears once in a zone, then this must be the ResolvedCellValue"
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 ("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 "#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"
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 ("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 "#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"
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 ("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
/**
rule "#11 as a last resort, find a zone which only has two unsolved cells and pick one of the values in it at random to try to proceed"
salience 10
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 to $possible1
$possible2 :PossibleCellValue( zone == $zone1, value == $val1, $row2 : row, $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 fifth PCV in this zone at all
not ( PossibleCellValue ( zone == $zone1 ) );
then
retract($possible1);
# insert a new String into the working memory describing in detail what we have done
insert ("Rule #11 fired, removing value "+$possible1.getValue()+" as a possibility from "+$possible1.getRow()+","+$possible1.getCol()+" because the values of "+$val1+" and "+$val3+" must be in the cells "+$row1+","+$col1+" and "+$row2+","+$col2);
end
**/
© 2015 - 2025 Weber Informatics LLC | Privacy Policy