Hello all,
I'm planning on making my first TAS. My goal is to make one in which I complete Very Hard mode of the classic puzzle game "Panel de Pon" as fast as possible. Although I'm debating this, I am hoping to accomplish this all with a Lua bot and zero human input. I want this for a multitude of reasons:
- The bot could probably run on multiple versions of the same game, so long as the memory addresses are slightly modified.
- Improving on the speed would be a lot simpler than redoing the entire game.
- It could serve as an educating experience for both myself and the TAS community.
- AI is fun!
In its current form, it will navigate to VS, select Very Hard mode, start the match, and move to a particular location on the grid. Also, it defines a function "cursor" that can be used to tell the bot to move the cursor so that the left cursor box is at the given column (Which can be anything integer 0 to 4) and row (Which can be anything integer 0 to 10) of the 11x5 playing grid. Presumably, the next step is to parse the grid and to have the bot decide what moves to make accordingly.
So, if anyone has any ideas or wants to contribute, I'm all ears. My current code can be seen below:
Language: lua
function chain()
end
function cursor(col, row)
local mode
while mode == nil or mode == 1 do
mode = memory.readbyte(0x7E00B1)
local coal = memory.readbyte(0x7E03A6)
local roal = 15 - memory.readbyte(0x7E03AA)
if coal > col then
press(1, {left=true})
end
if coal < col then
press(1, {right=true})
end
if roal <row> row then
press(1, {down=true})
end
if coal == col and roal == row then
break
end
end
end
function draw()
local grid = parse()
local ascii = ''
for row = 11, 1, -1 do
ascii = ascii .. '|'
for col = 1, 6 do
ascii = ascii .. grid[col][row] .. '|'
end
ascii = ascii .. '\n'
end
gui.text(105, 0, ascii)
end
function parse()
local array = {}
for col = 0, 5 do
local entry = {}
for row = 0, 10 do
local address = 0x7E1860 + (col * 2) - (row * 0x10)
local value = memory.readbyte(address)
if memory.readbyte(address + 1) ~= 0 then
value = 'G'
end
table.insert(entry, value)
end
table.insert(array, entry)
end
return array
end
function press(controller, buttons)
joypad.set(controller, buttons)
draw()
emu.frameadvance()
gui.text(0, 0, tostring(buttons))
for index, value in pairs(buttons) do
buttons[index] = false
end
joypad.set(controller, buttons)
draw()
emu.frameadvance()
end
function solve()
local grid = parse()
for row = 1, 11 do
local blocks = {}
for col = 1, 6 do
local block = tostring(grid[col][row])
if blocks[block] == nil then
blocks[block] = 0
end
blocks[block] = blocks[block] + 1
end
for index, value in pairs(blocks) do
if index ~= '0' and index ~= 'G' and value > 2 then
for col = 1, 5 do
if tostring(grid[col][row]) == index then
if tostring(grid[col + 1][row]) == index then
break
end
cursor(col, row)
press(1, {A=true})
end
end
for col = 6, 2, -1 do
if tostring(grid[col][row]) == index then
if tostring(grid[col - 1][row]) == index then
break
end
cursor(col - 1, row)
press(1, {A=true})
end
end
end
end
end
for group = 1, 11 do
local blocks = {}
for i = 1, 7 do
blocks[tostring(i)] = true
end
for row = 0, 2 do
local missing = {}
for i = 1, 7 do
missing[tostring(i)] = true
end
for col = 1, 6 do
missing[tostring(grid[col][group + row])] = nil
end
for index, value in pairs(missing) do
blocks[index] = nil
end
end
for index, value in pairs(blocks) do
for row = 0, 1 do
local start = -1
local finish = -1
for col = 1, 6 do
if tostring(grid[col][group + (row * 2)]) == index then
start = col
break
end
end
for col = 1, 6 do
if tostring(grid[col][group + 1]) == index then
finish = col
break
end
end
if start == -1 or finish == -1 then
break
end
while start <finish> finish do
cursor(start - 1, group + (row * 2))
press(1, {A=true})
start = start - 1
end
end
end
end
for row = 11, 1, -1 do
for col = 1, 6 do
if grid[col][row] ~= 0 and grid[col][row] ~= 'G' and row ~= 0 then
if col ~= 1 and grid[col - 1][row - 1] == 0 then
cursor(col - 1, row)
press(1, {A=true})
end
if col ~= 6 and grid[col + 1][row - 1] == 0 then
cursor(col, row)
press(1, {A=true})
end
end
end
end
for col = 1, 6 do
if grid[col][6] ~= 0 and grid[col][6] ~= 'G' then
return
end
end
press(1, {R=true})
end
while true do
local menu = memory.readbyte(0x7EA138)
if memory.readbyte(0x7E5564) ~= 0 and menu == 0 then
press(1, {A=true})
end
if menu == 1 then
press(1, {A=true})
end
if menu == 6 then
press(1, {up=true})
press(1, {A=true})
end
if menu == 10 then
if memory.readbyte(0x7E9677) == 126 then
press(1, {left=true})
elseif memory.readbyte(0x7E9677) == 109 then
press(1, {A=true, L=true, up=true})
elseif memory.readbyte(0x7E00B1) == 1 then
solve()
else
press(1, {start=true})
end
end
draw()
emu.frameadvance()
end