#Multi-objective evolving Monsters # SimulationControl Simulation (c) 2010 Jacob Schrum. # # This library is free software; you can redistribute it and/or # # modify it under the terms of the GNU Lesser General Public # # License as published by the Free Software Foundation; either # # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # # Lesser General Public License for more details. @use PhysicalControl. @use Movie. @use Mobile. @use Stationary. @use File. @include "Constants.tz". @include "Lists.tz". @include "FreeNetwork.tz". @include "MultiNetwork.tz". @include "FreeNetGa.tz". @include "NSGA2.tz". @include "CTUG-NSGA2.tz". @include "PartTUG-NSGA2.tz". @include "ZScoresGA.tz" @include "GraphicsHandler.tz". @include "Environment.tz". @include "Log.tz". @include "Math3D.tz". @include "Agent.tz". @include "Triangulate.tz". @include "Player.tz". @include "HUD.tz". @include "NetViewer.tz". @include "Sensor.tz". @include "Monster.tz". @include "CommandLineHandler.tz". @include "NetIO.tz". @include "EvolutionMode.tz". @include "BehaviorState.tz". @include "BrainPool.tz". @include "Resume.tz". @include "UnitTest.tz". Controller SimulationControl. PhysicalControl : SimulationControl { + variables: # Auxillary classes myHUD (object). # HUD view (object). # NetViewer triangulate (object). # Triangulate math (object). # Math3D netIO (object). # NetIO log (object). # Log graphics (object). # GraphicsHandler commandline (object). # CommandLineHandler evolution-mode (object). # EvolutionModeArbitrator behavior-state (object). # BehaviorState brain-pool (object). # BrainPool mode-arbitrator (object). # ModeArbitrator main-camera (object). # Camera resume-helper (object). # Resume list-ops (object). # List Operations # IO hide-text (int). write-settings-and-exit (int). settings-file (string). settings-path (string). #partition-log-objects (list). loaded-log-objects (list). loaded-log-args (list). loaded-fitnesses (list). loaded-inputs (list). loaded-input-args (list). loaded-input-ranges (list). excluded-fitnesses (list). load (int). overwrite-log (int). user-save (int). user-end (int). file-path (string). inputPath (string). inputFiles (string). experiment-theme (string). file-output (int). # Game mode tasks (list). pending-goal-increases (list). eval-limit (int). home-stretch-counter (int). home-stretch (int). skip-trial (int). user-increase-challenge (int). num-evals (int). current-iteration (int). current-game-mode (int). current-game-mode-counter (int). goal (object). # For player player (object). # Player deaths (int). previous-strategy (int). strategy-switches (int). player-shoots (int). # For monsters last-subpop-num (int). last-pop-slot (int). stay-bound (int). early-termination (int). shuffle-offset (int). subpop-size (int). number-of-subpops (int). monsters-from-each-subpop (int). monsters (list). kills-last-gen (int). additional-input-info (list). # For evolution multinetworks (int). last-pareto-front-size (int). use-shaping (int). partition-tug (int). recency-weighted-alpha (double). drop-defeated (int). long-term-averaging (int). goals-as-constraints (int). homogeneous (int). behavior-diversity (int). random-behavior-syllabus (int). observed-behavior-syllabus (int). sample-desired (int). stagnation-counter (int). children-per-parent (int). ga (object). # FreeNetGA selection (object). # NSGA2 or ZScoresGA fitness-info-list (list). current-fitnesses (list). current-mode-usage (list). current-mode-counts (list). parent-brains (list). parent-fitnesses (list). child-brains (list). child-fitnesses (list). current-population (int). current-population-num (int). player-powerups (int). phase (int). generation (int). # Diversity diversity-fitness-index (int). current-behavior-vectors (list). parent-behavior-vectors (list). # Stats interaction-occurred (int). steps-since-interaction (int). increase-all-goals (int). input-connectivity-sums (list). max-age (int). min-age (int). max-num-net-modes (int). min-num-net-modes (int). ave-percent-mode-usage (double). current-eval (int). num-successful (int). group-score (double). ave-group-score (double). ave-group-fight-score (double). ave-group-ram-score (double). ave-group-back-ram-score (double). ave-group-pred-score (double). player-score (double). ave-player-score (double). ave-player-fight-score (double). ave-player-ram-score (double). ave-player-back-ram-score (double). ave-player-prey-score (double). type-trials (list). type-trials-for-brains (list). ratio-children-in-new-pop (double). # Movie movieName (string). movie (object). # Movie #SMEG: put in FileCommands.tz or NetIO.tz + to file-exists named file (string): handle (object). eof (int). temp (string). print "Does $file exist?". if (file == ""): return 0. else { handle = new File. handle open-for-appending with-file file. handle close. handle open-for-reading with-file file. temp = handle read-line. eof = (handle is-end-of-file). handle close. print "$temp EOF: $eof". return (!eof). } + to click on theObject (object): if (theObject) && (theObject can-respond to "click") : { theObject click. } # id: a subpopulation index # population-slot: index within individual subpopulation + to get-type-trials-for sub id (int) slot population-slot (int): return type-trials-for-brains{id}{population-slot}. + to get-speed-difficulty: return (commandline num-param named "speed-difficulty"). # sd: 0 <= sd <= 1.0 + to set-speed-difficulty to sd (double): stagnation-counter = 0. commandline set-num-param named "speed-difficulty" to sd. # If backwards = 1, then go backwards instead of forwards + to next-in-speed-sequence reverse backwards = 0 (int): pos (int). sequence (list). pos = (commandline num-param named "speed-sequence-position"). sequence = (commandline list-param named "speed-sequence"). if backwards : { commandline set-num-param named "speed-sequence-position" to (pos - 1). self set-speed-difficulty to (sequence{ (pos - 1) }). } else { commandline set-num-param named "speed-sequence-position" to (pos + 1). self set-speed-difficulty to (sequence{ (pos + 1) }). } + to set-last-path-saved to filepath (string): print "Last save was in path $filepath". commandline set-string-param named "last-path-saved" to filepath. netIO set-last-path-saved to filepath. + to set-last-file-saved to file (string): print "Last save was in file $file". commandline set-string-param named "last-file-saved" to file. netIO set-last-file-saved to file. #SMEG:put in Resume.tz + to set-resume-file: commandline set-string-param named "resume-file" to "$file-path/$experiment-theme.txt". + to increase-stagnation-threshold: stagnation-counter = 0. commandline set-num-param named "stagnation-threshold" to ((commandline num-param named "stagnation-threshold") + (commandline num-param named "stagnation-increment")). + to decrease-stagnation-threshold: stagnation-counter = 0. commandline set-num-param named "stagnation-threshold" to (max(1,(commandline num-param named "stagnation-threshold") - (commandline num-param named "stagnation-increment"))). # Required for proper loading + to update-starting-innovation-counter: commandline set-num-param named "starting-innovation-number" to (ga get-innovation-counter). commandline set-num-param named "starting-network-id-number" to (ga get-id-counter). # Required for proper resumes + to update-end-generation: commandline set-num-param named "ending-generation" to generation. # Can only be used if selection is a PartTUG-NSGA2 + to get-size-of-tug-partition bits code (string): result (int). result = (selection get-size-of-partition bits code). #print "$code:", (self get-num-taken-from-partition bits code), "/ $result". #print code,",size:",result,",same:",(selection get-same-level-partitions partition code),",other:",(selection get-other-same-level-partitions partition code),",support:",(selection get-support-partitions partition code),",support size:",(selection get-available-support-size partition code). #print (selection get-categorized-support-partitions level-of code). return result. + to get-num-taken-from-partition bits code (string): return (selection get-num-taken bits code). + to add-partition-log-objects bits num = -1 (int) code code = "" (string): if (num == -1) : { # Start if (commandline bit-param named "pareto-front-first") : { log add-log-object named "PartitionSize" with-args { "front" } inputs additional-input-info. log add-log-object named "PartitionTaken" with-args { "front" } inputs additional-input-info. } if (commandline bit-param named "anti-duplicate-partition") : { log add-log-object named "PartitionSize" with-args { "anti-duplicate" } inputs additional-input-info. log add-log-object named "PartitionTaken" with-args { "anti-duplicate" } inputs additional-input-info. } self add-partition-log-objects bits ( |fitness-info-list| ). } else if (num == 0) : { # Base case log add-log-object named "PartitionSize" with-args { code } inputs additional-input-info. log add-log-object named "PartitionTaken" with-args { code } inputs additional-input-info. } else { # Recursive case self add-partition-log-objects bits (num - 1) code "0$code". self add-partition-log-objects bits (num - 1) code "1$code". } # Initialization + to get-fitness-goals: i (int). goals (list). goals = {}. for i = 0, i < |fitness-info-list|, i++ : { push (fitness-info-list{i}{SLOT_GOAL}) onto goals. } #print "Goals: $goals". return goals. + to include-fitness named fitness (string) on-or-off use-objective = 1 (int): i (int). push 0 onto pending-goal-increases. for i = 0, i < |excluded-fitnesses|, i++ : { if (fitness == excluded-fitnesses{i}) : { print "Fitness $fitness is being excluded.". return 0. } } push (log include-fitness named fitness on-or-off use-objective) onto fitness-info-list. #SMEG: put in Console.tz + to print-details: i (int). print "". print "Log objects:". for i = 0, i < |loaded-log-objects|, i++ : { print loaded-log-objects{i},"{",loaded-log-args{i},"}". } print "". print "Fitness:". for i = 0, i < |fitness-info-list|, i++ : { print fitness-info-list{i}{SLOT_DISPLAY_LABEL}. } print "". print "Inputs:". for i = 0, i < |additional-input-info|, i++ : { if (additional-input-info{i}{INPUT_SLOT_USE} == INPUT_ON) : { print (additional-input-info{i}{INPUT_SLOT_METHOD}), (additional-input-info{i}{INPUT_SLOT_ARGS}), (additional-input-info{i}{INPUT_SLOT_RANGE}). } } # fitness: name of valid fitness objective + to exclude-fitness named fitness (string) : push fitness onto excluded-fitnesses. print "Excluding fitness: ", excluded-fitnesses{ (|excluded-fitnesses| - 1) }. + to process-command-line-args: i (int). arg (string). key (string). hashEntry (list). tempDouble (double). tempList (list). tempInt (int). tempString (string). tempString2 (string). brainPath (string). brainFile (string). command-line-string-options (hash). command-line-numeric-options (hash). command-line-on-off-options (hash). command-line-list-options (hash). command-line-string-options = (commandline get-command-line-string-options). command-line-numeric-options = (commandline get-command-line-numeric-options). command-line-on-off-options = (commandline get-command-line-on-off-options). command-line-list-options = (commandline get-command-line-list-options). evolution-mode = new EvolutionModeArbitrator. for i = 1, i < (self get-argument-count), i++ : { arg = (self get-argument at-index i). if (arg == "h") || (arg == "help") : { # Force the io off commandline assign-command-line-on-off-val of "off" to "io". print "". foreach key in keys( command-line-string-options ): { hashEntry = command-line-string-options{key}. print hashEntry{COMMAND_LINE_COMMAND},"<$key>: default =",hashEntry{COMMAND_LINE_VAL}. } print "". foreach key in keys( command-line-numeric-options ): { hashEntry = command-line-numeric-options{key}. print hashEntry{COMMAND_LINE_COMMAND},"<$key>: default =",hashEntry{COMMAND_LINE_VAL}. } print "". foreach key in keys( command-line-on-off-options ): { hashEntry = command-line-on-off-options{key}. tempDouble = hashEntry{COMMAND_LINE_VAL}. print hashEntry{COMMAND_LINE_COMMAND},":",hashEntry{COMMAND_LINE_EXPLAIN},(commandline to-on-off of tempDouble). } print "". foreach key in keys( command-line-list-options ): { hashEntry = command-line-list-options{key}. print hashEntry{COMMAND_LINE_COMMAND},"<$key>: default =",hashEntry{COMMAND_LINE_VAL}. } print "". print "l , load ". print "brain-pool ". print "resume ". print "ef ". print "ls ". print "r (record a movie from the start of the simulation)". print "emode (defines evolution mode used)". print "d ". print "". self end-simulation. return. } else if (commandline num-arg named arg) : { i++. commandline assign-command-line-numeric-val of (self get-argument at-index i) to arg. } else if (commandline string-arg named arg) : { i++. commandline assign-command-line-string-val of (self get-argument at-index i) to arg. } else if (commandline bit-arg named arg) : { i++. commandline assign-command-line-on-off-val of (self get-argument at-index i) to arg. } else if (commandline list-arg named arg) : { i++. tempList = {}. tempString = (self get-argument at-index i). i++. tempString2 = (self get-argument at-index i). while tempString2 != "end" : { if tempString == "string" : { push ":$tempString2" onto tempList. } else if tempString == "int" : { tempInt = tempString2. push tempInt onto tempList. } else if tempString == "double" : { tempDouble = tempString2. push tempDouble onto tempList. } i++. tempString2 = (self get-argument at-index i). } commandline assign-command-line-list-val of tempList to arg. } else if (arg == "ef") : { i++. self exclude-fitness named (self get-argument at-index i). } else if (arg == "d") : { i++. # Write a settings file with the current default settings write-settings-and-exit = 1. settings-path = (self get-argument at-index i). i++. settings-file = (self get-argument at-index i). } else if (arg == "ls") : { # Load Settings from file i++. netIO load-settings from (self get-argument at-index i) fitnesses loaded-fitnesses inputs loaded-inputs input-args loaded-input-args input-ranges loaded-input-ranges commandline-options commandline log-objects loaded-log-objects log-args loaded-log-args. command-line-string-options = (commandline get-command-line-string-options). command-line-numeric-options = (commandline get-command-line-numeric-options). command-line-on-off-options = (commandline get-command-line-on-off-options). command-line-list-options = (commandline get-command-line-list-options). } else if (arg == "l") || (arg == "load") || (arg == "resume") : { load = 1. if (arg == "resume") : (resume-helper signal-resume). i++. inputPath = (self get-argument at-index i). self set-last-path-saved to inputPath. i++. inputFiles = (self get-argument at-index i). self set-last-file-saved to inputFiles. print "Loading $inputPath/$inputFiles". } else if (arg == "brain-pool") : { i++. brainPath = (self get-argument at-index i). commandline assign-command-line-string-val of brainPath to "bpp". i++. brainFile = (self get-argument at-index i). commandline assign-command-line-string-val of brainFile to "bps". print "Filling brain-pool from $brainPath/$brainFile". } else if (arg == "r") || (arg == "record") : { file-path = (commandline string-param named "file-path"). i++. movieName = (self get-argument at-index i). # Force the floor to display whenever recording a movie commandline assign-command-line-on-off-val of "on" to "floor". # Force the display text to be hidden whenever recording a movie commandline assign-command-line-on-off-val of "on" to "ht". print "Recording movies". #movie = new Movie. #movie record to "$file-path/$movieName.mpg". } else if (arg == "emode") : { i++. evolution-mode load-evolution-mode named (self get-argument at-index i). evolution-mode load-settings using commandline. } else { print "Argument \"$arg\" not recognized". self end-simulation. return. } } commandline finish-with-commandline. + to initialize-globals: sample-desired = 0. last-pareto-front-size = 0. use-shaping = 0. skip-trial = 0. user-save = 0. user-end = 0. current-iteration = 0. stagnation-counter = 0. home-stretch-counter = 0. home-stretch = 0. strategy-switches = 0. deaths = 0. phase = 0. generation = 0. current-eval = 0. kills-last-gen = 0. user-increase-challenge = 0. pending-goal-increases = {}. current-population = POPULATION_PARENTS. math = new Math3D. resume-helper = new Resume. commandline = new CommandLineHandler. triangulate = new Triangulate. triangulate give-math of math. netIO = new NetIO. list-ops = new Lists. excluded-fitnesses = {}. load = 0. overwrite-log = 0. movieName = "". + to determine-auto-resume-status: if (commandline bit-param named "file-output") : { # Check for auto-resume file # if it exists, set up a resume. Else, create the file and proceed normally if ((commandline string-param named "auto-resume") != "") : { print "Auto-resume on using resume file ",(commandline string-param named "auto-resume"). # Set up resume if (self file-exists named (commandline string-param named "auto-resume")) : { resume-helper read-auto-resume-info. if ((commandline string-param named "last-file-saved") != "") : { print "Last save: ", (commandline string-param named "last-file-saved"). load = 1. resume-helper signal-resume. inputPath = (commandline string-param named "last-path-saved"). self set-last-path-saved to inputPath. inputFiles = (commandline string-param named "last-file-saved"). self set-last-file-saved to inputFiles. print "Auto-resuming $inputPath/$inputFiles". overwrite-log = 1. } else if ((commandline string-param named "last-file-saved") == "") : { print "Nothing to automatically resume from yet". overwrite-log = 1. } } else { # Write file and continue as normal print "Creating Resume File.". resume-helper create-auto-resume-file named (commandline string-param named "auto-resume"). } } else { print "No auto-resume". } } + to initialize-commandline-dependent-globals: tempList (list). multinetworks = (commandline bit-param named "separate-networks-per-task"). eval-limit = (commandline num-param named "eval-limit"). player-shoots = (commandline bit-param named "player-shoots"). recency-weighted-alpha = (commandline num-param named "recency-weighted-alpha"). drop-defeated = (commandline bit-param named "targeting-unachieved-goals"). partition-tug = (commandline bit-param named "partition-tug"). long-term-averaging = (commandline bit-param named "long-term-averaging"). goals-as-constraints = (commandline bit-param named "constraint-based-tug"). file-output = (commandline bit-param named "file-output"). homogeneous = (commandline bit-param named "homogeneous"). behavior-diversity = (commandline bit-param named "use-behavior-diversity-fitness"). random-behavior-syllabus = (commandline bit-param named "random-behavior-syllabus"). observed-behavior-syllabus = (commandline bit-param named "observed-behavior-syllabus"). stay-bound = (commandline bit-param named "stay-bound"). early-termination = (commandline bit-param named "early-termination"). hide-text = (commandline bit-param named "hide-text"). file-path = (commandline string-param named "file-path"). experiment-theme = (commandline string-param named "name"). subpop-size = (commandline num-param named "subpop-size"). number-of-subpops = (commandline num-param named "number-of-subpops"). monsters-from-each-subpop = (commandline num-param named "monsters-from-each-subpop"). children-per-parent = (commandline num-param named "children-per-parent"). tempList = (commandline list-param named "task-set"). current-game-mode = tempList{0}. previous-strategy = (commandline num-param named "player-strategy"). # SMEG: Why is this class here? graphics = new GraphicsHandler. + to validity-check-on-commandline-parameters: if ((subpop-size % monsters-from-each-subpop) != 0) && (homogeneous == 0) : { print "subpop-size must be divisible by monsters-from-each-subpop.". self end-simulation. return. } if ((commandline bit-param named "keep-parents") == COMMAND_LINE_OFF) && (children-per-parent <= 1) : { print "children-per-parent must be greater than 1 if parents are not kept.". self end-simulation. return. } if (((commandline num-param named "new-nn-mode-rate") == 0.0) && ((commandline num-param named "num-network-modes") <= 1)) : { #if (commandline bit-param named "track-mode-usage") : #{ # print "No point tracking mode usage with only one mode per network.". # self end-simulation. # return. #} if ( (commandline bit-param named "inverse-usage-proportionate-mode-deletion") || (commandline bit-param named "delete-underused-modes")) : { print "Mode deletion has no point unless mode mutation is possible.". self end-simulation. return. } } if !(commandline bit-param named "new-modes-random-source") && !(commandline bit-param named "connect-inputs-on-mode-mutation") && ( (commandline bit-param named "inverse-usage-proportionate-mode-deletion") || (commandline bit-param named "delete-underused-modes") ) : { print "Cannot use mode deletion unless initial inputs to new modes come from hidden and/or input layers only.". self end-simulation. return. } + to initialize-genetic-algorithm-settings: ga = new FreeNetGA. ga set-innovation-counter to (commandline num-param named "starting-innovation-number"). ga set-id-counter to (commandline num-param named "starting-network-id-number"). + to initialize-tasks-list: tempList (list). i (int). tempList = (commandline list-param named "task-set"). tasks = {}. for i = 0, i < |tempList|, i++ : { # TASK_DIVERSITY_UNKNOWN is now deprecated push ( {tempList{i}, 0, TASK_DIVERSITY_UNKNOWN} ) onto tasks. } + to initialize-num-evals: num-evals = |tasks| * (commandline num-param named "start-evals"). if homogeneous : num-evals *= subpop-size. else num-evals *= (subpop-size / monsters-from-each-subpop). print "Number of evals per generation = $num-evals". self reset-shuffle-offset. + to init: i (int). j (int). k (int). log-objects (list). temp (string). temp2 (string). tempInt (int). tempList1 (list). tempList2 (list). tempList3 (list). fighting-mode (int). predation (int). as-prey (int). ramming (int). back-ramming (int). with-ball (int). unit-test (object). shaping-fitnesses (list). print "########### New Simulation Run ###########". write-settings-and-exit = 0. settings-file = "". settings-path = "". # Save memory self disable-freed-instance-protection. self initialize-globals. loaded-log-args = {}. loaded-log-objects = {}. loaded-fitnesses = {}. loaded-inputs = {}. loaded-input-args = {}. loaded-input-ranges = {}. self process-command-line-args. if (commandline bit-param named "unit-tests") : { unit-test = new UnitTest. unit-test run-tests. self end-simulation. return. } else { # Load ensemble brain pool if ( ((commandline string-param named "brain-pool-path") != "") && ((commandline string-param named "brain-pool-save") != "") ) : { brain-pool = new BrainPool. #SMEG: Do unit tests for this brain-pool load-brain-pool loader netIO from-path (commandline string-param named "brain-pool-path") files (commandline string-param named "brain-pool-save"). } self determine-auto-resume-status. # load from file if load : { loaded-log-objects = {}. loaded-log-args = {}. loaded-fitnesses = {}. loaded-inputs = {}. loaded-input-args = {}. loaded-input-ranges = {}. netIO load-settings from "$inputPath/$inputFiles" fitnesses loaded-fitnesses inputs loaded-inputs input-args loaded-input-args input-ranges loaded-input-ranges commandline-options commandline log-objects loaded-log-objects log-args loaded-log-args. print "". # command line should override file settings, unless resuming if !(resume-helper is-resuming) : self process-command-line-args. } self initialize-commandline-dependent-globals. self validity-check-on-commandline-parameters. self initialize-genetic-algorithm-settings. # End command line arguments # SMEG: put code for setting experiment-theme in separate method # Augment output file name if (commandline bit-param named "use-z-scores") : experiment-theme = "-Z$experiment-theme". self initialize-tasks-list. for i = 0, i < |tasks|, i++ : { if (tasks{i}{TASK_SLOT_TASK} == MODE_FIGHT) : experiment-theme = "Fight$experiment-theme". else if (tasks{i}{TASK_SLOT_TASK} == MODE_PRED) : experiment-theme = "Pred$experiment-theme". else if (tasks{i}{TASK_SLOT_TASK} == MODE_PREY) : experiment-theme = "Prey$experiment-theme". else if (tasks{i}{TASK_SLOT_TASK} == MODE_BALL) : experiment-theme = "Ball$experiment-theme". else if (tasks{i}{TASK_SLOT_TASK} == MODE_RAM) : experiment-theme = "Ram$experiment-theme". else if (tasks{i}{TASK_SLOT_TASK} == MODE_BACKRAM) : experiment-theme = "BackRam$experiment-theme". } # Starting network type if (load) && !(resume-helper is-resuming) : temp = "-Load". else if (commandline bit-param named "fs-net") : temp = "-Blank". else temp = "-Full". experiment-theme = "$experiment-theme$temp". temp = "". if (commandline bit-param named "use-z-scores") : selection = new ZScoresGA. else { if goals-as-constraints : { selection = new CTUG-NSGA2. } else if partition-tug : { selection = new PartTUG-NSGA2. } else { selection = new NSGA2. } tempList1 = (commandline list-param named "preferred-point"). if ( |tempList1| > 0 ) : { selection set-preferred-point to tempList1. selection set-last-front-selection to LAST_FRONT_RANK_PREFERENCE_POINT. } tempList1 = {}. if (commandline num-param named "alpha-dominance") > 0.0 : { selection set-alpha to (commandline num-param named "alpha-dominance"). } } selection set-generation to (commandline num-param named "ending-generation"). if (resume-helper is-resuming) : { print "Drop name $experiment-theme due to resume". experiment-theme = (commandline string-param named "experiment-theme"). experiment-theme = "R-$experiment-theme". print "Go with $experiment-theme instead". } else if (evolution-mode ask-has-mode) : { temp = evolution-mode get-name. temp2 = "-". experiment-theme = "$temp$temp2$experiment-theme". } temp = "". temp2 = "". commandline set-string-param named "experiment-theme" to experiment-theme. free evolution-mode. # Game mode self initialize-num-evals. tempInt = subpop-size * number-of-subpops. print "Num unique brains per population = $tempInt". # Create the environment. # 0 and 1 result in the same run. Adding 1 offsets this self set-random-seed to ((commandline num-param named "random-seed") + 1 + (commandline num-param named "random-seed-offset")). # SMEG:put in Environment.tz if (commandline bit-param named "use-walls") : self make-walls. if (commandline bit-param named "use-power-ups") : self place-powerups. triangulate fill-theta-starts with-sub-pops number-of-subpops monsters-per-sub monsters-from-each-subpop. # Create the Player. self spawn-player. # Setup GA self zero-scores. # The initial change to game mode will set this to 0 current-population-num = subpop-size - 1. fighting-mode = 0. predation = 0. as-prey = 0. with-ball = 0. ramming = 0. back-ramming = 0. for i = 0, i < |tasks|, i++ : { if (tasks{i}{TASK_SLOT_TASK} == MODE_FIGHT) : fighting-mode = 1. else if (tasks{i}{TASK_SLOT_TASK} == MODE_PRED) : predation = 1. else if (tasks{i}{TASK_SLOT_TASK} == MODE_PREY) : as-prey = 1. else if (tasks{i}{TASK_SLOT_TASK} == MODE_BALL) : with-ball = 1. else if (tasks{i}{TASK_SLOT_TASK} == MODE_RAM) : ramming = 1. else if (tasks{i}{TASK_SLOT_TASK} == MODE_BACKRAM) : back-ramming = 1. } log = new Log. log set-path to file-path. netIO set-file-path to file-path. # Set fitness objectives fitness-info-list = {}. shaping-fitnesses = (commandline string-list-param named "fitness-shaping"). if |shaping-fitnesses| > 0 : { use-shaping = 1. print "". print "Shaping on fitness objectives.". for i = 0, i < |shaping-fitnesses|, i++ : { if (shaping-fitnesses{i} == "BehavioralDiversity") : diversity-fitness-index = |fitness-info-list|. self include-fitness named shaping-fitnesses{i}. if (i <= (commandline num-param named "index-of-last-shaping-objective-added")) : fitness-info-list{i}{SLOT_USE_OBJECTIVE} = FITNESS_OBJECTIVE_ON. else fitness-info-list{i}{SLOT_USE_OBJECTIVE} = FITNESS_OBJECTIVE_OFF. } } else if |loaded-fitnesses| > 0 : { print "". print "Loading fitnesses from save file.". for i = 0, i < |loaded-fitnesses|, i++ : { if (loaded-fitnesses{i}{LOAD_FITNESS_LABEL} == "BehavioralDiversity") : diversity-fitness-index = |fitness-info-list|. self include-fitness named (loaded-fitnesses{i}{LOAD_FITNESS_LABEL}) on-or-off (loaded-fitnesses{i}{LOAD_FITNESS_USE_OBJECTIVE}). fitness-info-list{ (|fitness-info-list| - 1) }{SLOT_GOAL} = loaded-fitnesses{i}{LOAD_FITNESS_GOAL}. } } else { if fighting-mode : { (self include-fitness named "FightAssist"). (self include-fitness named "FightGroup"). (self include-fitness named "FightInflicted"). } if ramming : { (self include-fitness named "RamGroup"). } if back-ramming : { (self include-fitness named "BackRamGroup"). } if predation : { (self include-fitness named "PredAssist"). (self include-fitness named "PredGroup"). (self include-fitness named "PredInflicted"). } if as-prey : (self include-fitness named "PreyReceived"). if fighting-mode : (self include-fitness named "FightReceived"). if ramming : (self include-fitness named "RamReceived"). if back-ramming : (self include-fitness named "BackRamReceived"). if predation && stay-bound && (commandline bit-param named "use-pred-confined-time") : { (self include-fitness named "PredTimeConfined"). } if as-prey : (self include-fitness named "PreyAlive"). if fighting-mode : (self include-fitness named "FightAlive"). if ramming : (self include-fitness named "RamAlive"). if back-ramming : (self include-fitness named "BackRamAlive"). if with-ball : { (self include-fitness named "BallGoalTime"). (self include-fitness named "BallGoalDistance"). } if (commandline bit-param named "random-fitness") : self include-fitness named "Random". if (commandline bit-param named "anti-bloat-fitness") : self include-fitness named "AntiBloat". if (commandline bit-param named "mode-restricting-fitness") : self include-fitness named "ModeRestrict". if (commandline bit-param named "unused-mode-restricting-fitness") : self include-fitness named "UnusedModeRestrict". if behavior-diversity : { diversity-fitness-index = |fitness-info-list|. self include-fitness named "BehavioralDiversity". } } if partition-tug : selection set-objective-goals to (self get-fitness-goals). # Reclaim space free excluded-fitnesses. excluded-fitnesses = {}. self reset-fitness-averages. if (resume-helper is-resuming): # Remember previous averages { tempList1 = commandline list-param named "previous-fitness-average-averages". print "tempList1=", tempList1. tempList2 = commandline list-param named "previous-fitness-best-averages". print "tempList2=", tempList2. tempList3 = commandline list-param named "previous-achieving-percentage-aves". print "tempList3=", tempList3. for i = 0, i < |fitness-info-list|, i++ : { fitness-info-list{i}{SLOT_CURRENT_AVE_AVE} = tempList1{i}. fitness-info-list{i}{SLOT_BEST_AVE} = tempList2{i}. fitness-info-list{i}{SLOT_PERCENT_ACHIEVING_GOAL_AVE} = tempList3{i}. } } if behavior-diversity || (commandline bit-param named "restrict-similar-modes") : { behavior-state = new BehaviorState. behavior-state give-commandline this commandline. } self blank-current-fitnesses. # Set up monsters additional-input-info = {}. if |loaded-inputs| > 0 : { print "". print "Loading inputs from save file.". for i = 0, i < |loaded-inputs|, i++ : { # Backwards compatibility if (i >= |loaded-input-args|) : push {} onto loaded-input-args. if (i >= |loaded-input-ranges|) : push {} onto loaded-input-ranges. push { (loaded-inputs{i}), INPUT_ON, (loaded-input-args{i}), (loaded-input-ranges{i}) } onto additional-input-info. } } else { if ((commandline bit-param named "sensor-array-only") == COMMAND_LINE_OFF) : { if (commandline bit-param named "sense-task") : { if (fighting-mode) : push {"mode-is",INPUT_ON,{ MODE_FIGHT },{}} onto additional-input-info. if (predation) : push {"mode-is",INPUT_ON,{ MODE_PREY },{}} onto additional-input-info. if (as-prey) : push {"mode-is",INPUT_ON,{ MODE_PRED },{}} onto additional-input-info. if (with-ball) : push {"mode-is",INPUT_ON,{ MODE_BALL },{}} onto additional-input-info. if (ramming) : push {"mode-is",INPUT_ON,{ MODE_RAM },{}} onto additional-input-info. if (back-ramming) : push {"mode-is",INPUT_ON,{ MODE_BACKRAM },{}} onto additional-input-info. } if (commandline bit-param named "bias-senses") : { push {"get-bias",INPUT_ON,{},{}} onto additional-input-info. } push {"get-diff-from-player-heading",INPUT_ON,{},{PI}} onto additional-input-info. push {"get-angle-to-player",INPUT_ON,{},{PI}} onto additional-input-info. if with-ball : { push {"get-angle-to-goal",INPUT_ON,{},{PI}} onto additional-input-info. push {"get-angle-difference-between-ball-and-goal",INPUT_ON,{},{PI}} onto additional-input-info. push {"get-comparative-goal-player-distance",INPUT_ON,{},{LONG_DISTANCE_TO_GOAL}} onto additional-input-info. } if (commandline bit-param named "group-awareness") : { if (fighting-mode || as-prey) : push {"get-yelp-of-pain",INPUT_ON,{},{}} onto additional-input-info. if (fighting-mode || predation) : push {"get-shout-of-encouragement",INPUT_ON,{},{}} onto additional-input-info. } if (fighting-mode || predation) : push {"is-player-locked",INPUT_ON,{},{}} onto additional-input-info. if (commandline bit-param named "close-player-senses") : { push {"get-close-player-impulse",INPUT_ON,{},{}} onto additional-input-info. push {"get-very-close-player-impulse",INPUT_ON,{},{}} onto additional-input-info. } if (commandline bit-param named "anyone-close-senses") : { # TODO: add close senses for the goal push {"get-anyone-close-to-player",INPUT_ON,{},{}} onto additional-input-info. push {"get-anyone-very-close-to-player",INPUT_ON,{},{}} onto additional-input-info. } if (commandline bit-param named "player-front-sensor") : { push {"in-front-of-player",INPUT_ON,{},{}} onto additional-input-info. } if (commandline bit-param named "personal-awareness") : { if (fighting-mode || as-prey) : push {"get-just-hit",INPUT_ON,{},{}} onto additional-input-info. if (fighting-mode || predation) : push {"get-just-ate",INPUT_ON,{},{}} onto additional-input-info. } if fighting-mode : { push {"get-close-sword-impulse",INPUT_ON,{},{}} onto additional-input-info. push {"get-very-close-sword-impulse",INPUT_ON,{},{}} onto additional-input-info. } # Rarely used if (commandline bit-param named "facing-senses") : { push {"get-facing-player",INPUT_ON,{},{}} onto additional-input-info. push {"get-player-facing-me",INPUT_ON,{},{}} onto additional-input-info. } if (commandline bit-param named "distance-senses") : { push {"get-delta-player-distance",INPUT_ON,{},{MIN_GOAL_BUFFER}} onto additional-input-info. push {"get-distance-from-player",INPUT_ON,{},{LONG_DISTANCE_TO_GOAL}} onto additional-input-info. } if MONSTERS_INTERACT : { push {"get-just-bumped",INPUT_ON,{},{}} onto additional-input-info. } if MONSTERS_INTERACT || (commandline bit-param named "teamwork") : { push {"get-close-monster-impulse",INPUT_ON,{},{}} onto additional-input-info. push {"get-very-close-monster-impulse",INPUT_ON,{},{}} onto additional-input-info. push {"get-right-side-monster-impulse",INPUT_ON,{},{}} onto additional-input-info. push {"get-left-side-monster-impulse",INPUT_ON,{},{}} onto additional-input-info. } #push {"flanking-player",INPUT_ON,{},{}} onto additional-input-info. #if (commandline bit-param named "personal-awareness") : push {"get-energy",INPUT_ON,{},{MONSTER_START_ENERGY}} onto additional-input-info. # Communication if (commandline bit-param named "index-based-senses") : { for i = 0, i < (number-of-subpops * monsters-from-each-subpop), i++ : { push {"get-heading-diff-to-teammate",INPUT_ON,{i},{PI}} onto additional-input-info. push {"get-relative-angle-to-teammate",INPUT_ON,{i},{PI}} onto additional-input-info. push {"get-teammate-just-ate",INPUT_ON,{i},{}} onto additional-input-info. #TODO: consider using these again #push {"get-close-to-monster",INPUT_ON,{i},{}} onto additional-input-info. #push {"get-very-close-to-monster",INPUT_ON,{i},{}} onto additional-input-info. #push {"get-close-player-impulse-of-teammate",INPUT_ON,{i},{}} onto additional-input-info. #push {"get-very-close-player-impulse-of-teammate",INPUT_ON,{i},{}} onto additional-input-info. } } if (commandline bit-param named "use-walls") : push {"get-facing-x",INPUT_ON,{},{}} onto additional-input-info. if (commandline bit-param named "use-walls") : push {"get-facing-z",INPUT_ON,{},{}} onto additional-input-info. if (commandline bit-param named "use-walls") : push {"facing-wall",INPUT_ON,{},{}} onto additional-input-info. if (commandline bit-param named "use-walls") : push {"back-to-wall",INPUT_ON,{},{}} onto additional-input-info. if (commandline bit-param named "use-walls") : push {"get-just-hit-wall",INPUT_ON,{},{}} onto additional-input-info. } if (commandline bit-param named "use-walls") : { for i = 0, i < (commandline num-param named "sensor-array-size"), i++ : { push {"get-wall-sensor",INPUT_ON,{i},{}} onto additional-input-info. } } if player-shoots : { push {"get-angle-nearest-bullet",INPUT_ON,{},{}} onto additional-input-info. for i = 0, i < (commandline num-param named "sensor-array-size"), i++ : { push {"get-bullet-sensor",INPUT_ON,{i},{}} onto additional-input-info. } } for i = 0, i < (commandline num-param named "sensor-array-size"), i++ : { push {"get-player-sensor",INPUT_ON,{i},{}} onto additional-input-info. } for i = 0, i < (commandline num-param named "sensor-array-size"), i++ : { push {"get-monster-sensor",INPUT_ON,{i},{}} onto additional-input-info. } if fighting-mode && (commandline bit-param named "stick-sensors") : { for i = 0, i < (commandline num-param named "sensor-array-size"), i++ : { push {"get-sword-sensor",INPUT_ON,{i},{}} onto additional-input-info. } } } # Initialize syllabus if random-behavior-syllabus : { behavior-state randomize-syllabus length (self get-num-sensors). } else if observed-behavior-syllabus : { behavior-state determine-observed-syllabus-sample-points. } if (write-settings-and-exit) : { netIO set-file-path to settings-path. netIO write-save-file with-identifier settings-file commandline-options commandline fitnesses fitness-info-list inputs additional-input-info logs log. print "Wrote settings to file $settings-path/$settings-file.save". self end-simulation. } else { if (load != 1) : { # 3 outputs for forward/backward movement and 3 for turning if (commandline bit-param named "action-selector-net") : { commandline set-num-param named "num-output-neurons" to OUTPUTS_ACTION_SELECTOR. } if (commandline bit-param named "predefined-network-modes") : { commandline set-num-param named "num-output-neurons" to ((commandline num-param named "num-output-neurons")*|tasks|). } else if (commandline num-param named "num-network-modes") > 1 : { commandline set-num-param named "num-output-neurons" to (((commandline num-param named "num-output-neurons") + 1) * (commandline num-param named "num-network-modes")). } } if (number-of-subpops * monsters-from-each-subpop) > 1 : { monsters = (number-of-subpops * monsters-from-each-subpop) new Monster. } else { monsters = {new Monster}. } mode-arbitrator = new ModeArbitrator. mode-arbitrator set-params command commandline. parent-brains = {}. child-brains = {}. type-trials-for-brains = {}. for i = 0, i < number-of-subpops, i++ : { push {} onto type-trials-for-brains. push {} onto parent-brains. push {} onto child-brains. for j = 0, j < subpop-size, j++ : { #SMEG: Generalize this # the six 0s correspond to the 6 possible modes so far: Fight, Pred, Prey, Ball, Ram. BackRam push {0,0,0,0,0,0} onto (type-trials-for-brains{i}). push (ga new-starting-brain) onto (parent-brains{i}). for k = 0, k < children-per-parent, k++ : { push {} onto (child-brains{i}). } } } self give-monsters-starting-brains from parent-brains. # Load Population if load : { (self load-population from-path inputPath files inputFiles type "parents"). if (netIO get-unloaded-networks) : { print "The loaded population is fewer networks than supported by the simulation settings". eval-limit = |tasks| * (commandline num-param named "start-evals"). if homogeneous : eval-limit *= (netIO get-num-loaded-networks). else eval-limit *= ((netIO get-num-loaded-networks) / monsters-from-each-subpop). print "Therefore the simulation will terminate after $eval-limit evals". } } # Prepare log log-objects = {}. if (|loaded-log-objects| > 0) : { for i = 0, i < |loaded-log-objects|, i++ : { log add-log-object named (loaded-log-objects{i}) with-args (loaded-log-args{i}) inputs additional-input-info. } } else { log add-log-object named "Generation" with-args {} inputs additional-input-info. if (predation) : { log add-log-object named "AveGroupPredScore" with-args {} inputs additional-input-info. } if (as-prey) : { log add-log-object named "AvePlayerPreyScore" with-args {} inputs additional-input-info. } if fighting-mode : { log add-log-object named "AveGroupFightScore" with-args {} inputs additional-input-info. log add-log-object named "AvePlayerFightScore" with-args {} inputs additional-input-info. } if ramming : { log add-log-object named "AveGroupRamScore" with-args {} inputs additional-input-info. log add-log-object named "AvePlayerRamScore" with-args {} inputs additional-input-info. } if back-ramming : { log add-log-object named "AveGroupBackRamScore" with-args {} inputs additional-input-info. log add-log-object named "AvePlayerBackRamScore" with-args {} inputs additional-input-info. } if (commandline bit-param named "task-progression") : { log add-log-object named "Strategy" with-args {} inputs additional-input-info. } else { log add-log-object named "Speed" with-args {} inputs additional-input-info. } log add-log-object named "ParetoFrontSize" with-args {} inputs additional-input-info. log add-log-object named "SuccessfulIndividuals" with-args {} inputs additional-input-info. if ((commandline num-param named "new-nn-mode-rate") > 0.0) : { log add-log-object named "AverageOutputModes" with-args {} inputs additional-input-info. log add-log-object named "MaxOutputModes" with-args {} inputs additional-input-info. log add-log-object named "MinOutputModes" with-args {} inputs additional-input-info. } log add-log-object named "AverageParentAge" with-args {} inputs additional-input-info. log add-log-object named "MaxParentAge" with-args {} inputs additional-input-info. log add-log-object named "MinParentAge" with-args {} inputs additional-input-info. if ( |(commandline list-param named "preferred-point")| > 0 ) : { log add-log-object named "MinPrefPointDistance" with-args {} inputs additional-input-info. } if (commandline bit-param named "track-mode-usage") : { log add-log-object named "AvePercentModeUsage" with-args {} inputs additional-input-info. } log add-log-object named "TotalNodes" with-args {} inputs additional-input-info. for i = 0, i < |additional-input-info|, i++ : { log add-log-object named "InputUsage" with-args {i} inputs additional-input-info. } log add-log-object named "RatioChildren" with-args {} inputs additional-input-info. log add-log-object named "GoalIncrease" with-args {} inputs additional-input-info. if (commandline bit-param named "promote-solutions-if-variance-allows") : { log add-log-object named "Promotions" with-args {} inputs additional-input-info. } if partition-tug : { self add-partition-log-objects. #for i = 0, i < |partition-log-objects|, i++ : { # push (partition-log-objects{i}) onto log-objects. #} } } # Log objects now added directly #log assign-log-list of log-objects. if file-output : { #while (log log-file-exists with-file "$file-path/$experiment-theme.txt") && !overwrite-log : while (self file-exists named "$file-path/$experiment-theme.txt") && !overwrite-log : { print "$file-path/$experiment-theme.txt already exists". if (resume-helper is-resuming) : { experiment-theme = "R-$experiment-theme". print "Changing theme to $experiment-theme". } else { print "Log file already exists: $file-path/$experiment-theme.txt : terminating simulation". controller end-simulation. return. } } if overwrite-log : { print "Overwriting log because there was no useful info yet". } log write-headers using fitness-info-list to-file experiment-theme. } if (resume-helper is-resuming): { log copy-previous-file named (commandline string-param named "resume-file") to-file experiment-theme. print "Resuming previous experiment". #if (commandline bit-param named "progress-on-resume") : #{ # self increase-challenge. # print "Increasing the challenge". # commandline set-bit-param named "progress-on-resume" to COMMAND_LINE_OFF. #} } # Overwrite resume-file after copying over or set for first time self set-resume-file. log reset-log-averages. if ((load == 0) || (resume-helper is-resuming)) && (commandline bit-param named "task-progression") : { self set-speed-difficulty to 1.0. } # Start game self move-light to (0, 1000, 0). self set-display-text-scale to 0.4. self print-details. current-game-mode-counter = 0. self switch-current-game-mode. #Fence-post for movie recording if (movieName != "") : { movie = new Movie. movie record to "$file-path/$movieName.$current-eval.task$current-game-mode.mpg". print "recording: $file-path/$movieName.$current-eval.task$current-game-mode.mpg". } if (commandline bit-param named "HUD") : { myHUD = new HUD. myHUD set-fov with-width (commandline num-param named "hud-dimension") with-height (commandline num-param named "hud-dimension") at-orgin-x 1 at-orgin-y 1 at-distance 4. if (commandline bit-param named "focus-on-network-view") : { myHUD set-location to (0, 0, 0). myHUD set-viewdistance to VIEW_DISTANCE. myHUD track-object from (0, 10, -10). } else { myHUD set-location to (0,VIEW_HEIGHT,0). myHUD set-viewdistance to VIEW_DISTANCE. myHUD track-object. } } if (commandline bit-param named "focus-on-network-view") || (commandline bit-param named "HUD") : { view = new NetViewer. self draw-net net (monsters{0} extract-genome). } free loaded-log-objects. free loaded-log-args. free loaded-fitnesses. free loaded-inputs. free loaded-input-args. free loaded-input-ranges. loaded-log-objects = {}. loaded-log-args = {}. loaded-fitnesses = {}. loaded-inputs = {}. loaded-input-args = {}. loaded-input-ranges = {}. } # Create the Player again for proper sync self spawn-player. } + to get-current-game-mode-counter: if (current-game-mode-counter == 0) : return (|tasks| - 1). else return (current-game-mode-counter - 1). + to get-real-num-evals: if current-population == POPULATION_PARENTS : return num-evals. else return (num-evals * children-per-parent). + to get-generation: return (selection get-generation). # Maintains simulation display + to iterate: i (int). life (int). message-best (string). message-worst (string). message-avg (string). message-current (string). message-last (string). tempInt (int). tempDouble (double). temp (string). groupInt (int). playerInt (int). extra-stats (string). real-num-evals (int). monster-sample (int). living-indexes (list). current-monster-scores (list). last-monster-scores (list). if interaction-occurred : { steps-since-interaction = 0. interaction-occurred = 0. } steps-since-interaction++. # Only gather sample inputs during parent phase if current-population == POPULATION_PARENTS : { # If gathering input observations to form a behavior syllabus on this particular eval if sample-desired || (observed-behavior-syllabus && (behavior-state get-current-sample-eval) == current-eval) : { # Signal that a sample is desired at some point during this evaluation. # This simplifies the remainder of checks during this evaluation, and assures # that early termination of the evaluation does not result in a missing # sample. sample-desired = 1. # If the given time step of this eval was also chosen to be sampled if ( (behavior-state get-current-sample-time) == current-iteration ) : { # Find out which monsters are alive living-indexes = {}. for i = 0, i < |monsters|, i++ : { if (monsters{i} get-deaths) == 0 : { push i onto living-indexes. } } # Make sure a living index exists if |living-indexes| > 0 : { # Pick a random living monster in team to sample from monster-sample = random[ (|living-indexes| - 1) ]. behavior-state add-syllabus inputs (monsters{(living-indexes{ monster-sample })} get-inputs). # A sample is no longer desired since one was successfully obtained. sample-desired = 0. } } } } current-iteration++. self update-neighbors. if !hide-text : { groupInt = group-score. playerInt = player-score. if player: life = (player get-energy). generation = (selection get-generation). if player: self set-display-text number 0 to "Life: $life Deaths: $deaths PlayerScore: [$playerInt][$ave-player-score] GroupScore: [$groupInt][$ave-group-score] Interact: $steps-since-interaction" at-x -0.2 at-y -.9. if current-population == POPULATION_PARENTS : temp = "Parents". else if current-population == POPULATION_CHILDREN : temp = "Children". extra-stats = "Population: $temp ($current-population-num) Stagnation: $stagnation-counter". real-num-evals = (self get-real-num-evals). self set-display-text number 1 to "Eval: $current-eval/$real-num-evals $extra-stats Generation: $generation Kills: $kills-last-gen Iteration: $current-iteration" at-x -0.2 at-y -.95. current-monster-scores = ((monsters{0} extract-genome) get-average-scores). last-monster-scores = (current-fitnesses{last-subpop-num}{last-pop-slot}). message-best = "". message-worst = "". message-avg = "". message-current = "". for i=0, i<|fitness-info-list|, i++ : { temp = fitness-info-list{i}{SLOT_DISPLAY_LABEL}. if (fitness-info-list{i}{SLOT_USE_OBJECTIVE} == FITNESS_OBJECTIVE_OFF) : temp = "OFF:$temp". message-best = "$message-best$temp: ". message-worst = "$message-worst$temp: ". message-avg = "$message-avg$temp: ". message-current = "$message-current$temp: ". message-last = "$message-last$temp: ". tempInt = fitness-info-list{i}{SLOT_CURRENT_BEST_FITNESS}. message-best = "$message-best$tempInt ". tempInt = fitness-info-list{i}{SLOT_CURRENT_WORST_FITNESS}. message-worst = "$message-worst$tempInt ". tempInt = fitness-info-list{i}{SLOT_CURRENT_AVE}. tempDouble = fitness-info-list{i}{SLOT_STDEV}. message-avg = "$message-avg$tempInt+/-$tempDouble ". if (|current-monster-scores| > i) : { tempInt = current-monster-scores{i}. message-current = "$message-current$tempInt ". } if (|last-monster-scores| > i) : { tempInt = last-monster-scores{i}. message-last = "$message-last$tempInt ". } } self set-display-text number 4 to "Best: $message-best" at-x -.95 at-y .95. self set-display-text number 2 to "Average: $message-avg" at-x -.95 at-y .90. self set-display-text number 5 to "Worst: $message-worst" at-x -.95 at-y .85. self set-display-text number 7 to "Current: $message-current" at-x -.95 at-y .80. self set-display-text number 3 to "Last: $message-last" at-x -.95 at-y .75. #if user-save: self set-display-text number 6 to "User Save" at-x -.95 at-y .85. #else self set-display-text number 6 to "" at-x -.95 at-y .85. } super iterate. if (current-iteration > (commandline num-param named "eval-iterations")) || (skip-trial) || (self all-monsters-dead) || ((current-game-mode == MODE_BALL) && goal && (goal goal-sunk)) || (early-termination && ((commandline num-param named "steps-wo-interaction") < steps-since-interaction)) || (stay-bound && (current-game-mode == MODE_PRED) && !(self player-is-surrounded)) : { skip-trial = 0. # If the evaluation ends before a desired sample was provided, # then settle for a sample from any monster (may be dead, or experiencing strange inputs) if sample-desired : { # Repeat process for however many samples were supposed to come from this eval while ((behavior-state get-current-sample-eval) == current-eval) : { # Adding a syllabus changes the current sample-eval behavior-state add-syllabus inputs (monsters{( random[ (|monsters| - 1) ] )} get-inputs). } # Samples obtained, so they are no longer desired. sample-desired = 0. } steps-since-interaction = 0. #print "END EVAL". self end-eval. } # Stats + to just-increased-goals: result (int). result = increase-all-goals. increase-all-goals = 0. return result. + to num-tasks: #print "There are ", |tasks|, " num tasks". return |tasks|. + to zero-scores: #increase-all-goals = 0. last-subpop-num = 0. last-pop-slot = 0. interaction-occurred = 0. steps-since-interaction = 0. ave-percent-mode-usage = 0.0. ave-group-score = 0.0. group-score = 0.0. ave-player-score = 0.0. player-score = 0.0. player-powerups = 0. ave-group-fight-score = 0.0. ave-group-ram-score = 0.0. ave-group-back-ram-score = 0.0. ave-group-pred-score = 0.0. ave-player-fight-score = 0.0. ave-player-ram-score = 0.0. ave-player-back-ram-score = 0.0. ave-player-prey-score = 0.0. num-successful = 0. self zero-trials. + to zero-trials: i (int). j (int). k (int). reps (int). reps = 1. if current-population == POPULATION_CHILDREN : reps = children-per-parent. # SMEG: Generalize # the six 0s correspond to the 6 possible modes so far: Fight, Pred, Prey, Ball, Ram, BackRam type-trials = {0,0,0,0,0,0}. type-trials-for-brains = {}. for i = 0, i < number-of-subpops, i++ : { push {} onto type-trials-for-brains. for j = 0, j < subpop-size, j++ : { for k = 0, k < reps, k++ : { # the six 0s correspond to the 6 possible modes so far: Fight, Pred, Prey, Ball, Ram, BackRam push {0,0,0,0,0,0} onto (type-trials-for-brains{i}). } } } + to blank-current-fitnesses: reps (int). reps = 1. if current-population == POPULATION_CHILDREN : reps = children-per-parent. free current-fitnesses. current-fitnesses = (list-ops list-of-blanks size1 number-of-subpops size2 subpop-size size3 reps). if (commandline bit-param named "track-mode-usage") : { free current-mode-usage. current-mode-usage = (list-ops list-of-blanks size1 number-of-subpops size2 subpop-size size3 reps). free current-mode-counts. current-mode-counts = (list-ops list-of-blanks size1 number-of-subpops size2 subpop-size size3 reps). } if behavior-diversity : { free current-behavior-vectors. current-behavior-vectors = (list-ops list-of-blanks size1 number-of-subpops size2 subpop-size size3 reps). } #SMEG: put in Fitnesses.tz + to get-fitness-variance objective i (int): N (double). N = 2.0 * (number-of-subpops * subpop-size). return ( (fitness-info-list{i}{SLOT_SUM_OF_SQUARES}) / (N - 1.0) ). #SMEG: put in Fitnesses.tz + to get-fitness-stdev objective i (int): variance (double). variance = (self get-fitness-variance objective i). return (sqrt(variance)). + to set-last-pareto-front-size to val (int): last-pareto-front-size = val. + to get-last-pareto-front-size: return last-pareto-front-size. + to get-num-successful: return num-successful. + to get-promotions: return (selection get-promotions). + to get-group-score: return group-score. + to get-ave-percent-mode-usage: return ave-percent-mode-usage. + to get-ave-group-score: return ave-group-score. + to get-ave-group-fight-score: return ave-group-fight-score. + to get-ave-group-ram-score: return ave-group-ram-score. + to get-ave-group-back-ram-score: return ave-group-back-ram-score. + to get-ave-group-pred-score: return ave-group-pred-score. + to get-ave-player-score: return ave-player-score. + to get-ave-player-fight-score: return ave-player-fight-score. + to get-ave-player-ram-score: return ave-player-ram-score. + to get-ave-player-back-ram-score: return ave-player-back-ram-score. + to get-ratio-children-in-new-pop: return ratio-children-in-new-pop. + to get-ave-player-prey-score: return ave-player-prey-score. + to get-player-strategy: return (commandline num-param named "player-strategy"). + to set-player-strategy to strat (int): commandline set-num-param named "player-strategy" to strat. + to get-total-free-nodes: return |(all FreeNode)|. + to sum-input-connectivity: i (int). j (int). k (int). current-connectivity (list). input-connectivity-sums = {}. for i = 0, i < |parent-brains|, i++ : { for j = 0, j < |parent-brains{i}|, j++ : { current-connectivity = (parent-brains{i}{j} get-input-connectivity). if |input-connectivity-sums| == 0 : { input-connectivity-sums = current-connectivity. } else { for k = 0, k < |input-connectivity-sums|, k++ : { input-connectivity-sums{k} += current-connectivity{k}. } } } } # Only call after sum-input-connectivity + to get-input-connectivity of index (int): return input-connectivity-sums{index}. + to get-average-num-net-modes: tempList (list). i (int). sum (double). current (int). max-num-net-modes = -INT_INFINITY. min-num-net-modes = INT_INFINITY. sum = 0. if multinetworks : { tempList = (all MultiNetwork). } else { tempList = (all FreeNetwork). } for i = 0, i < |tempList|, i++ : { if multinetworks : { current = (tempList{i} num-networks). } else { current = (mode-arbitrator get-num-output-modes-from-net network (tempList{i})). } max-num-net-modes = max(max-num-net-modes,current). min-num-net-modes = min(min-num-net-modes,current). sum += current. } return (sum / ( |tempList| )). + to get-min-age: return min-age. + to get-max-age: return max-age. + to get-ave-age: i (int). j (int). sum (double). current (int). total (double). max-age = -INT_INFINITY. min-age = INT_INFINITY. sum = 0. total = 0.0. for j=0, j<|parent-brains|, j++ : { for i=0, i<|parent-brains{j}|, i++ : { current = ((parent-brains{j}{i}) get-age). max-age = max(max-age,current). min-age = min(min-age,current). sum += current. total++. } } return (sum / total). + to get-max-num-net-modes: return max-num-net-modes. + to get-min-num-net-modes: return min-num-net-modes. + to get-min-preferred-point-distance: return (selection get-min-preferred-point-distance). # Game Mode + to get-current-game-mode: return current-game-mode. + to mode-is mode m (int): return (current-game-mode == m). + to reset-all-network-scores: i (int). j (int). for j=0, j<|parent-brains|, j++ : { for i=0, i<|parent-brains{j}|, i++ : { (parent-brains{j}{i}) reset. } } for j=0, j<|child-brains|, j++ : { for i=0, i<|child-brains{j}|, i++ : { (child-brains{j}{i}) reset. } } # pos: index within subpopulation # - pos < |brains{i}| for all i + to replace-monsters from pos (int): i (int). j (int). monster-index (int). pop-slot (int). brains (list). random-offset (int). random-offset = 0. if current-population == POPULATION_PARENTS : brains = parent-brains. else if current-population == POPULATION_CHILDREN : brains = child-brains. for i = 0, i < number-of-subpops, i++ : { for j = 0, j < monsters-from-each-subpop, j++ : { monster-index = (i * monsters-from-each-subpop) + j. if homogeneous : pop-slot = pos. else { if (commandline bit-param named "random-sampling") && (shuffle-offset > 0) : { random-offset = random[ (|brains{i}| - 1) ]. } pop-slot = (pos + shuffle-offset + random-offset + j) % |brains{i}|. } #print "subpop-index: $i, population-slot: $pop-slot, remember-index: $monster-index". monsters{ monster-index } replace-brain with-genome (brains{i}{pop-slot}). monsters{ monster-index } assign-subpop-index of i. monsters{ monster-index } set-population-slot to pop-slot. monsters{ monster-index } remember-index of monster-index. } } #print (monsters{0} extract-genome), ":", ((monsters{0} extract-genome) get-mode-ages), ":", ((monsters{0} extract-genome) get-youngest-mode-age). self update-hud-network-view. + to update-hud-network-view: if myHUD || (commandline bit-param named "focus-on-network-view") : { self draw-net net (monsters{0} extract-genome). } + to switch-current-game-mode: reps (int). trials-so-far (int). reps = 1. if current-population == POPULATION_CHILDREN : reps = children-per-parent. #print "current-game-mode-counter: $current-game-mode-counter". if (current-game-mode-counter == 0) : { if homogeneous : { trials-so-far = type-trials-for-brains{0}{current-population-num}{ (tasks{ current-game-mode-counter }{TASK_SLOT_TASK}) }. # Give each homogeneous team all of its evaluations before switching it # Subpop 0 is used because a homogeneous team should only have one subpop if (trials-so-far == 0) || (trials-so-far == (commandline num-param named "start-evals")) : { current-population-num++. current-population-num %= (subpop-size * reps). #print "current-population-num: $current-population-num". self replace-monsters from current-population-num. } } else { current-population-num++. current-population-num %= ((subpop-size * reps) / monsters-from-each-subpop). if (current-population-num == 0) : shuffle-offset = (shuffle-offset + SHUFFLE_JUMP) % subpop-size. self replace-monsters from (current-population-num * monsters-from-each-subpop). } } current-game-mode = tasks{ current-game-mode-counter }{TASK_SLOT_TASK}. current-game-mode-counter = (current-game-mode-counter + 1) % |tasks|. # Write Networks + to catch-key-s-down: user-save = 1. + to catch-key-i-down: user-increase-challenge = 1. + to catch-key-n-down: #print "--------NEXT--------". skip-trial = 1. + to write-networks with-identifier name (string): i (int). currentAveAves (list). currentBestAves (list). currentPercentAchieveAves (list). # Update fitness averages currentAveAves = {}. currentBestAves = {}. currentPercentAchieveAves = {}. for i = 0, i < |fitness-info-list|, i++ : { push (fitness-info-list{i}{SLOT_CURRENT_AVE_AVE}) onto currentAveAves. push (fitness-info-list{i}{SLOT_BEST_AVE}) onto currentBestAves. push (fitness-info-list{i}{SLOT_PERCENT_ACHIEVING_GOAL_AVE}) onto currentPercentAchieveAves. } commandline set-list-param named "previous-fitness-average-averages" to currentAveAves. commandline set-list-param named "previous-fitness-best-averages" to currentBestAves. commandline set-list-param named "previous-achieving-percentage-aves" to currentPercentAchieveAves. netIO write-networks with-identifier name commandline-options commandline fitnesses fitness-info-list inputs additional-input-info parent-fitness-list parent-fitnesses child-fitness-list child-fitnesses children child-brains parents parent-brains logs log. #commandline set-bit-param named "progress-on-resume" to COMMAND_LINE_OFF. if ((commandline string-param named "auto-resume") != "") : { resume-helper create-auto-resume-file named (commandline string-param named "auto-resume"). } # Call when population is stagnating + to load-last-save: last-file-saved (string). last-path-saved (string). last-file-saved = netIO get-last-file-saved. last-path-saved = netIO get-last-path-saved. if (last-file-saved != "") : { (self load-population from-path last-path-saved files last-file-saved type "parents"). } self log-to-file text "#$experiment-theme - Stagnation Reset, loading: $last-path-saved/$last-file-saved". + to log-to-file text s (string): log log-to-file text s to-file experiment-theme. # filePath: directory with files # fileSet: name of files to load # group: "parents" or "children" (group to load) + to load-population from-path filePath (string) files fileSet (string) type group (string): netIO load-population from-path filePath files fileSet type group subpops number-of-subpops sub-size subpop-size parent-list parent-brains. self give-monsters-starting-brains from parent-brains. + to catch-key-e-down: self user-ends-simulation. + to user-ends-simulation: user-end = 1. print "User requests to terminate simulation". # Player movement control + to catch-key-up-down: if !(player is-locked): player set-forward-coeff to ((self get-speed-difficulty) * PLAYER_WALK_SPEED). + to catch-key-up-up: if !(player is-locked): player set-forward-coeff to 0. + to catch-key-down-down: if !(player is-locked): player set-forward-coeff to (-PLAYER_WALK_SPEED * (self get-speed-difficulty)). + to catch-key-down-up: if !(player is-locked): player set-forward-coeff to 0. + to catch-key-left-down: if !(player is-locked): player set-turn-angle to (-PLAYER_TURN_SPEED). + to catch-key-left-up: if !(player is-locked): player set-turn-angle to 0. + to catch-key-right-down: if !(player is-locked): player set-turn-angle to PLAYER_TURN_SPEED. + to catch-key-right-up: if !(player is-locked): player set-turn-angle to 0. # space bar #+ to catch-key-0x20-down: + to catch-key-z-down: if !(player is-locked): { if player-shoots : { if (player is-armed) : player attack. else player fire. } else { if (player is-armed) : player fire. else player attack. } } # Strategy Switch + to reset-strategy: stagnation-counter = 0. log reset-log-averages. self reset-fitness-averages. player set-forward-coeff to 0. player set-turn-angle to 0. # num: valid strategy constant + to switch-strategy to num (int): self reset-all-network-scores. self reset-strategy. previous-strategy = (self get-player-strategy). self set-player-strategy to num. # Player Info + to anyone-close-to-player: shortest-distance (double). shortest-distance = (triangulate get-distance-to-nearest-object from (player get-location) given monsters). if (shortest-distance < (commandline num-param named "very-close-player")) : return 1. return 0. + to anyone-very-close-to-player: shortest-distance (double). shortest-distance = (triangulate get-distance-to-nearest-object from (player get-location) given monsters). if (shortest-distance < ((commandline num-param named "very-close-player") / 2)) : return 1. return 0. + to anyone-in-front-of-player: i (int). for i=0, i<|monsters|, i++ : { if (monsters{i} in-front-of-player) : return 1. } return 0. + to player-is-swinging: return (player swinging). #SMEG: put in ParallelDimension.tz or AgentManager.tz + to spawn-player: i (int). bullets (list). t (double). r (double). x (double). z (double). #print "spawn player". if goal: free goal. if player : { player free-sword. free player. } player = new Player. player move to (0, 1, 0). if current-game-mode == MODE_BALL : { r = MIN_GOAL_BUFFER + ((self get-speed-difficulty) * (commandline num-param named "goal-distance")). t = random[(2 * PI)]. x = r * cos(t). z = r * sin(t). goal = new Goal. goal create at (x, 0.0, z). } if (commandline bit-param named "random-player-orientation") : { #print "Random orientation". player point vertex (0, 1, 0) at (math get-random-unit-vector). } else { #print "Not random". player point vertex (0, 1, 0) at (1,0,0). } bullets = all Bullet. for i = 0, i < |bullets|, i++ : { bullets{i} disappear after-hitting self. } for i = 0, i < |monsters|, i++ : { if (monsters{i} get-deaths) == 0 : monsters{i} new-placement. } if (commandline bit-param named "focus-on-network-view") : { main-camera = self get-main-camera. main-camera look at (0,VIEW_HEIGHT,0) from ((0.1,-0.1,10) * VIEW_DISTANCE). } else { self offset-camera by (0, CAMERA_HEIGHT, -20). self watch item player. } #self pause. + to all-monsters-dead: i (int). for i=0, i<|monsters|, i++ : { # Monster not dead if (monsters{i} get-deaths) == 0 : { return 0. } } return 1. + to increment-deaths: deaths++. kills-last-gen++. + to get-player-location: return (player get-location). + to get-player: return player. + to get-goal: return goal. # Monster Info + to next-theta-location: return (triangulate next-theta-location). + to get-team-size: return ( |monsters| ). + to get-monsters: return monsters. # damage: damage dealt to player + to assign-damage-assist of damage (double): i (int). neighbors (list). neighbors = (player get-neighbors). for i=0, i<|neighbors|, i++ : { if (neighbors{i} is a "Monster") && ((neighbors{i} get-distance from player) < (commandline num-param named "very-close-player")) : { neighbors{i} increase-damage-assist by damage. } } + to get-additional-input-info: return additional-input-info. + to get-bot-color: if current-game-mode < (graphics get-num-bot-colors) : return (graphics get-bot-color for-mode current-game-mode). else return (graphics get-bot-color for-mode 0). # Evolution # brains: list of list-ops of neural network brains + to give-monsters-starting-brains from brains (list): i (int). j (int). monster-index (int). pop-slot (int). pop-slot = 0. for i = 0, i < number-of-subpops, i++ : { for j = 0, j < monsters-from-each-subpop, j++ : { if (homogeneous == 0) : pop-slot = j. monster-index = ((i * monsters-from-each-subpop) + j). monsters{ monster-index } replace-brain with-genome ( brains{i}{pop-slot} ). monsters{ monster-index } assign-subpop-index of i. monsters{ monster-index } set-population-slot to pop-slot. monsters{ monster-index } remember-index of monster-index. } } + to get-number-of-subpops: return number-of-subpops. + to get-innovation-counter: return (ga get-innovation-counter). + to random-weight: return (ga random-weight). # Power ups + to player-gets-powerup: player-powerups++. + to get-num-player-powerups: return player-powerups. # Scores # damage: damage player dealt to a monster + to increase-player-score by damage (double): interaction-occurred = 1. player-score += damage. # amount: damage a monster dealt to the player + to adjust-group-score by amount (double): i (int). interaction-occurred = 1. group-score += amount. for i = 0, i < |monsters|, i++ : { monsters{i} group-damage-inflicted amount amount. } + to get-fitness-info-list: return fitness-info-list. # Replacing the population # keeper-ids: list of indicies either within parent-fitnesses # or corresponding to an index in child-fitnesses + to pick-new-parents from keeper-ids (list): i (int). j (int). keeper-hash (hash). key (int). temp-brains (list). parent-offset (int). children-kept (int). brains-needed (int). children-kept = 0. brains-needed = 0. # Each j is a subpopulation for j = 0, j < |keeper-ids|, j++ : { parent-offset = |parent-brains{j}|. temp-brains = parent-brains{j}. foreach key in keys( keeper-hash ) : keeper-hash{key} = 0. # Free the non-keepers to avoid memory leaks. # First remember who to keep. for i = 0, i < |keeper-ids{j}|, i++ : { keeper-hash{ keeper-ids{j}{i} } = 1. } # Free non-keeper parents for i = 0, i < |parent-brains{j}|, i++ : { if !(keeper-hash{i} == 1) : { # Results in a NULL pointer in the list free (parent-brains{j}{i}). free (parent-fitnesses{j}{i}). } } # Prepare to delete non-keeper children, but keep them around until after # network output is performed, just in case for i = 0, i < |child-brains{j}|, i++ : { if !(keeper-hash{ (parent-offset + i) } == 1) : (child-brains{j}{i}) prepare-to-die. else children-kept++. } parent-brains{j} = {}. # Rearrange keepers for i = 0, i < |keeper-ids{j}|, i++ : { push (self keeper-choose index (keeper-ids{j}{i}) parents (temp-brains) children (child-brains{j})) onto parent-brains{j}. brains-needed++. } temp-brains = {}. } ratio-children-in-new-pop = (children-kept * 1.0) / (brains-needed * 1.0). #if (commandline bit-param named "mutation-inverse-child-rate") : self update-child-ratio-mutation-rates. self give-monsters-starting-brains from parent-brains. self reset-shuffle-offset. # Given a keeper index, return the appropriate result from a list of # parent or children data + to keeper-choose index i (int) parents parents (list) children children (list): if i < |parents| : { return (parents{i}). } else { return (children{ (i - |parents|) }). } + to parents-survive-another-generation: i (int). j (int). for j=0, j<|parent-brains|, j++ : { for i=0, i<|parent-brains{j}|, i++ : { (parent-brains{j}{i}) survive-another-generation. } } # SMEG: Move into FreeNetGa + to get-random-children: i (int). j (int). k (int). newBrain (object). source-subpop (int). fitnesses (list). x (int). y (int). idFitnesses (list). individual-scores (list). source (list). child-brains = {}. for j=0, j<|parent-brains|, j++ : { source-subpop = j. push {} onto child-brains. # The meta fitnesses are only needed if selection is used between the parent and child populations. # Currently the only selection method available is binary tournament. if (commandline bit-param named "binary-tournament") : { idFitnesses = {}. for x=0, x<|parent-fitnesses{source-subpop}|, x++ : { individual-scores = {}. for y = 0, y < |parent-fitnesses{source-subpop}{x}|, y++ : { source = parent-fitnesses{source-subpop}{x}. if (fitness-info-list{y}{SLOT_USE_OBJECTIVE} == FITNESS_OBJECTIVE_ON) : { push (source{y}) onto individual-scores. } } push { x, individual-scores } onto idFitnesses. } #print "get meta-fitnesses from idFitnesses = ",idFitnesses. fitnesses = (selection get-meta-fitness base idFitnesses). #print "result: ", fitnesses. } for i=0, i<|parent-brains{j}|, i++ : { for k = 0, k < children-per-parent, k++ : { # Change source-subpop if there is a chance of cross-breeding if ((random[1.0]) < (commandline num-param named "cross-breed-percentage")) : { source-subpop = random[ (|parent-brains| - 1) ]. } if (commandline bit-param named "mating") : { newBrain = ( ga new-offspring of ( parent-brains{source-subpop} ) binary-tournament (commandline bit-param named "binary-tournament") selection selection scores fitnesses ). } else if (commandline bit-param named "binary-tournament") : { newBrain = ( ga get-mutated-binary-tournament-champion from (parent-brains{source-subpop}) with-scores fitnesses using selection ). } else { newBrain = (ga get-mutated-clone of (parent-brains{source-subpop}{i})). } push newBrain onto (child-brains{j}). } } } self give-monsters-starting-brains from child-brains. self reset-shuffle-offset. + to get-num-sensors: return ( |additional-input-info| ). + to get-num-network-inputs: # For ensembles if brain-pool : { # All outputs of brain pool feed in as inputs to controller network return (brain-pool get-number-brain-pool-outputs). } else return (self get-num-sensors). + to get-num-network-outputs: if brain-pool && (brain-pool chooses-one-representative) : { return (brain-pool get-brain-pool-size). } else return (self get-num-actuators). + to get-num-actuators: return (commandline num-param named "num-output-neurons"). # subpop: index of a subpopulation + to merge-fitnesses of subpop (int): i (int). j (int). fitnesses (list). offset (int). individual-scores (list). source (list). fitnesses = {}. if (commandline bit-param named "keep-parents") : { offset = |parent-fitnesses{subpop}|. for i=0, i<|parent-fitnesses{subpop}|, i++ : { individual-scores = {}. for j = 0, j < |parent-fitnesses{subpop}{i}|, j++ : { #if long-term-averaging : parent-fitnesses{subpop}{i} = ((parent-brains{subpop}{i}) get-average-scores). source = parent-fitnesses{subpop}{i}. if (fitness-info-list{j}{SLOT_USE_OBJECTIVE} == FITNESS_OBJECTIVE_ON) : { push (source{j}) onto individual-scores. } } push { i, individual-scores,((parent-brains{subpop}{i}) get-variances),((parent-brains{subpop}{i}) get-number-evaluations) } onto fitnesses. } } else offset = 0. for i=0, i<|child-fitnesses{subpop}|, i++ : { individual-scores = {}. for j = 0, j < |child-fitnesses{subpop}{i}|, j++ : { #if long-term-averaging : child-fitnesses{subpop}{i} = ((child-brains{subpop}{i}) get-average-scores). source = child-fitnesses{subpop}{i}. if (fitness-info-list{j}{SLOT_USE_OBJECTIVE} == FITNESS_OBJECTIVE_ON) : { push (source{j}) onto individual-scores. } } push { (i + offset), individual-scores,((child-brains{subpop}{i}) get-variances),((child-brains{subpop}{i}) get-number-evaluations)} onto fitnesses. } return fitnesses. # Checks to see if a set of scores achieves all goals, even # goals for disabled objectives. + to individual-is-successful scores s (list): i (int). result (int). result = 1. for i = 0, i<|fitness-info-list|, i++ : { # Unlike the GOAL, the SUCCESS_LEVEL never changes if( (fitness-info-list{i}{SLOT_USE_GOAL}) && (s{i} < fitness-info-list{i}{SLOT_SUCCESS_LEVEL}) ) : { result = 0. return 0. } } return result. # count individuals that achieve all goals + to count-successful-individuals from keeper-ids (list): j (int). k (int). scores (list). num-successful = 0. for j=0, j<|keeper-ids|, j++ : { # each k corresponds to an individual in subpopulation j for k=0, k<|keeper-ids{j}|, k++ : { # Depending on the value of the keeper id, the information about the individual # may be in the parent fitness list or the child fitness list scores = (self keeper-choose index (keeper-ids{j}{k}) parents (parent-fitnesses{j}) children (child-fitnesses{j})). if (self individual-is-successful scores scores) : num-successful++. } } # SMEG: Move to Fitnesses.tz # keeper-ids: list of indicies either within parent-fitnesses # or corresponding to an index in child-fitnesses + to update-best-and-worst-fitnesses from keeper-ids (list): i (int). j (int). k (int). n (double). value (double). scores (list). prev-avg (double). achievers (int). scores-in-objective (list). percentile (double). below-percentile (int). above-percentile (int). new-goal (double). in-between (double). for i = 0, i<|fitness-info-list|, i++ : { fitness-info-list{i}{SLOT_CURRENT_BEST_FITNESS} = -INFINITY. fitness-info-list{i}{SLOT_CURRENT_WORST_FITNESS} = INFINITY. fitness-info-list{i}{SLOT_CURRENT_AVE} = 0.0. fitness-info-list{i}{SLOT_SUM_OF_SQUARES} = 0.0. fitness-info-list{i}{SLOT_NUM_ACHIEVING_GOAL} = 0. } achievers = 0. # each i corresponds to a particular fitness objective for i=0, i<|fitness-info-list|, i++ : { scores-in-objective = {}. # n is the number of individuals added up to take the average of n = 0. # each j corresponds to a single subpopulation for j=0, j<|keeper-ids|, j++ : { # each k corresponds to an individual in subpopulation j for k=0, k<|keeper-ids{j}|, k++ : { # Depending on the value of the keeper id, the information about the individual # may be in the parent fitness list or the child fitness list scores = (self keeper-choose index (keeper-ids{j}{k}) parents (parent-fitnesses{j}) children (child-fitnesses{j})). value = scores{i}. push value onto scores-in-objective. n++. prev-avg = fitness-info-list{i}{SLOT_CURRENT_AVE}. fitness-info-list{i}{SLOT_CURRENT_AVE} += (value - fitness-info-list{i}{SLOT_CURRENT_AVE})/n. fitness-info-list{i}{SLOT_SUM_OF_SQUARES} += ((value - (fitness-info-list{i}{SLOT_CURRENT_AVE}))*(value - prev-avg)). if value > (fitness-info-list{i}{SLOT_CURRENT_BEST_FITNESS}) : { fitness-info-list{i}{SLOT_CURRENT_BEST_FITNESS} = value. fitness-info-list{i}{SLOT_FULL_SCORES_OF_BEST} = scores. } if value < (fitness-info-list{i}{SLOT_CURRENT_WORST_FITNESS}) : { fitness-info-list{i}{SLOT_CURRENT_WORST_FITNESS} = value. } if ((fitness-info-list{i}{SLOT_USE_GOAL}) && (value > (fitness-info-list{i}{SLOT_GOAL}))) : { fitness-info-list{i}{SLOT_NUM_ACHIEVING_GOAL} = fitness-info-list{i}{SLOT_NUM_ACHIEVING_GOAL} + 1. } } } fitness-info-list{i}{SLOT_PERCENT_ACHIEVING_GOAL} = ( (fitness-info-list{i}{SLOT_NUM_ACHIEVING_GOAL}) / (n * 1.0)). fitness-info-list{i}{SLOT_PERCENT_ACHIEVING_GOAL_AVE} += recency-weighted-alpha * (fitness-info-list{i}{SLOT_PERCENT_ACHIEVING_GOAL} - fitness-info-list{i}{SLOT_PERCENT_ACHIEVING_GOAL_AVE}). if partition-tug : { if (commandline bit-param named "always-adjust-part-tug-goals") : { list-ops ascending-sort the-list scores-in-objective. percentile = ((commandline num-param named "goal-achievement-percentage-for-increase")*(|scores-in-objective| - 1)). below-percentile = percentile. if (below-percentile == percentile) : { above-percentile = below-percentile. in-between = 0. } else { above-percentile = (below-percentile + 1). in-between = (percentile - below-percentile). } new-goal = (scores-in-objective{below-percentile} + ( (scores-in-objective{above-percentile} - scores-in-objective{below-percentile}) * in-between )). fitness-info-list{i}{SLOT_GOAL} = new-goal. self reset-fitness-average at i. } else if (commandline bit-param named "part-tug-goals-use-rwa") : { if (fitness-info-list{i}{SLOT_PERCENT_ACHIEVING_GOAL_AVE} > (commandline num-param named "goal-achievement-percentage-for-increase")) : { achievers++. } } else if (fitness-info-list{i}{SLOT_PERCENT_ACHIEVING_GOAL} > (commandline num-param named "goal-achievement-percentage-for-increase")) : { achievers++. } } fitness-info-list{i}{SLOT_STDEV} = (self get-fitness-stdev objective i). } increase-all-goals = 0. if (|fitness-info-list| == achievers) : { #print "Achiever based increase". increase-all-goals = 1. for i = 0, i < |fitness-info-list|, i++ : { self increase-goal with i. fitness-info-list{i}{SLOT_PERCENT_ACHIEVING_GOAL_AVE} = 0.0. } } self update-fitness-averages. if file-output : log log-data using fitness-info-list to-file experiment-theme. if partition-tug : selection set-objective-goals to (self get-fitness-goals). # Is called at the end of every sequence of parent evaluations and # every sequence of child evaluations + to end-phase: temp (string). switch (int). write (int). end (int). pareto-parent-ids (list). pareto-front-size (int). i (int). j (int). pareto-parent-brains (list). pareto-parent-fitnesses (list). if (home-stretch == 1) : home-stretch-counter = home-stretch-counter + 1. if (commandline num-param named "switch-every") > 0 : { switch = ( (current-population == POPULATION_CHILDREN) && (generation > 0) && (generation % (commandline num-param named "switch-every") == 0) ). } else { switch = user-increase-challenge || ( ((self get-player-strategy) != STRATEGY_HUMAN) && # No incremental evolution against humans (current-population == POPULATION_CHILDREN) && # Means a parent generation just finished (((commandline bit-param named "use-fitness-goals") == 0) || (self check-fitness-goals)) && (((commandline bit-param named "use-log-goals") == 0) || (log check-goals)) ). } end = (generation >= (commandline num-param named "max-gens")) || user-end || (home-stretch-counter == (commandline num-param named "home-stretch-generations")). # Simplified write condition to prevent weird decreasing goal error write = (generation > (2 + (commandline num-param named "ending-generation"))) && #Don't write networks if already written within 2 gens ( user-save || ( (generation > 0) && (current-population == POPULATION_CHILDREN) && # Means a parent generation just finished (generation % (commandline num-param named "gens-between-write") == 0)) || end ). #Make sure that info from switches are not lost #if switch : { #write = 1. #commandline set-num-param named "last-switch-generation" to generation. #} if switch && (commandline bit-param named "make-movie") && (!movie) : { movie = new Movie. movie record to "$file-path/$experiment-theme$generation.mpg". switch = 0. write = 0. } phase++. # changing tasks if switch : { if movie : { movie close. free movie. } if (commandline bit-param named "progress") : { end = (self increase-challenge) || end. # if end became true, then we need to write the last population (in case we haven't already) if (end) && (write == 0): { self end-phase-write is-switch switch is-end end. } } } # Moved here to assure that goals were increased before saving if write && file-output : { self end-phase-write is-switch switch is-end end. } if end : { temp = (commandline string-param named "name"). if (temp != "") : # Experiments without names are just quick tests, and shouldn't write Final Scores { self write-current-scores to-file "FinalScores-$temp" write-children 1. print "Final scores written to file". } if user-end : print "User terminates simulation". if (selection is a "NSGA2") : { selection = new NSGA2. selection set-generation to (commandline num-param named "ending-generation"). print "Saving the final Pareto front separately". # First turn on objectives TUG turned off for i = 0, i < |fitness-info-list|, i++ : { fitness-info-list{i}{SLOT_USE_OBJECTIVE} = FITNESS_OBJECTIVE_ON. # But turn off objectives that affect all modes (not actually part of the task) if (fitness-info-list{i}{SLOT_GAME_MODE} == GAME_MODE_ALL): fitness-info-list{i}{SLOT_USE_OBJECTIVE} = FITNESS_OBJECTIVE_OFF. } # Get Pareto front of just the last parent population: pareto-parent-ids = {}. pareto-parent-brains = {}. pareto-parent-fitnesses = {}. for i = 0, i < number-of-subpops, i++ : { push {} onto pareto-parent-ids. push {} onto pareto-parent-brains. push {} onto pareto-parent-fitnesses. # Free the children so they won't be part of the merge child-fitnesses{i} = {}. pareto-parent-ids{i} = (selection get-best choose (|parent-fitnesses{i}|) of-population (self merge-fitnesses of i)). # Size of pareto front is calculated as a side-effect of selection pareto-front-size = (selection get-last-largest-front-size). print "Pareto front size is $pareto-front-size". for j = 0, j < pareto-front-size, j++ : { push {} onto (pareto-parent-brains{i}). push {} onto (pareto-parent-fitnesses{i}). pareto-parent-fitnesses{i}{j} = ( parent-fitnesses{i}{ (pareto-parent-ids{i}{j}) } ). pareto-parent-brains{i}{j} = ( parent-brains{i}{ (pareto-parent-ids{i}{j}) } ). } } netIO write-networks with-identifier "FinalParetoFront-$temp" commandline-options commandline fitnesses fitness-info-list inputs additional-input-info parent-fitness-list pareto-parent-fitnesses child-fitness-list {} children {} parents pareto-parent-brains logs log. } print "Ending Simulation". self end-simulation. return. } self free-doomed-children. + to write-current-scores to-file name (string) write-children bit = 0 (int): netIO write-current-scores with-identifier name extension "scores" fitnesses fitness-info-list parent-fitness-list parent-fitnesses child-fitness-list child-fitnesses parents parent-brains children child-brains write-children bit. # Free networks in child population whose "prepared to die" value is set + to free-doomed-children: i (int). j (int). # Now that network output is done, free the children that should have # been deleted earlier for j = 0, j < |child-brains|, j++ : { for i = 0, i < |child-brains{j}|, i++ : { if ((child-brains{j}{i}) is-ready-to-die) : { free (child-brains{j}{i}). free (child-fitnesses{j}{i}). } } } # If files are to be written at the end of a phase, this # method is called. + to end-phase-write is-switch switch (int) is-end end (int): tempInt (int). ident (string). populations-logged (int). temp (string). #if switch : commandline set-bit-param named "progress-on-resume" to COMMAND_LINE_ON. #self report-object-allocation. self update-end-generation. populations-logged = log get-populations-logged. tempInt = (self get-player-strategy). ident = "Strat$tempInt". temp = (self get-speed-difficulty). ident = "Speed$temp$ident". if (switch) : ident = "Switch$ident". else ident = "Checkpoint$ident". if (end) : ident = "End$ident". ident = "Gen$generation$ident". ident = "$experiment-theme$populations-logged$ident". if (user-save) : ident = "User-Save-$ident". self log-to-file text "#$experiment-theme - Write networks: $ident". if (commandline bit-param named "network-output") || (end) : { self write-networks with-identifier ident. } log increment-populations-logged. user-save = 0. + to increase-pending-goals: i (int). for i = 0, i < |pending-goal-increases|, i++ : { if pending-goal-increases{i} : (self increase-goal with i). } + to increase-goal with index (int): s (double). pending-goal-increases{index} = 0. s = (commandline num-param named "goal-increase-alpha"). if(fitness-info-list{index}{SLOT_USE_GOAL}) : { #print "Increase: ", fitness-info-list{index}{SLOT_DISPLAY_LABEL}, " from ", fitness-info-list{index}{SLOT_GOAL} . fitness-info-list{index}{SLOT_GOAL} += s * (fitness-info-list{index}{SLOT_CURRENT_BEST_FITNESS} - fitness-info-list{index}{SLOT_GOAL}). #print "to ", fitness-info-list{index}{SLOT_GOAL}. self reset-fitness-average at index. } if partition-tug : selection set-objective-goals to (self get-fitness-goals). # Used for incremental evolution. # Depending on the command-line settings, either the movement speed # of the bot will be increased, or the bot will start exhibiting a different # sort of behavior. + to increase-challenge: end (int). i (int). shaping-index (int). user-increase-challenge = 0. end = 0. if use-shaping : { shaping-index = (commandline num-param named "index-of-last-shaping-objective-added"). shaping-index++. if ( shaping-index == |fitness-info-list| ) : { end = 1. } else { fitness-info-list{shaping-index}{SLOT_USE_OBJECTIVE} = FITNESS_OBJECTIVE_ON. commandline set-num-param named "index-of-last-shaping-objective-added" to shaping-index. self reset-all-network-scores. } } else { for i = 0, i < |fitness-info-list|, i++ : { # Make sure objectives are on in case they were turned off by "tug" fitness-info-list{i}{SLOT_USE_OBJECTIVE} = FITNESS_OBJECTIVE_ON. } } self decrease-stagnation-threshold. if (commandline bit-param named "task-progression") == 0 : { # Speed progression if (self get-speed-difficulty) < 1.0 : { self next-in-speed-sequence. self reset-all-network-scores. } else end = 1. if ((self get-speed-difficulty) == 1.0) : home-stretch = 1. # Doesn't change anything, but resets stats self reset-strategy. } else { # Task progression if (self get-player-strategy) == STRATEGY_STILL : { (self switch-strategy to STRATEGY_SPIN). }else if (self get-player-strategy) == STRATEGY_SPIN : { (self switch-strategy to STRATEGY_COMBO). }else if (self get-player-strategy) == STRATEGY_COMBO : { (self switch-strategy to STRATEGY_SMART). }else if (self get-player-strategy) == STRATEGY_SMART : { end = 1. } if (self get-player-strategy) == STRATEGY_SMART : home-stretch = 1. } if (home-stretch) && ((commandline num-param named "home-stretch-generations") > -1) : { if home-stretch-counter < (commandline num-param named "home-stretch-generations") : { end = 0. } else { end = 1. } } increase-all-goals = 0. # if end == 1 and there is a commandline option to turn on TUG-2.0, # then end should be set to 0 and all goals should be increased according to # SLOT_GOAL <- SLOT_GOAL + s * (SLOT_CURRENT_BEST_FITNESS - SLOT_GOAL) # where s is another commandline parameter if (end && ((commandline bit-param named "increase-goals-when-all-achieved") || (commandline bit-param named "increase-goal-when-turned-on"))) : { print "Average based increase". end = 0. increase-all-goals = 1. for i = 0, i < |fitness-info-list|, i++ : { self increase-goal with i. } } if (commandline bit-param named "open-ended-evolution") : end = 0. return end. + to decrease-challenge: if (commandline bit-param named "task-progression") == 0 : { # Speed progression if (self get-speed-difficulty) > 0.0 : (self next-in-speed-sequence reverse 1). # Doesn't change anything, but resets stats #self switch-strategy to (self get-player-strategy). self reset-strategy. } else { # Task progression if (self get-player-strategy) == STRATEGY_SPIN : (self switch-strategy to STRATEGY_STILL). else if (self get-player-strategy) == STRATEGY_COMBO : (self switch-strategy to STRATEGY_SPIN). else if (self get-player-strategy) == STRATEGY_SMART : (self switch-strategy to STRATEGY_COMBO). } home-stretch = 0. home-stretch-counter = 0. # SMEG: Move to Fitnesses.tz # # Checks if the population as a whole has obtained high enough fitness values # to meet all goals. Goals can be specified for each fitness objective, and they # are considered met if the average fitness of the population for that objective # has reached the goal defined for that objective. + to check-fitness-goals: i (int). failed (int). diversity-decision (int). goal-percentage (double). goal-adjustment (double). uncertainty (double). uncertainty = 0.0. goal-percentage = 1.0. # default is 100% if (commandline bit-param named "soft-goal-achievement") : { goal-percentage = (commandline num-param named "soft-goal-achievement-percentage"). } failed = 0. for i = 0, i < |fitness-info-list|, i++ : { if (commandline bit-param named "lower-bound-certainty-for-achievement") : { uncertainty = (fitness-info-list{i}{SLOT_STDEV}). } if ( fitness-info-list{i}{SLOT_USE_GOAL} == FITNESS_GOAL_ON ) : { if ( fitness-info-list{i}{SLOT_GOAL} > fitness-info-list{i}{SLOT_CURRENT_AVE_AVE} ) || ( fitness-info-list{i}{SLOT_GOAL} > (fitness-info-list{i}{SLOT_CURRENT_AVE} - uncertainty) ) : { # Has not beaten goal yet # Only consider failure if soft-achievement fails too goal-adjustment = (1.0 - goal-percentage) * (fitness-info-list{i}{SLOT_GOAL} - fitness-info-list{i}{SLOT_MIN}). if ( (fitness-info-list{i}{SLOT_GOAL} - goal-adjustment) > fitness-info-list{i}{SLOT_CURRENT_AVE_AVE} ) : { failed++. } if drop-defeated : { # Need to wait for additional data to be calculated before # goals can be properly increased. # Only increase goal if switching from objective being off to being on if ((fitness-info-list{i}{SLOT_USE_OBJECTIVE} == FITNESS_OBJECTIVE_OFF) && (commandline bit-param named "increase-goal-when-turned-on")) : { pending-goal-increases{i} = 1. } #print "Turn ", fitness-info-list{i}{SLOT_DISPLAY_LABEL}, " on". # Always restore objectives that are not beaten fitness-info-list{i}{SLOT_USE_OBJECTIVE} = FITNESS_OBJECTIVE_ON. } } else { #print "Check ", fitness-info-list{i}{SLOT_DISPLAY_LABEL}. # beat the goal (except for RANDOM) if drop-defeated && (fitness-info-list{i}{SLOT_DISPLAY_LABEL} != "Random") : { if (commandline bit-param named "hard-goal-achievement") : { goal-adjustment = (commandline num-param named "hard-goal-achievement-percentage") * (fitness-info-list{i}{SLOT_GOAL} - fitness-info-list{i}{SLOT_MIN}). if ( goal-adjustment < fitness-info-list{i}{SLOT_CURRENT_AVE_AVE} ) && ( goal-adjustment < (fitness-info-list{i}{SLOT_CURRENT_AVE} - uncertainty) ) : { #print "Turn ", fitness-info-list{i}{SLOT_DISPLAY_LABEL}, " off, higher than ", goal-adjustment. fitness-info-list{i}{SLOT_USE_OBJECTIVE} = FITNESS_OBJECTIVE_OFF. } } else { # Don't base selection on defeated goals fitness-info-list{i}{SLOT_USE_OBJECTIVE} = FITNESS_OBJECTIVE_OFF. } } } } } # Resolve conflict between TUG and BD by turning off BD when TUG turns other objectives off if (behavior-diversity && drop-defeated) : { diversity-decision = 1. # Default is to have BD on for i = 0, i < |fitness-info-list|, i++ : { if ((i != diversity-fitness-index) && (fitness-info-list{i}{SLOT_USE_OBJECTIVE} == FITNESS_OBJECTIVE_OFF)) : { diversity-decision = 0. # Choose not to use BD if another objective is off } } if diversity-decision : fitness-info-list{diversity-fitness-index}{SLOT_USE_OBJECTIVE} = FITNESS_OBJECTIVE_ON. else fitness-info-list{diversity-fitness-index}{SLOT_USE_OBJECTIVE} = FITNESS_OBJECTIVE_OFF. } return (failed == 0). + to reset-fitness-averages: i (int). tempList (list). for i = 0, i < |fitness-info-list|, i++ : { self reset-fitness-average at i. } # Since there are no champions at the start of the simulation, # the slot for storing the champion's scores holds the worst values tempList = {}. for i = 0, i < |fitness-info-list|, i++ : { push ( fitness-info-list{i}{SLOT_MIN} ) onto tempList. } for i = 0, i < |fitness-info-list|, i++ : { fitness-info-list{i}{SLOT_FULL_SCORES_OF_BEST} = tempList. } + to reset-fitness-average at index (int): fitness-info-list{index}{SLOT_CURRENT_AVE_AVE} = fitness-info-list{index}{SLOT_MIN}. fitness-info-list{index}{SLOT_BEST_AVE} = fitness-info-list{index}{SLOT_MIN}. fitness-info-list{index}{SLOT_WORST_AVE} = fitness-info-list{index}{SLOT_MIN}. # Takes existing fitnesses so far and combines them with scores from the current # evaluation to get a new set of current fitness scores for each evaluated network + to tally-up-fitness-scores: i (int). j (int). pop-slot (int). subpop-num (int). ave-scores-homo (list). individual-scores (list). if homogeneous : { # Homogeneous mode scores are the average scores across teammates # (this also works if the score is only defined at the group level, since each individual score # will equal the average score) ave-scores-homo = (monsters{0} get-fitnesses). for i=1, i<|monsters|, i++ : { individual-scores = (monsters{i} get-fitnesses). for j=0, j<|ave-scores-homo|, j++ : { ave-scores-homo{j} = ave-scores-homo{j} + individual-scores{j}. } } for j=0, j<|ave-scores-homo|, j++ : { ave-scores-homo{j} = ave-scores-homo{j} / (1.0 * |monsters|). } # In a homogeneous population, the pop-slot and subpop-num of each monster should be the same. pop-slot = monsters{0} get-population-slot. subpop-num = monsters{0} get-subpop-index. if (commandline bit-param named "use-worst-scores") : { # Now, set the stored fitness score to the min of the current score and the previous score. if ( |current-fitnesses{subpop-num}{pop-slot}| == 0 ) : current-fitnesses{subpop-num}{pop-slot} = ave-scores-homo. else { for j=0, j<|ave-scores-homo|, j++ : { current-fitnesses{subpop-num}{pop-slot}{j} = min( (current-fitnesses{subpop-num}{pop-slot}{j}), ave-scores-homo{j} ). } } } else { self average-list-actual-scores of-sub subpop-num and-slot pop-slot with ave-scores-homo. } } else { for i=0, i<|monsters|, i++ : { pop-slot = monsters{i} get-population-slot. subpop-num = monsters{i} get-subpop-index. self average-list-scores of-sub subpop-num and-slot pop-slot with (monsters{i}). } } #print current-fitnesses. # Takes previous fitness score for network (if exists) and averages with the new scores for each objective. # subpop-num: index of subpopulation # pop-slot: index within individual subpopulation # mon: specific Monster object # - Side-effects to list stored in old + to average-list-scores of-sub subpop-num (int) and-slot pop-slot (int) with mon (object): self average-list-actual-scores of-sub subpop-num and-slot pop-slot with (mon get-fitnesses). + to average-list-actual-scores of-sub subpop-num (int) and-slot pop-slot (int) with extra (list): i (int). old (list). inclusion-list (list). brains (list). # So that individual networks can track average scores across all evals inclusion-list = {}. old = current-fitnesses{subpop-num}{pop-slot}. type-trials-for-brains{subpop-num}{pop-slot}{current-game-mode} = type-trials-for-brains{subpop-num}{pop-slot}{current-game-mode} + 1. # After first eval, initialize fitnesses if |old| == 0 : { for i=0, i<|extra|, i++: { push 0.0 onto old. } } for i=0, i<|old|, i++ : { if (fitness-info-list{i}{SLOT_GAME_MODE} == current-game-mode) : { push 1 onto inclusion-list. old{i} += ((extra{i} - old{i}) / ((type-trials-for-brains{subpop-num}{pop-slot}{current-game-mode}) * 1.0)). } else if (fitness-info-list{i}{SLOT_GAME_MODE} == GAME_MODE_ALL) : { push 1 onto inclusion-list. old{i} += ((extra{i} - old{i}) / (math summation of (type-trials-for-brains{subpop-num}{pop-slot}))). } else { push 0 onto inclusion-list. } } # Now send the latest scores to the network, using the inclusion list if (current-population == POPULATION_PARENTS) : brains = parent-brains. else if (current-population == POPULATION_CHILDREN) : brains = child-brains. ((brains{subpop-num}{pop-slot}) incorporate-new-scores fitness extra inclusion inclusion-list). if long-term-averaging : current-fitnesses{subpop-num}{pop-slot} = (brains{subpop-num}{pop-slot} get-average-scores). last-subpop-num = subpop-num. last-pop-slot = pop-slot. # This more general function is called for when behaviors vectors # can only be calculated between evaluation phases (parent vs. child) + to gather-all-behavior-vectors: i (int). j (int). brains (list). if (current-population == POPULATION_PARENTS) : brains = parent-brains. else if (current-population == POPULATION_CHILDREN) : brains = child-brains. for i=0, i<|brains|, i++ : { for j=0, j<|brains{i}|, j++ : { current-behavior-vectors{i}{j} = (behavior-state get-network-behavior-vector network (brains{i}{j})). } } # This method only makes sense in cases where the behavior-vectors # can be calculated after each individual evaluation. # Store behavior vectors in current-behavior-vectors + to gather-behavior-vectors: i (int). pop-slot (int). subpop-num (int). for i=0, i<|monsters|, i++ : { pop-slot = monsters{i} get-population-slot. subpop-num = monsters{i} get-subpop-index. # Only gather behavior vectors for individual if not done yet. # Accounts for the fact that each network is evaluated multiple times. if (|current-behavior-vectors{subpop-num}{pop-slot}| == 0) : { current-behavior-vectors{subpop-num}{pop-slot} = (behavior-state get-behavior-vector given monsters index-of i). } } + to track-mode-usage: pop-slot (int). subpop-num (int). i (int). brains (list). #print "tmu". if current-population == POPULATION_PARENTS : brains = parent-brains. else if current-population == POPULATION_CHILDREN : brains = child-brains. for i = 0, i < |monsters|, i++ : { pop-slot = monsters{i} get-population-slot. subpop-num = monsters{i} get-subpop-index. if ( current-mode-usage{subpop-num}{pop-slot} == {} ) : { current-mode-usage{subpop-num}{pop-slot} = (monsters{i} get-mode-usage). current-mode-counts{subpop-num}{pop-slot} = (monsters{i} get-mode-counts). } else { self hash-merge modify (current-mode-usage{subpop-num}{pop-slot}) same (monsters{i} get-mode-usage). current-mode-counts{subpop-num}{pop-slot} = (self list-add modify (current-mode-counts{subpop-num}{pop-slot}) same (monsters{i} get-mode-counts)). } (brains{subpop-num}{pop-slot}) set-most-recent-mode-usage-percentages raw (current-mode-counts{subpop-num}{pop-slot}). } + to hash-merge modify a (hash) same b (hash): key (int). foreach key in keys( b ) : { a{key} = b{key}. } + to list-add modify a (list) same b (list): i (int). for i = 0, i < |a|, i++ : { a{i} = (a{i} + b{i}). } return a. # Finds the least used output mode and returns a list of info: # {mode index, # times used, % time used} + to get-least-used-mode subpopulation subpop-num (int) id pop-slot (int): counts (list). i (int). total (int). least-used-index (int). least-used-amount (int). counts = current-mode-counts{subpop-num}{pop-slot}. total = 0. least-used-amount = INT_INFINITY. for i = 0, i < |counts|, i++ : { total += counts{i}. if (counts{i} < least-used-amount) : { least-used-amount = counts{i}. least-used-index = i. } } return {least-used-index, least-used-amount, ((least-used-amount * 1.0) / (total * 1.0))}. # returning -1 means all modes are used. # otherwise, an underused mode index is returned + to net-has-underused-mode subpopulation subpop-num (int) id pop-slot (int): least (list). num-modes (int). underused-threshold (double). num-modes = |current-mode-counts{subpop-num}{pop-slot}|. # SMEGSMEG: May need to be tweaked. The rate should at least be a commandline param underused-threshold = ((1.0 / (num-modes * 1.0)) / 4.0). least = (self get-least-used-mode subpopulation subpop-num id pop-slot). if (least{MODE_COUNT_PERCENT} < underused-threshold) : { #print "Mode",least{MODE_COUNT_INDEX},"used only",least{MODE_COUNT_USAGE},"times (",least{MODE_COUNT_PERCENT},"%)". return (least{MODE_COUNT_INDEX}). } return -1. + to mark-underused-modes-for-deletion: i (int). j (int). underused-mode (int). brains (list). if current-population == POPULATION_PARENTS : brains = parent-brains. else if current-population == POPULATION_CHILDREN : brains = child-brains. for i = 0, i < |current-mode-counts|, i++ : { for j = 0, j < |current-mode-counts{i}|, j++ : { underused-mode = (self net-has-underused-mode subpopulation i id j). # An underused mode was found if (underused-mode > -1) : { #print "Plan to delete mode $underused-mode of $current-population {$i}{$j} from", current-mode-counts{i}{j}. #ga delete-output-mode of (brains{i}{j}) mode underused-mode. (brains{i}{j}) plan-to-delete-mode mode underused-mode. } } } + to percent-mode-usage subpopulation subpop-num (int) id pop-slot (int): total-used (int). net (object). brains (list). total-modes (int). tempHash (hash). key-list (list). percent (double). tempHash = (current-mode-usage{subpop-num}{pop-slot}). key-list = keys(tempHash). total-used = |key-list|. if (current-population == POPULATION_PARENTS) : brains = parent-brains. else if (current-population == POPULATION_CHILDREN) : brains = child-brains. net = brains{subpop-num}{pop-slot}. if multinetworks : { total-modes = |tasks|. } else { total-modes = (mode-arbitrator get-num-output-modes-from-net network net). } percent = ((1.0 * total-used) / (1.0 * total-modes)). if (percent > 1.0) : { print "Impossible mode usage". if (current-population == POPULATION_PARENTS) : print "Parents". else if (current-population == POPULATION_CHILDREN) : print "Children". print "$total-used / $total-modes = $percent". net print-network. self end-simulation. } return percent. + to average-percent-mode-usage: i (int). j (int). sum (double). total (int). total = 0. sum = 0.0. for i = 0, i < |current-mode-usage|, i++ : { for j = 0, j < |current-mode-usage{i}|, j++ : { total++. sum += (self percent-mode-usage subpopulation i id j). } } return (sum / total). # Called after every evaluation + to end-eval: i (int). j (int). temp (string). temp2 (string). tempInt (int). tempInt2 (int). tempDouble (double). tempList (list). fitnesses (list). scoresFile (object). net (object). #print "end-eval". current-iteration = 0. current-eval++. #Record a new movie for each evaluation if (movieName != "") : { movie close. free movie. fitnesses = {}. for i=0, i<|monsters|, i++ : { if (|fitnesses| == 0) : fitnesses = (monsters{i} get-fitnesses). else { tempList = (monsters{i} get-fitnesses). for j=0, j<|tempList|, j++ : { fitnesses{j} += tempList{j}. } } } temp = "". for j=0, j<|fitnesses|, j++ : { fitnesses{j} /= (|monsters| * 1.0). tempDouble = fitnesses{j}. temp = "$temp,$tempDouble". } tempInt = (current-game-mode-counter - 1). if (tempInt == -1) : tempInt = (|tasks| - 1). tempInt = tasks{ tempInt }{TASK_SLOT_TASK}. tempInt2 = ((current-eval - 1) / |tasks|). free scoresFile. scoresFile = new File. scoresFile open-for-writing with-file "$file-path/$movieName.$tempInt2.task$tempInt.scores$temp.txt". for j=0, j<|fitnesses|, j++ : { scoresFile write-line text fitnesses{j}. } scoresFile close. print "wrote scores: $file-path/$movieName.$tempInt2.task$tempInt.scores$temp.txt". tempInt = tasks{ ((current-game-mode-counter) % |tasks| ) }{TASK_SLOT_TASK}. tempInt2 = (current-eval / |tasks|). movie = new Movie. movie record to "$file-path/$movieName.$tempInt2.task$tempInt.mpg". print "recording: $file-path/$movieName.$tempInt2.task$tempInt.mpg". } if ((eval-limit > 0) && (current-eval > eval-limit)) : { if (commandline bit-param named "resave-wo-unused-modes") : { parent-fitnesses = current-fitnesses. print "Saving networks without unused modes". # Remove unused modes, save result, and exit for i = 0, i < |parent-brains|, i++ : { for j = 0, j < |parent-brains{i}|, j++ : { net = (parent-brains{i}{j}). tempList = (net get-most-recent-mode-usage-percentages). tempInt2 = |tempList|. tempInt = (ga delete-all-unused-modes network net usage tempList). print "Network($i,$j): $tempInt unused modes deleted out of $tempInt2". } } temp = "REDUCED". experiment-theme = "$experiment-theme$temp". self end-phase-write is-switch 0 is-end 1. self end-simulation. } print "Ending after $eval-limit evals". self end-simulation. } kills-last-gen = 0. type-trials{current-game-mode} = type-trials{current-game-mode} + 1. if current-game-mode == MODE_PREY : { ave-player-prey-score += (player-score - ave-player-prey-score)/(type-trials{current-game-mode}). } else if current-game-mode == MODE_PRED : { ave-group-pred-score += (group-score - ave-group-pred-score)/(type-trials{current-game-mode}). } else if current-game-mode == MODE_FIGHT : { ave-group-fight-score += (group-score - ave-group-fight-score)/(type-trials{current-game-mode}). ave-player-fight-score += (player-score - ave-player-fight-score)/(type-trials{current-game-mode}). } else if current-game-mode == MODE_RAM : { ave-group-ram-score += (group-score - ave-group-ram-score)/(type-trials{current-game-mode}). ave-player-ram-score += (player-score - ave-player-ram-score)/(type-trials{current-game-mode}). } else if current-game-mode == MODE_BACKRAM : { ave-group-back-ram-score += (group-score - ave-group-back-ram-score)/(type-trials{current-game-mode}). ave-player-back-ram-score += (player-score - ave-player-back-ram-score)/(type-trials{current-game-mode}). } if(current-game-mode == MODE_FIGHT || current-game-mode == MODE_PRED || current-game-mode == MODE_RAM || current-game-mode == MODE_BACKRAM):{ ave-group-score += (group-score - ave-group-score)/((type-trials{MODE_PRED})+(type-trials{MODE_FIGHT})+(type-trials{MODE_RAM})+(type-trials{MODE_BACKRAM})). } if(current-game-mode == MODE_FIGHT || current-game-mode == MODE_PREY || current-game-mode == MODE_RAM || current-game-mode == MODE_BACKRAM):{ ave-player-score += (player-score - ave-player-score)/((type-trials{MODE_PREY})+(type-trials{MODE_FIGHT})+(type-trials{MODE_RAM})+(type-trials{MODE_BACKRAM})). } self tally-up-fitness-scores. # With random behavior syllabus, behavior vectors can be collected immediately # because the set of input vectors was already randomly generated. if (random-behavior-syllabus && behavior-diversity) : self gather-behavior-vectors. group-score = 0. player-score = 0. player-powerups = 0. # Get hash data from monster and store it if (commandline bit-param named "track-mode-usage") : { self track-mode-usage. } if current-eval == (self get-real-num-evals) : { if (commandline bit-param named "track-mode-usage") : { ave-percent-mode-usage = (self average-percent-mode-usage). # Whenever this runs, underused modes are marked for deletion at the # point when the network is next copied, meaning that the fitness scores # of the network still apply to the particular network, but if evolution # every tries to make use of the network's mutated offspring, then the # underused mode will be removed. if (commandline bit-param named "delete-underused-modes") : { self mark-underused-modes-for-deletion. } } if current-population == POPULATION_PARENTS : { # Behavior vectors are observed during parent eval and cannot be collected until # after the parent eval phase. if (observed-behavior-syllabus && behavior-diversity) : self gather-all-behavior-vectors. self end-parent-eval-phase. } else if current-population == POPULATION_CHILDREN : { # The same vectors observed during the parent eval phase need to be used by the children. if (observed-behavior-syllabus && behavior-diversity) : self gather-all-behavior-vectors. if behavior-diversity : (self fill-in-behavior-diversity). temp = (commandline string-param named "name"). if (file-output && (temp != "")) : # Experiments without names are just quick tests, and shouldn't write scores { temp2 = "-Gen". self write-current-scores to-file "$temp$temp2$generation" write-children 0. } self end-child-eval-phase. if random-behavior-syllabus : { # The syllabus changes whenever the whole population changes behavior-state randomize-syllabus length (self get-num-sensors). } else if observed-behavior-syllabus : { # Determine new set of sample points # NOTE: It is safe to call this here because "end-child-eval-phase" # has already switched the population back to parent phase behavior-state determine-observed-syllabus-sample-points. } } # At this point, the "current-population" will have already been switched self end-phase. current-eval = 0. self blank-current-fitnesses. self zero-scores. } #print "Before: current-game-mode-counter:", (self get-current-game-mode-counter). self switch-current-game-mode. # Changes current-game-mode-counter #print "After: current-game-mode-counter:", (self get-current-game-mode-counter). if ((self get-current-game-mode-counter) > 0) && (commandline bit-param named "switch-task-during-eval") : { #print "Just appearance and scores". player set-appearance. for i=0, i<|monsters|, i++ : monsters{i} reset-scores. } else { #print "Positions and scores". self spawn-player. for i=0, i<|monsters|, i++ : monsters{i} reset. } + to update-fitness-averages: i (int). for i=0, i<|fitness-info-list|, i++ : { #print "Fitness $i: best:", fitness-info-list{i}{SLOT_CURRENT_BEST_FITNESS}. fitness-info-list{i}{SLOT_BEST_AVE} += recency-weighted-alpha * (fitness-info-list{i}{SLOT_CURRENT_BEST_FITNESS} - fitness-info-list{i}{SLOT_BEST_AVE}). fitness-info-list{i}{SLOT_WORST_AVE} += recency-weighted-alpha * (fitness-info-list{i}{SLOT_CURRENT_WORST_FITNESS} - fitness-info-list{i}{SLOT_WORST_AVE}). fitness-info-list{i}{SLOT_CURRENT_AVE_AVE} += recency-weighted-alpha * (fitness-info-list{i}{SLOT_CURRENT_AVE} - fitness-info-list{i}{SLOT_CURRENT_AVE_AVE}). } + to end-parent-eval-phase: # Input connectivity is based only on parents self sum-input-connectivity. if behavior-diversity : { free parent-behavior-vectors. parent-behavior-vectors = current-behavior-vectors. } free parent-fitnesses. parent-fitnesses = current-fitnesses. self parents-survive-another-generation. self get-random-children. self update-starting-innovation-counter. current-population = POPULATION_CHILDREN. # pick the last population so that immediate incrementing and modulus leads back to zero if homogeneous : current-population-num = ((subpop-size * children-per-parent) - 1). else current-population-num = (((subpop-size * children-per-parent) / monsters-from-each-subpop) - 1). + to fill-in-behavior-diversity: i (int). j (int). diversity (double). # Add current-behavior-vectors to parent-behavior-vectors to get all # vectors in one list, with parent vectors at the front. Technically, # parent-behavior-vectors contains child vectors as well at this point. # First go through each subpop for i = 0, i < |current-behavior-vectors|, i++ : { for j = 0, j < |current-behavior-vectors{i}|, j++ : { push (current-behavior-vectors{i}{j}) onto (parent-behavior-vectors{i}). } } # Now compare each behavior vector to all others to get the average distance # from the rest of population # Each subpop for i = 0, i < |parent-behavior-vectors|, i++ : { # Each individual for j = 0, j < |parent-behavior-vectors{i}|, j++ : { # Remember, that "parent-behavior-vectors" actually contains the child behavior vectors as well now diversity = (behavior-state get-behavioral-diversity-score of j within (parent-behavior-vectors{i})). if (j < |parent-fitnesses{i}|) : # Add to parent fitnesses { parent-fitnesses{i}{j}{diversity-fitness-index} = diversity. } else { # Add to child fitnesses, which are still stored in current-fitnesses current-fitnesses{i}{(j - |parent-fitnesses{i}|)}{diversity-fitness-index} = diversity. } } } free parent-behavior-vectors. free current-behavior-vectors. + to end-child-eval-phase: i (int). keeper-ids (list). alpha (double). standard (int). if (generation == ((commandline num-param named "max-gens") - 1)) : { #print "Multiply evals at gen: $generation/",(commandline num-param named "max-gens"). num-evals *= (commandline num-param named "final-eval-multiplier"). } standard = 1. free child-fitnesses. child-fitnesses = current-fitnesses. if goals-as-constraints : { selection set-goal-constraints from fitness-info-list. } keeper-ids = {}. for i = 0, i < number-of-subpops, i++ : { push {} onto keeper-ids. keeper-ids{i} = (selection get-best choose (|parent-fitnesses{i}|) of-population (self merge-fitnesses of i)). } stagnation-counter++. self count-successful-individuals from keeper-ids. log update-log-averages. if (stagnation-counter > (commandline num-param named "stagnation-threshold")) : { print "$stagnation-counter >", (commandline num-param named "stagnation-threshold"). self increase-stagnation-threshold. self zero-scores. log reset-log-averages. if (commandline bit-param named "burst-mutation-after-stagnation") : { standard = 0. # Many mutations to get unstuck self pick-new-parents from keeper-ids. ga burst-mutations population parent-brains. } else if (commandline bit-param named "decrease-goals-after-stagnation") : { # Decrease goals, but don't change population in any other way alpha = (commandline num-param named "goal-increase-alpha"). for i = 0, i < |fitness-info-list|, i++ : { # Goal is decreased because objective is being used, meaning it is not yet achieved if(fitness-info-list{i}{SLOT_USE_GOAL} && fitness-info-list{i}{SLOT_USE_OBJECTIVE}) : { print "Decreasing ", fitness-info-list{i}{SLOT_DISPLAY_LABEL}. fitness-info-list{i}{SLOT_GOAL} += alpha * (fitness-info-list{i}{SLOT_CURRENT_WORST_FITNESS} - fitness-info-list{i}{SLOT_GOAL}). self reset-fitness-average at i. } } if partition-tug : selection set-objective-goals to (self get-fitness-goals). } else { standard = 0. # Do all networks need to be freed? self load-last-save. } stagnation-counter = 0. if (commandline bit-param named "easier-after-stagnation") : { self decrease-challenge. } } if standard : { selection advance-generation. self pick-new-parents from keeper-ids. # This should run before the log averages are updated! #self count-successful-individuals from keeper-ids. self update-best-and-worst-fitnesses from keeper-ids. #It is now safe to increase goals that were flagged to be increased earlier self increase-pending-goals. } current-population = POPULATION_PARENTS. #current-population-num = ((subpop-size / monsters-from-each-subpop) - 1). # How long has this been running in a weird way? Does it matter? if homogeneous : current-population-num = ((subpop-size * children-per-parent) - 1). else current-population-num = (((subpop-size * children-per-parent) / monsters-from-each-subpop) - 1). # Environment + to draw-net net theNet (object): if view: { if (theNet is a "MultiNetwork") : { view draw net (theNet current-net). } else { view draw net theNet. } } + to get-brain-pool: return brain-pool. + to get-math: return math. + to get-list-ops: return list-ops. + to get-behavior-state: return behavior-state. + to get-mode-arbitrator: return mode-arbitrator. + to get-commandline: return commandline. + to get-graphics: return graphics. + to get-triangulate: return triangulate. + to reset-shuffle-offset: shuffle-offset = subpop-size - SHUFFLE_JUMP. # SMEG:put in Environment.tz + to make-walls: wallSize (vector). wallColor (vector). wallSize = (1,(HALF_WALL_HEIGHT * 2),(HALF_WALL_LENGTH * 2)). wallColor = (0,0,1). new Wall create at (-HALF_WALL_LENGTH,HALF_WALL_HEIGHT,0) size wallSize color wallColor. new Wall create at (HALF_WALL_LENGTH,HALF_WALL_HEIGHT,0) size wallSize color wallColor. wallSize = ((HALF_WALL_LENGTH * 2),(HALF_WALL_HEIGHT * 2),1). new Wall create at (0,HALF_WALL_HEIGHT,-HALF_WALL_LENGTH) size wallSize color wallColor. new Wall create at (0,HALF_WALL_HEIGHT,HALF_WALL_LENGTH) size wallSize color wallColor. # SMEG:put in Environment.tz + to place-powerups: new HealthBoost create radius 2.0 color (1,0,1). new SpeedBoost create radius 2.0 color (0,1,1). new GunBoost create radius 2.0 color (1,0.5,0). # Monster positions + to get-nearest-monster from loc (vector): return (triangulate get-nearest-object to loc given monsters). + to player-is-surrounded: return (triangulate is-surrounded by monsters point-at (player get-location)). # loc: position on plane # direction: points out from the given position + to get-angle-to-monster-center from loc (vector) facing direction (vector): return (triangulate get-angle-to-center from loc facing direction given monsters). # loc: position on plane # direction: points out from the given position + to get-angle-to-nearest-monster-in-front from loc (vector) facing direction (vector): return (triangulate get-angle-to-nearest-monster-in-front from loc facing direction given monsters). # monster1: index in list monsters # monster2: index in list monsters # - monster1 != monster2 + to get-signed-neg-difference-in-heading-from-heading-rear of monster1 (int) to monster2 (int): return (triangulate get-signed-neg-difference-in-heading-from-heading-rear of monster1 to monster2 given monsters). # monster1: index in list monsters # monster2: index in list monsters # - monster1 != monster2 + to get-signed-neg-angle-from-rear of monster1 (int) to monster2 (int): return (triangulate get-signed-neg-angle-from-rear of monster1 to monster2 given monsters). # mon: monster object + to get-angle-to-monster-nearest to mon (object): if (mon get-deaths) > 0 : return 0. return (triangulate get-angle-to-nearest-object from (mon get-location) facing (mon get-facing) given monsters). # mon: monster object + to get-angle-to-bullet-nearest to mon (object): if (mon get-deaths) > 0 : return 0. return (triangulate get-angle-to-nearest-object from (mon get-location) facing (mon get-facing) given (all Bullet)). + to get-close-player-impulse for-index i (int): return (monsters{i} get-close-player-impulse). + to get-very-close-player-impulse for-index i (int): return (monsters{i} get-very-close-player-impulse). }