Solving a wordsearch puzzle in matlab - matlab

Posting the entirety of my code in the hope somebody can help me debug this crap. Really hoping to reach a conclusion soon because I've been toying with this for way too long.
I have here a function extract which is passed a grid of integers which represent letters (i.e A=1,Z=26) from my wordsearch function. Given a direction and a target word which is represented by a row vector of ints, it should iterate through the grid to find where the first letter exists and move in all directions from here for length of the word and extract the word e.g. if we are looking for [14, 5, 9, 2] and 14 is first positioned at (4,4) we should end up at (4,8).
The word is then compared in the search function and if it matches the target word, a line is drawn from first letter to the last on an image of the actual wordsearch.
I know my if and for loops are off in some places but I'm finding it difficult to correct my code so that it works. Help! One thing in particular I'm having difficulty with is controlling flow so that if after checking all directions from a square containing the first letter, the next instance of that letter is evaluated. Where would it be best to do this?
Code has lots of errors as it is and could do with a couple of pointers telling me where it needs altering or cleaning up.
%//A function to find a word in a grid.
function test = extract(grid, direction, target)
%//switch through different cases that allow us to move to any adjacent cell to the current
switch upper(direction)
case 1
rowdir = -1;
coldir = 0;
case 2
rowdir = -1;
coldir = 1;
case 3
rowdir = 0;
coldir = 1;
case 4
rowdir = 1;
coldir = 1;
case 5
rowdir = 1;
coldir = 0;
case 6
rowdir = 1;
coldir = -1;
case 7
rowdir = 0;
coldir = -1;
case 8
rowdir = -1;
coldir = -1;
end
[i, j] = size(grid);
len = length(target);
[row,column] = find(target(1)==grid); %//find the letter of the word we are looking for in grid
%//row and column of last letter having moved in a particular direction
rowN = row + (len-1) * rowdir;
colN = column + (len-1) * coldir;
%//trying to say here to only move in a particular direction if we don't go out of bounds.
%//not sure I've succeeded
if (rowN > 1) | (rowN < i) | (colN > 1) | (colN < j)
testword = []; %empty array created
for index = 1:len
index_1 = index-1;
%//on loop get the letter in adjacent cell for direction we have moved
word = grid(row + (index_1 * rowdir), column + (index_1 * coldir));
testword{index} = word; %//letters are appended to create word for which we compare.
%//get co-ords of start letter. change to pixel co-ordinates so we can evaluate on image
wordstart = [(row*30)-15, (column*30)-15 ];
wordend = [((row + (len-1 * rowdir))*30)-15, ((column + (len-1 * coldir))*30)-15];
end
else
word = '';
end
x1 = wordstart(1);
x2 = wordend(1);
y1 = wordstart(2);
y2 = wordend(2);
test = [ word , [x1,x2] , [y1,y2]]; %//only way I could think of to get all of these as outputs
end
%//test is the image we want to evaluate on
%//words is the list of words
function trial1 = wordsearch(test, words)
imagesc(test);
colormap(gray);
hold on;
grid = %//grid is a 15x15 matrix
[row, column] = size(grid);
for iword = 1 : length(words)
target = char(words(iword)) - 'a' + 1;
for i = 1:row
for j = 1:column
for direction_num = 1:8 %//for each direction
direction = directions(direction_num, :);
testword = extract(grid,direction,target);
if testword(1)==target %//if word we have extracted equals the target word
%//draw_line function takes x co-ordinates and y co-ordinates and plots line.
draw_line(testword(2),testword(3),testword(4),testword(5));
end
end
end
end
end
hold off;
end
#Dan
My extract function now looks like:
[i, j] = size(grid);
len = length(target);
[row,column] = find(target(1)==grid);
for ii = 1:length(row)
start_row = row(ii);
start_column = column(ii);
rowN = start_row + len-1 * rowdir;
colN = start_column + len-1 * coldir;
if (rowN > 1) || (rowN < i) || (colN > 1) || (colN < j)
testword = [];
for index = 1:len
index_1 = index-1;
word = grid(start_row + (index_1 * rowdir), start_column + (index_1 * coldir));
testword{index} = word;
wordstart = [(start_row*30)-15, (start_column*30)-15 ];
wordend = [((start_row + (len-1 * rowdir))*30)-15, ((start_column + (len-1 * coldir))*30)-15];
end
else
end
end
What would I put as an else statement to check the word if previous in that particular direction takes you out of bounds?

for iword = 1 : length(words)
target = char(words(iword)) - 'a' + 1;
for i = 1:row
for j = 1:column
for direction_num = 1:8 %//for each direction
For every word, you are looping through every element in the grid (i.e. the i and j loops) but you don't actually ever use these i or j values. So those two loops do nothing! This is because you seems to do all of that inside your extract function. So drop those two loops, they are wasting an inordinate amount of time.
Inside your extract function, you have a line [row,column] = find.... This will find ALL the possible starting points. So you actually need to loop through either of those somewhere. So instead of your if (rowN > 1) | (rowN < i) | (colN > 1) | (colN < j) I would suggest something more like:
for ii = 1:length(row)
start_row = row(ii);
start_column = column(ii);
%// And now re-use your code, but swap out all your row for start_row and your column for start_column
.
.
.
end
That is the loop that will go through each of the possible starting letters.

Related

MATLAB — How to eliminate equal matrices that are created randomly inside loop?

The code segment I'm working on is given below:
NphaseSteps = 6;
phases = exp( 2*pi*1i * (0:(NphaseSteps-1))/NphaseSteps );
i = 1;
while i <= 10 %number of iterations
ind = randi([1 NphaseSteps],10,10);
inField{i} = phases(ind);
save('inField.mat', 'inField')
i = i + 1;
end
Now, what I want is to keep track of these randomly created matrices "inField{i}" and eliminate the ones that are equal to each other. I know that I can use "if" condition but since I'm new to programming I don't know how to use it more efficiently so that it doesn't take too much time. So, I need your help for a fast working program that does the job. Thanks in advance.
My actual code segment (after making the changes suggested by #bisherbas) is the following. Note that I actually want to use the variable "inField" inside the loop for every random created matrix and the loop advances only if the result satisfies a specific condition. So, I think the answer given by #bisherbas doesn't really eliminate the equal inField matrices before they are used in the calculation. This is, of course, my fault since I didn't declare that in the beginning.
NphaseSteps = 6;
phases = exp( 2*pi*1i * (0:(NphaseSteps-1))/NphaseSteps );
nIterations = 5;
inField = cell(1,nIterations);
i = 1;
j = 1;
while i <= nIterations % number of iterations
ind = randi([1 NphaseSteps],TMsize,TMsize);
tmp = phases(ind);
idx = cellfun(#(x) isequal(x,tmp),inField);
if ~any(idx)
inField{i} = tmp;
end
j = j+1;
outField{i} = TM * inField{i};
outI = abs(outField{i}).^2;
targetIafter{i} = abs(outField{i}(focusX,focusY)).^2;
middleI = targetIafter{i} / 2;
if (max(max(outI)) == targetIafter{i})...
&& ( sum(sum((outI > middleI).*(outI < max(max(outI))))) == 0 )
save('inFieldA.mat', 'inField')
i = i + 1;
end
if mod(j-1,10^6) == 0
fprintf('The number of random matrices tried is: %d million \n',(j-1)/10^6)
end
end
Additionally, I've written a seemingly long expression for my loop condition:
if (max(max(outI)) == targetIafter{i})...
&& ( sum(sum((outI > middleI).*(outI < max(max(outI))))) == 0 )
save('inFieldA.mat', 'inField')
i = i + 1;
end
Here I want a maximum element at some point (focusX, focusY) in the outField matrix. So the first condition decides whether the focus point has the maximum element for the matrix. But I additionally want all other elements to be smaller than a specific number (middleI) and that's why the second part of the if condition is written. However, I'm not very comfortable with this second condition and I'm open to any helps.
Try this:
NphaseSteps = 6;
phases = exp( 2*pi*1i * (0:(NphaseSteps-1))/NphaseSteps );
i = 1;
inField = cell(1,NphaseSteps);
while i <= NphaseSteps %number of iterations
ind = randi([1 NphaseSteps],NphaseSteps,NphaseSteps);
tmp = phases(ind);
idx = cellfun(#(x) isequal(x,tmp),inField);
if ~any(idx)
inField{i} = tmp;
end
save('inField.mat', 'inField')
i = i + 1;
end
Read more on cellfun here:
https://www.mathworks.com/help/matlab/ref/cellfun.html

Recursively divide a square field - Matlab crashes

I am working with simulation of wireless sensor networks in matlab.
I have a 200*200 by field in which 100 sensor nodes have been plotted randomly. Each node has an associated load value with it. I have to place charging stations in this field. I am trying to divide this square recursively as long as I do not found a small sub-square in which I can place only one charging station. Here is the code I wrote to divide the square recursively and count number of stations that can be placed in a subsquare:
%Inputs to the function
%numstations - No. of stations to be placed = 10
%boundCoords - A 2*2 matrix with min and max coordinates of square . e.g [0 0;200 200]
% sensors - A 100*3 matrix for nodes with 1st column as randomly generated 100 x-coordinates,
%second column as randomly generated 100 y-coordinates,
%third column as corresponding load of each node (can be random)
function stationPoss = deploy(numStations, boundCoords)
global sensors;
centerCoord = mean(boundCoords, 1);
numSensors = size(sensors, 1);
sumQuadLoad = zeros(1, 4);
for i = 1:numSensors
if sensors(i, 1) < boundCoords(2, 1) && sensors(i, 2) < boundCoords(2, 2)...
&& sensors(i, 1) > boundCoords(1, 1) && sensors(i, 2) > boundCoords(1, 2)
isIn34Quads = sensors(i, 1) > centerCoord(1); % N
isIn24Quads = sensors(i, 2) > centerCoord(2);
biQuadIndex = [isIn34Quads, isIn24Quads];
quadIndex = bi2de(biQuadIndex) + 1;
sumQuadLoad(quadIndex) = sumQuadLoad(quadIndex) + sensors(i, 3);
end
end
if numStations == 1
[maxQuadLoad, quad] = max(sumQuadLoad); %#ok<ASGLU>
delta = (centerCoord - boundCoords(1, :)) .* de2bi(quad - 1);
assoQuadCoords = [boundCoords(1, :); centerCoord] + repmat(delta, 2, 1);
stationPoss = mean(assoQuadCoords, 1);
else
sumLoad = sum(sumQuadLoad);
quadNumStations = zeros(1, 4);
for i = 1:3
if sumQuadLoad(i) == 0
quadNumStations(i) = 0;
else
quadNumStations(i) = floor(numStations * sumQuadLoad(i) / sumLoad);
end
end
quadNumStations(4) = numStations - sum(quadNumStations);
stationPoss = zeros(numStations, 2);
for i = 1:4
delta = (centerCoord - boundCoords(1, :)) .* de2bi(i - 1);
newBoundCoords = [boundCoords(1, :); centerCoord] + repmat(delta, 2, 1);
if quadNumStations(i) ~= 0
indexRange = sum(quadNumStations(1:i-1)) + (1:quadNumStations(i));
stationPoss(indexRange, :) = deploy(quadNumStations(i), newBoundCoords);
end
end
end
The problem is while trying to run this code with numStations=2 it works fine and with numStations=3 it sometimes crashes. For numStation > 3 it almost always crashes.
I tried to come up with a non-recursive way to write this function but wasn't able to.
Will anyone please help me to figure out the crash problem or in writing non recursive solution to the above function. I have already tried increasing the recursion limit.

Store data in a row matrix

I have a MATLAB program like this
for m = 1:2
%# Some code to calculate a matrix (Ytotale)
%# Size of Ytotale is (1200 * 144) %%
%#...
Yfinal = Ytotale;
for l = 1:1200
i = l;
j = retard(l,1);
if Yfinal(i,j) == 0
Yfinal(i,j:end) = circshift(Yfinal(i,j:end),[retard(l,2) retard(l,2)]);
for j = retard(l,1):retard(l,1)+retard(l,2)-1
Yfinal(i,j) = 1;
end
else
Yfinal(i,j:end) = circshift(Yfinal(i,j:end),[retard(l,2) retard(l,2)]);
for j = retard(l,1):retard(l,1)+retard(l,2)-1
Yfinal(i,j) = 0;
end
end
end
%# ( Here i , j are index of matrix Ytotale , and l is the index
%# of matrix retard of size (1200 * 2)
for i =1:1200
not_char(i,1) = sum(Yfinal(i,1:144));
req(i,1) = sum(Ytotale(i,1:144));
end
final = req - not_char;
ve_delay = sum(Yfinal(:,1:144))';
end
The total process will iterate from m = 1 to 2 and two Ytotale matrix will form, hence I want to store the value of ve_delay and final in a row matrix for each Ytotale , but my code overwrites the matrix values .
please help...
This answer is adapted from the comment by macduf
Try final{m} = req - not_char; and ve_delay{m} = sum(Yfinal(:,1:144)); . These values are now stored in a cell matrix (the curly bracket notation). You can convert the cell array into a regular array afterward.

Matlab error : Subscript indices must either be real positive integers or logicals

I have the following error in MATLAB:
??? Subscript indices must either be real positive integers or
logicals.
Error in ==> Lloyd_Max at 74 D(w_count) = mean((x -
centers(xq)).^2);
This is my code :
function [ xq,centers,D ] = Lloyd_Max( x,N,min_value,max_value )
%LLOYD_MAX Summary of this function goes here
% Detailed explanation goes here
x = x';
temp = (max_value - min_value)/2^N;
count=1;
for j=0:temp:((max_value - min_value)-temp),
centers(count) = (j + j + temp )/2;
count = count + 1;
end
for i=1:length(centers),
k(i) = centers(i);
end
w_count = 0;
while((w_count < 2) || (D(w_count) - D(w_count - 1) > 1e-6))
w_count = w_count + 1;
count1 = 2;
for i=2:(count-1),
T(i) = (k(i-1) + k(i))/2;
count1 = count1 +1 ;
end
T(1) = min_value;
T(count1) = max_value;
index = 1;
for j=2:count1,
tempc = 0;
tempk = 0;
for k=1:10000,
if(x(k) >= T(j-1) && x(k) < T(j))
tempk = tempk + x(k);
tempc = tempc + 1;
end
end
k(index) = tempk;
k_count(index) = tempc;
index = index + 1;
end
for i=1:length(k),
k(i) = k(i)/k_count(i);
end
for i=1:10000,
if (x(i) > max_value)
xq(i) = max_value;
elseif (x(i) < min_value)
xq(i) = min_value;
else
xq(i) = x(i);
end
end
for i=1:10000,
cnt = 1;
for l=2:count1,
if(xq(i) > T(l-1) && xq(i) <= T(l))
xq(i) = cnt;
end
cnt = cnt +1 ;
end
end
D(w_count) = mean((x - centers(xq)).^2);
end
end
and i call it and have these inputs :
M = 10000
t=(randn(M,1)+sqrt(-1)*randn(M,1))./sqrt(2);
A= abs(t).^2;
[xq,centers,D] = Lloyd_Max( A,2,0,4 );
I tried to comment the while and the D, Results :
I got the xq and the centers all normal, xq in the 1-4 range, centers 1-4 indexes and 0.5-3.5 range.
I dont know whats going wrong here...Please help me.
Thank in advance!
MYSTERY SOVLED!
Thank you all guys for your help!
I just putted out of the while the for loop :
for i=1:10000,
if (x(i) > max_value)
xq(i) = max_value;
elseif (x(i) < min_value)
xq(i) = min_value;
else
xq(i) = x(i);
end
end
and it worked like charm.... this loop was initilizing the array again. Sorry for that. Thank you again!
There is an assignment xq(i) = x(i) somewhere in the middle of your function, but you pass A as x from outside where you calculate A from t which is sampled by randn, so you can't promise xq is an integer.
I'm not sure exactly what you are aiming to do, but your vector xq does not contain integers, it contains doubles. If you want to use a vector of indices as you do with centers(xq), all elements of the vector need to be integers.
Upon a little inspection, it looks like xq are x values, you should find some way to map them to the integer of the closest cell to which they belong (i'm guessing 'centers' represents centers of cells?)

Indexes and values of surrounding cells in 3d matrix

I'd like to return the indexes and values of the 8 cells surrounding a cell in a 3d matrix.
mat = rand(5,5,5);
% Cell of interest
pos = [3 3 3]
pos_val = mat(pos(1), pos(2), pos(3))
% Surrounding cells
surrounding_pos = [pos(1)-1:pos(1)+1; pos(2)-1:pos(2)+1; pos(2)-1:pos(2)+1]
surrounding_val = mat(surrounding_pos(1,:), surrounding_pos(2,:), surrounding_pos(3,:))
This works fine for values in the centre of a matrix, but it breaks if pos is on the edge. (E.g. if pos was [3,4,5], surrounding_pos would include [3,4,6], which is out of bounds)
I could obviously remove surrounding_pos values <0 or >size(mat), but this doesn't seem like a terribly MATLABian method. Any ideas?
Same solution as discussed here, but extended to multiple (any) dimensions:
mat = randi(10,5,5,5);
siz = size(mat );
N = numel(siz); % number of dimensions
M = 1; % surrounding region size
pos = [3 3 3];
pos_val = mat(pos(1), pos(2), pos(3));
surrounding_pos = cell(N,1);
for ii=1:N
surrounding_pos{ii} = max(1,pos(ii)-M):min(siz(ii),pos(ii)+M);
end
surrounding_val2 = mat(surrounding_pos{:});
The important part is the last four lines, it avoids having to c/p the max, min thing for every dimension..
Or if you like short code, the loop changed to an arrayfun:
surrounding_pos = arrayfun(#(ii) max(1,pos(ii)-M):min(siz(ii),pos(ii)+M), 1:N,'uni',false);
surrounding_val2 = mat(surrounding_pos{:});
Here is a tidied up version. Cheers.
mat = rand(5,5,5);
N = size(mat)
if length(N) < 3 || length(N) > 3; error('Input must be 3 dimensional'); end;
pos = [1 3 5]
surrounding_val = mat(max(pos(1)-1, 1):min(pos(1)+1, N(1)), max(pos(2)-1, 1):min(pos(2)+1, N(2)), max(pos(3)-1, 1):min(pos(3)+1, N(3)))
EDIT: Added an error trap.
I found this post because I needed to grab the surrounding indices of a chosen point in a Matrix. It seems like the answers here are returning a matrix of the surrounding values, but the question is also interested in the surrounding indices. I was able to do this with "try/catch" statements, which I previously did not know existed in MATLAB. For a 2D Matrix, Z:
%Select a node in the matrix
Current = Start_Node;
%Grab its x, y, values (these feel reversed for me...)
C_x = rem(Start_Node, length(Z));
if C_x ==0
C_x =length(Z);
end
C_y = ceil(Start_Node/length(Z));
C_C = [C_x, C_y];
%Grab the node's surrounding nodes.
try
TRY = Z(C_x - 1, C_y);
Top = Current -1;
catch
Top = Inf;
end
try
TRY = Z(C_x + 1, C_y);
Bottom = Current +1;
catch
Bottom = Inf;
end
try
TRY = Z(C_x, C_y + 1);
Right = Current + length(Z);
catch
Right = Inf;
end
try
TRY = Z(C_x, C_y - 1);
Left = Current - length(Z);
catch
Left = Inf;
end
surround = [Top, Bottom, Left, Right];
m = numel(surround == inf);
k = 1;
%Eliminate infinites.
surround(surround==inf) =[];
I hope someone finds this information relevant.