Test Driver • Discusión de desafío • Enviar aventurero
Varios aventureros rivales están atacando las ruinas en busca de tesoros, pero solo pueden transportar tanto a la vez y tienen sus límites de resistencia. Quieren obtener el tesoro más valioso y salir antes de cansarse demasiado para continuar. Están tratando de hacerse lo más ricos posible de sus travesuras de saqueo.
Jugabilidad
Cada aventurero comienza en la primera habitación de la mazmorra con 1000 puntos de resistencia y 50 kg de espacio en su mochila.
El juego funciona por turnos, con todos los jugadores resolviendo sus turnos simultáneamente. Cada turno, puedes realizar una de las siguientes acciones:
- Pasar a la siguiente habitación.
- Moverse a la sala anterior.
- Oferta de resistencia para tomar un tesoro.
- Suelta un tesoro.
Moverse entre las habitaciones requiere 10 de resistencia, más 1 por cada 5 kg actualmente en su mochila, redondeado. Por ejemplo, un aventurero que lleva 3 kg de tesoro requiere 11 resistencia para moverse y uno que lleva 47 kg requiere 20 resistencia para moverse.
La caída del tesoro requiere 1 resistencia, independientemente del tesoro que se caiga.
Al salir de las ruinas, el jugador no tomará más turnos.
Si un jugador no puede realizar ninguna de estas acciones (debido a la escasez de resistencia o la ausencia de tesoros), su aventurero muere de agotamiento, derramando su tesoro en la habitación actualmente ocupada. Del mismo modo, si un jugador intenta realizar una acción no válida, su aventurero será asesinado por una trampa, lo que provocará el mismo derrame del tesoro.
Ofertas
La oferta mínima para un tesoro es 1 resistencia por 1 kg que pesa el tesoro. También puede ofertar puntos de resistencia adicionales para tener más probabilidades de obtener el tesoro. La resistencia que se ofertó se consume sin importar cuál sea el resultado.
En el caso de que varios jugadores hayan hecho una oferta para tomar el mismo tesoro, el jugador que oferte más alto obtiene el tesoro. Si más de un jugador hizo la oferta más alta, ninguno de ellos recibirá el tesoro.
Condición de victoria
El jugador con el mayor valor total de tesoros es el ganador. En el improbable caso de un empate, los empates van al menor peso total, luego al menor número de tesoros, luego el valor del tesoro más valioso, el segundo más valioso, el tercero ... hasta que se rompa el empate. En el caso casi imposible de que todavía haya un empate en este punto, el conductor de la prueba dice "atorníllelo" y el ganador se determina arbitrariamente.
En el contexto del torneo, los jugadores serán clasificados con el primer lugar recibiendo 10 puntos, el segundo lugar con 9 puntos, el tercer lugar con 8 puntos, etc., con jugadores muertos y aventureros sin tesoros que obtengan 0 puntos.
Sobre las ruinas
- Cada habitación contiene inicialmente entre y tesoros. (Donde es el número de habitación)
- Hay arbitrariamente muchas habitaciones, limitadas solo por la resistencia de los aventureros y su disposición a explorar.
- Cada tesoro tendrá un valor monetario (en $ enteros) y un peso (en kg enteros).
- Los tesoros tienden a ser más valiosos y abundantes a medida que profundizas en las ruinas.
- Las fórmulas específicas para generar tesoros son las siguientes: (usando notación para tiradas de dados)
- El peso se genera primero usando la fórmula (mínimo de 1)
- El valor del tesoro se genera a través de (donde es el número de habitación es el peso)
Información visible para los jugadores
En cada turno, los jugadores obtienen la siguiente información:
- El número de la habitación en la que se encuentran actualmente. Esto está indexado en 1, por lo que conceptualmente la salida está en la "habitación 0"
- Una lista de tesoros actualmente en la sala.
- Una lista de otros jugadores que también están actualmente en la sala.
- Tu inventario actual de tesoros
- Tu nivel de resistencia actual
Codificación
El controlador de prueba se puede encontrar aquí .
Debe implementar una subclase de esta Adventurer
clase:
class Adventurer:
def __init__(self, name, random):
self.name = name
self.random = random
def get_action(self, state):
raise NotImplementedError()
def enter_ruins(self):
pass
Solo necesita anular el get_action
método. enter_ruins
se ejecuta antes de que comience un juego y es tu oportunidad de preparar lo que quieras tener listo para el juego. No necesita anular __init__
, y realmente no debería . Si se __init__
bloquea, será descalificado.
get_action
recibe un único argumento que es un namedtuple
con los siguientes campos (en este orden, si prefiere la desestructuración):
room
: el número de la habitación en la que estás actualmentetreasures
: la lista de tesoros en la salaplayers
: la lista de otros jugadores en la sala. Solo obtienes el nombre del jugador de esta manera, por lo que no sabes qué bot los controla o su inventario / resistencia.inventory
: la lista de tesoros en tu mochilastamina
: tu nivel de resistencia actual
Este objeto además proporciona dos propiedades de utilidad:
carry_weight
: el peso total de todos los tesoros que llevastotal_value
: el valor total de todos los tesoros que llevas
Las listas treasures
y inventory
contienen namedtuple
s con estos atributos:
name
: el nombre del tesoro (para fines cosméticos)value
: el valor monetario del tesoro en $.weight
: el peso del tesoro en kg
get_action
debería devolver uno de los siguientes valores / patrones:
'next'
o'previous'
para pasar a las habitaciones siguientes / anteriores'take', <treasure index>, <bid>
(sí, como una tupla, aunque cualquier secuencia técnicamente funcionará también) para ofertar por el tesoro en el índice dado en la lista de tesoros de la sala. Ambos argumentos deben ser enteros. Las carrozas se redondearán hacia abajo.'drop', <inventory index>
para soltar el tesoro llevado encontrado en el índice dado. El índice debería (naturalmente) ser un número entero.
Otras restricciones
- Solo puede usar la instancia aleatoria que se le proporcionó durante la inicialización para la pseudoaleatoriedad.
- Cualquier otra cosa que pueda introducir el no determinismo conductual no está permitida. La intención aquí es hacer que los bots se comporten de manera idéntica cuando se les da la misma semilla para ayudar a probar nuevos bots (y potencialmente errores en el controlador de prueba). Solo la radiación cósmica debería causar cualquier desviación / no determinismo.
- Tenga en cuenta que los códigos hash son aleatorios en Python 3, por
hash
lo que no está permitido usarlos para tomar decisiones.dict
s están bien incluso cuando se usa el orden de iteración para las decisiones, ya que se ha garantizado que el orden es consistente desde Python 3.6.
- No puede eludir el controlador de prueba utilizando
ctypes
hacks oinspect
stack vudú (o cualquier otro método). Hay algunas cosas impresionantemente aterradoras que puede hacer con esos módulos. Por favor no lo hagas.- Cada bot se guarda en una caja de arena razonablemente bien a través de copias defensivas y la inmutabilidad natural de
namedtuple
s, pero hay algunas lagunas / vulnerabilidades incompatibles. - Se puede usar otra funcionalidad de
inspect
yctypes
siempre que ninguna se use para burlar la funcionalidad del controlador. - No se permite ningún método de capturar instancias de los otros bots en tu juego actual.
- Cada bot se guarda en una caja de arena razonablemente bien a través de copias defensivas y la inmutabilidad natural de
- Los bots deben operar solos y no pueden coordinarse con ningún otro bot de ninguna manera para ningún propósito. Esto incluye la creación de dos bots con objetivos diferentes, de modo que uno se sacrifique por el éxito del otro. Una vez que haya más de 10 competidores, no se te garantizará tener los dos bots en el mismo juego y los nombres de los aventureros no dan ninguna indicación de la clase de bot, por lo que este tipo de estrategias son limitadas de todos modos.
- Actualmente no existe una restricción estricta en el tiempo de ejecución, sin embargo, me reservo el derecho de restringirlo en el futuro si los torneos comienzan a tomar demasiado tiempo. Sea razonable e intente mantener el procesamiento por turnos por debajo de 100 ms , ya que no preveo la necesidad de restringirlo por debajo de ese umbral. (Los torneos se ejecutarán en aproximadamente 2 horas si todos los bots tardan unos 100 ms por turno).
- Su clase de bot debe tener un nombre único entre todas las presentaciones.
- Es posible que no recuerdes nada entre juegos. (Sin embargo, usted puede recordar las cosas entre turnos )
- No edite sys.modules. Cualquier cosa fuera de las variables de instancia debe tratarse como una constante.
- No puede modificar el código de ningún bot mediante programación, incluido el suyo.
- Esto incluye eliminar y restaurar su código. Esto es para simplificar la depuración y los torneos.
- Cualquier código que haga que el controlador se bloquee será descalificado de inmediato. Si bien se detectarán la mayoría de las excepciones, algunas pueden pasar y los valores predeterminados no se pueden detectar. (Sí, puedes segfault en Python gracias a
ctypes
)
Envíos
Para facilitar el raspado de respuestas, indique el nombre de su bot en la parte superior de la respuesta con un #Header1
y asegúrese de que su respuesta incluya al menos un bloque de código (solo se usará el primero en su respuesta). No necesita incluir ninguna importación o cadena de documentos, ya que el raspador los agregará automáticamente.
Estaré más inclinado a votar las respuestas con explicaciones detalladas y comprensibles. Es probable que otros se comporten igual.
Hablando en términos generales, su respuesta debe tener el siguiente formato:
# Name of Bot
Optional blurb
#imports go here
class BotName(Adventurer):
#implementation
Explanation of bot algorithm, credits, etc...
(rendido como)
Nombre del bot
Comentario opcional
#imports go here class BotName(Adventurer): #implementation
Explicación del algoritmo bot, créditos, etc.
Ejecutar el controlador de prueba localmente
Necesitará Python 3.7+ y le recomiendo que también instale a tabulate
través de pip. Raspar esta página para envíos también requiere lxml
y requests
. También debe usar un terminal con soporte para escapes de color ANSI para obtener mejores resultados. Puede encontrar información sobre cómo configurar esto en Windows 10 aquí .
Agregue su bot a un archivo en un subdirectorio dentro del mismo directorio que ruins.py
( ruins_bots
de manera predeterminada) y asegúrese de agregarlo from __main__ import Adventurer
en la parte superior del módulo. Esto se agrega a los módulos cuando el raspador descarga su envío, y si bien es definitivamente hacky, esta es la forma más sencilla de asegurarse de que su bot tenga acceso correctamente Adventurer
.
Todos los bots en ese directorio se cargarán dinámicamente en tiempo de ejecución, por lo que no se necesitan más cambios.
Torneo
El vencedor final se determinará en una serie de juegos con hasta 10 bots en cada juego. Si hay más de 10 envíos totales, los 10 mejores bots se determinarán dividiéndolos sistemáticamente en grupos de 10 hasta que cada bot haya jugado (exactamente) 20 juegos. Los 10 mejores bots serán seleccionados de este grupo con puntajes de reinicio y jugarán juegos hasta que el primer lugar haya alcanzado una ventaja de 50 puntos sobre el segundo lugar o hasta que se hayan jugado 500 juegos.
Hasta que haya al menos 10 presentaciones, los espacios vacíos se llenarán con "borrachos" que deambulan aleatoriamente por las ruinas y toman (y ocasionalmente arrojan) tesoros aleatorios hasta que se quedan sin resistencia y tienen que ir directamente a la salida.
Los torneos se volverán a ejecutar semanalmente si hay nuevos envíos. Este es un desafío KOTH abierto sin fecha de finalización establecida.
Tabla de clasificación
Desde el 4 de mayo de 2019 a las 4:25 PM MDT: (2019-05-04 4:25 -6: 00)
Seed: K48XMESC
Bot Class | Score | Mean Score
--------------+---------+--------------
BountyHunter | 898 | 7.301
Scoundrel | 847 | 6.886
Accountant | 773 | 6.285
Ponderer | 730 | 5.935
Artyventurer | 707 | 5.748
PlanAhead | 698 | 5.675
Sprinter | 683 | 5.553
Accomodator | 661 | 5.374
Memorizer | 459 | 3.732
Backwards | 296 | 2.407
Actualización - 15 de abril: un par de actualizaciones / aclaraciones de reglas
Actualización - 17 de abril: prohibición de un par de casos extremos notables de acciones nefastas como modificar el código de otros bots.
Actualización: 4 de mayo: recompensa otorgada a Sleafar por destruir absolutamente al revés. ¡Felicidades!
pip
instalado y encendido PATH
(que es el predeterminado para las instalaciones más nuevas AFAIK), desde Windows puede ejecutarlo pip install modulename
en el símbolo del sistema. Para otras circunstancias (que no conozco), vaya a pip , busque el módulo necesario y elija una opción.