Exercício – adicionar comportamento ao seu jogo
Agora que você adicionou classes e dados ao seu jogo de pedra, papel e tesoura, é hora de adicionar a última parte, que é o comportamento. Você adicionará o comportamento na forma de métodos. Você adicionará métodos às suas classes e o resultado final será um jogo de pedra, papel e tesoura funcional.
Implementar comportamento
Você já aprendeu que, para criar um programa em estilo OOP (programação orientada a objeto), primeiro você modela e depois codifica. A modelagem produziu a saída de uma tabela que representava por quais objetos, dados e comportamento o seu programa parece ser composto. Esta é a mesma tabela novamente.
Fase | Ator | Comportamento | Dados |
---|---|---|---|
Entrada | Participante | Escolhe um símbolo | Símbolo salvo como escolha em Participant(choice) |
Processando | GameRound | Compara a escolha tendo em mente as regras do jogo | Resultado inspecionado |
Processando | GameRound | Recebe pontos com base no valor do resultado | Pontos adicionados ao Participant(point) vencedor |
Processando | Game | Verificar resposta continuar | A resposta é true, continuar; caso contrário, sair |
Saída | Game | Nova crédito de rodada do jogo ou fim do jogo |
Desta vez, você se concentrará na coluna Behavior
e a preencherá com métodos que serão adicionados às suas classes. Além disso, você adicionará código a esses métodos para que eles funcionem da maneira que deveriam.
Este é o código até o momento. Vamos estendê-lo nas seguintes etapas:
Você deve ter um arquivo
rock-paper-scissor.py
. Se não tiver, siga estas etapas:Crie o arquivo
rock-paper-scissor
e abra o editor:touch rock-paper-scissor.py code .
e adicione o código abaixo:
class Participant: def __init__(self): self.points = 0 self.choice = "" class GameRound: class Game: def __init__(self): self.endGame = False self.participant = Participant() self.secondParticipant = Participant()
Iniciar um jogo
A primeira parte do jogo envolve configurá-lo, o que significa criar uma instância do próprio jogo e levar o jogo para um ponto em que ele fique aguardando a ação dos participantes.
Substitua o conteúdo de
rock-paper-scissor.py
por este código e salve o arquivo:class Participant: def __init__(self, name): self.name = name self.points = 0 self.choice = "" def choose(self): self.choice = input("{name}, select rock, paper or scissor: ".format(name= self.name)) print("{name} selects {choice}".format(name=self.name, choice = self.choice)) class GameRound: def __init__(self, p1, p2): p1.choose() p2.choose() def compareChoices(self): print("implement") def awardPoints(self): print("implement") class Game: def __init__(self): self.endGame = False self.participant = Participant("Spock") self.secondParticipant = Participant("Kirk") def start(self): game_round = GameRound(self.participant, self.secondParticipant) def checkEndCondition(self): print("implement") def determineWinner(self): print("implement") game = Game() game.start()
Você adicionou os métodos de sua tabela a cada objeto. As alterações feitas podem ser expressas por uma tabela para que seja mais fácil ver qual comportamento levou ao método que está sendo adicionado.
Comportamento Método Ator Escolhe um símbolo choose() Participante Compara opções compareChoices() GameRound Recebe pontos awardPoints() GameRound Verificar resposta continuar checkEndCondition() Game Crédito final do jogo determineWinner() Game A maior parte do comportamento na tabela anterior corresponde a métodos com nomes semelhantes. A exceção é Crédito final do jogo, que se torna
determineWinner()
. O motivo é que, como parte do final de um jogo, convém verificar quem ganhou e imprimir essas informações. Fica a seu critério dar outro nome a esse método.Execute o código invocando
python3
:python3 rock-paper-scissor.py
O programa produz uma saída como esta:
Spock, select rock, paper or scissor:
Essa saída significa que o programa está aguardando sua ação.
Verifique se o programa funciona selecionando
rock
e, em seguida, selecionando Enter. Selecionepaper
e Enter novamente:A saída será semelhante a este texto:
Spock, select rock, paper or scissor: rock Spock selects rock Kirk, select rock, paper or scissor: paper Kirk selects paper
Observação
Encontre a solução para este exercício em Iniciar um jogo – código de solução.
Implementar regras
Na descrição do problema, você lê que algumas escolhas vencem outras. Por exemplo, pedra vence tesoura, tesoura vence papel e assim por diante. É tentador escrever um código semelhante ao seguinte:
if choice1 == "rock" and choice2 == "scissor":
return 1
elif choice1 == "paper" and choice2 == "scissor":
return -1
else:
# something else
# and so on
Resulta em uma quantidade significativa de código escrito e torna-se um pouco difícil. E se o jogo precisar expandir o conjunto de regras, o que poderá tornar o código ainda mais difícil de ser mantido?
Felizmente, há uma forma melhor. Uma abordagem melhor é pensar nas regras como uma matriz. A ideia de usar uma matriz é expressar qual combinação ganha de outras combinações. Uma jogada vencedora recebe um 1
, um empate recebe um 0
e uma jogada perdedora recebe um -1
. A seguinte matriz destina-se a pedra, papel e tesoura:
Escolha | Pedra | Papel | Tesoura |
---|---|---|---|
Pedra | 0 | -1 | 1 |
Papel | 1 | 0 | -1 |
Tesoura | -1 | 1 | 0 |
Você pode implementar a tabela anterior em Python usando uma matriz multidimensional, desta forma:
rules = [
[0, -1, 1],
[1, 0, -1],
[-1, 1, 0]
]
rules[0][1] # Rock vs Paper = -1, Paper wins over Rock
Localize a classe
Participant
e adicione o métodotoNumericalChoice()
:def toNumericalChoice(self): switcher = { "rock": 0, "paper": 1, "scissor": 2 } return switcher[self.choice]
o método anterior converterá sua entrada de cadeia de caracteres de linha de comando em um inteiro. Isso facilitará a determinação de quem ganhou uma rodada.
Dica
Posicione o cursor para recuar o código corretamente.
Localize a classe
GameRound
e atualize o métodocompareChoices()
:def compareChoices(self, p1, p2): return self.rules[p1.toNumericalChoice()][p2.toNumericalChoice()]
o código permitirá que você compare duas escolhas e determine o vencedor.
Na mesma classe, adicione o método
getResultAsString()
:def getResultAsString(self, result): res = { 0: "draw", 1: "win", -1: "loss" } return res[result]
esse método ajudará a determinar o resultado e imprimirá um texto fácil de entender na tela.
Ainda na mesma classe, substitua o conteúdo de
__init__()
por este código:def __init__(self, p1, p2): self.rules = [ [0, -1, 1], [1, 0, -1], [-1, 1, 0] ] p1.choose() p2.choose() result = self.compareChoices(p1,p2) print("Round resulted in a {result}".format(result = self.getResultAsString(result) ))
O código anterior introduz o campo
rules
, que contém uma implementação das regras para pedra, papel e tesoura. Além disso, a chamada aself.compareChoices()
compara duas escolhas feitas. Por fim, há uma linha que imprime resultados amigáveis para leitores na tela.
Observação
Encontre a solução para este exercício em Implementar regras – código de solução.
Pontuar o jogo
A pontuação do jogo trata-se de atribuir pontos ao jogador correto após o término do jogo. O jogador vencedor recebe um ponto, um empate ou nenhum ponto caso perca.
Localize a classe
Participant
e adicione o métodoincrementPoint()
:def incrementPoint(self): self.points += 1
Dica
A introdução de um método para alterar um atributo é a primeira etapa para o encapsulamento. Se desejar, tente alterar o campo
points
para__points__
a fim de ocultar o membro exterior para praticar o encapsulamento.Localize a classe
GameRound
e adicione o seguinte código ao final do método__init()__
:if result > 0: p1.incrementPoint() elif result < 0: p2.incrementPoint()
Observação
Encontre a solução para este exercício em Pontuar o jogo – código de solução.
Adicionar uma consulta de continuação
Uma consulta de continuação é perguntar, no final da rodada do jogo, se o jogador quer continuar. Se o usuário optar por não continuar, ele poderá gerar os resultados atuais e o vencedor, se houver.
Localize a classe
Game
e atualize o métododetermineWinner()
:def determineWinner(self): resultString = "It's a Draw" if self.participant.points > self.secondParticipant.points: resultString = "Winner is {name}".format(name=self.participant.name) elif self.participant.points < self.secondParticipant.points: resultString = "Winner is {name}".format(name=self.secondParticipant.name) print(resultString)
Na mesma classe, atualize o método
checkEndCondition()
:def checkEndCondition(self): answer = input("Continue game y/n: ") if answer == 'y': GameRound(self.participant, self.secondParticipant) self.checkEndCondition() else: print("Game ended, {p1name} has {p1points}, and {p2name} has {p2points}".format(p1name = self.participant.name, p1points= self.participant.points, p2name=self.secondParticipant.name, p2points=self.secondParticipant.points)) self.determineWinner() self.endGame = True
Na mesma classe, substitua o código do método
start()
por este código:def start(self): while not self.endGame: GameRound(self.participant, self.secondParticipant) self.checkEndCondition()
Salve o arquivo.
Execute o comando
python3 rock-paper-scissor.py
para testar o seu programa:python3 rock-paper-scissor.py
Selecione
rock
epaper
como entradas e insiran
quando for solicitado a continuar.A saída é semelhante ao seguinte texto:
Spock, select rock, paper or scissor: rock Spock selects rock Kirk, select rock, paper or scissor: paper Kirk selects paper Round resulted in a loss Continue game y/n: n Game ended, Spock has 0, and Kirk has 1 Winner is Kirk
Observação
Encontre a solução para este exercício em Consulta de continuação – código de solução.
Parabéns, você concluiu! Você implementou uma versão OOP do jogo pedra, papel e tesoura.