CoreWar est un jeu entre deux joueurs humains dans lequel deux programmes partageant la même mémoire s'affrontent. Le but de chacun d'eux est de faire exécuter à l'autre une instruction invalide. Les programmes sont évidemment écrits par les joueurs, mais ceux-ci n'interviennent pas dans le déroulement de la partie.
Un tournoi est organisé entre les élèves de l'Ecole Normale Supérieure, sur la base d'une poule.
Pour pouvoir organiser convenablement le tournoi, j'ai besoin de savoir à peu près qui va participer. Si vous êtes vraiment intéressé(e), je vous serais reconnaissant de bien vouloir vous pré-inscrire.
Le règlement est disponible.
Le langage est un langage d'asemblage. Le compilateur est corewar_cmp fich, qui compile le fichier fich.cwa vers le fichier fich.cwc. Ce compilateur est disponible sur clipper en ~george/corewar.
La première instruction du programme est aussi la première exécutée.
Un ; commence un commentaire.
Le processeur est des plus rudimentaires: un pointeur d'instruction (invisible), un accumulateur, et 15 registres numérotés de 0 à 15. Toutes les adresses sont relatives à la position actuelle, le pointeur d'instruction étant incrémenté après l'exécution. Une instruction de saut désactive l'incrémentation automatique, donc jmp 0 boucle, et jmp 1 passe à l'instruction suivante (nop). De même, lm 1, si reg1=0, copie l'instruction lm 1 elle-même dans l'accumulateur. Toutes les instructions prennent un mot (16 bits). Tous les calculs sont sur 16 bits signés ([-32768;32767]).
La mémoire se compose de 32768 mots de 16 bits, adressée comme un cercle, avec comme origine le pointeur d'instruction du processeur. Cela signifie que 0 pointe sur l'instruction en cours, 1 sur la suivante, -1 et 32767 sur la précédente. Les programmes n'ont aucun accès à leur position absolue, ni évidemment, à celle de l'autre programme.
Instruction | Signification |
dat x | Vaut le mot x. Ceci n'est pas une instruction du processeur |
l x | Copie le contenu du registre x dans l'accumulateur |
s x | Copie le contenu de l'accumulateur dans le registre x |
add x | Ajoute le contenu du registre x à l'accumulateur |
sub x | Soustrait le contenu du registre x à l'accumulateur |
mul x | Multiplie l'accumulateur par le contenu du registre x |
div x | Divise l'accumulateur par le contenu du registre x |
mod x | Divise l'accumulateur par le registre x et garde le reste entier |
lm x | Copie la valeur du mot mémoire pointé par le registre x dans l'accumulateur |
sm x | Copie l'accumulateur dans le mot mémoire pointé par le registre x |
neg | Change la valeur de l'accumulateur en son opposé |
inc | Incrémente la valeur de l'accumulateur de 1 |
dec | Décrémente la valeur de l'accumulateur de 1 |
and x | Réalise un et binaire entre l'accumulateur et le registre x |
or x | Réalise un ou binaire entre l'accumulateur et le registre x |
xor x | Réalise un ou exclusif binaire entre l'accumulateur et le registre x |
shl x | Décale la valeur de l'accumulateur de x bits vers la gauche |
shr x | Décale la valeur de l'accumulateur de x bits vers la droite |
not | Change la valeur de l'accumulateur en son complémentaire binaire |
is=0 | Change l'accumulateur en -1 s'il était nul, 0 sinon |
is<>0 | Change l'accumulateur en -1 s'il était non nul, 0 sinon |
is<0 | Change l'accumulateur en -1 s'il était strictement négatif, 0 sinon |
is>0 | Change l'accumulateur en -1 s'il était strictement positif, 0 sinon |
is<=0 | Change l'accumulateur en -1 s'il était négatif ou nul, 0 sinon |
is>=0 | Change l'accumulateur en -1 s'il était positif ou nul, 0 sinon |
jmp x | Effectue un saut de x mots (x de -128 à 127) |
jc x | Effectue un saut de x mots (x de -128 à 127) si l'accumulateur est non nul, rien sinon |
ljmp | Effectue un saut de la valeur de l'accumulateur |
dlh x | Stoque x dans les 8 bits de poids fort de l'accumulateur |
dll x | Stoque x dans les 8 bits de poids faible de l'accumulateur |
Le combat se déroule dans la même mémoire, mais les processeurs sont distincts: ils ont chacun un pointeur d'instruction et un jeu d'instructions. Des droits d'accès imposent qu'ils exécoutent leurs instructions en alternance.
La mémoire est composée de 32768 mots de 16 bits, chaque instruction tient sur un mot. Les instructions sont composées de deux blocs de 8 bits: le code et l'argument. Pour une instruction sans argument, la valeur est simplement ignorée. Le code est dans les bits de gauche du mot, l'argument dans ceux de droite. Ceci correspond ici à code*256+argument, mais attention, sur 80x86, la formule est code+256*argument. Les codes valides sont les valeurs de 1 à 27. Donc la valeur 0 est toujours une instruction invalide. Attention, le contenu initial de la mémoire n'est pas prévisible à l'initialisation.
Lors d'un match, les programmes sont chargés de manière aléatoire (pour leur position relative), de manière à ce qu'ils ne se chevauchent pas néanmoins. Ils exécutent une instructions chacun à tour de rôle, en commençant par le premier programme. Ceci avantage le premier, mais c'est négligeable après une centaine d'instructions, et de toutes façons, les matches seront joués dans les deux sens.
Un programme est déclaré perdant s'il effectue une action invalide:
Les sources, et tous les fichiers sont disponibles sur clipper dans le répertoire ~george/corewar.
Pour toute question ou remarque, écrivez-moi.