Advertisement
Code-Akisame

LuigI/O version 2

May 30th, 2018
2,853
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 62.70 KB | None | 0 0
  1. -- LuigI/O by Akisame based on SethBling's MarI/O with modifications described here: https://pastebin.com/7qkeVVxi.
  2. -- 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, T will activate the turbo and S will save the current location in your pool.
  3.  
  4. -- This is an early version and still a work in progress.
  5. -- To use this script you will need to download FCEUX and create a savestate in state 1 as player 2(luigi) for smb. You will then need to go to config -> input and set player 2 to gamepad.
  6. -- Click file -> lua -> 'new lua script window' and load the script.
  7. -- Have fun!
  8. -- 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.
  9.  
  10.  
  11. --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
  12. --for loading specific generations replace nil with the filename as shown in the example below
  13. savedpool = nil
  14. --savedpool = "backup.71.SMB2-4.state.pool"
  15. --savedpool = "backups/backup.118.SMB2-1.state.pool"
  16.  
  17. -- HUD options. These can be changed on the fly by pressing 'M' for the mutation rates and 'N' for the network
  18. mutation_rates_disp = false
  19. neural_net_disp = true
  20.  
  21. --set to false if you want warning popups before loading anything that might cause you to lose your current progress
  22. nopopup = true
  23.  
  24. savestate_slot = 1 -- Load the level from FCEUX savestate slot.
  25.  
  26. --SAVE_LOAD_FILE = "test.pool" --filename to be used
  27. SAVE_LOAD_FILE = nil --auto generate appropriate name from level values in ram (might not completely match with actual level)
  28.  
  29. player = 2 --1 for mario 2 for luigi
  30.  
  31. AllowAutoTurbo = true --Automatic turbo
  32. AllowSlowdownNearMax = true --This is slow down the turbo when it nears to furthest it has currently gotten
  33. FirstGenSpeedup = true --This will speed up the first generation
  34. BottleneckTurbo = false --Activate turbo on bottleneck detection
  35. TurboGenBottleneck = 20 --will start the turbo when it is in a bottleneck for 20 generations. Please adjust to match your taste
  36.  
  37. os.execute("mkdir backups") --create the folder to save the pools in
  38.  
  39. SavestateObj = savestate.object(savestate_slot)
  40.  
  41.     ButtonNames = {
  42.         "A",
  43.         "B",
  44.         "up",
  45.         "down",
  46.         "left",
  47.         "right",
  48.     }
  49.  
  50.  
  51. BoxRadius = 6
  52. InputSize = (BoxRadius*2+1)*(BoxRadius*2+1)
  53.  
  54. switchtime = {10,12,18}
  55. switchtimer = {}
  56. initialswitchvalue = {}
  57. for i=1,#switchtime do
  58.     switchtimer[i] = switchtime[i]
  59.     initialswitchvalue[i] = 1
  60. end
  61.  
  62. Inputs = InputSize+1+#initialswitchvalue
  63. Outputs = #ButtonNames
  64.  
  65. Population = 100
  66. DeltaDisjoint = 2.0
  67. DeltaWeights = 0.4
  68. DeltaThreshold = 1.0
  69.  
  70. keyflag = false --used for keyboard input
  71. endlevel = false
  72. preparenext = false
  73. secondbest = 0
  74. maxright = 0
  75. restoreturbo = false
  76. rerunning = false
  77. killcounter = 0
  78.  
  79. StaleSpecies = 25 --increased slightly to allow for longer evolution
  80. mariohole = false --flag for mario falling into a hole
  81. mariopipe = false --flag for mario exiting a pipe
  82. marioPipeEnter = false --new flag for entering a pipe
  83. offset = 0 --offset value for when mario exits a pipe
  84. timebonus = 0 --timebonus to prevent the hard drops in fitness when exiting a pipe
  85. maxcounter = 0 --species that reach the max fitness
  86. currentTracker = 0 --tracks location on screen
  87. loop = false --flag for when a loop is detected
  88. previousmaxfitness = 0
  89. bottleneckcounter = 0
  90.  
  91. MutateConnectionsChance = 0.25
  92. PerturbChance = 0.90
  93. CrossoverChance = 0.75
  94. LinkMutationChance = 2.0
  95. NodeMutationChance = 0.50
  96. BiasMutationChance = 0.40
  97. StepSize = 0.1
  98. DisableMutationChance = 0.4
  99. EnableMutationChance = 0.2
  100. oscilationmutationchance = 0.2
  101. interbreedchance = 0.03
  102. networkswitchmutationchance = 0.01
  103. replaceSecondNetworkChance = 0.01
  104.  
  105. nswitch = true
  106. ntrigger = true
  107.  
  108. ncount = 0
  109.  
  110. TimeoutConstant = 120 --set to a higher value but see for yourself what is acceptable
  111.  
  112. MaxNodes = 1000000
  113.  
  114. function getPositions()
  115.         marioX = memory.readbyte(0x6D) * 0x100 + memory.readbyte(0x86)
  116.         marioY = memory.readbyte(0x03B8)+16
  117.         mariostate = memory.readbyte(0x0E) --get mario's state. (entering exiting pipes, dying, picking up a mushroom etc etc)
  118.         yspeed = memory.readbyte(0x009F) --y velocity 1-5 are falling and 250-255 is jumping
  119.         if yspeed >1 and yspeed <10 then
  120.             falling = true
  121.         else
  122.             falling = false
  123.         end
  124.        
  125.         currentscreen = memory.readbyte(0x071A) --finds current screen for loop detection
  126.         nextscreen = memory.readbyte(0x071B) --finds next screen
  127.        
  128.         CurrentWorld = memory.readbyte(0x075F) --finds the current world (value + 1 is world)
  129.         CurrentLevel = memory.readbyte(0x0760) --finds the current level (0=1 2=2 3=3 4=4)
  130.         demoruncheck = memory.readbyte(0x0770) --equals 0 for demo and 1 for normal run
  131.         statuscheck = memory.readbyte(0x0772) -- 3= playing 1 = loading
  132.        
  133.         screenX = memory.readbyte(0x03AD)
  134.         screenY = memory.readbyte(0x03B8)
  135. end
  136.  
  137. function getTile(dx, dy)
  138.         local x = marioX + dx + 8
  139.         local y = marioY + dy - 16
  140.         local page = math.floor(x/256)%2
  141.  
  142.         local subx = math.floor((x%256)/16)
  143.         local suby = math.floor((y - 32)/16)
  144.         local addr = 0x500 + page*13*16+suby*16+subx
  145.        
  146.         if suby >= 13 or suby < 0 then
  147.             return 0
  148.         end
  149.        
  150.         if memory.readbyte(addr) ~= 0 then
  151.             return 1
  152.         else
  153.             return 0
  154.         end
  155. end
  156.  
  157. function getSprites()
  158.         local sprites = {}
  159.         for slot=0,4 do
  160.             local enemy = memory.readbyte(0xF+slot)
  161.             if enemy ~= 0 then
  162.                 local ex = memory.readbyte(0x6E + slot)*0x100 + memory.readbyte(0x87+slot)
  163.                 local ey = memory.readbyte(0xCF + slot)+36 --changed this to stop sprites from floating in mid air on the neural network
  164.                 sprites[#sprites+1] = {["x"]=ex,["y"]=ey}
  165.             end
  166.         end
  167.        
  168.         return sprites
  169. end
  170.  
  171. function getInputs()
  172.     getPositions()
  173.    
  174.     sprites = getSprites()
  175.    
  176.     local inputs = {}
  177.    
  178.     for dy=-BoxRadius*16,BoxRadius*16,16 do
  179.         for dx=-BoxRadius*16,BoxRadius*16,16 do
  180.             inputs[#inputs+1] = 0
  181.            
  182.             tile = getTile(dx, dy)
  183.             if tile == 1 and marioY+dy < 0x1B0 then
  184.                 inputs[#inputs] = 1
  185.             end
  186.            
  187.             for i = 1,#sprites do
  188.                 distx = math.abs(sprites[i]["x"] - (marioX+dx))
  189.                 disty = math.abs(sprites[i]["y"] - (marioY+dy+16))
  190.                 if distx <= 8 and disty <= 8 then
  191.                     inputs[#inputs] = -1
  192.                 end
  193.             end
  194.         end
  195.     end
  196.    
  197.     return inputs
  198. end
  199.  
  200. function sigmoid(x)
  201.     return 2/(1+math.exp(-4.9*x))-1
  202. end
  203.  
  204. function newInnovation()
  205.     pool.innovation = pool.innovation + 1
  206.     return pool.innovation
  207. end
  208.  
  209. function newPool()
  210.     local pool = {}
  211.     pool.species = {}
  212.     pool.generation = 0
  213.     pool.innovation = Outputs
  214.     pool.currentSpecies = 1
  215.     pool.currentGenome = 1
  216.     pool.currentFrame = 0
  217.     pool.maxFitness = 0
  218.     pool.maxcounter = 0  --counter for %max species reached
  219.     pool.averagemaxfitness = 0
  220.    
  221.     return pool
  222. end
  223.  
  224. function newSpecies()
  225.     local species = {}
  226.     species.topFitness = 0
  227.     species.staleness = 0
  228.     species.genomes = {}
  229.     species.averageFitness = 0
  230.     species.nickname = 'none'
  231.     species.turbo = 'on'
  232.    
  233.     return species
  234. end
  235.  
  236. function getCurrentGenome()
  237.     local species = pool.species[pool.currentSpecies]
  238.     return species.genomes[pool.currentGenome]
  239. end
  240.  
  241. function toRGBA(ARGB)
  242.     return bit.lshift(ARGB, 8) + bit.rshift(ARGB, 24)
  243. end
  244.  
  245.  
  246. function newGenome()
  247.     local genome = {}
  248.     genome.genes = {}
  249.     genome.genes2 = {}
  250.     genome.fitness = 0
  251.     genome.adjustedFitness = 0
  252.     genome.network = {}
  253.     genome.network2 = {}
  254.     genome.maxneuron = 0
  255.     genome.globalRank = 0
  256.     genome.oscilations = {}
  257.     genome.networkswitch = 0
  258.     for i=1,#switchtime do
  259.         genome.oscilations[i] = switchtime[i]
  260.     end
  261.     genome.mutationRates = {}
  262.     genome.mutationRates["connections"] = MutateConnectionsChance
  263.     genome.mutationRates["link"] = LinkMutationChance
  264.     genome.mutationRates["bias"] = BiasMutationChance
  265.     genome.mutationRates["node"] = NodeMutationChance
  266.     genome.mutationRates["enable"] = EnableMutationChance
  267.     genome.mutationRates["disable"] = DisableMutationChance
  268.     genome.mutationRates["step"] = StepSize
  269.     genome.mutationRates["oscilation"] = oscilationmutationchance
  270.     genome.mutationRates["networkswitch"] = networkswitchmutationchance
  271.    
  272.     return genome
  273. end
  274.  
  275. function copyGenome(genome)
  276.     local genome2 = newGenome()
  277.     for g=1,#genome.genes do
  278.         table.insert(genome2.genes, copyGene(genome.genes[g]))
  279.     end
  280.     for g=1,#genome.genes2 do
  281.         table.insert(genome2.genes2, copyGene(genome.genes2[g]))
  282.     end
  283.     for i=1,#genome.oscilations do
  284.         genome2.oscilations[i] = genome.oscilations[i]
  285.     end
  286.     genome2.networkswitch = genome.networkswitch
  287.     genome2.maxneuron = genome.maxneuron
  288.     genome2.mutationRates["connections"] = genome.mutationRates["connections"]
  289.     genome2.mutationRates["link"] = genome.mutationRates["link"]
  290.     genome2.mutationRates["bias"] = genome.mutationRates["bias"]
  291.     genome2.mutationRates["node"] = genome.mutationRates["node"]
  292.     genome2.mutationRates["enable"] = genome.mutationRates["enable"]
  293.     genome2.mutationRates["disable"] = genome.mutationRates["disable"]
  294.     genome2.mutationRates["oscilation"] = genome.mutationRates["oscilation"]
  295.     genome2.mutationRates["networkswitch"] = genome.mutationRates["networkswitch"]
  296.    
  297.     return genome2
  298. end
  299.  
  300. function basicGenome()
  301.     local genome = newGenome()
  302.     local innovation = 1
  303.  
  304.     genome.maxneuron = Inputs
  305.     mutate(genome, 1)
  306.     mutate(genome, 2)
  307.    
  308.     return genome
  309. end
  310.  
  311. function newGene()
  312.     local gene = {}
  313.     gene.into = 0
  314.     gene.out = 0
  315.     gene.weight = 0.0
  316.     gene.enabled = true
  317.     gene.innovation = 0
  318.    
  319.     return gene
  320. end
  321.  
  322. function copyGene(gene)
  323.     local gene2 = newGene()
  324.     gene2.into = gene.into
  325.     gene2.out = gene.out
  326.     gene2.weight = gene.weight
  327.     gene2.enabled = gene.enabled
  328.     gene2.innovation = gene.innovation
  329.    
  330.     return gene2
  331. end
  332.  
  333. function newNeuron()
  334.     local neuron = {}
  335.     neuron.incoming = {}
  336.     neuron.value = 0.0
  337.     neuron.switcher = false
  338.     neuron.timer = 60
  339.     neuron.multiplier = 1
  340.    
  341.     return neuron
  342. end
  343.  
  344. function generateNetwork(genome)
  345.     local network = {}
  346.     network.neurons = {}
  347.    
  348.     for i=1,Inputs do
  349.         network.neurons[i] = newNeuron()
  350.     end
  351.    
  352.     for o=1,Outputs do
  353.         network.neurons[MaxNodes+o] = newNeuron()
  354.     end
  355.    
  356.     table.sort(genome.genes, function (a,b)
  357.         return (a.out < b.out)
  358.     end)
  359.     for i=1,#genome.genes do
  360.         local gene = genome.genes[i]
  361.         if gene.enabled then
  362.             if network.neurons[gene.out] == nil then
  363.                 network.neurons[gene.out] = newNeuron()
  364.             end
  365.             local neuron = network.neurons[gene.out]
  366.             table.insert(neuron.incoming, gene)
  367.             if network.neurons[gene.into] == nil then
  368.                 network.neurons[gene.into] = newNeuron()
  369.             end
  370.         end
  371.     end
  372.    
  373.     genome.network = network
  374.    
  375.     local network2 = {}
  376.     network2.neurons = {}
  377.    
  378.     for i=1,Inputs do
  379.         network2.neurons[i] = newNeuron()
  380.     end
  381.    
  382.     for o=1,Outputs do
  383.         network2.neurons[MaxNodes+o] = newNeuron()
  384.     end
  385.    
  386.     table.sort(genome.genes2, function (a,b)
  387.         return (a.out < b.out)
  388.     end)
  389.     for i=1,#genome.genes2 do
  390.         local gene = genome.genes2[i]
  391.         if gene.enabled then
  392.             if network2.neurons[gene.out] == nil then
  393.                 network2.neurons[gene.out] = newNeuron()
  394.             end
  395.             local neuron = network2.neurons[gene.out]
  396.             table.insert(neuron.incoming, gene)
  397.             if network2.neurons[gene.into] == nil then
  398.                 network2.neurons[gene.into] = newNeuron()
  399.             end
  400.         end
  401.     end
  402.    
  403.     genome.network2 = network2
  404. end
  405.  
  406. function evaluateNetwork(network, inputs, genome)
  407.     table.insert(inputs, 1) -- bias input node
  408.     for i = 1,#initialswitchvalue do
  409.         if genome.oscilations[i] > 0 then
  410.             if switchtimer[i] > 0 then
  411.                 switchtimer[i] = switchtimer[i] -1
  412.             else
  413.                 switchtimer[i] = genome.oscilations[i]
  414.                 initialswitchvalue[i] = initialswitchvalue[i]*-1
  415.             end
  416.         end
  417.         table.insert(inputs, initialswitchvalue[i])
  418.            
  419.     end
  420.        
  421.     if #inputs ~= Inputs then
  422.         emu.print("Incorrect number of neural network inputs.")
  423.         return {}
  424.     end
  425.    
  426.     for i=1,Inputs do
  427.         network.neurons[i].value = inputs[i]
  428.     end
  429.    
  430.     for _,neuron in pairs(network.neurons) do
  431.         local sum = 0
  432.         for j = 1,#neuron.incoming do
  433.             local incoming = neuron.incoming[j]
  434.             local other = network.neurons[incoming.into]
  435.             sum = sum + incoming.weight * other.value
  436.         end
  437.        
  438.         if #neuron.incoming > 0 then
  439.             if neuron.switcher and sigmoid(sum)>0 then
  440.                 neuron.timer = neuron.timer - 1
  441.             elseif neuron.switcher then
  442.                 neuron.timer = 120
  443.                 neuron.multiplier = 1
  444.             end
  445.            
  446.             if neuron.switcher and neuron.timer < 0 then
  447.                 neuron.multiplier = -neuron.multiplier
  448.                 neuron.timer = 10
  449.             end
  450.             neuron.value = sigmoid(sum) * neuron.multiplier
  451.            
  452.         end
  453.     end
  454.    
  455.     local outputs = {}
  456.     for o=1,Outputs do
  457.         local button = ButtonNames[o]
  458.         if network.neurons[MaxNodes+o].value > 0 then
  459.             outputs[button] = true
  460.         else
  461.             outputs[button] = false
  462.         end
  463.     end
  464.    
  465.     return outputs
  466. end
  467.  
  468. function crossover(g1, g2)
  469.     -- Make sure g1 is the higher fitness genome
  470.     if g2.fitness > g1.fitness then
  471.         tempg = g1
  472.         g1 = g2
  473.         g2 = tempg
  474.     end
  475.  
  476.     local child = newGenome()
  477.     for i=1,#g1.oscilations do
  478.         child.oscilations[i] = g1.oscilations[i]
  479.     end
  480.     child.networkswitch = g1.networkswitch
  481.     local innovations2 = {}
  482.     for i=1,#g2.genes do
  483.         local gene = g2.genes[i]
  484.         innovations2[gene.innovation] = gene
  485.     end
  486.    
  487.     for i=1,#g1.genes do
  488.         local gene1 = g1.genes[i]
  489.         local gene2 = innovations2[gene1.innovation]
  490.         if gene2 ~= nil and math.random(1,2) == 1 and gene2.enabled then
  491.             table.insert(child.genes, copyGene(gene2))
  492.         else
  493.             table.insert(child.genes, copyGene(gene1))
  494.         end
  495.     end
  496.     for i=1,#g1.genes2 do
  497.         local gene1 = g1.genes2[i]
  498.         local gene2 = innovations2[gene1.innovation]
  499.         if gene2 ~= nil and math.random(1,2) == 1 and gene2.enabled then
  500.             table.insert(child.genes2, copyGene(gene2))
  501.         else
  502.             table.insert(child.genes2, copyGene(gene1))
  503.         end
  504.     end
  505.    
  506.     child.maxneuron = math.max(g1.maxneuron,g2.maxneuron)
  507.    
  508.     for mutation,rate in pairs(g1.mutationRates) do
  509.         child.mutationRates[mutation] = rate
  510.     end
  511.    
  512.     return child
  513. end
  514.  
  515. function randomNeuron(genes, nonInput)
  516.     local neurons = {}
  517.     if not nonInput then
  518.         for i=1,Inputs do
  519.             neurons[i] = true
  520.         end
  521.     end
  522.     for o=1,Outputs do
  523.         neurons[MaxNodes+o] = true
  524.     end
  525.     for i=1,#genes do
  526.         if (not nonInput) or genes[i].into > Inputs then
  527.             neurons[genes[i].into] = true
  528.         end
  529.         if (not nonInput) or genes[i].out > Inputs then
  530.             neurons[genes[i].out] = true
  531.         end
  532.     end
  533.     local count = 0
  534.     for _,_ in pairs(neurons) do
  535.         count = count + 1
  536.     end
  537.     local n = math.random(1, count)
  538.     for k,v in pairs(neurons) do
  539.         n = n-1
  540.         if n == 0 then
  541.             return k
  542.         end
  543.     end
  544.    
  545.     return 0
  546. end
  547.  
  548. function containsLink(genes, link)
  549.     for i=1,#genes do
  550.         local gene = genes[i]
  551.         if gene.into == link.into and gene.out == link.out then
  552.             return true
  553.         end
  554.     end
  555. end
  556.  
  557. function pointMutate(genome, which)
  558.     local step = genome.mutationRates["step"]
  559.     local gene = {}
  560.     if which == 1 then
  561.         for i=1,#genome.genes do
  562.             gene = genome.genes[i]
  563.             if math.random() < PerturbChance then
  564.                 gene.weight = gene.weight + math.random() * step*2 - step
  565.             else
  566.                 gene.weight = math.random()*4-2
  567.             end
  568.         end
  569.     else
  570.         for i=1,#genome.genes2 do
  571.             gene = genome.genes2[i]
  572.             if math.random() < PerturbChance then
  573.                 gene.weight = gene.weight + math.random() * step*2 - step
  574.             else
  575.                 gene.weight = math.random()*4-2
  576.             end
  577.         end
  578.     end
  579. end
  580.  
  581. function linkMutate(genome, forceBias, which)
  582.     local neuron1 = 0
  583.     local neuron2 = 0
  584.     if which == 1 then
  585.         neuron1 = randomNeuron(genome.genes, false)
  586.         neuron2 = randomNeuron(genome.genes, true)
  587.     else
  588.         neuron1 = randomNeuron(genome.genes2, false)
  589.         neuron2 = randomNeuron(genome.genes2, true)
  590.     end
  591.    
  592.     local newLink = newGene()
  593.     if neuron1 <= Inputs and neuron2 <= Inputs then
  594.         --Both input nodes
  595.         return
  596.     end
  597.    
  598.     if neuron2 <= Inputs then
  599.         -- Swap output and input
  600.         local temp = neuron1
  601.         neuron1 = neuron2
  602.         neuron2 = temp
  603.     end
  604.  
  605.     newLink.into = neuron1
  606.     newLink.out = neuron2
  607.     if forceBias then
  608.         local adjustment = math.random(0,#initialswitchvalue)
  609.         newLink.into = Inputs - adjustment
  610.     end
  611.     if which == 1 then
  612.         if containsLink(genome.genes, newLink) then
  613.             return
  614.         end
  615.     else
  616.         if containsLink(genome.genes2, newLink) then
  617.             return
  618.         end
  619.     end
  620.     newLink.innovation = newInnovation()
  621.     newLink.weight = math.random()*4-2
  622.     if which == 1 then
  623.         table.insert(genome.genes, newLink)
  624.     else
  625.         table.insert(genome.genes2, newLink)
  626.     end
  627. end
  628.  
  629. function nodeMutate(genome, which)
  630.     if which == 1 then
  631.         if #genome.genes == 0 then
  632.             return
  633.         end
  634.     else
  635.         if #genome.genes2 == 0 then
  636.             return
  637.         end
  638.     end
  639.  
  640.     genome.maxneuron = genome.maxneuron + 1
  641.     local gene = {}
  642.     if which == 1 then
  643.         gene = genome.genes[math.random(1,#genome.genes)]
  644.     else
  645.         gene = genome.genes2[math.random(1,#genome.genes2)]
  646.     end
  647.     if not gene.enabled then
  648.         return
  649.     end
  650.     gene.enabled = false
  651.    
  652.     local gene1 = copyGene(gene)
  653.     gene1.out = genome.maxneuron
  654.     gene1.weight = 1.0
  655.     gene1.innovation = newInnovation()
  656.     gene1.enabled = true
  657.     if which == 1 then
  658.         table.insert(genome.genes, gene1)
  659.     else
  660.         table.insert(genome.genes2, gene1)
  661.     end
  662.    
  663.     local gene2 = copyGene(gene)
  664.     gene2.into = genome.maxneuron
  665.     gene2.innovation = newInnovation()
  666.     gene2.enabled = true
  667.     if which == 1 then
  668.         table.insert(genome.genes, gene2)
  669.     else
  670.         table.insert(genome.genes2, gene2)
  671.     end
  672. end
  673.  
  674. function enableDisableMutate(genome, enable, which)
  675.     local candidates = {}
  676.     if which == 1 then
  677.         for _,gene in pairs(genome.genes) do
  678.             if gene.enabled == not enable then
  679.                 table.insert(candidates, gene)
  680.             end
  681.         end
  682.     else
  683.         for _,gene in pairs(genome.genes2) do
  684.             if gene.enabled == not enable then
  685.                 table.insert(candidates, gene)
  686.             end
  687.         end
  688.     end
  689.    
  690.     if #candidates == 0 then
  691.         return
  692.     end
  693.    
  694.     local gene = candidates[math.random(1,#candidates)]
  695.     gene.enabled = not gene.enabled
  696. end
  697.  
  698. function oscilationMutate(genome)
  699.     mutationpoint = math.random(1,#genome.oscilations)
  700.     if genome.oscilations[mutationpoint]>0 then
  701.         if math.random(1,2) == 1 then
  702.             genome.oscilations[mutationpoint] = genome.oscilations[mutationpoint] + 1
  703.         else
  704.             genome.oscilations[mutationpoint] = genome.oscilations[mutationpoint] - 1
  705.         end
  706.     end
  707.     if genome.oscilations[mutationpoint]<0 then
  708.         genome.oscilations[mutationpoint] = 0
  709.     end
  710. end
  711.  
  712. function NswitchMutate(genome)
  713.     if math.random(1,2) == 1 then
  714.         if math.random(1,2) == 1 then
  715.             genome.networkswitch = genome.networkswitch + 0.1
  716.         else
  717.             genome.networkswitch = genome.networkswitch - 0.1
  718.         end
  719.     else
  720.         if math.random(1,2) == 1 then
  721.             genome.networkswitch = genome.networkswitch + 0.5
  722.         else
  723.             genome.networkswitch = genome.networkswitch - 0.5
  724.         end
  725.     end
  726.     if genome.networkswitch < 1 then
  727.         genome.networkswitch = math.random(0,8)
  728.     end
  729.     if genome.networkswitch > 8 then
  730.         genome.networkswitch = math.random(0,8)
  731.     end
  732. end
  733.  
  734. function mutate(genome, which)
  735.     for mutation,rate in pairs(genome.mutationRates) do
  736.         if math.random(1,2) == 1 then
  737.             genome.mutationRates[mutation] = 0.95*rate
  738.         else
  739.             genome.mutationRates[mutation] = 1.05263*rate
  740.         end
  741.     end
  742.     if math.random() < genome.mutationRates["connections"] then
  743.         pointMutate(genome, which)
  744.     end
  745.    
  746.     local p = genome.mutationRates["link"]
  747.     while p > 0 do
  748.         if math.random() < p then
  749.             linkMutate(genome, false, which)
  750.         end
  751.         p = p - 1
  752.     end
  753.  
  754.     p = genome.mutationRates["bias"]
  755.     while p > 0 do
  756.         if math.random() < p then
  757.             linkMutate(genome, true, which)
  758.         end
  759.         p = p - 1
  760.     end
  761.    
  762.     p = genome.mutationRates["node"]
  763.     while p > 0 do
  764.         if math.random() < p then
  765.             nodeMutate(genome, which)
  766.         end
  767.         p = p - 1
  768.     end
  769.    
  770.     p = genome.mutationRates["enable"]
  771.     while p > 0 do
  772.         if math.random() < p then
  773.             enableDisableMutate(genome, true, which)
  774.         end
  775.         p = p - 1
  776.     end
  777.  
  778.     p = genome.mutationRates["disable"]
  779.     while p > 0 do
  780.         if math.random() < p then
  781.             enableDisableMutate(genome, false, which)
  782.         end
  783.         p = p - 1
  784.     end
  785.    
  786.     p = genome.mutationRates["oscilation"]
  787.     while p > 0 do
  788.         if math.random() < p then
  789.             oscilationMutate(genome)
  790.         end
  791.         p = p - 1
  792.     end
  793.    
  794.     if genome.networkswitch > 0 then
  795.         p = genome.mutationRates["networkswitch"]
  796.         while p > 0 do
  797.             if math.random() < p then
  798.                 NswitchMutate(genome)
  799.             end
  800.             p = p - 1
  801.         end
  802.     end
  803. end
  804.  
  805. function disjoint(genes1, genes2)
  806.     local i1 = {}
  807.     for i = 1,#genes1 do
  808.         local gene = genes1[i]
  809.         i1[gene.innovation] = true
  810.     end
  811.  
  812.     local i2 = {}
  813.     for i = 1,#genes2 do
  814.         local gene = genes2[i]
  815.         i2[gene.innovation] = true
  816.     end
  817.    
  818.     local disjointGenes = 0
  819.     for i = 1,#genes1 do
  820.         local gene = genes1[i]
  821.         if not i2[gene.innovation] then
  822.             disjointGenes = disjointGenes+1
  823.         end
  824.     end
  825.    
  826.     for i = 1,#genes2 do
  827.         local gene = genes2[i]
  828.         if not i1[gene.innovation] then
  829.             disjointGenes = disjointGenes+1
  830.         end
  831.     end
  832.    
  833.     local n = math.max(#genes1, #genes2)
  834.    
  835.     return disjointGenes / n
  836. end
  837.  
  838. function weights(genes1, genes2)
  839.     local i2 = {}
  840.     for i = 1,#genes2 do
  841.         local gene = genes2[i]
  842.         i2[gene.innovation] = gene
  843.     end
  844.  
  845.     local sum = 0
  846.     local coincident = 0
  847.     for i = 1,#genes1 do
  848.         local gene = genes1[i]
  849.         if i2[gene.innovation] ~= nil then
  850.             local gene2 = i2[gene.innovation]
  851.             sum = sum + math.abs(gene.weight - gene2.weight)
  852.             coincident = coincident + 1
  853.         end
  854.     end
  855.    
  856.     return sum / coincident
  857. end
  858.    
  859. function sameSpecies(genome1, genome2)
  860.     if genome1.networkswitch == 0 and genome2.networkswitch == 0 then
  861.         local dd = DeltaDisjoint*disjoint(genome1.genes, genome2.genes)
  862.         local dw = DeltaWeights*weights(genome1.genes, genome2.genes)
  863.         return dd + dw < DeltaThreshold
  864.     elseif math.abs(genome1.networkswitch - genome2.networkswitch) > 0.6 then
  865.         return false
  866.     else
  867.         local dd = DeltaDisjoint*disjoint(genome1.genes, genome2.genes)
  868.         local dw = DeltaWeights*weights(genome1.genes, genome2.genes)
  869.         local dd2 = DeltaDisjoint*disjoint(genome1.genes2, genome2.genes2)
  870.         local dw2 = DeltaWeights*weights(genome1.genes2, genome2.genes2)
  871.         if dd + dw < DeltaThreshold and dd2 + dw2 < DeltaThreshold then
  872.             return true
  873.         else
  874.             return false
  875.         end
  876.     end
  877. end
  878.  
  879. function rankGlobally()
  880.     local global = {}
  881.     for s = 1,#pool.species do
  882.         local species = pool.species[s]
  883.         for g = 1,#species.genomes do
  884.             table.insert(global, species.genomes[g])
  885.         end
  886.     end
  887.     table.sort(global, function (a,b)
  888.         return (a.fitness < b.fitness)
  889.     end)
  890.    
  891.     for g=1,#global do
  892.         global[g].globalRank = g
  893.     end
  894. end
  895.  
  896. function calculateAverageFitness(species)
  897.     local total = 0
  898.    
  899.     for g=1,#species.genomes do
  900.         local genome = species.genomes[g]
  901.         total = total + genome.globalRank
  902.     end
  903.     if species.topFitness < pool.averagemaxfitness - (pool.standardDeviationMaxFitness *2) then
  904.         species.averageFitness = (total / #species.genomes) / 4
  905.     elseif species.topFitness < pool.averagemaxfitness - pool.standardDeviationMaxFitness then
  906.         species.averageFitness = (total / #species.genomes) / 2.5
  907.     elseif species.topFitness > pool.averagemaxfitness + (pool.standardDeviationMaxFitness *3) then
  908.         species.averageFitness = (total / #species.genomes) * 2
  909.     elseif species.topFitness > pool.averagemaxfitness + (pool.standardDeviationMaxFitness *2) then
  910.         species.averageFitness = (total / #species.genomes) * 1.5
  911.     else
  912.         species.averageFitness = total / #species.genomes
  913.     end
  914. end
  915.  
  916. function calculateStandardDeviationMax()
  917.     local deviationtotal = 0
  918.     for s=1,#pool.species do
  919.         deviationtotal = deviationtotal + math.abs(pool.species[s].topFitness - pool.averagemaxfitness)
  920.     end
  921.     pool.standardDeviationMaxFitness = deviationtotal / #pool.species
  922. end
  923.  
  924. function AverageMaxFitness()
  925.     local total = 0
  926.     for s = 1,#pool.species do
  927.         local species = pool.species[s]
  928.         total = total + species.topFitness
  929.     end
  930.    
  931.     pool.averagemaxfitness = total / #pool.species
  932. end
  933.  
  934. function totalAverageFitness()
  935.     local total = 0
  936.     for s = 1,#pool.species do
  937.         local species = pool.species[s]
  938.         total = total + species.averageFitness
  939.     end
  940.  
  941.     return total
  942. end
  943.  
  944. function cullSpecies(cutToOne)
  945.     for s = 1,#pool.species do
  946.         local species = pool.species[s]
  947.        
  948.         table.sort(species.genomes, function (a,b)
  949.             return (a.fitness > b.fitness)
  950.         end)
  951.        
  952.         local remaining = math.ceil(#species.genomes/2)
  953.         if cutToOne then
  954.             remaining = 1
  955.         end
  956.         while #species.genomes > remaining do
  957.             table.remove(species.genomes)
  958.         end
  959.     end
  960. end
  961.  
  962. function breedChild(species)
  963.     local child = {}
  964.     if math.random() < CrossoverChance then
  965.         g1 = species.genomes[math.random(1, #species.genomes)]
  966.         g2 = species.genomes[math.random(1, #species.genomes)]
  967.         child = crossover(g1, g2)
  968.     else
  969.         g = species.genomes[math.random(1, #species.genomes)]
  970.         child = copyGenome(g)
  971.     end
  972.     if child.networkswitch > 0 then
  973.         if math.random(1,2) == 1 then
  974.             mutate(child, 1)
  975.         else
  976.             mutate(child, 2)
  977.         end
  978.     else
  979.         mutate(child, 1)
  980.     end
  981.    
  982.     return child
  983. end
  984.  
  985. function secondbestspecies() --added this to help prevent the formation of monospecies when LuigI/O encounters a major bottleneck
  986.     local bestfitness = 0
  987.     local secondbestfitness = 0
  988.     for s = 1,#pool.species do
  989.         local species = pool.species[s]
  990.        
  991.         if species.topFitness > bestfitness then
  992.             secondbestfitness = bestfitness
  993.             bestfitness = species.topFitness
  994.         elseif species.topFitness > secondbestfitness then
  995.             secondbestfitness = species.topFitness
  996.         end
  997.     end
  998.     return secondbestfitness
  999. end
  1000.        
  1001.  
  1002. function removeStaleSpecies()
  1003.     local survived = {}
  1004.     secondbest = secondbestspecies()
  1005.     emu.print("Max Fitness: ".. pool.maxFitness ..". second best: ".. secondbest)
  1006.     for s = 1,#pool.species do
  1007.         local species = pool.species[s]
  1008.        
  1009.         table.sort(species.genomes, function (a,b)
  1010.             return (a.fitness > b.fitness)
  1011.         end)
  1012.        
  1013.         if species.genomes[1].fitness > species.topFitness then
  1014.             species.topFitness = species.genomes[1].fitness
  1015.             species.staleness = 0
  1016.         else
  1017.             species.staleness = species.staleness + 1
  1018.         end
  1019.         if species.staleness < StaleSpecies or species.topFitness >= secondbest then --originally species.topFitness >= pool.maxFitness
  1020.             table.insert(survived, species)
  1021.         end
  1022.     end
  1023.  
  1024.     pool.species = survived
  1025. end
  1026.  
  1027. function removeWeakSpecies()
  1028.     local survived = {}
  1029.  
  1030.     local sum = totalAverageFitness()
  1031.     for s = 1,#pool.species do
  1032.         local species = pool.species[s]
  1033.         breed = math.floor(species.averageFitness / sum * Population)
  1034.         if breed >= 1 then
  1035.             table.insert(survived, species)
  1036.         end
  1037.     end
  1038.  
  1039.     pool.species = survived
  1040. end
  1041.  
  1042.  
  1043. function addToSpecies(child)
  1044.     local foundSpecies = false
  1045.     for s=1,#pool.species do
  1046.         local species = pool.species[s]
  1047.         if not foundSpecies and sameSpecies(child, species.genomes[1]) then
  1048.             table.insert(species.genomes, child)
  1049.             foundSpecies = true
  1050.         end
  1051.     end
  1052.    
  1053.     if not foundSpecies then
  1054.         local childSpecies = newSpecies()
  1055.         table.insert(childSpecies.genomes, child)
  1056.         table.insert(pool.species, childSpecies)
  1057.     end
  1058. end
  1059.  
  1060. function replaceSecondNetwork(g1,g2)
  1061.     local genome2 = newGenome()
  1062.     for g=1,#g1.genes do
  1063.         table.insert(genome2.genes, copyGene(g1.genes[g]))
  1064.     end
  1065.     for i=1,#g1.oscilations do
  1066.         genome2.oscilations[i] = g1.oscilations[i]
  1067.     end
  1068.     genome2.networkswitch = g1.networkswitch
  1069.     genome2.maxneuron = g1.maxneuron
  1070.     genome2.mutationRates["connections"] = g1.mutationRates["connections"]
  1071.     genome2.mutationRates["link"] = g1.mutationRates["link"]
  1072.     genome2.mutationRates["bias"] = g1.mutationRates["bias"]
  1073.     genome2.mutationRates["node"] = g1.mutationRates["node"]
  1074.     genome2.mutationRates["enable"] = g1.mutationRates["enable"]
  1075.     genome2.mutationRates["disable"] = g1.mutationRates["disable"]
  1076.     genome2.mutationRates["oscilation"] = g1.mutationRates["oscilation"]
  1077.     genome2.mutationRates["networkswitch"] = g1.mutationRates["networkswitch"]
  1078.    
  1079.     if g2.networkswitch > 0 then
  1080.         if math.random(1,2) == 1 then
  1081.             for g=1,#g2.genes do
  1082.                 table.insert(genome2.genes2, copyGene(g2.genes[g]))
  1083.             end
  1084.         else
  1085.             for g=1,#g2.genes2 do
  1086.                 table.insert(genome2.genes2, copyGene(g2.genes2[g]))
  1087.             end
  1088.         end
  1089.     else
  1090.         for g=1,#g2.genes do
  1091.             table.insert(genome2.genes2, copyGene(g2.genes[g]))
  1092.         end
  1093.     end
  1094.     if genome2.networkswitch == 0 then
  1095.         local switch = math.pow(math.floor(g1.fitness/500),2)
  1096.         genome2.networkswitch = math.ceil(math.sqrt(math.random(1,switch)))+(math.random(0,9)/10)
  1097.     end
  1098.     print('network switch: '.. genome2.networkswitch)
  1099.     print('end number of genes2: '.. #genome2.genes2)
  1100.     return genome2
  1101. end
  1102.  
  1103.  
  1104.  
  1105. function newGeneration()
  1106.     if pool.maxFitness > previousmaxfitness then
  1107.         previousmaxfitness = pool.maxFitness
  1108.         bottleneckcounter = 0
  1109.         if AllowAutoTurbo then
  1110.             emu.speedmode("normal")
  1111.             turbo = false
  1112.         end
  1113.     else
  1114.         bottleneckcounter = bottleneckcounter + 1
  1115.     end
  1116.     if bottleneckcounter < 7 and Population > 300 then
  1117.         if pool.generation < 5 then
  1118.             Population = math.floor(Population * 0.9)
  1119.         else
  1120.             Population = math.floor(Population * 0.95)
  1121.         end
  1122.         if Population < 300 then
  1123.             Population = 300
  1124.         end
  1125.     elseif bottleneckcounter > 10 and Population <900 then
  1126.         Population = math.floor(Population * 1.10)
  1127.         if Population > 900 then
  1128.             Population = 900
  1129.         end
  1130.     end
  1131.     if bottleneckcounter > 25 then
  1132.         bottleneckcounter = 0
  1133.     end
  1134.     if bottleneckcounter > TurboGenBottleneck and AllowAutoTurbo and BottleneckTurbo then
  1135.         emu.speedmode("turbo")
  1136.         turbo = true
  1137.     end
  1138.     cullSpecies(false) -- Cull the bottom half of each species
  1139.     rankGlobally()
  1140.     removeStaleSpecies()
  1141.     AverageMaxFitness()
  1142.     calculateStandardDeviationMax()
  1143.     rankGlobally()
  1144.     for s = 1,#pool.species do
  1145.         local species = pool.species[s]
  1146.         calculateAverageFitness(species)
  1147.     end
  1148.     removeWeakSpecies()
  1149.     local sum = totalAverageFitness()
  1150.     local children = {}
  1151.     for s = 1,#pool.species do
  1152.         local species = pool.species[s]
  1153.         breed = math.floor(species.averageFitness / sum * Population) - 1
  1154.         if breed > 10 then
  1155.             breed = math.ceil(breed * math.sqrt(species.topFitness / pool.maxFitness))
  1156.         end
  1157.         if breed > Population/4 then
  1158.             breed = Population/4
  1159.         end
  1160.         for i=1,breed do
  1161.             table.insert(children, breedChild(species))
  1162.         end
  1163.     end
  1164.     cullSpecies(true) -- Cull all but the top member of each species
  1165.     if #pool.species < 30 then
  1166.         interbreedchance = 0.2
  1167.     else
  1168.         interbreedchance = 0.03
  1169.     end
  1170.     for i=1,#pool.species do
  1171.         if math.random() < interbreedchance then
  1172.             local counterbreed = math.random(1, #pool.species)
  1173.             if counterbreed ~= i then
  1174.                 table.insert(children, crossover(pool.species[i].genomes[1], pool.species[counterbreed].genomes[1]))
  1175.             end
  1176.         end
  1177.         if bottleneckcounter > 23 then
  1178.             if math.random() < 0.1 then
  1179.                 local tfit = pool.species[i].topFitness
  1180.                 child = copyGenome(pool.species[i].genomes[1])
  1181.                 switchlocation = math.floor(tfit/500)
  1182.                 if child.networkswitch == 0 then
  1183.                     if math.random(1,2) == 1 then
  1184.                         switchlocation = switchlocation + (math.random(0,10)/10)
  1185.                     end
  1186.                     child.networkswitch = switchlocation
  1187.                     table.insert(children, child)
  1188.                 end
  1189.             end
  1190.         end
  1191.         if math.random() < replaceSecondNetworkChance and pool.species[i].topFitness > 500 then
  1192.             if pool.species[i].genomes[1].networkswitch > 0 then
  1193.                 if math.random() < 0.5 then
  1194.                     local donornetwork = math.random(1, #pool.species)
  1195.                     if donornetwork ~= i then
  1196.                         table.insert(children, replaceSecondNetwork(pool.species[i].genomes[1], pool.species[donornetwork].genomes[1]))
  1197.                     end
  1198.                 end
  1199.             else
  1200.                 local donornetwork = math.random(1, #pool.species)
  1201.                 if donornetwork ~= i then
  1202.                     table.insert(children, replaceSecondNetwork(pool.species[i].genomes[1], pool.species[donornetwork].genomes[1]))
  1203.                 end
  1204.             end
  1205.         end
  1206.     end
  1207.     while #children + #pool.species < Population do
  1208.         local species = pool.species[math.random(1, #pool.species)]
  1209.         table.insert(children, breedChild(species))
  1210.     end
  1211.     for c=1,#children do
  1212.         local child = children[c]
  1213.         addToSpecies(child)
  1214.     end
  1215.     local children = {}
  1216.     local rem_gen = 0
  1217.     for s=1,#pool.species do
  1218.         local species = pool.species[s]
  1219.         if species.topFitness < secondbest and #species.genomes > Population/12 then
  1220.             while #species.genomes > Population/12 do
  1221.                 table.remove(species.genomes)
  1222.                 rem_gen = rem_gen +1
  1223.             end
  1224.         elseif species.topFitness >= secondbest and #species.genomes>Population/7 then
  1225.             while #species.genomes > Population/7 do
  1226.                 table.remove(species.genomes)
  1227.                 rem_gen = rem_gen +1
  1228.             end
  1229.         end
  1230.     end
  1231.     for x=1,rem_gen do
  1232.         local species = pool.species[math.random(1, #pool.species)]
  1233.         table.insert(children, breedChild(species))
  1234.     end
  1235.     for c=1,#children do
  1236.         local child = children[c]
  1237.         addToSpecies(child)
  1238.     end
  1239.     for s=1,#pool.species do
  1240.         local species = pool.species[s]
  1241.         if species.topFitness < secondbest and #species.genomes > Population/12 then
  1242.             while #species.genomes > Population/12 do
  1243.                 table.remove(species.genomes)
  1244.             end
  1245.         elseif species.topFitness >= secondbest and #species.genomes>Population/7 then
  1246.             while #species.genomes > Population/7 do
  1247.                 table.remove(species.genomes)
  1248.             end
  1249.         end
  1250.     end
  1251.    
  1252.     pool.generation = pool.generation + 1
  1253.     pool.maxcounter = 0 --reset max fitness counter
  1254.    
  1255.     writeFile("backups/backup." .. pool.generation .. "." .. SAVE_LOAD_FILE)
  1256.     writelatestgen() --tracker for the latest generation
  1257. end
  1258.    
  1259. function initializePool()
  1260.     pool = newPool()
  1261.  
  1262.     for i=1,Population do
  1263.         basic = basicGenome()
  1264.         addToSpecies(basic)
  1265.     end
  1266.  
  1267.     initializeRun()
  1268. end
  1269.  
  1270. function clearJoypad()
  1271.     controller = {}
  1272.     for b = 1,#ButtonNames do
  1273.         controller[ButtonNames[b]] = false
  1274.     end
  1275.     joypad.set(player, controller)
  1276. end
  1277.  
  1278. function initializeRun()
  1279.    
  1280.     savestate.load(SavestateObj);
  1281.     rightmost = 0
  1282.     pool.currentFrame = 0
  1283.     timeout = TimeoutConstant
  1284.     clearJoypad()
  1285.     currentTracker = memory.readbyte(0x071A) --sets the current tracker to the current screen
  1286.    
  1287.     local species = pool.species[pool.currentSpecies]
  1288.     local genome = species.genomes[pool.currentGenome]
  1289.     for i=1,#genome.oscilations do
  1290.         switchtimer[i] = genome.oscilations[i]
  1291.         initialswitchvalue[i] = 1
  1292.     end
  1293.     generateNetwork(genome)
  1294.     evaluateCurrent()
  1295. end
  1296.  
  1297. function reRun()
  1298.     savestate.load(savestate.object(previous_savestate));
  1299.     rightmost = 0
  1300.     pool.currentFrame = 0
  1301.     timeout = TimeoutConstant
  1302.     clearJoypad()
  1303.     currentTracker = memory.readbyte(0x071A) --sets the current tracker to the current screen
  1304.     offset = 0 --offset in x coordinates for pipe
  1305.     timebonus = 0 --used to freeze fitness
  1306.     mariohole = false --reset the fallen into hole variable
  1307.     mariopipe = false --is mario exiting a pipe or just teleporting
  1308.     loop = false --is this a loop?
  1309.     marioPipeEnter = false --has mario entered a pipe
  1310.     currentTracker = 1 --tracker for the loop
  1311.     killtrigger = false
  1312.     ntrigger = true
  1313.     nswitch = true
  1314.     local species = pool.species[pool.currentSpecies]
  1315.     local genome = species.genomes[pool.currentGenome]
  1316.     for i=1,#genome.oscilations do
  1317.         switchtimer[i] = genome.oscilations[i]
  1318.         initialswitchvalue[i] = 1
  1319.     end
  1320.     generateNetwork(genome)
  1321.     evaluateCurrent()
  1322. end
  1323.  
  1324. function evaluateCurrent()
  1325.     local species = pool.species[pool.currentSpecies]
  1326.     local genome = species.genomes[pool.currentGenome]
  1327.  
  1328.     inputs = getInputs()
  1329.     if nswitch then
  1330.         controller = evaluateNetwork(genome.network, inputs, genome)
  1331.     else
  1332.         controller = evaluateNetwork(genome.network2, inputs, genome)
  1333.     end
  1334.    
  1335.     if controller["left"] and controller["right"] then
  1336.         controller["left"] = false
  1337.         controller["right"] = false
  1338.     end
  1339.     if controller["up"] and controller["down"] then
  1340.         controller["up"] = false
  1341.         controller["down"] = false
  1342.     end
  1343.  
  1344.     joypad.set(player, controller)
  1345. end
  1346.  
  1347. if pool == nil then
  1348.     initializePool() --------------------------------------------------------------------------------------------------------------------------------------------------------
  1349. end
  1350.  
  1351.  
  1352. function nextGenome()
  1353.     pool.currentGenome = pool.currentGenome + 1
  1354.     if pool.currentGenome > #pool.species[pool.currentSpecies].genomes then
  1355.         pool.currentGenome = 1
  1356.         pool.currentSpecies = pool.currentSpecies+1
  1357.         if pool.currentSpecies > #pool.species then
  1358.             newGeneration()
  1359.             pool.currentSpecies = 1
  1360.         end
  1361.     end
  1362. end
  1363.  
  1364. function fitnessAlreadyMeasured()
  1365.     local species = pool.species[pool.currentSpecies]
  1366.     local genome = species.genomes[pool.currentGenome]
  1367.    
  1368.     return genome.fitness ~= 0
  1369. end
  1370.  
  1371. function GenerateNewKeepBest(genome)
  1372.     Population = 1000
  1373.     previousbest = copyGenome(genome)
  1374.     previousmaxfitness = 1
  1375.     maxright = 1
  1376.     offset = 0 --offset in x coordinates for pipe
  1377.     timebonus = 0 --used to freeze fitness
  1378.     mariohole = false --reset the fallen into hole variable
  1379.     mariopipe = false --is mario exiting a pipe or just teleporting
  1380.     loop = false --is this a loop?
  1381.     marioPipeEnter = false --has mario entered a pipe
  1382.     currentTracker = 1 --tracker for the loop
  1383.     pool = newPool()
  1384.     addToSpecies(previousbest)
  1385.     for i=1,Population-1 do
  1386.         basic = basicGenome()
  1387.         addToSpecies(basic)
  1388.     end
  1389.     initializeRun()
  1390. end
  1391.  
  1392. function displayGenome(genome)
  1393.     gui.opacity(0.53)
  1394.     if not genome then return end
  1395.     local network = {}
  1396.     if nswitch then
  1397.         network = genome.network
  1398.     else
  1399.         network = genome.network2
  1400.     end
  1401.     local cells = {}
  1402.     local i = 1
  1403.     local cell = {}
  1404.     for dy=-BoxRadius,BoxRadius do
  1405.         for dx=-BoxRadius,BoxRadius do
  1406.             cell = {}
  1407.             cell.x = 50+5*dx
  1408.             cell.y = 70+5*dy
  1409.             cell.value = network.neurons[i].value
  1410.             cells[i] = cell
  1411.             i = i + 1
  1412.         end
  1413.     end
  1414.     local biasCell = {}
  1415.     biasCell.x = 80
  1416.     biasCell.y = 110
  1417.     biasCell.value = network.neurons[Inputs-#initialswitchvalue].value
  1418.     cells[Inputs-#initialswitchvalue] = biasCell
  1419.     for i=0,#initialswitchvalue-1 do
  1420.         local switchCell = {}
  1421.         switchCell.x = 80-10*#initialswitchvalue+10*i
  1422.         switchCell.y = 110
  1423.         switchCell.value = network.neurons[Inputs-i].value
  1424.         cells[Inputs-i] = switchCell
  1425.     end
  1426.    
  1427.     gui.drawbox(215,32,245,82,toRGBA(0x80808080),toRGBA(0x00000000))
  1428.    
  1429.     gui.opacity(0.85)
  1430.     for o = 1,Outputs do
  1431.         cell = {}
  1432.         cell.x = 220
  1433.         cell.y = 30 + 8 * o
  1434.         cell.value = network.neurons[MaxNodes + o].value
  1435.         cells[MaxNodes+o] = cell
  1436.         local color
  1437.         if cell.value > 0 then
  1438.             color = 0xFF0000FF
  1439.         else
  1440.             color = 0xFF777777-- original color = 0xFF000000
  1441.         end
  1442.         gui.drawtext(225, 26+8*o, ButtonNames[o], toRGBA(color), 0x0) --moved slightly for better alignment
  1443.     end
  1444.    
  1445.     for n,neuron in pairs(network.neurons) do
  1446.         cell = {}
  1447.         if n > Inputs and n <= MaxNodes then
  1448.             cell.x = 140
  1449.             cell.y = 40
  1450.             cell.value = neuron.value
  1451.             -- if neuron.value >0 then
  1452.                 -- neuron.switcher = true
  1453.             -- end
  1454.             cells[n] = cell
  1455.         end
  1456.     end
  1457.     local genes = {}
  1458.     if nswitch then
  1459.         genes = genome.genes
  1460.     else
  1461.         genes = genome.genes2
  1462.     end
  1463.     for n=1,4 do
  1464.         for _,gene in pairs(genes) do
  1465.             if gene.enabled then
  1466.                 local c1 = cells[gene.into]
  1467.                 local c2 = cells[gene.out]
  1468.                 if gene.into > Inputs and gene.into <= MaxNodes then
  1469.                     c1.x = 0.75*c1.x + 0.25*c2.x
  1470.                     if c1.x >= c2.x then
  1471.                         c1.x = c1.x - 40
  1472.                     end
  1473.                     if c1.x < 90 then
  1474.                         c1.x = 90
  1475.                     end
  1476.                    
  1477.                     if c1.x > 220 then
  1478.                         c1.x = 220
  1479.                     end
  1480.                     c1.y = 0.75*c1.y + 0.25*c2.y
  1481.                    
  1482.                 end
  1483.                 if gene.out > Inputs and gene.out <= MaxNodes then
  1484.                     c2.x = 0.25*c1.x + 0.75*c2.x
  1485.                     if c1.x >= c2.x then
  1486.                         c2.x = c2.x + 40
  1487.                     end
  1488.                     if c2.x < 90 then
  1489.                         c2.x = 90
  1490.                     end
  1491.                     if c2.x > 220 then
  1492.                         c2.x = 220
  1493.                     end
  1494.                     c2.y = 0.25*c1.y + 0.75*c2.y
  1495.                 end
  1496.             end
  1497.         end
  1498.     end
  1499.    
  1500.     gui.drawbox(50-BoxRadius*5-3,70-BoxRadius*5-3,50+BoxRadius*5+2,70+BoxRadius*5+2, toRGBA(0x80808080), toRGBA(0xFF000000))
  1501.     for n,cell in pairs(cells) do
  1502.         if n > Inputs or cell.value ~= 0 then
  1503.             local color = math.floor((cell.value+1)/2*256)
  1504.             if color > 255 then color = 255 end
  1505.             if color < 0 then color = 0 end
  1506.             local opacity = 0xFF000000
  1507.             if cell.value == 0 then
  1508.                 opacity = 0x50000000
  1509.             end
  1510.             inversecolor = (color - 255) * (-1)
  1511.             bordercolor = 0x50000000 + inversecolor*0x10000 + inversecolor*0x100 + inversecolor
  1512.             color = opacity + color*0x10000 + color*0x100 + color
  1513.             gui.drawbox(cell.x-2,cell.y-2,cell.x+2,cell.y+2,toRGBA(color), toRGBA(bordercolor))
  1514.         end
  1515.     end
  1516.     for _,gene in pairs(genes) do
  1517.         if gene.enabled then
  1518.             local c1 = cells[gene.into]
  1519.             local c2 = cells[gene.out]
  1520.             local opacity = 0xF0000000
  1521.             if pool.generation > 50 then
  1522.                     opacity = 0x80000000
  1523.                 end
  1524.             if c1.value == 0 then
  1525.                 if pool.generation <10 then --slowly reducing the visibility of non active connections
  1526.                     opacity = 0x80000000
  1527.                 elseif pool.generation < 15 then
  1528.                     opacity = 0x60000000
  1529.                 elseif pool.generation < 25 then
  1530.                     opacity = 0x40000000
  1531.                 end
  1532.             end
  1533.             local color = 0x80-math.floor(math.abs(sigmoid(gene.weight))*0x80)
  1534.             if gene.weight > 0 then
  1535.                 color = opacity + 0x8000 + 0x10000*color
  1536.             else
  1537.                 color = opacity + 0x800000 + 0x100*color
  1538.             end
  1539.             if c1.value ~= 0 or pool.generation < 5 then -- remove non active connections from generation 50 onwards
  1540.                 gui.drawline(c1.x+1, c1.y, c2.x-3, c2.y, toRGBA(color))
  1541.             end
  1542.         end
  1543.     end
  1544.    
  1545.     gui.drawbox(49,71,51,78,toRGBA(0x80FF0000),toRGBA(0x00000000))
  1546.     if mutation_rates_disp then
  1547.         local pos = 120
  1548.         for mutation,rate in pairs(genome.mutationRates) do
  1549.             gui.drawtext(16, pos, mutation .. ": " .. rate, toRGBA(0xFF000000), 0x0)
  1550.             pos = pos + 8
  1551.         end
  1552.     end
  1553. end
  1554.  
  1555. function writeFile(filename)
  1556.         local file = io.open(filename, "w")
  1557.     file:write(pool.generation .. "\n")
  1558.     file:write(pool.maxFitness .. "\n")
  1559.     file:write(Population .. "\n")
  1560.     file:write(pool.innovation .. "\n")
  1561.     file:write(bottleneckcounter .. "\n")
  1562.     file:write(#pool.species .. "\n")
  1563.         for n,species in pairs(pool.species) do
  1564.         file:write(species.topFitness .. "\n")
  1565.         file:write(species.staleness .. "\n")
  1566.         file:write(#species.genomes .. "\n")
  1567.         for m,genome in pairs(species.genomes) do
  1568.             file:write(genome.fitness .. "\n")
  1569.             file:write(genome.maxneuron .. "\n")
  1570.             for mutation,rate in pairs(genome.mutationRates) do
  1571.                 file:write(mutation .. "\n")
  1572.                 file:write(rate .. "\n")
  1573.             end
  1574.             file:write("done\n")
  1575.            
  1576.             file:write(#genome.genes .. "\n")
  1577.             for l,gene in pairs(genome.genes) do
  1578.                 file:write(gene.into .. " ")
  1579.                 file:write(gene.out .. " ")
  1580.                 file:write(gene.weight .. " ")
  1581.                 file:write(gene.innovation .. " ")
  1582.                 if(gene.enabled) then
  1583.                     file:write("1\n")
  1584.                 else
  1585.                     file:write("0\n")
  1586.                 end
  1587.             end
  1588.             file:write(#genome.genes2 .. "\n")
  1589.             for l,gene in pairs(genome.genes2) do
  1590.                 file:write(gene.into .. " ")
  1591.                 file:write(gene.out .. " ")
  1592.                 file:write(gene.weight .. " ")
  1593.                 file:write(gene.innovation .. " ")
  1594.                 if(gene.enabled) then
  1595.                     file:write("1\n")
  1596.                 else
  1597.                     file:write("0\n")
  1598.                 end
  1599.             end
  1600.             file:write(genome.networkswitch .. "\n")
  1601.             file:write(#genome.oscilations .. "\n")
  1602.             for i=1,#genome.oscilations do
  1603.                 file:write(genome.oscilations[i] .. "\n")
  1604.             end
  1605.         end
  1606.         end
  1607.         file:close()
  1608. end
  1609.  
  1610. function savePool() --used to save when a new max fitness is reached
  1611.     local filename = "backups/backup." .. pool.generation .. "." .. SAVE_LOAD_FILE
  1612.     writeFile(filename)
  1613.     emu.print("saved pool due to new max fitness")  --suggestion by DeltaLeeds
  1614. end
  1615.  
  1616. function loadFile(filename)
  1617.         local file = io.open(filename, "r")
  1618.     pool = newPool()
  1619.     pool.generation = file:read("*number")
  1620.     pool.maxFitness = file:read("*number")
  1621.     Population = file:read("*number")
  1622.     pool.innovation = file:read("*number")
  1623.     bottleneckcounter = file:read("*number")
  1624.         local numSpecies = file:read("*number")
  1625.         for s=1,numSpecies do
  1626.         local species = newSpecies()
  1627.         table.insert(pool.species, species)
  1628.         species.topFitness = file:read("*number")
  1629.         species.staleness = file:read("*number")
  1630.         local numGenomes = file:read("*number")
  1631.         for g=1,numGenomes do
  1632.             local genome = newGenome()
  1633.             table.insert(species.genomes, genome)
  1634.             genome.fitness = file:read("*number")
  1635.             genome.maxneuron = file:read("*number")
  1636.             local line = file:read("*line")
  1637.             while line ~= "done" do
  1638.                 genome.mutationRates[line] = file:read("*number")
  1639.                 line = file:read("*line")
  1640.             end
  1641.             local numGenes = file:read("*number")
  1642.             for n=1,numGenes do
  1643.                 local gene = newGene()
  1644.                 table.insert(genome.genes, gene)
  1645.                 local enabled
  1646.                 --I am able to revert back to the original loading script with FCEUX
  1647.                 gene.into, gene.out, gene.weight, gene.innovation, enabled = file:read("*number", "*number", "*number", "*number", "*number")
  1648.                
  1649.                 if enabled == 0 then
  1650.                     gene.enabled = false
  1651.                 else
  1652.                     gene.enabled = true
  1653.                 end
  1654.                
  1655.             end
  1656.             local numGenes2 = file:read("*number")
  1657.             for n=1,numGenes2 do
  1658.                 local gene2 = newGene()
  1659.                 table.insert(genome.genes2, gene2)
  1660.                 local enabled
  1661.                 --I am able to revert back to the original loading script with FCEUX
  1662.                 gene2.into, gene2.out, gene2.weight, gene2.innovation, enabled = file:read("*number", "*number", "*number", "*number", "*number")
  1663.                
  1664.                 if enabled == 0 then
  1665.                     gene2.enabled = false
  1666.                 else
  1667.                     gene2.enabled = true
  1668.                 end
  1669.                
  1670.             end
  1671.             genome.networkswitch = file:read("*number")
  1672.             local numosci = file:read("*number")
  1673.             for i=1,numosci do
  1674.                 genome.oscilations[i] = file:read("*number")
  1675.             end
  1676.         end
  1677.     end
  1678.         file:close()
  1679.    
  1680.     while fitnessAlreadyMeasured() do
  1681.         nextGenome()
  1682.     end
  1683.     initializeRun()
  1684.     pool.currentFrame = pool.currentFrame + 1
  1685. end
  1686.  
  1687. function playTop()
  1688.     local maxfitness = 0
  1689.     local maxs, maxg
  1690.     for s,species in pairs(pool.species) do
  1691.         for g,genome in pairs(species.genomes) do
  1692.             if genome.fitness > maxfitness then
  1693.                 maxfitness = genome.fitness
  1694.                 maxs = s
  1695.                 maxg = g
  1696.             end
  1697.         end
  1698.     end
  1699.    
  1700.     pool.currentSpecies = maxs
  1701.     pool.currentGenome = maxg
  1702.     pool.maxFitness = maxfitness
  1703.     initializeRun()
  1704.     pool.currentFrame = pool.currentFrame + 1
  1705.     return
  1706. end
  1707.  
  1708. function fitnesstracker()
  1709.     if pool.maxFitness > 0 then
  1710.         local file = io.open('fitnesstracker.txt', "a")
  1711.         file:write("Gen: " .. pool.generation .. " Species: " .. pool.currentSpecies .. " Genome: " .. pool.currentGenome .. " Fitness: ".. pool.maxFitness .. "\n")
  1712.         file:close()
  1713.     end
  1714. end
  1715.  
  1716. function writelatestgen() --used to write the generation tracker to a file
  1717.     local file = io.open('backups/latestgen', "w")
  1718.     file:write(SAVE_LOAD_FILE .. "\n")
  1719.     file:write(savestate_slot .. "\n")
  1720.     file:write(pool.generation)
  1721.     file:close()
  1722. end
  1723.  
  1724. function readlatestgen() --used to retrieve the latest generation from a file
  1725.     local file = io.open('backups/latestgen', "r")
  1726.     SAVE_LOAD_FILE = file:read("*line")
  1727.     savestate_slot = file:read("*number")
  1728.     SavestateObj = savestate.object(savestate_slot)
  1729.     local latestgen = file:read("*number")
  1730.     file:close()
  1731.     local name = 'backups/backup.'.. latestgen .. '.' .. SAVE_LOAD_FILE
  1732.     print('loaded: '.. name)
  1733.     return name
  1734. end
  1735.  
  1736. function keyboardinput()
  1737.     local keyboard = input.get()
  1738.     if keyboard['N'] and keyflag == false then
  1739.         if neural_net_disp then
  1740.             neural_net_disp = false
  1741.         else
  1742.             neural_net_disp = true
  1743.         end
  1744.         keyflag = true
  1745.     end
  1746.     if keyboard['M'] and keyflag == false then
  1747.         if mutation_rates_disp then
  1748.             mutation_rates_disp = false
  1749.         else
  1750.             mutation_rates_disp = true
  1751.         end
  1752.         keyflag = true
  1753.     end
  1754.     if keyboard['L'] and keyflag == false then
  1755.         if not nopopup then
  1756.             local loadyn = input.popup('Are you sure you want to load the last saved generation?')
  1757.         end
  1758.         if loadyn == 'yes' or nopopup then
  1759.             name = readlatestgen()
  1760.             loadFile(name)
  1761.         end
  1762.         keyflag = true
  1763.     end
  1764.     if keyboard['B'] and keyflag == false then
  1765.         if not nopopup then
  1766.             local loadyn = input.popup('Are you sure you want to show the topFitness genome?')
  1767.         end
  1768.         if loadyn == 'yes' or nopopup then
  1769.             playTop()
  1770.         end
  1771.     end
  1772.     if keyboard['O'] and keyflag == false then
  1773.         pcall(InsertGenome)
  1774.         keyflag = true
  1775.     end
  1776.     if keyboard['U'] and keyflag == false then
  1777.         pcall(PlaceGenome)
  1778.         keyflag = true
  1779.     end
  1780.     if keyboard['S'] and keyflag == false then
  1781.         savePool()
  1782.         keyflag = true
  1783.     end
  1784.     if not (keyboard['N'] or keyboard['L'] or keyboard['M'] or keyboard['T'] or keyboard['B'] or keyboard['S']) and keyflag == true then
  1785.         keyflag = false
  1786.     end
  1787.     if keyboard['T'] and keyflag == false then
  1788.         if turbo then
  1789.             emu.speedmode("normal")
  1790.             turbo = false
  1791.             print('stop turbo')
  1792.         elseif not turbo and not restoreturbo then
  1793.             emu.speedmode("turbo")
  1794.             turbo = true
  1795.         elseif restoreturbo then
  1796.             restoreturbo = false
  1797.         end
  1798.         keyflag = true
  1799.     end
  1800. end
  1801.  
  1802. if savedpool then
  1803.     loadFile(savedpool)
  1804. end
  1805.  
  1806. writeFile("temp.pool")
  1807. requiredFitness = 0
  1808. if SAVE_LOAD_FILE == nil then
  1809.     SAVE_LOAD_FILE = "SMB".. CurrentWorld+1 .."-".. CurrentLevel ..".state.pool"
  1810. end
  1811.  
  1812.  
  1813. while true do
  1814.     keyboardinput()
  1815.     local backgroundColor = toRGBA(0xD0FFFFFF)
  1816.         gui.drawbox(0, 0, 260, 30, backgroundColor, backgroundColor)
  1817.    
  1818.     if pool.maxcounter == nil then
  1819.         pool.maxcounter = 0
  1820.         emu.print("caught missing variable")
  1821.     end
  1822.    
  1823.     local species = pool.species[pool.currentSpecies]
  1824.     local genome = species.genomes[pool.currentGenome]
  1825.    
  1826.     if neural_net_disp then
  1827.         displayGenome(genome)
  1828.     end
  1829.     if pool.generation == 0 and pool.currentSpecies ~= 1 and not turbo and AllowAutoTurbo and FirstGenSpeedup then
  1830.         emu.speedmode("turbo")
  1831.         turbo = true
  1832.     end
  1833.    
  1834.     if genome.networkswitch>0 then
  1835.         if math.floor(rightmost/10 / genome.networkswitch) % 50 == 0 and ntrigger == false then
  1836.             if nswitch == true then
  1837.                 nswitch = false
  1838.             else
  1839.                 nswitch = true
  1840.             end
  1841.             ntrigger = true
  1842.         elseif math.floor(rightmost/10 / genome.networkswitch) % 50 ~= 0 and ntrigger == true then
  1843.             ntrigger = false
  1844.         end
  1845.     end
  1846.    
  1847.     if pool.currentFrame%5 == 0 then
  1848.         evaluateCurrent()
  1849.     end
  1850.  
  1851.     joypad.set(player, controller)
  1852.  
  1853.     getPositions()
  1854.    
  1855.     if mariostate == 2 or mariostate == 3 then --detects when mario enters a pipe
  1856.         marioPipeEnter = true
  1857.         if mariostate == 2 then
  1858.             adjustfitness = true
  1859.         else
  1860.             adjustfitness = false
  1861.         end
  1862.     end
  1863.     if (CurrentWorld == 3 and CurrentLevel == 4) or (CurrentWorld == 6 and CurrentLevel == 4) or (CurrentWorld == 7 and CurrentLevel == 3) then
  1864.         if currentTracker == currentscreen or currentTracker == nextscreen and not mariopipe then --follows the progress of mario
  1865.             currentTracker = nextscreen
  1866.         elseif currentTracker > nextscreen and not mariopipe and not marioPipeEnter and mariostate ~= 7 then --if mario suddenly goes back trigger loop detection
  1867.             loop = true
  1868.         elseif currentscreen == 0 and nextscreen == 0 and mariopipe and mariostate ~= 7 then -- if mario enters a piperoom negate loop detection
  1869.             loop = false
  1870.             currentTracker = nextscreen
  1871.         elseif nextscreen >= (currentTracker - 1) and mariopipe and mariostate ~= 7 then -- if mario goes forward in the level by entering a pipe negate loop detection
  1872.             loop = false
  1873.             currentTracker = nextscreen
  1874.             pipeexit = true
  1875.         else --if nothing is true then we are in a loop
  1876.             if not pipeexit then --prevents the extra one frame flicker of the tracker
  1877.             loop = true
  1878.             else
  1879.             pipeexit = false
  1880.             end
  1881.         end
  1882.     end
  1883.     if marioPipeEnter == true and mariostate == 7 then --set mariopipe when exiting the pipe
  1884.         mariopipe = true
  1885.     end
  1886.     if adjustfitness then
  1887.         if mariopipe == true and mariostate ~= 7 and rightmost > marioX and not mariohole then --calculate offset
  1888.             offset = rightmost - marioX
  1889.             mariopipe = false
  1890.             marioPipeEnter = false
  1891.         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
  1892.             offset = 0
  1893.             mariopipe = false
  1894.             marioPipeEnter = false
  1895.         end
  1896.     else
  1897.         if mariopipe == true and mariostate ~= 7 and not mariohole then --calculate offset --and rightmost > marioX
  1898.             offset = rightmost - marioX
  1899.             mariopipe = false
  1900.             marioPipeEnter = false
  1901.         end
  1902.     end
  1903.    
  1904.     if marioY + memory.readbyte(0xB5)*255 > 512 then --added the fallen into a hole variable that will activate when mario goes below screen
  1905.         mariohole = true
  1906.     end
  1907.     if marioX > 2370 and marioX < 3000 and (CurrentWorld == 7 and CurrentLevel == 3) then
  1908.         if marioX < 2460 then
  1909.             if 2370 + offset - marioY + 192 + (50 *memory.readbyte(0x06D9)) > rightmost and not mariohole and not loop and not marioPipeEnter and not killtrigger and not falling then
  1910.                 rightmost = 2370 + offset - marioY + 192 + (50 *memory.readbyte(0x06D9))
  1911.                 timebonus = timebonus + (TimeoutConstant - timeout) * 11/20
  1912.                 timeout = TimeoutConstant
  1913.             end
  1914.         end
  1915.     else
  1916.         if marioX + offset - marioY/5 + 192/5 + (50 *memory.readbyte(0x06D9)) > rightmost and not mariohole and not loop and not marioPipeEnter and not killtrigger and not falling then
  1917.             rightmost = marioX + offset - marioY/5 + 192/5 + (50 *memory.readbyte(0x06D9))
  1918.             timebonus = timebonus + (TimeoutConstant - timeout) * 11/20
  1919.             timeout = TimeoutConstant
  1920.         end
  1921.     end
  1922.     if marioPipeEnter == true then --freeze fitness and timer when mario enters a pipe
  1923.         timeout = timeout + 1
  1924.         timebonus = timebonus + 2/3
  1925.     end
  1926.    
  1927.     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
  1928.         timeout = timeout +1
  1929.         timebonus = timebonus + 2/3
  1930.         endlevel = true
  1931.     end
  1932.     if endlevel and mariostate == 8 and demoruncheck == 1 and statuscheck == 3 then
  1933.         local timeoutBonus = pool.currentFrame / 4
  1934.         local fitness = rightmost - pool.currentFrame / 2 +40 + timebonus
  1935.         genome.fitness = fitness
  1936.         pool.maxFitness = fitness
  1937.         fitnesstracker()
  1938.         savePool()
  1939.         if not rerunning then
  1940.             SAVE_LOAD_FILE = "SMB".. CurrentWorld+1 .."-".. CurrentLevel ..".state.pool"
  1941.             previous_savestate = savestate_slot
  1942.             savestate_slot = savestate_slot + 1
  1943.             if savestate_slot == 10 then
  1944.                 savestate_slot = 1
  1945.             end
  1946.            
  1947.             Savestatebackup = savestate.object(savestate_slot)
  1948.             savestate.save(Savestatebackup)
  1949.             savestate.persist(Savestatebackup)
  1950.             savestate.save(SavestateObj)
  1951.             killcounter = 0
  1952.         end
  1953.         SavestateObj = savestate.object(savestate_slot)
  1954.         endlevel = false
  1955.         if (turbo or restoreturbo) and not rerunning then
  1956.             rerunning = true
  1957.             requiredFitness = 0
  1958.             emu.speedmode("normal")
  1959.             turbo = false
  1960.             restoreturbo = false
  1961.             reRun()
  1962.         else
  1963.             rerunning = false
  1964.             preparenext = true
  1965.         end
  1966.     end
  1967.    
  1968.     if CurrentWorld == 0 and CurrentLevel == 0 and demoruncheck == 0 then
  1969.         savestate.load(SavestateObj)
  1970.     end
  1971.    
  1972.     timeout = timeout - 1
  1973.     if preparenext then
  1974.         rerunning = false
  1975.         preparenext = false
  1976.         GenerateNewKeepBest(genome)
  1977.     end
  1978.     if rightmost > maxright then
  1979.         maxright = rightmost
  1980.     end
  1981.     if rightmost > maxright*0.85 and AllowSlowdownNearMax then
  1982.         if turbo and maxright > 200 and AllowSlowdownNearMax and not restoreturbo then
  1983.             emu.speedmode("normal")
  1984.             turbo = false
  1985.             restoreturbo = true
  1986.         end
  1987.     elseif species.turbo == 'off' then
  1988.         if turbo then
  1989.             emu.speedmode("normal")
  1990.             turbo = false
  1991.         end
  1992.     elseif requiredFitness > rightmost and requiredFitness > 10 and not turbo then
  1993.         emu.speedmode("turbo")
  1994.         turbo = true
  1995.         restoreturbo = false
  1996.     elseif requiredFitness < rightmost and turbo and requiredFitness > 10 then
  1997.         emu.speedmode("normal")
  1998.         turbo = false
  1999.         restoreturbo = true
  2000.     elseif restoreturbo and not (requiredFitness > 10) then
  2001.         emu.speedmode("turbo")
  2002.         turbo = true
  2003.         restoreturbo = false
  2004.     end
  2005.    
  2006.     local timeoutBonus = pool.currentFrame / 4
  2007.     if (mariostate == 11 or mariohole or math.floor(rightmost - (pool.currentFrame) / 2 + - (timeout + timeoutBonus)*2/3 +40 + timebonus) < -50 ) and timeout > 40-timeoutBonus then
  2008.         local temptimeout = timeout
  2009.         timeout = 30 - timeoutBonus
  2010.         local difference = temptimeout - timeout
  2011.         pool.currentFrame = pool.currentFrame + difference
  2012.         killtrigger = true
  2013.     end
  2014.     local timeoutBonus = pool.currentFrame / 4
  2015.     if timeout + timeoutBonus <= 0 then
  2016.         local fitness = rightmost - pool.currentFrame / 2 +40 + timebonus
  2017.         if fitness == 0 then
  2018.             fitness = -1
  2019.         end
  2020.        
  2021.             genome.fitness = fitness
  2022.        
  2023.        
  2024.         if fitness > pool.maxFitness then
  2025.             pool.maxFitness = fitness
  2026.             fitnesstracker()
  2027.             savePool()
  2028.         end
  2029.        
  2030.         if fitness > pool.maxFitness - 30 then
  2031.             pool.maxcounter = pool.maxcounter + 1
  2032.         end
  2033.        
  2034.         emu.print("Gen " .. pool.generation .. " species " .. pool.currentSpecies .. " genome " .. pool.currentGenome .. " fitness: " .. fitness)
  2035.         pool.currentSpecies = 1
  2036.         pool.currentGenome = 1
  2037.         while fitnessAlreadyMeasured() do
  2038.             offset = 0 --offset in x coordinates for pipe
  2039.             timebonus = 0 --used to freeze fitness
  2040.             mariohole = false --reset the fallen into hole variable
  2041.             mariopipe = false --is mario exiting a pipe or just teleporting
  2042.             loop = false --is this a loop?
  2043.             marioPipeEnter = false --has mario entered a pipe
  2044.             currentTracker = 1 --tracker for the loop
  2045.             killtrigger = false
  2046.             ntrigger = true
  2047.             nswitch = true
  2048.             if rerunning then
  2049.                 rerunning = false
  2050.                 preparenext = true
  2051.             end
  2052.             nextGenome()
  2053.         end
  2054.        
  2055.         initializeRun()
  2056.     end
  2057.  
  2058.     local measured = 0
  2059.     local total = 0
  2060.     for _,species in pairs(pool.species) do
  2061.         for _,genome in pairs(species.genomes) do
  2062.             total = total + 1
  2063.             if genome.fitness ~= 0 then
  2064.                 measured = measured + 1
  2065.             end
  2066.         end
  2067.     end
  2068.         gui.opacity(1) --made the top banner opaque. you can change this if you want a slightly transparent banner
  2069.         if turbo then
  2070.             gui.drawtext(250, 11, "T", toRGBA(0xFFFF0000), 0x0)
  2071.         end
  2072.         gui.drawtext(5, 11, "Gen " .. pool.generation .. " species " .. pool.currentSpecies .. " genome " .. pool.currentGenome .. " (" .. math.floor(measured/total*100) .. "%) ".. "Pop: ".. Population, toRGBA(0xFF000000), 0x0)
  2073.         gui.drawtext(5, 20, "Fitness: " .. math.floor(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
  2074.         gui.drawtext(80, 20, "Max Fitness:" .. math.floor(pool.maxFitness) .. " (".. math.floor(secondbest) .. ")".. " ".. "(" ..pool.maxcounter .. "x)", toRGBA(0xFF000000), 0x0)
  2075.        
  2076.     pool.currentFrame = pool.currentFrame + 1
  2077.  
  2078.     emu.frameadvance();
  2079. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement