// File: /workspace/github_cpp_makefile_star2_O2/ShootMe[P]Klondike-Solver/Solitaire.cpp
// Function: Solitaire::SolveMinimal(int)
SolveResult Solitaire::SolveMinimal(int maxClosedCount) {
	MakeAutoMoves();
	if (movesAvailableCount == 0) { return foundationCount == 52 ? SolvedMinimal : Impossible; }

	int openCount = 1;
	int maxFoundationCount = foundationCount;
	int bestSolutionMoveCount = 512;
	int totalOpenCount = 1;

	int powerOf2 = 1;
	while (maxClosedCount > (1 << (powerOf2 + 2))) {
		powerOf2++;
	}
	HashMap<int> closed(powerOf2);
	stack<shared_ptr<MoveNode>> open[512];
	Move movesToMake[512];
	Move bestSolution[512];
	bestSolution[0].Count = 255;
	int startMoves = MinimumMovesLeft() + MovesMadeNormalizedCount();

	shared_ptr<MoveNode> firstNode = movesMadeCount > 0 ? make_shared<MoveNode>(movesMade[movesMadeCount - 1]) : NULL;
	shared_ptr<MoveNode> node = firstNode;
	for (int i = movesMadeCount - 2; i >= 0; i--) {
		node->Parent = make_shared<MoveNode>(movesMade[i]);
		node = node->Parent;
	}
	open[startMoves].push(firstNode);
	while (closed.Size() < maxClosedCount) {
		//Check for lowest score length
		int index = startMoves;
		while (index < 512 && open[index].size() == 0) { index++; }

		//End solver if no more states
		if (index >= 512) { break; }

		//Get next state to evaluate
		openCount--;
		firstNode = open[index].top();
		open[index].pop();

		//Initialize game to the found state
		ResetGame(drawCount);
		int movesTotal = 0;
		node = firstNode;
		while (node != NULL) {
			movesToMake[movesTotal++] = node->Value;
			node = node->Parent;
		}
		while (movesTotal > 0) {
			MakeMove(movesToMake[--movesTotal]);
		}

		//Make any auto moves
		UpdateAvailableMoves();
		while (movesAvailableCount == 1) {
			Move move = movesAvailable[0];
			MakeMove(move);
			firstNode = make_shared<MoveNode>(move, firstNode);
			UpdateAvailableMoves();
		}
		movesTotal = MovesMadeNormalizedCount();

		//Check for best solution to foundations
		if (foundationCount > maxFoundationCount || (foundationCount == maxFoundationCount && bestSolutionMoveCount > movesTotal)) {
			bestSolutionMoveCount = movesTotal;
			maxFoundationCount = foundationCount;

			//Save solution
			for (int i = 0; i < movesMadeCount; i++) {
				bestSolution[i] = movesMade[i];
			}
			bestSolution[movesMadeCount].Count = 255;
		} else if (maxFoundationCount == 52) {
			//Dont check state if above or equal to current best solution
			int helper = MinimumMovesLeft();
			helper += movesTotal;
			if (helper >= bestSolutionMoveCount) { continue; }
		}

		//Make available moves and add them to be evaulated
		for (int i = 0; i < movesAvailableCount; i++) {
			Move move = movesAvailable[i];
			int movesAdded = MovesAdded(move);

			MakeMove(move);

			movesAdded += movesTotal;
			movesAdded += MinimumMovesLeft();
			if (maxFoundationCount < 52 || movesAdded < bestSolutionMoveCount) {
				int helper = movesAdded;
				helper += 52 - foundationCount + roundCount;
				HashKey key = GameState();
				KeyValue<int> * result = closed.Add(key, movesAdded);
				if (result == NULL || result->Value > movesAdded) {
					node = make_shared<MoveNode>(move, firstNode);
					if (result != NULL) { result->Value = movesAdded; }

					totalOpenCount++;
					openCount++;
					open[helper].push(node);
				}
			}

			UndoMove();
		}
	}

	//Reset game to best solution found
	ResetGame(drawCount);
	for (int i = 0; bestSolution[i].Count < 255; i++) {
		MakeMove(bestSolution[i]);
	}
	return closed.Size() >= maxClosedCount ? (maxFoundationCount == 52 ? SolvedMayNotBeMinimal : CouldNotComplete) : (maxFoundationCount == 52 ? SolvedMinimal : Impossible);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xb0b8, %rsp           # imm = 0xB0B8
movl %esi, %ebx
movq %rdi, %r14
callq 0x5036
cmpl $0x0, 0x1910(%r14)
movl 0x190c(%r14), %eax
je 0x5f24
movl %eax, 0xc(%rsp)
xorl %ecx, %ecx
pushq $0x4
popq %rax
incl %ecx
movl %eax, %edx
shll %cl, %edx
cmpl %ebx, %edx
jl 0x5e6f
movl %ebx, 0x1c(%rsp)
leaq 0x90(%rsp), %rdi
movl %ecx, %esi
callq 0x806c
xorl %r15d, %r15d
leaq (%rsp,%r15), %rdi
addq $0x10b0, %rdi           # imm = 0x10B0
callq 0x7eb6
addq $0x50, %r15
cmpq $0xa000, %r15           # imm = 0xA000
jne 0x5e8f
xorl %ebx, %ebx
leaq (%rsp,%rbx), %rdi
addq $0x8b0, %rdi            # imm = 0x8B0
callq 0x34b4
addq $0x4, %rbx
cmpq $0x800, %rbx            # imm = 0x800
jne 0x5eae
xorl %ebx, %ebx
leaq (%rsp,%rbx), %rdi
addq $0xb0, %rdi
callq 0x34b4
addq $0x4, %rbx
cmpq $0x800, %rbx            # imm = 0x800
jne 0x5ecd
movb $-0x1, 0xb2(%rsp)
movq %r14, %rdi
callq 0x477e
movl %eax, %r15d
movq %r14, %rdi
callq 0x46cc
movl %eax, %ebp
movl 0x1914(%r14), %eax
testl %eax, %eax
jle 0x5f32
decl %eax
leaq (%r14,%rax,4), %rsi
leaq 0x20(%rsp), %rdi
callq 0x8267
jmp 0x5f3a
xorl %ebp, %ebp
cmpl $0x34, %eax
sete %bpl
jmp 0x6388
xorps %xmm0, %xmm0
movaps %xmm0, 0x20(%rsp)
addl %r15d, %ebp
leaq 0x38(%rsp), %r15
leaq 0x20(%rsp), %rsi
movq %r15, %rdi
callq 0x841e
movl 0x1914(%r14), %ebx
addl $-0x2, %ebx
leaq 0x80(%rsp), %r12
leaq 0x78(%rsp), %r13
testl %ebx, %ebx
js 0x5f9e
movl %ebx, %eax
leaq (%r14,%rax,4), %rsi
movq %r13, %rdi
callq 0x8267
movq 0x38(%rsp), %rdi
movq %r13, %rsi
callq 0x35ee
movq %r12, %rdi
callq 0x350c
movq 0x38(%rsp), %rsi
movq %r15, %rdi
callq 0x3588
decl %ebx
jmp 0x5f66
movslq %ebp, %rbx
imulq $0x50, %rbx, %rax
leaq (%rsp,%rax), %rdi
addq $0x10b0, %rdi           # imm = 0x10B0
leaq 0x20(%rsp), %rsi
movq %rdi, 0x60(%rsp)
callq 0x891e
movq %rbx, 0x58(%rsp)
shlq $0x20, %rbx
movq %rbx, 0x50(%rsp)
movl $0x200, 0x10(%rsp)      # imm = 0x200
leaq 0x78(%rsp), %rbp
movl 0xc(%rsp), %r15d
movl 0x1c(%rsp), %eax
cmpl %eax, 0x98(%rsp)
jge 0x62f1
movq 0x60(%rsp), %r13
movq 0x50(%rsp), %rbx
movq 0x58(%rsp), %r12
cmpq $0x1ff, %r12            # imm = 0x1FF
jg 0x62f1
movq %r13, %rdi
callq 0x8634
testq %rax, %rax
jne 0x602f
incq %r12
movabsq $0x100000000, %rax      # imm = 0x100000000
addq %rax, %rbx
addq $0x50, %r13
jmp 0x5fff
sarq $0x20, %rbx
imulq $0x50, %rbx, %rax
leaq (%rsp,%rax), %r13
addq $0x10b0, %r13           # imm = 0x10B0
movq 0x30(%r13), %rsi
cmpq 0x38(%r13), %rsi
jne 0x605c
movq 0x48(%r13), %rax
movq -0x8(%rax), %rsi
movl $0x200, %eax            # imm = 0x200
addq %rax, %rsi
movl %r15d, 0x48(%rsp)
addq $-0x10, %rsi
leaq 0x20(%rsp), %rbx
movq %rbx, %rdi
callq 0x3588
movq %r13, %rdi
callq 0x867c
movl 0x1904(%r14), %esi
movq %r14, %rdi
callq 0x53c6
movq %rbx, %rsi
xorl %ebx, %ebx
leaq 0x80(%rsp), %r12
leaq 0x68(%rsp), %r15
leaq 0x38(%rsp), %rdi
callq 0x3588
movq 0x38(%rsp), %rsi
testq %rsi, %rsi
je 0x60d0
movl 0x10(%rsi), %eax
movl %eax, 0x8b0(%rsp,%rbx,4)
incq %rbx
jmp 0x609b
movl 0x8ac(%rsp,%rbx,4), %esi
decq %rbx
movq %r14, %rdi
callq 0x3e7e
testq %rbx, %rbx
jg 0x60be
movq %r14, %rdi
callq 0x4030
leaq 0x20(%rsp), %rbx
cmpl $0x1, 0x1910(%r14)
jne 0x612a
movl 0x1874(%r14), %esi
movl %esi, 0x68(%rsp)
movq %r14, %rdi
callq 0x3e7e
movq %rbp, %rdi
movq %r15, %rsi
movq %rbx, %rdx
callq 0x7f3a
movq %rbx, %rdi
movq %rbp, %rsi
callq 0x35ee
movq %r12, %rdi
callq 0x350c
movq %r14, %rdi
callq 0x4030
jmp 0x60e2
movq %r14, %rdi
callq 0x46cc
movl %eax, %ebx
movl 0x190c(%r14), %eax
movl %eax, 0xc(%rsp)
movl 0x48(%rsp), %edx
cmpl %edx, %eax
jg 0x6182
sete %al
cmpl %ebx, 0x10(%rsp)
setg %cl
andb %al, %cl
cmpb $0x1, %cl
je 0x6182
cmpl $0x34, %edx
jne 0x61bc
movq %r14, %rdi
callq 0x477e
addl %ebx, %eax
pushq $0x34
popq %r15
cmpl 0x10(%rsp), %eax
jge 0x5fdf
movl %ebx, 0x14(%rsp)
pushq $0x34
popq %rax
movl %eax, 0xc(%rsp)
jmp 0x61c4
movslq 0x1914(%r14), %rax
testl %eax, %eax
movl $0x0, %ecx
cmovgl %eax, %ecx
xorl %edx, %edx
cmpq %rdx, %rcx
je 0x61aa
movl (%r14,%rdx,4), %esi
movl %esi, 0xb0(%rsp,%rdx,4)
incq %rdx
jmp 0x6195
movb $-0x1, 0xb2(%rsp,%rax,4)
movl %ebx, 0x14(%rsp)
movl %ebx, 0x10(%rsp)
jmp 0x61c4
movl %ebx, 0x14(%rsp)
movl %edx, 0xc(%rsp)
xorl %ebx, %ebx
movslq 0x1910(%r14), %rax
cmpq %rax, %rbx
jge 0x5fda
movl 0x1874(%r14,%rbx,4), %eax
movl %eax, 0x18(%rsp)
movq %r14, %rdi
leaq 0x18(%rsp), %rsi
callq 0x48fe
movl %eax, 0x8(%rsp)
movl 0x18(%rsp), %esi
movq %r14, %rdi
callq 0x3e7e
movl 0x14(%rsp), %eax
addl %eax, 0x8(%rsp)
movq %r14, %rdi
callq 0x477e
movl %eax, %r13d
cmpl $0x34, 0xc(%rsp)
setl %al
addl 0x8(%rsp), %r13d
movl %r13d, 0x8(%rsp)
cmpl 0x10(%rsp), %r13d
setl %cl
orb %al, %cl
cmpb $0x1, %cl
jne 0x62e1
movl 0x1908(%r14), %eax
movq %rax, 0x48(%rsp)
subl 0x190c(%r14), %r13d
movq %rbp, %rdi
movq %r14, %rsi
callq 0x4986
leaq 0x90(%rsp), %rdi
movq %rbp, %r12
movq %rbp, %rsi
leaq 0x8(%rsp), %rdx
callq 0x7f5c
movq %rax, %rbp
testq %rax, %rax
je 0x627e
movl 0x20(%rbp), %eax
cmpl 0x8(%rsp), %eax
jle 0x62de
leaq 0x68(%rsp), %r15
movq %r15, %rdi
leaq 0x18(%rsp), %rsi
leaq 0x20(%rsp), %rdx
callq 0x7f3a
leaq 0x38(%rsp), %rdi
movq %r15, %rsi
callq 0x35ee
leaq 0x70(%rsp), %rdi
callq 0x350c
testq %rbp, %rbp
je 0x62b8
movl 0x8(%rsp), %eax
movl %eax, 0x20(%rbp)
movq 0x48(%rsp), %rax
addl %r13d, %eax
addl $0x34, %eax
cltq
imulq $0x50, %rax, %rax
leaq (%rsp,%rax), %rdi
addq $0x10b0, %rdi           # imm = 0x10B0
leaq 0x38(%rsp), %rsi
callq 0x891e
movq %r12, %rbp
movq %r14, %rdi
callq 0x4b72
incq %rbx
jmp 0x61c6
movl 0x1904(%r14), %esi
movq %r14, %rdi
callq 0x53c6
leaq 0xb2(%rsp), %rbx
cmpb $-0x1, (%rbx)
je 0x631e
movl -0x2(%rbx), %esi
movq %r14, %rdi
callq 0x3e7e
addq $0x4, %rbx
jmp 0x6308
movl 0x98(%rsp), %r14d
xorl %ebx, %ebx
movl %r15d, %r12d
cmpl $0x34, %r15d
sete %bl
leaq 0x40(%rsp), %rdi
callq 0x350c
leaq 0x28(%rsp), %rdi
callq 0x350c
movl $0x9fb0, %r15d          # imm = 0x9FB0
leaq (%rsp,%r15), %rdi
addq $0x10b0, %rdi           # imm = 0x10B0
callq 0x82c0
addq $-0x50, %r15
cmpq $-0x50, %r15
jne 0x634c
xorl %ebp, %ebp
cmpl $0x34, %r12d
sete %bpl
orl $-0x2, %ebp
cmpl 0x1c(%rsp), %r14d
cmovll %ebx, %ebp
leaq 0x90(%rsp), %rdi
callq 0x820c
movl %ebp, %eax
addq $0xb0b8, %rsp           # imm = 0xB0B8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x63ba
jmp 0x63e0
jmp 0x63e0
jmp 0x63e0
jmp 0x63ba
jmp 0x63e0
jmp 0x63e0
jmp 0x63e0
jmp 0x63e0
jmp 0x63e0
jmp 0x63e0
jmp 0x63e0
jmp 0x63e0
jmp 0x63e0
jmp 0x63ba
movq %rax, %rbx
jmp 0x63f7
movq %rax, %rbx
testq %r15, %r15
je 0x6417
leaq 0x1060(%rsp), %r14
leaq (%r14,%r15), %rdi
callq 0x82c0
addq $-0x50, %r15
jne 0x63cf
jmp 0x6417
movq %rax, %rbx
leaq 0x40(%rsp), %rdi
callq 0x350c
leaq 0x28(%rsp), %rdi
callq 0x350c
movl $0x9fb0, %r14d          # imm = 0x9FB0
leaq (%rsp,%r14), %rdi
addq $0x10b0, %rdi           # imm = 0x10B0
callq 0x82c0
addq $-0x50, %r14
cmpq $-0x50, %r14
jne 0x63fd
leaq 0x90(%rsp), %rdi
callq 0x820c
movq %rbx, %rdi
callq 0x2300