Earlier quoted context omitted.
Out of curiosity, what's the lowest score you've seen on 17x17 so far?
Down to 39: 1 0 1 0 2 0 2 1 0 2 1 3 3 2 3 3 1 3 3 0 3 1 2 3 0 0 1 1 1 2 2 2 0 1 3 2 3 2 2 0 1 0 3 0 3 3 1 1 0 2 1 0 3 1 2 1 1 2 3 1 0 3 0 0 3 2 0 2 0 1 1 3 3 3 1 0 1 1 2 2 3 2 0 2 0 3 1 2 2 3 1 0 1 0 3 0 2 0 3 0 1 2 1 1 1 2 0 2 3 2 3 3 0 0 1 2 0 0 3 2 2 0 0 3 1 0 1 3 1 3 0 1 2 1 3 2 0 0 2 0 0 2 0 3 1 2 1 2 1 3 3 1 3 3 2 2 1 0 3 0 1 1 0 3 1 2 0 3 2 3 1 3 3 0 1 3 2 2 1 3 0 2 2 0 1 3 0 2 3 2 1 2 1 1 2 0 0 1 0 3 0 2 3 3…
Score: 12
2 3 0 1 3 2 1 2 2 3 1 2 0 3 1 3 0
2 1 1 2 2 1 1 0 3 3 3 3 3 2 0 0 0
2 2 1 1 0 3 3 3 1 0 2 0 1 3 3 0 2
3 2 0 1 1 1 0 3 2 1 3 0 2 2 0 3 1
1 2 1 3 1 0 2 2 0 2 0 0 3 3 1 1 0
1 1 3 3 0 2 2 0 0 1 3 1 0 2 3 1 2
3 2 3 0 2 1 0 0 0 0 1 2 1 3 2 1 3
1 3 3 2 3 1 0 1 2 2 0 3 0 1 2 0 2
2 0 2 1 3 0 3 1 0 2 3 1 2 0 0 1 3
3 0 2 0 1 3 1 2 3 3 2 1 1 2 2 0 0
0 0 2 3 2 3 2 0 2 1 0 3 1 1 1 3 3
2 0 1 3 3 0 2 3 3 0 1 1 0 1 2 2 1
0 1 0 2 1 0 2 3 1 3 2 2 2 1 3 0 3
3 2 2 2 0 2 0 1 1 1 1 3 3 0 3 2 0
3 3 0 3 2 1 3 2 1 0 0 1 2 0 1 2 2
1 3 3 0 0 3 1 3 1 2 0 2 3 2 0 2 1
0 1 3 0 2 2 3 1 3 2 2 0 0 0 1 3 1
Edit: I can't reply to you, so...It's not pretty, but I did a few things. Instead of taking the top n candidates and breeding them randomly, I kept all of them (NUM_STATES 200 and KEPT_STATES 200), but weight them according to score. So the best scores have the highest chance of passing their DNA down to the next generation, but the occasional loser gets lucky too.
Mutation is also weighted, so the most likely number of mutations is zero, but it's possible to have up to 4. Increasing this value made the performance go down, but it's also possible that there is no way to get to a solution by incrementally tweaking a decent attempt. Which could explain why I'm stuck at 12.
There are a few optimizations that may or may not make a difference, for instance in the scoring function. I think the pick_best_states function was not actually picking the best states. If you had two states with the same score, the first one is kept, but the next one is not. I fixed this. The stupid thing is, with NUM_STATES and KEPT_STATES at 200, it's basically an n^2 sort now. I never bothered to improve that.
Finally, compiled with -O3 and let 'er rip.