// File: tewalds[P]morat/pentago/agentmctsthread.cpp
// Function: Morat::Pentago::AgentMCTS::do_backup(Morat::Pentago::AgentMCTS::Node*, Morat::Pentago::AgentMCTS::Node*, Morat::Side)
bool AgentMCTS::do_backup(Node * node, 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){
		uint64_t sims = 0, bestsims = 0, outcome = 0, best_outcome = 0;
		backup = NULL;

		Node * child = node->children.begin(),
			 * end = node->children.end();

		for( ; child != end; child++){
			Outcome child_outcome = child->outcome; //save a copy to avoid race conditions

			if(proofdepth < child->proofdepth+1)
				proofdepth = child->proofdepth+1;

			//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;
				outcome = 6;
				proofdepth = child->proofdepth+1;
				break;
			}else if(child_outcome == ~to_play){ //loss
				outcome = 0;
			}else if(child_outcome == Outcome::DRAW){ //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");
			}

			sims = child->exp.num();
			if(best_outcome < outcome){ //better outcome is always preferable
				best_outcome = outcome;
				bestsims = sims;
				backup = child;
			}else if(best_outcome == outcome && ((outcome == 0 && bestsims < sims) || bestsims > sims)){
				//find long losses or easy wins/draws
				bestsims = sims;
				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;
	}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 $0xe8, %rsp
movb %cl, %al
movb %al, 0xe6(%rsp)
movq %rdi, 0xd8(%rsp)
movq %rsi, 0xd0(%rsp)
movq %rdx, 0xc8(%rsp)
movq 0xd8(%rsp), %rax
movq %rax, 0x8(%rsp)
movq 0xd0(%rsp), %rax
movb 0x12(%rax), %al
movb %al, 0xc7(%rsp)
leaq 0xc7(%rsp), %rdi
leaq 0x36225(%rip), %rsi     # 0x5b81b
callq 0x140c0
testb $0x1, %al
jne 0x25601
jmp 0x2560e
movb $0x1, 0xe7(%rsp)
jmp 0x25bbe
movq 0xc8(%rsp), %rdi
addq $0x12, %rdi
leaq 0x361f7(%rip), %rsi     # 0x5b818
callq 0x14ae0
testb $0x1, %al
jne 0x2562c
jmp 0x25639
movb $0x0, 0xe7(%rsp)
jmp 0x25bbe
movq 0xc8(%rsp), %rax
movb 0x13(%rax), %al
movb %al, 0xc6(%rsp)
movq 0xc8(%rsp), %rdi
addq $0x12, %rdi
leaq 0xe6(%rsp), %rsi
callq 0x1da90
testb $0x1, %al
jne 0x2566d
jmp 0x25aff
movq $0x0, 0xb8(%rsp)
movq $0x0, 0xb0(%rsp)
movq $0x0, 0xa8(%rsp)
movq $0x0, 0xa0(%rsp)
movq $0x0, 0xc8(%rsp)
movq 0xd0(%rsp), %rdi
addq $0x18, %rdi
callq 0x1d7b0
movq %rax, 0x98(%rsp)
movq 0xd0(%rsp), %rdi
addq $0x18, %rdi
callq 0x1d800
movq %rax, 0x90(%rsp)
movq 0x98(%rsp), %rax
cmpq 0x90(%rsp), %rax
je 0x25ae5
movq 0x98(%rsp), %rax
movb 0x12(%rax), %al
movb %al, 0x8f(%rsp)
movzbl 0xc6(%rsp), %eax
movq 0x98(%rsp), %rcx
movzbl 0x13(%rcx), %ecx
addl $0x1, %ecx
cmpl %ecx, %eax
jge 0x25734
movq 0x98(%rsp), %rax
movzbl 0x13(%rax), %eax
addl $0x1, %eax
movb %al, 0xc6(%rsp)
leaq 0x8f(%rsp), %rdi
leaq 0x360d5(%rip), %rsi     # 0x5b818
callq 0x14ae0
testb $0x1, %al
jne 0x2574e
jmp 0x2575f
movq $0x3, 0xa8(%rsp)
jmp 0x25a0e
leaq 0x8f(%rsp), %rdi
leaq 0xe6(%rsp), %rsi
callq 0x1d9c0
testb $0x1, %al
jne 0x2577a
jmp 0x257b1
movq 0x98(%rsp), %rax
movq %rax, 0xc8(%rsp)
movq $0x6, 0xa8(%rsp)
movq 0x98(%rsp), %rax
movzbl 0x13(%rax), %eax
addl $0x1, %eax
movb %al, 0xc6(%rsp)
jmp 0x25ae5
movb 0xe6(%rsp), %al
movb %al, 0x8d(%rsp)
movzbl 0x8d(%rsp), %edi
callq 0x165d0
movb %al, 0x8e(%rsp)
leaq 0x8f(%rsp), %rdi
leaq 0x8e(%rsp), %rsi
callq 0x1d9c0
testb $0x1, %al
jne 0x257ee
jmp 0x257ff
movq $0x0, 0xa8(%rsp)
jmp 0x25a0a
leaq 0x8f(%rsp), %rdi
leaq 0x3600d(%rip), %rsi     # 0x5b81b
callq 0x14ae0
testb $0x1, %al
jne 0x25819
jmp 0x25875
movb 0xe6(%rsp), %al
movb %al, 0x8b(%rsp)
movzbl 0x8b(%rsp), %edi
callq 0x266c0
movb %al, 0x8c(%rsp)
leaq 0xc7(%rsp), %rdi
leaq 0x8c(%rsp), %rsi
callq 0x14ae0
testb $0x1, %al
jne 0x25856
jmp 0x25864
movq $0x4, 0xa8(%rsp)
jmp 0x25870
movq $0x2, 0xa8(%rsp)
jmp 0x25a08
movb 0xe6(%rsp), %al
movb %al, 0x88(%rsp)
movzbl 0x88(%rsp), %edi
callq 0x165d0
movb %al, 0x89(%rsp)
movzbl 0x89(%rsp), %edi
callq 0x266c0
movb %al, 0x8a(%rsp)
leaq 0x8f(%rsp), %rdi
leaq 0x8a(%rsp), %rsi
callq 0x14ae0
testb $0x1, %al
jne 0x258c6
jmp 0x258d7
movq $0x5, 0xa8(%rsp)
jmp 0x25a06
movb 0xe6(%rsp), %al
movb %al, 0x86(%rsp)
movzbl 0x86(%rsp), %edi
callq 0x266c0
movb %al, 0x87(%rsp)
leaq 0x8f(%rsp), %rdi
leaq 0x87(%rsp), %rsi
callq 0x14ae0
testb $0x1, %al
jne 0x25914
jmp 0x25925
movq $0x1, 0xa8(%rsp)
jmp 0x25a04
leaq 0x20(%rsp), %rdi
movq %rdi, (%rsp)
leaq 0x8f(%rsp), %rsi
callq 0x3f590
movq (%rsp), %rdx
leaq 0x20082(%rip), %rsi     # 0x459c8
leaq 0x40(%rsp), %rdi
callq 0x14410
jmp 0x25952
leaq 0x1decb(%rip), %rdx     # 0x43824
leaq 0x60(%rsp), %rdi
leaq 0x40(%rsp), %rsi
callq 0xaa40
jmp 0x2596a
leaq 0x60(%rsp), %rdi
callq 0x143d0
jmp 0x25976
leaq 0x60(%rsp), %rdi
callq 0x5290
leaq 0x40(%rsp), %rdi
callq 0x5290
leaq 0x20(%rsp), %rdi
callq 0x5290
leaq 0x2003f(%rip), %rdi     # 0x459da
leaq 0x1ff3f(%rip), %rsi     # 0x458e1
movl $0xfa, %edx
leaq 0x2006d(%rip), %rcx     # 0x45a1b
callq 0x52d0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x18(%rsp)
movl %eax, 0x14(%rsp)
jmp 0x259f5
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x18(%rsp)
movl %eax, 0x14(%rsp)
jmp 0x259eb
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x18(%rsp)
movl %eax, 0x14(%rsp)
leaq 0x60(%rsp), %rdi
callq 0x5290
leaq 0x40(%rsp), %rdi
callq 0x5290
leaq 0x20(%rsp), %rdi
callq 0x5290
jmp 0x25bcf
jmp 0x25a06
jmp 0x25a08
jmp 0x25a0a
jmp 0x25a0c
jmp 0x25a0e
movq 0x98(%rsp), %rdi
callq 0x1da00
movq %rax, 0xb8(%rsp)
movq 0xa0(%rsp), %rax
cmpq 0xa8(%rsp), %rax
jae 0x25a67
movq 0xa8(%rsp), %rax
movq %rax, 0xa0(%rsp)
movq 0xb8(%rsp), %rax
movq %rax, 0xb0(%rsp)
movq 0x98(%rsp), %rax
movq %rax, 0xc8(%rsp)
jmp 0x25aca
movq 0xa0(%rsp), %rax
cmpq 0xa8(%rsp), %rax
jne 0x25ac8
cmpq $0x0, 0xa8(%rsp)
jne 0x25a96
movq 0xb0(%rsp), %rax
cmpq 0xb8(%rsp), %rax
jb 0x25aa8
movq 0xb0(%rsp), %rax
cmpq 0xb8(%rsp), %rax
jbe 0x25ac8
movq 0xb8(%rsp), %rax
movq %rax, 0xb0(%rsp)
movq 0x98(%rsp), %rax
movq %rax, 0xc8(%rsp)
jmp 0x25aca
jmp 0x25acc
movq 0x98(%rsp), %rax
addq $0x20, %rax
movq %rax, 0x98(%rsp)
jmp 0x256db
cmpq $0x3, 0xa0(%rsp)
jne 0x25afd
movb $0x0, 0xe7(%rsp)
jmp 0x25bbe
jmp 0x25aff
movq 0xd0(%rsp), %rdi
addq $0x12, %rdi
movb 0xc7(%rsp), %al
movb %al, 0x13(%rsp)
movq 0xc8(%rsp), %rax
movb 0x12(%rax), %al
movb %al, 0x12(%rsp)
movb 0x13(%rsp), %al
movzbl %al, %esi
movzbl 0x12(%rsp), %edx
callq 0x3fe60
testb $0x1, %al
jne 0x25b3c
jmp 0x25b68
movq 0xc8(%rsp), %rcx
movq 0xd0(%rsp), %rax
movw 0x14(%rcx), %cx
movw %cx, 0x16(%rax)
movb 0xc6(%rsp), %cl
movq 0xd0(%rsp), %rax
movb %cl, 0x13(%rax)
jmp 0x25b9d
movq 0x8(%rsp), %rdi
movq 0xd0(%rsp), %rsi
movq 0xc8(%rsp), %rdx
movb 0xe6(%rsp), %al
movb %al, 0x11(%rsp)
movzbl 0x11(%rsp), %ecx
callq 0x255a0
andb $0x1, %al
movb %al, 0xe7(%rsp)
jmp 0x25bbe
movq 0xd0(%rsp), %rdi
addq $0x12, %rdi
leaq 0x35c6b(%rip), %rsi     # 0x5b81b
callq 0x140c0
andb $0x1, %al
movb %al, 0xe7(%rsp)
movb 0xe7(%rsp), %al
andb $0x1, %al
addq $0xe8, %rsp
retq
movq 0x18(%rsp), %rdi
callq 0x57a0
nopl (%rax)