def InitTable(size, value):
return [[value for i in range(size)] for j in range(size)]
class LightBoard:
def __init__(self, size, status=""):
self.clickBoard = InitTable(size, -1)
self.lightBoard = InitTable(size, 0)
self.toCheck = []
for i in range(size):
for j in range(size):
self.PushToCheck((i,j))
for pos, value in enumerate(status):
if value == "1":
self.lightBoard[pos/size][pos%size] = 1
self.size = size
def PopToCheck(self):
if len(self.toCheck) > 0:
pos = self.toCheck[-1]
del self.toCheck[-1]
else:
pos = None
return pos
def PushToCheck(self, pos):
self.toCheck.append(pos)
def ConnectedLight(self, pos):
x, y = pos
yield pos
if x - 1 >= 0: yield x-1,y
if x + 1 <self.size: yield x+1,y
if y -1 >= 0: yield x, y-1
if y+1 < self.size: yield x, y+1
def NotCheckLight(self, pos):
return [(x,y) for x, y in self.ConnectedLight(pos) if self.clickBoard[x][y] == -1]
def SetCheck(self, pos, value):
x, y = pos
self.clickBoard[x][y] = value
for x, y in self.ConnectedLight(pos):
self.lightBoard[x][y] = 1 - self.lightBoard[x][y]
def Pass(self, pos):
x, y = pos
self.clickBoard[x][y] = 0
def CancelPass(self, pos):
x, y = pos
self.clickBoard[x][y] = -1
def CheckError(self, pos):
for p in self.ConnectedLight(pos):
x, y = p
if self.lightBoard[x][y] == 0 and len(self.NotCheckLight(p)) == 0:
return True
return False
def Solve(board):
clickpos = board.PopToCheck()
if clickpos == None:
return board.clickBoard
pos = board.NotCheckLight(clickpos)[0]
board.SetCheck(pos, 1)
if not board.CheckError( pos ):
r = Solve(board)
if r: return r
board.SetCheck(pos, -1)
board.Pass(pos)
if not board.CheckError( pos ):
r = Solve(board)
if r: return r
board.CancelPass(pos)
board.PushToCheck(clickpos)
return False
from Tkinter import *
class LightButton(Button):
def __init__(self, parent, pos, board):
Button.__init__(self, parent, width=2)
self.board = board
self.status = 0
self.x, self.y = pos
self.SetColor()
self.bind("<Button-1>",self.onClick)
self.bind("<Button-3>",self.onRightClick)
def SetColor(self):
if self.status == 0:
self.config(bg="#cccccc")
if self.status == 1:
self.config(bg="#ffcccc")
def onClick(self,event):
toclick = [(0, 0), (-1,0), (1,0), (0, 1), (0, -1)]
self.config(text="")
for x,y in toclick:
try:
b = self.board[(self.x-x, self.y-y)]
b.status = 1 - b.status
b.SetColor()
except:
pass
def onRightClick(self, event):
self.status = 1 - self.status
self.SetColor()
if __name__ == "__main__":
from tkSimpleDialog import askinteger
def SolveIt():
boardStatus = ["0"] * Size * Size
for pos, light in buttons.items():
if light.status == 1:
boardStatus[pos[1]*Size+pos[0]] = "1"
clickBoard = Solve(LightBoard(Size, "".join(boardStatus)))
for x, r in enumerate(clickBoard):
for y, c in enumerate(r):
if c == 1:
buttons[(y,x)].config(text="*")
def Clear():
for button in buttons.values():
button.status = 0
button.SetColor()
root = Tk()
root.title("Light Solver")
f = Frame(root)
f.pack(side = TOP)
Button(f, text="Solve", command=SolveIt).pack(side=LEFT)
Button(f, text="Clear", command=Clear).pack(side=LEFT)
buttons = {}
Size = askinteger("Light Solver", "Please Input Board Size", initialvalue=5)
for y in range(Size):
f = Frame(root)
f.pack(side = LEFT)
for x in range(Size):
pos = x, y
b = LightButton(f, pos, buttons)
b.pack()
buttons[pos] = b
mainloop()
# 点灯游戏及其求解的方法,
#点灯游戏的游戏规则:
#(1)有个N行N列的灯板,当你开关其中一盏灯;
#(2)它和上下左右的灯的状态全部反转,目标是将全部的灯点亮;
#(3)这个程序采用递归回溯法对任意状态的灯板进行求解;
#(4)游戏中左点灯将按照游戏规则动作,右点灯只对一盏灯进行操作,以便您测试任何状态的自动求解。