Advertisement
SethBling

NeuralEvolve.lua

Mar 14th, 2015
1,515
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.08 KB | None | 0 0
  1. console.clear()
  2.  
  3. filename = "DP1.state"
  4. boxRadius = 6
  5. buttonNames = {
  6. "A",
  7. "B",
  8. "X",
  9. "Y",
  10. "Up",
  11. "Down",
  12. "Left",
  13. "Right",
  14. }
  15.  
  16. layerSizes = {30, 10, 10, 10, #buttonNames}
  17.  
  18.  
  19. function getTile(dx, dy)
  20. marioX = memory.read_s16_le(0x94)
  21. marioY = memory.read_s16_le(0x96)
  22.  
  23. x = math.floor((marioX+dx)/16)
  24. y = math.floor((marioY+dy)/16)
  25.  
  26. return memory.readbyte(0xC800 + math.floor(x/0x10)*0x1B0 + y*0x10 + x%0x10)
  27. end
  28.  
  29. function getSprites()
  30. local sprites = {}
  31. for slot=0,11 do
  32. local status = memory.readbyte(0x14C8+slot)
  33. if status ~= 0 then
  34. spritex = memory.readbyte(0xE4+slot) + memory.readbyte(0x14E0+slot)*256
  35. spritey = memory.readbyte(0xD8+slot) + memory.readbyte(0x14D4+slot)*256
  36. sprites[#sprites+1] = {["x"]=spritex, ["y"]=spritey}
  37. end
  38. end
  39.  
  40. return sprites
  41. end
  42.  
  43. function getExtendedSprites()
  44. local extended = {}
  45. for slot=0,11 do
  46. local number = memory.readbyte(0x170B+slot)
  47. if number ~= 0 then
  48. spritex = memory.readbyte(0x171F+slot) + memory.readbyte(0x1733+slot)*256
  49. spritey = memory.readbyte(0x1715+slot) + memory.readbyte(0x1729+slot)*256
  50. extended[#extended+1] = {["x"]=spritex, ["y"]=spritey}
  51. end
  52. end
  53.  
  54. return extended
  55. end
  56.  
  57. function getInputs()
  58. marioX = memory.read_s16_le(0x94)
  59. marioY = memory.read_s16_le(0x96)
  60.  
  61. sprites = getSprites()
  62. extended = getExtendedSprites()
  63.  
  64. local inputs = {}
  65.  
  66. for dy=-boxRadius*16,boxRadius*16,16 do
  67. for dx=-boxRadius*16,boxRadius*16,16 do
  68. inputs[#inputs+1] = 0
  69.  
  70. tile = getTile(dx, dy)
  71. if tile ~= 0x25 and marioY+dy < 0x1B0 then
  72. inputs[#inputs] = 1
  73. end
  74.  
  75. for i = 1,#sprites do
  76. distx = math.abs(sprites[i]["x"] - (marioX+dx))
  77. disty = math.abs(sprites[i]["y"] - (marioY+dy))
  78. if distx < 8 and disty < 8 then
  79. inputs[#inputs] = -1
  80. end
  81. end
  82.  
  83. for i = 1,#extended do
  84. distx = math.abs(extended[i]["x"] - (marioX+dx))
  85. disty = math.abs(extended[i]["y"] - (marioY+dy))
  86. if distx < 8 and disty < 8 then
  87. inputs[#inputs] = -1
  88. end
  89. end
  90. end
  91. end
  92.  
  93. mariovx = memory.read_s8(0x7B)
  94. mariovy = memory.read_s8(0x7D)
  95. inputs[#inputs+1] = mariovx / 70
  96. inputs[#inputs+1] = mariovy / 70
  97.  
  98. return inputs
  99. end
  100.  
  101.  
  102. function evaluate(inputs, chromosome)
  103. local layer = {}
  104. local prevLayer = inputs
  105. local c = 1
  106. for i=1,#layerSizes do
  107. layer = {}
  108. for n=1,layerSizes[i] do
  109. layer[n] = 0
  110. end
  111. for m=1,#layer do
  112. for n=1,#prevLayer do
  113. layer[m] = layer[m] + chromosome[c] * prevLayer[n]
  114. c = c + 1
  115. end
  116. layer[m] = math.atan(layer[m] + chromosome[c])
  117. c = c + 1
  118. end
  119. prevLayer = layer
  120. end
  121.  
  122. return layer
  123. end
  124.  
  125. function randomChromosome()
  126. local c = {}
  127.  
  128. inputs = getInputs()
  129. prevSize = #inputs
  130. for i=1,#layerSizes do
  131. for m=1,layerSizes[i] do
  132. for n=1,prevSize do
  133. c[#c+1] = math.random()*2-1
  134. end
  135. c[#c+1] = math.random()*2-1
  136. end
  137. prevSize = layerSizes[i]
  138. end
  139.  
  140. return c
  141. end
  142.  
  143. function initializeRun()
  144. savestate.load(filename);
  145. rightmost = 0
  146. frame = 0
  147. timeout = 20
  148. end
  149.  
  150. function crossover(c1, c2)
  151. local c = {["chromosome"] = {}, ["fitness"] = 0}
  152. local pick = true
  153. for i=1,#c1["chromosome"] do
  154. if math.random(#c1["chromosome"]/4) == 1 then
  155. pick = not pick
  156. end
  157. if pick then
  158. c["chromosome"][i] = c1["chromosome"][i]
  159. else
  160. c["chromosome"][i] = c2["chromosome"][i]
  161. end
  162. end
  163.  
  164. return c
  165. end
  166.  
  167. function mutate(c)
  168. for i=1,#c["chromosome"] do
  169. if math.random(50) == 1 then
  170. c["chromosome"][i] = math.random()*2-1
  171. end
  172. end
  173. end
  174.  
  175. function createNewGeneration()
  176. table.sort(pool, function (a,b)
  177. return (a["fitness"] > b["fitness"])
  178. end)
  179.  
  180.  
  181. for i=((#pool)/2),(#pool) do
  182. c1 = pool[math.random(#pool/2)]
  183. c2 = pool[math.random(#pool/2)]
  184. pool[i] = crossover(c1, c2)
  185. mutate(pool[i])
  186. end
  187.  
  188. generation = generation + 1
  189. end
  190.  
  191. function clearJoypad()
  192. local controller = {}
  193. for b = 1,#buttonNames do
  194. controller["P1 " .. buttonNames[b]] = false
  195. end
  196. joypad.set(controller)
  197. end
  198.  
  199. function showTop()
  200. clearJoypad()
  201. currentChromosome = 1
  202. initializeRun()
  203. end
  204.  
  205. form = forms.newform(200, 164, "Fitness")
  206. maxFitnessLabel = forms.label(form, "Top Fitness: ", 5, 8)
  207. goButton = forms.button(form, "Show Top", showTop, 5, 30)
  208. showUI = forms.checkbox(form, "Show Inputs", 5, 52)
  209. inputsLabel = forms.label(form, "Inputs", 5, 74)
  210. showChromosomes = forms.checkbox(form, "Show Chromosomes", 5, 96)
  211.  
  212. function onExit()
  213. forms.destroy(form)
  214. end
  215. event.onexit(onExit)
  216.  
  217. function connectionCost(chromosome)
  218. local total = 0
  219. for i=1,#chromosome["chromosome"] do
  220. c = chromosome["chromosome"][i]
  221. total = total + c*c
  222. end
  223.  
  224. return total
  225. end
  226.  
  227. pool = {}
  228. for i=1,20 do
  229. pool[i] = {["chromosome"] = randomChromosome(), ["fitness"] = 0}
  230. end
  231. currentChromosome = 1
  232. generation = 0
  233. maxfitness = 0
  234. initializeRun()
  235.  
  236. while true do
  237. marioX = memory.read_s16_le(0x94)
  238. marioY = memory.read_s16_le(0x96)
  239.  
  240. timeoutBonus = frame / 4
  241. if timeout + timeoutBonus <= 0 then
  242. fitness = rightmost - frame / 10 - connectionCost(pool[currentChromosome])/10
  243. pool[currentChromosome]["fitness"] = fitness
  244.  
  245. if fitness > maxfitness then
  246. forms.settext(maxFitnessLabel, "Top Fitness: " .. math.floor(fitness))
  247. maxfitness = fitness
  248. end
  249.  
  250. console.writeline("Generation " .. generation .. " chromosome " .. currentChromosome .. " fitness: " .. math.floor(fitness))
  251. if currentChromosome == #pool then
  252. createNewGeneration()
  253. currentChromosome = #pool/2+1
  254. else
  255. currentChromosome = currentChromosome + 1
  256. end
  257. initializeRun()
  258. end
  259.  
  260. inputs = getInputs()
  261. if timeout + timeoutBonus > 2 and frame % 5 == 0 then
  262. outputs = evaluate(inputs, pool[currentChromosome]["chromosome"])
  263.  
  264. controller = {}
  265. inputsString = ""
  266. for n = 1,#buttonNames do
  267. if outputs[n] > 0 then
  268. controller["P1 " .. buttonNames[n]] = true
  269. inputsString = inputsString .. buttonNames[n]
  270. else
  271. controller["P1 " .. buttonNames[n]] = false
  272. end
  273. end
  274.  
  275. forms.settext(inputsLabel, inputsString)
  276. end
  277. joypad.set(controller)
  278.  
  279. if timeout + timeoutBonus <= 2 then
  280. clearJoypad()
  281. end
  282.  
  283. if marioX > rightmost then
  284. timeout = 20
  285. rightmost = marioX
  286. end
  287.  
  288. timeout = timeout - 1
  289. frame = frame + 1
  290.  
  291.  
  292. if forms.ischecked(showUI) then
  293. layer1x = memory.read_s16_le(0x1A);
  294. layer1y = memory.read_s16_le(0x1C);
  295.  
  296. for dy = 0,boxRadius*2 do
  297. for dx = 0,boxRadius*2 do
  298. input = inputs[dy*(boxRadius*2+1)+dx+1]
  299. gui.drawText(marioX+(dx-boxRadius)*16-layer1x,marioY+(dy-boxRadius)*16-layer1y,string.format("%i", input),0x80FFFFFF, 11)
  300. end
  301. end
  302. end
  303.  
  304. if forms.ischecked(showChromosomes) then
  305. gui.drawBox(0, 3, 201, 3+#pool*3, 0xFFFFFFFF, 0xFFFFFFFF)
  306. for c=1,#pool do
  307. local y = 1+c*3
  308. local size = #pool[c]["chromosome"]
  309. for n=1,size do
  310. if n%math.floor(size/200) == 0 then
  311. local x = 1+n*200/#pool[c]["chromosome"]
  312. v = pool[c]["chromosome"][n]
  313. r = (1-v)/2
  314. g = (v-1)/2
  315. gui.drawLine(x, y, x, y+1, 0xFF000000 + math.floor(r*0xFF)*0x10000 + math.floor(g*0xFF)*0x100)
  316. end
  317. end
  318. end
  319. end
  320.  
  321. emu.frameadvance();
  322. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement