Skip to content

Instantly share code, notes, and snippets.

@TheLeftExit
Created April 18, 2026 14:03
Show Gist options
  • Select an option

  • Save TheLeftExit/1f0577ec65bfc753a02c1f1afe45de3a to your computer and use it in GitHub Desktop.

Select an option

Save TheLeftExit/1f0577ec65bfc753a02c1f1afe45de3a to your computer and use it in GitHub Desktop.
Chao Memory solver v2 (mGBA script)
if cbid then
return
end
buffer = console:createBuffer("Test buffer")
function indexof(t, v)
for key, value in pairs(t) do
if value == v then
return key
end
end
end
function processFrameCore()
local cardState = emu:read8(0x030019DC) -- 0..1: number of visible cards, else: waiting
if cardState > 1 then return end
local cursorX = emu:read8(0x030019AE) -- 0..5
local cursorY = emu:read8(0x030019AF) -- 0..4
local revealedCardX = emu:read8(0x030019EA) -- 0..5
local revealedCardY = emu:read8(0x030019EB) -- 0..4
local cardDataRaw = emu:readRange(0x03001990, 30) -- flattened 6x5 map (00..0D, FF)
local cardData = {}
for i = 0, 29 do
cardData[i] = string.byte(cardDataRaw, i + 1)
end
-- find next target
local targetPosition
if cardState == 1 then
-- find the matching card
local revealedCardId = cardData[revealedCardY * 6 + revealedCardX]
local targetId
if revealedCardId % 2 == 0 then
targetId = revealedCardId + 1
else
targetId = revealedCardId - 1
end
targetPosition = indexof(cardData, targetId)
console:log("Revealed card: "..tostring(revealedCardId))
console:log("Matching card: "..tostring(targetId).." at "..tostring(targetPosition))
else
-- find the closest remaining card
local targetDistance = 10
for position, id in pairs(cardData) do
local x = position % 6
local y = position // 6
local distance = math.abs(x - cursorX) + math.abs(y - cursorY)
if id ~= 255 and distance < targetDistance then
targetPosition = position
targetDistance = distance
end
end
console:log("Closest card at: "..tostring(targetPosition))
end
for position, id in pairs(cardData) do
buffer:moveCursor((position % 6) * 3, position // 6)
if(id ~= 255) then
buffer:print(tostring(id))
else
buffer:print("--")
end
buffer:moveCursor(0, 5)
buffer:print("Going to " .. tostring(targetPosition % 6) .. "," .. tostring(targetPosition // 6))
end
local deltaX = (targetPosition % 6) - cursorX
local deltaY = (targetPosition // 6) - cursorY
if deltaX < 0 then
emu:addKey(C.GBA_KEY.LEFT)
elseif deltaX > 0 then
emu:addKey(C.GBA_KEY.RIGHT)
elseif deltaY < 0 then
emu:addKey(C.GBA_KEY.UP)
elseif deltaY > 0 then
emu:addKey(C.GBA_KEY.DOWN)
else
emu:addKey(C.GBA_KEY.A)
end
end
function processFrame()
buffer:clear()
if(emu:getKey(C.GBA_KEY.B) ~= 0) then
buffer:setName("Discarded buffer")
callbacks:remove(cbid)
emu:setKeys(0)
cbid = nil
return
end
-- if we just pressed something, release and skip frame - effectively turboing the key
if(emu:getKeys() ~= 0) then
emu:setKeys(0)
return
end
gameState = emu:read8(0x030019D8)
if gameState == 00 then -- Not in memory game
buffer:print("Not in Chao Memory")
emu:addKey(C.GBA_KEY.A)
elseif gameState == 06 then
processFrameCore()
else
buffer:print("Waiting in Chao Memory")
end
end
cbid = callbacks:add("frame", processFrame)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment