// File: /workspace/github_cpp_makefile_star2_O3/ShootMe[P]Klondike-Solver/Solitaire.cpp
// Function: Solitaire::UpdateAvailableMoves()
void Solitaire::UpdateAvailableMoves() {
	movesAvailableCount = 0;
	int foundationMin = FoundationMin();
	Card talon[24];
	int talonMoves[24];
	int talonCount = GetTalonCards(talon, talonMoves);

	//Check tableau to foundation, Check tableau to tableau
	for (int i = TABLEAU1; i <= TABLEAU7; ++i) {
		Pile & pile1 = piles[i];
		int pile1Size = pile1.Size();

		if (pile1Size == 0) { continue; }

		int pile1UpSize = pile1.UpSize();
		Card card1 = pile1.Low();
		int cardFoundation = card1.Foundation;

		if (card1.Rank - piles[cardFoundation].Size() == 1) {
			//logic used to tell if we can safely move a card to its foundation
			if (card1.Rank < foundationMin) {
				movesAvailable[0].Set(i, cardFoundation, 1, pile1UpSize == 1 && pile1Size > 1 ? 1 : 0);
				movesAvailableCount = 1;
				return;
			}

			movesAvailable[movesAvailableCount++].Set(i, cardFoundation, 1, pile1UpSize == 1 && pile1Size > 1 ? 1 : 0);
		}

		Card card2 = pile1.High();
		int pile1Length = card2.Rank - card1.Rank + 1;
		bool kingMoved = false;

		for (int j = TABLEAU1; j <= TABLEAU7; ++j) {
			if (i == j) { continue; }

			Pile & pile2 = piles[j];

			if (pile2.Size() == 0) {
				if (card2.Rank == KING && pile1Size != pile1Length && !kingMoved) {
					movesAvailable[movesAvailableCount++].Set(i, j, pile1Length, 1);
					//only create one move for a blank spot
					kingMoved = true;
				}
				continue;
			}

			Card card3 = pile2.Low();
			//logic used to determine if a pile of cards can be moved ontop of another pile of cards
			if (card1.Rank >= card3.Rank || card2.Rank + 1 < card3.Rank || ((card3.IsRed ^ card1.IsRed) ^ (card3.IsOdd ^ card1.IsOdd)) != 0) {
				continue;
			}

			int pile1Moved = card3.Rank - card1.Rank;

			if (pile1Moved == pile1Length) {//we are moving all face up cards
				movesAvailable[movesAvailableCount++].Set(i, j, pile1Moved, pile1Size > pile1Moved ? 1 : 0);
				continue;
			}

			//look to see if we are covering a card that can be moved to the foundation
			Card card4 = pile1[pile1UpSize - pile1Moved - 1];
			if (card4.Rank - piles[card4.Foundation].Size() == 1) {
				movesAvailable[movesAvailableCount++].Set(i, j, pile1Moved, 0);
			}
		}
	}

	//Check talon cards
	for (int j = 0; j < talonCount; j++) {
		Card talonCard = talon[j];
		int foundation = talonCard.Foundation;
		int cardsToDraw = talonMoves[j];

		if (talonCard.Rank - piles[foundation].Size() == 1) {
			if (talonCard.Rank <= foundationMin) {
				if (drawCount == 1) {
					if (cardsToDraw == 0 || movesAvailableCount == 0) {
						movesAvailable[0].Set(WASTE, foundation, 1, cardsToDraw);
						movesAvailableCount = 1;
						return;
					} else {
						movesAvailable[movesAvailableCount++].Set(WASTE, foundation, 1, cardsToDraw);
						break;
					}
				} else {
					movesAvailable[movesAvailableCount++].Set(WASTE, foundation, 1, cardsToDraw);
					continue;
				}
			}

			movesAvailable[movesAvailableCount++].Set(WASTE, foundation, 1, cardsToDraw);
		}

		for (int i = TABLEAU1; i <= TABLEAU7; ++i) {
			Pile & pile = piles[i];

			if (pile.Size() != 0) {
				Card tableauCard = pile.Low();

				if (tableauCard.Rank - talonCard.Rank != 1 || tableauCard.IsRed == talonCard.IsRed) {
					continue;
				}

				movesAvailable[movesAvailableCount++].Set(WASTE, i, 1, cardsToDraw);
			} else if (talonCard.Rank == KING) {
				movesAvailable[movesAvailableCount++].Set(WASTE, i, 1, cardsToDraw);
				break;
			}
		}
	}

	if (foundationCount == 0) { return; }
	//Check foundation to tableau, very rarely needed to solve optimally
	Move lastMove = movesMade[movesMadeCount - 1];
	for (int i = FOUNDATION1C; i <= FOUNDATION4H; ++i) {
		Pile & pile1 = piles[i];
		int foundationRank = pile1.Size();
		if (foundationRank == 0 || foundationRank <= foundationMin) { continue; }

		for (int j = TABLEAU1; j <= TABLEAU7; ++j) {
			Pile & pile2 = piles[j];

			if (pile2.Size() != 0) {
				Card card = pile2.Low();

				if ((card.Foundation & 1) == (i & 1) || card.Rank - foundationRank != 1) {
					continue;
				}

				if (lastMove.From != j && lastMove.To != i) {
					movesAvailable[movesAvailableCount++].Set(i, j, 1, 0);
				}
			} else if (foundationRank == KING) {
				if (lastMove.From != j && lastMove.To != i) {
					movesAvailable[movesAvailableCount++].Set(i, j, 1, 0);
				}
				break;
			}
		}
	}
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x168, %rsp            # imm = 0x168
movq %rdi, %rbx
movl $0x0, 0x1910(%rdi)
callq 0x70fc
movl %eax, 0x2c(%rsp)
leaq 0x70(%rsp), %rsi
leaq 0x100(%rsp), %rdx
movq %rbx, %rdi
callq 0x6eea
movl %eax, 0x5c(%rsp)
leaq 0x800(%rbx), %rax
movq %rax, 0x48(%rsp)
leaq 0x1874(%rbx), %rax
movq %rax, 0x18(%rsp)
leaq 0x92c(%rbx), %rax
movq %rax, 0x60(%rsp)
movl $0x1, %eax
xorl %r14d, %r14d
movq %rbx, 0x8(%rsp)
movq %rax, 0x38(%rsp)
imulq $0x12c, %rax, %rdi      # imm = 0x12C
addq 0x48(%rsp), %rdi
movq %rdi, 0x50(%rsp)
callq 0x3a66
testl %eax, %eax
je 0x46c4
movl %eax, %r15d
movq 0x50(%rsp), %r12
movq %r12, %rdi
callq 0x3a76
movl %eax, 0x30(%rsp)
movq %r12, %rdi
callq 0x3ad2
movq %rax, %rcx
shrq $0x20, %rcx
movzbl %cl, %r12d
movq %rax, 0x68(%rsp)
movzbl %ah, %ebp
imulq $0x12c, %r12, %rdi      # imm = 0x12C
addq 0x48(%rsp), %rdi
callq 0x3a66
movl %ebp, %ecx
subl %eax, %ecx
cmpl $0x1, %ecx
movl %ebp, 0x20(%rsp)
jne 0x4514
cmpl 0x2c(%rsp), %ebp
jl 0x49c7
movq 0x8(%rsp), %rdx
movslq 0x1910(%rdx), %rax
leal 0x1(%rax), %ecx
movl %ecx, 0x1910(%rdx)
movq 0x18(%rsp), %rcx
leaq (%rcx,%rax,4), %rdi
cmpl $0x1, 0x30(%rsp)
sete %al
cmpl $0x2, %r15d
setge %cl
andb %al, %cl
movzbl %cl, %r8d
movzbl 0x38(%rsp), %esi
movl %r12d, %edx
movl $0x1, %ecx
callq 0x3714
movq 0x50(%rsp), %rdi
callq 0x3af4
movzbl %ah, %eax
movl 0x20(%rsp), %ecx
negl %ecx
leal (%rax,%rcx), %r13d
incl %r13d
leal 0x1(%rax), %ebx
cmpl $0xd, %eax
setne %al
cmpl %r13d, %r15d
sete %cl
setg 0x16(%rsp)
orb %al, %cl
movb %cl, 0x17(%rsp)
xorl %r12d, %r12d
movq 0x60(%rsp), %r15
movq $0x0, 0x40(%rsp)
movl %ebx, 0x34(%rsp)
cmpq %r12, %r14
jne 0x4577
incq %r12
addq $0x12c, %r15            # imm = 0x12C
cmpq $0x7, %r12
jne 0x455d
jmp 0x46c4
movq %r15, %rdi
callq 0x3a66
testl %eax, %eax
je 0x45f6
movq %r15, %rdi
callq 0x3ad2
movzbl %ah, %ecx
movl %ecx, %ebp
subl 0x20(%rsp), %ebp
jbe 0x4562
cmpl %ecx, %ebx
jb 0x4562
xorl 0x68(%rsp), %eax
movl %eax, %ecx
shrl $0x18, %ecx
shrl $0x10, %eax
movzbl %al, %eax
cmpl %eax, %ecx
jne 0x4562
cmpl %r13d, %ebp
jne 0x464c
movl %r13d, %ebx
movq 0x8(%rsp), %rdx
movslq 0x1910(%rdx), %rax
leal 0x1(%rax), %ecx
movl %ecx, 0x1910(%rdx)
movq 0x18(%rsp), %rcx
leaq (%rcx,%rax,4), %rdi
leal 0x1(%r12), %eax
movzbl 0x38(%rsp), %esi
movzbl %bl, %ecx
xorl %r8d, %r8d
movb 0x16(%rsp), %dl
movb %dl, %r8b
movzbl %al, %edx
jmp 0x46b6
movb 0x17(%rsp), %al
orb 0x40(%rsp), %al
testb $0x1, %al
jne 0x4562
movq 0x8(%rsp), %rdx
movslq 0x1910(%rdx), %rax
leal 0x1(%rax), %ecx
movl %ecx, 0x1910(%rdx)
movq 0x18(%rsp), %rcx
leaq (%rcx,%rax,4), %rdi
leal 0x1(%r12), %eax
movzbl 0x38(%rsp), %esi
movzbl %r13b, %ecx
movzbl %al, %edx
movl $0x1, %r8d
callq 0x3714
movb $0x1, %al
movq %rax, 0x40(%rsp)
jmp 0x4562
movl %ebp, %esi
notl %esi
addl 0x30(%rsp), %esi
movq 0x50(%rsp), %rdi
callq 0x3a7e
movzbl %ah, %ebx
shrq $0x20, %rax
movzbl %al, %eax
imulq $0x12c, %rax, %rdi      # imm = 0x12C
addq 0x48(%rsp), %rdi
callq 0x3a66
subl %eax, %ebx
cmpl $0x1, %ebx
jne 0x46bb
movq 0x8(%rsp), %rdx
movslq 0x1910(%rdx), %rax
leal 0x1(%rax), %ecx
movl %ecx, 0x1910(%rdx)
movq 0x18(%rsp), %rcx
leaq (%rcx,%rax,4), %rdi
leal 0x1(%r12), %edx
movl $0xff, %eax
andl %eax, %ebp
andl %eax, %edx
movzbl 0x38(%rsp), %esi
movl %ebp, %ecx
xorl %r8d, %r8d
callq 0x3714
movl 0x34(%rsp), %ebx
jmp 0x4562
movq 0x38(%rsp), %rax
incq %rax
incq %r14
cmpq $0x8, %rax
jne 0x4455
movl 0x5c(%rsp), %eax
testl %eax, %eax
jle 0x4872
movl %eax, %eax
movq %rax, 0x20(%rsp)
movq 0x8(%rsp), %rax
addq $0x92c, %rax            # imm = 0x92C
movq %rax, 0x40(%rsp)
xorl %r13d, %r13d
leaq (,%r13,2), %rax
addq %r13, %rax
movzbl 0x71(%rsp,%rax,2), %ebp
movzbl 0x73(%rsp,%rax,2), %r14d
movzbl 0x74(%rsp,%rax,2), %ebx
movl 0x100(%rsp,%r13,4), %r15d
imulq $0x12c, %rbx, %rdi      # imm = 0x12C
addq 0x48(%rsp), %rdi
callq 0x3a66
movl %ebp, %ecx
subl %eax, %ecx
cmpl $0x1, %ecx
jne 0x4777
cmpl %ebp, 0x2c(%rsp)
jge 0x47f6
movq 0x8(%rsp), %rdx
movslq 0x1910(%rdx), %rax
leal 0x1(%rax), %ecx
movl %ecx, 0x1910(%rdx)
movq 0x18(%rsp), %rcx
leaq (%rcx,%rax,4), %rdi
movzbl %bl, %edx
movzbl %r15b, %r8d
xorl %esi, %esi
movl $0x1, %ecx
callq 0x3714
movq $-0x7, %rbx
movzbl %r15b, %r15d
movq 0x40(%rsp), %r12
movq %r12, %rdi
callq 0x3a66
testl %eax, %eax
je 0x47e2
movq %r12, %rdi
callq 0x3ad2
movzbl %ah, %ecx
subl %ebp, %ecx
cmpl $0x1, %ecx
jne 0x47e8
shrl $0x18, %eax
cmpl %r14d, %eax
je 0x47e8
movq 0x8(%rsp), %rdx
movslq 0x1910(%rdx), %rax
leal 0x1(%rax), %ecx
movl %ecx, 0x1910(%rdx)
movq 0x18(%rsp), %rcx
leaq (%rcx,%rax,4), %rdi
leal 0x8(%rbx), %eax
movzbl %al, %edx
xorl %esi, %esi
movl $0x1, %ecx
movl %r15d, %r8d
callq 0x3714
jmp 0x47e8
cmpb $0xd, %bpl
je 0x4831
addq $0x12c, %r12            # imm = 0x12C
incq %rbx
jne 0x4787
jmp 0x4864
movq 0x8(%rsp), %rdx
cmpl $0x1, 0x1904(%rdx)
je 0x4a14
movslq 0x1910(%rdx), %rax
leal 0x1(%rax), %ecx
movl %ecx, 0x1910(%rdx)
movq 0x18(%rsp), %rcx
leaq (%rcx,%rax,4), %rdi
movzbl %bl, %edx
movzbl %r15b, %r8d
xorl %esi, %esi
movl $0x1, %ecx
jmp 0x485f
movq 0x8(%rsp), %rdx
movslq 0x1910(%rdx), %rax
leal 0x1(%rax), %ecx
movl %ecx, 0x1910(%rdx)
movq 0x18(%rsp), %rcx
leaq (%rcx,%rax,4), %rdi
addl $0x8, %ebx
movzbl %bl, %edx
xorl %esi, %esi
movl $0x1, %ecx
movl %r15d, %r8d
callq 0x3714
incq %r13
cmpq 0x20(%rsp), %r13
jne 0x46ff
movq 0x8(%rsp), %rax
cmpl $0x0, 0x190c(%rax)
je 0x4a02
movq 0x8(%rsp), %rcx
movslq 0x1914(%rcx), %rax
movzbl -0x4(%rcx,%rax,4), %ebx
movzbl -0x3(%rcx,%rax,4), %eax
movq %rax, 0x20(%rsp)
leaq 0x92c(%rcx), %rax
movq %rax, 0x40(%rsp)
movl $0x9, %ebp
imulq $0x12c, %rbp, %rdi      # imm = 0x12C
addq 0x48(%rsp), %rdi
callq 0x3a66
movl %eax, %r12d
testl %eax, %eax
sete %al
cmpl 0x2c(%rsp), %r12d
setle %cl
orb %al, %cl
jne 0x496f
movl $0x1, %r14d
movzbl %bpl, %r15d
movq 0x40(%rsp), %r13
movq %r13, %rdi
callq 0x3a66
testl %eax, %eax
je 0x4955
movq %r13, %rdi
callq 0x3ad2
movq %rax, %rcx
shrq $0x20, %rcx
xorl %ebp, %ecx
testb $0x1, %cl
je 0x495b
movzbl %ah, %eax
subl %r12d, %eax
cmpl $0x1, %eax
jne 0x495b
cmpq %r14, %rbx
je 0x495b
cmpq 0x20(%rsp), %rbp
je 0x495b
movq 0x8(%rsp), %rdx
movslq 0x1910(%rdx), %rax
leal 0x1(%rax), %ecx
movl %ecx, 0x1910(%rdx)
movq 0x18(%rsp), %rcx
leaq (%rcx,%rax,4), %rdi
movzbl %r14b, %edx
movl %r15d, %esi
movl $0x1, %ecx
xorl %r8d, %r8d
callq 0x3714
jmp 0x495b
cmpl $0xd, %r12d
je 0x4981
incq %r14
addq $0x12c, %r13            # imm = 0x12C
cmpq $0x8, %r14
jne 0x48e8
incq %rbp
cmpq $0xd, %rbp
jne 0x48b0
jmp 0x4a02
cmpq 0x20(%rsp), %rbp
sete %al
cmpq %r14, %rbx
sete %cl
orb %al, %cl
jne 0x496f
movq 0x8(%rsp), %rdx
movslq 0x1910(%rdx), %rax
leal 0x1(%rax), %ecx
movl %ecx, 0x1910(%rdx)
movq 0x18(%rsp), %rcx
leaq (%rcx,%rax,4), %rdi
movzbl %r14b, %edx
movl %r15d, %esi
movl $0x1, %ecx
xorl %r8d, %r8d
callq 0x3714
jmp 0x496f
cmpl $0x1, 0x30(%rsp)
sete %al
cmpl $0x2, %r15d
setge %cl
andb %al, %cl
movzbl %cl, %r8d
movzbl 0x38(%rsp), %esi
movq 0x18(%rsp), %rdi
movl %r12d, %edx
movl $0x1, %ecx
callq 0x3714
movq 0x8(%rsp), %rax
movl $0x1, 0x1910(%rax)
addq $0x168, %rsp            # imm = 0x168
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
testl %r15d, %r15d
je 0x4a59
movq 0x8(%rsp), %rax
movslq 0x1910(%rax), %rax
testq %rax, %rax
je 0x4a59
leal 0x1(%rax), %ecx
movq 0x8(%rsp), %rdx
movl %ecx, 0x1910(%rdx)
movq 0x18(%rsp), %rcx
leaq (%rcx,%rax,4), %rdi
movzbl %bl, %edx
movzbl %r15b, %r8d
xorl %esi, %esi
movl $0x1, %ecx
callq 0x3714
jmp 0x4872
movzbl %bl, %edx
movzbl %r15b, %r8d
movq 0x18(%rsp), %rdi
xorl %esi, %esi
jmp 0x49e9
nop