/*

Mind Killer
by Syed Mehroz Alam,

CIS-61, First Year, Sec-A, Batch 2002-03
Computer & Information Systems Dept,
NED University, Karachi, Pakistan.
Email: smehrozalam@yahoo.com

Date: 13-Dec-03
updated: 9-Apr-04
*/

#include
#include
#include
#include
#include
#include

//program constants(enumerations)
#define USERBOARD 1
#define RANDOMBOARD 2
#define F1_KEY 59


/* MAX_ORDER determines the maximum order of board
user_pos x,y determines the position of userboard (left board)
random_pos x,y determines the position of randomboard (given right board)
*/
#define MAX_ORDER 5
#define user_posx 80
#define user_posy 10
#define random_posx 350
#define random_posy  10


int SIZE;
int order=2;

typedef struct block
{
	int left;
	int right;
	int top;
	int bottom;
	int fill;
} BLOCK;

union REGS in,out;
BLOCK board[MAX_ORDER][MAX_ORDER];
BLOCK randomboard[MAX_ORDER][MAX_ORDER];
BLOCK userboard[MAX_ORDER][MAX_ORDER];

void Play(void);	//main function that uses the following:

//graphics and mouse initializers
void graph_init(void);
int initmouse(void);
void showmouseptr(void);
void restrictmouseptr(int x1, int y1, int x2, int y2);
void getmousepos(int *button, int *x, int *y);

void printblock(int x,int y,BLOCK bl);	//prints a single block at (x,y)
void makeboard(void);	//generates a board

//dislplays the passed board at position x,y
void displayboard(int x, int y, BLOCK b[MAX_ORDER][MAX_ORDER]);
void randomizeboard(void);	//randomizes the generated board

/*
the function returns the index of an element in a 2D array if its
starting address, size, no. of cols, and the given element's address is given
its a generic function that can be used for any type of array(int, char, etc)
*/
int find_element(void *starting_add, int cols, int size, void *element_add, int *x, int *y);

int chkboard(void);		//checks if the board is solved
void showhelp(void);	//displays help

void main(void)
{
	clrscr();
	textcolor(15);
	gotoxy(35,4); cprintf("Mind Killer");
	gotoxy(35,5); cprintf("ÍÍÍÍÍÍÍÍÍÍÍ");
	gotoxy(31,7); cprintf("by Syed Mehroz Alam");
	gotoxy(20,9);  cprintf("CIS-61, First Year, Sec-A, Batch 2002-03");
	gotoxy(20,10); cprintf("  Computer & Information Systems Dept,");
	gotoxy(20,11); cprintf("   NED University, Karachi, Pakistan.");
	gotoxy(20,13); cprintf("     Email: smehrozalam@yahoo.com");
	gotoxy(20,16); cprintf("     Press any key to begin......");
	getch();
	textcolor(7);

	Play();
}

void Play(void)
	{
	char temp[20];
	printf("\n\n\n\t\t\tEnter order(2 to 5) : ");
	order=atoi(gets(temp));
	SIZE=90-order*10;
	if ( order>5 || order<1 )
		exit(1);

	graph_init();
	int maxx=getmaxx(), maxy=getmaxy(), x, y, button;
	if (initmouse()==0)
	{
		outtextxy(400,425, "Can't Initialize Mouse..");
		outtextxy(400,450, "Press any key to exit...");
		getch();
		closegraph();
		exit(0);
	}

	restrictmouseptr(0,0,maxx-9,maxy-9);
	showmouseptr();

	randomize();
	makeboard();
	displayboard(user_posx,user_posy,userboard);
	randomizeboard();
	displayboard(random_posx,random_posy,randomboard);

	BLOCK *selected_box=NULL, *click_box=NULL;
	int click_x, click_y, click_board;
	int selected_x, selected_y, selected_board;
	int rec_x=0, rec_y=0;
	int block_x,block_y,invalid_move=0;
	char ch;
	time_t start, current;
	char tm[20];
	start = time(NULL);  /* Gets system time */
	float diff, temp_diff;
	int clearstatus=0;

	while ( 1 )
	{
		if (selected_box->fill==0 && clearstatus==0)
		{
			cleardevice();
			clearstatus=1;
		}
		displayboard(user_posx,user_posy,userboard);
		displayboard(random_posx,random_posy,randomboard);
		outtextxy(100,440,"Press F1 for help");
		current = time(NULL); /* Gets system time */
		temp_diff=difftime(current, start);
		if (temp_diff!=diff || selected_box->fill==0)
		{
			sprintf(tm, "Time ellapsed=%g secs", temp_diff );
			setcolor(0);
			setfillstyle(1,0);
			fillellipse(100, 420, 100, 10);
			setcolor(7);
			outtextxy(20,420,tm);
			diff=temp_diff;
		}



		if ( invalid_move==0 )	// if some block has moved
			if ( chkboard()==1 )
			{
				setcolor(15);
				outtextxy(100,400,"Congatulations! You have solved the game");
				for (int i=100;i<1500;i++)
				{
					sound(i);
					delay(1);
				}
				nosound();
				getch();
				closegraph();
				return;
			}
		if (rec_x)
		{
			setcolor(2);
			rectangle(rec_x, rec_y, rec_x+SIZE, rec_y+SIZE);
			setcolor(7);
		}
		delay(10);
		if ( kbhit() )
		{
			if ( (ch=getch())==27 ) // if escape key
				break;
			if (ch==0) // Special Key
			{
				char ch2=getch();
				if ( ch2==F1_KEY )
					showhelp();
			}

			if ( ch=='\r' )		// if Enter Key then display solution
			{
				outtextxy(getmaxx()-order*SIZE-20, getmaxy()-order*SIZE-35, "Solution");
				displayboard(getmaxx()-order*SIZE-20, getmaxy()-order*SIZE-20, board);
			}
		}
		getmousepos(&button, &x, &y);
		if (button==1)
			{
				clearstatus=0;
				click_x=(x-user_posx)/SIZE;
				click_y=(y-user_posy)/SIZE;
				if ( click_x>=0 && click_y>=0 && click_x<=order-1 && click_y<=order-1 ) // if clicked on userboard
				{
					rec_x=user_posx+click_x*SIZE+click_x*2;
					rec_y=user_posy+click_y*SIZE+click_y*2;
					click_box=&userboard[click_y][click_x];

					if ( click_box->fill!=0 )	// if clicked on filled box
					{
						selected_box=click_box;
					}
					else if ( click_box->fill==0 )	// if clicked on empty box
					{
						if ( selected_box!=NULL && selected_box->fill!=0)	// some box is already selected
						{
							invalid_move=0;
							find_element(userboard, MAX_ORDER, sizeof(userboard[0][0]), click_box, &block_x, &block_y);
							selected_box->fill=0;

							if ( block_x>0 && userboard[block_y][block_x-1].right!=selected_box->left && userboard[block_y][block_x-1].fill!=0)
								invalid_move=1;
							else if ( block_xright && userboard[block_y][block_x+1].fill!=0)
								invalid_move=1;
							else if ( block_y>0 && userboard[block_y-1][block_x].bottom!=selected_box->top && userboard[block_y-1][block_x].fill!=0)
								invalid_move=1;
							else if ( block_ybottom && userboard[block_y+1][block_x].fill!=0)
								invalid_move=1;

							if (!invalid_move)
							{
								*click_box=*selected_box;
//								selected_box->fill=0;
								click_box->fill=1;
							}
							else //if (invalid_move)
							{
								sound(1000);
								selected_box->fill=1;
								delay(100);
								nosound();
							}
						}
					}
				}

				else // if not clicked on userboard
				{
					click_x=(x-random_posx)/SIZE;
					click_y=(y-random_posy)/SIZE;
					if ( click_x>=0 && click_y>=0 && click_x<=order-1 && click_y<=order-1 )
					{
						rec_x=random_posx+click_x*SIZE+click_x*2;
						rec_y=random_posy+click_y*SIZE+click_y*2;
						click_box=&randomboard[click_y][click_x];
						if ( click_box->fill!=0 )	// if clicked on filled box
						{
							selected_box=click_box;
						}
						else	// if clicked on empty box
						{
							if ( selected_box!=NULL && selected_box->fill!=0)	// some box is already selected
							{
								*click_box=*selected_box;
								selected_box->fill=0;
							}
						}
					}	// end if clicked on randomboard

				}	// end if not clicked on userboard
			}	// end if (button==1)

	}
	closegraph();
}

void graph_init(void)
{
	/* request auto detection */
   int gdriver = DETECT, gmode, errorcode;

   /* initialize graphics and local variables */
   initgraph(&gdriver, &gmode, "..\\bgi");

   /* read result of initialization */
   errorcode = graphresult();
   /* an error occurred */
   if (errorcode != grOk)
   {
	  printf("Graphics error: %s\n", grapherrormsg(errorcode));
	  printf("Press any key to halt:");
	  getch();
	  exit(1);    /* terminate with an error code */
   }
}

int initmouse(void)
{
	in.x.ax=0;
	int86(0x33,&in, &out);
	return(out.x.ax);
}

void showmouseptr(void)
{
	in.x.ax=1;
	int86(0x33, &in, &out);
}

void restrictmouseptr(int x1, int y1, int x2, int y2)
{
	in.x.ax=7;
	in.x.cx=x1;
	in.x.dx=x2;
	int86(0x33,&in, &out);
	in.x.ax=8;
	in.x.cx=y1;
	in.x.dx=y2;
	int86(0x33, &in, &out);
}

void getmousepos(int *button, int *x, int *y)
{
	in.x.ax=3;
	int86(0x33, &in, &out);
	*button=out.x.bx;
	*x=out.x.cx;
	*y=out.x.dx;
}

void printblock(int x,int y,BLOCK bl)
{
	rectangle(x,y,x+SIZE,y+SIZE);
	setlinestyle(1,1,1);
	line(x,y,x+SIZE,y+SIZE);
	line(x+SIZE,y,x,y+SIZE);
	if ( bl.fill!=0 )
	{
		char temp[5];
		sprintf(temp, "%d", bl.left);
		outtextxy(x+5,y+SIZE/2-2, temp);
		sprintf(temp, "%d", bl.right);
		outtextxy(x+SIZE-10,y+SIZE/2-2, temp);
		sprintf(temp, "%d", bl.top);
		outtextxy(x+SIZE/2-2,y+5, temp);
		sprintf(temp, "%d", bl.bottom);
		outtextxy(x+SIZE/2-2,y+SIZE-10, temp);
	}
	setlinestyle(0,1,1);
}

void makeboard(void)
{
	for (int i=0;i0 && userboard[i][j].left!=userboard[i][j-1].right)
					return 0;
			if (i>0 && userboard[i][j].top!=userboard[i-1][j].bottom)
					return 0;
			if (j during the game displays one possible solution of the board.");
	setcolor(15);
	outtextxy(200,300, "Press any key to return to game");
	getch();
	setcolor(7);
	cleardevice();
}

    Source: geocities.com/smehrozalam/source

               ( geocities.com/smehrozalam)