简体   繁体   English

修改递归 function 中的集合?

[英]Modifying a set within a recursive function?

I'm trying to write a program to check if a particular word can be made using a given "boggle board".我正在尝试编写一个程序来检查是否可以使用给定的“boggle board”来制作特定的单词。 There full details of the challenge are here: Boggle Word Checker .挑战的完整细节在这里: Boggle Word Checker

Basically, the program is supposed find the first letter of a word, on the board, and then check if any of the adjacent letters to it on the board match the next letter of the word.基本上,该程序应该在板上找到单词的第一个字母,然后检查板上的任何相邻字母是否与该单词的下一个字母匹配。

This is what I've got so far (not pretty I know):这是我到目前为止所得到的(我不太清楚):

def pos(board, x, y):
    # function to get value from a grid, but return None if not on grid,to
    # prevent wraparound
    if x >= 0 and y >= 0 and x < len(board[0]) and y < len(board):
        return board[y][x]
    else:
        return None

def surrounds(board, x, y):
    # make a dictionary which to store the positions and values of adjacent
    # letters on board, given a single postision as input
    return {
        (x-1,y-1) : pos(board,x-1,y-1), #aboveLeft
        (x,y-1) : pos(board,x,y-1),     #aboveMiddle etc...
        (x+1,y-1) : pos(board,x+1,y-1),
        (x-1,y) : pos(board,x-1,y),
        (x+1,y) : pos(board,x+1,y),
        (x-1,y+1) : pos(board,x-1,y+1),
        (x,y+1) : pos(board,x,y+1),
        (x+1,y+1) : pos(board,x+1,y+1)
    }

def find_word(board, word):
    # initialise
    listOfCoords = []

    # find all occurrences of the first letter, and store their board
    # position in a list
    for i in range(len(board)):
        for j in range(len(board[0])):
            if board[i][j] == word[0]:
                listOfCoords.append([j,i])

    print('list of ' + word[0] + 's on board:')
    print(listOfCoords)
    print()

    # if word is only 1 letter long then we can return True at this point
    if listOfCoords and len(word) == 1:
        return True

    # otherwise we move on to look for the second letter
    return findnext(board,word,listOfCoords)

def findnext(board, word, mylist):
    for x, y in mylist:
        print("Current coords: {},{}\n".format(x,y))
        surroundings = surrounds(board,x,y)

        listFounds = []

        for k, v in surroundings.items():

            if v == word[1]:
                print("{} found at {}".format(v,k))
                print()

                if len(word) == 2:
                    print()
                    return True

                listFounds.append(k)

                if findnext(board, word[1:], listFounds) == True:
                    return True
    return False

testBoard = [
      ["E","A","R","A"],
      ["N","L","E","C"],
      ["I","A","I","S"],
      ["B","Y","O","R"]
    ]

print(find_word(testBoard, "CEREAL"))

However, I've encountered a problem, as the challenge specifies that no position on the board can be used more than once.但是,我遇到了一个问题,因为挑战指定板上没有 position 可以多次使用。 Therefore, in the above example, the program should return False for "CEREAL", but mine returns True.因此,在上面的示例中,程序应该为“CEREAL”返回 False,但我的返回 True。

I was thinking a way around this could be to use a set, which adds the coordinates to the set once a next letter is found.我在想解决这个问题的方法是使用一个集合,一旦找到下一个字母,它就会将坐标添加到集合中。 However I'm a bit lost as to where I would need to create the empty set, and how it would work with all the loops and recursion going on...但是,对于需要在哪里创建空集,以及它将如何与所有循环和递归一起工作,我有点迷茫......

For example, let's say we were looking for "CEREAL" on a different board, which has 2 Es adjacent to C.例如,假设我们在另一块板上寻找“CEREAL”,它有 2 个 E 与 C 相邻。 let's say the first path only leads to CER and the other leads to CEREAL.假设第一条路径只通向 CER,另一条通向 CEREAL。 If we go down the CER path first, the positions for it would be added to the set, and I would somehow need to remove them again before it goes down the CEREAL path.如果我们首先沿着 CER 路径 go,它的位置将被添加到集合中,并且我需要在它沿着 CEREAL 路径之前再次删除它们。

I'm struggling to think how to implement this in my program.我正在努力思考如何在我的程序中实现这一点。

You need to have an array of booleans the size of the board all set to False.您需要将一个布尔值数组设置为棋盘大小,全部设置为 False。 When you use a letter and call your function recursively, set the cell to True for the used letter.当您使用字母并递归调用 function 时,请将所用字母的单元格设置为 True。 When returning from the recursive call, set the cell value back to False.从递归调用返回时,将单元格值设置回 False。 You should only use letters with False values indicating that they have not been previously used.您应该只使用带有 False 值的字母,表明它们以前没有被使用过。

Alternatively, you can replace the used letter by None after keeping the letter in a temporary variable then do the recursive call.或者,您可以在将字母保存在临时变量中之后用 None 替换使用的字母,然后进行递归调用。 Upon the return from the recursive call put back the value of the cell from the temp variable.从递归调用返回后,从 temp 变量中放回单元格的值。

Steps:脚步:

  1. Find the 1st character match against the board找到与棋盘的第一个字符匹配
  2. Once a match is found, do a DFS with backtracking till you completely match the word or exhaust the search due to mismatch.找到匹配项后,使用回溯执行DFS ,直到您完全匹配该单词或由于不匹配而耗尽搜索。
  3. If complete match is not found in above step, continue scanning the board.如果在上述步骤中没有找到完全匹配,则继续扫描板。 (ie go to step 1) for the next character that matches on the board. (即 go 到第 1 步)用于匹配板上的下一个字符。
  4. If a match is found in step 3, report success.如果在步骤 3 中找到匹配项,则报告成功。

This solution works for NxM board as well.该解决方案也适用于NxM板。

def is_within_bounds(row, col, row_dim, col_dim):
    return row >= 0 and row < row_dim and col >= 0 and col < col_dim


def get_neighbors(row, col, row_dim, col_dim):
    for r_offset in (-1, 0, 1):
        for c_offset in (-1, 0, 1):
            if r_offset == 0 and c_offset == 0:
                continue
            r_new = row + r_offset
            c_new = col + c_offset
            if is_within_bounds(r_new, c_new, row_dim, col_dim):
                yield (r_new, c_new)


def is_word_found(board, word, row, col, visited):
    if word[0] != board[row][col]:
        return False
    if len(word) == 1:
        return True
    for neighbor in get_neighbors(row, col, len(board), len(board[0])):
        if neighbor not in visited:
            visited.add(neighbor)
            if is_word_found(board, word[1:], neighbor[0], neighbor[1], visited):
                return True
            visited.remove(neighbor)
    return False


def find_word(board, word):
    for row in range(len(board)):
        for col in range(len(board[0])):
            if word[0] != board[row][col]:
                continue
            if is_word_found(board, word, row, col, set()):
                return True
    return False

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM