So you want to see some crazy shit…?
This is a neuron-like corewars set of code I wrote back in 2006…
From the readme.txt:
This is a collection of "neuron-like" corewars code.
Whilst the signals being passed (at least up to v4) are basically pre-programmed actions,
one could alter this and instead use the neurons to process some input,
like a neural network.
Although there is no real advantage in corewars to do so.
Perhaps there is a better way to create "artificial intelligence" in corewars.
--
Another way, is using an "evolver" (see simple-evolver) where it takes code from
a random location and tries to store and execute it. If it fails, the code is discarded.
--
Another way, is the typical parasite method, which is by forking into random code. But
this can be easily defeated by the forkbomb.cw code.
--
The only other way i can think of is, some piece of code like this, with lots of jumps...
addr: data 0 # this gets randomised (within the boundaries of the code)
r: data 0 # just a var
line1: some instruction here, e.g. move 0, [r]
some instruction here to alter addr, e.g. add 1, addr
jump [addr]
line2: some instruction here
some instruction here to alter addr
jump [addr]
line3: some instruction here
...
...
...
and so on.
It then boils down to the "altering addr" method, which can be stored into a table or
based on "learning" or "statistics" -- thus improving its code over time, without
actually changing anything (except the order it's run).
E.g. you could use an sbox to hold all the addrs of code. Each "jump instruction"
jumps into a function which then permutates the sbox and returns a new addr accordingly.
The permutation function can then be optimised for a particular scenario.
This is similar to "neuron" with the signal handling/actions.
--
Here’s version 4 of the code:
# NB: This is complete and working, but there is a race condition with "sendsignal()"
# and "clone()" which can prevent signals being sent to newly moved neurons (moveneuron)
# because sendsignal() may be polling on the old location and doesn't know that it has moved.
#
# The only way to fix this is to implement a communications protocol similar to
# process_protect and process_module.
#
# But this code has already reached the limit of 200 instructions, so there is no way
# to fix this problem.
#
#
title "AAA - Neuron v4"
author "---------- DS -----------"
bootthreads: data 1 # initial case: minimum 1 more threads
# after "first neuron" and its clone...
# i.e. total = 3 threads
# self-signal to create initial neuron
boot: move 2, signalstatus
move 1, signal
add 256, signal
# move &bootstrap, jumpback
move &bootstrap2, jumpback
jump checksignal
#bootstrap: move 1, sendsignaldata # issue "create neuron" command to last neuron
# add 256, sendsignaldata
# move nextneuron, sendsignalneuron # &neuronmarker can be used instead of nextneuron
# move &bootstrap1, jumpback # in non-bootstrap "first neuron" type code.. i.e. with a poll loop
# jump sendsignal # otherwise, in bootstrap code, you need to checksignal()
# to get it to work.
# Since we have a cloned neuron already, due to this bootstrap,
# we just use it instead.
#bootstrap1: loop bootthreads, bootstrap
bootstrap2: move 4, sendsignaldata # issue new command action, for all neurons
add 256, sendsignaldata
add 512, sendsignaldata
move nextneuron, sendsignalneuron
move &bootstrap3, jumpback
jump sendsignal
bootstrap3: move &bootstrap5, jumpback
jump delay
bootstrap5: move 2, sendsignaldata # move neurons
add 256, sendsignaldata
add 512, sendsignaldata
move nextneuron, sendsignalneuron
move &bootstrap6, jumpback
jump sendsignal
bootstrap6: move &bootstrap2, jumpback
jump delay
delay: move 1000, i
delay2: loop i, delay2
jump [jumpback]
# ----------- begin neuron here --------------------------------------
# signals (sent as bit flags):
#
# (action signals) - you'd want one of these (you can combine these):
# 0 = do nothing.
# 1 = create more neurons
#
# (action signals with special conditions) - or these (don't combine these):
# 2 = move this neuron into a new cell
# since this moves the current neuron into a new place, you can't combine this.
# 4 = move 0, [random] (safe version, does not kill other neurons of same process)
# aborts on receiving another signal
# 8 = move 0, [random] (unsafe version)
# aborts on receiving another signal
# 32 = convert into an imp
# neuron transforms into an imp
# 64 = terminates
# neuron terminates
#
# (signal handling signals) - and you'd want one of these (at least one of these):
# 128 = signal prev neuron with this same signal
# 256 = signal next neuron with this same signal
# 512 = do action (even if you're not the last neuron to get this signal)
#
# NB: When you combine the flags, they will be handled in numerical order.
# Special conditions may prevent further flags from being "actioned".
# Also, signal propagation occurs FIRST before actions, so you cannot
# expect "newly created" neurons to receive a signal until the next signal is sent.
# (e.g. This is the only way to prevent signal 1 creating an infinite number of
# neurons. Similar problems occur with signal 2.)
# ------------- global variables: the values will not be copied on clone()->linkneuron() -----------------------------------
neuronmarker: data 1337
# --- public vars ---
signalstatus: data 0
signal: data 0
nextneuron: data 0
prevneuron: data 0
# --- private vars ---
jumpback: data 0 # jumpback address for various code
jumpbackclone: data 0 # jumpback address for clone code (only)
recvsignal: data 0 # received signal's value
sendsignaldata: data 0 # signal value to be sent
sendsignalneuron: data 0 # target address of neuron for sendsignal
s: data 0 # generic vars -- may be clobbered when entering a new function call.
r: data 0
i: data 0
# --- constants ---
sizeofvars: data 12 # size of all variables
entrypointoffset: data 15 # entry point offset from &neuronmarker
# ------------ main polling loop --------------------------------
# Clobbered: jumpback
main: jump main2
# data 0 # if your entrypointoffset is incorrect, it will terminate
# data 0 # as soon as it forks into the wrong offset.
# data 0 # (this is only useful for debugging)
# data 0 # but this exceeds the "max limit" of 200 instructions.
# data 0 # Uncomment as many as you want.
main2: move 0, signalstatus # clear signalstatus
poll: move &poll, jumpback
poll1: equal 2, signalstatus # poll signalstatus
jump checksignal
jump poll1
# ------------- Function: checksignal() ---------------------------------
# Clobbered but restored: jumpback
# Clobbered: signalstatus
checksignalret: data 0 # caller's return address
checksignal: move jumpback, checksignalret # save caller's return address
move signal, recvsignal # save it into recv signal, and reset signalstatus
checksignal0: equal 0, recvsignal # do nothing?
jump checksignalend
# similar to doaction()'s switch-case, but optimised for speed (not code size).
# i.e. does not do multiple evaluations but requires more opcodes for control.
checksignal128: move 128, i # check 'signal prev' flag
and recvsignal, i
equal 128, i
jump sendsignal128
jump checksignal256 # ->--+
# |
# |
sendsignal128: equal prevneuron, 0 # <= if we're the last neuron in this signal chain
jump checksignaldo # <= do the action.
move recvsignal, sendsignaldata # |
move prevneuron, sendsignalneuron # |
move &checksignal256, jumpback # ->--|--+
jump sendsignal # | |
# | |
# | |
checksignal256: move 256, i # <---+--+
and recvsignal, i
equal 256, i
jump sendsignal256
jump checksignal512 # ->--+
# |
sendsignal256: equal nextneuron, 0 # <= if we're the last neuron in this signal chain
jump checksignaldo # <= do the action.
move recvsignal, sendsignaldata # |
move nextneuron, sendsignalneuron # |
move &checksignal512, jumpback # ->--|--+
jump sendsignal # | |
# | |
# | |
checksignal512: move 512, i # <---+--+
and recvsignal, i
equal 512, i
jump checksignaldo # 512 -- do the action anyway.
jump checksignalend
checksignaldo: move &checksignalend2, jumpback
jump doaction # on return, doaction is expected to clear (or set) signalstatus
checksignalend: move 0, signalstatus # reset signalstatus -- we only passed a signal
checksignalend2: move checksignalret, jumpback # return to caller.
jump [jumpback]
# ----------- Function: doaction() --------------------
# Clobbered but restored: jumpback
# Clobbered: recvsignal, signalstatus (by action 4 and 8)
doactionret: data 0 # caller's return address
# think of the following code like a switch-case statement that operates on a bitflag
# it is optimised for code size, not speed. (it saves 1 or 2 jump instructions on each case in the switch-case)
# at the expense of re-evaluating the entire switch-case from the beginning.
doaction: move jumpback, doactionret
and 127, recvsignal # mask only the bits we want...
doactionstart: move &doactionstart, jumpback # set this as the jumpback value
# because "doaction" will change "recvsignal"
# by substracting from recvsignal the action being done.
# (this saves some code -- but you cannot do this for "signal handling actions"
equal 0, recvsignal # are we done yet?
jump doactiondone
move 1, i
and recvsignal, i
equal 1, i
jump doaction1
move 2, i
and recvsignal, i
equal 2, i
jump doaction2
move 4, i
and recvsignal, i
equal 4, i
jump doaction4
move 8, i
and recvsignal, i
equal 8, i
jump doaction8
move 32, i
and recvsignal, i
equal 32, i
jump doaction32
move 64, i
and recvsignal, i
equal 64, i
jump doaction64
data 0 # buggy code? undefined action signal
# -- NB these subroutines of doaction() will return to doaction()'s switch-case statement
# via "jump [jumpback]" and not "return to caller" since that only occurs once (see above).
# --- Action 1: Create more neurons
doaction1: add -1, recvsignal # substract from recvsignal, so this action isn't repeated again.
move &linkneurons, jumpbackclone # make clone() fork and link the neurons
jump clone # jumpback is already set by doaction()
# --- Action 2: Move neuron.
doaction2: add -2, recvsignal
move &moveneuron, jumpbackclone # no need to set jumpback
jump clone
# --- Action 4: move 0, [random] (safe version)
doaction4: move 0, signalstatus # reset signalstatus here.
doaction4p1: equal 2, signalstatus # check signalstatus -- if this changes, we stop action4
jump stopaction4
doaction4p2: info 2, r
own [r]
jump doaction4p2
move 0, [r]
jump doaction4p1
stopaction4: jump doactiondone2 # return, but don't reset signalstatus
# --- Action 8: move 0, [random] (unsafe, faster)
doaction8: move 0, signalstatus # reset signalstatus here.
doaction8p1: equal 2, signalstatus # check signalstatus -- if this changes, we stop action8
jump stopaction8
info 2, r
move 0, [r]
jump doaction8p1
stopaction8: jump doactiondone2 # return, but don't reset signalstatus
# --- Action 32: Convert into an imp
doaction32: move doaction32, imp # no need for jump [jumpback]
imp: data 0
# --- Action 64: Terminate neuron
doaction64: data 0 # no need for jump [jumpback]
# --- Done?
doactiondone: move 0, signalstatus # reset signalstatus.
doactiondone2: move doactionret, jumpback
jump [jumpback] # return to caller
# ----------- Function: sendsignal() -------------------------------------------
# Clobbered: None.
sendsignal: equal 1337, [sendsignalneuron] # check target is a valid neuron by testing beginmarker
jump sendsignal2
data 0 # buggy code? terminate
sendsignal2: move sendsignalneuron, r
add 1, r # set r to point to "signalstatus"
sendsignal3: equal 0, [r] # simplified version.
jump sendsignal4
jump sendsignal3
sendsignal4: move 1, [r] # lock signalstatus
move r, i
add 1, i # set i to point to "signal"
move sendsignaldata, [i] # send signal
move 2, [r] # update signalstatus to completed
sendsignalend: jump [jumpback] # return to caller.
# ----------- Function: clone() ------------------------------------------
# Clobbered: None. (Also see polymorphic functions.)
# NB: "jumpbackclone" is a polymorphic function descriptor (i.e. function pointer or subclass method)
# which changes the behaviour of the clone code
clone: info 2, r
own [r] # check if 'r' overwrites into another neuron.
jump clone
move &neuronmarker, s # grab length of neuron (i could hardcode this, but i dont want to)
neg s, i
add &endvar, i
add 1, i
move r, endvar # save 'r'
add i, r # check if 'r + len' overwrites into another neuron.
own [r]
jump clone
move endvar, r # restore 'r'
copy: movei s, r
loop i, copy
move 1337, [endvar] # set neuron marker
jump [jumpbackclone] # jump to the polymorphic function -- either moveneuron() or linkneurons()
# --- Polymorphic jumpbackclone function: linkneurons() ---
# Clobbered: nextneuron
linkneurons: equal 0, nextneuron
jump linkneurons1
data 0 # buggy code? terminate
linkneurons1: move endvar, r # zero the bss
add 1, r # (1st var location)
move sizeofvars, i # (number of vars)
zerobss: move 0, [r]
add 1, r
loop i, zerobss
move endvar, nextneuron # set our "nextneuron" to point to the clone
move endvar, r
add 4, r
move &neuronmarker, [r] # set "prevneuron" in the cloned neuron to us.
add entrypointoffset, endvar # readjust endvar to entry point of cloned neuron
fork [endvar] # fork
jump [jumpback] # return to caller
# --- Polymorphic jumpbackclone function: moveneuron() ---
moveneuron: move prevneuron, r
add 3, r
move endvar, [r] # set previous neuron's "next neuron" to new address
move nextneuron, r
add 4, r
move endvar, [r] # set next neuron's "prev neuron" to new address
add entrypointoffset, endvar # this is just a clone_move() operation, so re-adjust entrypoint
jump [endvar] # and only jump (don't fork)
# ------------------------------------------------------------------------------------
endvar: data 0 # end variable -- used to mark end of neuron -- only to be used by clone().
# data/code below is NOT used -- just to look nice in the gui -- only first neuron has this.
neuronendmarker: move &neuronendmarker, neuronendmarker1
neuronendmarker1: data 0
Leave a Reply