Advertisement
Guest User

Untitled

a guest
Sep 11th, 2019
200
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 12.20 KB | None | 0 0
  1. from collections import defaultdict
  2. from random import shuffle
  3. import numpy as np
  4.  
  5. start_time = time()
  6.  
  7. class Board():
  8.     def __init__(self):
  9.         self.bag = self.create_new_bag()
  10.         self.board = self.create_new_board()
  11.         self.words = self.get_first_letter_wordlist()
  12.         self.level = 3
  13.         self.move_history = []
  14.         self.points = 0
  15.         self.score = {"a": 1, "b": 3, "c": 3, "d": 2,
  16.                  "e": 1, "f": 4, "g": 2, "h": 4,
  17.                  "i": 1, "j": 8, "k": 5, "l": 1,
  18.                  "m": 3, "n": 1, "o": 1, "p": 3,
  19.                  "q": 10, "r": 1, "s": 1, "t": 1,
  20.                  "u": 1, "v": 4, "w": 4, "x": 8,
  21.                  "y": 4, "z": 10}
  22.         self.level1_bonus = {
  23.  
  24.             (1, 1): ('L', 3),
  25.             (5, 1): ('L', 3),
  26.             (2, 2): ('L', 2),
  27.             (4, 4): ('L', 2),
  28.             (3, 3): ('W', 2),
  29.             (2, 4): ('L', 2),
  30.             (4, 4): ('L', 2),
  31.             (1, 5): ('L', 3),
  32.             (5, 5): ('L', 3)
  33.         }
  34.         self.level2_bonus = {
  35.  
  36.             (1, 1): ('L', 3),
  37.             (5, 1): ('L', 3),
  38.             (2, 2): ('L', 2),
  39.             (4, 4): ('L', 2),
  40.             (3, 3): ('W', 2),
  41.             (2, 4): ('L', 2),
  42.             (4, 4): ('L', 2),
  43.             (1, 5): ('L', 3),
  44.             (5, 5): ('L', 3),
  45.             (3, 0): ('W', 2),
  46.             (3, 6): ('W', 2),
  47.             (0, 3): ('W', 2),
  48.             (6, 3): ('W', 2)
  49.         }
  50.         self.level3_bonus = {
  51.  
  52.             (1, 1): ('L', 3),
  53.             (5, 1): ('L', 3),
  54.             (2, 2): ('L', 2),
  55.             (4, 4): ('L', 2),
  56.             (3, 3): ('W', 2),
  57.             (2, 4): ('L', 2),
  58.             (4, 4): ('L', 2),
  59.             (1, 5): ('L', 3),
  60.             (5, 5): ('L', 3),
  61.             (3, 0): ('W', 2),
  62.             (3, 6): ('W', 2),
  63.             (0, 3): ('W', 2),
  64.             (6, 3): ('W', 2),
  65.             (0, 0): ('W', 3),
  66.             (6, 0): ('W', 3),
  67.             (0, 6): ('W', 3),
  68.             (6, 6): ('W', 3)
  69.         }
  70.  
  71.     def get_wordlist(self):
  72.     # TODO Change word to a dictionary for faster stuff?
  73.  
  74.         with open('game_words.txt') as f:
  75.             words = []
  76.             for line in f:
  77.                 line = line.rstrip()
  78.                 i = line.index('"')
  79.                 line = line[i + 2:-3]
  80.                 split_words = line.split('_')
  81.                 words += split_words
  82.         return words
  83.  
  84.     def get_first_letter_wordlist(self):
  85.         with open('game_words.txt') as f:
  86.             words = defaultdict(list)
  87.             for line in f:
  88.                 line = line.rstrip()
  89.                 i = line.index('"')
  90.                 line = line[i + 2:-3]
  91.                 split_words = line.split('_')
  92.                 for word in split_words:
  93.                     if len(word) > 2:
  94.                         words[word[0]].append(word)
  95.  
  96.         return words
  97.  
  98.     def create_new_board(self):
  99.         board = []
  100.         for x in range(7):
  101.             board.append([])
  102.  
  103.         for y in range(7):
  104.             for x in range(7):
  105.                 board[y].append(self.bag.pop())
  106.  
  107.         board = np.array(board)
  108.         return board
  109.  
  110.     def update_board_from_textfile(self):
  111.         with open('blast_board.txt') as f:
  112.             y = 0
  113.             x = 0
  114.             for line in f:
  115.                 for letter in line.rstrip():
  116.                     self.board[y][x] = letter
  117.                     x += 1
  118.                 x = 0
  119.                 y += 1
  120.  
  121.  
  122.     def create_new_bag(self):
  123.         bag = []
  124.         tiles = 'A-9, B-2, C-2, D-4, E-12, F-2, G-3, H-2, I-9, J-1, K-1, L-4, M-2, N-6, O-8, P-2, Q-1, R-6, S-4, T-6, U-4, V-2, W-2, X-1, Y-2, Z-1'
  125.         tiles = tiles.split(',')
  126.         for pair in tiles:
  127.             letter, num = pair.split('-')
  128.             letter = letter.lower()
  129.             letter = letter.replace(' ', '')
  130.             num = int(num)
  131.             for x in range(num):
  132.                 bag.append(letter)
  133.         shuffle(bag)
  134.         return bag
  135.  
  136.     def display_ascii_board(self):
  137.         print(self.board)
  138.  
  139.     def get_all_unconnected_words(self):
  140.         ans = {}
  141.         letter_counts = self.get_letter_counts_of_board()
  142.         for word in self.words:
  143.             if self.check_if_enough_letters_for_word(letter_counts, word):
  144.                 ans[word] = 1
  145.         return ans
  146.  
  147.     def get_letter_counts_of_board(self):
  148.         letters = defaultdict(int)
  149.         for row in self.board:
  150.             for letter in row:
  151.                 letters[letter] += 1
  152.         return letters
  153.  
  154.     def check_if_enough_letters_for_word(self, letter_counts, word):
  155.         for letter in word:
  156.             if word.count(letter) > letter_counts[letter]:
  157.                 return False
  158.         return True
  159.  
  160.     def check_if_move_valid(self, pos):
  161.         x = pos[0]
  162.         y = pos[1]
  163.         if x < 0 or x >= 6:
  164.             return False
  165.         if y < 0 or y >= 6:
  166.             return False
  167.         return self.board[y][x] != '!'
  168.  
  169.     def get_neighbors_of_pos(self, board, pos):
  170.         x = pos[0]
  171.         y = pos[1]
  172.         possible_moves = [(x, y - 1), (x + 1, y - 1), (x + 1, y), (x + 1, y + 1), (x, y + 1), (x - 1, y + 1),
  173.                           (x - 1, y), (x - 1, y - 1)]
  174.         valid_moves = []
  175.         for move in possible_moves:
  176.             if self.check_if_move_valid(move):
  177.                 valid_moves.append(move)
  178.         return valid_moves
  179.  
  180.     def check_if_word_is_possible(self, word, constraints):
  181.         start_positions = self.get_pos_of_letter_on_board(word[0][0])
  182.         if len(start_positions) == 0:
  183.             return False
  184.  
  185.         for pos in start_positions:
  186.             copy_board = self.board.copy()
  187.             result = self.try_to_build_word(word, '', copy_board, pos)
  188.             if result != False:
  189.                 # Check for constraints
  190.                 for pos in constraints:
  191.                     if pos not in word[1]:
  192.                         return False
  193.                 return result
  194.         return False
  195.  
  196.     def check_if_words_are_possible_from_pos(self, constraints, pos):
  197.         possible_words = []
  198.  
  199.         x = pos[0]
  200.         y = pos[1]
  201.         start_letter = self.board[y][x]
  202.  
  203.         for word in self.words[start_letter]:
  204.             word = (word, [])
  205.             copy_board = self.board.copy()
  206.             result = self.try_to_build_word(word, '', copy_board, pos)
  207.             if result != False:
  208.                 # Check for constraints
  209.                 for pos in constraints:
  210.                     if pos not in word[1]:
  211.                         return False
  212.                 possible_words.append(result)
  213.         return possible_words
  214.  
  215.     def check_if_string_is_a_substring_of_words(self, s, words):
  216.         for word in list(words.keys()):
  217.             if word.startswith(s):
  218.                 return True
  219.         return False
  220.  
  221.     def get_pos_of_letter_on_board(self, letter):
  222.         ans = []
  223.         for y in range(7):
  224.             for x in range(7):
  225.                 if self.board[y][x] == letter:
  226.                     ans.append((x, y))
  227.         return ans
  228.  
  229.     def try_to_build_word(self, goal, s, board, pos):
  230.         """Recursive, do not reference self.board"""
  231.  
  232.         x = pos[0]
  233.         y = pos[1]
  234.         s += board[y][x]
  235.         goal[1].append(pos)
  236.  
  237.         # If it matches the goal, got a match
  238.         if s == goal[0]:
  239.             return goal
  240.  
  241.         # If it isn't the correct substring, cancel out
  242.         if not goal[0].startswith(s):
  243.             goal[1].pop()
  244.             return False
  245.  
  246.         # Isn't a match, but could be.  Continue
  247.         copy_board = board.copy()
  248.         copy_board[y][x] = '!'
  249.  
  250.         # Get possible moves
  251.         moves = self.get_neighbors_of_pos(copy_board, (x, y))
  252.  
  253.         # No more possible moves, no bueno
  254.         if len(moves) == 0:
  255.             goal[1].pop()
  256.             return False
  257.  
  258.         # Check through other possiblities
  259.         for move in moves:
  260.             result = self.try_to_build_word(goal, s, copy_board, move)
  261.             if result != False:
  262.                 return result
  263.         goal[1].pop()
  264.         return False
  265.  
  266.     def get_word_value(self, word_path):
  267.         """Returns the value of the word.  Word_path is a tuple of word and list of paths"""
  268.  
  269.         word, path = word_path
  270.         value = 0
  271.         multiplier = 0
  272.         for letter, p in zip(word, path):
  273.  
  274.             base_letter_value = self.score[letter]
  275.             if self.level == 1:
  276.                 if p in self.level1_bonus:
  277.                     bonus = self.level1_bonus[p]
  278.                     if bonus[0] == 'L':
  279.                         base_letter_value *= bonus[1]
  280.                     else:
  281.                         multiplier += bonus[1]
  282.             elif self.level == 2:
  283.                 if p in self.level2_bonus:
  284.                     bonus = self.level2_bonus[p]
  285.                     if bonus[0] == 'L':
  286.                         base_letter_value *= bonus[1]
  287.                     else:
  288.                         multiplier += bonus[1]
  289.             elif self.level == 3:
  290.                 if p in self.level3_bonus:
  291.                     bonus = self.level3_bonus[p]
  292.                     if bonus[0] == 'L':
  293.                         base_letter_value *= bonus[1]
  294.                     else:
  295.                         multiplier += bonus[1]
  296.  
  297.             value += base_letter_value
  298.         if multiplier > 0:
  299.             value *= multiplier
  300.  
  301.         if len(word) == 4:
  302.             value += 10
  303.         if len(word) == 5:
  304.             value += 20
  305.         if len(word) == 6:
  306.             value += 30
  307.         if len(word) == 7:
  308.             value += 50
  309.         if len(word) == 8:
  310.             value += 60
  311.         if len(word) == 9:
  312.             value += 70
  313.         if len(word) == 10:
  314.             value += 80
  315.         if len(word) == 11:
  316.             value += 90
  317.         if len(word) == 12:
  318.             value += 100
  319.         if len(word) == 13:
  320.             value += 110
  321.         if len(word) == 14:
  322.             value += 120
  323.         if len(word) == 15:
  324.             value += 130
  325.  
  326.         return value
  327.  
  328.     def get_playable_moves(self, constraints):
  329.         """Constraints is a list of positions that must be included in the result"""
  330.         unconnected_words = self.get_all_unconnected_words()
  331.         playable_words = []
  332.         for word in unconnected_words:
  333.             word = (word, [])
  334.  
  335.             result = self.check_if_word_is_possible(word, constraints)
  336.             if result != False:
  337.                 playable_words.append(result)
  338.  
  339.         playable_words.sort(key=lambda x: len(x[0]), reverse=True)
  340.         return playable_words
  341.  
  342.     def get_playable_moves_via_squares(self, constraints):
  343.         """Constraints is a list of positions that must be included in the result"""
  344.         playable_words = []
  345.         for y in range(7):
  346.             for x in range(7):
  347.                 result = self.check_if_words_are_possible_from_pos(constraints, (x, y))
  348.                 if result != False:
  349.                     playable_words += result
  350.         return playable_words
  351.  
  352.     def get_best_scoring_move_and_path(self, constraints=[]):
  353.         #playable_words = self.get_playable_moves(constraints)
  354.         playable_words = self.get_playable_moves_via_squares(constraints)
  355.         top_scoring = 0
  356.         best = None
  357.         for word in playable_words:
  358.             value = self.get_word_value(word)
  359.             if value > top_scoring:
  360.                 best = word
  361.                 top_scoring = value
  362.  
  363.         return best
  364.  
  365.     def play_move(self, path):
  366.         for pos in path:
  367.             x = pos[0]
  368.             y = pos[1]
  369.             self.bag.append(self.board[y][x])
  370.             self.board[y][x] = '!'
  371.         shuffle(self.bag)
  372.  
  373.     def update_from_tiles(self, tile_grid):
  374.         for y in range(7):
  375.             for x in range(7):
  376.                 if (x, y) in tile_grid:
  377.                     self.board[y][x] = tile_grid[(x, y)].letter
  378.                 else:
  379.                     self.board[y][x] = '!'
  380.  
  381.  
  382.     def restock_board(self):
  383.         shuffle(self.bag)
  384.         ans = []
  385.         for y in range(7):
  386.             for x in range(7):
  387.                 if self.board[y][x] == '!':
  388.                     self.board[y][x] = self.bag.pop()
  389.                     ans.append((x, y))
  390.         return ans
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement