// File: /workspace/github_cpp_makefile_star2_O2/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
andl $0x0, 0x1910(%rdi)
callq 0x65e6
movl %eax, 0x28(%rsp)
leaq 0x70(%rsp), %rsi
leaq 0x100(%rsp), %rdx
movq %rbx, %rdi
callq 0x642c
movq %rax, 0x40(%rsp)
leaq 0x800(%rbx), %rax
movq %rax, 0x30(%rsp)
leaq 0x1874(%rbx), %rax
movq %rax, 0x18(%rsp)
movq %rbx, 0x8(%rsp)
leaq 0x92c(%rbx), %rax
movq %rax, 0x60(%rsp)
pushq $0x1
popq %r14
xorl %ebx, %ebx
cmpq $0x8, %r14
je 0x4333
imulq $0x12c, %r14, %rdi      # imm = 0x12C
addq 0x30(%rsp), %rdi
movq %rdi, 0x48(%rsp)
callq 0x3874
testl %eax, %eax
je 0x4328
movl %eax, %r15d
movq %r14, 0x10(%rsp)
movq 0x48(%rsp), %r14
movq %r14, %rdi
callq 0x3884
movl %eax, 0x2c(%rsp)
movq %r14, %rdi
callq 0x38e0
movq %rax, %rcx
shrq $0x20, %rcx
movzbl %cl, %r14d
movq %rax, 0x68(%rsp)
movzbl %ah, %ebp
imulq $0x12c, %r14, %rdi      # imm = 0x12C
addq 0x30(%rsp), %rdi
callq 0x3874
movl %ebp, %ecx
subl %eax, %ecx
cmpl $0x1, %ecx
movl %ebp, 0x3c(%rsp)
jne 0x4164
cmpl 0x28(%rsp), %ebp
jl 0x44d1
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, 0x2c(%rsp)
sete %al
cmpl $0x2, %r15d
setge %cl
andb %al, %cl
movzbl %cl, %r8d
movzbl 0x10(%rsp), %esi
movl %r14d, %edx
pushq $0x1
popq %rcx
callq 0x34c4
movq 0x48(%rsp), %rdi
callq 0x3902
movzbl %ah, %eax
movl 0x3c(%rsp), %ecx
negl %ecx
addl %eax, %ecx
incl %ecx
leal 0x1(%rax), %edx
movl %edx, 0x54(%rsp)
cmpl $0xd, %eax
setne %al
movl %ecx, 0x20(%rsp)
cmpl %ecx, %r15d
sete %cl
setg 0x6(%rsp)
orb %al, %cl
movb %cl, 0x7(%rsp)
xorl %r13d, %r13d
movq 0x60(%rsp), %r15
movq $0x0, 0x58(%rsp)
movq 0x10(%rsp), %r14
cmpq $0x7, %r13
je 0x4328
cmpq %r13, %rbx
je 0x4319
movq %r15, %rdi
callq 0x3874
movzbl %r14b, %r12d
movzbl 0x20(%rsp), %ebp
testl %eax, %eax
je 0x4259
movq %r15, %rdi
callq 0x38e0
movzbl %ah, %ecx
movl %ecx, %r14d
subl 0x3c(%rsp), %r14d
jbe 0x4314
cmpl %ecx, 0x54(%rsp)
jb 0x4314
xorl 0x68(%rsp), %eax
movl %eax, %ecx
shrl $0x18, %ecx
shrl $0x10, %eax
movzbl %al, %eax
cmpl %eax, %ecx
jne 0x4314
cmpl 0x20(%rsp), %r14d
jne 0x42a5
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(%r13), %eax
xorl %r8d, %r8d
movb 0x6(%rsp), %cl
movb %cl, %r8b
movzbl %al, %edx
movl %r12d, %esi
movl %ebp, %ecx
jmp 0x430f
movb 0x7(%rsp), %al
orb 0x58(%rsp), %al
testb $0x1, %al
jne 0x4319
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(%r13), %eax
movzbl %al, %edx
movl %r12d, %esi
movl %ebp, %ecx
pushq $0x1
popq %r8
callq 0x34c4
movb $0x1, %al
movq %rax, 0x58(%rsp)
jmp 0x4319
movl %r14d, %esi
notl %esi
addl 0x2c(%rsp), %esi
movq 0x48(%rsp), %rdi
callq 0x388c
movzbl %ah, %ebp
shrq $0x20, %rax
movzbl %al, %eax
imulq $0x12c, %rax, %rdi      # imm = 0x12C
addq 0x30(%rsp), %rdi
callq 0x3874
subl %eax, %ebp
cmpl $0x1, %ebp
jne 0x4314
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(%r13), %edx
movl $0xff, %eax
andl %eax, %r14d
andl %eax, %edx
movl %r12d, %esi
movl %r14d, %ecx
xorl %r8d, %r8d
callq 0x34c4
movq 0x10(%rsp), %r14
incq %r13
addq $0x12c, %r15            # imm = 0x12C
jmp 0x41b3
incq %r14
incq %rbx
jmp 0x409d
xorl %r14d, %r14d
movq 0x40(%rsp), %rax
testl %eax, %eax
cmovlel %r14d, %eax
movq %rax, 0x40(%rsp)
movq 0x8(%rsp), %rbx
leaq 0x92c(%rbx), %rax
movq %rax, 0x10(%rsp)
cmpq 0x40(%rsp), %r14
je 0x453e
imulq $0x6, %r14, %rax
movzbl 0x71(%rsp,%rax), %r12d
movzbl 0x73(%rsp,%rax), %ebp
movzbl 0x74(%rsp,%rax), %ebx
movl 0x100(%rsp,%r14,4), %r13d
imulq $0x12c, %rbx, %rdi      # imm = 0x12C
addq 0x30(%rsp), %rdi
callq 0x3874
movl %r12d, %ecx
subl %eax, %ecx
cmpl $0x1, %ecx
movq %r14, 0x20(%rsp)
jne 0x43d8
movzbl %bl, %edx
cmpl %r12d, 0x28(%rsp)
jge 0x4458
movq 0x8(%rsp), %rsi
movslq 0x1910(%rsi), %rax
leal 0x1(%rax), %ecx
movl %ecx, 0x1910(%rsi)
movq 0x18(%rsp), %rcx
leaq (%rcx,%rax,4), %rdi
movzbl %r13b, %r8d
xorl %esi, %esi
pushq $0x1
popq %rcx
callq 0x34c4
movq 0x10(%rsp), %r14
pushq $-0x7
popq %rbx
testq %rbx, %rbx
je 0x44bf
movq %r14, %rdi
callq 0x3874
movzbl %r13b, %r15d
testl %eax, %eax
je 0x4446
movq %r14, %rdi
callq 0x38e0
movzbl %ah, %ecx
subl %r12d, %ecx
cmpl $0x1, %ecx
jne 0x444c
shrl $0x18, %eax
cmpl %ebp, %eax
je 0x444c
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
pushq $0x1
popq %rcx
movl %r15d, %r8d
callq 0x34c4
jmp 0x444c
cmpb $0xd, %r12b
je 0x448e
incq %rbx
addq $0x12c, %r14            # imm = 0x12C
jmp 0x43e0
movq 0x8(%rsp), %rbx
cmpl $0x1, 0x1904(%rbx)
je 0x4505
movslq 0x1910(%rbx), %rax
leal 0x1(%rax), %ecx
movl %ecx, 0x1910(%rbx)
movq 0x18(%rsp), %rcx
leaq (%rcx,%rax,4), %rdi
movzbl %r13b, %r8d
xorl %esi, %esi
pushq $0x1
popq %rcx
jmp 0x44ba
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
pushq $0x1
popq %rcx
movl %r15d, %r8d
callq 0x34c4
movq 0x20(%rsp), %r14
incq %r14
movq 0x8(%rsp), %rbx
jmp 0x4357
cmpl $0x1, 0x2c(%rsp)
sete %al
cmpl $0x2, %r15d
setge %cl
andb %al, %cl
movzbl %cl, %r8d
movzbl 0x10(%rsp), %esi
pushq $0x1
popq %rcx
movq 0x18(%rsp), %rdi
movl %r14d, %edx
callq 0x34c4
movq 0x8(%rsp), %rbx
jmp 0x469c
testl %r13d, %r13d
je 0x4689
movslq 0x1910(%rbx), %rax
testq %rax, %rax
je 0x4689
leal 0x1(%rax), %ecx
movl %ecx, 0x1910(%rbx)
movq 0x18(%rsp), %rcx
leaq (%rcx,%rax,4), %rdi
movzbl %r13b, %r8d
pushq $0x1
popq %rcx
xorl %esi, %esi
callq 0x34c4
cmpl $0x0, 0x190c(%rbx)
je 0x46a6
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, 0x10(%rsp)
pushq $0x9
popq %rbp
cmpq $0xd, %rbp
je 0x46a6
imulq $0x12c, %rbp, %rdi      # imm = 0x12C
addq 0x30(%rsp), %rdi
callq 0x3874
movl %eax, %r12d
testl %eax, %eax
sete %al
cmpl 0x28(%rsp), %r12d
setle %cl
orb %al, %cl
jne 0x4681
movzbl %bpl, %r15d
movq 0x10(%rsp), %r13
pushq $0x1
popq %r14
cmpq $0x8, %r14
je 0x4681
movq %r13, %rdi
callq 0x3874
testl %eax, %eax
je 0x462a
movq %r13, %rdi
callq 0x38e0
movq %rax, %rcx
shrq $0x20, %rcx
xorl %ebp, %ecx
testb $0x1, %cl
je 0x4630
movzbl %ah, %eax
subl %r12d, %eax
cmpl $0x1, %eax
jne 0x4630
cmpq %r14, %rbx
je 0x4630
cmpq 0x20(%rsp), %rbp
je 0x4630
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
pushq $0x1
popq %rcx
xorl %r8d, %r8d
callq 0x34c4
jmp 0x4630
cmpl $0xd, %r12d
je 0x463f
incq %r14
addq $0x12c, %r13            # imm = 0x12C
jmp 0x45b5
cmpq 0x20(%rsp), %rbp
sete %al
cmpq %r14, %rbx
sete %cl
orb %al, %cl
jne 0x4681
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
pushq $0x1
popq %rcx
xorl %r8d, %r8d
callq 0x34c4
incq %rbp
jmp 0x4575
movzbl %r13b, %r8d
pushq $0x1
popq %rcx
movq 0x18(%rsp), %rdi
xorl %esi, %esi
callq 0x34c4
movl $0x1, 0x1910(%rbx)
addq $0x168, %rsp            # imm = 0x168
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq