Magic: the Gathering es un juego de cartas coleccionables donde, entre otras cosas, los jugadores juegan cartas que representan criaturas, que luego pueden atacar al otro jugador o defenderse de los ataques del otro jugador bloqueando.
En este desafío de código de golf, su programa estará en el lugar de un jugador de Magic que decida cómo bloquear en combate.
Cada criatura tiene dos atributos relevantes: poder y resistencia. El poder de una criatura es la cantidad de daño que puede causar en un combate, y su resistencia es la cantidad de daño necesaria para destruirla. La potencia siempre es al menos 0, y la tenacidad siempre es al menos 1.
Durante el combate en Magic, el jugador cuyo turno es declara que algunas de sus criaturas están atacando al oponente. Luego, el otro jugador, conocido como el jugador defensor, puede asignar a sus criaturas como bloqueadores. Una criatura puede bloquear solo una criatura por combate, pero varias criaturas pueden bloquear a la misma criatura.
Después de que se declaran los bloqueadores, el jugador atacante decide, por cada criatura atacante que fue bloqueada, cómo distribuir el daño (igual a su poder) que esa criatura inflige a las criaturas que lo bloquean.
Luego, se inflige daño. Cada criatura hace daño igual a su poder. Las criaturas atacantes que fueron bloqueadas infligen daño como se describe arriba. Las criaturas atacantes desbloqueadas infligen daño al jugador defensor. Las criaturas bloqueadoras hacen daño a la criatura que bloquearon. Las criaturas que pertenecen al jugador defensor que no bloquearon no infligen daño. (No se requiere que las criaturas bloqueen).
Finalmente, cualquier criatura con daño igual o mayor que su resistencia es destruida y eliminada del campo de batalla. Cualquier cantidad de daño menor que la resistencia de una criatura no tiene efecto.
Aquí hay un ejemplo de este proceso:
Una criatura con poder P y resistencia T se representa como P/T
Attacking:
2/2, 3/3
Defending player's creatures:
1/4, 1/1, 0/1
Defending player declares blockers:
1/4 and 1/1 block 2/2, 0/1 does not block.
Attacking player distributes damage:
2/2 deals 1 damage to 1/4 and 1 damage to 1/1
Damage is dealt:
2/2 takes 2 damage, destroyed.
3/3 takes 0 damage.
1/1 takes 1 damage, destroyed.
1/4 takes 1 damage.
0/1 takes 0 damage.
Defending player is dealt 3 damage.
El jugador defensor tiene 3 objetivos en combate: destruir las criaturas del oponente, preservar las propias criaturas y recibir el menor daño posible. Además, las criaturas con más poder y resistencia son más valiosas.
Para combinarlos en una sola medida, diremos que la puntuación del jugador defensor de un combate es igual a la suma de los poderes y la resistencia de sus criaturas sobrevivientes, menos la suma de los poderes y la resistencia de las criaturas sobrevivientes de su oponente, menos uno La mitad de la cantidad de daño infligido al jugador defensor. El jugador defensor quiere maximizar este puntaje, mientras que el jugador atacante quiere minimizarlo.
En el combate que se muestra arriba, el puntaje fue:
Defending player's surviving creatures:
1/4, 0/1
1 + 4 + 0 + 1 = 6
Attacking player's surviving creature:
3/3
3 + 3 = 6
Damage dealt to defending player:
3
6 - 6 - 3/2 = -1.5
Si el jugador defensor no hubiera bloqueado en absoluto en el combate descrito anteriormente, la puntuación habría sido
8 - 10 - (5/2) = -4.5
La elección óptima para el jugador defensor habría sido bloquear el 2/2
con el 1/1
y el 1/4
, y bloquear el 3/3
con el 0/1
. Si lo hubieran hecho, solo 1/4
y el 3/3
habría sobrevivido, y no se habría causado ningún daño al jugador defensor, haciendo el puntaje
5 - 6 - (0/2) = -1
Su desafío es escribir un programa que genere la opción de bloqueo óptima para el jugador defensor. "Óptimo" significa la elección que maximiza la puntuación, dado que el oponente distribuye el daño de la manera que minimiza la puntuación, dada la forma en que bloqueaste.
Esta es una maximina: el puntaje máximo sobre las distribuciones de daño que minimiza el puntaje para cada combinación de bloqueo.
Entrada: La entrada consistirá en dos listas de 2 tuplas, donde cada 2 tuplas tiene la forma (potencia, resistencia). La primera lista contendrá los poderes y la resistencia de cada criatura atacante (las criaturas de tu oponente). La segunda lista contendrá los poderes y la resistencia de cada una de tus criaturas.
Las tuplas y las listas se pueden representar en cualquier formato conveniente, como:
[[2, 2], [3, 3]]
[[1, 4], [1, 1], [0, 1]]
Salida: La salida consistirá en una serie de 2 tuplas, en la forma (criatura bloqueadora, criatura bloqueada), es decir, una de tus criaturas seguida de una de sus criaturas. Se hará referencia a las criaturas por su índice en las listas de entrada. Los índices pueden ser 0 o 1 indexados. De nuevo, cualquier formato conveniente. Cualquier orden está bien. Por ejemplo, el escenario de bloqueo óptimo desde arriba, dada la entrada anterior, podría representarse como:
[0, 0] # 1/4 blocks 2/2
[1, 0] # 1/1 blocks 2/2
[2, 1] # 0/1 blocks 3/3
Ejemplos:
Input:
[[2, 2], [3, 3]]
[[1, 4], [1, 1], [0, 1]]
Output:
[0, 0]
[1, 0]
[2, 1]
Input:
[[3, 3], [3, 3]]
[[2, 3], [2, 2], [2, 2]]
Output:
[1, 0]
[2, 0]
or
[1, 1]
[2, 1]
Input:
[[3, 1], [7, 2]]
[[0, 4], [1, 1]]
Output:
[1, 0]
or
[0, 0]
[1, 0]
Input:
[[2, 2]]
[[1, 1]]
Output:
(No output tuples).
La entrada y salida puede ser a través de STDIN, STDOUT, CLA, entrada / retorno de funciones, etc. Se aplican lagunas estándar . Esto es code-golf: el código más corto en bytes gana.
Para aclarar las especificaciones y proporcionar ideas iniciales, este pastebin proporciona una solución de referencia en Python. La best_block
función es una solución de muestra para este desafío, y ejecutar el programa proporcionará entradas y salidas más detalladas.