if ((ii!=fi)&&(jj!=fj)) ++t2;
}
}
}
if (t1>2) TSp=true;
if ((t1>2)&&(t2>1)) TFull=true;
if (_p.GetName()!="T") TFull=TSp=Spin;
}
if ((SpinRule==SR_Guildline)&&(!Mod8)&&(!IsSpinBonus(_p.GetName()))&&(Lines<4)) Spin=false;
if ((SpinRule==SR_Guildline)&&(!Mod8)) {
if ((!TSp)&&(Lines<4)) Spin=false;
}
bool CalcAllMini = ((SpinRule==SR_Default)&&(Gen.Pool.size()<=10)&&(!Mod8)&&((BotType==1)||(BotType==3)));
bool AllMini=false, ex1=false, ex2=false, sw=false, ew=false; int eu=0;
for (int i=0; i<PLX; ++i) {
for (int j=0; j<PLX; ++j) {
int x=o.x+i, y=o.y+j;
if ((x<1)||(y<1)||(x>LX)||(y>LY)) continue;
if (!p.GetGrid(i,j)) {
if (!CalcAllMini) continue;
int ad = 0;
if ((i>0)&&(p.GetGrid(i-1,j))) ++ad;
if ((i+1<PLX)&&(p.GetGrid(i+1,j))) ++ad;
if ((j>0)&&(p.GetGrid(i,j-1))) ++ad;
if ((j+1<PLX)&&(p.GetGrid(i,j+1))) ++ad;
if (ad>=2) {
ew=true; if (!D[x][y]) sw=true;
}
continue;
}
++Fill[x];
PieceHeight = max(PieceHeight,x);
LeftMost = min(LeftMost,y);
RightMost = max(RightMost,y);
Edge = min(Edge,min(y-1,LY-y));
if (!CalcAllMini) continue;
int ex = 0;
if ((x==1)||(D[x-1][y])) ++ex;
if ((x==LX)||(D[x+1][y])) {
++ex;
if ((i+1==PLX)||(!p.GetGrid(i+1,j))) ++eu;
}
if ((y==1)||(D[x][y-1])) ++ex;
if ((y==LY)||(D[x][y+1])) ++ex;
if (ex<=1) ex1=true;
if (ex<=2) ex2=true;
}
}
if (CalcAllMini) {
if (IsOType(_p.GetName())) AllMini=(eu<2);
else AllMini=((!Use90)||(ex1)||((ex2)&&((sw)||(!ew))));
}
int FillCnt=0, FillCol=0;
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (D[i][j]) {
if (!Upper[j]) {
Upper[j]=true; ++FillCol;
}
}
}
if ((Fill[i])&&(FillCol==LY)) ++FillCnt;
}
/*int LQH=0, RQH=0;
if ((BotType==6)||(BotType==7)) {
int acc = 0;
for (int i=1; i<=LX; ++i) {
int cur = 0;
for (int j=2; j<=LY; ++j) {
if (D[i][j]) break;
else ++cur;
}
if (cur>=LY-1) break;
if (cur) {
acc+=cur; if (acc>3) break;
}
else {
cur=0; LQH=i;
}
}
for (int i=1; i<=LX; ++i) {
int cur = 0;
for (int j=LY-1; j; --j) {
if (D[i][j]) break;
else ++cur;
}
if (cur>=LY-1) break;
if (cur) {
acc+=cur; if (acc>3) break;
}
else {
cur=0; RQH=i;
}
}
}*/
int Ero = 0;
for (int i=1; i<=LX; ++i) {
bool f = true;
for (int j=1; j<=LY; ++j) {
if (!D[i][j]) {
f=false; break;
}
}
for (int x : StaticLines) {
if (i==x) f=false;
}
if (f) {
if (Fill[i]) ++Lines;
Ero += Fill[i];
if (GravityType==GV_None) {
++pp; for (int j=1; j<=LY; ++j) D[pp][j]=false;
}
}
else {
++pp;
if (i!=pp) {
for (int j=1; j<=LY; ++j) {
D[pp][j]=D[i][j]; D[i][j]=false;
}
}
}
}
Sta->Clutch = false;
if ((ClutchRule==CLR_Default)&&(Lines)) Sta->Clutch=true;
if (ClutchRule==CLR_Always) Sta->Clutch=true;
if (Lines) ++Sta->Combo;
else Sta->Combo=0;
ll res = 0LL;
ll ares = 0LL;
bool SetSpin = (((BotType==1)||(BotType==3)||(BotType==6)||(BotType==7)||(BotType==8))&&(SpinMode));
for (int i=0; i<=LX+1; ++i) D[i][0]=D[i][LY+1]=true;
for (int i=0; i<=LY+1; ++i) D[0][i]=D[LX+1][i]=true;
int BegHeight=Height; Height=0;
bool qd = ((SetSpin)&&((BotType==6)||(BotType==7)));
int WellCol = -1;
if ((Sta->LastClearType.second>0)&&(Sta->LastClearType.second<4)&&(Height>6)) {
if (BotType==9) qd=false;
else if (qd) WellCol=-1;
}
int _wc = -1;
int _wh = 0;
if ((qd)||((SpinRule==SR_Guildline)&&(SetSpin)&&(!Mod8)&&((BotType==1)||(BotType==3)))) {
int mn = LX+1;
if (qd) {
for (int j=LY; j; --j) {
if ((j>=2)&&(j<=LY-1)) continue;
int p = 0;
for (int i=LX; i; --i) {
if (D[i][j]) {
p=i; break;
}
}
if (p<mn) {
mn=p; WellCol=j;
}
}
for (int j=LY; j; --j) {
if ((j==1)||(j==LY)) continue;
int p = 0;
for (int i=LX; i; --i) {
if (D[i][j]) {
p=i; break;
}
}
if (p<mn) {
mn=p; WellCol=j;
}
}
}
else {
for (int j=LY-3; j>=3; --j) {
int p = 0;
for (int i=LX; i; --i) {
if (D[i][j]) {
p=i; break;
}
}
if (p<mn) {
mn=p; WellCol=j;
}
}
for (int j=LY; j>=1; --j) {
if ((j!=1)&&(j!=LY)) continue;
int p = 0;
for (int i=LX; i; --i) {
if (D[i][j]) {
p=i; break;
}
}
if (p<mn) {
mn=p; WellCol=j;
}
}
for (int j=LY; j>=1; --j) {
if ((j!=2)&&(j!=LY-1)) continue;
int p = 0;
for (int i=LX; i; --i) {
if (D[i][j]) {
p=i; break;
}
}
if (p<mn) {
mn=p; WellCol=j;
}
}
_wc=WellCol; _wh=mn;
}
if (mn+10>SX) WellCol=-1;
}
if ((BotType==6)||(BotType==7)) {
if ((WellCol>=2)&&(WellCol<=LY-1)) WellCol=-1;
}
if ((Sta->LastClearType.second>0)&&(Sta->LastClearType.second<4)&&(Height>10)) {
if ((BotType==6)||(BotType==7)) WellCol=-1;
}
if ((BotType==9)&&(SpinMode)) {
int mn = LX+1;
for (int j=LY; j; --j) {
if ((j>=2)&&(j<=LY-1)) continue;
int p = 0;
for (int i=LX; i; --i) {
if (D[i][j]) {
p=i; break;
}
}
if (p<mn) {
mn=p; WellCol=j;
}
}
for (int j=LY; j; --j) {
if ((j==1)||(j==LY)) continue;
int p = 0;
for (int i=LX; i; --i) {
if (D[i][j]) {
p=i; break;
}
}
if (p<mn) {
mn=p; WellCol=j;
}
}
if (mn>=SX/2) WellCol=-1;
if ((WellCol>=2)&&(WellCol<=LY-1)) WellCol=-1;
if (WellCol==-1) res-=30000;
}
if ((qd)&&(WellCol==-1)) res-=30000;
/*if ((BotType==6)||(BotType==7)) {
if (SpinMode) res+=(LX-Height)*10;
}*/
if ((SpinRule==SR_Guildline)&&(!Mod8)&&((BotType==1)||(BotType==3))) {
WellCol = _wc;
if (SetSpin) {
if ((_wc==2)||(_wc==LY-1)) res-=200000;
if ((_wc==1)||(_wc==LY)) {
res-=50000; _wc=-1;
}
}
else WellCol=_wc=-1;
}
else _wc=-1;
//if (WellCol!=-1) printf("!%d\n",WellCol);
for (int i=1; i<=LX; ++i) {
int fc = 0;
for (int j=1; j<=LY; ++j) {
if (D[i][j]) ++fc;
}
int WellCnt = 0;
for (int j=1; j<=LY; ++j) {
if (D[i][j]) {
Height=max(Height,i); continue;
}
if (D[i+1][j]) {
if (GravityType==GV_None) ;
else if (BotType==5) {
if (((j<=2)||(D[i][j-1])||(D[i+1][j-1]))&&((j>=LY-1)||(D[i][j+1])||(D[i+1][j+1])))
res-=5LL;
else --res;
}
else if (BotType==9) res-=5LL;
else if (qd) res-=20LL;
else if ((!SetSpin)||(qd)) res-=5LL;
else if ((SpinRule==SR_Guildline)&&(!Mod8)) {
if ((((j<=2)||(D[i][j-1])||(D[i+1][j-1]))&&((j>=LY-1)||(D[i][j+1])||(D[i+1][j+1])))||((j==1)||(j==LY))) res-=50LL;
else res-=10LL;
}
else if ((((j<=2)||(D[i][j-1])||(D[i+1][j-1]))&&((j>=LY-1)||(D[i][j+1])||(D[i+1][j+1])))||((j==1)||(j==LY)))
res-=10LL;
else res+=0;
}
if ((D[i-1][j])||(i==1)) --res;
if ((D[i][j-1])||(j==1)||(j-1==WellCol)) --res;
if ((D[i][j+1])||(j==LY)||(j+1==WellCol)) --res;
if (((D[i][j-1])||(j==1)||(j-1==WellCol))&&((D[i][j+1])||(j==LY)||(j+1==WellCol))) {
if (_wc>0) {
if ((j!=_wc)&&(i>1)&&(!D[i-1][j])) res-=10;
if (j==_wc) ;
else if (!D[i+1][j]) ;
else if (abs(j-_wc)>1) res-=15;
else if (D[i][max(1,min(LY,_wc+_wc-j))]) res-=30;
else if ((!D[i-1][j])||(!D[i-1][max(1,min(LY,_wc+_wc-j))])) res-=30;
else if ((i+2<=LX)&&((D[i+2][j])&&(D[i+2][max(1,min(LY,_wc+_wc-j))]))) res-=30;
}
if (BotType==9) {
if (j!=WellCol) --res;
}
else if (((!qd)&&(_wc<0))||(j!=WellCol)) {
--res;
}
else if (fc>=LY-1) res+=2;
}
if ((_wc>0)&&((D[i+1][j])&&(D[i][j-1])&&(D[i][j+1]))&&(abs(i-_wc)>1)) res-=10;
}
}
if ((_wc>1)&&(_wc<LY)) {
int Base = 0;
for (int i=1; i<=LX; ++i) {
if ((D[i][_wc-1])&&(D[i][_wc+1])) Base=i;
}
int hl=0, hr=0;
while ((Base+hl+1<=LX)&&(D[Base+hl+1][_wc-1])) ++hl;
while ((Base+hr+1<=LX)&&(D[Base+hr+1][_wc+1])) ++hr;
int del = abs(hl-hr);
res -= ((del==1)?3:min(5,del))*2;
res -= Height*10;
}
if ((!SetSpin)&&((BotType==1)||(BotType==2)||(BotType==3)||(BotType==4))&&(PlayerCount>1)) ares-=Height*500;
if ((GetT)&&(SetSpin)&&((BotType==1)||(BotType==3))) {
int c1=0, c0=0;
int mul = 1;
int pp=0, ph=0;
for (int j=2; j<LY; ++j) {
for (int i=LX-1; i>=2; --i) {
if (D[i][j]) break;
if ((D[i][j])||(D[i-1][j])||(D[i+1][j])||(D[i][j-1])||(D[i][j+1])) continue;
if ((!D[i-1][j-1])||(!D[i-1][j+1])) continue;
int k = int(D[i+1][j-1])+int(D[i+1][j+1]);
if (j==_wc) mul=6;
if ((j!=_wc)&&(_wc>0)) continue;
if (k==1) {
++c1;
if (!pp) {
if (D[i+1][j-1]) pp=j-1;
if (D[i+1][j-1]) pp=j+1;
ph = i+1;
}
}
if (!k) {
if (((D[i][j-2])||(j==2))&&((D[i][j+2])||(j==LY-1))) ++c0;
}
}
}
if ((pp)&&(_wc>0)) {
int d = 1;
while ((ph+d<=LX)&&(D[ph+d][pp])) ++d;
if (d==1) ++res;
if (d>2) res-=2*(d-2);
}
if (c1) res+=5*mul;
else if (c0) res+=1*mul;
/*int c1=0, c0=0;
for (int j=2; j<=LY; ++j) {
for (int i=LX-1; i>=2; --i) {
if (D[i][j]) continue;
if ((D[i-1][j])||(D[i][j-1])||(D[i-1][j-1])) continue;
if ((j>2)&&((!D[i][j-2])&&(!D[i-1][j-2]))) continue;
if ((j<LY)&&((!D[i][j+1])&&(!D[i-1][j+1]))) continue;
if ((i>2)&&((!D[i-2][j])&&(!D[i-2][j-1]))) continue;
if (((j>2)&&(!D[i][j-2]))&&((j<LY)&&(!D[i-1][j+1]))) continue;
if (((j>2)&&(!D[i-1][j-2]))&&((j<LY)&&(!D[i][j+1]))) continue;
int k = int(D[i+1][j])+int(D[i+1][j-1]);
if (k) ++c1;
if (!k) {
if (((D[i][j-2])||(j==2))&&((D[i][j+1])||(j==LY))) ++c0;
}
}
}
if (c1) res+=5;
else if (c0) res+=1;*/
}
bool AllClear = (Height<=SolidHeight);
if ((BotType==6)||(BotType==7)) AllClear=false;
if (SetSpin) {
if ((AllClearRule!=AR_IO)&&(AllClearRule!=AR_Default)&&(AllClearRule!=AR_QP)&&(AllClearRule!=AR_Techmino)
&&(B2BRule!=BR_None)&&(B2BRule!=BR_Guildline)&&(B2BRule!=BR_Techmino)) AllClear=false;
}
Sta->LineAfterPC += Lines;
if (AllClear) Sta->LineAfterPC=0;
if ((Mod8)&&((Lines)||(Spin))) {
pair<string,int> NewClearType = make_pair("",Lines);
if (Spin) NewClearType.first=_p.GetRealName();
if (Mod8==2) {
if (Spin) NewClearType.first="X";
else NewClearType.second=0;
}
if (!Lines) NewClearType.second=-1;
if (NewClearType==Sta->LastClearType) ares-=10000000000LL;
Sta->LastClearType = NewClearType;
}
bool sth = false;
if ((Lines)&&(sth)) {
if (((Lines!=1)||((!Spin)&&((!Spinable)||(!TSp))))) ares-=1000000000LL;
else if ((_f)&&(Lines<4)&&(!Spin)&&(!TSp)) ares-=1000000000LL;
else ares+=10000LL;
}
if (BotType==5) {
int Parity=0, CParity=0;
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (D[i][j]) {
if (j&1) ++CParity;
else --CParity;
if ((i+j)&1) ++Parity;
else --Parity;
}
}
}
Parity=abs(Parity); CParity=abs(CParity);
//res -= CParity;
int Goal = 4;
if (Height+Sta->LineAfterPC>Goal) ares-=1000000000LL;
else {
int h = min(LX,Goal-Sta->LineAfterPC);
for (int i=1; i<=LY; ++i) {
if (!D[h][i]) --res;
}
vector<vector<char> > G(h+2,vector<char>(LY+2,0));
for (int i=0; i<=h+1; ++i) G[i][0]=G[i][LY+1]=1;
for (int i=0; i<=LY+1; ++i) G[0][i]=G[h+1][i]=1;
for (int i=1; i<=h; ++i) {
for (int j=1; j<=LY; ++j) G[i][j]=D[i][j];
}
for (int i=1; i<=h; ++i) {
for (int j=1; j<=LY; ++j) {
if (!G[i][j]) {
int val = VecDfs(G,i,j);
if (val&1) {
if ((i>=h-1)||(val==1)) res-=5000LL;
else res-=50LL;
}
else if (val&3) {
if ((i>=h-1)||(val==2)) res-=10LL;
else res-=5LL;
}
}
}
}
}
}
res -= Height;
int RotDis=((DefaultRot-o.d+4)&3); if (RotDis==3) RotDis=1;
ares += Lines*Ero*2000LL;
//if (!IsSpinBonus(p.GetName())) Spin=0; Spin|=TSp;
int _Spin = Spin;
if ((!Mod8)&&((SpinRule==SR_AllMini)||(BotType==8)||(Mod2==2))) Spin|=TSp;
if ((!Mod8)&&((CenterY==1)||(CenterY==LY))) {
if ((!Spin)&&(TSp)) Spin=AllMini=true;
}
if (qd) Spin=0;
if ((_f)&&(TQPScore<=1100000)&&(TFull)) Spin=0;
if ((_f)&&(AllClear)) Spin=0;
if ((Lines)&&((BotType==1)||(BotType==3)||(BotType==6)||(BotType==7)||(BotType==8))) {
int SpinBonus = ((!AllMini)?5000:2500);
if (GetT) SpinBonus=(TFull)?10000:(((TSp)&&(_Spin))?5000:500);
if (Lines>3) SpinBonus=max(SpinBonus,5000);
if (AllClear) SpinBonus=max(SpinBonus,10000);
if ((_f)&&(TFull)) SpinBonus=0;
if ((_f)&&(Lines==1)) SpinBonus*=5;
if ((_f)&&(TQPScore<=1100000)&&(Lines>1)&&(Lines<4)) SpinBonus=-5000;
if (SetSpin) {
bool CurB2B = (((Lines>3)&&(Mod8<2))||(Spin));
if ((AllClear)&&(!_f)&&((AllClearRule==AR_Default)||(AllClearRule==AR_IO)
||(AllClearRule==AR_QP)||(AllClearRule==AR_Techmino))) CurB2B=true;
if ((!QPBlighted)&&(Mod6==2)) CurB2B=true;
if ((Spinable)&&(TSp)&&(sth)) CurB2B=true;
if (CurB2B) {
//if ((BotType==1)&&(TFull)) SpinBonus*=10;
int l = Lines+2;
//if (GetT) l=((TFull)||(Lines>=4))?Lines+2:2;
if (_f) l=2;
if ((sth)||(_f)||(Gen.Pool.size()>=10)||(ModM)||((GetT)&&(!TSp))) ares+=ll(SpinBonus)*l;
else ares+=ll(SpinBonus)*(4+max(0,Sta->Combo-1))/4*l;
}
else ares-=max(0LL,((Mod8==2)?2000000LL:1000000LL)*(SX-PreHeight)/SX);
}
else if (((Lines>3)||(Spin))&&(Height+8<=SX)) {
SpinBonus /= 2;
if ((sth)||(_f)||(Gen.Pool.size()>=10)||(ModM)||((GetT)&&(!TSp))) ares+=ll(SpinBonus)*Lines;
else ares+=ll(SpinBonus)*(4+max(0,Sta->Combo-1))/4*Lines;
}
}
if ((SpinMode)&&(GetT)&&(IsSpinBonus(_p.GetName()))&&((!Lines)||(!TFull))) {
ares -= 300LL;
if (_wc>0) {
if (_wc-1>LY-_wc) {
if (y>_wc) ares-=100LL;
}
if (LY-_wc>_wc-1) {
if (y<_wc) ares-=100LL;
}
}
}
if (((BotType==1)||(BotType==3))&&((!ModM)&&(Gen.Pool.size()<10))) ares+=3000LL*ll(max(0,min(4,Sta->Combo-1)));
//if ((_wc>0)&&((!Lines)||(!TSp))&&(IsSpinBonus(_p.GetName()))) ares-=500LL;
//if ((GetT)&&((!Lines)||(!TFull))&&(IsSpinBonus(p.GetName()))&&(SetSpin)) ares-=100LL;
if ((Mod8==2)&&((BotType==1)||(BotType==3)||(BotType==8))&&(1||!ModP)) {
if ((SetSpin)&&(B2B>=4)) {
if ((Spin)&&(!Lines)) ares+=(ModP)?2000LL:5000LL;
}
}
if ((BotType==9)&&(Lines)&&(SpinMode)&&(WellCol>0)) {
if ((Combo)&&(SX-PreHeight<10)) ;
else if (FillCnt<4) res-=50;
}
if ((Lines)&&(!_f)) {
if (AllClear) ares+=(SetSpin)?5000LL:100000LL;
}
res = res*2000LL;
if ((SetSpin)&&(!qd)&&(BotType!=6)&&(BotType!=7)&&((Height+10<=SX)||(PlayerCount<2))) {
int hd=2, tot=0, tot4=0;
for (Piece &p : Gen.Pool) {
++tot; if (p.GetLX()>=4) ++tot4;
}
if (tot4*3>=tot) hd=4;
if (tot4*3>=tot*2) hd=8;
for (int i=Height; i>=1; --i) {
if (D[i][1]) {
if ((i>=Height-hd)&&((i==1)||(D[i-1][1]))) {
res += 2000LL;
if (D[i][2]) res+=1000L;
}
}
//else if (D[i+1][1]) res-=2000LL;
}
for (int i=Height; i>=1; --i) {
if (D[i][LY]) {
if ((i>=Height-hd)&&((i==1)||(D[i-1][LY]))) {
res += 2000LL;
if (D[i][LY-1]) res+=1000L;
}
}
//else if (D[i+1][LY]) res-=2000LL;
}
/*for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
int ed = (LY>>1)-min(j-1,LY-j-1);
if (D[i][j]) res-=((LY>>1)*(LY>>1)-ed*ed)*10LL;
}
}*/
}
if ((SetSpin)&&(!qd)&&(BotType!=6)&&(BotType!=7)&&(LY>=6)) {
int cnt = 0;
for (int i=1; i+2<=LX; ++i) {
for (int j=1; j<LY; ++j) {
if ((!D[i][j])&&(!D[i][j+1])
&&(!D[i+1][j])&&(!D[i+1][j+1])&&(D[i+1][j-1])&&(D[i+1][j+2])
&&((j==1)||(j==LY-1)||((!D[i+2][j])&&(!D[i+2][j+1])&&(D[i+2][j-1]&&D[i+2][j+2])))) ++cnt;
}
}
if (cnt) res-=2000LL*cnt;
}
if (!BotType) res-=Edge*100LL+10LL*ll(LeftMost+RightMost<=LY+LY)+ll(RotDis);
Sta->AccEval += ares;
for (int i=0; i<=LX+1; ++i) D[i][0]=D[i][LY+1]=false;
for (int i=0; i<=LY+1; ++i) D[0][i]=D[LX+1][i]=false;
return res;
}
static vector<pair<int,int> > TmpKick[4][4];
vector<Action> FinalSearch(AccessMap *Map, AccessMap *Tmp, int d, int x, int y, int gd, int gx, int gy, bool TryMini=false, bool HalfSame=false, bool Clutch=false) {
int LX=Map->LX, LY=Map->LY;
if ((BotType!=1)&&(BotType!=3)&&(BotType!=8)) TryMini=false;
if (!Map->Query(d,x,y)) {
if (!Clutch) return {A_HardDrop};
bool f = false;
for (int i=1; i<=LX-SX+6; ++i) {
++x;
if (Map->Query(d,x,y)) {
f=true; break;
}
}
if (!f) return {A_HardDrop};
}
Tmp->B[d][x][y] = false;
queue<PosTuple> qu;
queue<vector<Action> > ql;
qu.push((PosTuple){d,x,y}); ql.push(vector<Action>());
vector<Action> TmpRes = {A_HardDrop};
while (!qu.empty()) {
PosTuple o=qu.front(); qu.pop();
vector<Action> lst=ql.front(); ql.pop();
d=o.d; x=o.x; y=o.y;
if ((d==gd)&&(x==gx)&&(y==gy)) {
if (!TryMini) {
lst.push_back(A_HardDrop); return lst;
}
TmpRes=lst; TmpRes.push_back(A_HardDrop);
}
if ((SideGravity)&&(DropDelay)) {
if (Map->Query(d,x,y-1)) {
if (Tmp->Query(d,x,y-1)) {
lst.push_back(A_Left);
Tmp->B[d][x][y-1]=false; qu.push((PosTuple){d,x,y-1});
ql.push(lst); lst.pop_back();
}
continue;
}
}
if (Tmp->Query(d,x-1,y)) {
lst.push_back(A_SoftDrop);
Tmp->B[d][x-1][y]=false; qu.push((PosTuple){d,x-1,y});
ql.push(lst); lst.pop_back();
}
if ((!DropDelay)&&(Map->Query(d,x-1,y))) continue;
for (int nd=0; nd<4; ++nd) {
if (nd==d) continue;
bool f = true;
int dd = ((nd-d+4)&3);
if (dd==2) f=UseHalf;
else f=((Use2Rot)||((UseRotate)&&(dd==DefaultRot)));
if (!f) continue;
int nx=-1, ny=-1;
for (pair<int,int> o : TmpKick[d][nd]) {
if (Map->Query(nd,x+o.first,y+o.second)) {
nx=x+o.first; ny=y+o.second; break;
}
}
if (nx>=0) {
Action Act = A_Half;
if (((d+1)&3)==nd) Act=A_CW;
if (((d+3)&3)==nd) Act=A_CCW;
if ((TryMini)&&(Act!=A_Half)&&(Map->Query(nd,nx,ny))) {
if (((nd==gd)||((HalfSame)&&(nd==(gd^2))))&&(nx==gx)&&(ny==gy)) {
lst.push_back(Act); lst.push_back(A_HardDrop); return lst;
}
}
if (Tmp->Query(nd,nx,ny)) {
lst.push_back(Act);
Tmp->B[nd][nx][ny]=false; qu.push((PosTuple){nd,nx,ny});
ql.push(lst); lst.pop_back();
}
}
}
if ((UseMove)&&(Tmp->Query(d,x,y+1))) {
lst.push_back(A_Right);
Tmp->B[d][x][y+1]=false; qu.push((PosTuple){d,x,y+1});
ql.push(lst); lst.pop_back();
}
if ((UseMove)&&(Tmp->Query(d,x,y-1))) {
lst.push_back(A_Left);
Tmp->B[d][x][y-1]=false; qu.push((PosTuple){d,x,y-1});
ql.push(lst); lst.pop_back();
}
/*int gg = 1;
while (Map->Query(d,x-gg,y)) ++gg;
--gg;
if ((gg)&&(Tmp->Query(d,x-gg,y))) {
lst.push_back(A_SonicDrop);
Tmp->B[d][x-1][y]=false; qu.push((PosTuple){d,x-gg,y});
ql.push(lst); lst.pop_back();
}*/
}
return TmpRes;
}
//#warning Board::SearchNext
vector<Status*> CurLayer, Recycle;
int SearchDepth=1, Keep=1;
bool IgnoreAfterHold=true, GetT;
AccessMap *Map, *Tmp; Status *Current;
Instruction FinalInst, FinalStepInst;
int BeginInc;
vector<int> StaticLines; int SolidHeight=0;
int GetSearchSeg() {
if ((!BotType)||(BotType==8)||(BotType==9)) return 1;
if ((BotType==1)||(BotType==2)||(BotType==6)) return 9;
if ((BotType==3)||(BotType==4)||(BotType==7)) return 14;
if (BotType==5) return 12;
return 1;
}
bool _f = false;
int SameInstLim = 0;
bool SearchBegin() {
BotType = ActType;
TgD=-1; TgX=TgY=0;
if (ActType==5) {
BotType = 0;
if (AliveCount<=5) BotType=2;
}
if (PlayerCount>1) {
if (ActType==8) {
if (AliveCount>=30) BotType=9;
if (AliveCount<=5) BotType=1;
}
if (ActType==9) {
if (AliveCount<=5) BotType=1;
}
}
StaticLines.clear(); SolidHeight=0;
for (int i=1; i<=LX; ++i) {
bool f = true;
for (int j=1; j<=LY; ++j) {
if (!B[i][j]) {
f=false; break;
}
}
for (int j=1; j<=LY; ++j) {
if ((B[i][j])&&(IsUnclearable(B[i][j]))) {
if (f) ++SolidHeight;
StaticLines.push_back(i); break;
}
}
}
BeginInc=HoldPosInc; HoldPosInc=0;
bool HaveT=GetT=false;
if (((BotType==1)||(BotType==3))&&(!Mod8)&&(Mod2<2)&&((SpinRule==SR_Guildline)||(SpinRule==SR_AllMini))) GetT=true;
if (!DropDelay) HaveT=false;
for (Piece o : Pool) {
if (IsSpinBonus(o.GetName())) HaveT=true;
}
if (!HaveT) GetT=false;
if ((Mod9==2&&0)&&(TQPScore<300000)) _f=true;
else _f=false;
if (QPLevTime>=30000LL&&TQPScore>=150000) _f=false;
if (QPLevTime>=45000LL&&TQPScore>=50000) _f=false;
if (_f) GetT=false;
if (Gen.Pool.size()>=20) GetT=false;
SearchDepth=1, Keep=1;
IgnoreAfterHold = true;
CurLayer.clear(); SameInstLim=0;
if (!BotType) {
SearchDepth=1; Keep=1;
}
else if (BotType==1) {
SearchDepth=7; Keep=((HoldType)&&(HoldLen))?15:20;
if (ModP) Keep=20;
if ((BoardID<2)&&(SpinRule==SR_Guildline)) Keep=20;
//if ((ModP)&&(!BoardID)) Keep=100;
IgnoreAfterHold = false;
}
else if (BotType==2) {
SearchDepth=7; Keep=((HoldType)&&(HoldLen))?15:20;
if (ModP) Keep=20;
if ((PlayerCount<2)&&(StaticGarbHeight)) Keep=50;
IgnoreAfterHold = false;
}
else if (BotType==3) {
SearchDepth=12; Keep=30;
if (ModP==2) {
SearchDepth=12; Keep=50;
}
IgnoreAfterHold = false;
}
else if (BotType==4) {
SearchDepth=12; Keep=30;
if (ModP==2) {
SearchDepth=12; Keep=50;
}
IgnoreAfterHold = false;
}
else if (BotType==5) {
SearchDepth=10; Keep=200;
IgnoreAfterHold = false;
}
else if (BotType==6) {
SearchDepth=7; Keep=20;
if (ModP==2) {
SearchDepth=12; Keep=20;
}
IgnoreAfterHold = false;
}
else if (BotType==7) {
SearchDepth=12; Keep=50;
IgnoreAfterHold = false;
}
else if (BotType==8) {
SearchDepth=3; Keep=10;
IgnoreAfterHold = false;
}
else if (BotType==9) {
SearchDepth=1; Keep=1;
if ((!HoldLen)||(!HoldType)) {
SearchDepth=2; Keep=4;
}
BotType = 6;
}
if ((Mod2==2)&&(SearchDepth>2)) {
Keep=max(Keep,min(200,SearchDepth*Keep)); SearchDepth=2;
}
if ((Mod2==2)&&(SearchDepth>3)) {
SearchDepth=2; Keep=max(Keep,100);
}
int Height=0, Bub=0, BubH=0, HoleHeight=0;
bool bb = ((BotType==6)||(BotType==7));
for (int i=LX; i; --i) {
int ls=0, lu=0;
for (int j=1; j<=LY; ++j) {
if (CheckGrid(i,j)) Height=max(Height,i);
bool dn = CheckGrid(i-1,j);
if ((!CheckGrid(i+1,j))||(i==LX)) lu=j;
if ((!CheckGrid(i,j))&&
((CheckGrid(i,j-1))||((dn)&&(bb)&&(j==2)))&&
((CheckGrid(i,j+1))||((dn)&&(bb)&&(j==LY-1)))&&
(CheckGrid(i+1,j))&&((CheckGrid(i-1,j))||((PlayerCount>1)&&(Height+10>SX)))) {
++Bub; BubH=max(BubH,i);
}
else if ((!CheckGrid(i,j))&&(CheckGrid(i,j+1))&&(ls>=lu)) {
++Bub; BubH=max(BubH,i);
}
if (CheckGrid(i,j)) ls=j;
if ((!CheckGrid(i,j))&&(CheckGrid(i+1,j))) HoleHeight=max(i,HoleHeight);
}
}
PreHeight = Height;
int TotHeight = Height+min((((BotType==1)||(BotType==3))&&(QPMode)&&((WindUpCD)||(TQPScore<=1300000LL)))?5:((Mod8==2)?10:999),int(AttackIn.size()));
if ((TotHeight<=6)&&(Bub<2)&&((Mod8<2)||(TDig>=10))&&((Combo<3)||(B2B>=3))) SpinMode=true;
//if ((!ModM)&&(Gen.Pool.size()<15)&&(PlayerCount>1)&&(TotHeight+10<SX)&&(Bub<2)&&((!Combo)||(B2B>=5))) SpinMode=true;
if (TotHeight+(((PlayerCount<2)||(Gen.Pool.size()<18)||((B2B>=10)&&(TQPScore<2000000LL)))?5:10)>SX) SpinMode=false;
if ((Height<=SX-5)&&(CurZone)) SpinMode=true;
if ((BotType==6)||(BotType==7)) {
if (Mod2==2) {
if (TotHeight+9>SX) SpinMode=false;
}
int mn=LX+1, p=0;
for (int i=1; i<=LY; ++i) {
if ((i>=2)&&(i<=LY-1)) continue;
int cur = 0;
for (int j=LX; j; --j) {
if (CheckGrid(j,i)) {
cur=j; break;
}
}
if (cur<mn) {
mn=cur; p=i;
}
}
for (int i=1; i<=LY; ++i) {
if ((i==1)||(i==LY)) continue;
int cur = 0;
for (int j=LX; j; --j) {
if (CheckGrid(j,i)) {
cur=j; break;
}
}
if (cur<mn) {
mn=cur; p=i;
}
}
if ((((p!=1)&&(p!=LY)))||(BubH>mn)) BotType=2;
else if (!SpinMode) BotType=2;
else {
int d=(p==1)?1:-1, acc=0;
for (int i=mn+1; i<=LX; ++i) {
int j=p, cnt=0;
for (int jj=1; jj<LY; ++jj) {
j += d;
if (CheckGrid(i,j)) {
if (jj>1) break;
}
else ++cnt;
}
if (cnt>=LY-1) break;
if (cnt) acc+=cnt;
else if ((acc)&&(acc<3)) {
if ((mn)||(PlayerCount>1)) BotType=2;
BotType=2; break;
}
else acc=0;
}
}
}
while (Hold.size()>HoldLen) Hold.pop_back();
FillNext(SearchDepth+HoldLen+1);
if (!CheckActive()) return false;
Current = new Status(LX, LY);
Current->Cur=Cur; Current->Hold=Hold; Current->Next=Next;
Current->LineAfterPC = LineAfterPC;
Current->LastClearType = LastClearType;
Current->Combo = Combo;
Current->Clutch = CurClutch;
/*if ((GetT)&&(SpinMode)) {
bool f = (Current->Cur.GetName()=="T");
for (Piece &o : Current->Hold) f|=(o.GetName()=="T");
for (int i=0; i<SearchDepth-1; ++i) {
if (f) break;
if (Current->Next[i].GetName()=="T") f=true;
}
if (!f) Current->Next[max(0,SearchDepth-1)]=P_T;
}*/
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) Current->B[i][j]=((B[i][j])&&(!C[i][j]));
}
CurLayer = {Current};
Map = new AccessMap(LX,LY);
Tmp = new AccessMap(LX,LY);
FinalInst = (Instruction){-1,0,0,0,false};
FinalStepInst = (Instruction){-1,0,0,0,false};
return true;
}
bool SearchLayer(int i) {
vector<pair<Status*,ll> > NextLayer;
vector<llu> NextHash;
int LayerKeep = Keep;
//if ((BotType==1)&&(i>1)) Keep=10;
bool Final=(i+1==SearchDepth); ll FinalEval=-4000000000000000000LL;
for (Status *Sta : CurLayer) {
vector<pair<int,Piece> > PieceOpt = {make_pair(0,Sta->Cur)};
vector<llu> PieceHash = {Sta->Cur.GetHash()};
int Holds = 0;
if (HoldType==1) Holds=min(HoldLen,HoldRem);
if (HoldType==2) Holds=HoldLen;
int hp = (BotType==5)?3:1;
if ((i>=hp)&&(IgnoreAfterHold)) Holds=0;
int id = 0;
int StaHeight = 0;
for (int ii=1; ii<=LX; ++ii) {
for (int jj=1; jj<=LY; ++jj) {
if (Sta->B[ii][jj]) StaHeight=max(StaHeight,ii);
}
}
for (int j=0; j<int(HoldLen-Sta->Hold.size()); ++j) {
if (++id>Holds) break;
llu hsh=Sta->Next[j].GetHash(); bool f=true;
for (llu k : PieceHash) {
if (hsh==k) {
f=false; break;
}
}
if (f) {
PieceOpt.push_back(make_pair(id,Sta->Next[j])); PieceHash.push_back(hsh);
}
}
for (Piece &p : Sta->Hold) {
if (++id>Holds) break;
llu hsh=p.GetHash(); bool f=true;
for (llu k : PieceHash) {
if (hsh==k) {
f=false; break;
}
}
if (f) {
PieceOpt.push_back(make_pair(id,p)); PieceHash.push_back(hsh);
}
}
for (pair<int,Piece> &o : PieceOpt) {
vector<Piece> NewNext=Sta->Next, NewHold=Sta->Hold; Piece NewCur=Sta->Cur;
for (int j=0; j<o.first; ++j) {
if (NewHold.size()==HoldLen) {
Piece tmp = NewHold[0];
for (int i=0; i+1<HoldLen; ++i) NewHold[i]=NewHold[i+1];
NewHold[HoldLen-1] = NewCur;
NewCur = tmp;
}
else {
NewHold.push_back(NewCur);
NewCur = NewNext[0];
for (int k=0; k+1<NewNext.size(); ++k) NewNext[k]=NewNext[k+1];
NewNext.pop_back();
}
}
NewCur=NewNext[0]; for (int j=0; j+1<NewNext.size(); ++j) NewNext[j]=NewNext[j+1];
NewNext.pop_back();
GetAccessMap(Map, Sta, o.second);
Piece p = o.second;
vector<pair<PosTuple,bool> > Locations = GetLocations(Map, Tmp, p, StaHeight, ((i)||(o.first))?0:BeginInc,
(IsSpinBonus(p.GetName()))||(((BotType==1)||(BotType==3))&&(SpinRule==SR_Default)), Sta->Clutch);
if (Locations.empty()) break;
for (pair<PosTuple,bool> pr : Locations) {
PosTuple oo = pr.first;
Status *NewSta = nullptr;
if (Recycle.empty()) NewSta=new Status(*Sta);
else {
NewSta=Recycle.back(); Recycle.pop_back();
*NewSta = *Sta;
}
int PLX = p.GetLX();
int Unmoveable = 0;
for (int ii=0; ii<PLX; ++ii) {
for (int jj=0; jj<PLX; ++jj) {
if (!p.GetGrid(ii,jj,oo.d)) continue;
int x=oo.x+ii, y=oo.y+jj;
if (NewSta->CheckGrid(x+1,y)) Unmoveable|=1;
if (NewSta->CheckGrid(x-1,y)) Unmoveable|=2;
if (NewSta->CheckGrid(x,y+1)) Unmoveable|=4;
if (NewSta->CheckGrid(x,y-1)) Unmoveable|=8;
}
}
if (!i) NewSta->Inst=(Instruction){o.first,oo.d,oo.x,oo.y,((pr.second)||(Unmoveable==15))};
for (int ii=0; ii<PLX; ++ii) {
for (int jj=0; jj<PLX; ++jj) {
if (p.GetGrid(ii,jj,oo.d)) NewSta->B[oo.x+ii][oo.y+jj]=true;
}
}
NewSta->Next=NewNext; NewSta->Hold=NewHold; NewSta->Cur=NewCur;
int pp=-1; ll TmpEval=Eval(NewSta,p,oo,Unmoveable==15,oo.d,oo.x,oo.y,pr.second);
ll hsh = NewSta->GetHash((HoldType)?HoldLen:0);
ll NewEval = TmpEval+NewSta->AccEval;
if (Final) {
if (NewEval>FinalEval) {
FinalEval=NewEval; FinalStepInst=NewSta->Inst;
}
Recycle.push_back(NewSta); continue;
}
int sc=0, sp=-1;
for (int i=0; i<NextHash.size(); ++i) {
if (hsh==NextHash[i]) pp=i;
/*if (NextLayer[i].first->Inst==NewSta->Inst) {
++sc;
if (sp<0) sp=i;
else if (NextLayer[sp].second>NextLayer[i].second) sp=i;
}*/
}
if (pp>=0) {
if (NewEval>NextLayer[pp].second) {
NextLayer[pp].second = NewEval;
Recycle.push_back(NextLayer[pp].first);
NextLayer[pp].first = NewSta;
}
else Recycle.push_back(NewSta);
}
/*else if ((sp>=0)&&(SameInstLim>0)&&(sc>=SameInstLim)) {
if (NewEval>NextLayer[sp].second) {
Recycle.push_back(NextLayer[sp].first);
NextLayer[sp].first=NewSta; NextLayer[sp].second=NewEval;
NextHash[sp] = hsh;
}
else Recycle.push_back(NewSta);
}*/
else {
if (NextLayer.size()<LayerKeep) {
NextLayer.push_back(make_pair(NewSta, NewEval));
NextHash.push_back(hsh);
}
else {
int p = 0;
for (int i=1; i<NextLayer.size(); ++i) {
if (NextLayer[i].second<NextLayer[p].second) p=i;
}
if (NewEval>NextLayer[p].second) {
Recycle.push_back(NextLayer[p].first);
NextLayer[p].first=NewSta; NextLayer[p].second=NewEval;
NextHash[p] = hsh;
}
else Recycle.push_back(NewSta);
}
}
}
}
if (i) Recycle.push_back(Sta);
}
CurLayer.clear();
if (Final) {
if (FinalStepInst.ord>=0) FinalInst=FinalStepInst;
return true;
}
bool AllSame = false;
if (NextLayer.size()) {
int pos = 0;
for (int i=1; i<NextLayer.size(); ++i) {
if (NextLayer[i].second>NextLayer[pos].second) pos=i;
}
FinalInst = NextLayer[pos].first->Inst;
AllSame = true;
for (pair<Status*,ll> o : NextLayer) {
if (o.first->Inst!=FinalInst) {
AllSame=false; break;
}
}
}
for (pair<Status*,ll> o : NextLayer) CurLayer.push_back(o.first);
NextLayer.clear();
if (AllSame) return true;
return false;
}
vector<Action> SearchEnd() {
for (Status *p : CurLayer) delete p;
CurLayer.clear();
Piece p=P_Empty; int k=FinalInst.ord;
if (k<0) {
delete Map; delete Tmp;
delete Current; return {A_HardDrop};
}
if (!k) p=Cur;
else if (k<=HoldLen-Hold.size()) p=Next[k-1];
else p=Hold[k-HoldLen+Hold.size()-1];
GetAccessMap(Map, Current, p);
pair<int,int> Place=SpawnPlace(p), Anch[4];
Piece NewP = p;
for (int i=0; i<4; ++i) {
NewP.SetDir(i); Anch[i]=NewP.GetAnchor();
}
int d=DefaultDir, x=Place.first+Anch[d].first, y=Place.second+Anch[d].second;
for (int i=0; i<4; ++i) {
for (int j=0; j<4; ++j) {
TmpKick[i][j] = GetKickTable(i,j,p.GetRealName(),RotateSystem);
for (pair<int,int> &o : TmpKick[i][j]) {
swap(o.first, o.second);
o.first += Anch[j].first-Anch[i].first;
o.second += Anch[j].second-Anch[i].second;
}
}
}
for (int d=0; d<4; ++d) {
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) Tmp->B[d][i][j]=Map->B[d][i][j];
}
}
int od=FinalInst.d, ox=FinalInst.x+Anch[od].first, oy=FinalInst.y+Anch[od].second;
Tg=NewP; TgD=FinalInst.d; TgX+=FinalInst.x; TgY=FinalInst.y;
vector<Action> SearchRes = FinalSearch(Map,Tmp,d,x+((k)?0:BeginInc),y,od,ox,oy,FinalInst.sp,IsHalfSame(p.GetRealName()),((CurClutch)||(PreInc)||(HoldPosInc+BeginInc)));
vector<Action> res(k, A_Hold);
if (SearchRes.empty()) res.push_back(A_HardDrop);
else {
for (Action o : SearchRes) res.push_back(o);
}
delete Map; delete Tmp;
delete Current;
if (BoardID) {
for (Status *o : Recycle) delete o;
Recycle.clear();
}
return res;
}
int SearchStep = -1;
vector<Action> SearchNext(bool ByStep=false) {
TgD = -1;
if ((ByStep)||(SearchStep!=-1)) {
if (SearchStep==-1) {
if (SearchBegin()) SearchStep=0;
}
else if (SearchStep==-2) {
SearchStep=-1; return SearchEnd();
}
else {
bool f = SearchLayer(SearchStep);
if ((++SearchStep>=SearchDepth)||(f)) SearchStep=-2;
}
return vector<Action>();
}
if (!SearchBegin()) return vector<Action>();
for (int i=0; i<SearchDepth; ++i) {
if (SearchLayer(i)) break;
}
SearchStep = -1;
return SearchEnd();
}
int B2BColor(int x) {
if (B2BRule==BR_Techmino) {
if (B2B<50) return 0x888888;
if (B2B<=800) return 0xFF6666;
return 0x9999FF;
}
if (x<1) return (B2BRule==BR_Chain)?0xAA0000:0x888888;
if (x<4) return 0xFFE211;
if ((B2BRule!=BR_Surge)&&(B2BRule!=BR_QP)) return 0xFFE211;
vector<pair<int,int> > lst={{4,0x00FFCC},{13,0xFFFF00},{31,0xFF0000},{45,0xDF3782},{70,0xAF2FFF},{90,0x0080FF},
{130,0x66CCFF},{150,0x99FFFF},{220,0xE5E59C}};
int rr = -1;
for (int i=1; i<lst.size(); ++i) {
if ((lst[i-1].first<=x)&&(x<=lst[i].first)) rr=Mix(lst[i].second,lst[i-1].second,double(x-lst[i-1].first)/double(lst[i].first-lst[i-1].first));
}
if ((rr<0)&&(x<=lst[0].first)) rr=lst[0].second;
else if (rr<0) rr=lst.back().second;
if (Mod8==2) rr=Mix(0xFFFFFF,0xFFFFFF^rr,0.4);
return rr;
}
int GetHeight() {
for (int i=LX; i; --i) {
for (int j=1; j<=LY; ++j) {
if (CheckGrid(i,j)) return i;
}
}
return 0;
}
int GetPaintColor() {
if (PaintType==1) return P_Z.GetColor();
if (PaintType==2) return P_L.GetColor();
if (PaintType==3) return P_O.GetColor();
if (PaintType==4) return P_S.GetColor();
if (PaintType==5) return P_I.GetColor();
if (PaintType==6) return P_J.GetColor();
if (PaintType==7) return P_T.GetColor();
if (PaintType==8) return Garb;
return 0x39C5BB;
}
int ModPos = 0;
void PrintQPMod(int val, int clr, string s, string ss) {
if (!val) return;
double x=double(++ModPos)*1.5, y=LY+5;
if (val==1) Poly(x,y,0.6,4,clr,acos(-1.0)*0.25);
else {
Poly(x, y, 1, 4, 0xFF6666, 0);
Poly(x, y, 1, 4, 0xFF6666, acos(-1.0)*0.25);
}
double dd = (val==1)?1.0:1.5;
PrintStrM((val==1)?s:ss, x-0.25*dd, y-0.2*dd, 0.8*dd, (val==1)?Mix(0x000000,clr,0.5):0xFFFFFF, 0.2);
}
int GetLevelColor(int x) {
return LevelColor[max(0,min(int(LevelColor.size())-1,x))];
}
void PaintZenith() {
double len = min(8,LY)*1.5;
int MaxLevel = int(QPLevelScore.size());
int CurLevel = max(1,min(MaxLevel,Level));
int pp = 0;
int SurgeCount = 0;
if (B2B>4) {
if (B2BRule==BR_Surge) SurgeCount=B2B-1;
if (B2BRule==BR_QP) SurgeCount=B2B-4;
}
int OriSurgeCount = SurgeCount;
SurgeCount = max(0,SurgeCount-int(AttackIn.size()));
ll SurgeScore = DQPScore+ll(SurgeCount)*250LL*ll(QPRank+1);
if (SurgeCount<1) SurgeScore=-1LL;
int BegLevel = max(9,CurLevel);
for (int i=0; i<QPLevelScore.size(); ++i) {
if (SurgeScore>QPLevelScore[i]*1000LL) BegLevel=max(BegLevel,i+1);
}
int SurgeRank = QPRank;
if (OriSurgeCount>0) {
ll _Exp = QPExp;
if (SurgeCount) _Exp+=500+10000*min(SurgeCount,10000);
if (SurgeCount<OriSurgeCount) _Exp+=500+10000*(((Mod5==2)||(Mod9==2)||(ModD==2))?0:OriSurgeCount-SurgeCount);
_Exp = max(_Exp,0LL);
for (;;) {
ll req = max(40000LL,40000LL*(SurgeRank+1));
if ((SurgeRank>100)||(_Exp<req)) break;
SurgeRank+=_Exp/req; _Exp-=req;
}
}
for (int i=14; i>=0; --i) {
int d=BegLevel-i; if (d<1) continue;
ll Lower=QPLevelScore[d-1]*1000LL, Upper=(d==MaxLevel)?max(Lower+1000LL,DQPScore):QPLevelScore[d]*1000LL;
if (d>Level) {
PrintStrL("Stage "+IToS(d), i*2, LY+6, 0.7, 0x888888);
Rect(i*2+1, LY+6, 0.3, len, 0x444444);
}
else {
PrintStrL("Stage "+IToS(d), i*2, LY+6, 0.7, 0xCCCCCC);
Rect(i*2+1, LY+6, 0.3, len, 0x888888);
ll t=Time; if (QPSegTime.size()>d-1) t=QPSegTime[d-1];
PrintStrR(IToS(t/1000LL/60LL)+":"+IToS(t/1000LL%60LL/10LL)+IToS(t/1000LL%60LL%10LL)+"."+IToS(t%1000LL/100LL)+" ", i*2, LY+6+len, 0.7, (d==CurLevel)?0xFDD000:0xDDDDDD);
for (int j=pp; j<QPSeg.size(); ++j) {
pair<int,pair<ll,ll> > o = QPSeg[j];
ll l=max(Lower,o.second.first), r=min(min(Upper,DQPScore),o.second.second);
if (o.second.second<=Upper) pp=j+1;
if (l>Upper) break;
if (l>=r) continue;
Rect(i*2+1, LY+6+len*double(l-Lower)/double(Upper-Lower), 0.3, len*double(r-l)/double(Upper-Lower), Mix(0x000000,abs(o.first),0.3));
if (o.first<0)
Rect(i*2+1+0.15, LY+6+len*double(l-Lower)/double(Upper-Lower), 0.15, len*double(r-l)/double(Upper-Lower), abs(o.first));
}
}
if ((SurgeScore>=Lower)&&(SurgeScore<=Upper)) {
Rect(i*2+1-0.1,LY+6+len*double(SurgeScore-Lower)/double(Upper-Lower)-0.05,0.1,0.1,GetLevelColor(SurgeRank));
Rect(i*2+1,LY+6+len*double(SurgeScore-Lower)/double(Upper-Lower)-0.05,0.3,0.1,0xDDDDDD);
}
if ((DQPScore>=Lower)&&(DQPScore<=Upper))
Rect(i*2+1-0.1,LY+6+len*double(DQPScore-Lower)/double(Upper-Lower)-0.05,0.4,0.1,0xFDD000);
}
}
char KeyPause = 'O';
string GetKeyChar(Action x) {
int res = 0;
for (Monitor &o : Keys) {
if (o.Result==x) res=o.Key;
}
return KeyChar(res);
}
bool AvailBotAction(Action o) {
return ((o==A_Retry)&&((!QPMode)||(PlayerCount<2)||(Over)));
}
bool PreActive = false;
vector<Action> Actions;
vector<ConfigContent> BoardConfig;
int GetConfig(string Name, int Default) {
for (ConfigContent o : BoardConfig) {
if (ToLower(o.first)==ToLower(Name)) {
int tmp = SToI(o.second);
if (tmp!=SToIErr) return tmp;
}
}
return Default;
}
string GetConfig(string Name, string Default, vector<string> List) {
for (ConfigContent o : BoardConfig) {
if (ToLower(o.first)==ToLower(Name)) {
for (string x : List) {
if (ToLower(x)==ToLower(o.second)) return ToLower(x);
}
}
}
return ToLower(Default);
}
bool UseLeveling() {
return ((QPMode)||(LevTime)||(LevAttack)||(LevLine)||(LevPiece)||(LevStart)||(LevBase));
}
int GetLevel() {
if (QPMode) {
if ((Time>=0LL)&&(QPLevel<QPLevelScore.size())&&(TQPScore>=1000LL*QPLevelScore[QPLevel])) ++QPLevel;
return QPLevel;
}
int res = LevBase;
if (LevTime) {
ll tmp=Time, req=LevTime;
while (res<1000) {
if (tmp>=req) {
tmp-=req; ++res; req+=LevTimeInc;
}
else break;
}
}
if (LevLine) {
int tmp=TLine, req=LevLine;
while (res<1000) {
if (tmp>=req) {
tmp-=req; ++res; req+=LevLineInc;
}
else break;
}
}
if (LevPiece) {
int tmp=TPiece, req=LevPiece;
while (res<1000) {
if (tmp>=req) {
tmp-=req; ++res; req+=LevPieceInc;
}
else break;
}
}
if (LevAttack) {
int tmp=TAttack, req=LevAttack;
while (res<1000) {
if (tmp>=req) {
tmp-=req; ++res; req+=LevAttackInc;
}
else break;
}
}
return min(max(res,LevStart),min(1000,LevMax));
}
double GetLevelMultipler(int Level, double k) {
double mul = 1.0;
if (LevScaleMode==LS_Default) mul=pow(max(0.0,0.8-k*double(Level)),Level)/0.8;
if (LevScaleMode==LS_Div) mul=1.0/(1.0+k*double(Level));
if (LevScaleMode==LS_Dec) mul=max(0.0,1.0-k*double(Level));
if (LevScaleMode==LS_Exp) mul=pow(max(0.0,1.0-k),double(Level));
return max(0.0,min(1.0,mul));
}
void UpdateLevel() {
if (!UseLeveling()) {
DropDelay=BaseDropDelay; LockDelay=BaseLockDelay;
ARE=BaseARE; LCD=BaseLCD; CCD=BaseCCD; GravityDelay=BaseGravityDelay; return;
}
int _Level = GetLevel();
if (Level==_Level) return;
Level = _Level;
if ((Level)||(!QPMode))
AddFloatText(IToS(Level), 0xAAAAAA, 1.8, 0, 0.12, 0.06,
SX*0.25, LY*0.5-0.4, -1, 0, 0, 0);
if (QPMode) {
if (Level>1) QPSegTime.push_back(Time);
if ((Mod9==2)&&(QPLevTime<60000LL)&&(Level>1)) AddNotice("COOL!",0x66CCFF);
QPLevTime = 0LL;
}
if (ModM==1) {
MutatePool.clear(); for (int i=2; i<9; ++i) MutatePool.push_back(i);
}
double mul = GetLevelMultipler(Level,0.001*double(LevScaleRate));
DropDelay = (BaseDropDelay==Max)?Max:BaseDropDelay*mul;
if (Mod4==1) DropDelay/=30;
ARE = BaseARE*mul;
LCD = BaseLCD*mul;
CCD = BaseCCD; //CCD = BaseCCD*mul;
GravityDelay = BaseGravityDelay*mul;
LockDelay = BaseLockDelay;
if (Mod3==2) LCD=BaseLCD;
if (Mod4) {
vector<int> lst = {30,30,29,28,27,26,24,22,20,18,16};
if (Mod4==2) {
lst={24,24,22,20,18,16,15,14,13,12,11}; DropDelay=0;
}
int k = min(int(lst.size())-1,Level);
LockDelay = BaseLockDelay*lst[k]/30;
}
else if ((MasterBegin>=0)&&(Level>=MasterBegin)&&(!QPMode)) {
DropDelay = 0;
vector<int> lst = {300,295,276,252,228,204,175,168,156,150,132,115,114,108,102,96,85,84,78,72,66,55,50,45,40,37,33,30,28,26,24,22,20,18,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1};
int k = min(int(lst.size())-1,Level-MasterBegin);
LockDelay = BaseLockDelay*lst[k]/300;
}
if (QPMode) {
if (Mod9) GarbageDelay=max(400,2400-Level*200);
else {
GarbageDelay = max(500,5500-Level*500);
if (QPRevmode()) GarbageDelay=min(2500,GarbageDelay);
if ((Mod3==2)||(Mod6==2)||(Mod8==2)) GarbageDelay=2500;
}
}
}
int GetGarbHeight() {
for (int i=LX; i; --i) {
for (int j=1; j<=LY; ++j) {
if ((!C[i][j])&&(B[i][j]<0)) return i;
}
}
if (GarbageShape==GS_Empty) {
bool ff = false;
for (int i=LX; i; --i) {
bool f = true;
for (int j=1; j<=LY; ++j) {
if ((C[i][j])&&(B[i][j])) f=false;
}
if (!f) ff=true;
else if (ff) return i;
}
}
return 0;
}
int GetZoneBonus(int Lines) {
if (!CurZone) return 0;
return (Lines*(4+max(1,min(4,CurZone))*3)+3)/10;
}
bool IsZoneClear = false;
bool ClearZone() {
bool f = false;
int Lines = 0;
for (int i=1; i<=LX; ++i) {
if (B[i][1]==GarbZone) ++Lines;
for (int j=1; j<=LY; ++j) {
if (B[i][j]==GarbZone) {
f=true; B[i][j]=-B[i][j]; Chain=0;
}
}
}
ZoneAttack += GetZoneBonus(Lines);
if (Lines) IsZoneClear=true;
return f;
}
int ClearRound() {
int res=0, p=0;
for (int i=1; i<=LX; ++i) {
bool f = false;
for (int j=1; j<=LY; ++j) {
if (B[i][j]==GarbRound) f=true;
}
if (f) {
++res;
if (GravityType==GV_None) {
++p;
for (int j=1; j<=LY; ++j) B[p][j]=Age[p][j]=U[p][j]=0;
}
}
else {
++p;
if (p!=i) {
for (int j=1; j<=LY; ++j) {
B[p][j]=B[i][j]; B[i][j]=0;
Age[p][j]=Age[i][j]; U[p][j]=U[i][j];
Age[i][j]=U[i][j]=0;
}
}
}
}
return res;
}
void TopOut() {
if (CurZone) {
ClearZone();
CurZone=0; PreAREProcess(false);
return;
}
if ((Stock<0)||(StockRem>0)) {
if (Stock>=0) --StockRem;
ClearBoard(true); return;
}
Over=true; KOMessage=LastAttacker;
ClearSearchProcess();
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LY; ++j) {
if (C[i][j]) C[i][j]=false;
if (!B[i][j]) continue;
int tmp=abs(B[i][j]), grey=0;
grey+=tmp&255; tmp>>=8;
grey+=tmp&255; tmp>>=8;
grey+=tmp&255; grey=max(0,min(255,(grey+1)/3));
if (B[i][j]<0) grey=rand()%51+100;
int clr = (grey<<16)|(grey<<8)|grey;
if (B[i][j]<0) B[i][j]=-clr;
else B[i][j]=clr;
U[i][j] = NewUID();
}
}
}
int GetCopyPos() {
for (int i=1; i<=LX; ++i) {
bool f = true;
for (int j=1; j<=LY; ++j) {
if (IsUnclearable(B[i][j])) {
f=false; break;
}
}
if (f) return i;
}
return 0;
}
GarbageLayer RollGarbage(int Hole=-1) {
if (Hole<0) Hole=HolePos;
++GarbCount; int CopyPos=GetCopyPos();
GarbageLayer o(LY);
for (int i=1; i<=LY; ++i) {
if (GarbageShape==GS_Default) o.B[i]=(i!=Hole);
if (GarbageShape==GS_Bubble) o.B[i]=(i==Hole);
if (GarbageShape==GS_Empty) o.B[i]=0;
if (GarbageShape==GS_Full) o.B[i]=1;
if (GarbageShape==GS_Board) o.B[i]=(GarbCount+i)&1;
if (GarbageShape==GS_Random) o.B[i]=((rand()&1)&&(i!=Hole));
if (GarbageShape==GS_Stair) {
int p = 1;
if (LY>1) {
int val = (GarbCount-1)%((LY-1)<<1);
if (val<LY-1) p=val+1;
else p=LY-val+(LY-1);
}
o.B[i] = (i!=p);
}
if (GarbageShape==GS_Copy) o.B[i]=CheckGrid(CopyPos,i);
}
if ((Mod2==2)&&(LY>1)) {
if (rand()%100<max(10,min(55,Level*5))) QPRevMod2GarbSide^=1;
int tar = 1;
if (Hole==1) tar=2;
else if (Hole==LY) tar=LY-1;
else tar=Hole+((QPRevMod2GarbSide)?1:-1);
o.B[tar] = 0;
}
if (Mod6==1) {
if (rand()&1) o.B[rand()%LY+1]=0;
}
if (Mod6==2) {
for (int i=1; i<=LY; ++i) o.B[i]=(rand()%3)?0:1;
if (LY>=2) {
int d1=rand()%LY, d2=rand()%(LY-1); if (d2==d1) d2=LY-1;
o.B[d1+1]=0; o.B[d2+1]=1;
}
}
/*if (!BoardID) {
for (int i=1; i<=LY; ++i) {
if ((i<LatestReceive.B.size())&&(!LatestReceive.B[i])) o.B[i]^=1;
}
}*/
for (int i=1; i<=LY; ++i) {
if (o.B[i]) {
if (GarbageType==GT_Solid) o.B[i]=Solid;
else if (GarbageType==GT_Bricks) o.B[i]=RollColor();
else o.B[i]=Garb;
}
else {
if (GarbageType==GT_Lock) o.B[i]=GarbLock;
if (GarbageType==GT_Bomb) o.B[i]=GarbBomb;
}
}
//if (!BoardID) LatestReceive=o;
return o;
}
void RerollHole() {
bool Concentrate = ((QPMode)&&(LY>=5)&&(Mod5==2));
int Luck = 0;
if (QPMode) {
Luck = 33-3*min(Level,10);
if (Mod9) Luck-=33;
if (Mod3) Luck-=25;
if (Mod5==2) Luck=50;
}
if (!Luck) {
if (Concentrate) {
HolePos=rand()%(LY-4)+3; return;
}
HolePos=rand()%LY+1; return;
}
vector<pair<int,int> > Candidates;
for (int i=1; i<=LY; ++i) {
if ((Concentrate)&&((i<=2)||(i>=LY-1))) continue;
int w=0; bool f=false;
for (int j=LX; j; --j) {
if (CheckGrid(j,i)) f=true;
if (f) {
if (CheckGrid(j,i)) ++w;
else w+=2;
}
}
if (LastAttacker!=-1) w+=5*abs(i-HolePos);
Candidates.push_back(make_pair(i,w));
}
if (Candidates.empty()) {
if (Concentrate) {
HolePos=rand()%(LY-4)+3; return;
}
HolePos=rand()%LY+1; return;
}
shuffle(Candidates.begin(), Candidates.end(), GlobalGen);
stable_sort(Candidates.begin(), Candidates.end(), [](pair<int,int> x, pair<int,int> y) {
return x.second<y.second;
});
int totw=0, id=0;
for (pair<int,int> o : Candidates) {
++id; o.second=max(0,90+(9-id*2)*Luck); totw+=o.second;
}
if (!totw) {
if (Concentrate) {
HolePos=rand()%(LY-4)+3; return;
}
HolePos=rand()%LY+1; return;
}
int pp = GlobalGen()%totw;
for (pair<int,int> o : Candidates) {
pp -= o.second;
if (pp<0) {
HolePos=o.first; return;
}
}
if (Concentrate) {
HolePos=rand()%(LY-4)+3; return;
}
HolePos = rand()%LY+1;
}
int GetRiseHeight(int Level=0) {
for (int i=1; i<=LX; ++i) {
bool f1=false, f2=true;
bool p0 = false;
for (int j=1; j<=LY; ++j) {
if ((C[i][j])||(!IsUnclearable(B[i][j]))) f2=false;
if ((!C[i][j])&&(IsUnclearable(B[i][j]))) f1=true;
if ((!C[i][j])&&((B[i][j]==GarbLock)||(B[i][j]==GarbBomb))) p0=true;
}
int cur = 0;
if (f1) cur=1;
if (f2) cur=2;
if (p0) cur=0;
if (cur<=Level) return i-1;
}
return LX;
}
void AddGarbage(GarbageLayer o, int RiseLevel=0) {
int Row = GetRiseHeight(RiseLevel)+1;
if (Row>LX) return;
for (int i=LX; i>Row; --i) {
for (int j=1; j<=LY; ++j) {
B[i][j]=B[i-1][j]; C[i][j]=C[i-1][j];
Age[i][j]=Age[i-1][j]; U[i][j]=U[i-1][j];
}
}
int cU = NewUID();
for (int i=1; i<=LY; ++i) {
B[Row][i]=o.B[i]; C[Row][i]=false; U[Row][i]=0;
if (B[Row][i]) {
Age[Row][i]=500; U[Row][i]=cU;
}
else {
Age[Row][i]=0; cU=NewUID();
}
}
for (int i=LX; i>Row; --i) {
if (FallDest[i-1]) FallDest[i]=FallDest[i-1]+1;
else FallDest[i]=0;
}
FallDest[Row] = Row;
if (CheckActive()) {
++PosX; ++TgX;
if (Bot) ++HoldPosInc;
else if ((!GarbagePush)||(!SmoothLevel)) MoveDown();
}
else ++PreInc;
}
Piece GetFlip(Piece p) {
int PLX = p.GetLX();
vector<vector<int> > vec(PLX);
for (int i=0; i<PLX; ++i) {
for (int j=0; j<PLX; ++j) vec[PLX-i-1].push_back(p.GetRealGrid(i,PLX-j-1,0));
}
Piece *nw = new Piece(PLX,vec,p.GetColor(),p.GetRealName());
CustomPiece.push_back(nw);
return *nw;
}
Piece GetRotate(Piece p, int del) {
del&=3; if (del<0) del=(del+4)&3;
int PLX = p.GetLX();
vector<vector<int> > vec(PLX);
for (int i=0; i<PLX; ++i) {
for (int j=0; j<PLX; ++j) vec[PLX-i-1].push_back(p.GetRealGrid(i,j,del));
}
Piece *nw = new Piece(PLX,vec,p.GetColor(),p.GetRealName()+"@"+"URDL"[del]);
CustomPiece.push_back(nw);
return *nw;
}
int RollColor() {
for (;;) {
int R = max(0,min(255,int(randf()*256.0)));
int G = max(0,min(255,int(randf()*256.0)));
int B = max(0,min(255,int(randf()*256.0)));
if ((R+G+B>=400)&&(R+G+B<=600)) return (R<<16)|(G<<8)|B;
}
return 0;
}
pair<int,int> ReadMutateName(string s) {
if ((s.empty())||(s[0]!='?')) return make_pair(++MutateID,0);
int r=0, fst=0;
for (char ch : s) {
if (ch=='?') continue;
if ((ch>='0')&&(ch<='9')) r=r*10+ch-'0';
if (ch=='-') {
fst=r; r=0;
}
}
return make_pair(fst,r);
}
Piece GetMutate(Piece p) {
int LX = p.GetLX();
vector<vector<int> > vec(LX+2,vector<int>(LX+2));
vector<pair<int,int> > InsPos, DelPos;
for (int i=1; i<=LX; ++i) {
for (int j=1; j<=LX; ++j) vec[i][j]=(p.GetGrid(i-1,j-1)!=0);
}
int dc = 0;
for (int i=0; i<=LX+1; ++i) {
for (int j=0; j<=LX+1; ++j) {
int f = ((i)&&(vec[i-1][j]))
+((i<=LX)&&(vec[i+1][j]))
+((j)&&(vec[i][j-1]))
+((j<=LX)&&(vec[i][j+1]));
if ((!vec[i][j])&&(f)) {
bool dd = ((i)&&(i<=LX))&&((j)&&(j<=LX));
if ((LX<5)||(dd)) {
InsPos.push_back(make_pair(i,j));
if (dd) {
InsPos.push_back(make_pair(i,j)); InsPos.push_back(make_pair(i,j));
}
}
}
if (vec[i][j]) {
++dc; int w=5-f;
for (int k=0; k<w; ++k) DelPos.push_back(make_pair(i,j));
}
}
}
if ((InsPos.empty())&&(LX<5)) InsPos.push_back(make_pair(1,1));
int InsWeight = (InsPos.size())?7:0;
int DelWeight = (dc>1)?max(1,LX)*2:0;
if ((!InsWeight)&&(!DelWeight)) return p;
if (rand()%(InsWeight+DelWeight)<InsWeight) {
int d = rand()%InsPos.size();
vec[InsPos[d].first][InsPos[d].second] = 1;
}
else {
int d = rand()%DelPos.size();
vec[DelPos[d].first][DelPos[d].second] = 0;
}
int xl=LX+1, xr=0, yl=LX+1, yr=0;
for (int i=0; i<=LX+1; ++i) {
for (int j=0; j<=LX+1; ++j) {
if (!vec[i][j]) continue;
xl=min(xl,i); xr=max(xr,i);
yl=min(yl,j); yr=max(yr,j);
}
}
int NX = max(yr-yl+1,xr-xl+1);
int sx=xl-((NX-(xr-xl+1)+1)>>1), sy=yl-((NX-(yr-yl+1))>>1);
vector<vector<int> > nv(NX,vector<int>(NX));
for (int i=0; i<NX; ++i) {
for (int j=0; j<NX; ++j) {
int x=sx+i, y=sy+j;
if (((x>=0)&&(y>=0))&&((x<=LX+1)&&(y<=LX+1))) nv[NX-i-1][j]=vec[x][y];
}
}
pair<int,int> o = ReadMutateName(p.GetRealName());
int ad=1; if ((o.first==MutateID)&&(!p.GetRealName().empty())) ad=2;
bool tp = false;
if (p.GetLX()>=2) tp=true;
Piece *nw = new Piece(NX,nv,((o.second)||(tp))?p.GetColor():RollColor(),"?"+IToS(o.first)+"-"+IToS(o.second+ad));
CustomPiece.push_back(nw);
return *nw;
}
void DecD(double &a, int TimeDel, double r=1.0) {
if ((Bot)&&(BotSpeed<100)) {
a=0.0; return;
}
bool f = (a<0.0);
a = fabs(a);
double val = max(double(TimeDel)*0.001,a*double(TimeDel)*0.002)*12.0;
a = max(0.0,a-val*r);
if (f) a=-a;
}
int QPNextLevelDistance() {
if (QPLevel>=QPLevelScore.size()) return 100000000;
return int(min(100000000LL,max(0LL,QPLevelScore[QPLevel]*1000LL-TQPScore)));
}
char KeyRetry = 0;
bool RetryMsg = false;
ll QPExpReq() {
return max(40000LL,40000LL*(QPRank+1));
}
void GiveQPExp(int x) {
if ((Over)||(x<=0)||(!QPMode)) return;
/*double sz = 0.8*(1.0+0.1*sqrt(max(0.0,x*0.0002)));
AddFloatText("+"+Format("%.2f",double(x)*0.0001), 0xFDD000, sz, 0.08, 0.15, 0.1,
SX+2, LY*0.5-0.4, 0.3, 0, 0, 0);*/
QPAddExp += x;
/*ll exp=QPExp+x, req=QPExpReq(); int rnk=QPRank;
int ff = 0;
while (exp>=req) {
int ad = int(min(10000LL,exp/req));
exp -= req;
for (int i=0; i<ad; ++i) {
if (i) QPAddExp+=req;
++rnk; req+=40000LL;
}
if (++ff>1000) break;
}*/
}
int SelX=0, SelY=0; bool CursorMode=false;
bool QPHardmode() {
return ((Mod2==2)||(Mod3==2)||(Mod4==2)||(Mod5==2)||(Mod6==2)||(Mod7==2)||(Mod8==2)||(Mod9)
||(ModS==2)||(ModP==2)||(ModD==2)||(ModM==2)||(ModS==2));
}
bool QPRevmode() {
return ((Mod2==2)||(Mod3==2)||(Mod4==2)||(Mod5==2)||(Mod6==2)||(Mod7==2)||(Mod8==2)||(Mod9==2)
||(ModS==2)||(ModP==2)||(ModD==2)||(ModM==2)||(ModS==2));
}
int GetSize() {
return max(20,max(SX,(((QPMode)&&(Obs!=-1))||(PlayerCount<2))?LY:(LY<<1)));
}
bool GiveQPScoreMsg = false;
public :
void GetActions();
void Paint();
void GiveQPScore(ll x, bool Advanced=true, bool Multipler=true, int Color=0x99FFFF) {
if ((Over)||(!QPMode)||(x<=0)) return;
if (Multipler) {
int rem = x*(QPRank+1)%4;
x = x*(QPRank+1)/4;
if ((rand()&3)<rem) ++x;
}
if (!TargetSta) TQPScore+=x;
if (Advanced) {
GiveQPScoreMsg = true;
double sz = 0.8*(1.0+0.1*sqrt(max(0.0,x*0.001)));
AddFloatText("+"+IToS(x/1000LL)+"."+Format("%02lld",x%1000LL/10LL), Color, sz, 0.08, 0.15, 0.1,
SX+1, LY*0.5-0.4, 0.3, 0, 0, 0);
}
}
bool CheckCursor() {
if ((K<=0.001)||(tK<=0.001)) {
SelX=SelY=0; return false;
}
if (((CurX>=PX-K*2)&&(CurX<=PX+K*SX+K*2))&&((CurY>=PY-K*2)&&(CurY<=PY+K*LY+K*2))) {
SelX = SX-max(1,min(SX,int((CurX-PX)/K+1)))+1;
SelY = max(1,min(LY,int((CurY-PY)/K+1)));
return true;
}
SelX=SelY=0;
return false;
}
int Mod2=0, Mod3=0, Mod4=0, Mod5=0, Mod6=0, Mod7=0, Mod8=0, Mod9=0;
int ModS=0, ModP=0, ModM=0, ModD=0;
vector<int> SendAttack() {
if (AttackOut.empty()) return vector<int>();
int v=AttackOut.back(); AttackOut.pop_back();
return vector<int>({v});
}
//#warning ReceiveAttack
void ReceiveAttack(int x, int From=-1) {
if (x<=0) return;
if (LastAttacker<0) RerollHole();
if (From>=0) LastAttacker=From;
if (QPMode) {
InnerMess = min(10,Level)*((Mod9)?50:30);
if (Mod3) InnerMess+=250;
if (Mod3==2) InnerMess+=750;
if (Mod8==2) InnerMess+=300;
if ((Mod9<2)||(Time<60000LL*6)) InnerMess=max(0,InnerMess-QPWeightDec*15/10000);
if ((Mod9==2)&&(Time>=60000LL*11)) InnerMess=1000;
SegMess = InnerMess*5/2;
InnerMess = max(0,min(1000,InnerMess));
SegMess = max(0,min(1000,SegMess));
if (Mod5==1) InnerMess/=2;
if (Mod5==2) InnerMess/=3;
}
bool WindUp = false;
int Seg = min(4,(x+3)/4);
if ((x>=8)&&(QPMode)) {
WindUp=true; WindUpCD=1500+Seg*500;
}
if ((x<8)&&(QPMode)) WindUpCD=max(WindUpCD,2000*x/8);
if ((HolePos<1)||(HolePos>LY)) HolePos=rand()%LY+1;
x = min(5000,x);
for (int i=0; i<x; ++i) {
double ChangeProb = (((i)&&((!GarbageSeg)||(i%max(1,GarbageSeg))))?InnerMess:SegMess)*0.001;
if (randf()<ChangeProb) RerollHole();
GarbageLayer o=RollGarbage(); o.Delay=GarbageDelay;
if (WindUp) o.Delay+=1000+500*min(Seg-1,i/4);
//if (Mod5==2) o.Delay+=5000;
AttackIn.push_back(o);
}
QPWeightDec = min(180000,QPWeightDec+x*10000/((Mod5==2)?3:1));
}
void KeyBind(string Type, string val) {
Type=ToLower(Type); val=ToLower(val);
Action Tar; bool f=false;
for (pair<string,Action> o : KeyToAct) {
if (ToLower(o.first)==Type) {
f=true; Tar=o.second; break;
}
}
if (Type=="keypause") KeyPause=AskKey(val);
if (!f) return;
for (Monitor &o : Keys) {
if (o.Result==Tar) o.Key=AskKey(val);
}
}
void ChangeHandling(string Type, int val) {
Type = ToLower(Type);
for (Monitor &o : Keys) {
if ((o.Result==A_Left)||((o.Result==A_Right))) {
if (Type=="das") o.DAS=val;
if (Type=="arr") o.ARR=val;
if (Type=="dcd") o.DCD=val;
}
if ((o.Result==A_SoftDrop)||(o.Result==A_Up)) {
if (Type=="sddas") o.DAS=val;
if (Type=="sdarr") o.ARR=(o.Result==A_SoftDrop)?min(0,val):val;
if (Type=="dcd") o.DCD=val;
}
if (Type=="hcd") HCD=val;
}
if (Type=="das") DAS=val;
if (Type=="arr") ARR=val;
if (Type=="dcd") DCD=val;
if (Type=="sddas") SDDAS=val;
if (Type=="sdarr") SDARR=val;
if (Type=="smoothlevel") SmoothLevel=val;
}
void SetDefaultRot(int val) {
if ((val!=1)&&(val!=3)) return;
DefaultRot = val;
}
Monitor* FindMonitor(Action Result) {
for (Monitor &o : Keys) {
if (o.Result==Result) return &o;
}
return nullptr;
}
bool IsBot() {
return Bot;
}
double GetQPAttackWeightInc() {
return QPAttackWeightInc;
}
ll GetTime() {
return Time;
}
void ToggleBot() {
Bot = !Bot;
ClearSearchProcess(); PendingActions.clear();
if (CheckSpawn(Cur)) {
Spawn(Cur); ResetRem=ResetLim; FallTime=0;
}
HoldRem = HoldLen;
}
int GetLastAttacker() {
return LastAttacker;
}
int GetKOMessage() {
//if (!Over) return -2;
int tmp=KOMessage; KOMessage=-2;
return tmp;
}
void ForceRetry() {
RetryMsg = true;
}
int GetQPTargetWeight() {
if ((Over)||(Time<=0LL)||(WindUpCD>0)) return 0;
int res = 6;
if (Time>3*60000LL) res+=2;
if (Time>5*60000LL) res+=2;
if (Time>7*60000LL) res+=2;
if (!QPHardmode()) {
if (GetHeight()+AttackIn.size()+10>=SX) res-=3;
}
res = max(0,res-min(6,(QPWeightDec+2999)/3000));
if ((Mod3==2)||(Mod6==2)||(Mod8==2)) {
int gc = 0;
for (int i=1; i<=LX; ++i) {
bool f=false, df=false;
for (int j=1; j<=LY; ++j) {
if (C[i][j]) continue;
if (B[i][j]<0) {
f=true; if (IsUnclearable(B[i][j])) df=true;
}
}
if ((f)&&(!df)) ++gc;
if (gc>=5) break;
}
res = max(0,res-gc);
}
return res;
}
int ObserveLevel() {
return ((!Bot)&&(!Over));
}
int GetStackHeight() {
return StackHeight;
}
int GetBadge() {
return Badge;
}
int GetBoardID() {
return BoardID;
}
int KOCount=0, Badge=0, Rank=999;
Board(int _BoardID, vector<ConfigContent> Config={}, vector<Piece> _Pool={}, int Seed=-1, double _BotPos=0.0) {
BoardID = _BoardID;
LatestClock = int(GetClock());
BotPos = _BotPos;
if (Seed==-1) Seed=LatestClock;
BoardConfig = Config;
int _LX=GetConfig("LX",40), _LY=GetConfig("LY",10), _SX=GetConfig("SX",22);
Bot = bool(GetConfig("Bot",0));
LX=max(2,min(100,_LX)); LY=max(1,min(100,_LY));
HoldLen = max(0,min(5,GetConfig("HoldLen",1)));
NextLen = max(0,min(100,GetConfig("NextLen",5)));
HoldType = max(0,min(2,GetConfig("HoldType",1)));
DefaultRot = GetConfig("DefaultRot",3);
UID = 1;
if (DefaultRot!=1) DefaultRot=3;
DefaultDir = max(0,min(3,GetConfig("DefaultDir",0)));
BaseARE = max(0,min(Max,GetConfig("ARE",0)));
BaseLCD = max(0,min(Max,GetConfig("LCD",0)));
BaseCCD = max(0,min(Max,GetConfig("CCD",200)));
SpeedCap = max(0,min(Max,GetConfig("SpeedCap",0)));
DAS = max(-1,min(5000,GetConfig("DAS",200)));
ARR = max(-1,min(5000,GetConfig("ARR",0)));
SDDAS = max(-1,min(5000,GetConfig("SDDAS",200)));
SDARR = max(-1,min(5000,GetConfig("SDARR",20)));
HCD = max(0,min(5000,GetConfig("HCD",100)));
DCD = max(0,min(5000,GetConfig("DCD",0)));
SmoothLevel = max(0,min(4,GetConfig("SmoothLevel",3)));
BaseDropDelay = max(-1,min(Max,GetConfig("DropDelay",1000)));
if (BaseDropDelay<0) BaseDropDelay=Max;
BaseLockDelay = max(-1,min(Max,GetConfig("LockDelay",500)));
ResetLim = max(-1,min(Max,GetConfig("ResetLim",15)));