276 lines
7.5 KiB
Python
276 lines
7.5 KiB
Python
import tkinter
|
|
import random
|
|
import sudoku_generator
|
|
|
|
class Sudoku:
|
|
def __init__(self):
|
|
self.t = tkinter.Tk()
|
|
self.t.title("Sudoku")
|
|
self.t.resizable(0,0)
|
|
|
|
self.color_enterbox = "#555"
|
|
self.color_entertext = "#fff"
|
|
self.color_background = "#222"
|
|
self.color_helptext = "#ccc"
|
|
self.color_incorrecttext = "#f00"
|
|
self.color_giventext = "#7f7"
|
|
self.checkerboard_step = 2
|
|
self.color_checkerboard = self.checkerboard(self.color_enterbox)
|
|
|
|
self.font_enterbox = ["Consolas", 16]
|
|
self.font_helptext = ["Consolas", 10]
|
|
self.relief_enterbox = "ridge"
|
|
# flat, groove, raised, ridge, solid, sunken
|
|
self.docheckerboard = True
|
|
|
|
self.allow_wraparound = True
|
|
|
|
self.entry_square = 50
|
|
self.spacer_width = 3
|
|
self.misc_height = 0
|
|
self.window_square = (9 * self.entry_square) + (2 * self.spacer_width)
|
|
|
|
self.helptext = "W,A,S,D to easily move around; E to clear cell; Enter to grade"
|
|
self.create_helptext(self.helptext)
|
|
|
|
self.t.configure(width=self.window_square, height=self.window_square+self.misc_height)
|
|
self.t.configure(bg=self.color_background)
|
|
self.entities_entry = []
|
|
self.entities_stringvar = []
|
|
|
|
self.create_boxes()
|
|
|
|
self.t.bind("<KeyPress>", self.keypress)
|
|
self.keypress_movement = {
|
|
"w":[0, -1],
|
|
"s":[0, 1],
|
|
"a":[-1, 0],
|
|
"d":[1, 0]}
|
|
|
|
self.key_clearcurrent = ["e"]
|
|
self.key_grade = ["\r"]
|
|
|
|
print('Creating puzzle')
|
|
self.entries_solution = sudoku_generator.cgimain()[0]
|
|
for pos in range(len(self.entries_solution)):
|
|
self.entries_solution[pos] += 1
|
|
self.entries_given = self.entries_solution[:]
|
|
for pos in range(len(self.entries_given)):
|
|
if random.randint(0, 100) <= 50:
|
|
self.entries_given[pos] = None
|
|
#self.entries_given = self.entries_solution[1]
|
|
#self.entries_solution = self.entries_solution[0]
|
|
self.entries_current = []
|
|
|
|
self.apply_given()
|
|
|
|
self.cursor_position = [0,0]
|
|
self.select_entry_by_pos(self.cursor_position)
|
|
self.game_win = False
|
|
self.t.mainloop()
|
|
|
|
def keypress(self, event):
|
|
movement = self.keypress_movement.get(event.char, None)
|
|
if movement:
|
|
self.move_cursor(movement)
|
|
return
|
|
|
|
if event.char in self.key_clearcurrent:
|
|
x = self.cursor_position[0]
|
|
y = self.cursor_position[1]
|
|
index = (9 * y) + x
|
|
self.entities_entry[index].delete(0, "end")
|
|
elif event.char in self.key_grade:
|
|
self.grade()
|
|
|
|
def create_helptext(self, helptext):
|
|
helplabel = tkinter.Label(self.t, text=helptext)
|
|
helplabel.configure(font=self.font_helptext,
|
|
fg=self.color_helptext,
|
|
bg=self.color_background,
|
|
justify="left")
|
|
|
|
height = (2.3 * self.font_helptext[1])
|
|
height *= len(helptext.split('\n'))
|
|
height += self.spacer_width
|
|
print('Helptext added %d pixels in height' % height)
|
|
self.misc_height += height
|
|
helplabel.place(x=0, y=self.window_square + self.spacer_width)
|
|
|
|
|
|
def create_boxes(self):
|
|
spacer_y = 0
|
|
for y in range(9):
|
|
if (y > 0) and (y % 3 == 0):
|
|
spacer_y += self.spacer_width
|
|
ypos = (y * self.entry_square) + spacer_y
|
|
|
|
spacer_x = 0
|
|
for x in range(9):
|
|
if (x > 0) and (x % 3 == 0):
|
|
spacer_x += self.spacer_width
|
|
xpos = (x * self.entry_square) + spacer_x
|
|
|
|
enter = tkinter.Entry(self.t)
|
|
stringvar = tkinter.StringVar()
|
|
|
|
enter.stringvar = stringvar
|
|
enter.stringvar.trace("w", lambda name,index,mode, stringvar=stringvar: self.checkinput(stringvar))
|
|
|
|
enter.is_permanent = False
|
|
enter.stringvar.is_permanent = False
|
|
bg = self.color_enterbox
|
|
relief = self.relief_enterbox
|
|
if self.docheckerboard:
|
|
docheckerboard = (str(x+y)[-1] in "13579")
|
|
if docheckerboard:
|
|
bg = self.color_checkerboard
|
|
|
|
enter.configure(justify="c",
|
|
textvariable=enter.stringvar,
|
|
font=self.font_enterbox,
|
|
bg=bg,
|
|
fg=self.color_entertext,
|
|
relief=relief)
|
|
enter.bind("<Button-1>", self.update_position_byclick)
|
|
enter.coordinates = [x, y]
|
|
|
|
self.entities_entry.append(enter)
|
|
self.entities_stringvar.append(enter.stringvar)
|
|
enter.place(x=xpos, y=ypos, width=self.entry_square, height=self.entry_square)
|
|
|
|
def checkerboard(self, hexivalue):
|
|
hexivalue = hexivalue[1:]
|
|
if len(hexivalue) == 3:
|
|
r = hexivalue[0]
|
|
g = hexivalue[1]
|
|
b = hexivalue[2]
|
|
padding = "1"
|
|
if len(hexivalue) == 6:
|
|
r = hexivalue[:2]
|
|
g = hexivalue[2:4]
|
|
b = hexivalue[4:]
|
|
padding = "2"
|
|
|
|
hexiout = "#"
|
|
for colorcomponent in [r,g,b]:
|
|
decivalue = int(colorcomponent, 16)
|
|
if decivalue < self.checkerboard_step:
|
|
decivalue += self.checkerboard_step
|
|
else:
|
|
decivalue -= self.checkerboard_step
|
|
|
|
formatstring = "%0" + padding + "x"
|
|
hexivalue = formatstring % decivalue
|
|
hexiout += hexivalue
|
|
return hexiout
|
|
|
|
def checkinput(self, *bullish):
|
|
stringvar = bullish[0]
|
|
if stringvar.is_permanent:
|
|
index = self.entities_stringvar.index(stringvar)
|
|
stringvar.set(self.entries_solution[index])
|
|
self.entities_entry[index].configure(fg=self.color_giventext)
|
|
stringvalue = stringvar.get()
|
|
try:
|
|
test_for_integer= int(stringvalue)
|
|
test_for_nonzero= 14/test_for_integer
|
|
except:
|
|
stringvar.set("")
|
|
if len(stringvalue) > 1:
|
|
stringvar.set(stringvalue[0])
|
|
|
|
def update_position_byclick(self, event):
|
|
enter = event.widget
|
|
x = enter.coordinates[0]
|
|
y = enter.coordinates[1]
|
|
self.cursor_position = [x,y]
|
|
|
|
def select_entry_by_pos(self, position):
|
|
x = position[0]
|
|
y = position[1]
|
|
index = (9 * y) + x
|
|
self.entities_entry[index].focus_set()
|
|
|
|
def move_cursor(self, direction):
|
|
xdirection = direction[0]
|
|
ydirection = direction[1]
|
|
|
|
xposition = self.cursor_position[0]
|
|
yposition = self.cursor_position[1]
|
|
hasmoved = False
|
|
if (xposition > 0 or xdirection == 1) and (xposition < 8 or xdirection == -1) and (xdirection != 0):
|
|
xposition += xdirection
|
|
hasmoved = True
|
|
if (yposition > 0 or ydirection == 1) and (yposition < 8 or ydirection == -1) and (ydirection != 0):
|
|
yposition += ydirection
|
|
hasmoved = True
|
|
|
|
if self.allow_wraparound and hasmoved is False:
|
|
if xposition == 0 and xdirection == -1:
|
|
xposition = 8
|
|
elif xposition == 8 and xdirection == 1:
|
|
xposition = 0
|
|
|
|
elif yposition == 0 and ydirection == -1:
|
|
yposition = 8
|
|
elif yposition == 8 and ydirection == 1:
|
|
yposition = 0
|
|
|
|
self.cursor_position = [xposition, yposition]
|
|
self.select_entry_by_pos(self.cursor_position)
|
|
#print(self.cursor_position)
|
|
|
|
def generate_puzzle(self):
|
|
return [random.randint(1, 8) for x in range(81)]
|
|
|
|
def reset_colors(self):
|
|
for enterbox in self.entities_entry:
|
|
if not enterbox.is_permanent:
|
|
enterbox.configure(fg=self.color_entertext)
|
|
|
|
def apply_given(self):
|
|
for givenpos in range(len(self.entries_given)):
|
|
given = self.entries_given[givenpos]
|
|
if given:
|
|
self.entities_entry[givenpos].is_permanent = True
|
|
self.entities_stringvar[givenpos].is_permanent = True
|
|
self.checkinput(self.entities_stringvar[givenpos])
|
|
self.entities_entry[givenpos].configure(fg=self.color_giventext)
|
|
|
|
def grade(self):
|
|
self.entries_current = []
|
|
self.reset_colors()
|
|
|
|
self.game_win = True
|
|
self.has_errors = False
|
|
|
|
for enterbox_index in range(len(self.entities_entry)):
|
|
enterbox = self.entities_entry[enterbox_index]
|
|
cell = enterbox.get()
|
|
try:
|
|
cell = int(cell)
|
|
if cell != self.entries_solution[enterbox_index]:
|
|
self.game_win = False
|
|
self.has_errors = True
|
|
enterbox.configure(fg=self.color_incorrecttext)
|
|
except:
|
|
self.game_win = False
|
|
pass
|
|
if cell == '':
|
|
cell = 0
|
|
self.entries_current.append(cell)
|
|
|
|
if self.game_win:
|
|
print("WOOOOO")
|
|
|
|
elif not self.has_errors:
|
|
print('Doing well')
|
|
else:
|
|
print('Some mistakes')
|
|
|
|
#print(self.entries_solution)
|
|
#print(self.entries_current)
|
|
|
|
|
|
soduku = Sudoku()
|