// File: tewalds[P]morat/hex/agentmctsthread.cpp
// Function: Morat::Hex::AgentMCTS::do_backup(Morat::Hex::AgentMCTS::Node*, Morat::Hex::AgentMCTS::Node const*, Morat::Side)
bool AgentMCTS::do_backup(Node * node, const Node * backup, Side to_play){
	Outcome node_outcome = node->outcome;
	if(node_outcome >= Outcome::DRAW) //already proven, probably by a different thread
		return true;

	if(backup->outcome == Outcome::UNKNOWN) //nothing proven by this child, so no chance
		return false;

	uint8_t proofdepth = backup->proofdepth;
	if(backup->outcome != to_play){
		int best_outcome = 0;
		backup = NULL;

		for (const auto& child : node->children) {
			Outcome child_outcome = child.outcome; //save a copy to avoid race conditions
			int outcome = 0;

			//these should be sorted in likelyness of matching, most likely first
			if(child_outcome == Outcome::UNKNOWN){ // win/draw/loss
				outcome = 3;
			}else if(child_outcome == to_play){ //win
				backup = &child;
				best_outcome = 6;
				proofdepth = child.proofdepth;
				break;
			}else if(child_outcome == ~to_play){ //loss
				outcome = 0;
			}else if(child_outcome == Outcome::DRAW ||
			         child_outcome == Outcome::DRAW2){ //draw
				if(node_outcome == -to_play) //draw/loss, ie I can't win
					outcome = 4;
				else
					outcome = 2;
			}else if(child_outcome == -~to_play){ //win/draw, ie opponent can't win
				outcome = 5;
			}else if(child_outcome == -to_play){ //draw/loss, ie I can't win
				outcome = 1;
			}else{
				logerr("child_outcome == " + child_outcome.to_s() + "\n");
				assert(false && "How'd I get here? All outcomes should be tested above");
			}

			if(proofdepth < child.proofdepth)
				proofdepth = child.proofdepth;

			auto better_than_best = [&]() -> bool {
				// any child is better than nothing
				if (backup == NULL)
					return true;

				// a better outcome is always preferable
				if (best_outcome < outcome)
					return true;
				if (best_outcome > outcome)
					return false;

				// do we care about depth? if so, take the longest.
				if (longestloss) {
					if (backup->proofdepth < child.proofdepth)
						return true;
					if (backup->proofdepth > child.proofdepth)
						return false;
				}

				// all else equal, take the hardest to solve
				return (backup->exp.num() < child.exp.num());
			};

			if (better_than_best()) {
				best_outcome = outcome;
				backup = &child;
			}
		}

		if(best_outcome == 3) //no win, but found an unknown
			return false;
	}

	if(node->outcome.cas(node_outcome, backup->outcome)){
		node->bestmove = backup->move;
		node->proofdepth = proofdepth + 1;
	}else //if it was in a race, try again, might promote a partial solve to full solve
		return do_backup(node, backup, to_play);

	return (node->outcome >= Outcome::DRAW);
}

// Assembly:
subq $0x118, %rsp            # imm = 0x118
movb %cl, %al
movb %al, 0x116(%rsp)
movq %rdi, 0x108(%rsp)
movq %rsi, 0x100(%rsp)
movq %rdx, 0xf8(%rsp)
movq 0x108(%rsp), %rax
movq %rax, 0x10(%rsp)
movq 0x100(%rsp), %rax
movb 0x22(%rax), %al
movb %al, 0xf7(%rsp)
leaq 0xf7(%rsp), %rdi
leaq 0x4635d(%rip), %rsi     # 0x6d4c3
callq 0x1a8c0
testb $0x1, %al
jne 0x27171
jmp 0x2717e
movb $0x1, 0x117(%rsp)
jmp 0x276f9
movq 0xf8(%rsp), %rdi
addq $0x22, %rdi
leaq 0x4632f(%rip), %rsi     # 0x6d4c0
callq 0x1c810
testb $0x1, %al
jne 0x2719c
jmp 0x271a9
movb $0x0, 0x117(%rsp)
jmp 0x276f9
movq 0xf8(%rsp), %rax
movb 0x23(%rax), %al
movb %al, 0xf6(%rsp)
movq 0xf8(%rsp), %rdi
addq $0x22, %rdi
leaq 0x116(%rsp), %rsi
callq 0x1cb50
testb $0x1, %al
jne 0x271dd
jmp 0x27634
movl $0x0, 0xf0(%rsp)
movq $0x0, 0xf8(%rsp)
movq 0x100(%rsp), %rax
addq $0x28, %rax
movq %rax, 0xe8(%rsp)
movq 0xe8(%rsp), %rdi
callq 0x1c340
movq %rax, 0xe0(%rsp)
movq 0xe8(%rsp), %rdi
callq 0x1c390
movq %rax, 0xd8(%rsp)
movq 0xe0(%rsp), %rax
cmpq 0xd8(%rsp), %rax
je 0x2761b
movq 0xe0(%rsp), %rax
movq %rax, 0xd0(%rsp)
movq 0xd0(%rsp), %rax
movb 0x22(%rax), %al
movb %al, 0xcf(%rsp)
movl $0x0, 0xc8(%rsp)
leaq 0xcf(%rsp), %rdi
leaq 0x4623c(%rip), %rsi     # 0x6d4c0
callq 0x1c810
testb $0x1, %al
jne 0x2728f
jmp 0x2729f
movl $0x3, 0xc8(%rsp)
jmp 0x2756a
leaq 0xcf(%rsp), %rdi
leaq 0x116(%rsp), %rsi
callq 0x1c7c0
testb $0x1, %al
jne 0x272ba
jmp 0x272ec
movq 0xd0(%rsp), %rax
movq %rax, 0xf8(%rsp)
movl $0x6, 0xf0(%rsp)
movq 0xd0(%rsp), %rax
movb 0x23(%rax), %al
movb %al, 0xf6(%rsp)
jmp 0x2761b
movb 0x116(%rsp), %al
movb %al, 0xc6(%rsp)
movzbl 0xc6(%rsp), %edi
callq 0x1c680
movb %al, 0xc7(%rsp)
leaq 0xcf(%rsp), %rdi
leaq 0xc7(%rsp), %rsi
callq 0x1c7c0
testb $0x1, %al
jne 0x27329
jmp 0x27339
movl $0x0, 0xc8(%rsp)
jmp 0x27566
leaq 0xcf(%rsp), %rdi
leaq 0x4617b(%rip), %rsi     # 0x6d4c3
callq 0x1c810
testb $0x1, %al
jne 0x2736b
leaq 0xcf(%rsp), %rdi
leaq 0x46166(%rip), %rsi     # 0x6d4c6
callq 0x1c810
testb $0x1, %al
jne 0x2736b
jmp 0x273c5
movb 0x116(%rsp), %al
movb %al, 0xc4(%rsp)
movzbl 0xc4(%rsp), %edi
callq 0x297e0
movb %al, 0xc5(%rsp)
leaq 0xf7(%rsp), %rdi
leaq 0xc5(%rsp), %rsi
callq 0x1c810
testb $0x1, %al
jne 0x273a8
jmp 0x273b5
movl $0x4, 0xc8(%rsp)
jmp 0x273c0
movl $0x2, 0xc8(%rsp)
jmp 0x27564
movb 0x116(%rsp), %al
movb %al, 0xc1(%rsp)
movzbl 0xc1(%rsp), %edi
callq 0x1c680
movb %al, 0xc2(%rsp)
movzbl 0xc2(%rsp), %edi
callq 0x297e0
movb %al, 0xc3(%rsp)
leaq 0xcf(%rsp), %rdi
leaq 0xc3(%rsp), %rsi
callq 0x1c810
testb $0x1, %al
jne 0x27416
jmp 0x27426
movl $0x5, 0xc8(%rsp)
jmp 0x27562
movb 0x116(%rsp), %al
movb %al, 0xbf(%rsp)
movzbl 0xbf(%rsp), %edi
callq 0x297e0
movb %al, 0xc0(%rsp)
leaq 0xcf(%rsp), %rdi
leaq 0xc0(%rsp), %rsi
callq 0x1c810
testb $0x1, %al
jne 0x27463
jmp 0x27473
movl $0x1, 0xc8(%rsp)
jmp 0x27560
leaq 0x58(%rsp), %rdi
movq %rdi, 0x8(%rsp)
leaq 0xcf(%rsp), %rsi
callq 0x47e40
movq 0x8(%rsp), %rdx
leaq 0x27132(%rip), %rsi     # 0x4e5c8
leaq 0x78(%rsp), %rdi
callq 0x19f30
jmp 0x274a2
leaq 0x2543f(%rip), %rdx     # 0x4c8e8
leaq 0x98(%rsp), %rdi
leaq 0x78(%rsp), %rsi
callq 0xb910
jmp 0x274bd
leaq 0x98(%rsp), %rdi
callq 0x1a9b0
jmp 0x274cc
leaq 0x98(%rsp), %rdi
callq 0x5260
leaq 0x78(%rsp), %rdi
callq 0x5260
leaq 0x58(%rsp), %rdi
callq 0x5260
leaq 0x270e6(%rip), %rdi     # 0x4e5da
leaq 0x26ffa(%rip), %rsi     # 0x4e4f5
movl $0x116, %edx            # imm = 0x116
leaq 0x27114(%rip), %rcx     # 0x4e61b
callq 0x52a0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x50(%rsp)
movl %eax, 0x4c(%rsp)
jmp 0x27551
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x50(%rsp)
movl %eax, 0x4c(%rsp)
jmp 0x27547
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x50(%rsp)
movl %eax, 0x4c(%rsp)
leaq 0x98(%rsp), %rdi
callq 0x5260
leaq 0x78(%rsp), %rdi
callq 0x5260
leaq 0x58(%rsp), %rdi
callq 0x5260
jmp 0x2770a
jmp 0x27562
jmp 0x27564
jmp 0x27566
jmp 0x27568
jmp 0x2756a
movzbl 0xf6(%rsp), %eax
movq 0xd0(%rsp), %rcx
movzbl 0x23(%rcx), %ecx
cmpl %ecx, %eax
jge 0x27594
movq 0xd0(%rsp), %rax
movb 0x23(%rax), %al
movb %al, 0xf6(%rsp)
movq 0x10(%rsp), %rax
leaq 0xf8(%rsp), %rcx
movq %rcx, 0x20(%rsp)
leaq 0xf0(%rsp), %rcx
movq %rcx, 0x28(%rsp)
leaq 0xc8(%rsp), %rcx
movq %rcx, 0x30(%rsp)
movq %rax, 0x38(%rsp)
movq 0xd0(%rsp), %rax
movq %rax, 0x40(%rsp)
leaq 0x20(%rsp), %rdi
callq 0x28870
testb $0x1, %al
jne 0x275e2
jmp 0x27600
movl 0xc8(%rsp), %eax
movl %eax, 0xf0(%rsp)
movq 0xd0(%rsp), %rax
movq %rax, 0xf8(%rsp)
jmp 0x27602
movq 0xe0(%rsp), %rax
addq $0x30, %rax
movq %rax, 0xe0(%rsp)
jmp 0x27232
cmpl $0x3, 0xf0(%rsp)
jne 0x27632
movb $0x0, 0x117(%rsp)
jmp 0x276f9
jmp 0x27634
movq 0x100(%rsp), %rdi
addq $0x22, %rdi
movb 0xf7(%rsp), %al
movb %al, 0x1f(%rsp)
movq 0xf8(%rsp), %rax
movb 0x22(%rax), %al
movb %al, 0x1e(%rsp)
movb 0x1f(%rsp), %al
movzbl %al, %esi
movzbl 0x1e(%rsp), %edx
callq 0x48710
testb $0x1, %al
jne 0x27671
jmp 0x276a3
movq 0xf8(%rsp), %rcx
movq 0x100(%rsp), %rax
movw 0x24(%rcx), %cx
movw %cx, 0x26(%rax)
movzbl 0xf6(%rsp), %eax
addl $0x1, %eax
movb %al, %cl
movq 0x100(%rsp), %rax
movb %cl, 0x23(%rax)
jmp 0x276d8
movq 0x10(%rsp), %rdi
movq 0x100(%rsp), %rsi
movq 0xf8(%rsp), %rdx
movb 0x116(%rsp), %al
movb %al, 0x1d(%rsp)
movzbl 0x1d(%rsp), %ecx
callq 0x27110
andb $0x1, %al
movb %al, 0x117(%rsp)
jmp 0x276f9
movq 0x100(%rsp), %rdi
addq $0x22, %rdi
leaq 0x45dd8(%rip), %rsi     # 0x6d4c3
callq 0x1a8c0
andb $0x1, %al
movb %al, 0x117(%rsp)
movb 0x117(%rsp), %al
andb $0x1, %al
addq $0x118, %rsp            # imm = 0x118
retq
movq 0x50(%rsp), %rdi
callq 0x5760
nopw %cs:(%rax,%rax)