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/
|
||||
crashsave*
|
||||
*.backup
|
||||
*.pool
|
||||
|
|
100
donkutil.lua
100
donkutil.lua
|
@ -248,7 +248,7 @@ Sprite Details:
|
|||
|
||||
local partyX = memory.readword(PARTY_X)
|
||||
local partyY = memory.readword(PARTY_Y)
|
||||
local partyTileOffset = tile_offset_calculation(partyX, partyY, vertical)
|
||||
local partyTileOffset = tileOffsetCalculation(partyX, partyY, vertical)
|
||||
|
||||
local stats = string.format([[
|
||||
%s camera %d,%d
|
||||
|
@ -310,11 +310,11 @@ Tile offset: %04x
|
|||
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 offset = tile_offset_calculation(tileX, tileY, vertical)
|
||||
local offset = tileOffsetCalculation(tileX, tileY, vertical)
|
||||
|
||||
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
|
||||
end
|
||||
|
||||
|
@ -325,7 +325,7 @@ Tile offset: %04x
|
|||
--goto continue
|
||||
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::
|
||||
end
|
||||
|
@ -335,9 +335,9 @@ Tile offset: %04x
|
|||
local oam = memory2.OAM:readregion(0x00, 0x220)
|
||||
|
||||
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 = {
|
||||
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],
|
||||
tile = oam[idx * 4 + 3],
|
||||
flags = oam[idx * 4 + 4],
|
||||
|
@ -359,7 +359,7 @@ Tile offset: %04x
|
|||
::nextsprite::
|
||||
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)
|
||||
end
|
||||
|
||||
|
@ -376,8 +376,38 @@ Tile offset: %04x
|
|||
text(guiWidth - 125, 20, "Help [Hold 0]")
|
||||
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
|
||||
function tile_is_solid(x, y, tileVal, tileOffset)
|
||||
function tileIsSolid(x, y, tileVal, tileOffset)
|
||||
local origTileVal = tileVal
|
||||
|
||||
if tileVal == 0 or tileOffset == 0 then
|
||||
|
@ -388,13 +418,13 @@ function tile_is_solid(x, y, tileVal, tileOffset)
|
|||
return true
|
||||
end
|
||||
|
||||
local a2 = x & 0x1f
|
||||
local a2 = bit.band(x, 0x1f)
|
||||
|
||||
if tileVal & 0x4000 ~= 0 then
|
||||
a2 = (a2 ~ 0x1f) & 0xffff
|
||||
if bit.band(tileVal, 0x4000) ~= 0 then
|
||||
a2 = bit.band(bit.bxor(a2, 0x1f), 0xffff)
|
||||
end
|
||||
|
||||
tileVal = tileVal & 0x3fff
|
||||
tileVal = bit.band(tileVal, 0x3fff)
|
||||
|
||||
local solidLessThan = memory.readword(SOLID_LESS_THAN)
|
||||
|
||||
|
@ -402,65 +432,35 @@ function tile_is_solid(x, y, tileVal, tileOffset)
|
|||
return false
|
||||
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
|
||||
end
|
||||
|
||||
local tileMeta = memory.readword(memory.readword(0x7e009c) + tileVal)
|
||||
|
||||
if tileMeta & 0x8000 ~=0 then
|
||||
a2 = (a2 ~ 0x000f) & 0xffff
|
||||
if bit.band(tileMeta, 0x8000) ~=0 then
|
||||
a2 = bit.band(bit.bxor(a2, 0x000f), 0xffff)
|
||||
end
|
||||
|
||||
if tileMeta & tileVal & 0x2000 ~= 0 then
|
||||
tileMeta = (tileMeta ~ 0x8000) & 0xffff
|
||||
if bit.band(tileMeta, tileVal, 0x2000) ~= 0 then
|
||||
tileMeta = bit.band(bit.bxor(tileMeta, 0x8000), 0xffff)
|
||||
end
|
||||
|
||||
tileMeta = tileMeta & 0x00ff
|
||||
tileMeta = bit.band(tileMeta, 0x00ff)
|
||||
|
||||
if tileMeta == 0 then
|
||||
return false
|
||||
end
|
||||
|
||||
tileMeta = (tileMeta << 1) & 0xffff
|
||||
tileMeta = bit.band(bit.bxor(tileMeta, 1), 0xffff)
|
||||
|
||||
-- FIXME further tests?
|
||||
|
||||
return true
|
||||
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()
|
||||
set_timer_timeout(100 * 1000)
|
||||
end
|
||||
|
|
149
game.lua
149
game.lua
|
@ -3,15 +3,27 @@ config = require "config"
|
|||
spritelist = require "spritelist"
|
||||
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()
|
||||
partyX = memory.readword(0x7e0a2a) - 256
|
||||
partyY = memory.readword(0x7e0a2c) - 256
|
||||
tilePtr = memory.readhword(TILEDATA_POINTER)
|
||||
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 cameraY = memory.readword(0x7e17c0) - 256
|
||||
local cameraX = memory.readword(CAMERA_X) - 256
|
||||
local cameraY = memory.readword(CAMERA_Y) - 256
|
||||
|
||||
_M.screenX = (partyX-cameraX)*2
|
||||
_M.screenY = (partyY-cameraY)*2
|
||||
_M.screenX = (partyX-256-cameraX)*2
|
||||
_M.screenY = (partyY-256-cameraY)*2
|
||||
end
|
||||
|
||||
function _M.getBananas()
|
||||
|
@ -52,14 +64,104 @@ function _M.getHitTimer()
|
|||
return memory.readbyte(0x7e08c0) - memory.readbyte(0x7e08be)
|
||||
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)
|
||||
local partyScreenX = (partyX - cameraX) * 2
|
||||
local partyScreenY = (partyY - cameraY) * 2
|
||||
local tileX = math.floor((partyX + dx * TILE_SIZE) / TILE_SIZE) * TILE_SIZE
|
||||
local tileY = math.floor((partyY + dy * TILE_SIZE) / TILE_SIZE) * TILE_SIZE
|
||||
|
||||
x = math.floor((partyX+dx+8)/16)
|
||||
y = math.floor((partyY+dy)/16)
|
||||
local offset = _M.tileOffsetCalculation(tileX, tileY, vertical)
|
||||
|
||||
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
|
||||
|
||||
function _M.getSprites()
|
||||
|
@ -93,26 +195,23 @@ end
|
|||
function _M.getInputs()
|
||||
_M.getPositions()
|
||||
|
||||
sprites = _M.getSprites()
|
||||
extended = _M.getExtendedSprites()
|
||||
-- sprites = _M.getSprites()
|
||||
-- extended = _M.getExtendedSprites()
|
||||
|
||||
local inputs = {}
|
||||
local inputDeltaDistance = {}
|
||||
|
||||
local layer1x = memory.readword(0x7f0000);
|
||||
local layer1y = memory.read_s16_le(0x1C);
|
||||
|
||||
for dy=-config.BoxRadius*16,config.BoxRadius*16,16 do
|
||||
for dx=-config.BoxRadius*16,config.BoxRadius*16,16 do
|
||||
for dy = -config.BoxRadius, config.BoxRadius, 1 do
|
||||
for dx = -config.BoxRadius, config.BoxRadius, 1 do
|
||||
inputs[#inputs+1] = 0
|
||||
inputDeltaDistance[#inputDeltaDistance+1] = 1
|
||||
|
||||
tile = _M.getTile(dx, dy)
|
||||
if tile == 1 and partyY+dy < 0x1B0 then
|
||||
if tile == 1 --[[and partyY+dy < 0x1B0]] then
|
||||
inputs[#inputs] = 1
|
||||
end
|
||||
|
||||
for i = 1,#sprites do
|
||||
--[[ for i = 1,#sprites do
|
||||
distx = math.abs(sprites[i]["x"] - (partyX+dx))
|
||||
disty = math.abs(sprites[i]["y"] - (partyY+dy))
|
||||
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)
|
||||
end
|
||||
end
|
||||
end
|
||||
end ]]
|
||||
|
||||
for i = 1,#extended do
|
||||
--[[ for i = 1,#extended do
|
||||
distx = math.abs(extended[i]["x"] - (partyX+dx))
|
||||
disty = math.abs(extended[i]["y"] - (partyY+dy))
|
||||
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"]
|
||||
local dist = math.sqrt((distx * distx) + (disty * disty))
|
||||
if dist > 8 then
|
||||
|
@ -140,12 +239,12 @@ function _M.getInputs()
|
|||
end
|
||||
--if dist > 100 then
|
||||
--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)
|
||||
--end
|
||||
--inputs[#inputs] = {["value"]=-1, ["dw"]=dw}
|
||||
end
|
||||
end
|
||||
end ]]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
581
neat-donk.lua
581
neat-donk.lua
|
@ -6,6 +6,40 @@ game = require "game"
|
|||
mathFunctions = require "mathFunctions"
|
||||
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
|
||||
Outputs = #config.ButtonNames
|
||||
|
||||
|
@ -149,14 +183,13 @@ function evaluateNetwork(network, inputs, inputDeltas)
|
|||
table.insert(inputs, 1)
|
||||
table.insert(inputDeltas,99)
|
||||
if #inputs ~= Inputs then
|
||||
console.writeline("Incorrect number of neural network inputs.")
|
||||
print("Incorrect number of neural network inputs.")
|
||||
return {}
|
||||
end
|
||||
|
||||
|
||||
for i=1,Inputs do
|
||||
network.neurons[i].value = inputs[i] * inputDeltas[i]
|
||||
--network.neurons[i].value = inputs[i]
|
||||
end
|
||||
|
||||
for _,neuron in pairs(network.neurons) do
|
||||
|
@ -174,7 +207,7 @@ function evaluateNetwork(network, inputs, inputDeltas)
|
|||
|
||||
local outputs = {}
|
||||
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
|
||||
outputs[button] = true
|
||||
else
|
||||
|
@ -625,11 +658,10 @@ function newGeneration()
|
|||
|
||||
pool.generation = pool.generation + 1
|
||||
|
||||
--writeFile("backup." .. pool.generation .. "." .. forms.gettext(saveLoadFile))
|
||||
writeFile(forms.gettext(saveLoadFile) .. ".gen" .. pool.generation .. ".pool")
|
||||
writeFile(saveLoadFile .. ".gen" .. pool.generation .. ".pool")
|
||||
end
|
||||
|
||||
function initializePool()
|
||||
function initializePool(after)
|
||||
pool = newPool()
|
||||
|
||||
for i=1,config.NeatConfig.Population do
|
||||
|
@ -637,14 +669,10 @@ function initializePool()
|
|||
addToSpecies(basic)
|
||||
end
|
||||
|
||||
initializeRun()
|
||||
initializeRun(after)
|
||||
end
|
||||
|
||||
function initializeRun()
|
||||
print("Hello")
|
||||
print(config.NeatConfig.Filename)
|
||||
local rew = movie.to_rewind(config.NeatConfig.Filename)
|
||||
movie.unsafe_rewind(rew)
|
||||
function on_timer()
|
||||
if config.StartPowerup ~= NIL then
|
||||
game.writePowerup(config.StartPowerup)
|
||||
end
|
||||
|
@ -655,14 +683,34 @@ function initializeRun()
|
|||
startBananas = game.getBananas()
|
||||
startCoins = game.getCoins()
|
||||
startLives = game.getLives()
|
||||
checkMarioCollision = true
|
||||
marioHitCounter = 0
|
||||
checkPartyCollision = true
|
||||
partyHitCounter = 0
|
||||
powerUpCounter = 0
|
||||
powerUpBefore = game.getPowerup()
|
||||
local species = pool.species[pool.currentSpecies]
|
||||
local genome = species.genomes[pool.currentGenome]
|
||||
generateNetwork(genome)
|
||||
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
|
||||
|
||||
function evaluateCurrent()
|
||||
|
@ -674,20 +722,218 @@ function evaluateCurrent()
|
|||
|
||||
controller = evaluateNetwork(genome.network, inputs, inputDeltas)
|
||||
|
||||
if controller["P1 Left"] and controller["P1 Right"] then
|
||||
controller["P1 Left"] = false
|
||||
controller["P1 Right"] = false
|
||||
if controller[6] and controller[7] then
|
||||
controller[6] = false
|
||||
controller[7] = false
|
||||
end
|
||||
if controller["P1 Up"] and controller["P1 Down"] then
|
||||
controller["P1 Up"] = false
|
||||
controller["P1 Down"] = false
|
||||
if controller[4] and controller[5] then
|
||||
controller[4] = false
|
||||
controller[5] = false
|
||||
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
|
||||
|
||||
if pool == nil then
|
||||
initializePool()
|
||||
function on_input()
|
||||
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
|
||||
|
||||
function nextGenome()
|
||||
|
@ -709,13 +955,10 @@ function fitnessAlreadyMeasured()
|
|||
return genome.fitness ~= 0
|
||||
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)
|
||||
forms.clear(netPicture,0x80808080)
|
||||
netPicture:clear()
|
||||
netPicture:set()
|
||||
gui.solidrectangle(0, 0, 470, 200, 0x80808080)
|
||||
local network = genome.network
|
||||
local cells = {}
|
||||
local i = 1
|
||||
|
@ -739,17 +982,16 @@ function displayGenome(genome)
|
|||
for o = 1,Outputs do
|
||||
cell = {}
|
||||
cell.x = 220
|
||||
cell.y = 30 + 8 * o
|
||||
cell.y = 30 + 14 * o
|
||||
cell.value = network.neurons[config.NeatConfig.MaxNodes + o].value
|
||||
cells[config.NeatConfig.MaxNodes+o] = cell
|
||||
local color
|
||||
if cell.value > 0 then
|
||||
color = 0xFF0000FF
|
||||
color = 0x000000FF
|
||||
else
|
||||
color = 0xFF000000
|
||||
color = 0x00000000
|
||||
end
|
||||
--gui.drawText(223, 24+8*o, config.ButtonNames[o], color, 9)
|
||||
forms.drawText(netPicture,223, 24+8*o, config.ButtonNames[o], color, 9)
|
||||
gui.text(223, 24+14*o, config.ButtonNames[o], color, 0xff000000)
|
||||
end
|
||||
|
||||
for n,neuron in pairs(network.neurons) do
|
||||
|
@ -799,9 +1041,15 @@ function displayGenome(genome)
|
|||
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)
|
||||
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)
|
||||
--oid forms.drawBox(int componenthandle, int x, int y, int x2, int y2, [color? line = null], [color? background = null])
|
||||
gui.rectangle(
|
||||
50-config.BoxRadius*5-3,
|
||||
70-config.BoxRadius*5-3,
|
||||
config.BoxRadius*10+5,
|
||||
config.BoxRadius*10+5,
|
||||
2,
|
||||
0xFF000000,
|
||||
0x80808080
|
||||
)
|
||||
for n,cell in pairs(cells) do
|
||||
if n > Inputs or cell.value ~= 0 then
|
||||
local color = math.floor((cell.value+1)/2*256)
|
||||
|
@ -812,8 +1060,15 @@ function displayGenome(genome)
|
|||
opacity = 0x50000000
|
||||
end
|
||||
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.drawBox(cell.x-2,cell.y-2,cell.x+2,cell.y+2,opacity,color)
|
||||
gui.rectangle(
|
||||
math.floor(cell.x-5),
|
||||
math.floor(cell.y-5),
|
||||
5,
|
||||
5,
|
||||
1,
|
||||
0x00,
|
||||
color
|
||||
)
|
||||
end
|
||||
end
|
||||
for _,gene in pairs(genome.genes) do
|
||||
|
@ -831,65 +1086,40 @@ function displayGenome(genome)
|
|||
else
|
||||
color = opacity + 0x800000 + 0x100*color
|
||||
end
|
||||
--gui.drawLine(c1.x+1, c1.y, c2.x-3, c2.y, color)
|
||||
forms.drawLine(netPicture,c1.x+1, c1.y, c2.x-3, c2.y, color)
|
||||
gui.line(
|
||||
math.floor(c1.x+1),
|
||||
math.floor(c1.y),
|
||||
math.floor(c2.x-3),
|
||||
math.floor(c2.y),
|
||||
color
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
--gui.drawBox(49,71,51,78,0x00000000,0x80FF0000)
|
||||
forms.drawBox(netPicture, 49,71,51,78,0x00000000,0x80FF0000)
|
||||
--if forms.ischecked(showMutationRates) then
|
||||
gui.rectangle(
|
||||
49,
|
||||
71,
|
||||
2,
|
||||
7,
|
||||
0x00000000,
|
||||
0x80FF0000
|
||||
)
|
||||
|
||||
local pos = 100
|
||||
for mutation,rate in pairs(genome.mutationRates) do
|
||||
--gui.drawText(100, pos, mutation .. ": " .. rate, 0xFF000000, 10)
|
||||
forms.drawText(netPicture,100, pos, mutation .. ": " .. rate, 0xFF000000, 10)
|
||||
--forms.drawText(pictureBox,400,pos, mutation .. ": " .. rate)
|
||||
gui.text(100, pos, mutation .. ": " .. rate, 0x00000000, 0xff000000)
|
||||
|
||||
--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 + 8
|
||||
end
|
||||
--end
|
||||
forms.refresh(netPicture)
|
||||
pos = pos + 14
|
||||
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()
|
||||
local bitmap = netPicture:render()
|
||||
form:set()
|
||||
bitmap:draw(5, 250)
|
||||
gui.renderctx.setnull()
|
||||
end
|
||||
|
||||
function savePool()
|
||||
local filename = forms.gettext(saveLoadFile)
|
||||
local filename = saveLoadFile
|
||||
print(filename)
|
||||
writeFile(filename)
|
||||
end
|
||||
|
@ -906,7 +1136,7 @@ function mysplit(inputstr, sep)
|
|||
return t
|
||||
end
|
||||
|
||||
function loadFile(filename)
|
||||
function loadFile(filename, after)
|
||||
print("Loading pool from " .. filename)
|
||||
local file = io.open(filename, "r")
|
||||
pool = newPool()
|
||||
|
@ -961,9 +1191,11 @@ function loadFile(filename)
|
|||
while fitnessAlreadyMeasured() do
|
||||
nextGenome()
|
||||
end
|
||||
initializeRun()
|
||||
initializeRun(function()
|
||||
pool.currentFrame = pool.currentFrame + 1
|
||||
print("Pool loaded.")
|
||||
after()
|
||||
end)
|
||||
end
|
||||
|
||||
function flipState()
|
||||
|
@ -976,11 +1208,9 @@ function flipState()
|
|||
end
|
||||
end
|
||||
|
||||
function loadPool()
|
||||
function loadPool(after)
|
||||
filename = forms.openfile("DP1.state.pool",config.PoolDir)
|
||||
--local filename = forms.gettext(saveLoadFile)
|
||||
forms.settext(saveLoadFile, filename)
|
||||
loadFile(filename)
|
||||
loadFile(filename, after)
|
||||
end
|
||||
|
||||
function playTop()
|
||||
|
@ -999,167 +1229,24 @@ function playTop()
|
|||
pool.currentSpecies = maxs
|
||||
pool.currentGenome = maxg
|
||||
pool.maxFitness = maxfitness
|
||||
forms.settext(MaxLabel, "Max Fitness: " .. math.floor(pool.maxFitness))
|
||||
--forms.settext(MaxLabel, "Max Fitness: " .. math.floor(pool.maxFitness))
|
||||
initializeRun()
|
||||
pool.currentFrame = pool.currentFrame + 1
|
||||
return
|
||||
end
|
||||
|
||||
function onExit()
|
||||
forms.destroy(form)
|
||||
function on_quit()
|
||||
netPicture:clear()
|
||||
form:clear()
|
||||
end
|
||||
|
||||
if pool == nil then
|
||||
initializePool(function()
|
||||
writeFile(config.PoolDir.."temp.pool")
|
||||
|
||||
event.onexit(onExit)
|
||||
|
||||
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)
|
||||
|
||||
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()
|
||||
mainLoop()
|
||||
end)
|
||||
else
|
||||
writeFile(config.PoolDir.."temp.pool")
|
||||
mainLoop()
|
||||
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
|
||||
-- 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.
|
||||
0x72, -- Super Koopa, yellow cape, swoop.
|
||||
0x73, -- Super Koopa, feather/yellow cape (X&1).
|
||||
0x7A, -- Firework, makes Mario temporarily invisible.
|
||||
0x7A, -- Firework, makes party temporarily invisible.
|
||||
0x86, -- Wiggler.
|
||||
0x8D, -- Ghost house exit sign and door.
|
||||
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