# NN controlled Monsters # Monster.tz (c) 2010 Jacob Schrum. # See Simulation.tz for more copyright information @include "Agent.tz". @include "Sensor.tz". @include "Math3D.tz". @include "ModeArbitrator.tz". @define MONSTERS_INTERACT 0. Agent : FreeNetAgent { + variables: last-mode (int). scale-inputs (int). close-teammates (list). very-close-teammates (list). id (int). index (int). brain (object). inputs (list). display-inputs (string). close-monster-impulse (double). very-close-monster-impulse (double). close-player-impulse (double). very-close-player-impulse (double). close-powerup-impulse (double). close-sword-impulse (double). very-close-sword-impulse (double). right-side-monster-impulse (double). left-side-monster-impulse (double). output (list). sensors (list). selected (int). absence-negative (int). discrete-movement (int). discrete-turns (int). #net-modes (int). action-selector (int). mode-usage (hash). mode-counts (list). mode-arbitrator (object). #loner-death-distance (int). number-net-modes (int). + to simplify-inputs given xs (list): out (string). i (int). comma (string). attach (string). comma = ",". out = "{". for i = 0, i < |xs|, i++ : { if xs{i} == 0 : { attach = "0". } else if xs{i} == 1 : { attach = "1". } else if xs{i} == -1 : { attach = "-1". } else { attach = xs{i}. } out = "$out$attach". if (i+1) < |xs| : { out = "$out, ". } else { out = "$out}". } } + to setup-sensor-array number n (int): i (int). radians (double). radians = 0. sensors = {}. for i = 0, i < n, i++ : { if ((controller get-commandline) bit-param named "inverse-distance-sensors") : push (new DistanceSensor) onto sensors. else push (new BinarySensor) onto sensors. sensors{i} attach to self at radians. radians += (2.0 * PI) / n. } + to front-load-sensor-array number n (int): i (int). radians (double). rad-sequence (list). sensors = {}. # TODO: This list should be a commandline parameter rad-sequence = {0, PI/8.0, (15*PI)/8.0, PI/4.0, (7*PI)/4.0, PI/2.0, (3*PI)/2.0, (3*PI)/4.0, (5*PI)/4.0, PI}. for i = 0, i < n, i++ : { radians = rad-sequence{i}. if ((controller get-commandline) bit-param named "inverse-distance-sensors") : push (new DistanceSensor) onto sensors. else push (new BinarySensor) onto sensors. sensors{i} attach to self at radians. } + to mode-is mode m (int): return (controller mode-is mode m). + to get-player-sensor cell i (int): return (sensors{i} access-memory cell SENSOR_PLAYER). + to get-monster-sensor cell i (int): return (sensors{i} access-memory cell SENSOR_MONSTER). + to get-sword-sensor cell i (int): return (sensors{i} access-memory cell SENSOR_SWORD). + to get-wall-sensor cell i (int): return (sensors{i} access-memory cell SENSOR_WALL). + to get-bullet-sensor cell i (int): return (sensors{i} access-memory cell SENSOR_BULLET). + to click: monsters (list). i (int). monsters = (controller get-monsters). for i = 0, i < |monsters|, i++ : { monsters{ i } unselect. } controller draw-net net (self extract-genome). selected = 1. + to unselect: selected = 0. + to init: commandline (object). commandline = (controller get-commandline). scale-inputs = (commandline bit-param named "scale-inputs"). absence-negative = (commandline bit-param named "absence-negative"). discrete-movement = (commandline bit-param named "discrete-movement"). discrete-turns = (commandline bit-param named "discrete-turns"). #net-modes = (commandline num-param named "num-network-modes"). action-selector = (commandline bit-param named "action-selector-net"). #loner-death-distance = (commandline num-param named "loner-death-distance"). selected = 0. last-mode = -1. self set-neighborhood-size to (max((commandline num-param named "very-close-monster"), max((commandline num-param named "very-close-player"), max((commandline num-param named "very-close-sword"), max((commandline num-param named "very-close-powerup"), (commandline num-param named "very-close-wall")))))). if (commandline bit-param named "draw-lines") : self show-neighbor-lines. if (commandline bit-param named "front-load-sensors") : { self front-load-sensor-array number (commandline num-param named "sensor-array-size"). } else { self setup-sensor-array number (commandline num-param named "sensor-array-size"). } # Gather inputs for neural network brain and process them + to iterate: i (int). neighbors (list). item (object). additional-inputs (list). action-tuple (vector). commandline (object). best-mode (int). mode-outputs (list). tempList (list). if !(self is-locked) : { commandline = (controller get-commandline). self wipe-inputs. for i = 0, i < (controller get-team-size), i++ : { close-teammates{i} = (- absence-negative). very-close-teammates{i} = (- absence-negative). } close-monster-impulse = (- absence-negative). close-player-impulse = (- absence-negative). close-powerup-impulse = (- absence-negative). close-sword-impulse = (- absence-negative). very-close-monster-impulse = (- absence-negative). very-close-player-impulse = (- absence-negative). very-close-sword-impulse = (- absence-negative). right-side-monster-impulse = (- absence-negative). left-side-monster-impulse = (- absence-negative). # SMEG: This could probably all be removed. Neighbor calculation might be costly. neighbors = (self get-neighbors). foreach item in neighbors: { if (item is a "Monster"): { if (item get-distance from self) < (commandline num-param named "very-close-monster") : { close-monster-impulse = 1. close-teammates{ (item get-index) } = 1. if (item get-distance from self) < ((commandline num-param named "very-close-monster") / 2) : { very-close-monster-impulse = 1. very-close-teammates{ (item get-index) } = 1. } if (self has-on-right-side this-object item) : right-side-monster-impulse = 1. else left-side-monster-impulse = 1. } } else if (item is a "Player"): { if (item get-distance from self) < (commandline num-param named "very-close-player") : { close-player-impulse = 1. if (item get-distance from self) < ((commandline num-param named "very-close-player") / 2) : { very-close-player-impulse = 1. } } } else if (item is a "Sword"): { if (item get-distance from self) < (commandline num-param named "very-close-sword") : { close-sword-impulse = 1. if (item get-distance from self) < ((commandline num-param named "very-close-sword") / 2) : { very-close-sword-impulse = 1. } } } else if (item is a "PowerUp"): { if (item get-distance from self) < (commandline num-param named "very-close-powerup") : { close-powerup-impulse = 1. } } } # Additional Info additional-inputs = (controller get-additional-input-info). for i = 0, i < |additional-inputs|, i++ : { if ( additional-inputs{i}{INPUT_SLOT_USE} ) : { inputs{i} = (self call-method named (additional-inputs{i}{INPUT_SLOT_METHOD}) with-arguments (additional-inputs{i}{INPUT_SLOT_ARGS})). } else { inputs{i} = 0. } if (scale-inputs && (|additional-inputs{i}{INPUT_SLOT_RANGE}| == 1)) : { inputs{i} = ((self get-math) sigmoid-scale of (inputs{i}) border (additional-inputs{i}{INPUT_SLOT_RANGE}{0})). } } #print "$index: $inputs". self process these inputs. #controller pause. if (brain is a "MultiNetwork") : { best-mode = (controller get-current-game-mode-counter). mode-outputs = output. } else { mode-outputs = (mode-arbitrator net-outputs-of outputs output num-modes number-net-modes). best-mode = mode-outputs{ARBITRATE_MODE}. mode-outputs = mode-outputs{ARBITRATE_OUTPUT}. } if selected : { display-inputs = self simplify-inputs given inputs. controller set-display-text number 3 to "Inputs: $display-inputs" at-x -.95 at-y .75. controller set-display-text number 6 to "Outputs: $output ($best-mode) $mode-outputs" at-x -.95 at-y .70. } # Indicate that a given mode was used by the monster mode-usage{best-mode} = 1. mode-counts{best-mode} = (mode-counts{best-mode} + 1). #self set-label to "$best-mode". #self set-label to "$iterate-count". #self set-label to (self get-location). #tempList = keys(mode-usage). #self set-label to "$mode-counts | $tempList". if ( ((controller get-commandline) bit-param named "mode-coloration") && (last-mode != best-mode) ) : { self set-color to ((controller get-graphics) map-mode-to-color mode best-mode). } last-mode = best-mode. if (action-selector) : { action-tuple = (self get-action-selector-decision out mode-outputs). } else { action-tuple = (self get-analog-decision out mode-outputs). } if ((controller get-current-game-mode) == MODE_PREY) : { action-tuple::y = action-tuple::y * ((controller get-commandline) num-param named "prey-speed-ratio"). } self set-turn-angle to (action-tuple::x). self set-forward-coeff to (action-tuple::y). } super iterate. + to get-analog-decision out mode-outputs (list): new-forward-coeff (double). new-turn-angle (double). delta-forward-coeff (double). delta-turn-angle (double). delta-forward-coeff = mode-outputs{0}. delta-turn-angle = mode-outputs{1}. if discrete-movement : { if |delta-forward-coeff| < EPSILON_BUBBLE : new-forward-coeff = 0. else if delta-forward-coeff > 0 : new-forward-coeff = MONSTER_WALK_SPEED. else if delta-forward-coeff < 0 : new-forward-coeff = -MONSTER_WALK_SPEED. } else { delta-forward-coeff = delta-forward-coeff * MONSTER_WALK_SPEED_DELTA. new-forward-coeff = (self get-forward-coeff) + delta-forward-coeff. new-forward-coeff = min(new-forward-coeff, MONSTER_WALK_SPEED). new-forward-coeff = max(new-forward-coeff, -MONSTER_WALK_SPEED). } if discrete-turns : { if |delta-turn-angle| < EPSILON_BUBBLE : new-turn-angle = 0. else if delta-turn-angle > 0 : new-turn-angle = MONSTER_TURN_SPEED. else if delta-turn-angle < 0 : new-turn-angle = -MONSTER_TURN_SPEED. } else { delta-turn-angle = delta-turn-angle * MONSTER_TURN_SPEED_DELTA. new-turn-angle = (self get-turn-angle) + delta-turn-angle. new-turn-angle = min(new-turn-angle, MONSTER_TURN_SPEED). new-turn-angle = max(new-turn-angle, -MONSTER_TURN_SPEED). } return (new-turn-angle, new-forward-coeff, 0). + to get-action-selector-decision out mode-outputs (list): max-turn-output (double). max-move-output (double). max-turn-options (list). max-move-options (list). turn-choice (int). move-choice (int). new-forward-coeff (double). new-turn-angle (double). i (int). max-turn-output = max(mode-outputs{0}, max(mode-outputs{1}, mode-outputs{2})). max-move-output = max(mode-outputs{3}, max(mode-outputs{4}, mode-outputs{5})). # Turning max-turn-options = {}. for i = 0, i < 3, i++ : { if (mode-outputs{i} == max-turn-output) : push i onto max-turn-options. } turn-choice = random[ (|max-turn-options| - 1) ]. if max-turn-options{turn-choice} == 0 : new-turn-angle = -MONSTER_TURN_SPEED. # Turn left else if max-turn-options{turn-choice} == 2 : new-turn-angle = MONSTER_TURN_SPEED. # Turn right else new-turn-angle = 0. # No turn # Forward/backward movement max-move-options = {}. for i = 3, i < 6, i++ : { if (mode-outputs{i} == max-move-output) : push i onto max-move-options. } move-choice = random[ (|max-move-options| - 1) ]. if max-move-options{move-choice} == 3 : new-forward-coeff = -MONSTER_WALK_SPEED. # Move backwards else if max-move-options{move-choice} == 4 : new-forward-coeff = MONSTER_WALK_SPEED. # Move forwards else new-forward-coeff = 0. # No move return (new-turn-angle, new-forward-coeff, 0). # ID # i: index of subpopulation + to assign-subpop-index of i (int): id = i. + to get-subpop-index: return id. + to remember-index of tempInt (int): index = tempInt. + to get-index: return index. # Close senses + to get-close-monster-impulse: return close-monster-impulse. + to get-close-player-impulse: return close-player-impulse. + to get-very-close-player-impulse: return very-close-player-impulse. + to get-very-close-monster-impulse: return very-close-monster-impulse. + to get-close-powerup-impulse: return close-powerup-impulse. + to get-close-sword-impulse: return close-sword-impulse. + to get-very-close-sword-impulse: return very-close-sword-impulse. # Role-based monster senses # monsterPos: index of monster in list monsters + to get-heading-diff-to-teammate to monsterPos (int): return (controller get-signed-neg-difference-in-heading-from-heading-rear of id to (monsterPos % (controller get-team-size))). # Player proximity # i : index in list monsters + to get-close-player-impulse-of-teammate with-index i (int): return (controller get-close-player-impulse for-index i). # i : index in list monsters + to get-very-close-player-impulse-of-teammate with-index i (int): return (controller get-very-close-player-impulse for-index i). # Teammate proximity # monsterPos: index of monster in list monsters + to get-relative-angle-to-teammate to monsterPos (int): return (controller get-signed-neg-angle-from-rear of id to (monsterPos % (controller get-team-size))). + to get-close-to-monster with-index i (int): return close-teammates{ (i % (controller get-team-size)) }. + to get-very-close-to-monster with-index i (int): return very-close-teammates{ (i % (controller get-team-size)) }. + to get-relative-angle-to-closest-monster: return (controller get-angle-to-monster-nearest to self). # Locational senses + to flanking-player: angle-between (double). angle-between = angle((self get-vector-from-player), ((controller get-player) get-facing)). if (angle-between > (PI * 0.25)) && (angle-between < (PI * 0.75)) : { return 1. } else return 0. + to in-front-of-player: angle-between (double). mode (int). mode = (controller get-current-game-mode). # There is no front when the player is a ball if (mode == MODE_BALL) : return 0. if ((self get-deaths) > 0) : return 0. angle-between = | (angle((self get-vector-from-player), ((controller get-player) get-facing))) |. if angle-between < (PI/2) : { return 1. } else return 0. + to has-on-right-side this-object o (object): angle-diff (double). angle-diff = ((self get-math) signed-angle-difference between facing and ((o get-location) - (self get-location))). if (angle-diff < 0) : return 1. else return 0. + to get-right-side-monster-impulse: return right-side-monster-impulse. + to get-left-side-monster-impulse: return left-side-monster-impulse. # Player Relative Data + to get-vector-from-player: return ((self get-location) - (controller get-player-location)). + to player-relative-x: return (self get-vector-from-player)::x. + to player-relative-z: return (self get-vector-from-player)::z. + to get-vector-to-player: return ((controller get-player-location) - (self get-location)). + to get-vector-to-goal: goal (object). goal = (controller get-goal). if goal : return ((goal get-location) - (self get-location)). else return (0,0,0). + to get-distance-from-player: return |(self get-vector-to-player)|. + to get-comparative-goal-player-distance: goal (object). player (object). goal = (controller get-goal). if ( goal && !(goal goal-sunk) ) : { player = (controller get-player). return (( |( (goal get-location) - (player get-location) )| ) - ( |( (goal get-location) - (self get-location) )| )). } else { return 0. } + to get-angle-from-player: return angle(facing, (self get-vector-to-player)). + to get-facing-player: if |(self get-signed-angle-from-player)| < SMALL_ANGLE_AHEAD : return 1. else return 0. + to get-angle-to-player: return (-1 * ((self get-math) signed-angle-difference between (- facing) and (self get-vector-to-player))). + to get-angle-difference-between-ball-and-goal: goal (object). player (object). ball-to-goal (vector). monster-to-ball (vector). goal = (controller get-goal). if ( goal && !(goal goal-sunk) ) : { player = (controller get-player). ball-to-goal = ((goal get-location) - (player get-location)). monster-to-ball = (self get-vector-to-player). return (-1 * ((self get-math) signed-angle-difference between (ball-to-goal) and (monster-to-ball))). } else { return 0. } + to get-angle-to-goal: return (-1 * ((self get-math) signed-angle-difference between (- facing) and (self get-vector-to-goal))). + to get-signed-angle-from-player: return ((self get-math) signed-angle-difference between facing and (self get-vector-to-player)). + to get-diff-from-player-heading: #print "get-diff-from-player-heading:",(- facing),":",((controller get-player) get-facing). return (-1 * ((self get-math) signed-angle-difference between (- facing) and ((controller get-player) get-facing))). + to get-signed-difference-in-heading-from-player-heading: return ((self get-math) signed-angle-difference between facing and ((controller get-player) get-facing)). + to get-player-facing-me: if (self get-signed-difference-in-heading-from-player-heading) > (PI - SMALL_ANGLE_AHEAD) : return 1. else return 0. # Brain + to extract-genome: return brain. # input-vector: list of inputs to neural network + to process these input-vector (list): brain-pool (object). brain-pool = (controller get-brain-pool). if brain-pool : # Ensemble case { brain-pool activate-brain-pool with input-vector. free input-vector. input-vector = (brain-pool get-all-brain-pool-outputs). } if (brain is a "MultiNetwork") : { brain set-mode to (controller get-current-game-mode-counter). } #print "Num In:",(brain get-number-inputs). #print "Num Out:",(brain get-number-outputs). #brain print-network. brain run-with inputs input-vector. free output. output = (brain get-all-outputs). # The outputs are the rankings of the different members. # The outputs of one representative are chosen. if brain-pool && (brain-pool chooses-one-representative) : { output = (brain-pool get-outputs-of-member at (brain-pool get-representative outputs output)). } + to flush: #print "FLUSH". brain flush. # Powerup Senses + to get-nearest-powerup-distance: return (controller get-distance-to-nearest-powerup from (self get-location)). + to get-nearest-powerup-angle: return (controller get-angle-to-nearest-powerup from (self get-location) facing (self get-facing)). + to get-nearest-powerup-neg-angle-rear: return (-1 * (controller get-angle-to-nearest-powerup from (self get-location) facing (- (self get-facing)))). # Other senses + to get-bias: return BIAS. + to is-player-armed: return ((controller get-player) is-armed). + to is-player-locked: return ((controller get-player) is-locked). # NN Inputs + to wipe-inputs: i (int). for i=0, i<|inputs|, i++ : inputs{i} = 0. + to get-inputs: return inputs. } FreeNetAgent : Monster { + variables: ram (object). population-slot (int). yelp-of-pain (double). shout-of-encouragement (double). internal-group-score (double). damage-inflicted-to-player (double). damage-inflicted-this-round (double). damage-received-from-monsters (double). damage-received-from-player (double). damage-assist (double). damage-restored (double). deaths (int). kills (int). bumps (int). just-bumped (int). just-hit (int). just-ate (int). teammate-just-ate (list). powerups (int). birth-time (double). iterations (int). last-player-distance (double). distance-delta (double). disk (object). iterate-count (int). + to get-ram: return ram. + to get-population-slot: return population-slot. + to set-population-slot to slot (int): population-slot = slot. + to init: self reset. if ((controller get-commandline) bit-param named "use-disks") : { disk = new Mobile. disk set-shape to ((controller get-graphics) get-disk). disk set-transparency to 0.5. } if MONSTERS_INTERACT == 1 : self handle-collisions with-type "Monster" with-method "repell". self handle-collisions with-type "Player" with-method "eat". self handle-collisions with-type "Bullet" with-method "repell". self set-shape to ((controller get-graphics) get-monster-shape). self set-color to ((controller get-graphics) get-monster-color). + to group-damage-inflicted amount damage (double): if deaths == 0 : internal-group-score += damage. + to iterate: distance (double). loc (vector). mode (int). mode = (controller get-current-game-mode). if (mode == MODE_RAM || mode == MODE_BACKRAM) : { if !ram : { ram = new Ram. ram set-owner to self position mode. } } else if ram : { free ram. } if (iterate-count == 0) : { self clear-sensors. } # Tracks the number of iterations experienced, regardless of death. # Should always equal the total iterations in the trial so far. iterate-count++. if disk : { loc = (self get-location). disk move to (loc::x, (loc::y - 0.9), loc::z). } if deaths == 0 : { #self set-label to "($id,$population-slot)". self set-label to "$index". distance = (self get-distance-from-player). distance-delta = last-player-distance - distance. last-player-distance = distance. # If a fighter or predator gets too far from the player, just kill it already #if ((controller get-current-game-mode) != MODE_PREY) && # (distance > loner-death-distance) : #{ # self death. #} if armed : self fire. iterations++. super iterate. } # Communicate proximity + to get-angle-nearest-bullet: return (controller get-angle-to-bullet-nearest to self). + to get-anyone-close-to-player: result (double). result = (- absence-negative). if (controller anyone-close-to-player) : result = 1. return result. + to get-anyone-very-close-to-player: result (double). result = (- absence-negative). if ((controller anyone-very-close-to-player) == 1) : result = 1. return result. # Yelp of Pain + to emmit-yelp-of-pain: i (int). monsters (list). monsters = (controller get-monsters). for i=0, i<|monsters|, i++ : { monsters{i} hear-yelp-of-pain. } + to hear-yelp-of-pain: yelp-of-pain = 1. + to get-yelp-of-pain: if yelp-of-pain : { yelp-of-pain = 0. return 1. } else return 0. # Shout of Encouragement + to emmit-shout-of-encouragement: i (int). monsters (list). monsters = (controller get-monsters). for i=0, i<|monsters|, i++ : { monsters{i} hear-shout-of-encouragement. monsters{i} update-teammate-just-ate teammate (self get-index). } + to update-teammate-just-ate teammate i (int): teammate-just-ate{i} = 1. + to hear-shout-of-encouragement: shout-of-encouragement = 1. + to get-shout-of-encouragement: if shout-of-encouragement : { shout-of-encouragement = 0. return 1. } else return 0. # Acessors + to get-delta-player-distance: return distance-delta. + to get-damage-inflicted-this-round: return damage-inflicted-this-round. + to get-deaths: return deaths. + to player-is-swinging: return (controller player-is-swinging). + to get-iterations-alive: max-possible (double). max-possible = ((controller get-commandline) num-param named "eval-iterations"). if deaths == 0 : return max-possible. else return min(iterations, max-possible). + to get-iterations-confined: return iterations. + to get-negative-iterations-alive: return -iterations. + to get-random-fitness: return (random[ 100 ]). + to get-iterate-count: return iterate-count. + to get-mode-usage: return mode-usage. + to get-mode-counts: return mode-counts. # Initialize + to reset: i (int). #print "MONSTER RESET". if ram : free ram. self set-energy to MONSTER_START_ENERGY. self new-placement. close-teammates = {}. very-close-teammates = {}. teammate-just-ate = {}. for i = 0, i < (controller get-team-size), i++ : { push 0 onto close-teammates. push 0 onto very-close-teammates. push 0 onto teammate-just-ate. } just-bumped = 0. last-player-distance = (self get-distance-from-player). distance-delta = 0. birth-time = (controller get-time). iterations = 1. yelp-of-pain = 0. shout-of-encouragement = 0. just-hit = 0. just-ate = 0. iterate-count = 0. self reset-scores. + to clear-sensors: i (int). for i = 0, i < |sensors|, i++ : { sensors{i} clear-memory. } + to reset-scores: internal-group-score = 0. damage-inflicted-to-player = 0. damage-inflicted-this-round = 0. damage-received-from-monsters = 0. damage-received-from-player = 0. damage-assist = 0. damage-restored = 0. deaths = 0. kills = 0. bumps = 0. powerups = 0. + to new-placement: #print "new placement". self unlock. damage-inflicted-this-round = 0. if ((controller get-commandline) bit-param named "start-surrounding-player") : self move-to-planned-location. else self move-to-random-spot-in-bin. self set-facing to (self get-vector-to-player). self set-facing to (facing / |facing|). self set-turn-angle to 0. self clear-sensors. # r: distance from (0,1,0) # t: 0 <= t <= 2*PI (in radians) + to move-to-polar radius r (double) theta t (double): x (double). z (double). if brain: self flush. x = r * cos(t). z = r * sin(t). self move to (x, 1, z). + to move-to-planned-location: t (double). r (double). r = 1.5 * STARTING_BUFFER. t = (controller next-theta-location). self move-to-polar radius r theta t. + to move-to-random-spot-in-bin: t (double). r (double). r = random[STARTING_BUFFER] + STARTING_BUFFER. t = random[(2 * PI)]. self move-to-polar radius r theta t. # Track internal state + to increment-kills: kills++. + to increase-damage-assist by val (double): damage-assist += val. + to restore damage amount (double): damage-restored += amount. + to give-powerup: powerups++. # Brain + to replace-brain with-genome net (object): i (int). new-hash (hash). free mode-usage. free mode-counts. # Freeing a hash table is not enough. It still retains keys. mode-usage = new-hash. # Handled by simulation # SMEG self reset. if (net is a "MultiNetwork") : { number-net-modes = (net num-networks). } else { if !mode-arbitrator : mode-arbitrator = (controller get-mode-arbitrator). number-net-modes = (mode-arbitrator get-num-output-modes-from-net network net). } mode-counts = {}. for i = 0, i < number-net-modes, i++ : { push 0 onto mode-counts. } if ((controller get-commandline) bit-param named "homogeneous") : { # old brain can be deleted because it was just a copy, # and must be deleted to prevent memory leaks. if brain : free brain. brain = (net copy). } else brain = net. self flush. inputs = {}. for i = 0, i < (net get-number-inputs), i++ : { push 0 onto inputs. } # Fitness Functions + to punish-unused-modes: key (int). num-used (int). num-used = 0. foreach key in keys( mode-usage ) : { num-used += mode-usage{key}. } return (- (number-net-modes - num-used)). + to get-output-mode-restricting-fitness: return (- number-net-modes). + to get-anti-bloat-fitness: return (- (brain get-number-of-nodes)). + to get-group-score-fitness: return internal-group-score. + to get-damage-assist-fitness: return damage-assist. + to get-damage-inflicted-fitness: return damage-inflicted-to-player. + to get-damage-received-fitness: return (-damage-received-from-player). + to get-powerup-fitness: return powerups. + to get-bumps-fitness: return (-bumps). + to get-goal-distance-fitness: goal (object). player (object). goal = (controller get-goal). if ( goal && !(goal goal-sunk) ) : { player = (controller get-player). return (- |( (goal get-location) - (player get-location) )|). } else { return 0. } # A hack to make behavioral diversity work. This is just a place holder. # The actual behavioral diversity is calculated just before selection occurs. + to dummy-fitness: return 0. + to get-fitnesses: i (int). fitnesses (list). fitnesses = {}. for i=0, i<|(controller get-fitness-info-list)|, i++ : { # Only pay attention to certain fitnesses in certain modes if ((controller get-current-game-mode) == (controller get-fitness-info-list){i}{SLOT_GAME_MODE} ) || (GAME_MODE_ALL == (controller get-fitness-info-list){i}{SLOT_GAME_MODE} ) : { push (self call-method named (controller get-fitness-info-list){i}{SLOT_FITNESS_METHOD_NAME}) onto fitnesses. } else push 0.0 onto fitnesses. # Zero should be ignored anyway } return fitnesses. # Brief sensations + to get-just-bumped: if just-bumped : { just-bumped = 0. return 1. } else return 0. + to get-just-hit: if just-hit : { just-hit = 0. return 1. } else return 0. + to get-teammate-just-ate teammate i (int): if teammate-just-ate{i} : { teammate-just-ate{i} = 0. return 1. } return 0. + to get-just-ate: if just-ate : { just-ate = 0. return 1. } else return 0. + to get-just-hit-wall: if (just-hit-wall == 1) : { just-hit-wall = 0. return 1. } else return 0. # Collision Handlers + to repell from collider (object): to-collider (vector). if !(self is-locked) : { if (((collider is a "Bullet") && (collider from-player)) || (collider is a "Sword") || (collider is a "Monster") || (collider is a "Player")): { self lock. to-collider = ((collider get-location) - (self get-location)). to-collider = to-collider / |to-collider|. self set-facing to to-collider. self set-forward-coeff to (-MONSTER_REPELL_SPEED). if (collider is a "Monster"): { energy -= MONSTER_BUMP_LOSS. damage-received-from-monsters += MONSTER_BUMP_LOSS. bumps += 1. just-bumped = 1. return 1. } } } # Called whenever colliding with a Player + to eat the player (object): to-me (vector). mode (int). mode = (controller get-current-game-mode). # Assures monsters get hit when they are prey self set-label to "". if (mode == MODE_PRED || mode == MODE_FIGHT) : { self damage enemy player. } else if (mode == MODE_BALL) : { player lock. player free-sword. to-me = (self get-location) - (player get-location). to-me = to-me / |to-me|. player set-facing to to-me. player set-forward-coeff to (-PLAYER_REPELL_SPEED). just-ate = 1. self emmit-shout-of-encouragement. } + to damage enemy player (object): to-me (vector). if !(player is-locked): { player lock. player free-sword. to-me = (self get-location) - (player get-location). to-me = to-me / |to-me|. player set-facing to to-me. player set-forward-coeff to (-PLAYER_REPELL_SPEED). player set-energy to ((player get-energy) - MONSTER_BITE_LOSS). damage-inflicted-to-player += MONSTER_BITE_LOSS. (controller assign-damage-assist of MONSTER_BITE_LOSS). (self increase-damage-assist by ASSIST_HIT_BONUS). damage-inflicted-this-round = damage-inflicted-to-player. controller adjust-group-score by MONSTER_BITE_LOSS. just-ate = 1. self emmit-shout-of-encouragement. } + to shoot the player (object) with bullet (object): to-bullet (vector). if !(player is-locked): { player lock. player free-sword. to-bullet = (bullet get-location) - (player get-location). to-bullet = to-bullet / |to-bullet|. player set-facing to to-bullet. player set-forward-coeff to (-PLAYER_REPELL_SPEED). player set-energy to ((player get-energy) - BULLET_LOSS). damage-inflicted-to-player += BULLET_LOSS. damage-inflicted-this-round = damage-inflicted-to-player. controller adjust-group-score by BULLET_LOSS. self emmit-shout-of-encouragement. } + to receive-damage-from-player of damage (double): if (energy > 0) : { damage-received-from-player += damage. energy -= damage. (controller increase-player-score by damage). (self emmit-yelp-of-pain). just-hit = 1. } # Death + to brain-death: if ((controller get-commandline) bit-param named "homogeneous") : { if brain : free brain. } + to death: deaths++. # Hide under plane self move to (0,-1000,0). self remove-label. super death. } Mobile : Ram { + variables: owner (object). front (int). + to init: self set-shape to (new Sphere init-with radius 1). self handle-collisions with-type "Player" with-method "damage". + to damage enemy player (object): if owner && !(owner is-locked) : owner damage enemy player. + to set-owner to mon (object) position p (int): owner = mon. if (p == MODE_RAM) : { front = 1. } else { front = -1. } + to iterate: if owner: self move to ((owner get-location) + (front * (owner get-facing) * 2)). }