Classes Day 3 of 3
Day 15 of 100
For this three day challenge, we dove head first into classes. We started out with an intro to classes by building a little D&D text adventure game along with host Michael. You create classes of characters in the game and then write methods for them to attack or defend, depending on the outcome of a dice roll. All of this takes place in while
loop that continues to prompt the user until the hero wins or until the hero is defeated. It was a great game and a good, easy to follow demo of classes.
Day 2 we were given a scaffold of a Rock, Paper, Scissors text game to build using classes. It was harder for me initially because we used classes to build the players and the rolls. The players I understood because I could visualize that class and the attributes. The other class we created was for the rolls and the characteristics of each roll. This was a lot harder for me to grasp and it took a long time for me to really get the code right.
I did get stuck on how to assign the human player a roll object after getting their input and then how to apply the Roll
class methods to that input. In the end, I had to actually modify my code to run backwards when awarding the winners and losers of each round because I had spent so much time on it. I knew there would be another day to refine code and I wanted to take some time to think more about how to implement the challenge. I also left input validation, handling of ties, and calculating a final winner to day 3 as well.
Day 2 Code rps.py
from classes import Player, Roll
import random
import time
def main():
print_title()
rolls = build_the_three_rolls()
name = get_players_name()
player1 = Player(name)
player2 = Player("computer")
game_loop(player1, player2, rolls)
def print_title():
print('-' * 40)
print()
print(' ' * 9 + 'ROCK, PAPER, SCISSORS')
print()
print('-' * 40)
print()
def get_players_name():
name = input('What is your name: ')
return name
def build_the_three_rolls():
rolls = []
rolls.append(Roll('Rock', 'Scissors', 'Paper'))
rolls.append(Roll('Scissors', 'Paper', 'Rock'))
rolls.append(Roll('Paper', 'Rock', 'Scissors'))
return rolls
def game_loop(player1, player2, rolls):
count = 1
while count < 6:
player2.roll = random.choice(rolls)
#TODO: validate user input and store roll as object - correct can_defeat method
player1.roll = input('Enter [Rock], [Paper], or [Scissors]: ')
outcome = player2.roll.can_defeat(player1.roll)
time.sleep(1)
print(f'{player2.name} has rolled {player2.roll.name}')
time.sleep(1)
# TODO: add win counts and handle ties better
if outcome == 'Win':
print(f'{player1.roll} beats {player2.roll.name}, {player1.name} wins!')
elif outcome == 'Lose':
print(f'{player2.roll.name} beats {player1.roll}, {player2.name} wins!')
else:
print("It's a tie!")
count += 1
# TODO: Compute who won
if __name__ == '__main__':
main()
Day 2 Code classes.py
class Player:
def __init__(self, name):
self.name = name
self.roll = None
self.wins = 0
class Roll:
def __init__(self, name, cn_defeat, defeated_by):
self.name = name
self.cn_defeat = cn_defeat
self.defeated_by = defeated_by
def can_defeat(self, roll):
if roll == self.cn_defeat:
return 'Lose'
elif roll == self.defeated_by:
return 'Win'
else:
return 'Tie'
Day 3 was filled with refining code and try to fix what wasn't running correctly from day 2 and finish implementing all the requirements for the challenge. Assigning the human player the correct Roll
object based on their input was the biggest challenge. My solution finally worked after I realized the three difference Roll
objects were being passed to the game loop as a list. I had to iterate over the list to access each Roll
object and assign the correct one to the user.
It also took longer than expected to fix the battle method that return a wine, lose, or tie. After lots of print
statements and a little dive into the PyCharm debugger, I was able to sort out the methods, announce the winner of each round and calculate the final winner. All in a all a successful 3 days spent learning about classes.
Day 3 game code rps.py
from classes import Player, Roll
import random
import time
def main():
print_title()
rolls = build_the_three_rolls()
name = get_players_name()
player1 = Player(name)
player2 = Player("RPS Bot")
game_loop(player1, player2, rolls)
def print_title():
print('-' * 40)
print()
print(' ' * 9 + 'ROCK, PAPER, SCISSORS')
print()
print('-' * 40)
print()
def get_players_name():
name = input('What is your name: ')
return name
def build_the_three_rolls():
rolls = []
rolls.append(Roll('Rock', 'Scissors', 'Paper'))
rolls.append(Roll('Scissors', 'Paper', 'Rock'))
rolls.append(Roll('Paper', 'Rock', 'Scissors'))
return rolls
def game_loop(player1, player2, rolls):
# prompt the user for the number of rounds and validate the input
while True:
num_games = input(f'How many rounds do you want? ')
try:
val = int(num_games)
if val > 0:
num_games = int(num_games)
break
else:
print("Please enter a positive number greater than 0.")
except ValueError:
print("Please enter an integer.")
# set the round counter
count = 0
# convert the number of games to an int
num_games = int(num_games)
while count < num_games:
# assign player 2 a random roll
player2.roll = random.choice(rolls)
# prompt the user for a roll and validate input
player1.roll = input('Enter [R]ock, [P]aper, or [S]cissors: ')
while True:
if player1.roll == 'R':
for roll in rolls:
if roll.name == 'Rock':
player1.roll = roll
break
elif player1.roll == 'P':
for roll in rolls:
if roll.name == 'Paper':
player1.roll = roll
break
elif player1.roll == 'S':
for roll in rolls:
if roll.name == 'Scissors':
player1.roll = roll
break
else:
print("Input not recognized.")
player1.roll = input('Enter [R]ock, [P]aper, or [S]cissors: ')
outcome = player1.roll.can_defeat(player2.roll)
time.sleep(1)
# report the player 2 roll
print(f'{player2.name} has rolled {player2.roll.name}')
time.sleep(1)
# award the win and increment the round if there is a winner
if outcome == 'Win':
player1.wins += 1
count += 1
print(f'{player1.roll.name} beats {player2.roll.name}, {player1.name} wins!')
time.sleep(1)
print(f'That concludes round {count}. {player1.name} has '
f'{player1.wins} wins and {player2.name} has {player2.wins} wins.')
elif outcome == 'Lose':
player2.wins += 1
count += 1
print(f'{player2.roll.name} beats {player1.roll.name}, {player2.name} wins!')
time.sleep(1)
print(f'That concludes round {count}. {player1.name} has '
f'{player1.wins} wins and {player2.name} has {player2.wins} wins.')
else:
print("It's a tie. Doesn't count!")
# Compute the winner
if player1.wins > player2.wins:
winner = player1.name
elif player2.wins > player1.wins:
winner = player2.name
else:
winner = None
# Report the results
print(f'The final score is:')
print(f'\t {player1.name} with {player1.wins} wins')
print(f'\t {player2.name} with {player2.wins} wins')
if winner:
print(f'The winner is {winner}!')
else:
print(f'Looks like a tie. Next time, pick an odd number of rounds to avoid a tie.')
if __name__ == '__main__':
main()
Day 3 code for classes.py
class Player:
def __init__(self, name):
self.name = name
self.roll = None
self.wins = 0
class Roll:
def __init__(self, name, cn_defeat, defeated_by):
self.name = name
self.cn_defeat = cn_defeat
self.defeated_by = defeated_by
def can_defeat(self, roll):
if roll.name == self.cn_defeat:
return 'Win'
elif roll.name == self.defeated_by:
return 'Lose'
else:
return 'Tie'
And here is a 3 round game (with a couple ties):
----------------------------------------
ROCK, PAPER, SCISSORS
----------------------------------------
What is your name: Clark
How many rounds do you want? 3
Enter [R]ock, [P]aper, or [S]cissors: R
RPS Bot has rolled Rock
It's a tie. Doesn't count!
Enter [R]ock, [P]aper, or [S]cissors: R
RPS Bot has rolled Scissors
Rock beats Scissors, Clark wins!
That concludes round 1. Clark has 1 wins and RPS Bot has 0 wins.
Enter [R]ock, [P]aper, or [S]cissors: S
RPS Bot has rolled Rock
Rock beats Scissors, RPS Bot wins!
That concludes round 2. Clark has 1 wins and RPS Bot has 1 wins.
Enter [R]ock, [P]aper, or [S]cissors: S
RPS Bot has rolled Scissors
It's a tie. Doesn't count!
Enter [R]ock, [P]aper, or [S]cissors: R
RPS Bot has rolled Rock
It's a tie. Doesn't count!
Enter [R]ock, [P]aper, or [S]cissors: R
RPS Bot has rolled Rock
It's a tie. Doesn't count!
Enter [R]ock, [P]aper, or [S]cissors: P
RPS Bot has rolled Paper
It's a tie. Doesn't count!
Enter [R]ock, [P]aper, or [S]cissors: R
RPS Bot has rolled Rock
It's a tie. Doesn't count!
Enter [R]ock, [P]aper, or [S]cissors: R
RPS Bot has rolled Rock
It's a tie. Doesn't count!
Enter [R]ock, [P]aper, or [S]cissors: R
RPS Bot has rolled Rock
It's a tie. Doesn't count!
Enter [R]ock, [P]aper, or [S]cissors: R
RPS Bot has rolled Scissors
Rock beats Scissors, Clark wins!
That concludes round 3. Clark has 2 wins and RPS Bot has 1 wins.
The final score is:
Clark with 2 wins
RPS Bot with 1 wins
The winner is Clark!
It's beginning to feel like the random.choice()
method isn't so random...