def move_cheeses(n: int, i, source: int, intermediate1: int, intermediate2, destination: int) -> None: """Print moves to get n cheeses from source to destination, possibly using intermediate""" if i > 1: if n > 1: move_cheeses(n - i, i, source, destination, intermediate1,intermediate2) move_cheeses(i-1, i, source, intermediate2, destination, intermediate1) move_cheeses(1, i, source, intermediate1, intermediate2, destination) move_cheeses(i-1, i, intermediate1, source, intermediate2, destination) move_cheeses(n -i, i, intermediate2, intermediate1, source, destination) else: print("Move top cheese from {} to {}".format(source, destination)) else: # just one cheese --- no recursion required! print("Move top cheese from {} to {}".format(intermediate2, destination) if __name__ == '__main__' : NUM_CHEESES = 8 DELAY_BETWEEN_MOVES = .5 CONSOLE_ANIMATE = False # DO NOT MODIFY THE CODE BELOW. four_stools = TOAHModel(4) four_stools.fill_first_stool(number_of_cheeses=NUM_CHEESES) tour_of_four_stools(four_stools, console_animate=CONSOLE_ANIMATE, delay_btw_moves=DELAY_BETWEEN_MOVES) print(four_stools.number_of_moves())
class GUIController: def __init__(self: 'GUIController', number_of_cheeses: int, number_of_stools: int, content_width: float, content_height: float, cheese_scale: float): """ Initialize a new GUIView. number_of_cheeses - number of cheese to tower on the first stool number_of_stools - number of stools content_width - width in pixels of the working area content_height - height in pixels of the working area cheese_scale - height in pixels for showing cheese thicknesses, and to scale cheese diameters """ self._model = TOAHModel(number_of_stools) self._stools = [] self._cheese_to_move = None self._blinking = False self._number_of_stools = number_of_stools self.cheese_scale = cheese_scale self.root = TI.Tk() canvas = TI.Canvas(self.root, background="blue", width=content_width, height=content_height) canvas.pack(expand=True, fill=TI.BOTH) self.moves_label = TI.Label(self.root) self.show_number_of_moves() self.moves_label.pack() # the dimensions of a stool are the same as a cheese that's # one size bigger than the biggest of the number_of_cheeses cheeses. for stool_ind in range(number_of_stools): width = self.cheese_scale * (number_of_cheeses + 1) x_cent = content_width * (stool_ind + 1) / (number_of_stools + 1.0) y_cent = content_height - cheese_scale / 2 stool = StoolView(width, lambda s: self.stoolClicked(s), canvas, self.cheese_scale, x_cent, y_cent) self._stools.append(stool) # Can't use self._model.fill_first_stool because we need to # use CheeseView objects instead of just Cheese objects. total_size = self.cheese_scale for sizeparam in range(1, number_of_cheeses + 1): size = (number_of_cheeses + 1 - sizeparam) width = self.cheese_scale * size x_cent = content_width / (number_of_stools + 1.0) y_cent = content_height - cheese_scale / 2 - total_size cheese = CheeseView(size, width, lambda c: self.cheeseClicked(c), canvas, self.cheese_scale, x_cent, y_cent) self._model.add(0, cheese) total_size += self.cheese_scale def cheeseClicked(self: 'GUIController', cheese: 'CheeseView'): """React to cheese being clicked: if not in the middle of blinking then select cheese for moving, or for moving onto. cheese - clicked cheese """ if not self._blinking: self.select_cheese(cheese) def stoolClicked(self: 'GUIController', stool: 'StoolView'): """React to cheese being clicked: if not in the middle of blinking then select cheese for moving, or for moving onto. cheese - clicked cheese """ if not self._blinking: self.select_stool(stool) def select_cheese(self: 'GUIController', cheese: CheeseView): """ Called by cheeseClicked. If no cheese is selected to move, then select the cheese at top of clicked_cheese's stool (which may be clicked_cheese itself) and highlight it. If selected_cheese is already highlighted, then unhighlight it. Otherwise try to move self._cheese_to_move onto the stool that clicked_cheese is on. """ stool = self._stools[self._model.cheese_location(cheese)] stool_index = self.stool_index(stool) cheese = self._model.top_cheese(stool_index) #print(stool, stool_index, cheese) if self._cheese_to_move is None: self._cheese_to_move = cheese self._cheese_to_move.highlight(True) self.root.update() elif self._cheese_to_move is cheese: self._cheese_to_move.highlight(False) self._cheese_to_move = None self.root.update() else: self.select_platform_for_move(cheese, stool_index) def select_stool(self: 'GUIController', dest_stool: StoolView): """ Called by stoolClicked. Initiate a move if there is already some cheese highlighted (i.e. self._cheese_to_move is not None), unless self._cheese_to_move is on dest_stool, in which case do nothing. """ if self._cheese_to_move is not None: origin_stool = self._stools[ self._model.cheese_location(self._cheese_to_move)] dest_stool_index = self.stool_index(dest_stool) origin_stool_index = self.stool_index(origin_stool) if origin_stool_index != dest_stool_index: top_cheese = self._model.top_cheese(dest_stool_index) if top_cheese is None: self.select_platform_for_move(dest_stool, dest_stool_index) else: self.select_platform_for_move(top_cheese, dest_stool_index) def select_platform_for_move(self: 'GUIController', platform: PlatformView, stool_index: int): """ Actually responsible for showing the cheese move on the screen, and for telling the model to update itself. Change self._cheese_to_move's coordinates so that it's on top of platform. platform - the StoolView or CheeseView that we want to move self._cheese_to_move onto. stool_index - if platform is a stool, then this is its index, and if platform is a cheese then this is the index of the stool that it is on. """ if self._cheese_to_move is not None: try: from_stool = self._model.cheese_location( self._cheese_to_move) self._model.move(from_stool, stool_index) self._cheese_to_move.place(platform.x_center, platform.y_center - self.cheese_scale) self.show_number_of_moves() except IllegalMoveError as e: print(e) self._blinking = True for i in range(10): self._cheese_to_move.highlight(i % 2 != 0) self.root.update() time.sleep(0.1) self._blinking = False self._cheese_to_move.highlight(False) self._cheese_to_move = None self.root.update() def stool_index(self: 'GUIView', stool: 'StoolView') -> int: return self._stools.index(stool) def show_number_of_moves(self: 'GUIView'): """Show the number of moves so far.""" self.moves_label.config(text='Number of moves: ' + str(self._model.number_of_moves())) def get_stool(self: 'GUIController', i: int) -> 'StoolView': return self._stools[i] def top_cheese(self: 'GUIController', i: int) -> 'CheeseView': return self._model.top_cheese(i)
model = TOAHModel(4) model.fill_first_stool(y) index = 0 time.sleep(delay_btw_moves) print(model) while index < z: time.sleep(delay_btw_moves) m = x.get_move(index) model.move(m[0],m[1]) time.sleep(delay_btw_moves) print(model) time.sleep(delay_btw_moves) index += 1 if __name__ == '__main__': NUM_CHEESES = 9 DELAY_BETWEEN_MOVES = 0.5 CONSOLE_ANIMATE = True # DO NOT MODIFY THE CODE BELOW. four_stools = TOAHModel(4) four_stools.fill_first_stool(number_of_cheeses=NUM_CHEESES) tour_of_four_stools(four_stools, console_animate=CONSOLE_ANIMATE, delay_btw_moves=DELAY_BETWEEN_MOVES) print(four_stools.number_of_moves())
class GUIController: def __init__(self: 'GUIController', number_of_cheeses: int, number_of_stools: int, content_width: float, content_height: float, cheese_scale: float): """ Initialize a new GUIView. number_of_cheeses - number of cheese to tower on the first stool number_of_stools - number of stools content_width - width in pixels of the working area content_height - height in pixels of the working area cheese_scale - height in pixels for showing cheese thicknesses, and to scale cheese diameters """ self._model = TOAHModel(number_of_stools) self._stools = [] self._cheese_to_move = None self._blinking = False self._number_of_stools = number_of_stools self.cheese_scale = cheese_scale self.root = TI.Tk() canvas = TI.Canvas(self.root, background="blue", width=content_width, height=content_height) canvas.pack(expand=True, fill=TI.BOTH) self.moves_label = TI.Label(self.root) self.show_number_of_moves() self.moves_label.pack() # the dimensions of a stool are the same as a cheese that's # one size bigger than the biggest of the number_of_cheeses cheeses. for stool_ind in range(number_of_stools): width = self.cheese_scale * (number_of_cheeses + 1) x_cent = content_width * (stool_ind + 1) / (number_of_stools + 1.0) y_cent = content_height - cheese_scale / 2 stool = StoolView(width, lambda s: self.stoolClicked(s), canvas, self.cheese_scale, x_cent, y_cent) self._stools.append(stool) # Can't use self._model.fill_first_stool because we need to # use CheeseView objects instead of just Cheese objects. total_size = self.cheese_scale for sizeparam in range(1, number_of_cheeses + 1): size = (number_of_cheeses + 1 - sizeparam) width = self.cheese_scale * size x_cent = content_width / (number_of_stools + 1.0) y_cent = content_height - cheese_scale / 2 - total_size cheese = CheeseView(size, width, lambda c: self.cheeseClicked(c), canvas, self.cheese_scale, x_cent, y_cent) self._model.add(0, cheese) total_size += self.cheese_scale def cheeseClicked(self: 'GUIController', cheese: 'CheeseView'): """React to cheese being clicked: if not in the middle of blinking then select cheese for moving, or for moving onto. cheese - clicked cheese """ if not self._blinking: self.select_cheese(cheese) def stoolClicked(self: 'GUIController', stool: 'StoolView'): """React to cheese being clicked: if not in the middle of blinking then select cheese for moving, or for moving onto. cheese - clicked cheese """ if not self._blinking: self.select_stool(stool) def select_cheese(self: 'GUIController', cheese: CheeseView): """ Called by cheeseClicked. If no cheese is selected to move, then select the cheese at top of clicked_cheese's stool (which may be clicked_cheese itself) and highlight it. If selected_cheese is already highlighted, then unhighlight it. Otherwise try to move self._cheese_to_move onto the stool that clicked_cheese is on. """ stool = self._stools[self._model.cheese_location(cheese)] stool_index = self.stool_index(stool) cheese = self._model.top_cheese(stool_index) #print(stool, stool_index, cheese) if self._cheese_to_move is None: self._cheese_to_move = cheese self._cheese_to_move.highlight(True) self.root.update() elif self._cheese_to_move is cheese: self._cheese_to_move.highlight(False) self._cheese_to_move = None self.root.update() else: self.select_platform_for_move(cheese, stool_index) def select_stool(self: 'GUIController', dest_stool: StoolView): """ Called by stoolClicked. Initiate a move if there is already some cheese highlighted (i.e. self._cheese_to_move is not None), unless self._cheese_to_move is on dest_stool, in which case do nothing. """ if self._cheese_to_move is not None: origin_stool = self._stools[self._model.cheese_location( self._cheese_to_move)] dest_stool_index = self.stool_index(dest_stool) origin_stool_index = self.stool_index(origin_stool) if origin_stool_index != dest_stool_index: top_cheese = self._model.top_cheese(dest_stool_index) if top_cheese is None: self.select_platform_for_move(dest_stool, dest_stool_index) else: self.select_platform_for_move(top_cheese, dest_stool_index) def select_platform_for_move(self: 'GUIController', platform: PlatformView, stool_index: int): """ Actually responsible for showing the cheese move on the screen, and for telling the model to update itself. Change self._cheese_to_move's coordinates so that it's on top of platform. platform - the StoolView or CheeseView that we want to move self._cheese_to_move onto. stool_index - if platform is a stool, then this is its index, and if platform is a cheese then this is the index of the stool that it is on. """ if self._cheese_to_move is not None: try: from_stool = self._model.cheese_location(self._cheese_to_move) self._model.move(from_stool, stool_index) self._cheese_to_move.place( platform.x_center, platform.y_center - self.cheese_scale) self.show_number_of_moves() except IllegalMoveError as e: print(e) self._blinking = True for i in range(10): self._cheese_to_move.highlight(i % 2 != 0) self.root.update() time.sleep(0.1) self._blinking = False self._cheese_to_move.highlight(False) self._cheese_to_move = None def stool_index(self: 'GUIView', stool: 'StoolView') -> int: return self._stools.index(stool) def show_number_of_moves(self: 'GUIView'): """Show the number of moves so far.""" self.moves_label.config(text='Number of moves: ' + str(self._model.number_of_moves())) def get_stool(self: 'GUIController', i: int) -> 'StoolView': return self._stools[i] def top_cheese(self: 'GUIController', i: int) -> 'CheeseView': return self._model.top_cheese(i)
moves = MoveSequence([]) four_stool_solution(moves, cheese_num, 0, 1, 2, 3) #Then we apply it to our existing model, animating with delay if #requested. if console_animate: for move in moves._moves: print(model) model.move(move[0], move[1]) time.sleep(delay_btw_moves) print(model) else: for move in moves._moves: model.move(move[0], move[1]) if __name__ == '__main__': NUM_CHEESES = 25 DELAY_BETWEEN_MOVES = .1 CONSOLE_ANIMATE = True # DO NOT MODIFY THE CODE BELOW. four_stools = TOAHModel(4) four_stools.fill_first_stool(number_of_cheeses=NUM_CHEESES) tour_of_four_stools(four_stools, console_animate=CONSOLE_ANIMATE, delay_btw_moves=DELAY_BETWEEN_MOVES) print(four_stools.number_of_moves())
class ConsoleController: def __init__(self: 'ConsoleController', number_of_cheeses: int, number_of_stools: int): """ Initialize a new 'ConsoleController'. number_of_cheeses - number of cheese to tower on the first stool number_of_stools - number of stools """ self.number_of_cheeses = number_of_cheeses self.number_of_stools = number_of_stools self.model = TOAHModel(number_of_stools) self.cheeses = self.model.fill_first_stool(number_of_cheeses) self.play_loop() def play_loop(self: 'ConsoleController'): ''' Console-based game. TODO: -Start by giving instructions about how to enter moves (which is up to you). Be sure to provide some way of exiting the game, and indicate that in the instructions. -Use python's built-in function input() to read a potential move from the user/player. You should print an error message if the input does not meet the specifications given in your instruction or if it denotes an invalid move (e.g. moving a cheese onto a smaller cheese). You can print error messages from this method and/or from ConsoleController.move; it's up to you. -After each valid move, use the method TOAHModel.__str__ that we've provided to print a representation of the current state of the game. ''' print ("Welcome to Towers Of Anne Hoy!") print ("Instructions: The stool numbers start from 0.") print ("Please enter the source stool when prompted.") print ("Source stool is the stool number to move the cheese from.") print ("Please enter the destination stool when prompted.") print ("Destination stool is the stool number to move the cheese to.") print ("Enter 'e' to exit.") print (" ") print (self.model) print (" ") print ("Let's start!") print (" ") while True: try: if self.model.end_game_stool == self.model.stool_lst[-1]: print ("GAME OVER!") raise SystemExit self.play_loop origin_stool = input("Please enter the source stool: ") if origin_stool == 'e': print ("***Thanks for playing!***") raise SystemExit dest_stool = input("Please enter the destination stool: ") if dest_stool == 'e': print ("***Thanks for playing!***") raise SystemExit move(self.model, int(origin_stool), int(dest_stool)) print (self.model) print ("Number of moves so far: " +str(self.model.number_of_moves())) print (" ") except ValueError: print ("***Bad input***")
if number_of_cheeses == 'quit': print('Good Game!') else: # check if it's the right input! number_of_cheeses = input_checker(number_of_cheeses) print('How many stools?') number_of_stools = input() # if user wants to leave, let them! if number_of_stools == 'quit': print('Good Game!') else: number_of_stools = input_checker(number_of_stools) # Create a new CC object and initialize with user's inputs new_cc = ConsoleController(int(number_of_cheeses), int(number_of_stools)) # Also create a new TOAHModel which will be modified new_model = TOAHModel(int(number_of_stools)) # Fill the first stool so the game can be played new_model.fill_first_stool(int(number_of_cheeses)) # Print a string representation so user can visually see which # he/she plays the game print(new_model) print(new_model.number_of_moves()) # keep looping until user wants to exit by typing 'quit' new_cc.play_loop()
def tour_of_four_stools(model: TOAHModel, delay_btw_moves: float=0.5, console_animate: bool=False): """Move a tower of cheeses from the first stool in model to the fourth. model - a TOAHModel with a tower of cheese on the first stool and three other empty stools console_animate - whether to use ConsoleController to animate the tour delay_btw_moves - time delay between moves in seconds IF console_animate == True no effect if console_animate == False """ src = 0 spare_1 = 1 spare_2 = 2 dest = 3 num_cheeses = model.number_of_cheeses() rec_four_stools(model, num_cheeses, src, spare_1, spare_2, dest, delay_btw_moves, console_animate) if __name__ == '__main__': # DO NOT MODIFY THE CODE BELOW. model = TOAHModel(4) model.fill_first_stool(number_of_cheeses=8) tour_of_four_stools(model, console_animate=True, delay_btw_moves=0.5) print(model.number_of_moves()) # some debug code below, don't forget to comment it # # print(model.get_move_seq().get_moves())