#include <windows.h>
#include <vector>

using namespace std;

HANDLE wh;
HANDLE rh;
CHAR_INFO bb[4000];
COORD cBS = {80,50};
COORD cPos = {0,0};
SMALL_RECT wA = {0,0,79,49};
bool running = true;
int fc = 0;

struct u{ int x; int y; int dx; int dy; int state;};

vector<u> c;
vector<u> mush;
vector<u> bullets;

u s = {20, 49, 0, 0, 1};

int score, lives, i, j;

SetChar(int x, int y, char c, int a)
{
	bb[(y * 80) + x].Char.AsciiChar = c;
	bb[(y * 80) + x].Attributes = a;
}

void ResetC()
{
	c.clear();

	u head={19, 0, 1, 1, 1};
	c.push_back(head);

	for(i = 18; i >= 0; --i)
	{
		u b={i,0,0,0,0};
		c.push_back(b);
	}
}

SetPos(int x,int y)
{
	COORD c1={x,y};
	SetConsoleCursorPosition(wh, c1);
}

MoveCP()
{
	if(fc%2)
	{
		for(i = 19; i >- 1; --i)
		{
			int headx, heady;
			if(c[i].state == 1)
			{
				int tx = c[i].x + c[i].dx;

				bool hm = false;
				for(j = 0; j< mush.size(); ++j)
				{
					if(c[i].x + c[i].dx == mush[j].x && c[i].y == mush[j].y
						&& mush[j].state)
                        hm = true;
				}
				
				if( tx > 40 || tx < 0 || hm)
				{
					c[i].dx = -c[i].dx;
					int ty = c[i].y + c[i].dy;
					if(ty > 49 || ty < 0 || (ty < 39 && c[i].dy == -1))
					{
						c[i].dy =- c[i].dy;
					}
					c[i].y += c[i].dy;
				}
				else
				{
					c[i].x += c[i].dx;
				}
			}
			else
			{
				c[i].x = c[i-1].x;
				c[i].y = c[i-1].y;
			}
		}
	}
}

MoveS()
{
	bool ok = true;
	for(i = 0; i < mush.size(); ++i)
	{
		if(s.dx == mush[i].x && s.dy == mush[i].y)
			ok = false;
	}
	
	if(ok)
	{
		s.x = s.dx; s.y = s.dy;
	}
}

MoveB()
{
	for(j = 0; j < 2; ++j)
	{
		for(i = 0; i < 20; ++i)
		{
			int mrx, mry;
			if(c[i].state == 1)
			{
				mrx = c[i].dx;
				mry = c[i].dy;
			}
			
			if(bullets[j].x == c[i].x && bullets[j].y == c[i].y
				&& bullets[j].state != 0 && c[i].state != -1)
			{
				if(c[i].state == 0)
					score += 10;
				else
					score+=50;

				u m = {c[i].x, c[i].y, 0, 0, 1};
				mush.push_back(m);

				bullets[j].state = 0;

				c[i].state =- 1;
				if(i != 19)
				{
					if(c[i+1].state != -1)
					{
						c[i+1].state = 1;
						c[i+1].dx = mrx;
						c[i+1].dy = mry;
					}
				}

				int lc=0;
				for(int z = 0; z < 20; ++z)
				{
					if(c[z].state != -1)
						++lc;
				}

				if(lc == 0)
					ResetC();
			}
		}
		
		for(i = 0; i < mush.size(); ++i)
		{
			if(bullets[j].x == mush[i].x && bullets[j].y == mush[i].y
				&& bullets[j].state !=0 && mush[i].state == 1)
			{
				bullets[j].state = 0;
				mush[i].state = 0;
				score += 3;
			}
		}
		
		if(bullets[j].state == 1)
		{
			--bullets[j].y;
			if(bullets[j].y < 0)
				bullets[j].state = 0;
		}
	}
}

Init()
{
	wh = GetStdHandle(STD_OUTPUT_HANDLE);
	rh = GetStdHandle(STD_INPUT_HANDLE);
	SMALL_RECT w={0, 0, 79, 49};
	SetConsoleWindowInfo(wh, TRUE, &w);
	COORD b={80, 50};
	SetConsoleScreenBufferSize(wh, b);
}

Input()
{
	DWORD nE = 0;
	DWORD nER = 0;

	GetNumberOfConsoleInputEvents(rh, &nE);
	if(nE != 0)
	{
		INPUT_RECORD *eB = new INPUT_RECORD[nE];
		ReadConsoleInput(rh, eB, nE, &nER);
		for(i = 0; i < nER; ++i)
		{
			if (eB[i].EventType == KEY_EVENT)
			{
				if(eB[i].Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)
				{
					running = false;
				}
			}
			else if(eB[i].EventType == MOUSE_EVENT)
			{
				s.dx = eB[i].Event.MouseEvent.dwMousePosition.X;
				if(s.dx > 40)
					s.dx = 40;
				s.dy = eB[i].Event.MouseEvent.dwMousePosition.Y;
				if(s.dy < 40)
					s.dy=40;
				if(eB[i].Event.MouseEvent.dwButtonState
					& FROM_LEFT_1ST_BUTTON_PRESSED)
				{
					for(int z = 0; z < 2; ++z)
					{
                        if(bullets[z].state == 0)
						{
							bullets[z].x = s.x;
							bullets[z].y = s.y-1;
							bullets[z].state = 1;
							break;
						}
					}
				}
			}
		}
		delete eB;
	}
}

ResetM()
{
	mush.clear();
	for(i = 0; i < 100; ++i)
	{
		u m = {rand() % 40, (rand() % 46) +1, 0, 0, 1};
		mush.push_back(m);
	}
}

int main(int argc,char* argv[])
{
	Init();
	ResetC();
	ResetM();
	
	u b1={ -1, -1, 0, 0, 0};
	bullets.push_back(b1);
	bullets.push_back(b1);
	score = 0;
	lives = 3;
	
	while(running)
	{
		ZeroMemory(bb,4000*sizeof(CHAR_INFO));

		Input();
		MoveCP();
		MoveS();
		MoveB();
		
		for(i = 0; i < 50; ++i)
			SetChar(41, i, 219, 15);
		
		SetChar(s.x, s.y, 127, 15);
		
		for(i = 0; i < 20; ++i)
		{
			if(c[i].state == 1)
			{
				SetChar(c[i].x, c[i].y, 1, 2);
			}
			else if(c[i].state == 0)
			{
				SetChar(c[i].x, c[i].y, 15, 2);
			}
		}
		
		for(i = 0; i < mush.size(); ++i)
		{
			if(mush[i].state)
			{
				SetChar(mush[i].x, mush[i].y, 6, 14);
			}
		}
		
		for(i=0; i<2; ++i)
		{
			if(bullets[i].state)
				SetChar(bullets[i].x, bullets[i].y, 24, 15);
		}

		WriteConsoleOutput(wh, bb, cBS, cPos, &wA);
		
		bool ll = false;
		for(i = 0; i < c.size(); ++i)
		{
            if(c[i].state != -1 && c[i].x == s.x && c[i].y == s.y)
			{
				--lives;
				ll = true;
				ResetC();
			}
		}
		
		int mc = 0;
		for(i = 0; i < mush.size(); ++i)
			if(mush[i].state)
				++mc;

		if(mc < 50)
		{
			int nm = 0;
			do
			{
				nm = rand() % mush.size();
			} while(mush[nm].state);
			
			mush[nm].state = 1;
		}
		
		SetPos(45, 0);
		printf("SANDWORM!");
		SetPos(45,1);
		printf("Score: %d",score);
		SetPos(45,2);
		printf("Lives: %d",lives);
		
		if(!lives)
		{
			SetPos(16,20);
			printf("GAME OVER");
			Sleep(5000);
			score=0;
			lives=3;
			ResetM();
		}
		else if(ll)
			Sleep(1000);
		else
			Sleep(17);
		++fc;
	}

	return 0;
}
