// File: /workspace/github_cpp_makefile_star2_O3/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, %r14d
movl %r8d, %r15d
movl %ecx, 0x8(%rsp)
movl %edx, %ebp
movq %rsi, %rbx
movq %rdi, %r12
leaq 0x7c(%rsp), %rdi
callq 0x7b28
leaq 0x50(%rsp), %rdi
callq 0x7758
leaq 0x18(%rsp), %rdi
callq 0x7758
movq %r12, %rdi
callq 0x1123c
movl $0x80000000, %r13d      # imm = 0x80000000
testb %al, %al
jne 0x1110c
movq 0xb78(%rsp), %rax
movb (%rax), %al
testb $0x1, %al
jne 0x1110c
movq %rbx, %rdi
callq 0xf14e
xorl %r13d, %r13d
cmpl $0x2, %eax
jg 0x1110c
movq %rbx, %rdi
callq 0xf1a0
cmpl $0x31, %eax
jg 0x1110c
testl %ebp, %ebp
je 0x10c61
movq %r14, 0x10(%rsp)
movq %rbx, %rdi
callq 0xf142
movq %rax, %rdi
callq 0x12452
movq %rax, %r13
movq %rbx, %rdi
callq 0xf142
movq %rax, %rdi
callq 0x12470
movq (%r13), %r14
movq %rbx, %rdi
callq 0xf142
cmpq %rax, %r14
movq %r13, 0x30(%rsp)
jne 0x10c55
movl 0x1c(%r13), %ecx
testl %ecx, %ecx
jle 0x10c55
movl 0x14(%r13), %eax
cmpl %ebp, %ecx
movq 0x10(%rsp), %r14
jge 0x10c92
cmpl $0x2, %eax
jne 0x10ccd
movl 0x10(%r13), %eax
movl %eax, 0x58(%rsp)
movq 0x8(%r13), %rax
movq %rax, 0x50(%rsp)
jmp 0x10ccd
movl 0x8(%rsp), %r13d
movq 0x10(%rsp), %r14
jmp 0x10cd2
subq $0x8, %rsp
movq %r12, %rdi
movq %rbx, %rsi
movl $0x4, %edx
movl 0x10(%rsp), %ecx
movl %r15d, %r8d
movl %r14d, %r9d
pushq 0xb78(%rsp)
callq 0x112a8
addq $0x10, %rsp
movl %eax, %r13d
jmp 0x1110c
testl %eax, %eax
je 0x10cb1
cmpl $0x1, %eax
je 0x10cc2
cmpl $0x2, %eax
jne 0x10ccd
movl 0x10(%r13), %eax
movl %eax, 0x20(%rsp)
movq 0x8(%r13), %rax
movq %rax, 0x18(%rsp)
movl 0x18(%r13), %r13d
movl 0x8(%rsp), %eax
cmpl %eax, %r13d
cmovlel %eax, %r13d
jmp 0x10cd2
movl 0x18(%r13), %eax
cmpl %r15d, %eax
cmovll %eax, %r15d
movl 0x8(%rsp), %r13d
movq %rbx, %rdi
callq 0xf142
movq %rax, %rdi
callq 0x124ac
leaq 0x18(%rsp), %rdi
callq 0x7a5a
testb %al, %al
je 0x10d90
movq 0x18(%rsp), %rsi
movl 0x20(%rsp), %edx
movq %rbx, %rdi
callq 0x953e
decl %ebp
negl %r15d
negl %r13d
incl %r14d
movq %r12, %rdi
movq %rbx, %rsi
movl %ebp, %edx
movl %r15d, %ecx
movl %r13d, %r8d
movl %r14d, %r9d
pushq 0xb78(%rsp)
leaq 0x84(%rsp), %rax
pushq %rax
callq 0x10b54
addq $0x10, %rsp
movl %eax, %r13d
negl %r13d
movq 0x18(%rsp), %rax
movq 0xb70(%rsp), %rdi
movq %rax, 0x4(%rdi)
movl 0x20(%rsp), %eax
movl %eax, 0xc(%rdi)
leaq 0x80(%rsp), %rsi
movslq -0x4(%rsi), %rax
leal 0x1(%rax), %ecx
movl %ecx, (%rdi)
addq $0x10, %rdi
shlq $0x2, %rax
leaq (%rax,%rax,2), %rdx
callq 0x4230
movq 0x18(%rsp), %rsi
movl 0x20(%rsp), %edx
movq %rbx, %rdi
callq 0x9b20
jmp 0x1110c
movdqu 0x20(%rbx), %xmm0
movdqu 0x30(%rbx), %xmm1
por %xmm0, %xmm1
pshufd $0xee, %xmm1, %xmm0     # xmm0 = xmm1[2,3,2,3]
por %xmm1, %xmm0
movq %xmm0, %rax
movslq 0x170(%rbx), %rcx
testq %rax, 0x8(%rbx,%rcx,8)
je 0x10e3e
cmpl $0x3, %ebp
jl 0x10e3e
movq 0x160(%rbx), %rax
cmpl $0x0, -0x14(%rax)
jne 0x10e3e
leaq 0x1adc1(%rip), %rax     # 0x2bb98
movq (%rax), %rsi
movl 0x8(%rax), %edx
movq %rbx, %rdi
callq 0x953e
leal -0x3(%rbp), %edx
movl %r15d, %ecx
negl %ecx
movl %r13d, %r8d
negl %r8d
leal 0x1(%r14), %r9d
movq %r12, %rdi
movq %rbx, %rsi
pushq 0xb78(%rsp)
leaq 0x84(%rsp), %rax
pushq %rax
callq 0x10b54
addq $0x10, %rsp
movq %rbp, %r14
movl %eax, %ebp
negl %ebp
leaq 0x1ad74(%rip), %rax     # 0x2bb98
movq (%rax), %rsi
movl 0x8(%rax), %edx
movq %rbx, %rdi
callq 0x9b20
cmpl %ebp, %r15d
movq %r14, %rbp
jle 0x11109
movl %r15d, 0xc(%rsp)
xorl %r15d, %r15d
cmpl $0x5, %ebp
jl 0x10e64
movq 0x160(%rbx), %rax
cmpl $0x0, -0x14(%rax)
jne 0x10e5e
cmpl $-0x1, -0x24(%rax)
je 0x10e64
movl $0x1, %r15d
movq %rbp, 0x28(%rsp)
xorl %r14d, %r14d
leaq (%rsp,%r14), %rdi
addq $0x680, %rdi            # imm = 0x680
callq 0x7758
addq $0xc, %r14
cmpq $0x4b0, %r14            # imm = 0x4B0
jne 0x10e6c
leaq 0x680(%rsp), %r14
movq %rbx, %rdi
movq %r14, %rsi
callq 0x9d82
movl %eax, %ebp
movq 0x50(%rsp), %rcx
movl 0x58(%rsp), %r8d
movq %rbx, %rdi
movq %r14, %rsi
movl %eax, %edx
callq 0xcb22
testl %ebp, %ebp
movq 0x10(%rsp), %rcx
jle 0x110a1
movq %rbx, 0x38(%rsp)
addl 0x28(%rsp), %r15d
cmpl $0x2, %r15d
movl $0x1, %eax
cmovgel %r15d, %eax
decl %eax
movl %eax, 0x4c(%rsp)
movl 0xc(%rsp), %eax
negl %eax
movl %eax, 0x48(%rsp)
leal 0x1(%rcx), %eax
movl %eax, 0x44(%rsp)
movq 0xb70(%rsp), %rax
leaq 0x4(%rax), %rcx
movq %rcx, 0x60(%rsp)
addq $0x10, %rax
movq %rax, 0x68(%rsp)
movl %ebp, %eax
shlq $0x2, %rax
leaq (%rax,%rax,2), %rbx
xorl %r15d, %r15d
movl $0x0, 0x24(%rsp)
movq %r12, 0x70(%rsp)
movq 0x38(%rsp), %r12
leaq (%rsp,%r15), %r14
addq $0x680, %r14            # imm = 0x680
movq (%r14), %rsi
movl 0x8(%r14), %edx
movq %r12, %rdi
callq 0x953e
testb %al, %al
je 0x10fe8
movl %r13d, %r8d
negl %r8d
movq 0x70(%rsp), %rdi
movq %r12, %rsi
movl 0x4c(%rsp), %edx
movl 0x48(%rsp), %ecx
movl 0x44(%rsp), %r9d
pushq 0xb78(%rsp)
leaq 0x84(%rsp), %rax
pushq %rax
callq 0x10b54
addq $0x10, %rsp
movl %eax, %ebp
negl %ebp
movq (%r14), %rsi
movl 0x8(%r14), %edx
movq %r12, %rdi
callq 0x9b20
cmpl %ebp, 0xc(%rsp)
jle 0x110c9
incl 0x24(%rsp)
cmpl %ebp, %r13d
jge 0x10ff7
movl 0x8(%r14), %eax
movq 0x60(%rsp), %rcx
movl %eax, 0x8(%rcx)
movq (%r14), %rax
movq %rax, (%rcx)
movslq 0x7c(%rsp), %rax
leal 0x1(%rax), %ecx
movq 0xb70(%rsp), %rdx
movl %ecx, (%rdx)
shlq $0x2, %rax
leaq (%rax,%rax,2), %rdx
movq 0x68(%rsp), %rdi
leaq 0x80(%rsp), %rsi
callq 0x4230
movl %ebp, %r13d
jmp 0x10ff7
movq (%r14), %rsi
movl 0x8(%r14), %edx
movq %r12, %rdi
callq 0x9b20
movq 0x10(%rsp), %rcx
addq $0xc, %r15
cmpq %r15, %rbx
jne 0x10f29
cmpl $0x0, 0x24(%rsp)
movq 0x38(%rsp), %rbx
je 0x110a1
movq %rbx, %rdi
callq 0xf142
movq %rax, %rdi
callq 0x12470
movq %rbx, %rdi
callq 0xf142
movq 0x30(%rsp), %rcx
movq %rax, (%rcx)
movl %r13d, 0x18(%rcx)
movq 0x28(%rsp), %rax
movl %eax, 0x1c(%rcx)
movl $0x1, %eax
cmpl 0x8(%rsp), %r13d
jle 0x11087
xorl %eax, %eax
cmpl 0xc(%rsp), %r13d
jge 0x11087
movq 0x60(%rsp), %r14
movq %r14, %rdi
callq 0x7a5a
testb %al, %al
je 0x11121
movl 0x8(%r14), %eax
movq 0x30(%rsp), %rcx
movl %eax, 0x10(%rcx)
movq (%r14), %rax
movq %rax, 0x8(%rcx)
movl $0x2, %eax
movq 0x30(%rsp), %rcx
movl %eax, 0x14(%rcx)
movq %rbx, %rdi
callq 0xf142
movq %rax, %rdi
callq 0x124ac
jmp 0x1110c
movq 0x160(%rbx), %rax
movl -0x14(%rax), %eax
addl $0xffc2f700, %ecx       # imm = 0xFFC2F700
testl %eax, %eax
movq 0xb70(%rsp), %rdx
movl $0x0, (%rdx)
cmovel %eax, %ecx
movl %ecx, %r13d
jmp 0x1110c
movq 0x28(%rsp), %rsi
imull %esi, %esi
movq 0x38(%rsp), %rcx
movslq 0x170(%rcx), %rax
shlq $0xe, %rax
addq %rcx, %rax
movslq 0x680(%rsp,%r15), %rcx
movslq 0x684(%rsp,%r15), %rdx
shlq $0x8, %rcx
addq %rax, %rcx
addl %esi, 0x178(%rcx,%rdx,4)
movl 0xc(%rsp), %r13d
jmp 0x1110c
movl %r15d, %r13d
movl %r13d, %eax
addq $0xb38, %rsp            # imm = 0xB38
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x9d38(%rip), %rdi      # 0x1ae60
leaq 0x9d4e(%rip), %rsi      # 0x1ae7d
leaq 0x9d56(%rip), %rcx      # 0x1ae8c
movl $0x191, %edx            # imm = 0x191
callq 0x4190