diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1f93855 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.pool +*.state +*.bak diff --git a/README.md b/README.md index 5c35733..2d40b3e 100644 --- a/README.md +++ b/README.md @@ -14,12 +14,19 @@ Moved the neat graphics to the form window instead of as a gui overlay. I liked Did some miscellaneous house-keeping, like moving global config settings into their own file, etc. -Instructions +## Instructions +1. Install [BizHawk](https://github.com/TASVideos/BizHawk) prerequesites & emulator: + 1. [BizHawk prerequesites (currently 2.1)](https://github.com/TASVideos/BizHawk-Prereqs/releases) + 2. [BizHawk (currently 2.2.2)](https://github.com/TASVideos/BizHawk/releases) +2. Get the rom of [Super Mario World (USA)](https://www.google.de/search?q=Super+Mario+World+(USA).sfc). (Other Super Mario World roms might work too but are not tested) -You will need the bizhawk emulator located here: http://tasvideos.org/BizHawk.html - -And you will need the super mario world .rom file. (Easy to find online) - -Place the neat-mario folder in your \BizHawk-2.2\Lua\SNES\ folder, like BizHawk-2.2\Lua\SNES\neat-mario. - -Open bizhawk, click open rom, find super mario world .rom file. Once loaded, click Tools > Lua Console. In the new window, click script > open script. Select mario-net.lua in your \BizHawk-2.2\Lua\SNES\neat-mario folder. The neat control window will display and you can then click Start to begin training. +CRC | MD5 | SHA1 +------------- | ------------- | ------------- +B19ED489 | CDD3C8C37322978CA8669B34BC89C804 | 6B47BB75D16514B6A476AA0C73A683A2A4C18765 +3. Clone the repository or download the zip file and place the neat-mario folder in your \BizHawk-2.2\Lua\SNES\ folder. (like: BizHawk-2.2\Lua\SNES\neat-mario) +4. Open config.lua and change variable _M.BizhawkDir to point on your BizHawk directory. +5. Open BizHawk (EmuHawk.exe) +6. Click File > Open ROM (Ctrl + O) and find Super Mario World (USA).sfc file. +7. Once loaded, click Tools > Lua Console +8. In the new window, click Script > Open Script (Ctrl + O) and select mario-neat.lua in your \BizHawk-2.2\Lua\SNES\neat-mario folder. +9. The NEAT control window will display and you can then click Start to begin training. \ No newline at end of file diff --git a/neat-mario/config.lua b/neat-mario/config.lua index 011199f..6d727c6 100644 --- a/neat-mario/config.lua +++ b/neat-mario/config.lua @@ -1,8 +1,37 @@ local _M = {} +--[[ + Change BizhawkDir to your BizHawk directory. +--]] +--_M.BizhawkDir = "C:/Users/mmill/Downloads/BizHawk-2.2/" +_M.BizhawkDir = "X:/B2_BizHawkLab/BizHawk-2.2.2/" + +_M.StateDir = _M.BizhawkDir .. "Lua/SNES/neat-mario/state/" +_M.PoolDir = _M.BizhawkDir .. "Lua/SNES/neat-mario/pool/" + +--[[ + At the moment the first in list will get loaded. + Rearrange for other savestates. (will be redone soon) +--]] +_M.State = { + "DP1.state", -- Donut Plains 1 + "YI1.state", -- Yoshi's Island 1 + "YI2.state", -- Yoshi's Island 2 +} + +--[[ + Start game with specific powerup. + 0 = No powerup + 1 = Mushroom + 2 = Feather + 3 = Flower + Comment out to disable. +--]] +_M.StartPowerup = 0 + _M.NeatConfig = { --Filename = "DP1.state", -Filename = "C:/Users/mmill/Downloads/BizHawk-2.2/Lua/SNES/neat-mario/pool/DP1.state", +Filename = _M.PoolDir .. _M.State[1], Population = 300, DeltaDisjoint = 2.0, DeltaWeights = 0.4, diff --git a/neat-mario/game.lua b/neat-mario/game.lua index e7e37c8..78ef8a3 100644 --- a/neat-mario/game.lua +++ b/neat-mario/game.lua @@ -1,5 +1,6 @@ --Notes here config = require "config" +spritelist = require "spritelist" local _M = {} function _M.getPositions() @@ -25,6 +26,25 @@ function _M.getScore() return score end +function _M.getLives() + local lives = memory.readbyte(0x0DBE) + 1 + return lives +end + +function _M.writeLives(lives) + memory.writebyte(0x0DBE, lives - 1) +end + +function _M.getPowerup() + local powerup = memory.readbyte(0x0019) + return powerup +end + +function _M.writePowerup(powerup) + memory.writebyte(0x0019, powerup) +end + + function _M.getMarioHit(alreadyHit) local timer = memory.readbyte(0x1497) if timer > 0 then @@ -57,7 +77,7 @@ function _M.getSprites() if status ~= 0 then spritex = memory.readbyte(0xE4+slot) + memory.readbyte(0x14E0+slot)*256 spritey = memory.readbyte(0xD8+slot) + memory.readbyte(0x14D4+slot)*256 - sprites[#sprites+1] = {["x"]=spritex, ["y"]=spritey} + sprites[#sprites+1] = {["x"]=spritex, ["y"]=spritey, ["good"] = spritelist.Sprites[memory.readbyte(0x009e + slot) + 1]} end end @@ -71,7 +91,7 @@ function _M.getExtendedSprites() if number ~= 0 then spritex = memory.readbyte(0x171F+slot) + memory.readbyte(0x1733+slot)*256 spritey = memory.readbyte(0x1715+slot) + memory.readbyte(0x1729+slot)*256 - extended[#extended+1] = {["x"]=spritex, ["y"]=spritey} + extended[#extended+1] = {["x"]=spritex, ["y"]=spritey, ["good"] = spritelist.extSprites[memory.readbyte(0x170B + slot) + 1]} end end @@ -105,7 +125,7 @@ function _M.getInputs() distx = math.abs(sprites[i]["x"] - (marioX+dx)) disty = math.abs(sprites[i]["y"] - (marioY+dy)) if distx <= 8 and disty <= 8 then - inputs[#inputs] = -1 + inputs[#inputs] = sprites[i]["good"] local dist = math.sqrt((distx * distx) + (disty * disty)) if dist > 8 then @@ -121,7 +141,7 @@ function _M.getInputs() if distx < 8 and disty < 8 then --console.writeline(screenX .. "," .. screenY .. " to " .. extended[i]["x"]-layer1x .. "," .. extended[i]["y"]-layer1y) - inputs[#inputs] = -1 + inputs[#inputs] = extended[i]["good"] local dist = math.sqrt((distx * distx) + (disty * disty)) if dist > 8 then inputDeltaDistance[#inputDeltaDistance] = mathFunctions.squashDistance(dist) @@ -149,4 +169,4 @@ function _M.clearJoypad() joypad.set(controller) end -return _M +return _M \ No newline at end of file diff --git a/neat-mario/mario-neat.lua b/neat-mario/mario-neat.lua index bfe579c..451511f 100644 --- a/neat-mario/mario-neat.lua +++ b/neat-mario/mario-neat.lua @@ -1,6 +1,7 @@ --Update to Seth-Bling's MarI/O app config = require "config" +spritelist = require "spritelist" game = require "game" mathFunctions = require "mathFunctions" @@ -640,15 +641,20 @@ end function initializeRun() savestate.load(config.NeatConfig.Filename); + if config.StartPowerup ~= NIL then + game.writePowerup(config.StartPowerup) + end rightmost = 0 pool.currentFrame = 0 timeout = config.NeatConfig.TimeoutConstant game.clearJoypad() startCoins = game.getCoins() startScore = game.getScore() + startLives = game.getLives() checkMarioCollision = true marioHitCounter = 0 - + powerUpCounter = 0 + powerUpBefore = game.getPowerup() local species = pool.species[pool.currentSpecies] local genome = species.genomes[pool.currentGenome] generateNetwork(genome) @@ -969,7 +975,7 @@ function flipState() end function loadPool() - filename = forms.openfile("DP1.state.pool","C:/Users/mmill/Downloads/BizHawk-2.2/Lua/SNES/neat-mario/pool/") + filename = forms.openfile("DP1.state.pool",config.PoolDir) --local filename = forms.gettext(saveLoadFile) forms.settext(saveLoadFile, filename) loadFile(filename) @@ -1001,7 +1007,7 @@ function onExit() forms.destroy(form) end -writeFile("C:/Users/mmill/Downloads/BizHawk-2.2/Lua/SNES/neat-mario/pool/temp.pool") +writeFile(config.PoolDir.."temp.pool") event.onexit(onExit) @@ -1014,8 +1020,10 @@ FitnessLabel = forms.label(form, "Fitness: " .. "", 5, 30) MaxLabel = forms.label(form, "Max: " .. "", 130, 30) CoinsLabel = forms.label(form, "Coins: " .. "", 5, 65) -ScoreLabel = forms.label(form, "Score: " .. "", 130, 65) -DmgLabel = forms.label(form, "Damage: " .. "", 230, 65) +ScoreLabel = forms.label(form, "Score: " .. "", 130, 65, 90, 14) +LivesLabel = forms.label(form, "Lives: " .. "", 130, 80, 90, 14) +DmgLabel = forms.label(form, "Damage: " .. "", 230, 65, 110, 14) +PowerUpLabel = forms.label(form, "PowerUp: " .. "", 230, 80, 110, 14) startButton = forms.button(form, "Start", flipState, 155, 102) @@ -1026,7 +1034,8 @@ playTopButton = forms.button(form, "Play Top", playTop, 230, 102) saveLoadFile = forms.textbox(form, config.NeatConfig.Filename .. ".pool", 170, 25, nil, 5, 148) saveLoadLabel = forms.label(form, "Save/Load:", 5, 129) - +spritelist.InitSpriteList() +spritelist.InitExtSpriteList() while true do if config.Running == true then @@ -1062,6 +1071,16 @@ while true do checkMarioCollision = true end + powerUp = game.getPowerup() + if powerUp > 0 then + if powerUp ~= powerUpBefore then + powerUpCounter = powerUpCounter+1 + powerUpBefore = powerUp + end + end + + Lives = game.getLives() + timeout = timeout - 1 local timeoutBonus = pool.currentFrame / 4 @@ -1078,8 +1097,16 @@ while true do end local hitPenalty = marioHitCounter * 100 - - local fitness = coinScoreFitness - hitPenalty + rightmost - pool.currentFrame / 2 + local powerUpBonus = powerUpCounter * 100 + + local fitness = coinScoreFitness - hitPenalty + powerUpBonus + rightmost - pool.currentFrame / 2 + + if startLives < Lives then + local ExtraLiveBonus = (Lives - startLives)*1000 + fitness = fitness + ExtraLiveBonus + console.writeline("ExtraLiveBonus added " .. ExtraLiveBonus) + end + if rightmost > 4816 then fitness = fitness + 1000 console.writeline("!!!!!!Beat level!!!!!!!") @@ -1124,7 +1151,9 @@ while true do forms.settext(MeasuredLabel, "Measured: " .. math.floor(measured/total*100) .. "%") forms.settext(CoinsLabel, "Coins: " .. (game.getCoins() - startCoins)) forms.settext(ScoreLabel, "Score: " .. (game.getScore() - startScore)) + forms.settext(LivesLabel, "Lives: " .. Lives) forms.settext(DmgLabel, "Damage: " .. marioHitCounter) + forms.settext(PowerUpLabel, "PowerUp: " .. powerUpCounter) pool.currentFrame = pool.currentFrame + 1 diff --git a/neat-mario/spritelist.lua b/neat-mario/spritelist.lua new file mode 100644 index 0000000..1094bfb --- /dev/null +++ b/neat-mario/spritelist.lua @@ -0,0 +1,276 @@ +-- Idea from: https://github.com/kevino5233/MarIO_Enhanced/ +-- Spritelist from: https://www.smwcentral.net/?p=viewthread&t=7562 +-- Extended spritelist: https://web.archive.org/web/20170709102356/www.smwiki.net/wiki/RAM_Address/$7E:170B +-- + +local _M = {} + +_M.Sprites = {} + +-- Make sure this list is sorted before initialization. +_M.NeutralSprites = { + 0x0E, -- Keyhole. + 0x2C, -- Yoshi egg Red/Blue/Yellow/Blue (X&3). + 0x2D, -- Baby green Yoshi. + 0x2F, -- Portable spring board. + 0x35, -- Green Yoshi. + 0x3E, -- POW, blue/silver (X&1). + 0x41, -- Dolphin, horizontal. + 0x42, -- Dolphin2, horizontal. + 0x43, -- Dolphin, vertical. + 0x49, -- Growing/shrinking pipe end. + 0x4A, -- Goal Point Question Sphere. + 0x52, -- Moving ledge hole in ghost house. + 0x53, -- ??? + 0x54, -- Climbing net door, use with object 0x4A-E. + 0x55, -- Checkerboard platform, horizontal. + 0x56, -- Flying rock platform, horizontal. + 0x57, -- Checkerboard platform, vertical. + 0x58, -- Flying rock platform, vertical. + 0x59, -- Turn block bridge, horizontal and vertical. + 0x5A, -- Turn block bridge, horizontal. + 0x5B, -- Brown platform floating in water. + 0x5C, -- Checkerboard platform that falls. + 0x5D, -- Orange platform floating in water. + 0x5E, -- Orange platform, goes on forever. + 0x5F, -- Brown platform on a chain. + 0x60, -- Flat green switch palace switch. + 0x61, -- Floating skulls. + 0x62, -- Brown platform, line-guided. + 0x63, -- Checker/brown platform, line-guided (X&1). + 0x64, -- Rope mechanism, line-guided (X&1). + 0x6A, -- Coin game cloud. + 0x6B, -- Spring board, left wall. + 0x6C, -- Spring board, right wall. + 0x6D, -- Invisible solid block. + 0x79, -- Growing Vine. + 0x7C, -- ??? + 0x80, -- Key. + 0x81, -- Changing item from a translucent block. + 0x87, -- Lakitu's cloud, no time limit. (!) + 0x8A, -- Bird from Yoshi's house, max of 4. + 0x8B, -- Puff of smoke from Yoshi's house. + 0xA3, -- Grey platform on chain, clockwise/counter (X&1). + 0xBA, -- Timed lift, 4 sec/1 sec (X&1). + 0xC0, -- Grey platform on lava, sinks. + 0xC4, -- Grey platform that falls. + 0xC8, -- Light switch block for dark room. + 0xC9, -- ??? + 0xDA, -- Green Koopa shell. + 0xDB, -- Red Koopa shell. + 0xDC, -- Blue Koopa shell. + 0xDD, -- Yellow Koopa shell. + 0xDF, -- Green shell, won't use Special World color. + 0xE0 -- 3 platforms on chains, clockwise/counter (X&1). + } + +-- Make sure this list is sorted before initialization. +_M.GoodSprites = { + 0x21, -- Moving coin. + 0x45, -- Directional coins, no time limit. + 0x74, -- Mushroom. + 0x75, -- Flower. + 0x76, -- Star. + 0x77, -- Feather. + 0x78, -- 1-UP. + 0x7B, -- Standard Goal Point. + -- "Secret" Goal Point. + 0x83, -- Left flying question block, coin/flower/feather/1-UP (X&3). + 0x84, -- Flying question block, coin/flower/feather/1-UP (X&3). + 0xC1, -- Flying grey turnblocks, first up/down (X&1). + 0xC7 -- Invisible mushroom. + } + +-- Currently not used. +_M.BadSprites = { + 0x00, -- Green Koopa, no shell. + 0x01, -- Red Koopa, no shell. + 0x02, -- Blue Koopa, no shell. + 0x03, -- Yellow Koopa, no shell. + 0x04, -- Green Koopa. + 0x05, -- Red Koopa. + 0x06, -- Blue Koopa. + 0x07, -- Yellow Koopa. + 0x08, -- Green Koopa, flying left. + 0x09, -- Green bouncing Koopa (Y&1). + 0x0A, -- Red vertical flying Koopa. + 0x0B, -- Red horizontal flying Koopa. + 0x0C, -- Yellow Koopa with wings. + 0x0F, -- Goomba. + 0x10, -- Bouncing Goomba with wings. + 0x1A, -- Classic Pirhana Plant (use ExGFX). + 0x1C, -- Bullet Bill. + 0x4F, -- Jumping Pirhana Plant. + 0x50, -- Jumping Pirhana Plant, spit fire. + 0x7E, -- Flying Red coin, worth 5 coins. + 0x7F, -- Flying Yellow 1-UP. + 0xB1, -- Creating/Eating block (X&1). + 0xB9, -- Info Box, message 1/2 (X&1). + 0xBD, -- Sliding Koopa without a shell. + 0x0D, -- Bob-omb. + 0x11, -- Buzzy Beetle. + 0x13, -- Spiny. + 0x14, -- Spiny falling. + 0x15, -- Fish, horizontal. + 0x16, -- Fish, vertical. + 0x18, -- Surface jumping fish. + 0x1B, -- Bouncing football in place. + 0x1D, -- Hopping flame. + 0x1E, -- Lakitu Normal/Fish (X&1). + 0x1F, -- Magikoopa. + 0x20, -- Magikoopa's magic, stationary. + 0x22, -- Green vertical net Koopa, below/above (X&1). + 0x23, -- Red fast vertical net Koopa, below/above (X&1). + 0x24, -- Green horizontal net Koopa, below/above (X&1). + 0x25, -- Red fast horizontal net Koopa, below/above (X&1). + 0x26, -- Thwomp. + 0x27, -- Thwimp. + 0x28, -- Big Boo. + 0x29, -- Koopa Kid (place at X=12, Y=0 to 6). + 0x2A, -- Upside down Piranha Plant. + 0x2B, -- Sumo Brother's fire lightning. + 0x2E, -- Spike Top. + 0x30, -- Dry Bones, throws bones. + 0x31, -- Bony Beetle. + 0x32, -- Dry Bones, stay on ledge. + 0x33, -- Fireball, vertical. Requires buoyancy! + 0x34, -- Boss fireball, stationary. + 0x37, -- Boo. + 0x38, -- Eerie. + 0x39, -- Eerie, wave motion. + 0x3A, -- Urchin, fixed vertical/horizontal (X&1). + 0x3B, -- Urchin, wall detect v/h (X&1). + 0x3C, -- Urchin, wall follow clockwise/counter (X&1). + 0x3D, -- Rip Van Fish. + 0x3F, -- Para-Goomba. + 0x40, -- Para-Bomb. + 0x44, -- Torpedo Ted. + 0x47, -- Swimming/Jumping fish, doesn't need water. (!) + 0x48, -- Diggin' Chuck's rock. + 0x46, -- Diggin' Chuck. + 0x4B, -- Pipe dwelling Lakitu. + 0x4C, -- Exploding Block, fish/goomba/Koopa/Koopa with shell (X&3). + 0x4D, -- Ground dwelling Monty Mole, follow/hop (X&1). + 0x4E, -- Ledge dwelling Monty Mole, follow/hop (X&1). + 0x51, -- Ninji. + 0x65, -- Chainsaw, line-guided, right/left (X&1). + 0x66, -- Upside down chainsaw, line-guided, null/left (X&1). + 0x67, -- Grinder, line-guided, right/left (X&1). + 0x68, -- Fuzz Ball, line-guided, right/left (X&1). + 0x6E, -- Dino Rhino. + 0x6F, -- Dino Torch. + 0x70, -- Pokey. + 0x71, -- Super Koopa, red cape, swoop. + 0x72, -- Super Koopa, yellow cape, swoop. + 0x73, -- Super Koopa, feather/yellow cape (X&1). + 0x7A, -- Firework, makes Mario temporarily invisible. + 0x86, -- Wiggler. + 0x8D, -- Ghost house exit sign and door. + 0x8E, -- Invisible "Warp Hole" blocks. (!) + 0x8F, -- Scale platforms, long/short between (X&1). + 0x90, -- Large green gas bubble. + 0x91, -- Chargin' Chuck. + 0x92, -- Splitin' Chuck. + 0x93, -- Bouncin' Chuck. + 0x94, -- Whistlin' Chuck, fish/Koopa (X&1). + 0x95, -- Clapin' Chuck. + 0x97, -- Puntin' Chuck. + 0x98, -- Pitchin' Chuck. + 0x99, -- Volcano Lotus. + 0x9A, -- Sumo Brother. + 0x9B, -- Hammer Brother (requires sprite 9C). + 0x9C, -- Flying blocks for Hammer Brother. + 0x9D, -- Bubble with Goomba/bomb/fish/mushroom (X&3). + 0x9E, -- Ball and Chain, clockwise/counter (X&1). + 0x9F, -- Banzai Bill. + 0xA2, -- MechaKoopa. + 0xA4, -- Floating Spike ball, slow/fast (X&1). + 0xA5, -- Fuzzball/Sparky, ground-guided, left/right (X&1). + 0xA6, -- HotHead, ground-guided, left/right (X&1). + 0xA8, -- Blargg. + 0xAA, -- Fishbone. + 0xAB, -- Rex. + 0xAC, -- Wooden Spike, moving down and up. + 0xAD, -- Wooden Spike, moving up/down first (X&1). + 0xAE, -- Fishin' Boo. + 0xAF, -- Boo Block. + 0xB0, -- Reflecting stream of Boo Buddies. + 0xB2, -- Falling Spike. + 0xB3, -- Bowser statue fireball. + 0xB4, -- Grinder, non-line-guided. + 0xB6, -- Reflecting fireball. + 0xB7, -- Carrot Top lift, upper right. + 0xB8, -- Carrot Top lift, upper left. + 0xBB, -- Grey moving castle block, horizontal. + 0xBC, -- Bowser statue, normal/fire/leap (X&3). + 0xBE, -- Swooper Bat, hang/fly/fly/fly (X&3). + 0xBF, -- Mega Mole. + 0xC2, -- Blurp fish. + 0xC3, -- A Porcu-Puffer fish. + 0xC5, -- Big Boo Boss. + 0xC6, -- Dark room with spot light. + 0xDE, -- Group of 5 eeries, wave motion. + 0xE2, -- Boo Buddies, counter-clockwise. + 0xE3 -- Boo Buddies, clockwise. + } + +function _M.InitSpriteList() + local k = 1 + local j = 1 + for i=1, 256 do + local isGood = (k <= #_M.GoodSprites) and (_M.GoodSprites[k] == i - 1) + local isNeutral = (j <= #_M.NeutralSprites) and (_M.NeutralSprites[j] == i - 1) + if isGood then + k = k + 1 + _M.Sprites[#_M.Sprites + 1] = 1 + elseif isNeutral then + j = j + 1 + _M.Sprites[#_M.Sprites + 1] = 0 + else + _M.Sprites[#_M.Sprites + 1] = -1 + end + end +end + +_M.extSprites = {} + +-- Make sure this list is sorted before initialization. +_M.ExtNeutralSprites = { + 0x01, -- Puff of smoke with various objects. + 0x03, -- Flame left by hopping flame. + 0x05, -- Player fireball. + 0x0A, -- Coin from coin cloud game. + 0x0F, -- Trail of smoke (yellow Yoshi stomping the ground). + 0x10, -- Spinjump stars. + 0x11, -- Yoshi fireballs. + 0x12 -- Water bubble. +} + +-- Currently not used. +_M.ExtBadSprites = { + 0x02, -- Reznor fireball. + 0x04, -- Hammer. + 0x06, -- Bone from Dry Bones. + 0x07, -- Lava splash. + 0x08, -- Torpedo Ted shooter's arm. + 0x09, -- Unknown flickering object + 0x0B, -- Piranha Plant fireball. + 0x0C, -- Lava Lotus's fiery objects. + 0x0D, -- Baseball. + 0x0E -- Wiggler's flower. +} + +function _M.InitExtSpriteList() + local j = 1 + for i=1, 21 do + local isExtNeutral = (j <= #_M.ExtNeutralSprites) and (_M.ExtNeutralSprites[j] == i - 1) + if isExtNeutral then + j = j + 1 + _M.extSprites[#_M.extSprites + 1] = 0 + else + _M.extSprites[#_M.extSprites + 1] = -1 + end + end +end + +return _M \ No newline at end of file