Homework 6: Classes
- Due: Thursday 10/22 @ 11:59pm
- Points: 1
- Download: hw06.zip
To receive credit, you must solve each problem and then complete a short checkoff interview about your solution. You may use Preceptor for the interview or come to office hours to be interviewed by a member of the course staff. Staff will be doing in-person checkoffs for up to 3 business days after the assignment deadline (including any approved extension). If a checkoff happens more than 3 business days after the regular deadline, staff may ask to confirm your extended deadline via Flextensions. You will submit a Provenance bundle that includes a record of how you used VS Code, including interactions with Preceptor. Please do not use AI tools other than Preceptor for this assignment.
Readings: This homework relies on the following readings from Composing Programs:
Required Questions
Survey
Q1: Mid-Semester Feedback
As part of this assignment, fill out the Mid-Semester Feedback form.
Once you finish the survey, you will be presented with a passphrase. Put this
passphrase, as a string, on the line that says
passphrase = 'REPLACE_THIS_WITH_PASSPHRASE' in the Python file for this
assignment. For example, if the passphrase is abc, then the line should be
passphrase = 'abc'.
python3 -m pytest -k midsem_surveyOOP
Q2: Free Checking
Let's improve the Account class from lecture, which models a bank account that
can process deposits and withdrawals.
class Account:
"""An account has a balance and a holder.
>>> a = Account('John')
>>> a.deposit(10)
10
>>> a.balance
10
>>> a.interest
0.02
>>> a.time_to_retire(10.25) # 10 -> 10.2 -> 10.404
2
>>> a.balance # time_to_retire should not change the balance
10
>>> a.time_to_retire(11) # 10 -> 10.2 -> ... -> 11.040808032
5
>>> a.time_to_retire(100)
117
"""
max_withdrawal = 10
interest = 0.02
def __init__(self, account_holder):
self.balance = 0
self.holder = account_holder
def deposit(self, amount):
self.balance = self.balance + amount
return self.balance
def withdraw(self, amount):
if amount > self.balance:
return "Insufficient funds"
if amount > self.max_withdrawal:
return "Can't withdraw that amount"
self.balance = self.balance - amount
return self.balance
First, add a time_to_retire method to the Account class. This method
takes an amount and returns the number of years until the current balance
grows to at least amount, assuming that the bank adds the interest (the
current balance multiplied by the interest rate) to the balance at the end
of each year.
Important: Calling
time_to_retireshould not change the account balance.
def time_to_retire(self, amount):
"""Return the number of years until balance would grow to amount."""
assert self.balance > 0 and amount > 0 and self.interest > 0
"*** YOUR CODE HERE ***"
Second, implement the FreeChecking class, which is like Account except
that it charges a withdrawal fee withdraw_fee after free_withdrawals
withdrawals. If a withdrawal is unsuccessful, no fee is charged, but it still
counts toward the number of free withdrawals remaining.
class FreeChecking(Account):
"""A bank account that charges for withdrawals, but the first two are free!
>>> ch = FreeChecking('Jack')
>>> ch.balance = 20
>>> ch.withdraw(100) # First one's free, even though it was unsuccessful
'Insufficient funds'
>>> ch.withdraw(3) # Second withdrawal is also free
17
>>> ch.balance
17
>>> ch.withdraw(3) # Now there is a fee, since free_withdrawals is 2
13
>>> ch.withdraw(3)
9
>>> ch2 = FreeChecking('John')
>>> ch2.balance = 10
>>> ch2.withdraw(3) # No fee
7
>>> ch.withdraw(3) # ch still charges a fee
5
>>> ch.withdraw(5) # Not enough to cover fee + withdraw
'Insufficient funds'
"""
withdraw_fee = 1
free_withdrawals = 2
"*** YOUR CODE HERE ***"
python3 -m pytest -k checkingQ3: Cucumber
Cucumber is a card game. Cards are positive integers (no suits). A Cucumber
game has a number of players, numbered 0 through players - 1: 0, 1, 2, and 3
in a 4-player game.
A Round is created with its starter player and the Cucumber game it is played in.
In each Round, the players each play one card, starting with the starter
and in ascending order (player 0 follows player 3 in a 4-player game). If the
card played is as high as or higher than the highest card played so far, the
player who played it takes control. Once every player has played one card, the
round is complete, and its winner is the last player who took control. If a
player tries to play out of turn or after the round is over, the card is not
played, and play returns an error message instead, which play_round prints.
Complete the Round class, adding instance attributes as needed.
class Cucumber:
"""A game of Cucumber that records the winner of each completed round.
Each (who, card) pair in cards indicates who plays and what card they play.
>>> g = Cucumber(4)
>>> g.play_round(3, [(3, 4), (0, 8), (1, 8), (2, 5)])
>>> g.winners
[1]
>>> g.play_round(1, [(3, 5), (1, 4), (2, 5), (0, 8), (3, 7), (0, 6), (1, 7)])
It is not your turn, player 3
It is not your turn, player 0
The round is over, player 1
>>> g.winners
[1, 3]
>>> g.play_round(3, [(3, 7), (2, 5), (0, 9)]) # Round is never completed
It is not your turn, player 2
>>> g.winners
[1, 3]
>>> h = Cucumber(3)
>>> h.play_round(2, [(2, 5), (0, 6), (1, 4), (2, 9)])
The round is over, player 2
>>> h.winners
[0]
"""
def __init__(self, num_players):
self.winners = []
self.players = num_players
def play_round(self, starter, cards):
r = Round(starter, self)
for who, card in cards:
error = r.play(who, card)
if error is not None:
print(error)
if r.winner is not None:
self.winners.append(r.winner)
class Round:
"""One round of Cucumber."""
def __init__(self, starter, game):
self.starter = starter
self.next_player = starter
self.winner = None
"*** YOUR CODE HERE ***"
def play(self, who, card):
"""Play card for player who, or return an error string if who can't play."""
if self.is_complete():
return f'The round is over, player {who}'
if who != self.next_player:
return f'It is not your turn, player {who}'
self.next_player = _____
if _____:
"*** YOUR CODE HERE ***"
if self.is_complete():
"*** YOUR CODE HERE ***"
def is_complete(self):
"""Return whether every player has played once in this round."""
"*** YOUR CODE HERE ***"
python3 -m pytest -k CucumberSubmit
Run Provenance: Prepare Submission Bundle from the VS Code command palette to create your submission zip, and upload that zip to Gradescope. For a refresher on how to do this, refer to Lab 00.
Optional Questions
These questions are optional. If you don't complete them, you will still receive credit for this assignment. They are great practice, so do them anyway!
Q4: Cat
Below is the implementation of a Pet class. Each pet has two instance
attributes (name and owner), as well as one instance method (talk).
class Pet:
def __init__(self, name, owner):
self.name = name
self.owner = owner
def talk(self):
print(self.name)
Implement the Cat class, which inherits from Pet. To complete the
implementation, override or implement the following methods:
__init__
Set the Cat's name and owner attributes, and also add 2 new attributes:
is_hungry— should be set toFalsefullness— should be set to whatever thefullnessparameter is
Hint: You can call the
__init__method ofPet(the superclass ofCat) to set a cat'snameandownerusingsuper().
talk
Print out a cat's greeting, which is "<name of cat> says meow!".
get_hungry
Decrement a cat's fullness level by 1. When fullness reaches zero,
is_hungry becomes True. If this is called after fullness has already
reached zero, print the message "<name of cat> is hungry."
eat
This method is called when the cat eats some food. If the cat is hungry, then after calling this method both of the following should be true:
- The cat's
fullnessvalue is set to whateverCat.default_fullnessis. - The cat's
is_hungryvalue isFalse.
Also print out the food the cat ate. For example, if a cat named Thomas ate
fish, print 'Thomas ate a fish!'
Otherwise, if the cat wasn't hungry, print '<name of cat> is not hungry.'
class Cat(Pet):
default_fullness = 5
def __init__(self, name: str, owner: str, fullness: int = default_fullness):
"""
>>> cat = Cat('Thomas', 'Tammy')
>>> cat.name
'Thomas'
>>> cat.owner
'Tammy'
>>> cat.fullness # use default fullness value
5
>>> cat.is_hungry
False
>>> cat2 = Cat('Meow Meow', 'Yoobin', 3)
>>> cat2.fullness # use fullness value that was passed in
3
"""
"*** YOUR CODE HERE ***"
def talk(self) -> None:
"""
>>> Cat('Thomas', 'Tammy').talk()
Thomas says meow!
>>> Cat('Meow Meow', 'ThuyAnh').talk()
Meow Meow says meow!
"""
"*** YOUR CODE HERE ***"
def get_hungry(self) -> None:
"""
>>> cat = Cat('Thomas', 'Tammy', 2)
>>> cat.is_hungry
False
>>> cat.fullness
2
>>> cat.get_hungry()
>>> cat.is_hungry
False
>>> cat.fullness
1
>>> cat.get_hungry()
>>> cat.is_hungry
True
>>> cat.fullness
0
>>> cat.get_hungry()
Thomas is hungry.
>>> cat.is_hungry
True
>>> cat.fullness
0
"""
"*** YOUR CODE HERE ***"
def eat(self, food: str) -> None:
"""
>>> cat = Cat('Crookshanks', 'Hermione', 1)
>>> cat.eat('tuna')
Crookshanks is not hungry.
>>> cat.is_hungry
False
>>> cat.fullness
1
>>> cat.get_hungry()
>>> cat.eat('tuna')
Crookshanks ate a tuna!
>>> cat.is_hungry
False
>>> cat.fullness
5
"""
"*** YOUR CODE HERE ***"
python3 -m pytest -k cat