PageRenderTime 39ms CodeModel.GetById 19ms app.highlight 17ms RepoModel.GetById 1ms app.codeStats 0ms

/drools-examples/src/main/java/org/drools/examples/sudoku/Sudoku.java

https://github.com/wintonxu/drools
Java | 346 lines | 260 code | 33 blank | 53 comment | 67 complexity | 5564faa7e198b9f0e6fe5630630e79ad MD5 | raw file
  1/*
  2 * Copyright 2011 JBoss Inc
  3 *
  4 * Licensed under the Apache License, Version 2.0 (the "License");
  5 * you may not use this file except in compliance with the License.
  6 * You may obtain a copy of the License at
  7 *
  8 *      http://www.apache.org/licenses/LICENSE-2.0
  9 *
 10 * Unless required by applicable law or agreed to in writing, software
 11 * distributed under the License is distributed on an "AS IS" BASIS,
 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13 * See the License for the specific language governing permissions and
 14 * limitations under the License.
 15 */
 16package org.drools.examples.sudoku;
 17
 18import java.util.Formatter;
 19import java.util.HashSet;
 20import java.util.Set;
 21
 22import org.drools.KnowledgeBase;
 23import org.drools.event.rule.ObjectInsertedEvent;
 24import org.drools.event.rule.ObjectRetractedEvent;
 25import org.drools.event.rule.ObjectUpdatedEvent;
 26import org.drools.event.rule.WorkingMemoryEventListener;
 27import org.drools.examples.sudoku.swing.AbstractSudokuGridModel;
 28import org.drools.examples.sudoku.swing.SudokuGridEvent;
 29import org.drools.examples.sudoku.swing.SudokuGridModel;
 30import org.drools.runtime.StatefulKnowledgeSession;
 31import org.drools.runtime.rule.FactHandle;
 32
 33/**
 34 * An object of this class solves Sudoku problems.
 35 */
 36public class Sudoku extends AbstractSudokuGridModel implements SudokuGridModel {
 37
 38    public static Sudoku sudoku;
 39    
 40    public  Cell[][]    cells;
 41    private CellSqr[][] sqrs = new CellSqr[][]{ new CellSqr[3], new CellSqr[3], new CellSqr[3] };
 42    private CellRow[]   rows = new CellRow[9];
 43    private CellCol[]   cols = new CellCol[9];
 44    
 45    private KnowledgeBase kBase;
 46    private StatefulKnowledgeSession session;
 47    private SudokuWorkingMemoryListener workingMemoryListener = new SudokuWorkingMemoryListener();
 48    private Counter counter;
 49    private Boolean explain = false;
 50    private FactHandle steppingFactHandle;
 51    private Stepping stepping;
 52    private boolean unsolvable = false;
 53    
 54    /**
 55     * Constructor.
 56     * @param kBase a Knowledge Base with rules for solving Sudoku problems.
 57     */
 58    public Sudoku(KnowledgeBase kBase) {
 59        this.kBase = kBase;
 60        sudoku = this;
 61    }
 62    
 63    /*
 64     * (non-Javadoc)
 65     * @see org.drools.examples.sudoku.swing.SudokuGridModel#getCellValue(int, int)
 66     */
 67    public String getCellValue(int iRow, int iCol) {
 68        if (cells == null) return " ";
 69        return cells[iRow][iCol].valueAsString();
 70    }
 71    
 72    /**
 73     * Nice printout of the grid.
 74     */
 75    public void dumpGrid() {
 76        Formatter fmt = new Formatter(System.out);
 77        fmt.format("       ");
 78        for (int iCol = 0; iCol < 9; iCol++) {
 79            fmt.format("Col: %d     ", iCol);
 80        }
 81        System.out.println();
 82        for (int iRow = 0; iRow < 9; iRow++) {
 83            System.out.print("Row " + iRow + ": ");
 84            for (int iCol = 0; iCol < 9; iCol++) {
 85                if (cells[iRow][iCol].getValue() != null) {
 86                    fmt.format(" --- %d --- ", cells[iRow][iCol].getValue());
 87                } else {
 88                    StringBuilder sb = new StringBuilder();
 89                    Set<Integer> perms = cells[iRow][iCol].getFree();
 90                    for (int i = 1; i <= 9; i++) {
 91                        if (perms.contains(i)) {
 92                            sb.append(i);
 93                        } else {
 94                            sb.append(' ');
 95                        }
 96                    }
 97                    fmt.format(" %-10s", sb.toString());
 98                }
 99            }
100            System.out.println();
101        }
102    }
103    
104    /**
105     * Checks that everything is still according to the sudoku rules.
106     */
107    public void consistencyCheck() {
108        for (int iRow = 0; iRow < 9; iRow++) {
109            for (int iCol = 0; iCol < 9; iCol++) {
110                Cell cell = cells[iRow][iCol];
111                Integer value = cell.getValue();
112                if (value != null) {
113                    if (! cell.getFree().isEmpty()) {
114                        throw new IllegalStateException("free not empty");
115                    }
116                    // any containing group
117                    for (Cell other: cell.getExCells()) {
118                        // must not occur in any of the other cells
119                        if (value.equals(other.getValue())) {
120                            throw new IllegalStateException("duplicate");
121                        }
122                        // must not occur in the permissibles of any of the other cells
123                        if (other.getFree().contains(value)) {
124                            throw new IllegalStateException("not eliminated");
125                        }
126                    }
127                }
128            }
129        }
130        
131        for (int i = 0; i < rows.length; i++) {
132            Set<Integer> aSet = new HashSet<Integer>();
133            for (int j = 0; j < rows[i].getCells().size(); j++) {
134                Cell cell = rows[i].getCells().get(j);
135                Integer value = cell.getValue();
136                if (value != null) {
137                    aSet.add(value);
138                } else {
139                    aSet.addAll(cell.getFree());
140                }
141            }
142            if (! aSet.equals(CellGroup.allNine)) {
143                throw new IllegalStateException("deficit in row");
144            }
145        }
146        
147        for (int i = 0; i < cols.length; i++) {
148            Set<Integer> aSet = new HashSet<Integer>();
149            for (int j = 0; j < cols[i].getCells().size(); j++) {
150                Cell cell = cols[i].getCells().get(j);
151                Integer value = cell.getValue();
152                if (value != null) {
153                    aSet.add(value);
154                } else {
155                    aSet.addAll(cell.getFree());
156                }
157            }
158            if (! aSet.equals(CellGroup.allNine)) {
159                throw new IllegalStateException("deficit in column");
160            }
161        }
162
163        for (int ir = 0; ir < sqrs.length; ir++) {
164            for (int ic = 0; ic < sqrs[ir] .length; ic++) {
165                Set<Integer> aSet = new HashSet<Integer>();
166                for (int j = 0; j < sqrs[ir][ic].getCells().size(); j++) {
167                    Cell cell = sqrs[ir][ic].getCells().get(j);
168                    Integer value = cell.getValue();
169                    if (value != null) {
170                        aSet.add(value);
171                    } else {
172                        aSet.addAll(cell.getFree());
173                    }
174                }
175                if (! aSet.equals(CellGroup.allNine)) {
176                    throw new IllegalStateException("deficit in square");
177                }
178            }
179        }
180        System.out.println("+++ check OK +++");
181    }
182    
183    /*
184     * (non-Javadoc)
185     * @see org.drools.examples.sudoku.swing.SudokuGridModel#solve()
186     */
187    public void solve() {
188        if (this.isSolved()) return;
189        explain = false;
190        session.setGlobal("explain", explain);
191        if( steppingFactHandle != null ){
192            session.retract( steppingFactHandle );
193            steppingFactHandle = null;
194            stepping = null;
195        }
196        this.session.fireAllRules();
197//        dumpGrid();
198    }
199    
200    /*
201     * (non-Javadoc)
202     * @see org.drools.examples.sudoku.swing.SudokuGridModel#step()
203     */
204    public void step() {
205        if (this.isSolved()) return;
206        explain = true;
207        session.setGlobal("explain", explain);
208        this.counter.setCount(1);
209        session.update(session.getFactHandle(this.counter), this.counter);
210        if( steppingFactHandle == null ){
211            steppingFactHandle = session.insert( stepping = new Stepping() );
212        }
213        this.session.fireUntilHalt();
214        if( stepping.isEmergency() ){
215            this.unsolvable = true;
216        }
217//        dumpGrid();
218    }
219
220    public boolean isSolved() {
221        for (int iRow = 0; iRow < 9; iRow++) {
222            for (int iCol = 0; iCol < 9; iCol++) {
223                if (cells[iRow][iCol].getValue() == null) return false;
224            }
225        }
226        return true;
227    }
228    
229    public boolean isUnsolvable(){
230        return unsolvable;
231    }
232    
233    private void create() {
234        for (int i = 0; i < 9; i++) {
235            session.insert(Integer.valueOf(i+1));
236            rows[i] = new CellRow(i);
237            cols[i] = new CellCol(i);
238        }
239        
240        cells = new Cell[9][];
241        for (int iRow = 0; iRow < 9; iRow++) {
242            cells[iRow] = new Cell[9];
243            for (int iCol = 0; iCol < 9; iCol++) {
244                Cell cell = cells[iRow][iCol] = new Cell();
245                rows[iRow].addCell(cell);
246                cols[iCol].addCell(cell);
247            }
248        }
249
250        for (int i = 0; i < 3; i++) {
251            for (int j = 0; j < 3; j++) {
252                sqrs[i][j] = new CellSqr(rows[i*3], rows[i*3+1], rows[i*3+2],
253                                         cols[j*3], cols[j*3+1], cols[j*3+2]);
254            }
255        }
256
257        for (int iRow = 0; iRow < 9; iRow++) {
258            for (int iCol = 0; iCol < 9; iCol++) {
259                cells[iRow][iCol].makeReferences(rows[iRow], cols[iCol], sqrs[iRow/3][iCol/3]);
260                session.insert(cells[iRow][iCol]);
261            }
262            session.insert(rows[iRow]);
263            session.insert(cols[iRow]);
264            session.insert(sqrs[iRow/3][iRow%3]);
265        }
266    }
267
268    /*
269     * (non-Javadoc)
270     * @see org.drools.examples.sudoku.swing.SudokuGridModel#setCellValues(java.lang.Integer[][])
271     */
272    public void setCellValues(Integer[][] cellValues) {
273        if (session != null) {
274            session.removeEventListener(workingMemoryListener);
275            session.dispose();
276        }
277        
278        this.session = kBase.newStatefulKnowledgeSession();
279        session.setGlobal("explain", explain);
280        session.addEventListener(workingMemoryListener);
281
282        Setting s000 = new Setting(0, 0, 0);
283        FactHandle fh000 = this.session.insert(s000);
284        this.create();
285
286        int initial = 0;
287        for (int iRow = 0; iRow < 9; iRow++) {
288            for (int iCol = 0; iCol < 9; iCol++) {
289                Integer value = cellValues[iRow][iCol];
290                if (value != null) {
291                    session.insert(new Setting(iRow, iCol, value));
292                    initial++;
293                }
294            }
295        }
296        this.counter = new Counter(initial);
297        this.session.insert(counter);
298        this.session.retract(fh000);
299        this.session.fireUntilHalt();
300    }
301    
302    /*
303     * (non-Javadoc)
304     * @see java.lang.Object#toString()
305     */
306    @Override
307    public String toString() {
308        StringBuilder sb = new StringBuilder();
309
310        sb.append("Sudoku:").append('\n');
311        for (int iRow = 0; iRow < 9;  iRow++) {
312            sb.append("  ").append(rows[iRow].toString()).append('\n');
313        }
314        
315        return sb.toString();
316    }
317    
318    class SudokuWorkingMemoryListener implements WorkingMemoryEventListener {
319
320        public void objectInserted(ObjectInsertedEvent ev) {
321            if (ev.getObject() instanceof Counter) {
322                fireRestartEvent(null);
323            }
324        }
325
326        public void objectRetracted(ObjectRetractedEvent ev) {
327        }
328
329        public void objectUpdated(ObjectUpdatedEvent ev) {
330            if (ev.getObject() instanceof Cell) {
331                Cell cell = (Cell) ev.getObject();
332                if (cell.getValue() != null) {
333                    fireCellUpdatedEvent(new SudokuGridEvent(this,
334                            cell.getRowNo(),
335                            cell.getColNo(),
336                            cell.getValue()));
337                }
338            }
339        }
340    }
341    
342    public void validate(){
343        session.getAgenda().getAgendaGroup( "validate" ).setFocus();
344        session.fireUntilHalt();
345    }
346}