/*
  ##########################################################################################################################
  #                                                                                                                        #
  #       MAZE GENERATOR PROGRAM IN C PROGRAMMING LANGUAGE USING CONCEPT OF DATA STRUCTURE AND ALGORITHM                   #
  #                                                                                                                        #
  ##########################################################################################################################

*/


#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <conio.h>



typedef struct{
	int x, y;                                    //Node position - little waste of memory, but it allows faster generation
	void *parent;                                //Pointer to parent node
	char c;                                      //Character to be displayed
	char dirs;                                   //Directions that still haven't been explored
}Node;



Node *nodes;                                    //Nodes array  or pointer that works similar to the array
int width, height;                              //Maze dimensions should be in odd integer number





int init(){
	int i, j;
	Node *n;
	nodes = calloc( width * height, sizeof( Node ) );             //Allocate memory for maze
    // printf("nodes = %d\n\n",nodes);
	if ( nodes == NULL ){                                         //Exception handling
        return 1;
	}


	// to create boundaries

	for ( i = 0; i < width; i++ ){                                //Setup crucial nodes
		for ( j = 0; j < height; j++ ){
			n = nodes + i + j * width;
			if ( i * j % 2 ){                                     //for creating cell of maze
				n->x = i;
				n->y = j;
				n->dirs = 15;                //00001111                               //Assume that all directions can be explored (4 youngest bits set)
				n->c = ' ';
			}else{                                                //Add walls between nodes
			 n->c = '#';
			}
		}                                                        //ending of inner for
	}


	                                                            //ending of outer for
	return 0;                                                    // returning zero to say task successfully completed
}



Node *link( Node *n ){
	                                                            //Connects node to random neighbor (if possible) and returns
	                                                            //address of next node that should be visited

	int x, y;
	char dir;
	Node *dest;

                                                             	//Nothing can be done if null pointer is given - return
	if ( n == NULL ){                                           //Exception handling
        return NULL;
	}

	                                                            //While there are directions still unexplored
	while ( n->dirs ){



	/* rand function gives random value among 0,1,2,3.
	    depending upon the random value shifted 00000001 to left
	    for rand = 0,  dir = 00000001 == 1
        for rand = 1,  dir = 00000010 == 2
        for rand = 2,  dir = 00000100 == 4
        for rand = 3,  dir = 00001000 == 8
00000001
        */


		dir = ( 1 << ( rand() % 4 ) );                          //Randomly pick one direction


		/*
		   if dir = 00000001
		~00001111 == 11110000   bitwise 00000001

		ie 11110000 & 00000001 == 000000000

		*/


		                                                        //If it has already been explored - try again(exception handling)
		if ( ~ n->dirs & dir ){
                continue;
		}


		/*
		if dir = 00000001 then ~dir == 11111110 == 254

		a += b
		== a = a + b
		similarly
		 n->dirs &= ~dir;
		 ==
		  n->dirs =    n->dirs & ~dir;
         14 == 00001110 =   00001111 & 11111110

		*/

        n->dirs &= ~dir;                                        //Mark direction as explored


		                                                       //Depending on chosen direction
		switch ( dir ){
			                                                   //Check if it's possible to go right
			case 1:

			    /*
			    #####
			    #####
			    #####
			    */

				if ( n->x + 2 < width ){
					x = n->x + 2;
					y = n->y;
				}else{
				    continue;
				}
				break;

                                                               //Check if it's possible to go down
			case 2:


				if ( n->y + 2 < height){
					x = n->x;
					y = n->y + 2;

				}else{
				    continue;
				}
				break;

			                                                  //Check if it is possible to go left
			case 4:


				if ( n->x - 2 >= 0 ){
					x = n->x - 2;
					y = n->y;
				}else{
				    continue;
				}
				break;

			                                            //Check if it's possible to go up
			case 8:


				if ( n->y - 2 >= 0 ){
					x = n->x;
					y = n->y - 2;
				}else{
                    continue;
				}
				break;
		}


		/*
		nodes = 6500728
		let x = 1 and y = 1

		then x= 3, y =1

		so dest = 6500728 + 3 + 1 * 21
		        = 6500752
		*/


		dest = nodes + x + y * width;                //Get destination node into pointer (makes things a tiny bit faster)


		if ( dest->c == ' ' ){                       //Make sure that destination node is not a wall
                                                     //If destination is a linked node already - abort(terminated)
			if ( dest->parent != NULL ){
                 continue;
			}

			dest->parent = n;                                                   //Otherwise, adopt node


			  /*
			  n->x + ( x - n->x ) / 2 + ( n->y + ( y - n->y ) / 2 ) * width
			  1+(3 - 1)/2 + (1 +(1 - 1)/2)*21 == 23

			  here address of nodes[0] =  6500728
			  address of nodes[23] = 6500728 + 23 = 6500751


			  */

			                                                                     //Remove wall between nodes
			nodes[ n->x + ( x - n->x ) / 2 + ( n->y + ( y - n->y ) / 2 ) * width ].c = ' ';

			                                                                   //Return address of the child node
			return dest;
		}
	}

	//If nothing more can be done here - return parent's address
	return n->parent;
}








void draw(){
	int i, j;

	//Outputs maze to terminal - nothing special
	for ( i = 0; i < height; i++ ){
		for ( j = 0; j < width; j++ ){
			printf( "%c", nodes[j + i * width].c );
		}
		printf( "\n" );
	}
}


/*  method to move the player for future plan


void player(Node *basant){
    char select;
    Node *currentBasant;
    if(basant == NULL){
        printf("Error in player !!!");

    }else{
       basant->c = '#';
       printf(" A for Left\n");
       printf(" W for Up\n");
       printf(" D for Right\n");
       printf(" S for Down\n");

        while(1){

            select = getch();

            switch(select){

                 case 'a':
                     if(basant[0-1].c =='#'){

                     }else{
                     basant[0].c == ' ';
                     basant[0-1].c = '#';
                     currentBasant = & basant[0-1];
                     }
            //left arrow


            ###
            ###
            ###





                    break;

                 case 'w':
            //up arrow
              if(basant[0-width].c == '#'){

                     }else{
                     basant[0].c == ' ';
                     basant[0-width].c = '#';
                    currentBasant = & basant[0-width];

                     }


                   break;

                 case 'd':
            //right arrow
              if(basant[0+1].c == '#'){

                     }else{
                     basant[0].c == ' ';
                     basant[0+1].c = '#';
                     currentBasant = &basant[0+1];

                     }



                   break;
                 case 's':
                  //down arrow


            if(basant[0+width].c == '#'){

                     }else{
                     basant[0].c == ' ';
                     basant[0+width].c = '#';
                     currentBasant = &basant[0+width];
                     }
                   break;

             default:
                   continue;

            }


            //to draw a maze
            system("CLS");
	            draw();
            basant = currentBasant;


        }


    }
}


*/


int main(){


	Node *start, *last, *playerPosition;
	int ch;


	while(1){
        printf("\nWE HAVE FOLLOWING SERVICES.");
        printf("\n1.draw Maze");
        printf("\n2.Exit");
        printf("\nEnter tour choice : ");
        scanf("%d",&ch);

        switch(ch){
       case 1 :
                   //taking user input
	           printf("Enter dimension of maze( add number only ):>\n");
	           printf("Width = ");
	           scanf("%d",&width);
               printf("Height = ");
               scanf("%d",&height);
               printf("\n\n Generated maze is :\n\n\n\n");





	          //checking for dimension validity
	          if ( width < 3 || height < 3 ){
		       printf("invalid maze size value!\n");
		       exit( 1 );
	          }


	         //Allow only odd dimensions
	         if ( !( width % 2 ) || !( height % 2 ) ){
		      printf("dimensions must be odd!\n");
		      exit( 1 );
	        }

	           //Do not allow negative dimensions
	        if ( width <= 0 || height <= 0 ){
                printf("dimensions must be greater than 0!\n");
		        exit( 1 );
	        }

            //Seed random generator
	        srand( time( NULL ) );
	      //checking memory leak
	      if ( init() ){
             printf("out of memory!\n");
		     exit( 1 );
	      }



    //Setup start node


    /*

    start = nodes + 1 + width;
          = 6500728 +1 + 21
          = 6500750


          #######################################
          #start

    */

	start = nodes + 1 + width;
	playerPosition = start;
	start->parent = start;
	last = start;

	                                                  //Connect nodes until start node is reached and can't be left
	while( ( last = link(last) ) != start );

	draw();
	//code for player
	//function call to move the player for future plan
	//player(playerPosition);






        break;
       case 2:
           exit(0);
        break;
       default:
        printf("\nEnter correct choice !!!");

        }


	}
}