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

	int won = board.won();
	if(won >= 0){
		if(won == 0)
			return SCORE_DRAW;
		if(won == board.toplay())
			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 = max(alpha, node->score); break;
		case UBOUND: beta  = 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.hash()) + ", orientation: " + to_str(board.orient()) + ", state: " + board.state() + "\n");
//				logerr(node->to_s(board.orient()) + "\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 (MoveIterator move(board); !move.done(); ++move) {
			int16_t value = -negamax(move.board(), -beta, -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.hash(), score, bestmove, depth, flag));
	}
	return score;
}

// Assembly:
subq $0x138, %rsp            # imm = 0x138
movw %cx, %ax
movw %dx, %cx
movq %rdi, 0x128(%rsp)
movq %rsi, 0x120(%rsp)
movw %cx, 0x11e(%rsp)
movw %ax, 0x11c(%rsp)
movl %r8d, 0x118(%rsp)
movq 0x128(%rsp), %rax
movq %rax, 0x38(%rsp)
movq 0x58(%rax), %rcx
addq $0x1, %rcx
movq %rcx, 0x58(%rax)
movq 0x120(%rsp), %rdi
callq 0x15fb0
movsbl %al, %eax
movl %eax, 0x114(%rsp)
cmpl $0x0, 0x114(%rsp)
jl 0x3a98b
cmpl $0x0, 0x114(%rsp)
jne 0x3a948
movw $0x0, 0x136(%rsp)
jmp 0x3aebc
movl 0x114(%rsp), %eax
movl %eax, 0x34(%rsp)
movq 0x120(%rsp), %rdi
callq 0x17190
movb %al, %cl
movl 0x34(%rsp), %eax
movzbl %cl, %ecx
cmpl %ecx, %eax
jne 0x3a97c
movw $0x7fff, 0x136(%rsp)    # imm = 0x7FFF
jmp 0x3aebc
movw $0x8001, 0x136(%rsp)    # imm = 0x8001
jmp 0x3aebc
cmpl $0x0, 0x118(%rsp)
jg 0x3aa2b
movq 0x120(%rsp), %rdi
callq 0x3b9f0
movw %ax, %cx
movq 0x38(%rsp), %rax
movswl %cx, %edx
xorl %ecx, %ecx
subl %edx, %ecx
movw %cx, 0x112(%rsp)
cmpl $0x0, 0x6c(%rax)
je 0x3aa16
movq 0x38(%rsp), %rdi
movl 0x6c(%rdi), %ecx
movswl 0x112(%rsp), %eax
shll %cl, %eax
movw %ax, 0x112(%rsp)
addq $0x68, %rdi
callq 0x3ba40
movl %eax, %ecx
movq 0x38(%rsp), %rax
movl %ecx, 0x30(%rsp)
movl 0x6c(%rax), %ecx
movl $0x1, %eax
shll %cl, %eax
movl 0x30(%rsp), %ecx
subl $0x1, %eax
andl %eax, %ecx
movswl 0x112(%rsp), %eax
subl %ecx, %eax
movw %ax, 0x112(%rsp)
movw 0x112(%rsp), %ax
movw %ax, 0x136(%rsp)
jmp 0x3aebc
movw $0x8001, 0x110(%rsp)    # imm = 0x8001
leaq 0x10c(%rsp), %rdi
movl $0xfffffffe, %esi       # imm = 0xFFFFFFFE
movl $0x8, %edx
callq 0x16890
movq 0x38(%rsp), %rax
cmpq $0x0, 0x38(%rax)
je 0x3ac78
movq 0x38(%rsp), %rdi
movq 0x120(%rsp), %rsi
callq 0x3aee0
movq %rax, 0x100(%rsp)
cmpq $0x0, %rax
je 0x3ac78
movq 0x100(%rsp), %rax
movzbl 0x10(%rax), %eax
cmpl 0x118(%rsp), %eax
jl 0x3ac78
movq 0x100(%rsp), %rax
movzbl 0x11(%rax), %eax
movl %eax, 0x2c(%rsp)
subl $0x1, %eax
je 0x3aac6
jmp 0x3aab0
movl 0x2c(%rsp), %eax
subl $0x2, %eax
je 0x3aadf
jmp 0x3aabb
movl 0x2c(%rsp), %eax
subl $0x3, %eax
je 0x3ab05
jmp 0x3ab2b
movq 0x100(%rsp), %rax
movw 0x8(%rax), %ax
movw %ax, 0x136(%rsp)
jmp 0x3aebc
movq 0x100(%rsp), %rsi
addq $0x8, %rsi
leaq 0x11e(%rsp), %rdi
callq 0x3ba50
movw (%rax), %ax
movw %ax, 0x11e(%rsp)
jmp 0x3ab4a
movq 0x100(%rsp), %rsi
addq $0x8, %rsi
leaq 0x11c(%rsp), %rdi
callq 0x3ba90
movw (%rax), %ax
movw %ax, 0x11c(%rsp)
jmp 0x3ab4a
leaq 0x6e59(%rip), %rdi      # 0x4198b
leaq 0x6e6b(%rip), %rsi      # 0x419a4
movl $0x54, %edx
leaq 0x6e6b(%rip), %rcx      # 0x419b0
callq 0x4250
movswl 0x11e(%rsp), %eax
movswl 0x11c(%rsp), %ecx
cmpl %ecx, %eax
jl 0x3ab77
movq 0x100(%rsp), %rax
movw 0x8(%rax), %ax
movw %ax, 0x136(%rsp)
jmp 0x3aebc
movq 0x100(%rsp), %rdi
addq $0xc, %rdi
movl $0xfffffffc, 0xfc(%rsp) # imm = 0xFFFFFFFC
leaq 0xfc(%rsp), %rsi
callq 0x2de60
testb $0x1, %al
jne 0x3aba4
jmp 0x3ac76
movq 0x100(%rsp), %rax
movw 0xc(%rax), %ax
movw %ax, 0x10c(%rsp)
movq 0x120(%rsp), %rsi
leaq 0xd0(%rsp), %rdi
movl $0x28, %edx
callq 0x4300
movl 0x10c(%rsp), %eax
movl %eax, 0xc8(%rsp)
movl 0xc8(%rsp), %esi
leaq 0xd0(%rsp), %rdi
callq 0xd040
andb $0x1, %al
movb %al, 0xcf(%rsp)
testb $0x1, 0xcf(%rsp)
je 0x3ac09
jmp 0x3ac28
leaq 0x362b(%rip), %rdi      # 0x3e23b
leaq 0x6d8d(%rip), %rsi      # 0x419a4
movl $0x65, %edx
leaq 0x6d8d(%rip), %rcx      # 0x419b0
callq 0x4250
movq 0x38(%rsp), %rdi
movswl 0x11c(%rsp), %ecx
xorl %eax, %eax
subl %ecx, %eax
movw %ax, %cx
movswl 0x11e(%rsp), %edx
xorl %eax, %eax
subl %edx, %eax
movl 0x118(%rsp), %r8d
subl $0x1, %r8d
leaq 0xd0(%rsp), %rsi
movswl %cx, %edx
movswl %ax, %ecx
callq 0x3a8c0
movswl %ax, %ecx
xorl %eax, %eax
subl %ecx, %eax
movw %ax, 0x110(%rsp)
jmp 0x3ac78
movswl 0x110(%rsp), %eax
movswl 0x11c(%rsp), %ecx
cmpl %ecx, %eax
jge 0x3aded
movq 0x120(%rsp), %rsi
leaq 0x78(%rsp), %rdi
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
callq 0x15b10
leaq 0x78(%rsp), %rdi
callq 0x15c80
movb %al, 0x2b(%rsp)
jmp 0x3acb7
movb 0x2b(%rsp), %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x3aceb
movl $0x3, 0x68(%rsp)
jmp 0x3ade1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x70(%rsp)
movl %eax, 0x6c(%rsp)
leaq 0x78(%rsp), %rdi
callq 0x15e30
jmp 0x3aecc
leaq 0x78(%rsp), %rdi
callq 0x32d50
movq %rax, 0x20(%rsp)
jmp 0x3acfc
movw 0x11c(%rsp), %ax
negw %ax
movw %ax, 0x16(%rsp)
leaq 0x11e(%rsp), %rdi
leaq 0x110(%rsp), %rsi
callq 0x3ba50
movq %rax, 0x18(%rsp)
jmp 0x3ad28
movq 0x20(%rsp), %rsi
movq 0x38(%rsp), %rdi
movw 0x16(%rsp), %cx
movq 0x18(%rsp), %rax
movzwl (%rax), %eax
negl %eax
movl 0x118(%rsp), %r8d
decl %r8d
movswl %cx, %edx
movswl %ax, %ecx
callq 0x3a8c0
movw %ax, 0x14(%rsp)
jmp 0x3ad5e
movw 0x14(%rsp), %ax
movswl %ax, %ecx
xorl %eax, %eax
subl %ecx, %eax
movw %ax, 0x66(%rsp)
movswl 0x110(%rsp), %eax
movswl 0x66(%rsp), %ecx
cmpl %ecx, %eax
jge 0x3adce
movw 0x66(%rsp), %ax
movw %ax, 0x110(%rsp)
leaq 0x78(%rsp), %rdi
callq 0x32cd0
movq %rax, 0x8(%rsp)
jmp 0x3ad9e
movq 0x8(%rsp), %rax
movw (%rax), %ax
movw %ax, 0x10c(%rsp)
movswl 0x110(%rsp), %eax
movswl 0x11c(%rsp), %ecx
cmpl %ecx, %eax
jl 0x3adcc
movl $0x3, 0x68(%rsp)
jmp 0x3ade1
jmp 0x3adce
jmp 0x3add0
leaq 0x78(%rsp), %rdi
callq 0x15cb0
jmp 0x3addc
jmp 0x3aca7
leaq 0x78(%rsp), %rdi
callq 0x15e30
jmp 0x3aded
movq 0x38(%rsp), %rax
cmpq $0x0, 0x38(%rax)
je 0x3aeac
movswl 0x110(%rsp), %eax
movswl 0x11e(%rsp), %ecx
cmpl %ecx, %eax
jg 0x3ae19
movb $0x3, %al
movb %al, 0x7(%rsp)
jmp 0x3ae4b
movswl 0x110(%rsp), %ecx
movswl 0x11c(%rsp), %edx
movb $0x2, %al
movb $0x1, %sil
movb %sil, 0x5(%rsp)
cmpl %edx, %ecx
movb %al, 0x6(%rsp)
jge 0x3ae43
movb 0x5(%rsp), %al
movb %al, 0x6(%rsp)
movb 0x6(%rsp), %al
movb %al, 0x7(%rsp)
movb 0x7(%rsp), %al
movb %al, 0x65(%rsp)
movq 0x120(%rsp), %rdi
callq 0xd9e0
movq %rax, %rsi
movw 0x110(%rsp), %dx
movl 0x10c(%rsp), %eax
movl %eax, 0x44(%rsp)
movl 0x118(%rsp), %eax
movb %al, %r8b
movb 0x65(%rsp), %al
movl 0x44(%rsp), %ecx
leaq 0x48(%rsp), %rdi
movswl %dx, %edx
movsbl %r8b, %r8d
movsbl %al, %r9d
callq 0x3b8a0
movq 0x38(%rsp), %rdi
leaq 0x48(%rsp), %rsi
callq 0x3af20
movw 0x110(%rsp), %ax
movw %ax, 0x136(%rsp)
movw 0x136(%rsp), %ax
addq $0x138, %rsp            # imm = 0x138
retq
movq 0x70(%rsp), %rdi
callq 0x4660
nopw %cs:(%rax,%rax)