Tetris AllRGB

// Block shapes
// block type *7, rotation*4, x-posision*4
int nrot[7]; // number of rotated shapes
int bs_wid[7][4]; // width
int bs_ofs[7][4][4];
int bs_hei[7][4][4];
int bs_min[7][4]; //min y at x
int bs_pos[7][4][4];

void init_bs_aux(int blk, int rot, int o1, int o2, int o3, int o4, int h1, int h2, int h3, int h4)
{
    bs_ofs[blk][rot][0]=o1;
    bs_ofs[blk][rot][1]=o2;
    bs_ofs[blk][rot][2]=o3;
    bs_ofs[blk][rot][3]=o4;

    bs_hei[blk][rot][0]=h1;
    bs_hei[blk][rot][1]=h2;
    bs_hei[blk][rot][2]=h3;
    bs_hei[blk][rot][3]=h4;

    int x,y;
    int ymin=99;
    int np=0;
    for(x=0;x<4;x++)
    {
	for(y=0;y<bs_hei[blk][rot][x];y++)
	{
	    bs_pos[blk][rot][np] = x*10+(bs_ofs[blk][rot][x]+y);
	    np++;
	}
	if(bs_hei[blk][rot][x]!=0) bs_wid[blk][rot]=x+1;
	if(bs_ofs[blk][rot][x] < ymin)
	{
	    ymin=bs_ofs[blk][rot][x];
	    bs_min[blk][rot]=x;
	}
    }
}

int cmp_int(const void *i, const void *j)
{
        int *pi = (int *)i;
	    int *pj = (int *)j;
	        return -pj[0]+pi[0];
}

void init_bs()
{
    int rot,x;

/* 2x2
##
## 00
*/
    nrot[0]=1;
    init_bs_aux(0, 0, 0,0,0,0, 2,2,0,0);

/* bar
####  #
      #
      #
      #
*/
    nrot[1]=2;
    init_bs_aux(1, 0, 0,0,0,0, 4,0,0,0);
    init_bs_aux(1, 1, 0,0,0,0, 1,1,1,1);

/* L and inverse-L
#   ##  
#    #  ###    #
##   #  #    ###

00 000 *20 011
*/
    nrot[2]=4;
    init_bs_aux(2, 0, 2,0,0,0, 1,3,0,0);
    init_bs_aux(2, 1, 0,1,1,0, 2,1,1,0);
    init_bs_aux(2, 2, 0,0,0,0, 3,1,0,0);
    init_bs_aux(2, 3, 0,0,0,0, 1,1,2,0);

    nrot[3]=4;
    init_bs_aux(3, 0, 0,2,0,0, 3,1,0,0);
    init_bs_aux(3, 1, 1,1,0,0, 1,1,2,0);
    init_bs_aux(3, 2, 0,0,0,0, 1,3,0,0);
    init_bs_aux(3, 3, 0,0,0,0, 2,1,1,0);

/* Z and inverse-Z
      #
##   ##
 ##  #
*/
    nrot[4]=2;
    init_bs_aux(4, 0, 1,0,0,0, 1,2,1,0);
    init_bs_aux(4, 1, 0,1,0,0, 2,2,0,0);
    nrot[5]=2;
    init_bs_aux(5, 0, 0,0,1,0, 1,2,1,0);
    init_bs_aux(5, 1, 1,0,0,0, 2,2,0,0);

/*
 #
###

#
##
#

###
 #

*/
    nrot[6]=4;
    init_bs_aux(6, 0, 1,0,1,0, 1,2,1,0);
    init_bs_aux(6, 1, 0,0,0,0, 1,2,1,0);
    init_bs_aux(6, 2, 1,0,0,0, 1,3,0,0);
    init_bs_aux(6, 3, 1,1,0,0, 3,1,0,0);
}


//Uncomment these for 4096x4096
#define CBIT 8
//Addressing scheme 4 is fastest for CBIT=8
#define ADR_SCHEME4

// Use these for 512x512 test
//#define CBIT 6
//Addressing scheme 0 is fastest for CBIT=6
//#define ADR_SCHEME0

/////////////////////////////////////////////////////
// no need to edit below
#define CADR_SCHEME0

// Misc. consts
#define VMAX (1<<CBIT)
#define CBMASK (VMAX-1)

#define LBIT (CBIT+CBIT/2)
#define L (1<<LBIT)
#define L2 (L*L)
#define L2MASK (L2-1)
#define LMASK (L-1)
#define LMASKY (L2MASK ^ LMASK)


//Address conversion
// x, y ->3char
#define BTMOV(x, mask, sh) (((x)&mask)<<sh)
#define BTMOV2(x, mask, sh) (((x)&mask)>>sh)
// c00000 c0000 c000 c00  c0   c
//  8421 8421   8421 8421 8421 8421
//  yyxx yyxx   yyxx yyxx yyxx yyxx

#ifdef ADR_SCHEME0
#define XY2ADR(x,y) ((x)|((y)*L))
#define ADR2XY(a,x,y) { x=a&(L-1);y=a/L;}
#endif

// 4bit
#ifdef ADR_SCHEME4
#define XY2ADR(x,y) (\
	BTMOV(x,0xf,  0) | BTMOV(y,0xf,  4) | \
	BTMOV(x,0xf0, 4) | BTMOV(y,0xf0, 8) | \
	BTMOV(x,0xf00,8) | BTMOV(y,0xf00,12))
#define ADR2XY(a,x,y) {\
    x=BTMOV2((a),0x0f,0)  |BTMOV2((a),0xf00,4)  |BTMOV2((a),0xf0000,8);\
    y=BTMOV2((a),0xf0,4)  |BTMOV2((a),0xf000,8) |BTMOV2((a),0xf00000,12);}
#endif

// 3bit
#ifdef ADR_SCHEME3
#define XY2ADR(x,y) (\
	BTMOV(x,07,  0)  | BTMOV(y,07, 3)  |\
	BTMOV(x,070, 3)  | BTMOV(y,070,6)  |\
	BTMOV(x,0700,6)  | BTMOV(y,0700,9) |\
	BTMOV(x,07000,9) | BTMOV(y,07000,12))
#define ADR2XY(a,x,y) {\
    x=BTMOV2((a),07,0)  |BTMOV2((a),0700,3)   |BTMOV2((a),070000,6)  |BTMOV2((a),07000000,9);\
    y=BTMOV2((a),070,3) |BTMOV2((a),07000,6)  |BTMOV2((a),0700000,9) |BTMOV2((a),070000000,12);}
#endif

// 2bit
#ifdef ADR_SCHEME2
#define XY2ADR(x,y) (\
	BTMOV(x,0x3, 0) | BTMOV(y,0x3, 2) | BTMOV(x,0xc,2) | BTMOV(y,0xc,4) |\
	BTMOV(x,0x30,4) | BTMOV(y,0x30,6) | BTMOV(x,0xc0,6)|BTMOV(y,0xc0,8) |\
	BTMOV(x,0x300,8) | BTMOV(y,0x300,10) | BTMOV(x,0xc00,10)|BTMOV(y,0xc00,12) )
#define ADR2XY(a,x,y) {\
    x=BTMOV2(a,0x03,0)  |BTMOV2(a,0x30,2)   |BTMOV2(a,0x300,4)|\
    BTMOV2(a,0x3000,6)|BTMOV2(a,0x30000,8)|BTMOV2(a,0x300000,10);\
    y=BTMOV2(a,0x0c,2)  |BTMOV2(a,0xc0,4)   |BTMOV2(a,0xc00,6)|\
    BTMOV2(a,0xc000,8)|BTMOV2(a,0xc0000,10)|BTMOV2(a,0xc00000,12);}
#endif
//////////////////////////////////////////////////////////
#ifdef CADR_SCHEME4
#define rgb2idx(r,g,b) (\
	BTMOV(r,0x0f,0) | BTMOV(g,0x0f,4)  | BTMOV(b, 0x0f,8) |\
	BTMOV(r,0xf0,8) | BTMOV(g,0xf0,12) | BTMOV(b, 0xf0,16) \
	)
#endif

#ifdef CADR_SCHEME0
#define rgb2idx(r,g,b) ((r)|((g)<<CBIT)|((b)<<(CBIT*2)))
#define idx2egb(c,r,g,b) {r=(c)&CBMASK; g=((c)>>CBIT)&CBMASK;b=((c)>>(CBIT*2))&CBMASK;}
#endif
/////////////////////////////////////////////////////
// global variables block
typedef unsigned char rgbtype;
// main color data
rgbtype colr[L2],colg[L2], colb[L2];

#include <math.h>
#include <string.h>

#include <stdio.h>
#include <stdlib.h>

// dump color to a file
void dump(int idx, rgbtype *rr, rgbtype *gg, rgbtype *bb)
{
    bool do_stuff = true;

    if (do_stuff)
    {
	//init_cidx();
	char fn[128];
	sprintf(fn, "%04d.ppm",idx);
	FILE *fp;
	unsigned char *pbuf = (unsigned char *)malloc(L2*3);
	fp=fopen(fn,"w");
	if (fp==NULL)
	{
	    printf("cannot open %s for dump\n",fn);
	    exit(1);
	}
	int i;
	int vv = 255/(VMAX-1);
	printf("#Dump %s, color scale *%d Size %f Mb\n",fn, vv, L2*3e-6);
	int x,y;
	for(i=0;i<L2;i++)
	{
	    ADR2XY(i, x, y);
	    int ad= (x+y*L)*3;
	    pbuf[ad+0] = vv*rr[i];
	    pbuf[ad+1] = vv*gg[i];
	    pbuf[ad+2] = vv*bb[i];
	}
	fprintf(fp, "P6\n%d %d\n255\n", L,L);
	fwrite(pbuf,1,L2*3,fp);
	fclose(fp);
	free(pbuf);
    }
}



#define CBOX 4 //16
#define LBOX 4 //32


#define CBOX3 (CBOX*CBOX*CBOX)
#define LBOX2 (LBOX*LBOX)
int ctabr[CBOX3];
int ctabg[CBOX3];
int ctabb[CBOX3];

#define MCOL (256/CBOX)
#define NCOL (MCOL*MCOL*MCOL)
//int cused[NCOL];
int blkcolr[7][NCOL];
int blkcolg[7][NCOL];
int blkcolb[7][NCOL];
int blkcolA[7][NCOL];
int blkcoli[7][NCOL];
int blkcol_used[7];
int blk2col[7]={7,2,3,4,1,6,5};

#define BW (L/LBOX)
int hei[BW];
int lock[BW];
int lockx;

int blk_idx(int r, int g, int b, int *lv)
{
    int bit;
    int l=0;
    for(bit=MCOL;bit!=0;bit>>=1)
    {
	int c=0;
	if(r&bit)c+=2;
	if(g&bit)c+=4;
	if(b&bit)c+=1;
	if(c!=0)
	{
	    *lv=bit;
	    return c;
	}
	l++;
    }
    *lv=1;
    return 7;
}
void init_cused()
{
    int i;
    for(i=0;i<7;i++) blkcol_used[i]=0;
    int mm,r,g,b,c;
    for(mm=0;mm<=MCOL*3;mm++)
    {
	//V
	for(r=0;r<=mm;r++)
	{
	    if(r>=MCOL)continue;
	    for(g=0;g<=mm-r;g++)
	    {
		if(g>=MCOL)continue;
		b=mm-r-g;
		if(b>=MCOL || b<0)continue;
		int lv;
                int blk = blk_idx(r,g,b, &lv)-1;
		int ix=blkcol_used[blk];
		if(ix>=NCOL)
		{
		    printf("#error blkcol small %d/%d\n",ix,NCOL);
		    exit(1);
		}
                blkcolr[blk][ix]=r*CBOX;
                blkcolg[blk][ix]=g*CBOX;
                blkcolb[blk][ix]=b*CBOX;
                blkcolA[blk][ix]=lv;
		blkcol_used[blk]++;
	    }
	}
    }//mm

        int sbuf[NCOL*2];
    for(i=0;i<7;i++)
    {
	printf("#Block %d ncol %d\n", i, blkcol_used[i]);

	int b0=0,g0=0,r0=0;
	if((i+1)&1)b0=1;
	if((i+1)&2)r0=1;
	if((i+1)&4)g0=1;
	//sort
	int j;
	for(j=0;j<blkcol_used[i];j++)
	{
	    int a=blkcolA[i][j];
	    int r=blkcolr[i][j];
	    int g=blkcolg[i][j];
	    int b=blkcolb[i][j];
	    if(r+g+b==0)
	    {
		sbuf[j*2]=0;sbuf[j*2+1]=j;
		continue;
	    }
	    r-=r0*a;
	    g-=g0*a;
	    b-=b0*a;

	    if(r<0 || g<0 || b<0)
	    {
		printf(" %d %d %d  b %d rgb0 %d %d %d\n",blkcolr[i][j],blkcolg[i][j],blkcolb[i][j],a,r0,g0,b0);
		exit(1);
	    }
	    //hue
	    int hue=0;
	    int max=r, min=r;
	    if(r+g+b==0)
	    {
		sbuf[j*2]=0;sbuf[j*2+1]=j;
		continue;
	    }

	    //case 0
	    if(r>=g && g>=b)
	    {
		hue = (int)(60* g/r);
	    }
	    //case 1
	    if(g>=r && r>=b)
	    {
		hue =60 + (int)(60*(g-r)/g);
	    }
	    //case 2
	    if(g>=b && b>=r)
	    {
		hue = 120+(int)(60* b/g);
	    }
	    //case 3
	    if(b>=g && g>=r)
	    {
		hue =180 + (int)(60*(b-g)/b);
	    }
	    //case 4
	    if(b>=r && r>=g)
	    {
		hue = 240+(int)(60* r/b);
	    }
	    //case 5
	    if(r>=b && b>=g)
	    {
		hue =300 + (int)(60*(r-b)/r);
	    }

	    sbuf[j*2]=hue + a*360;sbuf[j*2+1]=j;
	}

	qsort(sbuf, blkcol_used[i], sizeof(int)*2, cmp_int);
	for(j=0;j<blkcol_used[i];j++)
	    blkcoli[i][j] = sbuf[j*2+1];

    }

}

void init_config()
{
    int i;
    for(i=0;i<BW;i++)hei[i]=lock[i]=0;
    lockx=0;
}

void init_pal()
{
    int nc=0;
    // HSV - V sort
    int mm;
    for(mm=0;mm<=CBOX*3;mm++)
    {
	int r,g,b;
	//V
	for(r=0;r<=mm;r++)
	{
	    if(r>=CBOX)continue;
	    for(g=0;g<=mm-r;g++)
	    {
		if(g>=CBOX)continue;
		b=mm-r-g;
		if(b>=CBOX || b<0)continue;
		ctabr[nc]=r;
		ctabg[nc]=g;
		ctabb[nc]=b;
		printf("#%d  %d %d %d\n",nc, r,g,b);
		nc++;
	    }
	}
    }//mm
    //col sort
    if(nc!=CBOX3)
    {
	printf("Error ctab\n");
	exit(1);
    }
}

void draw1(int r1, int g1, int b1, int x, int y, int blk, int rot)
{

    int nlig=CBOX3-1;
    int ndark=0;
    int wid=2;

    int xx,yy;
    int bx0[4],by0[4];
    int np;
    for(np=0;np<4;np++)
    {
	int bb =bs_pos[blk][rot][np];
	int bx=bb/10;
	int by=bb%10;
	bx0[np]=bx+x;
	by0[np]=by+y;
	//printf("%d  %d %d\n",np,bx0[np],by0[np]);
    }	


    // draw margin
#if 1
    // up
    for(yy=0;yy<wid;yy++){
	for(xx=yy;xx<LBOX-yy;xx++){
	    for(np=0;np<4;np++)
	    {
		int x0=bx0[np]*LBOX+xx;
		int y0=L-1-by0[np]*LBOX-(LBOX-1-yy);
		int ad=XY2ADR(x0,y0);
		colr[ad]=r1+ctabr[nlig];
		colg[ad]=g1+ctabg[nlig];
		colb[ad]=b1+ctabb[nlig];
		nlig--;

		y0=L-1-by0[np]*LBOX-yy;
		ad=XY2ADR(x0,y0);
		colr[ad]=r1+ctabr[ndark];
		colg[ad]=g1+ctabg[ndark];
		colb[ad]=b1+ctabb[ndark];
		ndark++;
	    }
	}}
    // side
    for(xx=0;xx<wid;xx++){
	for(yy=xx+1;yy<LBOX-xx-1;yy++){
	    for(np=0;np<4;np++)
	    {
		int x0=bx0[np]*LBOX+xx;
		int y0=L-1-by0[np]*LBOX-(LBOX-1-yy);
		int ad=XY2ADR(x0,y0);
		colr[ad]=r1+ctabr[nlig];
		colg[ad]=g1+ctabg[nlig];
		colb[ad]=b1+ctabb[nlig];
		nlig--;

		x0=bx0[np]*LBOX+(LBOX-1-xx);
		y0=L-1-by0[np]*LBOX-yy;

		ad=XY2ADR(x0,y0);
		colr[ad]=r1+ctabr[ndark];
		colg[ad]=g1+ctabg[ndark];
		colb[ad]=b1+ctabb[ndark];
		ndark++;
	    }
	}}

#endif

    for(yy=wid;yy<LBOX-wid;yy++){
	for(xx=wid;xx<LBOX-wid;xx++){
	    for(np=0;np<4;np++)
	    {
		int x0=bx0[np]*LBOX+xx;
		int y0=L-1-by0[np]*LBOX-yy;
		int ad=XY2ADR(x0,y0);
		colr[ad]=r1+ctabr[ndark];
		colg[ad]=g1+ctabg[ndark];
		colb[ad]=b1+ctabb[ndark];
		ndark++;
	    }
	}}
    if(ndark!=nlig+1)
    {
	printf("#error ndark=%d %d\n",ndark,nlig);
	exit(1);
    }

}


int place(int blk)
{
    int  hmin=BW*100;
    int x,mx;
    int mcnt=1;
    for(x=0;x<BW;x++)
    {
	if((hei[x]<=hmin) && (lock[x]==0) && hei[x]!=BW)
	{
	    if (hei[x]==hmin)
	    {
	        int r=(rand()>>8)%mcnt;
		if(r!=0)continue;
		mcnt++;
	    }
	    else mcnt=1;
	    hmin=hei[x];
	    mx=x;
	}
    }
    int rot;
    int cnt;

    if(hmin>=BW *50/64)
    {
	mx=(rand()>>8)%BW;
    }
    hmin=hei[mx];


    for(cnt=0;cnt<100;cnt++)
    {
	rot=(rand()>>8)%nrot[blk];
	    int ok=1;

	    int x;
	    for(x=0;x<bs_wid[blk][rot];x++)
	    {
		int xx=mx-bs_min[blk][rot] +x;
		if(xx>=BW || (xx<0))
		{
		    ok=0;
		    break;
		}
		if(lock[xx] != 0)
		{
		    ok=0;
		    break;
		}
		if (hei[xx] != hmin +bs_ofs[blk][rot][x] )ok=0;
		if (hmin +bs_ofs[blk][rot][x] + bs_hei[blk][rot][x]>BW)ok=0;

		int mg=0;
#if 1
		if (hei[xx] < BW*52/64)mg=3;
		else
#endif
		if (hei[xx] < BW*56/64)mg=2;
		else
		if (hei[xx] < BW*60/64)mg=1;
		//x-overhang
		if(x==0 && xx!=0)
		{
		    if(hei[xx-1] < hei[xx]+bs_hei[blk][rot][x] -mg)ok=0;
		}
		else if(x!=0)
		{
		    if(bs_ofs[blk][rot][x-1]+bs_hei[blk][rot][x-1] < bs_ofs[blk][rot][x]+bs_hei[blk][rot][x] -mg)ok=0;
		}
		if(ok==0)break;
	    }//x

	    // Place
	    if (ok==1)
	    {
		// chose color
		int cblk=blk2col[blk]-1;
		int cnt=0;
		while(1)
		{
		    if(blkcol_used[cblk]!=0)break;
		    cblk=(rand()>>8)%7;
		    cnt++;
		    if(cnt==1000)exit(1);
		}
		int ix=blkcol_used[cblk]-1;
	        int ix0 =blkcoli[cblk][ix];

		int r= blkcolr[cblk][ix0];
		int g= blkcolg[cblk][ix0];
		int b= blkcolb[cblk][ix0];
		blkcol_used[cblk]--;

		draw1(r,g,b, mx-bs_min[blk][rot], hmin,  blk,  rot);

		for(x=0;x<bs_wid[blk][rot];x++)
		{
		    int xx=mx-bs_min[blk][rot] +x;
		    //printf("H %d ofs %d\n", hei[xx], bs_ofs[blk][rot][x]);
		    hei[xx]+= bs_hei[blk][rot][x];
		}

		return 1;
	    }//ok=1

	mx=(rand()>>8)%BW;
	hmin=hei[mx];
    }//try

    return 0;
}

int  main(int argc, char **argv)
{

    srand(atoi(argv[1]));
    int i;
    init_bs();
    init_pal();
    init_config();
    init_cused();

    //test address
    for(i=0;i<L2;i++)
    {
	int x,y,a2;
	ADR2XY(i,x,y);
	a2=XY2ADR(x,y);
	if(i!=a2)exit(1);
    }

    int npl=0;
    int cnt=0;
    while(1)
    {
	int blk=(rand()>>8)%7;
	npl+=place(blk);
	if(npl==(int)(BW*BW/4  ))break;
	cnt++;
	if(cnt==BW*BW*10)break;
    }
    printf("Left %d\n", BW*BW/4-npl);

    dump(6, colr,colg,colb); //exit(1);
}