Lab07 题解 (UCB CS61A@2021 Fall)
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