def caesar_generator(num, op): """Returns a one-argument Caesar cipher function. The function should "rotate" a letter by an integer amount 'num' using an operation 'op' (either add or sub). You may use the provided `letter_to_num` and `num_to_letter` functions, which will map all lowercase letters a-z to 0-25 and all uppercase letters A-Z to 26-51. >>> letter_to_num('a') 0 >>> letter_to_num('c') 2 >>> num_to_letter(3) 'd' >>> caesar2 = caesar_generator(2, add) >>> caesar2('a') 'c' >>> brutus3 = caesar_generator(3, sub) >>> brutus3('d') 'a' """ "*** YOUR CODE HERE ***" return lambda x: num_to_letter(op(letter_to_num(x), num))
def solve(self): """Solving logic for the board The solver repeats the following steps until no more changes can be made - use letter_mask to find where remaining letters can be placed to maintain links from word_list - find either: a) tiles where only one of the remaining letters can go, or b) letters that can only go in one of the remaining tiles - for any newly solved tiles, use the tile_mask so no other letters can be placed there, and that letter cannot be placed in any other tile This method does not return anything - solution is stored as a 2D character array in self.solution""" connections = get_connections(self.word_list) # solved_letters stores only the letter value i # new_solved_letters stores (x, y, i) values solved_letters = {letter[2] for letter in self.start_letters} new_solved_letters = self.start_letters # main solving loop - repeat until each tile has exactly 1 letter while np.count_nonzero(self.tiles) > len(lowercase_letters): # create a copy of self.tiles old_tiles = self.tiles.copy() # given the newly added letters, use masks to find where new letters can be placed if new_solved_letters: for x, y, i in new_solved_letters: for j in connections[i]: mask = self.create_letter_mask(x, y, j) self.tiles = np.logical_and(self.tiles, mask) # if no new letters were added last iteration, instead find where other letters may go else: for i in range(len(lowercase_letters)): if i not in solved_letters: coords = np.argwhere(self.tiles[:, :, i]) for j in connections[i]: mask = self.create_letter_probability_mask( coords, j) self.tiles = np.logical_and(self.tiles, mask) # check if any tiles can now be solved new_solved_letters = set() for x, y, i in self.check_letters_solved( ) + self.check_tiles_solved(): if i not in solved_letters: self.solve_tile(x, y, i) new_solved_letters.add((x, y, i)) solved_letters.add(i) # if no changes have been made to the array, then the solver must be stuck if np.all(old_tiles == self.tiles): raise RuntimeError( "This grid cannot be solved by this program") num_array = np.sum(self.tiles * np.arange(25), axis=2) solution = np.empty_like(num_array, dtype=str) for (y, x), i in np.ndenumerate(num_array): solution[y, x] = num_to_letter(i) self.solution = solution
def caesar(x): return num_to_letter(op(letter_to_num(x), num))
def inner(letter): return num_to_letter(op(letter_to_num(letter), num))
def solve_tile(self, x, y, i): """Show that a single tile is solved by applying the mask""" mask = self.create_tile_mask(x, y, i) self.tiles = np.logical_and(self.tiles, mask) self.solution[y, x] = num_to_letter(i)