// File: /workspace/github_cpp_makefile_star2_O3/ShootMe[P]Klondike-Solver/Solitaire.cpp
// Function: Solitaire::MinimumMovesLeft()
int Solitaire::MinimumMovesLeft() {
	Pile & waste = piles[WASTE];
	int wasteSize = waste.Size();
	int win = piles[STOCK].Size();
	int stockCount = win / drawCount;
	stockCount += (win % drawCount) == 0 ? 0 : 1;
	win += stockCount;
	win += wasteSize;

	for (int i = wasteSize - 1; i > 0; --i) {
		Card card1 = waste.Up(i);

		for (int j = i - 1; j >= 0; --j) {
			Card card2 = waste.Up(j);

			if (card1.Suit == card2.Suit && card1.Rank > card2.Rank) {
				++win;
				break;
			}
		}
	}

	for (int i = TABLEAU1; i <= TABLEAU7; ++i) {
		Pile & pile = piles[i];
		int pileSize = pile.Size();
		int downSize = pile.DownSize();
		win += pileSize;
		win += downSize;
		if (downSize == 0) { continue; }

		pileSize -= downSize;
		unsigned char mins[28] = {};

		for (int j = pileSize - 1; j >= 0; j--) {
			Card card1 = pile.Up(j);

			mins[card1.Suit] = card1.Rank;
		}

		for (int j = downSize - 1; j >= 0; j--) {
			Card card1 = pile.Down(j);

			unsigned char & rank = mins[card1.Suit];
			unsigned char cardRank = card1.Rank;
			if (mins[card1.Suit + 4] == EMPTY) {
				if (rank > cardRank) {
					win++;
				}
				rank = cardRank;
				continue;
			} else if (rank > cardRank) {
				do {
					win++;
					rank = *(&rank + 4);
				} while (rank > cardRank);
			}

			do {
				unsigned char temp = rank;
				rank = cardRank;
				cardRank = temp;
				rank = *(&rank + 4);
			} while (rank < cardRank);
		}
	}

	return win;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x38, %rsp
movq %rdi, %rbx
leaq 0x800(%rdi), %r12
movq %r12, %rdi
callq 0x3a66
movl %eax, %r14d
leaq 0x1160(%rbx), %rdi
callq 0x3a66
movl %eax, %ebp
cltd
idivl 0x1904(%rbx)
addl %r14d, %ebp
addl %eax, %ebp
cmpl $0x1, %edx
sbbl $-0x1, %ebp
cmpl $0x2, %r14d
jl 0x4be2
movl %r14d, %r13d
decl %r13d
movl %r14d, %ecx
movq %rcx, 0x30(%rsp)
leal -0x1(%rcx), %esi
movq %r12, %rdi
movl %esi, 0xc(%rsp)
callq 0x3ab4
movq %rax, %rbx
movzbl %bh, %eax
movl %eax, %r14d
movl %r13d, %r15d
decl %r15d
movq %r12, %rdi
movl %r15d, %esi
callq 0x3ab4
movl %eax, %ecx
xorb %bl, %cl
jne 0x4bce
movzbl %ah, %eax
xorl %ecx, %ecx
cmpl %eax, %r14d
seta %cl
addl %ecx, %ebp
cmpl %eax, %r14d
ja 0x4bd3
testl %r15d, %r15d
jg 0x4ba8
decl %r13d
cmpl $0x2, 0x30(%rsp)
movl 0xc(%rsp), %r14d
jg 0x4b85
movl $0x1, %r13d
imulq $0x12c, %r13, %r14      # imm = 0x12C
addq %r12, %r14
movq %r14, %rdi
callq 0x3a66
movl %eax, %ebx
movq %r14, %rdi
callq 0x3a6e
addl %ebx, %ebp
addl %eax, %ebp
testl %eax, %eax
je 0x4ca0
movl %eax, %r15d
xorps %xmm0, %xmm0
movups %xmm0, 0x1c(%rsp)
movaps %xmm0, 0x10(%rsp)
notl %eax
addl %eax, %ebx
js 0x4c3c
movq %r14, %rdi
movl %ebx, %esi
callq 0x3ab4
movzbl %al, %ecx
movb %ah, 0x10(%rsp,%rcx)
addl $-0x1, %ebx
jb 0x4c26
testl %r15d, %r15d
jle 0x4ca0
movl %r15d, %ebx
leal -0x1(%rbx), %r15d
movq %r14, %rdi
movl %r15d, %esi
callq 0x3a9c
movzbl %al, %ecx
movabsq $0xffffffffff00, %rdx   # imm = 0xFFFFFFFFFF00
andq %rdx, %rax
shrq $0x8, %rax
leaq 0x10(%rsp), %rdx
movb 0x4(%rcx,%rdx), %dl
testb %dl, %dl
je 0x4c88
movzbl 0x10(%rsp,%rcx), %esi
movzbl %al, %edi
cmpl %esi, %edi
jae 0x4c97
incl %ebp
cmpb %al, %dl
ja 0x4c80
jmp 0x4c97
movzbl 0x10(%rsp,%rcx), %edx
movzbl %al, %esi
cmpl %edx, %esi
adcl $0x0, %ebp
movl %eax, %edx
movb %dl, 0x10(%rsp,%rcx)
cmpl $0x1, %ebx
jg 0x4c41
incq %r13
cmpq $0x8, %r13
jne 0x4be8
movl %ebp, %eax
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq