Download bot.cppLanguage: cpp
#include <stdio>
#include <stdarg>
#include <stdlib>
#include <string>
#include <time>
#include <algorithm>
#include <sstream>
#include <vector>
#include <bitset>
#include <deque>
#include <map>
#include <sys>
#include <sys>
#include <sys>
#include <unistd>
#include <boost>
#include <boost>
#include <boost>
static boost::mt19937 rng;
template<unsigned>
static inline unsigned GetRnd()
{
static boost::uniform_int<int> g(0, mod-1);
return g(rng);
}
static inline unsigned GetRnd(unsigned mod)
{
return boost::uniform_int<int> (0,mod-1) (rng);
}
static class BitSet16bit
{
unsigned* data;
unsigned setcount;
enum { bitsper = 8*sizeof(unsigned) };
enum { max = 0x10000U / bitsper };
public:
BitSet16bit() : data(0)
{
reset();
}
void reset()
{
delete[] data;
data = new unsigned[ max ];
for(size_t a=0; a<max; ++a) data[a] = 0;
setcount = 0;
}
void set(size_t index)
{
if(!operator[] (index))
{
data[ offset(index) ] |= mask(index);
++setcount;
}
}
inline bool operator[] (size_t index) const
{
return data [ offset(index) ] & mask(index);
}
inline size_t count() const
{
return setcount;
}
private:
BitSet16bit(const BitSet16bit&);
void operator=(const BitSet16bit&);
size_t offset(size_t index) const { return index / (bitsper); }
size_t mask(size_t index) const { return 1UL << (index % bitsper); }
} covered_preshots;
static class BitSet32bit
{
unsigned* data;
unsigned setcount;
enum { bitsper = 8*sizeof(unsigned) };
enum { max = (0x10000000U / bitsper)*0x10U };
public:
BitSet32bit() : data(0)
{
reset();
}
void reset()
{
delete[] data;
data = new unsigned[ max ];
for(size_t a=0; a<max; ++a) data[a] = 0;
setcount = 0;
}
void set(size_t index)
{
if(!operator[] (index))
{
data[ offset(index) ] |= mask(index);
++setcount;
}
}
inline bool operator[] (size_t index) const
{
return data [ offset(index) ] & mask(index);
}
inline size_t count() const
{
return setcount;
}
private:
BitSet32bit(const BitSet32bit&);
void operator=(const BitSet32bit&);
size_t offset(size_t index) const { return index / bitsper; }
size_t mask(size_t index) const { return 1UL << (index % bitsper); }
} covered_candidates;
static class deathset
{
int fd;
public:
deathset()
{
fd = open("/tmp/endcueset.dat", O_RDWR | O_CREAT | O_TRUNC, 0644);
reset();
}
void reset()
{
unsigned buf[0x10000];
for(size_t n=0; n<0x10000; ++n) buf[n] = 0;
flock(fd, LOCK_EX);
pwrite(fd, buf, 0x10000*sizeof(unsigned), 0);
flock(fd, LOCK_UN);
}
unsigned operator[] (size_t n) const
{
unsigned b = 0;
flock(fd, LOCK_EX);
pread(fd, &b, sizeof(unsigned), n*sizeof(unsigned));
flock(fd, LOCK_UN);
return b;
}
void set(size_t n, unsigned nframes)
{
unsigned b=0;
flock(fd, LOCK_EX);
pread(fd, &b, sizeof(unsigned), n*sizeof(unsigned));
if(b == 0 || nframes < b)
pwrite(fd, &nframes, sizeof(unsigned), n*sizeof(unsigned));
fdatasync(fd);
flock(fd, LOCK_UN);
}
size_t count() const
{
size_t result = 0;
unsigned buf[0x10000];
for(size_t n=0; n<0x10000; ++n) buf[n] = 0;
flock(fd, LOCK_EX);
pread(fd, buf, 0x10000*sizeof(unsigned), 0);
flock(fd, LOCK_UN);
for(size_t n=0; n<0x10000>= 9899
# include "../../../types.h"
# include "../../../state.h"
# include "../../../movie.h"
# include "../../../utils/memorystream.h"
# include "../../../fceu.h"
# include "../../../driver.h"
# include "../coroutine.h"
#else
extern "C" {
# include "types.h"
# include "state.h"
# include "movie.h"
# include "fceu.h"
}
# include "coroutine.h"
#endif
#define BISQBOT_INTERNAL
#include "bisqbotdefs.hh"
#include "bisqbot.hh"
int BotFrontDisableVideo=0;
#define INCLUDE_BOT_IN_SAVESTATE 0
struct SaveState
{
std::vector<unsigned> Data;
#if INCLUDE_BOT_IN_SAVESTATE
const BisqBotStateBase* Bot;
SaveState() : Bot(0) { }
~SaveState() { delete Bot; }
#endif
void Create()
{
#if INCLUDE_BOT_IN_SAVESTATE
delete Bot;
#endif
#if defined(FCEU_VERSION_NUMERIC) && FCEU_VERSION_NUMERIC >= 9899
memorystream ms;
FCEUSS_SaveMS(&ms, 0);
Data.resize(ms.size());
memcpy(&Data[0], ms.buf(), Data.size());
#else
FILE*fp = tmpfile();
FCEUSS_SaveFP(fp);
rewind(fp);
fseek(fp,0,SEEK_END);
long pos = ftell(fp);
rewind(fp);
SaveState result;
Data.resize(pos);
fread(&Data[0], 1, pos, fp);
fclose(fp);
#endif
#if INCLUDE_BOT_IN_SAVESTATE
Bot = BisqBotNewSaveState();
#endif
}
void Load() const
{
#if defined(FCEU_VERSION_NUMERIC) && FCEU_VERSION_NUMERIC >= 9899
memorystream ms;
ms.write( (const char*) &Data[0], Data.size());
ms.seekg(0);
FCEUSS_LoadFP(&ms, SSLOADPARAM_NOBACKUP);
#else
FILE*fp = tmpfile();
fwrite(&Data[0], 1, Data.size(), fp);
rewind(fp);
FCEUSS_LoadFP(fp, 0);
fclose(fp);
#endif
#if INCLUDE_BOT_IN_SAVESTATE
BisqBotLoadState(Bot);
#endif
}
#if INCLUDE_BOT_IN_SAVESTATE
private:
SaveState(const SaveState& b);
void operator=(const SaveState& b);
#endif
};
static unsigned char CurInput;
static bool Active=false;
static void DisplaySeq(const std::vector<unsigned>& Seq)
{
std::stringstream msg;
for(unsigned a=0; a<Seq.size(); )
{
unsigned c=1, ch=Seq[a];
while(a+c < Seq.size() && Seq[a+c] == ch) ++c;
#if 1
if(c) {
msg << "d(" << c << ",";
unsigned b=0;
if(ch & K_A) { if(b++)msg << '|'; msg << ("K_A"); }
if(ch & K_B) { if(b++)msg << '|'; msg << ("K_B"); }
if(ch & K_SE) { if(b++)msg << '|'; msg << ("K_SE"); }
if(ch & K_ST) { if(b++)msg << '|'; msg << ("K_ST"); }
if(ch & K_U) { if(b++)msg << '|'; msg << ("K_U"); }
if(ch & K_D) { if(b++)msg << '|'; msg << ("K_D"); }
if(ch & K_L) { if(b++)msg << '|'; msg << ("K_L"); }
if(ch & K_R) { if(b++)msg << '|'; msg << ("K_R"); }
if(!b) msg << "0";
msg << (") ");
a += c;
}
#else
msg << c; msg << '*';
unsigned b=0;
if(ch & K_A) { if(b++) msg << ("_"); msg << ("A"); }
if(ch & K_B) { if(b++) msg << ("_"); msg << ("B"); }
if(ch & K_SE) { if(b++) msg << ("_"); msg << ("SE"); }
if(ch & K_ST) { if(b++) msg << ("_"); msg << ("ST"); }
if(ch & K_U) { if(b++) msg << ("_"); msg << ("U"); }
if(ch & K_D) { if(b++) msg << ("_"); msg << ("D"); }
if(ch & K_L) { if(b++) msg << ("_"); msg << ("L"); }
if(ch & K_R) { if(b++) msg << ("_"); msg << ("R"); }
if(!b) msg << ("00");
msg << (", ");
a += c;
#endif
}
BotFrontMsg("%s", msg.str().c_str());
}
static std::vector<unsigned> GlobalSeqSample;
void BisqBotDisplaySeqSample()
{
DisplaySeq(GlobalSeqSample);
BotFrontMsg("\n");
}
void BotFrontMsg(const char*fmt, ...)
{
FILE*fp;
va_list ap;
va_start(ap,fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fflush(stderr);
fp = fopen("rockman.log", "at");
if(!fp) fp = fopen("rockman.log", "wt");
if(!fp) return;
flock(fileno(fp), LOCK_EX);
fseek(fp,0,SEEK_END);
va_start(ap,fmt);
fprintf(fp, "[%d]", (int)getpid());
vfprintf(fp, fmt, ap);
va_end(ap);
fclose(fp);
}
void BotFrontStart()
{
fprintf(stderr,"BotFrontStart\n");
BotFrontDisableVideo=1;
Active=true;
}
void BotFrontEnd()
{
fprintf(stderr,"BotFrontEnd\n");
BisqBotReset();
BotFrontDisableVideo=0;
Active=false;
}
void BotFrontToggle()
{
if(!Active)
BotFrontStart();
else
BotFrontEnd();
}
int BotFrontActive()
{
return Active ? 1 : 0;
}
unsigned BotFrontGetKeymask()
{
if(Active)
{
return CurInput;
}
return 0;
}
#if defined(FCEU_VERSION_NUMERIC) && FCEU_VERSION_NUMERIC >= 9899
# define framecount currFrameCounter
#else
extern "C" { extern uint32_t framecount; }
#endif
#include "averages.hh"
#include "mutation.hh"
#include <tr1>
static struct LunarFilenameManager
{
char LockFileName[512];
char StateFileName[512];
LunarFilenameManager()
{
int botfrontpid = getpid();
sprintf(LockFileName, "/tmp/botfront-lock-%d", botfrontpid);
sprintf(StateFileName, "botfrontL-middle-%d", botfrontpid);
}
} LunarFilenames;
namespace LunarballLaunchManager2ns{
unsigned MAX_FRAMES;
unsigned BALLS_REMAINING;
}
struct LunarballMethods
{
struct Winner
{
static void GetBest(unsigned& best_pocketed, unsigned& best_time)
{
best_pocketed=0; best_time=65535;
int flags = O_RDWR | O_CREAT;
int fd = open(LunarFilenames.LockFileName, flags, 0600);
if(fd < 0) return;
struct autocloser { int f;
autocloser(int fd):f(fd){}
~autocloser(){close(f);} }
au(fd);
flock(fd, LOCK_EX);
char Buf[sizeof(unsigned)*30];
if(pread(fd, Buf, sizeof(Buf), 0) < sizeof(Buf)) return;
unsigned* const best_pptr = (unsigned*)&Buf[0];
unsigned* const best_tptr = (unsigned*)&Buf[sizeof(unsigned)*10];
best_pocketed = best_pptr[0];
best_time = best_tptr[0];
}
static unsigned GetBestTimeWithPocketCount(unsigned count, unsigned& model)
{
int flags = O_RDWR | O_CREAT;
int fd = open(LunarFilenames.LockFileName, flags, 0600);
if(fd < 0) { model=0; return 65535; }
struct autocloser { int f;
autocloser(int fd):f(fd){}
~autocloser(){close(f);} }
au(fd);
flock(fd, LOCK_EX);
char Buf[sizeof(unsigned)*30];
if(pread(fd, Buf, sizeof(Buf), 0) < sizeof(Buf)) return 65535;
unsigned* const best_tptr = (unsigned*)&Buf[sizeof(unsigned)*10];
unsigned* const best_mptr = (unsigned*)&Buf[sizeof(unsigned)*20];
model = best_mptr[count];
return best_tptr[count];
}
static double GenRatio(double num_pocketed, double nframes)
{
if(nframes < 1) nframes = 1;
return num_pocketed / (nframes+6);
}
static bool SetBest(unsigned num_pocketed, unsigned nframes, unsigned model, bool Force)
{
using namespace LunarballLaunchManager2ns;
int flags = O_RDWR | O_CREAT | (Force ? O_TRUNC : 0);
int fd = open(LunarFilenames.LockFileName, flags, 0600);
struct autocloser { int f;
autocloser(int fd):f(fd){}
~autocloser(){close(f);} }
au(fd);
flock(fd, LOCK_EX);
char Buf[sizeof(unsigned)*30] = { 0 };
pread(fd, Buf, sizeof(Buf), 0);
unsigned* const best_pptr = (unsigned*)&Buf[0];
unsigned* const best_tptr = (unsigned*)&Buf[sizeof(unsigned)*10];
unsigned* const best_mptr = (unsigned*)&Buf[sizeof(unsigned)*20];
unsigned& best_pocketed = best_pptr[0];
unsigned& best_time = best_tptr[0];
unsigned& best_model = best_mptr[0];
if(!Force)
{
double ratio_now = GenRatio(num_pocketed, nframes);
double ratio_old = GenRatio(best_pocketed, best_time);
if(ratio_now <ratio_old> 0)
{
unsigned& ref_pocketed = best_pptr[num_pocketed];
unsigned& ref_time = best_tptr[num_pocketed];
unsigned& ref_model = best_mptr[num_pocketed];
double ratio_ref = GenRatio(ref_pocketed, ref_time);
if(ratio_now >= ratio_ref || ref_pocketed == 0 || ratio_ref == 0.0)
{
unsigned cur = model%65536;
unsigned pre = model/65536;
fprintf(stderr, "Ignoring: Pocketed %u (time %u, angle %u, velo %u, preangle %u, prevelo %u) (ball at %02X,%02X)\n",
num_pocketed, nframes, cur%256, cur/256,
pre%256, pre/256,
RAM[0x370], RAM[0x330]
);
ref_pocketed = num_pocketed;
ref_time = nframes;
ref_model = model;
pwrite(fd, Buf, sizeof(Buf), 0);
}
}
return false;
}
if(ratio_now == ratio_old)
{
unsigned now_cur = model%65536, old_cur = best_model%65536;
unsigned now_pre = model/65536, old_pre = best_model/65536;
unsigned now_cur_vel = now_cur/256, old_cur_vel = old_cur/256;
unsigned now_pre_vel = now_pre/256, old_pre_vel = old_pre/256;
if(num_pocketed < best_pocketed) return false;
if(now_cur_vel <old_cur_vel> old_pre_vel) return false;
if(model == best_model) return false;
}
}
best_pocketed = num_pocketed;
best_time = nframes;
best_model = model;
best_pptr[best_pocketed] = best_pocketed;
best_tptr[best_pocketed] = best_time;
best_mptr[best_pocketed] = best_model;
pwrite(fd, Buf, sizeof(Buf), 0);
if(!Force)
{
unsigned cur = model%65536;
unsigned pre = model/65536;
fprintf(stderr, "Record: Pocketed %u (time %u, angle %u, velo %u, preangle %u, prevelo %u) (ball at %02X,%02X)\n",
best_pocketed, best_time, cur%256, cur/256,
pre%256, pre/256,
RAM[0x370], RAM[0x330]
);
FCEUSS_Save(LunarFilenames.StateFileName);
if(RAM[0x18E] == 0)
MAX_FRAMES = std::min(MAX_FRAMES, best_time+3);
}
return true;
}
static void Compete(unsigned num_pocketed, unsigned nframes, unsigned model)
{
SetBest(num_pocketed, nframes, model, false);
ContestLimit(num_pocketed, nframes);
}
static void Load()
{
FCEUSS_Load(LunarFilenames.StateFileName);
}
static void LoadLimit()
{
int flags = O_RDONLY;
int fd = open(LunarFilenames.LockFileName, flags, 0600);
if(fd < 0) return;
struct autocloser { int f;
autocloser(int fd):f(fd){}
~autocloser(){close(f);} }
au(fd);
flock(fd, LOCK_EX);
char Buf[sizeof(unsigned)*30];
if(pread(fd, Buf, sizeof(Buf), 0) < sizeof(Buf)) return;
unsigned* const best_tptr = (unsigned*)&Buf[sizeof(unsigned)*10];
for(unsigned num_pocketed=1; num_pocketed<10; ++num_pocketed)
{
unsigned nframes = best_tptr[num_pocketed];
ContestLimit(num_pocketed, nframes);
}
}
static void ContestLimit(unsigned num_pocketed, unsigned nframes)
{
if(!num_pocketed || !nframes) return;
using namespace LunarballLaunchManager2ns;
unsigned max_hope = nframes * BALLS_REMAINING
/ num_pocketed;
if(num_pocketed < BALLS_REMAINING)
max_hope += 7 + 230;
else
max_hope += 3;
if(max_hope <MAX_FRAMES> minus_dist ? -1 : 1;
unsigned dist = std::min(plus_dist, minus_dist);
key = dir == 1 ? K_R : K_L;
unsigned elapse_norepeat = 16 + (dist-1)*1;
unsigned elapse_repeat = 1 + 2*(dist-1);
autofire = elapse_repeat <= elapse_norepeat;
}
bool operator==(const AimingMethod& b) const
{ return key==b.key && autofire==b.autofire; }
bool operator!=(const AimingMethod& b) const
{ return !operator==(b); }
bool operator<(const AimingMethod& b) const
{ return (key*2+autofire) <b>= maxframes) goto Fail;
}
EndLoop: Fail: ;
scrFinish(0);
}
};
static bool DoAiming(unsigned angle, unsigned& frames_begin, unsigned maxframes)
{
scrBegin;
static AimingMethod method;
method.Decide(angle);
static unsigned frno; frno=0;
while(method.Run(angle, frno++, frames_begin, maxframes)) scrReturn(1);
scrFinish(0);
}
static bool DoFiring(unsigned& frames_begin, unsigned maxframes)
{
scrBegin;
if(!frames_begin) RunFrameWith(0);
do { RunFrameWith(K_B); ++frames_begin;
if(WhitePocketed() || frames_begin > maxframes) goto Fail;
} while(RAM[0x3D0] == 0 || RAM[0x3D0] == 0xFF);
EndLoop: Fail:;
scrFinish(0);
}
static bool DoWaitBallsStop(unsigned& nframes, const char*& failreason, unsigned maxframes)
{
scrBegin;
while(RAM[0x3D0] != 0 && RAM[0x3D0] != 0xFF)
{
if(RAM[0x3A0] == 0)
{
for(unsigned b=1; b<16; ++b)
if(RAM[0x310+b] <0x10>= 4) goto NotAllPocketed;
break;
NotAllPocketed:;
}
if(WhitePocketed()) { goto Fail; }
if(++nframes > maxframes) { failreason="timeout"; goto Fail; }
RunFrameWith(0);
}
EndLoop: Fail:;
scrFinish(0);
}
static bool DoWaitNextShotPossible(
unsigned& nframes_total,
unsigned& nframes_transition,
bool verbose, unsigned maxframes)
{
scrBegin;
static SaveState tmp;
static unsigned was_angle, became_angle1, became_angle2;
static unsigned n_attempts;
static bool transition;
transition = false;
if(verbose) fprintf(stderr, "Waiting until next shot can be shot\n");
n_attempts = 0;
NextFrameWaiter:
if(++n_attempts >= 1000) goto Fail;
if(!transition && RAM[0x18F] == 0) transition = true;
if(nframes_total-nframes_transition > maxframes) goto Fail;
tmp.Create();
was_angle = RAM[0x3C0];
RunFrameWith(K_R); ++nframes_total; if(transition) ++nframes_transition;
became_angle1 = RAM[0x3C0];
if(became_angle1 == was_angle) goto NextFrameWaiter;
tmp.Load(); --nframes_total; if(transition) --nframes_transition;
RunFrameWith(K_L); ++nframes_total; if(transition) ++nframes_transition;
became_angle2 = RAM[0x3C0];
if(became_angle2 == was_angle) goto NextFrameWaiter;
if(became_angle1 == became_angle2) goto NextFrameWaiter;
tmp.Load(); --nframes_total; if(transition) --nframes_transition;
EndLoop: Fail: ;
scrFinish(0);
}
static bool DoProfileShot(unsigned& num_pocketed, unsigned& nframes,
const char*& failreason,
unsigned maxframes)
{
scrBegin;
failreason = 0;
static unsigned pocketed_begin;
pocketed_begin = GetPocketedCount();
while(DoFiring(nframes, maxframes)) scrReturn(1);
while(DoWaitBallsStop(nframes, failreason, maxframes)) scrReturn(1);
if(failreason) goto Fail;
num_pocketed = GetPocketedCount();
if(WhitePocketed()) { num_pocketed=0; goto Fail; }
if(num_pocketed >= pocketed_begin)
num_pocketed -= pocketed_begin; else num_pocketed=0;
Fail: ;
scrFinish(0);
}
static unsigned GetPocketedCount()
{
unsigned result = 0;
for(unsigned a=1; a<16;++a)
{
if(RAM[0x300+a]==0xC0) break;
if((RAM[0x300+a] & 15) != 2 && (RAM[0x300+a] & 15) != 1)
{
++result;
}
}
++result;
return result;
}
static bool WhitePocketed()
{
return (RAM[0x300] & 15) != 2
&& (RAM[0x300] & 15) != 1;
}
static double CalculateProspects()
{
static std::vector<double> pocket_x;
static std::vector<double> pocket_y;
static int LastInitPockets=-1;
static double maximumdistance;
if(LastInitPockets != RAM[0x187])
{
pocket_x.clear(); pocket_y.clear();
LastInitPockets = RAM[0x187];
for(unsigned y=1; y<19; ++y)
{
for(unsigned x=1; x<25; ++x)
{
unsigned char c = RAM[0x600 + y*26+x];
#define b(n) (((n)&~0xCC)==0)
if((c & 0x10) == 0x10
&& (b(RAM[0x600 + (y-1)*26+x])
|| b(RAM[0x600 + (y+1)*26+x])
|| b(RAM[0x600 + y*26+(x-1)])
|| b(RAM[0x600 + y*26+(x+1)])))
{
pocket_x.push_back(x);
pocket_y.push_back(y);
}
#undef b
}
}
maximumdistance=0;
unsigned n_pockets = pocket_x.size();
for(unsigned y=1; y<19; ++y)
for(unsigned x=1; x<25; ++x)
{
double mindist=9e39;
for(unsigned p=0; p<n_pockets; ++p)
{
double xd = x-pocket_x[p], yd = y-pocket_y[p];
double dist = std::sqrt(xd*xd+yd*yd);
if(dist <mindist>maximumdistance) maximumdistance=mindist;
}
}
unsigned n_pockets = pocket_x.size();
double result = 0;
for(unsigned n=1; n<16>= 0x10) continue;
if(BallState == 0x83 || BallState == 0x03 || BallState == 0x00)
{
continue;
}
#if 1
double ballx = int(RAM[0x370 + n] / 8) - 3;
double bally = int(RAM[0x330 + n] / 8) - 8;
double mindistsquared = 9e39;
for(unsigned p=0; p<n_pockets; ++p)
{
double xdist = ballx - pocket_x[p], ydist = bally - pocket_y[p];
double distsquared = xdist*xdist + ydist*ydist;
if(distsquared <mindistsquared>> 16) == (oldmodel >> 16))
{
if(mut_amount <0> 0)
{ unsigned dummy_model, best_time_this_pocket_count
= Winner::GetBestTimeWithPocketCount(num_pocketed,dummy_model);
if(best_time_this_pocket_count > 0
&& best_time_this_pocket_count*5/3 <nframes> 0)
{
if(IGNORE_SCORE_DELAYS)
{
static unsigned nf1, nf2; nf1=nf2=0;
while(DoWaitNextShotPossible(
nf1, nf2, false, 9999)) scrReturn(1);
}
else
{
while(DoWaitNextShotPossible(
nframes, nframes_transition, false, MAX_FRAMES)) scrReturn(1);
if(nframes-nframes_transition >= MAX_FRAMES) goto Fail;
}
}
static unsigned nframes_scoring;
nframes_scoring = nframes - nframes_transition;
cand.scoring = num_pocketed;
cand.scoring += prospects;
cand.scoring /= (double)(nframes_scoring ? nframes_scoring : 0);
cand.scoring *= 131072;
++cand.confidence;
goto EndLoop;
Fail:
if(!failreason && nframes-nframes_transition >= MAX_FRAMES) failreason="timeout";
if(!failreason && !num_pocketed) failreason="dummy";
if(!failreason) failreason="fail";
if(nframes <nframes_transition> 0)
Winner::Compete(num_pocketed,
nframes_scoring,
cand.GetModel());
fflush(stderr);
scrFinish(0);
}
typedef CandidateOptMapType i1s; typedef i1s::iterator i1;
typedef i1::value_type::second_type i2s; typedef i2s::iterator i2;
typedef i2::value_type::second_type i3s; typedef i3s::iterator i3;
typedef i3::value_type::second_type i4s; typedef i4s::iterator i4;
typedef i4::value_type::second_type i5s;
template<typename>
int RunCandidates_VelocityLoop(VelT& list, NextT& j,
unsigned& num_pocketed, unsigned& nframes, unsigned& vel)
{
using namespace LunarballLaunchManager2ns;
scrBegin;
while(!list.empty())
{
for(;;)
{
vel = RAM[0x3A0];
j = list.find(vel);
if(j != list.end()) break;
if(nframes++ >= MAX_FRAMES) goto Fail;
RunFrameWith(0x00);
}
static LunarState shot_state; shot_state.Save(num_pocketed,nframes);
scrReturn(2);
list.erase(j);
if(!list.empty()) shot_state.Load();
}
EndLoop: Fail: ;
scrFinish(0);
}
template<typename>
int RunCandidates_AngleLoop(AngT& list, NextT& k,
unsigned& num_pocketed, unsigned& nframes, unsigned& ang)
{
using namespace LunarballLaunchManager2ns;
scrBegin;
typedef std::map<unsigned> AimList;
typedef std::map<AimingMethod> AimMap;
static AimMap aims;
aims.clear();
for(k = list.begin(); k != list.end(); ++k)
{
AimingMethod method;
method.Decide(k->first);
aims[method][k->first] = k;
}
static LunarState begin; begin.Save(num_pocketed,nframes);
static typename AimMap::iterator ai;
for(ai = aims.begin(); ai != aims.end(); ++ai)
{
static unsigned aim_framecount; aim_framecount = 0;
if(ai != aims.begin()) begin.Load();
while(!ai->second.empty())
{
for(;;)
{
ang = RAM[0x3C0];
{ typename AimList::iterator j = ai->second.find(ang);
if(j != ai->second.end())
{
k = j->second;
ai->second.erase(j);
break;
} }
if(nframes++ >= MAX_FRAMES) goto FailAim;
RunFrameWith( (ai->first.autofire && (aim_framecount++&1))
? 0x00
: ai->first.key );
}
static LunarState aim_state; aim_state.Save(num_pocketed,nframes);
scrReturn(2);
if(!ai->second.empty()) aim_state.Load();
}
FailAim: ;
}
EndLoop: ;
scrFinish(0);
}
bool RunCandidates_4do(unsigned& num_pocketed, unsigned& nframes,
i5s& lsecond, unsigned preang, unsigned prevel,
unsigned ang, unsigned vel)
{
using namespace LunarballLaunchManager2ns;
scrBegin;
static const char* failreason; failreason = 0;
while(DoProfileShot(num_pocketed, nframes,
failreason, MAX_FRAMES)) scrReturn(1);
if(WhitePocketed() || failreason)
{
goto Fail;
}
while(AnalyzeShotResult(*lsecond, num_pocketed, nframes,
ang,vel,preang,prevel)) scrReturn(1);
Fail: ;
scrFinish(0);
}
bool RunCandidates_2do(unsigned& num_pocketed, unsigned& nframes,
i3s& jsecond, unsigned preang, unsigned prevel)
{
using namespace LunarballLaunchManager2ns;
scrBegin;
static const char* failreason; failreason = 0;
while(DoProfileShot(num_pocketed, nframes,
failreason, MAX_FRAMES)) scrReturn(1);
if(DO_DEATH && WhitePocketed())
{
unsigned model = preang + prevel*256;
fprintf(stderr, "!"); fflush(stderr);
deathset.set(model, nframes == 0 ? 1 : nframes);
num_pocketed = 0;
}
if(failreason)
{
for(i3 k = jsecond.begin(); k != jsecond.end(); ++k)
for(i4 l = k->second.begin(); l != k->second.end(); ++l)
l->second->first_shot_is_enough = true;
goto Fail;
}
if(num_pocketed > 0)
{
static bool first; first=true;
static i3 k;
static i4 l;
for(k = jsecond.begin(); k != jsecond.end(); ++k)
for(l = k->second.begin(); l != k->second.end(); ++l)
{
l->second->first_shot_is_enough = true;
if(first)
{
static unsigned ang, vel;
ang = k->first;
vel = l->first;
while(AnalyzeShotResult(*l->second, num_pocketed, nframes,
ang,vel,preang,prevel)) scrReturn(1);
first = false;
}
}
goto EndLoop;
}
if(!DO_DUALSHOT) goto EndLoop;
static unsigned nextshot; nextshot = 0;
if(IGNORE_SCORE_DELAYS)
{
static unsigned nf1; nf1=0;
while(DoWaitNextShotPossible(nf1, nextshot,
false, 9999)) scrReturn(1);
}
else
{
while(DoWaitNextShotPossible(nframes, nextshot,
false, MAX_FRAMES)) scrReturn(1);
}
if(nextshot) { failreason="??transition"; goto Fail; }
while(RunCandidates_3(num_pocketed, nframes, jsecond, preang, prevel)) scrReturn(1);
EndLoop: Fail: ;
scrFinish(0);
}
bool RunCandidates_4(unsigned& num_pocketed, unsigned& nframes,
i4s& ksecond, unsigned preang, unsigned prevel, unsigned ang)
{
scrBegin;
for(;;)
{
static i4 l;
static unsigned vel;
{ int c = RunCandidates_VelocityLoop(ksecond, l, num_pocketed, nframes, vel);
if(!c) break;
if(c == 1) goto Idle;
}
while(RunCandidates_4do(num_pocketed, nframes, l->second, preang, prevel, ang, vel)) scrReturn(1);
continue;
Idle: scrReturn(1);
}
scrFinish(0);
}
bool RunCandidates_3(unsigned& num_pocketed, unsigned& nframes,
i3s& jsecond, unsigned preang, unsigned prevel)
{
scrBegin;
for(;;)
{
static i3 k;
static unsigned ang;
{ int c = RunCandidates_AngleLoop(jsecond, k, num_pocketed, nframes, ang);
if(!c) break;
if(c == 1) goto Idle;
}
while(RunCandidates_4(num_pocketed, nframes, k->second, preang, prevel, ang)) scrReturn(1);
continue;
Idle: scrReturn(1);
}
scrFinish(0);
}
bool RunCandidates_2(unsigned& num_pocketed, unsigned& nframes,
i2s& isecond, unsigned preang)
{
scrBegin;
for(;;)
{
static i2 j;
static unsigned prevel;
{ int c = RunCandidates_VelocityLoop(isecond, j, num_pocketed, nframes, prevel);
if(!c) break;
if(c == 1) goto Idle;
}
while(RunCandidates_2do(num_pocketed, nframes, j->second, preang, prevel)) scrReturn(1);
continue;
Idle: scrReturn(1);
}
scrFinish(0);
}
bool RunCandidates_1(unsigned& num_pocketed, unsigned& nframes,
i1s& optmap)
{
scrBegin;
for(;;)
{
static i1 i;
static unsigned preang;
{ int c = RunCandidates_AngleLoop(optmap, i, num_pocketed, nframes, preang);
if(!c) break;
if(c == 1) goto Idle;
}
while(RunCandidates_2(num_pocketed, nframes, i->second, preang)) scrReturn(1);
continue;
Idle: scrReturn(1);
}
scrFinish(0);
}
bool RunCandidates(const SaveState& itbegin_state, CandidateOptMapType& optmap)
{
scrBegin;
itbegin_state.Load();
static unsigned num_pocketed; num_pocketed = 0;
static unsigned nframes; nframes = 0;
while(RunCandidates_1(num_pocketed, nframes, optmap)) scrReturn(1);
scrFinish(0);
}
typedef std::deque<CandidateType> CandidateListType;
void WaitCandidate(CandidateListType& CandidateList,
std::map<int>& pid_list,
bool block)
{
for(int waitflag = block ? 0 : WNOHANG; ; waitflag = WNOHANG)
{
int status = 0;
int pid = waitpid(-1, &status, waitflag);
if(pid <= 0) break;
std::map<int>::iterator i = pid_list.find(pid);
if(i == pid_list.end())
{
fprintf(stderr, "Unknown child %d died\n", pid);
}
else
{
const unsigned first_candno = i->second;
unsigned candno = first_candno;
unsigned end_candno = candno + NUM_CANDIDATES_PER_PROCESS;
if(end_candno > CandidateList.size()) end_candno = CandidateList.size();
for(; candno <end_candno>LoadRes();
}
pid_list.erase(i);
}
if(WIFSIGNALED(status))
{
fprintf(stderr, "Child died at signal %d\n",
WTERMSIG(status));
}
}
}
int LaunchNCandidates
(CandidateListType& CandidateList, const unsigned first_candno,
std::map<int>& pid_list,
const SaveState& itbegin)
{
scrBegin;
if(true)
{
Winner::LoadLimit();
int pid;
fflush(stdout);
fflush(stderr);
pid = fork();
if(pid > 0)
{
pid_list[pid] = first_candno;
fprintf(stderr, "."); fflush(stderr);
goto end;
}
if(pid <0> CandidateList.size())
end_candno = CandidateList.size();
static CandidateOptMapType optmap;
optmap.clear();
for(unsigned candno=first_candno; candno <end_candno>GetModel();
unsigned cur = model%65536, ang=cur%256, vel=cur/256;
unsigned pre = model/65536, preang=pre%256, prevel=pre/256;
optmap[preang][prevel][ang][vel] = candit;
candit->scoring = 0;
}
while(RunCandidates(itbegin, optmap)) scrReturn(1);
optmap.clear();
for(unsigned candno=first_candno; candno < end_candno; ++candno)
CandidateList[candno].SaveRes();
fflush(stdout);
fflush(stderr);
_exit(0);
end:;
scrFinish(0);
}
int RunCandidates(CandidateListType& CandidateList,
const SaveState& itbegin)
{
scrBegin;
if(CandidateList.empty()) return 0;
static std::map<int> pid_list;
pid_list.clear();
BotFrontDisableVideo=2;
static unsigned candno;
for(candno=0; candno<CandidateList>= NUM_FORKS);
} while(pid_list.size() >= NUM_FORKS);
while(LaunchNCandidates(CandidateList, candno, pid_list, itbegin)) scrReturn(1);
}
BotFrontDisableVideo=1;
while(!pid_list.empty())
{
WaitCandidate(CandidateList, pid_list, true);
}
scrFinish(0);
}
static void CreateSeedF(
CandidateListType& WinnerList,
unsigned model,
bool is_oneshot)
{
CandidateType tmp;
bool skip = false;
if(covered_preshots[model >> 16])
(skip=true);
if(covered_candidates[model])
(skip=true);
if(deathset[model >> 16] && deathset[model & 0xFFFF])
(skip=true);
if(!skip)
{
WinnerList.push_back(tmp.SetModel(model, is_oneshot));
if(is_oneshot) covered_preshots.set(model >> 16);
covered_candidates.set(model);
}
}
int Run()
{
scrBegin;
static CandidateListType WinnerList;
BeginNewShot:
Winner::SetBest(0,0,0, true);
LunarballLaunchManager2ns::MAX_FRAMES = INIT_MAX_FRAMES;
LunarballLaunchManager2ns::BALLS_REMAINING = RAM[0x18E];
WinnerList.clear();
covered_candidates.reset();
covered_preshots.reset();
deathset.reset();
for(unsigned a=0; a< CandidateType::CountSeeds(); ++a)
WinnerList.push_back(CandidateType().SetSeed(a));
#define CreateSeed(pok,tim,ang,vel,preang,prevel, is_oneshot) \
CreateSeedF(WinnerList, \
(ang+vel*256U) + (preang + prevel*256U)*65536U, is_oneshot);
fprintf(stderr, "Beginning new shot. Table=%u, remaining balls=%u; %u on 16-bit donelist, %lu on 32-bit, %u deaths\n",
RAM[0x187], RAM[0x18E],
(unsigned) covered_preshots.count(),
(unsigned long) covered_candidates.count(),
(unsigned) deathset.count()
);
static SaveState itbegin;
itbegin.Create();
{unsigned n_skipped = 0;
for(unsigned preang=0; preang<256; preang += 1)
for(unsigned prevel=18; prevel<256; prevel += 3)
{
size_t a = WinnerList.size();
CreateSeed(0,0, preang,255, preang, prevel, false);
n_skipped += WinnerList.size() == a;
}
if(n_skipped)
fprintf(stderr, "- %u CHOICES SKIPPED??\n", (unsigned)n_skipped);}
static unsigned generationno;
static unsigned n_generations_no_improvement;
n_generations_no_improvement = 0;
static double best_scoring;
static CandidateType best_candidate;
best_scoring = -999999;
for(generationno=1; Active; ++generationno)
{
static CandidateListType CandidateList;
if(DO_DEATH && generationno == 2)
{
for(unsigned angle_begin = 0; angle_begin < 256; angle_begin += 32)
{
std::vector< std::pair<unsigned> > deaths;
for(unsigned d=0; d<65536; ++d)
{
if((d%256) <angle_begin>= angle_begin+32) continue;
if(deathset[d])
deaths.push_back( std::pair<unsigned>
( deathset[d], d ) );
}
std::sort(deaths.begin(), deaths.end());
fprintf(stderr, "Chosen deaths:\n");
for(unsigned dn=0; dn<deaths.size() && dn < 4; ++dn)
{
unsigned d = deaths[dn].second;
fprintf(stderr, "- angle %u, velocity %u, %u frames\n",
d%256, d/256, deaths[dn].first);
for(unsigned ang=0; ang<256; ang += 1)
for(unsigned vel=18; vel<256> 250)
LunarballLaunchManager2ns::MAX_FRAMES = 250;
if(DO_DUALSHOT)
{
for(unsigned preang=0; preang<256; preang += 1)
for(unsigned prevel=18; prevel<=140; prevel += 3)
{
if(RAM[0x187] == 23 && RAM[0x18E] == 4)
if(preang < 156)continue;
if(RAM[0x187] == 26 && RAM[0x18E] == 4)
if(preang < 9)continue;
if(RAM[0x187] == 30 && RAM[0x18E] == 3)
if(preang < 193)continue;
static const int dists[] = {
35,1,
50,2,
90,4,
128,6, -1};
int prevdist=0;
for(int n=0; dists[n*2] != -1; ++n)
{
int dist = dists[n*2];
int skip = dists[n*2+1];
for(; prevdist <= dist; prevdist += skip)
{
const unsigned minvel = 171;
for(unsigned vel=minvel; vel<256; vel+=3)
CreateSeed(0, 0, ((preang-prevdist)&255), vel, (preang&0xFF), prevel, false);
if(prevdist != 0)
for(unsigned vel=minvel; vel<256> 2) CandidateList.clear();
))
for(unsigned a=0; a<NUM_RANDOMS>> 16]) continue;
covered_candidates.set(c);
CandidateList.push_back(tmp);
}
++n_generations_no_improvement;
{
fprintf(stderr, "Generation %u: %u candidates based on %u; %u on 16-bit donelist, %lu on 32-bit, %u deaths, frame limit %u\n",
generationno, (unsigned)CandidateList.size(), (unsigned)WinnerList.size(),
(unsigned) covered_preshots.count(),
(unsigned long) covered_candidates.count(),
(unsigned) deathset.count(),
LunarballLaunchManager2ns::MAX_FRAMES );
}
if(CandidateList.empty())
{
fprintf(stderr, "Out of candidates, ending this generation\n");
break;
}
WinnerList.clear();
for(unsigned candno=0; candno<CandidateList.size(); ++candno)
CandidateList[candno].key = candno;
while(RunCandidates(CandidateList, itbegin)) scrReturn(1);
fprintf(stderr, "\r");
for(unsigned candno=0; candno<CandidateList>key = candno;
if(candit->first_shot_is_enough)
{
covered_preshots.set( candit->GetModel() >> 16 );
}
}
std::sort(CandidateList.begin(), CandidateList.end(),
std::mem_fun_ref(&CandidateType::BetterScoring));
for(unsigned candno=0; candno<CandidateList>scoring > best_scoring)
{
best_scoring = candit->scoring;
best_candidate = *candit;
n_generations_no_improvement = 0;
}
break;
}
for(unsigned n=1; n<10; ++n)
{
unsigned model=0;
unsigned time = Winner::GetBestTimeWithPocketCount(n, model);
if(time == 0 || time == 65535) continue;
CandidateType tmp;
tmp.SetModel(model, false);
tmp.confidence = 1;
tmp.scoring = (n / (double)time);
tmp.scoring += n * 1e-5;
tmp.scoring += ((model/0x100)&0xFF) * (1e-5/256.0);
tmp.scoring += ((model/0x1000000)&0xFF) * (1e-5/65536.0);
tmp.scoring *= 131072;
WinnerList.push_front(tmp);
}
for(unsigned n=0; n<WINNERS>scoring);
for(CandidateListType::const_iterator i=CandidateList.begin();
i!=CandidateList.end(); ++i)
quality_all.Cumulate(i->scoring);
fprintf(stderr, "Average quality of generation %u: %g (all), %g (inheritors)\n",
generationno,
quality_all.GetValue(), quality_best.GetValue());
if(n_generations_no_improvement >= min_generations_no_improvement
|| !DO_DUALSHOT) break;
}
#undef CreateSeed
Winner::Load();
if(true)
{
fprintf(stderr, "Beginning new shot\n");
FCEUSS_Save("botfrontL-newshotbegin");
goto BeginNewShot;
}
BotFrontEnd();
Winner::Load();
FCEUSS_Save("botfrontL-final");
scrFinish(0);
}
#undef RunFrameWith
};
void BotFrontIter()
{
scrBegin;
Restart:
while(!Active)
{
BisqBotEvaluate(0);
BisqBotReset();
scrReturnV;
}
struct timeval tv;
gettimeofday(&tv,NULL);
rng.seed(tv.tv_usec + tv.tv_sec*1000000ULL);
if(!FCEUI_EmulationPaused()) FCEUI_ToggleEmulationPause();
#if 1
static LunarballLaunchManager2 code;
while(Active) { code.Run(); scrReturnV; }
BotFrontEnd();
FCEUSS_Save("botfrontL-end");
goto Restart;
#endif
goto Restart;
scrFinishV;
}
Edited by feos: Replaced with a regular code embed. Original code is backed up at https://files.tasvideos.org/2095/archives/injection.7z