¡Prepárate para un duelo de ingenio, estrategia y… código! ¿Quién ganará en esta batalla algorítmica de Piedra, Papel y Tijera? ⚔️
🔮 Enunciado del Problema
Ana y Alejandro, dos entusiastas de la programación, han llevado su rivalidad hasta el ancestral juego de Piedra, Papel y Tijera. Para automatizar la ardua tarea de determinar el ganador, necesitamos tu ayuda.
El Desafío:
Escribe una función en Python que reciba como entrada una serie de partidas de Piedra, Papel y Tijera y determine quién ha ganado en general.
Parámetros:
games[n][2]: Una lista de listas, donde cada sublista representa una partida. Cada partida contiene las jugadas de ambos jugadores como strings de un solo carácter:'r': Piedra'p': Papel's': Tijera
Retorna:
string: El resultado general del juego:'Jugador 1': Si el Jugador 1 ha ganado más partidas que el Jugador 2.'Jugador 2': Si el Jugador 2 ha ganado más partidas que el Jugador 1.'Empate': Si ambos jugadores han ganado el mismo número de partidas.
Ejemplos:
>>> rock_paper_seasor([['r', 's'], ['s', 'r']])
'Empate'
>>> rock_paper_seasor([['r', 's']])
'Jugador 1'
>>> rock_paper_seasor([['s', 'r'], ['r', 'r']])
'Jugador 2'
>>> rock_paper_seasor([['p', 'p'], ['s', 's'], ['r', 's'], ['r', 'p']])
'Empate'
Notas Adicionales:
- Asume que la entrada siempre será válida. No es necesario validar los caracteres de entrada.
- La función debe ser eficiente y optimizada para el rendimiento.
🧩 Resolución Paso a Paso
La clave de esta solución radica en mantener un rastreador de puntaje que se incrementa o disminuye según quién gane cada partida. En lugar de hacer comparaciones directas entre las jugadas, simplificamos la lógica con condicionales anidados que evalúan las combinaciones ganadoras.
Primero, inicializamos una variable llamada result para llevar la cuenta de las victorias y derrotas. Esta variable actuará como un termómetro del dominio en el juego:
result = 0
A continuación, iteramos sobre cada partida en la lista games. Este bucle for es el motor que impulsa la evaluación de cada enfrentamiento:
for game in games:
m1 = game[0]
Dentro del bucle, asignamos la jugada del jugador 1 a la variable m1, que nos servirá como punto de referencia para determinar el resultado de la partida. Observamos que asumimos que el jugador 1 siempre juega primero.
Ahora viene la parte crucial: evaluar quién gana cada partida y actualizar el puntaje. Utilizamos condicionales if y elif para verificar las posibles combinaciones ganadoras:
if 's' in game and 'p' in game:
result += -1 if m1 == 's' else 1
elif 'p' in game and 'r' in game:
result += -1 if m1 == 'p' else 1
elif 'r' in game and 's' in game:
result += -1 if m1 == 'r' else 1
En este bloque, utilizamos el operador ternario condition ? value_if_true : value_if_false (en este caso value_if_true if condition else value_if_false), una forma concisa de escribir un if-else en una sola línea. Si el jugador 1 gana la partida (por ejemplo, jugando tijera contra papel), restamos 1 a result. Si el jugador 2 gana, sumamos 1 a result.
Finalmente, después de evaluar todas las partidas, determinamos el ganador general basándonos en el valor de result:
return 'Jugador 1' if result < 0 else 'Jugador 2' if result > 0 else 'Empate'
Aquí nuevamente utilizamos el operador ternario. Si result es negativo, el Jugador 1 ha ganado. Si es positivo, el Jugador 2 ha ganado. Si es cero, hay un empate.
Solución Completa:
def rock_paper_seasor(games):
"level: medium; points: 6"
result = 0
for game in games:
m1 = game[0]
if 's' in game and 'p' in game:
result += -1 if m1 == 's' else 1
elif 'p' in game and 'r' in game:
result += -1 if m1 == 'p' else 1
elif 'r' in game and 's' in game:
result += -1 if m1 == 'r' else 1
return 'Jugador 1' if result < 0 else 'Jugador 2' if result > 0 else 'Empate'
🧠 Conceptos Clave
La solución propuesta se sustenta sobre pilares fundamentales de la programación. La iteración, mediante el bucle for, nos permite procesar cada partida individualmente. Las condicionales (if, elif) son esenciales para implementar la lógica del juego, determinando el ganador en función de las jugadas. El operador ternario, por su parte, ofrece una sintaxis concisa y elegante para expresar decisiones simples. Las estructuras de datos, en este caso, la lista de listas games, son cruciales para organizar la información de entrada de manera eficiente.
La lógica de juego está encapsulada en las comparaciones de jugadas y la actualización del puntaje. Se utilizan comparaciones dentro de las condicionales para determinar si una jugada es ganadora o perdedora. Cada uno de estos conceptos, aunque individualmente sencillos, se entrelazan para crear una solución robusta y eficiente.
¿Sabías que la complejidad temporal de esta función es O(n), donde n es el número de partidas? Esto significa que el tiempo de ejecución crece linealmente con la cantidad de partidas, lo que la hace eficiente incluso para grandes conjuntos de datos.
💫 Reflexiones Finales
Esta solución, aunque funcional, puede optimizarse aún más. Por ejemplo, podríamos utilizar un diccionario para mapear las jugadas a valores numéricos, simplificando las comparaciones. Además, podríamos considerar la posibilidad de extender la función para manejar entradas inválidas o para incluir otras variantes del juego, como “Piedra, Papel, Tijera, Lagarto, Spock”.
Si te ha gustado este análisis y quieres profundizar en el mundo de los algoritmos y la resolución de problemas, ¡no dudes en explorar otros artículos de nuestro blog! La programación es un universo infinito de posibilidades, ¡y te invitamos a descubrirlo junto a nosotros! 🚀