-1

如果我输入一个字符,则不会输出一切正常的消息(应该如此)。但是如果我输入了 2 个正确的字符,那么检查就会显示一切正常。尽管只有在所有字符都填写并正确时才应使用它。我是初学者,我不知道如何解决它。代码中有很多多余的部分,但检查工作对我来说很重要。整个程序代码如下所示。

    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 += '%s\n' % word.word
            return outStr
    
        def legend(self):
            outStr = ''
            for word in self.current_word_list:
                outStr += '%d. (%d,%d) %s: %s\n' % (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()
4

1 回答 1

1

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

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

不是很准确。实际上,测试填字游戏中任何单词的任何首字母都不会触发事件。例如,“pumpernicke l”中的“p”。相反,单词中其他任何地方的单个字母都会触发您的警报。例如“pumpernicke l”中的“m”。

问题在于你的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)

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

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

当你打电话set_cellcopy,你会用它的标签编号覆盖填字游戏中每个单词的第一个字母self

例如“pumpernicke l”变成“1 umpernicke l”

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

您可以使用copy.deepcopy创建不同的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

一般说明:有一种称为单一职责原则的哲学,它本质上建议每个功能都处理单个任务并且单独执行该任务。虽然有许多“正确”的方法来设计程序,但在解决这个问题时牢记这一原则可能会有所帮助。

于 2021-04-19T00:59:48.243 回答