#include <bits/stdc++.h>
#include <windows.h>
#include <conio.h>
#define color(x) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),x)
#define curpos(x,y) SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),{y,x})
using namespace std;
struct RandomGenerator {
int StartSeed;
int CurSeed;
int CurCount;
RandomGenerator() {
CurCount = 0;
CurSeed = int(time(0));
StartSeed = CurSeed;
srand(CurSeed);
}
RandomGenerator(int Seed) {
CurCount = 0;
CurSeed = Seed;
StartSeed = CurSeed;
srand(CurSeed);
}
void Srand(int Seed) {
CurCount = 0;
CurSeed = Seed;
StartSeed = CurSeed;
srand(CurSeed);
}
int Rand() {
++CurCount;
if (CurCount==0x8000) {
CurCount = 0;
CurSeed += (StartSeed^0x66CCFF)+1;
srand(CurSeed);
}
return rand();
}
int Rand32() {
return ((Rand()>>1)<<16)|Rand()|((Rand()&1)<<15);
}
int Rand(int Mod) {
return Rand32()%Mod;
}
} Rnd;
struct ClassTile {
int LenX, LenY, MidX, MidY, Color;
int Block[100][100];
ClassTile() {
LenX=LenY=MidX=MidY=0; Color=7;
memset(Block, 0, sizeof(Block));
}
void Init(string str, int clr) {
LenX = LenY = 0;
Color = clr;
int CurY = 0;
for (unsigned int i=0; i<str.size(); ++i) {
char ch = str[i];
if (ch=='|') {
++LenX; CurY=0;
}
else if (ch=='*') Block[LenX][CurY++]=true;
else if (ch=='#') {
MidX=LenX; MidY=CurY;
Block[LenX][CurY++] = true;
}
else if (ch=='.') Block[LenX][CurY++]=false;
LenY = max(LenY,CurY);
}
}
} BasicTiles[7], Tiles[7][4];
int SaveInFile = true;
int LenX=40, DisX=21, LenY=10;
int MovesLimit = 15;
int TileCount = 7;
int NormalTimeLimit=500, LockTimeLimit=500;
int NextDisplay = 5;
int AttackEnabled = false;
int AttackLayerLimit = 8;
int SingleAttackLimit = 20;
int RandomByBag = true;
int EnableHold = true;
int Gravity = 1;
int AttackByTime = 0;
int EnableKickWall = true;
int Enable180Spin = true;
int DisplayDropLocation = true;
int AllSpin = true;
int OSpin = true;
int B2BForAllSpin = false;
int ImmeadiateLock = false;
int ShowDisappearEffect = true;
int GoalLines = 0;
ifstream fin; int Options=0, LimL[100], LimR[100], DisplayType[100], Multiplier[100];
int *Pointers[100]; string Name[100];
void TryRead(string _Name, int &x, int _LimL, int _LimR, int _DisplayType=0, int _Multiplier=1) {
int r; ++Options;
Pointers[Options]=&x; Name[Options]=_Name;
LimL[Options]=_LimL; LimR[Options]=_LimR;
DisplayType[Options]=_DisplayType; Multiplier[Options]=_Multiplier;
if (fin>>r) x=r;
}
char GetKey() {
if (GetKeyState(VK_SHIFT)&32768) return 1;
char r=getch(); while (kbhit()) r=getch();
return r;
}
void SettingsBoard() {
fin.open("settings.txt");
fin.clear(); fin.clear();
++DisX;
TryRead("Save Options at Local", SaveInFile, 0, 1, 2);
TryRead("Height of Board", DisX, 2, 80);
TryRead("Width of Board", LenY, 4, 80);
TryRead("Real Height of Board", LenX, 2, 80);
TryRead("Drop Time (ms)", NormalTimeLimit, 0, 10000000, 1, 50);
TryRead("Lock Time (ms)", LockTimeLimit, 0, 10000000, 1, 50);
TryRead("Show Next Pieces", NextDisplay, 0, 5, 1);
TryRead("Moves Limit Per Drop", MovesLimit, 0, 1000, 1);
TryRead("Attack Myself", AttackEnabled, 0, 1, 2);
TryRead("Max Attack Layer Per Round", AttackLayerLimit, 0, 50, 1);
TryRead("Single Attack Limit", SingleAttackLimit, 0, 50, 1);
TryRead("Use 7-Bag Piece Random", RandomByBag, 0, 1, 2);
TryRead("Enable Hold Function", EnableHold, 0, 1, 2);
TryRead("Gravity", Gravity, 0, 80, 1);
TryRead("Send Garbage By Time", AttackByTime, 0, 10000000, 1, 50);
TryRead("Enable Kick Wall", EnableKickWall, 0, 1, 2);
TryRead("Enable 180-Degree Rotate", Enable180Spin, 0, 1, 2);
TryRead("Show Ghost Piece", DisplayDropLocation, 0, 1, 2);
TryRead("Show All Spins", AllSpin, 0, 1, 2);
TryRead("Enable O-Spin", OSpin, 0, 1, 2);
TryRead("Bonus For All Spins", B2BForAllSpin, 0, 1, 2);
TryRead("Lock Immeadiately on Ground", ImmeadiateLock, 0, 1, 2);
TryRead("Disappear Effect", ShowDisappearEffect, 0, 1, 2);
TryRead("Goal Lines", GoalLines, 0, 10000, 1);
fin.clear(); fin.close();
int Selected = 1;
for (;;) {
for (int i=1; i<=Options; ++i) {
curpos(i, 35);
color((Selected==i)?15:7);
if (!DisplayType[i]) printf("%d ",*Pointers[i]);
else if (DisplayType[i]==1) {
if (*Pointers[i]) printf("%d ",*Pointers[i]);
else {
color((Selected==i)?12:4);
printf("NO ");
}
}
else if (DisplayType[i]==2) {
if (*Pointers[i]) {
color((Selected==i)?10:2);
printf("YES");
}
else {
color((Selected==i)?12:4);
printf("NO ");
}
}
curpos(i, 3);
color((Selected==i)?7:8);
cout << Name[i];
printf(" ");
}
char ch=GetKey(); if (isupper(ch)) ch=tolower(ch);
if ((ch=='\r')||(ch=='\n')||(ch==' ')) break;
if (ch==104) Selected=max(1,Selected-1);
if (ch==112) Selected=min(Options,Selected+1);
if (((ch==107)||(ch==109))&&(DisplayType[Selected]==2)) *Pointers[Selected]^=1;
else if (ch==107) *Pointers[Selected]=max(*Pointers[Selected]-Multiplier[Selected],LimL[Selected]);
else if (ch==109) *Pointers[Selected]=min(*Pointers[Selected]+Multiplier[Selected],LimR[Selected]);
DisX = min(DisX,LenX);
}
if (SaveInFile) {
ofstream fout("settings.txt");
for (int i=1; i<=Options; ++i) fout<<*Pointers[i]<<" ";
fout.clear(); fout.close();
}
--DisX;
system("cls");
}
int Hold; int HoldAvailable;
int TotalTiles, TotalLines, TotalAttack, Combo, B2B;
int AttackRemain, AttackQueue[1000];
int B2BMessage;
int Board[100][100]; int Active[100][100], DropTo[100][100], AttackColor[100];
int DisappearEffect[100][100];
int TileQueue[100], QueueLen;
long long BeginTime;
int OnGround;
int MessageRemain;
int ResetBar;
int Record = 2000000000;
string MessageA; int MessageColorA;
string MessageB; int MessageColorB;
ClassTile RotateTile(ClassTile Tile, int K=1) {
K = (K%4+4)%4;
while (K--) {
ClassTile NewTile; NewTile.Color=Tile.Color;
NewTile.LenX=Tile.LenY; NewTile.LenY=Tile.LenX;
NewTile.MidY=Tile.LenX-Tile.MidX-1; NewTile.MidX=Tile.MidY;
for (int i=0; i<Tile.LenX; ++i) {
for (int j=0; j<Tile.LenY; ++j) NewTile.Block[j][Tile.LenX-i-1]=Tile.Block[i][j];
}
Tile = NewTile;
}
return Tile;
}
int CheckTile(int i, int j) {
if (((i<0)||(i>=LenX))||((j<0)||(j>=LenY))) return true;
return ((Board[i][j]!=0)&&(!Active[i][j]));
}
int CheckTileNoUpper(int i, int j) {
if ((i<0)||((j<0)||(j>=LenY))) return true;
return ((Board[i][j]!=0)&&(!Active[i][j]));
}
void Display() {
int DropLen = LenX;
for (int i=0; i<LenX; ++i) {
for (int j=0; j<LenY; ++j) {
DropTo[i][j] = false;
if (Active[i][j]) {
int Len=0; while (!CheckTile(i-Len-1,j)) ++Len;
DropLen = min(DropLen,Len);
}
}
}
for (int i=1; i<min(AttackRemain,DisX); ++i) {
if (AttackQueue[i]!=AttackQueue[i-1]) AttackColor[i]=!AttackColor[i-1];
else AttackColor[i]=AttackColor[i-1];
}
for (int i=0; i<LenX; ++i) {
for (int j=0; j<LenY; ++j) {
if (Active[i][j]) DropTo[i-DropLen][j]=true;
}
}
int GoalBar = 0;
if (GoalLines) GoalBar=int(floor(double(DisX)*double(TotalLines)/double(GoalLines)));
for (int i=DisX; i>=0; --i) {
curpos(DisX-i+5,12);
color(((AttackEnabled)||(DisX-i<2)?8:7)<<4); if (AttackRemain>i) color((AttackColor[i]?4:12)<<4);
printf(" ");
color((DisX-i<2?8:7)<<4); printf(" ");
for (int j=0; j<LenY; ++j) {
if ((!Board[i][j])&&(DropTo[i][j])&&(DisplayDropLocation)) {
color(7); printf("□");
}
else if (!Active[i][j]) {
color(Board[i][j]<<4|8);
if ((DisappearEffect[i][j])&&(!Board[i][j])&&(ShowDisappearEffect)) printf("※");
else printf(" ");
}
else {
color(Board[i][j]); printf("■");
}
}
color((i<GoalBar)?(2<<4):((DisX-i<2?8:7)<<4)); printf(" ");
color(((ResetBar>i)?12:(DisX-i<2?8:7))<<4); printf(" ");
color(0);
}
color(((Hold==-1)||(!HoldAvailable))?8:15); curpos(2,1);
if (EnableHold) printf("H O L D");
for (int i=0; i<5; ++i) {
curpos(4+i, 1);
for (int j=0; j<5; ++j) {
if ((Hold==-1)||(!BasicTiles[Hold].Block[4-i][j])) color(0);
else color((HoldAvailable)?BasicTiles[Hold].Color:8);
printf("■");
}
}
color(15); curpos(2,18+LenY*2);
if (NextDisplay) printf("N E X T");
for (int d=0; d<NextDisplay; ++d) {
for (int i=0; i<5; ++i) {
curpos(3+d*5+i, 18+LenY*2);
for (int j=0; j<5; ++j) {
if (!BasicTiles[TileQueue[d]].Block[4-i][j]) color(0);
else color(BasicTiles[TileQueue[d]].Color);
printf("■");
}
}
}
curpos(DisX+6, 12);
for (int j=-1; j<=LenY; ++j) {
color(7<<4); printf(" ");
}
double Seconds = double(clock()-BeginTime)*0.001+0.001;
int SecondsInt = int(floor(Seconds));
color(MessageColorA); curpos(10,1); cout<<MessageA;
color(MessageColorB); curpos(11,1); cout<<MessageB;
curpos(12,1); color(15);
if ((Combo<2)||(!MessageRemain)) printf(" ");
else printf("%d Combo",Combo-1);
curpos(13,1); color((B2B)?14:12);
if ((!B2BMessage)||((!B2B)&&(!MessageRemain))) printf(" ");
else printf("B2B x %d",max(0,B2B-1));
color(15); curpos(17,1); printf("Time");
color(11); curpos(18,1); printf("%02d:%02d",SecondsInt/60,SecondsInt%60);
color(15); curpos(19,1); printf("Pieces");
color(10); curpos(20,1); printf("%d ",TotalTiles);
color(11); curpos(21,1); printf("%.2f /s ",double(TotalTiles)/Seconds);
color(15); curpos(22,1); printf("Lines");
color(10); curpos(23,1); printf("%d ",TotalLines);
color(11); curpos(24,1); printf("%.2f /m ",double(TotalLines*60)/Seconds);
color(15); curpos(25,1); printf("Attack");
color(10); curpos(26,1); printf("%d ",TotalAttack);
color(11); curpos(27,1); printf("%.2f /m ",double(TotalAttack*60)/Seconds);
if (GoalLines) {
curpos(27, 1);
if (TotalLines>=GoalLines) {
color(10); printf("COMPLETED");
}
else {
color(14); printf("(%.2f%%)",double(TotalLines)/double(GoalLines)*100.0);
}
}
}
int CheckDown() {
for (int i=0; i<LenX; ++i) {
for (int j=0; j<LenY; ++j) {
if ((Active[i][j])&&(CheckTile(i-1,j))) return false;
}
}
return true;
}
int CheckLeft() {
for (int i=0; i<LenX; ++i) {
for (int j=0; j<LenY; ++j) {
if ((Active[i][j])&&(CheckTile(i,j-1))) return false;
}
}
return true;
}
int CheckRight() {
for (int i=0; i<LenX; ++i) {
for (int j=0; j<LenY; ++j) {
if ((Active[i][j])&&(CheckTile(i,j+1))) return false;
}
}
return true;
}
int MoveDown() {
if (!CheckDown()) return false;
for (int i=0; i+1<LenX; ++i) {
for (int j=0; j<LenY; ++j) {
if (Active[i+1][j]) {
Active[i][j]=true; Board[i][j]=Board[i+1][j];
}
else if (Active[i][j]) {
Active[i][j]=false; Board[i][j]=0;
}
}
}
for (int j=0; j<LenY; ++j) {
if (Active[LenX-1][j]) {
Active[LenX-1][j]=false; Board[LenX-1][j]=0;
}
}
return true;
}
int MoveLeft() {
if (!CheckLeft()) return false;
for (int j=0; j+1<LenY; ++j) {
for (int i=0; i<LenX; ++i) {
if (Active[i][j+1]) {
Active[i][j]=true; Board[i][j]=Board[i][j+1];
}
else if (Active[i][j]) {
Active[i][j]=false; Board[i][j]=0;
}
}
}
for (int i=0; i<LenX; ++i) {
if (Active[i][LenY-1]) {
Active[i][LenY-1]=false; Board[i][LenY-1]=0;
}
}
return true;
}
int MoveRight() {
if (!CheckRight()) return false;
for (int j=LenY-1; j>=0; --j) {
for (int i=0; i<LenX; ++i) {
if (Active[i][j-1]) {
Active[i][j]=true; Board[i][j]=Board[i][j-1];
}
else if (Active[i][j]) {
Active[i][j]=false; Board[i][j]=0;
}
}
}
for (int i=0; i<LenX; ++i) {
if (Active[i][0]) {
Active[i][0]=false; Board[i][0]=0;
}
}
return true;
}
int TryNewRotate(ClassTile Tile, int x, int y) {
for (int i=0; i<Tile.LenX; ++i) {
for (int j=0; j<Tile.LenY; ++j) {
if ((Tile.Block[i][j])&&(CheckTile(x+i,y+j))) return false;
}
}
for (int i=0; i<LenX; ++i) {
for (int j=0; j<LenY; ++j) {
if (Active[i][j]) {
Active[i][j]=false; Board[i][j]=0;
}
}
}
for (int i=0; i<Tile.LenX; ++i) {
for (int j=0; j<Tile.LenY; ++j) {
if (Tile.Block[i][j]) {
Active[x+i][y+j]=true; Board[x+i][y+j]=Tile.Color;
}
}
}
return true;
}
vector<pair<int,int> > KickTable[4][4], IKickTable[4][4];
int Rotate(ClassTile OldTile, ClassTile NewTile, int From, int To) { // To be modified - 2023/10/20 11:04
if ((!OSpin)&&(NewTile.Color==14)) return false;
int FirstActiveX=-1, FirstActiveY=-1;
for (int i=0; i<LenX; ++i) {
for (int j=0; j<LenY; ++j) {
if (Active[i][j]) {
FirstActiveY=j; break;
}
}
if (FirstActiveY>=0) {
FirstActiveX=i; break;
}
}
int FirstTileX=-1, FirstTileY=-1;
for (int i=0; i<OldTile.LenX; ++i) {
for (int j=0; j<OldTile.LenY; ++j) {
if (OldTile.Block[i][j]) {
FirstTileY=j; break;
}
}
if (FirstTileY>=0) {
FirstTileX=i; break;
}
}
int BaseX = FirstActiveX-FirstTileX+((NewTile.Color==14||NewTile.Color==11)?0:OldTile.MidX-NewTile.MidX);
int BaseY = FirstActiveY-FirstTileY+((NewTile.Color==14||NewTile.Color==11)?0:OldTile.MidY-NewTile.MidY);
if (!EnableKickWall) {
if (TryNewRotate(NewTile,BaseX,BaseY)) return true;
return false;
}
if (NewTile.Color==14) {
if (!OnGround) return true;
int Shift = 0;
if ((To-From+4)%4==1) Shift=-1;
if ((To-From+4)%4==3) Shift=1;
if (TryNewRotate(NewTile,BaseX-3,BaseY+Shift)) return true;
if (TryNewRotate(NewTile,BaseX-2,BaseY+Shift)) return true;
if (TryNewRotate(NewTile,BaseX-1,BaseY+Shift)) return true;
}
else if (KickTable[From][To].empty()) {
if (OnGround) {
if (TryNewRotate(NewTile,BaseX-2,BaseY)) return true;
if (TryNewRotate(NewTile,BaseX-1,BaseY)) return true;
if ((NewTile.Color!=14)&&(TryNewRotate(NewTile,BaseX,BaseY))) return true;
int d = Rnd.Rand(2)?1:-1;
if (TryNewRotate(NewTile,BaseX-2,BaseY+d)) return true;
if (TryNewRotate(NewTile,BaseX-2,BaseY-d)) return true;
if (TryNewRotate(NewTile,BaseX-1,BaseY+d)) return true;
if (TryNewRotate(NewTile,BaseX-1,BaseY-d)) return true;
if (TryNewRotate(NewTile,BaseX,BaseY+d)) return true;
if (TryNewRotate(NewTile,BaseX,BaseY-d)) return true;
}
else {
if (TryNewRotate(NewTile,BaseX,BaseY)) return true;
if (TryNewRotate(NewTile,BaseX-1,BaseY)) return true;
if (TryNewRotate(NewTile,BaseX-2,BaseY)) return true;
int d = Rnd.Rand(2)?1:-1;
if (TryNewRotate(NewTile,BaseX,BaseY+d)) return true;
if (TryNewRotate(NewTile,BaseX,BaseY-d)) return true;
if (TryNewRotate(NewTile,BaseX-1,BaseY+d)) return true;
if (TryNewRotate(NewTile,BaseX-1,BaseY-d)) return true;
if (TryNewRotate(NewTile,BaseX-2,BaseY+d)) return true;
if (TryNewRotate(NewTile,BaseX-2,BaseY-d)) return true;
}
}
else if (NewTile.Color==11) {
for (pair<int,int> p : IKickTable[From][To]) {
if (TryNewRotate(NewTile,BaseX+p.second,BaseY+p.first)) return true;
}
}
else {
for (pair<int,int> p : KickTable[From][To]) {
if (TryNewRotate(NewTile,BaseX+p.second,BaseY+p.first)) return true;
}
}
return false;
}
int NoPlacement(ClassTile Tile, int x, int y) {
for (int i=0; i<Tile.LenX; ++i) {
for (int j=0; j<Tile.LenY; ++j) {
if ((Tile.Block[i][j])&&(CheckTileNoUpper(x+i,y+j))) return true;
}
}
return false;
}
int CheckSpin(ClassTile Tile) {
return NoPlacement(Tile,0,1)&&NoPlacement(Tile,0,-1)
&&NoPlacement(Tile,1,0)&&NoPlacement(Tile,-1,0);
}
void RemoveActive() {
for (int i=0; i<LenX; ++i) {
for (int j=0; j<LenY; ++j) {
if (Active[i][j]) {
Active[i][j]=false; Board[i][j]=0;
}
}
}
}
int FinalDrop() {
string Construct = "";
for (int i=0; i<LenX; ++i) {
for (int j=0; j<LenY; ++j) {
if (Active[i][j]) Construct+="*";
else Construct+=".";
}
Construct += "|";
}
ClassTile Tile; Tile.Init(Construct,0);
int Spin = CheckSpin(Tile);
for (int i=0; i<LenX; ++i) {
for (int j=0; j<LenY; ++j) Active[i][j]=false;
}
return Spin;
}
int SpawnTile(ClassTile Tile) {
int PosY=(LenY>>1)+(Tile.LenY>>1)-1, PosX=DisX;
PosY = max(PosY,Tile.LenY-1);
PosY = min(PosY,LenY-1);
PosX-=Tile.LenX-1; PosY-=Tile.LenY-1;
for (int i=Tile.LenX-1; i>=0; --i) {
bool flag = true;
for (int j=0; j<Tile.LenY; ++j) {
if (Tile.Block[i][j]) {
flag=false; break;
}
}
if (flag) ++PosX;
else break;
}
for (int i=0; i<Tile.LenX; ++i) {
for (int j=0; j<Tile.LenY; ++j) {
if ((Tile.Block[i][j])&&(CheckTile(PosX+i,PosY+j))) return false;
}
}
for (int i=0; i<Tile.LenX; ++i) {
for (int j=0; j<Tile.LenY; ++j) {
if (Tile.Block[i][j]) {
Board[PosX+i][PosY+j] = Tile.Color;
Active[PosX+i][PosY+j] = true;
}
}
}
return true;
}
int CheckAllClear() {
for (int i=0; i<LenX; ++i) {
for (int j=0; j<LenY; ++j) {
if (Board[i][j]) return false;
}
}
return true;
}
long long StartTimeForKey;
char GetKeyInLimit(long long TimeLimit) {
if (GetKeyState(VK_SHIFT)&32768) return 1;
if (kbhit()) {
char res='!'; while (kbhit()) res=getch();
return res;
}
while ((!TimeLimit)||(clock()-StartTimeForKey<TimeLimit)) {
if (GetKeyState(VK_SHIFT)&32768) return 1;
if (kbhit()) {
char res='!'; while (kbhit()) res=getch();
return res;
}
}
return '!';
}
int TileExist[100];
int RandomTile() {
int MinCount=TileExist[0]; for (int i=1; i<TileCount; ++i) MinCount=min(TileExist[i],MinCount);
int NextTile = Rnd.Rand(TileCount);
while (TileExist[NextTile]!=MinCount) NextTile=Rnd.Rand(TileCount);
if (RandomByBag) ++TileExist[NextTile];
return NextTile;
}
int NewTile(int Certain=-1) {
int NextTile = Certain;
if (Certain==-1) {
NextTile = TileQueue[0];
for (int i=0; i+1<max(1,NextDisplay); ++i) TileQueue[i]=TileQueue[i+1];
TileQueue[max(1,NextDisplay)-1] = RandomTile();
}
if (!SpawnTile(Tiles[NextTile][0])) return -1;
else return NextTile;
}
int RemoveFullLines() {
int NewLine=0, Lines=0;
for (int i=0; i<LenX; ++i) {
int LineClear = true;
for (int j=0; j<LenY; ++j) {
if (!Board[i][j]) {
LineClear=false; break;
}
}
if (LineClear) {
++Lines;
for (int j=0; j<LenY; ++j) DisappearEffect[i][j]=true;
}
else {
if (NewLine<i) {
for (int j=0; j<LenY; ++j) Board[NewLine][j]=Board[i][j];
}
++NewLine;
}
}
for (int i=NewLine; i<LenX; ++i) {
for (int j=0; j<LenY; ++j) Board[i][j]=0;
}
return Lines;
}
void AddAttackLayer(int y) {
for (int i=LenX-2; i>=0; --i) {
for (int j=0; j<LenY; ++j) {
Board[i+1][j]=Board[i][j]; Active[i+1][j]=Active[i][j];
}
}
for (int i=0; i<LenY; ++i) {
Board[0][i]=(i==y)?0:8; Active[0][i]=false;
}
MoveDown();
}
int RemoveAttackLayer() {
if (!AttackRemain) return false;
for (int i=0; i+1<AttackRemain; ++i) AttackQueue[i]=AttackQueue[i+1];
--AttackRemain;
return true;
}
int EnableAttackLayer() {
if (!AttackRemain) return false;
AddAttackLayer(AttackQueue[0]);
for (int i=0; i+1<AttackRemain; ++i) AttackQueue[i]=AttackQueue[i+1];
--AttackRemain;
return true;
}
int main() {
SettingsBoard();
if (!AttackLayerLimit) AttackLayerLimit=10000;
if (!SingleAttackLimit) SingleAttackLimit=10000;
if (!MovesLimit) MovesLimit=1000000000;
BasicTiles[0].Init("....|....|*#**|....|",11); // I
BasicTiles[1].Init("*#*|*..|",1); // J
BasicTiles[2].Init("*#*|..*|",6); // L
BasicTiles[3].Init("**|#*|",14); // O
BasicTiles[4].Init("*#.|.**|",10); // S
BasicTiles[5].Init("*#*|.*.|",13); // T
BasicTiles[6].Init(".#*|**.|",12); // Z
KickTable[0][3] = {{ 0, 0}, {-1, 0}, {-1,+1}, { 0,-2}, {-1,-2}};
KickTable[3][0] = {{ 0, 0}, {+1, 0}, {+1,-1}, { 0,+2}, {+1,+2}};
KickTable[3][2] = {{ 0, 0}, {+1, 0}, {+1,-1}, { 0,+2}, {+1,+2}};
KickTable[2][3] = {{ 0, 0}, {-1, 0}, {-1,+1}, { 0,-2}, {-1,-2}};
KickTable[2][1] = {{ 0, 0}, {+1, 0}, {+1,+1}, { 0,-2}, {+1,-2}};
KickTable[1][2] = {{ 0, 0}, {-1, 0}, {-1,-1}, { 0,+2}, {-1,+2}};
KickTable[1][0] = {{ 0, 0}, {-1, 0}, {-1,-1}, { 0,+2}, {-1,+2}};
KickTable[0][1] = {{ 0, 0}, {+1, 0}, {+1,+1}, { 0,-2}, {+1,-2}};
IKickTable[0][3] = {{ 0, 0}, {-2, 0}, {+1, 0}, {-2,-1}, {+1,+2}};
IKickTable[3][0] = {{ 0, 0}, {+2, 0}, {-1, 0}, {+2,+1}, {-1,-2}};
IKickTable[3][2] = {{ 0, 0}, {-1, 0}, {+2, 0}, {-1,+2}, {+2,-1}};
IKickTable[2][3] = {{ 0, 0}, {+1, 0}, {-2, 0}, {+1,-2}, {-2,+1}};
IKickTable[2][1] = {{ 0, 0}, {+2, 0}, {-1, 0}, {+2,+1}, {-1,-2}};
IKickTable[1][2] = {{ 0, 0}, {-2, 0}, {+1, 0}, {-2,-1}, {+1,+2}};
IKickTable[1][0] = {{ 0, 0}, {+1, 0}, {-2, 0}, {+1,-2}, {-2,+1}};
IKickTable[0][1] = {{ 0, 0}, {-1, 0}, {+2, 0}, {-1,+2}, {+2,-1}};
for (int i=0; i<TileCount; ++i) {
Tiles[i][0] = BasicTiles[i];
for (int j=1; j<4; ++j) Tiles[i][j]=RotateTile(Tiles[i][j-1],1);
}
int MovesLeft=MovesLimit; QueueLen=1;
for (int i=0; i<max(1,NextDisplay); ++i) TileQueue[i]=RandomTile();
int TileID=NewTile(), TileStatus=0; Hold=-1;
HoldAvailable = true;
TotalTiles=TotalLines=Combo=0;
MessageRemain = 0;
long long LastAttack=BeginTime=StartTimeForKey=clock();
Display();
MessageA=MessageB=" ";
AttackRemain = 0;
int ResetCooldown = 0;
int Win = false;
for (;;) {
char ch = GetKeyInLimit((long long)(CheckDown()?NormalTimeLimit:LockTimeLimit));
int NextRound = false;
if ((ch!='!')&&(ch!='q')&&(ch!='c')) {
if (!MovesLeft) {
ch='!'; MovesLeft=MovesLimit;
}
else --MovesLeft;
}
else MovesLeft=MovesLimit;
if (isupper(ch)) ch=tolower(ch);
int HoldChange = false;
OnGround = !CheckDown();
int HoldTo = -1;
if (ch!='r') {
if (ResetCooldown) --ResetCooldown;
else ResetBar=max(0,ResetBar-10);
}
if (ch==107) MoveLeft();
else if (ch==109) MoveRight();
else if (ch=='r') {
++ResetBar; ResetCooldown=5;
}
else if ((ch==104)||(ch=='z')) {
if (Rotate(Tiles[TileID][TileStatus],Tiles[TileID][(TileStatus+1)&3],TileStatus,(TileStatus+1)&3)) TileStatus=(TileStatus+1)&3;
//else if ((Enable180Spin)&&(Rotate(Tiles[TileID][TileStatus],Tiles[TileID][(TileStatus+2)&3],TileStatus,(TileStatus+2)&3))) TileStatus=(TileStatus+2)&3;
}
else if (ch=='x') {
if (Rotate(Tiles[TileID][TileStatus],Tiles[TileID][(TileStatus+3)&3],TileStatus,(TileStatus+3)&3)) TileStatus=(TileStatus+3)&3;
//else if ((Enable180Spin)&&(Rotate(Tiles[TileID][TileStatus],Tiles[TileID][(TileStatus+2)&3],TileStatus,(TileStatus+2)&3))) TileStatus=(TileStatus+2)&3;
}
else if ((ch=='a')&&(Enable180Spin)) {
if ((Enable180Spin)&&(Rotate(Tiles[TileID][TileStatus],Tiles[TileID][(TileStatus+2)&3],TileStatus,(TileStatus+2)&3))) TileStatus=(TileStatus+2)&3;
}
else if (ch==' ') {
while (CheckDown()) MoveDown();
NextRound = true;
}
else if (ch=='c') {
if ((EnableHold)&&(HoldAvailable)) {
if (Hold>=0) {
swap(Hold,TileID); HoldTo=TileID;
}
else Hold=TileID;
NextRound=HoldChange=true; HoldAvailable=false;
RemoveActive();
}
}
else if ((ch==112)||(ch=='!')) {
for (int i=0; i<((ch=='!')?Gravity:max(1,Gravity)); ++i) {
if (CheckDown()) {
MoveDown(); MovesLeft=MovesLimit;
if ((ImmeadiateLock)&&(!CheckDown())) {
NextRound=true; break;
}
}
else if (ch=='!') {
NextRound=true; break;
}
}
}
else if (ch=='q') {
while (kbhit()) getch();
Sleep(50); getch();
}
int Over = false;
if (MessageRemain) {
if (--MessageRemain==0) MessageA=MessageB=" ";
}
if (NextRound) {
for (int i=0; i<LenX; ++i) {
for (int j=0; j<LenY; ++j) DisappearEffect[i][j]=false;
}
if (!HoldChange) {
MessageA=MessageB=" "; MessageColorB=15;
int Spin=FinalDrop(); int NewLines=RemoveFullLines();
if (NewLines) ++Combo;
else Combo=0;
TotalLines += NewLines;
if (NewLines==1) MessageB=" SINGLE";
if (NewLines==2) MessageB=" DOUBLE";
if (NewLines==3) MessageB=" TRIPLE";
if (NewLines==4) MessageB=" Q U A D";
int NewAttack = 0;
if (NewLines) {
if (NewLines>1) NewAttack=1<<(NewLines-2);
if ((Spin)&&((TileID==5)||(B2BForAllSpin))) NewAttack=NewLines<<1;
--Combo;
if (Combo>=2) ++NewAttack;
if (Combo>=4) ++NewAttack;
if (Combo>=6) ++NewAttack;
if (Combo>=8) ++NewAttack;
if (Combo>=11) ++NewAttack;
++Combo;
}
if (CheckAllClear()) {
MessageColorB=12; MessageB="ALL CLEAR ";
NewAttack += 10;
}
if ((!AllSpin)&&(TileID!=5)) Spin=false;
if (Spin) {
MessageColorA = BasicTiles[TileID].Color;
if (TileID==0) MessageA=" I-SPIN";
if (TileID==1) MessageA=" J-SPIN";
if (TileID==2) MessageA=" L-SPIN";
if (TileID==3) MessageA=" O-SPIN";
if (TileID==4) MessageA=" S-SPIN";
if (TileID==5) MessageA=" T-SPIN";
if (TileID==6) MessageA=" Z-SPIN";
}
if (NewLines) {
if ((NewLines==4)||((Spin)&&((TileID==5)||(B2BForAllSpin)))) {
++B2B; B2BMessage=(B2B>1);
if (B2B>1) NewAttack+=int(floor(sqrt(double(B2B-1))));
}
else if (B2B>=2) {
B2B=0; B2BMessage=true;
}
else {
B2B=0; B2BMessage=false;
}
TotalAttack += NewAttack;
while ((NewAttack)&&(AttackRemain)) {
RemoveAttackLayer(); --NewAttack;
}
NewAttack = min(NewAttack,SingleAttackLimit);
if (!AttackEnabled) NewAttack=0;
int y = Rnd.Rand(LenY);
for (int i=0; i<NewAttack; ++i) AttackQueue[AttackRemain++]=y;
}
else {
B2BMessage = false;
int AttackReceive = min(AttackLayerLimit,AttackRemain);
while (AttackReceive--) EnableAttackLayer();
}
MessageRemain = 15;
HoldAvailable=true; ++TotalTiles;
}
TileID=NewTile(HoldTo); TileStatus=0;
if (TileID==-1) Over=true;
}
if ((!Over)&&(CheckDown())&&(AttackByTime)&&(clock()-LastAttack>(long long)(AttackByTime))) {
LastAttack=clock(); AddAttackLayer(Rnd.Rand(LenY));
}
StartTimeForKey = clock();
if ((GoalLines)&&(TotalLines>=GoalLines)&&(!Win)) {
color(14); system("cls");
while (kbhit()) getch();
printf(" TETRIS HOT NEWS!\n\n");
color(15); printf(" WOW! Gamer xxx competed in %d Line(s)\n",GoalLines);
printf(" challenge taking time ");
double Seconds = double(clock()-BeginTime)*0.001+0.001;
int SecondsInt = int(floor(Seconds));
color(11); printf("%02d:%02d.\n", SecondsInt/60, SecondsInt%60);
Record = min(Record, SecondsInt);
color(7);
if (Record>=SecondsInt) {
Record=SecondsInt; color(10); printf(" NEW RECORD!\n");
}
else printf(" (Record : %02d:%02d.)\n", Record/60, Record%60);
color(15);
printf("\n SHARE IT!\n (press any key to countinue)\n");
getch();
system("cls");
Win = true;
}
Display();
if (ResetBar>=DisX) Over=true;
if (Over) {
for (int i=0; i<LenX; ++i) {
for (int j=0; j<LenY; ++j) Active[i][j]=false;
}
TileID = -1;
Win = false;
int BlockCount=Combo=B2B=0;
int BaseAttackRemain = AttackRemain;
int BaseResetBar = ResetBar;
int BaseTotalLines = TotalLines;
int BaseTotalTiles = TotalTiles;
int BaseTotalAttack = TotalAttack;
for (int i=0; i<LenX; ++i) {
for (int j=0; j<LenY; ++j) {
if (Board[i][j]) ++BlockCount;
}
}
int BlockRemain = BlockCount;
B2BMessage=false; Hold=-1; HoldAvailable=true;
MessageA=" "; MessageB="GAME OVER ";
MessageRemain=1; MessageColorB=12;
int lp = -1;
for (int i=LenX-1; i>=0; --i) {
for (int j=0; j<LenY; ++j) {
if (!Board[i][j]) continue;
--BlockRemain;
TotalLines = int(floor(double(BaseTotalLines)/double(BlockCount)*double(BlockRemain)));
TotalTiles = int(floor(double(BaseTotalTiles)/double(BlockCount)*double(BlockRemain)));
TotalAttack = int(floor(double(BaseTotalAttack)/double(BlockCount)*double(BlockRemain)));
AttackRemain = int(floor(double(BaseAttackRemain)/double(BlockCount)*double(BlockRemain)));
ResetBar = int(floor(double(BaseResetBar)/double(BlockCount)*double(BlockRemain)));
Board[i][j]=0; DisappearEffect[i][j]=true;
if (lp!=BlockRemain*15/BlockCount) {
Display(); lp=BlockRemain*15/BlockCount;
}
}
}
MovesLeft=MovesLimit; QueueLen=1;
for (int i=0; i<TileCount; ++i) TileExist[i]=0;
for (int i=0; i<max(1,NextDisplay); ++i) TileQueue[i]=RandomTile();
LastAttack=StartTimeForKey=BeginTime=clock();
TileID=NewTile(); TileStatus=0;
while (kbhit()) getch();
MessageRemain = 0;
MessageA=MessageB=" ";
system("cls"); Display();
}
}
return 0;
}