Tic Tac Toe with a win and taken check - Matlab - matlab

I'm making a tic tac toe game and I'm bombarded with various errors everytime I try to debug. I'm not sure where the problem is. The main error is either
Index exceeds matrix dimensions
or
Subscript indices must either be real positive integers or logicals
in line 8 of my 'checktaken' function.
Below is my code, where tttGame is the main function, boardplot does the plotting, and checkwintest/check taken see if a position is taken or if there is a win. I have asked many people for help and most haven't a clue whats wrong. Examples/code of your answers will help. Thanks!
Main function:
function tttGame
%%
%This function determines which players turn it is and whether there is a
%win or not
wonX = 0;
wonO = 0;
tttArray = zeros(3);
tttXArray = zeros(3);
tttOArray = zeros(3);
while wonX ~= 1 || wonO ~= 1
%%
%Initialize values
pXInputRow = 0;
pXInputCol = 0;
pOInputRow = 0;
pOInputCol = 0;
%%
%Show prompt to input values
pXInputRow = input('Player X Enter Row: ');
pXInputCol = input('Player X Enter Column: ');
%Plot and prompt Player X
boardplot(tttArray, pXInputRow, pXInputCol, pOInputRow, pOInputCol)
%Check taken location
checktaken(tttArray, pXInputRow, pXInputCol, pOInputRow, pOInputCol);
%If place is taken, prompt player to input again
if checktaken(tttArray, pXInputRow, pXInputCol, pOInputRow, pOInputCol) == 1
%Show prompt to input values
msgbox('That spot is taken')
pXInputRow = input('Enter Row: ');
pXInputCol = input('Enter Column: ');
%Otherwise, continue and change taken/player position on board
else
tttArray(pXInputRow, pXInputCol) = 1; %Set the position as taken
tttXArray(pXInputRow, pXInputCol) = 1; %Set the position for X
end
%Check if theres a win
checkwintest(tttXArray, tttOArray)
%Reset values
pXInputRow = 0;
pXInputCol = 0;
%%
%Show prompt to input values
pOInputRow = input('Player O Enter Row: ');
pOInputCol = input('Player O Enter Column: ');
%Prompt and plot Player O
boardplot(tttArray, pXInputRow, pXInputCol, pOInputRow, pOInputCol)
%Check taken location
checktaken(tttArray, pXInputRow, pXInputCol, pOInputRow, pOInputCol);
%If place is taken, prompt player to input again
if checktaken(tttArray, pXInputRow, pXInputCol, pOInputRow, pOInputCol) == 1
%Show prompt to input values
msgbox('That spot is taken')
pOInputRow = input('Enter Row: ');
pOInputCol = input('Enter Column: ');
%Otherwise, continue and change taken/player position on board
else
tttArray(pOInputRow, pOInputCol) = 1;%Set the position as taken
tttOArray(pOInputRow, pOInputCol) = 1;%Set the position for O;
end
%%
%Check win again
checkwintest(tttXArray, tttOArray)
%Reset values
pOInputRow = 0;
pOInputCol = 0;
end
end
Winning function
function [wonX, wonO] = checkwintest(tttXArray, tttOArray, tttGame)
%Test to see whether this format of win testing works
%Find any nonzero value in the tttX/OArray matrix. Returns 1 if true.
%All Columns, rows, diagonals
if any(all(tttXArray)) || any(all(tttXArray, 2)) || any(all(diag(tttXArray)))...
|| any(all(diag(fliplr((tttXArray)))));
wonX = 1;
elseif any(all(tttOArray)) || any(all(tttOArray, 2)) || any(all(diag(tttOArray)))...
|| any(all(fliplr(diag(tttOArray))));
wonO = 1;
else
wonX = 0;
wonO = 0;
end
%Send a message if a player won
if wonX == 1
playerXWonMessage = 'Congratulations Player X, you win!';
msgbox(playerXWonMessage)
exit(tttGame);
elseif wonO == 1
playerOWonMessage = 'Congratulations Player O, you win!';
msgbox(playerOWonMessage)
exit(tttGame);
end
end
Then
function [spotTaken] = checktaken(tttArray, pXInputRow, pXInputCol, pOInputRow, pOInputCol)
%Function used to check if spot is taken
%Setup Error Messages
errorMessage = 'This spot is taken, please choose another spot';
errorMessageTitle = 'Spot Taken';
spotTaken = 0;
if (tttArray(pXInputRow, pXInputCol) == 1) || (tttArray(pOInputRow, pOInputCol) == 1)
msgbox(errorMessage, errorMessageTitle)
spotTaken = 1;
end
end
and
function boardplot(tttArray, pXInputRow, pXInputCol, pOInputRow, pOInputCol)
%Setup the window for the game
close all;
clc;
figure('Name','Tic Tac Toe');
plot(-1. -1)
axis([0 3 0 3])
set(gca,'xTick',1:3)
set(gca,'yTick',1:3)
set(gca,'xTickLabel',[1 2 3])
set(gca,'yTickLabel',[1 2 3])
grid on
hold on
shg
%Plot
plot(pXInputRow - 0.5, pXInputCol - 0.5,'x', 'MarkerSize', 50)
hold on
plot(pOInputRow - 0.5, pOInputCol - 0.5,'o', 'MarkerSize', 50)
hold on
end

So I solved the problem and rewrote most of my code.
First I did not pass the proper inputs to the function checktaken (and other functions) which obviously led to some errors.
Then I rewrote my user input statements to use only 2 variables for rows/cols rather than 4, where there are 2 for each player.
checktaken is rewritten as follows:
function [spotTaken] = checktaken(tttArray, x, y)
%This function is used to check if spot is taken
%Function takes users row/col input as indices for the taken locations
%array, 'tttArray'. It then returns whether the spot is taken or not.
%Setup Error Messages
errorMessage = 'This spot is taken, please choose another spot';
errorMessageTitle = 'Spot Taken';
spotTaken = 0; %Initialization
%If the location's value is 1(taken), show error message and return
%spotTaken as 1(true).
if tttArray(x,y) == 1
msgbox(errorMessage, errorMessageTitle)
pause(3)
spotTaken = 1;
end
end
And I take the input via
function [a,b] = pickunospot
%This nested function creates the prompt for the player and takes
%the inputs as indices to be used later on in our arrays
prompt = {'Row (1,2, or 3)', '(Col (1, 2, or 3)'};
name = 'Enter your choice of row or column';
pt=inputdlg(prompt, name);
a = str2num(pt{2});
b = str2num(pt{1});
end
and call it like this
[x,y] = pickunospot;
where x and y are the rows/cols and can be used as matrix indices in checktaken.
This prevented any matrix index errors and limited the issue with 'not enough input arguments'.

Related

Nested for loop error or indexing error in MATLAB

I have created this code from scratch. I want to make a plot and/or histogram of my "Observed" and "State" (these are 2 matrices). Some problem occurs at the 200th iteration, where my State matrix just becomes all 0's, there is no data being input into the State matrix. Can anyone troubleshoot the code? My possible states are {1,2,3}.
UPDATE:
When I adjust my n value, it adjusts how much of length T it will fill. So, n=5, only runs for 1/5 of T and n=1, run for entire length of T. I need an nxT matrix at the end (5X1000). The problem lies in the way I setup my for loops.
I still cannot solve the error though.
%Initialize A,pi,T
N = 3; # of states
%A is transition prob matrix
A = [.99,.005,.005;.005,.990,.005;.005,.005,.990];
%pi is initial state vector
pi = [1/3,1/3,1/3];
%T is # of observations per simulation
T = 1000;
%n is # of simulations
n = 5;
%Allocate space for the state matrix
State = zeros(n,T);
Observe = zeros(n,T);
%Create dummy emission matrix, must be row stochastic
B = ones(n,T)./T;
%loop over # of simulations
for i=1:1:n
x = rand(1);
if x <= (1/3)
State(i,1) = 1;
elseif x > (1/3) && x <= (2/3)
State(i,1) = 2;
else
State(i,1) = 3;
end
if State(i,1) == 1
b = -1;
elseif State(i,1) == 2
b = 0;
else
b = 1;
end
Observe(i,1)= normrnd(b,1);
for k=2:1:T
%Possible state 1,2,3
State(k) = randsample(N, 1, true, A(State(k-1),:));
if State == 1
c = -1;
elseif State == 2
c = 0;
else
c = 1;
end
Observe(i,k)= normrnd(c,1);
end
end
State(k) = randsample(N, 1, true, A(State(k-1),:));
This line is missing index (i) in position 1 inside State(k-1). It should be:
State(i,k) = randsample(N, 1, true, A(State(i,k-1),:));

single perceptron not converging

I am programming a simple perceptron in matlab but it is not converging and I can't figure out why.
The goal is to binary classify 2D points.
%P1 Generate a dataset of two-dimensional points, and choose a random line in
%the plane as your target function f, where one side of the line maps to +1 and
%the other side to -1. Let the inputs xn 2 R2 be random points in the plane,
%and evaluate the target function f on each xn to get the corresponding output
%yn = f(xn).
clear all;
clc
clear
n = 20;
inputSize = 2; %number of inputs
dataset = generateRandom2DPointsDataset(n)';
[f , m , b] = targetFunction();
signs = classify(dataset,m,b);
weights=ones(1,2)*0.1;
threshold = 0;
fprintf('weights before:%d,%d\n',weights);
mistakes = 1;
numIterations = 0;
figure;
plotpv(dataset',(signs+1)/2);%mapping signs from -1:1 to 0:1 in order to use plotpv
hold on;
line(f(1,:),f(2,:));
pause(1)
while true
mistakes = 0;
for i = 1:n
if dataset(i,:)*weights' > threshold
result = 1;
else
result = -1;
end
error = signs(i) - result;
if error ~= 0
mistakes = mistakes + 1;
for j = 1:inputSize
weights(j) = weights(j) + error*dataset(i,j);
end
end
numIterations = numIterations + 1
end
if mistakes == 0
break
end
end
fprintf('weights after:%d,%d\n',weights);
random points and signs are fine since plotpv is working well
The code is based on that http://es.mathworks.com/matlabcentral/fileexchange/32949-a-perceptron-learns-to-perform-a-binary-nand-function?focused=5200056&tab=function.
When I pause the infinite loop, this is the status of my vairables:
I am not able to see why it is not converging.
Additional code( it is fine, just to avoid answers asking for that )
function [f,m,b] = targetFunction()
f = rand(2,2);
f(1,1) = 0;
f(1,2) = 1;
m = (f(2,2) - f(2,1));
b = f(2,1);
end
function dataset = generateRandom2DPointsDataset(n)
dataset = rand(2,n);
end
function values = classify(dataset,m,b)
for i=1:size(dataset,1)
y = m*dataset(i,1) + b;
if dataset(i,2) >= y, values(i) = 1;
else values(i) = -1;
end
end
end

How can i read and store mouse coordinates while the rest of the function does not do much, pretty much stall?

so i have a matlab function below that returns a matrix of [x y time_elapsed] coordinates from 'start' to 'target', and 'target' is reached when it is at distance of acc_length to it. the time_elapsed is to help me get the speed profile.
Currently, this works fine with sampling roughly every 0.01s and there is a 2-second pause when starting the motion from 'start'.
My question is how can i do the same thing - having the user to wait 2s once 'start' position is reached, but instead of pausing the program, how can I still read the mouse coordinates(within the 2s period) while nothing useful happens for 2s?
P.S. i want to get these coordinate to calculate the precision of user to the start.
function arr = pmove(start, target, acc_length)
uimenufcn(gcf,'WindowCommandWindow');
arr = [];
checkStart = 1;
checkEnd = 0;
while checkStart
pt = get(0,'PointerLocation');
pt = [pt(1) - 1920/2, pt(2) - 1080/2];
d = pdist( [start; pt] );
if ~checkEnd & d <= acc_length;
disp('Start moving to target after 2 seconds.')
pause(2);
pt = get(0, 'PointerLocation');
pt = [pt(1) - 1920/2, pt(2)-1080/2, 0];
arr = cat(1, arr, pt);
checkEnd = 1;
tic;
continue;
end
if checkEnd
d = pdist( [target; pt] );
t_elapsed = toc;
pt = [pt , t_elapsed];
arr = cat(1, arr, pt);
if d <= acc_length
checkStart = 0;
end
end
if ~isempty(arr)
figure(gcf)
hold on;
plot(arr(:,1), arr(:,2) );
%drawnow;
axis equal;
end
pause(0.01);
end
end
You can replace the pause(2) line with:
for i=1:200
pt2 = get(0, 'PointerLocation');
% do your calculation
pause(0.01);
end
i'm using another while-true loop and checking the time_elapsed, if it is longer than 2.1s (tolerance of 0.1s for the user) i break out of the loop. During which, i get the pointer cordinates about every 0.01s and run my calculations.
tic;
while 1
pt2 = get(0,'PointerLocation');
% calculation
time_elaps = toc;
if time_elaps > 2.1 % tolerance of 0.1s
break;
end
pause(0.01);
end

how to update axes in guide - matlab

i write a code using GUI and Mfile in MATHLAB. in my program i have a board.each time, computer put a marble and rotate the board then get a marble place and rotate direction of the board from user and After each of these things, i want it shows the result in axes1 in GUI. but it doesen't work in line 9 in the code below:
% some codes...
1. while(currentDepth < 7)
2. if(mod(currentDepth,2) ~= (plrC-1))
3. plat(currentDepth);
4. drawTable(); % show the result in axes1 --> it works
5. else
6. getMarble();
7. drawTable(); % show the result in axes1 --> it works
8. rotate();
9. drawTable(); % show the result in axes1 --> it dosen't work
10. end
11. end
% some codes...
.
function drawTable()
global board;
% some codes...
imshow(board,[0 4]);
end
do you have any idea?
it's rotate function. th board is divided into 4 parts just 1 part rotates.
function rotate()
global board;
block = 0;
vector = 'non';
while(block<1 || block>4)
block = str2double(cell2mat(inputdlg('chose a block: 1/2/3/4','board rotation')));
end
switch block
case 1
k=1; z=1;
case 2
k=1; z=4;
case 3
k=4; z=1;
case 4
k=4; z=4;
end
while(~strcmp(vector,'left') && ~strcmp(vector,'right'))
vector = questdlg('rotate left or right','Rotation','left','right','right');
end
if(strcmp(vector,'left'))
board(k:k+2,z:z+2)=rot90(board(k:k+2,z:z+2));
else
board(k:k+2,z:z+2)=rot90(board(k:k+2,z:z+2),3);
end
end
ok now here we have a simplified code. make a new GUI with an axes then run the code below from 'OpeningFnc'. you will see my problem.
function test()
currentDepth = 1;
plrC = 1;
plrO = 2;
board = zeros(6);
while(currentDepth < 40)
if(mod(currentDepth,2) == 1)
plat();
drawTable(); % show the result in axes1 --> it works
else
getMarble();
drawTable(); % show the result in axes1 --> it works
rotate();
drawTable(); % show the result in axes1 --> it dosen't work
end
currentDepth = currentDepth +1;
end
function plat()
for a=1:5000
for b=1:5000
for c=1:50
m = a + b;
end
end
end
row = 1;
column = 1;
while(board(row,column) ~= 0)
row = randi(6);
column = randi(6);
end
board(row,column) = plrC;
row = randi([1 4]);
column = randi([1 4]);
board(row:row+2,column:column+2)=rot90(board(row:row+2,column:column+2));
end
function drawTable()
board(board==0) = board(board==0)+4;
B = zeros(305);
B(:,152:154) = 3;
B(152:154,:) = 3;
for i=1:6
for j=1:6
x = (i*5)+1+(i-1)*45;
y = (j*5)+1+(j-1)*45;
B(x:x+44,y:y+44) = board(i,j);
end
end
imshow(B,[0 4]);
board(board==4) = board(board==4)*0;
end
function getMarble()
board(board==0) = board(board==0)+4;
b = zeros(305);
b(:,152:154) = 3;
b(152:154,:) = 3;
for i=1:6
for j=1:6
x = (i*5)+1+(i-1)*45;
y = (j*5)+1+(j-1)*45;
b(x:x+44,y:y+44) = board(i,j);
end
end
imshow(b,[0 4]);
i = 0;
while(i~=4)
[x,y] = ginput(1);
if(x<0 || x>305 || y<0 || y>305)
i = 0;
else
i = b(ceil(y),ceil(x));
end
end
y = ceil(y/50);
x = ceil(x/50);
board(y,x) = plrO;
end
function rotate()
block = 0;
vector = 'non';
while(block<1 || block>4)
block = str2double(cell2mat(inputdlg('chose a block: 1/2/3/4','board rotation')));
end
switch block
case 1
k=1; z=1;
case 2
k=1; z=4;
case 3
k=4; z=1;
case 4
k=4; z=4;
end
while(~strcmp(vector,'left') && ~strcmp(vector,'right'))
vector = questdlg('rotate left or right','Rotation','left','right','right');
end
if(strcmp(vector,'left'))
board(k:k+2,z:z+2)=rot90(board(k:k+2,z:z+2));
else
board(k:k+2,z:z+2)=rot90(board(k:k+2,z:z+2),3);
end
end
end
as ThP said, i have to add drawnow() function at the end of drawTable.

MATLAB: data points won't connect?

I only have about two weeks of experience with programming/Matlab, so I'm just a beginner. In my code I would like to plot mu as a function of alpha. When I display mu it shows the 10 values of mu for each value of alpha. However, when I plot the graph it gives the values of mu as seperate points. But I want the points to be connected with just one line. How can I solve this problem?
n=40; %number of months
p=0.23; %probability of success
num_of_simulations=100;
s=rng; x = rand(1,n)<p;
rng(s);
hold on;
for alpha=0.01:0.01:0.1;
for i=1:num_of_simulations
x = rand(1,n)<p;
S0=5000; %initial value
Y(1)=S0*alpha; %deposit
for k=1
if x(1,1)==1;
S(1, i)=S0+2*Y(1);
else
S(1, i)=S0-Y(1);
end
end
for k=2:n
Y(k)=S(k-1, i)*alpha;
if x(1,k)==1;
S(k, i)=S(k-1, i)+2*Y(k);
else
S(k, i)=S(k-1, i)-Y(k);
end
end
Sn(i)=S(n,i); %end value for each simulations
end
mu=mean(Sn);
disp(mu);
plot(alpha,mu);
end
The reason your points aren't connected is because you plot each point separately. If we take a different approach and take alpha = 0.01:0.01:0.1; out of the for loop definition and then change the for loop definition to for j=1:numel(alpha) we can still loop over every element of alpha. Now we need to change each use of alpha in the loop to alpha(j) so that we are referring to the current element of alpha and not every element. Following on from this we need to change mu to mu(j). What this means is that when the entire loop has finished we have all of the values of alpha and mu stored and 1 call to plot(alpha, mu) will plot the data with the points connected as in
This also enables us to remove hold on; too as we only plot once.
I've included the complete edited code here for you to see. The changes are minuscule and should make sense.
clear all
close all
n = 40; %number of months
p = 0.23; %probability of success
num_of_simulations = 100;
s = rng;
x = rand(1, n) < p;
rng(s);
alpha = 0.01:0.01:0.1;
for j = 1:numel(alpha)
for i = 1:num_of_simulations
x = rand(1, n) < p;
S0 = 5000; %initial value
Y(1) = S0*alpha(j); %deposit
for k = 1
if x(1, 1) == 1;
S(1, i) = S0 + 2*Y(1);
else
S(1, i) = S0 - Y(1);
end
end
for k = 2:n
Y(k) = S(k-1, i)*alpha(j);
if x(1, k) == 1;
S(k, i) = S(k-1, i) + 2*Y(k);
else
S(k, i) = S(k-1, i) - Y(k);
end
end
Sn(i) = S(n, i); %end value for each simulations
end
mu(j) = mean(Sn);
disp(mu(j));
end
plot(alpha, mu);