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 """ self.number_of_stools = number_of_stools self.number_of_cheeses = number_of_cheeses self.toah = TOAHModel(number_of_stools) self.toah.fill_first_stool(number_of_cheeses) self.instructions = \ ('The objective of the game is to move the given stack of cheeses \n' 'to the right most stool with the least amount of moves.\n' 'To move a block of cheese from stool X to stool Y \n' 'enter stool numbers in the format x,y\n' "Enter 'Info' if you wish to read this message again\n" "Enter 'Quit' to exit the game") def play_loop(self): """ Play Console-based game. @param ConsoleController self: @rtype: None """ print(self.instructions) command = input("Enter a move or type Quit to exit: ") while command != 'Quit': c = command.strip().split(',') try: if command == 'Info': print(self.instructions) elif len(c) != 2 or not (c[0].isnumeric() and c[1].isnumeric()): raise IllegalMoveError elif not 0 < int(c[0]) <= int(self.number_of_stools): print('Error ' + c[0] + ' is not within the range\n') elif not 0 < int(c[1]) <= int(self.number_of_stools): print('Error ' + c[1] + ' is not within the range\n') elif not self.toah.get_top_cheese(int(c[0]) - 1): print('stool ' + str(int(c[0]) - 1) + ' has No cheese!') else: move(self.toah, int(c[0]) - 1, int(c[1]) - 1) print(self.toah) except IllegalMoveError: print( 'Incorrect input, input must be positve #,#, Info or Quit\n' ) command = input("Enter a move or type Quit to exit: ") print("\nYou have successfully quit the game!")
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)
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. """ def exception_handler(origin, dest, model): """ Handles the exceptions @type origin: int @type dest: int @type model: TOAHModel @rtype: None|str """ try: move(model, origin, dest) except IllegalMoveError: print("That's invalid. Choose other stools. \n") else: pass print("=" * 10 + "WELCOME TO THE TOUR OF ANNE HOY GAME" + "=" * 10) print("\n\n\nInstructions:\n-To exit the game, type '-1' when" "asked for the moves\n-Each stool is numbered, starting" "from 1") print("---Rules---") print("*Enter all information in numeral numbers") print("**The goal of this game is to stack all the cheeses onto the" " last stool") print( "***It is only possible to add cheeses on top of a larger cheese") print("****Only can move existing cheese on a stool") print("*****to EXIT type in -1 as destination") print("") model = TOAHModel(self.number_of_stools) model.fill_first_stool(self.number_of_cheeses) print(model.__str__()) print('') print("Begin") print("") origin = 0 dest = 0 while origin != -1 and dest != -1: origin = int(input("Move from stool: ")) if origin == -1: break dest = int(input("To stool: ")) if dest == -1: break while ((origin > model.num_of_stools - 1) or (origin < 0) or (dest > model.num_of_stools - 1) or (dest < 0) or (len(model._stools[origin]) == 0) or (len(model._stools[dest]) > 0 and (model.get_top_cheese(origin).size > model.get_top_cheese(dest).size))): exception_handler(origin, dest, model) origin = int(input("Move from stool: ")) dest = int(input("To stool: ")) move(model, origin, dest) print(model.__str__())
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 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 """ 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: @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. """ inp = 0 while inp != 'end': inp = input(""" - specify the origin and destination of the cheese in the following format: "orig dest" - in that order with a space in between, be sure both are ints - ensure that you do not place bigger or equal cheese on smaller cheese - to exit the game type "end" """) try: if inp != 'end': #orig, dest = inp.split(' ')[0], inp.split(' ')[1] orig, dest = int(inp.split(' ')[0]), int(inp.split(' ')[1]) if len(self.model._stools[dest] ) == 0: # you forgot this again move(self.model, orig, dest) print(str(self.model)) # elif self.model.get_top_cheese(orig) < self.model.get_top_cheese(dest): elif (self.model.get_top_cheese(orig).size < self.model.get_top_cheese(dest).size): move(self.model, orig, dest) print(str(self.model)) else: print('smaller cheese please') except IndexError: print( 'specify the origin and destination of the cheese in the following format: "orig dest"' ) else: 'GAME OVER'