// File: /workspace/github_cpp_makefile_star2_O1/ksabry[P]bfbrute/src/ProgramIterator.h
// Function: ProgramIterator<400ul, 32ul, 12ul, 32ul>::StringDistanceRecursive(char const*, unsigned long, unsigned long, unsigned char*, unsigned long)
uint_fast32_t StringDistanceRecursive(const char* target, uint_fast32_t targetSize, uint_fast32_t shortCircuit, uint8_t* currentData, uint_fast32_t currentDataIdx)
	{
		if (targetSize == 0)
		{
			return 0;
		}

		uint_fast32_t bestScore = 100000;
		char c = target[0];

		// Compute best scores for reaching each specific data index
		uint_fast32_t dataDeltaScores[data_size];
		for (uint_fast32_t idx = 0; idx < data_size; idx++)
		{
			dataDeltaScores[idx] = abs(static_cast<int_fast32_t>(currentDataIdx - idx));
		}
		for (int_fast32_t startDelta = -8; startDelta <= 8; startDelta++)
		{
			int_fast32_t startIdx = static_cast<int_fast32_t>(currentDataIdx) + startDelta;
			if (startIdx < 0 || startIdx >= data_size)
			{
				continue;
			}
			for (int_fast32_t innerDelta = -8; innerDelta <= 8; innerDelta++)
			{
				if (innerDelta == 0)
				{
					continue;
				}
				int_fast32_t innerIdx = startIdx;
				while (currentData[innerIdx])
				{
					innerIdx += innerDelta;
					if (innerIdx < 0 || innerIdx >= data_size)
					{
						goto loop_fail;
					}
				}
				for (int_fast32_t endDelta = -8; endDelta <= 8; endDelta++)
				{
					int_fast32_t endIdx = innerIdx + endDelta;
					if (endIdx < 0 || endIdx >= data_size)
					{
						continue;
					}
					uint_fast32_t dataDeltaScore = 2 + abs(startDelta) + abs(innerDelta) + abs(endDelta);
					if (dataDeltaScore < dataDeltaScores[endIdx])
					{
						dataDeltaScores[endIdx] = dataDeltaScore;
					}
				}
			loop_fail:;
			}
		}

		// Search through reaching each specific data index and directly modifying the data to match the next character
		for (uint_fast32_t newDataIdx = 0; newDataIdx < data_size; newDataIdx++)
		{
			uint_fast32_t charScore = 1 + dataDeltaScores[newDataIdx] + abs(static_cast<int8_t>(c - currentData[newDataIdx]));

			if (charScore > shortCircuit)
			{
				continue;
			}

			char oldData = currentData[newDataIdx];
			currentData[newDataIdx] = c;
			uint_fast32_t restScore = StringDistanceRecursive(target + 1, targetSize - 1, shortCircuit - charScore, currentData, newDataIdx);
			currentData[newDataIdx] = oldData;

			if (charScore + restScore < bestScore)
			{
				bestScore = charScore + restScore;
			}

#ifdef CASE_INSENSITIVE
			if ('a' <= c && c <= 'z')
			{
				char upperC = toupper(c);
				uint_fast32_t upperCharScore = 1 + dataDeltaScores[newDataIdx] + abs(static_cast<int8_t>(upperC - currentData[newDataIdx]));

				if (upperCharScore > shortCircuit)
				{
					continue;
				}

				char oldData = currentData[newDataIdx];
				currentData[newDataIdx] = upperC;
				uint_fast32_t restScore = StringDistanceRecursive(target + 1, targetSize - 1, shortCircuit - upperCharScore, currentData, newDataIdx);
				currentData[newDataIdx] = oldData;

				if (upperCharScore + restScore < bestScore)
				{
					bestScore = upperCharScore + restScore;
				}
			}
#endif
		}

		// TODO: Search for any multi-output loops ><[><+-.><+-]
		return bestScore;
	}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xcb8, %rsp            # imm = 0xCB8
movq %rcx, 0x28(%rsp)
movq %rdi, 0x20(%rsp)
movq %rdx, 0x10(%rsp)
testq %rdx, %rdx
je 0x8116
movq %r8, %rbx
movq %rsi, 0x18(%rsp)
movb (%rsi), %al
movb %al, 0xf(%rsp)
xorl %eax, %eax
movq %r9, %rcx
movq %rcx, %rdx
negq %rdx
cmovsq %rcx, %rdx
movq %rdx, 0x30(%rsp,%rax,8)
incq %rax
decq %rcx
cmpq $0x190, %rax            # imm = 0x190
jne 0x7fa6
leaq -0x10(%r9), %rax
leaq (%rsp,%r9,8), %rcx
addq $-0x50, %rcx
movq $-0x8, %rdx
leaq (%rdx,%r9), %rsi
cmpq $0x18f, %rsi            # imm = 0x18F
ja 0x8080
movq %rdx, %rdi
negq %rdi
cmovsq %rdx, %rdi
addq $0x2, %rdi
movq $-0x8, %r8
movq $-0x40, %r10
testq %r8, %r8
je 0x8073
movq %rcx, %r11
movq %rax, %r13
movq %rsi, %r15
cmpb $0x0, (%rbx,%r15)
je 0x802c
addq %r8, %r15
addq %r8, %r13
addq %r10, %r11
cmpq $0x18f, %r15            # imm = 0x18F
jbe 0x8011
jmp 0x8073
movq %r8, %rbp
negq %rbp
cmovsq %r8, %rbp
addq %rdi, %rbp
movq $-0x8, %r15
cmpq $0x18f, %r13            # imm = 0x18F
ja 0x8063
movq %r15, %r14
negq %r14
cmovsq %r15, %r14
addq %rbp, %r14
movq (%r11), %r12
cmpq %r12, %r14
cmovaeq %r12, %r14
movq %r14, (%r11)
incq %r15
incq %r13
addq $0x8, %r11
cmpq $0x9, %r15
jne 0x8040
incq %r8
addq $0x8, %r10
cmpq $0x9, %r8
jne 0x8003
incq %rdx
incq %rax
addq $0x8, %rcx
cmpq $0x9, %rdx
jne 0x7fd6
movq 0x18(%rsp), %r12
incq %r12
decq 0x10(%rsp)
movl $0x186a0, %ebp          # imm = 0x186A0
xorl %r13d, %r13d
movb 0xf(%rsp), %sil
movq 0x30(%rsp,%r13,8), %rax
movb (%rbx,%r13), %r15b
movl %esi, %ecx
subb %r15b, %cl
movl %ecx, %edx
sarb $0x7, %dl
xorb %dl, %cl
subb %dl, %cl
movzbl %cl, %ecx
leaq (%rax,%rcx), %r14
incq %r14
movq 0x28(%rsp), %rcx
subq %r14, %rcx
jb 0x8108
movb %sil, (%rbx,%r13)
movq 0x20(%rsp), %rdi
movq %r12, %rsi
movq 0x10(%rsp), %rdx
movq %rbx, %r8
movq %r13, %r9
callq 0x7f6a
movb 0xf(%rsp), %sil
movb %r15b, (%rbx,%r13)
addq %r14, %rax
cmpq %rbp, %rax
cmovbq %rax, %rbp
incq %r13
cmpq $0x190, %r13            # imm = 0x190
jne 0x80ae
jmp 0x8118
xorl %ebp, %ebp
movq %rbp, %rax
addq $0xcb8, %rsp            # imm = 0xCB8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nop