

#include <stdio.h>
#include <io.h>
#include <system.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "poolcue.h"
#include "poolball.h"
#include "keyboard.h"

#define VC_MAX 3200
#define ACC 100
#define pi 3.1415926
#define angle_trans 0.05236   //!WXC
#define zero 0.0001
#define n_zero -0.0001
#define sq_zero 0.01
#define PRODUCT 0.34    // PRODUCT = dx * vc , when dx = min(zero), vc = vc_max
#define edge_acc 0.95


//Audio
//1 = loud; 2 = low
#define IOWR_AUDIO_EN(data)\
		IOWR_8DIRECT(AUDIO_0_BASE, 0, data);

//Write to vga ram
#define IOWR_VGA_STRENGTHBAR(data) \
	IOWR_16DIRECT(DE2_VGA_RASTER_0_BASE, 128, data)
#define SERVELINE_EN(flag)\
	IOWR_16DIRECT(DE2_VGA_RASTER_0_BASE, 130, flag)

//Words
//Enable
//6:WIN! ; 5: GAME ; 4: NEW ; 3: network ; 2: single ; 1: PLR 2 ; 0: PLR1
#define IOWR_VGA_WORD_EN(data) \
	IOWR_16DIRECT(DE2_VGA_RASTER_0_BASE, 132, data)
#define IOWR_VGA_WORD_HL_EN(data) \
	IOWR_16DIRECT(DE2_VGA_RASTER_0_BASE, 134, data)
#define IOWR_VGA_WORD_POS_X(n, data) \
	IOWR_16DIRECT(DE2_VGA_RASTER_0_BASE, (68 + 2*n)*2, data)
#define IOWR_VGA_WORD_POS_Y(n, data) \
	IOWR_16DIRECT(DE2_VGA_RASTER_0_BASE, (69 + 2*n)*2, data)

struct balltype
{
	int pos_x,pos_y;
	int vc_x, vc_y;
	int count_x, count_y;
	short int dir_x, dir_y;
	short int flag;
	float dx, dy;
	int force_move;
	int bias_x, bias_y;
}ball[16];


int hole[6][2]={{24,158},{320,154},{615,158},
				{24,461},{320,465},{615,461}};

int player=0;
int change=1;
int oops = 0;
int plball[2]={0,0};
int i_0 =0;
int i_1 =0;
int ex = 1;
int cue_ready = 0;
int angle = 0;
int strength = 0;
int release = 0;
int begin_flag;
float swtich_d;

void decide_direction(int ball_num)
{
	if((ball[ball_num].dx * ball[ball_num].dx + ball[ball_num].dy * ball[ball_num].dy) >= zero)
	{
		if(ball[ball_num].dx >= zero)
		{
			ball[ball_num].vc_x = (int)(PRODUCT / ball[ball_num].dx);
			ball[ball_num].dir_x = 1;
		}
		else if (ball[ball_num].dx <= n_zero)
		{
			ball[ball_num].vc_x = - (int)(PRODUCT / ball[ball_num].dx);
			ball[ball_num].dir_x = -1;
		}
		else
		{
			ball[ball_num].vc_x = VC_MAX + 1;
			ball[ball_num].dir_x = 0;
			ball[ball_num].dx = 0;
		}
		if(ball[ball_num].dy >= zero)
		{
			ball[ball_num].vc_y = (int)(PRODUCT / ball[ball_num].dy);
			ball[ball_num].dir_y = 1;
		}
		else if (ball[ball_num].dy <= n_zero)
		{
			ball[ball_num].vc_y = - (int)(PRODUCT / ball[ball_num].dy);
			ball[ball_num].dir_y = -1;
		}
		else
		{
			ball[ball_num].vc_y = VC_MAX + 1;
			ball[ball_num].dir_y = 0;
			ball[ball_num].dy = 0;
		}
	}
	else
	{
		ball[ball_num].vc_x = VC_MAX + 1;
		ball[ball_num].dir_x = 0;
		ball[ball_num].dx = 0;
		ball[ball_num].vc_y = VC_MAX + 1;
		ball[ball_num].dir_y = 0;
		ball[ball_num].dy = 0;
	}

	if(ball[ball_num].vc_x < ball[ball_num].count_x)
	{
		ball[ball_num].count_x = ball[ball_num].vc_x;
	}

	if(ball[ball_num].vc_y < ball[ball_num].count_y)
	{
		ball[ball_num].count_y = ball[ball_num].vc_y;
	}

}
void dir_change(int i, char axle, int change_to)
{
	if(axle == 'x')
	{
		if((change_to == 1 && ball[i].dx < 0) || (change_to == -1 && ball[i].dx > 0))
		{
			ball[i].dx = -ball[i].dx;
		}
	}
	else if(axle == 'y')
	{
		if((change_to == 1 && ball[i].dy < 0) || (change_to == -1 && ball[i].dy > 0))
		{
			ball[i].dy = -ball[i].dy;
		}
	}
}

void detect_bound_edge(int i)
{
	  if(ball[i].pos_x < 45 && ball[i].pos_y < 179)  //left_up pocket area
	  {
		  if(39 - ball[i].pos_x > 179 - ball[i].pos_y)
		  {
			  swtich_d = ball[i].dx;
			  ball[i].dx = ball[i].dy;
			  ball[i].dy = swtich_d;
			  dir_change(i, 'x', 1);
			  dir_change(i, 'y', -1);
			  ball[i].dx *= edge_acc;
			  ball[i].dy *= edge_acc;
			  decide_direction (i);
			  IOWR_AUDIO_EN(2);
		  }
		  else if(173 - ball[i].pos_y > 45 - ball[i].pos_x)
		  {
			  swtich_d = ball[i].dx;
			  ball[i].dx = ball[i].dy;
			  ball[i].dy = swtich_d;
			  dir_change(i, 'x', -1);
			  dir_change(i, 'y', 1);
			  ball[i].dx *= edge_acc;
			  ball[i].dy *= edge_acc;
			  decide_direction (i);
			  IOWR_AUDIO_EN(2);
		  }
	  }
	  else if(ball[i].pos_x > 594 && ball[i].pos_y < 179)  //right_up pocket area
	  {
		  if(ball[i].pos_x - 600 > 179 - ball[i].pos_y)
		  {
			  swtich_d = ball[i].dx;
			  ball[i].dx = ball[i].dy;
			  ball[i].dy = swtich_d;
			  dir_change(i, 'x', -1);
			  dir_change(i, 'y', -1);
			  ball[i].dx *= edge_acc;
			  ball[i].dy *= edge_acc;
			  decide_direction (i);
			  IOWR_AUDIO_EN(2);
		  }
		  else if(173 - ball[i].pos_y > ball[i].pos_x - 594)
		  {
			  swtich_d = ball[i].dx;
			  ball[i].dx = ball[i].dy;
			  ball[i].dy = swtich_d;
			  dir_change(i, 'x', 1);
			  dir_change(i, 'y', 1);
			  ball[i].dx *= edge_acc;
			  ball[i].dy *= edge_acc;
			  decide_direction (i);
			  IOWR_AUDIO_EN(2);
		  }

	  }
	  else if(ball[i].pos_x < 45 && ball[i].pos_y > 440)  //left_down pocket area
	  {
		  if(39 - ball[i].pos_x > ball[i].pos_y - 440)
		  {
			  swtich_d = ball[i].dx;
			  ball[i].dx = ball[i].dy;
			  ball[i].dy = swtich_d;
			  dir_change(i, 'x', 1);
			  dir_change(i, 'y', 1);
			  ball[i].dx *= edge_acc;
			  ball[i].dy *= edge_acc;
			  decide_direction (i);
			  IOWR_AUDIO_EN(2);

		  }
		  else if(ball[i].pos_y - 446 > 45 - ball[i].pos_x)
		  {
			  swtich_d = ball[i].dx;
			  ball[i].dx = ball[i].dy;
			  ball[i].dy = swtich_d;
			  dir_change(i, 'x', -1);
			  dir_change(i, 'y', -1);
			  ball[i].dx *= edge_acc;
			  ball[i].dy *= edge_acc;
			  decide_direction (i);
			  IOWR_AUDIO_EN(2);
		  }

	  }
	  else if(ball[i].pos_x > 594 && ball[i].pos_y > 440)  //right_down pocket area
	  {
		  if(ball[i].pos_x - 600 > ball[i].pos_y - 440)
		  {
			  swtich_d = ball[i].dx;
			  ball[i].dx = ball[i].dy;
			  ball[i].dy = swtich_d;
			  dir_change(i, 'x', -1);
			  dir_change(i, 'y', 1);
			  ball[i].dx *= edge_acc;
			  ball[i].dy *= edge_acc;
			  decide_direction (i);
			  IOWR_AUDIO_EN(2);

		  }
		  else if(ball[i].pos_y - 446 > ball[i].pos_x - 594)
		  {
			  swtich_d = ball[i].dx;
			  ball[i].dx = ball[i].dy;
			  ball[i].dy = swtich_d;
			  dir_change(i, 'x', 1);
			  dir_change(i, 'y', -1);
			  ball[i].dx *= edge_acc;
			  ball[i].dy *= edge_acc;
			  decide_direction (i);
			  IOWR_AUDIO_EN(2);
		  }
	  }
	  else
	  {
		  if(ball[i].pos_x <= 39)  //left edge
		  {
			  ball[i].pos_x = 39;
			  dir_change(i, 'x', 1);
			  ball[i].dx *= edge_acc;
			  //ball[i].dy *= edge_acc;
			  decide_direction (i);
			  IOWR_AUDIO_EN(2);
		  }
		  if(ball[i].pos_x >= 600)  //right edge
		  {
			  ball[i].pos_x = 600;
			  dir_change(i, 'x', -1);
			  ball[i].dx *= edge_acc;
			  //ball[i].dy *= edge_acc;
			  decide_direction (i);
			  IOWR_AUDIO_EN(2);
		  }

		  if(ball[i].pos_y <= 173)   //up edge
		  {
			  if(ball[i].pos_y > 168 ) //up_mid pocket area
			  {
				  if(ball[i].pos_x < 336 && ball[i].pos_x > 304)
				  {

					  if(173 - ball[i].pos_y > ball[i].pos_x - 304)
					  {
						  swtich_d = ball[i].dx;
						  ball[i].dx = ball[i].dy;
						  ball[i].dy = swtich_d;
						  dir_change(i, 'x', 1);
						  dir_change(i, 'y', 1);

						  ball[i].dx *= edge_acc;
						  ball[i].dy *= edge_acc;
						  decide_direction (i);
						  IOWR_AUDIO_EN(2);

					  }
					  else if(173 - ball[i].pos_y > 336 - ball[i].pos_x)
					  {
						  swtich_d = ball[i].dx;
						  ball[i].dx = ball[i].dy;
						  ball[i].dy = swtich_d;
						  dir_change(i, 'x', -1);
						  dir_change(i, 'y', 1);

						  ball[i].dx *= edge_acc;
						  ball[i].dy *= edge_acc;
						  decide_direction (i);
						  IOWR_AUDIO_EN(2);
					  }

				  }
				  else  //normal
				  {
					  ball[i].pos_y = 173;
					  dir_change(i, 'y', 1);
					  //ball[i].dx *= edge_acc;
					  ball[i].dy *= edge_acc;
					  decide_direction (i);
					  IOWR_AUDIO_EN(2);

				   }
			  }
			  else
			  {
				  if(ball[i].pos_x >= 325)
				  {
					  //ball[i].pos_y = 173;
					  dir_change(i, 'x', -1);
					  ball[i].dx *= edge_acc;
					  //ball[i].dy *= edge_acc;
					  decide_direction (i);
					  IOWR_AUDIO_EN(2);
				  }
				  else if(ball[i].pos_x <= 315)
				  {
					  //ball[i].pos_y = 173;
					  dir_change(i, 'x', 1);
					  ball[i].dx *= edge_acc;
					  //ball[i].dy *= edge_acc;
					  decide_direction (i);
					  IOWR_AUDIO_EN(2);

				  }
			  }


		  }

		  if(ball[i].pos_y >= 446)   //down edge
		  {
			  if(ball[i].pos_y < 451) //up_mid pocket area
			  {
				  if(ball[i].pos_x < 336 && ball[i].pos_x > 304)
				  {
					  if(ball[i].pos_y - 446 > ball[i].pos_x - 304)
					  {
						  swtich_d = ball[i].dx;
						  ball[i].dx = ball[i].dy;
						  ball[i].dy = swtich_d;
						  dir_change(i, 'x', 1);
						  dir_change(i, 'y', -1);

						  ball[i].dx *= edge_acc;
						  ball[i].dy *= edge_acc;
						  decide_direction (i);
						  IOWR_AUDIO_EN(2);

					  }
					  else if(ball[i].pos_y - 446 > 336 - ball[i].pos_x)
					  {
						  swtich_d = ball[i].dx;
						  ball[i].dx = ball[i].dy;
						  ball[i].dy = swtich_d;
						  dir_change(i, 'x', -1);
						  dir_change(i, 'y', -1);

						  ball[i].dx *= edge_acc;
						  ball[i].dy *= edge_acc;
						  decide_direction (i);
						  IOWR_AUDIO_EN(2);
					  }

				  }
				  else  //normal
				  {
					  ball[i].pos_y = 446;
					  dir_change(i, 'y', -1);
					  //ball[i].dx *= edge_acc;
					  ball[i].dy *= edge_acc;
					  decide_direction (i);
					  IOWR_AUDIO_EN(2);
				  }
			  }
			  else
			  {
				  if(ball[i].pos_x >= 325)
				  {
					  //ball[i].pos_y = 173;
					  dir_change(i, 'x', -1);
					  ball[i].dx *= edge_acc;
					  //ball[i].dy *= edge_acc;
					  decide_direction (i);
					  IOWR_AUDIO_EN(2);
				  }
				  else if(ball[i].pos_x <= 315)
				  {
					  //ball[i].pos_y = 173;
					  dir_change(i, 'x', 1);
					  ball[i].dx *= edge_acc;
					  //ball[i].dy *= edge_acc;
					  decide_direction (i);
					  IOWR_AUDIO_EN(2);
				  }
			  }


		  }

	  }
}

void bound_balls(int b1,int b2)
{
	float s1=100,s2=100,s,d1,d2,x,y,dx1,dx2,dy1,dy2;
	float dis_v_sq;
	int dis1_x, dis2_x;
	int dis1_y, dis2_y;

	x = ball[b2].pos_x - ball[b1].pos_x;
	y = ball[b2].pos_y - ball[b1].pos_y;

	//Audio

	dis_v_sq = (ball[b2].dx - ball[b1].dx)*(ball[b2].dx - ball[b1].dx) + (ball[b2].dy - ball[b1].dy)*(ball[b2].dy - ball[b1].dy);
	if(dis_v_sq > 0.1024)
	{
		IOWR_AUDIO_EN(1);
	}
	else if(dis_v_sq > 0)
	{
		IOWR_AUDIO_EN(1);
	}


	if(!(fabs(ball[b1].dx) < zero && fabs(ball[b1].dy) < zero))
	{
		s1 = atan2(ball[b1].dy,ball[b1].dx);
	}

	if(!(fabs(ball[b2].dx) < zero && fabs(ball[b2].dy) < zero))
	{
		s2 = atan2(ball[b2].dy,ball[b2].dx);
	}
	s = atan2(y,x);

	if(s1!=100 && fabs(s-s1) < pi/2)
	{
		d1=sqrt(ball[b1].dx * ball[b1].dx + ball[b1].dy * ball[b1].dy)*cos(s-s1);
		dx1= d1*cos(s);
		dy1= d1*sin(s);
		ball[b1].dx -= dx1;
		ball[b1].dy -= dy1;
		ball[b2].dx += dx1;
		ball[b2].dy += dy1;
	}

	if(s2 != 100 && fabs(s-s2) > pi/2)
	{
		d2=sqrt(ball[b2].dx * ball[b2].dx + ball[b2].dy * ball[b2].dy)*cos(pi-(s-s2));
		dx2= d2*cos(pi-s);
		dy2= d2*sin(pi-s);
		ball[b1].dx += dx2;
		ball[b1].dy += dy2;
		ball[b2].dx -= dx2;
		ball[b2].dy -= dy2;
	}


	ball[b1].dx *= 0.90;
	ball[b1].dy *= 0.90;
	ball[b2].dx *= 0.90;
	ball[b2].dy *= 0.90;
	decide_direction (b1);
	decide_direction (b2);

	if(x*x + y*y < 196)
	{
		if(x > 0)
		{
			dis2_x = 1;
			dis1_x = -1;
		}
		else
		{
			dis2_x = -1;
			dis1_x = 1;
		}

		if(y > 0)
		{
			dis2_y = 1;
			dis1_y = -1;
		}
		else
		{
			dis2_y = -1;
			dis1_y = 1;
		}

		moveball(b1, &ball[b1].pos_x, &ball[b1].pos_y, dis1_x, dis1_y, &ball[b1].bias_x, &ball[b1].bias_y);
		moveball(b2, &ball[b2].pos_x, &ball[b2].pos_y, dis2_x, dis2_y, &ball[b2].bias_x, &ball[b2].bias_y);

		ball[b2].force_move = 1;
	}
}

void win(int b)
{
	int i,m=0;
	if(b==7)    // if the black ball pockets
	{
		ex = 0;
		//printf("Start again?\n");
		ball[b].pos_x = 120;
		ball[b].pos_y = 48;
		placeball(b, ball[b].pos_x, ball[b].pos_y, 0, 0, &ball[b].bias_x, &ball[b].bias_y);
		if(plball[player]==0)    // if player directly pocket the black ball without pocketing his balls first
		{
			//printf("win player: %d",!player);
			IOWR_VGA_WORD_EN(71);
			IOWR_VGA_WORD_POS_X(0, 52);
			IOWR_VGA_WORD_POS_Y(0, 60);
			IOWR_VGA_WORD_POS_X(1, 52);
			IOWR_VGA_WORD_POS_Y(1, 90);
			IOWR_VGA_WORD_POS_X(2, 550);
			IOWR_VGA_WORD_POS_Y(2, 40);
			if(player == 0)
			{
				IOWR_VGA_WORD_HL_EN(64);
				IOWR_VGA_WORD_POS_X(6, 10);
				IOWR_VGA_WORD_POS_Y(6, 90);
			}
			else
			{
				IOWR_VGA_WORD_HL_EN(64);
				IOWR_VGA_WORD_POS_X(6, 10);
				IOWR_VGA_WORD_POS_Y(6, 60);
			}
		}
		else
		{
			for(i = plball[player]-1; i < plball[player]+6; i++)
			{
				if(ball[i].flag==1)  // if player doesn't pocket all his balls before pocketing black ball
				{
					m=1;
					break;
				}
			}
			if(m)
			{
				printf("win player: %d",!player);
				IOWR_VGA_WORD_EN(71);
				IOWR_VGA_WORD_POS_X(0, 52);
				IOWR_VGA_WORD_POS_Y(0, 60);
				IOWR_VGA_WORD_POS_X(1, 52);
				IOWR_VGA_WORD_POS_Y(1, 90);
				IOWR_VGA_WORD_POS_X(2, 550);
				IOWR_VGA_WORD_POS_Y(2, 40);
				if(player == 0)
				{
					IOWR_VGA_WORD_HL_EN(64);
					IOWR_VGA_WORD_POS_X(6, 10);
					IOWR_VGA_WORD_POS_Y(6, 60);
				}
				else
				{
					IOWR_VGA_WORD_HL_EN(64);
					IOWR_VGA_WORD_POS_X(6, 10);
					IOWR_VGA_WORD_POS_Y(6, 90);
				}
			}
			else
			{
				printf("win player: %d",player);
				IOWR_VGA_WORD_EN(71);
				IOWR_VGA_WORD_POS_X(0, 52);
				IOWR_VGA_WORD_POS_Y(0, 60);
				IOWR_VGA_WORD_POS_X(1, 52);
				IOWR_VGA_WORD_POS_Y(1, 90);
				IOWR_VGA_WORD_POS_X(2, 550);
				IOWR_VGA_WORD_POS_Y(2, 40);
				if(player == 0)
				{
					IOWR_VGA_WORD_HL_EN(64);
					IOWR_VGA_WORD_POS_X(6, 10);
					IOWR_VGA_WORD_POS_Y(6, 90);
				}
				else
				{
					IOWR_VGA_WORD_HL_EN(64);
					IOWR_VGA_WORD_POS_X(6, 10);
					IOWR_VGA_WORD_POS_Y(6, 60);
				}
			}
		}
	}
	else if(b==15)		//if the cue ball pockets
	{
		oops = 1;
		ball[b].pos_x = 100;
		ball[b].pos_y = 48;
		placeball(b, ball[b].pos_x, ball[b].pos_y, 0, 0, &ball[b].bias_x, &ball[b].bias_y);
	}
	else if(plball[player]==0)	//if player first pockets a ball, then he has to pocket the same type balls afterwards
	{
		if(b >=0 && b < 7)
		{
			plball[player]=1;
			plball[!player]=9;
			if(player == 0)
			{
				ball[b].pos_x = 100 + 17 * i_0;
				ball[b].pos_y = 68;
				placeball(b, ball[b].pos_x, ball[b].pos_y, 0, 0, &ball[b].bias_x, &ball[b].bias_y);
				i_0 ++;
			}
			else
			{
				ball[b].pos_x = 100 + 17 * i_1;
				ball[b].pos_y = 98;
				placeball(b, ball[b].pos_x, ball[b].pos_y, 0, 0, &ball[b].bias_x, &ball[b].bias_y);
				i_1 ++;
			}
		}
		else if(b >= 8&&b<15)
		{
			plball[player]=9;
			plball[!player]=1;
			if(player == 0)
			{
				ball[b].pos_x = 100 + 17 * i_0;
				ball[b].pos_y = 68;
				placeball(b, ball[b].pos_x, ball[b].pos_y, 0, 0, &ball[b].bias_x, &ball[b].bias_y);
				i_0 ++;
			}
			else
			{
				ball[b].pos_x = 100 + 17 * i_1;
				ball[b].pos_y = 98;
				placeball(b, ball[b].pos_x, ball[b].pos_y, 0, 0, &ball[b].bias_x, &ball[b].bias_y);
				i_1 ++;
			}
		}
		change=0;
	}
}

void place_cue_ball()
{
	int i;
	int f;
	SERVELINE_EN(1);
	while(cue_ready == 0)
	{
		get_key(&strength, &angle, &release);
		ball[15].pos_x = 172;
		ball[15].pos_y = 173 + (int)(2.3 * angle);
		placeball(15, ball[15].pos_x, ball[15].pos_y, 0, 0, &ball[15].bias_x, &ball[15].bias_y);
		if(release == 1)
		{
			f = 1;
			for(i = 0; i < 15; i++)
			{
				if(ball[i].pos_x >= 158 && ball[i].pos_x <= 186)
				{
					if(ball[i].pos_y >= (ball[15].pos_y - 14) && ball[i].pos_y <= (ball[15].pos_y + 14))
					{
						f = 0;
					}
				}
			}
			if(f)
			{
				cue_ready =1;
				begin_flag = 0;
				ball[15].flag = 1;
				SERVELINE_EN(0);
			}
			release = 0;
		}
	}
}

int main()
{
	printf("Hello from Nios II!\n");

	int i;
	int j;
	int ff;
	float temp_angle;
	int acc_count = 0;
	short int move_flag;
	short int bias_x;
	short int bias_y;
	int dis_x;
	int dis_y;
	int hole_dis_x;
	int hole_dis_y;

	int ballxy_triangle[15][2]={{3,4},{1,-3},{-1,2},{-3,-1},
								{3,-4},{3,-2},{1,-1},{-1,0},
								{-5,0},{1,1},{3,0},{-3,1},
								{-1,-2},{1,3},{3,2},};

start:
    angle = 60;
	strength = 0;
	release = 0;
	cue_ready = 0;
	i_0 = 0;
	i_1 = 0;
	begin_flag = 0;
	oops = 0;
	//display "NEW GAME"
	IOWR_VGA_WORD_EN(48);
	IOWR_VGA_WORD_HL_EN(48);
	IOWR_VGA_WORD_POS_X(4, 280);
	IOWR_VGA_WORD_POS_Y(4, 60);
	IOWR_VGA_WORD_POS_X(5, 320);
	IOWR_VGA_WORD_POS_Y(5, 60);
	get_key(&strength, &angle, &release);
	if(release == 0)  //wait for player to press "return"
	{
		goto start;
	}
	release = 0;

	//display main screen printouts
	IOWR_VGA_WORD_EN(15);
	IOWR_VGA_WORD_HL_EN(5);
	IOWR_VGA_WORD_POS_X(0, 52);
	IOWR_VGA_WORD_POS_Y(0, 60);
	IOWR_VGA_WORD_POS_X(1, 52);
	IOWR_VGA_WORD_POS_Y(1, 90);
	IOWR_VGA_WORD_POS_X(2, 550);
	IOWR_VGA_WORD_POS_Y(2, 40);
	IOWR_VGA_WORD_POS_X(3, 550);
	IOWR_VGA_WORD_POS_Y(3, 60);

	// initialize the position of the balls
	for(i = 0; i < 15; i++)			// initialize the position of the 15 balls
	{
		ball[i].pos_x = 500 + ballxy_triangle[i][0]*8;
		ball[i].pos_y = 310 + ballxy_triangle[i][1]*8;
		placeball(i, ball[i].pos_x, ball[i].pos_y, 0, 0, &ball[i].bias_x, &ball[i].bias_y);
		ball[i].flag = 1;
		ball[i].force_move = 0;
	}
	/*ball[15].pos_x = 104;
	ball[15].pos_y = 300;
	placeball(15, ball[15].pos_x, ball[15].pos_y, 0, 0, &ball[15].bias_x, &ball[15].bias_y);
	ball[15].flag = 1;*/

	// initialize the speed and direction of the balls
	for(i = 0; i < 16; i++)
	{
		ball[i].vc_x = VC_MAX + 1;
		ball[i].vc_y = VC_MAX + 1;
		ball[i].count_x = 0;
		ball[i].count_y = 0;
		ball[i].dir_x = 1;
		ball[i].dir_y = -1;
		ball[i].dx = 0;
		ball[i].dy = 0;
	}
	// initialize the strength bar
	strength = 16;
	IOWR_VGA_STRENGTHBAR(16);

	/*ball[7].flag = 1;
		  //ball[15].flag = 1;
		  //ball[15].pos_x = 334;
		  //ball[15].pos_y = 178;
		  ball[7].pos_x = 172;		//left-up hole : 24,158
		  ball[7].pos_y = 180;
		  placeball(7, ball[7].pos_x, ball[7].pos_y, 0, 0, &ball[7].bias_x, &ball[7].bias_y);
		  //placeball(15, ball[15].pos_x, ball[15].pos_y, 0, 0, &ball[15].bias_x, &ball[15].bias_y);*/


	place_cue_ball();
	printf("cue_ready = %d",cue_ready);

	ball[7].flag = 1;
	ball[15].flag = 1;
	ball[15].pos_x = 305;
	ball[15].pos_y = 178;
	ball[7].pos_x = 34;		//left-up hole : 24,158
	ball[7].pos_y = 168;
	placeball(7, ball[7].pos_x, ball[7].pos_y, 0, 0, &ball[7].bias_x, &ball[7].bias_y);
	placeball(15, ball[15].pos_x, ball[15].pos_y, 0, 0, &ball[15].bias_x, &ball[15].bias_y);


	while(cue_ready)
	{

		while(ex)
		{
			while(begin_flag == 0)
			{
				cx = ball[15].pos_x;
				cy = ball[15].pos_y;
				get_key(&strength, &angle, &release);
				print_poolcue(cx, cy, angle);
				IOWR_VGA_STRENGTHBAR(strength);

				if (release == 1)
				{
					begin_flag = 1;
					temp_angle = angle_trans * angle;
					ball[15].dx= - (strength + 1) * sq_zero * cos(temp_angle);
					ball[15].dy= - (strength + 1) * sq_zero * sin(temp_angle);
					decide_direction (15);
					ball[15].count_x = ball[15].vc_x;
					ball[15].count_y = ball[15].vc_y;
				}
			}

			while(begin_flag == 1)
			{
				release = 0;
				for(i = 15; i >= 0; i--)
				{
					if(ball[i].flag != 0)
					{
						move_flag = 0;
						//Update (Position update) counter
								if(ball[i].count_x > 0)
								{
									ball[i].count_x --;
									bias_x = 0;
								}
								else if(ball[i].vc_x <= VC_MAX)
								{
									ball[i].count_x = ball[i].vc_x;
									move_flag = 1;
									if(ball[i].dir_x == 1)
									{
										bias_x = 1;
									}
									else if(ball[i].dir_x == -1)
									{
										bias_x = -1;
									}
									else
									{
										bias_x = 0;
									}
								}
								else
								{
									bias_x = 0;
								}

								if(ball[i].count_y > 0)
								{
									ball[i].count_y --;
									bias_y = 0;
								}
								else if(ball[i].vc_y <= VC_MAX)
								{
									ball[i].count_y = ball[i].vc_y;
									move_flag = 1;
									if(ball[i].dir_y == 1)
									{
										bias_y = 1;
									}
									else if(ball[i].dir_y == -1)
									{
										bias_y = -1;
									}
									else
									{
										bias_y = 0;
									}
								}
								else
								{
									bias_y = 0;
								}


								//Update positions
								if(move_flag || ball[i].force_move)
								{
									if(move_flag)
									{
										moveball(i, &ball[i].pos_x, &ball[i].pos_y, bias_x, bias_y, &ball[i].bias_x, &ball[i].bias_y);
									}

									ball[i].force_move = 0;
									//detect and handle the situation when a ball hits edge
									detect_bound_edge(i);


									for(j = 15; j >= 0; j--)
									{
										if(j != i)
										{
											dis_x = abs(ball[i].pos_x - ball[j].pos_x);
											dis_y = abs(ball[i].pos_y - ball[j].pos_y);
											if(dis_x < 14 || dis_y < 14)
											{
												if(dis_x * dis_x + dis_y * dis_y <= 196)
												{
													bound_balls(i, j);
												}
											}
										}
									}

									for(j = 0; j < 6; j++)
									{
										hole_dis_x = ball[i].pos_x - hole[j][0];
										hole_dis_y = ball[i].pos_y - hole[j][1];
										if(hole_dis_x * hole_dis_x + hole_dis_y * hole_dis_y <= 144)     //original:144
										{
											printf("pocketed!\n");
											ball[i].flag = 0;
											if(plball[player]!=0 && oops == 0) // if player pocket before and it's not the cue ball pocketed
											{
												if(i >= (plball[player]-1) && i <= plball[player]+5) // if player is pocketing his balls, then no need to switch turn
												{
													change=0;
													if(player == 0)
													{
														ball[i].pos_x = 100 + 17 * i_0;
														ball[i].pos_y = 68;
														placeball(i, ball[i].pos_x, ball[i].pos_y, 0, 0, &ball[i].bias_x, &ball[i].bias_y);
														i_0 ++;
													}
													else
													{
														ball[i].pos_x = 100 + 17 * i_1;
														ball[i].pos_y = 98;
														placeball(i, ball[i].pos_x, ball[i].pos_y, 0, 0, &ball[i].bias_x, &ball[i].bias_y);
														i_1 ++;
													}
												}
												else			// if player is pocketing other's balls, then need to switch turn
												{
													change=1;
													if(player == 0)
													{
														ball[i].pos_x = 100 + 17 * i_1;
														ball[i].pos_y = 98;
														placeball(i, ball[i].pos_x, ball[i].pos_y, 0, 0, &ball[i].bias_x, &ball[i].bias_y);
														i_1 ++;
													}
													else
													{
														ball[i].pos_x = 100 + 17 * i_0;
														ball[i].pos_y = 68;
														placeball(i, ball[i].pos_x, ball[i].pos_y, 0, 0, &ball[i].bias_x, &ball[i].bias_y);
														i_0 ++;
													}
												}
											}
											win(i);
										}
									}
								}
					}
					while(IORD_16DIRECT(IRTIMER_0_BASE, 0) != 0)
					{

					}

					IOWR_16DIRECT(IRTIMER_0_BASE, 0, 3000);
				}

				//Update Speed (dx,dy)
				if(acc_count >= ACC)
				{
					acc_count = 0;
					for(i = 16; i >= 0; i--)
					{
						ball[i].dx = ball[i].dx * 0.95;
						ball[i].dy = ball[i].dy * 0.95;
						decide_direction(i);
					}
				}
				else
				{
					acc_count ++;
				}

				ff=1;
				for(j = 15; j >= 0; j--)
				{
					if(!(ball[j].dx == 0 && ball[j].dy ==0) && ball[j].flag == 1)	//if there're still balls moving
					{
						ff=0;
						break;
					}
				}
				if(ff)		//if all the balls have stopped
				{
					begin_flag = 0;
					release = 0;
					if(change == 1)
					{
						player=!player;
						if(player == 0)
						{
							IOWR_VGA_WORD_HL_EN(5);
						}
						else
						{
							IOWR_VGA_WORD_HL_EN(6);
						}
					}
					change=1;
					if(oops == 1)		//see if the cue ball is pocketed.
					{
						/*ball[15].pos_x = 104;
										ball[15].pos_y = 310;
										placeball(15, ball[15].pos_x, ball[15].pos_y, 0, 0, &ball[15].bias_x, &ball[15].bias_y);
										ball[15].flag = 1;*/
						cue_ready = 0;
						place_cue_ball();
						change=1;
						oops = 0;
					}
				}
			}

		}
		if(ex == 0)
		{
			/*get_key(&strength, &angle, &release);
			if(release == 1)
			{

				release = 0;*/
				ex = 1;
				goto start;
			//}
		}
	}

	return 0;
}
