// File: /workspace/github_c_makefile_star2_O2/upcrob[P]garry/moves.c
// Function: bestMoveHelper(char*, int, int, MoveSet*, Move*, int)
MoveDef* bestMoveHelper(char* board, int color, int depth, MoveSet* legalMoves, Move* prevMove, int evaluator)
{
	//Save state of castle variables
	char tmpWKC = whiteKCastleInvalid;
	char tmpWQC = whiteQCastleInvalid;
	char tmpBKC = blackKCastleInvalid;
	char tmpBQC = blackQCastleInvalid;
	
	if (depth == 0)
	{
		//we have reached the end of the search (base case)
		//determine best greedy legal move
		int i, best;
		if (color == WHITE)
			best = -INFINITY;
		else
			best = INFINITY;
		for (i = 0; i < legalMoves->size; i++)
		{
			Move* move = getMove(legalMoves, i);
			if (color == WHITE)
			{
				//white
				if (move->boardScore > best)
					best = move->boardScore;	//update best move
			} else {
				//black
				if (move->boardScore < best)
					best = move->boardScore;	//update best move
			}
		}
		
		//choose random best move if multiple close to best
		int icount = 0;
		int* indices = (int*) malloc(sizeof(int) * legalMoves->size);
		for (i = 0; i < legalMoves->size; i++)
		{
			Move* move = getMove(legalMoves, i);
			if (abs(best - move->boardScore) <= RAND_RANGE)
				indices[icount++] = i;
		}
		
		MoveDef* m = (MoveDef*) malloc(sizeof(MoveDef));
		if (icount == 0)
			m->index = indices[0];
		else
			m->index = indices[(int) rand() % icount];
		m->value = best;
		free(indices);
		
		return m;
	} else {
		//recursive case
		//execute each move and recurse
		int i;
		
		//declare variables for the next move and an empty board
		char* nextBoard = buildNewBoard();
		MoveSet* nextLegal;
		char nextColor;
		
		//initialize variables, best holds the "best" next move
		MoveDef* best;
		best = (MoveDef*) malloc(sizeof(MoveDef));
		best->index = 0;
		if (color == WHITE)
		{
			nextColor = BLACK;
			best->value = -INFINITY;
		} else {
			nextColor = WHITE;
			best->value = INFINITY;
		}
		
		//recursively search each next legal move for the one
		//that leads to the best end case
		for (i = 0; i < legalMoves->size; i++)
		{
			cloneBoard(board, nextBoard);	//copy board
			Move* testMove = getMove(legalMoves, i);	//get move from the set of legal moves
			executeMove(nextBoard, testMove, prevMove);	//execute it
			nextLegal = getLegalMoves(nextBoard, nextColor, testMove, evaluator);	//get the next set of legal moves available
			MoveDef* m;
			if (nextLegal->size == 0)
			{
				//no legal moves available, either a checkmate or stalemate
				m = (MoveDef*) malloc(sizeof(MoveDef));
				m->index = 0;
				if (color == WHITE)
				{
					//check for stalemate
					if (kingInCheck(nextBoard, BLACK))
					{
						m->value = CHECKMATE_VALUE;	//black's king in checkmate
					} else {
						m->value = 0;	//stalemate
					}
				} else {
					//check for stalemate
					if (kingInCheck(nextBoard, WHITE))
					{
						m->value = -CHECKMATE_VALUE;	//white's king in checkmate
					} else {
						m->value = 0;	//stalemate
					}
				}
			} else {
				//recurse
				m = bestMoveHelper(nextBoard, nextColor, depth - 1, nextLegal, testMove, evaluator);
			}

			if (color == WHITE)
			{
				//white
				if (m->value > best->value)
				{
					//update current best move found
					best->index = i;
					best->value = m->value;
				}
			} else {
				//black
				if (m->value < best->value)
				{
					//update current best most found
					best->index = i;
					best->value = m->value;
				}
			}
			
			//free memory
			free(m);
			destroyMoveSet(nextLegal);
		}
		
		//free memory
		free(nextBoard);
		
		//restore castling variables
		whiteKCastleInvalid = tmpWKC;
		whiteQCastleInvalid = tmpWQC;
		blackKCastleInvalid = tmpBKC;
		blackQCastleInvalid = tmpBQC;
		
		//return best index
		return best;
	}
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x38, %rsp
movq %r8, -0x58(%rbp)
movq %rcx, %rbx
movl %esi, %r14d
movq %rdi, -0x50(%rbp)
testl %edx, %edx
je 0x9773
movl %r9d, %r12d
movq %rbx, -0x60(%rbp)
movl %edx, %r15d
movb 0x3c3c(%rip), %al       # 0xd211
movb %al, -0x29(%rbp)
movb 0x3c34(%rip), %al       # 0xd212
movb %al, -0x2a(%rbp)
movb 0x3c2c(%rip), %al       # 0xd213
movb %al, -0x2b(%rbp)
movb 0x3c24(%rip), %al       # 0xd214
movb %al, -0x2c(%rbp)
callq 0x3450
movq %rax, %r13
pushq $0x8
popq %rdi
callq 0x2250
andl $0x0, (%rax)
movl %r14d, -0x30(%rbp)
testl %r14d, %r14d
movl $0x82d48b00, %edx       # imm = 0x82D48B00
movl $0x7d2b7500, %ecx       # imm = 0x7D2B7500
cmovel %edx, %ecx
pushq $0x32
popq %rdx
movl $0x0, %ebx
cmovel %edx, %ebx
movq %rax, -0x38(%rbp)
movl %ecx, 0x4(%rax)
decl %r15d
movl %r15d, -0x3c(%rbp)
xorl %r14d, %r14d
movl %r12d, -0x44(%rbp)
movl %ebx, -0x40(%rbp)
movq -0x60(%rbp), %r15
movslq 0x4(%r15), %rax
cmpq %rax, %r14
jge 0x9736
movq -0x50(%rbp), %rdi
movq %r13, %rsi
callq 0x359b
movq 0x8(%r15), %rax
movq (%rax,%r14,8), %r15
movq %r13, %rdi
movq %r15, %rsi
movq -0x58(%rbp), %rdx
callq 0x88df
movq %r13, %rdi
movl %ebx, %esi
movq %r15, %rdx
movl %r12d, %ecx
callq 0x41dc
movl %r12d, %r9d
movq %rax, %r12
cmpl $0x0, 0x4(%rax)
je 0x96ae
movq %r13, %rdi
movl %ebx, %esi
movl -0x3c(%rbp), %edx
movq %r12, %rcx
movq %r15, %r8
callq 0x959e
movq %rax, %r15
movl 0x4(%rax), %eax
cmpl $0x0, -0x30(%rbp)
jne 0x96df
jmp 0x972b
pushq $0x8
popq %rdi
callq 0x2250
movq %rax, %r15
andl $0x0, (%rax)
cmpl $0x0, -0x30(%rbp)
je 0x970d
movq %r13, %rdi
xorl %esi, %esi
callq 0x372c
testb %al, %al
movl $0xffff3cb0, %eax       # imm = 0xFFFF3CB0
movl $0x0, %ecx
cmovel %ecx, %eax
movl %eax, 0x4(%r15)
movq -0x38(%rbp), %rcx
cmpl 0x4(%rcx), %eax
jge 0x96ee
movl %r14d, (%rcx)
movl %eax, 0x4(%rcx)
movq %r15, %rdi
callq 0x2200
movq %r12, %rdi
callq 0x8e41
incq %r14
movl -0x44(%rbp), %r12d
movl -0x40(%rbp), %ebx
jmp 0x963d
movq %r13, %rdi
pushq $0x32
popq %rsi
callq 0x372c
testb %al, %al
movl $0xc350, %eax           # imm = 0xC350
movl $0x0, %ecx
cmovel %ecx, %eax
movl %eax, 0x4(%r15)
movq -0x38(%rbp), %rcx
cmpl 0x4(%rcx), %eax
jg 0x96e8
jmp 0x96ee
movq %r13, %rdi
callq 0x2200
movb -0x29(%rbp), %al
andb $0x1, %al
movb %al, 0x3ac8(%rip)       # 0xd211
movb -0x2a(%rbp), %al
andb $0x1, %al
movb %al, 0x3abe(%rip)       # 0xd212
movb -0x2b(%rbp), %al
andb $0x1, %al
movb %al, 0x3ab4(%rip)       # 0xd213
movb -0x2c(%rbp), %al
andb $0x1, %al
movb %al, 0x3aaa(%rip)       # 0xd214
movq -0x38(%rbp), %rbx
jmp 0x9833
testl %r14d, %r14d
movl $0x82d48b00, %eax       # imm = 0x82D48B00
movl $0x7d2b7500, %r15d      # imm = 0x7D2B7500
cmovel %eax, %r15d
movslq 0x4(%rbx), %rdi
xorl %eax, %eax
testl %edi, %edi
movl $0x0, %r12d
cmovgl %edi, %r12d
cmpq %rax, %r12
je 0x97c1
movq 0x8(%rbx), %rcx
movq (%rcx,%rax,8), %rcx
movl 0x8(%rcx), %ecx
testl %r14d, %r14d
je 0x97b5
cmpl %r15d, %ecx
cmovll %ecx, %r15d
jmp 0x97bc
cmpl %r15d, %ecx
cmovgl %ecx, %r15d
incq %rax
jmp 0x9797
shlq $0x2, %rdi
callq 0x2250
movq %rax, %r14
xorl %eax, %eax
xorl %r13d, %r13d
cmpq %rax, %r12
je 0x9800
movq 0x8(%rbx), %rcx
movq (%rcx,%rax,8), %rcx
movl %r15d, %edx
subl 0x8(%rcx), %edx
movl %edx, %ecx
negl %ecx
cmovsl %edx, %ecx
cmpl $0x14, %ecx
ja 0x97fb
movslq %r13d, %rcx
incl %r13d
movl %eax, (%r14,%rcx,4)
incq %rax
jmp 0x97d2
pushq $0x8
popq %rdi
callq 0x2250
movq %rax, %rbx
movq %r14, %rcx
testl %r13d, %r13d
je 0x9823
callq 0x2060
cltd
idivl %r13d
movslq %edx, %rcx
leaq (%r14,%rcx,4), %rcx
movl (%rcx), %ecx
movl %ecx, (%rbx)
movl %r15d, 0x4(%rbx)
movq %r14, %rdi
callq 0x2200
movq %rbx, %rax
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq