// File: /workspace/github_cpp_makefile_star2_O2/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, 0x18(%rsp)
movq %rdx, 0x8(%rsp)
testq %rdx, %rdx
je 0x7095
movq %r8, %rbx
movb (%rsi), %al
movb %al, 0x7(%rsp)
xorl %eax, %eax
movq %r9, %rcx
cmpq $0x190, %rax            # imm = 0x190
je 0x6f3e
movq %rcx, %rdx
negq %rdx
cmovsq %rcx, %rdx
movq %rdx, 0x30(%rsp,%rax,8)
incq %rax
decq %rcx
jmp 0x6f1f
movq %rsi, 0x10(%rsp)
leaq -0x10(%r9), %rsi
leaq (%rsp,%r9,8), %rcx
addq $-0x50, %rcx
pushq $-0x8
popq %rdi
movq %r9, 0x20(%rsp)
cmpq $0x9, %rdi
je 0x7013
leaq (%rdi,%r9), %r8
cmpq $0x18f, %r8             # imm = 0x18F
pushq $-0x8
popq %r9
jbe 0x6f83
incq %rdi
incq %rsi
addq $0x8, %rcx
movq 0x20(%rsp), %r9
jmp 0x6f57
movq %rdi, %r10
negq %r10
cmovsq %rdi, %r10
addq $0x2, %r10
pushq $-0x40
popq %r11
movq %r9, %r13
testq %r13, %r13
je 0x6fc4
cmpq $0x9, %r13
je 0x6f72
movq %rcx, %rbp
movq %rsi, %rax
movq %r8, %rdx
cmpb $0x0, (%rbx,%rdx)
je 0x6fcd
addq %r13, %rdx
addq %r13, %rax
addq %r11, %rbp
cmpq $0x18f, %rdx            # imm = 0x18F
jbe 0x6fac
incq %r13
addq $0x8, %r11
jmp 0x6f98
movq %r13, %r15
negq %r15
cmovsq %r13, %r15
addq %r10, %r15
movq %r9, %r14
cmpq $0x9, %r14
je 0x6fc4
cmpq $0x18f, %rax            # imm = 0x18F
ja 0x7007
movq %r14, %rdx
negq %rdx
cmovsq %r14, %rdx
addq %r15, %rdx
movq (%rbp), %r12
cmpq %r12, %rdx
cmovaeq %r12, %rdx
movq %rdx, (%rbp)
incq %r14
incq %rax
addq $0x8, %rbp
jmp 0x6fdd
movq 0x10(%rsp), %r12
incq %r12
decq 0x8(%rsp)
movl $0x186a0, %ebp          # imm = 0x186A0
xorl %r13d, %r13d
movb 0x7(%rsp), %sil
cmpq $0x190, %r13            # imm = 0x190
je 0x7097
movq 0x30(%rsp,%r13,8), %rax
movb (%rbx,%r13), %r14b
movl %esi, %ecx
subb %r14b, %cl
movl %ecx, %edx
sarb $0x7, %dl
xorb %dl, %cl
subb %dl, %cl
movzbl %cl, %ecx
leaq (%rax,%rcx), %r15
incq %r15
movq 0x28(%rsp), %rcx
subq %r15, %rcx
jb 0x7090
movb %sil, (%rbx,%r13)
movq 0x18(%rsp), %rdi
movq %r12, %rsi
movq 0x8(%rsp), %rdx
movq %rbx, %r8
movq %r13, %r9
callq 0x6ee8
movb 0x7(%rsp), %sil
movb %r14b, (%rbx,%r13)
addq %r15, %rax
cmpq %rbp, %rax
cmovbq %rax, %rbp
incq %r13
jmp 0x702d
xorl %ebp, %ebp
movq %rbp, %rax
addq $0xcb8, %rsp            # imm = 0xCB8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq