Piedra, Papel o Tijera
Contents
2. Piedra, Papel o Tijera¶
El primer ejercicio que te proponemos es desarrollar el clásico piedra papel o tijera, un juego que seguro ha decidido tu destino en más de una ocasión. Es sencillo y te servirá para repasar conceptos básicos. Aunque seguramente ya sabes jugar, vamos a repasar las normas:
Cada jugador podrá escoger uno de estos tres elementos:
Piedra
Papel
Tijera
El ganador del juego se dedice segun la siguiente clasificación:
La piedra gana a la tijera
La tijera gana al papel
El papel gana a la piedra
See also
Puedes encontrar más información sobre este juego aquí.
2.2. Petición de nombres y tiradas¶
Nuestro juego va a permitir que dos jugadores se disputen varias partidas. En este caso, el segundo jugador será el ordenador, pero podremos personalizarlo dándole un nombre. Para ello, vas a implementar la función request_data() que va a preguntar al usuario por los nombres de los dos juegadores y el número de partidas que quieren jugar. La función request_data() no recibe ningún argumento de entrada, pero sí que devuelve una variable data de tipo DICT que contiene los nombres de los dos jugadores y el numero de partidas.
Para limitar la duración del juego, la función request_data() sólo aceptará entre 1 y 10 partidas.
Solución:¶
def request_data():
user = input("Enter your name: ")
rival = input("Enter your rival name: ")
attempts = int(input("How many battles to play?:"))
while (attempts < 0 or attempts > 10):
print("Error, the number of battles must be between 1 and 10")
attempts = int(input("How many battles to play?:"))
data = dict(user=user, rival=rival, attempts=attempts)
return data
Note
Para asegurarnos de que el usuario sólo puede elegir entre 1 y 10 partidas, hemos utilizado un bucle WHILE:
while (attempts < 0 or attempts > 10):
print("Error, the number of battles must be between 1 and 10")
attempts = int(input("How many battles to play?:"))
Este bucle se repetirá indefinidamente hasta que el jugador introduzca un valor para la variable attemps que se encuentre entre 1 y 10.
Vamos a probar su ejecución dando los nombres de los dos jugadores y un número de partidas:
parameters=request_data()
parameters
Enter your name: Theo
Enter your rival name: Simon
How many battles to play?:5
{'user': 'Theo', 'rival': 'Simon', 'attempts': 5}
2.3. Elección de la jugada¶
Nuestro juego comienza pidiéndo al jugador que seleccione una de las tres posibles jugadas. Para evitar que el usuario tenga que escribir los nombres de las jugadas, vamos a simplificarlo asignando un número a cada una de ellas. Para ser coherentes con el mensaje impreso por la función menu, vamos a definir la siguiente correspondencia:
[1] - Rock
[2] - Paper
[3] - Scissors
La función select_option() no recibe ningún argumento de entrada pero sí debe devolver una variable de tipo STRING con el nombre del elemento elegido.
Solución¶
def select_option():
option = int(input("Choose your weapon: \n"))
while option < 1 or option > 3:
print("""Option not allowed. Choose:
[1] - Rock
[2] - Paper
[3] - Scissors
""")
option = int(input("Choose your weapon: \n"))
if option == 1:
user_choice = "rock"
elif option == 2:
user_choice = "paper"
else:
user_choice = "scissors"
return user_choice
Note
De nuevo, para hacer el juego más resistente a fallos, utilizamos otro bucle WHILE para asegurar que sólo vamos a aceptar como jugadas válidas los números 1, 2 o 3.
while option < 1 or option > 3:
print("""Option not allowed. Choose:
[1] - Rock
[2] - Paper
[3] - Scissors
""")
option = int(input("Choose your weapon: \n"))
select_option()
Choose your weapon:
1
'rock'
2.4. Simulando al rival¶
Sería complicado implementar este juego para dos jugadores reales sin que uno de ellos viera la jugada del otro con antelación. Para transmitir la sensación de jugar contra un adversario real, vamos a permitir al ordenador elegir una jugada de manera aleatoria y completamente oculta al jugador.
Para ello vas a diseñar la función rival_simulation() que elegirá un elemento aleatorio de entre las opciones “papper”, “rock” y “scissors”. Esta funcionalidad se simplifica mucho utilizando la función choice de la librería random.
See also
Puedes encontrar la documentación de ese método aquí.
La función rival_simulation() tampoco recibe ningún argumento, y como única salida debe devolver la jugada del rival simulado en formato STRING.
Solución¶
import random
def rival_simulation():
options = ["paper", "rock", "scissors"]
rival_choice = random.choice(options)
return rival_choice
See also
Puedes consultar la gran variedad de funcionalidades de la librería random aqui.
Para probar que la función genera valores aleatorios, prueba a ejecutar la siguiente celda varias veces y deberías obtener diferentes resultados:
rival_simulation()
'scissors'
2.5. Decidir el ganador¶
Antes de implementar nuestro programa principal, tenemos que definir una última función. En este caso será el método calculate_winner(user_choice, rival_choice, parameters) que es la encargada de definir, a partir de las jugadas del usuario y del rival, quién ha resultado ganador. Los argumentos de entrada son:
user_choice contiene la jugada del usuario en formato STRING
rival_choice contiene la jugada del rival en formato STRING
parameters el diccionario con los nombres de los jugadores y el número de partidas
La función debe devolver una única variable que contendrá el nombre del jugador vencedor en formato STRING o la palabra “tie” en caso de que se haya producido un empate.
Solución¶
def calculate_winner(user_choice, rival_choice, parameters):
if user_choice==rival_choice:
print("We had a tie!")
winner = "tie"
elif (user_choice == "paper" and rival_choice == "scissors") or \
(user_choice == "rock" and rival_choice == "paper") or \
(user_choice == "scissors" and rival_choice == "rock"):
winner = parameters['rival']
print("The winner is: ",winner)
else:
winner = parameters['user']
print("The winner is: ",winner)
return winner
Ahora podemos probar diferentes combinaciones para asegurarnos que calculate_winner funciona correctamente. Por ejemplo, si ambos jugadores eligen la misma acción:
winner=calculate_winner("rock", "rock", parameters)
We had a tie!
En caso de que el jugador (Theo) obtena una jugada ganadora sobre el ordenador (Simon):
winner=calculate_winner("rock", "scissors", parameters)
The winner is: Theo
Y por último, el caso en el que el jugador (Theo) obtena una jugada perdedora frente al ordenador (Simon):
winner=calculate_winner("rock", "paper", parameters)
The winner is: Simon
2.6. Juego completo¶
Con todas estas funciones ya podemos implementar nuestro programa principal en el que un usuario y el ordenador se disputen un número de partidas. El programa principal debe contabilizar las victorias de cada uno de ellos y presentar un resumen cuando se hayan completado todas las partidas.
Solución¶
user_wins = 0
computer_wins = 0
ties = 0
parameters=request_data()
for i in range(parameters["attempts"]):
print("Match number {}".format(i))
menu()
user_choice = select_option()
rival_choice = rival_simulation()
print(f"{user_choice.upper()} against {rival_choice.upper()}!!!")
winner = calculate_winner(user_choice,rival_choice,parameters)
if winner == parameters["user"]:
user_wins += 1
elif winner == parameters["rival"]:
computer_wins += 1
else:
ties += 1
print(f"""
- {parameters["user"]} won {user_wins} matches\n
- {parameters["rival"]} won {computer_wins} matches \n
- There were {ties} ties\n
""")
Note
Como ves, es un código muy sencillo. Un bucle FOR se encarga de repetir la partida tantas veces como se haya decidido en la función request_data. Tres contadores: user_wins, computer_wins y ties se encargan de ir sumando las victorias y los empates. Y una última instrucción print imprime un resumen por pantalla:
print(f"""
- {parameters["user"]} won {user_wins} matches\n
- {parameters["rival"]} won {computer_wins} matches \n
- There were {ties} ties\n
""")
Seguro que a estas alturas ya te habrás dado cuenta que la función print es muy versatil y permite muchas maneras de presentar información por pantalla. En este ejemplo vemos una de las más populares en las que se puede “insertar” la variable dentro del mensaje del print utilizando las llaves “{}”.
Otra posibles alternativa habría sido:
print("- {} won {} matches\n- {} won {} matches \n- There were {} ties\n".
format(parameters["user"],user_wins, parameters["rival"],computer_wins,ties))
O incluso:
print("- ",parameters["user"], "won ",user_wins," matches\n")
print("- ",parameters["rival"],"won ",computer_wins," matches\n")
print("- There were ",ties," ties\n")
2.7. Extensiones del juego¶
Facil, ¿verdad?. Puedes complicar el juego con nuevas posibilidades. Al final de cada capítulo te sugerimos unas ideas para mejorar el juego y de paso, practicar con nuevos recursos. Algunas propuestas son muy sencillas, pero el objetivo de este capítulo, y del libro en general, es favorecer la práctica de la programación de una manera divertida.
Puedes enriquecer los mensajes de salida utilizando iconos como estos: ✊, ✋ y ✌
Puedes intentar codificar variantes del juego añadiendo más elementos. Aquí tienes algunas sugerencias.
Al terminar el juego, puedes preguntar al usuario si quiere echarse otra partida contra el ordenador. Y en caso de responder afirmativamente, resetear los contadores y volver a reinicializar el juego