def OnInit(self): # Load the Sudoku solving programs #clips.Load("sudoku.clp") #clips.Load("solve.clp") self.engine = MyClipsEngine() self.interpreter = MyClipsInterpreter(self.engine) self.solvedCells = SudokuSolvedCells() self.solvedCells.install(self.engine.eventsManager) self.rulesUsed = SudokuTecniqueUsed() self.rulesUsed.install(self.engine.eventsManager) self.interpreter.evaluate('(load "../res/sudoku/sudoku.clp")') self.interpreter.evaluate('(load "../res/sudoku/solve.clp")') self.interpreter.evaluate('(load "../res/sudoku/output-frills.clp")') #self.interpreter.evaluate('(watch rules)') # Load the GUI from SudokuDemo.xrc resource = wx.xrc.XmlResource('SudokuDemo.xrc') self.frame = resource.LoadFrame(None, 'SudokuDemoFrame') # Store references to widgets that are being used at run-time. self.openfile = wx.xrc.XRCCTRL(self.frame, 'OpenFile') self.clear = wx.xrc.XRCCTRL(self.frame, 'Clear') self.reset = wx.xrc.XRCCTRL(self.frame, 'Reset') self.solve = wx.xrc.XRCCTRL(self.frame, 'Solve') self.techniques = wx.xrc.XRCCTRL(self.frame, 'Techniques') # Bind button events to handler functions self.openfile.Bind(wx.EVT_BUTTON, self.on_openfile) self.clear.Bind(wx.EVT_BUTTON, self.on_clear) self.reset.Bind(wx.EVT_BUTTON, self.on_reset) self.solve.Bind(wx.EVT_BUTTON, self.on_solve) self.techniques.Bind(wx.EVT_BUTTON, self.on_techniques) # Set max length in each of the wx.TextCtrls to 1. This can, # sadly, NOT be done using XRCEd. for g in range(1,10): for c in range(1,10): cell = wx.xrc.XRCCTRL(self.frame, '%d%d' % (g, c)) cell.SetMaxLength(1) self.solved = False self.resetvalues = {} # Bind the close event to the exit function and show the GUI self.frame.Bind(wx.EVT_CLOSE, self.exit) self.frame.Show(True) return True
class SudokuDemo(wx.App): def OnInit(self): # Load the Sudoku solving programs #clips.Load("sudoku.clp") #clips.Load("solve.clp") self.engine = MyClipsEngine() self.interpreter = MyClipsInterpreter(self.engine) self.solvedCells = SudokuSolvedCells() self.solvedCells.install(self.engine.eventsManager) self.rulesUsed = SudokuTecniqueUsed() self.rulesUsed.install(self.engine.eventsManager) self.interpreter.evaluate('(load "../res/sudoku/sudoku.clp")') self.interpreter.evaluate('(load "../res/sudoku/solve.clp")') self.interpreter.evaluate('(load "../res/sudoku/output-frills.clp")') #self.interpreter.evaluate('(watch rules)') # Load the GUI from SudokuDemo.xrc resource = wx.xrc.XmlResource('SudokuDemo.xrc') self.frame = resource.LoadFrame(None, 'SudokuDemoFrame') # Store references to widgets that are being used at run-time. self.openfile = wx.xrc.XRCCTRL(self.frame, 'OpenFile') self.clear = wx.xrc.XRCCTRL(self.frame, 'Clear') self.reset = wx.xrc.XRCCTRL(self.frame, 'Reset') self.solve = wx.xrc.XRCCTRL(self.frame, 'Solve') self.techniques = wx.xrc.XRCCTRL(self.frame, 'Techniques') # Bind button events to handler functions self.openfile.Bind(wx.EVT_BUTTON, self.on_openfile) self.clear.Bind(wx.EVT_BUTTON, self.on_clear) self.reset.Bind(wx.EVT_BUTTON, self.on_reset) self.solve.Bind(wx.EVT_BUTTON, self.on_solve) self.techniques.Bind(wx.EVT_BUTTON, self.on_techniques) # Set max length in each of the wx.TextCtrls to 1. This can, # sadly, NOT be done using XRCEd. for g in range(1,10): for c in range(1,10): cell = wx.xrc.XRCCTRL(self.frame, '%d%d' % (g, c)) cell.SetMaxLength(1) self.solved = False self.resetvalues = {} # Bind the close event to the exit function and show the GUI self.frame.Bind(wx.EVT_CLOSE, self.exit) self.frame.Show(True) return True def on_openfile(self, event): """ Loads a Sudoku puzzle from disk. """ # Show a File Open Dialog dlg = wx.FileDialog(self.frame, message = "Open a Sudoku puzzle", style = wx.OPEN) if dlg.ShowModal() == wx.ID_OK: self.solved = False self.solve.Enable(True) self.techniques.Enable(False) path = dlg.GetPath() puzzle = open(path) positions = { 1 : [11, 12, 13, 21, 22, 23, 31, 32, 33], 2 : [14, 15, 16, 24, 25, 26, 34, 35, 36], 3 : [17, 18, 19, 27, 28, 29, 37, 38, 39], 4 : [41, 42, 43, 51, 52, 53, 61, 62, 63], 5 : [44, 45, 46, 54, 55, 56, 64, 65, 66], 6 : [47, 48, 49, 57, 58, 59, 67, 68, 69], 7 : [71, 72, 73, 81, 82, 83, 91, 92, 93], 8 : [74, 75, 76, 84, 85, 86, 94, 95, 96], 9 : [77, 78, 79, 87, 88, 89, 97, 98, 99] } lines = 0 for line in puzzle.readlines(): lines += 1 line = line.strip() if len(line) != 9: raise Exception("Malformed puzzle!") cells = positions[lines] for id, value in zip(cells, line): cell = wx.xrc.XRCCTRL(self.frame, '%d' % (id)) if value in ["1", "2", "3", "4", "5", "6", "7", "8", "9"]: cell.SetValue(str(value)) else: cell.SetValue("") cell.SetSize((20,20)) if lines != 9: raise Exception("Malformed puzzle!") puzzle.close() def on_clear(self, event): """ Clears the Sudoku grid. """ self.solved = False self.solve.Enable(True) self.techniques.Enable(False) for g in range(1,10): for c in range(1,10): cell = wx.xrc.XRCCTRL(self.frame, '%d%d' % (g, c)) cell.SetValue("") cell.SetSize((20,20)) def on_reset(self, event): """ Resets the Sudoku grid to the last puzzle solved. """ self.solved = False self.solve.Enable(True) self.techniques.Enable(False) for g in range(1,10): for r in range(3): for c in range(3): cell = wx.xrc.XRCCTRL(self.frame, '%d%d' % (g, (r* 3)+ c+ 1)) try: cell.SetValue(self.resetvalues[(g,r,c)]) except: cell.SetValue("") cell.SetSize((20,20)) def on_solve(self, event): """ Solves the Sudoku puzzle and updates the grid with the solution. """ #clips.Reset() #clips.Assert("(phase expand-any)") #clips.Assert("(size 3)") #self.engine.reset() #self.interpreter.evaluate('(assert (phase expand-any))') #self.interpreter.evaluate('(assert (size 3))') # Remember the initial starting values # of the puzzle for the reset command. grid_rule = ''' (defrule grid-values ?f <- (phase grid-values) => (retract ?f) (assert (phase expand-any)) (assert (size 3)) ''' self.resetvalues = {} for i in range(9): rowgroup = i / 3 colgroup = i % 3 for r in range(3): for c in range(3): cell = wx.xrc.XRCCTRL(self.frame, '%d%d' % (i+ 1, (r* 3)+ c+ 1)) self.resetvalues[(i+ 1,r,c)] = cell.GetValue() assertStr = "(possible (row %d) (column %d) (group %d) (id %d) " % \ ((r + (rowgroup * 3) + 1), (c + (colgroup * 3) + 1), (i + 1), ((i * 9) + (r * 3) + c + 1)) if self.resetvalues[(i+ 1,r,c)] == "": assertStr = assertStr + "(value any))" else: assertStr = assertStr + "(value " + self.resetvalues[(i+ 1, r, c)] + "))" #clips.Assert(str(assertStr)) #self.interpreter.evaluate('(assert %s)'%str(assertStr)) grid_rule += "(assert %s)\n"%str(assertStr) grid_rule += ")" #print grid_rule self.interpreter.evaluate(grid_rule) self.engine.reset() self.solved = True self.reset.Enable(True) self.solve.Enable(False) self.techniques.Enable(True) # Solve the puzzle #clips.Run() self.engine.run() #ff = self.engine.facts #for f in ff: # print f #print self.solvedCells.grid for i in range(9): rowgroup = i / 3 colgroup = i % 3 for r in range(3): for c in range(3): cell = wx.xrc.XRCCTRL(self.frame, '%d%d' % (i+ 1, (r* 3)+ c+ 1)) if cell.GetValue() == "": # Any cells that have not been assigned a value # are given a '?' for their content cell.SetValue("?") value = self.solvedCells.getValueAtCell(r + (rowgroup * 3) + 1, c + (colgroup * 3) + 1) cell.SetValue(str(value)) # Retrieve the solution from CLIPS. # for i in range(9): # rowgroup = i / 3 # colgroup = i % 3 # for r in range(3): # for c in range(3): # cell = wx.xrc.XRCCTRL(self.frame, '%d%d' % (i+ 1, (r* 3)+ c+ 1)) # if cell.GetValue() == "": # # Any cells that have not been assigned a value # # are given a '?' for their content # cell.SetValue("?") # # evalStr = "(find-all-facts ((?f possible)) (and (eq ?f:row %d) (eq ?f:column %d)))" % \ # ((r + (rowgroup * 3) + 1), # (c + (colgroup * 3) + 1)) # # pv = clips.Eval(evalStr) # if len(pv) == 1: # fv = pv[0] # cell.SetValue(str(fv.Slots["value"])) def on_techniques(self, event): """ Opens a wx.Dialog that displays which solution techniques was used to solve the current puzzle. """ # evalStr = "(find-all-facts ((?f technique)) TRUE)"; # techniques = clips.Eval(evalStr) # # message = "" # tNum = len(techniques) # for i in range(1, tNum+ 1): # evalStr = "(find-fact ((?f technique-employed)) (eq ?f:priority %d))" % (i) # pv = clips.Eval(evalStr) # # if len(pv) > 0: # fv = pv[0] # # message = "%s\n%s. %s" % (message, fv.Slots["priority"], fv.Slots["reason"]) #print self.rulesUsed.rules message = "\n".join(self.rulesUsed.rules) dlg = wx.MessageDialog(self.frame, message, "Solution Techniques", wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() def exit(self, event): """ Destroys the GUI and exits the application. """ self.frame.Destroy() sys.exit(0)