Assignment 2: CSC148H1 S 20201:Introduction to Computer ScienceAssignment 2CSC148:Assignment 2: BlockyDue date: Tuesday, March 31, 2020 before noon sharp (not 12:10).You may complete this assignment individually or with a partner who can be from any section ofthe course.Learning goalsBy the end of this assignment, you should be able to:model hierarchical data using treesimplement recursive operations on trees (both non-mutating and mutating)convert a tree into a flat, two-dimensional structureuse inheritance to design classes according to a common interfaceCoding GuidelinesThese guidelines are designed to help you write well-designed code that will adhere to theinterfaces we have defined (and thus will be able to pass our test cases).You must:write each method in such a way that the docstrings you have been given in the starter codeaccurately describe the body of the method.avoid writing duplicate code.write a docstring for any class, function, or method that lacks one.You must NOT:change the parameters, parameter type annotations, or return types in any of the methods orfunction you have been given in the starter code.add or remove any parameters in any of the methods you have been given in the starter code.change the type annotations of any public or private attributes you have been given in thestarter code.create any new public attributes.create any new public methods.write a method or function that mutates an object if the docstring doesn’t that it will bemutated.add any more import statements to your code, except for imports from the typing module.You may find it helpful to:2020/3/14 Assignment 2: CSC148H1 S 20201:Introduction to Computer Sciencehttps://q.utoronto.ca/courses/130571/pages/assignment-2 2/14create new private helper methods or functions for the classes you have been given.if you create new private methods or functions you must provide type annotations for everyparameter and return value. You must also write a full docstring for this method asdescribed in the function design recipe(https://q.utoronto.ca/courses/130571/files/5593988/download) *create new private attributes for the classes you have been given.if you create new private attributes you must give them a type annotation and include adescription of them in the class’s docstring as described in the class design recipe(https://q.utoronto.ca/courses/130571/files/5594041/download) *import more objects from the typing moduleoverride the inherited version of the __eq__ special method in some cases (this is not thesame as creating a new public method).While writing your code you can assume that all arguments passed to the methods and functionsyou have been given in the starter code will respect the preconditions and type annotationsoutlined in the methods’ docstrings.Introduction: the Blocky gameBlocky is a game with simple moves on a simple structure. But, like a Rubik’s Cube, it is quitechallenging to play. The game is played on a randomly-generated game board made of squaresof four different colours, such as this:(https://q.utoronto.ca/courses/130571/files/6426939/download?wrap=1)Each player has their own goal that they are working towards, such as creating the largestconnected “blob” of blue. After each move, the player sees their score, which is determined byhow well they have achieved their goal and which moves they have made. The game continuesfor a certain number of turns, and the player with the highest score at the end is the winner. Next,let’s look in more detail at the rules of the game and the different ways it can be configured forplay.The Blocky board and terminologyWe call the game board a ‘block’, which is best defined recursively. A block is either:2020/3/14 Assignment 2: CSC148H1 S 20201:Introduction to Computer Sciencehttps://q.utoronto.ca/courses/130571/pages/assignment-2 3/14a square of one colour, ora square that is subdivided into 4 equal-sized blocks.The largest block of all, containing the whole structure, is called the top-level block. We say thatthe top-level block is at level 0. If the top-level block is subdivided, we say that its four sub-blocksare at level 1. More generally, if a block at level k is subdivided, its four sub-blocks are at levelk+1.A Blocky board has a maximum allowed depth, which is the number of levels down it can go. Aboard with maximum allowed depth 0 would not be fun to play on – it couldn’t be subdividedbeyond the top level, meaning that it would be of one solid colour. This board was generated withmaximum depth of 5:For scoring, the units of measure are squares the size of the blocks at the maximum alloweddepth. We will call these blocks unit cells.Actions and MovesA number of actions can be performed in Blocky. A move is an action that is performed on aspecific block. The actions are:1. Rotate clockwise2. Rotate counterclockwise3. Swap Horizontally4. Swap Vertically5. Smash6. Paint7. Combine8. PassThe Smash action can only be performed on blocks with no children. If a block is smashed, thenit is sub-divided into four new, randomly-generated sub-blocks. Smashing a unit cell is also notallowed (it is already at the maximum depth).2020/3/14 Assignment 2: CSC148H1 S 20201:Introduction to Computer Sciencehttps://q.utoronto.ca/courses/130571/pages/assignment-2 4/14The Paint action sets a block’s colour to a new, specified colour. It can only be performed on unitcells.The Combine action turns a block into a leaf based on the majority colour of its children. It canonly be performed on a block that is subdivided and whose children are at the maximum depth. Ifthere is a majority colour among the four children, then the children are discarded and the blockhas the majority colour. A majority colour means that one colour is the majority amongst allchildren; a tie does not constitute a majority.The Pass action does not mutate the block. It can be used by a player who wishes to skip theirturn.Choosing a block and levelsWhat makes moves interesting is that they can be applied to any block at any level. For example,if the user selects the entire top-level block for this board:and chooses to rotate it counter-clockwise, the resulting board is this:But if instead, on the original board, they rotated the block at level 1 (one level down from the toplevelblock) in the upper left-hand corner, the resulting board is this:2020/3/14 Assignment 2: CSC148H1 S 20201:Introduction to Computer Sciencehttps://q.utoronto.ca/courses/130571/pages/assignment-2 5/14And if instead they were to rotate the block a further level down, still sticking in the upper-leftcorner, they would get this:Of course there are many other blocks within the board at various levels that the player couldhave chosen.PlayersThe game can be played solitaire (with a single player) or with two to four players. There are threekinds of players:1. A human player chooses moves based on user input.2. A random player is a computer player that, as the name implies, chooses moves randomly.3. A smart player is a computer player that chooses moves more intelligently: It generates a setof random moves and, for each move, checks what its score would be if it were to make thatmove. Then it picks the one that yields the best score.Goals and scoringAt the beginning of the game, each player is assigned a randomly-generated goal. There are twotypes of goal:1. Blob goal.The player must aim for the largest “blob” of a given colour c. A blob is a group of connected2020/3/14 Assignment 2: CSC148H1 S 20201:Introduction to Computer Sciencehttps://q.utoronto.ca/courses/130571/pages/assignment-2 6/14blocks with the same colour. Two blocks are connected if their sides touch; touching cornersdoesn’t count. The player’s score is the number of unit cells in the largest blob of colour c.2. Perimeter goal.The player must aim to put the most possible units of a given colour c on the outer perimeterof the board. The player’s score is the total number of unit cells of colour c that are on theperimeter. There is a premium on corner cells: they count twice towards the score.Notice that both goals are relative to a particular colour. We will call that the target colour for thegoal.In addition to the points gained by the player from achieving their goal, a player can also losepoints based on the actions they perform.Rotating, Swapping, and Passing cost 0 points.Painting and Combining cost 1 point each time they are performed.Smashing costs 3 points each time it is performed.Congurationsof the gameA Blocky game can be configured in several ways:Maximum allowed depth.While the specific colour pattern for the board is randomly generated, we control how finelysubdivided the squares can be.Number and type of players.There can be any number of players of each type. The “difficulty” of a smart player (how hardit is to play against) can also be configured.Number of moves.A game can be configured to run for any desired number of moves. (A game will end early ifany player closes the game window.)Setup and starter code1. Download the zip file that contains the starter code here a2.zip(https://q.utoronto.ca/courses/130571/files/6427246/download?wrap=1) .2. Unzip the file and place the contents in pycharm in your a2 folder (remember to set your a2folder as a sources root)3. You should see the following files and directories:actions.pyblock.pyblocky.pygame.pygoal.pyplayer.pyrenderer.pysettings.pyexample_tests.py2020/3/14 Assignment 2: CSC148H1 S 20201:Introduction to Computer Sciencehttps://q.utoronto.ca/courses/130571/pages/assignment-2 7/14the images directoryTask 1: Understand the Block data structureSurprise, surprise: we will use a tree to represent the nested structure of a block. Our trees willhave some very strong restrictions on their structure and contents, however. For example, a nodecannot have 3 children. This is because a block is either solid-coloured or subdivided. If it is solidcoloured,it is represented by a node with no children. If it is subdivided, it is subdivided intoexactly four sublocks. Representation invariants document this rule and several other criticallyimportant facts.1. Open block.py , and read through the class docstring carefully. A Block has quite a fewattributes to understand, and the Representation Invariants are critical.2. Draw the Block data structure corresponding to the game board below, assuming themaximum depth was 2 (and notice that it was indeed reached). You can just write a letter foreach colour value. Assume that the size of the top-level block is 750.Did you draw 9 nodes? Do the attribute values of each node satisfy the representationinvariants? Note: If you come to office hours, we will ask to see your drawing beforeanswering questions!Task 2: Initialize Blocks and draw themFile(s): block.py , blocky.pyWith a good understanding of the data structure, you are ready to start implementing some of thekey functionality. You should be able to run the game, though it will only show you a blank board.In order to see an actual Blocky board, you must:1. To make a Block drawable, you must implement _block_to_squares in blocky.py2. To make a Block interesting, you must implement Block.smash in block.pyFor implementing _block_to_squares , read the documentation from Block , paying special note ofthe positions and sizes of a Block and its children. Here is the strategy to use for implementingBlock.smash : If a Block is not yet at its maximum depth, it can be subdivided; this method willdecide whether or not to actually do so. To decide:2020/3/14 Assignment 2: CSC148H1 S 20201:Introduction to Computer Sciencehttps://q.utoronto.ca/courses/130571/pages/assignment-2 8/14Use function random.random to generate a random number in the interval [0, 1).Subdivide if the random number is less than math.exp(-0.25 * level) , where level is the levelof the Block within the tree.If a Block is not going to be subdivided, use a random integer to pick a colour for it from thelist of colours in settings.COLOUR_LIST .Method Block.smash is responsible for giving appropriate values to the attributes of all Block swithin the Block it generates. Notice that the randomly-generated Block may not reach itsmaximum allowed depth. It all depends on what random numbers are generated.Check your work: We have provided an implementation of Block.__str__ that allows you to printa Block in text form. Use this to confirm that your Block.__smash__ method works correctly. Wehave also provided some pytest code for testing the _blocks_to_squares function in the blocky.pymodule. See example_tests.py for the test case. If both are working properly, then you should seea correctly initialized game board when you run the game.Task 3: The goal classes and random goalsFile(s): goal.py , settings.pyWe need to have some basic ability to set goals and compute a player’s score with respect totheir goal. Get familiar with the abstract Goal class in goal.py . It defines two abstract methods:score and description . Goal has two subclasses: BlobGoal and PerimeterGoal . The basicskeletons for these classes are provided.Implement the function generate_goals in the goal.py module. This function generates a list ofrandom goals. Each goal is of the same type (i.e., BlobGoal or PerimeterGoal ) but has a differentcolour. The supported colours can be found in the settings.py module in a Python list calledCOLOUR_LIST .Once you have appropriately implemented generate_goals , implement the BlobGoal.descriptionand PerimeterGoal.description methods. You should see these descriptions at the bottomCSC148留学生作业代做、代写Computer Science作业、Python编程语言作业调试、Python作业代做 of thewindow when running the game.Task 4: The Player class and random playersFile(s): player.pyGet familiar with the abstract Player class in player.py . A concrete implementation of a humanplayer is given to you; see: HumanPlayer . In order for the user to be able to play the game, theymust be able to select by hovering over it with the mouse. See the HumanPlayer.get_selected_blockmethod. For this to work, you must implement the function _get_block in the player.py module.Note: Do not make changes to the HumanPlayer class.In order to support more than one player, you will need to implement the create_players functionin players.py . This function will generate the right number of human players, random players, and2020/3/14 Assignment 2: CSC148H1 S 20201:Introduction to Computer Sciencehttps://q.utoronto.ca/courses/130571/pages/assignment-2 9/14smart players (with the given difficulty levels), in that order. Give the players consecutive playeridentifiers (IDs), starting at 0. Assign each player a random goal.Check your work: You should be able to run a game with only human players. Try runningfunction two_player_game – you can uncomment out the call to it in the main block of module game .To select a block for action, put the cursor anywhere inside it and use the W and S keyboard keysto select the desired level. The area to the right of the game board gives you instructions on thekey to press for each action.So far, no real moves are happening and the score never changes. But, you should see the boardand see play pass back and forth between players. Finally, the game should end when thedesired number of moves has been reached.Task 5: The Blocky actionsLet’s improve playability by supporting all the actions in Blocky. Each of these actions will mutateBlocks in some way.Before you begin, you should review the representation invariants for class Block . They arecritical to the correct functioning of the program, and it is the responsibility of all methods in theclass to maintain them. When you are done, double check that each of your mutating methodsmaintains the representation invariants of class Block .Implement also the Block._update_children_positions method and consider it as a handy helpermethod for other Block methods than change the order of children. The (x, y) coordinates for theupper left corner of a child block are different depending on which child it is!Check your work: Now when you play the game, you should see the board changing. You mayfind it easiest to use function solitaire_game to try out the various moves.Task 6: Implement scoring for perimeter goalsFile(s): goal.pyNow let’s get scoring working. The unit we use when scoring against a goal is a unit cell. The sizeof a unit cell depends on the maximum depth in the Block . For example, with maximum depth of4, we might get this board:2020/3/14 Assignment 2: CSC148H1 S 20201:Introduction to Computer Sciencehttps://q.utoronto.ca/courses/130571/pages/assignment-2 10/14If you count down through the levels, you’ll see that the smallest blocks are at level 4. Thoseblocks are unit cells. It would be possible to generate that same board even if maximum depthwere 5. In that case, the unit cells would be one size smaller, even though no Block has beendivided to that level.Notice that the perimeter may include unit cells of the target colour as well as larger blocks of thatcolour. For a larger block, only the unit-cell-sized portions on the perimeter count. Forexample, suppose maximum depth were 3, the target colour were red, and the board were in thisstate:Only the red blocks on the edge would contribute, and the score would be 4: one for each of thetwo unit cells on the right edge, and two for the unit cells inside the larger red block that areactually on the edge. (Notice that the larger red block isn’t divided into four unit cells, but we stillscore as if it were.)Remember that corner cells count twice towards the score. So if the player rotated the lowerright block to put the big red block on the corner (below) the score would rise to 6:2020/3/14 Assignment 2: CSC148H1 S 20201:Introduction to Computer Sciencehttps://q.utoronto.ca/courses/130571/pages/assignment-2 11/14Now that we understand these details of scoring for a perimeter goal, we can implement it.1. It is very difficult to compute a score for a perimeter goal or a blob goal by walking through thetree structure. (Think about that!) The goals are much more easily assessed by walkingthrough a two-dimensional representation of the game board. Your next task is to provide thatpossibility: in module goal.py , define function _flatten .2. Now implement the score method in class PerimeterGoal to truly calculate the score. Begin byflattening the board to make your job easier!Check your work: Now when you play the game, if a player has a perimeter goal, you shouldsee the score changing. Check to confirm that it is changing correctly.Task 7: Implement scoring for blob goalsFile(s): goal.pyScoring with a blob goal involves flattening the tree, iterating through the cells in the flattenedtree, and finding out, for each cell, what size of blob it is part of (if it is part of a blob of the targetcolour). The score is the biggest of these.But how do we find out the size of the blob that a cell is part of? (Sounds like a helper method,eh?) We’ll start from the given cell andif it’s not the target colour, then it is not in a blob of the target colour, so this cell should report0.if it is of the target colour, then it is in a blob of the target colour. It might be a very small blobconsisting of itself only, or a bigger one. It must ask its neighbours the size of blob that theyare in, and then use that to report its own blob size. (Sounds, recursive, eh?)A potential problem with this is that when we ask a neighbour for their blob size, they will count usin that blob size, and this cell will end up being double counted (or worse). To avoid such issues,we will keep track of which cells have already been “visited” by the algorithm. To do this, makeanother nested list structure that is exactly parallel to the flattened tree. In each cell, store:-1 if the cell has not been visited yet0 if it has been visited, and it is not of the target colour2020/3/14 Assignment 2: CSC148H1 S 20201:Introduction to Computer Sciencehttps://q.utoronto.ca/courses/130571/pages/assignment-2 12/141 if it has been visited and is of the target colourYour task is to implement this algorithm.1. Open goal.py and read the docstring for helper method BlobGoal._undiscovered_blob_size .2. Draw a 4-by-4 grid with a small blob on it, and a parallel 4-by-4 grid full of -1 values. Pick a cellthat is in your blob, and suppose we call BlobGoal._undiscovered_blob_size . Trace what themethod should do. Remember not to unwind the recursion! Just assume that when youask a neighbour to report its answer, it will do it correctly (and will update the visited structurecorrectly).3. Implement BlobGoal._undiscovered_blob_size .4. Now replace your placeholder implementation of BlobGoal.score with a real one. Use_undiscovered_blob_size as a helper method.Although we only have two types of goal, you can see that to add a whole new kind of goal, suchas stringing a colour along a diagonal, one would only have to define a new child class of Goal ,implement the score method for that goal, and then update the code that configures the game toinclude the new goal as a possibility.Check your work: Now when you play the game, a player’s score should update after eachmove, regardless of what type of goal the player has.Task 8: Add random playersFile(s): player.pyBefore you can implement a Player sub-class, you need to understand the game loop. Ingame.py , the Game.run_game method contains what seems like an infinite loop. This is the gameloop, and it will iterate many times per second. On each iteration, the game will ask the operatingsystem for any events that have occured (i.e., it will call pygame.event.get() ). The game itselfreacts to only the events it is interested in – we call this event-driven programming. The loop willexit if the event indicates that the user would like to quit the game (e.g., if they have closed thewindow). Otherwise, the event is forwarded to a Player object. After all events are processed, thegame is updated by asking the player to make a move. Because the game loop needs to keepiterating quickly, our Player object must respond quickly.The HumanPlayer object is already implemented and reacts to specific keyboard events. When akeyboard key is pressed, the HumanPlayer object will translate the key into a desired action (ifpossible). A very short time (fractions of a second) later, the game will ask the player to make amove. If there is no desired action, then the HumanPlayer will not make a move (i.e., by returningNone ). Otherwise, the action that was translated from a keyboard event is converted into a movebased on the block the user is selecting.For both RandomPlayer and SmartPlayer , we have provided a private attribute _proceed . Thisattribute is initially False . Only when the user clicks their mouse will the attribute be set to True(e.g., see RandomPlayer.process_event ) This communicates that the RandomPlayer or SmartPlayershould make a move. Once a move is determined, you must set the _proceed attribute back to2020/3/14 Assignment 2: CSC148H1 S 20201:Introduction to Computer Sciencehttps://q.utoronto.ca/courses/130571/pages/assignment-2 13/14False so that the next time it is this player’s turn, the player will wait for a mouse click again. Theskeleton code for this is already provided for you in both RandomPlayer.generate_move andSmartPlayer.generate_move .We will now implement the class RandomPlayer . Do not change the following methods:RandomPlayer.get_selected_blockRandomPlayer.process_eventYour first task is to implement the initializer ( RandomPlayer.__init__ ). You must inherit the attributesof the Player class and document them. Once that is done, you will need to implement how theRandomPlayer will make a random but valid move on the board. We will do this in theRandomPlayer.generate_move method. You must note mutate the given board parameter whengenerating a random move! In order to assess whether a move is valid, the RandomPlayer mustcreate a copy of the board for each move it wants to try. To do this, to implement theBlock.create_copy method. Once you have a copy, you can mutate that copy by applying the moveon it and checking to see if it was successful. If you implemented Block.create_copy correctly, thenmutating the copy should not impact the original board.Hint: No block from your copy should not have the same id as a block from the original board.But you can always find the block you copied from the original board based on the position andlevel of the copy. Do you already have a function that can do this?Task 8: Add smart playersFile(s): player.py , block.pyWe will now implement the class SmartPlayer . Do not change the following methods:SmartPlayer.get_selected_blockSmartPlayer.process_eventYour first task is to implement the initializer ( SmartPlayer.__init__ ). You must inherit the attributesof the Player class and document them. A SmartPlayer has a “difficulty” level, which indicates howdifficult it is to play against it.Next, implement how the SmartPlayer will make moves on the board by completing theSmartPlayer.generate_move method. A SmartPlayer randomly generates n valid moves, where n isthe SmartPlayer ’s difficulty value. It then picks the one that yields the best score, without takinginto account any penalty that might apply to an action.When scoring each of the valid moves, you must not mutate the given board parameter. TheSmartPlayer must create a copy of the board for each move it wants to assess. One you have acopy, you can mutate that copy by applying the move on it.If no best move was found and the current score is best, the SmartPlayer should pass.Check your work: Now you can run games with all types of players.2020/3/14 Assignment 2: CSC148H1 S 20201:Introduction to Computer Sciencehttps://q.utoronto.ca/courses/130571/pages/assignment-2 14/14Polish!Take some time to polish up. This step will improve your mark, but it also feels so good. Here aresome things you can do:Pay attention to any violations of the “PEP8” Python style guidelines that PyCharm points out.Fix them!In each module you are submitting, run the provided python_ta.check_all() code to check forerrors. Fix them!Check your docstrings to make sure they are precise and complete and that they follow theconventions of the Function Design Recipe and the Class Design Recipe.Read through and polish your internal comments.Remove any code you added just for debugging, such as print statements.Remove any pass statement where you have added the necessary code.Remove the word “TODO” and/or “FIXME” wherever you have completed the task.Take pride in your gorgeous code!Submission instructionsThe following files are not to be submitted: actions.py , game.py , renderer.py , settings.py . Yourcode should run as if they were not modified from the original starter code.1. Login to MarkUs and create a group for the assignment (or specify that you’re working alone).2. DOES YOUR CODE RUN?!3. Submit the files: block.py , blocky.py , goal.py , player.py .4. On a fresh Teaching Lab machine, download all of the files you submitted, and test your codethoroughly. Your code will be tested on the Teaching Lab machines, so it must run in thatenvironment.5. Congratulations, you are finished with your third (and last) assignment in CSC148! Go havesome chocolate or do a cartwheel. :)转自:http://www.daixie0.com/contents/3/4902.html