class GUIController: """ Graphical User Interface (GUI) controller === Attributes === @param float cheese_scale: height in pixels to scale cheese height @param root tk.Tk: tkinter root window """ def __init__(self, number_of_cheeses, number_of_stools, content_width, content_height, cheese_scale): """ Initialize a new GUIView. @param GUIController self: @param int number_of_cheeses: number of cheeses for first stool @param int number_of_stools: number of stools @param float content_width: width, in pixels, of working area @param float content_height: height, in pixels, of working area @param float 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 = tk.Tk() canvas = tk.Canvas(self.root, background="blue", width=content_width, height=content_height) canvas.pack(expand=True, fill=tk.BOTH) self.moves_label = tk.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.stool_clicked(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.cheese_clicked(c), canvas, self.cheese_scale, x_cent, y_cent) self._model.add(cheese, 0) total_size += self.cheese_scale def cheese_clicked(self, cheese): """ React to cheese being clicked: if not in the middle of blinking then select cheese for moving, or for moving onto. @param GUIController self: @param CheeseView cheese: clicked cheese @rtype: None """ if not self._blinking: self.select_cheese(cheese) def stool_clicked(self, stool): """ React to cheese being clicked: if not in the middle of blinking then select cheese for moving, or for moving onto. @param GUIController self: @param StoolView stool: clicked stool @rtype: None """ if not self._blinking: self.select_stool(stool) def select_cheese(self, cheese): """ Select top cheese. 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. @param GUIController self: @param CheeseView cheese: clicked cheese @rtype: None """ stool = self._stools[self._model.get_cheese_location(cheese)] stool_index = self.stool_index(stool) cheese = self._model.get_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, dest_stool): """ 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. @param GUIController self: @type dest_stool: StoolView @rtype: None """ if self._cheese_to_move is not None: origin_stool = self._stools[ self._model.get_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.get_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, platform, stool_index): """ Show the cheese move on screen, and update the model. Change self._cheese_to_move's coordinates so that it's on top of platform. @param GUIController self: @param PlatformView platform: @param int stool_index: @rtype: None """ if self._cheese_to_move is not None: try: from_stool = self._model.get_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, stool): """ Return the index of stool. @param GUIController self: @param StoolView stool: @rtype: int >>> gui = GUIController(5, 4, 1024, 320, 20) >>> s = gui.get_stool(0) >>> gui.stool_index(s) == 0 True >>> gui.stool_index(s) == 1 False """ return self._stools.index(stool) def show_number_of_moves(self): """Show the number of moves so far. @param GUIController self: @rtype: None """ self.moves_label.config(text="Number of moves: " + str(self._model.number_of_moves())) def get_stool(self, i): """ Return ith stool. @param GUIController self: @param int i: @rtype: StoolView # examples not really practical here """ return self._stools[i] def get_top_cheese(self, i): """ Return the top cheese from ith stool. @param GUIController self: @param int i: @rtype: CheeseView # examples not really practical here """ return self._model.get_top_cheese(i)
print("move final " + str(m) + " took " + str(a)) count += a #count += move_cheeses(model, n-m, 0, 1, 2, animate) #count += move_cheeses(model, m, 0, 1, 3, animate) #count += move_cheeses(model, n-m, 2, 0, 3, animate) return count if __name__ == '__main__': #mod = TOAHModel(4) #mod.fill_first_stool(5) #print(tour_of_four_stools(mod,animate=True)) #move_cheeses(mod, 8, 0, 1, 2) num_cheeses = 100 delay_between_moves = 0.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, delay_between_moves) print(four_stools.number_of_moves()) # Leave files below to see what python_ta checks. # File tour_pyta.txt must be in same folder import python_ta python_ta.check_all(config="tour_pyta.txt")
class ConsoleController: """ Controller for text console. """ def __init__(self, number_of_cheeses, number_of_stools): """ Initialize a new ConsoleController self. @param ConsoleController self: the ConsoleController itself @param int number_of_cheeses: the number of cheeses @param int number_of_stools: the number of stools @rtype: None """ self.model = TOAHModel(number_of_stools) self.model.fill_first_stool(number_of_cheeses) def play_loop(self): """ Play Console-based game. @param ConsoleController self: the ConsoleController itself @rtype: None 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 spe instruction or if it denotes an invalid move (e.g. moving a cheese ontcifications given in youro 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 the Game of Hanoi-------- Type two integers like x y (two integers x and y seperated by a space) to move a cheese from xth stool to yth stool. If the input move is invalid, an error message will be sent until you type a valid move. NO.{} represent the number of successful moves you have made. Type quit to exit the game. """) move_order = input('Please order a move or type quit to exit the game:') n = self.model.get_number_of_stools() while move_order != 'quit': try: from_stool = int(move_order.split()[0]) - 1 dest_stool = int(move_order.split()[1]) - 1 if len(move_order.split()) != 2: print("Hey, dude! Please follow the format!") elif from_stool == -1 or dest_stool == -1: print("Hey, dude! We don't have that stool!") else: move(self.model, from_stool, dest_stool) except IndexError: if len(move_order.split()) != 2: print("Hey, dude! Please follow the format!") elif from_stool + 1 > n or dest_stool + 1 > n: print("Hey, dude! We don't have that stool") else: print("Hey, dude! Please follow the format!") except IllegalMoveError: if from_stool == dest_stool: print("Hey, dude! Origin and destination stools must " "be distinct!") elif self.model.get_top_cheese(from_stool) is None: print("Hey, dude! Can't find a cheese from an empty stool!") elif self.model.get_top_cheese(from_stool).size > self.model\ .get_top_cheese(dest_stool).size: print('Hey, dude! A big cheese can not be on a small one!') except ValueError: print("Hey, dude! Don't type other characters!") print(self.model) move_order = input('NO.{} Give me a move:'. format(self.model.number_of_moves()))
class TestTOAH(unittest.TestCase): """Unit tests for Assignment 1.""" def setUp(self): self.toah = TOAHModel(4) self.optimals = [ 0, 1, 3, 5, 9, 13, 17, 25, 33, 41, 49, 65, 81, 97, 113, 129, 161, 193, 225, 257, 289, 321, 385, 449, 513, 577, 641, 705, 769, 897, 1025, 1153, 1281, 1409, 1537, 1665, 1793, 2049, 2305, 2561, 2817, 3073, 3329, 3585, 3841, 4097, 4609, 5121, 5633 ] def test_all_cheeses(self): for i in range(0, len(self.optimals)): self.toah = TOAHModel(4) self.toah.fill_first_stool(i) tour.tour_of_four_stools(self.toah) self.assertEqual(self.toah.number_of_moves(), self.optimals[i]) def test_0_cheeses(self): self.toah.fill_first_stool(0) tour.tour_of_four_stools(self.toah) self.assertEqual(self.toah.number_of_moves(), self.optimals[0]) def test_1_cheeses(self): self.toah.fill_first_stool(1) tour.tour_of_four_stools(self.toah) self.assertEqual(self.toah.number_of_moves(), self.optimals[1]) def test_2_cheeses(self): self.toah.fill_first_stool(2) tour.tour_of_four_stools(self.toah) self.assertEqual(self.toah.number_of_moves(), self.optimals[2]) def test_3_cheeses(self): self.toah.fill_first_stool(3) tour.tour_of_four_stools(self.toah) self.assertEqual(self.toah.number_of_moves(), self.optimals[3]) def test_4_cheeses(self): self.toah.fill_first_stool(4) tour.tour_of_four_stools(self.toah) self.assertEqual(self.toah.number_of_moves(), self.optimals[4]) def test_5_cheeses(self): self.toah.fill_first_stool(5) tour.tour_of_four_stools(self.toah) self.assertEqual(self.toah.number_of_moves(), self.optimals[5]) def test_6_cheeses(self): self.toah.fill_first_stool(6) tour.tour_of_four_stools(self.toah) self.assertEqual(self.toah.number_of_moves(), self.optimals[6]) def test_7_cheeses(self): self.toah.fill_first_stool(7) tour.tour_of_four_stools(self.toah) self.assertEqual(self.toah.number_of_moves(), self.optimals[7]) def test_8_cheeses(self): self.toah.fill_first_stool(8) tour.tour_of_four_stools(self.toah) self.assertEqual(self.toah.number_of_moves(), self.optimals[8]) def test_9_cheeses(self): self.toah.fill_first_stool(9) tour.tour_of_four_stools(self.toah) self.assertEqual(self.toah.number_of_moves(), self.optimals[9]) def test_10_cheeses(self): self.toah.fill_first_stool(10) tour.tour_of_four_stools(self.toah) self.assertEqual(self.toah.number_of_moves(), self.optimals[10]) def test_11_cheeses(self): self.toah.fill_first_stool(11) tour.tour_of_four_stools(self.toah) self.assertEqual(self.toah.number_of_moves(), self.optimals[11]) def test_12_cheeses(self): self.toah.fill_first_stool(12) tour.tour_of_four_stools(self.toah) self.assertEqual(self.toah.number_of_moves(), self.optimals[12]) def test_13_cheeses(self): self.toah.fill_first_stool(13) tour.tour_of_four_stools(self.toah) self.assertEqual(self.toah.number_of_moves(), self.optimals[13]) def test_14_cheeses(self): self.toah.fill_first_stool(14) tour.tour_of_four_stools(self.toah) self.assertEqual(self.toah.number_of_moves(), self.optimals[14])
if animate: animate_model = TOAHModel(4) animate_model.fill_first_stool(model.get_number_of_cheeses()) move_seq = model.get_move_seq() print(animate_model) for i in range(move_seq.length()): (src_stool, dst_stool) = move_seq.get_move(i) time.sleep(delay_btw_moves) animate_model.move(src_stool, dst_stool) print(animate_model) if __name__ == '__main__': NUM_CHEESES = 5 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, animate=CONSOLE_ANIMATE, delay_btw_moves=DELAY_BETWEEN_MOVES) print(FOUR_STOOLS.number_of_moves()) # Leave files below to see what python_ta checks. # File tour_pyta.txt must be in same folder import python_ta python_ta.check_all(config="tour_pyta.txt")
class ConsoleController: """ Controller for text console. """ def __init__(self, number_of_cheeses, number_of_stools): """ Initialize a new ConsoleController self. @param ConsoleController self: @param int number_of_cheeses: @param int number_of_stools: @rtype: None """ if isinstance(number_of_cheeses, int) and isinstance( number_of_stools, int): self.number_of_cheeses = number_of_cheeses self.number_of_stools = number_of_stools self.model = TOAHModel(self.number_of_stools) self.model.fill_first_stool(self.number_of_cheeses) self.complete = self.model._stools[0][:] else: print("Please enter a NUMBER of cheeses and a NUMBER of stools") def play_loop(self): """ Play Console-based game. @param ConsoleController self: @rtype: None 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. """ flag = True player_input = '' orginial_stool = 0 destination_stool = 0 print( "\nThis is how you play.\n\nEnter from which stool you want to move to and its destination\nas an ordered pair, i.e. (cheese stool location, stool I want to move to), (0,1) means \nI want to move the top cheese on stool 1 to top of stool 2.\nAnd you can only stack smaller cheese on larger cheese: enter quit anytime to exit the game \nother wise we will keep playing\n" ) print() print("here is the model of the game") print(self.model) while flag: if self.complete == self.model._stools[self.number_of_stools - 1]: print("\ncongratulations you won!!!\n") print("You completed the puzzel in " + str(self.model.number_of_moves()) + " moves") flag = False else: player_input = input( "please enter the ordered pair of your movement: ") if player_input.lower() == 'quit': print('goodbye') flag = False else: r = player_input.split(',') if player_input[0] != '(' or player_input[-1] != ')': print( '\nPlease enter the NUMBER of your source and destination stool as an ordered pair!\n' ) else: try: orginial_stool = int(r[0][1:]) destination_stool = int(r[1][:-1]) except ValueError: print( '\nPlease enter the NUMBER of your source and destination stool\n' ) else: if orginial_stool < self.model.get_number_of_stools( ) and destination_stool < self.model.get_number_of_stools( ): move(self.model, orginial_stool, destination_stool) print(self.model) else: print( '\nPlease enter an appropriate stool and/or cheese\n' )