#include<iostream>
#include<cmath>
#include<ctime>

using namespace std;

// defining grid size
const int XSIZE = 5;
const int YSIZE = 5;
const double FOOD_PROB = .3;        // 30% prob of a grid zone having food
const double CAVE_PROB = .3;        // 20% prob of a grid zone having a cave
const double TELE_PROB = .5;        // 50% prob of Bin Laden teleporting through a cave.
const int FOOD_PACK    =  5;        // Amount of food the ranger gets when he gets food
const int TURN_FREEZE  =  3;        // Bin Laded needs to wait 3 moves after teleporting
const int INITIAL_FOOD_SUPPLY = 15; // The Ranger starts the game with 15 food units 

// defining structs
struct grid_zone {
	bool food;
	bool cave;
	bool osama;
	bool ranger;
	bool investigated;
	bool bombed;
};

struct special_forces {
	int food;
	void move(grid_zone grid[][YSIZE], int* pfood, special_forces ranger);
	void call_b52_airstrike(grid_zone grid[][YSIZE]);
};

struct terrorist {
	bool teleported;      // a flag to let the program know if bin laden 
	                      // teleported in his last move
	int wait;             // this variable will be used to count down the 3 
	                      // turn wait after teleporting
	void move(grid_zone grid[][YSIZE]);
};

struct point {
	int x;
	int y;
};
// global variables

int osama_x, osama_y;    // x and y positions for Osama in the grid
int ranger_x, ranger_y;  // x and y positions for The Ranger

// function definitions
void print_grid(grid_zone grid[][YSIZE], special_forces ranger);
void init_grid(grid_zone grid[][YSIZE]);
//void move_terrorist(grid_zone grid[][YSIZE]);
//void move_ranger(grid_zone grid[][YSIZE], int* pfood);
void print_grid_structures(grid_zone grid[][YSIZE]);
void init_players(int* pfood, bool* pteleported, int* pwait);
//void call_b52_airstrike();
bool hitOsama(grid_zone grid[][YSIZE]);

int main(void)
{
	grid_zone grid[XSIZE][YSIZE];
	special_forces ranger;          // This is the user
	terrorist osama;                // This is osama for the game
	bool found = false;             // Has Osama been captured yet?

	//cout << CLOCKS_PER_SEC << "\n";

	// initialize the players
	init_players(&ranger.food, &osama.teleported, &osama.wait); 

	//initialize the grid
	init_grid(grid);
	
	print_grid(grid, ranger);
	//print_grid_structures(grid);

	while (found == false){
		if (ranger.food <= 0){
			//ranger dies
			cout << "The ranger has run out of food and dies.\n";
			break;
		}
		osama.move(grid);
		ranger.move(grid, &ranger.food, ranger);
		//osama.move(grid);
		print_grid(grid, ranger);
		//print_grid_structures(grid);

		// Have we captured bin laden?
		if ( (osama_x == ranger_x) && (osama_y == ranger_y) ){
			cout << "\n**** You found Osama Bin Laden!!!!!! ****\n\n";
			found = true;
		}

		// did we hit him with bombs?


	}

	return 0;
}

void print_grid(grid_zone grid[][YSIZE], special_forces ranger)
{
	int i, j, n;
	bool pause = false;

	for(j=0; j<YSIZE; ++j){
		for(n=0; n<XSIZE; ++n){
			if(n == (XSIZE-1)){
				cout << "------\n";
			}else{
				cout << "-----";
			}
		}
		//cout << "-------------------------\n";
		for(i=0; i<XSIZE; ++i){

			// if the Ranger has entered this particular grid zone then print it, 
			// else we cannot see what's in it
			if (grid[j][i].investigated == true && grid[j][i].bombed == false){
				cout << "|";
				// caves
				if(grid[j][i].food == true){
					cout << "f";
				}else{
					cout << " ";
				}
				// Osama
				if( (i == osama_x) && (j == osama_y)){
					cout << "O";
				}else{
					cout << " ";
				}
				// food
				if(grid[j][i].cave == true){
					cout << "c";
				}else{
					cout << " ";				
				}
				// 101st Airborn Ranger
				if ( (i == ranger_x) && (j == ranger_y) ){
					if(i == (XSIZE-1) ){  // if on edge of grid
						cout << "R|\n";
					}else{
						cout << "R";
					}
				}else{
					if(i == (XSIZE-1) ){  // if on edge of grid
						cout << " |\n";
					}else{
						cout << " ";
					}
				}
			}else if(grid[j][i].investigated == false && grid[j][i].bombed == false){
				// this grid zone hasn't been investigated, don't show it
				if (i == (XSIZE-1)){
					cout << "|????|\n";
				}else{
					cout << "|????";
				}
			}else if(grid[j][i].bombed == true){
				if (i == (XSIZE-1)){
					cout << "|BOOM|\n";
				}else{
					cout << "|BOOM";
				}
			}
		}
	}
	for(n=0; n<XSIZE; ++n){
		if(n == (XSIZE-1)){
			cout << "------\n";
		}else{
			cout << "-----";
		}
	}
	// print the amount of food left over
	cout << " Food: " << ranger.food << "\n";

	// we just bombed, pause for a second and recall print_grid()
	for(j=0; j<YSIZE; ++j){
		for(i=0; i <XSIZE; ++i){
			if(grid[j][i].bombed == true){
				//cout << "debug: pause = true\n";
				pause = true;
				break;
			}
		}
		if (true == pause){
			break;
		}
	}

	if (pause){
		//cout << "debug: waiting\n";
		for(i=0; i<120E6; ++i);
	}

	// did we hit Osama?
	if (pause){
		if (hitOsama(grid)){
			cout << ":::::::::::::::::::::::::::::\n";
			cout << "::  You Bombed Bin Laden!! ::\n";
			cout << ":::::::::::::::::::::::::::::\n";
		}else{
			cout << "::::::::::::::\n";
			cout << "::  Missed  ::\n";
			cout << "::::::::::::::\n";
		}
	}


	// set all bombed to false

	for(j=0; j<YSIZE; ++j){
		for(i=0; i <XSIZE; ++i){
			grid[j][i].bombed = false;		
		}
	}

	if (pause){
		print_grid(grid, ranger);
	}


}

void print_grid_structures(grid_zone grid[][YSIZE])
{
	int i, j;

	for(j=0; j<YSIZE; ++j){
		for(i=0; i<XSIZE; ++i){
			cout << "food = " << grid[j][i].food << "\n";
			cout << "cave = " << grid[j][i].cave << "\n";
			cout << "osama = " << grid[j][i].osama << "\n";
			cout << "ranger = " << grid[j][i].ranger << "\n";
			cout << "inveti = " << grid[j][i].investigated << "\n";
			cout << "bombed = " << grid[j][i].bombed << "\n";
			cout << "---------\n";
		}
	}	
}

// *************************************************************** //
//  This function will initialize the grid.  It will place caves   //
//  at the corners of the grid for "teleportation" (or randomly    //
//  if you wish).  It will place food randomly.  The probability   //
//  of having food at a particular grid zone is given by the var   //
//  FOOD_PROB.  This function will all place Bin Laden randomly    //
//  in the map.                                                    //
// *************************************************************** //
void init_grid(grid_zone grid[][YSIZE])
{
	int i,j;

	srand( (unsigned)time(NULL) );

	// initialize food and caves

	for(j=0; j<YSIZE; ++j){
		for(i=0; i<XSIZE; ++i){
			// place food randomly around grid
			//cout << FOOD_PROB;
			if( ((double)rand() / RAND_MAX) < FOOD_PROB ){
				grid[j][i].food = true;
				//cout << "food\n";
			}else{
				//cout << "no food\n";
				grid[j][i].food = false;
			}

			// place caves randomly
			/*if( ((double)rand() / RAND_MAX) < CAVE_PROB ){
				grid[j][i].cave = true;
			}else{
				grid[j][i].cave = false;
			}*/

			// place caves at corners of grid for "teleporting"
			if( ((i == 0) && (j == 0))         ||
				((i == 0) && (j == (YSIZE-1))) ||
				((i == (XSIZE-1)) && (j == 0)) ||
				((i==(XSIZE-1)) && (j==(YSIZE-1))) ){
				grid[j][i].cave = true;
			}else{
				grid[j][i].cave = false;
			}
		}
	}

	// place Osama Bin Laden somewhere

	do{
		osama_x = rand() % 5;
		osama_y = rand() % 5;
	}while ( (osama_x == XSIZE) || (osama_y == YSIZE));
	
	//cout << "osama_x = " << osama_x << "; osama_y = " << osama_y << "\n";

	for(j=0; j<YSIZE; ++j){
		for(i=0; i<XSIZE; ++i){
			if( (osama_y == j) && (osama_x == i) ){
				grid[j][i].osama = true;
			}else{
				grid[j][i].osama = false;
			}
		}
	}

	// Place the 101st Airborn Ranger in the center of the grid
	ranger_x = (XSIZE-1);
	ranger_y = (YSIZE-1);
	for(j=0; j<YSIZE; ++j){
		for(i=0; i<XSIZE; ++i){
			if ( (j == ranger_y) && (i == ranger_x) ){
				//cout << " !!!!!!!!!!!!!\n";
				grid[j][i].ranger = true;
				grid[j][i].investigated = true;
			}else{
				//cout << " *************\n";
				grid[j][i].ranger = false;
				grid[j][i].investigated = false;
			}
		}
	}

	// set all grid zones to "not bombed" (yet!)

	for(j=0; j<YSIZE; ++j){
		for(i=0; i<XSIZE; ++i){
			grid[j][i].bombed = false;
		}
	}

	// for debugging purposes, set all grid zones to investigated = true so
	// we can see what's going on
	for(j=0; j<YSIZE; ++j){
		for(i=0; i<XSIZE; ++i){
			grid[j][i].investigated = true;
		}
	}
}

void init_players(int* pfood, bool* pteleported, int* pwait)
{
	*pfood = INITIAL_FOOD_SUPPLY;
	*pteleported = false;
	*pwait = TURN_FREEZE;
}

// *********************************************************************** //
//  This function will move the location of Osama Bin Laden in the grid.   //
// *********************************************************************** //
void terrorist::move(grid_zone grid[][YSIZE])
{
	int temp;
	bool move = NULL;
	bool done = false;
	int numCaves = 0; // number of caves on the grid
	int count = 0;
	int i,j;
	int cave_teleporting_to;

	int old_osama_x = osama_x;
	int old_osama_y = osama_y;

	// move Osama's x coordinate
	/* while (!move){
		temp = rand() % 3;
		if (temp == 0){ // move left
			if (osama_x == 0){
				move = false;
			}else{
				//cout << "Moving Osama to the left\n";
				--osama_x;
				move = true;
			}
		}
		if (temp == 1){
			// do nothing, stay put
			//cout << "Osama not moving horizontally\n";
			move = true;
		}
		if (temp == 2){ // move right
			if (osama_x == (XSIZE-1) ){
				move = false;
			}else{
				//cout << "Moving Osama to the right\n";
				++osama_x;
				move = true;
			}
		}
	}
	move = false;

	// move Osama's y coordinate
	while (!move){
		temp = rand() % 3;
		if (temp == 0){  // move up
			if(osama_y == 0){
				move = false;
			}else{
				//cout << "Moving Osama up\n";
				--osama_y;
				move = true;
			}
		}
		if (temp == 1){  // stay put
			//cout << "Osama not moving up or down\n";
			move = true;
		}
		if (temp == 2){  // move down
			if (osama_y == (YSIZE-1) ){
				move = false;
			}else{
				//cout << "Moving Osama down\n";
				++osama_y;
				move = true;
			}
		}
	} */

	// Is Osama in a cave?  If so, lets give him a TELE_PROB probability of teleporting

	if(grid[osama_y][osama_x].cave == true){ // osama is in a grid-zone with a cave
		if ( ((double)rand() / RAND_MAX) < TELE_PROB ){
			// Osama moves through the caves.  He comes out at a random one

			// first, count the number of caves in my grid (by default there is
			// four but this can change.
			for(j=0; j<YSIZE; ++j){
				for(i=0; i<XSIZE; ++i){
					if(grid[j][i].cave == true){
						++numCaves;
					}
				}
			}
			// define an array of cave locations.  We will randomly
			// pick a cave to teleport to from this array
			point * caves = new point [numCaves];

			// cycle through and fill up this new array with cave locations
			for(j=0; j<YSIZE; ++j){
				for(i=0; i<XSIZE; ++i){
					if(grid[j][i].cave == true){
						caves[count].x = i;
						caves[count].y = j;
						++count;
					}
				}
			}
			// 
			while (!done){
				cave_teleporting_to = rand() % numCaves; // gives ua a random number from 0 -> (numCaves-1)

				// check if we are already in this cave
				// if we are, loop through the while statement again
				if ( (caves[cave_teleporting_to].x == osama_x) && (caves[cave_teleporting_to].y == osama_y)){
					done = false;
				}else{
					done = true;
				}
			}
			// change osama's position
			osama_x = caves[cave_teleporting_to].x;
			osama_y = caves[cave_teleporting_to].y;
			move = true;
			//cout << "Osama has teleported to "<< osama_x << "," << osama_y << "\n";
		}
	} // end if(osama in a cave)

	while(move == false){
		temp = rand() % 9 + 1;  // get random number from 1 -> 9

		switch (temp){
			case 1: // move southwest
				if ( (osama_y == (YSIZE-1)) || (osama_x == 0) ){
					//cout << "*** Cannot move off the grid ***\n";
					move = false;
				}else{
					--osama_x;
					++osama_y;
					move = true;
				}
				break;

			case 2: // move south
				if ( osama_y == (YSIZE-1) ){
					//cout << "*** Cannot move off the grid ***\n";
					move = false;
				}else{
					++osama_y;
					move = true;
				}
				break;

			case 3: // move southeast
				if ( (osama_y == (YSIZE-1)) || (osama_x == (XSIZE-1)) ){
					//cout << "*** Cannot move off the grid ***\n";
					move = false;
				}else{
					++osama_y;
					++osama_x;
					move = true;
				}
				break;

			case 4: // move west
				if ( osama_x == 0 ){
					//cout << "*** Cannot move off the grid ***\n";
					move = false;
				}else{
					--osama_x;
					move = true;
				}
				break;

			case 5: // stay put
				move = true;
				break;

			case 6: // move east
				if (osama_x == (XSIZE-1) ){
					//cout << "*** Cannot move off the grid ***\n";
					move = false;
				}else{
					++osama_x;
					move = true;
				}
				break;

			case 7: // move northwest
				if ( (osama_y == 0) || (osama_x == 0) ){
					//cout << "*** Cannot move off the grid ***\n";
					move = false;
				}else{
					--osama_y;
					--osama_x;
					move = true;
				}
				break;

			case 8: // move north
				if (osama_y == 0){
					//cout << "*** Cannot move off the grid ***\n";
					move = false;
				}else{
					--osama_y;
					move = true;
				}
				break;

			case 9: // move northeast
				if ( (osama_y == 0) || (osama_x == (XSIZE-1) ) ){
					//cout << "*** Cannot move off the grid ***\n";
					move = false;
				}else{
					--osama_y;
					++osama_x;
					move = true;
				}
				break;

			default:
				cout << "That is not an option, choose again.\n";
				move = false;
		}

	}



	grid[old_osama_y][old_osama_x].ranger = 0;
	grid[osama_y][osama_x].ranger = 1;

}

// *************************************************************** //
//  This function will take input from the user and move the       //
//  ranger in the direction he/she desires.                        //
//  1 = southwest                                                  //
//  2 = south                                                      //
//  3 = southeast                                                  //
//  4 = west                                                       //
//  5 = stay put                                                   //
//  6 = east                                                       //
//  7 = northwest                                                  //
//  8 = north                                                      //
//  9 = northeast                                                  //
// *************************************************************** //
void special_forces::move(grid_zone grid[][YSIZE], int* pfood, special_forces ranger)
{
	char ranger_move;
	bool move = false;

	int old_ranger_x = ranger_x;
	int old_ranger_y = ranger_y;
	
	if (*pfood <= 0){ // this statement is probably not needed, taken care of in main()
		cout << "*** You don't have enough food to move, Osama Wins. ***\n";
	}else{
		while (move == false){

			cout << "Enter direction of movement > ";
			cin >> ranger_move;

			switch (ranger_move){
				/*case 1: // move southwest
					if ( (ranger_y == (YSIZE-1)) || (ranger_x == 0) ){
						cout << "*** Cannot move off the grid. Choose again ***\n";
						move = false;
					}else{
						--ranger_x;
						++ranger_y;
						move = true;
					}
					break;*/

				case '2': // move south
					if (ranger_y == (YSIZE-1)){
						cout << "*** Cannot move off the grid.  Choose again ***\n";
						move = false;
					}else{
						++ranger_y;
						move = true;
					}
					break;
		
				/*case 3: // move southeast
					if ( (ranger_y == (YSIZE-1)) || (ranger_x == (XSIZE-1)) ){
						cout << "*** Cannot move off the grid.  Choose again ***\n";
						move = false;
					}else{
						++ranger_y;
						++ranger_x;
						move = true;
					}
					break;*/

				case '4': // move west
					if (ranger_x == 0){
						cout << "*** Cannot move off the grid.  Choose again ***\n";
						move = false;
					}else{
						--ranger_x;
						move = true;
					}
					break;
	
				case '5': // stay put
					move = true;
					break;

				case '6': // move east
					if (ranger_x == (XSIZE-1)){
						cout << "*** Cannot move off the grid.  Choose again ***\n";
						move = false;
					}else{
						++ranger_x;
						move = true;
					}
					break;

				/*case 7: // move northwest
					if ( (ranger_x == 0) || (ranger_y == 0) ){
						cout << "*** Cannot move off the grid.  Choose again ***\n";
						move = false;
					}else{
						--ranger_x;
						--ranger_y;
						move = true;
					}
					break;*/

				case '8': // move north
					if (ranger_y == 0){
						cout << "*** Cannot move off the grid. Choose again ***\n";
						move = false;
					}else{
						--ranger_y;
						move = true;
					}
					break;
			
				/*case 9: // move northeast
					if ( (ranger_y == 0) || (ranger_x == (XSIZE-1)) ){
						cout << "*** Cannot move off the grid. Choose again ***\n";
						move = false;
					}else{
						++ranger_x;
						--ranger_y;
						move = true;
					}
					break;*/

				case 'b':
				case 'B': // call in a B52 Airstrike
					ranger.call_b52_airstrike(grid);
					move = true;
					break;

				default:
					cout << "That isn't a choice\n";
					move = false;
			}
		}
	}
	grid[old_ranger_y][old_ranger_x].ranger = false;
	grid[ranger_y][ranger_x].ranger = true;

	// now that we've moved, we will reduce the amount of food by one
	if(move){
		--*pfood;
	}

	// if we picked up food, ad that to the total amount
	if (grid[ranger_y][ranger_x].food == true){
		*pfood = *pfood + FOOD_PACK;
		// keep the "f" here so the user knows he landed on some food
		// we will remove it after he moves off the grid
		//grid[ranger_y][ranger_x].food = false;
	}

	// remove the "f" from the grid the Ranger is moving from
	if (grid[old_ranger_y][old_ranger_x].food == true){
		grid[old_ranger_y][old_ranger_x].food = false;
	}

	// now that we've investigated a new grid zone, we need to display it
	grid[ranger_y][ranger_x].investigated = true;
}

void special_forces::call_b52_airstrike(grid_zone grid[][YSIZE])
{
	int xf, xl;
	int yf, yl;

	cout << "You are calling in an air strike!\n";
	cout << "Enter first x coor >";
	cin >> xf;
	cout << "Enter first y coor >";
	cin >> yf;

	cout << "Enter last x coor >";
	cin >> xl;
	cout << "Enter last y coor >";
	cin >> yl;

	// mark those coordinates as bombed

	grid[yf][xf].bombed = true;
	grid[yl][xl].bombed = true;
}

bool hitOsama(grid_zone grid[][YSIZE])
{
	cout << "Debug: Enter hitOsama\n";

	int i, j;
	bool osamaDead = false;

	if (grid[osama_y][osama_x].bombed == true){
		osamaDead = true;
	}

	for(j=0; j<YSIZE; ++j){
		for(i=0; i<XSIZE; ++i){
			cout << grid[j][i].bombed << " ";
		}
		cout << "\n";
	}

	cout << "Debug: osamaDead = " << osamaDead << "\n";

	return (osamaDead);
	cout << "Debug: Exit hitOsama\n";
}




