Advertisement
austinh115

[LUA] MarI/O edit to include species name

Jun 17th, 2015
216
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 32.61 KB | None | 0 0
  1. -- MarI/O by SethBling
  2. -- Feel free to use this code, but please do not redistribute it.
  3. -- Intended for use with the BizHawk emulator and Super Mario World or Super Mario Bros. ROM.
  4. -- For SMW, make sure you have a save state named "DP1.state" at the beginning of a level,
  5. -- and put a copy in both the Lua folder and the root directory of BizHawk.
  6.  
  7. if gameinfo.getromname() == "Super Mario World (USA)" then
  8.     Filename = "DP1.state"
  9.     ButtonNames = {
  10.         "A",
  11.         "B",
  12.         "X",
  13.         "Y",
  14.         "Up",
  15.         "Down",
  16.         "Left",
  17.         "Right",
  18.     }
  19. elseif gameinfo.getromname() == "Super Mario Bros." then
  20.     Filename = "SMB1-1.state"
  21.     ButtonNames = {
  22.         "A",
  23.         "B",
  24.         "Up",
  25.         "Down",
  26.         "Left",
  27.         "Right",
  28.     }
  29. end
  30.  
  31. -- https://www.randomlists.com/random-words
  32. -- I'm sure there is a better way of doing this, but I just did it real fast.
  33. NameDictionary = {
  34.     "hate",
  35.     "jittery",
  36.     "stuff",
  37.     "mist",
  38.     "sound",
  39.     "envious",
  40.     "statement",
  41.     "phone",
  42.     "tow",
  43.     "judge",
  44.     "absorbed",
  45.     "mute",
  46.     "cream",
  47.     "snail",
  48.     "mass",
  49.     "fumbling",
  50.     "prepare",
  51.     "seat",
  52.     "young",
  53.     "irritate",
  54.     "toothsome",
  55.     "seed",
  56.     "religion",
  57.     "fall",
  58.     "button",
  59.     "wash",
  60.     "ready",
  61.     "juice",
  62.     "mouth",
  63.     "concentrate",
  64.     "invite",
  65.     "strange",
  66.     "call",
  67.     "crash",
  68.     "treatment",
  69.     "exist",
  70.     "dry",
  71.     "horn",
  72.     "watch",
  73.     "cut",
  74.     "ancient",
  75.     "scrawny",
  76.     "coach",
  77.     "hollow",
  78.     "powder",
  79.     "hesitant",
  80.     "moldy",
  81.     "flashy",
  82.     "question",
  83.     "umbrella",
  84.     "worm",
  85.     "average",
  86.     "effect",
  87.     "apologise",
  88.     "dogs",
  89.     "tacit",
  90.     "power",
  91.     "hurried",
  92.     "filthy",
  93.     "pedal",
  94.     "thundering",
  95.     "obnoxious",
  96.     "continue",
  97.     "eggs",
  98.     "sheet",
  99.     "necessary",
  100.     "cheer",
  101.     "maddening",
  102.     "unable",
  103.     "poison",
  104.     "kaput",
  105.     "voracious",
  106.     "demonic",
  107.     "entertaining",
  108.     "mint",
  109.     "real",
  110.     "slow",
  111.     "long",
  112.     "minor",
  113.     "water",
  114.     "test",
  115.     "brake",
  116.     "false",
  117.     "dusty",
  118.     "profit",
  119.     "doll",
  120.     "hop",
  121.     "capricious",
  122.     "door",
  123.     "solid",
  124.     "quarrelsome",
  125.     "race",
  126.     "sheep",
  127.     "debonair",
  128.     "stone",
  129.     "wry",
  130.     "pointless",
  131.     "snobbish",
  132.     "concern",
  133.     "ratty",
  134.     "heat",
  135.     "rigid",
  136.     "girl",
  137.     "phobic",
  138.     "spot",
  139.     "breakable",
  140.     "destroy",
  141.     "chalk",
  142.     "unhealthy",
  143.     "worried",
  144.     "sweltering",
  145.     "work",
  146.     "untidy",
  147.     "gullible",
  148.     "beg",
  149.     "magical",
  150.     "silver",
  151.     "clear",
  152.     "territory",
  153.     "relax",
  154.     "letter",
  155.     "axiomatic",
  156.     "annoy",
  157.     "amazing",
  158.     "glow",
  159.     "fasten",
  160.     "leg",
  161.     "far-flung",
  162.     "medical",
  163.     "rose",
  164.     "magic",
  165.     "enchanted",
  166.     "understood",
  167.     "liquid",
  168.     "earsplitting",
  169.     "flower",
  170.     "harass",
  171.     "things",
  172.     "plant",
  173.     "gusty",
  174.     "jumpy",
  175.     "mend",
  176.     "adorable",
  177.     "water",
  178.     "taste",
  179.     "explain",
  180.     "basketball",
  181.     "press",
  182.     "seemly",
  183.     "name",
  184.     "wine",
  185.     "silky",
  186.     "ghost",
  187.     "cowardly",
  188.     "oafish",
  189.     "tax",
  190.     "drink",
  191.     "north",
  192.     "clumsy",
  193.     "bury",
  194.     "teeny",
  195.     "probable",
  196.     "fat",
  197.     "knife",
  198.     "splendid",
  199.     "box",
  200.     "sink",
  201.     "learn",
  202.     "prefer",
  203.     "torpid",
  204.     "calendar",
  205.     "brake",
  206.     "crack",
  207.     "desert",
  208.     "lopsided",
  209.     "book",
  210.     "pets",
  211.     "drawer",
  212.     "low",
  213.     "habitual",
  214.     "abrasive",
  215.     "innocent",
  216.     "aquatic",
  217.     "play",
  218.     "violent",
  219.     "flowery",
  220.     "finger",
  221.     "drain",
  222.     "furniture",
  223.     "unique",
  224.     "frog",
  225.     "unlock",
  226.     "damp",
  227.     "weight",
  228.     "notebook",
  229.     "store",
  230.     "ugly",
  231.     "suggestion",
  232.     "sin",
  233.     "transport",
  234.     "sleet",
  235.     "roll",
  236.     "mix",
  237.     "lowly",
  238.     "overjoyed",
  239.     "prick",
  240.     "extend",
  241.     "deafening",
  242.     "lake",
  243.     "upset",
  244.     "creature",
  245.     "uneven",
  246.     "change",
  247.     "harmony",
  248.     "cute",
  249.     "development",
  250.     "charge",
  251.     "talented",
  252.     "challenge",
  253.     "neighborly",
  254.     "channel",
  255.     "obtain",
  256.     "thaw",
  257.     "comfortable",
  258.     "secretive",
  259.     "delightful",
  260.     "tour",
  261.     "wacky",
  262.     "reign",
  263.     "jail",
  264.     "muddled",
  265.     "ill-fated",
  266.     "card",
  267.     "nondescript",
  268.     "slope",
  269.     "face",
  270.     "mine",
  271.     "narrow",
  272.     "rambunctious",
  273.     "quizzical",
  274.     "sock",
  275.     "womanly",
  276.     "peace",
  277.     "milk",
  278.     "recondite",
  279.     "expert",
  280.     "complete",
  281.     "exuberant",
  282.     "fluffy",
  283.     "elite",
  284.     "lunch",
  285.     "vivacious",
  286.     "craven",
  287.     "question",
  288.     "unsightly",
  289.     "appliance",
  290.     "blue",
  291.     "lacking",
  292.     "loaf",
  293.     "teaching",
  294.     "rock",
  295.     "hands",
  296.     "touch",
  297.     "fear",
  298.     "horses",
  299.     "growth",
  300.     "bright",
  301.     "amount",
  302.     "lucky",
  303.     "health",
  304.     "crawl",
  305.     "ethereal",
  306.     "forgetful",
  307.     "divide",
  308.     "troubled",
  309.     "pushy",
  310.     "bird",
  311.     "river",
  312.     "range",
  313.     "board",
  314.     "wash",
  315.     "oatmeal",
  316.     "trains",
  317.     "expand",
  318.     "enthusiastic",
  319.     "clean",
  320.     "circle",
  321.     "license",
  322.     "fuel",
  323.     "nail",
  324.     "well-made",
  325.     "ad hoc",
  326.     "stamp",
  327.     "poke",
  328.     "heal",
  329.     "rely",
  330.     "songs",
  331.     "possessive",
  332.     "rainy",
  333.     "behave"
  334. }
  335.  
  336. BoxRadius = 6
  337. InputSize = (BoxRadius*2+1)*(BoxRadius*2+1)
  338.  
  339. Inputs = InputSize+1
  340. Outputs = #ButtonNames
  341.  
  342. Population = 300
  343. DeltaDisjoint = 2.0
  344. DeltaWeights = 0.4
  345. DeltaThreshold = 1.0
  346.  
  347. StaleSpecies = 15
  348.  
  349. MutateConnectionsChance = 0.25
  350. PerturbChance = 0.90
  351. CrossoverChance = 0.75
  352. LinkMutationChance = 2.0
  353. NodeMutationChance = 0.50
  354. BiasMutationChance = 0.40
  355. StepSize = 0.1
  356. DisableMutationChance = 0.4
  357. EnableMutationChance = 0.2
  358.  
  359. TimeoutConstant = 20
  360.  
  361. MaxNodes = 1000000
  362.  
  363. function getPositions()
  364.     if gameinfo.getromname() == "Super Mario World (USA)" then
  365.         marioX = memory.read_s16_le(0x94)
  366.         marioY = memory.read_s16_le(0x96)
  367.        
  368.         local layer1x = memory.read_s16_le(0x1A);
  369.         local layer1y = memory.read_s16_le(0x1C);
  370.        
  371.         screenX = marioX-layer1x
  372.         screenY = marioY-layer1y
  373.     elseif gameinfo.getromname() == "Super Mario Bros." then
  374.         marioX = memory.readbyte(0x6D) * 0x100 + memory.readbyte(0x86)
  375.         marioY = memory.readbyte(0x03B8)+16
  376.    
  377.         screenX = memory.readbyte(0x03AD)
  378.         screenY = memory.readbyte(0x03B8)
  379.     end
  380. end
  381.  
  382. function getTile(dx, dy)
  383.     if gameinfo.getromname() == "Super Mario World (USA)" then
  384.         x = math.floor((marioX+dx+8)/16)
  385.         y = math.floor((marioY+dy)/16)
  386.        
  387.         return memory.readbyte(0x1C800 + math.floor(x/0x10)*0x1B0 + y*0x10 + x%0x10)
  388.     elseif gameinfo.getromname() == "Super Mario Bros." then
  389.         local x = marioX + dx + 8
  390.         local y = marioY + dy - 16
  391.         local page = math.floor(x/256)%2
  392.  
  393.         local subx = math.floor((x%256)/16)
  394.         local suby = math.floor((y - 32)/16)
  395.         local addr = 0x500 + page*13*16+suby*16+subx
  396.        
  397.         if suby >= 13 or suby < 0 then
  398.             return 0
  399.         end
  400.        
  401.         if memory.readbyte(addr) ~= 0 then
  402.             return 1
  403.         else
  404.             return 0
  405.         end
  406.     end
  407. end
  408.  
  409. function getSprites()
  410.     if gameinfo.getromname() == "Super Mario World (USA)" then
  411.         local sprites = {}
  412.         for slot=0,11 do
  413.             local status = memory.readbyte(0x14C8+slot)
  414.             if status ~= 0 then
  415.                 spritex = memory.readbyte(0xE4+slot) + memory.readbyte(0x14E0+slot)*256
  416.                 spritey = memory.readbyte(0xD8+slot) + memory.readbyte(0x14D4+slot)*256
  417.                 sprites[#sprites+1] = {["x"]=spritex, ["y"]=spritey}
  418.             end
  419.         end    
  420.        
  421.         return sprites
  422.     elseif gameinfo.getromname() == "Super Mario Bros." then
  423.         local sprites = {}
  424.         for slot=0,4 do
  425.             local enemy = memory.readbyte(0xF+slot)
  426.             if enemy ~= 0 then
  427.                 local ex = memory.readbyte(0x6E + slot)*0x100 + memory.readbyte(0x87+slot)
  428.                 local ey = memory.readbyte(0xCF + slot)+24
  429.                 sprites[#sprites+1] = {["x"]=ex,["y"]=ey}
  430.             end
  431.         end
  432.        
  433.         return sprites
  434.     end
  435. end
  436.  
  437. function getExtendedSprites()
  438.     if gameinfo.getromname() == "Super Mario World (USA)" then
  439.         local extended = {}
  440.         for slot=0,11 do
  441.             local number = memory.readbyte(0x170B+slot)
  442.             if number ~= 0 then
  443.                 spritex = memory.readbyte(0x171F+slot) + memory.readbyte(0x1733+slot)*256
  444.                 spritey = memory.readbyte(0x1715+slot) + memory.readbyte(0x1729+slot)*256
  445.                 extended[#extended+1] = {["x"]=spritex, ["y"]=spritey}
  446.             end
  447.         end    
  448.        
  449.         return extended
  450.     elseif gameinfo.getromname() == "Super Mario Bros." then
  451.         return {}
  452.     end
  453. end
  454.  
  455. function getInputs()
  456.     getPositions()
  457.    
  458.     sprites = getSprites()
  459.     extended = getExtendedSprites()
  460.    
  461.     local inputs = {}
  462.    
  463.     for dy=-BoxRadius*16,BoxRadius*16,16 do
  464.         for dx=-BoxRadius*16,BoxRadius*16,16 do
  465.             inputs[#inputs+1] = 0
  466.            
  467.             tile = getTile(dx, dy)
  468.             if tile == 1 and marioY+dy < 0x1B0 then
  469.                 inputs[#inputs] = 1
  470.             end
  471.            
  472.             for i = 1,#sprites do
  473.                 distx = math.abs(sprites[i]["x"] - (marioX+dx))
  474.                 disty = math.abs(sprites[i]["y"] - (marioY+dy))
  475.                 if distx <= 8 and disty <= 8 then
  476.                     inputs[#inputs] = -1
  477.                 end
  478.             end
  479.  
  480.             for i = 1,#extended do
  481.                 distx = math.abs(extended[i]["x"] - (marioX+dx))
  482.                 disty = math.abs(extended[i]["y"] - (marioY+dy))
  483.                 if distx < 8 and disty < 8 then
  484.                     inputs[#inputs] = -1
  485.                 end
  486.             end
  487.         end
  488.     end
  489.    
  490.     --mariovx = memory.read_s8(0x7B)
  491.     --mariovy = memory.read_s8(0x7D)
  492.    
  493.     return inputs
  494. end
  495.  
  496. function sigmoid(x)
  497.     return 2/(1+math.exp(-4.9*x))-1
  498. end
  499.  
  500. function newInnovation()
  501.     pool.innovation = pool.innovation + 1
  502.     return pool.innovation
  503. end
  504.  
  505. function newPool()
  506.     local pool = {}
  507.     pool.species = {}
  508.     pool.generation = 0
  509.     pool.innovation = Outputs
  510.     pool.currentSpecies = 1
  511.     pool.currentGenome = 1
  512.     pool.currentFrame = 0
  513.     pool.maxFitness = 0
  514.    
  515.     return pool
  516. end
  517.  
  518. function newSpecies()
  519.     local species = {}
  520.     species.topFitness = 0
  521.     species.staleness = 0
  522.     species.genomes = {}
  523.     species.averageFitness = 0
  524.    
  525.     return species
  526. end
  527.  
  528. function newGenome()
  529.     local genome = {}
  530.     genome.genes = {}
  531.     genome.fitness = 0
  532.     genome.adjustedFitness = 0
  533.     genome.network = {}
  534.     genome.maxneuron = 0
  535.     genome.globalRank = 0
  536.     genome.mutationRates = {}
  537.     genome.mutationRates["connections"] = MutateConnectionsChance
  538.     genome.mutationRates["link"] = LinkMutationChance
  539.     genome.mutationRates["bias"] = BiasMutationChance
  540.     genome.mutationRates["node"] = NodeMutationChance
  541.     genome.mutationRates["enable"] = EnableMutationChance
  542.     genome.mutationRates["disable"] = DisableMutationChance
  543.     genome.mutationRates["step"] = StepSize
  544.    
  545.     return genome
  546. end
  547.  
  548. function copyGenome(genome)
  549.     local genome2 = newGenome()
  550.     for g=1,#genome.genes do
  551.         table.insert(genome2.genes, copyGene(genome.genes[g]))
  552.     end
  553.     genome2.maxneuron = genome.maxneuron
  554.     genome2.mutationRates["connections"] = genome.mutationRates["connections"]
  555.     genome2.mutationRates["link"] = genome.mutationRates["link"]
  556.     genome2.mutationRates["bias"] = genome.mutationRates["bias"]
  557.     genome2.mutationRates["node"] = genome.mutationRates["node"]
  558.     genome2.mutationRates["enable"] = genome.mutationRates["enable"]
  559.     genome2.mutationRates["disable"] = genome.mutationRates["disable"]
  560.    
  561.     return genome2
  562. end
  563.  
  564. function basicGenome()
  565.     local genome = newGenome()
  566.     local innovation = 1
  567.  
  568.     genome.maxneuron = Inputs
  569.     mutate(genome)
  570.    
  571.     return genome
  572. end
  573.  
  574. function newGene()
  575.     local gene = {}
  576.     gene.into = 0
  577.     gene.out = 0
  578.     gene.weight = 0.0
  579.     gene.enabled = true
  580.     gene.innovation = 0
  581.    
  582.     return gene
  583. end
  584.  
  585. function copyGene(gene)
  586.     local gene2 = newGene()
  587.     gene2.into = gene.into
  588.     gene2.out = gene.out
  589.     gene2.weight = gene.weight
  590.     gene2.enabled = gene.enabled
  591.     gene2.innovation = gene.innovation
  592.    
  593.     return gene2
  594. end
  595.  
  596. function newNeuron()
  597.     local neuron = {}
  598.     neuron.incoming = {}
  599.     neuron.value = 0.0
  600.    
  601.     return neuron
  602. end
  603.  
  604. function generateNetwork(genome)
  605.     local network = {}
  606.     network.neurons = {}
  607.    
  608.     for i=1,Inputs do
  609.         network.neurons[i] = newNeuron()
  610.     end
  611.    
  612.     for o=1,Outputs do
  613.         network.neurons[MaxNodes+o] = newNeuron()
  614.     end
  615.    
  616.     table.sort(genome.genes, function (a,b)
  617.         return (a.out < b.out)
  618.     end)
  619.     for i=1,#genome.genes do
  620.         local gene = genome.genes[i]
  621.         if gene.enabled then
  622.             if network.neurons[gene.out] == nil then
  623.                 network.neurons[gene.out] = newNeuron()
  624.             end
  625.             local neuron = network.neurons[gene.out]
  626.             table.insert(neuron.incoming, gene)
  627.             if network.neurons[gene.into] == nil then
  628.                 network.neurons[gene.into] = newNeuron()
  629.             end
  630.         end
  631.     end
  632.    
  633.     genome.network = network
  634. end
  635.  
  636. function evaluateNetwork(network, inputs)
  637.     table.insert(inputs, 1)
  638.     if #inputs ~= Inputs then
  639.         console.writeline("Incorrect number of neural network inputs.")
  640.         return {}
  641.     end
  642.    
  643.     for i=1,Inputs do
  644.         network.neurons[i].value = inputs[i]
  645.     end
  646.    
  647.     for _,neuron in pairs(network.neurons) do
  648.         local sum = 0
  649.         for j = 1,#neuron.incoming do
  650.             local incoming = neuron.incoming[j]
  651.             local other = network.neurons[incoming.into]
  652.             sum = sum + incoming.weight * other.value
  653.         end
  654.        
  655.         if #neuron.incoming > 0 then
  656.             neuron.value = sigmoid(sum)
  657.         end
  658.     end
  659.    
  660.     local outputs = {}
  661.     for o=1,Outputs do
  662.         local button = "P1 " .. ButtonNames[o]
  663.         if network.neurons[MaxNodes+o].value > 0 then
  664.             outputs[button] = true
  665.         else
  666.             outputs[button] = false
  667.         end
  668.     end
  669.    
  670.     return outputs
  671. end
  672.  
  673. function crossover(g1, g2)
  674.     -- Make sure g1 is the higher fitness genome
  675.     if g2.fitness > g1.fitness then
  676.         tempg = g1
  677.         g1 = g2
  678.         g2 = tempg
  679.     end
  680.  
  681.     local child = newGenome()
  682.    
  683.     local innovations2 = {}
  684.     for i=1,#g2.genes do
  685.         local gene = g2.genes[i]
  686.         innovations2[gene.innovation] = gene
  687.     end
  688.    
  689.     for i=1,#g1.genes do
  690.         local gene1 = g1.genes[i]
  691.         local gene2 = innovations2[gene1.innovation]
  692.         if gene2 ~= nil and math.random(2) == 1 and gene2.enabled then
  693.             table.insert(child.genes, copyGene(gene2))
  694.         else
  695.             table.insert(child.genes, copyGene(gene1))
  696.         end
  697.     end
  698.    
  699.     child.maxneuron = math.max(g1.maxneuron,g2.maxneuron)
  700.    
  701.     for mutation,rate in pairs(g1.mutationRates) do
  702.         child.mutationRates[mutation] = rate
  703.     end
  704.    
  705.     return child
  706. end
  707.  
  708. function randomNeuron(genes, nonInput)
  709.     local neurons = {}
  710.     if not nonInput then
  711.         for i=1,Inputs do
  712.             neurons[i] = true
  713.         end
  714.     end
  715.     for o=1,Outputs do
  716.         neurons[MaxNodes+o] = true
  717.     end
  718.     for i=1,#genes do
  719.         if (not nonInput) or genes[i].into > Inputs then
  720.             neurons[genes[i].into] = true
  721.         end
  722.         if (not nonInput) or genes[i].out > Inputs then
  723.             neurons[genes[i].out] = true
  724.         end
  725.     end
  726.  
  727.     local count = 0
  728.     for _,_ in pairs(neurons) do
  729.         count = count + 1
  730.     end
  731.     local n = math.random(1, count)
  732.    
  733.     for k,v in pairs(neurons) do
  734.         n = n-1
  735.         if n == 0 then
  736.             return k
  737.         end
  738.     end
  739.    
  740.     return 0
  741. end
  742.  
  743. function containsLink(genes, link)
  744.     for i=1,#genes do
  745.         local gene = genes[i]
  746.         if gene.into == link.into and gene.out == link.out then
  747.             return true
  748.         end
  749.     end
  750. end
  751.  
  752. function pointMutate(genome)
  753.     local step = genome.mutationRates["step"]
  754.    
  755.     for i=1,#genome.genes do
  756.         local gene = genome.genes[i]
  757.         if math.random() < PerturbChance then
  758.             gene.weight = gene.weight + math.random() * step*2 - step
  759.         else
  760.             gene.weight = math.random()*4-2
  761.         end
  762.     end
  763. end
  764.  
  765. function linkMutate(genome, forceBias)
  766.     local neuron1 = randomNeuron(genome.genes, false)
  767.     local neuron2 = randomNeuron(genome.genes, true)
  768.      
  769.     local newLink = newGene()
  770.     if neuron1 <= Inputs and neuron2 <= Inputs then
  771.         --Both input nodes
  772.         return
  773.     end
  774.     if neuron2 <= Inputs then
  775.         -- Swap output and input
  776.         local temp = neuron1
  777.         neuron1 = neuron2
  778.         neuron2 = temp
  779.     end
  780.  
  781.     newLink.into = neuron1
  782.     newLink.out = neuron2
  783.     if forceBias then
  784.         newLink.into = Inputs
  785.     end
  786.    
  787.     if containsLink(genome.genes, newLink) then
  788.         return
  789.     end
  790.     newLink.innovation = newInnovation()
  791.     newLink.weight = math.random()*4-2
  792.    
  793.     table.insert(genome.genes, newLink)
  794. end
  795.  
  796. function nodeMutate(genome)
  797.     if #genome.genes == 0 then
  798.         return
  799.     end
  800.  
  801.     genome.maxneuron = genome.maxneuron + 1
  802.  
  803.     local gene = genome.genes[math.random(1,#genome.genes)]
  804.     if not gene.enabled then
  805.         return
  806.     end
  807.     gene.enabled = false
  808.    
  809.     local gene1 = copyGene(gene)
  810.     gene1.out = genome.maxneuron
  811.     gene1.weight = 1.0
  812.     gene1.innovation = newInnovation()
  813.     gene1.enabled = true
  814.     table.insert(genome.genes, gene1)
  815.    
  816.     local gene2 = copyGene(gene)
  817.     gene2.into = genome.maxneuron
  818.     gene2.innovation = newInnovation()
  819.     gene2.enabled = true
  820.     table.insert(genome.genes, gene2)
  821. end
  822.  
  823. function enableDisableMutate(genome, enable)
  824.     local candidates = {}
  825.     for _,gene in pairs(genome.genes) do
  826.         if gene.enabled == not enable then
  827.             table.insert(candidates, gene)
  828.         end
  829.     end
  830.    
  831.     if #candidates == 0 then
  832.         return
  833.     end
  834.    
  835.     local gene = candidates[math.random(1,#candidates)]
  836.     gene.enabled = not gene.enabled
  837. end
  838.  
  839. function mutate(genome)
  840.     for mutation,rate in pairs(genome.mutationRates) do
  841.         if math.random(1,2) == 1 then
  842.             genome.mutationRates[mutation] = 0.95*rate
  843.         else
  844.             genome.mutationRates[mutation] = 1.05263*rate
  845.         end
  846.     end
  847.  
  848.     if math.random() < genome.mutationRates["connections"] then
  849.         pointMutate(genome)
  850.     end
  851.    
  852.     local p = genome.mutationRates["link"]
  853.     while p > 0 do
  854.         if math.random() < p then
  855.             linkMutate(genome, false)
  856.         end
  857.         p = p - 1
  858.     end
  859.  
  860.     p = genome.mutationRates["bias"]
  861.     while p > 0 do
  862.         if math.random() < p then
  863.             linkMutate(genome, true)
  864.         end
  865.         p = p - 1
  866.     end
  867.    
  868.     p = genome.mutationRates["node"]
  869.     while p > 0 do
  870.         if math.random() < p then
  871.             nodeMutate(genome)
  872.         end
  873.         p = p - 1
  874.     end
  875.    
  876.     p = genome.mutationRates["enable"]
  877.     while p > 0 do
  878.         if math.random() < p then
  879.             enableDisableMutate(genome, true)
  880.         end
  881.         p = p - 1
  882.     end
  883.  
  884.     p = genome.mutationRates["disable"]
  885.     while p > 0 do
  886.         if math.random() < p then
  887.             enableDisableMutate(genome, false)
  888.         end
  889.         p = p - 1
  890.     end
  891. end
  892.  
  893. function disjoint(genes1, genes2)
  894.     local i1 = {}
  895.     for i = 1,#genes1 do
  896.         local gene = genes1[i]
  897.         i1[gene.innovation] = true
  898.     end
  899.  
  900.     local i2 = {}
  901.     for i = 1,#genes2 do
  902.         local gene = genes2[i]
  903.         i2[gene.innovation] = true
  904.     end
  905.    
  906.     local disjointGenes = 0
  907.     for i = 1,#genes1 do
  908.         local gene = genes1[i]
  909.         if not i2[gene.innovation] then
  910.             disjointGenes = disjointGenes+1
  911.         end
  912.     end
  913.    
  914.     for i = 1,#genes2 do
  915.         local gene = genes2[i]
  916.         if not i1[gene.innovation] then
  917.             disjointGenes = disjointGenes+1
  918.         end
  919.     end
  920.    
  921.     local n = math.max(#genes1, #genes2)
  922.    
  923.     return disjointGenes / n
  924. end
  925.  
  926. function weights(genes1, genes2)
  927.     local i2 = {}
  928.     for i = 1,#genes2 do
  929.         local gene = genes2[i]
  930.         i2[gene.innovation] = gene
  931.     end
  932.  
  933.     local sum = 0
  934.     local coincident = 0
  935.     for i = 1,#genes1 do
  936.         local gene = genes1[i]
  937.         if i2[gene.innovation] ~= nil then
  938.             local gene2 = i2[gene.innovation]
  939.             sum = sum + math.abs(gene.weight - gene2.weight)
  940.             coincident = coincident + 1
  941.         end
  942.     end
  943.    
  944.     return sum / coincident
  945. end
  946.    
  947. function sameSpecies(genome1, genome2)
  948.     local dd = DeltaDisjoint*disjoint(genome1.genes, genome2.genes)
  949.     local dw = DeltaWeights*weights(genome1.genes, genome2.genes)
  950.     return dd + dw < DeltaThreshold
  951. end
  952.  
  953. function rankGlobally()
  954.     local global = {}
  955.     for s = 1,#pool.species do
  956.         local species = pool.species[s]
  957.         for g = 1,#species.genomes do
  958.             table.insert(global, species.genomes[g])
  959.         end
  960.     end
  961.     table.sort(global, function (a,b)
  962.         return (a.fitness < b.fitness)
  963.     end)
  964.    
  965.     for g=1,#global do
  966.         global[g].globalRank = g
  967.     end
  968. end
  969.  
  970. function calculateAverageFitness(species)
  971.     local total = 0
  972.    
  973.     for g=1,#species.genomes do
  974.         local genome = species.genomes[g]
  975.         total = total + genome.globalRank
  976.     end
  977.    
  978.     species.averageFitness = total / #species.genomes
  979. end
  980.  
  981. function totalAverageFitness()
  982.     local total = 0
  983.     for s = 1,#pool.species do
  984.         local species = pool.species[s]
  985.         total = total + species.averageFitness
  986.     end
  987.  
  988.     return total
  989. end
  990.  
  991. function cullSpecies(cutToOne)
  992.     for s = 1,#pool.species do
  993.         local species = pool.species[s]
  994.        
  995.         table.sort(species.genomes, function (a,b)
  996.             return (a.fitness > b.fitness)
  997.         end)
  998.        
  999.         local remaining = math.ceil(#species.genomes/2)
  1000.         if cutToOne then
  1001.             remaining = 1
  1002.         end
  1003.         while #species.genomes > remaining do
  1004.             table.remove(species.genomes)
  1005.         end
  1006.     end
  1007. end
  1008.  
  1009. function breedChild(species)
  1010.     local child = {}
  1011.     if math.random() < CrossoverChance then
  1012.         g1 = species.genomes[math.random(1, #species.genomes)]
  1013.         g2 = species.genomes[math.random(1, #species.genomes)]
  1014.         child = crossover(g1, g2)
  1015.     else
  1016.         g = species.genomes[math.random(1, #species.genomes)]
  1017.         child = copyGenome(g)
  1018.     end
  1019.    
  1020.     mutate(child)
  1021.    
  1022.     return child
  1023. end
  1024.  
  1025. function removeStaleSpecies()
  1026.     local survived = {}
  1027.  
  1028.     for s = 1,#pool.species do
  1029.         local species = pool.species[s]
  1030.        
  1031.         table.sort(species.genomes, function (a,b)
  1032.             return (a.fitness > b.fitness)
  1033.         end)
  1034.        
  1035.         if species.genomes[1].fitness > species.topFitness then
  1036.             species.topFitness = species.genomes[1].fitness
  1037.             species.staleness = 0
  1038.         else
  1039.             species.staleness = species.staleness + 1
  1040.         end
  1041.         if species.staleness < StaleSpecies or species.topFitness >= pool.maxFitness then
  1042.             table.insert(survived, species)
  1043.         end
  1044.     end
  1045.  
  1046.     pool.species = survived
  1047. end
  1048.  
  1049. function removeWeakSpecies()
  1050.     local survived = {}
  1051.  
  1052.     local sum = totalAverageFitness()
  1053.     for s = 1,#pool.species do
  1054.         local species = pool.species[s]
  1055.         breed = math.floor(species.averageFitness / sum * Population)
  1056.         if breed >= 1 then
  1057.             table.insert(survived, species)
  1058.         end
  1059.     end
  1060.  
  1061.     pool.species = survived
  1062. end
  1063.  
  1064.  
  1065. function addToSpecies(child)
  1066.     local foundSpecies = false
  1067.     for s=1,#pool.species do
  1068.         local species = pool.species[s]
  1069.         if not foundSpecies and sameSpecies(child, species.genomes[1]) then
  1070.             table.insert(species.genomes, child)
  1071.             foundSpecies = true
  1072.         end
  1073.     end
  1074.    
  1075.     if not foundSpecies then
  1076.         local childSpecies = newSpecies()
  1077.         table.insert(childSpecies.genomes, child)
  1078.         table.insert(pool.species, childSpecies)
  1079.     end
  1080. end
  1081.  
  1082. function newGeneration()
  1083.     cullSpecies(false) -- Cull the bottom half of each species
  1084.     rankGlobally()
  1085.     removeStaleSpecies()
  1086.     rankGlobally()
  1087.     for s = 1,#pool.species do
  1088.         local species = pool.species[s]
  1089.         calculateAverageFitness(species)
  1090.     end
  1091.     removeWeakSpecies()
  1092.     local sum = totalAverageFitness()
  1093.     local children = {}
  1094.     for s = 1,#pool.species do
  1095.         local species = pool.species[s]
  1096.         breed = math.floor(species.averageFitness / sum * Population) - 1
  1097.         for i=1,breed do
  1098.             table.insert(children, breedChild(species))
  1099.         end
  1100.     end
  1101.     cullSpecies(true) -- Cull all but the top member of each species
  1102.     while #children + #pool.species < Population do
  1103.         local species = pool.species[math.random(1, #pool.species)]
  1104.         table.insert(children, breedChild(species))
  1105.     end
  1106.     for c=1,#children do
  1107.         local child = children[c]
  1108.         addToSpecies(child)
  1109.     end
  1110.    
  1111.     pool.generation = pool.generation + 1
  1112.    
  1113.     writeFile("backup." .. pool.generation .. "." .. forms.gettext(saveLoadFile))
  1114. end
  1115.    
  1116. function initializePool()
  1117.     pool = newPool()
  1118.  
  1119.     for i=1,Population do
  1120.         basic = basicGenome()
  1121.         addToSpecies(basic)
  1122.     end
  1123.  
  1124.     initializeRun()
  1125. end
  1126.  
  1127. function clearJoypad()
  1128.     controller = {}
  1129.     for b = 1,#ButtonNames do
  1130.         controller["P1 " .. ButtonNames[b]] = false
  1131.     end
  1132.     joypad.set(controller)
  1133. end
  1134.  
  1135. function initializeRun()
  1136.     savestate.load(Filename);
  1137.     rightmost = 0
  1138.     pool.currentFrame = 0
  1139.     timeout = TimeoutConstant
  1140.     clearJoypad()
  1141.    
  1142.     local species = pool.species[pool.currentSpecies]
  1143.     local genome = species.genomes[pool.currentGenome]
  1144.     generateNetwork(genome)
  1145.     evaluateCurrent()
  1146. end
  1147.  
  1148. function evaluateCurrent()
  1149.     local species = pool.species[pool.currentSpecies]
  1150.     local genome = species.genomes[pool.currentGenome]
  1151.  
  1152.     inputs = getInputs()
  1153.     controller = evaluateNetwork(genome.network, inputs)
  1154.    
  1155.     if controller["P1 Left"] and controller["P1 Right"] then
  1156.         controller["P1 Left"] = false
  1157.         controller["P1 Right"] = false
  1158.     end
  1159.     if controller["P1 Up"] and controller["P1 Down"] then
  1160.         controller["P1 Up"] = false
  1161.         controller["P1 Down"] = false
  1162.     end
  1163.  
  1164.     joypad.set(controller)
  1165. end
  1166.  
  1167. if pool == nil then
  1168.     initializePool()
  1169. end
  1170.  
  1171.  
  1172. function nextGenome()
  1173.     pool.currentGenome = pool.currentGenome + 1
  1174.     if pool.currentGenome > #pool.species[pool.currentSpecies].genomes then
  1175.         pool.currentGenome = 1
  1176.         pool.currentSpecies = pool.currentSpecies+1
  1177.         if pool.currentSpecies > #pool.species then
  1178.             newGeneration()
  1179.             pool.currentSpecies = 1
  1180.         end
  1181.     end
  1182. end
  1183.  
  1184. function fitnessAlreadyMeasured()
  1185.     local species = pool.species[pool.currentSpecies]
  1186.     local genome = species.genomes[pool.currentGenome]
  1187.    
  1188.     return genome.fitness ~= 0
  1189. end
  1190.  
  1191. function displayGenome(genome)
  1192.     local network = genome.network
  1193.     local cells = {}
  1194.     local i = 1
  1195.     local cell = {}
  1196.     for dy=-BoxRadius,BoxRadius do
  1197.         for dx=-BoxRadius,BoxRadius do
  1198.             cell = {}
  1199.             cell.x = 50+5*dx
  1200.             cell.y = 70+5*dy
  1201.             cell.value = network.neurons[i].value
  1202.             cells[i] = cell
  1203.             i = i + 1
  1204.         end
  1205.     end
  1206.     local biasCell = {}
  1207.     biasCell.x = 80
  1208.     biasCell.y = 110
  1209.     biasCell.value = network.neurons[Inputs].value
  1210.     cells[Inputs] = biasCell
  1211.    
  1212.     for o = 1,Outputs do
  1213.         cell = {}
  1214.         cell.x = 220
  1215.         cell.y = 30 + 8 * o
  1216.         cell.value = network.neurons[MaxNodes + o].value
  1217.         cells[MaxNodes+o] = cell
  1218.         local color
  1219.         if cell.value > 0 then
  1220.             color = 0xFF0000FF
  1221.         else
  1222.             color = 0xFF000000
  1223.         end
  1224.         gui.drawText(223, 24+8*o, ButtonNames[o], color, 9)
  1225.     end
  1226.    
  1227.     for n,neuron in pairs(network.neurons) do
  1228.         cell = {}
  1229.         if n > Inputs and n <= MaxNodes then
  1230.             cell.x = 140
  1231.             cell.y = 40
  1232.             cell.value = neuron.value
  1233.             cells[n] = cell
  1234.         end
  1235.     end
  1236.    
  1237.     for n=1,4 do
  1238.         for _,gene in pairs(genome.genes) do
  1239.             if gene.enabled then
  1240.                 local c1 = cells[gene.into]
  1241.                 local c2 = cells[gene.out]
  1242.                 if gene.into > Inputs and gene.into <= MaxNodes then
  1243.                     c1.x = 0.75*c1.x + 0.25*c2.x
  1244.                     if c1.x >= c2.x then
  1245.                         c1.x = c1.x - 40
  1246.                     end
  1247.                     if c1.x < 90 then
  1248.                         c1.x = 90
  1249.                     end
  1250.                    
  1251.                     if c1.x > 220 then
  1252.                         c1.x = 220
  1253.                     end
  1254.                     c1.y = 0.75*c1.y + 0.25*c2.y
  1255.                    
  1256.                 end
  1257.                 if gene.out > Inputs and gene.out <= MaxNodes then
  1258.                     c2.x = 0.25*c1.x + 0.75*c2.x
  1259.                     if c1.x >= c2.x then
  1260.                         c2.x = c2.x + 40
  1261.                     end
  1262.                     if c2.x < 90 then
  1263.                         c2.x = 90
  1264.                     end
  1265.                     if c2.x > 220 then
  1266.                         c2.x = 220
  1267.                     end
  1268.                     c2.y = 0.25*c1.y + 0.75*c2.y
  1269.                 end
  1270.             end
  1271.         end
  1272.     end
  1273.    
  1274.     gui.drawBox(50-BoxRadius*5-3,70-BoxRadius*5-3,50+BoxRadius*5+2,70+BoxRadius*5+2,0xFF000000, 0x80808080)
  1275.     for n,cell in pairs(cells) do
  1276.         if n > Inputs or cell.value ~= 0 then
  1277.             local color = math.floor((cell.value+1)/2*256)
  1278.             if color > 255 then color = 255 end
  1279.             if color < 0 then color = 0 end
  1280.             local opacity = 0xFF000000
  1281.             if cell.value == 0 then
  1282.                 opacity = 0x50000000
  1283.             end
  1284.             color = opacity + color*0x10000 + color*0x100 + color
  1285.             gui.drawBox(cell.x-2,cell.y-2,cell.x+2,cell.y+2,opacity,color)
  1286.         end
  1287.     end
  1288.     for _,gene in pairs(genome.genes) do
  1289.         if gene.enabled then
  1290.             local c1 = cells[gene.into]
  1291.             local c2 = cells[gene.out]
  1292.             local opacity = 0xA0000000
  1293.             if c1.value == 0 then
  1294.                 opacity = 0x20000000
  1295.             end
  1296.            
  1297.             local color = 0x80-math.floor(math.abs(sigmoid(gene.weight))*0x80)
  1298.             if gene.weight > 0 then
  1299.                 color = opacity + 0x8000 + 0x10000*color
  1300.             else
  1301.                 color = opacity + 0x800000 + 0x100*color
  1302.             end
  1303.             gui.drawLine(c1.x+1, c1.y, c2.x-3, c2.y, color)
  1304.         end
  1305.     end
  1306.    
  1307.     gui.drawBox(49,71,51,78,0x00000000,0x80FF0000)
  1308.    
  1309.     if forms.ischecked(showMutationRates) then
  1310.         local pos = 100
  1311.         for mutation,rate in pairs(genome.mutationRates) do
  1312.             gui.drawText(100, pos, mutation .. ": " .. rate, 0xFF000000, 10)
  1313.             pos = pos + 8
  1314.         end
  1315.     end
  1316. end
  1317.  
  1318. function writeFile(filename)
  1319.         local file = io.open(filename, "w")
  1320.     file:write(pool.generation .. "\n")
  1321.     file:write(pool.maxFitness .. "\n")
  1322.     file:write(#pool.species .. "\n")
  1323.         for n,species in pairs(pool.species) do
  1324.         file:write(species.topFitness .. "\n")
  1325.         file:write(species.staleness .. "\n")
  1326.         file:write(#species.genomes .. "\n")
  1327.         for m,genome in pairs(species.genomes) do
  1328.             file:write(genome.fitness .. "\n")
  1329.             file:write(genome.maxneuron .. "\n")
  1330.             for mutation,rate in pairs(genome.mutationRates) do
  1331.                 file:write(mutation .. "\n")
  1332.                 file:write(rate .. "\n")
  1333.             end
  1334.             file:write("done\n")
  1335.            
  1336.             file:write(#genome.genes .. "\n")
  1337.             for l,gene in pairs(genome.genes) do
  1338.                 file:write(gene.into .. " ")
  1339.                 file:write(gene.out .. " ")
  1340.                 file:write(gene.weight .. " ")
  1341.                 file:write(gene.innovation .. " ")
  1342.                 if(gene.enabled) then
  1343.                     file:write("1\n")
  1344.                 else
  1345.                     file:write("0\n")
  1346.                 end
  1347.             end
  1348.         end
  1349.         end
  1350.         file:close()
  1351. end
  1352.  
  1353. function savePool()
  1354.     local filename = forms.gettext(saveLoadFile)
  1355.     writeFile(filename)
  1356. end
  1357.  
  1358. function loadFile(filename)
  1359.         local file = io.open(filename, "r")
  1360.     pool = newPool()
  1361.     pool.generation = file:read("*number")
  1362.     pool.maxFitness = file:read("*number")
  1363.     forms.settext(maxFitnessLabel, "Max Fitness: " .. math.floor(pool.maxFitness))
  1364.         local numSpecies = file:read("*number")
  1365.         for s=1,numSpecies do
  1366.         local species = newSpecies()
  1367.         table.insert(pool.species, species)
  1368.         species.topFitness = file:read("*number")
  1369.         species.staleness = file:read("*number")
  1370.         local numGenomes = file:read("*number")
  1371.         for g=1,numGenomes do
  1372.             local genome = newGenome()
  1373.             table.insert(species.genomes, genome)
  1374.             genome.fitness = file:read("*number")
  1375.             genome.maxneuron = file:read("*number")
  1376.             local line = file:read("*line")
  1377.             while line ~= "done" do
  1378.                 genome.mutationRates[line] = file:read("*number")
  1379.                 line = file:read("*line")
  1380.             end
  1381.             local numGenes = file:read("*number")
  1382.             for n=1,numGenes do
  1383.                 local gene = newGene()
  1384.                 table.insert(genome.genes, gene)
  1385.                 local enabled
  1386.                 gene.into, gene.out, gene.weight, gene.innovation, enabled = file:read("*number", "*number", "*number", "*number", "*number")
  1387.                 if enabled == 0 then
  1388.                     gene.enabled = false
  1389.                 else
  1390.                     gene.enabled = true
  1391.                 end
  1392.                
  1393.             end
  1394.         end
  1395.     end
  1396.         file:close()
  1397.    
  1398.     while fitnessAlreadyMeasured() do
  1399.         nextGenome()
  1400.     end
  1401.     initializeRun()
  1402.     pool.currentFrame = pool.currentFrame + 1
  1403. end
  1404.  
  1405. function loadPool()
  1406.     local filename = forms.gettext(saveLoadFile)
  1407.     loadFile(filename)
  1408. end
  1409.  
  1410. function playTop()
  1411.     local maxfitness = 0
  1412.     local maxs, maxg
  1413.     for s,species in pairs(pool.species) do
  1414.         for g,genome in pairs(species.genomes) do
  1415.             if genome.fitness > maxfitness then
  1416.                 maxfitness = genome.fitness
  1417.                 maxs = s
  1418.                 maxg = g
  1419.             end
  1420.         end
  1421.     end
  1422.    
  1423.     pool.currentSpecies = maxs
  1424.     pool.currentGenome = maxg
  1425.     pool.maxFitness = maxfitness
  1426.     forms.settext(maxFitnessLabel, "Max Fitness: " .. math.floor(pool.maxFitness))
  1427.     initializeRun()
  1428.     pool.currentFrame = pool.currentFrame + 1
  1429.     return
  1430. end
  1431.  
  1432. function onExit()
  1433.     forms.destroy(form)
  1434. end
  1435.  
  1436. writeFile("temp.pool")
  1437.  
  1438. event.onexit(onExit)
  1439.  
  1440. form = forms.newform(200, 260, "Fitness")
  1441. maxFitnessLabel = forms.label(form, "Max Fitness: " .. math.floor(pool.maxFitness), 5, 8)
  1442. showNetwork = forms.checkbox(form, "Show Map", 5, 30)
  1443. showMutationRates = forms.checkbox(form, "Show M-Rates", 5, 52)
  1444. restartButton = forms.button(form, "Restart", initializePool, 5, 77)
  1445. saveButton = forms.button(form, "Save", savePool, 5, 102)
  1446. loadButton = forms.button(form, "Load", loadPool, 80, 102)
  1447. saveLoadFile = forms.textbox(form, Filename .. ".pool", 170, 25, nil, 5, 148)
  1448. saveLoadLabel = forms.label(form, "Save/Load:", 5, 129)
  1449. playTopButton = forms.button(form, "Play Top", playTop, 5, 170)
  1450. hideBanner = forms.checkbox(form, "Hide Banner", 5, 190)
  1451.  
  1452.  
  1453. while true do
  1454.     local backgroundColor = 0xD0FFFFFF
  1455.     if not forms.ischecked(hideBanner) then
  1456.         gui.drawBox(0, 0, 300, 26, backgroundColor, backgroundColor)
  1457.     end
  1458.  
  1459.     local species = pool.species[pool.currentSpecies]
  1460.     local genome = species.genomes[pool.currentGenome]
  1461.    
  1462.     if forms.ischecked(showNetwork) then
  1463.         displayGenome(genome)
  1464.     end
  1465.    
  1466.     if pool.currentFrame%5 == 0 then
  1467.         evaluateCurrent()
  1468.     end
  1469.  
  1470.     joypad.set(controller)
  1471.  
  1472.     getPositions()
  1473.     if marioX > rightmost then
  1474.         rightmost = marioX
  1475.         timeout = TimeoutConstant
  1476.     end
  1477.    
  1478.     timeout = timeout - 1
  1479.    
  1480.    
  1481.     local timeoutBonus = pool.currentFrame / 4
  1482.     if timeout + timeoutBonus <= 0 then
  1483.         local fitness = rightmost - pool.currentFrame / 2
  1484.         if gameinfo.getromname() == "Super Mario World (USA)" and rightmost > 4816 then
  1485.             fitness = fitness + 1000
  1486.         end
  1487.         if gameinfo.getromname() == "Super Mario Bros." and rightmost > 3186 then
  1488.             fitness = fitness + 1000
  1489.         end
  1490.         if fitness == 0 then
  1491.             fitness = -1
  1492.         end
  1493.         genome.fitness = fitness
  1494.        
  1495.         if fitness > pool.maxFitness then
  1496.             pool.maxFitness = fitness
  1497.             forms.settext(maxFitnessLabel, "Max Fitness: " .. math.floor(pool.maxFitness))
  1498.             writeFile("backup." .. pool.generation .. "." .. forms.gettext(saveLoadFile))
  1499.         end
  1500.        
  1501.         console.writeline("Gen " .. pool.generation .. " species " .. pool.currentSpecies .. " genome " .. pool.currentGenome .. " fitness: " .. fitness)
  1502.         pool.currentSpecies = 1
  1503.         pool.currentGenome = 1
  1504.         while fitnessAlreadyMeasured() do
  1505.             nextGenome()
  1506.         end
  1507.         initializeRun()
  1508.     end
  1509.  
  1510.     local measured = 0
  1511.     local total = 0
  1512.     for _,species in pairs(pool.species) do
  1513.         for _,genome in pairs(species.genomes) do
  1514.             total = total + 1
  1515.             if genome.fitness ~= 0 then
  1516.                 measured = measured + 1
  1517.             end
  1518.         end
  1519.     end
  1520.     if not forms.ischecked(hideBanner) then
  1521.         -- gui.drawText(0, 0, "Gen " .. pool.generation .. " species " .. pool.currentSpecies .. " genome " .. pool.currentGenome .. " (" .. math.floor(measured/total*100) .. "%)", 0xFF000000, 11)
  1522.         gui.drawText(0, 0, "Gen " .. pool.generation .. " species " .. NameDictionary[pool.currentSpecies] .. " #" .. pool.currentGenome .. " (" .. math.floor(measured/total*100) .. "%)", 0xFF000000, 11)
  1523.         gui.drawText(0, 12, "Fitness: " .. math.floor(rightmost - (pool.currentFrame) / 2 - (timeout + timeoutBonus)*2/3), 0xFF000000, 11)
  1524.         gui.drawText(100, 12, "Max Fitness: " .. math.floor(pool.maxFitness), 0xFF000000, 11)
  1525.     end
  1526.        
  1527.     pool.currentFrame = pool.currentFrame + 1
  1528.  
  1529.     emu.frameadvance();
  1530. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement