/*
  This is a toolkit for making 2D grid mazes of arbitrary size.
  written by WolfCoder (2009)
*/

/* Includes */
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include "mazegen.h"

#define TILE_FLOOR 0
#define TILE_WALL 1
#define DIR_UP 1
#define DIR_RIGHT 2
#define DIR_DOWN 4
#define DIR_LEFT 8

// Each tile can be something, usually the floor or a wall
/* MAZEGEN Globals */
int maze_width, maze_height;
unsigned char maze[1000][1000];

/* INTERNAL USE ONLY: Recursivly makes the maze */
void maze_carve(int x,int y)
{
  /* Punch out the wall */
  maze[x][y] = TILE_FLOOR;
  printf("punch: (%d,%d)\n", x,y);
   
  /* Decide where to go next */
  int decide = rand()%4; /* 0, 1, 2, or 3 */
 
  while(1)
  { int openDir = 15;
    /* Only terminate when all four sides are either out of bounds or filled */
    if(y <= 1 || maze[x][y-2] == TILE_FLOOR)             openDir -= DIR_UP;
    if(x >= maze_width-2 || maze[x+2][y] == TILE_FLOOR)  openDir -= DIR_RIGHT;
    if(y >= maze_height-2 || maze[x][y+2] == TILE_FLOOR) openDir -= DIR_DOWN;
    if(x <= 1 || maze[x-2][y] == TILE_FLOOR)             openDir -= DIR_LEFT;
    if (openDir == 0) return;

    /* Try going upwards */
    if(decide == 0)
    { if (openDir & DIR_UP)
      { /* Carve upwards */
        //maze[x][y-1] = TILE_FLOOR;
        maze_carve(x,y-1);
      }
      else
      { /* Stop! We're not going there, pick a different direction */
        decide++;
      }
    }

    /* Try going Right */
    if(decide == 1)
    { if (openDir & DIR_RIGHT)
      { /* Carve right */
        //maze[x+1][y] = TILE_FLOOR;
        maze_carve(x+1,y);
      }
      else
      { /* Stop! We're not going there, pick a different direction */
        decide++;
      }
    }

    /* Try going Down */
    if(decide == 2)
    { if (openDir & DIR_DOWN)
      { /* Carve down */
        // maze[x][y+1] = TILE_FLOOR;
        maze_carve(x,y+1);
      }
      else
      { /* Stop! We're not going there, pick a different direction */
        decide++;
      }
    }


    /* Try going Left */
    if(decide == 3)
    { if (openDir & DIR_LEFT)
      { /* Carve left */
        //maze[x-1][y] = TILE_FLOOR;
        maze_carve(x-1,y);
      }
      else
      { /* Stop! We're not going there, pick a different direction */
        decide = 0;
      }
    }
  }
}

/* Generates a basic maze of width and height */
int maze_generate(int width, int height)
{
  /* Free any possible old maze */
  maze_free();

  /* Check the width and height */
  if (width < 3 || height < 3 || (width%2 == 0) || (height%2 == 0))
  { printf("Error: maze_generate(%d,%d): Maze dimensions must be odd integers >= 3.\n", width, height);
    return -1;
  }
  /* Allocate and fill the maze for use in memory */
  maze_width = width;
  maze_height = height;

  /* Fill the maze with wall tiles */
  //memset(maze,TILE_WALL,maze_width*maze_height*sizeof(unsigned char));
  int x, y;
  for(y = 0; y < maze_height; y++)
  { for(x = 0; x < maze_width; x++)
    { maze[x][y] = TILE_WALL;
      //printf("[%d, %d]:%d, ",x, y, maze[x][y]);

    }
  }


  /* Carve the maze out */
  int start_x = 1 + rand()%(maze_width-1);
  int start_y = 1 + rand()%(maze_height-1);
  /* make starting point odd */
  if (start_x%2 == 0) start_x--;
  if (start_y%2 == 0) start_y--;

  /* Now run the algorithm */
  maze_carve(start_x,start_y);

  /* Punch out the exit and entrance */
  maze[1][0] = TILE_FLOOR;
  maze[maze_width-2][maze_height-1] = TILE_FLOOR;
  return 0;
}

/* Frees memory used by the maze generator */
void maze_free()
{
}

/* Prints out the maze and its size */
void maze_print()
{
  int y,x;
  printf("Maze: Width=%d Height=%d\n",maze_width,maze_height);

  /* Go through the entire map */
  for(y = 0; y < maze_height; y++)
  { for(x = 0; x < maze_width; x++)
    { //printf("[%d, %d], ",x, y);

      /* Draw the tile if it's a wall, or a space if not. */
      if(maze[x][y] == TILE_WALL) printf("%c",219);
      else printf(" ");
    }
    /* Don't forget to return! */
    printf("\n");
  }
  printf("\n");
}

int main()
{ maze_generate(5,5); 
  maze_print();
}

