MANUAL DE REDCODE
CoreDuel implementa el estándar ICWS'94 con las extensiones de pMARS (p-space, FOR/ROF, expresiones en EQU). Si conoces pMARS, todo esto te resultará familiar.
0. De qué va este juego
Escribes programas pequeños, bots, y los mandas a la Arena a luchar contra otros bots. Un bot se escribe en Redcode, un lenguaje parecido al ensamblador con 19 instrucciones. Todos los bots de una partida se cargan en una memoria compartida, el núcleo: un anillo de 8000 celdas (el final enlaza con el principio) dentro de un ordenador emulado muy simple llamado MARS. En ese ordenador no hay nada más: ni pantalla, ni archivos, solo instrucciones en celdas y unos pocos procesos que las ejecutan.
Cada bot empieza con un proceso en una posición aleatoria, a por lo menos 100 celdas de los demás. El emulador da turnos a los bots por rotación; en su turno, un bot ejecuta una instrucción de uno de sus procesos. Un proceso muere al ejecutar una instrucción DAT (o al dividir entre cero); un bot muere cuando pierde su último proceso. Como todos comparten la memoria, para ganar hay que sobrescribir el código del rival con bombas DAT, buscarlo escaneando el núcleo o inundar el núcleo con copias de uno mismo, manteniendo vivo el propio código.
Una ronda termina cuando solo queda un bot o tras 80000 ciclos. Una partida son una o más rondas; los supervivientes de cada ronda suman puntos y gana el mejor total. Ese es todo el juego: escribir un programa mejor que el del otro jugador.
Para empezar:
- Bots: clona un clásico de la biblioteca (Imp, Dwarf) o escribe uno nuevo; el editor comprueba el código mientras escribes.
- Arena: rellena los slots de bots (un solo bot es una prueba), fija rondas y velocidad, EMPEZAR y mira el núcleo.
- Tutorial: ocho lecciones breves que construyen un bot funcional paso a paso. El resto de este manual es la referencia del lenguaje.
1. El núcleo
El núcleo es un anillo de 8000 celdas. Cada celda contiene una instrucción. Las direcciones dan la vuelta: celda 7999 + 1 = celda 0. En Redcode no hay direcciones absolutas; toda dirección es relativa a la instrucción que la usa.
Antes de cada ronda, todas las celdas contienen DAT.F $0, $0. Los guerreros se colocan en posiciones aleatorias separadas al menos MINDISTANCE (100) celdas. Cada guerrero empieza con un proceso en su ORG.
Los procesos se turnan: el guerrero A ejecuta una instrucción, luego el guerrero B, y así sucesivamente. Un guerrero con varios procesos los ejecuta por turnos rotativos (round-robin), uno por turno.
Un proceso muere cuando ejecuta DAT o divide por cero. Un guerrero muere cuando muere su último proceso. La ronda termina cuando queda un solo guerrero o tras MAXCYCLES (80000) ciclos.
2. Estructura del programa
;redcode-94
;name Dwarf
;author A. K. Dewdney
;strategy Bombs every 4th cell.
;assert CORESIZE == 8000
ORG start
target DAT.F #0, #0
start ADD.AB #4, target
MOV.AB #0, @target
JMP start
END
- Todo lo que va después de
;es un comentario. Las líneas;name,;authory;strategyse muestran en la lista de bots y en la arena. ;assert EXPRdebe ser verdadera o el guerrero se rechaza. Úsala para indicar para qué tamaño de núcleo lo ajustaste.- El texto anterior a
;redcode(cabeceras de correo, prosa) se ignora. - Las etiquetas van al principio de la línea. Se admiten dos puntos al final (
start: ADD ...). Las etiquetas distinguen mayúsculas y minúsculas. - Los códigos de operación, modificadores y modos no distinguen mayúsculas y minúsculas.
- Un programa puede tener como máximo
MAXLENGTH(100) instrucciones.
3. Sintaxis de las instrucciones
label OPCODE.MOD A-mode A-value, B-mode B-value ; comment
Cada instrucción tiene un código de operación (opcode), un modificador, un operando A y un operando B. Cada operando es un modo de direccionamiento más un valor. Los valores son expresiones (ver 8) que se evalúan respecto a la dirección de la propia instrucción.
Si escribes un solo operando, el ensamblador completa el otro:
DAT xse convierte enDAT #0, x.- Para cualquier otro opcode, el único operando es A y B pasa a ser
$0.
4. Modos de direccionamiento
Cada operando se resuelve en un puntero (una dirección de celda) antes de ejecutar el opcode. Los dos operandos se evalúan siempre, primero A, incluso cuando el opcode ignora uno de ellos. Por eso los efectos secundarios de predecremento/postincremento ocurren incluso en JMP.
#inmediato. El puntero es la propia instrucción actual; el valor se usa como número.$directo (el modo por defecto). Puntero = aquí + valor.@indirecto por B. Puntero = (aquí + valor) + campo B de esa celda.<indirecto por B con predecremento. Primero decrementa el campo B de la celda (aquí + valor) y luego actúa como@.>indirecto por B con postincremento. Actúa como@y luego incrementa el campo B de esa celda.*indirecto por A. Como@, pero a través del campo A.{indirecto por A con predecremento. Como<, a través del campo A.}indirecto por A con postincremento. Como>, a través del campo A.
Nota: en ICWS'94 el operando inmediato también tiene puntero: la propia instrucción. MOV.I #0, 1 copia la instrucción entera una celda hacia adelante. Es el clásico Imp.
5. Modificadores
El modificador indica qué campos lee y escribe el opcode. Para una instrucción con puntero A a y puntero B b:
.Acampo A de a al campo A de b..Bcampo B de a al campo B de b..ABcampo A de a al campo B de b..BAcampo B de a al campo A de b..Fambos campos, A a A y B a B..Xambos campos cruzados, A a B y B a A..Ila instrucción entera, incluidos opcode y modos. Solo paraMOV; en aritmética.Ise comporta como.F.
Modificador por defecto si lo omites:
DAT,NOP:.FMOV,CMP,SEQ,SNE:.ABsi A es inmediato,.Bsi B es inmediato, si no.IADD,SUB,MUL,DIV,MOD:.ABsi A es inmediato,.Bsi B es inmediato, si no.FSLT,LDP,STP:.ABsi A es inmediato, si no.BJMP,JMZ,JMN,DJN,SPL:.B
6. Códigos de operación
DATMata al proceso que lo ejecuta. También es la celda de datos habitual y la bomba.MOVCopia de A a B.ADDB = B + A (según el modificador).SUBB = B - A.MULB = B * A.DIVB = B / A. La división por cero mata al proceso; con.F/.X/.Iel otro campo se escribe igualmente si su divisor no es cero.MODB = B mod A. Misma regla del cero queDIV.JMPSalta al puntero A.JMZSalta a A si el campo o campos de B comprobados son cero. Con.F/.X/.Iambos campos deben ser cero.JMNSalta a A si el campo o campos comprobados no son cero. Con.F/.X/.I: si alguno no es cero.DJNDecrementa el campo o campos comprobados de B y luego salta a A si el resultado no es cero. El clásico contador de bucle.SPLAñade un proceso nuevo en el puntero A, en cola detrás de los procesos actuales. El proceso actual continúa en la instrucción siguiente. HastaMAXPROCESSES(8000) por guerrero; a partir de ahíSPLno hace nada.SEQSalta la instrucción siguiente si A es igual a B (según el modificador).CMPes un sinónimo.SNESalta la instrucción siguiente si A es distinto de B.SLTSalta la instrucción siguiente si A es menor que B (sin signo, 0..7999).LDPCarga desde p-space: el valor de p-space[valor A] se escribe en el destino B.STPGuarda en p-space: el valor A se escribe en p-space[valor B].NOPNo hace nada (pero aun así evalúa ambos operandos).
Toda la aritmética es módulo CORESIZE. Los números en el núcleo siempre van de 0 a 7999; -1 se guarda como 7999.
7. Directivas
ORG labelDónde empieza la ejecución. Por defecto: la primera instrucción.END [label]Fin del código fuente; una etiqueta opcional actúa comoORG.name EQU exprConstante textual; cada uso posterior de name se sustituye por expr. Puede contener un operando con su modo (EQU #7) o incluso un opcode.FOR n ... ROFRepite el bloque n veces. Una etiqueta en la línea delFOR, o en la línea justo anterior, es el contador (empieza en 1).&counterdentro del bloque se expande al contador con dos dígitos, así quelabel&igeneralabel01,label02, ... Los bloquesFOR 0se omiten, útiles como comentarios largos.PIN nIdentidad de p-space. Dos guerreros con el mismoPINcomparten su p-space (salvo la celda 0).
ORG loop
loop FOR 3
MOV.I #0, &loop
ROF
8. Expresiones
Operadores, de mayor a menor prioridad: unarios - + !, luego * / % (enteros, con truncamiento), luego + -, luego comparaciones == != < > <= >=, luego && y ||. Se admiten paréntesis. Las comparaciones dan 1 o 0.
Constantes predefinidas: CORESIZE, MAXCYCLES, MAXPROCESSES, MAXLENGTH, MINDISTANCE, PSPACESIZE, ROUNDS, WARRIORS (2), VERSION (92), CURLINE (índice de la instrucción actual).
Una etiqueta usada en una expresión vale su distancia a la instrucción actual, así que label+1 es la celda que sigue a label, y start-target es simplemente un número de celdas.
9. P-space
Cada guerrero tiene un array privado de PSPACESIZE (500) celdas que se conserva entre las rondas de una partida. Los índices dan la vuelta. La celda 0 es especial y siempre privada: al comienzo de cada ronda contiene el resultado anterior, 0 si el guerrero murió y, si no, el número de guerreros supervivientes (1 = victoria, 2 = empate). En la primera ronda contiene CORESIZE-1.
LDP.AB #0, x carga ese resultado en el campo B de x. STP.B x, #1 guarda el campo B de x en la celda 1. Un guerrero puede usarlo para cambiar de estrategia tras una derrota.
10. Reglas de la partida
- Tamaño del núcleo 8000, ciclos máx. 80000, procesos máx. 8000, longitud máx. 100, distancia mín. 100, p-space 500.
- Una partida son N rondas. Las posiciones iniciales dependen de la semilla de la partida y del número de ronda; la misma semilla reproduce la misma partida.
- Puntuación: cada superviviente de una ronda recibe (W*W-1)/S puntos, W = número de guerreros, S = supervivientes; los demás, 0. Con dos guerreros son 3 por victoria, 1 cada uno por empate, 0 por derrota.
- Hasta 36 guerreros pueden compartir el núcleo (los Ajustes fijan el límite de slots); empiezan a al menos MINDISTANCE de distancia y el mismo bot puede ocupar varios slots.
- El guerrero que ejecuta primero se alterna en cada ronda.
- El modo de prueba (un bot) indica SOBREVIVIÓ o MURIÓ al llegar a
MAXCYCLES.
11. Patrones comunes
- Imp:
MOV.I #0, 1. Las bombas no lo matan, pero nunca gana solo. - Puerta anti-imp:
JMP 0, <gate. Decrementa la celda de delante en cada ciclo y convierte los imps que llegan enMOV.I 0, 0. - Bombardero (Dwarf): bucle de
ADD,MOV,JMPque sueltaDATs con un paso que cubre todo el núcleo. - Escáner: compara celdas con cero y bombardea lo que encuentra.
- Replicador (paper): se copia a sí mismo en otro sitio con un bucle de
MOVy luego haceSPLallí. - Bomba SPL: alfombras de
SPL 0; el guerrero que cae en ellas llena su cola de procesos con bucles inútiles. - Arranque (boot): copia el guerrero lejos y ejecuta la copia, de modo que el código original sirve de señuelo.