Tic Tac Toe with a win and taken check - Matlab

2019-09-13 01:21发布

问题:

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

回答1:

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'.