// File: /workspace/github_c_makefile_star2_O2/upcrob[P]garry/chess.c
// Function: main
int main(int argc, char* argv[])
{	
	//Initialize MPI
	Init(argc, argv);
	proc = COMM_WORLD.Get_rank();
	numProcs = COMM_WORLD.Get_size();

	//Require at least 1 slave node to run
	if (numProcs < 2)
	{
		if (proc == HEAD)
			printf("Program requires at least 1 slave node to run.\nTerminating.\n");
		Finalize();
		return 0;
	}

	//Divide between head and slave node program
	if (proc == HEAD)
	{
		//Head node code
		//======================================================================
		
		//initialize variables
		queueIndex = 0;
		queueFull = FALSE;
		moveQueue = (Move**) malloc(sizeof(Move*) * MQ_SIZE);
		int colorFlag = WHITE;
		MoveSet* moves;
		char* board = buildNewBoard();
		
		//setup empty previous move
		prev = newMove();
	
		//resume play from log file if requested
		if (streq(argv[argc - 1], (char*) "-r"))
		{
			printf("\n* * RESUMING GAME FROM LOG * *\n\n");
			
			int i = 0;
			char buffer[6];
			
			FILE* fp = fopen("chesslog.txt", "r");
			int c = fgetc(fp);
			while (c != EOF)
			{
				buffer[i++] = (char) c;
				if (c == '\n')
				{
					//Move read, execute it
					buffer[i] = '\0';
					Move* move = strToMove(buffer);
					if (move->startRow == CASTLE)
					{
						//Set player that is castling
						if (colorFlag == WHITE)
							move->pieceId = KING;
						else
							move->pieceId = KING + BLACK;
					}
					executeMove(board, move, prev);
					free(move);
					
					//Switch players
					if (colorFlag == WHITE)
						colorFlag = BLACK;
					else
						colorFlag = WHITE;
					i = 0;
				}
				c = fgetc(fp);
			}
			fclose(fp);
		} else {
			//initialize (clear) log file
			initLog("chesslog.txt");
		}
		
		//show board
		printBoard(board);
		printf("\n");
		
		//main game loop
		int i, j;
		while (TRUE)
		{
			if (colorFlag == WHITE)
				moves = getLegalMoves(board, WHITE, prev, 1);
			else
				moves = getLegalMoves(board, BLACK, prev, 1);

			//check for checkmate/stalemate
			if (moves->size == 0)
			{
				if (!kingInCheck(board, WHITE) && !kingInCheck(board, BLACK))
				{
					//stalemate
					printf("STALEMATE.\n");
				} else {
					//checkmate, determine color
					if (colorFlag == WHITE)
						printf("CHECKMATE: BLACK WINS.\n");
					else
						printf("CHECKMATE: WHITE WINS.\n");
				}
				
				//End program
				sendKillSig();
				free(board);
				Finalize();
				return 0;
			}

			//execute turns (ai or human)
			int status;
			if (colorFlag == WHITE)
			{
				//white's turn
				status = computeMove(TYPE_WHITE, board, moves, WHITE, FUNCTION_WHITE);		
				if (status == 0)
				{
					Finalize();
					return 0;
				}
			} else {
				//black's turn
				status = computeMove(TYPE_BLACK, board, moves, BLACK, FUNCTION_BLACK);
				if (status == 0)
				{
					Finalize();
					return 0;
				}
			}
			destroyMoveSet(moves);

			//Add move to queue
			Move* prevClone = cloneMove(prev);
			enqueueMove(prevClone);
			
			//Check queue for repeats
			if (moveLoopDetected())
			{
				printf("REPEATED MOVES DETECTED. GAME ENDS IN A DRAW.\n");
				sendKillSig();
				free(board);
				Finalize();
				return 0;
				
			}
			
			//Log move
			logMove("chesslog.txt", prev);
			
			//Swap turns
			if (colorFlag == WHITE)
				colorFlag = BLACK;
			else
				colorFlag = WHITE;
		}

		//free memory
		free(board);
		//======================================================================
	} else {
		//Slave node code
		//======================================================================
		int color;
		int depth;
		int evaluator;
		char board[64];
		while (TRUE)
		{
			//Receive data from HEAD node
			COMM_WORLD.Recv(&color, 1, MPI_INT, HEAD, 0);
			
			//Terminate program if color is -1
			if (color == -1)
				break;
			
			COMM_WORLD.Recv(&depth, 1, MPI_INT, HEAD, 0);
			COMM_WORLD.Recv(&evaluator, 1, MPI_INT, HEAD, 0);
			COMM_WORLD.Recv(&board, 64, MPI_CHAR, HEAD, 0);
			MoveSet* set = receiveMoveSet();
			Move* prevMove = receiveMove();
			
			//Determine best move
			MoveDef* bmd = bestMoveHelper(board, color, depth, set, prevMove, evaluator);
			
			//Send MoveDef back to head node
			sendMoveDef(bmd);
			
			//Free memory
			destroyMoveSet(set);
			free(bmd);
			free(prevMove);
		}
		//======================================================================
	}
	
	//Finalize MPI
	Finalize();
	return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x78, %rsp
leaq -0x4c(%rbp), %rax
movl %edi, (%rax)
leaq -0x58(%rbp), %rcx
movq %rsi, (%rcx)
movq %rax, %rdi
movq %rcx, %rsi
callq 0x2f55
movq 0xaa94(%rip), %rbx      # 0xcfd0
movq %rbx, %rdi
callq 0x2f64
movl %eax, 0xacae(%rip)      # 0xd1f8
movq %rbx, %rdi
callq 0x2f84
movl %eax, 0xaca4(%rip)      # 0xd1fc
movl 0xac9a(%rip), %ecx      # 0xd1f8
cmpl $0x1, %eax
jg 0x257c
testl %ecx, %ecx
jne 0x28ba
leaq 0x7b5d(%rip), %rdi      # 0xa0cf
callq 0x22e0
jmp 0x28ba
testl %ecx, %ecx
je 0x26a3
leaq 0xa69d(%rip), %r14      # 0xcc28
movq 0xaa46(%rip), %rbx      # 0xcfd8
movq 0xaa37(%rip), %r15      # 0xcfd0
pushq $0x1
popq %r12
leaq -0x40(%rbp), %r13
movq %r14, -0x40(%rbp)
movq %rbx, -0x38(%rbp)
movq %r15, %rdi
leaq -0x2c(%rbp), %rsi
movl %r12d, %edx
movq %r13, %rcx
xorl %r8d, %r8d
xorl %r9d, %r9d
callq 0x2fa4
cmpl $-0x1, -0x2c(%rbp)
je 0x28ba
movq %r14, -0x40(%rbp)
movq %rbx, -0x38(%rbp)
movq %r15, %rdi
leaq -0x48(%rbp), %rsi
movl %r12d, %edx
movq %r13, %rcx
xorl %r8d, %r8d
xorl %r9d, %r9d
callq 0x2fa4
movq %r14, -0x40(%rbp)
movq %rbx, -0x38(%rbp)
movq %r15, %rdi
leaq -0x44(%rbp), %rsi
movl %r12d, %edx
movq %r13, %rcx
xorl %r8d, %r8d
xorl %r9d, %r9d
callq 0x2fa4
movq %r14, -0x40(%rbp)
movq 0xa99a(%rip), %rax      # 0xcfb0
movq %rax, -0x38(%rbp)
movq %r15, %rdi
leaq -0xa0(%rbp), %r12
movq %r12, %rsi
pushq $0x40
popq %rdx
movq %r13, %rcx
xorl %r8d, %r8d
xorl %r9d, %r9d
callq 0x2fa4
callq 0x98d2
movq %r14, %rbx
movq %rax, %r14
callq 0x9b31
movq %rax, %r13
movl -0x2c(%rbp), %esi
movl -0x48(%rbp), %edx
movl -0x44(%rbp), %r9d
movq %r12, %rdi
movq %r14, %rcx
movq %rax, %r8
callq 0x959e
movq %r15, %r12
movq %rax, %r15
movq %rax, %rdi
callq 0x9aa8
movq %r14, %rdi
movq %rbx, %r14
movq 0xa95a(%rip), %rbx      # 0xcfd8
callq 0x8e41
movq %r15, %rdi
movq %r12, %r15
pushq $0x1
popq %r12
callq 0x2200
movq %r13, %rdi
leaq -0x40(%rbp), %r13
callq 0x2200
jmp 0x25a1
andl $0x0, 0xab5e(%rip)      # 0xd208
andl $0x0, 0xab5b(%rip)      # 0xd20c
movl $0xa0, %edi
callq 0x2250
movq %rax, 0xab3e(%rip)      # 0xd200
callq 0x3450
movq %rax, %rbx
callq 0x9845
movq %rax, 0xab1a(%rip)      # 0xd1f0
movq -0x58(%rbp), %rax
movslq -0x4c(%rbp), %rcx
movq -0x8(%rax,%rcx,8), %rdi
leaq 0x791a(%rip), %rsi      # 0xa004
callq 0x9c6c
pushq $0x32
popq %r14
testl %eax, %eax
je 0x279d
leaq 0x795c(%rip), %rdi      # 0xa05e
callq 0x22e0
leaq 0x78f9(%rip), %rdi      # 0xa007
leaq 0x78f0(%rip), %rsi      # 0xa005
callq 0x21f0
movq %rax, %r15
xorl %r12d, %r12d
leaq -0xa0(%rbp), %r13
movq %r15, %rdi
callq 0x22f0
cmpl $-0x1, %eax
je 0x2793
movb %al, (%r13)
incq %r13
cmpl $0xa, %eax
jne 0x2727
movb $0x0, (%r13)
leaq -0xa0(%rbp), %rdi
callq 0x28d9
movq %rax, %r13
cmpb $-0x2, 0x1(%rax)
jne 0x276a
testl %r12d, %r12d
pushq $0x38
popq %rax
pushq $0x6
popq %rcx
cmovel %ecx, %eax
movb %al, (%r13)
movq 0xaa7f(%rip), %rdx      # 0xd1f0
movq %rbx, %rdi
movq %r13, %rsi
callq 0x88df
movq %r13, %rdi
callq 0x2200
testl %r12d, %r12d
movl $0x0, %r12d
cmovel %r14d, %r12d
jmp 0x2720
movq %r15, %rdi
callq 0x21a0
jmp 0x27ac
leaq 0x7863(%rip), %rdi      # 0xa007
callq 0x29c2
xorl %r12d, %r12d
movq %rbx, %rdi
callq 0x35d0
pushq $0xa
popq %rdi
callq 0x2280
pushq $0x1
popq %r15
movq 0xaa29(%rip), %rdx      # 0xd1f0
movq %rbx, %rdi
testl %r12d, %r12d
je 0x27f5
movl %r14d, %esi
movl %r15d, %ecx
callq 0x41dc
cmpl $0x0, 0x4(%rax)
je 0x286d
movq %rax, %r13
movl %r15d, %edi
movq %rbx, %rsi
movq %rax, %rdx
movl %r14d, %ecx
jmp 0x2812
xorl %esi, %esi
movl %r15d, %ecx
callq 0x41dc
cmpl $0x0, 0x4(%rax)
je 0x286d
movq %rax, %r13
xorl %edi, %edi
movq %rbx, %rsi
movq %rax, %rdx
xorl %ecx, %ecx
pushq $0x2
popq %r8
callq 0x2a50
testl %eax, %eax
je 0x28ba
movq %r13, %rdi
callq 0x8e41
movq 0xa9be(%rip), %rdi      # 0xd1f0
callq 0x9898
movq %rax, %rdi
callq 0x2cdd
callq 0x2d3f
testl %eax, %eax
jne 0x28a1
movq 0xa9a1(%rip), %rsi      # 0xd1f0
leaq 0x77b1(%rip), %rdi      # 0xa007
callq 0x2e49
testl %r12d, %r12d
movl $0x0, %r12d
cmovel %r14d, %r12d
jmp 0x27c0
movq %rbx, %rdi
xorl %esi, %esi
callq 0x372c
testb %al, %al
jne 0x288a
pushq $0x32
popq %rsi
movq %rbx, %rdi
callq 0x372c
testb %al, %al
je 0x28d0
testl %r12d, %r12d
leaq 0x7824(%rip), %rax      # 0xa0b8
leaq 0x787d(%rip), %rdi      # 0xa118
cmoveq %rax, %rdi
jmp 0x28a8
leaq 0x77d7(%rip), %rdi      # 0xa07f
callq 0x22e0
callq 0x29db
movq %rbx, %rdi
callq 0x2200
callq 0x2120
xorl %eax, %eax
addq $0x78, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x77d6(%rip), %rdi      # 0xa0ad
jmp 0x28a8