Problem Analysis
The spiral picture is a deliberate distraction. What actually matters is a single arithmetic observation: each time I wrap one new layer around the centre, I add exactly four corner cells - one at each corner of the larger square - and these corners lie precisely on the two diagonals. If I index layers as k = 1, 2, 3, ..., the side length at layer k is 2k+1, an odd number, and the bottom-right corner is always the odd square (2k+1)^2. This is because the spiral fills clockwise to the bottom-right and the largest value on a side-(2k+1) spiral is (2k+1)^2. The remaining three corners are reached by repeatedly subtracting 2k (the side length minus one), since each edge of the square spans exactly that many cells between consecutive corners. So the entire diagonal sequence is a closed-form function of k - I never need to build or store the grid.
The real work is counting how many diagonal entries are prime and watching when the running ratio of primes to total diagonal entries first drops below 10%. I test primality with trial division: for a candidate n, I check divisibility by odd numbers up to sqrt(n), costing O(sqrt(n)) per test. The largest corner at the answer (side length 26241) is about 26241^2 ~ 6.9 * 10^8, so each test does at most ~13000 divisor checks. I process roughly n/2 layers, and a corner near layer k costs O(k) work, so the total is O(n^2) in the side length n - comfortably within a single linear pass, which is why this sits at Level 2. The bottom-right corner is an odd square (and thus never prime for k >= 1), so I could skip it, but testing it uniformly is harmless.
Solution Approach
Layer-by-Layer Diagonal Scan (Python and C)
Both files implement the same algorithm; only the language idioms differ. The core loop walks layers from k = 1 upward. For each layer I compute side_length = 2k+1 and the step side_length - 1 = 2k. From the bottom-right corner bottom_right = side_length^2 I derive the other three by successive subtraction:
bottom_left = bottom_right - steptop_left = bottom_left - steptop_right = top_left - step
I keep two running accumulators: num_prime_diagonals (starting at 0) and num_diagonal_elements (starting at 1, to count the centre cell 1, which lies on both diagonals but is not prime). Each layer adds 4 to the total and adds 1 per prime corner. After updating, I check whether the ratio has dropped below the threshold and, if so, return the current side length.
In Python I expressed layer enumeration as a generator that yields a 5-tuple (side_length, bottom_right, bottom_left, top_left, top_right), and the solve function consumes it with a for loop. This separates "how to produce corners" from "when to stop". The C version is a direct port: an unbounded for (int layer = 1; ; layer++) with the same arithmetic. The crucial difference is type width. The corner values exceed the 32-bit signed range (~2.1 * 10^9) well before the answer, so the C code uses long long throughout the corner arithmetic to avoid silent overflow - note in particular (long long)side_length * side_length, which casts before multiplying so the squaring itself does not overflow. Both programs accept the threshold as a command-line argument so they can be re-run at other ratios.