if (l) rec(0.1,0,0.8,0.1,clr);
		clr = Mix(0x000000,clr,0.05);
		if (d) rec(0.9,0.1,0.1,0.8,clr);
		if (r) rec(0.1,0.9,0.8,0.1,clr);
	}
	#undef sq
	#undef rec
	void PaintGrid(double x, double y, int clr, EBlockStyle Style, double th=0.0, double rx=0.0, double ry=0.0, bool u=false, bool d=false, bool l=false, bool r=false) {
		PaintTile(SX-x, y-1, clr, 1.0, Style, th, SX-rx+1, ry-1, u, d, l, r);
	}
	void PaintPiece(const Piece &p, double x, double y, double sz, int clr=-1, EBlockStyle Style=S_Active, int MinSize=4) {
		int LX=p.GetLX(); double ss=sz/double(LX);
		if (K*double(GetSize())>=8.0) Square(x,y,sz,BoardColor);
		if (LX<MinSize) {
			x+=0.5*sz*double(MinSize-LX)/double(MinSize); y+=0.5*sz*double(MinSize-LX)/double(MinSize);
			ss = sz/double(MinSize);
		}
		for (int i=0; i<LX; ++i) {
			for (int j=0; j<LX; ++j) {
				int val = p.GetGrid(LX-i-1,j);
				if (!val) continue;
				if (clr>=0) val=clr;
				PaintTile(x+i*ss, y+j*ss, abs(val), ss, Style);
			}
		}
	}
	void GetAccessMap(AccessMap *res, Status *Sta, Piece &p) {
		Piece NewP = p;
		for (int d=0; d<4; ++d) {
			NewP.SetDir(d);
			pair<int,int> Anch = NewP.GetAnchor();
			for (int i=1; i<=Sta->LX; ++i) {
				for (int j=1; j<=Sta->LY; ++j) res->B[d][i][j]=Sta->CheckPlace(NewP,i-Anch.first,j-Anch.second);
			}
		}
	}
	struct PosTuple {
		int d, x, y;
		bool operator <(PosTuple b) const {
			if (d!=b.d) return d<b.d;
			if (x!=b.x) return x<b.x;
			return y<b.y;
		}
		bool operator ==(PosTuple b) const {
			return ((d==b.d)&&(x==b.x)&&(y==b.y));
		}
	};
	vector<pair<PosTuple,bool> > GetLocations(AccessMap *Map, AccessMap *Tmp, Piece p, int Height, int Inc, bool TryFinalRotate=false, bool Clutch=false) {
		int LX=Map->LX, LY=Map->LY;
		pair<int,int> Anch[4]; Piece NewP=p;
		for (int i=0; i<4; ++i) {
			NewP.SetDir(i); Anch[i]=NewP.GetAnchor();
		}
		vector<pair<PosTuple,bool> > res;
		vector<PosTuple> SpinPos;
		pair<int,int> Place = SpawnPlace(p);
		int d=p.GetDir(), x=Place.first+Anch[d].first+Inc, y=Place.second+Anch[d].second;
		if (!Map->Query(d,x,y)) {
			if (!Clutch) return res;
			bool f = false;
			for (int i=1; i<=LX-SX+6; ++i) {
				++x; ++Place.first;
				if (Map->Query(d,x,y)) {
					f=true; break;
				}
			}
			if (!f) return res;
		}
		int HeightLim = Height+2;
		for (int d=0; d<4; ++d) {
			for (int i=1; i<=LX; ++i) {
				for (int j=1; j<=LY; ++j) {
					if (i<=HeightLim) Tmp->B[d][i][j]=Map->B[d][i][j];
					else Tmp->B[d][i][j]=false;
				}
			}
		}
		x = min(x,HeightLim);
		Tmp->B[d][x][y]=false; stack<PosTuple> stk; stk.push((PosTuple){d,x,y});
		vector<pair<int,int> > Kick[4][4];
		for (int i=0; i<4; ++i) {
			for (int j=0; j<4; ++j) {
				Kick[i][j] = GetKickTable(i,j,p.GetRealName(),RotateSystem);
				for (pair<int,int> &o : Kick[i][j]) {
					swap(o.first, o.second);
					o.first += Anch[j].first-Anch[i].first;
					o.second += Anch[j].second-Anch[i].second;
				}
			}
		}
		while (!stk.empty()) {
			PosTuple o=stk.top(); stk.pop();
			d=o.d; x=o.x; y=o.y;
			if ((SideGravity)&&(DropDelay)) {
				if (Map->Query(d,x,y-1)) {
					if (Tmp->Query(d,x,y-1)) {
						Tmp->B[d][x][y-1]=false; stk.push((PosTuple){d,x,y-1});
					}
					continue;
				}
			}
			if (Tmp->Query(d,x-1,y)) {
				Tmp->B[d][x-1][y]=false; stk.push((PosTuple){d,x-1,y});
			}
			else if (!Map->Query(d,x-1,y)) res.push_back(make_pair((PosTuple){d,x-Anch[d].first,y-Anch[d].second},false));
			if ((!DropDelay)&&(Map->Query(d,x-1,y))) continue;
			if ((UseMove)&&(Tmp->Query(d,x,y-1))) {
				Tmp->B[d][x][y-1]=false; stk.push((PosTuple){d,x,y-1});
			}
			if ((UseMove)&&(Tmp->Query(d,x,y+1))) {
				Tmp->B[d][x][y+1]=false; stk.push((PosTuple){d,x,y+1});
			}
			for (int nd=0; nd<4; ++nd) {
				if (nd==d) continue;
				int dd = ((nd-d+4)&3);
				bool f = true;
				if (dd==2) f=UseHalf;
				else f=((Use2Rot)||((UseRotate)&&(dd==DefaultRot)));
				if (!f) continue;
				int nx=-1, ny=-1;
				for (pair<int,int> o : Kick[d][nd]) {
					if (Map->Query(nd,x+o.first,y+o.second)) {
						nx=x+o.first; ny=y+o.second; break;
					}
				}
				if (nx>=0) {
					if (Tmp->Query(nd,nx,ny)) {
						if ((TryFinalRotate)&&(dd!=2)) SpinPos.push_back((PosTuple){nd,nx-Anch[nd].first,ny-Anch[nd].second});
						Tmp->B[nd][nx][ny]=false; stk.push((PosTuple){nd,nx,ny});
					}
				}
			}
		}
		if (!TryFinalRotate) return res;
		sort(res.begin(), res.end());
		sort(SpinPos.begin(), SpinPos.end());
		int pp = 0;
		for (pair<PosTuple,bool> &o : res) {
			while ((pp<SpinPos.size())&&(SpinPos[pp]<o.first)) ++pp;
			if ((pp<SpinPos.size())&&(SpinPos[pp]==o.first)) o.second=true;
		}
		return res;
	}
	int VecDfs(vector<vector<char> > &vec, int x, int y) {
		if (vec[x][y]) return 0;
		vec[x][y] = 1;
		return 1+VecDfs(vec,x+1,y)+VecDfs(vec,x-1,y)+VecDfs(vec,x,y+1)+VecDfs(vec,x,y-1);
	}
	//#warning Board::Eval
	int PreHeight;
	int DHeight(bool **D, int j, int wh) {
		if ((j<1)||(j>LY)) return LX;
		for (int i=wh+1; i<=LX; ++i) {
			if (!D[i][j]) return i;
		}
		return LX+1;
	}
	ll Eval(Status *Sta, Piece &_p, PosTuple o, bool Spin, int d, int x, int y, bool Spinable) {
		int LX=Sta->LX, LY=Sta->LY;
		bool **D = Sta->B;
		int Lines=0, pp=0;
		int Height=0, PieceHeight=0, LeftMost=LY, RightMost=0, Edge=LY;
		Piece p=_p; p.SetDir(o.d);
		int PLX = p.GetLX();
		vector<int> Fill(LX+2,0), Upper(LY+2,0);
		bool Use90=Spinable; Spinable|=Spin;
		bool TSp=false, TFull=false;
		int CenterY = 0;
		if (((BotType==1)||(BotType==3)||(BotType==8))&&((Spin)||(Spinable))&&(IsSpinBonus(_p.GetName()))) {
			int px=x+1, py=y+1;
			int t1=0, t2=0;
			int fi=0, fj=0;
			if (!d) fi=1;
			else if (d==1) fj=1;
			else if (d==2) fi=-1;
			else fj=-1;
			fi=-fi; fj=-fj;
			CenterY = py;
			for (int ii=-1; ii<=1; ii+=2) {
				for (int jj=-1; jj<=1; jj+=2) {
					int nx=px+ii, ny=py+jj;
					if (Sta->CheckGrid(nx,ny)) {
						++t1;
						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)&&(!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-=100000; _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) ;
						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))) Spin|=TSp;
		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:1000);
			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,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))) {
			if (SetSpin) {
				if ((Spin)&&(!Lines)) ares+=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=2;
			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&&0) {
				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:999,int(AttackIn.size()));
		if ((TotHeight<=6)&&(Bub<2)&&((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);
		}
	}
	void Paint() {
		if (K<0.001) return;
		bool Simple = ((Bot)&&(K*double(GetSize())<8.0));
		if ((QPMode)&&(!Simple)) PaintZenith();
		if (!Simple) {
			Rect(2, 0, SX-2, LY, ((QPBlighted)||(CurZone))?Mix(0xFFE211,GridColor,0.3):GridColor);
			Rect(0, 0, 2, LY, ((QPBlighted)||(CurZone))?Mix(0xFFE211,OverGridColor,0.3):OverGridColor);
			for (int i=0; i<SX; ++i) {
				for (int j=0; j<LY; ++j) {
					int clr = BoardColor;
					if (SX-i<=RoundHeight) clr=RoundColor;
					if ((VanishHeight)&&(SX-i>=VanishHeight)) clr=VanishColor;
					Square(i+0.025, j+0.025, 0.95, clr); 
				}
			}
		}
		else Rect(0,0,SX,LY,BoardColor);
		int FallDist = LX;
		for (int j=1; j<=LY; ++j) {
			int pre = 0;
			for (int i=1; i<=LX; ++i) {
				if (C[i][j]) FallDist=min(FallDist,i-pre-1);
				else if (B[i][j]) pre=i;
			}
		}
		bool Inactive=false, CDown=CheckDown();
		double FallRate=0.0, LockRate=0.0, ClearRate=0.0;
		if (CDown) {
			if ((DropDelay)&&(SmoothLevel>=1)) FallRate=max(0.0,min(1.0,double(FallTime)/double(DropDelay)));
			else FallRate=0.0;
		}
		else {
			if (LockDelay>0) LockRate=max(0.0,min(1.0,double(FallTime)/double(LockDelay)));
			else if (!LockDelay) LockRate=0.0;
		}
		if ((InactiveTime>0)&&(InactiveTot>0)) {
			Inactive = true;
			ClearRate = 1.0-max(0.0,min(1.0,double(InactiveTime)/double(InactiveTot)));
		}
		double grat = max(0.0,min(1.0,double(PushCD)/double(max(1,GarbagePush))));
		if (!SmoothLevel) grat=0.0;
		if ((ShadowType==2)&&(!Simple)) {
			for (int j=1; j<=LY; ++j) {
				bool f = false;
				for (int i=1; i<=LX; ++i) {
					if (C[i][j]) f=true;
				}
				if (!f) continue;
				for (int i=1; i<=SX; ++i)
					Square(SX-i+grat+0.025,j-1+0.025,0.95,ShadowColor);
			}
		}
		if ((UseTip)&&((TgD>=0)&&(TgD<4))) {
			int PLX = Tg.GetLX();
			for (int i=0; i<PLX; ++i) {
				for (int j=0; j<PLX; ++j) {
					int b = Tg.GetGrid(i,j,TgD);
					if (!b) continue;
					int x=i+TgX, y=j+TgY;
					Square(SX-x+0.025, y-1+0.025, 0.95, Mix(abs(b),BackgroundColor,0.3));
				}
			}
		}
		if ((ShadowType==1)&&(!Simple)) {
			for (int i=1; i<=SX; ++i) {
				for (int j=1; j<=LY; ++j) {
					if ((!CheckOut(i+FallDist,j))&&(C[i+FallDist][j])) Square(SX-i+grat+0.025,j-1+0.025,0.95,ShadowColor);
				}
			}
		}
		if (SelX) {
			int clr = 0x39C5BB;
			if (!CursorMode) clr=0x66CCFF;
			Square(SX-SelX+0.025, SelY-1+0.025, 0.95, Mix(clr,BackgroundColor,0.3));
		}
		int RiseHeight=GetRiseHeight(), GarbID=-1;
		for (int i=1; i<=LX; ++i) {
			for (int j=1; j<=LY; ++j) {
				if ((B[i][j]<0)&&(!C[i][j])) {
					++GarbID; break;
				}
			}
		}
		if ((NextLen)&&(!Simple)) PrintStrM("NEXT",0,LY+2.5,1,0xEEEEEE,0.12);
		if ((SmoothLevel<=3)||(NextLen<2)||((Bot)&&(BotSpeed<100))) DNext=0; 
		for (int i=0; i<NextLen; ++i) {
			Piece p = (Next.size()>i)?Next[i]:P_Empty;
			if (i<5) PaintPiece(p,(double(i)+DNext)*3.5+1,LY+1,3);
			else {
				int d = i-5;
				PaintPiece(p, 1.5+1.2*(d%15), LY+1.2*(d/15)+5, 1, p.GetColor(), S_Simple);
			}
		}
		if ((HoldType)&&(HoldLen)) {
			if (!Simple) PrintStrM("HOLD",0,-2.5,1,((HoldRem)||(HoldType==2))?0xEEEEEE:0x888888, 0.12);
			for (int i=0; i<HoldLen; ++i) {
				int clr = -1;
				if ((HoldType==1)&&(i+HoldLen-Hold.size()>=HoldRem)) clr=0x888888;
				PaintPiece((Hold.size()>i)?Hold[i]:P_Empty, i*3.5+1, -4, 3, clr);
			}
		}
		int ZoneID = 0;
		for (int i=1; i<=LX; ++i) {
			bool gb = false;
			for (int j=1; j<=LY; ++j) {
				int clr = abs(B[i][j]);
				if (B[i][j]<0) gb=true;
				if (!clr) continue;
				if (C[i][j]) continue;
				clr = Mix(0x000000,clr,0.1);
				clr = Mix(0xFFFFFF,clr,0.3*max(0.0,min(1.0,double((Age[i][j]<0)?500:Age[i][j])/500.0)));
				if (Mod7) {
					double vrat = Age[i][j]/500.0;
					if (Mod7==1) {
						int d = int(Time%5000LL);
						if (d<=500) vrat=max(vrat,double(500-d)/500.0);
					}
					if (B[i][j]<0) {
						if (Mod7==1) vrat=1.0;
						else vrat=max(vrat,double(3-GarbID)/3.0);
					}
					if ((B[i][j]>=GarbQuest)&&(B[i][j]<=GarbQuest+20)) vrat=1.0;
					if (Bot) vrat=max(vrat,0.2);
					if (vrat<0.001) continue;
					clr = Mix(clr,BackgroundColor,vrat);
				}
				double di = 0.0;
				if (Inactive) {
					if (Age[i][j]<0) di+=Age[i][j]*ClearRate;
					else if (FallDest[i]) di-=(i-FallDest[i])*ClearRate;
					else {
						double rat = max(0.0,min(1.0,ClearRate*LY-j+1));
						if (rat>0.999) continue;
						rat = 1.0-(1.0-rat)*(1.0-rat);
						clr = Mix(0xFFFFFF,clr,0.3);
						clr = Mix(BoardColor,clr,rat);
					}
				}
				PaintGrid(i+di-((i<=RiseHeight)?0.0:grat), j, abs(clr), (B[i][j]<0)?S_Garbage:S_Default,
				0, 0, 0,
				U[i+1][j]==U[i][j], U[i-1][j]==U[i][j], U[i][j-1]==U[i][j], U[i][j+1]==U[i][j]);
				if ((B[i][j]>=GarbQuest)&&(B[i][j]<=GarbQuest+20)) {
					PrintStrM(IToS(B[i][j]-GarbQuest), SX-i+0.3, j-0.7, 0.7, 0xCC99FF);
				}
				if ((j==1)&&(B[i][j]==GarbZone)) ++ZoneID;
			}
			if (gb) --GarbID;
		}
		if (ZoneID) {
			PrintStrM(IToS(ZoneID)+" Lines", SX-(ZoneID*0.5+0.5)+0.3-0.5, (LY*0.5+0.5)-0.7, 1, 0xFFFFFF);
			PrintStrM(IToS(ZoneAttack+GetZoneBonus(ZoneID))+" Attack", SX-(ZoneID*0.5+0.5)+0.3+0.5, (LY*0.5+0.5)-0.7, 1, 0xFFFFFF);
		}
		double Cx=PosX+0.5*Cur.GetLX()-FallRate+PDx-grat, Cy=PosY+0.5*Cur.GetLX()+PDy;
		for (int i=1; i<=LX; ++i) {
			for (int j=1; j<=LY; ++j) {
				int clr = abs(B[i][j]);
				if (!clr) continue;
				if (!C[i][j]) continue;
				clr = Mix(0x000000,clr,0.1*LockRate);
				PaintGrid(i-FallRate+PDx-grat, j+PDy, abs(clr), S_Active, PDth, Cx, Cy,
				C[i+1][j], C[i-1][j], C[i][j-1], C[i][j+1]);
			}
		}
		pair<int,int> NextPos = SpawnPlace(Next[0]);
		int PLX = Next[0].GetLX();
		double hrat = 1.0-max(0.0,min(1.0,(SX-GetHeight()-2)*0.15));
		if (!Simple) {
			for (int i=0; i<PLX; ++i) {
				for (int j=0; j<PLX; ++j) {
					if (!Next[0].GetGrid(i,j)) continue;
					int x=i+NextPos.first, y=j+NextPos.second;
					PrintStrM("*", SX-x+0.2, y-1+0.3, 1, Mix(0xFF0000,0xCCCCCC,hrat*0.3+0.7), 0.2*hrat);
				}
			}
		}
		for (int i=0; i<min(GarbagePreview,int(AttackIn.size())); ++i) {
			for (int j=1; j<=LY; ++j) {
				if (AttackIn[i].B[j]) PaintGrid(-i-0.5,j,Mix(abs(AttackIn[i].B[j]),BackgroundColor,max(0.2,0.8-0.1*i)),S_Garbage);
			}
		}
		for (int i=1; i<=min(100,max(SX,int(AttackIn.size()))); ++i) {
			int clr=0x333333; double w=0.15;
			if ((GarbageGap>=0)&&(i<=GarbageGap)) clr=0x888888;
			if (AttackIn.size()>=i) {
				int del = AttackIn[i-1].Delay;
				clr = Mix(0xFFE211,0xFF6666,max(0.0,min(1.0,double(del)*0.001)));
				if (!AttackIn[i-1].Delay) clr=0xEE0000;
				if (AttackIn[i-1].Delay<0) clr=0xDF3782;
				if (AttackIn[i-1].Delay>GarbageDelay-GarbagePass) clr=Mix(0xFFFFFF,clr,0.3);
				if ((GarbageGap>=0)&&(i>GarbageGap)) clr=Mix(0x000000,clr,0.3);
				w = 0.2;
			}
			else if (Simple) continue;
			Rect(SX-i+0.1, -0.2-0.5*w, 0.8, w, clr);
		}
		if ((AttackIn.size())&&(!Simple)) PrintStrR('-'+IToS(AttackIn.size()),SX,-0.5,0.8,0xFF6666,0.15);
		double rat = 1.0;
		if (!CDown) rat=1.0-LockRate;
		if ((!Simple)&&(QPMode)) {
			int sz = LevelColor.size();
			int CurClr = LevelColor[max(0,min(sz-1,QPRank))];
			int NextClr = LevelColor[max(0,min(sz-1,QPRank+1))];
			if (NextClr==CurClr) CurClr=Mix(0x000000,CurClr,0.1);
			double rat = max(0.0,min(1.0,double(QPExp)/double(QPExpReq())));
			Rect(SX+0.5, 0, 0.25, LY, CurClr);
			Rect(SX+0.5, LY*(1.0-rat)*0.5, 0.25, LY*rat, NextClr);
			rat = max(0.0,min(1.0,double(QPExpDecCD)*0.0002));
			Rect(SX+0.7, LY*(1.0-rat)*0.5, 0.05, LY*rat, 0xDDDDDD);
		}
		if (Simple) ;
		else if (Bot) {
			Rect(SX, 0, 0.5, LY, 0xCCCCCC);
			if ((!HideStat)||(SelX)) {
				PrintStrL(IToS(BotSpeed), SX+0.7, 0, 0.7, 0xDDDDDD);
				PrintStrR(GetBotName(ActType), SX+0.7, LY-0.5, 0.7, 0xDDDDDD);
			}
			else PrintStrM("Autoplay Demonstration",SX+0.7,LY*0.5,0.6,0x66CCFF);
			if (Menu=="home") PrintStrM("Click to Manually Control",SX+1.5,LY*0.5,0.5,0xBBBBBB);
		}
		else {
			if (Inactive) rat=1.0;
			Rect(SX, 0, 0.25, LY, 0xBBBBBB);
			Rect(SX, 0, 0.25, LY*rat, Mix(0x888888,0xFFE211,(Inactive)?0.5:0));
			PrintStrL((LockDelay<0)?"":IToS(((CDown)||(Inactive))?LockDelay:max(0,LockDelay-FallTime)), SX+0.7, 0, 0.7, 0xFFE211);
			PrintStrR((ResetRem==Max)?"":IToS(ResetRem), SX+0.7, LY, 0.7, 0x39C5BB);
			if (CursorMode) {
				if (UsePlace) PrintStrR("Edit Mode",SX+1.4,LY,0.5,0xAAAAAA);
			}
			else if ((UseClick)&&(!CursorMoveLock)) PrintStrR("Cursor Control",SX+1.4,LY,0.5,0xAAAAAA);
			if (UseUndo) {
				int v = max(0,int(History.size())-HistoryPos-1);
				PrintStrR(Str(12)+IToS(v),SX+0.25,-0.8,0.7,(v)?0x9999FF:0x888888);
				v = max(0,HistoryPos);
				PrintStrL(IToS(v)+Str(13),SX+0.25,LY+0.5,0.7,(v)?0x9999FF:0x888888);
			}
			rat = 0.0;
			if (ResetLim) rat=max(0.0,min(1.0,double(ResetRem)/double(ResetLim)));
			if (Inactive) rat=(ResetLim)?1.0:0.0;
			Rect(SX+0.25, 0, 0.25, LY, 0x888888);
			Rect(SX+0.25, 0, 0.25, LY*rat, Mix(0x888888,0x39C5BB,(Inactive)?0.5:0));
			if (Menu=="home") PrintStrM("Click to Autoplay",SX+1.5,LY*0.5,0.5,0xBBBBBB);
		}
		if ((!Simple)&&(UseZone)) {
			if (CurZone) PrintStrL("["+IToS(CurZone)+"] "+((ZoneRem>0)?IToS(ZoneRem):""),SX+1.5,0,0.7,0xFFE211);
			else if ((!ZoneReq)||(ZoneProgress>=ZoneSeg*ZoneReq)) PrintStrL("["+IToS(ZoneSeg)+"] MAX",SX+1.5,0,0.7,0xFFA500);
			else PrintStrL("["+IToS(ZoneProgress/ZoneReq)+"] +"+IToS(ZoneProgress%ZoneReq)+"/"+IToS(ZoneReq),SX+1.5,0,0.7,(ZoneProgress>=ZoneReq)?0xFFA500:0xAAAAAA);
		}
		if (Simple) ;
		else if ((PlayerCount>2)&&(!QPMode)) {
			PrintStrM(vector<string>({"None","All","Even","Elimination","Random",
			"Payback","Badges","Attackers","Backfire"})[TargetType], SX+2, LY*0.5, 0.8, 0xCCCCCC);
		}
		else if ((UsePlace)&&(!Bot)&&(CursorMode)) {
			PrintStrM("<"+vector<string>({"X","Z","L","O","S","I","J","T","G"})[PaintType]+">", SX+2, LY*0.5, 0.8, GetPaintColor());
		}
		if (Simple) ;
		else if (Inactive) {
			rat = max(0.0,min(1.0,double(InactiveTime)/double(max(1,InactiveTot))));
			Rect(SX, LY*0.5*(1.0-rat)*double(Bot), 0.5, LY*rat, 0x888888);
			//PrintStrL(IToS(InactiveTime), SX+1.4, 0, 0.7, 0x666666);
		}
		if (!Simple) {
			ModPos = 0;
			PrintQPMod(Mod2, 0xEE82EE, Str(22), "NH");
			PrintQPMod(Mod3, 0xFFA500, Str(23), "MS");
			PrintQPMod(Mod4, 0xFDD000, Str(24), "GV");
			PrintQPMod(Mod5, 0xEE0000, Str(25), "VL");
			PrintQPMod(Mod6, 0x66CCFF, Str(26), "DH");
			PrintQPMod(Mod7, 0x9999FF, Str(27), "IN");
			PrintQPMod(Mod8, 0x00FFCC, Str(28), "AS");
			PrintQPMod(Mod9, 0xFFE211, Str(29), "EX");
			PrintQPMod(ModS, 0x0080FF, Str(30), "SN");
			PrintQPMod(ModP, 0xCCCCCC, "?", "PT");
			PrintQPMod(ModM, 0xAAAAAA, "?", "MT");
		}
		if (AllClearAge>=5000) AllClearAge=5000;
		else if (!Simple) {
			double rat = 1.0-max(0.0,min(1.0,AllClearAge/5000.0));
			PrintStrM("ALL", 0.5*SX-1, 0.5*LY-0.4, 2, 0xFFE211, 0.15*rat);
			PrintStrM("CLEAR", 0.5*SX+1, 0.5*LY-0.4, 2, 0xFFE211, 0.15*rat);
		}
		if ((Mod8)&&(SpinText==LastClearType.first)&&(SpinText.size())) SpinAge=min(SpinAge,3000);
		if (SpinAge>=5000) SpinAge=5000;
		else if (!Simple) {
			double rat = 1.0-max(0.0,min(1.0,SpinAge/5000.0));
			double rr = 1.0-(1.0-rat)*(1.0-rat);
			if (SpinGrade==3) PrintAction(SpinText+"-Spin", 4.5, -2, 0.8, Mix(SpinColor,BackgroundColor,rr), 0.15*rr, 1.5-0.5*rat*rat*rat*rat*rat);
			else if (SpinGrade==2) PrintAction("Mini "+SpinText+"-Spin", 4.5, -2, 0.7, Mix(SpinColor,BackgroundColor,rr), 0.15*rr, 1.5-0.5*rat*rat*rat*rat*rat);
			else if (SpinGrade==1) {
				PrintAction("Mini", 4.3, -2, 0.55, Mix(SpinColor,BackgroundColor,rr), 0.15*rr,  1.5-0.5*rat*rat*rat*rat*rat);
				PrintAction(SpinText+"-Spin", 4.7, -2, 0.55, Mix(SpinColor,BackgroundColor,rr), 0.15*rr,  1.5-0.5*rat*rat*rat*rat*rat);
			}
			else PrintAction(SpinText, 4.5, -2, 0.8, Mix(SpinColor,BackgroundColor,rr), 0.15*rr, 1.5-0.5*rat*rat*rat*rat*rat);
		}
		if ((Mod8)&&(LineClearText==LastClearType.second)) LineClearAge=min(LineClearAge,3000);
		if (LineClearAge>=5000) LineClearAge=5000;
		else if (!Simple) {
			double rat = 1.0-max(0.0,min(1.0,LineClearAge/5000.0));
			double rr = 1.0-(1.0-rat)*(1.0-rat);
			string Text = (LineClearText>=0)?LineClearWord[min(LineClearText,int(LineClearWord.size()-1))]:"";
			double dd = 6.0/min(6,max(1,int(Text.size())));
			PrintAction(Text, 5.5, -2, 1.3, Mix(LineClearColor,BackgroundColor,rr), 0.15*rr, dd*(1.7-0.7*rat*rat*rat*rat*rat));
		}
		if (B2BAge>=5000) B2BAge=5000;
		else if (!Simple) {
			double rat = 1.0-max(0.0,min(1.0,B2BAge/5000.0));
			double rr = 1.0-(1.0-rat)*(1.0-rat);
			int clr = B2BColor(B2BText);
			if (!((B2BBlinkRem/150)&1)) {
				string str = "B2B *"+IToS(B2BText);
				if (B2BRule==BR_Guildline) str="Back-to-Back";
				if (B2BRule==BR_Techmino) str="B2B "+IToS(B2B/10)+"."+IToS(B2B%10)+"%";
				PrintAction(str, 7, -2, 0.8, Mix(clr,BackgroundColor,rr), 0.15*rr, 1.5-0.5*rat*rat*rat*rat*rat);
			}
		}
		if (ComboAge>=5000) ComboAge=5000;
		else if (!Simple) {
			double rat = 1.0-max(0.0,min(1.0,ComboAge/5000.0));
			double rr = 1.0-(1.0-rat)*(1.0-rat);
			int clr = (ComboText)?Mix(0xFFFFFF,0x39C5BB,(double(min(21,ComboText)-1)/20.0)):0x888888;
			PrintAction(IToS(ComboText)+" Combo", 8, -2, 0.8, Mix(clr,BackgroundColor,rr), 0.15*rr, 1.5-0.5*rat*rat*rat*rat*rat);
		}
		double StatEnd = max(SX,((SX<4)?20:22));
		if ((!HideStat)&&(!Simple)) {
			if (QPMode) {
				PrintStrR("Boost", StatEnd-12.8, -2, 0.7, 0xEEEEEE);
				PrintStrR(IToS(QPRank), StatEnd-12, -2.1, 1, 0x99FFFF, 0.13);
				if (PlayerCount>1) PrintStrR(IToS(KOCount)+" KO\'s", StatEnd-11, -2, 0.7, 0x99FFFF);
			}
			else if (PlayerCount>1) {
				PrintStrR("Badge", StatEnd-12.8, -2, 0.7, 0xEEEEEE);
				PrintStrR(IToS(Badge), StatEnd-12, -2.1, 1, 0x99FFFF, 0.13);
				PrintStrR(IToS(KOCount)+" KO\'s", StatEnd-11, -2, 0.7, 0x99FFFF);
			}
			else if (UseLeveling()) {
				PrintStrR("Level", StatEnd-11.8, -2, 0.7, 0xEEEEEE);
				PrintStrR(IToS((Level<0)?max(LevBase,LevStart):Level), StatEnd-11, -2.1, 1, 0x99FFFF, 0.13);
			}
			ll t = abs(Time);
			PrintStrR("Time", StatEnd-9.8, -2, 0.7, 0xEEEEEE);
			int clr = 0x99FFFF;
			if (Time<0LL) PrintStrR(Format("-%02d:%02d.",int(t/60000LL),int(t/1000LL%60LL)), StatEnd-9, -2.1, 1, 0x99FFFF, 0.13);
			else {
				if (TarTime) {
					if (t<TarTime) {
						clr=(TypeTime)?0xEE82EE:0xFDD000; t=TarTime-t;
					}
					else {
						clr=(TypeTime)?0xFF6666:0x00FFCC; if (TypeTime) t=TarTime;
					}
				}
				PrintStrR(Format("%02d:%02d.",int(t/60000LL),int(t/1000LL%60LL)), StatEnd-9, -2.1, 1, clr, 0.13);
			}
			PrintStrR(Format("%03lld",t%1000LL), StatEnd-8.8, -1, 0.65, clr, 0.14);
			t = max(Time,1LL);
			PrintStrR("Piece", StatEnd-7.8, -2, 0.7, 0xEEEEEE);
			int val=TPiece; clr=0x99FFFF;
			if (TarPiece) {
				if (TPiece<TarPiece) {
					clr=(TypePiece)?0xEE82EE:0xFDD000; val=TarPiece-TPiece;
				}
				else {
					clr=(TypePiece)?0xFF6666:0x00FFCC; if (TypePiece) val=TarPiece;
				}
			}
			PrintStrR(IToS(val), StatEnd-7, -2, 1, clr, 0.13);
			PrintStrR(Format("%.2f /s",double(TPiece)/double(t)*1000.0), StatEnd-6, -2, 0.7, 0x99FFFF);
			PrintStrR("Line", StatEnd-5.3, -2, 0.7, 0xEEEEEE);
			val=TLine; clr=0x99FFFF;
			if (TarLine) {
				if (TLine<TarLine) {
					clr=(TypeLine)?0xEE82EE:0xFDD000; val=TarLine-TLine;
				}
				else {
					clr=(TypeLine)?0xFF6666:0x00FFCC; if (TypeLine) val=TarLine;
				}
			}
			PrintStrR(IToS(val), StatEnd-4.5, -2, 1, clr, 0.13);
			if ((TDig)||(TarDig)) {
				int tmp = IToS(val).size();
				val=TDig; clr=0x99FFFF;
				if (TarDig) {
					if (TDig<TarDig) {
						clr=(TypeDig)?0xEE82EE:0xFDD000; val=TarDig-TDig;
					}
					else {
						clr=(TypeDig)?0xFF6666:0x00FFCC; if (TypeDig) val=TarDig;
					}
				}
				PrintStrR(IToS(val), StatEnd-4.3, -2-tmp*2.0/3.0, 0.7, clr, 0.13);
			}
			PrintStrR(Format("%.2f /m",double(TLine)/double(t)*60000.0), StatEnd-3.5, -2, 0.7, 0x99FFFF);
			PrintStrR("Attack", StatEnd-2.8, -2, 0.7, 0xEEEEEE);
			val=TAttack; clr=0x99FFFF;
			if (TarAttack) {
				if (TAttack<TarAttack) {
					clr=(TypeAttack)?0xEE82EE:0xFDD000; val=TarAttack-TAttack;
				}
				else {
					clr=(TypeAttack)?0xFF6666:0x00FFCC; if (TypeAttack) val=TarAttack;
				}
			}
			PrintStrR(IToS(val), StatEnd-2, -2, 1, clr, 0.13);
			if (IntRule==IR_Accumulate) {
				int val = max(0,min(99,int(round(AttackAcc*100.0))));
				PrintStrL(IToS(val/10)+IToS(val%10), StatEnd-1.7, -1.3, 0.7, 0x99FFFF, 0.13);
			}
			PrintStrR(Format("%.2f /m",double(TAttack)/double(t)*60000.0), StatEnd-1, -2, 0.7, 0x99FFFF);
			if (Stock>0) {
				PrintStrR("Stock", StatEnd-0.3, -2, 0.7, 0xEEEEEE);
				PrintStrR(IToS((Over)?0:StockRem+1), StatEnd+0.5, -2, 1, clr, 0.13);