Advertisement
SethBling

NeuralEvolve.lua

Mar 14th, 2015
3,702
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.81 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 = {100, 20, 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(0x1C800 + 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 == 1 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. local 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. if math.random(10)==1 then
  134. c[#c+1] = math.random()*2-1
  135. else
  136. c[#c+1] = math.random()*0.2-0.1
  137. end
  138. end
  139. c[#c+1] = math.random()*2-1
  140. end
  141. prevSize = layerSizes[i]
  142. end
  143.  
  144. return c
  145. end
  146.  
  147. function initializeRun()
  148. savestate.load(filename);
  149. rightmost = 0
  150. frame = 0
  151. timeout = 20
  152. end
  153.  
  154. function crossover(c1, c2)
  155. local c = {["chromosome"] = {}, ["fitness"] = 0}
  156. local pick = true
  157. for i=1,#c1["chromosome"] do
  158. if math.random(#c1["chromosome"]/2) == 1 then
  159. pick = not pick
  160. end
  161. if pick then
  162. c["chromosome"][i] = c1["chromosome"][i]
  163. else
  164. c["chromosome"][i] = c2["chromosome"][i]
  165. end
  166. end
  167.  
  168. return c
  169. end
  170.  
  171. function mutate(c)
  172. for i=1,#c["chromosome"] do
  173. if math.random(50) == 1 then
  174. c["chromosome"][i] = math.random()*2-1
  175. end
  176. end
  177. end
  178.  
  179. function createNewGeneration()
  180. table.sort(pool, function (a,b)
  181. return (a["fitness"] > b["fitness"])
  182. end)
  183.  
  184.  
  185. for i=((#pool)/2),(#pool) do
  186. c1 = pool[math.random(#pool/2)]
  187. c2 = pool[math.random(#pool/2)]
  188. pool[i] = crossover(c1, c2)
  189. mutate(pool[i])
  190. end
  191.  
  192. generation = generation + 1
  193. end
  194.  
  195. function clearJoypad()
  196. local controller = {}
  197. for b = 1,#buttonNames do
  198. controller["P1 " .. buttonNames[b]] = false
  199. end
  200. joypad.set(controller)
  201. end
  202.  
  203. function showTop()
  204. clearJoypad()
  205. currentChromosome = 1
  206. initializeRun()
  207. end
  208.  
  209. function onExit()
  210. forms.destroy(form)
  211. end
  212. event.onexit(onExit)
  213.  
  214. function connectionCost(chromosome)
  215. local total = 0
  216. for i=1,#chromosome["chromosome"] do
  217. c = chromosome["chromosome"][i]
  218. total = total + c*c
  219. end
  220.  
  221. return total
  222. end
  223.  
  224. function initializeSimulation()
  225. pool = {}
  226. for i=1,20 do
  227. pool[i] = {["chromosome"] = randomChromosome(), ["fitness"] = 0}
  228. end
  229. currentChromosome = 1
  230. generation = 0
  231. maxfitness = 0
  232. initializeRun()
  233. end
  234.  
  235. if pool == nil then
  236. initializeSimulation()
  237. else
  238. forms.settext(maxFitnessLabel, "Top Fitness: " .. math.floor(maxfitness))
  239. end
  240.  
  241. form = forms.newform(200, 164, "Fitness")
  242. maxFitnessLabel = forms.label(form, "Top Fitness: ", 5, 8)
  243. goButton = forms.button(form, "Show Top", showTop, 5, 30)
  244. goButton = forms.button(form, "Restart", initializeSimulation, 80, 30)
  245. showUI = forms.checkbox(form, "Show Inputs", 5, 52)
  246. inputsLabel = forms.label(form, "Inputs", 5, 74)
  247. showChromosomes = forms.checkbox(form, "Show Map", 5, 96)
  248.  
  249. while true do
  250. marioX = memory.read_s16_le(0x94)
  251. marioY = memory.read_s16_le(0x96)
  252.  
  253. timeoutBonus = frame / 4
  254. if timeout + timeoutBonus <= 0 then
  255. fitness = rightmost - frame / 10 - connectionCost(pool[currentChromosome])/10
  256. pool[currentChromosome]["fitness"] = fitness
  257.  
  258. if fitness > maxfitness then
  259. forms.settext(maxFitnessLabel, "Top Fitness: " .. math.floor(fitness))
  260. maxfitness = fitness
  261. end
  262.  
  263. console.writeline("Generation " .. generation .. " chromosome " .. currentChromosome .. " fitness: " .. math.floor(fitness))
  264. if currentChromosome == #pool then
  265. createNewGeneration()
  266. currentChromosome = #pool/2+1
  267. else
  268. currentChromosome = currentChromosome + 1
  269. end
  270. initializeRun()
  271. end
  272.  
  273. if timeout + timeoutBonus > 2 and frame % 5 == 0 then
  274. inputs = getInputs()
  275. outputs = evaluate(inputs, pool[currentChromosome]["chromosome"])
  276.  
  277. controller = {}
  278. inputsString = ""
  279. for n = 1,#buttonNames do
  280. if outputs[n] > 0 then
  281. controller["P1 " .. buttonNames[n]] = true
  282. inputsString = inputsString .. buttonNames[n]
  283. else
  284. controller["P1 " .. buttonNames[n]] = false
  285. end
  286. end
  287.  
  288. forms.settext(inputsLabel, inputsString)
  289. end
  290. joypad.set(controller)
  291.  
  292. if timeout + timeoutBonus <= 2 then
  293. clearJoypad()
  294. end
  295.  
  296. if marioX > rightmost then
  297. timeout = 20
  298. rightmost = marioX
  299. end
  300.  
  301. timeout = timeout - 1
  302. frame = frame + 1
  303.  
  304.  
  305. if forms.ischecked(showUI) and inputs ~= nil then
  306. layer1x = memory.read_s16_le(0x1A);
  307. layer1y = memory.read_s16_le(0x1C);
  308.  
  309. for dy = 0,boxRadius*2 do
  310. for dx = 0,boxRadius*2 do
  311. input = inputs[dy*(boxRadius*2+1)+dx+1]
  312. local x = marioX+(dx-boxRadius)*16-layer1x
  313. local y = marioY+(dy-boxRadius)*16-layer1y
  314. if input == -1 then
  315. gui.drawBox(x, y, x+16, y+16, 0xFFFF0000, 0xA0FF0000)
  316. elseif input == 1 then
  317. gui.drawBox(x, y, x+16, y+16, 0xFF00FF00, 0xA000FF00)
  318. else
  319. gui.drawBox(x, y, x+16, y+16, 0xFFFFFF00, 0xA0FFFF00)
  320. end
  321. --gui.drawText(,,string.format("%i", input),0x80FFFFFF, 11)
  322. end
  323. end
  324.  
  325. local x = marioX-layer1x
  326. local y = marioY-layer1y
  327. gui.drawBox(x, y, x+16, y+32, 0xFF000000)
  328.  
  329. end
  330.  
  331. if forms.ischecked(showChromosomes) then
  332. gui.drawBox(0, 3, 201, 3+#pool*3, 0xFFFFFFFF, 0xFFFFFFFF)
  333. for c=1,#pool do
  334. local y = 1+c*3
  335. local size = #pool[c]["chromosome"]
  336. for n=1,size do
  337. if n%math.floor(size/200) == 0 then
  338. local x = 1+n*200/#pool[c]["chromosome"]
  339. v = pool[c]["chromosome"][n]
  340. r = (1-v)/2
  341. g = (v-1)/2
  342. gui.drawLine(x, y, x, y+1, 0xFF000000 + math.floor(r*0xFF)*0x10000 + math.floor(g*0xFF)*0x100)
  343. end
  344. end
  345. end
  346. end
  347.  
  348. emu.frameadvance();
  349. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement