Setting up your workspace:
You are expected to work in teams of 4.
You will need to meet regularly with your team and collaborate using the workspace in Ed.
One member needs to:
Create an Ed workspace for your team and share it with the other members
Upload the code sca old into the workspace and share it with the team.
Testing your code:
The assignment is broken up into individual coding tasks.
You can code and test using the Ed lessons.
These lessons are not to submit your work, only to test your code against some basic automated checks.
If tasks need imported code from earlier tasks, the automated tests will use their own version however you will need to copy and paste your solutions from previous tasks to do your own testing.
Skeleton/Starter Code:
Tasks will start with some skeleton/starter code for each method in a class.
You will get less starting code as you go through the tasks.
Make sure function and variable names match what is listed in the task; these will be needed to pass automated tests
Hearts
In this assignment, you’ll be using the more advanced concepts you’ve learned to build another textbased game, of the popular card game Hearts. More precisely, we will use rules of the variant called Black Lady, but we will use the name “Hearts” for simplicity.
In Hearts, players avoid certain cards and try to have the lowest score by the time one player eventually reaches 100.
It is usually played with 4 players, but many versions works with 3-5 (including ours).
You can learn the game using the online versions, like this one. The complete version of this assignment will follow almost the same rules as the one linked.
Be sure you are familiar with the game before getting started.
You will code the full set of rules throughout the tasks one part at a time.
One round of hearts (assuming 4 players):
Before each round starts:
Start a new deck (52 cards).
Deal 13 cards to each player.
Each player picks 3 cards to pass o� to another player.
Once the round begins, players take turns playing all 13 tricks:
Each trick is de ned by a player playing one card each.
The player who has the Two of Clubs starts the leads the �rst trick by playing that card. At the end of each trick, the player with the highest ranking card from the suit of the lead card takes the trick.
The winner/taker of a trick receives all points from that trick, and leads the next trick. There are 26 points in the deck:
Each card of the Hearts suit is worth 1 point.
The Queen of Spade is worth 13 points.
Rounds repeat until someone reaches a target score limit (usually 100 points), after which the player with the lowest score wins. If there are multiple players with the lowest score, rounds continue until a winner is decided.
Players attempt to minimise the number of points they score by avoiding taking tricks with penalty cards.
Special case:
If one player wins all 26 points within a round, they receive 0 points, while all others receive 26 (this is known as “Shooting the Moon”)
Task 1: Cards
The rst task is to create your own module cards.py to represent cards from a standard deck of 52 playing cards as Python objects.
Required module: Enum
Use the module enum to hold the rank and suit of a card. We use enum to make custom data types that hold a range of unique values.
For example, here’s an object for the �rst �ve Roman numerals
from enum import Enum class RomanNumerals(Enum):
I = 1
II = 2
III = 3
IV = 4
V = 5
var1 = RomanNumerals.I
var2 = RomanNumerals.IV
print(var1 == var2) #prints False
print(var2) # prints RomanNumerals.IV
print(var2.name) # prints IV
print(var2.value) # prints 4
1.1 class Rank
Create a class Rank(Enum) within cards.py that represents the range of ranks within a suit. Please use the following strings for naming your values:
(Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace)
For Hearts, an Ace is the strongest rank of a suit, so we recommend you start your enum with Two =2 .
You will also need to de�ne a magic method that will allow you to compare ranks like regular integer types. To use the inequality operators < or > on Python objects you need __lt__
1.2 class Suit
Create a class Suit(Enum) within cards.py that represents the range of suits within a deck of cards.
In Hearts the suits have ordered value, de�ned below in increasing order:
(Clubs, Diamonds, Spades, Hearts) Again please use the above strings for naming your values. The magic method __lt__ is needed to compare suits.
1.3 class Card
Finally, create a class Card to represent an object represents a combination of Rank and Suit . We need to be able to sort a list of cards like a list of regular integers, for which you need to implement the magic methods __eq__ and __lt__ .
Create instance variables rank and suit so that they can be accessed using Card.rank or Card.suit and return the corresponding Rank or Suit object.
You will need the following magic methods de�ned for this class:
__init__(self, rank, suit) – initialise class by setting the passed arguments as instance variables
__eq__ – cards can only be equal if they have the same suit and rank
__lt__ – compare suit �rst then rank to determine if a card is less than the other
__str__ – to use print() or str() on our custom objects
__repr__ – should simply call self.__str__() , allows you to see the same string of your card rather than <cards.Card object at 0x000001FECBCB0640> in the error log or when printing a list of cards directly.
Examples
You should be able to use the class from a di�erent �le like below:
from cards import Card, Rank, Suit
card1 = Card(Rank.Two, Suit.Spades)
card2 = Card(Rank.Ace, Suit.Hearts)
print(f”{card1}, {card2}”)
Task 2: Basic AI Player
Task 2 is to create an object BasicAIPlayer , tracking attributes such as a player’s hand of cards and deciding what card to play on a given trick.
We’ll start with a basic AI rather than a human player so that you can simulate rounds for building out the game logic, and later tasks will introduce user input into the game.
2.1 Player Attributes
This object will be called with a string argument for the player’s name, which should be returned by the magic methods __str__ and __repr__ .
BasicAIPlayer will also need the following instance variables:
hand for the list of cards held by player (initially empty),
round_score to track points earned in current round,
total_score to track points earned in total game.
2.2 Valid Play
Implement the method check_valid_play(self, card, trick, broken_hearts) that takes the arguments:
card : a card from the player’s hand to validate play against,
trick : a list of cards played in the trick so far, in order of play,
broken_hearts : Boolean to represent if hearts have been broken yet (see below). and returns a tuple with the following:
Boolean type where True represents a valid play and False an invalid one,
String for the error message associated with the invalid play.
The rules that determine a valid play are:
If a player is leading the trick, they may lead with any card except:
If the player holds the Two of Clubs. In this case, they must always play it.
A trick cannot be led by Hearts if hearts have not been broken yet ( broken_hearts == False ) unless there is no other option. In other words, a player cannot lead with Hearts unless Hearts have already been played in this round. If a player is not leading:
They must follow suit (play a card from the same suit as the lead card).
If they cannot, they may play any card, unless this is the �rst trick of the round, in which case they cannot play Hearts or the Queen of Spades.
We say that Hearts are broken when someone has no cards from the lead suit and plays one from Hearts instead.
Note that you can test whether a trick is the �rst of a round by checking if the Two of Clubs is the lead card.
Returning the error message in a string will be used in later tasks where you implement the human player, you will not need to output it for this task.
Example:
from cards import Card, Rank, Suit
player = BasicAIPlayer(“Test Player 1”)
player.hand = [Card(Rank.Four, Suit.Clubs), Card(Rank.Ace, Suit.Hearts), Card(Rank.King, Suit.Spades), trick, broken_hearts = [Card(Rank.Seven, Suit.Spades), Card(Rank.Eight, Suit.Spades)], False
print(player.check_valid_play(player.hand[0], trick, broken_hearts))
>>> (False, ‘Player still has cards from the suit of the current trick’)
2.3 Playing and Passing Cards
The game objects (which you’ll create in later tasks) will interact with the player object by adjusting the attributes from above, as well as the methods play_card() to determine a card to play on a given trick and pass_cards() to return their chosen 3 cards to pass o at the start of each round.
Implement play_card(self, trick, broken_hearts) so that it returns the lowest ranking card from the player’s hand that constitutes a valid play, removing it from self.hand before returning.
The arguments passed are:
trick : a list of cards played in the trick so far, in order of play.
broken_hearts : Boolean to represent if hearts have been broken yet.
play_card for the basic AI must always play the lowest ranking card possible.
Implement pass_cards(self) so that it returns a list of three cards from the player’s hands to pass
o, again removing them from self.hand before returning.
Example:
The following code creates a Player object, deals four cards to it and asks it to play a card:
player = BasicAIPlayer(“Test Player 1”)
player.hand.append(Card(Rank.Four, Suit.Clubs))
player.hand.append(Card(Rank.Ace, Suit.Hearts))
player.hand.append(Card(Rank.King, Suit.Spades))
player.hand.append(Card(Rank.Ten, Suit.Spades))
print(player.play_card(trick=[Card(Rank.Seven, Suit.Spades)], broken_hearts=False))
Ten of Spades
This is an example of the basic AI selecting which cards to pass given a sample hand:
player = BasicAIPlayer(“Test Player 1”)
player.hand = [Card(Rank.Four, Suit.Clubs), Card(Rank.Ace, Suit.Hearts), Card(Rank.King, Suit.Spades), print(player.pass_cards())
[Ten of Spades, King of Spades, Ace of Hearts]
Task 3: Round
Create a class Round that takes a list of players (assume that players have been dealt their hands and card have already been passed before Round is called) and executes a round of the game.
Each iteration of a round begins with a new trick and players take turns playing one card each, after which the one who played the highest ranking card from the suit of the trick takes the trick. The suit of the trick is denied by the suit of the lead card, and the player with the Two of Clubs must lead the first trick of the round. After each iteration, the player who takes the trick leads the next trick.
You will need to ensure you have an ag for hearts being broken, and switch it to true as soon as someone plays a Hearts card.
When a player takes a trick, they receive one point for every Hearts card in the trick, and the Queen of Spades is a wildcard that gives 13 points.
The round continues until players have played all cards (so for a round with 4 players, each player will have 13 cards therefore 13 iterations of the round would be expected). Your class should work with any number of players assuming they each hold an equal number of cards.
Turns are taken clockwise, in our case where we have a list of players this means taking turns in increasing order of index.
For example in the below list of players:
players = [BasicAIPlayer(“Player 1”), BasicAIPlayer(“Player 2”), BasicAIPlayer(“Player 3″), BasicAIPlayIf player 2 leads a trick, the order of turns would be Player 2, Player 3, Player 4, Player 1.
Your class should only update Player.round_score throughout execution and doesn’t need to return anything.
In order to pass the automated tests for simulating a round, ensure you only print in three cases for now. Use the below print statements where appropriate within your methods.
print(f”{player} plays {trick.played_cards[player]}”)
print(“Hearts have been broken!”) # make sure this prints after the above play message
print(f”{taker} takes the trick. Points received: {penalty}”)
This way your print statements act as a log of round events that can be tested against. You can customise what is printed and how in later tasks where we pretty things up into a usable interface.
Task 4: Hearts
In this task you need to create a class Hearts for the game itself.
This object should ask for two inputs upon initialisation:
An integer for the target score one player needs to reach before the game ends An integer for the number of players between 3 – 5
If the inputs are invalid your constructor should print so and prompt the user to enter again. The game class should then execute rounds until at least one player reaches the target score, at which point the player with the lowest score is the winner. If there are multiple players with the winning score, rounds must continue until there is only one.
Before each round:
Players need to be dealt a hand from a new deck. Your solution should generate a standard deck of 52 playing cards, shu�e it using random and deal them out to the player one by one. If the game is starting with 3 players, remove the Two of Diamonds from play so that all players get an equal number of cards. For 5 players, remove Two of Diamonds and Two of Spades.
Ensure every player has at least one card that isn’t the Queen of Spades or from Hearts , as this rare situation would break the game. You’ll need to deal again until a valid deal is confirmed.
Once cards are dealt, print each player’s deck for automated testing (you wouldn’t want this information given to the user in your �nal game).
Players then have to choose 3 cards to pass, which should be passed to the appropriate corresponding player. The order in which the passes rotate for a traditional game of 4 players is shown below:
For our implementation where you have a list of players, you need to recreate the same e�ect by passing cards from one player to the one a certain number of positions after them. The round number should dictate how many positions ahead cards are passed, and you need to wrap around when at the end of the list.
Again for automated testing, for each player print the card they chose to pass and to whom. Please refer to the printing strings provided below. You would also want to remove these from your �nal game as a player should not know about passes that don’t involve them. Once round preparation is complete the game can execute a round. After each round:
Check if a player has shot the moon by earning all 26 points within the round, in which case they receive 0 for this round and all other players receive 26.
Output requirements for testing
In order to pass the automated tests for simulating a game, ensure your class version in task4.py follows the below printing requirements and prints them in the order that they are prescribed: Make player names “Player x” starting at 1.
Before each round print:
f”========= Starting round {x} =========” starting with round 1.
Each player’s hand as: f”{player} was dealt {player.hand}”
Each pass as: f”{player} passed {cards} to {player_passed_to}”
Your Round class should care of all print statements during execution.
After each round print: “========= End of round {x} =========”
If a player shoots the moon: f”{player} has shot the moon! Everyone else receives 26 points”
For each player’s total score after the round: f”{player}’s total score:
{player.total_score}” And, when there is a winner: f”{winning_player}, is the winner!” For final submission, copy your completed task 4 into a le task4.py so that you can continue changing hearts.py as you wish. Your automated tests will be executed on task4.py instead
Task 5: Players
Now lets create a proper set of players including one for user input.
5.1 Base Player Create a class Player to be the base object inherited by all player types. This would just be your class from Task 2 however the methods play_card and pass_cards would not be included (only constructor and check_valid_play ).
Now change your original BasicAIPlayer class to inherit the base player object instead of initialising everything on it’s own, and de�ne the methods play_card and pass_cards with the existing
implementation from Task 2.
5.2 Human Player
Create a class HumanPlayer that inherits the base player and asks the user to input a name when initialising itself.
Implement play_card(self, trick, broken_hearts) so that the current trick and hand is printed before asking the user which card they wish to play, and returning that card if the play is valid. If the play is not valid, the associated error message from check_valid_play should be displayed before prompting the user again.
You will need to validate the user’s input to make sure it is an integer and it is within the appropriate range.
Implement pass_cards(self, passing_to) so that the current hand is printed before asking the user which cards they wish to pass (user input should be a comma-separated list of the chosen indexes). The prompt should also state the name of the player the user will be passing to. Remember to remove the selected cards from the current hand before returning them.
Again you will need to validate the user’s input and ensure they’ve entered three integers separated by commas. These integers need to be within the range of the length of their hand, and contain no duplicates.
The game will be cumbersome to play in the current state, however as long as your player object can take input as per special applications it’ll be a lot better once you pretty it up in the final task.
5.3 Better AI Player
Create a class BetterAIPlayer that inherits the base player and functions the same as the basic AI player however should implement a more advanced strategy of play rather than the greedy approach
The automated test for this task is for you to test your better AI, it will use your solution to run 100 simulated games against three BasicAIPlayer s. In order for your solution to get full marks, you should have at least three improvements that result in BetterAIPlayer performing noticeably better than the basic AI (win > 35% of the time at least once within several tries)
Task 6: Final Game
Now that you have a working foundation for the game, you need to package it up into a user-friendly experience. It’s up to you to design your final game, however, the below set of requirements will be required for you to get marks for this task.
Ensure you’ve removed the printing of player hands and passing events from Hearts as a user should not know that information.
Add additional print statements throughout Round and Hearts to create a better user experience. Update Hearts so that it initialises one HumanPlayer , and at least one of both BetterAIPlayer and BasicAIPlayer .
Use text art similar to what you learned in assignment 1 to create a pretty print version of your cards by updating the __str__ method for your Cards class.
Create a method for HumanPlayer that prints the player’s hand using the pretty print text art for each card and concatenates them side by side into one string. You should at least display the index for each card below it, however, you’re free to create better designs as long as the user is not left having
to count indexes.
Import the time module and use time.sleep(x) to pause execution between plays so that the user is not overwhelmed with sudden prints every turn.
Below is an example of what your final output could look like.
Get Solution of this Assessment. Hire Experts to solve this assignment for you Before Deadline.
The post Create an Ed workspace for your team and share it with the other members Upload the code sca old into the workspace: Python and Java Coding Assignment, CU, Malaysia appeared first on Malaysia Assignment Help.