// File: /workspace/github_c_makefile_star2_O1/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 $0x48, %rsp
movq %r8, -0x70(%rbp)
movq %rcx, %r12
movl %esi, %ebx
movq %rdi, -0x68(%rbp)
movl %edx, -0x3c(%rbp)
testl %edx, %edx
je 0x8622
movl %r9d, -0x54(%rbp)
movb 0x3ccc(%rip), %al       # 0xc129
movb %al, -0x29(%rbp)
movb 0x3cc4(%rip), %al       # 0xc12a
movb %al, -0x2a(%rbp)
movb 0x3cbc(%rip), %al       # 0xc12b
movb %al, -0x2b(%rbp)
movb 0x3cb4(%rip), %al       # 0xc12c
movb %al, -0x2c(%rbp)
callq 0x1eb4
movq %rax, %r13
movl $0x8, %edi
callq 0x1140
xorl %ecx, %ecx
movl %ebx, -0x44(%rbp)
testl %ebx, %ebx
movl $0x82d48b00, %edx       # imm = 0x82D48B00
movl $0x7d2b7500, %esi       # imm = 0x7D2B7500
cmovel %edx, %esi
movl $0x32, %ebx
cmovnel %ecx, %ebx
movl $0x0, (%rax)
movq %rax, -0x38(%rbp)
movl %esi, 0x4(%rax)
cmpl $0x0, 0x4(%r12)
jle 0x85e5
decl -0x3c(%rbp)
xorl %r15d, %r15d
movl %ebx, -0x40(%rbp)
movq %r13, -0x50(%rbp)
movq %r12, -0x60(%rbp)
movq -0x68(%rbp), %rdi
movq %r13, %rsi
callq 0x1fed
movq 0x8(%r12), %rax
movq (%rax,%r15,8), %r14
movq %r13, %rdi
movq %r14, %rsi
movq -0x70(%rbp), %rdx
callq 0x7824
movq %r13, %rdi
movl %ebx, %esi
movq %r14, %rdx
movl %ebx, %r12d
movl -0x54(%rbp), %ebx
movl %ebx, %ecx
callq 0x2f28
cmpl $0x0, 0x4(%rax)
je 0x8576
movq %r13, %rdi
movl %r12d, %esi
movl -0x3c(%rbp), %edx
movq %rax, %r12
movq %rax, %rcx
movq %r14, %r8
movl %ebx, %r9d
callq 0x842a
movq %rax, %r14
movq -0x38(%rbp), %rcx
movl 0x4(%r14), %eax
cmpl $0x0, -0x44(%rbp)
je 0x85ab
cmpl 0x4(%rcx), %eax
movl -0x40(%rbp), %ebx
movq -0x50(%rbp), %r13
jge 0x854f
movl %r15d, (%rcx)
movl %eax, 0x4(%rcx)
movq %r14, %rdi
callq 0x1130
movq %r12, %rdi
callq 0x7db5
incq %r15
movq -0x60(%rbp), %r12
movslq 0x4(%r12), %rax
cmpq %rax, %r15
jl 0x84d3
jmp 0x85e5
movq %rax, %r12
movl $0x8, %edi
callq 0x1140
movq %rax, %r14
movl $0x0, (%rax)
cmpl $0x0, -0x44(%rbp)
je 0x85b9
movq -0x50(%rbp), %rdi
xorl %esi, %esi
callq 0x2174
testb %al, %al
je 0x85d8
movl $0xffff3cb0, 0x4(%r14)  # imm = 0xFFFF3CB0
jmp 0x852f
cmpl 0x4(%rcx), %eax
movl -0x40(%rbp), %ebx
movq -0x50(%rbp), %r13
jg 0x8549
jmp 0x854f
movq -0x50(%rbp), %rdi
movl $0x32, %esi
callq 0x2174
testb %al, %al
je 0x85d8
movl $0xc350, 0x4(%r14)      # imm = 0xC350
jmp 0x852f
movl $0x0, 0x4(%r14)
jmp 0x852f
movq %r13, %rdi
callq 0x1130
movb -0x29(%rbp), %al
andb $0x1, %al
movb %al, 0x3b31(%rip)       # 0xc129
movb -0x2a(%rbp), %al
andb $0x1, %al
movb %al, 0x3b27(%rip)       # 0xc12a
movb -0x2b(%rbp), %al
andb $0x1, %al
movb %al, 0x3b1d(%rip)       # 0xc12b
movb -0x2c(%rbp), %al
andb $0x1, %al
movb %al, 0x3b13(%rip)       # 0xc12c
movq -0x38(%rbp), %rbx
jmp 0x86ed
testl %ebx, %ebx
movl $0x82d48b00, %eax       # imm = 0x82D48B00
movl $0x7d2b7500, %r14d      # imm = 0x7D2B7500
cmovel %eax, %r14d
movslq 0x4(%r12), %r15
testq %r15, %r15
jle 0x8667
movq 0x8(%r12), %rax
xorl %ecx, %ecx
movq (%rax,%rcx,8), %rdx
movl 0x8(%rdx), %edx
testl %ebx, %ebx
je 0x8658
cmpl %r14d, %edx
cmovll %edx, %r14d
jmp 0x865f
cmpl %r14d, %edx
cmovgl %edx, %r14d
incq %rcx
cmpq %rcx, %r15
jne 0x8644
leaq (,%r15,4), %rdi
callq 0x1140
movq %rax, %rbx
testl %r15d, %r15d
jle 0x86af
movq 0x8(%r12), %rax
xorl %ecx, %ecx
xorl %r12d, %r12d
movq (%rax,%rcx,8), %rdx
movl %r14d, %esi
subl 0x8(%rdx), %esi
movl %esi, %edx
negl %edx
cmovsl %esi, %edx
cmpl $0x14, %edx
ja 0x86a5
movslq %r12d, %rdx
incl %r12d
movl %ecx, (%rbx,%rdx,4)
incq %rcx
cmpq %rcx, %r15
jne 0x8686
jmp 0x86b2
xorl %r12d, %r12d
movl $0x8, %edi
callq 0x1140
movq %rbx, %rcx
testl %r12d, %r12d
je 0x86da
movq %rax, %r15
callq 0x1050
cltd
idivl %r12d
movslq %edx, %rcx
movq %r15, %rax
leaq (%rbx,%rcx,4), %rcx
movl (%rcx), %ecx
movl %ecx, (%rax)
movl %r14d, 0x4(%rax)
movq %rbx, %rdi
movq %rax, %rbx
callq 0x1130
movq %rbx, %rax
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq