it\'s Friday afternoon, let\'s have a fun puzzle/algorithm problem to solve.
One of my favorite Nintendo DS games is Picross DS. The game is quite simple, it involves so
The real problem is whether anyone can come up with an algorithm that solves the said puzzle faster than a human? This is easy for relatively easy puzzles such as the reference one but if the puzzle grows most of the algorithms here will quickly slow down. Here is the puzzle I tried to solve. The problem is that the 4th row for example has 2220075 possible combinations I believe. If Charlie's algorithm temporarily accepts a wrong row for row 3, it will go through all these combinations for row 4. And this is not to mention the case where the algorithm contradicts itself on row 35 over a mistake it made on row 2.
My algorithm was similar to John's. It failed to run in x86 mode on my 64bit desktop. When I switched it to 64bit mode and let it run overnight, my computer was completely unusable in the morning. The process was reserving 8 Gigs of memory (8 Gigs physical on the desktop) and the computer wouldn't respond due to the frantic swapping. And it hadn't even solved all the possible rows. Not to mention it hadn't even touched the possible column combinations.
List<List<int>> rows =
new List<List<int>>()
{
new List<int> { 8,29,4 },
new List<int> { 6,4,25,4,3 },
new List<int> { 5,3,2,3,9,4,2,1,3 },
new List<int> { 4,2,2,2,2,1,2,2 },
new List<int> { 4,1,1,9,10,2,2,1 },
new List<int> { 3,2,6,5,5,1,1 },
new List<int> { 3,1,5,5,1,1 },
new List<int> { 3,1,4,4,1,1 },
new List<int> { 3,1,4,4,1,1 },
new List<int> { 3,1,3,3,1,1 },
new List<int> { 3,1,3,6,2 },
new List<int> { 3,1,2,3,2,4,2 },
new List<int> { 4,3,1,8,7,1,2,3 },
new List<int> { 4,2,1,12,11,1,2,4 },
new List<int> { 5,1,2,7,2,2,6,1,1,4 },
new List<int> { 4,1,1,1,6,2,2,6,1,2,1,3 },
new List<int> { 4,1,1,2,4,3,4,3,1,1,1,1,3 },
new List<int> { 4,1,1,2,1,4,1,2,3,2,1,2,2 },
new List<int> { 3,1,1,1,2,5,6,1,1,1,3,2 },
new List<int> { 3,2,1,1,2,1,5,4,4,2,1,2,1,2 },
new List<int> { 3,2,2,1,1,4,2,2,3,1,1,2,1,1,2 },
new List<int> { 3,1,3,2,1,1,4,1,5,3,2,1,3,1,2 },
new List<int> { 3,1,2,1,2,1,3,7,4,1,4,2,2 },
new List<int> { 2,1,4,1,1,1,2,6,2,2,2,3,2,1 },
new List<int> { 2,2,4,1,2,1,2,5,2,1,1,3,2,1 },
new List<int> { 2,2,1,4,1,1,3,3,2,1,4,4,1 },
new List<int> { 2,3,3,2,1,3,3,7,4,1 },
new List<int> { 2,3,2,4,5,8,1,2,1 },
new List<int> { 1,1,3,11,6,7,1,3,1 },
new List<int> { 1,1,2,2,13,10,2,3,2 },
new List<int> { 1,2,3,1,6,1,1,7,1,5,2 },
new List<int> { 1,1,3,2,6,1,1,1,1,4,1,4,2 },
new List<int> { 1,1,6,7,2,4,2,5,6,1 },
new List<int> { 1,1,2,3,1,4,2,2,11,2,1 },
new List<int> { 1,1,1,1,2,1,5,10,1,1,1 },
new List<int> { 1,1,1,1,4,7,4,10,1,1,1 },
new List<int> { 1,2,1,1,28,1,1,3 },
new List<int> { 1,2,1,2,27,2,1,3 },
new List<int> { 1,1,1,1,26,1,1,1,1 },
new List<int> { 2,3,1,28,2,1,2,1 }
};
List<List<int>> cols =
new List<List<int>>()
{
new List<int> { 40 },
new List<int> { 28,1 },
new List<int> { 23,8 },
new List<int> { 5,6,7,4 },
new List<int> { 3,6,1,9,3,1 },
new List<int> { 2,3,2,5,4,2,2 },
new List<int> { 1,2,4,1,2,5,2 },
new List<int> { 1,1,4,9,2,3,2 },
new List<int> { 2,4,2,6,1,4,3 },
new List<int> { 1,4,1,3,4,1,6 },
new List<int> { 1,4,3,2,3,5,5 },
new List<int> { 2,4,1,2,3,4,1,3 },
new List<int> { 1,2,3,4,2,2,4,4,1 },
new List<int> { 1,1,2,3,2,1,4,2,4 },
new List<int> { 2,3,5,3,3,5,4 },
new List<int> { 3,1,6,1,2,5,5 },
new List<int> { 3,2,6,2,15 },
new List<int> { 3,1,8,2,13 },
new List<int> { 2,2,4,5,15 },
new List<int> { 2,2,2,2,22 },
new List<int> { 2,1,1,1,12,6 },
new List<int> { 2,1,10,4,5 },
new List<int> { 3,1,3,1,2,4 },
new List<int> { 3,1,1,4,3,1,4 },
new List<int> { 3,2,2,3,2,2,5 },
new List<int> { 3,1,1,5,1,1,5 },
new List<int> { 3,1,1,5,1,1,5 },
new List<int> { 3,1,1,5,1,1,5 },
new List<int> { 3,2,5,2,1,1,4 },
new List<int> { 3,1,1,3,2,2,4 },
new List<int> { 3,1,6,4,5 },
new List<int> { 2,2,12,2,6 },
new List<int> { 2,2,1,1,22 },
new List<int> { 2,1,2,2,5,15 },
new List<int> { 3,1,4,3,2,14 },
new List<int> { 3,1,7,2,1,13 },
new List<int> { 3,2,6,1,1,6,8 },
new List<int> { 3,2,5,2,2,4,7 },
new List<int> { 2,1,2,4,1,1,1,4,1,4,2 },
new List<int> { 1,1,4,4,3,1,4,5,1 },
new List<int> { 1,1,5,1,1,2,1,2,2,3,2 },
new List<int> { 1,5,2,2,1,5,5,3 },
new List<int> { 1,6,2,1,4,2,6,1 },
new List<int> { 1,6,2,6,5,2 },
new List<int> { 1,5,3,1,9,2 },
new List<int> { 2,2,4,2,6,3 },
new List<int> { 1,2,2,2,9,2,1 },
new List<int> { 3,5,5,8,4 },
new List<int> { 4,13,9 },
new List<int> { 27,2 }
};
Copyright goes to Tampere Guild of Information Technology / Kaisapais / A finnish brewery.
Steven Simpson has written a nonogram solver that's freely available in different versions, including a JavaScript script. He discusses details of the algorithms on that website (such as here- basically, he's using a series of linesolvers that trade off speed vs. completeness, coupled with divide and conquer by guessing when all the linesolvers reach a dead end. He also has links to other approaches, which cover more ground than we have here.
Let me point out 2 interesting twists on the classic nonogram puzzles :
When the puzzle does more than just list lengths of occupied cells. This public challenge constrained some cells in advance as being occupied : http://www.gchq.gov.uk/press_and_media/news_and_features/Pages/Directors-Christmas-puzzle-2015.aspx
When the nonogram contains more than just empty/occupied cells, but uses patches of different colors to occupy the cells. For example see http://onlinenonograms.com ; from solving these by hand, I get the feeling that these are actually easier to solve than the regular nonograms.
A particular challenge for algorithm designers is that the colored nonograms benefit greatly from considering horizontal/vertical constraints together. The usual line-per-line solvers are at a clear disadvantage here.
Determining whether a Nonogram solution exists/is unique is NP-hard. See http://en.wikipedia.org/wiki/Nonogram#cite_note-0