# divisionblocks.tz # Lee Spector, lspector@hampshire.edu # prepared for distribution June, 2007 # This file contains the code used to produce the data in: "Division Blocks and the Open-Ended # Evolution of Development, Form, and Behavior," by Lee Spector, Jon Klein, and Mark Feinstein, # to appear in the Proceedings of the 2007 Genetic and Evolutionary Computation Conference (GECCO-2007). # For newer (debugged/enhanced) versions of the divisionblocks code please contact Lee Spector # (lspector@hampshire.edu). Note that this file includes code for many features (e.g. "comets," # simulated "clouds," partitions, various energy costs, etc.) that are not described in the # GECCO-2007 paper or used in producing its results. # Note on early termination: This code specifies to terminate the simulation after 1000 steps of # reproductive competence. This was done as part of the data collection procedure for the GECCO-2007 # paper, but if you want to experiment then you'll probably want to let the simulation run longer. # Confusingly, the check for termination is performed in the "print-stats" method -- so that's where # to go to remove it. # Use of this code requires the "breve" simulation environment, available from: # http://www.spiderland.org/breve # ----------------------------------------------------------------------------------------------- # MISCELLANEOUS NOTES # - size-based splits, joint toward sun # - size-based breaks (small cumulative size of links) AND force-based breaks # - Ahesion control currently allows for force-based breaks but NOT attachment of unlinked # blocks. Consider adding adhesion-controlled attachment. # - size has double buffering - persistence and also grow # - Transport (joint and diffusion) is handled by a global randomized process to prevent # the order bias that would result (?) from the obvious implementation in joint/block # iterate or post-iterate methods. # - On TIME_SCALE: The default iteration-step is 0.05, meaning there are 20 iterations per # simulation second. TIME_SCALE = 1 would make 1 day per 2pi simulation seconds, or # about 1 day per 125.6 iterations. TIME_SCALE = 2 is about 1 day per 251.2 iterations, etc. # action matrices are laid out as follows (with e=effectors, h=hidden-nodes, s=sensors): # # e->e | h->e | ---- # -------------------------- # e->h | h->h | s->h # -------------------------- # ---- | ---- | ---- # # (blanked-out parts must be zero -- s->e and all *->s) @use Mobile. @use PhysicalControl. @use Link. @use Joint. @use Stationary. @use Vector. @use Matrix. @use File. @use Camera. @use Image. # POSSIBLY USEFUL CONSTANTS @define E 2.718281828459045. @define E_SQUARED 7.3890560989306495. @define ONE_OVER_E_SQUARED 0.1353352832366127. @define PI 3.141592653589793. # WORLD/SIMULATION PARAMETERS @define FLOOR_SIZE 400. # NOTE: sun exposure depends on this, must be recalibrated if this changes @define THROW_COMETS 0. # 0/1 for do/don't throw @define COMET_SIZE 10. @define RANGE_FOR_EX_NIHILO_GENERATION 400. #150.0. @define TIME_SCALE 3. # = about 377 iterations/day (incl night) @define DAYLIGHT (0.5, 0.7, 1.0). @define REPRODUCTIVE_COMPETENCE_THRESHOLD 250. @define MAX_BLOCKS 2000. @define MAX_BLOCKS_AFTER_REAP 1000. @define BLOCK_REAPER_TOURNAMENT_SIZE 10. # INITIALIZATION PARAMETERS @define INITIALIZATION_POPULATION_SIZE 50. #25. #100. #150. #75. #150. #250. # ACTION MATRIX PARAMETERS @define PERSISTENCE 0.75. #0.5. #0.9. #0.0. #0.75. # BLOCK PARAMETERS @define MINIMUM_SIZE 1.0. @define MAXIMUM_SIZE 9.0. @define SPLIT_SIZE 8.0. @define MAX_VELOCITY_FOR_SPLIT 5.0. @define BREAK_SIZE 0. # combined volume of joined links, break when lower than this (0=never for this reason) @define MAX_JOINT_FORCE 100000.0. @define MAX_GROWTH_RATE 1.01. @define MAX_SHRINK_RATE 0.99. @define SIZE_GOOD_ENOUGH_DELTA 0.75. @define MINIMUM_CORPSE_LIFETIME 10. @define MAXIMUM_CORPSE_LIFETIME 100. @define MAXIMUM_COPY_FIDELITY 50000. @define MINIMUM_COPY_FIDELITY 0. @define MINIMUM_MUTATION_LIMIT 0.1. @define MAXIMUM_MUTATION_LIMIT 1.0. @define MINIMUM_PULSERATE 0.0. @define MAXIMUM_PULSERATE 0.5. @define MAXIMUM_SIGMOID_COMPRESSION 100.0. @define MINIMUM_SIGMOID_COMPRESSION 0.1. @define NEIGHBORHOOD_RADIUS 20. @define ENFORCE_HIDDEN_NODE_ARCHITECTURE 0. # PHOTOSYNTHESIS PARAMETERS @define MAX_EXPOSURE 50.0. # higher values effectively make solar skin less efficient @define HEIGHT_EXPOSURE_SCALING_FACTOR 0.1. @define PHOTON_ENERGY 0.05. # amount of energy per full exposure per iteration # ENERGY DONATION PARAMETERS @define MINIMUM_DONATION_SIZE 0.001. @define MAXIMUM_DONATION_SIZE 0.1. @define JOINT_DONATION_ATTEMPTS_PER_JOINT 10. # GARBAGE PARAMETERS @define GARBAGE_ACCUMULATED_PER_UNIT_CUBE 0. @define GARBAGE_ACCUMULATED_PER_BLOCK 0.005. @define GARBAGE_METABOLISM_SCALING_FACTOR 15. # GARBAGE COLLECTION PARAMETERS @define MINIMUM_COLLECTION_SIZE 0.001. @define MAXIMUM_COLLECTION_SIZE 0.1. @define JOINT_COLLECTION_ATTEMPTS_PER_JOINT 10. # COSTS @define METABOLIC_COST_PER_UNIT_CUBE 0.000002. @define METABOLIC_COST_PER_BLOCK 0.0005. @define SPLIT_COST 0.0. @define JOINT_FORCE_COST_PER_ITERATION 0.00000000025. @define SIZE_CHANGE_COST_PER_ITERATION 0.0. @define COST_PER_COLLISION 0.005. # COST SCALING @define GLOBAL_RESOURCE_SURCHARGE_SCALING_FACTOR 0.0. @define MIMIMUM_BLOCKS_FOR_GLOBAL_RESOURCE_SURCHARGE 500. @define LOCAL_RESOURCE_SURCHARGE_SCALING_FACTOR 0.1. # BIRDS-EYE-CAM @define BIRDS_EYE_CAM_SIZE 200. # purely cosmetic @define MAX_ZOOM_DELTA 0.1. @define MAX_AIM_DELTA 0.1. @define SPIN 0.005. Controller DivisionBlocksController. PhysicalControl : DivisionBlocksController { + variables: # camera control autoCameraMode (int). autoCameraMenu (object). prevCameraAim (vector). prevCameraZoom (float). cameraHasBeenAimed (int). # state vector components sensors, effectors, hidden-nodes (list). numberOfEffectors, numberOfHiddenNodes, numberOfSensors, stateVectorLength (int). iteration (int). most-recent-ex-nihilo (int). number-of-splits (int). #terrain (object). seed (int). sun-position (vector). global-resource-surcharge (float). log-file (object). frozen (int). skin-image-hack (object). #this hackage is the only way I've been able to avoid flashes on splits... rework cloud-texture (object). relative-sun-height (float). # 1 at noon, -1 at midnight, just for logging birds-eye-cam (object). birds-eye-cam-image (object). comet-probability-denominator (int). peak-collisions-per-block-in-one-iteration (int). + to get-skin-image-hack: return skin-image-hack. + to set-skin-image-hack from-image i (object): x, y (int). for x=0,x<4,x++: { for y=0,y<4,y++: { skin-image-hack set-pixel to (i get-rgb-pixel at-x x at-y y) at-x x at-y y. } } + to reset-skin-image-hack: x, y (int). for x=0,x<4,x++: { for y=0,y<4,y++: { skin-image-hack set-pixel to (1, 1, 1) at-x x at-y y. } } + to set-relative-sun-height to h (float): relative-sun-height = h. + to get-frozen: return frozen. + to freeze: frozen = 1. + to unfreeze: frozen = 0. + to get-numberOfEffectors: return numberOfEffectors. + to get-numberOfHiddenNodes: return numberOfHiddenNodes. + to get-numberOfSensors: return numberOfSensors. + to get-stateVectorLength: return stateVectorLength. + to get-iteration: return iteration. + to init: n, i, j (int). island-size (float). # undocumented internal function that may help avoid crashes? (ask Jon) self enable-auto-disable. self disable-freed-instance-protection. # also prevents crashes in long runs #self enable-freed-instance-protection. cloud-texture = (new Image load from "images/clouds.png"). effectors = { "sizex", "sizey", "sizez", "jointx", "jointy", "jointz", "stemx", "stemy", "stemz", "tag", "donationsize", "donation", "stemdonationsize", "stemdonation", "collectionsize", "collection", "stemcollectionsize", "stemcollection", "copyfidelity", "mutationlimit", "matecontribution", "matetag", "adhesion", "pulserate", "sigmoidcompression" }. numberOfEffectors = | effectors |. hidden-nodes = { "hidden1", "hidden2", "hidden3", "hidden4", "hidden5", "hidden6", "hidden7", "hidden8", "hidden9", "hidden10" }. numberOfHiddenNodes = | hidden-nodes |. sensors = { "zero", "plus", "minus", "energy", "waste", "exposure", "pulse", "rotx", "roty", "rotz", "localtag", "localenergy", "localwaste", "connectedtag", "stemtag", "connectedenergy", "stemenergy", "connectedwaste", "stemwaste" }. numberOfSensors = | sensors |. stateVectorLength = numberOfEffectors + numberOfHiddenNodes + numberOfSensors. #print stateVectorLength. # uncomment the following to print code for state vector access methods #self print-state-vector-access-methods. #controller end-simulation. #self set-output-filter to 50. # print warnings iteration = 0. most-recent-ex-nihilo = 0. number-of-splits = 0. # camera control menu autoCameraMenu = (self add-menu named "Automatic Camera Control" for-method "set-autoCameraMode"). autoCameraMode = 1. autoCameraMenu check. #self point-camera at (0, 0, 0) from (180, 50, 0). #(160, 45, 0). #self offset-camera by (180, 50, 0). #(5, 1.5, 6). self offset-camera by (cos(iteration * SPIN) * 180, 50, sin(iteration * SPIN) * 180). cameraHasBeenAimed = 0. # misc initializations sun-position = (0, 0, 0). # just to have a position before it iterates global-resource-surcharge = 1.0. self enable-shadow-volumes. self enable-lighting. self enable-smooth-drawing. self enable-light-exposure-detection. #self enable-light-exposure-drawing. self disable-light-exposure-drawing. self disable-fast-physics. ##sloppy but fast #self enable-fast-physics. #self set-fast-physics-iterations to 3. #1. #2. #10. self double-gravity. self disable-text. log-file = new File. skin-image-hack = new Image. skin-image-hack init-with width 4 height 4. # set random seed seed = random[1000000]. #seed = 12345. self log text "random seed: $seed". self set-random-seed to seed. # create initial objects new Sun. #new SmallFloor. for i=0, i<5, i+=1: { for j=0, j<5, j+=1: { #if ((i==1) || (i==2)) && ((j==1) || (j==2)): island-size = FLOOR_SIZE/5. #else island-size = FLOOR_SIZE/9. island-size = FLOOR_SIZE/(12 - (4 * ((i % 2) + (j % 2)))). # 11&3 #+ (1 * |i - j|)). #(new SmallFloor) register with-shape (new Cube init-with size (island-size, 5, island-size)) (new SmallFloor) register with-shape (new PolygonDisk init-with radius (island-size / 2) sides 4 height 5) #(new SmallFloor) register with-shape (new Cube init-with size (island-size, 5, island-size)) at-location ( (0-(FLOOR_SIZE/2)) + ((i+0.5)*(FLOOR_SIZE/5)), -2.5, (0-(FLOOR_SIZE/2)) + ((j+0.5)*(FLOOR_SIZE/5)) ). } } new SubFloor. #self make-partitions. #10 new Clouds. for n=0, n peak-collisions-per-block-in-one-iteration: { peak-collisions-per-block-in-one-iteration = v. self log text "New peak-collisions-per-block-in-one-iteration: $peak-collisions-per-block-in-one-iteration". } + to get-global-resource-surcharge: return global-resource-surcharge. + to get-sun-position: return sun-position. + to set-sun-position to position (vector): sun-position = position. + to get-cloud-texture: return cloud-texture. + to record-split: number-of-splits += 1. + to make-partitions: partition1, partition2 (object). partition1 = (new Stationary) register with-shape (new Cube init-with size (200, 20, 10)) at-location (0, 5, 0). partition1 set-color to (0.1, 0.1, 0.1). partition2 = (new Stationary) register with-shape (new Cube init-with size (10, 20, 200)) at-location (0, 5, 0). partition2 set-color to (0.1, 0.1, 0.1). + to set-autoCameraMode: autoCameraMode = 1 - autoCameraMode. if autoCameraMode: { autoCameraMenu check. } else { autoCameraMenu uncheck. } + to auto-adjust-camera: location (vector). topDiff (float). item (object). provisionalNewZoom (float). numBlocks (int). location = (0, 0, 0). numBlocks = 0. foreach item in all Blocks: { if item: if (item get-location): if (item get-location)::x: { location += (item get-location). numBlocks += 1. } } if numBlocks > 0: location /= numBlocks. topDiff = 0.0. foreach item in all Blocks: { if item: if (item get-location): if (item get-location)::x: if topDiff < |location - (item get-location) |: topDiff = | location - (item get-location) |. } # throttled camera motion code provisionalNewZoom = (.5 * topDiff) + 100. #120 if cameraHasBeenAimed == 0: { self aim-camera at (0, 0, 0). self zoom-camera to provisionalNewZoom. prevCameraAim = (0, 0, 0). prevCameraZoom = provisionalNewZoom. cameraHasBeenAimed = 1. } else { if abs(|prevCameraAim - location|) < MAX_AIM_DELTA: { self aim-camera at location. prevCameraAim = location. } else { prevCameraAim = (((location - prevCameraAim) / | prevCameraAim - location |) * MAX_AIM_DELTA) + prevCameraAim. self aim-camera at prevCameraAim. } if abs(prevCameraZoom - provisionalNewZoom) < MAX_ZOOM_DELTA: { prevCameraZoom = provisionalNewZoom. } else { if prevCameraZoom - provisionalNewZoom < 0: { prevCameraZoom = prevCameraZoom + MAX_ZOOM_DELTA. } else { prevCameraZoom = prevCameraZoom - MAX_ZOOM_DELTA. } } self zoom-camera to prevCameraZoom. } self offset-camera by (cos(iteration * SPIN) * 180, 50, sin(iteration * SPIN) * 180). + to log text s (string): print s. log-file open-for-appending with-file "log". log-file write-line text s. log-file close. + to print-stats: b (object). f (float). v (vector). numBlocks, numJoints, i (int). #i = | (all Objects) |. #self log text "Total objects: $i". if (iteration % 10) == 0: { self log text "--- PERIODIC STATISTICS ---". self log text "Iteration: $iteration". self log text "Relative sun height: $relative-sun-height". numBlocks = | all Blocks |. self log text "Blocks: $numBlocks". f = (((| all Blocks | * 1.0 )/ MAX_BLOCKS) * 2) - 1. self log text "Block count normalized: $f". numJoints = | all Joints |. self log text "Joints: $numJoints". f = (((| all Joints | * 1.0 )/ (MAX_BLOCKS * 3)) * 2) - 1. self log text "Joint count normalized: $f". f = ((((| all Joints | * 1.0) / | all Blocks |) / 1.5) * 2) - 1. self log text "J/B ratio normalized: $f". i = iteration - most-recent-ex-nihilo. self log text "Iterations since most recent ex-nihilo generation: $i". if i > 1000: controller end-simulation. # HERE IS THE CHECK FOR EARLY TERMINATION -- COMMENT OUT TO LET CONTINUE self log text "Cumulative number of splits: $number-of-splits". # controller report-object-allocation. f = 0. foreach b in all Blocks: f += (b get-block-age). if numBlocks > 0: f /= numBlocks. self log text "Average block age: $f". f = 0. foreach b in all Blocks: f += (b get-battery). if numBlocks > 0: f /= numBlocks. self log text "Average block battery: $f". f = 0. foreach b in all Blocks: f += (b get-trash). if numBlocks > 0: f /= numBlocks. self log text "Average block trash: $f". v = (0, 0, 0). foreach b in all Blocks: v += (b get-size). if numBlocks > 0: v /= numBlocks. self log text "Average block size: $v". v = (0, 0, 0). numJoints = | all Joints |. # BUG IN JOINT VELOCITY ACCESS #foreach b in all Joints: { # #print (b get-joint-velocity-vector). # v += (b get-joint-velocity-vector). #} #if numJoints > 0: v /= numJoints. #self log text "Average joint velocity: $v". f = 0. foreach b in all Blocks: f += (b get-tag). if numBlocks > 0: f /= numBlocks. self log text "Average block tag: $f". f = 0. foreach b in all Blocks: f += (b get-donationsize). if numBlocks > 0: f /= numBlocks. self log text "Average donation size: $f". f = 0. foreach b in all Blocks: f += (b get-stemdonationsize). if numBlocks > 0: f /= numBlocks. self log text "Average stem donation size: $f". f = 0. foreach b in all Blocks: f += (b get-donation). if numBlocks > 0: f /= numBlocks. self log text "Average donation tolerance: $f". f = 0. foreach b in all Blocks: f += (b get-stemdonation). if numBlocks > 0: f /= numBlocks. self log text "Average stem donation tolerance: $f". f = 0. foreach b in all Blocks: f += (b get-collectionsize). if numBlocks > 0: f /= numBlocks. self log text "Average collection size: $f". f = 0. foreach b in all Blocks: f += (b get-stemcollectionsize). if numBlocks > 0: f /= numBlocks. self log text "Average stem collection size: $f". f = 0. foreach b in all Blocks: f += (b get-collection). if numBlocks > 0: f /= numBlocks. self log text "Average collection tolerance: $f". f = 0. foreach b in all Blocks: f += (b get-stemcollection). if numBlocks > 0: f /= numBlocks. self log text "Average stem collection tolerance: $f". f = 0. foreach b in all Blocks: f += (b get-copyfidelity). if numBlocks > 0: f /= numBlocks. self log text "Average block copy fidelity: $f". f = 0. foreach b in all Blocks: f += (b get-mutationlimit). if numBlocks > 0: f /= numBlocks. self log text "Average block mutation limit: $f". f = 0. foreach b in all Blocks: f += (b get-matecontribution). if numBlocks > 0: f /= numBlocks. self log text "Average block mate contribution: $f". f = 0. foreach b in all Blocks: f += |(b get-matetag) - (b get-tag)| / 2.0. if numBlocks > 0: f /= numBlocks. self log text "Average block preferred mate difference (/2): $f". f = 0. foreach b in all Blocks: f += (b get-adhesion). if numBlocks > 0: f /= numBlocks. self log text "Average block adhesion: $f". f = 0. foreach b in all Blocks: f += (b get-pulserate). if numBlocks > 0: f /= numBlocks. self log text "Average block pulse rate: $f". f = 0. foreach b in all Blocks: f += (b get-sigmoidcompression). if numBlocks > 0: f /= numBlocks. self log text "Average block sigmoid compression: $f". f = 0. foreach b in all Blocks: f += (b get-location)::y. if numBlocks > 0: f /= numBlocks. self log text "Average block height: $f". self log text "Global resource surcharge: $global-resource-surcharge.". birds-eye-cam-image read-pixels at-x 0 at-y 0. f = (birds-eye-cam-image get-compression-size). self log text "Compression size: $f". ## hidden node values # SHOULD BE REWRITTEN FOR VARIABLE NUM OF HIDDEN NODES # DEFERRED SINCE NOT SURE WE'LL EVER WANT TO PRINT THIS # f = 0. # foreach b in all Blocks: f += (b get-hidden1). # if numBlocks > 0: f /= numBlocks. # self log text "Average block hidden node #1 value: $f". # f = 0. # foreach b in all Blocks: f += (b get-hidden2). # if numBlocks > 0: f /= numBlocks. # self log text "Average block hidden node #2 value: $f". # f = 0. # foreach b in all Blocks: f += (b get-hidden3). # if numBlocks > 0: f /= numBlocks. # self log text "Average block hidden node #3 value: $f". # f = 0. # foreach b in all Blocks: f += (b get-hidden4). # if numBlocks > 0: f /= numBlocks. # self log text "Average block hidden node #4 value: $f". # f = 0. # foreach b in all Blocks: f += (b get-hidden5). # if numBlocks > 0: f /= numBlocks. # self log text "Average block hidden node #5 value: $f". # f = 0. # foreach b in all Blocks: f += (b get-hidden6). # if numBlocks > 0: f /= numBlocks. # self log text "Average block hidden node #6 value: $f". ### print a random state vector and/or matrix (comment/uncomment) #b = (all Blocks){random[numBlocks - 1]}. #print "Randomly chosen state vector:". #(b get-state-vector) print-matlab-style. #print "Randomly chosen action-matrix:". #(b get-action-matrix) print-matlab-style. self log text "--- END PERIODIC STATISTICS ---". } + to one-to-one-donation with-source source (object) with-destination destination (object) size donation-size (float) tolerance source-tolerance (float): source-tag, destination-tag (float). ## EXPERIMENTAL donation size as percentage of current battery donation-size = donation-size * (1 + (source get-battery)). if ((source get-battery) > (-1 + donation-size)) && ((destination get-battery) < (1 - donation-size)): { source-tag = (source get-tag). destination-tag = (destination get-tag). if abs(source-tag - destination-tag) < source-tolerance: { source set-battery to (source get-battery) - donation-size. destination set-battery to (destination get-battery) + donation-size. } } + to joint-donation: joints (list). j, source, destination (object). attempt (int). raw-size, donation-size, tolerance (float). joints = all BloctoplasmJoints. for attempt=1, attempt<(|joints| * JOINT_DONATION_ATTEMPTS_PER_JOINT), attempt +=1: { j = joints{random[|joints| - 1]}. if random[1] == 0: { source = (j get-parent). destination = (j get-child). } else { source = (j get-child). destination = (j get-parent). } raw-size = (source get-donationsize). tolerance = 1 + (source get-donation). if (source get-stem): { if (source get-stem) == j: { raw-size = (source get-stemdonationsize). tolerance = 1 + (source get-stemdonation). } } donation-size = MINIMUM_DONATION_SIZE + (((raw-size + 1) / 2) * (MAXIMUM_DONATION_SIZE - MINIMUM_DONATION_SIZE)). self one-to-one-donation with-source source with-destination destination size donation-size tolerance tolerance. } + to one-to-one-collection with-source source (object) with-destination destination (object) size collection-size (float) tolerance destination-tolerance (float): source-tag, destination-tag (float). ## EXPERIMENTAL collection size as percentage of remaining capacity collection-size = collection-size * (2.0 - (1.0 + (destination get-trash))). if ((source get-trash) > (-1 + collection-size)) && ((destination get-trash) < (1 - collection-size)): { source-tag = (source get-tag). destination-tag = (destination get-tag). if abs(source-tag - destination-tag) < destination-tolerance: { source set-trash to (source get-trash) - collection-size. destination set-trash to (destination get-trash) + collection-size. } } + to joint-collection: joints (list). j, source, destination (object). attempt (int). raw-size, collection-size, tolerance (float). joints = all BloctoplasmJoints. for attempt=1, attempt<(|joints| * JOINT_COLLECTION_ATTEMPTS_PER_JOINT), attempt +=1: { j = joints{random[|joints| - 1]}. if random[1] == 0: { source = (j get-parent). destination = (j get-child). } else { source = (j get-child). destination = (j get-parent). } raw-size = (destination get-collectionsize). tolerance = 1 + (destination get-collection). if (destination get-stem): { if (destination get-stem) == j: { raw-size = (destination get-stemcollectionsize). tolerance = 1 + (source get-stemcollection). } } collection-size = MINIMUM_COLLECTION_SIZE + (((raw-size + 1) / 2) * (MAXIMUM_COLLECTION_SIZE - MINIMUM_COLLECTION_SIZE)). self one-to-one-collection with-source source with-destination destination size collection-size tolerance tolerance. } + to iterate: num_blocks, i (int). iteration += 1. num_blocks = |all Blocks|. self update-neighbors. if autoCameraMode: self auto-adjust-camera. self print-stats. self joint-donation. self joint-collection. if num_blocks < REPRODUCTIVE_COMPETENCE_THRESHOLD: { for i = 0, i < 10, i = i + 1: { (new Block) init-ex-nihilo. } most-recent-ex-nihilo = iteration. } else if num_blocks > MAX_BLOCKS: { while | all Blocks | > MAX_BLOCKS_AFTER_REAP: { (self conduct-weak-block-tournament) vanish. } } num_blocks = |all Blocks|. # may have changed above if num_blocks > MIMIMUM_BLOCKS_FOR_GLOBAL_RESOURCE_SURCHARGE: { global-resource-surcharge = 1.0 + ((num_blocks - MIMIMUM_BLOCKS_FOR_GLOBAL_RESOURCE_SURCHARGE) * GLOBAL_RESOURCE_SURCHARGE_SCALING_FACTOR). } else { global-resource-surcharge = 1.0. } if THROW_COMETS: { if | all Blocks | > 1000: { comet-probability-denominator = 9. } else if | all Blocks | < 500: { comet-probability-denominator = 100000. } if random[comet-probability-denominator] == 0: { new Comet. } } super iterate. + to post-iterate: birds-eye-cam look at (0, 0, 0) from (0, (FLOOR_SIZE / 2.0) * PI, 0.1). + to conduct-weak-block-tournament: # returns a relatively weak block weakest, challenger (object). weakest-energy, challenger-energy (float). i (int). weakest = (all Blocks){random[|all Blocks| - 1]}. weakest-energy = (weakest get-battery). for i = 0, i < BLOCK_REAPER_TOURNAMENT_SIZE, i++: { challenger = (all Blocks){random[|all Blocks| - 1]}. challenger-energy = (challenger get-battery). if (challenger-energy < weakest-energy): { weakest = challenger. weakest-energy = challenger-energy. } } return weakest. + to dump-selection: (self get-selection) dump. + to badval-pause value v (float) message m (string): if (v > 1) : { print "More than 1! ", m. controller pause. } if (v < -1) : { print "Less than -1! ", m. controller pause. } else if isnan(v): { print "NAN! ", m. controller pause. } else if isinf(v): { print "INF! ", m. controller pause. } + to bigbadval-pause value v (float) message m (string): if isnan(v): { print "NAN! ", m. controller pause. } else if isinf(v): { print "INF! ", m. controller pause. } + to bigbadval value v (float) message m (string): if isnan(v): { print "NAN! ", m. return 1. } else if isinf(v): { print "INF! ", m. return 1. } else return 0. + to print-state-vector-access-methods: # just a coding utility # After changing the list uncomment the call in the controller init method # and then copy the output to the appropriate places. c (string). i (int). i = 0. foreach c in effectors: { print " + to get-$c: controller badval-pause value (state-vector get-value at $i) message \"get-$c\". return (state-vector get-value at $i).". print " + to set-$c to value (float): controller badval-pause value value message \"set-$c\". (state-vector set-value to value at $i).". i+=1. } foreach c in hidden-nodes: { print " + to get-$c: controller badval-pause value (state-vector get-value at $i) message \"get-$c\". return (state-vector get-value at $i).". print " + to set-$c to value (float): controller badval-pause value value message \"set-$c\". (state-vector set-value to value at $i).". i+=1. } foreach c in sensors: { print " + to get-$c: controller badval-pause value (state-vector get-value at $i) message \"get-$c\". return (state-vector get-value at $i).". print " + to set-$c to value (float): controller badval-pause value value message \"set-$c\". (state-vector set-value to value at $i).". i+=1. } } Link : Block (aka Blocks) { + variables: joints (list). stem (object). size, desired-size (vector). shape (object). age, birthtime (float). battery, trash (float). state-vector, action-matrix (object). recent-exposure, recent-raw-exposure (float). texture-image (object). collisions-this-iteration (int). havent-hit-subfloor (int). + to get-state-vector: return state-vector. + to get-action-matrix: return action-matrix. + to get-battery: return battery. + to set-battery to value (float): battery = value. + to get-trash: return trash. + to set-trash to value (float): trash = value. + to get-block-age: return age. # note there's a get-age defined for all objects (in seconds) + to get-size: return size. + to get-shape: return shape. + to get-texture-image: return texture-image. + to get-stem: return stem. + to set-stem to j (object): stem = j. + to get-volume: if (|size::x|<0) || (|size::y|<0) || (|size::z|<0): { print "NEGATIVE VOLUME COMPONENT". controller pause. } return size::x * size::y * size::z. # produced by print-state-vector-access-methods + to get-sizex: controller badval-pause value (state-vector get-value at 0) message "get-sizex". return (state-vector get-value at 0). + to set-sizex to value (float): controller badval-pause value value message "set-sizex". (state-vector set-value to value at 0). + to get-sizey: controller badval-pause value (state-vector get-value at 1) message "get-sizey". return (state-vector get-value at 1). + to set-sizey to value (float): controller badval-pause value value message "set-sizey". (state-vector set-value to value at 1). + to get-sizez: controller badval-pause value (state-vector get-value at 2) message "get-sizez". return (state-vector get-value at 2). + to set-sizez to value (float): controller badval-pause value value message "set-sizez". (state-vector set-value to value at 2). + to get-jointx: controller badval-pause value (state-vector get-value at 3) message "get-jointx". return (state-vector get-value at 3). + to set-jointx to value (float): controller badval-pause value value message "set-jointx". (state-vector set-value to value at 3). + to get-jointy: controller badval-pause value (state-vector get-value at 4) message "get-jointy". return (state-vector get-value at 4). + to set-jointy to value (float): controller badval-pause value value message "set-jointy". (state-vector set-value to value at 4). + to get-jointz: controller badval-pause value (state-vector get-value at 5) message "get-jointz". return (state-vector get-value at 5). + to set-jointz to value (float): controller badval-pause value value message "set-jointz". (state-vector set-value to value at 5). + to get-stemx: controller badval-pause value (state-vector get-value at 6) message "get-stemx". return (state-vector get-value at 6). + to set-stemx to value (float): controller badval-pause value value message "set-stemx". (state-vector set-value to value at 6). + to get-stemy: controller badval-pause value (state-vector get-value at 7) message "get-stemy". return (state-vector get-value at 7). + to set-stemy to value (float): controller badval-pause value value message "set-stemy". (state-vector set-value to value at 7). + to get-stemz: controller badval-pause value (state-vector get-value at 8) message "get-stemz". return (state-vector get-value at 8). + to set-stemz to value (float): controller badval-pause value value message "set-stemz". (state-vector set-value to value at 8). + to get-tag: controller badval-pause value (state-vector get-value at 9) message "get-tag". return (state-vector get-value at 9). + to set-tag to value (float): controller badval-pause value value message "set-tag". (state-vector set-value to value at 9). + to get-donationsize: controller badval-pause value (state-vector get-value at 10) message "get-donationsize". return (state-vector get-value at 10). + to set-donationsize to value (float): controller badval-pause value value message "set-donationsize". (state-vector set-value to value at 10). + to get-donation: controller badval-pause value (state-vector get-value at 11) message "get-donation". return (state-vector get-value at 11). + to set-donation to value (float): controller badval-pause value value message "set-donation". (state-vector set-value to value at 11). + to get-stemdonationsize: controller badval-pause value (state-vector get-value at 12) message "get-stemdonationsize". return (state-vector get-value at 12). + to set-stemdonationsize to value (float): controller badval-pause value value message "set-stemdonationsize". (state-vector set-value to value at 12). + to get-stemdonation: controller badval-pause value (state-vector get-value at 13) message "get-stemdonation". return (state-vector get-value at 13). + to set-stemdonation to value (float): controller badval-pause value value message "set-stemdonation". (state-vector set-value to value at 13). + to get-collectionsize: controller badval-pause value (state-vector get-value at 14) message "get-collectionsize". return (state-vector get-value at 14). + to set-collectionsize to value (float): controller badval-pause value value message "set-collectionsize". (state-vector set-value to value at 14). + to get-collection: controller badval-pause value (state-vector get-value at 15) message "get-collection". return (state-vector get-value at 15). + to set-collection to value (float): controller badval-pause value value message "set-collection". (state-vector set-value to value at 15). + to get-stemcollectionsize: controller badval-pause value (state-vector get-value at 16) message "get-stemcollectionsize". return (state-vector get-value at 16). + to set-stemcollectionsize to value (float): controller badval-pause value value message "set-stemcollectionsize". (state-vector set-value to value at 16). + to get-stemcollection: controller badval-pause value (state-vector get-value at 17) message "get-stemcollection". return (state-vector get-value at 17). + to set-stemcollection to value (float): controller badval-pause value value message "set-stemcollection". (state-vector set-value to value at 17). + to get-copyfidelity: controller badval-pause value (state-vector get-value at 18) message "get-copyfidelity". return (state-vector get-value at 18). + to set-copyfidelity to value (float): controller badval-pause value value message "set-copyfidelity". (state-vector set-value to value at 18). + to get-mutationlimit: controller badval-pause value (state-vector get-value at 19) message "get-mutationlimit". return (state-vector get-value at 19). + to set-mutationlimit to value (float): controller badval-pause value value message "set-mutationlimit". (state-vector set-value to value at 19). + to get-matecontribution: controller badval-pause value (state-vector get-value at 20) message "get-matecontribution". return (state-vector get-value at 20). + to set-matecontribution to value (float): controller badval-pause value value message "set-matecontribution". (state-vector set-value to value at 20). + to get-matetag: controller badval-pause value (state-vector get-value at 21) message "get-matetag". return (state-vector get-value at 21). + to set-matetag to value (float): controller badval-pause value value message "set-matetag". (state-vector set-value to value at 21). + to get-adhesion: controller badval-pause value (state-vector get-value at 22) message "get-adhesion". return (state-vector get-value at 22). + to set-adhesion to value (float): controller badval-pause value value message "set-adhesion". (state-vector set-value to value at 22). + to get-pulserate: controller badval-pause value (state-vector get-value at 23) message "get-pulserate". return (state-vector get-value at 23). + to set-pulserate to value (float): controller badval-pause value value message "set-pulserate". (state-vector set-value to value at 23). + to get-sigmoidcompression: controller badval-pause value (state-vector get-value at 24) message "get-sigmoidcompression". return (state-vector get-value at 24). + to set-sigmoidcompression to value (float): controller badval-pause value value message "set-sigmoidcompression". (state-vector set-value to value at 24). + to get-hidden1: controller badval-pause value (state-vector get-value at 25) message "get-hidden1". return (state-vector get-value at 25). + to set-hidden1 to value (float): controller badval-pause value value message "set-hidden1". (state-vector set-value to value at 25). + to get-hidden2: controller badval-pause value (state-vector get-value at 26) message "get-hidden2". return (state-vector get-value at 26). + to set-hidden2 to value (float): controller badval-pause value value message "set-hidden2". (state-vector set-value to value at 26). + to get-hidden3: controller badval-pause value (state-vector get-value at 27) message "get-hidden3". return (state-vector get-value at 27). + to set-hidden3 to value (float): controller badval-pause value value message "set-hidden3". (state-vector set-value to value at 27). + to get-hidden4: controller badval-pause value (state-vector get-value at 28) message "get-hidden4". return (state-vector get-value at 28). + to set-hidden4 to value (float): controller badval-pause value value message "set-hidden4". (state-vector set-value to value at 28). + to get-hidden5: controller badval-pause value (state-vector get-value at 29) message "get-hidden5". return (state-vector get-value at 29). + to set-hidden5 to value (float): controller badval-pause value value message "set-hidden5". (state-vector set-value to value at 29). + to get-hidden6: controller badval-pause value (state-vector get-value at 30) message "get-hidden6". return (state-vector get-value at 30). + to set-hidden6 to value (float): controller badval-pause value value message "set-hidden6". (state-vector set-value to value at 30). + to get-hidden7: controller badval-pause value (state-vector get-value at 31) message "get-hidden7". return (state-vector get-value at 31). + to set-hidden7 to value (float): controller badval-pause value value message "set-hidden7". (state-vector set-value to value at 31). + to get-hidden8: controller badval-pause value (state-vector get-value at 32) message "get-hidden8". return (state-vector get-value at 32). + to set-hidden8 to value (float): controller badval-pause value value message "set-hidden8". (state-vector set-value to value at 32). + to get-hidden9: controller badval-pause value (state-vector get-value at 33) message "get-hidden9". return (state-vector get-value at 33). + to set-hidden9 to value (float): controller badval-pause value value message "set-hidden9". (state-vector set-value to value at 33). + to get-hidden10: controller badval-pause value (state-vector get-value at 34) message "get-hidden10". return (state-vector get-value at 34). + to set-hidden10 to value (float): controller badval-pause value value message "set-hidden10". (state-vector set-value to value at 34). + to get-zero: controller badval-pause value (state-vector get-value at 35) message "get-zero". return (state-vector get-value at 35). + to set-zero to value (float): controller badval-pause value value message "set-zero". (state-vector set-value to value at 35). + to get-plus: controller badval-pause value (state-vector get-value at 36) message "get-plus". return (state-vector get-value at 36). + to set-plus to value (float): controller badval-pause value value message "set-plus". (state-vector set-value to value at 36). + to get-minus: controller badval-pause value (state-vector get-value at 37) message "get-minus". return (state-vector get-value at 37). + to set-minus to value (float): controller badval-pause value value message "set-minus". (state-vector set-value to value at 37). + to get-energy: controller badval-pause value (state-vector get-value at 38) message "get-energy". return (state-vector get-value at 38). + to set-energy to value (float): controller badval-pause value value message "set-energy". (state-vector set-value to value at 38). + to get-waste: controller badval-pause value (state-vector get-value at 39) message "get-waste". return (state-vector get-value at 39). + to set-waste to value (float): controller badval-pause value value message "set-waste". (state-vector set-value to value at 39). + to get-exposure: controller badval-pause value (state-vector get-value at 40) message "get-exposure". return (state-vector get-value at 40). + to set-exposure to value (float): controller badval-pause value value message "set-exposure". (state-vector set-value to value at 40). + to get-pulse: controller badval-pause value (state-vector get-value at 41) message "get-pulse". return (state-vector get-value at 41). + to set-pulse to value (float): controller badval-pause value value message "set-pulse". (state-vector set-value to value at 41). + to get-rotx: controller badval-pause value (state-vector get-value at 42) message "get-rotx". return (state-vector get-value at 42). + to set-rotx to value (float): controller badval-pause value value message "set-rotx". (state-vector set-value to value at 42). + to get-roty: controller badval-pause value (state-vector get-value at 43) message "get-roty". return (state-vector get-value at 43). + to set-roty to value (float): controller badval-pause value value message "set-roty". (state-vector set-value to value at 43). + to get-rotz: controller badval-pause value (state-vector get-value at 44) message "get-rotz". return (state-vector get-value at 44). + to set-rotz to value (float): controller badval-pause value value message "set-rotz". (state-vector set-value to value at 44). + to get-localtag: controller badval-pause value (state-vector get-value at 45) message "get-localtag". return (state-vector get-value at 45). + to set-localtag to value (float): controller badval-pause value value message "set-localtag". (state-vector set-value to value at 45). + to get-localenergy: controller badval-pause value (state-vector get-value at 46) message "get-localenergy". return (state-vector get-value at 46). + to set-localenergy to value (float): controller badval-pause value value message "set-localenergy". (state-vector set-value to value at 46). + to get-localwaste: controller badval-pause value (state-vector get-value at 47) message "get-localwaste". return (state-vector get-value at 47). + to set-localwaste to value (float): controller badval-pause value value message "set-localwaste". (state-vector set-value to value at 47). + to get-connectedtag: controller badval-pause value (state-vector get-value at 48) message "get-connectedtag". return (state-vector get-value at 48). + to set-connectedtag to value (float): controller badval-pause value value message "set-connectedtag". (state-vector set-value to value at 48). + to get-stemtag: controller badval-pause value (state-vector get-value at 49) message "get-stemtag". return (state-vector get-value at 49). + to set-stemtag to value (float): controller badval-pause value value message "set-stemtag". (state-vector set-value to value at 49). + to get-connectedenergy: controller badval-pause value (state-vector get-value at 50) message "get-connectedenergy". return (state-vector get-value at 50). + to set-connectedenergy to value (float): controller badval-pause value value message "set-connectedenergy". (state-vector set-value to value at 50). + to get-stemenergy: controller badval-pause value (state-vector get-value at 51) message "get-stemenergy". return (state-vector get-value at 51). + to set-stemenergy to value (float): controller badval-pause value value message "set-stemenergy". (state-vector set-value to value at 51). + to get-connectedwaste: controller badval-pause value (state-vector get-value at 52) message "get-connectedwaste". return (state-vector get-value at 52). + to set-connectedwaste to value (float): controller badval-pause value value message "set-connectedwaste". (state-vector set-value to value at 52). + to get-stemwaste: controller badval-pause value (state-vector get-value at 53) message "get-stemwaste". return (state-vector get-value at 53). + to set-stemwaste to value (float): controller badval-pause value value message "set-stemwaste". (state-vector set-value to value at 53). + to init: zero-size, svlength (float). age = 0.0. birthtime = (controller get-time). self enable-physics. self set-neighborhood-size to NEIGHBORHOOD_RADIUS. svlength = (controller get-stateVectorLength). state-vector = new Vector. state-vector init-with size svlength. state-vector set-all-values to 0.0. # we make the action matrix a square even though the sensor rows will all be zero # and should be unnecessary -- reason: matrix mult appears to fail with non-squares action-matrix = new Matrix2D. action-matrix init-with x-size svlength y-size svlength. action-matrix set-all-values to 0.0. texture-image = (new DynamicTexture). self set-texture-image to texture-image. #self set-texture-scale to 10.0. zero-size = (MAXIMUM_SIZE + MINIMUM_SIZE) / 2.0. #size = (SPLIT_SIZE - 0.1, SPLIT_SIZE - 0.1, SPLIT_SIZE - 0.1). # for calibrating photosynthesis size = (zero-size, zero-size, zero-size). desired-size = (zero-size, zero-size, zero-size). shape = (new Cube init-with size size). self set-shape to shape. self handle-collisions with-type "Block" with-method "handle-block-collision". self handle-collisions with-type "Comet" with-method "handle-comet-collision". self handle-collisions with-type "SubFloor" with-method "handle-subfloor-collision". collisions-this-iteration = 0. stem = 0. havent-hit-subfloor = 1. + to handle-block-collision with other (object): battery -= COST_PER_COLLISION. collisions-this-iteration += 1. if collisions-this-iteration == 1: { if (controller get-iteration) > 2: { #print "block collision". controller one-to-one-donation with-source self with-destination other size MINIMUM_DONATION_SIZE + ((((self get-donationsize) + 1) / 2) * (MAXIMUM_DONATION_SIZE - MINIMUM_DONATION_SIZE)) tolerance (self get-donation). controller one-to-one-collection with-source other with-destination self size MINIMUM_COLLECTION_SIZE + ((((other get-collectionsize) + 1) / 2) * (MAXIMUM_COLLECTION_SIZE - MINIMUM_COLLECTION_SIZE)) tolerance (other get-collection). #battery -= COST_PER_COLLISION. #print "ouch", self. } else { # collision at start of run, from initial placements, delete self vanish-without-corpse. } } + to handle-comet-collision with comet (object): if self: self vanish-without-corpse. + to handle-subfloor-collision with subfloor (object): if self: { self disable-physics. #vanish-without-corpse. if havent-hit-subfloor: { self set-velocity to (0, 0, 0). havent-hit-subfloor = 0. } battery -= 0.01. self set-acceleration to (0, -10, 0). } + to dump: print "state vector:". state-vector print-matlab-style. print "action matrix:". action-matrix print-matlab-style. + to init-ex-nihilo: range, i, j (float). num-e, num-h, num-s, svlength (int). range = RANGE_FOR_EX_NIHILO_GENERATION. self move to ((random[range] - (range / 2)), 3 + random[5.0], (random[range] - (range / 2))). battery = 1. trash = -1. # randomize matrices (already initialized to 0.0) num-e = (controller get-numberOfEffectors). num-h = (controller get-numberOfHiddenNodes). num-s = (controller get-numberOfSensors). svlength = num-e + num-h + num-s. if ENFORCE_HIDDEN_NODE_ARCHITECTURE: { # first do upper left corner (4 areas in layout diagram above) for i=0, i<(num-e + num-h), i+=1: for j=0, j<(num-e + num-h), j+=1: action-matrix set-value to random[2.0] - 1 at-x i at-y j. # now do the s->h area for i=num-e, i<(num-e + num-h), i+=1: for j=(num-e + num-h), j size::x + SIZE_GOOD_ENOUGH_DELTA): { scale-vector::x = MAX_GROWTH_RATE. } if (desired-size::y < size::y - SIZE_GOOD_ENOUGH_DELTA): { scale-vector::y = MAX_SHRINK_RATE. } else if (desired-size::y > size::y + SIZE_GOOD_ENOUGH_DELTA): { scale-vector::y = MAX_GROWTH_RATE. } if (desired-size::z < size::z - SIZE_GOOD_ENOUGH_DELTA): { scale-vector::z = MAX_SHRINK_RATE. } else if (desired-size::z > size::z + SIZE_GOOD_ENOUGH_DELTA): { scale-vector::z = MAX_GROWTH_RATE. } if scale-vector != (1.0, 1.0, 1.0): { (self get-shape) scale by scale-vector. size::x *= scale-vector::x. size::y *= scale-vector::y. size::z *= scale-vector::z. battery -= SIZE_CHANGE_COST_PER_ITERATION. } + to vanish: j, o, c (object). foreach j in joints: { if j: { o = (j get-parent). if (o == self): o = (j get-child). o remove-joint with j. free j. } } # # make corpse c = new Corpse. c set-shape to shape. c move to (self get-location). c set-rotation to (self get-rotation). c set-velocity to (self get-velocity). c set-lifetime to MINIMUM_CORPSE_LIFETIME + ((((self get-trash) + 1) / 2) * (MAXIMUM_CORPSE_LIFETIME - MINIMUM_CORPSE_LIFETIME)). #free shape. (don't -- it's getting passed to the corpse) free texture-image. free state-vector. free action-matrix. free self. + to vanish-without-corpse: j, o (object). foreach j in joints: { if j: { o = (j get-parent). if (o == self): o = (j get-child). o remove-joint with j. free j. } } free shape. free texture-image. free state-vector. free action-matrix. free self. + to sigmoid value v (float): raw-compression, compression (float). ## version that allows for negative compressions = negative slope sigmoid #raw-compression = (self get-sigmoidcompression). #compression = MINIMUM_SIGMOID_COMPRESSION + # abs(raw-compression * (MAXIMUM_SIGMOID_COMPRESSION - MINIMUM_SIGMOID_COMPRESSION)). #if raw-compression < 0: compression = 0 - compression. # fix sign # version that only allows for positive compressions = positive slope sigmoid raw-compression = ((self get-sigmoidcompression) + 1.0) / 2.0. compression = MINIMUM_SIGMOID_COMPRESSION + abs(raw-compression * (MAXIMUM_SIGMOID_COMPRESSION - MINIMUM_SIGMOID_COMPRESSION)). return (2 * (1 / (1 + E^(0 - (compression * v))))) - 1. + to garbage-scaling-factor: return 1.0 + ((((self get-trash) + 1) / 2) * GARBAGE_METABOLISM_SCALING_FACTOR). + to get-height-exposure-factor: return 1.0 + max(0, ((self get-location)::y * HEIGHT_EXPOSURE_SCALING_FACTOR)). + to get-number-of-neighbors: all-neighboring-objects, neighbors (list). obj (object). all-neighboring-objects = (self get-neighbors). foreach obj in all-neighboring-objects: { if obj && (obj is a "Block"): push obj onto neighbors. } return |neighbors|. + to get-local-resource-surcharge: return max(1.0, 0.0 + ((self get-number-of-neighbors) / 10)). + to iterate: i (int). temp-state-vector (object). if (controller get-frozen): return. controller update-peak-collisions-per-block-in-one-iteration value collisions-this-iteration. collisions-this-iteration = 0. age = age + 1. trash += (self get-volume) * GARBAGE_ACCUMULATED_PER_UNIT_CUBE. trash += GARBAGE_ACCUMULATED_PER_BLOCK. if trash > 1: trash = 1. self set-waste to trash. # photosynthesize recent-raw-exposure = (self get-light-exposure). # for debugging #controller badval-pause value recent-raw-exposure message "in light exposure.". #print "raw exposure: $recent-raw-exposure". # for calibrating MAX_EXPOSURE, but note that this will be based on scaled... #print "height-exposure-factor: ", (self get-height-exposure-factor). recent-exposure = (((recent-raw-exposure * (self get-height-exposure-factor)) / MAX_EXPOSURE) * 2) - 1. if recent-exposure > 1: recent-exposure = 1. self set-exposure to recent-exposure. # exposure is now -1..1 battery += ((recent-exposure + 1) / 2) * PHOTON_ENERGY. #print "battery increment: ", ((recent-exposure + 1) / 2) * PHOTON_ENERGY. if battery > 1: battery = 1. # energy threshold # cost of metabolism, depends on size, age, and resource availability battery -= (self get-volume) * METABOLIC_COST_PER_UNIT_CUBE * (self garbage-scaling-factor) * (controller get-global-resource-surcharge) * (self get-local-resource-surcharge). if ((self get-volume) * METABOLIC_COST_PER_UNIT_CUBE * (self garbage-scaling-factor) * (controller get-global-resource-surcharge) * (self get-local-resource-surcharge)) < 0: { print (self get-volume), METABOLIC_COST_PER_UNIT_CUBE, (self garbage-scaling-factor), (controller get-global-resource-surcharge), (self get-local-resource-surcharge). controller pause. } # EXPERIMENTALLY TEMPORARILY BASED ON SURFACE AREA RATHER THAN VOLUME # battery -= ((size::x * size::x) + (size::y * size::y) + (size::z * size::z)) * METABOLIC_COST_PER_UNIT_CUBE. battery -= METABOLIC_COST_PER_BLOCK * (self garbage-scaling-factor) * (controller get-global-resource-surcharge) * (self get-local-resource-surcharge). if battery < -1: battery = -1. self set-energy to battery. #vanish if no energy or off the world or self-penetrating if (battery <= -1): { self vanish. } else if (self get-location)::y < -20: { #-75: { # -10: { self vanish-without-corpse. } else if (self check-for-self-penetrations): { self vanish. } else { # survived -- do stuff # set remaining sensor components of state vector self set-sensor-components. self color-skin. self set-texture-scale to 5.0 - ((battery + 1.0) * 2.25). # moved here in hopes of forcing an update self set-texture-image to texture-image. # added here in hopes of forcing an update # update state vector by matrix (scaled) temp-state-vector = new Vector. temp-state-vector init-with size (controller get-stateVectorLength). # print "before:". # state-vector print-matlab-style. state-vector transform with-matrix action-matrix with-result temp-state-vector. # NORMALIZATION -- NOT SURE IF THIS SHOULD OR SHOULDN'T BE HERE AT THE MOMENT #temp-state-vector scale by (1.0 / STATE_VECTOR_LENGTH). for i=0, i<(controller get-stateVectorLength), i+=1: temp-state-vector set-value to (self sigmoid value (temp-state-vector get-value at i)) at i. # print "result:". # temp-state-vector print-matlab-style. state-vector scale by PERSISTENCE. temp-state-vector scale by (1.0 - PERSISTENCE). state-vector add-values of temp-state-vector. # scaled-by (1.0 - PERSISTENCE). # print "after:". # state-vector print-matlab-style. free temp-state-vector. # act based on new state vector # set new desired size desired-size::x = (self map-to-size-range value (self get-sizex)). desired-size::y = (self map-to-size-range value (self get-sizey)). desired-size::z = (self map-to-size-range value (self get-sizez)). self grow. # split if indicated if |(self get-velocity)| < MAX_VELOCITY_FOR_SPLIT: { if size::x > SPLIT_SIZE: self split-toward-sun dimension 0. else if size::y > SPLIT_SIZE: self split-toward-sun dimension 1. else if size::z > SPLIT_SIZE: self split-toward-sun dimension 2. } # don't do anything else here, since won't exist if split } + to color-skin: x, y (int). dotr, dotg, dotb, framer, frameg, frameb (float). # all denominators would be 2 for the full color range -- they're higher to keep it from being to garish, or lower to accentuate # (frame: r=waste, g=donation tolerance, b=donation size ; dot: r=exposure, g=stem donation tolerance, b=stem donation size) framer = ((self get-waste) + 1) / 1.0. #2.5. frameg = ((self get-donation) + 1) / 3.5. frameb = ((self get-donationsize) + 1) / 3.5. dotr = ((self get-exposure) + 1) / 0.5. #2.5. dotg = ((self get-collection) + 1) / 3. dotb = ((self get-collectionsize) + 1) / 3. for x=0,x<4,x++: { for y=0,y<4,y++: { if ((x == 1) || (x == 2)) && ((y == 1) || (y == 2)): { texture-image set-pixel to (dotr, dotg, dotb) at-x x at-y y. #debug #if collisions > 0: texture-image set-pixel to (1, 0, 0) at-x x at-y y. } else { texture-image set-pixel to (framer, frameg, frameb) at-x x at-y y. #debug #if collisions > 0: texture-image set-pixel to (1, 0, 0) at-x x at-y y. } } } + to map-to-size-range value v (float): scale (float). scale = (MAXIMUM_SIZE - MINIMUM_SIZE) / 2.0. return MINIMUM_SIZE + ((v + 1) * scale). + to map-from-size-range value v (float): # note that real sizes can actually be negative numbers, so you also have to abs scale (float). scale = (MAXIMUM_SIZE - MINIMUM_SIZE) / 2.0. return ((abs(v) - MINIMUM_SIZE) / scale) - 1. + to clamp01 value v (float): if v < 0: return 0. else if v > 1: return 1. else return v. + to get-pulserate-mapped: # maps from -1..1 indication of rate to time multiplier rate (float). rate = (self get-pulserate). rate = (rate + 1) / 2. # normalize to 0..1 rate = MINIMUM_PULSERATE + (rate * (MAXIMUM_PULSERATE - MINIMUM_PULSERATE)). # translate to correct range return rate * 6.283185307179586. + to set-sensor-components: v (vector). all-neighboring-objects, neighbors (list). obj, j, stem-block (object). tag-accum, energy-accum, waste-accum, scaling-denom, distance-from-neighborhood-edge (float). num-neighbors (int). # constants self set-zero to 0. self set-plus to 1. self set-minus to -1. # energy -- computed in photosynthesis/survival code in iterate method # exposure -- computed in photosynthesis/survival code in iterate method # pulse self set-pulse to sin(((controller get-time) - birthtime) * (self get-pulserate-mapped)). # rotx, roty, rotz v = ((self get-rotation) * (1, 1, 1)). if v: v /= |v|. self set-rotx to v::x. self set-roty to v::y. self set-rotz to v::z. # localtag, localenergy, localwaste all-neighboring-objects = (self get-neighbors). foreach obj in all-neighboring-objects: { if obj && (obj is a "Block"): push obj onto neighbors. } num-neighbors = |neighbors|. tag-accum = 0.0. energy-accum = 0.0. waste-accum = 0.0. scaling-denom = 0.0. if num-neighbors > 0: { foreach obj in neighbors: { distance-from-neighborhood-edge = max(0, NEIGHBORHOOD_RADIUS - |(self get-location) - (obj get-location)|). scaling-denom += distance-from-neighborhood-edge. tag-accum += distance-from-neighborhood-edge * (obj get-tag). energy-accum += distance-from-neighborhood-edge * (obj get-energy). waste-accum += distance-from-neighborhood-edge * (obj get-waste). } if scaling-denom > 0: { tag-accum /= scaling-denom. energy-accum /= scaling-denom. waste-accum /= scaling-denom. } } else { # values when no neighbors # tag-accum is already 0, probably appropriate energy-accum = -1.0. waste-accum = -1.0. } self set-localtag to tag-accum. self set-localenergy to energy-accum. self set-localwaste to waste-accum. # connectedtag, connectedenergy, connectedwaste, stemtag, stemenergy, stemwaste neighbors = {}. stem-block = 0. foreach j in joints: { if j: { obj = (j get-parent). if (obj == self): obj = (j get-child). push obj onto neighbors. if (self get-stem): { if (self get-stem) == j: stem-block = obj. pop neighbors. } } } num-neighbors = |neighbors|. tag-accum = 0.0. energy-accum = 0.0. waste-accum = 0.0. if num-neighbors > 0: { foreach obj in neighbors: { tag-accum += (obj get-tag). energy-accum += (obj get-energy). waste-accum += (obj get-waste). } tag-accum /= num-neighbors. energy-accum /= num-neighbors. waste-accum /= num-neighbors. } else { # values when no neighbors # tag-accum is already 0, probably appropriate energy-accum = -1.0. waste-accum = -1.0. } self set-connectedtag to tag-accum. self set-connectedenergy to energy-accum. self set-connectedwaste to waste-accum. if stem-block: { self set-stemtag to (stem-block get-tag). self set-stemenergy to (stem-block get-energy). self set-stemwaste to (stem-block get-waste). } else { # defaults self set-stemtag to 0.0. self set-stemenergy to -1.0. self set-stemwaste to -1.0. } + to add-joint with joint (object): push joint onto joints. + to remove-joint with joint (object): new-joints (list). j (object). foreach j in joints: { if (j != joint): push j onto new-joints. } joints = new-joints. + to resize-for-split with-parent-size newSize (vector) on-axis axis (vector): free shape. size = (self recalculate-split point newSize on-axis axis). if (|size::x|<0) || (|size::y|<0) || (|size::z|<0): { print "NEGATIVE SIZE COMPONENT". controller pause. } shape = (new Cube init-with size size). self set-shape to shape. + to recalculate-split point point (vector) on-axis axis (vector): if axis::x > 0: point::x /= 2.0. if axis::y > 0: point::y /= 2.0. if axis::z > 0: point::z /= 2.0. return point. + to get-axis for-edge p (vector): % If they're splitting on an edge, the 0 coordinate is the one % which corresponds to the axis. if p::x == 0.0: return (1, 0, 0). if p::y == 0.0: return (0, 1, 0). if p::z == 0.0: return (0, 0, 1). + to split-toward-sun dimension d (int): # d: 0=x, 1=y, 2=z edges (list). edge, best-edge (vector). i (int). distance, best-distance (float). battery -= SPLIT_COST. if battery <= -1: { self vanish. } else { if d == 0: { edges = {(0, -1, -1), (0, -1, 1), (0, 1, -1), (0, 1, 1)}. } else if d == 1: { edges = {(-1, 0, -1), (-1, 0, 1), (1, 0, -1), (1, 0, 1)}. } else: { edges = {(-1, -1, 0), (-1, 1, 0), (1, -1, 0), (1, 1, 0)}. } for i=0, i<4, i+=1: { edge = edges{i}. distance = | (controller get-sun-position ) - ((self get-location) + ((self get-rotation) * edge)) |. if i==0: { best-edge = edge. best-distance = distance. } else { if distance < best-distance: { best-edge = edge. best-distance = distance. } } } self split-edge on best-edge. } + to report-on-self-penetrations text t (string): if (self check-for-self-penetrations): { controller log text "Self-penetration: $t". } + to split-edge on edge (vector): parentLinkPoint, childLinkPoint, c1size, c2size, axis (vector). normal, minV, maxV (vector). child1, child2, joint, parentLink, childLink, mate (object). fidelity, i, j, stemOfParent, stemOfChild (int). mate-contribution (float). num-e, num-h, num-s, svlength (int). controller record-split. axis = (self get-axis for-edge edge). controller set-skin-image-hack from-image texture-image. child1 = new Block. child2 = new Block. controller reset-skin-image-hack. child1 resize-for-split with-parent-size size on-axis axis. child2 resize-for-split with-parent-size size on-axis axis. # fix the positions of the new objects. child1 set-rotation to (self get-rotation). child2 set-rotation to (self get-rotation). # is this right? child1 set-velocity to (self get-velocity). child2 set-velocity to (self get-velocity). child1 move to (self get-location) + (self get-rotation) * ((child1 get-shape) get-point-on-shape on-vector axis). child2 move to (self get-location) - (self get-rotation) * ((child2 get-shape) get-point-on-shape on-vector axis). # Go through the records of the joints we own and decide which of the # children it should get attached to. foreach joint in joints: { if joint: { # figure out whether we are considered the parent or child for # this joint and get the link points. normal = (joint get-joint-normal). minV = (joint get-min-joint-limit-vector). maxV = (joint get-max-joint-limit-vector). parentLinkPoint = (joint get-parent-link-point). childLinkPoint = (joint get-child-link-point). stemOfParent = 0. if ((joint get-parent) get-stem) == joint: stemOfParent = 1. stemOfChild = 0. if ((joint get-child) get-stem) == joint: stemOfChild = 1. # if the dot product of the link point and the split axis is # positive, the joint belongs on child1, otherwise, child2. if (joint get-parent) == self: { childLink = (joint get-child). if dot(parentLinkPoint, axis) > 0.0: { parentLinkPoint -= ((child1 get-shape) get-point-on-shape on-vector axis). parentLink = child1. } else { parentLinkPoint += ((child2 get-shape) get-point-on-shape on-vector axis). parentLink = child2. } parentLink add-joint with joint. } else { parentLink = (joint get-parent). if dot(childLinkPoint, axis) > 0.0: { childLinkPoint -= ((child1 get-shape) get-point-on-shape on-vector axis). childLink = child1. } else { childLinkPoint += ((child2 get-shape) get-point-on-shape on-vector axis). childLink = child2. } childLink add-joint with joint. } # break the old joint and rejoin. joint break. maxV::y = -angle(parentLinkPoint, normal) + 1.57. joint link parent parentLink to-child childLink with-parent-point parentLinkPoint with-child-point childLinkPoint with-normal normal use-current-relative-rotation 1. joint set-strength-limit to 10000. joint enable-automatic-joint-scaling. joint set-joint-limit-vectors min minV max maxV. if stemOfParent: (parentLink set-stem to joint). if stemOfChild: (childLink set-stem to joint). } } joint = new BloctoplasmJoint. # this is the totally new joint (not a recreated one). # Figure out the link points by taking the cube's size, positive # and negative on the axis in question. maxV = (1, 1, 0). c1size = (child1 get-size) / 2.0. c2size = (child2 get-size) / 2.0. if edge::x == 0: { c1size::y *= edge::y. c2size::y *= edge::y. c1size::z *= edge::z. c2size::z *= edge::z. c1size::x *= -1. } if edge::y == 0: { c1size::x *= edge::x. c2size::x *= edge::x. c1size::z *= edge::z. c2size::z *= edge::z. c1size::y *= -1. } if edge::z == 0: { c1size::x *= edge::x. c2size::x *= edge::x. c1size::y *= edge::y. c2size::y *= edge::y. c1size::z *= -1. } joint link parent child1 to-child child2 with-parent-point c1size with-child-point c2size with-normal axis use-current-relative-rotation 1. joint set-strength-limit to 10000. joint enable-automatic-joint-scaling. joint set-joint-limit-vectors min (-1, -1, 0) max (1, -angle(c1size, axis) + 1.57, 0). # add this joint to the childrens' joint lists child1 add-joint with joint. child2 add-joint with joint. # make the new joint the stem for a child without an inherited stem if (child1 get-stem) == 0: (child1 set-stem to joint). if (child2 get-stem) == 0: (child2 set-stem to joint). ## PARTITION ENERGY AND SET TEXTURE SCALE child1 set-battery to ((battery + 1) / 2) - 1. child2 set-battery to ((battery + 1) / 2) - 1. child1 set-texture-scale to 5.0 - (((child1 get-battery) + 1) * 2.25). child2 set-texture-scale to 5.0 - (((child2 get-battery) + 1) * 2.25). ## PARTITION TRASH #child1 set-trash to ((trash + 1) / 2) - 1. #child2 set-trash to ((trash + 1) / 2) - 1. ## experimentally don't child1 set-trash to -1. child2 set-trash to -1. ### STATE VECTOR INHERITANCE ## first copy the parent's vector #(child1 get-state-vector) copy from state-vector. #(child2 get-state-vector) copy from state-vector. ## then override size components from the real new sizes, with offset and scaling #child1 set-sizex to (self map-from-size-range value c1size::x). #child2 set-sizex to (self map-from-size-range value c2size::x). #child1 set-sizey to (self map-from-size-range value c1size::y). #child2 set-sizey to (self map-from-size-range value c2size::y). #child1 set-sizez to (self map-from-size-range value c1size::z). #child2 set-sizez to (self map-from-size-range value c2size::z). ### STATE VECTOR INHERITANCE, only for hidden nodes and asymmetric num-e = (controller get-numberOfEffectors). num-h = (controller get-numberOfHiddenNodes). for i=num-e, i<(num-e + num-h), i+=1: if ((i / 2) * 2) == i: ((child1 get-state-vector) set-value to (state-vector get-value at i) at i). else ((child2 get-state-vector) set-value to (state-vector get-value at i) at i). # action matrix inheritance (child1 get-action-matrix) copy from action-matrix. (child2 get-action-matrix) copy from action-matrix. # crossover num-e = (controller get-numberOfEffectors). num-h = (controller get-numberOfHiddenNodes). num-s = (controller get-numberOfSensors). svlength = num-e + num-h + num-s. mate = (self select-mate). if mate: { mate-contribution = (((self get-matecontribution) + 1) / 2). # GET MATE ELEMENTS FOR CHILD1 if ENFORCE_HIDDEN_NODE_ARCHITECTURE: { # first do upper left corner (4 areas in layout diagram above) for i=0, i<(num-e + num-h), i+=1: for j=0, j<(num-e + num-h), j+=1: if random[1.0] < mate-contribution: (child1 get-action-matrix) set-value to ((mate get-action-matrix) get-value at-x i at-y j) at-x i at-y j. # now do the s->h area for i=num-e, i<(num-e + num-h), i+=1: for j=(num-e + num-h), jh area for i=num-e, i<(num-e + num-h), i+=1: for j=(num-e + num-h), jh area for i=num-e, i<(num-e + num-h), i+=1: for j=(num-e + num-h), jh area for i=num-e, i<(num-e + num-h), i+=1: for j=(num-e + num-h), j 0: { closest = neighbors{0}. remove neighbors{0}. foreach obj in neighbors: if |(self get-matetag) - (obj get-tag)| < |(self get-matetag) - (closest get-tag)|: closest = obj. return closest. } else return 0. + to mutate value v (float): # could be a gaussian some day limit, newval (float). limit = ((self get-mutationlimit) + 1) / 2. # now it's 0..1 limit = MINIMUM_MUTATION_LIMIT + (limit * (MAXIMUM_MUTATION_LIMIT - MINIMUM_MUTATION_LIMIT)). newval = v + (random[2.0 * limit] - limit). if newval < -1: return -1. else if newval > 1: return 1. else return newval. } BallJoint : BloctoplasmJoint (aka BloctoplasmJoints) { + to post-iterate: parent-volume, child-volume (float). x-component, y-component, z-component, parent-contrib, child-contrib (float). force-limit, energy-charge, force-magnitude (float). f (vector). # move joint based on joint/stem specs of links parent-contrib = (parent get-jointx). if (parent get-stem): { if (parent get-stem) == self: parent-contrib = (parent get-stemx). } child-contrib = (child get-jointx). if (child get-stem): { if (child get-stem) == self: child-contrib = (child get-stemx). } x-component = PI * (parent-contrib + child-contrib) / 2.0. parent-contrib = (parent get-jointy). if (parent get-stem): { if (parent get-stem) == self: parent-contrib = (parent get-stemy). } child-contrib = (child get-jointy). if (child get-stem): { if (child get-stem) == self: child-contrib = (child get-stemy). } y-component = PI * (parent-contrib + child-contrib) / 2.0. parent-contrib = (parent get-jointz). if (parent get-stem): { if (parent get-stem) == self: parent-contrib = (parent get-stemz). } child-contrib = (child get-jointz). if (child get-stem): { if (child get-stem) == self: child-contrib = (child get-stemz). } z-component = PI * (parent-contrib + child-contrib) / 2.0. # could be a scaling factor here, but unity seems to be about right self set-joint-velocity to ((x-component, y-component, z-component) - (self get-joint-angles)). # charge BOTH connected blocks depending on |(self get-force)| f = (self get-force). if (controller bigbadval value f::x message "force x component.") || (controller bigbadval value f::y message "force y component.") || (controller bigbadval value f::z message "force z component.") || (controller bigbadval value |f| message "force length."): f = (0, 0, 0). if f: { energy-charge = |f| * JOINT_FORCE_COST_PER_ITERATION. #removed: * 2. parent set-battery to ((parent get-battery) - energy-charge). child set-battery to ((parent get-battery) - energy-charge). } ## BREAK IN APPROPRIATE CIRCUMSTANCES # break when combined link size too small parent-volume = (parent get-volume). child-volume = (child get-volume). if (parent-volume + child-volume) < BREAK_SIZE: { self break. #print "----------------------------------------------------break". free self. } else if f: { # break if too much force force-limit = ((parent get-adhesion) + (child get-adhesion)) / 2.0. # average force-limit = (force-limit + 1.0) * (MAX_JOINT_FORCE / 2.0). # then normalize/scale force-magnitude = |f|. if force-magnitude > force-limit: { self break. print "----------------------------------------------------break (force = $force-magnitude)". free self. } } + to dearchive: (super dearchive). } Mobile : Sun { + to init: self set-lightmap to 2. self set-shape to ((new Shape) init-with-sphere radius 20). + to iterate: lightPosition (vector). time (double). time = (controller get-time) / TIME_SCALE. lightPosition = (0, cos(time), sin(time)) + (0, .2, 0). controller set-relative-sun-height to cos(time). self move to FLOOR_SIZE * lightPosition * 2. # the 2 is just to get out of the way of birds-eye-cam controller move-light to ((FLOOR_SIZE / 2) + 1 ) * lightPosition. controller set-light-exposure-source to ((FLOOR_SIZE / 2) + 1 ) * lightPosition. controller set-sun-position to FLOOR_SIZE * lightPosition. controller set-background-color to lightPosition::y * DAYLIGHT. } Mobile : Corpse { + variables: age (float). transparency (float). lifetime (int). faderate (float). + to init: #self enable-physics. self set-color to (1, 1, 1). transparency = 1.0. age = 0. self handle-collisions with-type "Comet" with-method "handle-comet-collision". self handle-collisions with-type "SubFloor" with-method "handle-subfloor-collision". + to set-lifetime to time (int): lifetime = time. # not sure about this formula, but it seems to behave correctly and it's only cosmetic faderate = 1.0 - ((lifetime ^ (1.0 / (lifetime * 1.0))) - 1.0). + to handle-comet-collision with comet (object): free (self get-shape). free (self). + to handle-subfloor-collision with subfloor (object): #free (self get-shape). #free (self). + to iterate: age = age + 1. (self get-shape) scale by (1.02, 1.02, 1.02). transparency *= faderate. #0.9. #0.87. self set-transparency to transparency. if age > lifetime: { free (self get-shape). free (self). } } # end of Corpse methods Stationary : SmallFloor { } Stationary : SubFloor { + to init: self register with-shape (new Cube init-with size (FLOOR_SIZE + 50, 5, FLOOR_SIZE + 50)) at-location (0, -7.5, 0). #(0, -52.5, 0). self set-color to (0, 0.15, 0.2). } Image : DynamicTexture { + to init: x, y (int). self init-with width 4 height 4. for x=0,x<4,x++: { for y=0,y<4,y++: { self set-pixel to ((controller get-skin-image-hack) get-rgb-pixel at-x x at-y y) at-x x at-y y. } } } Mobile : Clouds { + variables: drifting (int). driftLocation (vector). + to init: self set-shape to ((new Shape) init-with-polygon-disk radius 15 sides 25 height 1.0). #self set-shape to ((new Shape) init-with-sphere radius 20). self set-color to (1, 1, 1). #(0.5, 0.5, 0.5). #self set-transparency to 0.75. #self set-texture-scale to 100. #self set-texture-image to (controller get-cloud-texture). self move to random[(200.0, 10.0, 200.0)] - (100.0, -40.0, 100.0). self set-velocity to (0, 0, 0). #self set-color to (1, 1, 0.3). + to maybe-teleport: if random[250] == 0: { self drift to random[(200.0, 10.0, 200.0)] - (100.0, -40.0, 100.0). } + to iterate: if drifting: { self offset by .04 * (driftLocation - (self get-location)). if (|driftLocation - (self get-location)| < .001): { self move to driftLocation. drifting = 0. } } else { self maybe-teleport. } + to drift to location (vector): drifting = 1. driftLocation = location. } Mobile : Comet (aka Comets) { + variables: timeSinceHitFloor (int). cometSize (float). + to init: range (float). cometSize = 10 * COMET_SIZE. range = FLOOR_SIZE. timeSinceHitFloor = -1. self set-shape to (new Cube init-with size (cometSize, 10, cometSize)). self set-color to (0.5, 0.25, 0.0). self move to (random[range]-(range/2), range/2, random[range]-(range/2)). self handle-collisions with-type "SmallFloor" with-method "handle-floor-collision". self set-acceleration to (0,-100,0). + to handle-floor-collision with floor (object): if timeSinceHitFloor < 0: { timeSinceHitFloor = 0. self set-velocity to (0, 0, 0). self set-acceleration to (0, -10, 0). } + to iterate: if timeSinceHitFloor >= 0: timeSinceHitFloor += 1. if (timeSinceHitFloor > 40) || ((self get-location)::y < -100): { free (self get-shape). free (self). } }