Il s'agit d'une adaptation de Core War , une programmation KOTH datant du 20e siècle. Pour être plus précis, il utilise un ensemble d'instructions incroyablement simplifié basé principalement sur la proposition d'origine .
Contexte
Dans Core War, deux programmes se battent pour contrôler l'ordinateur. Le but de chaque programme est de gagner en localisant et en terminant le programme opposé.
La bataille se déroule dans la mémoire principale de l'ordinateur. Cette mémoire est appelée Core et contient 8192 adresses. Lorsque la bataille commence, le code de chaque compétiteur (appelé guerrier) est placé dans un morceau de mémoire aléatoire. L'exécution du programme alterne entre les guerriers, exécutant une instruction de chacun. Chaque instruction est capable de modifier une partie du Core, conduisant à la possibilité de programmes auto-modifiés.
Le but est de mettre fin au programme adverse. Un programme se termine lorsqu'il tente d'exécuter une instruction non valide, qui est n'importe quelle DAT
instruction.
L'ensemble d'instructions
Chaque programme se compose d'une série d'instructions de bas niveau, chacune prenant deux champs, appelés champs A et B.
Ce jeu d'instructions s'inspire largement des spécifications d'origine. Les principaux changements sont 1) des précisions sur l'ajout / la soustraction de commandes et 2) un changement du #
mode d'adressage pour permettre son utilisation n'importe où. La plupart des versions complètes de Core Wars ont plus de 20 opcodes, 8 modes d'adressage et un ensemble de "modificateurs d'instructions".
Opcodes
Chaque instruction doit avoir l'un des sept opcodes différents.
DAT A B
- (données) - Cela contient simplement les chiffresA
etB
. Surtout, un processus meurt lorsqu'il tente d'exécuter une instruction DAT.MOV A B
- (déplacer) - Ceci déplace le contenu de l'emplacementA
mémoire vers l'emplacement mémoireB
. Voici une démonstration d'avant-après:MOV 2 1 ADD @4 #5 JMP #1 -1
MOV 2 1 JMP #1 -1 JMP #1 -1
ADD A B
- (ajouter) - Ceci ajoute le contenu de l'emplacementA
mémoire à l'emplacement mémoireB
. Les deux premiers champs des deux sont ajoutés et les seconds champs sont ajoutés.ADD 2 1 MOV @4 #5 JMP #1 -1
ADD 2 1 MOV @5 #4 JMP #1 -1
SUB A B
- (soustraire) - Ceci soustrait le contenu de l'emplacement mémoireA
de (et stocke le résultat dans) l'emplacement mémoireB
.SUB 2 1 MOV @4 #5 JMP #1 -1
SUB 2 1 MOV @3 #6 JMP #1 -1
JMP A B
- (saut) - Aller à l'emplacementA
, qui sera exécuté au cycle suivant.B
doit être un nombre mais ne fait rien (vous pouvez cependant l'utiliser pour stocker des informations).JMP 2 1337 ADD 1 2 ADD 2 3
Le saut signifie que
ADD 2 3
sera exécuté le cycle suivant.JMZ A B
- (saut si zéro) - Si les deux champs de ligneB
sont à 0, alors le programme saute à l'emplacementA
.JMZ 2 1 SUB 0 @0 DAT 23 45
Comme les deux champs de l'instruction 1 sont 0, la commande DAT sera exécutée au tour suivant, entraînant une mort imminente.
CMP A B
- (comparer et ignorer s'ils ne sont pas égaux) - Si les champs des instructionsA
etB
ne sont pas égaux, ignorer l'instruction suivante.CMP #1 2 ADD 2 #3 SUB @2 3
Étant donné que les deux champs des instructions 1 et 2 ont une valeur égale, la commande ADD n'est pas ignorée et est exécutée au tour suivant.
Lorsque deux instructions sont ajoutées / soustraites, les deux champs (A et B) sont ajoutés / soustraits par paire. Le mode d'adressage et l'opcode ne sont pas modifiés.
Modes d'adressage
Il existe trois types de modes d'adressage. Chacun des deux champs d'une instruction possède l'un de ces trois modes d'adressage.
Immédiat
#X
-X
est la ligne à utiliser directement dans le calcul. Par exemple,#0
est la première ligne du programme. Les lignes négatives font référence aux lignes du noyau avant le début du programme.... //just a space-filler ... ADD #3 #4 DAT 0 1 DAT 2 4
Cela ajoutera la première des deux lignes DAT à la seconde, car celles-ci se trouvent respectivement sur les lignes 3 et 4. Cependant, vous ne voudriez pas utiliser ce code, car le DAT va tuer votre bot au cycle suivant.
Relative
X
- Le nombreX
représente l'emplacement d'une adresse de mémoire cible, par rapport à l'adresse actuelle. Le nombre à cet emplacement est utilisé dans le calcul. Si la ligne#35
est en cours d'exécution et contient-5
, alors la ligne#30
est utilisée.... //just a space-filler ... ADD 2 1 DAT 0 1 DAT 2 4
Cela ajoutera la deuxième ligne DAT à la première.
Indirect
@X
- Le nombreX
représente une adresse relative. Le contenu à cet emplacement est temporairement ajouté au numéro X pour former une nouvelle adresse relative, à partir de laquelle le numéro est récupéré. Si la ligne#35
est en cours d'exécution et que son deuxième champ l'est@4
et que le deuxième champ de la ligne#39
contient le nombre-7
, alors la ligne#32
est utilisée.... //just a space-filler ... ADD @1 @1 DAT 0 1 DAT 2 4
Cela ajoutera le premier DAT au second, mais d'une manière plus compliquée. Le premier champ est @ 1, qui obtient les données de cette adresse relative, qui est le premier champ du premier DAT, un 0. Ceci est interprété comme une deuxième adresse relative de cet emplacement, donc 1 + 0 = 1 donne le total décalage par rapport à l'instruction d'origine. Pour le deuxième champ, @ 1 obtient la valeur de cette adresse relative (le 1 dans le deuxième champ du premier DAT) et l'ajoute à lui-même de la même manière. Le décalage total est alors 1 + 1 = 2. Ainsi, cette instruction est exécutée de manière similaire à
ADD 1 2
.
Chaque programme peut contenir jusqu'à 64 instructions.
Lorsqu'un tour commence, les deux programmes sont placés de manière aléatoire dans une banque de mémoire avec 8192 emplacements. Le pointeur d'instruction pour chaque programme commence au début du programme et est incrémenté après chaque cycle d'exécution. Le programme meurt une fois que son pointeur d'instruction a tenté d'exécuter une DAT
instruction.
Paramètres du noyau
La taille de base est 8192, avec un délai d'attente de 8192 * 8 = 65536 ticks. Le cœur est cyclique, donc l'écriture à l'adresse 8195 équivaut à l'écriture à l'adresse 3. Toutes les adresses inutilisées sont initialisées à DAT #0 #0
.
Chaque concurrent ne doit pas dépasser 64 lignes. Les entiers seront stockés sous forme d'entiers signés 32 bits.
Analyse
Afin de faciliter la programmation pour les concurrents, j'ajouterai une fonction d'étiquette de ligne à l'analyseur. Tous les mots qui apparaissent sur une ligne avant un opcode seront interprétés comme des étiquettes de ligne. Par exemple, tree mov 4 6
a l'étiquette de ligne tree
. Si, n'importe où dans le programme, un champ contient tree
#tree
ou @tree
, un nombre sera substitué. De plus, la capitalisation est ignorée.
Voici un exemple de substitution d'étiquettes de ligne:
labelA add labelB @labelC
labelB add #labelC labelC
labelC sub labelA @labelB
Ici, les étiquettes A, B et C sont sur les lignes 0, 1 et 2. Les instances de #label
seront remplacées par le numéro de ligne de l'étiquette. Les instances de label
ou @label
sont remplacées par l'emplacement relatif de l'étiquette. Les modes d'adressage sont conservés.
ADD 1 @2
ADD #2 1
SUB -2 @-1
Notation
Pour chaque paire de concurrents, chaque bataille possible est effectuée. Étant donné que l'issue d'une bataille dépend des décalages relatifs des deux programmes, chaque décalage possible (environ 8 000 d'entre eux) est essayé. De plus, chaque programme a la possibilité de se déplacer en premier dans chaque décalage. Le programme qui remporte la majorité de ces offsets est le vainqueur de la paire.
Pour chaque paire gagnée par un guerrier, il obtient 2 points. Pour chaque égalité, un guerrier reçoit 1 point.
Vous êtes autorisé à soumettre plus d'un guerrier. Les règles typiques pour les soumissions multiples s'appliquent, telles que pas de tag-teaming, pas de coopération, pas de création de roi, etc.
Le controlle
Le code du contrôleur, avec deux exemples de robots simples, se trouve ici . Étant donné que cette compétition (lorsqu'elle est exécutée à l'aide des paramètres officiels) est complètement déterministe, le classement que vous créez sera exactement le même que le classement officiel.
Exemple Bot
Voici un exemple de bot qui montre certaines fonctionnalités du langage.
main mov bomb #-1
add @main main
jmp #main 0
bomb dat 0 -1
Ce bot fonctionne en effaçant lentement toutes les autres mémoires du noyau en le remplaçant par une "bombe". Puisque la bombe est une DAT
instruction, tout programme qui atteint une bombe sera détruit.
Il y a deux étiquettes de ligne, "principale" et "bombe" qui remplacent les numéros. Après le prétraitement, le programme ressemble à ceci:
MOV 3 #-1
ADD @-1 -1
JMP #0 0
DAT 0 -1
La première ligne copie la bombe sur la ligne immédiatement au-dessus du programme. La ligne suivante ajoute la valeur de la bombe ( 0 -1
) à la commande de déplacement, et elle montre également une utilisation du @
mode d'adressage. Cet ajout fait que la commande de déplacement pointe vers une nouvelle cible. La commande suivante retourne inconditionnellement au début du programme.
Classement actuel
24 - Turbo
22 - DwarvenEngineer
20 - HanShotFirst
18 - Dwarf
14 - ScanBomber
10 - Paranoid
10 - FirstTimer
10 - Janitor
10 - Evolved
6 - EasterBunny
6 - CopyPasta
4 - Imp
2 - Slug
Résultats par paire:
Dwarf > Imp
CopyPasta > Imp
Evolved > Imp
FirstTimer > Imp
Imp > Janitor
Imp > ScanBomber
Slug > Imp
DwarvenEngineer > Imp
HanShotFirst > Imp
Turbo > Imp
EasterBunny > Imp
Paranoid > Imp
Dwarf > CopyPasta
Dwarf > Evolved
Dwarf > FirstTimer
Dwarf > Janitor
Dwarf > ScanBomber
Dwarf > Slug
DwarvenEngineer > Dwarf
HanShotFirst > Dwarf
Turbo > Dwarf
Dwarf > EasterBunny
Dwarf > Paranoid
Evolved > CopyPasta
FirstTimer > CopyPasta
Janitor > CopyPasta
ScanBomber > CopyPasta
CopyPasta > Slug
DwarvenEngineer > CopyPasta
HanShotFirst > CopyPasta
Turbo > CopyPasta
CopyPasta > EasterBunny
Paranoid > CopyPasta
Evolved > FirstTimer
Evolved > Janitor
ScanBomber > Evolved
Evolved > Slug
DwarvenEngineer > Evolved
HanShotFirst > Evolved
Turbo > Evolved
EasterBunny > Evolved
Paranoid > Evolved
Janitor > FirstTimer
ScanBomber > FirstTimer
FirstTimer > Slug
DwarvenEngineer > FirstTimer
HanShotFirst > FirstTimer
Turbo > FirstTimer
FirstTimer > EasterBunny
FirstTimer > Paranoid
ScanBomber > Janitor
Janitor > Slug
DwarvenEngineer > Janitor
HanShotFirst > Janitor
Turbo > Janitor
Janitor > EasterBunny
Janitor > Paranoid
ScanBomber > Slug
DwarvenEngineer > ScanBomber
HanShotFirst > ScanBomber
Turbo > ScanBomber
ScanBomber > EasterBunny
ScanBomber > Paranoid
DwarvenEngineer > Slug
HanShotFirst > Slug
Turbo > Slug
EasterBunny > Slug
Paranoid > Slug
DwarvenEngineer > HanShotFirst
Turbo > DwarvenEngineer
DwarvenEngineer > EasterBunny
DwarvenEngineer > Paranoid
Turbo > HanShotFirst
HanShotFirst > EasterBunny
HanShotFirst > Paranoid
Turbo > EasterBunny
Turbo > Paranoid
Paranoid > EasterBunny
La dernière mise à jour (nouvelles versions de Turbo et Paranoid) a pris environ 5 minutes pour fonctionner sur un ancien ordinateur portable. Je tiens à remercier Ilmari Karonen pour ses améliorations au contrôleur . Si vous avez une copie locale du contrôleur, vous devez mettre à jour vos fichiers.
la source
Réponses:
Ingénieur nain
Un nain nouveau et amélioré. Victoires contre tout le reste soumis jusqu'à présent. La fantaisie taille de pas optimisée corestep optimisée est probablement exagérée ici.
Les fonctionnalités notables incluent la boucle de bombardement rapide qui lance deux bombes en quatre cycles, pour une vitesse de bombardement moyenne de 0,5 c dans l'ancien jargon de Core War, et l'utilisation de
JMZ
pour détecter lorsque le bombardement est terminé et qu'il est temps de passer au plan B ( ici, un lutin).Je jouais à Core War dans les années 90 (certains d'entre vous ont peut-être vu guide de j'ai écrit en 1997), donc j'ai pensé qu'il serait intéressant de voir quelles anciennes stratégies du monde RedCode '88 / '94 pourraient être utile dans cette variante.
Mes premières réflexions ont été:
Il n'y a pas
SPL
, donc pas de réplicateurs (et pas d'anneaux / spirales d'imp). Cela devrait renforcer les bombardiers. (Aussi, toutes ces stratégies de bombardement sophistiquées conçues pour faire face aux réplicateurs et aux spirales de lutin? Totalement inutiles et inutiles ici. Il suffit de bombarder avec n'importe quelDAT
art.)Là encore, la
CMP
numérisation est toujours potentiellement plus rapide que le bombardement, donc un scanner rapide pourrait avoir une chance.L'absence d'entrées / descentes rend les effacements de cœur très lents. En fait, un noyau clair dans cette variante est à peu près juste un bombardier avec une taille de pas (sous-optimale) de ± 1. Encore une fois, cela nuit également aux scanners; un scanner à un coup → stratégie de bombardier pourrait cependant fonctionner.
Les scanneurs rapides / bombardiers rapides (une stratégie de début de jeu utilisant une boucle de balayage / bombardement déroulée, pour ceux qui ne connaissent pas trop le jargon de Core War) sont toujours potentiellement utiles, mais uniquement contre les programmes longs (ce qu'ils sont eux-mêmes, donc il y a une sorte de rétroaction effet ici). Difficile de dire si cela en vaut vraiment la peine.
Le système de notation est intéressant. Les égalités marquent la moitié autant de points qu'une victoire (plutôt que 1/3, comme dans Core War traditionnel), ce qui les rend plus attrayantes. Là encore, le seul programme susceptible de marquer beaucoup de liens selon ces règles est un imp. (De plus, l'absence de dé / incréments rend les portes des lutins difficiles, donc même les simples lutins ont en fait une chance de marquer une égalité s'ils atteignent leur adversaire vivant.)
De plus, parce que le classement final ne dépend que des programmes que vous battez, et non de la fréquence à laquelle vous les battez, il a tendance à favoriser les entrées généralistes. Il est préférable de battre à peine tous vos adversaires, que de détruire totalement la moitié d'entre eux et de perdre à peine le reste.
Parce que le code est public, il est toujours possible de trouver un programme qui peut battre n'importe quelle soumission antérieure donnée - peut-être même plusieurs d'entre eux - peu importe leur qualité en général. De telles astuces (comme ajuster la taille de votre pas pour frapper votre adversaire juste avant de vous frapper) peuvent facilement sembler bon marché. Et, bien sûr, le joueur cible pourrait toujours simplement soumettre une nouvelle version avec différentes constantes.
Quoi qu'il en soit, le résultat de tout cela est que j'ai décidé d'essayer d'écrire soit un bombardier rapide soit un scanner très rapide, et peut être de coller un scanner rapide / bombardier dessus. Parmi ces options, un bombardier rapide semblait le plus simple et le plus susceptible de fonctionner.
À ce stade, j'ai passé beaucoup trop de temps à peaufiner et à optimiser le code de l'interpréteur de PhiNotPi, parce que je pensais que je ferais probablement beaucoup d'essais de force brute pour optimiser les constantes. En l'occurrence, je n'ai jamais eu à le faire - le code ci-dessus est à peu près la première version qui a réellement fonctionné (après quelques tentatives infructueuses qui se sont suicidées à cause de bugs stupides).
L'astuce qui rend mon bombardier rapide est d'utiliser l'adressage indirect pour lancer deux bombes pour chacune
ADD
. Voici comment cela fonctionne:Au premier cycle, nous exécutons
MOV bomb @aim
. Cela copie l'bomb
instruction à l'endroit où se trouve dans le noyau le champ B desaim
points (initialement, exactement 6326 instructions avantaim
, ou 6328 instructions avantstep
; vous verrez pourquoi ces nombres importent plus tard).À l'étape suivante, nous exécutons l'
aim
instruction elle-même! Au premier passage, il ressemble à ceci:MOV bomb @-6326
. Ainsi, il copiebomb
à l'emplacement vers lequel pointe le champ B de l'instruction à 6326 lignes avant lui-même.Alors, qu'y a-t-il à 6326 lignes avant
aim
? Eh bien, c'est la copie debomb
nous venons de placer là un cycle plus tôt! Et nous nous sommes juste arrangés pour que le champ B debomb
ait une valeur non nulle, de sorte que la nouvelle bombe ne sera pas copiée sur l'ancienne, mais à une certaine distance (en fait, ici, la distance est 3164, qui est la moitié de notre taille de pas nominale 6328; mais d'autres décalages pourraient fonctionner, peut-être même mieux).Au cycle suivant, nous ajustons notre objectif avec
SUB step aim
, ce qui soustrait les valeurs de l'step
instruction (qui se trouve également être le saut que nous allons exécuter ensuite, bien que cela aurait pu être juste un simpleDAT
quelque part) deaim
.(Un détail à noter ici est que nous voulons en quelque sorte que la valeur A
step
soit nulle, de sorte que nous lancerons toujours les mêmes bombes à la prochaine itération. Cependant, cela n'est pas strictement nécessaire; seules les bombes lancées par la première instruction doit avoir leur champ B égal à 3164, le reste peut être n'importe quoi.)Ensuite, la
JMZ
vérification que l'instruction 6328 s'éloigne d'elle est toujours nulle, et si c'est le cas, revient en haut du code. Maintenant, 6328 est la taille de pas de notre bombardier, et est divisible par 8 (mais pas 16); ainsi, si nous continuions à lancer des bombes toutes les 6328 étapes, nous finirions par revenir à notre point de départ, après avoir bombardé chaque huitième instruction dans le noyau (et avec les bombes supplémentaires compensées par 3163 = 6328/2 ≡ 4 (mod 8) , nous aurions touché une instruction sur quatre ).Mais nous avons commencé notre bombardement à 6328 instructions avant le
JMZ
, et avons reculé de -6328 à chaque itération, nous allons donc bombarder l'emplacement 6328 pas après laJMZ
seule itération avant de toucher leJMZ
lui - même. Donc, lorsque leJMZ
détecte une bombe à 6328 instructions après cela, c'est un signe que nous avons couvert autant de noyau que possible sans nous toucher et que nous devrions passer à une stratégie de sauvegarde avant de nous tuer.Quant à la stratégie de sauvegarde, c'est juste un vieux
MOV 0 1
démon, car je ne pouvais pas penser à mieux pour l'instant. À mon avis, si nous avons bombardé chaque quatrième emplacement du noyau et que nous n'avons toujours pas gagné, nous combattons probablement quelque chose de très petit ou de très défensif, et nous pourrions aussi bien essayer de survivre et de nous contenter d'une égalité. Ce n'est pas grave, parce que de tels programmes petits ou défensifs ne sont généralement pas très bons pour tuer quoi que ce soit d'autre, et donc même si nous ne gagnons que quelques combats par hasard, nous devrons probablement continuer.Ps.
Au cas où quelqu'un d'autre le voudrait, voici ma fourchette légèrement améliorée du code de tournoi de PhiNotPi . Il est environ deux fois plus rapide, enregistre les anciens résultats de bataille afin que vous n'ayez pas besoin de les réexécuter et corrige ce que je pense être un bug mineur dans le calcul des résultats de bataille.Les modifications ont été fusionnées dans la version principale par PhiNotPi. Merci!la source
Vue graphique
Cela peut être utilisé comme un outil de débogage. Il affiche le noyau et indique l'emplacement du lecteur. Pour l'utiliser, vous devez l'appeler à partir du code. J'ai également fourni un modifed
Game.java
qui affiche automatiquement le GraphView.PhiNotPi et Ilmari Karonen ont récemment changé de contrôleur. Ilmari Karonen a eu la gentillesse de fournir une GameView mise à jour à cet endroit .
Game.java modifié:
la source
./Game.java:275: error: method toString in class Object cannot be applied to given types; System.out.println(Player.toString(line)); ^ required: no arguments found: int[]
printCore()
méthode.Turbo
Ma deuxième tentative CoreWar. Conçu pour battre Nain. Scanne par 3 pour les données, puis met une bombe tous les 2. Chaque étape se déroule en seulement 3 instructions, dans l'espoir que les bombes des nains le manquent.
NOUVEAU Turbo ++ : désormais amélioré. Il balaye en arrière jusqu'à ce qu'il trouve des données, puis s'y déplace, puis bombarde en arrière. L'espoir est que le mouvement soit tapote l'adversaire, soit soit vers un endroit déjà bombardé et donc sûr (ish).
... Et un montage pour le faire balayer plus clairsemement le fait battre tout le monde!
la source
Nain
Un programme commun et simple qui représente un nain jetant des pierres. Il place une
DAT
instruction toutes les quatre adresses.EDIT: corrige l'adressage. Apparemment, les modes d'adressage sont différents de la spécification à laquelle l'OP est lié.
la source
add 3 3
, mais cela doublerait chaque boucle au lieu de l'ajouter, et cela ne serait pas utile.#4
est un immédiat, il ajoute donc le nombre4
à la 2e valeur de l'adresse qui se trouve3
après l'adresse actuelle.#
mode d'adressage dans le défi. Comme indiqué dans la spécification, j'ai apporté une modification au#
mode d'adressage.Évolué
Honnêtement, je ne comprends pas comment cela fonctionne. Il semble construire son code source avant de faire quoi que ce soit. J'adorerais que quelqu'un me donne une explication de son fonctionnement.Après l'avoir étudié, j'ai découvert qu'il s'agissait simplement d'un nain modifié avec un garde-lutin. Au lieu de bombarder les ennemis avec des
DAT
instructions, il mélange le code des ennemis. Il bombarde également tous les deux registres au lieu de tous les quatre registres. Avec suffisamment de temps, il se détruirait sans aucun doute.la source
FirstTimer
Si cela fonctionne, il devrait essayer de prendre position au début du noyau et de créer une défense
la source
#0
fait référence au début de votre programme (c'est-à-dire le même que#main
), pas au début du noyau (qui n'est pas vraiment un concept significatif de toute façon - le noyau est circulaire, votre code ne peut pas dire où il commence ou se termine). Ce qui se passe, c'est que votre première instruction (main
) se remplace par leMOV #data #100
, après quoi votre code se transforme efficacement en un noyau avant clair de 0,25c (= une instruction par quatre cycles).#0
pour le début du core. Les 5 premières instructions sont alors totalement inutiles.CopyPasta
Jamais participé à un CoreWar, ce programme simple essaie juste de se copier-coller puis d'exécuter la copie. Il peut ne pas avoir le bon comportement, veuillez me dire si c'est le cas.
C'est trop pacifiste et ne peut pas gagner en fait.
la source
JMP loop 0
). Puis, quand il saute à l'endroit où le début de la copie devrait être, c'est juste de l'espace vide et il perd.Concierge
Il devrait vérifier si les adresses suivantes sont vides et sinon il les nettoie (donc, espérons-le, effacer le bot adverse).
Edit: Cette nouvelle version devrait être plus rapide (maintenant que j'ai bien compris la
JMZ
commande et la@
référence).la source
ADD 3 -2
, mais tu as raison qu'il devrait la changer, je pense.JMZ
et j'ai penséJMZ A B
vérifierA
et sauter àB
0 alors qu'apparemment c'est le contraire. Merci de l'avoir remarqué car je ne l'ai pas fait :)ScanBomber
Supprimer mes commentaires avant de compiler. Analyse pendant un certain temps, puis bombarde lorsqu'il trouve un programme. Mais il perdra probablement encore contre mon Nain.
la source
#
complètement différemment de la spécification (lire le lien auquel il a lié), je n'ai pas encore fixé ce programme pour cela.#
avant chaque référencezero
? Ouais, je pense que je dois ...Han Shot First (v2)
J'ai pensé que la compétition pourrait utiliser un peu plus de diversité, alors voici ma deuxième entrée: un
CMP
scanner à un coup .Il s'agit de la version 2 , avec des défenses anti-Imp améliorées - elle peut désormais battre Imp, ne serait-ce que par un seul point. Il perd toujours contre Dwarven Engineer, mais bat tout le reste jusqu'à présent, le plaçant actuellement en première place à égalité.
Il fonctionne en comparant les emplacements de noyau adjacents à 5 étapes d'intervalle, à des intervalles de 10 étapes, jusqu'à ce qu'il trouve une différence. Quand il le fait, il commence à lancer des bombes à des intervalles de 2 étapes jusqu'à ce qu'il tue son adversaire ou fasse une boucle tout autour du noyau pour se rejoindre.
Si l'analyse ne pas trouver quoi que ce soit d' autre, ce sera autour de la boucle et finira par trouver son propre code et l' attaquer. Ce serait suicidaire, mais pour la coïncidence heureuse que la première bombe atterrit carrément sur la
aim
ligne, provoquant le lancement de la prochaine bombe 12 positions (plutôt que les 2 habituelles) dans le noyau, sautant commodément le code. (Cela se produit également avec une probabilité de 50% si le scan trouve quelque chose, mais ne parvient pas à tuer l'adversaire.) Étant donné que la taille du noyau est un multiple de deux, cela se produira également si le bombardement tourne en boucle, éliminant le besoin d'un stratégie de sauvegarde supplémentaire.(Cette astuce d'auto-bombardement était à l'origine une pure coïncidence - j'avais prévu une façon complètement différente de passer du mode de numérisation au mode de bombardement si rien n'était trouvé, mais lorsque j'ai testé le code pour la première fois, les constantes avaient juste raison de le faire travailler de cette façon, et j'ai décidé de m'en tenir à cela.)
la source
Lutin
Parcourez simplement le programme.
la source
Limace
Parcourt l'espace mémoire vers l'arrière. Jette parfois une bombe loin.
la source
lapin de Pâques
Il aime sauter en arrière :)
la source
Paranoïaque
Une sorte de copie de pâtes mais il vérifiera si le code a été modifié par bombardement. Si c'est le cas, copiez devant un nain et exécutez-le. Si je parviens à refaire la GameView, j'essaierai de changer certaines des constantes.
la source