不可能使填字游戏检查适用于所有符号



如果我输入一个字符,则不会输出一切正常的消息(应该是这样(。但如果我输入了两个正确的字符,那么检查会显示一切正常。尽管只有当所有字符都填写正确时才能使用。我是一个初学者,我不知道如何修复它。代码中有很多多余的内容,但对我来说,检查有效是唯一重要的。整个程序代码如下所示。

import random, re, time, string
from copy import copy as duplicate

class Crossword(object):
def __init__(self, cols, rows, empty = '-', maxloops = 2000, available_words=[]):
self.cols = cols
self.rows = rows
self.empty = empty
self.maxloops = maxloops
self.available_words = available_words
self.randomize_word_list()
self.current_word_list = []
self.debug = 0
self.clear_grid()

def clear_grid(self):
self.grid = []
for i in range(self.rows):
ea_row = []
for j in range(self.cols):
ea_row.append(self.empty)
self.grid.append(ea_row)

def randomize_word_list(self):
temp_list = []
for word in self.available_words:
if isinstance(word, Word):
temp_list.append(Word(word.word, word.clue))
else:
temp_list.append(Word(word[0], word[1]))
random.shuffle(temp_list)
temp_list.sort(key=lambda i: len(i.word), reverse=True)
self.available_words = temp_list

def compute_crossword(self, time_permitted = 1.00, spins=2):
time_permitted = float(time_permitted)

count = 0
copy = Crossword(self.cols, self.rows, self.empty, self.maxloops, self.available_words)

start_full = float(time.time())
while (float(time.time()) - start_full) < time_permitted or count == 0:
self.debug += 1
copy.current_word_list = []
copy.clear_grid()
copy.randomize_word_list()
x = 0
while x < spins:
for word in copy.available_words:
if word not in copy.current_word_list:
copy.fit_and_add(word)
x += 1

if len(copy.current_word_list) > len(self.current_word_list):
self.current_word_list = copy.current_word_list
self.grid = copy.grid
count += 1
return

def suggest_coord(self, word):
count = 0
coordlist = []
glc = -1
for given_letter in word.word:
glc += 1
rowc = 0
for row in self.grid:
rowc += 1
colc = 0
for cell in row:
colc += 1
if given_letter == cell:
try:
if rowc - glc > 0:
if ((rowc - glc) + word.length) <= self.rows:
coordlist.append([colc, rowc - glc, 1, colc + (rowc - glc), 0])
except: pass
try:
if colc - glc > 0:
if ((colc - glc) + word.length) <= self.cols:
coordlist.append([colc - glc, rowc, 0, rowc + (colc - glc), 0])
except: pass

new_coordlist = self.sort_coordlist(coordlist, word)
return new_coordlist

def sort_coordlist(self, coordlist, word):
new_coordlist = []
for coord in coordlist:
col, row, vertical = coord[0], coord[1], coord[2]
coord[4] = self.check_fit_score(col, row, vertical, word)
if coord[4]:
new_coordlist.append(coord)
random.shuffle(new_coordlist)
new_coordlist.sort(key=lambda i: i[4], reverse=True)
return new_coordlist

def fit_and_add(self, word):
fit = False
count = 0
coordlist = self.suggest_coord(word)

while not fit and count < self.maxloops:

if len(self.current_word_list) == 0:
vertical, col, row = random.randrange(0, 2), 1, 1

if self.check_fit_score(col, row, vertical, word):
fit = True
self.set_word(col, row, vertical, word, force=True)
else:
try:
col, row, vertical = coordlist[count][0], coordlist[count][1], coordlist[count][2]
except IndexError: return

if coordlist[count][4]:
fit = True
self.set_word(col, row, vertical, word, force=True)

count += 1
return

def check_fit_score(self, col, row, vertical, word):

if col < 1 or row < 1:
return 0

count, score = 1, 1
for letter in word.word:
try:
active_cell = self.get_cell(col, row)
except IndexError:
return 0

if active_cell == self.empty or active_cell == letter:
pass
else:
return 0

if active_cell == letter:
score += 1

if vertical:
if active_cell != letter:
if not self.check_if_cell_clear(col+1, row):
return 0

if not self.check_if_cell_clear(col-1, row):
return 0

if count == 1:
if not self.check_if_cell_clear(col, row-1):
return 0

if count == len(word.word):
if not self.check_if_cell_clear(col, row+1):
return 0
else:
if active_cell != letter:
if not self.check_if_cell_clear(col, row-1):
return 0

if not self.check_if_cell_clear(col, row+1):
return 0

if count == 1:
if not self.check_if_cell_clear(col-1, row):
return 0

if count == len(word.word):
if not self.check_if_cell_clear(col+1, row):
return 0

if vertical:
row += 1
else:
col += 1

count += 1

return score

def set_word(self, col, row, vertical, word, force=False):
if force:
word.col = col
word.row = row
word.vertical = vertical
self.current_word_list.append(word)

for letter in word.word:
self.set_cell(col, row, letter)
if vertical:
row += 1
else:
col += 1
return

def set_cell(self, col, row, value):
self.grid[row-1][col-1] = value

def get_cell(self, col, row):
return self.grid[row-1][col-1]

def check_if_cell_clear(self, col, row):
try:
cell = self.get_cell(col, row)
if cell == self.empty:
return True
except IndexError:
pass
return False

def solution(self):
outStr = ""
for r in range(self.rows):
for c in self.grid[r]:
outStr += '%s ' % c
outStr += 'n'
return outStr

def word_find(self):
outStr = ""
for r in range(self.rows):
for c in self.grid[r]:
if c == self.empty:
outStr += '%s ' % string.ascii_lowercase[random.randint(0,len(string.ascii_lowercase)-1)]
else:
outStr += '%s ' % c
outStr += 'n'
return outStr

def order_number_words(self):
self.current_word_list.sort(key=lambda i: (i.col + i.row))
count, icount = 1, 1
for word in self.current_word_list:
word.number = count
if icount < len(self.current_word_list):
if word.col == self.current_word_list[icount].col and word.row == self.current_word_list[icount].row:
pass
else:
count += 1
icount += 1

def display(self, order=True):
outStr = ""
if order:
self.order_number_words()

copy = self

for word in self.current_word_list:
copy.set_cell(word.col, word.row, word.number)

for r in range(copy.rows):
for c in copy.grid[r]:
outStr += '%s ' % c
outStr += 'n'

outStr = re.sub(r'[a-z]', ' ', outStr)
return outStr

def word_bank(self):
outStr = ''
temp_list = duplicate(self.current_word_list)
random.shuffle(temp_list)
for word in temp_list:
outStr += '%sn' % word.word
return outStr

def legend(self):
outStr = ''
for word in self.current_word_list:
outStr += '%d. (%d,%d) %s: %sn' % (word.number, word.col, word.row, word.down_across(), word.clue )
return outStr

class Word(object):
def __init__(self, word=None, clue=None):
self.word = re.sub(r's', '', word.lower())
self.clue = clue
self.length = len(self.word)
self.row = None
self.col = None
self.vertical = None
self.number = None

def down_across(self):
if self.vertical:
return 'down'
else:
return 'across'

word_list = ['saffron', 'The dried, orange yellow plant used to as dye and as a cooking spice.'], 
['pumpernickel', 'Dark, sour bread made from coarse ground rye.'], 
['leaven', 'An agent, such as yeast, that cause batter or dough to rise..'], 
['coda', 'Musical conclusion of a movement or composition.'], 
['paladin', 'A heroic champion or paragon of chivalry.'], 
['syncopation', 'Shifting the emphasis of a beat to the normally weak beat.'], 
['albatross', 'A large bird of the ocean having a hooked beek and long, narrow wings.'], 
['harp', 'Musical instrument with 46 or more open strings played by plucking.'], 
['piston', 'A solid cylinder or disk that fits snugly in a larger cylinder and moves under pressure as in an engine.'], 
['caramel', 'A smooth chery candy made from suger, butter, cream or milk with flavoring.'], 
['coral', 'A rock-like deposit of organism skeletons that make up reefs.'], 
['dawn', 'The time of each morning at which daylight begins.'], 
['pitch', 'A resin derived from the sap of various pine trees.'], 
['fjord', 'A long, narrow, deep inlet of the sea between steep slopes.'], 
['lip', 'Either of two fleshy folds surrounding the mouth.'], 
['lime', 'The egg-shaped citrus fruit having a green coloring and acidic juice.'], 
['mist', 'A mass of fine water droplets in the air near or in contact with the ground.'], 
['plague', 'A widespread affliction or calamity.'], 
['yarn', 'A strand of twisted threads or a long elaborate narrative.'], 
['snicker', 'A snide, slightly stifled laugh.']

a = Crossword(17, 17, '-', 5000, word_list)
a.compute_crossword(2)
print (a.word_bank())
print (a.solution())
print (a.word_find())
print (a.display())
print (a.legend())
print (len(a.current_word_list), 'из', len(word_list))
print (a.debug)

###############################################################################

from tkinter import *
from tkinter.messagebox import showwarning, showinfo

class CellEntry(Entry):

def __init__(self, master, **kw):
self._variable = StringVar()
self._variable.trace("w", self._callback)
super().__init__(master, textvariable=self._variable, **kw)

def _callback(self, *args):
value = self._variable.get()
self._variable.set('' if not value else value[-1])

class App:
def __init__(self, crossword):
self.root = Tk()
self.root.title("Crossword")
self._crossword = crossword
self._grid = Frame(self.root)
self._grid.pack(padx=30, pady=30)
self._cells = {}
for col in range(1, crossword.cols + 1):
for row in range(crossword.rows):
c = crossword.get_cell(col, row)
if c != '-':
entry = CellEntry(self._grid, width=3, justify=CENTER)
entry.grid(row=row, column=col)
self._cells[(col, row)] = entry

for w in crossword.current_word_list:
row, col = w.row, w.col
if w.down_across() == 'down':
row -= 1
else:
col -= 1
Label(self._grid, text=str(w.number)).grid(column=col, row=row)
Button(self.root, text='Questions', command=self.questions).pack(pady=10)
Button(self.root, text='Check', command=self.check).pack(pady=10)

def check(self):
for (col, row), entry in self._cells.items():
if entry.get() == self._crossword.get_cell(col, row):
showinfo('OK!!!')
return

'''for (col, row), entry in self._cells.items():
if entry.get() != self._crossword.get_cell(col, row):
showwarning('...', 'Something went wrong')
return
else:
showinfo('...', 'Ok')'''




def questions(self):
super().__init__()
self.label = Label(text=a.legend(),justify=LEFT,font=("Arial Bold", 9))
self.label.pack(padx=20, pady=20)

def run(self):
self.root.mainloop()

App(a).run()

您的代码中可能有许多区域存在意外行为,可能需要在其他地方进行重构,但为了解决您引用的特定问题:

如果我输入一个字符,则不会输出一切正常的消息(应该是这样(。但如果我输入了两个正确的字符,那么检查就会显示一切正常

不太准确。事实上,测试填字游戏中任何单词的第一个字母不会触发该事件。";p〃;在";p u m p e r n i c k e l";例如相反,单词中的任何其他字母都会触发您的警报。";m〃;在";p u m p e r n i c k e l";例如

问题在于您的Crossword.display功能

def display(self, order=True):
outStr = ""
if order:
self.order_number_words()
copy = self
for word in self.current_word_list:
copy.set_cell(word.col, word.row, word.number)
for r in range(copy.rows):
for c in copy.grid[r]:
outStr += '%s ' % c
outStr += 'n'
outStr = re.sub(r'[a-z]', ' ', outStr)
return outStr

特别是这些线路:

copy = self
for word in self.current_word_list:
copy.set_cell(word.col, word.row, word.number)

您试图通过运行copy = self来创建副本(不同的对象是self的副本(,但是,您所做的是创建self的别名。

本质上,copyself指的是内存中的同一对象。因此,对copy进行的修改也对self进行。

当您在copy上调用set_cell时,将填字游戏中每个单词的第一个字母用self中标签的编号覆盖

例如";p u m p e r n i c k e l";变成";1μm p e r n i c k e l";

由于您的数据中引入了此错误,当您进行比较时,您无法正确评估值是否正确,因为没有正确的值进行比较。这就是为什么您的警报在这些情况下不会出现的原因。

您可以使用copy.depopy创建self的不同副本。

def display(self, order=True):
outStr = ""
if order:
self.order_number_words()
copy = deepcopy(self)
for word in self.current_word_list:
copy.set_cell(word.col, word.row, word.number)
for r in range(copy.rows):
for c in copy.grid[r]:
outStr += '%s ' % c
outStr += 'n'
outStr = re.sub(r'[a-z]', ' ', outStr)
return outStr

您需要更新您的进口声明以包括deepcopy:

from copy import copy as duplicate, deepcopy

一般说明:有一种哲学被称为"单一责任原则",它本质上建议每个职能部门都只负责一项任务。虽然存在许多";正确的";设计程序的方法,在处理这个问题时,牢记这一原则可能会有所帮助。

最新更新