// -std=c++14 -lgdi32 -lOpengl32

#include <bits/stdc++.h>
#include <windows.h>
#include <conio.h>
#include <gl/gl.h>

using namespace std;
typedef long long ll;

mt19937 rng(time(0));

int rnd(int p) {
	return int(rng()%p);
}
double rndf() {
	return double(rnd(10001)*0.0001);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
	switch (message) {
	case WM_CREATE:
		return 0;
	case WM_CLOSE:
		PostQuitMessage (0);
		return 0;
	case WM_DESTROY:
		return 0;
	case WM_KEYDOWN:
		switch (wParam) {
		case VK_ESCAPE:
			PostQuitMessage(0);
			return 0;
		}
		return 0;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
}
void EnableOpenGL(HWND hWnd, HDC *hDC, HGLRC *hRC) {
	PIXELFORMATDESCRIPTOR pfd; int iFormat;
	*hDC = GetDC(hWnd);
	ZeroMemory(&pfd, sizeof(pfd));
	pfd.nSize = sizeof(pfd);
	pfd.nVersion = 1;
	pfd.dwFlags = PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER;
	pfd.iPixelType = PFD_TYPE_RGBA;
	pfd.cColorBits = 24;
	pfd.cDepthBits = 16;
	pfd.iLayerType = PFD_MAIN_PLANE;
	iFormat = ChoosePixelFormat(*hDC, &pfd);
	SetPixelFormat(*hDC, iFormat, &pfd);
	*hRC = wglCreateContext(*hDC);
	wglMakeCurrent(*hDC, *hRC);
}
void DisableOpenGL(HWND hWnd, HDC hDC, HGLRC hRC) {
	wglMakeCurrent(NULL, NULL);
	wglDeleteContext(hRC);
	ReleaseDC(hWnd, hDC);
}
int Mix(int ca, int cb, double rt) {
	int Ar = (ca>>16);
	int Ag = ((ca>>8)&((1<<8)-1));
	int Ab = (ca&((1<<8)-1));
	int Br = (cb>>16);
	int Bg = ((cb>>8)&((1<<8)-1));
	int Bb = (cb&((1<<8)-1));
	int R = int(floor(rt*double(Ar)+(1.0-rt)*double(Br)));
	int G = int(floor(rt*double(Ag)+(1.0-rt)*double(Bg)));
	int B = int(floor(rt*double(Ab)+(1.0-rt)*double(Bb)));
	return (max(0,min(255,R))<<16)+(max(0,min(255,G))<<8)+max(0,min(255,B));
}
int PS = 800;
struct ClassPiece {
	int B[10][10], LX, LY, clr, SDel, FstX, FstY;
	ClassPiece() {
		LX=LY=clr=SDel=0; FstX=FstY=-1;
		for (int i=0; i<=9; ++i) {
			for (int j=0; j<=9; ++j) B[i][j]=0;
		}
	}
	ClassPiece(int _LX, int _LY, int _clr, int _SDel, vector<vector<int> > _B) {
		LX=_LX; LY=_LY; clr=_clr; SDel=_SDel; FstX=FstY=-1;
		for (int i=0; i<=9; ++i) {
			for (int j=0; j<=9; ++j) B[i][j]=0;
		}
		for (int i=0; i<_LX; ++i) {
			for (int j=0; j<_LY; ++j) {
				B[i][j] = _B[_LX-i-1][j];
				if ((B[i][j])&&(FstX<0)) {
					FstX=i; FstY=j;
				}
			}
		}
	}
} Piece[55][4];
int PieceCnt = 7;
vector<pair<int,int> > Kick[55][4][4];
bool CheckKey(char ch) {
	return bool(GetAsyncKeyState(ch)&0x8000);
}
struct Particle {
	double x, y, vx, vy, ax, ay, sz, de, th; int n, clr;
};
struct FloatText {
	double x, y, sz, bd, de; string str; int clr;
};
struct ClassSta {
	int p, d, x, y;
	bool operator <(ClassSta b) const {
		if (p!=b.p) return p<b.p;
		if (d!=b.d) return d<b.d;
		if (x!=b.x) return x<b.x;
		return y<b.y;
	}
};
#warning char
vector<string> Char[999]; string LCW[999], SLCW[999], ATKN[999];
char PName[55] = {' ','I','J','L','O','S','T','Z'};
void InitChar() {
	LCW[1] = "SINGLE";
	LCW[2] = "DOUBLE";
	LCW[3] = "TRIPLE";
	LCW[4] = "QUAD";
	SLCW[1] = "Single";
	SLCW[2] = "Double";
	SLCW[3] = "Triple";
	SLCW[4] = "Quad";
	ATKN[1] = "Even";
	ATKN[2] = "KO\'s";
	ATKN[3] = "Random";
	ATKN[4] = "Payback";
	ATKN[5] = "Badges";
	ATKN[6] = "Attackers";
	Char['0'] = {"fbdj375zf","zj"};
	Char['1'] = {"kc6","48"};
	Char['2'] = {"fbdjo483"};
	Char['3'] = {"fbdjosy374","qs"};
	Char['4'] = {"7dckuy"};
	Char['5'] = {"eapmt374"};
	Char['6'] = {"jdbfz573ysp"};
	Char['7'] = {"aejr6"};
	Char['8'] = {"qsodbfquz573ys"};
	Char['9'] = {"tqkfbdj375z"};
	Char['A'] = {"4c8","vx"};
	Char['B'] = {"sojdapsy374p"};
	Char['C'] = {"jdbfz573"};
	Char['D'] = {"adj374a"};
	Char['E'] = {"ea48","pt"};
	Char['F'] = {"ea4","pt"};
	Char['G'] = {"jdbfz56ytr","y8"};
	Char['H'] = {"a4","e8","pt"};
	Char['I'] = {"ae","48","c6"};
	Char['J'] = {"de375z"};
	Char['K'] = {"a4","eq8","pq"};
	Char['L'] = {"a48"};
	Char['M'] = {"4are8"};
	Char['N'] = {"4a8e"};
	Char['O'] = {"fbdj375zf"};
	Char['P'] = {"4adjosp"};
	Char['Q'] = {"6yjdbfz56","w8"};
	Char['R'] = {"4adjosp","q8"};
	Char['S'] = {"jdbfkqsy375z"};
	Char['T'] = {"ae","c6"};
	Char['U'] = {"az573e"};
	Char['V'] = {"a6e"};
	Char['W'] = {"a5m7e"};
	Char['X'] = {"a8","4e"};
	Char['Y'] = {"6r","are"};
	Char['Z'] = {"ae48"};
	Char['a'] = {"y65zplnt8"};
	Char['b'] = {"a473tnk"};
	Char['c'] = {"tnlpz573"};
	Char['d'] = {"e85zplo"};
	Char['e'] = {"uxtnlpz58"};
	Char['f'] = {"edh;?","ko"};
	Char['g'] = {"85zplntBFD>"};
	Char['h'] = {"a4","plms7"};
	Char['i'] = {"76rq","h"};
	Char['j'] = {"i","rs<@?9"};
	Char['k'] = {"a9","su<"};
	Char['l'] = {"c67"};
	Char['m'] = {"4k","plr6","rnt8"};
	Char['n'] = {"4k","plms7"};
	Char['o'] = {"z573tnlpz"};
	Char['p'] = {"z573tnlp","kC"};
	Char['q'] = {"oG","tnlpz573"};
	Char['r'] = {"4k","plms"};
	Char['s'] = {"z573xvplnt"};
	Char['t'] = {"ko","c173"};
	Char['u'] = {"kz562","n78"};
	Char['v'] = {"k6o"};
	Char['w'] = {"kp5r7to"};
	Char['x'] = {"k8","o4"};
	Char['y'] = {"kz573","oBFD>"};
	Char['z'] = {"ko48"};
	Char['+'] = {"ko","cw"};
	Char['-'] = {"kn"};
	Char['*'] = {"ay","eu"};
	Char['/'] = {"e4"};
	Char[','] = {"y7"};
	Char['.'] = {"7"};
	Char['?'] = {"fbdjorw","6"};
	Char['!'] = {"cw","6"};
	Char[':'] = {"h","w"};
	Char['#'] = {"fj","uy","b4","e7"};
	Char['|'] = {"c6"};
	Char['\''] = {"dm"};
	Char[1] = {"ht1ph","mswqm","r"};
	Char[2] = {"hp1th","hm","pq","ts","1w","r"};
	/*
	a b c d e
	f g h i j
	k l m n o
	p q r s t
	u v w x y
	z 0 1 2 3
	4 5 6 7 8
	9 : ; < =
	> ? @ A B
	C D E F G
	*/
}
int _TIME=time(0), Plrs, PlrsCnt, RoundTot=0; char buf[9999];
int PaintLim = 10;
struct Board {
	#warning board
	int Plr; bool Over=false;
	int B[111][111], C[111][111], LE[111][111], LX, LY, DX;
	int Hold, HoldEnable;
	int DropL=300, LockL=1000, ResetLim=15;
	int GarbageGap = 8;
	//int DAS=60, ARR=0, SDDAS=0, SDARR=0;
	int DAS=300, ARR=20, SDDAS=300, SDARR=20;
	int GarbDelay=500, GarbRise=0;
	deque<int> Next; vector<Particle> PQu; vector<FloatText> TQu; 
	deque<pair<int,pair<int,ll> > > Rec; queue<int> Atk;
	deque<pair<int,int> > ActiveGarb;
	double KX, KY, sz=1.0; int Pid, Dir;
	char KEY_LEFT = VK_LEFT;
	char KEY_RIGHT = VK_RIGHT;
	char KEY_DOWN = VK_DOWN;
	char KEY_CW = 'X';
	char KEY_CCW = 'Z';
	char KEY_180 = 'A';
	char KEY_HARD = ' ';
	char KEY_HOLD = 'C';//VK_SHIFT;
	char KEY_ROT = VK_UP;
	char KEY_EVEN = '1';
	char KEY_KO = '2';
	char KEY_RANDOM = '3';
	char KEY_PAYBACK = '4';
	char KEY_BADGE = '5';
	char KEY_ATTACKERS = '6';
	int AtkType = 1;
	int DropTime, ResetRem; bool Bot=false;
	int LastGarb=0, Combo, B2B;
	double ShiftX, ShiftY; mt19937 gen;
	vector<char> KeyList = {KEY_DOWN,KEY_LEFT,KEY_RIGHT,KEY_CW,KEY_CCW,KEY_180,KEY_HARD,KEY_HOLD,VK_UP,KEY_EVEN,KEY_KO,KEY_RANDOM,KEY_PAYBACK,KEY_BADGE,KEY_ATTACKERS};
	vector<char> DasKey = {KEY_DOWN,KEY_LEFT,KEY_RIGHT};
	int KeySta[256], KeyTime[256], Key, RotType=3; bool KeyDas[256], UseDas[256];
	double avx=0.0, avy=0.0; ll begtm = clock();
	int OperDis, OperTime=0; bool MiniSpin=false;
	int SumPiece=0, SumLine=0, SumAttack=0, SumDig=0, KO=0, SKO=0;
	int ClearType=0, ClearTm=0, ClearColor=0, SpinType=0, SpinFull=0, SpinTm=0, SpinDis=0;
	int ComboType=0, ComboTm=0, B2BType=0, B2BTm=0, Wins=0;
	string FullLCW=""; int FullTm=0, VSRnk=0;
	double SKX, SKY, Ssz, isz; int LstAtk=-1; bool BeFrom=false, BeTo=false;
	Board() {
	}
	Board(int _Plr, int _LX, int _LY, int _DX, double _KX, double _KY, bool _Bot=false, int _OperTime=0) {
		Plr=_Plr; begtm=clock();
		LX=_LX; LY=_LY; DX=_DX;
		KX=SKX=_KX; KY=SKY=_KY; Bot=_Bot; OperTime=_OperTime;
		for (int i=0; i<111; ++i) {
			for (int j=0; j<111; ++j) B[i][j]=C[i][j]=0;
		}
		for (int i=0; i<256; ++i) {
			KeySta[i]=KeyTime[i]=0; KeyDas[i]=UseDas[i]=false;
		}
		for (int i : DasKey) UseDas[i]=true;
		Next.clear();
		Hold=DropTime=0; HoldEnable=1; ResetRem=ResetLim;
		double tmp = min(300.0/double(10),600.0/double(22))*0.7;
		isz=sz=Ssz=min(300.0/double(LY),600.0/double(DX))*0.7/tmp*20.0;
		SumPiece=SumLine=SumAttack=0;
		ShiftX=ShiftY=0.0; gen=mt19937(_TIME);
	}
	void Plot(double x, double y, int clr) {
		int _clr=clr; clr=abs(clr);
		x+=KX; y+=KY;
		int B=clr&255; clr>>=8;
		int G=clr&255; clr>>=8;
		int R = clr&255;
		double px = 1.0-x/double(PS);
		double py = y/double(PS);
		px = px*1.6-0.8;
		py = py*1.6-0.8;
		glColor3f(min(1.0,max(0.0,double(R)/255.0)), min(1.0,max(0.0,double(G)/255.0)), min(1.0,max(0.0,double(B)/255.0)));
		glVertex2f(py*2.0/3.0-1.0/3.0, px);
	}
	void Poly(double x, double y, double r, int n, int clr, double th=0.0) {
		glBegin(GL_POLYGON);
		for (int i=0; i<n; ++i) {
			Plot(x-r*cos(th), y+r*sin(th), clr);
			th += 2.0*acos(-1.0)/double(n);
		}
		glEnd();
	}
	void Square(double x, double y, double d, int clr) {
		glBegin(GL_POLYGON);
		Plot(x, y, clr);
		Plot(x+d, y, clr);
		Plot(x+d, y+d, clr);
		Plot(x, y+d, clr);
		glEnd();
	}
	void Rectangle(double x, double y, double dx, double dy, int clr) {
		glBegin(GL_POLYGON);
		Plot(x, y, clr);
		Plot(x+dx, y, clr);
		Plot(x+dx, y+dy, clr);
		Plot(x, y+dy, clr);
		glEnd();
	}
	void PaintChar(int ch, double x, double y, double sz, int clr, double bd=0.15) {
		bd*=sz; sz/=6.0;
		for (string str : Char[ch]) {
			if (str.size()==1) {
				int val = ((str[0]>='a')&&(str[0]<='z'))?str[0]-'a':26+str[0]-'0';
				double sx=x+sz*double(val/5), sy=y+sz*double(val%5);
				double dx=bd*0.5, dy=bd*0.5;
				glBegin(GL_POLYGON);
				Plot(sx+dx, sy+dy, clr);
				Plot(sx+dx, sy-dy, clr);
				Plot(sx-dx, sy-dy, clr);
				Plot(sx-dx, sy+dy, clr);
				glEnd();
				continue;
			}
			for (int i=1; i<str.size(); ++i) {
				int val = ((str[i-1]>='a')&&(str[i-1]<='z'))?str[i-1]-'a':26+str[i-1]-'0';
				double sx=x+sz*double(val/5), sy=y+sz*double(val%5);
				val = ((str[i]>='a')&&(str[i]<='z'))?str[i]-'a':26+str[i]-'0';
				double ex=x+sz*double(val/5), ey=y+sz*double(val%5);
				double dx=ex-sx, dy=ey-sy, len=sqrt(dx*dx+dy*dy);
				double rat = bd/len*0.2;
				sx-=rat*dx; sy-=rat*dy;
				ex+=rat*dx; ey+=rat*dy;
				dx=sy-ey; dy=ex-sx;
				rat = 0.5*bd/sqrt((sx-ex)*(sx-ex)+(sy-ey)*(sy-ey));
				dx*=rat; dy*=rat;
				glBegin(GL_POLYGON);
				Plot(sx+dx, sy+dy, clr);
				Plot(ex+dx, ey+dy, clr);
				Plot(ex-dx, ey-dy, clr);
				Plot(sx-dx, sy-dy, clr);
				glEnd();
			}
		}
	}
	void PaintStrL(string str, double x, double y, double sz, int clr, double bd=0.15, double dis=1.0) {
		dis *= sz;
		for (char ch : str) {
			PaintChar(int(ch), x, y, sz, clr, bd);
			y += dis;
		}
	}
	void PaintStrR(string str, double x, double y, double sz, int clr, double bd=0.15, double dis=1.0) {
		dis *= sz;
		reverse(str.begin(), str.end());
		for (char ch : str) {
			PaintChar(int(ch), x, y, sz, clr, bd);
			y -= dis;
		}
	}
	void PaintStrM(string str, double x, double y, double sz, int clr, double bd=0.15, double dis=1.0) {
		dis *= sz;
		y -= dis*0.5*double(str.size()-1)-sz*0.5;
		for (char ch : str) {
			PaintChar(int(ch), x, y, sz, clr, bd);
			y += dis;
		}
	}
	bool CheckActive() {
		for (int i=1; i<=LX; ++i) {
			for (int j=1; j<=LY; ++j) {
				if (C[i][j]) return true;
			}
		}
		return false;
	}
	bool CheckPlace(int x, int y) {
		if ((min(x,y)<1)||((x>LX)||(y>LY))) return true;
		return ((B[x][y])&&(!C[x][y]));
	}
	int QueryHeight() {
		for (int i=LX; i; --i) {
			for (int j=1; j<=LY; ++j) {
				if ((B[i][j])&&(!C[i][j])) return i;
			}
		}
		return 0;
	}
	bool Spawn(int _Pid, int _Dir) {
		ClassPiece P = Piece[_Pid][_Dir];
		if (LY<P.LY) return false;
		int SX=DX-1+P.SDel, SY=(LY-P.LY)/2+1;
		SY = max(1,min(LY-P.LY+1,SY));
		SX = max(1,min(LX,SX));
		for (int i=0; i<P.LX; ++i) {
			for (int j=0; j<P.LY; ++j) {
				if ((CheckPlace(SX+i,SY+j))&&(P.B[i][j])) return false;
			}
		}
		for (int i=1; i<=LX; ++i) {
			for (int j=1; j<=LY; ++j) {
				if (C[i][j]) {
					B[i][j]=C[i][j]=0; LE[i][j]=10000;
				}
			}
		}
		for (int i=0; i<P.LX; ++i) {
			for (int j=0; j<P.LY; ++j) {
				if (P.B[i][j]) {
					C[SX+i][SY+j]=1; B[SX+i][SY+j]=_Pid;
				}
			}
		}
		Pid=_Pid; Dir=_Dir;
		return true;
	}
	bool CheckUp() {
		for (int i=1; i<=LX; ++i) {
			for (int j=1; j<=LY; ++j) {
				if ((C[i][j])&&(CheckPlace(i+1,j))) return false;
			}
		}
		return true;
	}
	bool CheckDown() {
		for (int i=1; i<=LX; ++i) {
			for (int j=1; j<=LY; ++j) {
				if ((C[i][j])&&(CheckPlace(i-1,j))) return false;
			}
		}
		return true;
	}
	bool MoveDown() {
		if (!CheckDown()) return false;
		for (int i=1; i<LX; ++i) {
			for (int j=1; j<=LY; ++j) {
				if (C[i+1][j]) {
					B[i][j]=B[i+1][j]; C[i][j]=1;
					B[i+1][j]=C[i+1][j]=0;
				}
			}
		}
		MiniSpin = false;
		return true;
	}
	bool CheckLeft() {
		for (int i=1; i<=LX; ++i) {
			for (int j=1; j<=LY; ++j) {
				if ((C[i][j])&&(CheckPlace(i,j-1))) return false;
			}
		}
		return true;
	}
	bool MoveLeft() {
		if (!CheckLeft()) return false;
		for (int i=1; i<=LX; ++i) {
			for (int j=1; j<=LY; ++j) {
				if (C[i][j+1]) {
					B[i][j]=B[i][j+1]; C[i][j]=1;
					B[i][j+1]=C[i][j+1]=0;
				}
			}
		}
		MiniSpin = false;
		return true;
	}
	bool CheckRight() {
		for (int i=1; i<=LX; ++i) {
			for (int j=1; j<=LY; ++j) {
				if ((C[i][j])&&(CheckPlace(i,j+1))) return false;
			}
		}
		return true;
	}
	bool MoveRight() {
		if (!CheckRight()) return false;
		for (int i=1; i<=LX; ++i) {
			for (int j=LY; j; --j) {
				if (C[i][j-1]) {
					B[i][j]=B[i][j-1]; C[i][j]=1;
					B[i][j-1]=C[i][j-1]=0;
				}
			}
		}
		MiniSpin = false;
		return true;
	}
	#warning rotate
	bool Rotate(int NewDir) {
		if ((NewDir<0)||(NewDir>3)||(NewDir==Dir)||(!Pid)) return false;
		int FstX=0, FstY=0;
		for (int i=1; i<=LX; ++i) {
			for (int j=1; j<=LY; ++j) {
				if (C[i][j]) {
					FstX=i; FstY=j; break;
				}
			}
			if (FstX) break;
		}
		if (!FstX) return false;
		int SX=FstX-Piece[Pid][Dir].FstX, SY=FstY-Piece[Pid][Dir].FstY;
		ClassPiece P = Piece[Pid][NewDir];
		bool flag = false;
		int beg=Dir; if (beg&1) beg^=2;
		int en=NewDir; if (en&1) en^=2;
		for (pair<int,int> KT : Kick[Pid][beg][en]) {
			SX+=KT.second; SY+=KT.first;
			bool ok = true;
			for (int i=0; i<P.LX; ++i) {
				for (int j=0; j<P.LY; ++j) {
					if ((P.B[i][j])&&(CheckPlace(SX+i,SY+j))) {
						ok=false; break;
					}
				}
				if (!ok) break;
			}
			if (ok) {
				flag=true; break;
			}
			else {
				SX-=KT.second; SY-=KT.first;
			}
		}
		if (!flag) return false;
		MiniSpin = false;
		for (int i=1; i<=LX; ++i) {
			for (int j=1; j<=LY; ++j) {
				if (C[i][j]) B[i][j]=C[i][j]=0;
			}
		}
		for (int i=0; i<P.LX; ++i) {
			for (int j=0; j<P.LY; ++j) {
				if (P.B[i][j]) {
					B[SX+i][SY+j]=Pid; C[SX+i][SY+j]=1;
				}
			}
		}
		Dir = NewDir;
		if ((!CheckUp())&&(!CheckDown())&&(!CheckLeft())&&(!CheckRight())) {
			double x=0.0, y=0.0; int bn=0;
			for (int i=1; i<=LX; ++i) {
				for (int j=1; j<=LY; ++j) {
					if (C[i][j]) {
						++bn; x+=double(i); y+=double(j);
					}
				}
			}
			x=x/double(bn)-0.5; y=y/double(bn)+0.5;
			double dx=sz*double(DX-x), dy=sz*double(y-1);
			double th = rndf()*acos(-1.0)*2.0;
			for (int i=0; i<10; ++i) {
				th += acos(-1.0)*2.0/10.0;
				PQu.push_back({dx,dy,sin(th)*0.1,cos(th)*0.1,0,0,sz*0.15,0.006,rndf()*acos(-1.0)*2.0,5,Mix(Piece[Pid][0].clr,0xFFFFFF,0.7)});
			}
		}
		else if (!CheckDown()) {
			bool ok = true;
			for (int i=1; i<=LX; ++i) {
				for (int j=1; j<=LY; ++j) {
					if (!C[i][j]) continue;
					if (int(C[i-1][j])+int(C[i+1][j])+int(C[i][j-1])+int(C[i][j+1])<2) continue;
					if (int(CheckPlace(i-1,j-1))+int(CheckPlace(i+1,j-1))+int(CheckPlace(i-1,j+1))+int(CheckPlace(i+1,j+1))<3) ok=false;
				}
			}
			if (ok) {
				MiniSpin = true;
				double x=0.0, y=0.0; int bn=0;
				for (int i=1; i<=LX; ++i) {
					for (int j=1; j<=LY; ++j) {
						if (C[i][j]) {
							++bn; x+=double(i); y+=double(j);
						}
					}
				}
				x=x/double(bn)-0.5; y=y/double(bn)+0.5;
				double dx=sz*double(DX-x), dy=sz*double(y-1);
				double th = rndf()*acos(-1.0)*2.0;
				for (int i=0; i<5; ++i) {
					th += acos(-1.0)*2.0/5.0;
					PQu.push_back({dx,dy,sin(th)*0.1,cos(th)*0.1,0,0,sz*0.1,0.006,rndf()*acos(-1.0)*2.0,5,Mix(Piece[Pid][0].clr,0xFFFFFF,0.7)});
				}
			}
		}
		return true;
	}
	int Spin, SemiSpin; double ravx=0.0, ravy=0.0;
	void Lock() {
		Spin = ((!CheckUp())&&(!CheckDown())&&(!CheckLeft())&&(!CheckRight()));
		SemiSpin = false;
		if (Spin) {
			int sw=0; bool ex=false;
			for (int i=1; i<=LX; ++i) {
				for (int j=1; j<=LY; ++j) {
					int tc=0, te=0;
					for (int ii=-1; ii<=1; ++ii) {
						for (int jj=-1; jj<=1; ++jj) {
							int dis = abs(ii)+abs(jj);
							if ((dis)&&((!CheckPlace(i+ii,j+jj)&&(C[i+ii][j+jj])))) ++tc;
							if ((dis==1)&&((!CheckPlace(i+ii,j+jj)&&(!B[i+ii][j+jj])))) ++te;
						}
					}
					if ((C[i][j])&&(te>1)) ex=true;
					if ((B[i][j])&&(!C[i][j])&&(tc>=3)) ++sw;
				}
			}
			SemiSpin = ((ex)&&(sw<2));
		}
		++SumPiece;
		int totx=0, toty=0, tot=0;
		for (int i=1; i<=LX; ++i) {
			for (int j=1; j<=LY; ++j) {
				if (C[i][j]) {
					totx+=i; toty+=j; ++tot;
					C[i][j]=0; LE[i][j]=10000;
				}
			}
		}
		avx = double(totx)/double(max(tot,1));
		avy = double(toty)/double(max(tot,1));
		ravx = sz*double(DX-avx)+sz*0.5+KX;
		ravy = sz*double(avy-1)+sz*0.5+KY;
	}
	void HardDrop() {
		while (CheckDown()) {
			for (int i=1; i<=LX; ++i) {
				for (int j=1; j<=LY; ++j) {
					if (C[i][j]) {
						double dx=sz*double(DX-i)+sz*rndf(), dy=sz*double(j-1)+sz*rndf();
						PQu.push_back({dx,dy,-0.2,0,0,0,2,0.002,rndf()*acos(-1.0),4,Mix(0xFFFFFF,Piece[B[i][j]][0].clr,0.3)});
					}
				}
			}
			MoveDown();
		}
		Lock();
	}
	bool Dig = false;
	int RemoveLines() {
		int res=0; Dig=false;
		for (int i=1; i<=LX; ++i) {
			bool ok=true, garb=false;
			for (int j=1; j<=LY; ++j) {
				if (!CheckPlace(i,j)) ok=false;
				if (B[i][j]==54) garb=true;
			}
			if (!ok) continue;
			if (garb) {
				Dig=true; ++SumDig;
			}
			for (int j=1; j<=LY; ++j) {
				double dx=sz*double(DX-i-res)+sz*0.5, dy=sz*double(j-1)+sz*0.5;
				PQu.push_back({dx,dy,-0.7+0.2*(rnd(10000)*0.0001),0.2*(rnd(10000)*0.0001-0.5),0.003,0,sz*0.12,0.001,rnd(10000)*0.0002*acos(-1.0),12,Piece[B[i][j]][0].clr});
			}
			++res;
			for (int j=i; j<LX; ++j) {
				for (int k=1; k<=LY; ++k) {
					B[j][k]=B[j+1][k]; C[j][k]=C[j+1][k]; LE[j][k]=LE[j+1][k];
				}
			}
			for (int j=1; j<=LY; ++j) B[LX][j]=C[LX][j]=LE[LX][j]=0;
			--i;
		}
		return res;
	}
	void PaintText(int tm) {
		#warning text
		ll timer = max(1LL,clock()-begtm);
		double tsz=sz*0.6, tx=sz*DX;
		sprintf(buf, "%.2f /m", double(SumAttack)*60000.0/double(timer));
		tx-=tsz; PaintStrR(buf, tx, -tsz*3.5, tsz*0.8, 0x006666);
		if (Plrs>2) {
			sprintf(buf, "%.2f VS", double(SumAttack+SumDig)*100000.0/double(timer));
			PaintStrL(buf, tx+tsz*0.2, sz*LY+tsz*1.5, tsz*0.6, 0x006666);
		}
		sprintf(buf, "%d", SumAttack);
		tx-=tsz*1.5; PaintStrR(buf, tx, -tsz*3.5, tsz, 0x006666);
		if (Plrs>2) {
			sprintf(buf, "%2d", VSRnk);
			PaintStrL(buf, tx, sz*LY+tsz*1.5, tsz, 0x006666);
			sprintf(buf, " /%2d", PlrsCnt);
			PaintStrL(buf, tx+tsz*0.6, sz*LY+tsz*4.5, tsz*0.6, 0x006666);
			sprintf(buf, " /%2d", Plrs);
			PaintStrL(buf, tx-tsz, sz*LY+tsz*4.5, tsz*0.6, 0x888888);
		}
		else if (Plrs==2) {
			sprintf(buf, "%.2f", double(SumAttack+SumDig)*100000.0/double(timer));
			PaintStrL(buf, tx, sz*LY+tsz*1.5, tsz, 0x006666);
		}
		tx-=tsz*1.2; PaintStrR("ATTACK", tx, -tsz*3.5, tsz*0.8, 0x888888);
		if (Plrs>2) PaintStrL("RANK", tx, sz*LY+tsz*1.5, tsz*0.8, 0x888888);
		else if (Plrs==2) PaintStrL("VS SCORE", tx, sz*LY+tsz*1.5, tsz*0.8, 0x888888);
		tx -= tsz;
		sprintf(buf, "%.2f /m", double(SumLine)*60000.0/double(timer));
		tx-=tsz; PaintStrR(buf, tx, -tsz*3.5, tsz*0.8, 0x006666);
		sprintf(buf, "%d", SumLine);
		tx-=tsz*1.5; PaintStrR(buf, tx, -tsz*3.5, tsz, 0x006666);
		tx-=tsz*1.2; PaintStrR("LINE", tx, -tsz*3.5, tsz*0.8, 0x888888);
		tx -= tsz;
		sprintf(buf, "%.2f /s", double(SumPiece)*1000.0/double(timer));
		tx-=tsz; PaintStrR(buf, tx, -tsz*3.5, tsz*0.8, 0x006666);
		sprintf(buf, "%d", SumPiece);
		tx-=tsz*1.5; PaintStrR(buf, tx, -tsz*3.5, tsz, 0x006666);
		tx-=tsz*1.2; PaintStrR("PIECE", tx, -tsz*3.5, tsz*0.8, 0x888888);
		tx -= tsz;
		sprintf(buf, ".%03d",timer%1000);
		tx-=tsz*1.5; PaintStrR(buf, tx+tsz*0.2, -tsz*3.5, tsz*0.8, 0x006666);
		sprintf(buf, "%02d:%02d",timer/60000,timer/1000%60);
		PaintStrR(buf, tx, -tsz*6.5, tsz, 0x006666);
		tx-=tsz*1.2; PaintStrR("TIME", tx, -tsz*3.5, tsz*0.8, 0x888888);
		if (Plrs>2) {
			tx -= tsz;
			sprintf(buf, "%d KO\'s", KO);
			tx-=tsz; PaintStrR(buf, tx, -tsz*3.5, tsz*0.8, 0x006666);
			sprintf(buf, "%d", SKO);
			tx-=tsz*1.5; PaintStrR(buf, tx, -tsz*3.5, tsz, 0x006666);
			tx-=tsz*1.2; PaintStrR("BADGE", tx, -tsz*3.5, tsz*0.8, 0x888888);
		}
		else if (Plrs==2) {
			tx -= tsz;
			sprintf(buf, "of %d", RoundTot);
			tx-=tsz; PaintStrR(buf, tx, -tsz*3.5, tsz*0.8, 0x006666);
			sprintf(buf, "%d", Wins);
			tx-=tsz*1.5; PaintStrR(buf, tx, -tsz*3.5, tsz, 0x006666);
			tx-=tsz*1.2; PaintStrR("POINT", tx, -tsz*3.5, tsz*0.8, 0x888888);
		}
		tx = sz*4.0;
		SpinTm = max(0,SpinTm-tm*((SpinDis)?50:10));
		int bg = Mix(0xFFFFFF,0x000000,0.92);
		double rat = double(SpinTm)/15000.0;
		sprintf(buf, "%c-Spin", PName[SpinType]);
		if (SpinFull==2) PaintStrR(buf, tx, -tsz*3.5, tsz, Mix(Piece[SpinType][0].clr,bg,rat), 0.05+0.1*rat, 1.5-0.5*rat);
		else if (SpinFull==1) {
			sprintf(buf, "Semi %c-Spin", PName[SpinType]);
			PaintStrR(buf, tx+tsz*0.1, -tsz*3.5, tsz*0.8, Mix(Piece[SpinType][0].clr,bg,rat), 0.05+0.1*rat, 1.5-0.5*rat);
		}
		else {
			PaintStrR("Mini", tx-tsz*0.4, -tsz*3.5, tsz*0.7, Mix(Piece[SpinType][0].clr,bg,rat), 0.05+0.1*rat, 1.5-0.5*rat);
			PaintStrR(buf, tx+tsz*0.5, -tsz*3.5, tsz*0.7, Mix(Piece[SpinType][0].clr,bg,rat), 0.05+0.1*rat, 1.5-0.5*rat);
		}
		tx += tsz*2.0;
		ClearTm = max(0,ClearTm-tm*10);
		bg = Mix(0xFFFFFF,0x000000,0.92);
		rat = double(ClearTm)/10000.0;
		PaintStrR(LCW[ClearType], tx, -tsz*3.5, tsz*1.5, Mix((ClearColor)?Piece[ClearColor][0].clr:0x888888,bg,rat), 0.05+0.1*rat, 1.5-0.5*rat);
		tx += tsz*2.5;
		ComboTm = max((ComboType)?7500:0,ComboTm-tm*((ComboType)?10:50));
		rat = double(ComboTm)/10000.0;
		sprintf(buf, "%d Combo", ComboType);
		PaintStrR(buf, tx, -tsz*3.5, tsz, Mix((ComboType)?0x39C5BB:0xAAAAAA,bg,rat), 0.05+0.1*rat, 1.5-0.5*rat);
		tx += tsz*1.8;
		B2BTm = max((B2BType)?7500:0,B2BTm-tm*((B2BType)?10:50));
		rat = double(B2BTm)/10000.0;
		sprintf(buf, "B2B x%d", B2BType);
		PaintStrR(buf, tx, -tsz*3.5, tsz, Mix((B2BType)?((B2BType>3)?0x9999FF:0xFFA500):0x888888,bg,rat), 0.05+0.1*rat, 1.5-0.5*rat);
	}
	#warning paint
	void Paint(int tm) {
		tm *= 2;
		if (isz!=Ssz) {
			double del = fabs(isz-Ssz);
			double val = min(del,max(del*0.0008*tm,tm*0.002));
			if (isz>Ssz) isz-=val;
			else isz+=val;
		}
		if (KX!=SKX) {
			double del = fabs(KX-SKX);
			double val = min(del,max(del*0.001*tm,tm*0.01));
			if (KX>SKX) KX-=val;
			else KX+=val;
		}
		if (KY!=SKY) {
			double del = fabs(KY-SKY);
			double val = min(del,max(del*0.001*tm,tm*0.01));
			if (KY>SKY) KY-=val;
			else KY+=val;
		}
		tm /= 2;
		PaintText(tm);
		bool ckd = CheckDown();
		int DropLen = 3321;
		for (int j=1; j<=LY; ++j) {
			int lst = 0;
			for (int i=1; i<=LX; ++i) {
				if (C[i][j]) DropLen=min(DropLen,i-lst-1);
				else if (B[i][j]) lst=i;
			}
		}
		sz = isz;
		//sz=floor(sz); if (int(sz)&1) sz+=1.0;
		deque<pair<int,pair<int,int> > > rec;
		int ActiveTot=0;
		for (pair<int,int> o : ActiveGarb) {
			rec.push_back(make_pair(o.first,make_pair(o.second,-1LL))); ActiveTot+=o.first;
		}
		for (pair<int,pair<int,int> > o : Rec) rec.push_back(o);
		int RecTot=0; for (pair<int,pair<int,int> > o : rec) RecTot+=o.first;
		for (int i=1; i<=DX; ++i) {
			for (int j=1; j<=LY; ++j) {
				int clr=0xDDDDDD; if (i+2>DX) clr=Mix(clr,0xEE0000,0.8);
				Square(sz*double(DX-i),sz*double(j-1),sz,clr);
				Square(sz*double(DX-i)+sz*0.05,sz*double(j-1)+sz*0.05,sz*0.9,0xFFFFFF);
			}
			if (i>RecTot) {
				Rectangle(sz*double(DX-i),-5,sz-3,3,0xCCCCCC); continue;
			}
			bool flag=false, active=false, avail=false; int cur=0;
			ll curt=clock(); int clr=0;
			for (pair<int,pair<int,int> > o : rec) {
				if (cur+1==i) flag=true;
				cur += o.first;
				if (cur>=i) {
					if (o.second.second<0LL) active=true;
					else if (curt-ll(GarbDelay)>=o.second.second) avail=true;
					else {
						double rat = min(1.0,max(0.0,double(curt-o.second.second)/double(max(1,GarbDelay))));
						clr = Mix(0xFFA500,0xFFE211,rat);
					}
					break;
				}
			}
			Rectangle(sz*double(DX-i), -5, (flag)?sz-3:sz, 3, (active)?0xDF3782:(((avail)?((i<=ActiveTot+GarbageGap)?0xEE0000:0xFF6666):clr)));
		}
		int GVC = 10;
		for (int i=1; i<=GVC; ++i) {
			if (i>RecTot) break;
			int pos=0, cur=0;
			for (pair<int,pair<int,int> > o : rec) {
				cur += o.first;
				if (cur>=i) {
					pos=o.second.first; break;
				}
			}
			for (int j=1; j<=LY; ++j) {
				if (j==pos) continue;
				int clr = Mix(0xEEEEEE,0xCCCCCC,double(i-1)/double(GVC));
				Square(sz*0.4+sz*double(DX-(1-i)),sz*double(j-1),sz,clr);
				Square(sz*0.4+sz*double(DX-(1-i))+sz*0.15,sz*double(j-1)+sz*0.15,sz*0.7,Mix(0xFFFFFF,clr,0.2));
				Square(sz*0.4+sz*double(DX-(1-i))+sz*0.25,sz*double(j-1)+sz*0.25,sz*0.5,clr);
			}
		}
		double rat = max(0.0,min(1.0,double(DropTime)/double(max(1,LockL))));
		if (CheckDown()) rat=0.0;
		rat = 1.0-rat;
		Rectangle(sz*double(DX),0.0,sz*0.2,sz*LY,0xEEEEEE);
		Rectangle(sz*double(DX),0.0,sz*0.2,sz*LY*rat,0xFDD000);
		rat = max(0.0,min(1.0,double(ResetRem)/double(max(1,ResetLim))));
		Rectangle(sz*0.2+sz*double(DX),0.0,sz*0.2,sz*LY,0xDDDDDD);
		Rectangle(sz*0.2+sz*double(DX),0.0,sz*0.2,sz*LY*rat,0xFFA500);
		if (Bot) Rectangle(sz*double(DX),0.0,sz*0.4,sz*LY,0xDEDEDE);
		for (int i=1; i<=LX; ++i) {
			for (int j=1; j<=LY; ++j) {
				if (!B[i][j]) {
					if (i>DX) continue;
					if ((DropLen+i<=LX)&&(C[DropLen+i][j])) Square(sz*double(DX-i)+sz*0.1,sz*double(j-1)+sz*0.1,sz*0.8,0xEEEEEE);
					continue;
				}
				int clr = Piece[B[i][j]][0].clr;
				if ((!C[i][j])&&(LE[i][j])) {
					clr = Mix(0xFFFFFF,clr,LE[i][j]*0.00005);
					LE[i][j] = max(0,LE[i][j]-tm*40);
				}
				//if ((C[i][j])&&(B[i][j])) clr=Mix(0xFFFFFF,clr,0.1);
				double rat = 0.0;
				if ((C[i][j])&&(ckd)) rat=max(0.0,min(1.0,double(DropTime)/double(max(1,DropL))));
				Square(sz*double(DX-i)+rat*sz,sz*double(j-1),sz,clr);
				double lrat = max(0.0,min(1.0,double(DropTime)/double(max(1,LockL))));
				if (ckd) lrat=0.0;
				if (C[i][j]) {
					Square(sz*double(DX-i)+rat*sz+sz*0.15,sz*double(j-1)+sz*0.15,sz*0.7,Mix(0xFFFFFF,clr,0.5-0.2*lrat));
					Square(sz*double(DX-i)+rat*sz+sz*0.25,sz*double(j-1)+sz*0.25,sz*0.5,clr);
				}
				else {
					Square(sz*double(DX-i)+rat*sz+sz*0.15,sz*double(j-1)+sz*0.15,sz*0.7,Mix(0xFFFFFF,clr,0.3));
					Square(sz*double(DX-i)+rat*sz+sz*0.25,sz*double(j-1)+sz*0.25,sz*0.5,clr);
				}
			}
		}
		double msz = sz*0.8;
		int SX=0, SY=0;
		if (Hold) {
			if (Piece[Hold][0].LX<=3) SX=1;
			if (Piece[Hold][0].LX<=1) SX=2;
			if (Piece[Hold][0].LY<=3) SY=1;
			if (Piece[Hold][0].LY<=1) SY=2;
		}
		Rectangle(10, -sz*3-msz*4.5, msz*4.0, msz*6.0, 0xFFFFFF);
		for (int i=0; i<3; ++i) {
			for (int j=0; j<5; ++j) {
				int clr = 0xFFFFFF;
				if (min(4-i-SX,4-j-SY)>=0) {
					if (Piece[Hold][0].B[4-i-SX][4-j-SY]) clr=(HoldEnable)?Piece[Hold][0].clr:0x888888;
				}
				if (clr==0xFFFFFF) continue;
				Square(msz*double(i)+10, msz*0.5*double(!(Piece[Hold][0].LY&1))-sz*3-msz*double(j), msz*0.9, Mix(clr,0xFFFFFF,0.2));
				Square(msz*double(i)+10, msz*0.5*double(!(Piece[Hold][0].LY&1))-sz*3-msz*double(j), msz*0.8, clr);
			}
		}
		for (int d=0; d<5; ++d) {
			Rectangle(-msz*1+10+msz*double(d*5), sz*double(LY+1)-msz*0.5, msz*4.0, msz*6.0, 0xFFFFFF);
			if (Next.size()<=d) break;
			int cur = Next[d];
			SX=SY=0;
			if (Piece[cur][0].LY<=3) SY=1;
			if (Piece[cur][0].LY<=1) SY=2;
			for (int i=0; i<3; ++i) {
				for (int j=0; j<5; ++j) {
					int clr = 0xFFFFFF;
					if (min(2-i-SX,j-SY)>=0) clr=(Piece[cur][0].B[2-i-SX][j-SY])?Piece[cur][0].clr:0xFFFFFF;
					if (clr==0xFFFFFF) continue;
					Square(msz*double(i+d*5)+10, msz*0.5*double(!(Piece[cur][0].LY&1))+sz*double(LY+1)+msz*double(j), msz*0.9, Mix(clr,0xFFFFFF,0.2));
					Square(msz*double(i+d*5)+10, msz*0.5*double(!(Piece[cur][0].LY&1))+sz*double(LY+1)+msz*double(j), msz*0.8, clr);
				}
			}
		}
	}
	void PaintParticle(int tm, int tars) {
		ll del = clock()-begtm;
		sprintf(buf, "%d Targeting You", tars);
		if ((Plrs>2)&&(!Over)) PaintStrM(buf,sz*double(DX+1),sz*0.5*double(LY-1),sz*0.5,(tars<2)?((tars)?0x888888:0xCCCCCC):((tars<6)?0xFFA500:0xEE0000));
		if ((Plrs>2)&&(!Over)) PaintStrM(ATKN[AtkType],sz*double(DX+2),sz*0.5*double(LY-1),sz*0.5,0xDF3782);
		FullTm = max(0,FullTm-tm*10);
		double rat = double(FullTm)/10000.0;
		//if (FullTm) PaintStrM(FullLCW,sz*double(DX+2),sz*0.5*double(LY-1),sz*0.5,0x888888,rat*0.1,2.0-rat);
		int pcnt = 0;
		rat = double(max(1,tm));
		for (int i=0; i<PQu.size(); ++i) {
			Particle o = PQu[i];
			Poly(o.x, o.y, o.sz*sz/15.0, o.n, o.clr, o.th);
			o.x+=o.vx*rat; o.y+=o.vy*rat;
			o.vx+=o.ax*rat; o.vy+=o.ay*rat;
			o.sz -= o.de*rat*0.5;
			if ((Bot)&&((sz<10)||(OperTime<5))&&(o.clr>=0)) o.sz=-1.0;
			if (o.sz>0.0) PQu[pcnt++]=o;
		}
		while (PQu.size()>pcnt) PQu.pop_back();
		int tcnt = 0;
		for (int i=0; i<TQu.size(); ++i) {
			FloatText o = TQu[i];
			PaintStrM(o.str, o.x, o.y, o.sz, abs(o.clr), o.bd);
			o.bd -= o.de*rat*0.5;
			if ((Bot)&&(sz<10)&&(o.clr>=0)) o.bd=-1.0;
			if (o.bd>0.0) TQu[tcnt++]=o;
		}
		while (TQu.size()>tcnt) TQu.pop_back();
		if (BeFrom) PaintStrM(string(1,1),sz*double(DX)*0.3,-0.15*sz*double(LY),sz*0.8*double(LY),0xDF3782,0.06);
		if (BeTo) PaintStrM(string(1,2),sz*double(DX)*0.3,-0.15*sz*double(LY),sz*0.8*double(LY),0xFDD000,0.06);
	}
	vector<char> GetKey(int tm) {
		if (Bot) return vector<char>();
		vector<char> res;
		for (char ch : KeyList) {
			bool nw = CheckKey(ch);
			if (UseDas[ch]) {
				if (!KeySta[ch]) {
					if (nw) {
						KeySta[ch]=true; res.push_back(ch); KeyTime[ch]=0;
					}
				}
				else {
					if (!nw) {
						KeySta[ch]=KeyDas[ch]=false; KeyTime[ch]=0;
					}
					else {
						KeyTime[ch]+=tm; int val=(KeyDas[ch])?ARR:((ch==KEY_DOWN)?SDDAS:DAS);
						if (KeyTime[ch]>=val) {
							KeyTime[ch]-=val; KeyDas[ch]=true;
							res.push_back(ch);
						}
					}
				}
				if ((nw)&&(!((ch==KEY_DOWN)?SDDAS:DAS))) KeyDas[ch]=true;
			}
			else {
				if ((nw)&&(!KeySta[ch])) res.push_back(ch);
				KeySta[ch] = nw;
			}
		}
		return res;
	}
	set<ClassSta> st; map<ClassSta,string> mp;
	bool CheckPos(ClassSta o) {
		int p=o.p, d=o.d, x=o.x, y=o.y;
		for (int i=0; i<Piece[p][d].LX; ++i) {
			for (int j=0; j<Piece[p][d].LY; ++j) {
				if ((Piece[p][d].B[i][j])&&(CheckPlace(x+i,y+j))) return false;
			}
		}
		return true;
	}
	void bfs(int p, int d, int x, int y) {
		ClassSta o = (ClassSta){p,d,x,y};
		if (!CheckPos(o)) return;
		queue<ClassSta> q; q.push(o); st.insert(o);
		while (!q.empty()) {
			o=q.front(); q.pop();
			ClassSta nw=o; --nw.x;
			if ((!st.count(nw))&&(CheckPos(nw))) {
				mp[nw] = mp[o]+KEY_DOWN;
				st.insert(nw); q.push(nw);
			}
			nw=o; --nw.y;
			if ((!st.count(nw))&&(CheckPos(nw))) {
				mp[nw] = mp[o]+KEY_LEFT;
				st.insert(nw); q.push(nw);
			}
			nw=o; ++nw.y;
			if ((!st.count(nw))&&(CheckPos(nw))) {
				mp[nw] = mp[o]+KEY_RIGHT;
				st.insert(nw); q.push(nw);
			}
			for (int i=0; i<4; ++i) {
				if (i==o.d) continue;
				int beg=o.d; if (beg&1) beg^=2;
				int en=i; if (i&1) en^=2;
				char ch = KEY_180;
				if (i==((o.d+1)&3)) ch=KEY_CW;
				if (i==((o.d+3)&3)) ch=KEY_CCW;
				for (pair<int,int> KT : Kick[p][beg][en]) {
					nw=o; nw.d=i; nw.x+=KT.second; nw.y+=KT.first;
					if (CheckPos(nw)) {
						if (!st.count(nw)) {
							mp[nw] = mp[o]+ch;
							st.insert(nw); q.push(nw);
						}
						break;
					}
				}
			}
		}
	}
	void AddGarbage(int x, int pos) {
		for (int i=LX; i>x; --i) {
			for (int j=1; j<=LY; ++j) {
				B[i][j]=B[i-x][j]; C[i][j]=C[i-x][j]; LE[i][j]=LE[i-x][j];
			}
		}
		for (int i=1; i<=min(x,LX); ++i) {
			for (int j=1; j<=LY; ++j) {
				C[i][j]=0; B[i][j]=54*(j!=pos);
				if (B[i][j]) LE[i][j]=20000;
				else LE[i][j]=0;
			}
		}
	}
	void ClearAll(int seed, bool Over=true) {
		for (int i=1; i<=LX; ++i) {
			for (int j=1; j<=LY; ++j) {
				double dx=sz*double(DX-i)+sz*0.5, dy=sz*double(j-1)+sz*0.5;
				if (B[i][j]) {
					if (Over) {
						double vx = -0.7+0.2*(rnd(10000)*0.0001);
						double vy = 0.2*(rnd(10000)*0.0001-0.5);
						double theta = acos(-1.0)*rndf();
						PQu.push_back({dx,dy,vx,vy,0.001,0,sz*0.5,0.002,theta,4,Mix(Piece[B[i][j]][0].clr,0xFFFFFF,0.7)});
						PQu.push_back({dx,dy,vx,vy,0.001,0,sz*0.5*0.7,0.002,theta,4,Mix(Piece[B[i][j]][0].clr,0xFFFFFF,0.5)});
						PQu.push_back({dx,dy,vx,vy,0.001,0,sz*0.5*0.5,0.002,theta,4,Mix(Piece[B[i][j]][0].clr,0xFFFFFF,0.7)});
					}
				}
				B[i][j]=C[i][j]=0;
				if ((!Over)&&(i<=DX)&&(!rnd(3))) PQu.push_back({dx,dy,-0.7+0.2*(rnd(10000)*0.0001),0.2*(rnd(10000)*0.0001-0.5),0.003,0,sz*0.1,0.0005,rnd(10000)*0.0002*acos(-1.0),8,0xFDD000});
			}
		}
		Combo=B2B=LastGarb=ComboTm=B2BTm=ComboType=B2BType=0;
		SumPiece=SumLine=SumAttack=SumDig=KO=SKO=0;
		while (Rec.size()) Rec.pop_front();
		while (ActiveGarb.size()) ActiveGarb.pop_front();
		while (Atk.size()) Atk.pop();
		gen = mt19937(seed);
		vector<int> vec; Next.clear(); Hold=Spin=0;
		for (int i=1; i<=PieceCnt; ++i) vec.push_back(i);
		shuffle(vec.begin(), vec.end(), gen);
		for (int i : vec) Next.push_back(i);
		Oper.clear();
		DropTime=0; ResetRem=ResetLim; MiniSpin=false;
		begtm = clock();
	}
	void Victory() {
		double asz = sz*0.12*double(LY);
		TQu.push_back({sz*0.5*double(DX)-asz*1.5,sz*0.5*double(LY)-asz*0.7,asz,0.25,0.0001,"VICTORY",0xFFA500}); 
		TQu.push_back({sz*0.5*double(DX)-asz*1.5,sz*0.5*double(LY)-asz*0.7,asz,0.1,0.00005,"VICTORY",0xFFE211});
		sprintf(buf, "%d Points", Wins);
		TQu.push_back({sz*0.5*double(DX),sz*0.5*double(LY)-asz*0.7,asz,0.2,0.0001,string(buf),0xFFFFFF});
		TQu.push_back({sz*0.5*double(DX),sz*0.5*double(LY)-asz*0.7,asz,0.1,0.00005,string(buf),0x0080FF});
	}
	#warning frame
	double MdRate = 0.0;
	deque<char> Oper; int D[99][99],G[99][99];
	void ScreenEffect(double ss, double de, int clr, int pp=1) {
		for (int i=1; i<=DX; ++i) {
			for (int j=1; j<=LY; ++j) {
				double dx=sz*double(DX-i)+sz*rndf(), dy=sz*double(j-1)+sz*rndf();
				if (!rnd(pp)) PQu.push_back({dx,dy,0.05,0,0,0,ss,de,rndf()*acos(-1.0),6,clr});
			}
		}
	}
	void LockEff(int clr, double ss, int n, double ve) {
		double dx=sz*double(DX-avx), dy=sz*double(avy-1);
		double th = rndf()*acos(-1.0)*2.0;
		for (int i=0; i<n; ++i) {
			th += acos(-1.0)*2.0/double(n);
			PQu.push_back({dx,dy,sin(th)*ve,cos(th)*ve,0,0,ss,0.006,rndf()*acos(-1.0)*2.0,5,clr});
		}
	} 
	int Frame(int tm, int tars, bool PermitAI=false) {
		if (Over) return 0;
		int totx=0, toty=0, tot=0;
		for (int i=1; i<=LX; ++i) {
			for (int j=1; j<=LY; ++j) {
				if (C[i][j]) {
					totx+=i; toty+=j; ++tot;
				}
			}
		}
		if (tot) {
			int avx = double(totx)/double(max(tot,1));
			int avy = double(toty)/double(max(tot,1));
			ravx = sz*double(DX-avx)+sz*0.5+KX;
			ravy = sz*double(avy-1)+sz*0.5+KY;
		}
		if (!Bot) DropTime+=tm;
		else OperDis+=tm;
		while (Next.size()<10) {
			vector<int> vec;
			for (int i=1; i<=PieceCnt; ++i) vec.push_back(i);
			shuffle(vec.begin(), vec.end(), gen);
			for (int i : vec) Next.push_back(i);
		}
		if (ActiveGarb.size()) {
			LastGarb += tm;
			if (LastGarb>GarbRise) {
				AddGarbage(1,ActiveGarb.front().second); MoveDown();
				if (!(--ActiveGarb.front().first)) ActiveGarb.pop_front();
				LastGarb = 0;
			}
		}
		else LastGarb=0;
		if (!CheckActive()) {
			HoldEnable=true; int Lines=RemoveLines();
			if ((Spin)||(MiniSpin)) {
				SpinType=Pid; SpinDis=0; SpinTm=15000; SpinFull=(Spin)?((SemiSpin)?1:2):0;
			}
			else if (Lines) SpinDis=1;
			SumLine += Lines;
			int Attack = (Lines>1)?(1<<Lines-2):0;
			if (Spin) Attack=Lines*2-int(SemiSpin*0);
			int ComboAttack=0, Surge=0;
			bool AC=bool(Lines), HAC=bool(Lines)&&(!Dig);
			for (int i=1; i<=LX; ++i) {
				for (int j=1; j<=LY; ++j) {
					if (B[i][j]) {
						AC=false; if (B[i][j]!=54) HAC=false;
					}
				}
			}
			if (Lines) {
				++Combo; ClearType=Lines; ClearTm=10000;
				if (Spin) ClearColor=Pid;
				else ClearColor=0;
				if (Combo>1) {
					ComboType=Combo-1; ComboTm=10000;
				}
				if (Combo>1) ++ComboAttack;
				if (Combo>4) ++ComboAttack;
				if (Combo>6) ++ComboAttack;
				if (Combo>8) ++ComboAttack;
				if (Combo>11) ++ComboAttack;
				if (Combo>1) LockEff(0x39C5BB,sz*0.15,3+min(35,Combo-2),0.03);
				if ((Spin)||(Lines>3)||(MiniSpin)||(AC)||(HAC)) {
					++B2B; if ((AC)||(HAC)) ++B2B;
					if (B2B>1) {
						B2BType=B2B-1; B2BTm=10000; 
					}
					if ((Spin)||(Lines>3)||(MiniSpin)) {
						if (B2B>1) ++Attack;
						if (B2B>3) ++Attack;
						if (B2B>8) ++Attack;
						if (B2B>24) ++Attack;
						if (B2B>67) ++Attack;
					}
					int clr=0xF3BDBD;
					if (B2B>1) clr=0xFFE211;
					if (B2B>4) clr=0x00FFCC;
					LockEff(clr, (B2B>1)?sz*0.25:sz*0.15, (B2B>1)?(3+min(35,B2B-2)):2, 0.04);
				}
				else {
					Surge=max(0,B2B-1); B2B=0;
				}
			}
			else Combo=ComboType=0;
			if ((Spin)||(MiniSpin)||(Lines)) {
				FullLCW=""; FullTm=10000;
				if (B2B>1) FullLCW="B2B ";
				else if (Spin) FullLCW=FullLCW+PName[Pid]+"-Spin ";
				else if (MiniSpin) FullLCW=FullLCW+"Mini "+PName[Pid]+"-Spin ";
				if (Lines) FullLCW=FullLCW+SLCW[Lines];
				else if (FullLCW.size()) FullLCW.pop_back();
			}
			Attack = max(ComboAttack,Attack*(4+max(0,Combo-1))/4);
			if ((Dig)&&(B2B)) ++Attack;
			if (Surge) {
				B2BType=0; B2BTm=10000;
			}
			if (Surge>3) {
				Attack+=Surge; LockEff(0x00FFCC,sz*0.15,15,0.2);
			}
			else if (Surge) {
				LockEff(0xFF6666,sz*0.15,3,0.04); Surge=0;
			}
			if (AC) {
				ScreenEffect(sz*0.1,0.005,0xFFE211,3); Attack+=LY;
				double asz = sz*0.16*double(LY);
				TQu.push_back({sz*0.5*double(DX)-asz*1.5,sz*0.5*double(LY)-asz*0.7,asz,0.2,0.0002,"ALL",0xFDD000}); 
				TQu.push_back({sz*0.5*double(DX),sz*0.5*double(LY)-asz*0.7,asz,0.2,0.0002,"CLEAR",0xFDD000});
			}
			else if (HAC) {
				ScreenEffect(sz*0.05,0.005,0xFFE211,3); Attack+=(LY+1)/2;
				double asz = sz*0.16*double(LY);
				TQu.push_back({sz*0.5*double(DX)-asz*1.5,sz*0.5*double(LY)-asz*0.7,asz,0.2,0.0004,"HALF",0xFDD000}); 
				TQu.push_back({sz*0.5*double(DX),sz*0.5*double(LY)-asz*0.7,asz,0.2,0.0004,"CLEAR",0xFDD000});
			}
			if ((tars>1)&&(Lines)&&((Rec.size())||(ActiveGarb.size()))) {
				int add = (tars-1)*3/2;
				if (B2B) Attack+=add;
				else Attack+=add/2;
			}
			ll curtm = clock();
			int Mins = int((curtm-begtm)/30000LL);
			if ((Mins>=6)&&(Plrs>1)) Attack=Attack*min(15,Mins)/6;
			if (SKO==47) Attack+=ceil(Attack*0.2952*2);
			else if (SKO==94) Attack+=ceil(Attack*0.3321*2);
			else {
				int Bonus = 0;
				if (SKO>=2) ++Bonus;
				if (SKO>=4) ++Bonus;
				if (SKO>=8) ++Bonus;
				if (SKO>=16) ++Bonus;
				if (SKO>=32) ++Bonus;
				if (SKO>=64) ++Bonus;
				Attack += Attack*Bonus/10;
			}
			SumAttack += Attack;
			int Cancel = 0; 
			while ((ActiveGarb.size())&&(Attack)) {
				int val=min(Attack,ActiveGarb.front().first);
				Attack-=val; ActiveGarb.front().first-=val; Cancel+=val;
				if (!ActiveGarb.front().first) ActiveGarb.pop_front();
			}
			while ((Rec.size())&&(Attack)) {
				int val=min(Attack,Rec.front().first); Attack-=val; Cancel+=val;
				Rec.front().first-=val; if (!Rec.front().first) Rec.pop_front();
			}
			if (Cancel) {
				sprintf(buf, "%d", Cancel);
				double px=sz*(DX-avx), py=sz*avy, rat=min(10.0,1.0+double(Cancel-1)*0.1);
				double th=rndf()*acos(-1.0)*2.0; px+=sin(th)*sz*3.0; py+=cos(th)*sz*3.0;
				int clr = 0x888888;
				if (Surge) clr=0x00FFCC;
				else if ((Spin)||(MiniSpin)) clr=Piece[Pid][0].clr;
				else if (Combo>1) clr=0x39C5BB;
				TQu.push_back((FloatText){px,py,sz*rat,0.4,0.0011/min(3.0,rat),string(buf),clr});
				TQu.push_back((FloatText){px,py,sz*rat,0.3,0.001/min(3.0,rat),string(buf),0xFFFFFF});
			}
			if (Attack) {
				sprintf(buf, "%d", Attack);
				double px=sz*(DX-avx), py=sz*avy, rat=min(10.0,1.0+double(Attack-1)*0.1);
				double th=rndf()*acos(-1.0)*2.0; px+=sin(th)*sz*3.0; py+=cos(th)*sz*3.0;
				int clr = 0x888888;
				if (Surge) clr=0x00FFCC;
				else if ((Spin)||(MiniSpin)) clr=Piece[Pid][0].clr;
				else if (Combo>1) clr=0x39C5BB;
				TQu.push_back((FloatText){px,py,sz*rat,0.4,0.0011/min(3.0,rat),string(buf),(B2B>1)?0xFDD000:0xFFFFFF});
				TQu.push_back((FloatText){px,py,sz*rat,0.3,0.001/min(3.0,rat),string(buf),clr});
			}
			if (Attack) Atk.push(Attack);
			if (!Lines) {
				int rem = GarbageGap;
				while ((Rec.size())&&(Rec.front().second.second+ll(GarbDelay)<curtm)&&(rem)) {
					int val = min(rem,Rec.front().first);
					rem -= val;
					if (GarbRise) ActiveGarb.push_back(make_pair(val,Rec.front().second.first));
					else AddGarbage(val, Rec.front().second.first);
					Rec.front().first-=val; if (!Rec.front().first) Rec.pop_front();
				}
			}
			bool suc = Spawn(Next.front(),0);
			int seed = time(0);
			if (suc) Next.pop_front();
			else {
				while (Atk.size()) Atk.pop();
				while (Rec.size()) Rec.pop_front();
				Over = true;
				return seed;
				ClearAll(seed);
				return seed;
			}
			DropTime=0; ResetRem=ResetLim;
			if (!suc) return seed;
		}
		if ((Bot)&&(CheckActive())&&(Oper.empty())&&(PermitAI)) {
			st.clear(); mp.clear();
			int fx=0, fy=0;
			for (int i=1; i<=LX; ++i) {
				for (int j=1; j<=LY; ++j) {
					if (C[i][j]) {
						fx=i; fy=j; break;
					}
				}
				if (fx) break;
			}
			bfs(Pid, 0, fx-Piece[Pid][0].FstX, fy-Piece[Pid][0].FstY);
			int pp = (Hold)?Hold:Next.front();
			int SX=DX-1+Piece[pp][0].SDel, SY=(LY-Piece[pp][0].LY)/2+1;
			SY = max(1,min(LY-Piece[pp][0].LY+1,SY));
			SX = max(1,min(LX,SX));
			if ((Pid!=pp)&&(HoldEnable)) bfs(pp,0,SX,SY);
			string rstr; int MaxEval=-1000000000; ClassSta best;
			for (ClassSta o : st) {
				if (st.count((ClassSta){o.p,o.d,o.x-1,o.y})) continue;
				int Height = 0;
				for (int i=1; i<=LX; ++i) {
					for (int j=1; j<=LY; ++j) {
						D[i][j]=((B[i][j])&&(!C[i][j])); if (D[i][j]) Height=i; 
					}
				}
				for (int i=0; i<Piece[o.p][o.d].LX; ++i) {
					for (int j=0; j<Piece[o.p][o.d].LY; ++j) {
						if (Piece[o.p][o.d].B[i][j]) {
							D[o.x+i][o.y+j]=2; Height=max(Height,o.x+i);
						}
					}
				}
				bool sU=false, sD=false, sL=false, sR=false;
				for (int i=1; i<=LX; ++i) {
					for (int j=1; j<=LY; ++j) {
						if (D[i][j]!=2) continue;
						if ((i==1)||(D[i-1][j]==1)) sD=true;
						if ((i==LX)||(D[i+1][j]==1)) sU=true;
						if ((j==1)||(D[i][j-1]==1)) sL=true;
						if ((j==LY)||(D[i][j+1]==1)) sR=true;
					}
				}
				#warning eval
				int Eval = 0;
				if ((Plr==2&&0)&&(Height+8<DX)) {
					bool ff = false;
					int mx=0, bel=1;
					for (int j=1; j<=LY; ++j) {
						int cnt = 0;
						for (int i=1; i<=LX; ++i) {
							if (!B[i][j]) ++cnt;
						}
						if (cnt>=mx) {
							mx=cnt; bel=j;
						}
					}
					for (int i=1; i<=LX; ++i) {
						for (int j=1; j<=LY; ++j) {
							if ((D[i][j]==2)&&(j==bel)) ff=true;
						}
					}
					if (ff) Eval-=10;
				}
				for (int i=1; i<=LY; ++i) G[LX+1][i]=1;
				for (int i=LX; i; --i) {
					for (int j=1; j<=LY; ++j) {
						if (D[i][j]) G[i][j]=0;
						else G[i][j]=G[i+1][j];
					}
					for (int j=2; j<=LY; ++j) {
						if (!D[i][j]) G[i][j]|=G[i][j-1];
					}
					for (int j=LY-1; j; --j) {
						if (!D[i][j]) G[i][j]|=G[i][j+1];
					}
				}
				int Land=0, Lines=0, Ero=0, pn=0;
				for (int i=1; i<=LX; ++i) {
					bool ok=true; int ins=0;
					for (int j=1; j<=LY; ++j) {
						if (!D[i][j]) ok=false;
						if (D[i][j]==2) {
							++ins; Land=i;
						}
					}
					if (ok) {
						++Lines; Ero+=ins;
					}
					else {
						++pn; for (int j=1; j<=LY; ++j) D[pn][j]=D[i][j];
					}
				}
				bool Alt = ((Plr==2||Plr==3)&&(Height+8<DX));
				int GarC = 0;
				for (int i=1; i<=LX; ++i) {
					for (int j=1; j<=LY; ++j) {
						if (B[i][j]==54) {
							++GarC; break;
						}
					}
				}
				//if (GarC>5) Alt=false;
				for (int i=pn+1; i<=LX; ++i) {
					for (int j=1; j<=LY; ++j) D[i][j]=0;
				}
				Eval += Ero*Lines-Land;
				for (int i=1; i<=LY; ++i) D[0][i]=1;
				for (int i=1; i<=LX; ++i) D[i][0]=D[i][LY+1]=1;
				int Bubble = 0;
				for (int i=2; i<=LX; ++i) {
					for (int j=1; j<=LY; ++j) {
						if ((D[i][j])&&(!D[i][j-1])&&(!G[i][j-1])) ++Bubble;
					}
				}
				if ((Plr==3)&&(Height+12<DX)) Eval-=Bubble;
				if ((sU*sD*sL*sR)||(Lines>=4)) Eval+=Lines*((Combo<1&&Lines==1)?15:15);
				else {
					bool ok = true;
					/*for (int i=1; i<=LX; ++i) {
						for (int j=1; j<=LY; ++j) {
							if (D[i][j]!=2) continue;
							if (int(D[i-1][j]==2)+int(D[i+1][j]==2)+int(D[i][j-1]==2)+int(D[i][j+1]==2)<2) continue;
							if (int(D[i-1][j-1]==1)+int(D[i+1][j-1]==1)+int(D[i-1][j+1]==1)+int(D[i+1][j+1]==1)<3) ok=false;
						}
					}*/
					if (ok) Eval+=Lines*0;
					else if (Combo<2) {
						if (Height+12<DX) Eval-=Ero*Lines/((Bubble)?3:1);
					}
				}
				for (int i=1; i<=LY; ++i) D[0][i]=3;
				int BRC = 2;//(GarC<2)?5:1;
				if (Bubble) BRC=1;
				if (Bubble>1) BRC=0;
				if (Plr==2) BRC=1;
				int BRem=BRC, LstIso=0;
				for (int i=LX; i; --i) {
					D[i][0]=D[i][LY+1]=3;
					int UseB=0, Tot=0; bool Iso=false; int Sep=0;
					for (int j=1; j<=LY; ++j) {
						if ((!D[i][j])&&(D[i+1][j])&&(!G[i][j])) BRem=0;
						if (D[i][j]) ++Tot;
						if ((!D[i][j])&&((j==1)||(D[i][j-1]))&&((j==LY)||(D[i][j+1]))) Iso=true;
						if ((!D[i][j])&&((j==1)||(D[i][j-1]))) ++Sep;
					}
					if (Tot+2>LY) BRem=0;
					for (int j=1; j<=LY; ++j) {
						if ((!D[i][j])&&(D[i+1][j])) {
							if ((G[i][j])&&(Alt)&&((i<2)||(D[i-1][j]))&&(BRem)) ++UseB;
							Eval -= 4;
						}
						if (bool(D[i][j])!=bool(D[i-1][j])) --Eval;
						if (bool(D[i][j])!=bool(D[i][j-1])) --Eval;
						if ((!D[i][j])&&((D[i][j+1])&&(D[i][j-1]))) --Eval;
					}
					if ((Iso)&&(LstIso)&&(Alt)&&(Plr==3)) Eval-=((BRC)?3:1);
					LstIso = Iso;
					if (UseB==1) Eval+=12;
					if (UseB>1) BRem=0;
					if (!D[i][LY]) --Eval;
					if (UseB) --BRem;
					if ((Iso)||(Sep>1)) BRem=0;
					if ((!UseB)&&(BRem<BRC)) BRem=0;
				}
				Eval *= 100;
				Eval += 10*abs(fy-Piece[Pid][0].FstY-o.y);
				Eval += (fy-Piece[Pid][0].FstY>o.y);
				if (Eval>MaxEval) {
					MaxEval=Eval; rstr=mp[o]; best=o;
				}
			}
			Oper.clear(); if (best.p!=Pid) Oper.push_back(KEY_HOLD);
			for (char ch : rstr) Oper.push_back(ch);
			if ((Oper.size())&&(double(rnd(1<<30)+1)/double(1<<30)<MdRate)) {
				int type = rnd(3);
				if (!type) {
					deque<char> NwOper;
					for(char c:Oper) if(rng()&1) NwOper.push_back(c);
					Oper = NwOper;
				}
				else if (type==1) Oper.resize(rnd(Oper.size()));
				else shuffle(Oper.begin(),Oper.end(),rng);
			}
			Oper.push_back(KEY_HARD);
			//printf("*%d %d %d %d\n",best.p,best.d,best.x,best.y);
		}
		vector<char> chs = GetKey(tm);
		if ((Oper.size())&&(OperTime<=OperDis)) {
			OperDis = 0;
			bool tp = (Oper.front()==KEY_DOWN);
			chs.push_back(Oper.front()); Oper.pop_front();
			if (tp) {
				while ((Oper.size())&&(Oper.front()==KEY_DOWN)) {
					chs.push_back(Oper.front()); Oper.pop_front();
				}
			}
		}
		if (CheckActive()) {
			bool ckd = CheckDown();
			bool rsl = false;
			for (char ch : chs) {
				if (ch==KEY_LEFT) {
					rsl|=MoveLeft();
					if ((!ARR)&&(!Bot)&&(KeyDas[ch])) {
						if ((!SDARR)&&(KeyDas[KEY_DOWN])) {
							while (MoveDown());
						}
						while (MoveLeft()) {
							if ((!SDARR)&&(KeyDas[KEY_DOWN])) {
								while (MoveDown());
							}
						}
					}
				}
				if (ch==KEY_RIGHT) {
					rsl|=MoveRight();
					if ((!ARR)&&(!Bot)&&(KeyDas[ch])) {
						if ((!SDARR)&&(KeyDas[KEY_DOWN])) {
							while (MoveDown());
						}
						while (MoveRight()) {
							if ((!SDARR)&&(KeyDas[KEY_DOWN])) {
								while (MoveDown());
							}
						}
					}
				}
				if (ch==KEY_CW) rsl|=Rotate((Dir+1)&3);
				if (ch==KEY_CCW) rsl|=Rotate((Dir+3)&3);
				if (ch==KEY_180) rsl|=Rotate((Dir+2)&3);
				if (ch==KEY_ROT) rsl|=Rotate((Dir+RotType)&3);
				if (ch==KEY_DOWN) {
					if ((KeyDas[KEY_DOWN])&&(!Bot)) {
						if (ckd) {
							if (SDARR) DropTime+=DropL*double(tm)/double(SDARR);
							else {
								while (CheckDown()) MoveDown();
							}
						}
					}
					else MoveDown();
				}
				if (ch==KEY_HARD) HardDrop();
				if (ch==KEY_HOLD) {
					if (!HoldEnable) continue;
					if (Hold) {
						int tmp = Pid;
						Spawn(Hold, 0);
						Hold = tmp;
					}
					else {
						int tmp = Pid;
						Spawn(Next.front(),0); Next.pop_front();
						Hold = tmp;
					}
					HoldEnable = false;
					DropTime=0; ResetRem=ResetLim;
				}
				if (ch==KEY_EVEN) AtkType=1;
				if (ch==KEY_KO) AtkType=2;
				if (ch==KEY_RANDOM) AtkType=3;
				if (ch==KEY_PAYBACK) AtkType=4;
				if (ch==KEY_BADGE) AtkType=5;
				if (ch==KEY_ATTACKERS) AtkType=6;
			}
			if ((CheckActive())&&(!Bot)) {
				bool nckd = CheckDown();
				if ((ckd)&&(nckd)) rsl=false;
				if ((DropTime)&&(rsl)&&(ResetRem>0)) {
					DropTime=0; --ResetRem;
				}
				if (nckd) {
					if (!DropL) {
						while (CheckDown()) MoveDown();
						if (ResetRem>0) DropTime=0;
					}
					else if (DropTime>=DropL) {
						while (DropTime>=DropL) {
							if (!CheckDown()) {
								if (ResetRem>0) DropTime=0;
								break;
							}
							if (ResetRem>0) DropTime-=DropL;
							MoveDown();
						}
						if (ResetRem>0) DropTime%=DropL;
					}
				}
				else if ((DropTime>LockL)&&(!Bot)) Lock();
			}
		}
		//Paint(tm);
		return 0;
	}
} ;//P1(1,40,10,22,0.0,0.0,true,20), P2(1,40,10,22,0.0,500.0,true,20);
Board Plr[100];
int Tar[999], curh[999]; bool KOCount[999];
#warning main
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow) {
	WNDCLASS wc;
	HWND hWnd;
	HDC hDC;
	HGLRC hRC;		
	MSG msg;
	BOOL bQuit = FALSE;
	wc.style = CS_OWNDC;
	wc.lpfnWndProc = WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = HBRUSH(GetStockObject (BLACK_BRUSH));
	wc.lpszMenuName = NULL;
	wc.lpszClassName = "GLSample";
	RegisterClass(&wc);
	//hWnd = GetConsoleWindow();
	hWnd = CreateWindow("GLSample", "", WS_CAPTION|WS_POPUPWINDOW|WS_VISIBLE, 0, 0, 1500, 1000, NULL, NULL, hInstance, NULL);
	EnableOpenGL(hWnd, &hDC, &hRC);
	InitChar();
	Piece[1][0] = ClassPiece(4,4,0x66CCFF,-1,{{0,0,0,0},{1,1,1,1},{0,0,0,0},{0,0,0,0}});
	Piece[1][1] = ClassPiece(4,4,0x66CCFF,-1,{{0,0,1,0},{0,0,1,0},{0,0,1,0},{0,0,1,0}});
	Piece[1][2] = ClassPiece(4,4,0x66CCFF,-1,{{0,0,0,0},{0,0,0,0},{1,1,1,1},{0,0,0,0}});
	Piece[1][3] = ClassPiece(4,4,0x66CCFF,-1,{{0,1,0,0},{0,1,0,0},{0,1,0,0},{0,1,0,0}});
	Piece[2][0] = ClassPiece(3,3,0x0080FF,-1,{{1,0,0},{1,1,1},{0,0,0}});
	Piece[2][1] = ClassPiece(3,3,0x0080FF,-1,{{0,1,1},{0,1,0},{0,1,0}});
	Piece[2][2] = ClassPiece(3,3,0x0080FF,-1,{{0,0,0},{1,1,1},{0,0,1}});
	Piece[2][3] = ClassPiece(3,3,0x0080FF,-1,{{0,1,0},{0,1,0},{1,1,0}});
	Piece[3][0] = ClassPiece(3,3,0xFFA500,-1,{{0,0,1},{1,1,1},{0,0,0}});
	Piece[3][1] = ClassPiece(3,3,0xFFA500,-1,{{0,1,0},{0,1,0},{0,1,1}});
	Piece[3][2] = ClassPiece(3,3,0xFFA500,-1,{{0,0,0},{1,1,1},{1,0,0}});
	Piece[3][3] = ClassPiece(3,3,0xFFA500,-1,{{1,1,0},{0,1,0},{0,1,0}});
	Piece[4][0] = ClassPiece(3,3,0xFFE211,-1,{{0,1,1},{0,1,1},{0,0,0}});
	Piece[4][1] = ClassPiece(3,3,0xFFE211,-1,{{0,0,0},{0,1,1},{0,1,1}});
	Piece[4][2] = ClassPiece(3,3,0xFFE211,-1,{{0,0,0},{1,1,0},{1,1,0}});
	Piece[4][3] = ClassPiece(3,3,0xFFE211,-1,{{1,1,0},{1,1,0},{0,0,0}});
	Piece[5][0] = ClassPiece(3,3,0x33EE00,-1,{{0,1,1},{1,1,0},{0,0,0}});
	Piece[5][1] = ClassPiece(3,3,0x33EE00,-1,{{0,1,0},{0,1,1},{0,0,1}});
	Piece[5][2] = ClassPiece(3,3,0x33EE00,-1,{{0,0,0},{0,1,1},{1,1,0}});
	Piece[5][3] = ClassPiece(3,3,0x33EE00,-1,{{1,0,0},{1,1,0},{0,1,0}});
	Piece[6][0] = ClassPiece(3,3,0xEE82EE,-1,{{0,1,0},{1,1,1},{0,0,0}});
	Piece[6][1] = ClassPiece(3,3,0xEE82EE,-1,{{0,1,0},{0,1,1},{0,1,0}});
	Piece[6][2] = ClassPiece(3,3,0xEE82EE,-1,{{0,0,0},{1,1,1},{0,1,0}});
	Piece[6][3] = ClassPiece(3,3,0xEE82EE,-1,{{0,1,0},{1,1,0},{0,1,0}});
	Piece[7][0] = ClassPiece(3,3,0xEE0000,-1,{{1,1,0},{0,1,1},{0,0,0}});
	Piece[7][1] = ClassPiece(3,3,0xEE0000,-1,{{0,0,1},{0,1,1},{0,1,0}});
	Piece[7][2] = ClassPiece(3,3,0xEE0000,-1,{{0,0,0},{1,1,0},{0,1,1}});
	Piece[7][3] = ClassPiece(3,3,0xEE0000,-1,{{0,1,0},{1,1,0},{1,0,0}});
	Piece[54][0] = ClassPiece(1,1,0x888888,-1,{{1}});
	Piece[54][1] = ClassPiece(1,1,0x888888,-1,{{1}});
	Piece[54][2] = ClassPiece(1,1,0x888888,-1,{{1}});
	Piece[54][3] = ClassPiece(1,1,0x888888,-1,{{1}});
	for (int i=0; i<4; ++i) {
		for (int j=0; j<4; ++j) {
			Kick[1][0][3]={{0,0},{-2,0},{+1,0},{-2,-1},{+1,+2}};
			Kick[1][3][0]={{0,0},{+2,0},{-1,0},{+2,+1},{-1,-2}};
			Kick[1][3][2]={{0,0},{-1,0},{+2,0},{-1,+2},{+2,-1}};
			Kick[1][2][3]={{0,0},{+1,0},{-2,0},{+1,-2},{-2,+1}};
			Kick[1][2][1]={{0,0},{+2,0},{-1,0},{+2,+1},{-1,-2}};
			Kick[1][1][2]={{0,0},{-2,0},{+1,0},{-2,-1},{+1,+2}};
			Kick[1][1][0]={{0,0},{+1,0},{-2,0},{+1,-2},{-2,+1}};
			Kick[1][0][1]={{0,0},{-1,0},{+2,0},{-1,+2},{+2,-1}};
			Kick[1][0][2]={{0,0},{0,+1},{+1,+1},{-1,+1},{+1,0},{-1,0}};
			Kick[1][2][0]={{0,0},{0,-1},{-1,-1},{+1,-1},{-1,0},{+1,0}};
			Kick[1][1][3]={{0,0},{-1,0},{-1,+2},{-1,+1},{0,+2},{0,+1}};
			Kick[1][3][1]={{0,0},{+1,0},{+1,+2},{+1,+1},{0,+2},{0,+1}};
			for (int o=2; o<55; ++o) {
				Kick[o][0][3]={{0,0},{-1,0},{-1,+1},{0,-2},{-1,-2}};
				Kick[o][3][0]={{0,0},{+1,0},{+1,-1},{0,+2},{+1,+2}};
				Kick[o][3][2]={{0,0},{+1,0},{+1,-1},{0,+2},{+1,+2}};
				Kick[o][2][3]={{0,0},{-1,0},{-1,+1},{0,-2},{-1,-2}};
				Kick[o][2][1]={{0,0},{+1,0},{+1,+1},{0,-2},{+1,-2}};
				Kick[o][1][2]={{0,0},{-1,0},{-1,-1},{0,+2},{-1,+2}};
				Kick[o][1][0]={{0,0},{-1,0},{-1,-1},{0,+2},{-1,+2}};
				Kick[o][0][1]={{0,0},{+1,0},{+1,+1},{0,-2},{+1,-2}};
				Kick[o][0][2]={{0,0},{0,+1},{+1,+1},{-1,+1},{+1,0},{-1,0}};
				Kick[o][2][0]={{0,0},{0,-1},{-1,-1},{+1,-1},{-1,0},{+1,0}};
				Kick[o][1][3]={{0,0},{-1,0},{-1,+2},{-1,+1},{0,+2},{0,+1}};
				Kick[o][3][1]={{0,0},{+1,0},{+1,+2},{+1,+1},{0,+2},{0,+1}};
			}
		}
	}
	vector<pair<int,int> > CCW={{0,0},{0,-1},{1,0},{1,-1},{0,-2},{1,-2},{2,0},{2,-1},{2,-2},{-1,0},{-1,-1},{0,1},{1,1},{2,1},{-1,-2},{-2,0},{0,2},{1,2},{2,2},{-2,-1},{-2,-2},{-1,1}}, CW, FLIP;
	for (pair<int,int>p:CCW) CW.push_back(make_pair(-p.first,p.second));
	for (int i=0; i<CW.size(); ++i){
		FLIP.push_back(CCW[i]); FLIP.push_back(CW[i]);
	}
	for (int i=0; i<4; ++i) {
		for (int j=0; j<4; ++j) {
			for (int o=1; o<0; ++o) {
				if (j==((i+1)&3)) Kick[o][i][j]=CCW;
				if (j==((i+2)&3)) Kick[o][i][j]=FLIP;
				if (j==((i+3)&3)) Kick[o][i][j]=CW;
			}
		}
	}
	#warning plr
	double bsz = 20.0;
	Plrs = 100;
	for (int i=0; i+1<Plrs; ++i) {
		Plr[i] = Board(i%3+1,26,10,22,0.0,0.0,true,10);
		Plr[i].Ssz=Plr[i].sz=Plr[i].isz=bsz/5;
		Plr[i].KX = 110.0*(i/11)-80;
		Plr[i].KY = 90.0*(i%11)+450;
		Tar[i] = -1;
		Plr[i].MdRate = 0.03*(double(rnd(1<<30))/double(1<<30));
		Plr[i].AtkType = rnd(6)+1;
	}
	Plr[Plrs-1]=Board(2,26,10,22,0.0,100.0); Plr[Plrs-1].AtkType=1;
	//Plrs=2; Plr[0]=Board(1,40,10,22,0.0,100.0,true,5); Plr[1]=Board(3,40,10,22,0.0,600.0,true,5);Plr[0].MdRate=Plr[1].MdRate=0;
	//Plr[1].MdRate = 0.05;
	//Plr[0].MdRate=0.02,Plr[1].MdRate=0.002;
	//Plrs=1; Plr[0]=Board(3,40,10,22,0.0,400.0,true); Plr[0].MdRate=0;
	ll CurT = clock();
	bool ObserveAI=1; int PaintTm=0, Obs=-1;
	int PrevPlrs = Plrs;
	int ClearOnDuel = 1;
	while (!bQuit) {
		if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
			if (msg.message==WM_QUIT) bQuit=true;
			else {
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}
		else {
			for (int i=0; i<Plrs; ++i) Plr[i].BeFrom=Plr[i].BeTo=false;
			if ((PlrsCnt>2)&&(Obs>=0)) {
				if (Tar[Obs]>=0) Plr[Tar[Obs]].BeTo=true;
				for (int i=0; i<Plrs; ++i) {
					if (Tar[i]==Obs) Plr[i].BeFrom=true;
				}
			}
			if ((Obs>=0)&&(Plr[Obs].Over)) {
				if (!Plr[Plr[Obs].LstAtk].Over) Obs=Plr[Obs].LstAtk;
				else Obs=-1;
			}
			if (Obs<0) {
				for (int i=0; i<Plrs; ++i) {
					if ((!Plr[i].Bot)&&(!Plr[i].Over)) {
						if (Obs<0) Obs=i;
					}
				}
				for (int i=0; i<Plrs; ++i) {
					if ((Plr[i].Bot)&&(!Plr[i].Over)) {
						if (Obs<0) Obs=i;
					}
				}
			}
			vector<int> PlrOrd;
			for (int i=0; i<Plrs; ++i) {
				if ((!Plr[i].Bot)&&(!Plr[i].Over)) PlrOrd.push_back(i);
			}
			for (int i=0; i<Plrs; ++i) {
				if ((Plr[i].Bot)&&(!Plr[i].Over)) PlrOrd.push_back(i);
			}
			if (PlrOrd.size()==1) {
				Plr[PlrOrd[0]].SKX=0; Plr[PlrOrd[0]].SKY=400; Plr[PlrOrd[0]].Ssz=bsz;
			}
			else if (PlrOrd.size()==2) {
				if (PlrOrd[0]!=Obs) swap(PlrOrd[0],PlrOrd[1]);
				Plr[PlrOrd[0]].SKX=0; Plr[PlrOrd[0]].SKY=100; Plr[PlrOrd[0]].Ssz=bsz;
				Plr[PlrOrd[1]].SKX=0; Plr[PlrOrd[1]].SKY=600; Plr[PlrOrd[1]].Ssz=bsz;
			}
			else if (PlrOrd.size()>2){
				int pos = 0;
				for (int i : PlrOrd) {
					if (Obs==i) {
						Plr[i].SKX=0; Plr[i].SKY=100; Plr[i].Ssz=bsz;
						continue;
					}
					Plr[i].SKX=110*(pos/11)-80; Plr[i].SKY=90*(pos%11)+450; Plr[i].Ssz=bsz/5;
					++pos;
				}
			}
			PlrsCnt = 0;
			for (int i=0; i<Plrs; ++i) {
				PlrsCnt+=(!Plr[i].Over); if (Plr[i].Over) continue;
				Plr[i].VSRnk = 1;
				for (int j=0; j<Plrs; ++j) {
					if ((make_pair(Plr[j].SumAttack+Plr[j].SumDig,j)>make_pair(Plr[i].SumAttack+Plr[i].SumDig,i))&&(!Plr[j].Over)) ++Plr[i].VSRnk;
				}
			}
			if ((Plrs>2)&&(PrevPlrs>2)&&(PlrsCnt==2)&&(ClearOnDuel)) {
				int seed = time(0);
				for (int i=0; i<Plrs; ++i) {
					if (Plr[i].Over) continue;
					for (int j=1; j<=Plr[i].LX; ++j) {
						for (int k=1; k<=Plr[i].LY; ++k) {
							Plr[i].B[j][k]=Plr[i].C[j][k]=0;
						}
					}
					Plr[i].Hold=0; Plr[i].Next.clear(); Plr[i].gen=mt19937(seed);
				}
			}
			PrevPlrs = PlrsCnt;
			ll NewT=clock(); int del=int(NewT-CurT);
			CurT=NewT; PaintTm+=del;
			int AILim = 15;
			vector<int> Bot;
			for (int i=0; i<Plrs; ++i) {
				int tars=0; for (int j=0; j<Plrs; ++j) tars+=((Tar[j]==i)&&(!Plr[j].Over));
				if (Plr[i].Bot) Bot.push_back(i);
				else Plr[i].Frame(del,tars);
			}
			shuffle(Bot.begin(), Bot.end(), rng);	
			AILim = min(AILim,int(Bot.size()));
			for (int i=0; i<Plrs; ++i) {
				if (!Plr[i].Bot) continue;
				bool ok = false;
				for (int j=0; j<AILim; ++j) {
					if (Bot[j]==i) ok=true;
				}
				int tars=0; for (int j=0; j<Plrs; ++j) tars+=((Tar[j]==i)&&(!Plr[j].Over));
				Plr[i].Frame(del, tars, ok);
			}
			for (int i=0; i<Plrs; ++i) curh[i]=Plr[i].QueryHeight();
			for (int i=0; i<Plrs; ++i) {
				if (rnd(20000)<del) Tar[i]=-1;
				if (Plr[i].AtkType==6) {
					bool ok = false;
					for (int j=0; j<Plrs; ++j) {
						if ((!Plr[j].Over)&&(j!=i)&&(Tar[j]==i)) ok=true;
					}
					if (ok) Tar[i]=-1;
				}
				if (((Tar[i]<0)||(Plr[Tar[i]].Over))&&(PlrsCnt>1)) {
					vector<int> TarList;
					for (int j=0; j<Plrs; ++j) {
						if (i==j) continue;
						if (!Plr[j].Over) TarList.push_back(j);
					}
					Tar[i] = -1;
					if (TarList.size()) {
						shuffle(TarList.begin(), TarList.end(), rng);
						if (Plr[i].AtkType==3) Tar[i]=TarList[0];
						else if (Plr[i].AtkType==4) {
							if ((Plr[i].LstAtk>=0)&&(!Plr[Plr[i].LstAtk].Over)) Tar[i]=Plr[i].LstAtk;
							else Tar[i]=TarList[0];
						}
						else if (Plr[i].AtkType==6) {
							vector<int> lst;
							for (int j : TarList) {
								if (Tar[j]==i) lst.push_back(j);
							}
							if (lst.size()) Tar[i]=lst[rnd(lst.size())];
							else Tar[i]=TarList[0];
						}
						else {
							vector<pair<int,int> > lst;
							for (int i : TarList) {
								int val = 0;
								if (Plr[i].AtkType==1) val=-curh[i];
								else if (Plr[i].AtkType==2) val=curh[i];
								else val=Plr[i].SKO;
								lst.push_back(make_pair(val,i));
							}
							vector<int> pool;
							for (int i=0; i<min(10,int(TarList.size())); ++i) {
								for (int j=i; j<10; ++j) pool.push_back(lst[i].second);
							}
							Tar[i] = pool[rnd(pool.size())];
						}
					}
				}
				while (Plr[i].Atk.size()) {
					int nw = Plr[i].Atk.front();
					int tar=Tar[i]; ll curtm=clock();
					if (tar>=0) {
						Plr[tar].Rec.push_back(make_pair(Plr[i].Atk.front(),make_pair(rnd(Plr[tar].LY)+1,curtm)));
						double fx=Plr[i].ravx-Plr[tar].KX, fy=Plr[i].ravy-Plr[tar].KY;
						double ex=Plr[tar].ravx-Plr[tar].KX, ey=Plr[tar].ravy-Plr[tar].KY;
						double ss = 5+2*min(Plr[i].Atk.front()-1,20);
						ss/=Plr[tar].sz; ss*=10;
						int seg=sqrt((fx-ex)*(fx-ex)+(fy-ey)*(fy-ey))/30.0; double cx=fx, cy=fy;
						for (int i=0; i<seg; ++i) {
							cx += (ex-fx)/double(seg+3);
							cy += (ey-fy)/double(seg+3);
							Plr[tar].PQu.push_back({cx,cy,0,0,0,0,double(i)/double(seg)*ss,0.2/Plr[tar].sz,0,8,-Mix(0xFFFFFF,0xDF3782,0.6)});
						}
						Plr[tar].LstAtk = i;
					}
					Plr[i].Atk.pop();
				}
			}
			int OverCnt = 0;
			int Hm=0, HmOver=0;
			for (int i=0; i<Plrs; ++i) {
				if (Plr[i].Over) {
					++OverCnt;
					if ((Plr[i].LstAtk>=0)&&(!KOCount[i])) {
						Plr[Plr[i].LstAtk].SKO += 1+Plr[i].SKO;
						++Plr[Plr[i].LstAtk].KO; KOCount[i]=true;
					}
				}
				if (!Plr[i].Bot) {
					++Hm; if (Plr[i].Over) ++HmOver;
				}
			}
			if (((OverCnt+1>=Plrs)&&(Plrs>1))||((Plrs==1)&&(OverCnt))||((Hm)&&(Hm==HmOver)&&(!ObserveAI))) {
				int seed=time(0); Obs=-1; ++RoundTot;
				for (int i=0; i<Plrs; ++i) {
					if (!Plr[i].Over) {
						++Plr[i].Wins; Plr[i].Victory();
					}
					else Plr[i].ClearAll(0,true);
				}
				if (Plrs>1) {
					PaintTm = 0;
					while (PaintTm<3000) {
						ll NxtT = clock();
						int del=int(NxtT-CurT); PaintTm+=del;
						CurT = NxtT;
						glClearColor(0.92, 0.92, 0.92, 0);
						glClear(GL_COLOR_BUFFER_BIT);
						glPushMatrix();
						for (int i=0; i<Plrs; ++i) {
							if (!Plr[i].Over) Plr[i].PaintText(del);
						}
						for (int i=0; i<Plrs; ++i) {
							if (!Plr[i].Over) Plr[i].Paint(del);
						}
						for (int i=0; i<Plrs; ++i) {
							Plr[i].PaintParticle(del,0);
						}
						glPopMatrix();
						SwapBuffers(hDC);
					}
				}
				for (int i=0; i<Plrs; ++i) {
					Plr[i].ClearAll(seed,Plr[i].Over); Plr[i].Over=false; 
					Plr[i].LstAtk=-1; KOCount[i]=false;
				}
			}
			if (PaintTm>=PaintLim) {
				glClearColor(0.92, 0.92, 0.92, 0);
				glClear(GL_COLOR_BUFFER_BIT);
				glPushMatrix();
				for (int i=0; i<Plrs; ++i) {
					if (!Plr[i].Over) {
						int tars=0; for (int j=0; j<Plrs; ++j) tars+=((Tar[j]==i)&&(!Plr[j].Over));
						Plr[i].Paint(PaintTm);
					}
				}
				for (int i=0; i<Plrs; ++i) {
					if (!Plr[i].Over) {
						int tars=0; for (int j=0; j<Plrs; ++j) tars+=((Tar[j]==i)&&(!Plr[j].Over));
						Plr[i].PaintParticle(PaintTm, tars);
					}
				}
				PaintTm = 0;
				glPopMatrix();
				SwapBuffers(hDC);
			}
		}
	}
	DisableOpenGL(hWnd, hDC, hRC);
	DestroyWindow(hWnd);
	return msg.wParam;
}