#include <avr/io.h>			// hlavičkový soubor pro mikrokontrolér ATmega16
#include <stdio.h>	

#include <avr/pgmspace.h>
#include <stdlib.h>
#define F_OSC 16000000
#include <avr/io.h> 
#include <avr/interrupt.h>
#include <stdio.h>
//#define F_CPU 16000000
#include <util/delay.h>



void mazani (void)					////pokud bylo po skonceni cesty jedne kostky v nejakem radku
{									//	same jednicky tak te smaze a zbytek posune
	unsigned char *bckp;
	for (int jj=(buff); jj<12; jj++)
		{	
			if	(*ppouk==0b11111111)
				{
					bckp=ppouk;					
					for (int nn=0; nn<(12-jj); nn++)
						{	*ppouk=*(ppouk-1);
							*(ppouk--)	;
						}
					ppouk=ppoukb;//+1;
					jj=buff;
					score++;
				}							
				*(ppouk--);
		}
	ppouk=ppoukb;
}




int jaky_tvar()			// Nahodny vyber tvaru kostky
	{
		c = rand() % 7;

		return c;
	}


void zap_tvar(int stav)		//aktivuje prislusnou rotaci kostky
	{	
		if(c==0)    sp=iKK;		// tavar : kostka
			
		else if(c==1) 			//tvar :  L
			{
				if((stav) >= (4)) 	//pokud doslo k otoceni o 360°, pouzije se opet prvni rotace
					{	stav=0;	}
				sp=*iLL[stav];		//nahrnani kostky L s prislusnou rotaci
			}

		else if(c==2)			// tavar : obrácené L
			{
				if((stav) >= (4)) 	//pokud doslo k otoceni o 360°
					{	stav=0;	}
				sp=*ixLL[stav];	
			}

		else if(c==3)			// tavar : Z
			{
				if((stav) >= (2)) 	//pokud doslo k otoceni o 360°
					{	stav=0;	}
				sp=*iZZ[stav];	
			}

		else if(c==4)			// tavar : S
			{
				if((stav) >= (2)) 	//pokud doslo k otoceni o 360°
					{	stav=0;	}
				sp=*iSS[stav];
			}

		else if(c==5)			// tavar : I
			{
				if((stav) >= (2)) 	//pokud doslo k otoceni o 360°
					{	stav=0;	}
				sp=*iII[stav];	
			}

		else if(c==6)			// tavar : T
			{
				if((stav) >= (4)) 	//pokud doslo k otoceni o 360°
					{	stav=0;	}
				sp=*iTT[stav];	
			}
			roto=stav;
	}


void aktiva (unsigned char *isp)		////funkce na pocitani nenulovych radku padakjici kostky
	{
		rad=0;
	//	zap_tvar(roto);
			
		for(int ff=0;ff<buff;ff++)			//	pocitani nenulovych radku noveho symbolu
			{	if(*isp!=0)		
					{	rad++;	}	
				*isp--;
			}	
	}


void nacteni_symbolu (void)		//Nacte symbol do stavoveho pole koska(pk2)
	{
		zap_tvar(roto);
		for (int ii=0;ii<rad;ii++)
			{
				*(pk2) = *sp;
				*pk2--;
				*sp--;	
			}
		pk2=pk2b;
	}


void kontrola_kauzality(int ix)			//kontroluje jestli kostka ve stavovem poli neprekrila aktivni
			{							// LED ve statickem obrazu
				for (int j=0;j<rad;j++)
					{		
						if( ( ((*(ppou11+iii))&(*(pk2)))!=0) )
							{	sta++;	}
						*pk2--;
						ppou11--;		
					}
				pk2=pk2b;
				ppou11=ppou11b;
			}	


void posunP (void)		//posune kostku ve stavovem poli doprava
	{	int ii;
		int konec_obrazovky=0;
		int prekryti_kostek=0;

		for (ii=0;ii<rad;ii++)
			{
				if( ((*(pk2)&0b00000001)!=0 ) )		//kontrola nebylo-li dosazeno konce "obrazovky"
					{	konec_obrazovky++;	}
				*pk2--;
			}
		pk2=pk2b;

	if( konec_obrazovky==0 )				//pokud nebylo dosazeno konce obr.
		{
			for (ii=0;ii<rad;ii++)
				{
					*(pk2) =(*(pk2)>>1);	//posune kostku ve stav. poli o jeden bit doprava
					*pk2--;
				}
			pk2=pk2b;
		
			for (ii=0;ii<rad;ii++)			//kontrola jestli posun kostky nezpusobyl prekryti akt. LED
				{							// ve statickem obrazu
					if( (*(pk2)&*(ppou11+iii))!=0 )
							{	prekryti_kostek++;	}
					*ppou11--;
					*pk2--;
				}
			pk2=pk2b;
			ppou11=ppou11b;

			if(prekryti_kostek!=0 )		//pokud doslo k prekriti akt. LED vrati posun zpet.
				{
					for (ii=0;ii<rad;ii++)
						{
							*(pk2) =(*(pk2)<<1);	//posunutoP--;
							*pk2--;
						}
					pk2=pk2b;
				}
		}
		kontrola_kauzality(iii);
	if(( konec_obrazovky==0) && (prekryti_kostek==0)) posunutoP++;	//pokud bylo vse OK inkrementuje promennou posunutoP,
																	// ktera se vyuziva ve funkci rotace
	}


void posunL (void)			///Stejne jako pro posun doprava jen v opacnem smeru (doleva)
	{	int ii;
		int konec_obrazovky=0;
		int prekryti_kostek=0;

		for (ii=0;ii<rad;ii++)
			{
				if( (*(pk2)&0b10000000)!=0 )
					{	konec_obrazovky++;	}
				*pk2--;
			}
		 pk2=pk2b;

		if( konec_obrazovky==0 )
			{
				for (ii=0;ii<rad;ii++)
					{
						*(pk2) =(*(pk2)<<1);
						*pk2--;
					}
				pk2=pk2b;
		
				for (ii=0;ii<rad;ii++)
					{
						if( (*(pk2)&*(ppou11+iii))!=0 )
							{	prekryti_kostek++;	}
						*ppou11--;
						*pk2--;
					}
				pk2=pk2b;
				ppou11=ppou11b;

				if(prekryti_kostek!=0 )
					{
						for (ii=0;ii<rad;ii++)
							{
								*(pk2) =(*(pk2)>>1);	//posunutoP--;
								*pk2--;
							}
						pk2=pk2b;
					}
			}
		kontrola_kauzality(iii);
		if(( konec_obrazovky==0) && (prekryti_kostek==0)) posunutoL++;

	}



void rotace ( void )		// funkce ktera otoci kostku
		{
			int oka=0;

			roto++;
			zap_tvar(roto);			//nacteni noveho tvaru kostky
			aktiva(sp);

			for (int ii=0;ii<rad;ii++)		// kopirovani noveho tvaru
						{
							*(rsp) = *(sp);	
							*rsp--;
							*sp--;
						}
			rsp=rspb;
			
			for(int oo=0;oo<posunutoL;oo++)		//pokud nedoslo k posunu doleva tak  se tento cyklus neuplatni
				{								// 			
					for(int qi=0;qi<rad;qi++)
						{						//testovani zda je vlevo od kostky jeste misto, tedy nula
								if( (*(rsp-qi) & 0b10000000)!=0)	
									{	oka++;	}
						}

					if (oka==0)
						{
							for(int qi=0;qi<rad;qi++)
								{
									*(rsp) =(*(rsp)<<1);	
									*rsp--;	
								}
							rsp = rspb;
						}

					}
			oka=0;

			for(int oo=0;oo<posunutoP;oo++)		//pokud nedoslo k posunu doleva tak  se tento cyklus neuplatni
				{
					for(int qi=0;qi<rad;qi++)
						{						//testovani zda je vlevo od kostky jeste misto, tedy nula
								if( (*(rsp-qi) & 0b00000001)!=0)	
									{	oka++;	}
						}

					if (oka==0)
						{
							for(int qi=0;qi<rad;qi++)		//posune nove nacteny tvar kostky doprava 
								{							//pokud je jeste misto
									*(rsp) =(*(rsp)>>1);	
									*rsp--;	
								}
							rsp = rspb;
						}
					}

			oka=0;

			for(int qi=0;qi<rad;qi++)				// testuje zda posunem nedoslo k prekriti
					{						
							if ( (*(rsp-qi) & *(ppou11+iii)) !=0 )	
								{	oka++;	}
					}

			if (oka==0)
				{
					for(int qi=0;qi<rad;qi++)	//pokud bylo vse v poradku tak prekopiruje novy tvar symbolu
						{						// (orotovany a patricne posunuty) do stavoveho pole koska(pk)
							*(pk2) =(*(rsp));	
							*rsp--;	
							*pk2--;
						}
					rsp = rspb;
					pk2 = pk2b;
				}				
		}



void zobraz_fce(void)		// funkce vykreslujici stav hry na LED
	{	DDRB = 0b00000111;	
		
		if (sta==0)	
		{		
			for (int p=0;p<rad;p++)					//pokud nedoslo pri funkci kontrola_kauzality
				{	*(ppou22+iii-p)= *(pk2-p);	}	//k prekriti aktivnich LED prekopiruje stav kostky z pole koska
			*(ppou22+iii-rad-1)= 0;				//do pole urceneho pro zobrazovani padajici kostky (poule2)
		}	
		for (int zob=buff; zob<12; zob++)		//cyklus vykreslujici postupne radek po radku cele pole LED
			{	
				PORTB = (zob-buff);		// na spodnich 3 bitech portu B je urceni radku
				PORTA =~ *ppou11;		// na port A se posila cely adekvatni radek (8 bitu)
				*ppou11++;				// z pole statickeho obrazu
//delay_ms(1);								
										// na port A se posila cely adekvatni radek (8 bitu)
				PORTA =~ *ppou22;		// z pole poule2
				*ppou22++;				// 
//delay_ms(1);
			}
		ppou11 = ppou11b;
		ppou22 = ppou22b;
	}

