BeeBee: BasicBot frontend and LuaBot. Pretty much stable, afaik.

This commit is contained in:
qfox 2008-08-01 21:58:18 +00:00
parent c6b90a037e
commit dc97747998
2 changed files with 86 additions and 27 deletions

View File

@ -1,11 +1,11 @@
-- LuaBot, concept bot for FCEU and ZSnes and any other emu that has compatible Lua engine -- LuaBot, concept bot for FCEU and snes9x and any other emu that has compatible Lua engine
-- qFox, 30 July 2008 -- qFox, 30 July 2008
-- version 1.04 -- version 1.06
-- Botscript data following -- Botscript data following:
-- Rom: ROMNAME -- Rom: -- ROMNAME
-- Comment: COMMENT -- Comment: -- COMMENT
-- Version: VERSION -- Version: -- VERSION
local function realcount(t) -- accurately count the number of elements of a table, even if they contain nil values. not fast, but accurate. local function realcount(t) -- accurately count the number of elements of a table, even if they contain nil values. not fast, but accurate.
local n = 0; local n = 0;
@ -34,8 +34,12 @@ end;
local loopcounter = 0; -- counts the main loop local loopcounter = 0; -- counts the main loop
local key1 = {}; -- holds the to be pressed keys this frame for player 1 local key1 = {}; -- holds the to be pressed keys this frame for player 1
local key2 = {}; -- holds the to be pressed keys this frame for player 2 local key2 = {}; -- holds the to be pressed keys this frame for player 2
local key3 = {}; -- holds the to be pressed keys this frame for player 3
local key4 = {}; -- holds the to be pressed keys this frame for player 4
local lastkey1 = {}; -- keys pressed in previous frame for player 1 local lastkey1 = {}; -- keys pressed in previous frame for player 1
local lastkey2 = {}; -- keys pressed in previous frame for player 2 local lastkey2 = {}; -- keys pressed in previous frame for player 2
local lastkey3 = {}; -- keys pressed in previous frame for player 1
local lastkey4 = {}; -- keys pressed in previous frame for player 2
local frame = 0; -- number of frames (current value is current frame count, incremented at the start of a new frame) local frame = 0; -- number of frames (current value is current frame count, incremented at the start of a new frame)
local attempt = 1; -- number of attempts (current value is current attempt, incremented after the end of an attempt) local attempt = 1; -- number of attempts (current value is current attempt, incremented after the end of an attempt)
local segment = 1; -- number of segments (current value is current segment, incremented after the end of a segment) local segment = 1; -- number of segments (current value is current segment, incremented after the end of a segment)
@ -53,6 +57,8 @@ local maxsegments = 100;
local playingbest = false; -- when going to the next segment, we need to play the best segment to record, this indicates when we're doing so local playingbest = false; -- when going to the next segment, we need to play the best segment to record, this indicates when we're doing so
local keyrecording1 = {}; -- every key pressed for player 1 is put in here local keyrecording1 = {}; -- every key pressed for player 1 is put in here
local keyrecording2 = {}; -- every key pressed for player 2 is put in here local keyrecording2 = {}; -- every key pressed for player 2 is put in here
local keyrecording3 = {}; -- every key pressed for player 3 is put in here
local keyrecording4 = {}; -- every key pressed for player 4 is put in here
-- some constants/macro's/whatever to make source easier to read -- some constants/macro's/whatever to make source easier to read
local press = maxvalue; local press = maxvalue;
@ -365,17 +371,21 @@ local function onInputEnd() -- code ran after getting input (lastkey are still v
-- ONINPUTEND -- ONINPUTEND
end; end;
-- the bot starts here.. -- the bot starts here.. (nothing is added from the user from this point onwards)
onStart(); -- run this code first onStart(); -- run this code first
segments[segment].savestate = savestate.create(); -- create anonymous savestate obj for start of first segment segments[segment].savestate = savestate.create(); -- create anonymous savestate obj for start of first segment
savestate.save(segments[segment].savestate); -- save current state to it, it will be reloaded at the start of each frame savestate.save(segments[segment].savestate); -- save current state to it, it will be reloaded at the start of each frame
local startkey1 = key1; -- save the last key pressed in the onStart. serves as an anchor for the first segment local startkey1 = key1; -- save the last key pressed in the onStart. serves as an anchor for the first segment
local startkey2 = key2; local startkey2 = key2;
local startkey3 = key3; -- save the last key pressed in the onStart. serves as an anchor for the first segment
local startkey4 = key4;
local startvars = vars; -- save the vars array (it might have been used by the onStart) local startvars = vars; -- save the vars array (it might have been used by the onStart)
lastkey1 = key1; -- to enter the loop... lastkey1 = key1; -- to enter the loop...
lastkey2 = key2; lastkey2 = key2;
lastkey3 = key3;
lastkey4 = key4;
--FCEU.speedmode("maximum"); -- uncomment this line to make the bot run faster ("normal","turbo","maximum") --FCEU.speedmode("maximum"); -- uncomment this line to make the bot run faster ("normal","turbo","maximum")
onSegmentStart(); onSegmentStart();
@ -429,8 +439,12 @@ while (rand_if(isRunEnd())) do
segments[segment].best.tie4 = segments[segment].prev.tie4; segments[segment].best.tie4 = segments[segment].prev.tie4;
segments[segment].best.keys1 = keyrecording1; -- backup the recorded keys segments[segment].best.keys1 = keyrecording1; -- backup the recorded keys
segments[segment].best.keys2 = keyrecording2; -- backup the recorded keys player 2 segments[segment].best.keys2 = keyrecording2; -- backup the recorded keys player 2
segments[segment].best.keys3 = keyrecording3; -- backup the recorded keys
segments[segment].best.keys4 = keyrecording4; -- backup the recorded keys player 2
segments[segment].best.lastkey1 = lastkey1; -- backup the lastkey segments[segment].best.lastkey1 = lastkey1; -- backup the lastkey
segments[segment].best.lastkey2 = lastkey2; -- backup the lastkey segments[segment].best.lastkey2 = lastkey2; -- backup the lastkey
segments[segment].best.lastkey3 = lastkey3; -- backup the lastkey
segments[segment].best.lastkey4 = lastkey4; -- backup the lastkey
segments[segment].best.vars = vars; -- backup the vars table segments[segment].best.vars = vars; -- backup the vars table
end end
@ -454,6 +468,8 @@ while (rand_if(isRunEnd())) do
frame = 0; frame = 0;
keyrecording1 = {}; -- reset the recordings :) keyrecording1 = {}; -- reset the recordings :)
keyrecording2 = {}; keyrecording2 = {};
keyrecording3 = {};
keyrecording4 = {};
-- set lastkey to lastkey of previous segment (or start, if first segment) -- set lastkey to lastkey of previous segment (or start, if first segment)
-- also set the vars table to the table of the previous segment -- also set the vars table to the table of the previous segment
if (segment == 1) then if (segment == 1) then
@ -463,6 +479,8 @@ while (rand_if(isRunEnd())) do
else else
lastkey1 = segments[segment-1].best.lastkey1; lastkey1 = segments[segment-1].best.lastkey1;
lastkey2 = segments[segment-1].best.lastkey2; lastkey2 = segments[segment-1].best.lastkey2;
lastkey3 = segments[segment-1].best.lastkey3;
lastkey4 = segments[segment-1].best.lastkey4;
vars = segments[segment-1].best.vars; vars = segments[segment-1].best.vars;
end; end;
-- load the segment savestate to go back to the start of this segment -- load the segment savestate to go back to the start of this segment
@ -486,6 +504,8 @@ while (rand_if(isRunEnd())) do
playingbest = false; playingbest = false;
lastkey1 = segments[segment].best.lastkey1; lastkey1 = segments[segment].best.lastkey1;
lastkey2 = segments[segment].best.lastkey2; lastkey2 = segments[segment].best.lastkey2;
lastkey3 = segments[segment].best.lastkey3;
lastkey4 = segments[segment].best.lastkey4;
vars = segments[segment].best.vars; vars = segments[segment].best.vars;
segment = segment + 1; segment = segment + 1;
segments[segment] = {}; segments[segment] = {};
@ -495,10 +515,11 @@ while (rand_if(isRunEnd())) do
-- reset vars -- reset vars
frame = 0; -- onSegmentStart and onAttemptStart expect this to be one fewer... frame = 0; -- onSegmentStart and onAttemptStart expect this to be one fewer...
attempt = 1; attempt = 1;
--key1 = {}; -- i dont think this has to be done just for the two events below. they get reset anyways before input.
--key2 = {};
keyrecording1 = {}; -- reset recordings :) keyrecording1 = {}; -- reset recordings :)
keyrecording2 = {}; keyrecording2 = {};
keyrecording3 = {};
keyrecording4 = {};
-- after this, the next segment starts because playingbest is no longer true -- after this, the next segment starts because playingbest is no longer true
onSegmentStart(); onSegmentStart();
onAttemptStart(); onAttemptStart();
@ -506,6 +527,8 @@ while (rand_if(isRunEnd())) do
else else
key1 = segments[segment].best.keys1[frame]; -- fill keys with that of the best attempt key1 = segments[segment].best.keys1[frame]; -- fill keys with that of the best attempt
key2 = segments[segment].best.keys2[frame]; key2 = segments[segment].best.keys2[frame];
key3 = segments[segment].best.keys3[frame];
key4 = segments[segment].best.keys4[frame];
gui.text(10,10,"Playback best of segment "..segment.."\nFrame: "..frame); gui.text(10,10,"Playback best of segment "..segment.."\nFrame: "..frame);
end; end;
end; end;
@ -526,6 +549,8 @@ while (rand_if(isRunEnd())) do
key1 = {}; key1 = {};
key2 = {}; key2 = {};
key3 = {};
key4 = {};
onInputStart(); onInputStart();
@ -549,18 +574,44 @@ while (rand_if(isRunEnd())) do
if (rand_if(pressKeySelect2())) then key2.select = 1; end; if (rand_if(pressKeySelect2())) then key2.select = 1; end;
if (rand_if(pressKeyStart2())) then key2.start = 1; end; if (rand_if(pressKeyStart2())) then key2.start = 1; end;
-- player 3
if (rand_if(pressKeyUp3()) ) then key3.up = 1; end;
if (rand_if(pressKeyDown3())) then key3.down = 1; end;
if (rand_if(pressKeyLeft3())) then key3.left = 1; end;
if (rand_if(pressKeyRight3())) then key3.right = 1; end;
if (rand_if(pressKeyA3())) then key3.A = 1; end;
if (rand_if(pressKeyB3())) then key3.B = 1; end;
if (rand_if(pressKeySelect3())) then key3.select = 1; end;
if (rand_if(pressKeyStart3())) then key3.start = 1; end;
-- player 2
if (rand_if(pressKeyUp4()) ) then key4.up = 1; end;
if (rand_if(pressKeyDown4())) then key4.down = 1; end;
if (rand_if(pressKeyLeft4())) then key4.left = 1; end;
if (rand_if(pressKeyRight4())) then key4.right = 1; end;
if (rand_if(pressKeyA4())) then key4.A = 1; end;
if (rand_if(pressKeyB4())) then key4.B = 1; end;
if (rand_if(pressKeySelect4())) then key4.select = 1; end;
if (rand_if(pressKeyStart4())) then key4.start = 1; end;
onInputEnd(); onInputEnd();
lastkey1 = key1; lastkey1 = key1;
lastkey2 = key2; lastkey2 = key2;
lastkey3 = key3;
lastkey4 = key4;
keyrecording1[frame] = key1; -- record these keys keyrecording1[frame] = key1; -- record these keys
keyrecording2[frame] = key2; -- record these keys keyrecording2[frame] = key2; -- record these keys
keyrecording3[frame] = key3; -- record these keys
keyrecording4[frame] = key4; -- record these keys
end; end;
-- actually set the keys here. -- actually set the keys here.
joypad.set(1, key1); joypad.set(1, key1);
joypad.set(2, key2); joypad.set(2, key2);
joypad.set(3, key3);
joypad.set(4, key4);
-- next frame -- next frame
FCEU.frameadvance(); FCEU.frameadvance();

View File

@ -1,7 +1,4 @@
-- BasicBot, a LuaBot frontend -- BeeBee, BasicBot Frontend v1.06
-- qFox, 30 July 2008
-- version 1.04 (unstable load button!)
-- we need iup, so include it here -- we need iup, so include it here
local iuplua_open = package.loadlib("iuplua51.dll", "iuplua_open"); local iuplua_open = package.loadlib("iuplua51.dll", "iuplua_open");
iuplua_open(); iuplua_open();
@ -37,12 +34,12 @@ function emu.OnCloseIup()
end; end;
function createTextareaTab(reftable, tmptable, token, tab, fun, val) -- specific one, at that :) function createTextareaTab(reftable, tmptable, token, tab, fun, val) -- specific one, at that :)
reftable[token] = iup.multiline{title="Contents",expand="YES", border="YES",value=val}; reftable[token] = iup.multiline{title="Contents",expand="YES", border="YES" }; -- ,value=val};
tmptable[token] = iup.vbox{iup.label{title="function "..fun.."()\n local result = no;"},reftable[token],iup.label{title=" return result;\nend;"}}; tmptable[token] = iup.vbox{iup.label{title="function "..fun.."()\n local result = no;"},reftable[token],iup.label{title=" return result;\nend;"}};
tmptable[token].tabtitle = tab; tmptable[token].tabtitle = tab;
end; end;
function createTextareaTab2(reftable, tmptable, token, fun, arg) -- specific one, at that :) this one generates no return values function createTextareaTab2(reftable, tmptable, token, fun, arg) -- specific one, at that :) this one generates no return values
reftable[token] = iup.multiline{title="Contents",expand="YES", border="YES",value=fun}; reftable[token] = iup.multiline{title="Contents",expand="YES", border="YES" }; --,value=fun};
if (arg) then if (arg) then
tmptable[token] = iup.vbox{iup.label{title="function "..fun.."(wasOk) -- wasOk (boolean) is true when the attempt was ok\n"},reftable[token],iup.label{title="end;"}}; tmptable[token] = iup.vbox{iup.label{title="function "..fun.."(wasOk) -- wasOk (boolean) is true when the attempt was ok\n"},reftable[token],iup.label{title="end;"}};
else else
@ -148,7 +145,7 @@ function createGUI(n)
tabs7.tabtitle = "Selection"; tabs7.tabtitle = "Selection";
playertabs = iup.tabs{general,tabs1,tabs2,tabs3,tabs4,tabs5,tabs6,tabs7,title}; playertabs = iup.tabs{general,tabs1,tabs2,tabs3,tabs4,tabs5,tabs6,tabs7,title};
handles[n] = iup.dialog{playertabs, title="Basic Bot Frontend", size="450x200"} handles[n] = iup.dialog{playertabs, title="BeeBee; BasicBot Frontend", size="450x200"}
handles[n]:showxy(iup.CENTER, iup.CENTER) handles[n]:showxy(iup.CENTER, iup.CENTER)
-- now set the callback function for the save button. this will use all the references above. -- now set the callback function for the save button. this will use all the references above.
@ -242,22 +239,33 @@ function createGUI(n)
local file = iup.filedlg{allownew="NO",dialogtype="OPEN",directory="./lua",showhidden="YES",title="Save botfile",extfilter="BasicBot (*.bot)|*.bot|All files (*.*)|*.*|"}; local file = iup.filedlg{allownew="NO",dialogtype="OPEN",directory="./lua",showhidden="YES",title="Save botfile",extfilter="BasicBot (*.bot)|*.bot|All files (*.*)|*.*|"};
file:popup(iup.ANYWHERE,iup.ANYWHERE); file:popup(iup.ANYWHERE,iup.ANYWHERE);
if (file.status == 1) then -- cancel if (file.status == 1) then -- cancel
iup.Message ("Success", "Canceled by you...");
return; return;
end; end;
local nellen = string.len("\n"); -- platform independent local nellen = string.len("\n"); -- platform independent
fh = assert(io.open(file.value,"r")); fh = assert(io.open(file.value,"r"));
print("seek: "..fh:seek());
print("version: "..fh:read("*l")); fh:read("*n"); -- version
print("seek: "..fh:seek()); fh:read("*l"); -- return
if (true) then return; end;
local len;
local data;
for token,crap in pairs(reftable) do for token,crap in pairs(reftable) do
local len = fh:read("*n"); -- read line (length) len = fh:read("*n"); -- read line (length)
if (not len) then break; end; if (not len) then
fh:seek("set",fh:seek("cur", nellen)); -- remove the aesthetic return iup.Message ("Warning", "End of file reached too soon!");
print(len); break;
reftable[token].value = fh:read(len); end; -- no more data... (should we erase the rest?)
fh:seek("set",fh:seek("cur", nellen)); -- remove the aesthetic return fh:read("*l"); -- return
data = fh:read(len);
if (not data) then
iup.Message ("Warning", "End of file reached too soon!");
break;
end; -- no more data... (should we erase the rest?)
reftable[token].value = data;
fh:read("*l"); -- return
end; end;
iup.Message ("Success", "Settings loaded!");
end; end;
end; end;