Algorithm works kind of. It figures out how to go forward
and reset when dying. GUI is messed up. Enemies not yet added to inputs.
This commit is contained in:
parent
210d625e2c
commit
34b4528953
7 changed files with 557 additions and 350 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -3,3 +3,4 @@ catchem/
|
||||||
state/
|
state/
|
||||||
crashsave*
|
crashsave*
|
||||||
*.backup
|
*.backup
|
||||||
|
*.pool
|
||||||
|
|
100
donkutil.lua
100
donkutil.lua
|
@ -248,7 +248,7 @@ Sprite Details:
|
||||||
|
|
||||||
local partyX = memory.readword(PARTY_X)
|
local partyX = memory.readword(PARTY_X)
|
||||||
local partyY = memory.readword(PARTY_Y)
|
local partyY = memory.readword(PARTY_Y)
|
||||||
local partyTileOffset = tile_offset_calculation(partyX, partyY, vertical)
|
local partyTileOffset = tileOffsetCalculation(partyX, partyY, vertical)
|
||||||
|
|
||||||
local stats = string.format([[
|
local stats = string.format([[
|
||||||
%s camera %d,%d
|
%s camera %d,%d
|
||||||
|
@ -310,11 +310,11 @@ Tile offset: %04x
|
||||||
local tileX = math.floor((partyX + x * TILE_SIZE) / TILE_SIZE) * TILE_SIZE
|
local tileX = math.floor((partyX + x * TILE_SIZE) / TILE_SIZE) * TILE_SIZE
|
||||||
local tileY = math.floor((partyY + y * TILE_SIZE) / TILE_SIZE) * TILE_SIZE
|
local tileY = math.floor((partyY + y * TILE_SIZE) / TILE_SIZE) * TILE_SIZE
|
||||||
|
|
||||||
local offset = tile_offset_calculation(tileX, tileY, vertical)
|
local offset = tileOffsetCalculation(tileX, tileY, vertical)
|
||||||
|
|
||||||
local tile = memory.readword(tilePtr + offset)
|
local tile = memory.readword(tilePtr + offset)
|
||||||
|
|
||||||
if not tile_is_solid(tileX, tileY, tile, offset) then
|
if not tileIsSolid(tileX, tileY, tile, offset) then
|
||||||
goto continue
|
goto continue
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -325,7 +325,7 @@ Tile offset: %04x
|
||||||
--goto continue
|
--goto continue
|
||||||
end
|
end
|
||||||
|
|
||||||
gui.text(screenX, screenY, string.format("%04x\n%02x", offset & 0xffff, tile), FG_COLOR, 0x66888800)
|
gui.text(screenX, screenY, string.format("%04x\n%02x", bit.band(offset, 0xffff), tile), FG_COLOR, 0x66888800)
|
||||||
|
|
||||||
::continue::
|
::continue::
|
||||||
end
|
end
|
||||||
|
@ -335,9 +335,9 @@ Tile offset: %04x
|
||||||
local oam = memory2.OAM:readregion(0x00, 0x220)
|
local oam = memory2.OAM:readregion(0x00, 0x220)
|
||||||
|
|
||||||
for idx=0,0x200/4-1,1 do
|
for idx=0,0x200/4-1,1 do
|
||||||
local twoBits = (oam[0x201 + math.floor(idx / 4)] >> ((idx % 4) * 2)) & 0x03
|
local twoBits = bit.band(bit.lrshift(oam[0x201 + math.floor(idx / 4)], ((idx % 4) * 2)), 0x03)
|
||||||
local screenSprite = {
|
local screenSprite = {
|
||||||
x = math.floor(oam[idx * 4 + 1] * ((-1) ^ (twoBits & 0x01))),
|
x = math.floor(oam[idx * 4 + 1] * ((-1) ^ bit.band(twoBits, 0x01))),
|
||||||
y = oam[idx * 4 + 2],
|
y = oam[idx * 4 + 2],
|
||||||
tile = oam[idx * 4 + 3],
|
tile = oam[idx * 4 + 3],
|
||||||
flags = oam[idx * 4 + 4],
|
flags = oam[idx * 4 + 4],
|
||||||
|
@ -359,7 +359,7 @@ Tile offset: %04x
|
||||||
::nextsprite::
|
::nextsprite::
|
||||||
end
|
end
|
||||||
|
|
||||||
if screenSprite.flags & 0x21 ~= 0x00 and screenSprite.tile >= 224 and screenSprite.tile <= 238 then
|
if bit.band(screenSprite.flags, 0x21) ~= 0x00 and screenSprite.tile >= 224 and screenSprite.tile <= 238 then
|
||||||
gui.text(screenSprite.x * 2, screenSprite.y * 2, screenSprite.tile, 0x00000000, 0x00ffff00)
|
gui.text(screenSprite.x * 2, screenSprite.y * 2, screenSprite.tile, 0x00000000, 0x00ffff00)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -376,8 +376,38 @@ Tile offset: %04x
|
||||||
text(guiWidth - 125, 20, "Help [Hold 0]")
|
text(guiWidth - 125, 20, "Help [Hold 0]")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Logic from 0xb5c3e1, 0xb5c414, 0xb5c82c
|
||||||
|
function tileOffsetCalculation (x, y, vertical)
|
||||||
|
local newX = x - 256
|
||||||
|
local newY = y - 256
|
||||||
|
|
||||||
|
if not vertical then
|
||||||
|
if newY < 0 then
|
||||||
|
newY = 0
|
||||||
|
elseif newY >= 0x1ff then
|
||||||
|
newY = 0x1ff
|
||||||
|
end
|
||||||
|
|
||||||
|
newY = bit.band(bit.band(bit.bnot(newY), 0xffff) + 1, 0x1e0)
|
||||||
|
|
||||||
|
newX = bit.band(newX, 0xffe0)
|
||||||
|
|
||||||
|
newY = bit.lrshift(bit.band(bit.bxor(newY, 0x1e0), 0xffff), 4)
|
||||||
|
|
||||||
|
return newY + newX
|
||||||
|
else
|
||||||
|
newY = bit.band(bit.band(bit.bnot(newY), 0xffff) + 1, 0xffe0)
|
||||||
|
|
||||||
|
newX = bit.lrshift(bit.band(newX, 0xffe0), 4)
|
||||||
|
|
||||||
|
newY = bit.band(bit.lshift(bit.band(bit.bxor(newY, 0xffe0), 0xffff), 1), 0xffff)
|
||||||
|
|
||||||
|
return newY + newX
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- 0xb5c94d
|
-- 0xb5c94d
|
||||||
function tile_is_solid(x, y, tileVal, tileOffset)
|
function tileIsSolid(x, y, tileVal, tileOffset)
|
||||||
local origTileVal = tileVal
|
local origTileVal = tileVal
|
||||||
|
|
||||||
if tileVal == 0 or tileOffset == 0 then
|
if tileVal == 0 or tileOffset == 0 then
|
||||||
|
@ -388,13 +418,13 @@ function tile_is_solid(x, y, tileVal, tileOffset)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
local a2 = x & 0x1f
|
local a2 = bit.band(x, 0x1f)
|
||||||
|
|
||||||
if tileVal & 0x4000 ~= 0 then
|
if bit.band(tileVal, 0x4000) ~= 0 then
|
||||||
a2 = (a2 ~ 0x1f) & 0xffff
|
a2 = bit.band(bit.bxor(a2, 0x1f), 0xffff)
|
||||||
end
|
end
|
||||||
|
|
||||||
tileVal = tileVal & 0x3fff
|
tileVal = bit.band(tileVal, 0x3fff)
|
||||||
|
|
||||||
local solidLessThan = memory.readword(SOLID_LESS_THAN)
|
local solidLessThan = memory.readword(SOLID_LESS_THAN)
|
||||||
|
|
||||||
|
@ -402,65 +432,35 @@ function tile_is_solid(x, y, tileVal, tileOffset)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
tileVal = (tileVal << 2) & 0xffff
|
tileVal = bit.band(bit.lshift(tileVal, 2), 0xffff)
|
||||||
|
|
||||||
if a2 & 0x10 ~= 0 then
|
if bit.band(a2, 0x10) ~= 0 then
|
||||||
tileVal = tileVal + 2
|
tileVal = tileVal + 2
|
||||||
end
|
end
|
||||||
|
|
||||||
local tileMeta = memory.readword(memory.readword(0x7e009c) + tileVal)
|
local tileMeta = memory.readword(memory.readword(0x7e009c) + tileVal)
|
||||||
|
|
||||||
if tileMeta & 0x8000 ~=0 then
|
if bit.band(tileMeta, 0x8000) ~=0 then
|
||||||
a2 = (a2 ~ 0x000f) & 0xffff
|
a2 = bit.band(bit.bxor(a2, 0x000f), 0xffff)
|
||||||
end
|
end
|
||||||
|
|
||||||
if tileMeta & tileVal & 0x2000 ~= 0 then
|
if bit.band(tileMeta, tileVal, 0x2000) ~= 0 then
|
||||||
tileMeta = (tileMeta ~ 0x8000) & 0xffff
|
tileMeta = bit.band(bit.bxor(tileMeta, 0x8000), 0xffff)
|
||||||
end
|
end
|
||||||
|
|
||||||
tileMeta = tileMeta & 0x00ff
|
tileMeta = bit.band(tileMeta, 0x00ff)
|
||||||
|
|
||||||
if tileMeta == 0 then
|
if tileMeta == 0 then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
tileMeta = (tileMeta << 1) & 0xffff
|
tileMeta = bit.band(bit.bxor(tileMeta, 1), 0xffff)
|
||||||
|
|
||||||
-- FIXME further tests?
|
-- FIXME further tests?
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Logic from 0xb5c3e1, 0xb5c414, 0xb5c82c
|
|
||||||
function tile_offset_calculation (x, y, vertical)
|
|
||||||
local partyX = x - 256
|
|
||||||
local partyY = y - 256
|
|
||||||
|
|
||||||
if not vertical then
|
|
||||||
if partyY < 0 then
|
|
||||||
partyY = 0
|
|
||||||
elseif partyY >= 0x1ff then
|
|
||||||
partyY = 0x1ff
|
|
||||||
end
|
|
||||||
|
|
||||||
partyY = (((~partyY) & 0xffff) + 1) & 0x1e0
|
|
||||||
|
|
||||||
partyX = partyX & 0xffe0
|
|
||||||
|
|
||||||
partyY = ((partyY ~ 0x1e0) & 0xffff) >> 4
|
|
||||||
|
|
||||||
return partyY + partyX
|
|
||||||
else
|
|
||||||
partyY = (((~partyY) & 0xffff) + 1) & 0xffe0
|
|
||||||
|
|
||||||
partyX = (partyX & 0xffe0) >> 4
|
|
||||||
|
|
||||||
partyY = (((partyY ~ 0xffe0) & 0xffff) << 1) & 0xffff
|
|
||||||
|
|
||||||
return partyY + partyX
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function on_timer()
|
function on_timer()
|
||||||
set_timer_timeout(100 * 1000)
|
set_timer_timeout(100 * 1000)
|
||||||
end
|
end
|
||||||
|
|
149
game.lua
149
game.lua
|
@ -3,15 +3,27 @@ config = require "config"
|
||||||
spritelist = require "spritelist"
|
spritelist = require "spritelist"
|
||||||
local _M = {}
|
local _M = {}
|
||||||
|
|
||||||
|
TILE_SIZE = 32
|
||||||
|
TILE_COLLISION_MATH_POINTER = 0x7e17b2
|
||||||
|
VERTICAL_POINTER = 0xc414
|
||||||
|
TILEDATA_POINTER = 0x7e0098
|
||||||
|
CAMERA_X = 0x7e17ba
|
||||||
|
CAMERA_Y = 0x7e17c0
|
||||||
|
PARTY_X = 0x7e0a2a
|
||||||
|
PARTY_Y = 0x7e0a2c
|
||||||
|
SOLID_LESS_THAN = 0x7e00a0
|
||||||
|
|
||||||
function _M.getPositions()
|
function _M.getPositions()
|
||||||
partyX = memory.readword(0x7e0a2a) - 256
|
tilePtr = memory.readhword(TILEDATA_POINTER)
|
||||||
partyY = memory.readword(0x7e0a2c) - 256
|
vertical = memory.readword(TILE_COLLISION_MATH_POINTER) == VERTICAL_POINTER
|
||||||
|
partyX = memory.readword(PARTY_X)
|
||||||
|
partyY = memory.readword(PARTY_Y)
|
||||||
|
|
||||||
local cameraX = memory.readword(0x7e17ba) - 256
|
local cameraX = memory.readword(CAMERA_X) - 256
|
||||||
local cameraY = memory.readword(0x7e17c0) - 256
|
local cameraY = memory.readword(CAMERA_Y) - 256
|
||||||
|
|
||||||
_M.screenX = (partyX-cameraX)*2
|
_M.screenX = (partyX-256-cameraX)*2
|
||||||
_M.screenY = (partyY-cameraY)*2
|
_M.screenY = (partyY-256-cameraY)*2
|
||||||
end
|
end
|
||||||
|
|
||||||
function _M.getBananas()
|
function _M.getBananas()
|
||||||
|
@ -52,14 +64,104 @@ function _M.getHitTimer()
|
||||||
return memory.readbyte(0x7e08c0) - memory.readbyte(0x7e08be)
|
return memory.readbyte(0x7e08c0) - memory.readbyte(0x7e08be)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Logic from 0xb5c3e1, 0xb5c414, 0xb5c82c
|
||||||
|
function _M.tileOffsetCalculation (x, y, vertical)
|
||||||
|
local newX = x - 256
|
||||||
|
local newY = y - 256
|
||||||
|
|
||||||
|
if not vertical then
|
||||||
|
if newY < 0 then
|
||||||
|
newY = 0
|
||||||
|
elseif newY >= 0x1ff then
|
||||||
|
newY = 0x1ff
|
||||||
|
end
|
||||||
|
|
||||||
|
newY = bit.band(bit.band(bit.bnot(newY), 0xffff) + 1, 0x1e0)
|
||||||
|
|
||||||
|
newX = bit.band(newX, 0xffe0)
|
||||||
|
|
||||||
|
newY = bit.lrshift(bit.band(bit.bxor(newY, 0x1e0), 0xffff), 4)
|
||||||
|
|
||||||
|
return newY + newX
|
||||||
|
else
|
||||||
|
newY = bit.band(bit.band(bit.bnot(newY), 0xffff) + 1, 0xffe0)
|
||||||
|
|
||||||
|
newX = bit.lrshift(bit.band(newX, 0xffe0), 4)
|
||||||
|
|
||||||
|
newY = bit.band(bit.lshift(bit.band(bit.bxor(newY, 0xffe0), 0xffff), 1), 0xffff)
|
||||||
|
|
||||||
|
return newY + newX
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 0xb5c94d
|
||||||
|
function _M.tileIsSolid(x, y, tileVal, tileOffset)
|
||||||
|
local origTileVal = tileVal
|
||||||
|
|
||||||
|
if tileVal == 0 or tileOffset == 0 then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
if questionable_tiles then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local a2 = bit.band(x, 0x1f)
|
||||||
|
|
||||||
|
if bit.band(tileVal, 0x4000) ~= 0 then
|
||||||
|
a2 = bit.band(bit.bxor(a2, 0x1f), 0xffff)
|
||||||
|
end
|
||||||
|
|
||||||
|
tileVal = bit.band(tileVal, 0x3fff)
|
||||||
|
|
||||||
|
local solidLessThan = memory.readword(SOLID_LESS_THAN)
|
||||||
|
|
||||||
|
if tileVal >= solidLessThan then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
tileVal = bit.band(bit.lshift(tileVal, 2), 0xffff)
|
||||||
|
|
||||||
|
if bit.band(a2, 0x10) ~= 0 then
|
||||||
|
tileVal = tileVal + 2
|
||||||
|
end
|
||||||
|
|
||||||
|
local tileMeta = memory.readword(memory.readword(0x7e009c) + tileVal)
|
||||||
|
|
||||||
|
if bit.band(tileMeta, 0x8000) ~=0 then
|
||||||
|
a2 = bit.band(bit.bxor(a2, 0x000f), 0xffff)
|
||||||
|
end
|
||||||
|
|
||||||
|
if bit.band(tileMeta, tileVal, 0x2000) ~= 0 then
|
||||||
|
tileMeta = bit.band(bit.bxor(tileMeta, 0x8000), 0xffff)
|
||||||
|
end
|
||||||
|
|
||||||
|
tileMeta = bit.band(tileMeta, 0x00ff)
|
||||||
|
|
||||||
|
if tileMeta == 0 then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
tileMeta = bit.band(bit.bxor(tileMeta, 1), 0xffff)
|
||||||
|
|
||||||
|
-- FIXME further tests?
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
function _M.getTile(dx, dy)
|
function _M.getTile(dx, dy)
|
||||||
local partyScreenX = (partyX - cameraX) * 2
|
local tileX = math.floor((partyX + dx * TILE_SIZE) / TILE_SIZE) * TILE_SIZE
|
||||||
local partyScreenY = (partyY - cameraY) * 2
|
local tileY = math.floor((partyY + dy * TILE_SIZE) / TILE_SIZE) * TILE_SIZE
|
||||||
|
|
||||||
x = math.floor((partyX+dx+8)/16)
|
local offset = _M.tileOffsetCalculation(tileX, tileY, vertical)
|
||||||
y = math.floor((partyY+dy)/16)
|
|
||||||
|
|
||||||
return memory.readbyte(0x1C800 + math.floor(x/0x10)*0x1B0 + y*0x10 + x%0x10)
|
local tile = memory.readword(tilePtr + offset)
|
||||||
|
|
||||||
|
if not _M.tileIsSolid(tileX, tileY, tile, offset) then
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
return 1
|
||||||
end
|
end
|
||||||
|
|
||||||
function _M.getSprites()
|
function _M.getSprites()
|
||||||
|
@ -93,26 +195,23 @@ end
|
||||||
function _M.getInputs()
|
function _M.getInputs()
|
||||||
_M.getPositions()
|
_M.getPositions()
|
||||||
|
|
||||||
sprites = _M.getSprites()
|
-- sprites = _M.getSprites()
|
||||||
extended = _M.getExtendedSprites()
|
-- extended = _M.getExtendedSprites()
|
||||||
|
|
||||||
local inputs = {}
|
local inputs = {}
|
||||||
local inputDeltaDistance = {}
|
local inputDeltaDistance = {}
|
||||||
|
|
||||||
local layer1x = memory.readword(0x7f0000);
|
for dy = -config.BoxRadius, config.BoxRadius, 1 do
|
||||||
local layer1y = memory.read_s16_le(0x1C);
|
for dx = -config.BoxRadius, config.BoxRadius, 1 do
|
||||||
|
|
||||||
for dy=-config.BoxRadius*16,config.BoxRadius*16,16 do
|
|
||||||
for dx=-config.BoxRadius*16,config.BoxRadius*16,16 do
|
|
||||||
inputs[#inputs+1] = 0
|
inputs[#inputs+1] = 0
|
||||||
inputDeltaDistance[#inputDeltaDistance+1] = 1
|
inputDeltaDistance[#inputDeltaDistance+1] = 1
|
||||||
|
|
||||||
tile = _M.getTile(dx, dy)
|
tile = _M.getTile(dx, dy)
|
||||||
if tile == 1 and partyY+dy < 0x1B0 then
|
if tile == 1 --[[and partyY+dy < 0x1B0]] then
|
||||||
inputs[#inputs] = 1
|
inputs[#inputs] = 1
|
||||||
end
|
end
|
||||||
|
|
||||||
for i = 1,#sprites do
|
--[[ for i = 1,#sprites do
|
||||||
distx = math.abs(sprites[i]["x"] - (partyX+dx))
|
distx = math.abs(sprites[i]["x"] - (partyX+dx))
|
||||||
disty = math.abs(sprites[i]["y"] - (partyY+dy))
|
disty = math.abs(sprites[i]["y"] - (partyY+dy))
|
||||||
if distx <= 8 and disty <= 8 then
|
if distx <= 8 and disty <= 8 then
|
||||||
|
@ -124,14 +223,14 @@ function _M.getInputs()
|
||||||
--gui.drawLine(screenX, screenY, sprites[i]["x"] - layer1x, sprites[i]["y"] - layer1y, 0x50000000)
|
--gui.drawLine(screenX, screenY, sprites[i]["x"] - layer1x, sprites[i]["y"] - layer1y, 0x50000000)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end ]]
|
||||||
|
|
||||||
for i = 1,#extended do
|
--[[ for i = 1,#extended do
|
||||||
distx = math.abs(extended[i]["x"] - (partyX+dx))
|
distx = math.abs(extended[i]["x"] - (partyX+dx))
|
||||||
disty = math.abs(extended[i]["y"] - (partyY+dy))
|
disty = math.abs(extended[i]["y"] - (partyY+dy))
|
||||||
if distx < 8 and disty < 8 then
|
if distx < 8 and disty < 8 then
|
||||||
|
|
||||||
--console.writeline(screenX .. "," .. screenY .. " to " .. extended[i]["x"]-layer1x .. "," .. extended[i]["y"]-layer1y)
|
--print(screenX .. "," .. screenY .. " to " .. extended[i]["x"]-layer1x .. "," .. extended[i]["y"]-layer1y)
|
||||||
inputs[#inputs] = extended[i]["good"]
|
inputs[#inputs] = extended[i]["good"]
|
||||||
local dist = math.sqrt((distx * distx) + (disty * disty))
|
local dist = math.sqrt((distx * distx) + (disty * disty))
|
||||||
if dist > 8 then
|
if dist > 8 then
|
||||||
|
@ -140,12 +239,12 @@ function _M.getInputs()
|
||||||
end
|
end
|
||||||
--if dist > 100 then
|
--if dist > 100 then
|
||||||
--dw = mathFunctions.squashDistance(dist)
|
--dw = mathFunctions.squashDistance(dist)
|
||||||
--console.writeline(dist .. " to " .. dw)
|
--print(dist .. " to " .. dw)
|
||||||
--gui.drawLine(screenX, screenY, extended[i]["x"] - layer1x, extended[i]["y"] - layer1y, 0x50000000)
|
--gui.drawLine(screenX, screenY, extended[i]["x"] - layer1x, extended[i]["y"] - layer1y, 0x50000000)
|
||||||
--end
|
--end
|
||||||
--inputs[#inputs] = {["value"]=-1, ["dw"]=dw}
|
--inputs[#inputs] = {["value"]=-1, ["dw"]=dw}
|
||||||
end
|
end
|
||||||
end
|
end ]]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
581
neat-donk.lua
581
neat-donk.lua
|
@ -6,6 +6,40 @@ game = require "game"
|
||||||
mathFunctions = require "mathFunctions"
|
mathFunctions = require "mathFunctions"
|
||||||
util = require "util"
|
util = require "util"
|
||||||
|
|
||||||
|
guiWidth, guiHeight = gui.resolution()
|
||||||
|
form = gui.renderctx.new(500, 500)
|
||||||
|
netPicture = gui.renderctx.new(470, 200)
|
||||||
|
runInitialized = {}
|
||||||
|
frameAdvanced = {}
|
||||||
|
|
||||||
|
--int forms.pictureBox(int formhandle, [int? x = null], [int? y = null], [int? width = null], [int? height = null])
|
||||||
|
|
||||||
|
--[[ GenerationLabel = forms.label(form, "Generation: " .. pool.generation, 5, 5)
|
||||||
|
SpeciesLabel = forms.label(form, "Species: " .. pool.currentSpecies, 130, 5)
|
||||||
|
GenomeLabel = forms.label(form, "Genome: " .. pool.currentGenome, 230, 5)
|
||||||
|
MeasuredLabel = forms.label(form, "Measured: " .. "", 330, 5)
|
||||||
|
|
||||||
|
FitnessLabel = forms.label(form, "Fitness: " .. "", 5, 30)
|
||||||
|
MaxLabel = forms.label(form, "Max: " .. "", 130, 30)
|
||||||
|
|
||||||
|
BananasLabel = forms.label(form, "Bananas: " .. "", 5, 65)
|
||||||
|
CoinsLabel = forms.label(form, "Coins: " .. "", 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)
|
||||||
|
|
||||||
|
restartButton = forms.button(form, "Restart", initializePool, 155, 102)
|
||||||
|
saveButton = forms.button(form, "Save", savePool, 5, 102)
|
||||||
|
loadButton = forms.button(form, "Load", loadPool, 80, 102)
|
||||||
|
playTopButton = forms.button(form, "Play Top", playTop, 230, 102)
|
||||||
|
|
||||||
|
saveLoadLabel = forms.label(form, "Save/Load:", 5, 129) ]]
|
||||||
|
saveLoadFile = config.NeatConfig.Filename .. ".pool"
|
||||||
|
spritelist.InitSpriteList()
|
||||||
|
spritelist.InitExtSpriteList()
|
||||||
|
|
||||||
Inputs = config.InputSize+1
|
Inputs = config.InputSize+1
|
||||||
Outputs = #config.ButtonNames
|
Outputs = #config.ButtonNames
|
||||||
|
|
||||||
|
@ -149,14 +183,13 @@ function evaluateNetwork(network, inputs, inputDeltas)
|
||||||
table.insert(inputs, 1)
|
table.insert(inputs, 1)
|
||||||
table.insert(inputDeltas,99)
|
table.insert(inputDeltas,99)
|
||||||
if #inputs ~= Inputs then
|
if #inputs ~= Inputs then
|
||||||
console.writeline("Incorrect number of neural network inputs.")
|
print("Incorrect number of neural network inputs.")
|
||||||
return {}
|
return {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
for i=1,Inputs do
|
for i=1,Inputs do
|
||||||
network.neurons[i].value = inputs[i] * inputDeltas[i]
|
network.neurons[i].value = inputs[i] * inputDeltas[i]
|
||||||
--network.neurons[i].value = inputs[i]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
for _,neuron in pairs(network.neurons) do
|
for _,neuron in pairs(network.neurons) do
|
||||||
|
@ -174,7 +207,7 @@ function evaluateNetwork(network, inputs, inputDeltas)
|
||||||
|
|
||||||
local outputs = {}
|
local outputs = {}
|
||||||
for o=1,Outputs do
|
for o=1,Outputs do
|
||||||
local button = "P1 " .. config.ButtonNames[o]
|
local button = o - 1
|
||||||
if network.neurons[config.NeatConfig.MaxNodes+o].value > 0 then
|
if network.neurons[config.NeatConfig.MaxNodes+o].value > 0 then
|
||||||
outputs[button] = true
|
outputs[button] = true
|
||||||
else
|
else
|
||||||
|
@ -625,11 +658,10 @@ function newGeneration()
|
||||||
|
|
||||||
pool.generation = pool.generation + 1
|
pool.generation = pool.generation + 1
|
||||||
|
|
||||||
--writeFile("backup." .. pool.generation .. "." .. forms.gettext(saveLoadFile))
|
writeFile(saveLoadFile .. ".gen" .. pool.generation .. ".pool")
|
||||||
writeFile(forms.gettext(saveLoadFile) .. ".gen" .. pool.generation .. ".pool")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function initializePool()
|
function initializePool(after)
|
||||||
pool = newPool()
|
pool = newPool()
|
||||||
|
|
||||||
for i=1,config.NeatConfig.Population do
|
for i=1,config.NeatConfig.Population do
|
||||||
|
@ -637,14 +669,10 @@ function initializePool()
|
||||||
addToSpecies(basic)
|
addToSpecies(basic)
|
||||||
end
|
end
|
||||||
|
|
||||||
initializeRun()
|
initializeRun(after)
|
||||||
end
|
end
|
||||||
|
|
||||||
function initializeRun()
|
function on_timer()
|
||||||
print("Hello")
|
|
||||||
print(config.NeatConfig.Filename)
|
|
||||||
local rew = movie.to_rewind(config.NeatConfig.Filename)
|
|
||||||
movie.unsafe_rewind(rew)
|
|
||||||
if config.StartPowerup ~= NIL then
|
if config.StartPowerup ~= NIL then
|
||||||
game.writePowerup(config.StartPowerup)
|
game.writePowerup(config.StartPowerup)
|
||||||
end
|
end
|
||||||
|
@ -655,14 +683,34 @@ function initializeRun()
|
||||||
startBananas = game.getBananas()
|
startBananas = game.getBananas()
|
||||||
startCoins = game.getCoins()
|
startCoins = game.getCoins()
|
||||||
startLives = game.getLives()
|
startLives = game.getLives()
|
||||||
checkMarioCollision = true
|
checkPartyCollision = true
|
||||||
marioHitCounter = 0
|
partyHitCounter = 0
|
||||||
powerUpCounter = 0
|
powerUpCounter = 0
|
||||||
powerUpBefore = game.getPowerup()
|
powerUpBefore = game.getPowerup()
|
||||||
local species = pool.species[pool.currentSpecies]
|
local species = pool.species[pool.currentSpecies]
|
||||||
local genome = species.genomes[pool.currentGenome]
|
local genome = species.genomes[pool.currentGenome]
|
||||||
generateNetwork(genome)
|
generateNetwork(genome)
|
||||||
evaluateCurrent()
|
evaluateCurrent()
|
||||||
|
for i=#runInitialized,1,-1 do
|
||||||
|
table.remove(runInitialized, i)()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local rew = movie.to_rewind(config.NeatConfig.Filename)
|
||||||
|
|
||||||
|
function on_post_rewind()
|
||||||
|
set_timer_timeout(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
function on_video()
|
||||||
|
gui.kill_frame()
|
||||||
|
end
|
||||||
|
|
||||||
|
function initializeRun(after)
|
||||||
|
settings.set_speed(1)
|
||||||
|
gui.subframe_update(false)
|
||||||
|
table.insert(runInitialized, after)
|
||||||
|
movie.unsafe_rewind(rew)
|
||||||
end
|
end
|
||||||
|
|
||||||
function evaluateCurrent()
|
function evaluateCurrent()
|
||||||
|
@ -674,20 +722,218 @@ function evaluateCurrent()
|
||||||
|
|
||||||
controller = evaluateNetwork(genome.network, inputs, inputDeltas)
|
controller = evaluateNetwork(genome.network, inputs, inputDeltas)
|
||||||
|
|
||||||
if controller["P1 Left"] and controller["P1 Right"] then
|
if controller[6] and controller[7] then
|
||||||
controller["P1 Left"] = false
|
controller[6] = false
|
||||||
controller["P1 Right"] = false
|
controller[7] = false
|
||||||
end
|
end
|
||||||
if controller["P1 Up"] and controller["P1 Down"] then
|
if controller[4] and controller[5] then
|
||||||
controller["P1 Up"] = false
|
controller[4] = false
|
||||||
controller["P1 Down"] = false
|
controller[5] = false
|
||||||
end
|
end
|
||||||
|
|
||||||
joypad.set(controller)
|
for b=1,#config.ButtonNames,1 do
|
||||||
|
if controller[b] then
|
||||||
|
input.set(0, b - 1, 1)
|
||||||
|
else
|
||||||
|
input.set(0, b - 1, 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if pool == nil then
|
function on_input()
|
||||||
initializePool()
|
for i=#frameAdvanced,1,-1 do
|
||||||
|
table.remove(frameAdvanced, i)()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function on_paint()
|
||||||
|
gui.left_gap(500)
|
||||||
|
gui.top_gap(0)
|
||||||
|
gui.bottom_gap(0)
|
||||||
|
gui.right_gap(0)
|
||||||
|
if genomeDisplay ~= nil and movie.currentframe() % 10 == 0 then
|
||||||
|
displayGenome(genomeDisplay)
|
||||||
|
end
|
||||||
|
gui.renderctx.setnull()
|
||||||
|
form:render():draw(-500, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
function advanceFrame(after)
|
||||||
|
table.insert(frameAdvanced, after)
|
||||||
|
--exec("+advance-frame")
|
||||||
|
end
|
||||||
|
|
||||||
|
function mainLoop (species, genome)
|
||||||
|
advanceFrame(function()
|
||||||
|
if not config.Running then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if species ~= nil and genome ~= nil then
|
||||||
|
local measured = 0
|
||||||
|
local total = 0
|
||||||
|
for _,species in pairs(pool.species) do
|
||||||
|
for _,genome in pairs(species.genomes) do
|
||||||
|
total = total + 1
|
||||||
|
if genome.fitness ~= 0 then
|
||||||
|
measured = measured + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
gui.circle(game.screenX-84, game.screenY-84, 192 / 2, 1, 0x50000000)
|
||||||
|
--[[ forms.settext(FitnessLabel, "Fitness: " .. math.floor(rightmost - (pool.currentFrame) / 2 - (timeout + timeoutBonus)*2/3))
|
||||||
|
forms.settext(GenerationLabel, "Generation: " .. pool.generation)
|
||||||
|
forms.settext(SpeciesLabel, "Species: " .. pool.currentSpecies)
|
||||||
|
forms.settext(GenomeLabel, "Genome: " .. pool.currentGenome)
|
||||||
|
forms.settext(MaxLabel, "Max: " .. math.floor(pool.maxFitness))
|
||||||
|
forms.settext(MeasuredLabel, "Measured: " .. math.floor(measured/total*100) .. "%")
|
||||||
|
forms.settext(BananasLabel, "Bananas: " .. (game.getBananas() - startBananas))
|
||||||
|
forms.settext(CoinsLabel, "Coins: " .. (game.getCoins() - startCoins))
|
||||||
|
forms.settext(LivesLabel, "Lives: " .. Lives)
|
||||||
|
forms.settext(DmgLabel, "Damage: " .. partyHitCounter)
|
||||||
|
forms.settext(PowerUpLabel, "PowerUp: " .. powerUpCounter)
|
||||||
|
]]
|
||||||
|
pool.currentFrame = pool.currentFrame + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
species = pool.species[pool.currentSpecies]
|
||||||
|
genome = species.genomes[pool.currentGenome]
|
||||||
|
|
||||||
|
genomeDisplay = genome
|
||||||
|
|
||||||
|
if pool.currentFrame%5 == 0 then
|
||||||
|
evaluateCurrent()
|
||||||
|
end
|
||||||
|
|
||||||
|
for b=1,#config.ButtonNames,1 do
|
||||||
|
if controller[b] then
|
||||||
|
input.set(0, b - 1, 1)
|
||||||
|
else
|
||||||
|
input.set(0, b - 1, 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
game.getPositions()
|
||||||
|
if partyX > rightmost then
|
||||||
|
rightmost = partyX
|
||||||
|
timeout = config.NeatConfig.TimeoutConstant
|
||||||
|
end
|
||||||
|
|
||||||
|
local hitTimer = game.getHitTimer()
|
||||||
|
|
||||||
|
if checkPartyCollision == true then
|
||||||
|
if hitTimer > 0 then
|
||||||
|
partyHitCounter = partyHitCounter + 1
|
||||||
|
--print("party took damage, hit counter: " .. partyHitCounter)
|
||||||
|
checkPartyCollision = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if hitTimer == 0 then
|
||||||
|
checkPartyCollision = 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
|
||||||
|
if timeout + timeoutBonus <= 0 then
|
||||||
|
|
||||||
|
local bananas = game.getBananas() - startBananas
|
||||||
|
local coins = game.getCoins() - startCoins
|
||||||
|
|
||||||
|
print("Bananas: " .. bananas .. " coins: " .. coins)
|
||||||
|
|
||||||
|
local bananaCoinsFitness = (bananas * 50) + (coins * 0.2)
|
||||||
|
if (bananas + coins) > 0 then
|
||||||
|
print("Bananas and Coins added " .. bananaCoinsFitness .. " fitness")
|
||||||
|
end
|
||||||
|
|
||||||
|
local hitPenalty = partyHitCounter * 100
|
||||||
|
local powerUpBonus = powerUpCounter * 100
|
||||||
|
|
||||||
|
local fitness = bananaCoinsFitness - hitPenalty + powerUpBonus + rightmost - pool.currentFrame / 2
|
||||||
|
|
||||||
|
if startLives < Lives then
|
||||||
|
local ExtraLiveBonus = (Lives - startLives)*1000
|
||||||
|
fitness = fitness + ExtraLiveBonus
|
||||||
|
print("ExtraLiveBonus added " .. ExtraLiveBonus)
|
||||||
|
end
|
||||||
|
|
||||||
|
if rightmost > 4816 then
|
||||||
|
fitness = fitness + 1000
|
||||||
|
print("!!!!!!Beat level!!!!!!!")
|
||||||
|
end
|
||||||
|
if fitness == 0 then
|
||||||
|
fitness = -1
|
||||||
|
end
|
||||||
|
genome.fitness = fitness
|
||||||
|
|
||||||
|
if fitness > pool.maxFitness then
|
||||||
|
pool.maxFitness = fitness
|
||||||
|
writeFile(saveLoadFile .. ".gen" .. pool.generation .. ".pool")
|
||||||
|
end
|
||||||
|
|
||||||
|
print("Gen " .. pool.generation .. " species " .. pool.currentSpecies .. " genome " .. pool.currentGenome .. " fitness: " .. fitness)
|
||||||
|
pool.currentSpecies = 1
|
||||||
|
pool.currentGenome = 1
|
||||||
|
while fitnessAlreadyMeasured() do
|
||||||
|
nextGenome()
|
||||||
|
end
|
||||||
|
initializeRun(function()
|
||||||
|
mainLoop(species, genome)
|
||||||
|
end)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
advanceFrame(mainLoop)
|
||||||
|
end)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function writeFile(filename)
|
||||||
|
local file = io.open(filename, "w")
|
||||||
|
file:write(pool.generation .. "\n")
|
||||||
|
file:write(pool.maxFitness .. "\n")
|
||||||
|
file:write(#pool.species .. "\n")
|
||||||
|
for n,species in pairs(pool.species) do
|
||||||
|
file:write(species.topFitness .. "\n")
|
||||||
|
file:write(species.staleness .. "\n")
|
||||||
|
file:write(#species.genomes .. "\n")
|
||||||
|
for m,genome in pairs(species.genomes) do
|
||||||
|
file:write(genome.fitness .. "\n")
|
||||||
|
file:write(genome.maxneuron .. "\n")
|
||||||
|
for mutation,rate in pairs(genome.mutationRates) do
|
||||||
|
file:write(mutation .. "\n")
|
||||||
|
file:write(rate .. "\n")
|
||||||
|
end
|
||||||
|
file:write("done\n")
|
||||||
|
|
||||||
|
file:write(#genome.genes .. "\n")
|
||||||
|
for l,gene in pairs(genome.genes) do
|
||||||
|
file:write(gene.into .. " ")
|
||||||
|
file:write(gene.out .. " ")
|
||||||
|
file:write(gene.weight .. " ")
|
||||||
|
file:write(gene.innovation .. " ")
|
||||||
|
if(gene.enabled) then
|
||||||
|
file:write("1\n")
|
||||||
|
else
|
||||||
|
file:write("0\n")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
file:close()
|
||||||
end
|
end
|
||||||
|
|
||||||
function nextGenome()
|
function nextGenome()
|
||||||
|
@ -709,13 +955,10 @@ function fitnessAlreadyMeasured()
|
||||||
return genome.fitness ~= 0
|
return genome.fitness ~= 0
|
||||||
end
|
end
|
||||||
|
|
||||||
form = forms.newform(500, 500, "Mario-Neat")
|
|
||||||
netPicture = forms.pictureBox(form, 5, 250,470, 200)
|
|
||||||
|
|
||||||
--int forms.pictureBox(int formhandle, [int? x = null], [int? y = null], [int? width = null], [int? height = null])
|
|
||||||
|
|
||||||
function displayGenome(genome)
|
function displayGenome(genome)
|
||||||
forms.clear(netPicture,0x80808080)
|
netPicture:clear()
|
||||||
|
netPicture:set()
|
||||||
|
gui.solidrectangle(0, 0, 470, 200, 0x80808080)
|
||||||
local network = genome.network
|
local network = genome.network
|
||||||
local cells = {}
|
local cells = {}
|
||||||
local i = 1
|
local i = 1
|
||||||
|
@ -739,17 +982,16 @@ function displayGenome(genome)
|
||||||
for o = 1,Outputs do
|
for o = 1,Outputs do
|
||||||
cell = {}
|
cell = {}
|
||||||
cell.x = 220
|
cell.x = 220
|
||||||
cell.y = 30 + 8 * o
|
cell.y = 30 + 14 * o
|
||||||
cell.value = network.neurons[config.NeatConfig.MaxNodes + o].value
|
cell.value = network.neurons[config.NeatConfig.MaxNodes + o].value
|
||||||
cells[config.NeatConfig.MaxNodes+o] = cell
|
cells[config.NeatConfig.MaxNodes+o] = cell
|
||||||
local color
|
local color
|
||||||
if cell.value > 0 then
|
if cell.value > 0 then
|
||||||
color = 0xFF0000FF
|
color = 0x000000FF
|
||||||
else
|
else
|
||||||
color = 0xFF000000
|
color = 0x00000000
|
||||||
end
|
end
|
||||||
--gui.drawText(223, 24+8*o, config.ButtonNames[o], color, 9)
|
gui.text(223, 24+14*o, config.ButtonNames[o], color, 0xff000000)
|
||||||
forms.drawText(netPicture,223, 24+8*o, config.ButtonNames[o], color, 9)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
for n,neuron in pairs(network.neurons) do
|
for n,neuron in pairs(network.neurons) do
|
||||||
|
@ -799,9 +1041,15 @@ function displayGenome(genome)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--gui.drawBox(50-config.BoxRadius*5-3,70-config.BoxRadius*5-3,50+config.BoxRadius*5+2,70+config.BoxRadius*5+2,0xFF000000, 0x80808080)
|
gui.rectangle(
|
||||||
forms.drawBox(netPicture, 50-config.BoxRadius*5-3,70-config.BoxRadius*5-3,50+config.BoxRadius*5+2,70+config.BoxRadius*5+2,0xFF000000, 0x80808080)
|
50-config.BoxRadius*5-3,
|
||||||
--oid forms.drawBox(int componenthandle, int x, int y, int x2, int y2, [color? line = null], [color? background = null])
|
70-config.BoxRadius*5-3,
|
||||||
|
config.BoxRadius*10+5,
|
||||||
|
config.BoxRadius*10+5,
|
||||||
|
2,
|
||||||
|
0xFF000000,
|
||||||
|
0x80808080
|
||||||
|
)
|
||||||
for n,cell in pairs(cells) do
|
for n,cell in pairs(cells) do
|
||||||
if n > Inputs or cell.value ~= 0 then
|
if n > Inputs or cell.value ~= 0 then
|
||||||
local color = math.floor((cell.value+1)/2*256)
|
local color = math.floor((cell.value+1)/2*256)
|
||||||
|
@ -812,8 +1060,15 @@ function displayGenome(genome)
|
||||||
opacity = 0x50000000
|
opacity = 0x50000000
|
||||||
end
|
end
|
||||||
color = opacity + color*0x10000 + color*0x100 + color
|
color = opacity + color*0x10000 + color*0x100 + color
|
||||||
forms.drawBox(netPicture,cell.x-2,cell.y-2,cell.x+2,cell.y+2,opacity,color)
|
gui.rectangle(
|
||||||
--gui.drawBox(cell.x-2,cell.y-2,cell.x+2,cell.y+2,opacity,color)
|
math.floor(cell.x-5),
|
||||||
|
math.floor(cell.y-5),
|
||||||
|
5,
|
||||||
|
5,
|
||||||
|
1,
|
||||||
|
0x00,
|
||||||
|
color
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
for _,gene in pairs(genome.genes) do
|
for _,gene in pairs(genome.genes) do
|
||||||
|
@ -831,65 +1086,40 @@ function displayGenome(genome)
|
||||||
else
|
else
|
||||||
color = opacity + 0x800000 + 0x100*color
|
color = opacity + 0x800000 + 0x100*color
|
||||||
end
|
end
|
||||||
--gui.drawLine(c1.x+1, c1.y, c2.x-3, c2.y, color)
|
gui.line(
|
||||||
forms.drawLine(netPicture,c1.x+1, c1.y, c2.x-3, c2.y, color)
|
math.floor(c1.x+1),
|
||||||
|
math.floor(c1.y),
|
||||||
|
math.floor(c2.x-3),
|
||||||
|
math.floor(c2.y),
|
||||||
|
color
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--gui.drawBox(49,71,51,78,0x00000000,0x80FF0000)
|
gui.rectangle(
|
||||||
forms.drawBox(netPicture, 49,71,51,78,0x00000000,0x80FF0000)
|
49,
|
||||||
--if forms.ischecked(showMutationRates) then
|
71,
|
||||||
|
2,
|
||||||
|
7,
|
||||||
|
0x00000000,
|
||||||
|
0x80FF0000
|
||||||
|
)
|
||||||
|
|
||||||
local pos = 100
|
local pos = 100
|
||||||
for mutation,rate in pairs(genome.mutationRates) do
|
for mutation,rate in pairs(genome.mutationRates) do
|
||||||
--gui.drawText(100, pos, mutation .. ": " .. rate, 0xFF000000, 10)
|
gui.text(100, pos, mutation .. ": " .. rate, 0x00000000, 0xff000000)
|
||||||
forms.drawText(netPicture,100, pos, mutation .. ": " .. rate, 0xFF000000, 10)
|
|
||||||
--forms.drawText(pictureBox,400,pos, mutation .. ": " .. rate)
|
|
||||||
|
|
||||||
--void forms.drawText(int componenthandle, int x, int y, string message, [color? forecolor = null], [color? backcolor = null], [int? fontsize = null], [string fontfamily = null], [string fontstyle = null], [string horizalign = null], [string vertalign = null])
|
pos = pos + 14
|
||||||
|
|
||||||
pos = pos + 8
|
|
||||||
end
|
|
||||||
--end
|
|
||||||
forms.refresh(netPicture)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function writeFile(filename)
|
local bitmap = netPicture:render()
|
||||||
local file = io.open(filename, "w")
|
form:set()
|
||||||
file:write(pool.generation .. "\n")
|
bitmap:draw(5, 250)
|
||||||
file:write(pool.maxFitness .. "\n")
|
gui.renderctx.setnull()
|
||||||
file:write(#pool.species .. "\n")
|
|
||||||
for n,species in pairs(pool.species) do
|
|
||||||
file:write(species.topFitness .. "\n")
|
|
||||||
file:write(species.staleness .. "\n")
|
|
||||||
file:write(#species.genomes .. "\n")
|
|
||||||
for m,genome in pairs(species.genomes) do
|
|
||||||
file:write(genome.fitness .. "\n")
|
|
||||||
file:write(genome.maxneuron .. "\n")
|
|
||||||
for mutation,rate in pairs(genome.mutationRates) do
|
|
||||||
file:write(mutation .. "\n")
|
|
||||||
file:write(rate .. "\n")
|
|
||||||
end
|
|
||||||
file:write("done\n")
|
|
||||||
|
|
||||||
file:write(#genome.genes .. "\n")
|
|
||||||
for l,gene in pairs(genome.genes) do
|
|
||||||
file:write(gene.into .. " ")
|
|
||||||
file:write(gene.out .. " ")
|
|
||||||
file:write(gene.weight .. " ")
|
|
||||||
file:write(gene.innovation .. " ")
|
|
||||||
if(gene.enabled) then
|
|
||||||
file:write("1\n")
|
|
||||||
else
|
|
||||||
file:write("0\n")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
file:close()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function savePool()
|
function savePool()
|
||||||
local filename = forms.gettext(saveLoadFile)
|
local filename = saveLoadFile
|
||||||
print(filename)
|
print(filename)
|
||||||
writeFile(filename)
|
writeFile(filename)
|
||||||
end
|
end
|
||||||
|
@ -906,7 +1136,7 @@ function mysplit(inputstr, sep)
|
||||||
return t
|
return t
|
||||||
end
|
end
|
||||||
|
|
||||||
function loadFile(filename)
|
function loadFile(filename, after)
|
||||||
print("Loading pool from " .. filename)
|
print("Loading pool from " .. filename)
|
||||||
local file = io.open(filename, "r")
|
local file = io.open(filename, "r")
|
||||||
pool = newPool()
|
pool = newPool()
|
||||||
|
@ -961,9 +1191,11 @@ function loadFile(filename)
|
||||||
while fitnessAlreadyMeasured() do
|
while fitnessAlreadyMeasured() do
|
||||||
nextGenome()
|
nextGenome()
|
||||||
end
|
end
|
||||||
initializeRun()
|
initializeRun(function()
|
||||||
pool.currentFrame = pool.currentFrame + 1
|
pool.currentFrame = pool.currentFrame + 1
|
||||||
print("Pool loaded.")
|
print("Pool loaded.")
|
||||||
|
after()
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
function flipState()
|
function flipState()
|
||||||
|
@ -976,11 +1208,9 @@ function flipState()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function loadPool()
|
function loadPool(after)
|
||||||
filename = forms.openfile("DP1.state.pool",config.PoolDir)
|
filename = forms.openfile("DP1.state.pool",config.PoolDir)
|
||||||
--local filename = forms.gettext(saveLoadFile)
|
loadFile(filename, after)
|
||||||
forms.settext(saveLoadFile, filename)
|
|
||||||
loadFile(filename)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function playTop()
|
function playTop()
|
||||||
|
@ -999,167 +1229,24 @@ function playTop()
|
||||||
pool.currentSpecies = maxs
|
pool.currentSpecies = maxs
|
||||||
pool.currentGenome = maxg
|
pool.currentGenome = maxg
|
||||||
pool.maxFitness = maxfitness
|
pool.maxFitness = maxfitness
|
||||||
forms.settext(MaxLabel, "Max Fitness: " .. math.floor(pool.maxFitness))
|
--forms.settext(MaxLabel, "Max Fitness: " .. math.floor(pool.maxFitness))
|
||||||
initializeRun()
|
initializeRun()
|
||||||
pool.currentFrame = pool.currentFrame + 1
|
pool.currentFrame = pool.currentFrame + 1
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
function onExit()
|
function on_quit()
|
||||||
forms.destroy(form)
|
netPicture:clear()
|
||||||
|
form:clear()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if pool == nil then
|
||||||
|
initializePool(function()
|
||||||
writeFile(config.PoolDir.."temp.pool")
|
writeFile(config.PoolDir.."temp.pool")
|
||||||
|
mainLoop()
|
||||||
event.onexit(onExit)
|
end)
|
||||||
|
else
|
||||||
GenerationLabel = forms.label(form, "Generation: " .. pool.generation, 5, 5)
|
writeFile(config.PoolDir.."temp.pool")
|
||||||
SpeciesLabel = forms.label(form, "Species: " .. pool.currentSpecies, 130, 5)
|
mainLoop()
|
||||||
GenomeLabel = forms.label(form, "Genome: " .. pool.currentGenome, 230, 5)
|
|
||||||
MeasuredLabel = forms.label(form, "Measured: " .. "", 330, 5)
|
|
||||||
|
|
||||||
FitnessLabel = forms.label(form, "Fitness: " .. "", 5, 30)
|
|
||||||
MaxLabel = forms.label(form, "Max: " .. "", 130, 30)
|
|
||||||
|
|
||||||
BananasLabel = forms.label(form, "Bananas: " .. "", 5, 65)
|
|
||||||
CoinsLabel = forms.label(form, "Coins: " .. "", 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)
|
|
||||||
|
|
||||||
restartButton = forms.button(form, "Restart", initializePool, 155, 102)
|
|
||||||
saveButton = forms.button(form, "Save", savePool, 5, 102)
|
|
||||||
loadButton = forms.button(form, "Load", loadPool, 80, 102)
|
|
||||||
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
|
|
||||||
|
|
||||||
local species = pool.species[pool.currentSpecies]
|
|
||||||
local genome = species.genomes[pool.currentGenome]
|
|
||||||
|
|
||||||
displayGenome(genome)
|
|
||||||
|
|
||||||
if pool.currentFrame%5 == 0 then
|
|
||||||
evaluateCurrent()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
joypad.set(controller)
|
|
||||||
|
|
||||||
game.getPositions()
|
|
||||||
if partyX > rightmost then
|
|
||||||
rightmost = partyX
|
|
||||||
timeout = config.NeatConfig.TimeoutConstant
|
|
||||||
end
|
|
||||||
|
|
||||||
local hitTimer = game.getHitTimer()
|
|
||||||
|
|
||||||
if checkMarioCollision == true then
|
|
||||||
if hitTimer > 0 then
|
|
||||||
marioHitCounter = marioHitCounter + 1
|
|
||||||
--console.writeline("Mario took damage, hit counter: " .. marioHitCounter)
|
|
||||||
checkMarioCollision = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if hitTimer == 0 then
|
|
||||||
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
|
|
||||||
if timeout + timeoutBonus <= 0 then
|
|
||||||
|
|
||||||
local bananas = game.getBananas() - startBananas
|
|
||||||
local coins = game.getCoins() - startCoins
|
|
||||||
|
|
||||||
--console.writeline("Bananas: " .. bananas .. " coins: " .. coins)
|
|
||||||
|
|
||||||
local bananaCoinsFitness = (bananas * 50) + (coins * 0.2)
|
|
||||||
if (bananas + coins) > 0 then
|
|
||||||
console.writeline("Bananas and Coins added " .. bananaCoinsFitness .. " fitness")
|
|
||||||
end
|
|
||||||
|
|
||||||
local hitPenalty = marioHitCounter * 100
|
|
||||||
local powerUpBonus = powerUpCounter * 100
|
|
||||||
|
|
||||||
local fitness = bananaCoinsFitness - 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!!!!!!!")
|
|
||||||
end
|
|
||||||
if fitness == 0 then
|
|
||||||
fitness = -1
|
|
||||||
end
|
|
||||||
genome.fitness = fitness
|
|
||||||
|
|
||||||
if fitness > pool.maxFitness then
|
|
||||||
pool.maxFitness = fitness
|
|
||||||
--writeFile("backup." .. pool.generation .. "." .. forms.gettext(saveLoadFile))
|
|
||||||
writeFile(forms.gettext(saveLoadFile) .. ".gen" .. pool.generation .. ".pool")
|
|
||||||
end
|
|
||||||
|
|
||||||
console.writeline("Gen " .. pool.generation .. " species " .. pool.currentSpecies .. " genome " .. pool.currentGenome .. " fitness: " .. fitness)
|
|
||||||
pool.currentSpecies = 1
|
|
||||||
pool.currentGenome = 1
|
|
||||||
while fitnessAlreadyMeasured() do
|
|
||||||
nextGenome()
|
|
||||||
end
|
|
||||||
initializeRun()
|
|
||||||
end
|
|
||||||
|
|
||||||
local measured = 0
|
|
||||||
local total = 0
|
|
||||||
for _,species in pairs(pool.species) do
|
|
||||||
for _,genome in pairs(species.genomes) do
|
|
||||||
total = total + 1
|
|
||||||
if genome.fitness ~= 0 then
|
|
||||||
measured = measured + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
gui.drawEllipse(game.screenX-84, game.screenY-84, 192, 192, 0x50000000)
|
|
||||||
forms.settext(FitnessLabel, "Fitness: " .. math.floor(rightmost - (pool.currentFrame) / 2 - (timeout + timeoutBonus)*2/3))
|
|
||||||
forms.settext(GenerationLabel, "Generation: " .. pool.generation)
|
|
||||||
forms.settext(SpeciesLabel, "Species: " .. pool.currentSpecies)
|
|
||||||
forms.settext(GenomeLabel, "Genome: " .. pool.currentGenome)
|
|
||||||
forms.settext(MaxLabel, "Max: " .. math.floor(pool.maxFitness))
|
|
||||||
forms.settext(MeasuredLabel, "Measured: " .. math.floor(measured/total*100) .. "%")
|
|
||||||
forms.settext(BananasLabel, "Bananas: " .. (game.getBananas() - startBananas))
|
|
||||||
forms.settext(CoinsLabel, "Coins: " .. (game.getCoins() - startCoins))
|
|
||||||
forms.settext(LivesLabel, "Lives: " .. Lives)
|
|
||||||
forms.settext(DmgLabel, "Damage: " .. marioHitCounter)
|
|
||||||
forms.settext(PowerUpLabel, "PowerUp: " .. powerUpCounter)
|
|
||||||
|
|
||||||
pool.currentFrame = pool.currentFrame + 1
|
|
||||||
|
|
||||||
end
|
|
||||||
emu.frameadvance();
|
|
||||||
|
|
||||||
end
|
|
Binary file not shown.
|
@ -1,4 +1,4 @@
|
||||||
-- Idea from: https://github.com/kevino5233/MarIO_Enhanced/
|
-- Idea from: https://github.com/kevino5233/party_Enhanced/
|
||||||
-- Spritelist from: https://www.smwcentral.net/?p=viewthread&t=7562
|
-- 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
|
-- Extended spritelist: https://web.archive.org/web/20170709102356/www.smwiki.net/wiki/RAM_Address/$7E:170B
|
||||||
--
|
--
|
||||||
|
@ -163,7 +163,7 @@ _M.BadSprites = {
|
||||||
0x71, -- Super Koopa, red cape, swoop.
|
0x71, -- Super Koopa, red cape, swoop.
|
||||||
0x72, -- Super Koopa, yellow cape, swoop.
|
0x72, -- Super Koopa, yellow cape, swoop.
|
||||||
0x73, -- Super Koopa, feather/yellow cape (X&1).
|
0x73, -- Super Koopa, feather/yellow cape (X&1).
|
||||||
0x7A, -- Firework, makes Mario temporarily invisible.
|
0x7A, -- Firework, makes party temporarily invisible.
|
||||||
0x86, -- Wiggler.
|
0x86, -- Wiggler.
|
||||||
0x8D, -- Ghost house exit sign and door.
|
0x8D, -- Ghost house exit sign and door.
|
||||||
0x8E, -- Invisible "Warp Hole" blocks. (!)
|
0x8E, -- Invisible "Warp Hole" blocks. (!)
|
||||||
|
|
20
state-test.lua
Normal file
20
state-test.lua
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
PARTY_X = 0x7e0a2a
|
||||||
|
TILE_SIZE = 32
|
||||||
|
|
||||||
|
print(memory.readword(PARTY_X))
|
||||||
|
|
||||||
|
function on_post_rewind()
|
||||||
|
print("Async?")
|
||||||
|
print(memory.readword(PARTY_X))
|
||||||
|
end
|
||||||
|
|
||||||
|
function movement(addr, val)
|
||||||
|
if memory.readword(addr) > TILE_SIZE * 20 then
|
||||||
|
local rew = movie.to_rewind("pool/PiratePanic.lsmv")
|
||||||
|
movie.unsafe_rewind(rew)
|
||||||
|
print("Sync?")
|
||||||
|
print(memory.readword(PARTY_X))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
memory2.WRAM:registerwrite(0x0a2a, movement)
|
Loading…
Add table
Reference in a new issue