Home > Blockchain >  get all words combinations and path from letters arry
get all words combinations and path from letters arry

Time:06-13

I create a boogle game, and I need to build a function that receives in input: the letter board (list of lists), the list of legal words and an integer n.

The function must return all n-length tracks of valid words. For example n = 3 then the function must return all the paths on the three-length board which are actually valid words.

I wrote a code that returns in a particular example one route out of three routes that must be returned.

Input:

board1 = [['Q', 'O', 'Q', 'Q'],
                 ['D', 'O', 'G', 'Q'],
                 ['Q', 'O', 'Q', 'Q'],
                 ['Q', 'Q', 'Q', 'Q']]
word_dict = {'DOG': True}
n = 3
board = Board(board1)
length_n_paths(3, board, word_dict)

My Output:

[((1, 0), (1, 1), (1, 2))]

Wanted Output:

[[(1, 0), (0, 1), (1, 2)], [(1, 0), (1, 1), (1, 2)], [(1, 0), (2, 1), (1, 2)]]

I used a combination, first I found all the possible combinations of letters of length n, then I went through a coordinate coordinate and checked if each coordinate is in a valid position according to the coordinate in front of it, and then I checked if the word coming out of the letter combination is a word from the word list. If so - I will return its path in a list with the other legal words paths.

my code:

direct_lst=['Up','Down','Right','Left','Up_right','Up_left','Down_right','Down_left']

class Board:
    def __init__(self, board):
        self.board = board


    def get_board_coordinate(self):

        cord_lst = []
        row = len(self.board)
        col = len(self.board[0])
        for i in range(row):
            for j in range(col):
                cord_lst.append((i, j))
        return cord_lst

    def possible_directions(self, coordinate, next_coordinate):




        y, x = coordinate
        directions_funcs = {
            # A dictionary that matches between a letter and the direction of the desired search
            'Up': (y - 1, x),
            'Down': (y   1, x),
            'Right': (y, x   1),
            'Left': (y, x - 1),
            'Up_right': (y - 1, x   1),
            'Up_left': (y - 1, x - 1),
            'Down_right': (y   1, x   1),
            'Down_left': (y   1, x   1)
        }
        it_ok = False
        for direction in direct_lst:
            if directions_funcs[direction] == next_coordinate:
                it_ok = True
        return it_ok




def is_valid_path(board, path, words):

    word = board.board[path[0][0]][path[0][1]]
    board_coordinates = board.get_board_coordinate()
    for cord in range(len(path)-1):
        if path[cord] in board_coordinates and path[cord 1] in board_coordinates:
            if not board.possible_directions(path[cord], path[cord   1]):
                return None
            else:
                word  = board.board[path[cord   1][0]][path[cord   1][1]]
        else:
            return None
    if word in set(words):
        return word
import itertools

def create_dict(board, n):
    new_dict = dict()
    row = len(board.board)
    col = len(board.board[0])
    for i in range(row):
        for j in range(col):
            new_dict[(i, j)] = board.board[i][j]
        result_list = list(map(list, itertools.combinations(new_dict.items(), n)))
    return result_list



def coordinates_lst_and_str_lst(board, n):

    combine = create_dict(board, n)

    all_cord_dic = dict()
    for lst in combine:
        is_it_ok = True
        cord_lst = []
        str_l = ""
        for i in range(n):

            cord_lst.append(lst[i][0])
            str_l  = lst[i][1]
            try:
                if not board.possible_directions(lst[i][0], lst[i   1][0]):
                    is_it_ok = False
                    break
            except IndexError:
                break
        if is_it_ok:

            all_cord_dic[tuple(cord_lst)] = str_l
            all_cord_dic[tuple(cord_lst)[::-1]] = str_l[::-1]
    return all_cord_dic

def length_n_paths(n, board, words):
    possible_words = coordinates_lst_and_str_lst(board, n)

    my_dict = {key:val for key, val in possible_words.items() if val in words}
    return list(my_dict.keys())

I think the problem is in the combination but I dont know how to fix it. I would be happy for any help.

CodePudding user response:

After debugging, it's apparent that the result possible_words does not contain the key (1, 0), (0, 1), (1, 2), so that explains why it's not part of the answer - so the question becomes why doesn't the call to coordinates_lst_and_str_lst() generate that tuple (and the other 'missing' one)

If you break after constructing combine in coordinates_lst_and_str_lst, you will find that [((1, 0), 'D'), ((0, 1), 'O'), ((1, 2), 'G')] is not in combine, this means coordinates_lst_and_str_lst can't find it as a solution.

So, the problem must be in create_dict, which apparently isn't creating all the legal moves.

And indeed, in create_dict, you use itertools.combinations(), which gives you all the unique combinations of n items from a collection, disregarding their order, but you care about the order.

So, you don't want itertools.combinations(new_dict.items(), n), you want itertools.permutations(new_dict.items(), n). Have a closer look at the difference between combinations and permutations (of size n).

CodePudding user response:

You said any help was welcome so I started from scratch to create this... which produces the expected answer. I made inline notes to explain what the algorithm is doing. It probably isn't the most efficient solution and has room for optimization, but it should still perform pretty well. And it should give a valid solution for any board and any number of words.

class Board:
    def __init__(self, board, word_dict, n):
        self.board = board  
        self.height = len(board)  
        self.width = len(board[0])

        # the list of all directions possible to adjacent characters
        self.adj = [(x,y) for x in [-1,0,1] for y in [-1,0,1] if (x,y) != (0,0)]
        self.n = n
        self.word_dict = word_dict

        # list of words that are the same length as n
        self.words = [i for i in self.word_dict if len(i) == n]

        # list where all the valid solutions will be stored
        self.results = []

    def is_legal(self,r,c):
        if r >= 0 and r < self.height:
            if c >= 0 and c < self.width:
                return True
        return False

    def get_combinations(self, row, col, chars, word, path):
        if chars == self.n:   # base case: if chars == self.n
            self.results.append(path)  # we have a valid solution so append to results
            return   #return
        for y,x in self.adj:   # otherwise iterate through adjacent indeces
            r, c = row   y, col   x # adj space
            
            # if the adjacent space exists on board and isn't already 
            # in the list of visited spaces
            if self.is_legal(r,c) and (r,c) not in path: 

                if self.board[r][c] == word[chars]:   # if adj space contains 
                                                      # the next character in 
                                                      # the word

                    # add it to the current path, and recursively check all
                    # of the adjacent values for the matching space
                    self.get_combinations(r,c,chars 1,word,path [(r,c)])

    def solve(self):
        for i, row in enumerate(self.board):  # for each row
            for j, col in enumerate(row):     # for each character in row

                for word in self.words:       # for each word with length of n
                    if word[0] == col:        # if character is the same as...
                                              # the first of word

                        # get all the path solutions for that word from this 
                        # position on the board.
                        self.get_combinations(i, j, 1, word, [(i,j)])  



board1 = [['Q', 'O', 'Q', 'Q'],
          ['D', 'O', 'G', 'Q'],
          ['Q', 'O', 'Q', 'Q'],
          ['Q', 'Q', 'Q', 'Q']]

word_dict = {'DOG': True}
n = 3
board = Board(board1, word_dict, n)
board.solve()
print(board.results)

CodePudding user response:

0

I have a laravel project using SESSION_DRIVER=database, so the session persist in the database, can I/should I use session()->put(), session()->has(), session()->forget() etc in my api controllers?

  • Related