18
1
Overview
Pearls (or Masyu) is a logic game played on a grid. There are black and white pearls placed on the grid. The object is to form a single, closed loop that travels through each pearl using only straight line segments and right angles.
There are some rules that govern how the loop interacts with pearls:
- White pearls must be traveled straight through, but the loop must turn in the previous and/or next cell in its path.
- Black pearls must be turned upon, but the loop must travel straight through the next and previous cells in its path.
- The loop must not cross or otherwise intersect itself. All cells have exactly zero or two loop entry/exits.
An example puzzle from Wikipedia (and its solution):
Your objective is to solve a given puzzle. If there are multiple possible solutions, it does not matter which one you give.
Input
Input will be an unsolved square grid. The example shown above would look like this:
..w.w.....
....w...b.
..b.b.w...
...w..w...
b....w...w
..w....w..
..b...w...
w...b....w
......ww..
..b......b
w
is a white pearl, b
is a black pearl, and .
is an empty cell.
Assume input is valid. This means it is well formed, and at least one solution is possible. All valid puzzles are at least 3x3, and contain at least one pearl.
Output
Output is a string of coordinates representing the path. The upper left corner of the grid is 0 0
, upper right is n-1 0
, where n is the width of the grid.
A path is simply a series of ordered coordinates:
x1 y1 x2 y2 x3 y3 ...
The path is assumed to be closed, so you do not need to repeat the first coordinate at the end, but there is no penalty for doing so.
The output should consist of at least all corners in the path. You do not have to output every cell on the path if there is no turn. For instance, the output for the example could start with:
1 0 5 0 5 1 ...
or
1 0 2 0 3 0 4 0 5 0 5 1 ...
Output should not contain any cell not in the path. You may start at any cell in the path.
Snippet
Here's a snippet you can use to visualize your solution. Just paste in the grid you're working on and the path you output. I'm aware that it's painful to look at my code, so I just suggest you don't ;)
function draw(){document.getElementById("output").innerHTML=gridSVG+pathSVG}function drawCoords(){coords=document.getElementById("coords").value;var e=prefix+'<path fill="none" d="';if(nums=coords.match(/[^\s]+/g),!(nums.length<2)){for(e+="M "+(nums[0]*scale+offset)+" "+(nums[1]*scale+offset),i=2;i<nums.length;i+=2)e+=" L "+(nums[i]*scale+offset)+" "+(nums[i+1]*scale+offset);e+=" L "+(nums[0]*scale+offset)+" "+(nums[1]*scale+offset),e+='" stroke="black" stroke-width="2"/>'+suffix,pathSVG=e,draw()}}function drawPath(){path=document.getElementById("path").value;var e=prefix+'<path fill="none" d="'+path+'" stroke="black" stroke-width="2"/>'+suffix;pathSVG=e,draw()}function drawGrid(){grid=document.getElementById("grid").value;var e=prefix;for(lines=grid.match(/[^\s]+/g),width=lines[0].length*scale,height=lines.length*scale,i=0;i<=lines.length;i++)e+='<path stroke="gray" d="M 0 '+i*scale+" L "+width+" "+i*scale+'"/>',e+='<path stroke="gray" d="M '+i*scale+" 0 L "+i*scale+" "+height+'"/>';for(j=0;j<lines.length;j++)for(line=lines[j],i=0;i<line.length;i++)"w"==line.charAt(i)&&(e+='<circle cx="'+(i*scale+offset)+'" cy="'+(j*scale+offset)+'" r="'+.8*offset+'" stroke="black" fill="white"/>'),"b"==line.charAt(i)&&(e+='<circle cx="'+(i*scale+offset)+'" cy="'+(j*scale+offset)+'" r="'+.8*offset+'" stroke="black" fill="black"/>');e+=suffix,gridSVG=e,draw()}var prefix='<svg height="400" width="400">',suffix="</svg>",scale=30,offset=scale/2,pathSVG="",gridSVG="";
svg{position: absolute;left: 50px;}
Paste grid input here<br><input id="grid" type="textarea" size="80" oninput='drawGrid()' /><br><br>Paste path output here<br><input id="coords" type="textarea" size="80" oninput='drawCoords()' /><br><br><div id="output"></div>
Test Cases
These test cases show one possible output for each input (except the last, which is shown unsolved). There may be other valid paths, you might go CW or CCW or start at a different point, etc. Solutions should be able to solve the test cases in seconds/minutes/hours, not days/weeks/eons.
...
w..
..b
0 0 1 0 2 0 2 1 2 2 1 2 0 2 0 1
.wb..b
......
..b...
w.ww..
......
b....b
0 0 2 0 2 2 4 2 4 1 3 1 3 0 5 0 5 5 3 5 3 4 4 4 4 3 1 3 1 4 2 4 2 5 0 5 0 2 1 2 1 1 0 1
.....w.b.w..
ww..b...b...
.w.....b....
...wbww..b.b
....b.......
w.w.........
..w......b.b
.....bb.....
.....b.....w
w.ww..b.....
...w......w.
b..w.....b..
You didn't put the solution for the last test case... – mbomb007 – 2015-04-20T21:00:49.530
2@mbomb007 Correct. – Geobits – 2015-04-20T21:47:57.757
So there's no solution? – mbomb007 – 2015-04-21T13:45:16.600
2There is a solution. I left it open so answers would have something to show for their effort. Also, it may help to solve a puzzle or two by hand to get a feel for the rules, and that's hard to do if all the examples are pre-solved. – Geobits – 2015-04-21T13:47:21.733
Is a grid 2x2 or larger grid with no Pearls considered valid (second sentence suggests not, and the point about the input being unsolved (if there are no unstrung pearls, it must be solved))? If so, would you expect a loop, just with no pearls in it, or what exactly? Presumably there is no requirement for any of a particular color to be present? – VisualMelon – 2015-04-22T09:15:18.020
@VisualMelon A valid puzzle is 3x3 or larger with at least one pearl, no color requirement. Edited post. – Geobits – 2015-04-22T12:38:39.247
Can I assume a limit on the maximum puzzle size or make it a compile time variable? In reality a brute force solution will work in reasonable time only up to a certain size and I haven't seen puzzles of this type bigger than 30 in one dimension. – nutki – 2015-04-22T23:00:16.840
@nutki The algorithm should theoretically work for any size in finite time, assuming infinite resources. However, it only needs to work in reasonable time for the test cases given. The time limit is really only to discourage the brutest of brute forces (something like 2^(n^2)), to facilitate testing. – Geobits – 2015-04-23T12:50:27.593
Oh, and for anyone who likes this type of puzzle, there's this: http://manpages.ubuntu.com/manpages/precise/man6/pearl.6.html
– Geobits – 2015-04-23T12:52:25.237@Geobits, is then compile time variable fine? This is what my solution currently does. If that is not OK, then C is penalized as then you require dynamic memory allocation and in C I need to use libc for that plus I cannot use 2D arrays which need to be statically sized. On the other hand I can easily set the limit to 1000x1000 and for that size the code wouldn't finish in this universe. – nutki – 2015-04-23T13:33:09.820
@nutki Yes, that's fine. At most, just add a short note saying that the byte size would be (slightly) affected if you were doing something orders of magnitude larger for some reason. – Geobits – 2015-04-23T13:34:34.043