Advertisement
Code-Akisame

LuigI/O Version 3 with Hard mode addons

Dec 16th, 2018
1,184
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 98.03 KB | None | 0 0
  1. --LuigI/O v3.0, a neuroevolutionary AI designed to teach itself how to beat Super Mario Bros and Lost Levels
  2.  
  3. --Based on MarI/O created by Sethbling
  4. --LuigI/O versions 1, 2, and many minor adjustments and bugfixes made by Akisame
  5. --LuigI/O version 3 made by Electra & Akisame
  6. --Thanks to LuigI/O testers Akisame, Electra, Jonathan, AlejoGDOfficial, and Niko.
  7.  
  8. --V3 changelog: https://pastebin.com/KxtgyRe6
  9.  
  10. -- Pressing N will show the Neural net, pressing M will show the mutation rates, pressing L will load the last saved generation, pressing B will display the genome with the top fitness.
  11.  
  12. -- To use this script you will need to download FCEUX and create a savestate in state 1 as as player 1 (mario) for smb or as either player in Lost Levels.
  13. -- If you are playing Lost Levels, set this variable to 1:
  14. LostLevels = 0
  15. -- If you want to play as Luigi in SMB1, set this variable to 2:
  16. player = 2
  17. -- To set the game in turbo, do NES -> Emulation Speed -> Turbo, also make sure to set priority to realtime in Task Manager
  18. -- If you want it to go as fast as possible turn off the neural net win N, it doubles the speed basically
  19.  
  20. -- Click file -> lua -> 'new lua script window' and load the script.
  21. -- Have fun!
  22.  
  23. -- Keep in mind that this code is provided for Non-Commercial usage and it is not permitted to request financial compensation (either by means of ads, donations, subscriptions or other means) for selling, streaming or otherwise previewing this code or its execution.
  24.  
  25. --FCEUX doesn't allow for user string input but if you press 'L' on your keyboard it should load the latest generation that was saved
  26. --for loading specific generations replace nil with the filename as shown in the example below
  27. savedpool = nil --"backups/backup.666.SMB8-3.state.pool"
  28. --savedpool = "backup.71.SMB2-4.state.pool"
  29. --savedpool = "backups/backup.118.SMB2-1.state.pool"
  30.  
  31. -- HUD options. These can be changed on the fly by pressing 'M' for the mutation rates and 'N' for the network
  32. mutation_rates_disp = false
  33. neural_net_disp = true
  34.  
  35. --set to false if you want warning popups before loading anything that might cause you to lose your current progress
  36. nopopup = true
  37.  
  38. savestate_slot = 1 -- Load the level from FCEUX savestate slot. Set to 3 if you are loading a level that mario has reached by completing another level
  39.  
  40. --SAVE_LOAD_FILE = "test.pool" --filename to be used
  41. SAVE_LOAD_FILE = nil --auto generate appropriate name from level values in ram (might not completely match with actual level)
  42.  
  43. AllowAutoTurbo = true --Automatic turbo
  44. AllowSlowdownNearMax = false --This is slow down the turbo when it nears to furthest it has currently gotten
  45. FirstGenSpeedup = false --This will speed up the first generation
  46. BottleneckTurbo = false --Activate turbo on bottleneck detection
  47. TurboGenBottleneck = 20 --will start the turbo when it is in a bottleneck for 20 generations. Please adjust to match your taste
  48.  
  49. World43SavestateSlot = 2
  50.  
  51. activateNicknames = true --allows you to give species nicknames
  52. displayBasicInfo = true --writes basic info about a species to a file so you can show it in a stream
  53.  
  54. os.execute("mkdir backups") --create the folder to save the pools in
  55. os.execute("mkdir v3wins") --create a folder for the v3 winning genomes
  56. os.execute("mkdir v2wins") --create a folder for the v2 winning genomes
  57.  
  58.  
  59. SavestateObj = savestate.object(savestate_slot)
  60.  
  61.     ButtonNames = {
  62.         "A",
  63.         "B",
  64.         "up",
  65.         "down",
  66.         "left",
  67.         "right",
  68.     }
  69.  
  70.  
  71. BoxRadius = 6
  72. InputSize = (BoxRadius*2+1)*(BoxRadius*2+1)
  73.  
  74. switchtime = {10,12,18}
  75. switchtimer = {}
  76. initialswitchvalue = {}
  77. for i=1,#switchtime do
  78.     switchtimer[i] = switchtime[i]
  79.     initialswitchvalue[i] = 1
  80. end
  81.  
  82. Inputs = InputSize+1+#initialswitchvalue+2
  83. Outputs = #ButtonNames
  84.  
  85. Population = 1000
  86. DeltaDisjoint = 2.0
  87. DeltaWeights = 0.4
  88. DeltaThreshold = 1.0
  89.  
  90. keyflag = false --used for keyboard input
  91. endlevel = false --flag to detect a level finish
  92. preparenext = false --flag for preparing for the next level
  93. secondbest = 0 --second best fitness
  94. maxright = 0 --Highest fitness without speed compensation
  95. restoreturbo = false --flag for temporary turning off turbo
  96. rerunning = false --flag for requiring rerunning the level if it finished with turbo enabled
  97. killcounter = 0 --number of deaths
  98.  
  99. StaleSpecies = 25 --increased slightly to allow for longer evolution
  100. mariohole = false --flag for mario falling into a hole
  101. mariopipe = false --flag for mario exiting a pipe
  102. marioPipeEnter = false --new flag for entering a pipe
  103. offset = 0 --offset value for when mario exits a pipe
  104. timebonus = 0 --timebonus to prevent the hard drops in fitness when exiting a pipe
  105. maxcounter = 0 --species that reach the max fitness
  106. currentTracker = 0 --tracks location on screen
  107. loop = false --flag for when a loop is detected
  108. previousmaxfitness = 0 --memory slot for the previous max fitness. used to check if it increased more than a set amount
  109. bottleneckcounter = 0 --amount of generations since last "real" breakthrough
  110.  
  111. MutateConnectionsChance = 0.25
  112. PerturbChance = 0.90
  113. CrossoverChance = 0.75
  114. LinkMutationChance = 2.0
  115. NodeMutationChance = 0.50
  116. BiasMutationChance = 0.40
  117. SpeedMutationChance = 0.075
  118. StepSize = 0.1
  119. DisableMutationChance = 0.4
  120. EnableMutationChance = 0.2
  121. oscillationmutationchance = 0.2
  122. interbreedchance = 0.03
  123. networkswitchmutationchance = 0.01
  124.  
  125. nswitch = 1
  126. ntrigger = true
  127.  
  128. ncount = 0
  129.  
  130. TimeoutConstant = 120 --set to a higher value but see for yourself what is acceptable
  131.  
  132. MaxNodes = 1000000
  133.  
  134. MaxNetworks = 95 --Max networks it is able to have, 95 is basically no limit but you can set it lower
  135. speciesToAutoNetworkSwitch = 10 --Number of gens after each bottleneck loop where network chance is increased
  136. increasedNetworkChance = 0.02 --Increased network chance
  137. rsncChanceDecrease = 0.1 --Multiplier to the rsnc chance of adding new network rather than replacing, applied a number of times equal to the number of new networks
  138. replaceSecondNetworkChance = 0.02 --Chance of rsnc by default
  139. minBnLoopsBeforeNew = 1 --Number of bottleneck loops before the first network switch (increases by 1 per network switch)
  140.  
  141. gensBetweenPopOscil = 6 --generations after a breakthrough where the population decreases before starting a population oscillation
  142. popOscilMultiplier = 1 --Multiplier on the base length for an oscillation (default is about 20 for the first, 30 for the second, etc)
  143.  
  144. networkPenaltyInner = 0.7
  145. networkPenaltyOuter = 0.87
  146. -- Multiplies average by (Inner * Outer^networks)^networks to encourage new networks to not take over population until sure they are needed
  147. maxIncreaseWithoutBnReset = 30 --Number the max fitness can increase by before triggering bottleneck reset
  148.  
  149. hbValue = 60
  150.  
  151. function getPositions()
  152.         marioX = memory.readbyte(0x6D) * 0x100 + memory.readbyte(0x86)
  153.         marioY = memory.readbyte(0x03B8)+16
  154.         mariostate = memory.readbyte(0x0E) --get mario's state. (entering exiting pipes, dying, picking up a mushroom etc etc)
  155.         yspeed = memory.readbyte(0x009F) --y velocity 1-5 are falling and 250-255 is jumping
  156.         xspeed = memory.readbyte(0x0057) --x position ranging from -48 to 48
  157.         if yspeed >1 and yspeed <10 then
  158.             falling = true
  159.         else
  160.             falling = false
  161.         end
  162.  
  163.         currentscreen = memory.readbyte(0x071A) --finds current screen for loop detection
  164.         nextscreen = memory.readbyte(0x071B) --finds next screen
  165.  
  166.         CurrentWorld = memory.readbyte(0x075F) --finds the current world (value + 1 is world)
  167.         CurrentLevel = memory.readbyte(0x0760) --finds the current level (0=1 2=2 3=3 4=4)
  168.         demoruncheck = memory.readbyte(0x0770) --equals 0 for demo and 1 for normal run
  169.         statuscheck = memory.readbyte(0x0772) -- 3= playing 1 = loading
  170.  
  171.         screenX = memory.readbyte(0x03AD)
  172.         screenY = memory.readbyte(0x03B8)
  173. end
  174.  
  175. hiddenblocks = {}
  176. hitblocks = 0
  177.  
  178. function getTile(dx, dy)
  179.         local x = marioX + dx + 8
  180.         local y = marioY + dy - 16
  181.         local page = math.floor(x/256)%2
  182.  
  183.         local subx = math.floor((x%256)/16)
  184.         local suby = math.floor((y - 32)/16)
  185.         local addr = 0x500 + page*13*16+suby*16+subx
  186.  
  187.     local tilex = math.floor(x/16)
  188.     local tiley = math.floor(y/16)
  189.  
  190.     local hbid = 95 - LostLevels
  191.     if (memory.readbyte(addr) == hbid) then
  192.         local dupe = false
  193.         for b=1,#hiddenblocks do
  194.         if hiddenblocks[b][1] == tilex and hiddenblocks[b][2] == tiley then
  195.             dupe = true
  196.             break
  197.         end
  198.         end
  199.         if not dupe and tiley > -1 then
  200.             table.insert(hiddenblocks,{tilex,tiley})
  201.         end
  202.     end
  203.  
  204.     for b=1,#hiddenblocks do
  205.         if hiddenblocks[b][1] == tilex and hiddenblocks[b][2] == tiley then
  206.                 if memory.readbyte(addr) ~= hbid then
  207.                  table.remove(hiddenblocks,b)
  208.              hitblocks = hitblocks + 1
  209.              break
  210.         end
  211.         end
  212.     end
  213.  
  214.         if suby >= 13 or suby < 0 then
  215.             return 0
  216.         end
  217.  
  218.         if memory.readbyte(addr) ~= 0 then
  219.             return 1
  220.         else
  221.             return 0
  222.         end
  223. end
  224.  
  225. function getSprites()
  226.         local sprites = {}
  227.         for slot=0,4 do
  228.             local enemy = memory.readbyte(0xF+slot)
  229.             if enemy ~= 0 then
  230.                 local ex = memory.readbyte(0x6E + slot)*0x100 + memory.readbyte(0x87+slot)
  231.                 local ey = memory.readbyte(0xCF + slot)+36 --changed this to stop sprites from floating in mid air on the neural network
  232.                 sprites[#sprites+1] = {["x"]=ex,["y"]=ey}
  233.             end
  234.         end
  235.  
  236.         return sprites
  237. end
  238.  
  239. function getInputs()
  240.     getPositions()
  241.  
  242.     sprites = getSprites()
  243.  
  244.     local inputs = {}
  245.  
  246.     for dy=-BoxRadius*16,BoxRadius*16,16 do
  247.         for dx=-BoxRadius*16,BoxRadius*16,16 do
  248.             inputs[#inputs+1] = 0
  249.  
  250.             tile = getTile(dx, dy)
  251.             if tile == 1 and marioY+dy < 0x1B0 then
  252.                 inputs[#inputs] = 1
  253.             end
  254.  
  255.             for i = 1,#sprites do
  256.                 distx = math.abs(sprites[i]["x"] - (marioX+dx))
  257.                 disty = math.abs(sprites[i]["y"] - (marioY+dy+16))
  258.                 if distx <= 8 and disty <= 8 then
  259.                     inputs[#inputs] = -1
  260.                 end
  261.             end
  262.         end
  263.     end
  264.  
  265.     --mariovx = memory.read_s8(0x7B)
  266.     --mariovy = memory.read_s8(0x7D)
  267.  
  268.     return inputs
  269. end
  270.  
  271. function sigmoid(x)
  272.     return 2/(1+math.exp(-4.9*x))-1
  273. end
  274.  
  275. function newInnovation()
  276.     pool.innovation = pool.innovation + 1
  277.     return pool.innovation
  278. end
  279.  
  280. function newGSID()
  281.     pool.gsid = pool.gsid + 1
  282.     return pool.gsid
  283. end
  284.  
  285. function newPool()
  286.     local pool = {}
  287.     pool.species = {}
  288.     pool.generation = 0
  289.     pool.innovation = Outputs
  290.     pool.currentSpecies = 1
  291.     pool.currentGenome = 1
  292.     pool.currentFrame = 0
  293.     pool.measured = 0
  294.     pool.total = 0
  295.     hitblocks = 0
  296.     hiddenblocks = {}
  297.     pool.maxFitness = 0
  298.     pool.maxcounter = 0  --counter for %max species reached
  299.     pool.gsid = -1
  300.     return pool
  301. end
  302.  
  303. function newSpecies()
  304.     local species = {}
  305.     species.topFitness = 0
  306.     species.staleness = 0
  307.     species.genomes = {}
  308.     species.averageFitness = 0
  309.     species.nickname = 'none'
  310.     species.turbo = 'on'
  311.     species.gsid = newGSID()
  312.     species.topright = 0
  313.     return species
  314. end
  315.  
  316. function getCurrentGenome()
  317.     local species = pool.species[pool.currentSpecies]
  318.     return species.genomes[pool.currentGenome]
  319. end
  320.  
  321. function toRGBA(ARGB)
  322.     return bit.lshift(ARGB, 8) + bit.rshift(ARGB, 24)
  323. end
  324.  
  325.  
  326. function newGenome()
  327.     local genome = {}
  328.     genome.old = 0
  329.     genome.genes = {}
  330.     genome.genes[1] = {}
  331.     genome.fitness = 0
  332.     genome.adjustedFitness = 0
  333.     genome.network = {}
  334.     genome.network[1] = {}
  335.     genome.maxneuron = 0
  336.     genome.globalRank = 0
  337.     genome.oscillations = {{}}
  338.     genome.networkswitch = {}
  339.     for i=1,#switchtime do
  340.         genome.oscillations[1][i] = switchtime[i]
  341.     end
  342.     genome.mutationRates = {}
  343.     genome.mutationRates["connections"] = MutateConnectionsChance
  344.     genome.mutationRates["link"] = LinkMutationChance
  345.     genome.mutationRates["bias"] = BiasMutationChance
  346.     genome.mutationRates["node"] = NodeMutationChance
  347.     genome.mutationRates["enable"] = EnableMutationChance
  348.     genome.mutationRates["disable"] = DisableMutationChance
  349.     genome.mutationRates["step"] = StepSize
  350.     genome.mutationRates["oscillation"] = oscillationmutationchance
  351.     genome.mutationRates["networkswitch"] = networkswitchmutationchance
  352.  
  353.     return genome
  354. end
  355.  
  356. function copyGenome(genome)
  357.     local genome2 = newGenome()
  358.     genome2.old = genome.old
  359.     for n=1,#genome.genes do
  360.         if n > 1 then
  361.             table.insert(genome2.genes, {})
  362.             table.insert(genome2.oscillations, {})
  363.         end
  364.         for g=1,#genome.genes[n] do
  365.             table.insert(genome2.genes[n], copyGene(genome.genes[n][g]))
  366.         end
  367.  
  368.         for i=1,#genome.oscillations[n] do
  369.             genome2.oscillations[n][i] = genome.oscillations[n][i]
  370.         end
  371.     end
  372.     for n=1,#genome.networkswitch do
  373.         table.insert(genome2.networkswitch, genome.networkswitch[n])
  374.     end
  375.     genome2.maxneuron = genome.maxneuron
  376.     genome2.mutationRates["connections"] = genome.mutationRates["connections"]
  377.     genome2.mutationRates["link"] = genome.mutationRates["link"]
  378.     genome2.mutationRates["bias"] = genome.mutationRates["bias"]
  379.     genome2.mutationRates["node"] = genome.mutationRates["node"]
  380.     genome2.mutationRates["enable"] = genome.mutationRates["enable"]
  381.     genome2.mutationRates["disable"] = genome.mutationRates["disable"]
  382.     genome2.mutationRates["oscillation"] = genome.mutationRates["oscillation"]
  383.     genome2.mutationRates["networkswitch"] = genome.mutationRates["networkswitch"]
  384.  
  385.     return genome2
  386. end
  387.  
  388. function basicGenome()
  389.     local genome = newGenome()
  390.     local innovation = 1
  391.  
  392.     genome.maxneuron = Inputs
  393.     mutate(genome, 1)
  394.  
  395.     return genome
  396. end
  397.  
  398. function newGene()
  399.     local gene = {}
  400.     gene.into = 0
  401.     gene.out = 0
  402.     gene.weight = 0.0
  403.     gene.enabled = true
  404.     gene.innovation = 0
  405.  
  406.     return gene
  407. end
  408.  
  409. function copyGene(gene)
  410.     local gene2 = newGene()
  411.     gene2.into = gene.into
  412.     gene2.out = gene.out
  413.     gene2.weight = gene.weight
  414.     gene2.enabled = gene.enabled
  415.     gene2.innovation = gene.innovation
  416.  
  417.     return gene2
  418. end
  419.  
  420. function copyGeneOld(gene)
  421.     local gene2 = newGene()
  422.     gene2.into = gene.into
  423.     gene2.out = gene.out
  424.     if gene2.into > Inputs-2 and gene2.into <= MaxNodes then gene2.into = gene2.into + 2 end
  425.     if gene2.out > Inputs-2 and gene2.out <= MaxNodes then gene2.out = gene2.out + 2 end
  426.        
  427.     gene2.weight = gene.weight
  428.     gene2.enabled = gene.enabled
  429.     gene2.innovation = gene.innovation
  430.  
  431.     return gene2
  432. end
  433.  
  434. function newNeuron()
  435.     local neuron = {}
  436.     neuron.incoming = {}
  437.     neuron.value = 0.0
  438.     neuron.switcher = false
  439.     neuron.timer = 60
  440.     neuron.multiplier = 1
  441.  
  442.     return neuron
  443. end
  444.  
  445. function generateNetwork(genome,printing)
  446.     for n=1,#genome.genes do
  447.         local network = {}
  448.         network.neurons = {}
  449.  
  450.         for i=1,Inputs do
  451.             network.neurons[i] = newNeuron()
  452.         end
  453.  
  454.         for o=1,Outputs do
  455.             network.neurons[MaxNodes+o] = newNeuron()
  456.         end
  457.  
  458.         table.sort(genome.genes[n], function (a,b)
  459.             return (a.out < b.out)
  460.         end)
  461.         for i=1,#genome.genes[n] do
  462.             local gene = genome.genes[n][i]
  463.             if gene.enabled then
  464.                 if network.neurons[gene.out] == nil then
  465.                     network.neurons[gene.out] = newNeuron()
  466.                 end
  467.                 local neuron = network.neurons[gene.out]
  468.                 table.insert(neuron.incoming, gene)
  469.                 if network.neurons[gene.into] == nil then
  470.                     network.neurons[gene.into] = newNeuron()
  471.                 end
  472.             end
  473.         end
  474.  
  475.         genome.network[n] = network
  476.     end
  477. end
  478.  
  479. function evaluateNetwork(n, inputs, genome)
  480.     local network = genome.network[n]
  481.     local Inputs = Inputs
  482.     if genome.old >= nswitch then
  483.         Inputs = Inputs -2
  484.     end
  485.     table.insert(inputs, 1) -- bias input node
  486.     for i = 1,#initialswitchvalue do
  487.         if genome.oscillations[n][i] > 0 then --oscillating nodes
  488.             if switchtimer[i] > 0 then
  489.                 switchtimer[i] = switchtimer[i] -1
  490.             else
  491.                 switchtimer[i] = genome.oscillations[n][i]
  492.                 initialswitchvalue[i] = initialswitchvalue[i]*-1
  493.             end
  494.         end
  495.         table.insert(inputs, initialswitchvalue[i])
  496.     end
  497.     if not (genome.old >= nswitch) then --speed nodes
  498.         if (xspeed < 100) then
  499.             table.insert(inputs,xspeed / 48)
  500.         else
  501.             table.insert(inputs,(xspeed - 256) / 48)
  502.         end
  503.         if (yspeed < 10) then
  504.             table.insert(inputs,yspeed / 5)
  505.         else
  506.             table.insert(inputs,(yspeed - 256) / 5)
  507.         end
  508.  
  509.         if #inputs ~= Inputs then
  510.             return {}
  511.         end
  512.     end
  513.     for i=1,Inputs do
  514.         network.neurons[i].value = inputs[i]
  515.     end
  516.     for _,neuron in pairs(network.neurons) do
  517.         local sum = 0
  518.         for j = 1,#neuron.incoming do
  519.             local incoming = neuron.incoming[j]
  520.             local other = network.neurons[incoming.into]
  521.             sum = sum + incoming.weight * other.value
  522.         end
  523.        
  524.         if #neuron.incoming > 0 then
  525.             if neuron.switcher and sigmoid(sum)>0 then
  526.                 neuron.timer = neuron.timer - 1
  527.             elseif neuron.switcher then
  528.                 neuron.timer = 120
  529.                 neuron.multiplier = 1
  530.             end
  531.            
  532.             if neuron.switcher and neuron.timer < 0 then
  533.                 neuron.multiplier = -neuron.multiplier
  534.                 neuron.timer = 10
  535.             end
  536.             neuron.value = sigmoid(sum) * neuron.multiplier
  537.            
  538.         end
  539.     end
  540.    
  541.     local outputs = {}
  542.     for o=1,Outputs do
  543.         local button = ButtonNames[o]
  544.         if network.neurons[MaxNodes+o].value > 0 then
  545.             outputs[button] = true
  546.         else
  547.             outputs[button] = false
  548.         end
  549.     end
  550.    
  551.     --emu.print(outputs)
  552.     --emu.print(pool.currentFrame/5)
  553.     --emu.print(network.neurons)
  554.     return outputs
  555. end
  556.  
  557. function crossover(g1, g2)
  558.     if g2.fitness > g1.fitness then
  559.         tempg = g1
  560.         g1 = g2
  561.         g2 = tempg
  562.     end
  563.     local child = newGenome()
  564.     for n=1,#g1.networkswitch do
  565.         table.insert(child.networkswitch, g1.networkswitch[n])
  566.     end
  567.     child.old = math.min(g1.old,g2.old)
  568.     for n=1,#g1.genes do
  569.         local innovations2 = {}
  570.         local g1old = g1.old >= n
  571.         local g2old = g2.old >= n
  572.         if n > 1 then
  573.             table.insert(child.genes,{})
  574.             table.insert(child.oscillations,{})
  575.         end
  576.         if #g2.genes >= n then
  577.             for i=1,#g2.genes[n] do
  578.                 local gene = g2.genes[n][i]
  579.                 innovations2[gene.innovation] = gene
  580.             end
  581.             for i=1,#g1.oscillations[n] do
  582.                 child.oscillations[n][i] = g1.oscillations[n][i]
  583.             end
  584.         else
  585.             for i=1,#g1.oscillations[n] do
  586.                 child.oscillations[n][i] = switchtime[i]
  587.             end
  588.         end
  589.         for i=1,#g1.genes[n] do
  590.             local gene1 = g1.genes[n][i]
  591.             local gene2 = innovations2[gene1.innovation]
  592.             if (g1old and not g2old) then
  593.                 if gene2 ~= nil and math.random(1,2) == 1 and gene2.enabled then
  594.                     table.insert(child.genes[n], copyGene(gene2))
  595.                 else
  596.                     table.insert(child.genes[n], copyGeneOld(gene1))
  597.                 end
  598.             elseif (g2old and not g1old) then
  599.                 if gene2 ~= nil and math.random(1,2) == 1 and gene2.enabled then
  600.                     table.insert(child.genes[n], copyGeneOld(gene2))
  601.                 else
  602.                     table.insert(child.genes[n], copyGene(gene1))
  603.                 end
  604.             else
  605.                 if gene2 ~= nil and math.random(1,2) == 1 and gene2.enabled then
  606.                     table.insert(child.genes[n], copyGene(gene2))
  607.                 else
  608.                     table.insert(child.genes[n], copyGene(gene1))
  609.                 end
  610.             end
  611.         end
  612.     end
  613.  
  614.     child.maxneuron = math.max(g1.maxneuron,g2.maxneuron)
  615.  
  616.     for mutation,rate in pairs(g1.mutationRates) do
  617.         child.mutationRates[mutation] = rate
  618.     end
  619.  
  620.     return child
  621. end
  622.  
  623. function randomNeuron(genes, nonInput)
  624.     local neurons = {}
  625.     if not nonInput then
  626.         for i=1,Inputs do
  627.             neurons[i] = true
  628.         end
  629.     end
  630.     for o=1,Outputs do
  631.         neurons[MaxNodes+o] = true
  632.     end
  633.     for i=1,#genes do
  634.         if (not nonInput) or genes[i].into > Inputs then
  635.             neurons[genes[i].into] = true
  636.         end
  637.         if (not nonInput) or genes[i].out > Inputs then
  638.             neurons[genes[i].out] = true
  639.         end
  640.     end
  641.     local count = 0
  642.     for _,_ in pairs(neurons) do
  643.         count = count + 1
  644.     end
  645.     local n = math.random(1, count)
  646.     for k,v in pairs(neurons) do
  647.         n = n-1
  648.         if n == 0 then
  649.             return k
  650.         end
  651.     end
  652.  
  653.     return 0
  654. end
  655.  
  656. function containsLink(genes, link)
  657.     for i=1,#genes do
  658.         local gene = genes[i]
  659.         if gene.into == link.into and gene.out == link.out then
  660.             return true
  661.         end
  662.     end
  663. end
  664.  
  665. function pointMutate(genome, which)
  666.     local step = genome.mutationRates["step"]
  667.     local gene = {}
  668.     for i=1,#genome.genes[which] do
  669.         gene = genome.genes[which][i]
  670.         if math.random() < PerturbChance then
  671.             gene.weight = gene.weight + math.random() * step*2 - step
  672.         else
  673.             gene.weight = math.random()*4-2
  674.         end
  675.     end
  676. end
  677.  
  678. function linkMutate(genome, forceBias, forceSpeed, which)
  679.     local neuron1 = randomNeuron(genome.genes[which], false)
  680.     local neuron2 = randomNeuron(genome.genes[which], true)
  681.  
  682.     local newLink = newGene()
  683.     if neuron1 <= Inputs and neuron2 <= Inputs then
  684.         --Both input nodes
  685.         return
  686.     end
  687.  
  688.     if neuron2 <= Inputs then
  689.         -- Swap output and input
  690.         local temp = neuron1
  691.         neuron1 = neuron2
  692.         neuron2 = temp
  693.     end
  694.  
  695.     newLink.into = neuron1
  696.     newLink.out = neuron2
  697.     if forceBias then
  698.         local adjustment = math.random(0,#initialswitchvalue)
  699.         newLink.into = Inputs - adjustment - 2
  700.     end
  701.     if forceSpeed then
  702.         local adjustment = math.random(0,1)
  703.         newLink.into = Inputs - adjustment
  704.     end
  705.     if containsLink(genome.genes[which], newLink) then
  706.         return
  707.     end
  708.     newLink.innovation = newInnovation()
  709.     newLink.weight = math.random()*4-2
  710.     table.insert(genome.genes[which], newLink)
  711. end
  712.  
  713. function nodeMutate(genome, which)
  714.     if #genome.genes[which] == 0 then
  715.         return
  716.     end
  717.  
  718.     genome.maxneuron = genome.maxneuron + 1
  719.     local gene = {}
  720.     gene = genome.genes[which][math.random(1,#genome.genes[which])]
  721.     if not gene.enabled then
  722.         return
  723.     end
  724.     gene.enabled = false
  725.  
  726.     local gene1 = copyGene(gene)
  727.     gene1.out = genome.maxneuron
  728.     gene1.weight = 1.0
  729.     gene1.innovation = newInnovation()
  730.     gene1.enabled = true
  731.     table.insert(genome.genes[which], gene1)
  732.  
  733.     local gene2 = copyGene(gene)
  734.     gene2.into = genome.maxneuron
  735.     gene2.innovation = newInnovation()
  736.     gene2.enabled = true
  737.     table.insert(genome.genes[which], gene2)
  738. end
  739.  
  740. function enableDisableMutate(genome, enable, which)
  741.     local candidates = {}
  742.     for _,gene in pairs(genome.genes[which]) do
  743.         if gene.enabled == not enable then
  744.             table.insert(candidates, gene)
  745.         end
  746.     end
  747.  
  748.     if #candidates == 0 then
  749.         return
  750.     end
  751.  
  752.     local gene = candidates[math.random(1,#candidates)]
  753.     gene.enabled = not gene.enabled
  754. end
  755.  
  756. function oscillationMutate(genome, which)
  757.     mutationpoint = math.random(1,#genome.oscillations[which])
  758.     if genome.oscillations[which][mutationpoint]>0 then
  759.         if math.random(1,2) == 1 then
  760.             genome.oscillations[which][mutationpoint] = genome.oscillations[which][mutationpoint] + 1
  761.         else
  762.             genome.oscillations[which][mutationpoint] = genome.oscillations[which][mutationpoint] - 1
  763.         end
  764.     end
  765.     if genome.oscillations[which][mutationpoint]<0 then
  766.         genome.oscillations[which][mutationpoint] = 0
  767.     end
  768. end
  769.  
  770. function NswitchMutate(genome)
  771.     which = #genome.networkswitch
  772.     if math.random() < 0.25 then
  773.         which = math.random(1,#genome.networkswitch)
  774.     end
  775.     genome.networkswitch[which] = genome.networkswitch[which] + math.random()-0.5
  776.     if genome.networkswitch[which] < 0 then
  777.         genome.networkswitch[which] = math.random(0,12)
  778.     end
  779.     if genome.networkswitch[which] > 12 then
  780.         genome.networkswitch[which] = math.random(0,12)
  781.     end
  782.     table.sort(genome.networkswitch, function(a,b)
  783.         return (a < b)
  784.     end)
  785. end
  786.  
  787. function mutate(genome, which)
  788.     for mutation,rate in pairs(genome.mutationRates) do
  789.         if math.random(1,2) == 1 then
  790.             genome.mutationRates[mutation] = 0.95*rate
  791.         else
  792.             genome.mutationRates[mutation] = 1.05263*rate
  793.         end
  794.     end
  795.     if math.random() < genome.mutationRates["connections"] then
  796.         pointMutate(genome, which)
  797.     end
  798.  
  799.     local p = genome.mutationRates["link"]
  800.     while p > 0 do
  801.         if math.random() < p then
  802.             linkMutate(genome, false, false, which)
  803.         end
  804.         p = p - 1
  805.     end
  806.  
  807.     p = genome.mutationRates["bias"]
  808.     while p > 0 do
  809.         if math.random() < p then
  810.             linkMutate(genome, true, false, which)
  811.         end
  812.         p = p - 1
  813.     end
  814.    
  815.     p = SpeedMutationChance
  816.     if math.random() < p and genome.old >= which then
  817.         linkMutate(genome, false, true, which)
  818.     end
  819.     p = p - 1
  820.  
  821.     p = genome.mutationRates["node"]
  822.     while p > 0 do
  823.         if math.random() < p then
  824.             nodeMutate(genome, which)
  825.         end
  826.         p = p - 1
  827.     end
  828.  
  829.     p = genome.mutationRates["enable"]
  830.     while p > 0 do
  831.         if math.random() < p then
  832.             enableDisableMutate(genome, true, which)
  833.         end
  834.         p = p - 1
  835.     end
  836.  
  837.     p = genome.mutationRates["disable"]
  838.     while p > 0 do
  839.         if math.random() < p then
  840.             enableDisableMutate(genome, false, which)
  841.         end
  842.         p = p - 1
  843.     end
  844.  
  845.     p = genome.mutationRates["oscillation"]
  846.     while p > 0 do
  847.         if math.random() < p then
  848.             oscillationMutate(genome, which)
  849.         end
  850.         p = p - 1
  851.     end
  852.  
  853.     if #genome.networkswitch > 0 then
  854.         p = genome.mutationRates["networkswitch"]
  855.         while p > 0 do
  856.             if math.random() < p then
  857.                 NswitchMutate(genome)
  858.             end
  859.             p = p - 1
  860.         end
  861.     end
  862. end
  863.  
  864. function disjoint(genes1, genes2)
  865.     local i1 = {}
  866.     for i = 1,#genes1 do
  867.         local gene = genes1[i]
  868.         i1[gene.innovation] = true
  869.     end
  870.  
  871.     local i2 = {}
  872.     for i = 1,#genes2 do
  873.         local gene = genes2[i]
  874.         i2[gene.innovation] = true
  875.     end
  876.  
  877.     local disjointGenes = 0
  878.     for i = 1,#genes1 do
  879.         local gene = genes1[i]
  880.         if not i2[gene.innovation] then
  881.             disjointGenes = disjointGenes+1
  882.         end
  883.     end
  884.  
  885.     for i = 1,#genes2 do
  886.         local gene = genes2[i]
  887.         if not i1[gene.innovation] then
  888.             disjointGenes = disjointGenes+1
  889.         end
  890.     end
  891.  
  892.     local n = math.max(#genes1, #genes2)
  893.  
  894.     return disjointGenes / n
  895. end
  896.  
  897. function weights(genes1, genes2)
  898.     local i2 = {}
  899.     for i = 1,#genes2 do
  900.         local gene = genes2[i]
  901.         i2[gene.innovation] = gene
  902.     end
  903.  
  904.     local sum = 0
  905.     local coincident = 0
  906.     for i = 1,#genes1 do
  907.         local gene = genes1[i]
  908.         if i2[gene.innovation] ~= nil then
  909.             local gene2 = i2[gene.innovation]
  910.             sum = sum + math.abs(gene.weight - gene2.weight)
  911.             coincident = coincident + 1
  912.         end
  913.     end
  914.     if coincident == 0 then
  915.         return 10
  916.     end
  917.     return sum / coincident
  918. end
  919.  
  920. function sameSpecies(genome1, genome2)
  921.     if #genome1.networkswitch ~= #genome2.networkswitch then
  922.         return false
  923.     end
  924.     for n=1,#genome1.networkswitch do
  925.         if math.abs(genome1.networkswitch[n] - genome2.networkswitch[n]) > 0.6 then
  926.             return false
  927.         end
  928.     end
  929.     for n=1,#genome1.genes do
  930.         --if genome2.genes[n] == nil then
  931.             --emu.print(genome1.genes)
  932.             --emu.print(genome1.networkswitch)
  933.             --emu.print(genome2.genes)
  934.             --emu.print(genome2.networkswitch)
  935.         --end
  936.         dd = DeltaDisjoint*disjoint(genome1.genes[n],genome2.genes[n])
  937.         dw = DeltaWeights*weights(genome1.genes[n],genome2.genes[n])
  938.         if dd + dw > DeltaThreshold then
  939.             return false
  940.         end
  941.     end
  942.     return true
  943. end
  944.  
  945. function rankGlobally()
  946.     local global = {}
  947.     for s = 1,#pool.species do
  948.         local species = pool.species[s]
  949.         for g = 1,#species.genomes do
  950.             table.insert(global, species.genomes[g])
  951.         end
  952.     end
  953.     table.sort(global, function (a,b)
  954.         return (a.fitness < b.fitness)
  955.     end)
  956.  
  957.     for g=1,#global do
  958.         global[g].globalRank = g
  959.     end
  960. end
  961.  
  962. function calculateAverageFitness(species)
  963.     local total = 0
  964.  
  965.     for g=1,#species.genomes do
  966.         local genome = species.genomes[g]
  967.         total = total + genome.globalRank
  968.     end
  969.         if species.topFitness < pool.averagemaxfitness - (pool.standardDeviationMaxFitness *2) then
  970.             species.averageFitness = (total / #species.genomes) / 4
  971.         elseif species.topFitness < pool.averagemaxfitness - pool.standardDeviationMaxFitness then
  972.             species.averageFitness = (total / #species.genomes) / 2.5
  973.         elseif species.topFitness > pool.averagemaxfitness + (pool.standardDeviationMaxFitness *3) then
  974.             species.averageFitness = (total / #species.genomes) * 2
  975.         elseif species.topFitness > pool.averagemaxfitness + (pool.standardDeviationMaxFitness *2) then
  976.             species.averageFitness = (total / #species.genomes) * 1.5
  977.         else
  978.             species.averageFitness = total / #species.genomes
  979.         end
  980.         species.averageFitness = species.averageFitness * math.pow(networkPenaltyOuter*math.pow(networkPenaltyInner,#species.genomes[1].networkswitch),#species.genomes[1].networkswitch)
  981. end
  982.  
  983. function calculateStandardDeviationMax()
  984.     local deviationtotal = 0
  985.     for s=1,#pool.species do
  986.         deviationtotal = deviationtotal + math.abs(pool.species[s].topFitness - pool.averagemaxfitness)
  987.     end
  988.     pool.standardDeviationMaxFitness = deviationtotal / #pool.species
  989. end
  990.  
  991. function AverageMaxFitness()
  992.     local total = 0
  993.     for s = 1,#pool.species do
  994.         local species = pool.species[s]
  995.         total = total + species.topFitness
  996.     end
  997.  
  998.     pool.averagemaxfitness = total / #pool.species
  999. end
  1000.  
  1001. function totalAverageFitness()
  1002.     local total = 0
  1003.     for s = 1,#pool.species do
  1004.         local species = pool.species[s]
  1005.         total = total + species.averageFitness
  1006.     end
  1007.  
  1008.     return total
  1009. end
  1010.  
  1011. function cullSpecies(cutToOne)
  1012.     for s = 1,#pool.species do
  1013.         local species = pool.species[s]
  1014.  
  1015.         table.sort(species.genomes, function (a,b)
  1016.             return (a.fitness > b.fitness)
  1017.         end)
  1018.  
  1019.         local percent = 0.5
  1020.         --if species.staleness > 10 then
  1021.             --percent = math.pow(0.5,(species.staleness+5)/15)
  1022.         --end
  1023.         local remaining = math.ceil(#species.genomes*percent)
  1024.         if cutToOne then
  1025.             remaining = 1
  1026.         end
  1027.         while #species.genomes > remaining do
  1028.             table.remove(species.genomes)
  1029.         end
  1030.     end
  1031. end
  1032.  
  1033. function breedChild(species)
  1034.     local child = {}
  1035.     if math.random() < CrossoverChance then
  1036.         g1 = species.genomes[math.random(1, #species.genomes)]
  1037.         g2 = species.genomes[math.random(1, #species.genomes)]
  1038.         child = crossover(g1, g2)
  1039.     else
  1040.         g = species.genomes[math.random(1, #species.genomes)]
  1041.         child = copyGenome(g)
  1042.     end
  1043.  
  1044.     local which = #child.genes
  1045.     if which > 1 and species.topright > 0 then
  1046.         emu.print(child.networkswitch[#child.networkswitch])
  1047.         local mutatePrevNetworkChance = 0.5 + (child.networkswitch[#child.networkswitch]-species.topright/500)/2
  1048.         if math.random() < mutatePrevNetworkChance then
  1049.             which = #child.genes - 1
  1050.         end
  1051.     end
  1052.    
  1053.     mutate(child,which)
  1054.  
  1055.     return child
  1056. end
  1057.  
  1058. function secondbestspecies() --added this to help prevent the formation of monospecies when LuigI/O encounters a major bottleneck
  1059.     local bestfitness = 0
  1060.     local secondbestfitness = 0
  1061.     for s = 1,#pool.species do
  1062.         local species = pool.species[s]
  1063.  
  1064.         if species.topFitness > bestfitness then
  1065.             secondbestfitness = bestfitness
  1066.             bestfitness = species.topFitness
  1067.         elseif species.topFitness > secondbestfitness then
  1068.             secondbestfitness = species.topFitness
  1069.         end
  1070.     end
  1071.     return secondbestfitness
  1072. end
  1073.  
  1074.  
  1075. function removeStaleSpecies()
  1076.     local survived = {}
  1077.     --emu.print("Max Fitness: ".. pool.maxFitness ..". second best: ".. secondbest)
  1078.     for s = 1,#pool.species do
  1079.         local species = pool.species[s]
  1080.  
  1081.         table.sort(species.genomes, function (a,b)
  1082.             return (a.fitness > b.fitness)
  1083.         end)
  1084.  
  1085.         if species.genomes[1].fitness > species.topFitness then
  1086.             species.topFitness = species.genomes[1].fitness
  1087.             species.staleness = 0
  1088.         else
  1089.             species.staleness = species.staleness + 1
  1090.         end
  1091.     end
  1092.     secondbest = secondbestspecies()
  1093.  
  1094.     for s = 1,#pool.species do
  1095.         local species = pool.species[s]
  1096.         if species.staleness < StaleSpecies or species.topFitness >= secondbest then --originally species.topFitness >= pool.maxFitness
  1097.             table.insert(survived, species)
  1098.         end
  1099.     end
  1100.  
  1101.     pool.species = survived
  1102. end
  1103.  
  1104. function removeWeakSpecies()
  1105.     local survived = {}
  1106.     local breed
  1107.     local sum = totalAverageFitness()
  1108.     for s = 1,#pool.species do
  1109.         local species = pool.species[s]
  1110.         breed = math.floor(species.averageFitness / sum * Population)
  1111.         if breed >= 1 then
  1112.             table.insert(survived, species)
  1113.         end
  1114.     end
  1115.  
  1116.     pool.species = survived
  1117. end
  1118.  
  1119.  
  1120. function addToSpecies(child)
  1121.     local foundSpecies = false
  1122.     for s=1,#pool.species do
  1123.         local species = pool.species[s]
  1124.         if not foundSpecies and sameSpecies(child, species.genomes[1]) then
  1125.             table.insert(species.genomes, child)
  1126.             foundSpecies = true
  1127.         end
  1128.     end
  1129.  
  1130.     if not foundSpecies then
  1131.         local childSpecies = newSpecies()
  1132.         table.insert(childSpecies.genomes, child)
  1133.         table.insert(pool.species, childSpecies)
  1134.     end
  1135. end
  1136.  
  1137. function replaceSecondNetwork(g1,g2,tr)
  1138.     local genome2 = newGenome()
  1139.    
  1140.     for n=1,#g1.genes do
  1141.         if n > 1 then
  1142.             table.insert(genome2.genes,{})
  1143.             table.insert(genome2.oscillations,{})
  1144.         end
  1145.         if g1.old >= n then
  1146.             for g=1,#g1.genes[n] do
  1147.                 table.insert(genome2.genes[n], copyGeneOld(g1.genes[n][g]))
  1148.             end
  1149.         else
  1150.             for g=1,#g1.genes[n] do
  1151.                 table.insert(genome2.genes[n], copyGene(g1.genes[n][g]))
  1152.             end
  1153.         end
  1154.         for i=1,#g1.oscillations[n] do
  1155.             genome2.oscillations[n][i] = g1.oscillations[n][i]
  1156.         end
  1157.     end
  1158.     for n=1,#g1.networkswitch do
  1159.         genome2.networkswitch[n] = g1.networkswitch[n]
  1160.     end
  1161.     genome2.maxneuron = g1.maxneuron
  1162.     genome2.mutationRates["connections"] = g1.mutationRates["connections"]
  1163.     genome2.mutationRates["link"] = g1.mutationRates["link"]
  1164.     genome2.mutationRates["bias"] = g1.mutationRates["bias"]
  1165.     genome2.mutationRates["node"] = g1.mutationRates["node"]
  1166.     genome2.mutationRates["enable"] = g1.mutationRates["enable"]
  1167.     genome2.mutationRates["disable"] = g1.mutationRates["disable"]
  1168.     genome2.mutationRates["oscillation"] = g1.mutationRates["oscillation"]
  1169.     genome2.mutationRates["networkswitch"] = g1.mutationRates["networkswitch"]
  1170.  
  1171.     if g1.fitness + 300 <= pool.maxFitness or math.random() > math.pow(rsncChanceDecrease,#genome2.networkswitch) or #genome2.genes >= MaxNetworks or bnLoops < #genome2.genes then
  1172.        
  1173.         genome2.genes[#genome2.genes] = {}
  1174.         which = math.random(1,#g2.genes)
  1175.         if g2.old >= which then
  1176.             for g=1,#g2.genes[which] do
  1177.                 table.insert(genome2.genes[#genome2.genes], copyGeneOld(g2.genes[which][g]))
  1178.             end
  1179.         else
  1180.             for g=1,#g2.genes[which] do
  1181.                 table.insert(genome2.genes[#genome2.genes], copyGene(g2.genes[which][g]))
  1182.             end
  1183.         end
  1184.     else
  1185.         table.insert(genome2.genes,{})
  1186.         which = math.random(1,#g2.genes)
  1187.         if g2.old >= which then
  1188.             for g=1,#g2.genes[which] do
  1189.                 table.insert(genome2.genes[#genome2.genes], copyGeneOld(g2.genes[which][g]))
  1190.             end
  1191.         else
  1192.             for g=1,#g2.genes[which] do
  1193.                 table.insert(genome2.genes[#genome2.genes], copyGene(g2.genes[which][g]))
  1194.             end
  1195.         end
  1196.         table.insert(genome2.oscillations,{switchtime[1],switchtime[2],switchtime[3]})
  1197.         table.insert(genome2.networkswitch,tr/500 - 0.2-0.1*math.random())
  1198.     end
  1199.     table.sort(genome2.networkswitch, function(a,b)
  1200.         return (a < b)
  1201.     end)
  1202.     return genome2
  1203. end
  1204.  
  1205. function FileExists(name)
  1206.     local file = io.open(name,"r")
  1207.     if file~=nil then io.close(file) return true else return false end
  1208. end
  1209.  
  1210. bnLoops = 0
  1211. function newGeneration()
  1212.     writeFile("backups/backup3." .. pool.generation .. "." .. SAVE_LOAD_FILE)
  1213.     if originalmaxfitness == nil or originalmaxfitness > previousmaxfitness then
  1214.         originalmaxfitness = previousmaxfitness
  1215.     end
  1216.     local population = Population
  1217.     if pool.maxFitness-maxIncreaseWithoutBnReset > previousmaxfitness then
  1218.         previousmaxfitness = pool.maxFitness
  1219.         originalmaxfitness = pool.maxFitness
  1220.         bottleneckcounter = 0
  1221.         if AllowAutoTurbo then
  1222.             emu.speedmode("normal")
  1223.             turbo = false
  1224.         end
  1225.         bnLoops = 0
  1226.     elseif pool.maxFitness - (4*maxIncreaseWithoutBnReset) > originalmaxfitness then
  1227.         previousmaxfitness = pool.maxFitness
  1228.         originalmaxfitness = pool.maxFitness
  1229.         bottleneckcounter = 0
  1230.         if AllowAutoTurbo then
  1231.             emu.speedmode("normal")
  1232.             turbo = false
  1233.         end
  1234.         bnLoops = 0
  1235.     else
  1236.         bottleneckcounter = bottleneckcounter + 1
  1237.         previousmaxfitness = pool.maxFitness
  1238.     end
  1239.     local bottleneckc = bottleneckcounter
  1240.     local GBPO = gensBetweenPopOscil
  1241.     local targetPop = math.min(900,500 + 100*bnLoops)
  1242.     local length= math.min(12*popOscilMultiplier,(5 + 2*bnLoops)*popOscilMultiplier)
  1243.     local targetPopLower = math.min(300,600 - targetPop/2)
  1244.     local currentPopLower = math.min(300,targetPopLower+50)
  1245.  
  1246.     if bottleneckc <= GBPO then
  1247.     if population > 300 then
  1248.             population = math.floor(population * 0.905 * 0.905)
  1249.             if population < 300 then population = 300 end
  1250.         end
  1251.     end
  1252.     if bottleneckc > GBPO then
  1253.         if bottleneckc < GBPO + length then
  1254.             population = currentPopLower + math.floor((targetPop - currentPopLower)/length*(bottleneckc-GBPO))
  1255.         elseif bottleneckc == GBPO + length then
  1256.             population = targetPop
  1257.         elseif bottleneckc <= GBPO + length*3 then
  1258.             population = targetPopLower + math.floor((targetPop - targetPopLower)/length/2*(GBPO+length*3-bottleneckc))
  1259.         end
  1260.         if bottleneckc == GBPO + length*3 then
  1261.             bottleneckcounter = 0
  1262.             bnLoops = bnLoops + 1
  1263.         end
  1264.     end
  1265.     if bottleneckcounter > TurboGenBottleneck and AllowAutoTurbo and BottleneckTurbo then
  1266.         emu.speedmode("turbo")
  1267.         turbo = true
  1268.     end
  1269.    
  1270.     Population = population
  1271.  
  1272.  
  1273.     cullSpecies(false) -- Cull the bottom half of each species
  1274.     rankGlobally()
  1275.     removeStaleSpecies()
  1276.     AverageMaxFitness()
  1277.     calculateStandardDeviationMax()
  1278.     rankGlobally()
  1279.     local numSpecies = #pool.species
  1280.     for s = 1,numSpecies do
  1281.         local species = pool.species[s]
  1282.         calculateAverageFitness(species)
  1283.     end
  1284.     removeWeakSpecies()
  1285.     local sum = totalAverageFitness()
  1286.     local children = {}
  1287.     local breed
  1288.     for s = 1,#pool.species do
  1289.         local species = pool.species[s]
  1290.         breed = math.floor(species.averageFitness / sum * population) - 1
  1291.         if breed > 10 then
  1292.             breed = math.ceil(breed * math.sqrt(species.topFitness / pool.maxFitness))
  1293.         end
  1294.         if breed > population/4 then
  1295.             breed = math.floor(Population/4)
  1296.         end
  1297.         for i=1,breed do
  1298.             table.insert(children, breedChild(species))
  1299.         end
  1300.     end
  1301.     cullSpecies(true) -- Cull all but the top member of each species
  1302.     if #pool.species < 30 then
  1303.         interbreedchance = 0.2
  1304.     else
  1305.         interbreedchance = 0.03
  1306.     end
  1307.     for i=1,#pool.species do
  1308.         if math.random() < interbreedchance then
  1309.             local counterbreed = math.random(1, #pool.species)
  1310.             if counterbreed ~= i then
  1311.                 table.insert(children, crossover(pool.species[i].genomes[1], pool.species[counterbreed].genomes[1]))
  1312.  
  1313.             end
  1314.         end
  1315.             if pool.species[i].topFitness + 300 > pool.maxFitness and (math.random() < increasedNetworkChance*(bnLoops - #pool.species[i].genomes[1].networkswitch) or #pool.species <= speciesToAutoNetworkSwitch) and #pool.species[i].genomes[1].genes < MaxNetworks then
  1316.                 local tfit = pool.species[i].topFitness
  1317.                 child = copyGenome(pool.species[i].genomes[1])
  1318.                 switchlocation = pool.species[i].topright/500 - 0.2 - 0.1*math.random()
  1319.                 table.insert(child.networkswitch,switchlocation)
  1320.                 table.insert(child.oscillations,{switchtime[1],switchtime[2],switchtime[3]})
  1321.                 table.insert(child.genes,{})
  1322.                 table.insert(children, child)
  1323.                 table.sort(child.networkswitch, function(a,b)
  1324.                     return (a < b)
  1325.             end)
  1326.                 emu.print(pool.species[i].genomes[1].fitness)
  1327.                 emu.print(switchlocation)
  1328.             end
  1329.         if math.random() < replaceSecondNetworkChance and pool.species[i].topFitness > 500 then
  1330.             if #pool.species[i].genomes[1].networkswitch > 0 then
  1331.                 if math.random() < 0.5 then
  1332.                     local donornetwork = math.random(1, #pool.species)
  1333.                     if donornetwork ~= i then
  1334.                         table.insert(children, replaceSecondNetwork(pool.species[i].genomes[1], pool.species[donornetwork].genomes[1],pool.species[i].topright))
  1335.                     end
  1336.                 end
  1337.             else
  1338.                 local donornetwork = math.random(1, #pool.species)
  1339.                 if donornetwork ~= i then
  1340.                     table.insert(children, replaceSecondNetwork(pool.species[i].genomes[1], pool.species[donornetwork].genomes[1],pool.species[i].topright))
  1341.                 end
  1342.             end
  1343.         end
  1344.     end
  1345.     while #children + #pool.species < Population do
  1346.         local species = pool.species[math.random(1, #pool.species)]
  1347.         table.insert(children, breedChild(species))
  1348.     end
  1349.     for c=1,#children do
  1350.         local child = children[c]
  1351.         addToSpecies(child)
  1352.     end
  1353.     local children = {}
  1354.     local replace = 0
  1355.     for s=1,#pool.species do
  1356.         local species = pool.species[s]
  1357.         if species.topFitness < secondbest and #species.genomes > Population/12 then
  1358.             while #species.genomes > Population/12 do
  1359.                 table.remove(species.genomes)
  1360.                 replace = replace + 1
  1361.             end
  1362.         elseif species.topFitness >= secondbest and #species.genomes>Population/7 then
  1363.             while #species.genomes > Population/7 do
  1364.                 table.remove(species.genomes)
  1365.                 replace = replace + 1
  1366.             end
  1367.         end
  1368.     end
  1369.     for r=1,replace do
  1370.         local species = pool.species[math.random(1, #pool.species)]
  1371.         table.insert(children, breedChild(species))
  1372.     end
  1373.     for c=1,#children do
  1374.         local child = children[c]
  1375.         addToSpecies(child)
  1376.     end
  1377.     count = 0
  1378.     for s=1,#pool.species do
  1379.         local species = pool.species[s]
  1380.         if species.topFitness < secondbest and #species.genomes > Population/12 then
  1381.             while #species.genomes > Population/12 do
  1382.                 table.remove(species.genomes)
  1383.             end
  1384.         elseif species.topFitness >= secondbest and #species.genomes>Population/7 then
  1385.             while #species.genomes > Population/7 do
  1386.                 table.remove(species.genomes)
  1387.             end
  1388.         end
  1389.         count = count + #species.genomes
  1390.     end
  1391.  
  1392.     --emu.print("Count: " .. count)
  1393.     secondbest = secondbestspecies()
  1394.     pool.generation = pool.generation + 1
  1395.     pool.maxcounter = 0 --reset max fitness counter
  1396.  
  1397.     --gsidFile("backups/gsid." .. pool.generation .. "." .. SAVE_LOAD_FILE)
  1398.     writeFile("backups/backup3." .. SAVE_LOAD_FILE)
  1399.     writelatestgen() --tracker for the latest generation
  1400. end
  1401.  
  1402. function initializePool()
  1403.     pool = newPool()
  1404.     added = LoadPreviousV2Win()
  1405.     added = added + LoadPreviousV3Win(added)
  1406.     local basic
  1407.     for i=1,Population-added do
  1408.         basic = basicGenome()
  1409.         addToSpecies(basic)
  1410.     end
  1411.  
  1412.     initializeRun()
  1413. end
  1414.  
  1415. function clearJoypad()
  1416.     controller = {}
  1417.     for b = 1,#ButtonNames do
  1418.         controller[ButtonNames[b]] = false
  1419.     end
  1420.     joypad.set(player, controller)
  1421. end
  1422.  
  1423. function LoadPreviousV3Win(start)
  1424.     if FileExists('v3wins.txt') then
  1425.         local file = io.open('v3wins.txt', "r")
  1426.         local line = file:read("*line")
  1427.         local count = 0
  1428.         while line ~= nil do
  1429.             PlaceV3Genome(line)
  1430.             count = count + 1
  1431.             line = file:read("*line")
  1432.         end
  1433.         file:close()
  1434.        
  1435.         local file = io.open('v3nicks.txt', "r")
  1436.         local line = file:read("*line")
  1437.         local count2 = start
  1438.         while line ~= nil do
  1439.             count2 = count2 + 1
  1440.             pool.species[count2].nickname = line
  1441.             line = file:read("*line")
  1442.         end
  1443.         file:close()
  1444.         return count
  1445.     else
  1446.         return 0
  1447.     end
  1448. end
  1449.  
  1450. function LoadPreviousV2Win()
  1451.     if FileExists('v2wins.txt') then
  1452.         local file = io.open('v2wins.txt', "r")
  1453.         local line = file:read("*line")
  1454.         local count = 0
  1455.         while line ~= nil do
  1456.             PlaceGenome(line)
  1457.             count = count + 1
  1458.             line = file:read("*line")
  1459.         end
  1460.         file:close()
  1461.         local file = io.open('v2nicks.txt', "r")
  1462.         local line = file:read("*line")
  1463.         local count2 = 0
  1464.         while line ~= nil do
  1465.             count2 = count2 + 1
  1466.             pool.species[count2].nickname = line
  1467.             line = file:read("*line")
  1468.         end
  1469.         file:close()
  1470.         return count
  1471.     else
  1472.         return 0
  1473.     end
  1474. end
  1475.  
  1476. function PlaceV3Genome(filename)
  1477.     if FileExists(filename) then
  1478.         local file = io.open(filename, "r")
  1479.         local genome = newGenome()
  1480.         local innov = pool.innovation
  1481.         genome.fitness = 0
  1482.         genome.old = 0
  1483.         genome.maxneuron = file:read("*number")
  1484.         local line = file:read("*line")
  1485.         while line ~= "done" do
  1486.             genome.mutationRates[line] = file:read("*number")
  1487.             line = file:read("*line")
  1488.         end
  1489.         local splits = file:read("*number")
  1490.        
  1491.         local highinnov = 0
  1492.         print(splits)
  1493.         for s=1,splits do
  1494.             local numGenes = file:read("*number")
  1495.             for n=1,numGenes do
  1496.                 local gene = newGene()
  1497.                 table.insert(genome.genes[s], gene)
  1498.                 local enabled
  1499.                 gene.into, gene.out, gene.weight, gene.innovation, enabled = file:read("*number", "*number", "*number", "*number", "*number")
  1500.                 if gene.innovation > highinnov then highinnov = gene.innovation end
  1501.                 gene.innovation = gene.innovation + innov
  1502.                 -- if gene.into > Inputs-2 and gene.into <= Inputs then gene.into = gene.into + 2 end
  1503.                 -- if gene.out > Inputs-2 and gene.out <= Inputs then gene.out = gene.out + 2 end
  1504.                 --gene.into = gene.into+2
  1505.                 --gene.out = gene.out+2
  1506.                 if enabled == 0 then
  1507.                     gene.enabled = false
  1508.                 else
  1509.                     gene.enabled = true
  1510.                 end
  1511.             end
  1512.             if s < splits then
  1513.                 table.insert(genome.genes,{})
  1514.                 table.insert(genome.oscillations,{})
  1515.             end
  1516.         end
  1517.         for n=1,splits-1 do
  1518.             genome.networkswitch[n] = file:read("*number")
  1519.         end
  1520.         local numosci = 3
  1521.         for n=1,splits do
  1522.  
  1523.             for o=1,numosci do
  1524.                 genome.oscillations[n][o] = file:read("*number")
  1525.             end
  1526.         end
  1527.         pool.innovation = pool.innovation + highinnov
  1528.         addToSpecies(genome)
  1529.         file:close()
  1530.     end
  1531. end
  1532.  
  1533. function PlaceGenome(filename)
  1534.     filename = filename .. ".txt"
  1535.     if FileExists(filename) then
  1536.         emu.print("loading in genome at location " .. filename)
  1537.        
  1538.         local file = io.open(filename, "r")
  1539.         local genome = newGenome()
  1540.         local innov = pool.innovation
  1541.         genome.fitness = 0
  1542.         genome.old = 1
  1543.         genome.maxneuron = file:read("*number")
  1544.         local line = file:read("*line")
  1545.         while line ~= "done" do
  1546.             genome.mutationRates[line] = file:read("*number")
  1547.             line = file:read("*line")
  1548.         end
  1549.         local numGenes = file:read("*number")
  1550.         local highinnov = 0
  1551.         for n=1,numGenes do
  1552.             local gene = newGene()
  1553.             table.insert(genome.genes[1], gene)
  1554.             local enabled
  1555.             gene.into, gene.out, gene.weight, gene.innovation, enabled = file:read("*number", "*number", "*number", "*number", "*number")
  1556.             if gene.innovation > highinnov then highinnov = gene.innovation end
  1557.             gene.innovation = gene.innovation + innov
  1558.             -- if gene.into > Inputs-2 and gene.into <= Inputs then gene.into = gene.into + 2 end
  1559.             -- if gene.out > Inputs-2 and gene.out <= Inputs then gene.out = gene.out + 2 end
  1560.             --gene.into = gene.into+2
  1561.             --gene.out = gene.out+2
  1562.             if enabled == 0 then
  1563.                 gene.enabled = false
  1564.             else
  1565.                 gene.enabled = true
  1566.             end
  1567.         end
  1568.         --table.insert(genome.genes,{})
  1569.         table.insert(genome.oscillations,{})
  1570.         local numGenes2 = file:read("*number")
  1571.         genes2 = {}
  1572.         for n=1,numGenes2 do
  1573.             local gene2 = newGene()
  1574.             table.insert(genes2, gene2)
  1575.             local enabled
  1576.             --I am able to revert back to the original loading script with FCEUX
  1577.             gene2.into, gene2.out, gene2.weight, gene2.innovation, enabled = file:read("*number", "*number", "*number", "*number", "*number")
  1578.             if gene2.innovation > highinnov then highinnov = gene2.innovation end
  1579.             gene2.innovation = gene2.innovation + innov
  1580.             -- if gene2.into > Inputs-2 and gene2.into <= Inputs then gene2.into = gene2.into + 2 end
  1581.             -- if gene2.out > Inputs-2 and gene2.out <= Inputs then gene2.out = gene2.out + 2 end
  1582.            
  1583.             if enabled == 0 then
  1584.                 gene2.enabled = false
  1585.             else
  1586.                 gene2.enabled = true
  1587.             end
  1588.         end
  1589.         pool.innovation = pool.innovation + highinnov
  1590.         local ns = file:read("*number")
  1591.         local numosci = file:read("*number")
  1592.         for i=1,numosci do
  1593.             genome.oscillations[1][i] = file:read("*number")
  1594.         end
  1595.         if (ns > 0) then
  1596.             genome.old = 2
  1597.             genome.genes[2] = genes2
  1598.             for i=1,numosci do
  1599.                 genome.oscillations[2][i] = genome.oscillations[1][i]
  1600.             end
  1601.             table.insert(genome.networkswitch,ns)
  1602.         end
  1603.        
  1604.        
  1605.         addToSpecies(genome)
  1606.         file:close()
  1607.     end
  1608. end
  1609.  
  1610. function initializeRun()
  1611.  
  1612.     savestate.load(SavestateObj);
  1613.     rightmost = 0
  1614.     pool.currentFrame = 0
  1615.     hitblocks = 0
  1616.     timebonus = 0
  1617.     hiddenblocks = {}
  1618.     timeout = TimeoutConstant
  1619.     clearJoypad()
  1620.     currentTracker = memory.readbyte(0x071A) --sets the current tracker to the current screen
  1621.     local measured = 0
  1622.     local total = 0
  1623.     for _,species in pairs(pool.species) do
  1624.         for _,genome in pairs(species.genomes) do
  1625.             total = total + 1
  1626.             if genome.fitness ~= 0 then
  1627.                 measured = measured + 1
  1628.             end
  1629.         end
  1630.     end
  1631.     pool.measured = measured
  1632.     pool.total = total
  1633.     local species = pool.species[pool.currentSpecies]
  1634.     local genome = species.genomes[pool.currentGenome]
  1635.     for i=1,#genome.oscillations[1] do
  1636.         switchtimer[i] = genome.oscillations[1][i]
  1637.         initialswitchvalue[i] = 1
  1638.     end
  1639.     generateNetwork(genome,true)
  1640.     evaluateCurrent()
  1641. end
  1642.  
  1643. function reRun()
  1644.     savestate.load(savestate.object(previous_savestate));
  1645.     rightmost = 0
  1646.     pool.currentFrame = 0
  1647.     hitblocks = 0
  1648.     hiddenblocks = {}
  1649.     timeout = TimeoutConstant
  1650.     clearJoypad()
  1651.     currentTracker = memory.readbyte(0x071A) --sets the current tracker to the current screen
  1652.     offset = 0 --offset in x coordinates for pipe
  1653.     timebonus = 0 --used to freeze fitness
  1654.     mariohole = false --reset the fallen into hole variable
  1655.     mariopipe = false --is mario exiting a pipe or just teleporting
  1656.     loop = false --is this a loop?
  1657.     marioPipeEnter = false --has mario entered a pipe
  1658.     currentTracker = 1 --tracker for the loop
  1659.     killtrigger = false
  1660.     ntrigger = true
  1661.     nswitch = 1
  1662.     local species = pool.species[pool.currentSpecies]
  1663.     local genome = species.genomes[pool.currentGenome]
  1664.     for i=1,#genome.oscillations[1] do
  1665.         switchtimer[i] = genome.oscillations[1][i]
  1666.         initialswitchvalue[i] = 1
  1667.     end
  1668.     generateNetwork(genome,true)
  1669.     evaluateCurrent()
  1670. end
  1671.  
  1672. function evaluateCurrent()
  1673.     local species = pool.species[pool.currentSpecies]
  1674.     local genome = species.genomes[pool.currentGenome]
  1675.  
  1676.     --emu.print(nswitch)
  1677.     inputs = getInputs()
  1678.     controller = evaluateNetwork(nswitch, inputs, genome)
  1679.  
  1680.     if controller["left"] and controller["right"] then
  1681.         controller["left"] = false
  1682.         controller["right"] = false
  1683.     end
  1684.     if controller["up"] and controller["down"] then
  1685.         controller["up"] = false
  1686.         controller["down"] = false
  1687.     end
  1688.  
  1689.     joypad.set(player, controller)
  1690. end
  1691.  
  1692. if pool == nil then
  1693.     initializePool() --------------------------------------------------------------------------------------------------------------------------------------------------------
  1694. end
  1695.  
  1696.  
  1697. function nextGenome()
  1698.     pool.currentGenome = pool.currentGenome + 1
  1699.     if pool.currentGenome > #pool.species[pool.currentSpecies].genomes then
  1700.         pool.currentGenome = 1
  1701.         pool.currentSpecies = pool.currentSpecies+1
  1702.         if pool.currentSpecies > #pool.species then
  1703.             newGeneration()
  1704.             pool.currentSpecies = 1
  1705.         end
  1706.     end
  1707. end
  1708.  
  1709. function fitnessAlreadyMeasured()
  1710.     local species = pool.species[pool.currentSpecies]
  1711.     local genome = species.genomes[pool.currentGenome]
  1712.     --return false
  1713.     return genome.fitness ~= 0
  1714. end
  1715.  
  1716. function exportGenome(genome, nickname)
  1717.     local filename = "v3wins/v3-" .. CurrentWorld+1 .."-".. CurrentLevel .. "-H.txt"
  1718.     local file2 = io.open("v3wins.txt", "a")
  1719.     file2:write(filename .. "\n")
  1720.     file2:close()
  1721.     local file3 = io.open("v3nicks.txt", "a")
  1722.     if nickname == "none" then
  1723.         file3:write("nameless winner" .. "\n")
  1724.     else
  1725.         file3:write(nickname .. "\n")
  1726.     end
  1727.     file3:close()
  1728.     local file = io.open(filename, "w")
  1729.     file:write(genome.maxneuron .. "\n")
  1730.     for mutation,rate in pairs(genome.mutationRates) do
  1731.         file:write(mutation .. "\n")
  1732.         file:write(rate .. "\n")
  1733.     end
  1734.     file:write("done\n")
  1735.     file:write(#genome.genes .. "\n")
  1736.     for k,network in pairs(genome.genes) do
  1737.         file:write(#network .. "\n")
  1738.         for l,gene in pairs(network) do
  1739.             file:write(gene.into .. " ")
  1740.             file:write(gene.out .. " ")
  1741.             file:write(gene.weight .. " ")
  1742.             file:write(gene.innovation .. " ")
  1743.             if(gene.enabled) then
  1744.                 file:write("1\n")
  1745.             else
  1746.                 file:write("0\n")
  1747.             end
  1748.         end
  1749.         --emu.print(#network)
  1750.     end
  1751.     --emu.print(#genome.genes)
  1752.     for i,ns in pairs(genome.networkswitch) do
  1753.         file:write(ns .. "\n")
  1754.     end
  1755.     --emu.print(genome.oscillations)
  1756.     for i,osc in pairs(genome.oscillations) do
  1757.         file:write(#osc .. "\n")
  1758.         for i,oscn in pairs(osc) do
  1759.             file:write(oscn .. "\n")
  1760.         end
  1761.     end
  1762.     file:write(genome.old)
  1763.     file:close()
  1764. end
  1765.  
  1766. function GenerateNewKeepBest(genome, nickname)
  1767.     Population = 1000
  1768.     previousbest = copyGenome(genome)
  1769.     exportGenome(previousbest, nickname) --saves the winning genome
  1770.     previousmaxfitness = 1
  1771.     originalmaxfitness = 1
  1772.     maxright = 1
  1773.     offset = 0 --offset in x coordinates for pipe
  1774.     timebonus = 0 --used to freeze fitness
  1775.     timeout = TimeoutConstant
  1776.     mariohole = false --reset the fallen into hole variable
  1777.     mariopipe = false --is mario exiting a pipe or just teleporting
  1778.     loop = false --is this a loop?
  1779.     marioPipeEnter = false --has mario entered a pipe
  1780.     currentTracker = 1 --tracker for the loop
  1781.     pool = newPool()
  1782.     added = LoadPreviousV2Win()
  1783.     added = added + LoadPreviousV3Win(added)
  1784.     --addToSpecies(previousbest)
  1785.     for i=1,Population-added do
  1786.         basic = basicGenome()
  1787.         addToSpecies(basic)
  1788.     end
  1789.     initializeRun()
  1790. end
  1791.  
  1792. function displayGenome(genome)
  1793.     gui.opacity(0.53)
  1794.     local Inputs = Inputs
  1795.     local nswitch = nswitch
  1796.     local BoxRadius = BoxRadius
  1797.     if genome.old >= nswitch then
  1798.         Inputs = Inputs -2
  1799.     end
  1800.     if not genome then return end
  1801.     local network = {}
  1802.     network = genome.network[nswitch]
  1803.     local cells = {}
  1804.     local i = 1
  1805.     local cell = {}
  1806.     for dy=-BoxRadius,BoxRadius do
  1807.         for dx=-BoxRadius,BoxRadius do
  1808.             cell = {}
  1809.             cell.x = 50+5*dx
  1810.             cell.y = 70+5*dy
  1811.             cell.value = network.neurons[i].value
  1812.             cells[i] = cell
  1813.             i = i + 1
  1814.         end
  1815.     end
  1816.     local biasCell = {}
  1817.     biasCell.x = 80
  1818.     biasCell.y = 110
  1819.     local switchCell = {}
  1820.     local speedCell = {}
  1821.     if genome.old >= nswitch then
  1822.         biasCell.value = network.neurons[Inputs-#initialswitchvalue].value
  1823.         cells[Inputs-#initialswitchvalue] = biasCell
  1824.         for i=0,#initialswitchvalue-1 do
  1825.             switchCell = {}
  1826.             switchCell.x = 80-10*#initialswitchvalue+10*i
  1827.             switchCell.y = 110
  1828.             switchCell.value = network.neurons[Inputs-i].value
  1829.             cells[Inputs-i] = switchCell
  1830.         end
  1831.     else
  1832.         biasCell.value = network.neurons[Inputs-#initialswitchvalue-2].value
  1833.         cells[Inputs-#initialswitchvalue-2] = biasCell
  1834.         for i=0,#initialswitchvalue-1 do
  1835.             switchCell = {}
  1836.             switchCell.x = 80-10*#initialswitchvalue+10*i
  1837.             switchCell.y = 110
  1838.             switchCell.value = network.neurons[Inputs-i-2].value
  1839.             cells[Inputs-i-2] = switchCell
  1840.         end
  1841.         for i=0,1 do
  1842.             speedCell = {}
  1843.             speedCell.x = 80 - 10*(6)+10*i
  1844.             speedCell.y = 110
  1845.             speedCell.value = network.neurons[Inputs-i].value
  1846.             cells[Inputs-i] = speedCell
  1847.         end
  1848.     end
  1849.  
  1850.     gui.drawbox(215,32,245,82,toRGBA(0x80808080),toRGBA(0x00000000))
  1851.     local color
  1852.     gui.opacity(0.85)
  1853.     for o = 1,Outputs do
  1854.         cell = {}
  1855.         cell.x = 220
  1856.         cell.y = 30 + 8 * o
  1857.         cell.value = network.neurons[MaxNodes + o].value
  1858.         cells[MaxNodes+o] = cell
  1859.        
  1860.         if cell.value > 0 then
  1861.             color = 0xFF0000FF
  1862.         else
  1863.             color = 0xFF777777-- original color = 0xFF000000
  1864.         end
  1865.         gui.drawtext(225, 26+8*o, ButtonNames[o], toRGBA(color), 0x0) --moved slightly for better alignment
  1866.     end
  1867.     for n,neuron in pairs(network.neurons) do
  1868.         cell = {}
  1869.         if n > Inputs and n <= MaxNodes then
  1870.             cell.x = 140
  1871.             cell.y = 40
  1872.             cell.value = neuron.value
  1873.             -- if neuron.value >0 then
  1874.                 -- neuron.switcher = true
  1875.             -- end
  1876.             cells[n] = cell
  1877.         end
  1878.     end
  1879.     local genes = {}
  1880.     genes = genome.genes[nswitch]
  1881.     for n=1,4 do
  1882.         for _,gene in pairs(genes) do
  1883.             if gene.enabled then
  1884.                 local c1 = cells[gene.into]
  1885.                 local c2 = cells[gene.out]
  1886.                 if gene.into > Inputs and gene.into <= MaxNodes then
  1887.                     c1.x = 0.75*c1.x + 0.25*c2.x
  1888.                     if c1.x >= c2.x then
  1889.                         c1.x = c1.x - 40
  1890.                     end
  1891.                     if c1.x < 90 then
  1892.                         c1.x = 90
  1893.                     end
  1894.  
  1895.                     if c1.x > 220 then
  1896.                         c1.x = 220
  1897.                     end
  1898.                     c1.y = 0.75*c1.y + 0.25*c2.y
  1899.  
  1900.                 end
  1901.                 if gene.out > Inputs and gene.out <= MaxNodes then
  1902.                     c2.x = 0.25*c1.x + 0.75*c2.x
  1903.                     if c1.x >= c2.x then
  1904.                         c2.x = c2.x + 40
  1905.                     end
  1906.                     if c2.x < 90 then
  1907.                         c2.x = 90
  1908.                     end
  1909.                     if c2.x > 220 then
  1910.                         c2.x = 220
  1911.                     end
  1912.                     c2.y = 0.25*c1.y + 0.75*c2.y
  1913.                 end
  1914.             end
  1915.         end
  1916.     end
  1917.  
  1918.     gui.drawbox(50-BoxRadius*5-3,70-BoxRadius*5-3,50+BoxRadius*5+2,70+BoxRadius*5+2, toRGBA(0x80808080), toRGBA(0xFF000000))
  1919.     for n,cell in pairs(cells) do
  1920.         if n > Inputs or cell.value ~= 0 then
  1921.             color = math.floor((cell.value+1)/2*256)
  1922.             if color > 255 then color = 255 end
  1923.             if color < 0 then color = 0 end
  1924.             local opacity = 0xFF000000
  1925.             if cell.value == 0 then
  1926.                 opacity = 0x50000000
  1927.             end
  1928.             inversecolor = (color - 255) * (-1)
  1929.             bordercolor = 0x50000000 + inversecolor*0x10000 + inversecolor*0x100 + inversecolor
  1930.             color = opacity + color*0x10000 + color*0x100 + color
  1931.             gui.drawbox(cell.x-2,cell.y-2,cell.x+2,cell.y+2,toRGBA(color), toRGBA(bordercolor))
  1932.         end
  1933.     end
  1934.     for _,gene in pairs(genes) do
  1935.         if gene.enabled then
  1936.             local c1 = cells[gene.into]
  1937.             local c2 = cells[gene.out]
  1938.             local opacity = 0xF0000000
  1939.             if pool.generation > 50 then
  1940.                     opacity = 0x80000000
  1941.                 end
  1942.             if c1.value == 0 then
  1943.                 if pool.generation <10 then --slowly reducing the visibility of non active connections
  1944.                     opacity = 0x80000000
  1945.                 elseif pool.generation < 15 then
  1946.                     opacity = 0x60000000
  1947.                 elseif pool.generation < 25 then
  1948.                     opacity = 0x40000000
  1949.                 end
  1950.             end
  1951.             local color = 0x80-math.floor(math.abs(sigmoid(gene.weight))*0x80)
  1952.             if gene.weight > 0 then
  1953.                 color = opacity + 0x8000 + 0x10000*color
  1954.             else
  1955.                 color = opacity + 0x800000 + 0x100*color
  1956.             end
  1957.             if c1.value ~= 0 or pool.generation < 5 then -- remove non active connections from generation 50 onwards
  1958.                 gui.drawline(c1.x+1, c1.y, c2.x-3, c2.y, toRGBA(color))
  1959.             end
  1960.         end
  1961.     end
  1962.  
  1963.     gui.drawbox(49,71,51,78,toRGBA(0x80FF0000),toRGBA(0x00000000))
  1964.     if mutation_rates_disp then
  1965.         local pos = 120
  1966.         for mutation,rate in pairs(genome.mutationRates) do
  1967.             gui.drawtext(16, pos, mutation .. ": " .. rate, toRGBA(0xFF000000), 0x0)
  1968.             pos = pos + 8
  1969.         end
  1970.     end
  1971. end
  1972.  
  1973. function toBase95(num,places)
  1974.     local str = ""
  1975.     for p=1,places do
  1976.         local numPlace = math.floor(num / math.pow(95,p-1))
  1977.         str = str .. string.char((numPlace % 95) + 32)
  1978.     end
  1979.     return str
  1980. end
  1981.  
  1982. function fromBase95(str,places)
  1983.     local num = 0
  1984.     for p=1,string.len(str) do
  1985.         local numPlace = string.byte(string.sub(str,p,p))-32
  1986.         num = num + numPlace * math.pow(95,p-1)
  1987.     end
  1988.     return num
  1989. end
  1990.  
  1991. function gsidFile(filename)
  1992.     local file = io.open(filename, "w")
  1993.     file:write("G")
  1994.     for n,species in pairs(pool.species) do
  1995.         file:write(toBase95(species.gsid,3))
  1996.     end
  1997.     file:close()
  1998. end
  1999.  
  2000. function writeFile(filename)
  2001.     local file = io.open(filename, "w")
  2002.     file:write("B" .. "\n")
  2003.     file:write(pool.generation .. "\n")
  2004.     file:write(math.floor(pool.maxFitness*10)/10 .. "\n")
  2005.     file:write(Population .. "\n")
  2006.     file:write(bnLoops .. "\n")
  2007.     file:write(bottleneckcounter .. "\n")
  2008.     file:write(pool.innovation .. "\n")
  2009.     file:write(pool.gsid .. "\n")
  2010.     file:write(#pool.species .. "\n")
  2011.     for n,species in pairs(pool.species) do
  2012.         file:write(math.floor(species.topFitness*10)/10 .. "\n")
  2013.         file:write(species.staleness .. "\n")
  2014.         file:write(species.gsid .. "\n")
  2015.         file:write(#species.genomes .. "\n")
  2016.         for m,genome in pairs(species.genomes) do
  2017.             file:write(math.floor(genome.fitness*10)/10 .. "\n")
  2018.             file:write(genome.maxneuron .. "\n")
  2019.             for i,rate in pairs(genome.mutationRates) do
  2020.                 file:write(i .. "\n")
  2021.                 file:write(math.floor(rate*10000)/10000 .. "\n")
  2022.             end
  2023.             file:write("done" .. "\n")
  2024.             file:write(#genome.genes .. "\n")
  2025.             for k,network in pairs(genome.genes) do
  2026.                 file:write(#network .. "\n")
  2027.                 for l,gene in pairs(network) do
  2028.                     local enabledChar
  2029.                     if(gene.enabled) then
  2030.                         enabledChar = "1"
  2031.                     else
  2032.                         enabledChar = "0"
  2033.                     end
  2034.                     file:write(gene.into .. " " .. gene.out .. " " .. math.floor(gene.weight*10000000)/10000000 .. " " .. gene.innovation .. " " .. enabledChar .. "\n")
  2035.                 end
  2036.                 --emu.print(#network)
  2037.             end
  2038.             --emu.print(#genome.genes)
  2039.             for i,ns in pairs(genome.networkswitch) do
  2040.                 file:write(math.floor(ns*500)/500 .. "\n")
  2041.             end
  2042.             --emu.print(genome.oscillations)
  2043.             for i,osc in pairs(genome.oscillations) do
  2044.                 for i,oscn in pairs(osc) do
  2045.                     file:write(oscn .. "\n")
  2046.                 end
  2047.             end
  2048.             file:write(genome.old .. "\n")
  2049.         end
  2050.     end
  2051.     file:close()
  2052. end
  2053.  
  2054. function savePool() --used to save when a new max fitness is reached
  2055.     local filename = "backups/backup3." .. pool.generation .. "." .. SAVE_LOAD_FILE
  2056.     writeFile(filename)
  2057.     emu.print("saved pool due to new max fitness")  --suggestion by DeltaLeeds
  2058. end
  2059.  
  2060. function loadFile(filename)
  2061.     emu.print(filename)
  2062.     local file = io.open(filename, "r")
  2063.     fileString = file:read("*line")
  2064.     file:close()
  2065.     if string.sub(fileString,1,1) == "B" then
  2066.         local file = io.open(filename, "r")
  2067.         file:read("*line")
  2068.         pool = newPool()
  2069.         pool.species = {}
  2070.         pool.generation = file:read("*number")
  2071.         pool.maxFitness = file:read("*number")
  2072.         pool.maxFitness = 0
  2073.         previousmaxfitness = pool.maxFitness
  2074.         Population = file:read("*number")
  2075.         bnLoops = file:read("*number")
  2076.         bottleneckcounter = file:read("*number")
  2077.         pool.innovation = file:read("*number")
  2078.         local gsidMax = file:read("*number")
  2079.         local numSpecies = file:read("*number")
  2080.         for s=1,numSpecies do
  2081.             local species = newSpecies()
  2082.             species.genomes = {}
  2083.             species.topFitness = file:read("*number")
  2084.             species.topFitness = 0
  2085.             species.staleness = file:read("*number")
  2086.             species.gsid = file:read("*number")
  2087.             local numGenomes = file:read("*number")
  2088.             for g=1,numGenomes do
  2089.                 local genome = newGenome()
  2090.                 genome.fitness = file:read("*number")
  2091.                 genome.fitness = 0
  2092.                 --emu.print(genome.fitness)
  2093.                 genome.maxneuron = file:read("*number")
  2094.                 local line = file:read("*line")
  2095.                 while line ~= "done" do
  2096.                     if line == "oscilation" then line = "oscillation" end
  2097.                     genome.mutationRates[line] = file:read("*number")
  2098.                     line = file:read("*line")
  2099.                 end
  2100.                 local numNetworks = file:read("*number")
  2101.                 for n=1,numNetworks do
  2102.                     if n > 1 then
  2103.                         table.insert(genome.genes,{})
  2104.                         table.insert(genome.oscillations,{})
  2105.                     end
  2106.                     local numGenes = file:read("*number")
  2107.                     for gn=1,numGenes do
  2108.                         local gene = newGene()
  2109.                         local enabled
  2110.                         gene.into, gene.out, gene.weight, gene.innovation, enabled = file:read("*number", "*number", "*number", "*number", "*number")
  2111.                         if enabled == 0 then
  2112.                             gene.enabled = false
  2113.                         else
  2114.                             gene.enabled = true
  2115.                         end
  2116.                         table.insert(genome.genes[n],gene)
  2117.                     end
  2118.                     --emu.print("gn" .. #genome.genes[n])
  2119.                 end
  2120.                 --emu.print("N" .. numNetworks)
  2121.                 for n=1,numNetworks-1 do
  2122.                     table.insert(genome.networkswitch,file:read("*number"))
  2123.                 end
  2124.  
  2125.                 --emu.print(genome.networkswitch)
  2126.                 for n=1,numNetworks do
  2127.                     genome.oscillations[n][1]=file:read("*number")
  2128.                     genome.oscillations[n][2]=file:read("*number")
  2129.                     genome.oscillations[n][3]=file:read("*number")
  2130.                 end
  2131.                 --emu.print(genome.oscillations)
  2132.                 table.insert(species.genomes,genome)
  2133.                 --emu.print(genome.oscillations)
  2134.                 genome.old = file:read("*number")
  2135.             end
  2136.             table.insert(pool.species,species)
  2137.         end
  2138.         pool.gsid = gsidMax
  2139.     elseif string.sub(fileString,1,1) == "A" then
  2140.         local i = 1
  2141.         pool = newPool()
  2142.         pool.species = {}
  2143.         pool.generation = fromBase95(string.sub(fileString,i+1,i+2))
  2144.         pool.maxFitness = 0--fromBase95(string.sub(fileString,i+3,i+5))/10
  2145.         if pool.maxFitness > 80000 then
  2146.           pool.maxFitness = pool.maxFitness - 85737.5
  2147.         end
  2148.         previousmaxfitness = pool.maxFitness
  2149.         Population = fromBase95(string.sub(fileString,i+6,i+7))
  2150.         bnLoops = fromBase95(string.sub(fileString,i+8,i+8))
  2151.         bottleneckcounter = fromBase95(string.sub(fileString,i+9,i+9))
  2152.         pool.innovation = fromBase95(string.sub(fileString,i+10,i+13))
  2153.         local gsidMax = fromBase95(string.sub(fileString,i+14,i+16))
  2154.         local numSpecies = fromBase95(string.sub(fileString,i+17,i+18))
  2155.         i = i + 18
  2156.         for s=1,numSpecies do
  2157.             local species = newSpecies()
  2158.             species.genomes = {}
  2159.             species.topFitness = 0--fromBase95(string.sub(fileString,i+1,i+3))/10
  2160.             if species.topFitness > 80000 then
  2161.               species.topFitness = species.topFitness - 85737.5
  2162.             end
  2163.             species.staleness = fromBase95(string.sub(fileString,i+4,i+4))
  2164.             species.gsid = fromBase95(string.sub(fileString,i+5,i+7))
  2165.             local numGenomes = fromBase95(string.sub(fileString,i+8,i+9))
  2166.             i = i + 9
  2167.             for g=1,numGenomes do
  2168.                 local genome = newGenome()
  2169.                 genome.fitness = 0--fromBase95(string.sub(fileString,i+1,i+3))/10
  2170.  
  2171.                 if genome.fitness > 80000 then
  2172.                   genome.fitness = genome.fitness - 85737.5
  2173.                 end
  2174.                 genome.fitness = 0
  2175.                 --emu.print(genome.fitness)
  2176.                 genome.maxneuron = fromBase95(string.sub(fileString,i+4,i+5))
  2177.                 genome.mutationRates["connections"] = fromBase95(string.sub(fileString,i+6,i+8))/10000
  2178.                 genome.mutationRates["oscillation"] = fromBase95(string.sub(fileString,i+9,i+11))/10000
  2179.                 genome.mutationRates["link"] = fromBase95(string.sub(fileString,i+12,i+14))/10000
  2180.                 genome.mutationRates["enable"] = fromBase95(string.sub(fileString,i+15,i+17))/10000
  2181.                 genome.mutationRates["step"] = fromBase95(string.sub(fileString,i+18,i+20))/10000
  2182.                 genome.mutationRates["networkswitch"] = fromBase95(string.sub(fileString,i+21,i+23))/10000
  2183.                 genome.mutationRates["bias"] = fromBase95(string.sub(fileString,i+24,i+26))/10000
  2184.                 genome.mutationRates["node"] = fromBase95(string.sub(fileString,i+27,i+29))/10000
  2185.                 genome.mutationRates["disable"] = fromBase95(string.sub(fileString,i+30,i+32))/10000
  2186.                 local numNetworks = fromBase95(string.sub(fileString,i+33,i+33))
  2187.                 i = i + 33
  2188.                 for n=1,numNetworks do
  2189.                     if n > 1 then
  2190.                         table.insert(genome.genes,{})
  2191.                         table.insert(genome.oscillations,{})
  2192.                     end
  2193.                     local numGenes = fromBase95(string.sub(fileString,i+1,i+2))
  2194.                     i = i + 2
  2195.                     for gn=1,numGenes do
  2196.                         local gene = newGene()
  2197.                         gene.into = fromBase95(string.sub(fileString,i+1,i+2))
  2198.                         gene.out = fromBase95(string.sub(fileString,i+3,i+4))
  2199.                         gene.weight = (fromBase95(string.sub(fileString,i+5,i+8))/10000000)-4
  2200.                         gene.innovation = fromBase95(string.sub(fileString,i+9,i+12))
  2201.                         gene.enabled = (string.sub(fileString,i+13,i+13) == "1")
  2202.                         table.insert(genome.genes[n],gene)
  2203.                         i = i + 13
  2204.                         if gene.into > 9000 then gene.into = gene.into + 991000 end
  2205.                         if gene.out > 9000 then gene.out = gene.out + 991000 end
  2206.                     end
  2207.                     --emu.print("gn" .. #genome.genes[n])
  2208.                 end
  2209.                 --emu.print("N" .. numNetworks)
  2210.                 for n=1,numNetworks-1 do
  2211.                     table.insert(genome.networkswitch,fromBase95(string.sub(fileString,i+1,i+2))/500)
  2212.                     i = i + 2
  2213.                 end
  2214.  
  2215.                 --emu.print(genome.networkswitch)
  2216.                 for n=1,numNetworks do
  2217.                     genome.oscillations[n][1]=fromBase95(string.sub(fileString,i+1,i+1))
  2218.                     genome.oscillations[n][2]=fromBase95(string.sub(fileString,i+2,i+2))
  2219.                     genome.oscillations[n][3]=fromBase95(string.sub(fileString,i+3,i+3))
  2220.                     i = i + 3
  2221.                 end
  2222.                 --emu.print(genome.oscillations)
  2223.                 table.insert(species.genomes,genome)
  2224.                 --emu.print(genome.oscillations)
  2225.             end
  2226.             table.insert(pool.species,species)
  2227.         end
  2228.         pool.gsid = gsidMax
  2229.     else
  2230.         local file = io.open(filename, "r")
  2231.         pool = newPool()
  2232.         pool.generation = file:read("*number")
  2233.         pool.maxFitness = file:read("*number")
  2234.         previousmaxfitness = pool.maxFitness
  2235.         Population = file:read("*number")
  2236.         pool.innovation = file:read("*number")
  2237.         bottleneckcounter = file:read("*number")
  2238.         local numSpecies = file:read("*number")
  2239.         pool.gsid = numSpecies - 1
  2240.         maxstale = 0
  2241.         for s=1,numSpecies do
  2242.             local species = newSpecies()
  2243.             table.insert(pool.species, species)
  2244.             species.topFitness = file:read("*number")
  2245.             species.staleness = file:read("*number")
  2246.             if species.staleness > maxstale then maxstale = species.staleness end
  2247.             species.gsid = s - 1
  2248.             local numGenomes = file:read("*number")
  2249.             for g=1,numGenomes do
  2250.                 local genome = newGenome()
  2251.                 table.insert(species.genomes, genome)
  2252.                 genome.fitness = file:read("*number")
  2253.                 genome.maxneuron = file:read("*number")
  2254.                 genome.fitness = 0
  2255.                 local line = file:read("*line")
  2256.                 while line ~= "done" do
  2257.                     if line == "oscilation" then line = "oscillation" end
  2258.                     genome.mutationRates[line] = file:read("*number")
  2259.                     line = file:read("*line")
  2260.                 end
  2261.                 local numGenes = file:read("*number")
  2262.                 genes1 = {}
  2263.                 genes1Legacy = {}
  2264.                 for n=1,numGenes do
  2265.                     local gene = newGene()
  2266.                     table.insert(genes1Legacy, gene)
  2267.                     local enabled
  2268.                     --I am able to revert back to the original loading script with FCEUX
  2269.                     gene.into, gene.out, gene.weight, gene.innovation, enabled = file:read("*number", "*number", "*number", "*number", "*number")
  2270.                     if enabled == 0 then
  2271.                         gene.enabled = false
  2272.                     else
  2273.                         gene.enabled = true
  2274.                     end
  2275.                 end
  2276.                
  2277.                 local genomeLegacy = newGenome()
  2278.                 genomeLegacy.genes = {genes1Legacy}
  2279.                 MaxNodes = 1000000
  2280.                 generateNetwork(genomeLegacy,false)
  2281.                 --MaxNodes = 9000
  2282.                 local net = genomeLegacy.network[1]
  2283.                 local mapping = {}
  2284.                 local numMappedNodes = 0
  2285.                 for nid, neuron in pairs(net.neurons) do
  2286.                     numMappedNodes = numMappedNodes + 1
  2287.                     if numMappedNodes == 174 then numMappedNodes = 176 end
  2288.                     mapping[nid+0.5] = numMappedNodes
  2289.                     --emu.print(mapping)
  2290.                 end
  2291.                 for nid, neuron in pairs(net.neurons) do
  2292.                     for inc=1,#neuron.incoming do
  2293.                         local geneWrong = neuron.incoming[inc]
  2294.                         local geneRight = newGene()
  2295.                         geneRight.weight = geneWrong.weight
  2296.                         geneRight.enabled = geneWrong.enabled
  2297.                         geneRight.innovation = geneWrong.innovation
  2298.                         geneRight.out = mapping[nid+0.5]
  2299.                         if mapping[geneWrong.into+0.5] ~= nil then
  2300.                             geneRight.into = mapping[geneWrong.into+0.5]
  2301.                             table.insert(genes1,geneRight)
  2302.                             if geneRight.enabled and s == 1 and g == 2 then
  2303.                                 --emu.print("ACCEPTED " .. geneWrong.into .. " " .. geneWrong.out .. " " .. geneRight.out .. " " .. geneRight.into)
  2304.                             end
  2305.                         elseif s == 1 and g == 2 then
  2306.                             emu.print("REJECTED " .. geneWrong.into .. " " .. geneWrong.out .. " " .. geneRight.out)
  2307.                         end
  2308.                     end
  2309.                    
  2310.                     --emu.print(nid)
  2311.                 end
  2312.                
  2313.                 for outputid=1,6 do
  2314.                     local geneRight = newGene()
  2315.                     geneRight.weight = 1.0
  2316.                     geneRight.enabled = true
  2317.                     geneRight.innovation = newInnovation()
  2318.                     geneRight.into = mapping[outputid+1000000.5]
  2319.                     geneRight.out = 9000+outputid
  2320.                     table.insert(genes1,geneRight)
  2321.                 end
  2322.                
  2323.                
  2324.                 local numGenes2 = file:read("*number")
  2325.                 genes2 = {}
  2326.                 genes2Legacy = {}
  2327.                 for n=1,numGenes2 do
  2328.                     local gene2 = newGene()
  2329.                     table.insert(genes2Legacy, gene2)
  2330.                     local enabled
  2331.                     --I am able to revert back to the original loading script with FCEUX
  2332.                     gene2.into, gene2.out, gene2.weight, gene2.innovation, enabled = file:read("*number", "*number", "*number", "*number", "*number")
  2333.                     if enabled == 0 then
  2334.                         gene2.enabled = false
  2335.                     else
  2336.                         gene2.enabled = true
  2337.                     end
  2338.  
  2339.                 end
  2340.                
  2341.                 local genome2Legacy = newGenome()
  2342.                 genome2Legacy.genes = {genes2Legacy}
  2343.                 MaxNodes = 1000000
  2344.                 generateNetwork(genome2Legacy,false)
  2345.                 MaxNodes = 9000
  2346.                 net = genome2Legacy.network[1]
  2347.                 mapping = {}
  2348.                 numMappedNodes = 0
  2349.                 for nid, neuron in pairs(net.neurons) do
  2350.                     numMappedNodes = numMappedNodes + 1
  2351.                     if numMappedNodes == 174 then numMappedNodes = 176 end
  2352.                     mapping[nid+0.5] = numMappedNodes
  2353.                     --emu.print(mapping)
  2354.                 end
  2355.                 for nid, neuron in pairs(net.neurons) do
  2356.                     for inc=1,#neuron.incoming do
  2357.                         local geneWrong = neuron.incoming[inc]
  2358.                         local geneRight = newGene()
  2359.                         geneRight.weight = geneWrong.weight
  2360.                         geneRight.enabled = geneWrong.enabled
  2361.                         geneRight.innovation = geneWrong.innovation
  2362.                         geneRight.out = mapping[nid+0.5]
  2363.                         if mapping[geneWrong.into+0.5] ~= nil then
  2364.                             geneRight.into = mapping[geneWrong.into+0.5]
  2365.                             table.insert(genes2,geneRight)
  2366.                             if geneRight.enabled and s == 1 and g == 2 then
  2367.                                 --emu.print("ACCEPTED " .. geneWrong.into .. " " .. geneWrong.out .. " " .. geneRight.out .. " " .. geneRight.into)
  2368.                             end
  2369.                         elseif s == 1 and g == 2 then
  2370.                             emu.print("REJECTED " .. geneWrong.into .. " " .. geneWrong.out .. " " .. geneRight.out)
  2371.                         end
  2372.                     end
  2373.                    
  2374.                     --emu.print(nid)
  2375.                 end
  2376.                
  2377.                 for outputid=1,6 do
  2378.                     local geneRight = newGene()
  2379.                     geneRight.weight = 1.0
  2380.                     geneRight.enabled = true
  2381.                     geneRight.innovation = newInnovation()
  2382.                     geneRight.into = mapping[outputid+1000000.5]
  2383.                     geneRight.out = 9000+outputid
  2384.                     table.insert(genes2,geneRight)
  2385.                 end
  2386.                
  2387.                
  2388.                
  2389.                 ns = file:read("*number")
  2390.                 if ns == 0 then
  2391.                     genome.networkswitch = {}
  2392.                     genome.oscillations = {{}}
  2393.                     genome.genes = {genes1}
  2394.                 else
  2395.                     genome.networkswitch = {ns}
  2396.                     genome.genes = {genes1,genes2}
  2397.                     genome.oscillations = {{},{}}
  2398.                 end
  2399.                 local numosci = file:read("*number")
  2400.                 for i=1,numosci do
  2401.                     genome.oscillations[1][i] = file:read("*number")
  2402.                     if ns > 0 then
  2403.                         genome.oscillations[2][i] = genome.oscillations[1][i]
  2404.                     end
  2405.                 end
  2406.                 if g == 1 then
  2407.                     genomeCopy = copyGenome(genome)
  2408.                     table.insert(species.genomes,genomeCopy)
  2409.                 end
  2410.             end
  2411.             if s == 1 then
  2412.                 --emu.print(species.genomes[2].genes[1])
  2413.                 --emu.print("*3")
  2414.             end
  2415.             bnLoops = 0
  2416.             bottleneck = 0
  2417.             for i=1,maxstale do
  2418.                 bottleneck = bottleneck + 1
  2419.                 length= math.min(12*popOscilMultiplier,(5 + 2*bnLoops)*popOscilMultiplier)
  2420.                 if bottleneckcounter == GBPO + length*3 then
  2421.                     bottleneckcounter = 0
  2422.                     bnLoops = bnLoops + 1
  2423.                 end
  2424.             end
  2425.         end
  2426.         file:close()
  2427.     end
  2428.  
  2429.     --while fitnessAlreadyMeasured() do
  2430.     --    nextGenome()
  2431.     --end
  2432.     initializeRun()
  2433.     pool.currentFrame = pool.currentFrame + 1
  2434. end
  2435.  
  2436.  
  2437. function playTop()
  2438.     local maxfitness = 0
  2439.     local maxs, maxg
  2440.     rightmost = 0
  2441.     pool.currentFrame = 0
  2442.     hitblocks = 0
  2443.     hiddenblocks = {}
  2444.     offset = 0 --offset in x coordinates for pipe
  2445.     timebonus = 0 --used to freeze fitness
  2446.     mariohole = false --reset the fallen into hole variable
  2447.     mariopipe = false --is mario exiting a pipe or just teleporting
  2448.     loop = false --is this a loop?
  2449.     marioPipeEnter = false --has mario entered a pipe
  2450.     currentTracker = 1 --tracker for the loop
  2451.     killtrigger = false
  2452.     ntrigger = true
  2453.     nswitch = 1
  2454.     for s,species in pairs(pool.species) do
  2455.         for g,genome in pairs(species.genomes) do
  2456.             if genome.fitness > maxfitness then
  2457.                 maxfitness = genome.fitness
  2458.                 maxs = s
  2459.                 maxg = g
  2460.             end
  2461.         end
  2462.     end
  2463.  
  2464.     pool.currentSpecies = maxs
  2465.     pool.currentGenome = maxg
  2466.     pool.maxFitness = maxfitness
  2467.     initializeRun()
  2468.     pool.currentFrame = pool.currentFrame + 1
  2469.     return
  2470. end
  2471.  
  2472. function fitnesstracker()
  2473.     if pool.maxFitness > 0 then
  2474.         local file = io.open('fitnesstracker.txt', "a")
  2475.         file:write("Gen: " .. pool.generation .. " Species: " .. pool.currentSpecies .. " Genome: " .. pool.currentGenome .. " Fitness: ".. pool.maxFitness .. "\n")
  2476.         file:close()
  2477.     end
  2478. end
  2479.  
  2480. function writelatestgen() --used to write the generation tracker to a file
  2481.     local file = io.open('backups/latestgen', "w")
  2482.     file:write(SAVE_LOAD_FILE .. "\n")
  2483.     file:write(savestate_slot .. "\n")
  2484.     file:write(pool.generation)
  2485.     file:close()
  2486. end
  2487.  
  2488. function readlatestgen() --used to retrieve the latest generation from a file
  2489.     if FileExists('backups/latestgen') then
  2490.         local file = io.open('backups/latestgen', "r")
  2491.         SAVE_LOAD_FILE = file:read("*line")
  2492.         savestate_slot = file:read("*number")
  2493.         SavestateObj = savestate.object(savestate_slot)
  2494.         local latestgen = file:read("*number")-1
  2495.         file:close()
  2496.         local name = 'backups/backup3.' .. SAVE_LOAD_FILE
  2497.         print('loaded: '.. name)
  2498.         return name
  2499.     else
  2500.         print('Please first run the AI normally before trying to fast load the latest generation')
  2501.     end
  2502. end
  2503.  
  2504. function keyboardinput()
  2505.     local keyboard = input.get()
  2506.     if keyboard['N'] and keyflag == false then
  2507.         if neural_net_disp then
  2508.             neural_net_disp = false
  2509.         else
  2510.             neural_net_disp = true
  2511.         end
  2512.         keyflag = true
  2513.     end
  2514.     if keyboard['M'] and keyflag == false then
  2515.         if mutation_rates_disp then
  2516.             mutation_rates_disp = false
  2517.         else
  2518.             mutation_rates_disp = true
  2519.         end
  2520.         keyflag = true
  2521.     end
  2522.     if keyboard['L'] and keyflag == false then
  2523.         if not nopopup then
  2524.             local loadyn = input.popup('Are you sure you want to load the last saved generation?')
  2525.         end
  2526.         if loadyn == 'yes' or nopopup then
  2527.             name = readlatestgen()
  2528.             loadFile(name)
  2529.         end
  2530.         keyflag = true
  2531.     end
  2532.     if keyboard['B'] and keyflag == false then
  2533.         if not nopopup then
  2534.             local loadyn = input.popup('Are you sure you want to show the topFitness genome?')
  2535.         end
  2536.         if loadyn == 'yes' or nopopup then
  2537.             playTop()
  2538.         end
  2539.     end
  2540.  
  2541.  
  2542.     if keyboard['S'] and keyflag == false then
  2543.         savePool()
  2544.         keyflag = true
  2545.     end
  2546.     if not (keyboard['N'] or keyboard['L'] or keyboard['M'] or keyboard['T'] or keyboard['B'] or keyboard['S']) and keyflag == true then
  2547.         keyflag = false
  2548.     end
  2549.     if keyboard['T'] and keyflag == false then
  2550.         if turbo then
  2551.             emu.speedmode("normal")
  2552.             turbo = false
  2553.             print('stop turbo')
  2554.         elseif not turbo and not restoreturbo then
  2555.             emu.speedmode("turbo")
  2556.             turbo = true
  2557.         elseif restoreturbo then
  2558.             restoreturbo = false
  2559.         end
  2560.         keyflag = true
  2561.     end
  2562. end
  2563.  
  2564.  
  2565. writeFile("temp.pool")
  2566. requiredFitness = 0
  2567. minFitness = 0
  2568. if SAVE_LOAD_FILE == nil then
  2569.     if LostLevels == 1 then
  2570.         SAVE_LOAD_FILE = "SMBLL".. CurrentWorld+1 .."-".. CurrentLevel ..".state.pool"
  2571.     else
  2572.         SAVE_LOAD_FILE = "SMB".. CurrentWorld+1 .."-".. CurrentLevel ..".state.pool"
  2573.     end
  2574. end
  2575.  
  2576. if savedpool then
  2577.     loadFile(savedpool)
  2578. end
  2579.  
  2580.  
  2581. while true do
  2582.     keyboardinput()
  2583.     local backgroundColor = toRGBA(0xD0FFFFFF)
  2584.         gui.drawbox(0, 0, 260, 30, backgroundColor, backgroundColor)
  2585.  
  2586.     if pool.maxcounter == nil then
  2587.         pool.maxcounter = 0
  2588.         --emu.print("caught missing variable")
  2589.     end
  2590.  
  2591.     local species = pool.species[pool.currentSpecies]
  2592.     local genome = species.genomes[pool.currentGenome]
  2593.  
  2594.     if neural_net_disp then
  2595.         displayGenome(genome)
  2596.     end
  2597.     if pool.generation == 0 and pool.currentSpecies ~= 1 and not turbo and AllowAutoTurbo and FirstGenSpeedup then
  2598.         emu.speedmode("turbo")
  2599.         turbo = true
  2600.     -- elseif pool.generation == 2 and turbo and AllowAutoTurbo and FirstGenSpeedup then
  2601.         -- emu.speedmode("turbo")
  2602.         -- turbo = false
  2603.     end
  2604.  
  2605.     local nscompare = rightmost / 500.0
  2606.     local nsw = 1
  2607.     for n=1,#genome.networkswitch do
  2608.         if nscompare > genome.networkswitch[n] then
  2609.             nsw = n+1
  2610.         end
  2611.     end
  2612.     nswitch = nsw
  2613.  
  2614.     if pool.currentFrame%5 == 0 then
  2615.         evaluateCurrent()
  2616.     end
  2617.  
  2618.     joypad.set(player, controller)
  2619.  
  2620.     getPositions()
  2621.     local mariostate = mariostate
  2622.     local adjustfitness
  2623.     local CurrentWorld = CurrentWorld
  2624.     local CurrentLevel = CurrentLevel
  2625.     local marioX = marioX
  2626.     local marioY = marioY
  2627.     if mariostate == 2 or mariostate == 3 then --detects when mario enters a pipe
  2628.         marioPipeEnter = true
  2629.         if mariostate == 2 then
  2630.             adjustfitness = true
  2631.         else
  2632.             adjustfitness = false
  2633.         end
  2634.     end
  2635.     if (CurrentWorld == 3 and CurrentLevel == 4) or (CurrentWorld == 6 and CurrentLevel == 4) or (CurrentWorld == 7 and CurrentLevel == 3) then
  2636.         if currentTracker == currentscreen or currentTracker == nextscreen and not mariopipe then --follows the progress of mario
  2637.             currentTracker = nextscreen
  2638.         elseif currentTracker > nextscreen and not mariopipe and not marioPipeEnter and mariostate ~= 7 then --if mario suddenly goes back trigger loop detection
  2639.             loop = true
  2640.         elseif currentscreen == 0 and nextscreen == 0 and mariopipe and mariostate ~= 7 then -- if mario enters a piperoom negate loop detection
  2641.             loop = false
  2642.             currentTracker = nextscreen
  2643.         elseif nextscreen >= (currentTracker - 1) and mariopipe and mariostate ~= 7 then -- if mario goes forward in the level by entering a pipe negate loop detection
  2644.             loop = false
  2645.             currentTracker = nextscreen
  2646.             pipeexit = true
  2647.         else --if nothing is true then we are in a loop
  2648.             if not pipeexit then --prevents the extra one frame flicker of the tracker
  2649.             loop = true
  2650.             else
  2651.             pipeexit = false
  2652.             end
  2653.         end
  2654.     end
  2655.     if marioPipeEnter == true and mariostate == 7 then --set mariopipe when exiting the pipe
  2656.         mariopipe = true
  2657.     end
  2658.     if adjustfitness then
  2659.         if mariopipe == true and mariostate ~= 7 and rightmost > marioX and not mariohole then --calculate offset
  2660.             offset = rightmost - marioX
  2661.             mariopipe = false
  2662.             marioPipeEnter = false
  2663.         elseif mariopipe == true and mariostate ~= 7 and rightmost <= marioX and not mariohole then --if the exit coordinates are higher than rightmost after exiting a pipe set offset to 0
  2664.             offset = 0
  2665.             mariopipe = false
  2666.             marioPipeEnter = false
  2667.         end
  2668.     else
  2669.         if mariopipe == true and mariostate ~= 7 and not mariohole then --calculate offset --and rightmost > marioX
  2670.             offset = rightmost - marioX
  2671.             mariopipe = false
  2672.             marioPipeEnter = false
  2673.         end
  2674.     end
  2675. --Custom Fix: Springs
  2676.     --emu.print(marioY + memory.readbyte(0xB5)*255)
  2677.     if (marioY + memory.readbyte(0xB5)*255 > 512)then --added the fallen into a hole variable that will activate when LuigI/O goes below screen
  2678.         if marioY + memory.readbyte(0xB5)*255 > 768 and not mariohole then -- Added this bit to prevent LuigI/O from being treated as fallen when he goes too high on the screen due to Lost Level springs.
  2679.         TimeoutConstant = 800 -- Increase the TimeoutConstant so that the game won't timeout when LuigI/O uses the spring.
  2680.         else
  2681.         mariohole = true
  2682.        
  2683.         end
  2684.     else -- If LuigI/O's marioY + 0xB5 byte * 255 is less than 512, he is visible on the screen
  2685.         TimeoutConstant = 120 --Reset TimeoutConstant back to normal when visible on screen.
  2686.     end
  2687.     local dis = false
  2688.     local specialy = false
  2689.     if marioX > 2370 and marioX < 2460 and (LostLevels == 0 and CurrentWorld == 7 and CurrentLevel == 3) then
  2690.     specialy = true
  2691.     end
  2692.     if marioX > 2460 and marioX < 3000 and (LostLevels == 0 and CurrentWorld == 7 and CurrentLevel == 3) then
  2693.     dis = true
  2694.     end
  2695.     if marioX > 3000 and marioX < 3160 and marioY < 192 and marioY > 64 and (LostLevels == 1 and CurrentWorld == 1 and CurrentLevel == 1) then
  2696.     dis = true
  2697.     end
  2698.  
  2699.     if marioX > 496 and marioX < 928 and marioY < 128 and (LostLevels == 1 and CurrentWorld == 2 and CurrentLevel == 4) then
  2700.     dis = true
  2701.     end
  2702.     if marioX > 928 and marioX < 1264 and marioY < 160 and (LostLevels == 1 and CurrentWorld == 2 and CurrentLevel == 4) then
  2703.     dis = true
  2704.     end
  2705.     if marioX > 1632 and marioX < 2384 and (marioY > 80 or hitblocks == 0) and (LostLevels == 1 and CurrentWorld == 2 and CurrentLevel == 4) then
  2706.     dis = true
  2707.     end
  2708.    
  2709.     local ymulti = 0.2
  2710.     if (LostLevels == 0 and CurrentWorld == 3 and CurrentLevel > 2) then ymulti = 1 end
  2711.    
  2712.     local newright = marioX + offset - (marioY - 192)*ymulti + (50 *memory.readbyte(0x06D9))
  2713.     if specialy then
  2714.         newright = 2370 + offset - marioY + 192 + (50 *memory.readbyte(0x06D9))
  2715.     end
  2716.    
  2717.     if LostLevels == 0 and CurrentWorld == 3 and CurrentLevel == 4 then
  2718.         if marioX > 1680 and marioX < 2288 and marioY <= 144 then
  2719.             dis = true
  2720.         end
  2721.         if marioX > 300 and marioX < 1200 and marioY > 80 then
  2722.             dis = true
  2723.         end
  2724.         if marioX > 1512 and marioX < 1680 then
  2725.             if marioY <= 80 then
  2726.                 newright = marioX + offset + 112 + (50 *memory.readbyte(0x06D9))
  2727.             elseif marioY <= 144 then
  2728.                 newright = 3360 - marioX + offset + 176 + (50 *memory.readbyte(0x06D9))
  2729.             else
  2730.                 newright = 352 + marioX + offset + 224 + (50 *memory.readbyte(0x06D9))
  2731.             end
  2732.         elseif marioX > 1680 then
  2733.             newright = 352 + marioX + offset + 224 + 192 - marioY + (50 *memory.readbyte(0x06D9))
  2734.         end
  2735.     end
  2736.    
  2737.    
  2738.     if newright > rightmost and not mariohole and not loop and not marioPipeEnter and not killtrigger and not falling and not dis then
  2739.         rightmost = newright
  2740.         if rightmost > species.topright then
  2741.             species.topright = rightmost
  2742.         end
  2743.         timebonus = timebonus + (TimeoutConstant - timeout) * 11/20
  2744.         timeout = TimeoutConstant
  2745.     end
  2746.  
  2747.     if marioPipeEnter == true then --freeze fitness and timer when mario enters a pipe
  2748.         timeout = timeout + 1
  2749.         timebonus = timebonus + 2/3
  2750.     end
  2751.  
  2752. --Custom Fix: Changes made for Lost Levels 3-1 so that going in the subworld trap pipe won't increase fitness and for the last part "(marioX > 2900 and memory.readbyte(0xB5)*255 > 768)", when LuigI/O goes over the flagpole thanks to the spring (yes, it can happen, I tested), fitness will not increase as well.
  2753.     if(CurrentWorld == 2 and CurrentLevel == 0 and LostLevels == 1) then
  2754.         if (mariopipe and ((marioX > 500 and marioX < 572) or (marioX > 1244 and marioX < 1396) or (marioX > 3558 and marioX < 3708))) or (marioX > 2900 and memory.readbyte(0xB5)*255 > 768)  then
  2755.             loop = true
  2756.         end
  2757.     end
  2758.  
  2759.     if (mariostate == 4 or (memory.readbyte(0x000C) == 1 and statuscheck == 0) or ((memory.readbyte(0x06D6) ~= 0 and memory.readbyte(0x06D6) ~= 1) and marioPipeEnter)) or endlevel then --and statuscheck == 0
  2760.         timeout = timeout +1
  2761.         timebonus = timebonus + 2/3
  2762.         endlevel = true
  2763.     end
  2764.  
  2765.  
  2766.     if endlevel and mariostate == 8 and demoruncheck == 1 and statuscheck == 3 + LostLevels then
  2767.         local timeoutBonus = pool.currentFrame / 4
  2768.         local fitness = rightmost - pool.currentFrame / 2 +40 + timebonus
  2769.         genome.fitness = fitness
  2770.         pool.maxFitness = fitness
  2771.         fitnesstracker()
  2772.         savePool()
  2773.         if not rerunning then
  2774.             if LostLevels==1 then
  2775.                 SAVE_LOAD_FILE = "SMBLL".. CurrentWorld+1 .."-".. CurrentLevel ..".state.pool"
  2776.             else
  2777.                 SAVE_LOAD_FILE = "SMB".. CurrentWorld+1 .."-".. CurrentLevel ..".state.pool"
  2778.             end
  2779.             previous_savestate = savestate_slot
  2780.             savestate_slot = savestate_slot + 1
  2781.             if savestate_slot == 10 then
  2782.                 savestate_slot = 1
  2783.             end
  2784.  
  2785.             Savestatebackup = savestate.object(savestate_slot)
  2786.             savestate.save(Savestatebackup)
  2787.             savestate.persist(Savestatebackup)
  2788.             savestate.save(SavestateObj)
  2789.  
  2790.         end
  2791.         SavestateObj = savestate.object(savestate_slot)
  2792.         endlevel = false
  2793.         if (turbo or restoreturbo) and not rerunning then
  2794.             rerunning = true
  2795.             requiredFitness = 0
  2796.             minFitness = 0
  2797.             emu.speedmode("normal")
  2798.             turbo = false
  2799.             restoreturbo = false
  2800.             reRun()
  2801.         else
  2802.             rerunning = false
  2803.             preparenext = true
  2804.         end
  2805.     end
  2806.  
  2807.     if CurrentWorld == 0 and CurrentLevel == 0 and demoruncheck == 0 then
  2808.         savestate.load(SavestateObj)
  2809.     end
  2810.  
  2811.     timeout = timeout - 1
  2812.     if preparenext then
  2813.         rerunning = false
  2814.         preparenext = false
  2815.         GenerateNewKeepBest(genome, species.nickname)
  2816.     end
  2817.     if rightmost > maxright then
  2818.         maxright = rightmost
  2819.     end
  2820.     if rightmost > maxright*0.85 and AllowSlowdownNearMax then
  2821.         if turbo and maxright > 200 and AllowSlowdownNearMax and not restoreturbo then
  2822.             emu.speedmode("normal")
  2823.             turbo = false
  2824.             restoreturbo = true
  2825.         end
  2826.     elseif restoreturbo and not (requiredFitness > 10) then
  2827.         emu.speedmode("turbo")
  2828.         turbo = true
  2829.         restoreturbo = false
  2830.     end
  2831.     --emu.print(marioX .. " " .. marioY)
  2832.     local timeoutBonus = pool.currentFrame / 4
  2833.     if (mariostate == 11 or mariohole or math.floor(rightmost - (pool.currentFrame) / 2 + - (timeout + timeoutBonus)*2/3 +40 + timebonus) < -50 ) and timeout > 40-timeoutBonus then
  2834.         local temptimeout = timeout
  2835.         timeout = 30 - timeoutBonus
  2836.         local difference = temptimeout - timeout
  2837.         pool.currentFrame = pool.currentFrame + difference
  2838.         killtrigger = true
  2839.     end
  2840.     local timeoutBonus = pool.currentFrame / 4
  2841.     if timeout + timeoutBonus <= 0 then
  2842.         local fitness = rightmost - pool.currentFrame / 2 +40 + timebonus + hitblocks * hbValue
  2843.         if fitness == 0 then
  2844.             fitness = -1
  2845.         end
  2846.  
  2847.             genome.fitness = fitness
  2848.  
  2849.         if species.topFitness < secondbest and fitness > secondbest and fitness < pool.maxFitness then --system for automatically updating the second best value
  2850.             secondbest = fitness
  2851.         elseif species.topFitness < pool.maxFitness and fitness > pool.maxFitness then
  2852.             secondbest = pool.maxFitness
  2853.         elseif species.topFitness == secondbest and fitness > secondbest and fitness < pool.maxFitness then
  2854.             secondbest = fitness
  2855.         elseif species.topFitness == secondbest and fitness > pool.maxFitness then
  2856.             secondbest = pool.maxFitness
  2857.         end
  2858.        
  2859.         if fitness > pool.maxFitness then
  2860.             pool.maxFitness = fitness
  2861.             fitnesstracker()
  2862.             savePool()
  2863.         end
  2864.  
  2865.         if fitness > pool.maxFitness - 30 then
  2866.             pool.maxcounter = pool.maxcounter + 1
  2867.         end
  2868.  
  2869.         emu.print("Gen " .. pool.generation .. " species " .. pool.currentSpecies .. " genome " .. pool.currentGenome .. " fitness: " .. fitness)
  2870.         pool.currentSpecies = 1
  2871.         pool.currentGenome = 1
  2872.         while fitnessAlreadyMeasured() do
  2873.             offset = 0 --offset in x coordinates for pipe
  2874.             timebonus = 0 --used to freeze fitness
  2875.             mariohole = false --reset the fallen into hole variable
  2876.             mariopipe = false --is mario exiting a pipe or just teleporting
  2877.             loop = false --is this a loop?
  2878.             marioPipeEnter = false --has mario entered a pipe
  2879.             currentTracker = 1 --tracker for the loop
  2880.             killtrigger = false
  2881.             ntrigger = true
  2882.             nswitch = 1
  2883.             if rerunning then
  2884.                 rerunning = false
  2885.                 preparenext = true
  2886.             end
  2887.             nextGenome()
  2888.         end
  2889.        
  2890.  
  2891.         initializeRun()
  2892.     end
  2893.  
  2894.    
  2895.         gui.opacity(1) --made the top banner opaque. you can change this if you want a slightly transparent banner
  2896.         if turbo then
  2897.             gui.drawtext(250, 11, "T", toRGBA(0xFFFF0000), 0x0)
  2898.         end
  2899.         gui.drawtext(5, 11, "Gen " .. pool.generation .. " species " .. pool.currentSpecies .. " genome " .. pool.currentGenome .. " (" .. math.floor(pool.measured/pool.total*100) .. "%) ".. "Pop: ".. Population, toRGBA(0xFF000000), 0x0)
  2900.         gui.drawtext(5, 20, "Fitness: " .. math.floor(hitblocks * hbValue + rightmost - (pool.currentFrame) / 2 + - (timeout + timeoutBonus)*2/3 +40 + timebonus) , toRGBA(0xFF000000), 0x0) --the (timeout + timeoutBonus)*2/3 makes sure that the displayed fitness remains stable for the viewers pleasure
  2901.         gui.drawtext(80, 20, "Max Fitness:" .. math.floor(pool.maxFitness) .. " (".. math.floor(secondbest) .. ")".. " ".. "(" .. pool.maxcounter .. "x)", toRGBA(0xFF000000), 0x0)
  2902.  
  2903.     pool.currentFrame = pool.currentFrame + 1
  2904.  
  2905.     emu.frameadvance();
  2906. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement