// File: tewalds[P]morat/pentago/agentab.cpp
// Function: Morat::Pentago::AgentAB::negamax(Morat::Pentago::Board const&, short, short, int)
int16_t AgentAB::negamax(const Board & board, int16_t alpha, int16_t beta, int depth) {
	nodes_seen++;

	Outcome won = board.outcome();
	if(won >= Outcome::DRAW){
		if(won == Outcome::DRAW)
			return SCORE_DRAW;
		if(won == +board.to_play())
			return SCORE_WIN;
		return SCORE_LOSS;
	}

	if (depth <= 0){ //terminal node?
		int16_t score = -board.score();
		if(randomness){
			score <<= randomness;
			score -= rand() & ((1 << randomness)-1);
		}
		return score;
	}

	int16_t score = SCORE_LOSS;
	Move bestmove = M_RESIGN;
	Node * node;

	if(TT && (node = tt_get(board)) && node->depth >= depth){
		switch(node->flag){
		case VALID:  return node->score;
		case LBOUND: alpha = std::max(alpha, node->score); break;
		case UBOUND: beta  = std::min(beta,  node->score); break;
		default:     assert(false && "Unknown flag!");
		}
		if(alpha >= beta)
			return node->score;

		if(node->bestmove != M_UNKNOWN){
			//try the previous best move first
			bestmove = node->bestmove;
			Board n = board;
			bool move_success = n.move(bestmove);

			if(!move_success){
				logerr("FAIL!!!\nhash: " + to_str(board.simple_hash()) + ", state: " + board.state() + "\n");
				logerr(node->to_s() + "\n");
				logerr(board.to_s());
			}

			assert(move_success);
			score = -negamax(n, -beta, -alpha, depth-1);
		}
	}

	if (score < beta) { // no cutoff from bestmove
		//TODO: sort moves first?

		//generate moves
		for (RandomMoveIterator<XORShift_uint32> move(board, rand); !move.done(); ++move) {
//		for (MoveIterator move(board); !move.done(); ++move) {
			int16_t value = -negamax(move.board(), -beta, -std::max(alpha, score), depth-1);
			if (score < value) {
				score = value;
				bestmove = *move;
				if (score >= beta){
					break;
				}
			}
		}
	}

	if (TT) {
		uint8_t flag = (score <= alpha ? UBOUND :
		                score >= beta  ? LBOUND : VALID);
		tt_set(Node(board.simple_hash(), score, bestmove, depth, flag));
	}
	return score;
}

// Assembly:
subq $0x268, %rsp            # imm = 0x268
movw %cx, %ax
movw %dx, %cx
movq %rdi, 0x258(%rsp)
movq %rsi, 0x250(%rsp)
movw %cx, 0x24e(%rsp)
movw %ax, 0x24c(%rsp)
movl %r8d, 0x248(%rsp)
movq 0x258(%rsp), %rax
movq %rax, 0x58(%rsp)
movq 0x58(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x58(%rax)
movq 0x250(%rsp), %rdi
callq 0x14100
movb %al, 0x247(%rsp)
leaq 0x247(%rsp), %rdi
leaq 0x489ca(%rip), %rsi     # 0x5b81b
callq 0x140c0
testb $0x1, %al
jne 0x12e5f
jmp 0x12ee9
leaq 0x247(%rsp), %rdi
leaq 0x489ad(%rip), %rsi     # 0x5b81b
callq 0x14ae0
testb $0x1, %al
jne 0x12e79
jmp 0x12e88
movw $0x0, 0x266(%rsp)
jmp 0x1373e
movq 0x250(%rsp), %rdi
callq 0x14b50
movb %al, 0x245(%rsp)
movzbl 0x245(%rsp), %edi
callq 0x14b20
movb %al, 0x246(%rsp)
leaq 0x247(%rsp), %rdi
leaq 0x246(%rsp), %rsi
callq 0x14ae0
testb $0x1, %al
jne 0x12ecb
jmp 0x12eda
movw $0x7fff, 0x266(%rsp)    # imm = 0x7FFF
jmp 0x1373e
movw $0x8001, 0x266(%rsp)    # imm = 0x8001
jmp 0x1373e
cmpl $0x0, 0x248(%rsp)
jg 0x12f89
movq 0x250(%rsp), %rdi
callq 0x14b70
movw %ax, %cx
movq 0x58(%rsp), %rax
movswl %cx, %edx
xorl %ecx, %ecx
subl %edx, %ecx
movw %cx, 0x242(%rsp)
cmpl $0x0, 0x6c(%rax)
je 0x12f74
movq 0x58(%rsp), %rdi
movl 0x6c(%rdi), %ecx
movswl 0x242(%rsp), %eax
shll %cl, %eax
movw %ax, 0x242(%rsp)
addq $0x68, %rdi
callq 0x14bc0
movl %eax, %ecx
movq 0x58(%rsp), %rax
movl %ecx, 0x54(%rsp)
movl 0x6c(%rax), %ecx
movl $0x1, %eax
shll %cl, %eax
movl 0x54(%rsp), %ecx
subl $0x1, %eax
andl %eax, %ecx
movswl 0x242(%rsp), %eax
subl %ecx, %eax
movw %ax, 0x242(%rsp)
movw 0x242(%rsp), %ax
movw %ax, 0x266(%rsp)
jmp 0x1373e
movw $0x8001, 0x240(%rsp)    # imm = 0x8001
leaq 0x23e(%rsp), %rdi
movl $0xfffffffe, %esi       # imm = 0xFFFFFFFE
callq 0x14180
movq 0x58(%rsp), %rax
cmpq $0x0, 0x38(%rax)
je 0x134d3
movq 0x58(%rsp), %rdi
movq 0x250(%rsp), %rsi
callq 0x13760
movq %rax, 0x230(%rsp)
cmpq $0x0, %rax
je 0x134d3
movq 0x230(%rsp), %rax
movzbl 0xc(%rax), %eax
cmpl 0x248(%rsp), %eax
jl 0x134d3
movq 0x230(%rsp), %rax
movzbl 0xd(%rax), %eax
movl %eax, 0x50(%rsp)
subl $0x1, %eax
je 0x1301f
jmp 0x13009
movl 0x50(%rsp), %eax
subl $0x2, %eax
je 0x13038
jmp 0x13014
movl 0x50(%rsp), %eax
subl $0x3, %eax
je 0x1305e
jmp 0x13084
movq 0x230(%rsp), %rax
movw 0x8(%rax), %ax
movw %ax, 0x266(%rsp)
jmp 0x1373e
movq 0x230(%rsp), %rsi
addq $0x8, %rsi
leaq 0x24e(%rsp), %rdi
callq 0x14bd0
movw (%rax), %ax
movw %ax, 0x24e(%rsp)
jmp 0x130a3
movq 0x230(%rsp), %rsi
addq $0x8, %rsi
leaq 0x24c(%rsp), %rdi
callq 0x14c10
movw (%rax), %ax
movw %ax, 0x24c(%rsp)
jmp 0x130a3
leaq 0x31110(%rip), %rdi     # 0x4419b
leaq 0x31122(%rip), %rsi     # 0x441b4
movl $0x5a, %edx
leaq 0x3112a(%rip), %rcx     # 0x441c8
callq 0x52d0
movswl 0x24e(%rsp), %eax
movswl 0x24c(%rsp), %ecx
cmpl %ecx, %eax
jl 0x130d0
movq 0x230(%rsp), %rax
movw 0x8(%rax), %ax
movw %ax, 0x266(%rsp)
jmp 0x1373e
movq 0x230(%rsp), %rdi
addq $0xa, %rdi
movl $0xfffffffc, 0x22c(%rsp) # imm = 0xFFFFFFFC
leaq 0x22c(%rsp), %rsi
callq 0x14c50
testb $0x1, %al
jne 0x130fd
jmp 0x134d1
movq 0x230(%rsp), %rax
movw 0xa(%rax), %ax
movw %ax, 0x23e(%rsp)
movq 0x250(%rsp), %rsi
leaq 0x200(%rsp), %rdi
movl $0x28, %edx
callq 0x5380
movw 0x23e(%rsp), %ax
movw %ax, 0x1fd(%rsp)
leaq 0x200(%rsp), %rdi
movzwl 0x1fd(%rsp), %esi
callq 0x14c70
andb $0x1, %al
movb %al, 0x1ff(%rsp)
testb $0x1, 0x1ff(%rsp)
jne 0x13458
movq 0x250(%rsp), %rdi
callq 0x14ec0
movq %rax, %rsi
leaq 0x158(%rsp), %rdi
movq %rdi, 0x48(%rsp)
callq 0x14600
movq 0x48(%rsp), %rdx
leaq 0x31082(%rip), %rsi     # 0x44217
leaq 0x178(%rsp), %rdi
callq 0x14410
jmp 0x131a4
leaq 0x3107b(%rip), %rdx     # 0x44226
leaq 0x198(%rsp), %rdi
leaq 0x178(%rsp), %rsi
callq 0xaa40
jmp 0x131c2
movq 0x250(%rsp), %rsi
leaq 0x128(%rsp), %rdi
callq 0x2f450
jmp 0x131d9
leaq 0x1b8(%rsp), %rdi
leaq 0x198(%rsp), %rsi
leaq 0x128(%rsp), %rdx
callq 0x14510
jmp 0x131f8
leaq 0x30625(%rip), %rdx     # 0x43824
leaq 0x1d8(%rsp), %rdi
leaq 0x1b8(%rsp), %rsi
callq 0xaa40
jmp 0x13216
leaq 0x1d8(%rsp), %rdi
callq 0x143d0
jmp 0x13225
leaq 0x1d8(%rsp), %rdi
callq 0x5290
leaq 0x1b8(%rsp), %rdi
callq 0x5290
leaq 0x128(%rsp), %rdi
callq 0x5290
leaq 0x198(%rsp), %rdi
callq 0x5290
leaq 0x178(%rsp), %rdi
callq 0x5290
leaq 0x158(%rsp), %rdi
callq 0x5290
movq 0x230(%rsp), %rsi
leaq 0xe8(%rsp), %rdi
movq %rdi, 0x40(%rsp)
callq 0x14ff0
movq 0x40(%rsp), %rsi
leaq 0x3058b(%rip), %rdx     # 0x43824
leaq 0x108(%rsp), %rdi
callq 0xaa40
jmp 0x132a8
leaq 0x108(%rsp), %rdi
callq 0x143d0
jmp 0x132b7
leaq 0x108(%rsp), %rdi
callq 0x5290
leaq 0xe8(%rsp), %rdi
callq 0x5290
movq 0x250(%rsp), %rsi
leaq 0xc8(%rsp), %rdi
movq %rdi, 0x38(%rsp)
movl $0x1, %edx
callq 0x2f570
movq 0x38(%rsp), %rdi
callq 0x143d0
jmp 0x132fc
leaq 0xc8(%rsp), %rdi
callq 0x5290
jmp 0x13458
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x150(%rsp)
movl %eax, 0x14c(%rsp)
jmp 0x133d7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x150(%rsp)
movl %eax, 0x14c(%rsp)
jmp 0x133ca
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x150(%rsp)
movl %eax, 0x14c(%rsp)
jmp 0x133bd
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x150(%rsp)
movl %eax, 0x14c(%rsp)
jmp 0x133b0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x150(%rsp)
movl %eax, 0x14c(%rsp)
jmp 0x133a3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x150(%rsp)
movl %eax, 0x14c(%rsp)
leaq 0x1d8(%rsp), %rdi
callq 0x5290
leaq 0x1b8(%rsp), %rdi
callq 0x5290
leaq 0x128(%rsp), %rdi
callq 0x5290
leaq 0x198(%rsp), %rdi
callq 0x5290
leaq 0x178(%rsp), %rdi
callq 0x5290
leaq 0x158(%rsp), %rdi
callq 0x5290
jmp 0x1374e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x150(%rsp)
movl %eax, 0x14c(%rsp)
jmp 0x13420
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x150(%rsp)
movl %eax, 0x14c(%rsp)
leaq 0x108(%rsp), %rdi
callq 0x5290
leaq 0xe8(%rsp), %rdi
callq 0x5290
jmp 0x1374e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x150(%rsp)
movl %eax, 0x14c(%rsp)
leaq 0xc8(%rsp), %rdi
callq 0x5290
jmp 0x1374e
testb $0x1, 0x1ff(%rsp)
je 0x13464
jmp 0x13483
leaq 0x30dc5(%rip), %rdi     # 0x44230
leaq 0x30d42(%rip), %rsi     # 0x441b4
movl $0x6b, %edx
leaq 0x30d4a(%rip), %rcx     # 0x441c8
callq 0x52d0
movq 0x58(%rsp), %rdi
movswl 0x24c(%rsp), %ecx
xorl %eax, %eax
subl %ecx, %eax
movw %ax, %cx
movswl 0x24e(%rsp), %edx
xorl %eax, %eax
subl %edx, %eax
movl 0x248(%rsp), %r8d
subl $0x1, %r8d
leaq 0x200(%rsp), %rsi
movswl %cx, %edx
movswl %ax, %ecx
callq 0x12de0
movswl %ax, %ecx
xorl %eax, %eax
subl %ecx, %eax
movw %ax, 0x240(%rsp)
jmp 0x134d3
movswl 0x240(%rsp), %eax
movswl 0x24c(%rsp), %ecx
cmpl %ecx, %eax
jge 0x1366c
movq 0x58(%rsp), %rdx
movq 0x250(%rsp), %rsi
addq $0x68, %rdx
leaq 0x80(%rsp), %rdi
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
callq 0x15340
leaq 0x80(%rsp), %rdi
callq 0x15520
movb %al, 0x37(%rsp)
jmp 0x13521
movb 0x37(%rsp), %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x1355e
movl $0x3, 0x7c(%rsp)
jmp 0x1365d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x150(%rsp)
movl %eax, 0x14c(%rsp)
leaq 0x80(%rsp), %rdi
callq 0x15610
jmp 0x1374e
leaq 0x80(%rsp), %rdi
callq 0x15540
movq %rax, 0x28(%rsp)
jmp 0x13572
movw 0x24c(%rsp), %ax
negw %ax
movw %ax, 0x1e(%rsp)
leaq 0x24e(%rsp), %rdi
leaq 0x240(%rsp), %rsi
callq 0x14bd0
movq %rax, 0x20(%rsp)
jmp 0x1359e
movq 0x28(%rsp), %rsi
movq 0x58(%rsp), %rdi
movw 0x1e(%rsp), %cx
movq 0x20(%rsp), %rax
movzwl (%rax), %eax
negl %eax
movl 0x248(%rsp), %r8d
decl %r8d
movswl %cx, %edx
movswl %ax, %ecx
callq 0x12de0
movw %ax, 0x1c(%rsp)
jmp 0x135d4
movw 0x1c(%rsp), %ax
movswl %ax, %ecx
xorl %eax, %eax
subl %ecx, %eax
movw %ax, 0x7a(%rsp)
movswl 0x240(%rsp), %eax
movswl 0x7a(%rsp), %ecx
cmpl %ecx, %eax
jge 0x13647
movw 0x7a(%rsp), %ax
movw %ax, 0x240(%rsp)
leaq 0x80(%rsp), %rdi
callq 0x15550
movq %rax, 0x10(%rsp)
jmp 0x13617
movq 0x10(%rsp), %rax
movw (%rax), %ax
movw %ax, 0x23e(%rsp)
movswl 0x240(%rsp), %eax
movswl 0x24c(%rsp), %ecx
cmpl %ecx, %eax
jl 0x13645
movl $0x3, 0x7c(%rsp)
jmp 0x1365d
jmp 0x13647
jmp 0x13649
leaq 0x80(%rsp), %rdi
callq 0x15570
jmp 0x13658
jmp 0x1350e
leaq 0x80(%rsp), %rdi
callq 0x15610
jmp 0x1366c
movq 0x58(%rsp), %rax
cmpq $0x0, 0x38(%rax)
je 0x1372e
movswl 0x240(%rsp), %eax
movswl 0x24e(%rsp), %ecx
cmpl %ecx, %eax
jg 0x13698
movb $0x3, %al
movb %al, 0xf(%rsp)
jmp 0x136ca
movswl 0x240(%rsp), %ecx
movswl 0x24c(%rsp), %edx
movb $0x2, %al
movb $0x1, %sil
movb %sil, 0xd(%rsp)
cmpl %edx, %ecx
movb %al, 0xe(%rsp)
jge 0x136c2
movb 0xd(%rsp), %al
movb %al, 0xe(%rsp)
movb 0xe(%rsp), %al
movb %al, 0xf(%rsp)
movb 0xf(%rsp), %al
movb %al, 0x79(%rsp)
movq 0x250(%rsp), %rdi
callq 0x14ec0
movq %rax, %rsi
movw 0x240(%rsp), %cx
movw 0x23e(%rsp), %ax
movw %ax, 0x66(%rsp)
movl 0x248(%rsp), %eax
movb %al, %r8b
movb 0x79(%rsp), %al
leaq 0x68(%rsp), %rdi
movswl %cx, %edx
movzwl 0x66(%rsp), %ecx
movsbl %r8b, %r8d
movsbl %al, %r9d
callq 0x141a0
movq 0x58(%rsp), %rdi
leaq 0x68(%rsp), %rsi
callq 0x137a0
movw 0x240(%rsp), %ax
movw %ax, 0x266(%rsp)
movw 0x266(%rsp), %ax
addq $0x268, %rsp            # imm = 0x268
retq
movq 0x150(%rsp), %rdi
callq 0x57a0
nopl (%rax,%rax)