COMP 202
posted: due:
Primary Learning Objectives
Uno
Summer 2020
Friday, June 12, 2020 Monday, June 22, at 23:59
By the end of this assignment, students should be able to…
• apply problem-solving to a given problem and implement the solution in Python • collaboratively solve a problem and write Python code
Submission instructions
• This file is contained within a .zip file. Also in the .zip file are a series of Python code files. You will write the solutions to this assignment in these Python code files. (Make sure to unzip the zip file, as you cannot write solutions in files which are inside a zip file.)
• When ready to submit, upload the student ai.py Python code file to codePost under the appropriate heading. If working in a team, both team members must submit the same code file.
• You can submit multiple times on codePost, so don’t worry if you realize that your current submission contains an error.
• Submit early, submit often! (Computer crashes do occur, and codePost may be overloaded during rush hours.)
Coding instructions
Please read the following instructions carefully to avoid losing marks.
• You must include your name and McGill ID number at the top of each .py file that you submit. By doing so, you are certifying that the code file is entirely your own, and represents the result of your sole effort.
• You are expected to comment your code, on average 1 comment for every 5-6 lines.
• You are expected to use descriptive variable names whenever possible. Do not use variable names like x, y or z (unless you are dealing with a mathematical function). Instead, use names like user input, sum of numbers, or average value.
• Some questions will ask you to print text to the screen in the exact same form as given in the examples. Make sure that the output of your program exactly matches the output of the examples in these cases or marks will be deducted.
1
• Some questions will ask you to define a function. The function you define must have the same name, parameters and return value as specified. Further, questions may have examples to show the output that your program is required to produce. Make sure that the output of your program exactly matches the output of the examples. (Input values are highlighted in gray, as they should be input by the user.)
• Those with prior programming knowledge may be able to solve a question with advanced Python concepts. Although it may be more efficient to do so, it defeats the purpose of the assignment as we are testing on specific language constructs. Therefore, please only use concepts (language constructs, types, functions, methods, etc.) seen in class. Solutions that use Python concepts not seen in class will be penalized. Further, the use of third-party modules, unless explicitly specified, is not permitted.
Policies
• Late assignments will be accepted up to 2 days (48 hours) after the due date and will be penalized by 10 points per day. Note that submitting one minute late is the same as submitting 23 hours late. We will deduct 10 points for any student who submits or resubmits after the due date irrespective of the reason, be it wrong file submitted, wrong file format submitted or any other reason. This policy will hold regardless of whether or not the student can provide proof that the assignment was indeed “done” on time.
• If your program does not work at all, e.g., gives an error and does not produce any output, zero points will be given for that question. If your program executes without errors but produces incorrect output, partial marks may be awarded based on the correctness of the code.
• If anything is unclear, it is up to you to seek clarification by either directly asking a TA during office hours or making a post on Piazza.
• This project may optionally be done in teams of two; you may work alone if you prefer. Only you, and your partner if you choose to work with one, may work on this assignment. Do not ask friends or tutors to do this project for you. You must not copy any other person’s work in any manner (electronically or otherwise), nor give a copy of your work to any other person, excluding your teammate. Code similarity detection software will be run on all assignments. Students under suspicion of plagiarism will be reported to their faculty’s Disciplinary Officer.
Working with a partner
There are several tools and strategies you can use if you choose to work with a partner.
• First, to find a partner, there will be a post on Piazza with some instructions to do so.
• When working with a partner, it is highly suggested to do some audio and/or video confer- encing with them in order to discuss ideas and implementation details. Feel free to use any online platform (Zoom, FaceTime, WhatsApp, etc.).
• There are a few websites that allow for collaborative code editing. For example, codeshare.io allows you to work on a code file with another person. Alternatively, you could just copy and
2
paste the code into a Google Doc and work on it together.
• Comments are extremely important to write for this project. Comments will let you describe to your partner what you are trying to do without having to explain it to them verbally.
• If your partner writes some code, make sure to look it over and test it for yourself, to make sure it works.
3
The time has come for the first annual COMP 202 Uno Tournament.
Your task in this project is to design and implement an algorithm that can compete in a game of Uno.
Uno is a popular card game (similar to Crazy Eights) in which each player holds a hand of cards, and tries to be the first one to get rid of all the cards in their hand. Players are seated in a circle, and take turns in sequence (clockwise). In the middle of the table is an ‘up card’, a card placed face-up on the table. When it is your turn, you can play one of the cards in your hand on top of the up card, making that card the new up card, and at the same time reducing the size of your hand by 1.
The card you choose to play on top of the up card must meet the following rules:
• Most cards have a color: either red, green, blue or yellow. You may play a card if it has the same color as the up card.
• Each colored card has a rank: either a number from 0-9, or a special rank such as ‘skip’, ‘reverse’, or ‘draw 2.’ You may play a card if it has the same rank as the up card, even if it is of a different color.
• There are two kinds of ‘wild’ cards: ordinary wild cards, and ‘draw 4’ wild cards. Either kind can be played on any up card. When you do so, you are able to ‘call’ a new color, specifying what color the next player must play.
Some special cards have an effect after being played:
• If a ‘skip’ card is played, the next player in sequence (in clockwise order) is skipped.
• If a ‘draw 2’ card is played, the next player in sequence must draw two cards from the deck, and is then skipped.
• If a ‘wild draw 4’ card is played, the next player in sequence must draw four cards from the deck, and is then skipped. (The player who played the ‘wild draw 4’ card then must call a color, as with a normal wild card.)
• If a ‘reverse’ card is played, the sequence of players is reversed to counterclockwise (or back to clockwise, if it had been previously reversed).
The object of the game is to run out of cards. When a player runs out of cards, the game ends and they are awarded points based on the cards remaining in the opponents’ hands, as follows:
1. For every numbered card held by an opponent, the winner of the round gets points equal to that number (5 points for a 5, 1 point for a 1, 0 points for a 0, etc.)
2. For every ‘special’ coloured card (draw two, reverse and skip) held by an opponent, the winner of the round gets 20 points.
3. For every ‘wild’ card (either normal or draw 4) held by an opponent, the winner of the round gets 50 points.
Normally, players continue playing game after game until one player reaches 500 points, and is declared the overall winner of the game.
4
Requirements
The template code provided to you contains Python code files that implement the rules of Uno. This code includes shuffling the deck, dealing hands to players, drawing an initial up card, enforcing the rules mentioned above, declaring a winner and calculating the scores. The only thing it does not do is actually choose a card to play from a hand (or call a color if a wild card is played).
You, and possibly your partner if you choose to work with a classmate, will be writing your own code to do those two things: play a card from your hand, and call a color in case you choose to play a wild card. There will be one method for each component, which you must fill in inside the student ai.py file. The main Uno game code will import your file and call your methods at the appropriate times in the game.
In particular, the UnoAI class inside the student ai.py file has two methods which you must complete:
play method
play(hand, up card, called color, game state)
Collectively, these four arguments tell your method important information about the current state of the game, with which you will decide which card to play.
• hand: a list of Card objects representing the cards in your hand
• up card: a Card object representing the current up card
• called color: the current called color (only important if the ‘up card’ is a wild card).
• game state: a way to find out other miscellaneous things about the state of the game (as listed below), for use in building a more sophisticated strategy.
The method should return the index of the card in the hand list that you want to play. In the event that you cannot play any card, you should return -1. (Note that returning -1 for a hand in which you can legally play a card is an error.)
If you wish, you may call methods on the GameState object (the fourth argument), to access detailed information about the state of the game. These are the methods you can call:
• get num cards in hand of upcoming players(): returns a list, of length equal to the num- ber of players minus 1. The integer at index 0 of the list corresponds to how many cards the next player after you has. The integer at index 1 of the list corresponds to how many cards the the second player after you has (e.g., the person sitting next to the person next to you), and so on. (Note: when we say ‘the next person,’ we assume that there was no skip or reverse played.)
• get most recent color called by upcoming players(): returns a list just like above, ex- cept instead of integers, it contains strings corresponding to color names (‘red’, ‘green’, ‘yellow’ or ‘blue’). The colors correspond to the most recent color each player had called the last time they played a wild card. (If a player has not yet played a wild card this round, the color will be the string ‘none’.)
5
• get total score of upcoming players(): returns a list giving you the total cumulative score for each player (in the 50,000 game match, as described in the Tournament section below), in the same order as the above functions.
• get played cards(): returns a list of the cards (as Card objects) that have been played, in order, since the last deck reshuffling. (A deck reshuffling occurs if/when the draw pile runs out of cards, and consists of the cards in the discard pile being reshuffled and turned face down to become the new draw pile. Deck reshuffling does not happen very often.)
Note: Do not call any other methods or access any attributes of the game state argument.
Some of the code above mentions Card objects. These are objects of the Card class, and as such,
have the following three attributes, which you may access as you like:
• color: a string for the card’s color (refer to the COLORS list defined at the top of card.py to see all the possibilities).
• rank: a string for the card’s rank (refer to the RANKS list).
• number: an integer for the card’s number, if the card’s rank is ‘number’, and -1 otherwise.
call color method
The other method you must write is as follows:
call color(hand)
This method must return what color you want to call when you play a wild card. The provided game code will only call this method if your play method decides to play a wild card.
The method takes only one argument: a list of Card objects that are in your current hand. It must return one of the four valid colors.
Hints
• If your opponent wins the round, they will gain points based on the cards in your hand. It might be a good idea to minimize the number of points in your hand at any time (getting rid of wild cards as soon as possible, then special cards, then 9’s, then 8’s, and so on).
• However, it is not good to waste wild cards unless you really need to use them. It may be better to play them only when you absolutely have to.
• If you have a lot of points of a particular color, it may be good to call that color when you next play a wild card, to have a higher chance to get rid of those cards sooner.
• Suppose the up card is a red 5. You have both a red 3 and a blue 5. Should you change the color to blue or keep it red? (Similar to the decision of what color to call when you play a wild card.) Note that the up card may be red because your opponent wanted it to be red, so it may be in your best interests to change it.
• In a Uno deck, there are only four 0 cards (one of each color), compared to eight of every other number (two of each color). Playing a 0 card means it will be less likely for an opponent
6
to be able to change the color before you get a chance to play again. If you have multiple cards of the same color, with one being a 0, you may want to play the 0 early on, since you will be more likely to be able to get rid of another card of the same color on your next turn.
• Decisions on what card to play can be influenced by how big your hand is. If you only have a few cards left, you may want to take more short-term risks to win; if you have a lot of cards, you may want to instead just ditch as many points as possible, so that your loss is as small as possible.
• As these hints are available to everyone, you could expect many of your opponents to im- plement these same ideas. It may be a good idea to anticipate their moves, and counteract them before they are made. For instance, if everyone is trying to ditch high point values first, you could try to keep high point values early in the game, so that it’s less likely someone can switch the color on you later on by playing a card of the same rank. Or, if everyone is going to try to switch the color to favor their hand, you might want to deliberately call a different color when you have the choice, depending on circumstances.
How to test your code
In order to thoroughly test your two methods, a comprehensive test suite has been developed. When you run the tests.py file, it will execute your methods on 10,000 random hands, and ensure that your methods return a correct result in each case. It is highly recommended that you perform this operation on your code before submission. Code that does not pass the tests will not receive a passing grade.
You will observe that if you try running the tests.py file without writing any code, there will be a large number of error messages. When just starting out to test your code, you may want to limit the number of tests performed, for example by writing an if statement inside the tests.py file to break out of the loop after num total reaches 100, say. But make sure to remove that condition before submitting, so that you can run your code against all 10,000 tests, or you may not receive a passing grade if a test failed.
We also provide to you the main.py file. This file contains only one test, so you may choose to use this test first.
Note that although you will submit to codePost, no tests will run on your code on upload; you must run the tests.py file manually before upload.
Tournament format
During our testing of your code, your algorithm will face off against all other submitted algorithms in a round-robin tournament. Each game will have four players at the table. The game will continue with the same four players until 50,000 rounds have been played, at which point a winner will be selected. This large number of rounds will ensure that any so-called ‘lucky deals’ will even out over time, leaving the superior program the victor.
7
Grading
The grading of this assignment will be dependent on your submission’s performance in the afore- mentioned tournament.
If your team’s submission places in the top four positions (judged by total cumulative score) of the tournament, you will receive a bonus to your final course grade, based on which position you obtained. First place will obtain a 1% bonus. Second place will obtain 1 0.75% bonus; third will receive 0.5% and fourth will receive 0.25%.
If you do not place amongst the top four positions, I will inspect your code to judge whether you attempted a non-trivial, intelligent approach. Your code must be well-commented and you must describe your strategy in the docstring of the methods. Points will be awarded based on how thorough and creative I judge your program to be.
Note: if your code does not pass the tests, as described above, and as such cannot be entered into the tournament at all, you will not receive a passing grade.
8