// File: /workspace/github_cpp_makefile_star2_O2/codeandkey[P]neocortex/src/search.cpp
// Function: neocortex::search::Search::alphabeta(neocortex::Position&, int, int, int, int, neocortex::PV*, std::atomic<bool>&)
int search::Search::alphabeta(Position& root, int depth, int alpha, int beta, int ply_dist, PV* pv_line, std::atomic<bool>& abort_watch) {
	PV local_pv;
	Move tt_move, tt_exact_move;
	int value;
	int depth_reduction = 1;
	int depth_extension = 0;

	if (allocated_time_expired() || abort_watch) {
		return score::INCOMPLETE;
	}

	/* Check for threefold repetition or 50-move rule */
	if (root.num_repetitions() >= 3 || root.halfmove_clock() >= 50) {
		return eval::CONTEMPT;
	}

	if (!depth) {
		return quiescence(root, search::QDEPTH, alpha, beta, ply_dist, pv_line);
	}

	int alpha_orig = alpha;

	/* Look up cached results in TT */

	tt::entry* entry = tt::lookup(root.get_tt_key());

	tt::lock(root.get_tt_key());
	if (entry->key == root.get_tt_key() && entry->depth >= 1) {
		if (entry->depth >= depth) {
			switch (entry->type) {
			case tt::entry::EXACT:
				/* Get exact pv move from TT */
				tt_exact_move = entry->pv_move;
			case tt::entry::LOWERBOUND:
				if (entry->value > alpha) alpha = entry->value;
				break;
			case tt::entry::UPPERBOUND:
				if (entry->value < beta) beta = entry->value;
				break;
			}
		}
		else {
			/* TT entry isn't deep enough to use, but we keep the PV move for ordering */
			if (entry->type == tt::entry::EXACT) {
				tt_move = entry->pv_move;
			}
		}
	}
	tt::unlock(root.get_tt_key());

	/* If there is an exact PV, just search under the PV move */
	if (tt_exact_move.is_valid()) {
		// Re-search under pv node to regenerate complete pv, should be fast as all should hit TT
		root.make_move(tt_exact_move);

		value = -alphabeta(root, depth + depth_extension - depth_reduction, -beta, -alpha, ply_dist + 1, &local_pv, abort_watch);

		pv_line->moves[0] = tt_exact_move;
		pv_line->len = local_pv.len + 1;

		memcpy(pv_line->moves + 1, local_pv.moves, local_pv.len * sizeof local_pv.moves[0]);
		root.unmake_move(tt_exact_move);

		return value;
	}

	/* Perform null move reduction if available */
	if (root.null_move_allowed() && depth >= search::NULL_MOVE_REDUCTION) {
		root.make_move(Move::null);
		int nm_score = -alphabeta(root, depth - search::NULL_MOVE_REDUCTION, -beta, -alpha, ply_dist + 1, &local_pv, abort_watch);
		root.unmake_move(Move::null);

		if (nm_score >= beta) {
			return beta; // cutoff
		}
	}

	/* Check / capture extension */
	if (depth >= 5) { // don't do excessive extensions near horizon
		if (root.check() || root.capture()) {
			depth_extension++;
		}
	}

	Move pl_moves[MAX_PL_MOVES];
	int num_pl_moves = root.pseudolegal_moves(pl_moves);
	int num_moves = 0; /* num of legal moves */

	root.order_moves(pl_moves, num_pl_moves, tt_move);

	for (int i = 0; i < num_pl_moves; ++i) {
		if (root.make_move(pl_moves[i])) {

			num_moves++;

			int new_depth = depth + depth_extension - depth_reduction;

			if (new_depth < 0) {
				new_depth = 0;
			}

			value = -alphabeta(root, new_depth, -beta, -alpha, ply_dist + 1, &local_pv, abort_watch);

			/*if (depth == 1) {
				neocortex_debug("Made move %s, resulting score %d\n", pl_moves[i].to_uci().c_str(), value);
			}*/

			root.unmake_move(pl_moves[i]);

			if (value == score::INCOMPLETE) {
				return value;
			}

			if (value >= beta) {
				// Add history bonus for cutoff in normal AB
				root.add_history_bonus(pl_moves[i], depth);
				return beta;
			}

			if (value > alpha) {
				alpha = value;

				pv_line->moves[0] = pl_moves[i];
				pv_line->len = local_pv.len + 1;

				memcpy(pv_line->moves + 1, local_pv.moves, local_pv.len * sizeof local_pv.moves[0]);
			}
		}
		else {
			root.unmake_move(pl_moves[i]);
		}
	}

	if (!num_moves) {
		if (root.check()) {
			pv_line->len = 0;
			return score::CHECKMATED + ply_dist;
		}
		else {
			pv_line->len = 0;
			return eval::CONTEMPT;
		}
	}

	/* Write result to TT */
	tt::lock(root.get_tt_key());
	entry->key = root.get_tt_key();
	entry->value = alpha;
	entry->depth = depth;

	if (alpha <= alpha_orig) {
		entry->type = tt::entry::UPPERBOUND;
	}
	else if (alpha >= beta) {
		entry->type = tt::entry::LOWERBOUND;
	}
	else {
		assert(pv_line->moves[0].is_valid());

		entry->pv_move = pv_line->moves[0];
		entry->type = tt::entry::EXACT;
	}
	tt::unlock(root.get_tt_key());

	return alpha;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xb38, %rsp            # imm = 0xB38
movl %r9d, %r13d
movl %r8d, %ebp
movl %ecx, 0xc(%rsp)
movl %edx, %r14d
movq %rsi, %rbx
movq %rdi, %r12
leaq 0x7c(%rsp), %rdi
callq 0x700c
leaq 0x50(%rsp), %rdi
callq 0x6d44
leaq 0x28(%rsp), %rdi
callq 0x6d44
movq %r12, %rdi
callq 0xe468
movl $0x80000000, %r15d      # imm = 0x80000000
testb %al, %al
jne 0xe390
movq 0xb78(%rsp), %rax
movb (%rax), %al
testb $0x1, %al
jne 0xe390
movq %rbx, %rdi
callq 0xc994
xorl %r15d, %r15d
cmpl $0x2, %eax
jg 0xe390
movq %rbx, %rdi
callq 0xc9d6
cmpl $0x31, %eax
jg 0xe390
testl %r14d, %r14d
je 0xdf1d
movq %r14, 0x18(%rsp)
movq %rbx, %rdi
callq 0xc988
movq %rax, %rdi
callq 0xf598
movq %rax, %r15
movq %rbx, %rdi
callq 0xc988
movq %rax, %rdi
callq 0xf5b6
movq (%r15), %r14
movq %rbx, %rdi
callq 0xc988
cmpq %rax, %r14
movq %r15, 0x40(%rsp)
jne 0xdf11
movl 0x1c(%r15), %ecx
testl %ecx, %ecx
jle 0xdf11
movl 0x14(%r15), %eax
movq 0x18(%rsp), %r14
cmpl %r14d, %ecx
jge 0xdf4a
cmpl $0x2, %eax
jne 0xdf83
movl 0x10(%r15), %eax
movl %eax, 0x58(%rsp)
movq 0x8(%r15), %rax
movq %rax, 0x50(%rsp)
jmp 0xdf83
movl 0xc(%rsp), %r15d
movq 0x18(%rsp), %r14
jmp 0xdf88
subq $0x8, %rsp
pushq $0x4
popq %rdx
movq %r12, %rdi
movq %rbx, %rsi
movl 0x14(%rsp), %ecx
movl %ebp, %r8d
movl %r13d, %r9d
pushq 0xb78(%rsp)
callq 0xe4c8
popq %rcx
popq %rdx
movl %eax, %r15d
jmp 0xe390
testl %eax, %eax
je 0xdf69
cmpl $0x1, %eax
je 0xdf7a
cmpl $0x2, %eax
jne 0xdf83
movl 0x10(%r15), %eax
movl %eax, 0x30(%rsp)
movq 0x8(%r15), %rax
movq %rax, 0x28(%rsp)
movl 0x18(%r15), %r15d
movl 0xc(%rsp), %eax
cmpl %eax, %r15d
cmovlel %eax, %r15d
jmp 0xdf88
movl 0x18(%r15), %eax
cmpl %ebp, %eax
cmovll %eax, %ebp
movl 0xc(%rsp), %r15d
movq %rbx, %rdi
callq 0xc988
movq %rax, %rdi
callq 0xf5e3
leaq 0x28(%rsp), %rdi
callq 0x6f7c
testb %al, %al
je 0xe040
movq 0x28(%rsp), %rsi
movl 0x30(%rsp), %edx
movq %rbx, %rdi
callq 0x8258
decl %r14d
negl %ebp
negl %r15d
incl %r13d
movq %r12, %rdi
movq %rbx, %rsi
movl %r14d, %edx
movl %ebp, %ecx
movl %r15d, %r8d
movl %r13d, %r9d
pushq 0xb78(%rsp)
leaq 0x84(%rsp), %rax
pushq %rax
callq 0xde0e
popq %rcx
popq %rdx
movl %eax, %r15d
negl %r15d
movq 0x28(%rsp), %rax
movq 0xb70(%rsp), %rdi
movq %rax, 0x4(%rdi)
movl 0x30(%rsp), %eax
movl %eax, 0xc(%rdi)
leaq 0x80(%rsp), %rsi
movslq -0x4(%rsi), %rax
leal 0x1(%rax), %ecx
movl %ecx, (%rdi)
addq $0x10, %rdi
imulq $0xc, %rax, %rdx
callq 0x4290
movq 0x28(%rsp), %rsi
movl 0x30(%rsp), %edx
movq %rbx, %rdi
callq 0x8824
jmp 0xe390
movq %rbx, %rdi
callq 0xed18
xorb $0x1, %al
cmpl $0x3, %r14d
setl %cl
orb %al, %cl
movq %r13, 0x38(%rsp)
jne 0xe0cf
leaq 0x18b67(%rip), %r14     # 0x26bc8
movq (%r14), %rsi
movl 0x8(%r14), %edx
movq %rbx, %rdi
callq 0x8258
movq 0x18(%rsp), %rax
leal -0x3(%rax), %edx
movl %ebp, %ecx
negl %ecx
movl %r15d, %r8d
negl %r8d
leal 0x1(%r13), %r9d
movq %r12, %rdi
movq %rbx, %rsi
pushq 0xb78(%rsp)
leaq 0x84(%rsp), %rax
pushq %rax
callq 0xde0e
popq %rcx
popq %rdx
movl %ebp, %r13d
movl %eax, %ebp
negl %ebp
movq (%r14), %rsi
movl 0x8(%r14), %edx
movq 0x18(%rsp), %r14
movq %rbx, %rdi
callq 0x8824
cmpl %ebp, %r13d
movl %r13d, %ebp
movq 0x38(%rsp), %r13
jle 0xe32b
movl $0x0, 0x14(%rsp)
cmpl $0x5, %r14d
jl 0xe0f7
movq 0x160(%rbx), %rax
cmpl $0x0, -0x14(%rax)
jne 0xe0f0
cmpl $-0x1, -0x24(%rax)
je 0xe0f7
pushq $0x1
popq %rax
movl %eax, 0x14(%rsp)
movl %ebp, 0x10(%rsp)
pushq $0x1
popq %rax
movl %eax, 0x24(%rsp)
xorl %r14d, %r14d
leaq (%rsp,%r14), %rdi
addq $0x680, %rdi            # imm = 0x680
callq 0x6d44
addq $0xc, %r14
cmpq $0x4b0, %r14            # imm = 0x4B0
jne 0xe105
leaq 0x680(%rsp), %r14
movq %rbx, %rdi
movq %r14, %rsi
callq 0x8a04
movl %eax, %ebp
movq 0x50(%rsp), %rcx
movl 0x58(%rsp), %r8d
movq %rbx, %rdi
movq %r14, %rsi
movl %eax, %edx
callq 0xae9c
movl 0x14(%rsp), %ecx
addl 0x18(%rsp), %ecx
cmpl $0x2, %ecx
pushq $0x1
popq %rax
cmovll %eax, %ecx
decl %ecx
movl %ecx, 0x14(%rsp)
movl 0x10(%rsp), %eax
negl %eax
movl %eax, 0x4c(%rsp)
leal 0x1(%r13), %eax
movl %eax, 0x48(%rsp)
movq 0xb70(%rsp), %rax
leaq 0x4(%rax), %rcx
movq %rcx, 0x60(%rsp)
addq $0x10, %rax
movq %rax, 0x68(%rsp)
xorl %r14d, %r14d
testl %ebp, %ebp
cmovlel %r14d, %ebp
imulq $0xc, %rbp, %rax
movq %rax, 0x70(%rsp)
movl $0x0, 0x34(%rsp)
cmpq %r14, 0x70(%rsp)
je 0xe291
leaq (%rsp,%r14), %r13
addq $0x680, %r13            # imm = 0x680
movq (%r13), %rsi
movl 0x8(%r13), %edx
movq %rbx, %rdi
callq 0x8258
testb %al, %al
je 0xe26d
movl %r15d, %r8d
negl %r8d
movq %r12, %rdi
movq %rbx, %rsi
movl 0x14(%rsp), %edx
movl 0x4c(%rsp), %ecx
movl 0x48(%rsp), %r9d
pushq 0xb78(%rsp)
leaq 0x84(%rsp), %rax
pushq %rax
callq 0xde0e
popq %rcx
popq %rdx
movl %eax, %ebp
negl %ebp
movq (%r13), %rsi
movl 0x8(%r13), %edx
movq %rbx, %rdi
callq 0x8824
cmpl %ebp, 0x10(%rsp)
jle 0xe330
incl 0x34(%rsp)
cmpl %ebp, %r15d
jge 0xe27d
movl 0x8(%r13), %eax
movq 0x60(%rsp), %rcx
movl %eax, 0x8(%rcx)
movq (%r13), %rax
movq %rax, (%rcx)
movslq 0x7c(%rsp), %rax
leal 0x1(%rax), %ecx
movq 0xb70(%rsp), %rdx
movl %ecx, (%rdx)
imulq $0xc, %rax, %rdx
movq 0x68(%rsp), %rdi
leaq 0x80(%rsp), %rsi
callq 0x4290
jmp 0xe280
movq (%r13), %rsi
movl 0x8(%r13), %edx
movq %rbx, %rdi
callq 0x8824
movl %r15d, %ebp
movq 0x38(%rsp), %r13
addq $0xc, %r14
movl %ebp, %r15d
jmp 0xe1ab
cmpl $0x0, 0x34(%rsp)
je 0xe36b
movq %rbx, %rdi
callq 0xc988
movq %rax, %rdi
callq 0xf5b6
movq %rbx, %rdi
callq 0xc988
movq 0x40(%rsp), %rcx
movq %rax, (%rcx)
movl %r15d, 0x18(%rcx)
movq 0x18(%rsp), %rax
movl %eax, 0x1c(%rcx)
cmpl 0xc(%rsp), %r15d
jle 0xe30d
movl $0x0, 0x24(%rsp)
cmpl 0x10(%rsp), %r15d
jge 0xe30d
movq 0x60(%rsp), %r14
movq %r14, %rdi
callq 0x6f7c
testb %al, %al
je 0xe3a5
movl 0x8(%r14), %eax
movq 0x40(%rsp), %rcx
movl %eax, 0x10(%rcx)
movq (%r14), %rax
movq %rax, 0x8(%rcx)
pushq $0x2
popq %rax
movl %eax, 0x24(%rsp)
movq 0x40(%rsp), %rax
movl 0x24(%rsp), %ecx
movl %ecx, 0x14(%rax)
movq %rbx, %rdi
callq 0xc988
movq %rax, %rdi
callq 0xf5e3
jmp 0xe390
movl %ebp, %r15d
jmp 0xe390
movq 0x18(%rsp), %rsi
imull %esi, %esi
movslq 0x170(%rbx), %rax
shlq $0xe, %rax
addq %rbx, %rax
movslq 0x680(%rsp,%r14), %rcx
movslq 0x684(%rsp,%r14), %rdx
shlq $0x8, %rcx
addq %rax, %rcx
addl %esi, 0x178(%rcx,%rdx,4)
movl 0x10(%rsp), %r15d
jmp 0xe390
movq 0x160(%rbx), %rax
movl -0x14(%rax), %eax
movq 0xb70(%rsp), %rcx
andl $0x0, (%rcx)
addl $0xffc2f700, %r13d      # imm = 0xFFC2F700
testl %eax, %eax
cmovel %eax, %r13d
movl %r13d, %r15d
movl %r15d, %eax
addq $0xb38, %rsp            # imm = 0xB38
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x7a64(%rip), %rdi      # 0x15e10
leaq 0x7a7a(%rip), %rsi      # 0x15e2d
leaq 0x7a82(%rip), %rcx      # 0x15e3c
movl $0x191, %edx            # imm = 0x191
callq 0x41f0