Advertisement
mroberts

Mario Neural Network

Nov 10th, 2015
12,301
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 27.11 KB | None | 0 0
  1. ----------------------------------------------------------------------------------------------------------------------------------------------------
  2. --Super Mario Bros.
  3. --Neural Network Learning
  4. --by Michael Roberts
  5. --06/2015
  6. --
  7. --Use with FCEUX v2.2.2
  8.  
  9.  
  10. ----------------------------------------------------------------------------------------------------------------------------------------------------
  11. --RAM Addresses for variables
  12. ----------------------------------------------------------------------------------------------------------------------------------------------------
  13.  
  14. saveState = savestate.object(1)
  15. savestate.save(saveState)
  16.  
  17. RamNametableHi = 0x20
  18. RamNametableLow = 0x01
  19. RamNametableSize = 0x2BF
  20. RamNametableSolidStart = 0x01
  21.  
  22. --Screen attributes
  23. RamObjectMapStart = 0x500
  24. MapTileNum = 208
  25.  
  26. --Player attributes
  27. RamPlayerX = 0x86
  28. RamPlayerY = 0x3B8
  29. RamPlayerScreenX = 0x6D
  30. RamLives = 0x75A
  31. RamCoins = 0x75E
  32.  
  33. --Game attributes
  34. RamWorld = 0x75F
  35. RamLevel = 0x760
  36. --Score
  37. RamScoreDigit1 = 0x7D8 --10^5
  38. RamScoreDigit2 = 0x7D9 --10^4
  39. RamScoreDigit3 = 0x7DA --10^3
  40. RamScoreDigit4 = 0x7DB --10^2
  41. RamScoreDigit5 = 0x7DC --10^1
  42.  
  43.  
  44. --Enemy attributes
  45. RamEnemyX = 0x87 --starting address in memory for multiple enemies
  46. RamEnemyY = 0xCF
  47. RamEnemyScreenX = 0x6E
  48. EnemyNumSlots = 5
  49. RamEnemyFlag = 0xF --In Zelda, it's enemy direction used as flag
  50.  
  51. --Projectile attributes
  52. --RamProjectileX = 0x87 --starting address in memory for multiple enemies
  53. --RamProjectileY = 0xCF
  54. --RamProjectileScreenX = 0x6E
  55. --ProjectileNumSlots = 5
  56. --RamProjectileFlag = 0xF --In Zelda, it's enemy direction used as flag
  57.  
  58.  
  59. ------------------------------------------------------------------------------------------------------------------------------------------------------
  60.  
  61. --timer = 40
  62. index = 1
  63. --AReady = true
  64. --BReady = true
  65. vblankFlag = 0
  66. vblankOff = 0
  67. --PPU2002 = {}
  68.  
  69. generation = 1
  70. fitness = 0
  71. maxFitness = 0
  72. startFitness = 0
  73.  
  74. timeStuck = 0
  75. maxStuckTime = 100 --220
  76. lastX = 0
  77. lastY = 0
  78. lastLives = 0
  79. timerHold = 0
  80. lastScreen = 0
  81. screenTimeStuck = 0
  82. maxScreenStuckTime = 350
  83.  
  84. playerX = 0
  85. playerY = 0
  86. playerRoomX = 0
  87. playerRoomY = 0
  88. playerMapX = 0
  89. playerMapY = 0
  90. playerLives = 0
  91.  
  92.  
  93. room = {}
  94. map = {}
  95. for i=1,2*MapTileNum do
  96. map[i] = 0
  97. end
  98.  
  99.  
  100. enemyX = {}
  101. enemyY = {}
  102. enemyRoomX = {}
  103. enemyRoomY = {}
  104. enemyMapX = {}
  105. enemyMapY = {}
  106. enemyDir = {}
  107. projectileX = {}
  108. projectileY = {}
  109. projectileRoomX = {}
  110. projectileRoomY = {}
  111.  
  112.  
  113. drawRoom = false
  114. drawMap = false
  115. drawView = true
  116. drawCoord = false
  117. drawNeurons = true
  118. drawWeights = true
  119. drawController = true
  120. drawPopulation = true
  121.  
  122. viewRadius = 2
  123. viewDiameter = 2*viewRadius+1
  124.  
  125. viewBox = {}
  126. for i=1,viewDiameter*viewDiameter do
  127. viewBox[i] = 0
  128. end
  129.  
  130.  
  131.  
  132. inputNum = viewDiameter*viewDiameter + 1
  133. outputNum = 6 --6 buttons on the controller
  134. layerNum = 2
  135. layerSize = {inputNum, 12, outputNum}
  136. --layerSize array has layerNum+1 entries. (inputNum layer is counted as layer 0)
  137.  
  138. populationSize = 25
  139.  
  140. populationFitness = {}
  141. for i=1, populationSize do
  142. populationFitness[i] = nil
  143. end
  144. currentChild = 1
  145. currentParent1 = 0
  146. currentParent2 = 0
  147. mutationProbability = .05
  148. meanFitness = 0
  149. stdvFitness = 0
  150.  
  151.  
  152. inputViewNum = MapTileNum --this is the number of inputs to X that are from the view or map
  153.  
  154. --inputSigmoidStrength = 4.394/inputNum
  155. --hiddenSigmoidStrength = 4.394/layerSize
  156. outputStepStrength = 0 --layerSize/4
  157. --sigmoid strength = 4ln3/N --4ln3 = 4.394
  158. --where N=number of neurons input into current layer being calculated.
  159.  
  160. --X[1][] = input
  161. --X[layerNum+1][] = output
  162. --Y = output bool
  163. --
  164. --S[l] = W[l]*X[l-1]
  165. --X[l] = f(S[l])
  166. --f is shaping function (tanh)
  167.  
  168. Y = {}
  169. for i=1, outputNum do
  170. Y[i] = false
  171. end
  172.  
  173. X = {}
  174. S = {}
  175. delta = {}
  176. for l=1,layerNum+1 do
  177. X[l] = {}
  178. S[l] = {}
  179. delta[l] = {}
  180. for i=1, layerSize[l] do
  181. X[l][i] = 0
  182. S[l][i] = 0
  183. delta[l][i] = 0
  184. end
  185. end
  186.  
  187.  
  188. W = {}
  189. memW = {}
  190. for p=1, populationSize do
  191. W[p] = {}
  192. for l=1,layerNum do
  193. W[p][l] = {}
  194. memW[l] = {}
  195. for i=1,layerSize[l+1] do
  196. W[p][l][i] = {}
  197. memW[l][i] = {}
  198. for j=1,layerSize[l] do
  199. W[p][l][i][j] = 2*math.random() - 1 --math.random(3)-2
  200. memW[l][i][j] = W[p][l][i][j]
  201. end
  202. end
  203. end
  204. end
  205.  
  206. --Training parameters
  207.  
  208. --trainingMode = 1 -> begin in training mode. 0 is game running mode
  209. geneticMode = true
  210. trainingMode = false
  211.  
  212. recordMode = 1
  213. keyPressReady = true
  214.  
  215. randomChangeSize = .1
  216. stepSize = .1
  217. sampleRate = 10
  218. sampleTimer = 0
  219. controllerInput = {}
  220. errorVal = 0
  221.  
  222. Y_Train = {}
  223. for i=1, outputNum do
  224. Y_Train[i] = 0
  225. end
  226.  
  227.  
  228. --------------------------------------------------------------------------------------------------------------------------------------------
  229. --Functions
  230. --------------------------------------------------------------------------------------------------------------------------------------------
  231.  
  232. function readPPU()
  233. memory.writebyte(0x2006, RamNametableHi)
  234. memory.writebyte(0x2006, RamNametableLow)
  235. j=1
  236. for i=0,RamNametableSize do
  237. local val = memory.readbyte(0x2007)
  238. room[i+1] = val
  239.  
  240. if (math.floor(i/32))%2 == 0 then
  241. if i%2 == 0 then
  242. map[j] = val
  243. j = j+1
  244. end
  245. end
  246.  
  247. --if val <= RamNametableSolidStart then
  248. -- room[i+1] = 0
  249. --else
  250. -- room[i+1] = 1
  251. --end
  252. end
  253. end
  254.  
  255.  
  256.  
  257. function inputView()
  258. for i = -viewRadius, viewRadius do
  259. for j = -viewRadius, viewRadius do
  260. local x = playerMapX+i-1
  261. local y = playerMapY+j-1
  262. local page = math.floor(x/16)
  263. local xAddress = x - 16*page+1
  264. local yAddress = y + 13*(page%2)
  265. if xAddress >= 1 and xAddress < 32 and yAddress >= 1 and yAddress <= 25 then
  266. viewBox[(i+viewRadius+1)+viewDiameter*(j+viewRadius)] = map[xAddress + 16*yAddress]
  267. else
  268. viewBox[(i+viewRadius+1)+viewDiameter*(j+viewRadius)] = 0
  269. end
  270. end
  271. end
  272. end
  273.  
  274.  
  275.  
  276. function inputMap()
  277. for i=1, 2*MapTileNum do
  278. if memory.readbyte(0x500 + i-1) ~= 0 then
  279. map[i] = 1
  280. else
  281. map[i] = 0
  282. end
  283. end
  284.  
  285. for i=1, EnemyNumSlots do
  286. if memory.readbyte(RamEnemyFlag+(i-1)) ~= 0 then
  287. local page = math.floor(enemyMapX[i]/16)
  288. local xAddress = enemyMapX[i] - 16*page
  289. local yAddress = enemyMapY[i] - 1 + 13*(page%2)
  290. if xAddress >= 1 and xAddress < 32 and yAddress >= 1 and yAddress <= 25 then
  291. map[xAddress + 16*yAddress] = -1
  292. end
  293. end
  294. end
  295. end
  296.  
  297.  
  298.  
  299. function inputPlayer()
  300. playerX = memory.readbyte(RamPlayerX) + memory.readbyte(RamPlayerScreenX)*0x100 + 4
  301. playerY = memory.readbyte(RamPlayerY) + 16
  302. playerRoomX = math.floor(playerX/8)+1
  303. playerRoomY = math.floor(playerY/7.5)-7
  304. playerMapX = math.floor((playerX%512)/16)+1
  305. playerMapY = math.floor((playerY-32)/16)+1
  306. end
  307.  
  308.  
  309.  
  310. function inputEnemies()
  311. for i=1,EnemyNumSlots do
  312. if memory.readbyte(RamEnemyFlag+(i-1)) ~= 0 then
  313. enemyX[i] = memory.readbyte(RamEnemyX+(i-1)) + memory.readbyte(RamEnemyScreenX+(i-1))*0x100
  314. enemyY[i] = memory.readbyte(RamEnemyY+(i-1)) + 24
  315. else
  316. enemyX[i] = -1
  317. enemyY[i] = -1
  318. end
  319. enemyRoomX[i] = math.floor(enemyX[i]/8)+1
  320. enemyRoomY[i] = math.floor(enemyY[i]/7.5)-7
  321. enemyMapX[i] = math.floor((enemyX[i]%512)/16)+1
  322. enemyMapY[i] = math.floor((enemyY[i]-32)/16)
  323. end
  324. --for i=1,ProjectileNumSlots do
  325. -- if memory.readbyte(RamProjectileFlag-(i-1)) ~= 0 then
  326. -- projectileX[i] = memory.readbyte(RamProjectileX-(i-1))
  327. -- projectileY[i] = memory.readbyte(RamProjectileY-(i-1))
  328. -- else
  329. -- projectileX[i] = -1
  330. -- projectileY[i] = -1
  331. -- end
  332. -- projectileRoomX[i] = math.floor(projectileX[i]/8)
  333. -- projectileRoomY[i] = math.floor(projectileY[i]/7.5)
  334. --end
  335. end
  336.  
  337.  
  338.  
  339. function inputViewToX(startPosition)
  340. for i=1,(viewDiameter)*(viewDiameter) do
  341. X[1][startPosition-1+i] = viewBox[i]
  342. end
  343. end
  344.  
  345.  
  346.  
  347. function inputMapToX(startPosition)
  348. for i=1,MapTileNum do
  349. if map[i] <= RamNametableSolidStart then
  350. X[1][startPosition-1+i] = 0
  351. else
  352. X[1][startPosition-1+i] = 1
  353. end
  354. end
  355. end
  356.  
  357.  
  358.  
  359. function inputCoordToX(startPosition)
  360. X[1][startPosition] = playerMapX/32
  361. X[1][startPosition+1] = playerMapY/13
  362. --X[1][startPosition+2] = playerHealth
  363. end
  364.  
  365.  
  366.  
  367. function inputEnemyToX(startPosition)
  368. for i=0,EnemyNumSlots-1 do
  369. X[1][startPosition+2*i] = enemyMapX[i+1]/32
  370. X[1][startPosition+2*i+1] = enemyMapY[i+1]/13
  371. end
  372. --for i=0,ProjectileNumSlots-1 do
  373. -- X[1][startPosition+2*i+14] = projectileX[i+1]/256
  374. -- X[1][startPosition+2*i+15] = projectileY[i+1]/240
  375. --end
  376. end
  377.  
  378.  
  379.  
  380. function inputNoise(val)
  381. for i=1,inputNum do
  382. X[1][i] = X[1][i] + val*(2*math.random()-1)
  383. if X[1][i] > 1 then
  384. X[1][i] = 1
  385. end
  386. if X[1][i] < -1 then
  387. X[1][i] = -1
  388. end
  389. end
  390. end
  391.  
  392.  
  393.  
  394. function drawGui()
  395. local mapDrawX = -8
  396. local mapDrawY = 0
  397. local mapScale = 8
  398. local viewDrawX = 56
  399. local viewDrawY = 56
  400. local neuronDrawSpacing = 32
  401. local neuronVerticalSpacing = 4
  402. local controllerDrawX = 176
  403. local controllerDrawY = 48 --200
  404. local drawNeuronsX = 88
  405.  
  406. if drawRoom == true then
  407. for i=0,RamNametableSize do
  408. local x = i%32
  409. local y = math.floor(i/32)
  410. if tunicColor%2 == 0 then
  411. gui.text(x*8, 64+y*8, room[i+1]%16)
  412. else
  413. gui.text(x*8, 64+y*8, math.floor(room[i+1]/16))
  414. end
  415. --if room[i+1] <= 0x77 then
  416. -- gui.box(mapDrawX+x*mapScale, mapDrawY+y*mapScale, mapDrawX+x*mapScale+mapScale, mapDrawY+y*mapScale+mapScale, "black")
  417. --else
  418. -- gui.box(mapDrawX+x*mapScale, mapDrawY+y*mapScale, mapDrawX+x*mapScale+mapScale, mapDrawY+y*mapScale+mapScale, "blue")
  419. --end
  420. end
  421. gui.box(mapDrawX+playerMapX*mapScale, mapDrawY+mapScale*(playerMapY-8), mapDrawX+mapScale*(playerMapX+1.5), mapDrawY+mapScale*(playerMapY-6.5), "green")
  422. for i=1,EnemyNumSlots do
  423. if enemyX[i] ~= -1 then
  424. gui.box(mapDrawX+enemyRoomX[i]*mapScale, mapDrawY+mapScale*(enemyRoomY[i]-8), mapDrawX+mapScale*(enemyRoomX[i]+1.5), mapDrawY+mapScale*(enemyRoomY[i]-6.5), "red")
  425. end
  426. end
  427. --for i=1,ProjectileNumSlots do
  428. -- if projectileX[i] ~= -1 then
  429. -- gui.box(mapDrawX+projectileRoomX[i]*mapScale, mapDrawY+mapScale*(projectileRoomY[i]-8), mapDrawX+mapScale*(projectileRoomX[i]+1), mapDrawY+mapScale*(projectileRoomY[i]-7), "red")
  430. -- end
  431. --end
  432. end
  433.  
  434. if drawMap == true then
  435. --gui.box(0,0,256,240,"black")
  436. for i=0,2*MapTileNum-1 do
  437. local x = 16*math.floor(i/208) + i%16 + 1
  438. local y = math.floor(i/16) - 13*math.floor(i/208) + 1
  439. --local x = i%16 + 1 -- + 16*(i%208)
  440. --local y = math.floor(i/16) + 1 - 13*(i%208)
  441. --gui.text(mapDrawX+x*16, mapDrawY++y*16, map[i+1]%16)
  442.  
  443. if map[i+1] == 0 then
  444. gui.box(mapDrawX+x*mapScale, mapDrawY+y*mapScale, mapDrawX+(x+1)*mapScale-1, mapDrawY+(y+1)*mapScale-1, "black")
  445. elseif map[i+1] == 1 then
  446. gui.box(mapDrawX+x*mapScale, mapDrawY+y*mapScale, mapDrawX+(x+1)*mapScale-1, mapDrawY+(y+1)*mapScale-1, "blue")
  447. elseif map[i+1] == -1 then
  448. gui.box(mapDrawX+x*mapScale, mapDrawY+y*mapScale, mapDrawX+(x+1)*mapScale-1, mapDrawY+(y+1)*mapScale-1, "red")
  449. end
  450. end
  451. gui.box(mapDrawX+playerMapX*mapScale, mapDrawY+mapScale*playerMapY, mapDrawX+mapScale*(playerMapX+1)-1, mapDrawY+mapScale*(playerMapY+1)-1, "green")
  452. gui.box(mapDrawX+(playerMapX-viewRadius)*mapScale, mapDrawY+mapScale*(playerMapY-viewRadius), mapDrawX+(playerMapX+viewRadius+1)*mapScale, mapDrawY+mapScale*(playerMapY+viewRadius+1), "clear", "white")
  453. --Draw enemies on map. Replaced by inputing enemies into map[i] as -1 values
  454. --for i=1,EnemyNumSlots do
  455. -- if enemyX[i] ~= -1 then
  456. -- gui.box(mapDrawX+enemyMapX[i]*mapScale, mapDrawY+mapScale*enemyMapY[i], mapDrawX+mapScale*(enemyMapX[i]+1)-1, mapDrawY+mapScale*(enemyMapY[i]+1)-1, "red")
  457. -- end
  458. --end
  459. --for i=1,4 do
  460. -- if projectileX[i] ~= -1 then
  461. -- gui.box(mapDrawX+projectileRoomX[i]*mapScale, mapDrawY+mapScale*(projectileRoomY[i]-8), mapDrawX+mapScale*(projectileRoomX[i]+1), mapDrawY+mapScale*(projectileRoomY[i]-7), "red")
  462. -- end
  463. --end
  464. end
  465.  
  466. if drawView == true then
  467. for i=1,viewDiameter*viewDiameter do
  468. local x = (i-1)%viewDiameter - viewRadius
  469. local y = math.floor((i-1)/viewDiameter) - viewRadius
  470. if viewBox[i] == 1 then
  471. gui.box(viewDrawX+8*x, viewDrawY+8*y, viewDrawX+8*(x+1)-1, viewDrawY+8*(y+1)-1, "blue")
  472. elseif viewBox[i] == 0 then
  473. gui.box(viewDrawX+8*x, viewDrawY+8*y, viewDrawX+8*(x+1)-1, viewDrawY+8*(y+1)-1, "black")
  474. elseif viewBox[i] == -1 then
  475. gui.box(viewDrawX+8*x, viewDrawY+8*y, viewDrawX+8*(x+1)-1, viewDrawY+8*(y+1)-1, "red")
  476. end
  477. end
  478. gui.box(viewDrawX, viewDrawY, viewDrawX+8-1, viewDrawY+8-1, "green")
  479. end
  480.  
  481. if drawCoord == true then
  482. gui.text(192,8,playerX)
  483. gui.text(224,8,playerY)
  484. gui.text(192,16,playerMapX)
  485. gui.text(224,16,playerMapY)
  486. --gui.text(168,48,playerHealth)
  487. end
  488.  
  489. if drawNeurons == true then
  490. for l=1,layerNum+1 do
  491. local layerDrawSpacing = (neuronVerticalSpacing*inputNum) / layerSize[l]
  492. for i=1, layerSize[l] do
  493. if X[l][i] >= -0.5 and X[l][i] <= 0.5 then
  494. gui.box(drawNeuronsX+neuronDrawSpacing*(l-1), 10+(i-1)*layerDrawSpacing, drawNeuronsX+3+neuronDrawSpacing*(l-1), 10+i*layerDrawSpacing, "gray", "black")
  495. elseif X[l][i] > 0.5 then
  496. gui.box(drawNeuronsX+neuronDrawSpacing*(l-1), 10+(i-1)*layerDrawSpacing, drawNeuronsX+3+neuronDrawSpacing*(l-1), 10+i*layerDrawSpacing, "green", "black")
  497. elseif X[l][i] < -0.5 then
  498. gui.box(drawNeuronsX+neuronDrawSpacing*(l-1), 10+(i-1)*layerDrawSpacing, drawNeuronsX+3+neuronDrawSpacing*(l-1), 10+i*layerDrawSpacing, "red", "black")
  499. end
  500. end
  501. end
  502. end
  503.  
  504. if drawController == true then
  505. gui.box(controllerDrawX-1, controllerDrawY-1, controllerDrawX+64, controllerDrawY+24, "black")
  506. --A
  507. if Y[1] == true then
  508. gui.box(controllerDrawX+56, controllerDrawY+8, controllerDrawX+63, controllerDrawY+15, "blue")
  509. else
  510. gui.box(controllerDrawX+56, controllerDrawY+8, controllerDrawX+63, controllerDrawY+15, "gray")
  511. end
  512. --up
  513. if Y[2] == true then
  514. gui.box(controllerDrawX+8, controllerDrawY, controllerDrawX+15, controllerDrawY+7, "blue")
  515. else
  516. gui.box(controllerDrawX+8, controllerDrawY, controllerDrawX+15, controllerDrawY+7, "gray")
  517. end
  518. --left
  519. if Y[3] == true then
  520. gui.box(controllerDrawX, controllerDrawY+8, controllerDrawX+7, controllerDrawY+15, "blue")
  521. else
  522. gui.box(controllerDrawX, controllerDrawY+8, controllerDrawX+7, controllerDrawY+15, "gray")
  523. end
  524. --B
  525. if Y[4] == true then
  526. gui.box(controllerDrawX+40, controllerDrawY+8, controllerDrawX+47, controllerDrawY+15, "blue")
  527. else
  528. gui.box(controllerDrawX+40, controllerDrawY+8, controllerDrawX+47, controllerDrawY+15, "gray")
  529. end
  530. --right
  531. if Y[5] == true then
  532. gui.box(controllerDrawX+16, controllerDrawY+8, controllerDrawX+23, controllerDrawY+15, "blue")
  533. else
  534. gui.box(controllerDrawX+16, controllerDrawY+8, controllerDrawX+23, controllerDrawY+15, "gray")
  535. end
  536. --down
  537. if Y[6] == true then
  538. gui.box(controllerDrawX+8, controllerDrawY+16, controllerDrawX+15, controllerDrawY+23, "blue")
  539. else
  540. gui.box(controllerDrawX+8, controllerDrawY+16, controllerDrawX+15, controllerDrawY+23, "gray")
  541. end
  542. end
  543.  
  544. if drawWeights == true then
  545. for l=1,layerNum do
  546. local layerInSpacing = (neuronVerticalSpacing*inputNum) / layerSize[l]
  547. local layerOutSpacing = (neuronVerticalSpacing*inputNum) / layerSize[l+1]
  548. for i=1,layerSize[l+1] do
  549. for j=1,layerSize[l] do
  550. if W[currentChild][l][i][j] >= .6 then
  551. gui.line(drawNeuronsX+3+neuronDrawSpacing*(l-1), 10+(j-.5)*layerInSpacing, drawNeuronsX-1+neuronDrawSpacing*l, 10+(i-.5)*layerOutSpacing, {0,0,255,48})
  552. end
  553. if W[currentChild][l][i][j] <= -.6 then
  554. gui.line(drawNeuronsX+3+neuronDrawSpacing*(l-1), 10+(j-.5)*layerInSpacing, drawNeuronsX-1+neuronDrawSpacing*l, 10+(i-.5)*layerOutSpacing, {255,0,0,48})
  555. end
  556. end
  557. end
  558. end
  559. end
  560.  
  561. if drawPopulation == true then
  562. if currentParent1 > 0 then
  563. gui.box(4, 8*currentParent1, 10, 8*(currentParent1+1)-2, "blue")
  564. end
  565. if currentParent2 > 0 then
  566. gui.box(4, 8*currentParent2, 10, 8*(currentParent2+1)-2, "blue")
  567. end
  568. gui.box(4, 8*currentChild, 10, 8*(currentChild+1)-2, "green")
  569. for i=1, populationSize do
  570. if populationFitness[i] ~= nil then
  571. gui.text(12, 8*i, populationFitness[i])
  572. end
  573. end
  574. end
  575. end
  576.  
  577.  
  578.  
  579. function multiply(matrixIn, vectorIn, rows, collumns)
  580. local vectorOut = {}
  581.  
  582. for i=1,rows do
  583. vectorOut[i] = 0
  584. for j=1,collumns do
  585. vectorOut[i] = vectorOut[i] + matrixIn[i][j]*vectorIn[j]
  586. end
  587. end
  588.  
  589. return vectorOut
  590. end
  591.  
  592.  
  593.  
  594. function sigmoid(inputVector, inputLength, strength)
  595. local vectorOut = {}
  596. for i=1,inputLength do
  597. vectorOut[i] = 2/(1+math.exp(-strength*inputVector[i])) - 1
  598. end
  599. return vectorOut
  600. end
  601.  
  602.  
  603.  
  604. function tanh(inputVector, inputLength)
  605. local vectorOut = {}
  606. for i=1,inputLength do
  607. vectorOut[i] = (math.exp(inputVector[i]) - math.exp(-inputVector[i])) / (math.exp(inputVector[i]) + math.exp(-inputVector[i]))
  608. end
  609. return vectorOut
  610. end
  611.  
  612.  
  613.  
  614. function stepFunction(inputVector, inputLength)
  615. local vectorOut = {}
  616. for i=1,inputLength do
  617. if inputVector[i] >= outputStepStrength then
  618. vectorOut[i] = true
  619. else
  620. vectorOut[i] = false
  621. end
  622. end
  623. return vectorOut
  624. end
  625.  
  626.  
  627.  
  628. function forwardPropogate()
  629. X[1][1] = -1
  630. for l=1, layerNum do
  631. S[l+1] = multiply(W[currentChild][l], X[l], layerSize[l+1], layerSize[l])
  632. X[l+1] = tanh(S[l+1], layerSize[l+1])
  633. if l < layerNum then
  634. X[l+1][1] = -1
  635. end
  636. end
  637. Y = stepFunction(X[layerNum+1], outputNum)
  638.  
  639. --make it so up/down etc. can't be hit at same time
  640. doublePressNegate(3,5)
  641. doublePressNegate(2,6)
  642. doublePressNegate(5,6)
  643. doublePressNegate(2,5)
  644. doublePressNegate(3,6)
  645. end
  646.  
  647.  
  648.  
  649. function doublePressNegate(button1, button2)
  650. if Y[button1] == true and Y[button2] == true then
  651. if X[layerNum+1][button1] > X[layerNum+1][button2] then
  652. Y[button2] = false
  653. else
  654. Y[button1] = false
  655. end
  656. end
  657. end
  658.  
  659.  
  660.  
  661. function outputToController()
  662. local controllerInput = {}
  663. controllerInput = {A=Y[1], up=Y[2], left=Y[3], B=Y[4], select=nil, right=Y[5], down=Y[6], start=nil}
  664. joypad.write(1, controllerInput)
  665. end
  666.  
  667.  
  668.  
  669. function controllerOverride()
  670. local controllerInput = {}
  671. controllerInput = joypad.read(1)
  672. Y[1] = controllerInput["A"]
  673. Y[2] = controllerInput["up"]
  674. Y[3] = controllerInput["left"]
  675. Y[4] = controllerInput["B"]
  676. Y[5] = controllerInput["right"]
  677. Y[6] = controllerInput["down"]
  678. end
  679.  
  680.  
  681.  
  682. function updateWeightsFromMem()
  683. for l=1,layerNum do
  684. for i=1,layerSize[l+1] do
  685. for j=1,layerSize[l] do
  686. --if math.random() < stepSize then
  687. -- W[l][i][j] = (memW[l][i][j] + 2)%3 - 1
  688. --else
  689. -- W[l][i][j] = memW[l][i][j]
  690. --end
  691.  
  692. W[currentChild][l][i][j] = memW[l][i][j] + randomChangeSize*(2*math.random() - 1)
  693.  
  694. --if W[i][j][k] > 1 then
  695. -- W[i][j][k] = 1
  696. --end
  697. --if W[i][j][k] < -1 then
  698. -- W[i][j][k] = -1
  699. --end
  700. end
  701. end
  702. end
  703. end
  704.  
  705.  
  706.  
  707. function updateWeightsRandom()
  708. for l=1,layerNum do
  709. for i=1,layerSize[l+1] do
  710. for j=1,layerSize[l] do
  711. W[currentChild][l][i][j] = 2*math.random() - 1 --math.random(3)-2
  712. memW[l][i][j] = W[currentChild][l][i][j]
  713. end
  714. end
  715. end
  716. end
  717.  
  718.  
  719.  
  720. function updateMemWeights()
  721. for l=1,layerNum do
  722. for i=1,layerSize[l+1] do
  723. for j=1,layerSize[l] do
  724. memW[l][i][j] = W[currentChild][l][i][j]
  725. end
  726. end
  727. end
  728. end
  729.  
  730.  
  731.  
  732. function restartOld()
  733. if fitness > maxFitness then
  734. maxFitness = fitness
  735. updateMemWeights()
  736. end
  737.  
  738. updateWeightsFromMem()
  739.  
  740. if fitness <= minFitness then
  741. if maxFitness <= minFitness then
  742. updateWeightsRandom()
  743. end
  744. end
  745.  
  746. generation = generation + 1
  747. fitness = 0
  748. timeStuck = 0
  749.  
  750. savestate.load(saveState)
  751.  
  752. inputPlayer()
  753. inputMap()
  754. inputView()
  755. end
  756.  
  757.  
  758.  
  759. function inputController()
  760. --controllerInput = {A=true, up=false, left=false, B=false, select=nil, right=false, down=false, start=nil}
  761. controllerInput = joypad.read(1)
  762. for i=1, outputNum do
  763. Y_Train[i] = 0
  764. end
  765. if controllerInput["A"] == true then
  766. Y_Train[1] = 1
  767. end
  768. if controllerInput["up"] == true then
  769. Y_Train[2] = 1
  770. end
  771. if controllerInput["left"] == true then
  772. Y_Train[3] = 1
  773. end
  774. if controllerInput["B"] == true then
  775. Y_Train[4] = 1
  776. end
  777. if controllerInput["right"] == true then
  778. Y_Train[5] = 1
  779. end
  780. if controllerInput["down"] == true then
  781. Y_Train[6] = 1
  782. end
  783.  
  784. if controllerInput["select"] == true then
  785. trainingMode = false
  786.  
  787. timeStuck = 0
  788. screenTimeStuck = 0
  789.  
  790. savestate.load(saveState)
  791.  
  792. inputPlayer()
  793. inputEnemies()
  794. inputMap()
  795. inputView()
  796. fitness = playerX
  797. end
  798. if controllerInput["up"] == true and keyPressReady == true then
  799. recordMode = (recordMode+1)%2
  800. keyPressReady = false
  801. end
  802. if controllerInput["up"] == false then
  803. keyPressReady = true
  804. end
  805. end
  806.  
  807.  
  808.  
  809. function backPropogate()
  810. for i=1, outputNum do
  811. delta[layerNum+1][i] = (1-X[layerNum+1][i]*X[layerNum+1][i]) * (X[layerNum+1][i] - Y_Train[i])
  812. end
  813.  
  814. for l=0, layerNum-2 do
  815. for j=1, layerSize[layerNum-l] do
  816. local matrixProduct = 0
  817. for k=1, layerSize[layerNum-l+1] do
  818. matrixProduct = matrixProduct + W[layerNum-l][k][j] * delta[layerNum-l+1][k]
  819. end
  820. delta[layerNum-l][j] = (1 - X[layerNum-l][j]*X[layerNum-l][j]) * matrixProduct
  821. end
  822. end
  823. end
  824.  
  825.  
  826.  
  827. function batchGradientDescent()
  828. for l=1, layerNum do
  829. for i=1, layerSize[l+1] do
  830. for j=1, layerSize[l] do
  831.  
  832. --l = math.random(layerNum)
  833. --i = math.random(layerSize[l+1])
  834. --j = math.random(layerSize[l])
  835. W[currentChild][l][i][j] = W[currentChild][l][i][j] - stepSize * delta[l+1][i] * X[l][j]
  836. end
  837. end
  838. end
  839. end
  840.  
  841.  
  842.  
  843. function restart()
  844. generation = generation + 1/populationSize
  845. if populationFitness[currentChild] == nil then
  846. populationFitness[currentChild] = fitness
  847. elseif fitness > populationFitness[currentChild] then
  848. populationFitness[currentChild] = fitness
  849. end
  850.  
  851.  
  852. if #populationFitness < populationSize then
  853. currentChild = currentChild + 1
  854. else
  855. currentChild = minimum(populationFitness)
  856. if math.random() <= .5 then
  857. currentParent1 = maximum(populationFitness)
  858. if currentParent1 == currentChild then
  859. currentParent1 = math.random(populationSize-1)
  860. if currentParent1 >= currentChild then
  861. currentParent1 = currentParent1+1
  862. end
  863. end
  864. else
  865. currentParent1 = math.random(populationSize-1)
  866. if currentParent1 >= currentChild then
  867. currentParent1 = currentParent1+1
  868. end
  869. end
  870. currentParent2 = math.random(populationSize-2)
  871. if currentParent2 >= currentChild then
  872. currentParent2 = currentParent2+1
  873. end
  874. if currentParent2 >= currentParent1 then
  875. currentParent2 = currentParent2+1
  876. end
  877. if currentParent2 == currentChild then
  878. currentParent2 = currentParent2+1
  879. end
  880.  
  881. meanFitness = mean(populationFitness)
  882. stdvFitness = standardDev(populationFitness)
  883. if stdvFitness <= meanFitness/6 then
  884. uniformCrossover(mutationProbability*2)
  885. else
  886. uniformCrossover(mutationProbability)
  887. end
  888. end
  889.  
  890. timeStuck = 0
  891. screenTimeStuck = 0
  892. savestate.load(saveState)
  893. inputPlayer()
  894. startFitness = playerX
  895. end
  896.  
  897.  
  898.  
  899. function minimum(vectorIn)
  900. local val = vectorIn[1]
  901. local index = 1
  902. for i=1, #vectorIn do
  903. if vectorIn[i] < val then
  904. index = i
  905. val = vectorIn[i]
  906. end
  907. end
  908. return index
  909. end
  910.  
  911.  
  912.  
  913. function maximum(vectorIn)
  914. local val = vectorIn[1]
  915. local index = 1
  916. for i=1, #vectorIn do
  917. if vectorIn[i] > val then
  918. index = i
  919. val = vectorIn[i]
  920. end
  921. end
  922. return index
  923. end
  924.  
  925.  
  926.  
  927. function uniformCrossover(probability)
  928. for l=1, layerNum do
  929. for i=1, layerSize[l+1] do
  930. for j=1, layerSize[l] do
  931. if math.random() < probability then
  932. W[currentChild][l][i][j] = 2*math.random()-1
  933. else
  934. if math.random() <=0.5 then
  935. W[currentChild][l][i][j] = W[currentParent1][l][i][j]
  936. else
  937. W[currentChild][l][i][j] = W[currentParent2][l][i][j]
  938. end
  939. end
  940. end
  941. end
  942. end
  943. end
  944.  
  945.  
  946.  
  947. function mean(arrayIn)
  948. local sum = 0
  949. --if #arrayIn > 0 then
  950. for i=1, #arrayIn do
  951. sum = sum + arrayIn[i]
  952. end
  953. return sum / #arrayIn
  954. --else
  955. -- return 0
  956. --end
  957. end
  958.  
  959.  
  960.  
  961. function standardDev(arrayIn)
  962. local sum = 0
  963. local stdv = 0
  964. local meanVal = mean(arrayIn)
  965. --if #arrayIn > 1 then
  966. for i=1, #arrayIn do
  967. sum = sum + (arrayIn[i] - meanVal) * (arrayIn[i] - meanVal)
  968. end
  969. stdv = math.sqrt(sum / (#arrayIn-1))
  970. return stdv
  971. --else
  972. -- return 0
  973. --end
  974. end
  975.  
  976. ------------------------------------------------------------------------------------------------------------------------------------------------------------
  977. --Main Code
  978. ------------------------------------------------------------------------------------------------------------------------------------------------------------
  979.  
  980.  
  981. inputPlayer()
  982. lastX = playerX
  983. lastY = playerY
  984. lastScreen = memory.readbyte(RamPlayerScreenX)
  985. startFitness = playerX
  986. playerLives = memory.readbyte(RamLives)
  987. lastLives = playerLives
  988.  
  989. while (true) do
  990.  
  991. --read PPU only when changing rooms
  992. --vblankFlag = memory.readbyte(0xE3)
  993. --if vblankFlag == 1 then
  994. -- vblankOff = 1
  995. --elseif vblankOff == 1 then
  996. -- readPPU()
  997. -- vblankOff = 0
  998. --end
  999.  
  1000. inputPlayer()
  1001. inputEnemies()
  1002. inputMap()
  1003. inputView()
  1004.  
  1005.  
  1006.  
  1007. index = 2 --first neuron slot is for constant X[1] = 1
  1008. inputViewToX(index)
  1009. index = index + viewDiameter*viewDiameter
  1010.  
  1011. --inputCoordToX(index)
  1012. --index = index + 2
  1013.  
  1014. --inputEnemyToX(index)
  1015. --index = index + 2*EnemyNumSlots
  1016.  
  1017. --inputNoise(.1)
  1018.  
  1019. forwardPropogate()
  1020.  
  1021. if trainingMode == true then
  1022. inputController()
  1023. if recordMode == 1 then
  1024. sampleTimer = sampleTimer + 1
  1025. if sampleTimer >= sampleRate then
  1026. sampleTimer = 0
  1027. backPropogate()
  1028. batchGradientDescent()
  1029.  
  1030. errorVal = 0
  1031. for i=1, 6 do
  1032. errorVal = errorVal + ((X[layerNum+1][i] - Y_Train[i])*(X[layerNum+1][i] - Y_Train[i]))/2
  1033. end
  1034. end
  1035. gui.text(0,8,errorVal)
  1036. --outputToController()
  1037. end
  1038. else
  1039. outputToController()
  1040. --timeStuck = 0
  1041. --screenTimeStuck = 0
  1042.  
  1043. fitness = playerX - startFitness
  1044.  
  1045. if timerHold == 0 then
  1046. if math.abs(playerX - lastX) < 2 then
  1047. timeStuck = timeStuck + 1
  1048. else
  1049. timeStuck = 0
  1050. end
  1051. if memory.readbyte(RamPlayerScreenX) == lastScreen then
  1052. screenTimeStuck = screenTimeStuck + 1
  1053. else
  1054. screenTimeStuck = 0
  1055. end
  1056. end
  1057.  
  1058. if (timeStuck >= maxStuckTime) or (screenTimeStuck >= maxScreenStuckTime) then
  1059. if geneticMode == true then
  1060. emu.print(fitness)
  1061. restart()
  1062. else
  1063. restartOld()
  1064. end
  1065. end
  1066.  
  1067. playerLives = memory.readbyte(RamLives)
  1068. if lastLives ~= playerLives then
  1069. --timerHold = 200
  1070. --timeStuck = 0
  1071. --screenTimeStuck = 0
  1072. savestate.load(saveState)
  1073. restart()
  1074. end
  1075.  
  1076. if timerHold > 0 then
  1077. timerHold = timerHold - 1
  1078. end
  1079.  
  1080. --Cause seizures if he sits still for too long
  1081. --if timeStuck >= maxStuckTime then
  1082. -- inputNoise(.7)
  1083. --end
  1084. end
  1085.  
  1086. drawGui()
  1087.  
  1088. gui.text(220, 8, math.floor(generation))
  1089. gui.text(48, 8, fitness)
  1090. --gui.text(48, 16, startFitness)
  1091. --gui.text(48, 24, timerHold)
  1092. --gui.text(64, 24, timeStuck)
  1093. --gui.text(48, 16, math.floor(meanFitness))
  1094. --gui.text(48, 24, math.floor(stdvFitness))
  1095.  
  1096.  
  1097. lastX = playerX
  1098. lastY = playerY
  1099. lastScreen = memory.readbyte(RamPlayerScreenX)
  1100. lastLives = playerLives
  1101.  
  1102.  
  1103. emu.frameadvance()
  1104.  
  1105. end
  1106.  
  1107. ------------------------------------------------------------------------------------------------------------------------------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement