Ejercicio: Adición de comportamiento al juego
Ahora que ha agregado clases y datos al juego "Piedra, papel, tijeras", es el momento de agregar el último elemento: el comportamiento. Agregará el comportamiento en forma de métodos. Agregará métodos a las clases y el resultado final será un juego "Piedra, papel, tijeras" funcional.
Implementación del comportamiento
Ha aprendido que para compilar un programa en el estilo de la programación orientada a objetos (OOP) primero se modela y después se programa. Como resultado, el modelado ha generado una tabla que representa los objetos, los datos y el comportamiento que supuestamente componen el programa. Esta es la misma tabla de nuevo.
Fase | Actor | Comportamiento | data |
---|---|---|---|
Entrada | Participante | Elige el símbolo | Símbolo guardado como opción en Participant(choice) |
Processing | GameRound | Compara las opciones con las reglas del juego | Resultado inspeccionado |
Processing | GameRound | Se conceden puntos según el valor del resultado | Se agregan puntos al objeto Participant(point) ganador |
Processing | Juego | Se comprueba la respuesta para continuar | Si la respuesta es true, se continúa; de lo contrario, se sale |
Output | Juego | Nueva ronda del juego o crédito final del juego |
Esta vez se centrará en la columna Behavior
y la rellenará con métodos que se agregarán a las clases. Además, agregará código a esos métodos para que funcionen de la manera prevista.
Este es el código escrito hasta ahora. Se ampliará en los pasos siguientes:
Debe tener un archivo
rock-paper-scissor.py
. De lo contrario, siga estos pasos:Cree el archivo
rock-paper-scissor
y abra el editor:touch rock-paper-scissor.py code .
y agregue el código siguiente:
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 un juego
La primera parte del juego implica su configuración, lo que significa que debe crear una instancia del propio juego y llevarlo a un punto en el que espere a que los participantes actúen.
Reemplace el contenido de
rock-paper-scissor.py
por este código y guarde el archivo: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()
Ha agregado los métodos de la tabla a cada objeto. Los cambios que ha realizado se pueden expresar en una tabla para que sea más fácil ver qué comportamiento ha provocado que se agregue cada método.
Comportamiento Método Actor Elige el símbolo choose() Participante Compara las opciones compareChoices() GameRound Concede puntos awardPoints() GameRound Se comprueba la respuesta para continuar checkEndCondition() Juego Crédito final del juego determineWinner() Juego La mayor parte del comportamiento de la tabla anterior se corresponde a métodos con nombres similares. La excepción es Crédito final del juego, que se convierte en
determineWinner()
. La razón es que, como parte del final de un juego, es interesante comprobar quién ha ganado e imprimir esa información. Es decisión suya si quiere asignar otro nombre a este método.Invoque
python3
para ejecutar el código:python3 rock-paper-scissor.py
El programa genera una salida como la siguiente:
Spock, select rock, paper or scissor:
Esa salida significa que el programa está a la espera de que actúe.
Para asegurarse de que el programa funciona, seleccione
rock
y después presione Entrar. Seleccionepaper
y vuelva a presionar Entrar:La salida será similar a este texto:
Spock, select rock, paper or scissor: rock Spock selects rock Kirk, select rock, paper or scissor: paper Kirk selects paper
Nota:
Puede encontrar la solución para este ejercicio en Iniciar un juego: código de la solución.
Implementación de reglas
En la descripción del problema, ha leído que unas opciones ganan a otras. Por ejemplo, la piedra gana a las tijeras, las tijeras ganan al papel, etc. Es tentador escribir código como el siguiente:
if choice1 == "rock" and choice2 == "scissor":
return 1
elif choice1 == "paper" and choice2 == "scissor":
return -1
else:
# something else
# and so on
Como resultado, se escribe una cantidad considerable de código y se hace difícil de manejar. ¿Qué ocurre si el juego necesita expandir su conjunto de reglas, lo que podría dificultar todavía más el mantenimiento del código?
Afortunadamente, existe una solución mejor. Un mejor enfoque consiste en pensar en las reglas como una matriz. La idea de usar una matriz es para expresar qué combinación gana a las demás. Un movimiento ganador obtiene un 1
, un empate obtiene un 0
y un movimiento perdedor obtiene un -1
. La matriz siguiente es para piedra, papel y tijeras:
Opción | Piedra | Documento | Tijeras |
---|---|---|---|
Piedra | 0 | -1 | 1 |
Documento | 1 | 0 | -1 |
Tijeras | -1 | 1 | 0 |
Puede implementar la tabla anterior en Python mediante una matriz multidimensional, como la siguiente:
rules = [
[0, -1, 1],
[1, 0, -1],
[-1, 1, 0]
]
rules[0][1] # Rock vs Paper = -1, Paper wins over Rock
Busque la clase
Participant
y agregue el métodotoNumericalChoice()
:def toNumericalChoice(self): switcher = { "rock": 0, "paper": 1, "scissor": 2 } return switcher[self.choice]
El método anterior convertirá la entrada de cadena de línea de comandos en un entero. De esta forma será más sencillo determinar el ganador de una ronda.
Sugerencia
Asegúrese de colocar el cursor para aplicar sangría correctamente en el código.
Busque la clase
GameRound
y actualice el métodocompareChoices()
:def compareChoices(self, p1, p2): return self.rules[p1.toNumericalChoice()][p2.toNumericalChoice()]
El código le permitirá comparar dos opciones y determinar el ganador.
En la misma clase, agregue el método
getResultAsString()
:def getResultAsString(self, result): res = { 0: "draw", 1: "win", -1: "loss" } return res[result]
Este método le ayudará a determinar el resultado e imprimirá en la pantalla un texto fácil de entender.
Todavía en la misma clase, reemplace el contenido 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) ))
El código anterior presenta el campo
rules
, que contiene una implementación de las reglas para "Piedra, papel, tijeras". Además, la llamada aself.compareChoices()
compara las dos opciones realizadas. Por último, hay una fila que imprime en la pantalla resultados sencillos de leer.
Nota:
Puede encontrar la solución para este ejercicio en Implementación de reglas: código de la solución.
Puntuación del juego
La puntuación del juego consiste en asignar puntos al jugador correcto una vez que ha finalizado la partida. El jugador ganador obtiene un punto, un empate o ningún punto en caso de perder.
Busque la clase
Participant
y agregue el métodoincrementPoint()
:def incrementPoint(self): self.points += 1
Sugerencia
La introducción de un método para cambiar un atributo es el primer paso hacia la encapsulación. Si quiere, intente cambiar el campo
points
por__points__
para ocultar el miembro al exterior y practicar con la encapsulación.Busque la clase
GameRound
y agregue el código siguiente al final del método__init()__
:if result > 0: p1.incrementPoint() elif result < 0: p2.incrementPoint()
Nota:
Puede encontrar la solución para este ejercicio en Puntuación del juego: código de la solución.
Adición de una consulta de continuación
Una consulta de continuación es una pregunta al final de la ronda del juego en la que se le pregunta al jugador si quiere continuar. Si el usuario decide no continuar, sería recomendable generar los resultados actuales y el ganador, en caso de que lo haya.
Busque la clase
Game
y actualice el 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)
En la misma clase, actualice el 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
En la misma clase, reemplace el contenido del método
start()
por este código:def start(self): while not self.endGame: GameRound(self.participant, self.secondParticipant) self.checkEndCondition()
Guarde el archivo.
Ejecute el comando
python3 rock-paper-scissor.py
para probar el programa:python3 rock-paper-scissor.py
Seleccione
rock
ypaper
como entradas, y escriban
cuando se le pregunte si quiere continuar.El resultado tendrá un aspecto similar al texto siguiente:
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
Nota:
Puede encontrar la solución para este ejercicio en Consulta de continuación: código de la solución.
Enhorabuena, lo ha conseguido. Ha implementado una versión de OOP del juego "Piedra, papel, tijeras".