Accounts
Q2: Retirement
Add a
time_to_retire
method to theAccount
class. This method takes in anamount
and returns how many years the holder would need to wait in order for the currentbalance
to grow to at leastamount
, assuming that the bank addsbalance
times theinterest
rate to the total balance at the end of every year.
問題描述如下: 每一年你的 balance
都會有利息, 問你哪一年你達到了 amount
可以退休了, 用代碼模擬這個過程即可
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
year, curAmount = 0, self.balance
while True:
year += 1
curAmount *= (1 + self.interest)
if curAmount > amount:
return year
Q3: FreeChecking
Implement the
FreeChecking
class, which is like theAccount
class from lecture except that it charges a withdraw fee after 2 withdrawals. If a withdrawal is unsuccessful, it still counts towards the number of free withdrawals remaining, but no fee for the withdrawal will be charged.
和普通的 withdraw
方法相比, 我們要額外檢查一個參數 - free_withdrawals
, 它表示我們可以在不支付消費的情況下取款的次數. 這里要注意兩個點:
- 取款失敗也會扣免費次數
- 在要支付小費的情況下, 得小費+余額>取款金額才能成功取款
注意好這兩個點寫出代碼就沒有什么難度了
def withdraw(self, amount):
if self.free_withdrawals > 0:
if amount > self.balance:
self.free_withdrawals -= 1
return "Insufficient funds"
if amount > self.max_withdrawal:
self.free_withdrawals -= 1
return "Can't withdraw that amount"
self.free_withdrawals -= 1
self.balance = self.balance - amount
else:
if amount + self.withdraw_fee > self.balance:
self.free_withdrawals -= 1
return "Insufficient funds"
if amount + self.withdraw_fee > self.max_withdrawal:
self.free_withdrawals -= 1
return "Can't withdraw that amount"
self.balance = self.balance - amount - self.withdraw_fee
Magic: the Lambda-ing
Description
下面要實現的是一個卡牌游戲, 兩個玩家都有一副卡牌, 並且持有手牌. 雙方玩家需要在每個回合中打出一張手牌. 每張手牌都有攻擊力和防御力, 能量高的人獲勝. 能量計算方式如下 $$(持有手牌的攻擊力)-(對方卡牌的防御力)/2$$
第一個勝利 8 回合以上的人獲得游戲的勝利.
同時還有下面幾張特殊卡牌:
- AI 卡: 強制讓對手出的卡牌的攻擊力減去它的防御力, 然后讓它的防御力 * 2
- Tutor 卡: 強制讓對手棄三張卡牌並重新抽三張牌
- TA 卡: 強制交換對手出的卡牌的攻擊力和防御力
- Instructor 卡: 根據對手出的卡牌來增加自己卡牌堆里面的卡牌的攻擊力和防御力, 然后刪除對手卡牌堆里所有跟他出的卡身材(攻擊力和防御力)一樣的
Q4: Making Cards
To play a card game, we're going to need to have cards, so let's make some! We're gonna implement the basics of the
Card
class first.First, implement the
Card
class constructor inclasses.py
. This constructor takes three arguments:
- a string as the
name
of the card- an integer as the
attack
value of the card- an integer as the
defense
value of the cardEach
Card
instance should keep track of these values using instance attributes calledname
,attack
, anddefense
.You should also implement the
power
method inCard
, which takes in another card as an input and calculates the current card's power. Refer to the Rules of the Game if you'd like a refresher on how power is calculated.
在本體中我們要完成構造函數的代碼和計算能量的函數, 其實就是把上面的規則翻譯成代碼, 很簡單.
class Card:
cardtype = 'Staff'
def __init__(self, name, attack, defense):
"""
Create a Card object with a name, attack,
and defense.
"""
self.name = name
self.attack = attack
self.defense = defense
def power(self, opponent_card):
"""
Calculate power as:
(player card's attack) - (opponent card's defense)/2
"""
return self.attack - opponent_card.defense / 2
Q5: Making a Player
Now that we have cards, we can make a deck, but we still need players to actually use them. We'll now fill in the implementation of the
Player
class.A
Player
instance has three instance attributes:
name
is the player's name. When you play the game, you can enter your name, which will be converted into a string to be passed to the constructor.deck
is an instance of theDeck
class. You can draw from it using its.draw()
method.hand
is a list ofCard
instances. Each player should start with 5 cards in their hand, drawn from theirdeck
. Each card in the hand can be selected by its index in the list during the game. When a player draws a new card from the deck, it is added to the end of this list.Complete the implementation of the constructor for
Player
so thatself.hand
is set to a list of 5 cards drawn from the player'sdeck
.Next, implement the
draw
andplay
methods in thePlayer
class. Thedraw
method draws a card from the deck and adds it to the player's hand. Theplay
method removes and returns a card from the player's hand at the given index.Call
deck.draw()
when implementingPlayer.__init__
andPlayer.draw
. Don't worry about how this function works - leave it all to the abstraction!
在這一題中進一步對手牌完善了描述, 我們一開始有 5 張手牌. 我們需要完成下面的功能:
- 構造函數, 在這里要從
deck
中取出 5 張手牌, 為了代碼的簡潔我們這里可以在這里使用 List comprehension draw
函數, 從卡牌堆取一張牌到手牌, 這個直接用deck.draw()
即可play
函數, 其實就是出牌函數, 我們需要根據索引出牌, 記得把牌刪掉, 要區分 python 中的.remove()
和.pop()
方法
def __init__(self, deck, name):
"""Initialize a Player object.
"""
self.deck = deck
self.name = name
self.hand = [deck.draw() for i in range(5)]
def draw(self):
"""Draw a card from the player's deck and add it to their hand.
"""
assert not self.deck.is_empty(), 'Deck is empty!'
self.hand.append(self.deck.draw())
def play(self, card_index):
"""Remove and return a card from the player's hand at the given index.
"""
card = self.hand[card_index]
self.hand.pop(card_index)
return card
Optional Questions
Q6: AIs: Defenders
Implement the
effect
method for AIs, which reduces the opponent card's attack by the opponent card's defense, and then doubles the opponent card's defense.Note: The opponent card's resulting attack value cannot be negative.
這個問題要我們實現前面提到過的 AI 卡的功能, 就按照那個功能寫代碼即可, 注意如果攻擊力算出來小於 0, 我們需要把它設置為 0
def effect(self, opponent_card, player, opponent):
"""
Reduce the opponent's card's attack by its defense,
then double its defense.
"""
opponent_card.attack -= opponent_card.defense
if opponent_card.attack < 0:
opponent_card.attack = 0
opponent_card.defense *= 2
Q7: Tutors: Flummox
Implement the
effect
method for TAs, which swaps the attack and defense of the opponent's card.
也就是實現上面的 Tutor 卡, 注意這里我們要如何實現棄牌, 我們不應該破壞封裝, 也就是我們要假裝不知道內部實現細節, 那么查看 Player
類有什么方法我們可以使用. 顯然, 我們可以用 play
把前三張牌打出去, 然后從牌堆里 draw
三張牌出來
def effect(self, opponent_card, player, opponent):
"""
Discard the first 3 cards in the opponent's hand and have
them draw the same number of cards from their deck.
"""
# discard 3 cards
for i in range(3):
opponent.play(i)
# draw 3 cards
for i in range(3):
opponent.draw()
# You should add your implementation above this.
print('{} discarded and re-drew 3 cards!'.format(opponent.name))
Q8: TAs: Shift
Implement the
effect
method for TAs, which swaps the attack and defense of the opponent's card.
TA 卡的功能很簡單, 無非就是交換攻擊力和防御力而已, 在 python 中要實現這個功能是十分簡潔的
def effect(self, opponent_card, player, opponent):
"""
Swap the attack and defense of an opponent's card.
"""
opponent_card.attack, opponent_card.defense = opponent_card.defense, opponent_card.attack
Q9: The Instructor Arrives
A new challenger has appeared! Implement the
effect
method for the Instructors, who add the opponent card's attack and defense to all cards in the player's deck and then removes all cards in the opponent's deck that have the same attack or defense as the opponent's card.Note: If you mutate a list while iterating through it, you may run into trouble. Try iterating through a copy of the list instead. You can use slicing to make a copy of a list:
>>> original = [1, 2, 3, 4] >>> copy = original[:] >>> copy [1, 2, 3, 4] >>> copy is original False
也就是我們要實現上面的 Instructor 卡, 相比於其他三個卡來說, 這個的功能稍微復雜些, 但是也還好. 關鍵之處在於如何一邊遍歷列表, 一邊刪除自己想要的元素. 可以查看這里面的回答知道改怎么做, 知道了這一點之后做這一題就不難了
def effect(self, opponent_card, player, opponent):
"""
Adds the attack and defense of the opponent's card to
all cards in the player's deck, then removes all cards
in the opponent's deck that share an attack or defense
stat with the opponent's card.
"""
orig_opponent_deck_length = len(opponent.deck.cards)
# add the attack and defense of the opponent's card ...
for card in player.deck.cards:
card.attack += opponent_card.attack
card.defense += opponent_card.defense
# remove all cards in the opponent's deck that share ...
for card in opponent.deck.cards[:]:
if card.attack == opponent_card.attack and card.defense == opponent_card.defense:
opponent.deck.cards.remove(card)
# You should add your implementation above this.
discarded = orig_opponent_deck_length - len(opponent.deck.cards)
if discarded:
print('{} cards were discarded from {}\'s deck!'.format(discarded, opponent.name))
return