Doug’s MATLAB Video Tutorials
September 25th, 2008
Puzzler: Cleverness needed
I have been working on a side project and I found I needed the following algorithm:

Given a binary five by five matrix, I need to find the ‘1′ value that is in the position that has the lowest value in the spiral map above. I call that the target square. Once that target is found, then I need to return a delta x and delta y that will get me closer to that target. Delta x and delta y must be taken relative to the center square, and can only be from the set [-1, 0, 1].
As an example, given the matrix:

The ‘1′ in the (2,2) position in the matrix is the target because it maps to 9, and the other two ‘1′ values map to larger values, 11 and 18. From here, the delta x is -1 and delta y is 1.
If the target was 18, then the values would have been delta x of 0 and delta y of -1.
A final edge case, if the input matrix were all zeros, then delta x and delta y should be chosen randomly, but still pulled from the set [-1, 0, 1].
This is not a particularly difficult algorithm to program if you use 25 if, elseif statements. However, I am looking to be a bit more clever with this. Please post your solution in the comments, make it a function of this form:
[deltaX, deltaY] = puzzler(inMatrix)
As always with these puzzlers, be sure to use the proper tags in the comments.
<pre> <code>
[deltaX, deltaY] = puzzler(inMatrix)
%% All the code so someone can just copy and paste it from the comments.
</code> </pre>
11:12 UTC |
Posted in Topic: Puzzler |
Permalink |
You can follow any responses to this entry through the RSS 2.0 feed.
You can skip to the end and leave a response. Pinging is currently not allowed.
Leave a Reply
|
What’s the logic in having the jump between the 9-10 valued cells being diagonal? I’m more interested in generating the spiral square for an arbitrary matrix size.
ah, beaten to the finish line. had the same idea for the spiral, slightly different for dx dy.
Hi,
This code is similar to what has been posted before. The computation of deltaX and deltaY is more rigorous than what is needed for this particular problem. But it is more easily ported to the case of any arbitrary sized square matrix.
Note: The spiral matrix I use is slightly different from what Doug specified. The difference comes when you go from 9 to 10. Not sure why you go from 9 to 10 the way you do. If needed, the spiral matrix “spMat” can be hard coded as given in the problem.
Some great solutions here.
To answer ST and Stefan, the reason I am using a different spiral is that the target directly above is the most important in each of the rings.
I have been taking these solutions in and have made one that fits my style the best:
So here is the function that can work on any arbitrary-sized binary square input matrix. How one defines the “center square”, or what I call “pivot”, for a square matrix with even number of rows and columns is an issue. I just choose the center of the even matrix based on where the indexing starts in the spiral matrix that I use in my code, just to keep it simple.
So, the center square location for an NxN matrix is:
N Odd: (ceil(N/2) , ceil(N/2))
N Even: (floor(N/2)+1 , ceil(N/2))
Other center locations can be chosen too, if the code can start the spiral indexing from that location. Well, in that case maybe we can make the pivot location as one of the inputs, although it will have to be one of the central locations for the spiral indexing to continue without a break and cover all the elements.
Yi,
I have tried the above solution, but it does not give the correct answers. I think the idea is correct, but when using min, you are not getting the unique result that you expect.
Also, it does not take into account the edge case of no target existing.
Doug
Here is my solution. I like it because it is simple and fast. I think I got all those indices correct!
Oops, looks like I missed the edge requirement too. This does it.
There is a spiral command in basic matlab? I thought the challenge was to code that particular pattern….
Oh well, seems you guys allready solved it far enough as is still interesting.
–DA
Speaking of which, the spiral function seems to exist and have embedded help coments, but it does not seem to exist in the doc. Sneaky there…..
Pros:
Scalable
Doesn’t generate big matrix
Cons:
Uses find twice, possibly slow
~Adam
Matt,
It is always interesting to see how people solve the problem. Yours is a little different from the rest. It took me a while to understand what IDXA was. Then I figured out it was the absolute indices of the matrix in preferred order. The rest follows from that. This makes the problem a short look-up table type of problem
While it makes the code a little harder to visualize, it does make for very clean code. There are always trade-offs.
Doug
PS. You never actually define your outputs in the function, not do you have the function keyword, but the ideas are there.
Daniel,
Spiral is not documented as such, because it is not a MATLAB function, it is a MALTAB demo:
>> which spiral
C:\Program Files\MATLAB\R2008a\toolbox\matlab\demos\spiral.m
These are treated differently, even thought this demo happens to be useful as a stand alone function also.
Doug
Doug,
You caught me! I must have copied your formatting example from above, then pasted my function in the middle. I think I remember seeing two ‘function declarations’ and deleting one. I must have erased mine instead of yours! Oh, well, you get that the function declaration should look like:
function [dx,dy] = puzzler(a)
I would be interested to see if one could come up with a fast way to get idxa for any size input, and if that is faster than some of the other scalable submissions. The other two “lookup vectors” should be easy enough to generate. Interesting…
So I’m a little late to the party. What I came up with was pretty much what everyone else came up with.
for those who really want to tackle the problem of creating spiral matrices…
compare a recursive approach like this, to the classic for-loop approach in spiral.m. I think a recursive approach like this is far and away easier to understand for a problem like this. Memorywise, it’s a tad wasteful, and it’s not as fast. But it’s readable.
Doug,
Thanks for pointing out errors in my original code. I should test it before posting. Anyway, here is the version with corrections. It has been tested, hence should be correct.
If you happen to want to do this for every pixel in a binary image then you can do something different to the methods suggested above, which I think will work out being faster, because it involves a multiplication which could be done over an image using conv2:
In fact, I use exactly this trick in my print2im function on the FEX.
This solution uses a method different to those above, and so may be of interest. It uses ‘angle’ to determine which square is the correct target, without needing to construct any spiral matrices.
It should work for any size input matrix (although I’ve only tested 5×5, and even-edged matrices will assume a starting point for the spiral at one of the cells near the centre).
The code assumes that inMatrix is of type logical.