Function inside MATLAB Gui code not outputing variable

I am writing a GUI in matlab programmatically. I have all the code that I need for the window and the push buttons in the function for the GUI. For one of my pushbuttons, I have a function that references another function for the output of that function to be used in this function. However, the function that it needs to get the variable from is not outputting any data. the code works for that function if I try to run it outside of the GUI script meaning that I also have the function saved as a separate .M file and when I try to get it to output something alone from the GUI, I get an output. I'm hoping that someone can tell me what I'm maybe doing wrong? The following is an example of what I'm currently doing.
function easygame(~,~)
ir=1:9;
ic=reshape(ir,3,3)';
numbers=SudokuGame(ir,ic);
to_be_removed=25;
numbers_removed=removed(numbers,to_be_removed);
displayed(numbers_removed); %display the generated puzzle on the board for play by the user
userlock(numbers_removed); %locks the display from being altered except in the blank (removed) spaces
end
...more code
function numbers=SudokuGame(ir,ic)
numbers=1+mod(bsxfun(@plus,ir,ic(:)),9);
%step 1
p=randperm(9,9);
%step 2 (rows)
r=bsxfun(@plus,randperm(3,3),3*(randperm(3,3)-1)');
%step 3 (cols)
c=bsxfun(@plus,randperm(3,3),3*(randperm(3,3)-1)');
%permute away
numbers=p(numbers);
numbers=numbers(r,:);
numbers=numbers(:,c);
%step 4 (transpose at random)
if randi(2)==1;
numbers=numbers';
end
end
SudokuGame is supposed to output a number array that will be used in the easygame function but it is not for some reason. Because I also have SudokuGame saved as a separate function file, when I say numbers=SudokuGame(ir,ic) in the Matlab command window it runs fine. I also get the same error that numbers is not being generated if I try to reference the outside Matlab function in my GUI code instead of having it inside my GUI function code.

6 Kommentare

Morgan - are you observing any errors when you try to call SudokuGame from within your GUI? If I use your above example and call easygame, then the call to SudokuGame does return something. You may need to post an example that exhibits the behaviour that you are describing especially that of the pushbutton. Can you post that code instead?
Hi Geoff, yes what I was saying is that when I use SudokuGame outside of my GUI, I do get a returned array as a response of the function which can then be used in my easygame function. However, when I use easygame to call SudokuGame from within my GUI, and both functions are within my GUI function code, I get an error saying that the array that SudokuGame is supposed to output for use in easygame doesnt't appear so the function doesn't work. As for when you sak if I can post an example that exhibits the behavior I am describing especially the pushbutton, what exactly do you mean? Do you mean actually post the code easygame that calls on the SudokuGame code? or something else. The way I have the pushbutton coded is as follows:
uicontrol('Parent',display,...
'Style','pushbutton',...
'String','Easy',...
'Units','normalized',...
'Position',[0.8,0.92,0.15,0.06],...
'Callback',@easygame);
the function for easygame is as follows:
function easygame(~,~)
ir=1:9;
ic=reshape(ir,3,3)';
numbers=SudokuGame(ir,ic);
to_be_removed=25;
numbers_removed=removed(numbers,to_be_removed);
displayed(numbers_removed); %display the generated puzzle on the board for play by the user
userlock(numbers_removed); %locks the display from being altered except in the blank (removed) spaces
end
I had originally had it such that SudokuGame had no inputs and ir and ic were both in the function but I have since changed it to how you see it above to try and figure out if this was part of my problem. The code for SudokuGame is as follows:
function numbers=SudokuGame(ir,ic)
numbers=1+mod(bsxfun(@plus,ir,ic(:)),9);
%step 1
p=randperm(9,9);
%step 2 (rows)
r=bsxfun(@plus,randperm(3,3),3*(randperm(3,3)-1)');
%step 3 (cols)
c=bsxfun(@plus,randperm(3,3),3*(randperm(3,3)-1)');
%permute away
numbers=p(numbers);
numbers=numbers(r,:);
numbers=numbers(:,c);
%step 4 (transpose at random)
if randi(2)==1;
numbers=numbers';
end
end
Hopefully I am understanding you properly but if not I would be more than willing to answer whatever questions you may have.
Morgan,
I think we need to see the text of the error you are receiving. You can also attach the actual .m files to the question to make our debugging easier.
When I copy-paste your code and wrap it in a function to test, SudokuGame() returns an array to the callback function. See my attached .m file.
I commented out the displayed() and userlock() calls since we don't have that code available. And I made a dummy version of removed() to make sure that numbers can be passed to other functions.
I'm afraid without seeing your actual error (and probably your code) it's going to be tough to go any farther.
My intuition is that you are running into either a variable scope issue or possibly an overloaded function name issue.
Hi Nick, as I have already told you twice now, the error that I am getting out when I try to run the GUI is that it says "undefined function or variable 'number'". I have attached the code so that you can see what I'm doing for the rest of it. Although the error is definitely in something between the easygame and SudokuGame functions as far as I can tell.
Hi, Morgan,
Not trying to beat a dead horse, but in the future we need all the red error text, not just a small part snipped out of it. This means line numbers, actual lines of code that generated the error, traceback to prior functions, etc. - everything that is in red color.
See my answer below, it turns out the error is not where you described :)
Morgan, I second what Nick says. We need ALL THE RED TEXT not just a small part snipped from it. We also would love it if you would read this link. Many people (like me for instance) won't even download and try your code until we see the entire error message so we know what line it crashed on. Come on, make it easy for us to help you, not hard. For example I see Nick downloaded it but he said "it turns out the error is not where you described", so that was kind of a waste of some of his time. He'd need to fix that before he could even get to the error you asked about.

Melden Sie sich an, um zu kommentieren.

 Akzeptierte Antwort

Nick Counts
Nick Counts am 19 Nov. 2016
Bearbeitet: Nick Counts am 19 Nov. 2016
Morgan,
Sorry if it seemed like we were asking you for something you already gave us, but the entirety of the error message is important to understand what's going on. In any case, this is what we were after:
Note that this error actually shows that the issue is in removed() and not in easygame().
Now that I see the code, it looks like it is a variable scope issue. Let me explain.
On line 114 you create a variable called numbers and assign it a value of what SudokuGame() returns. NOTE: this works. Now line 114 is inside the easygame() function block, so it is only available inside that function. This is referred to as variable scope (Matlab calls this workspaces).
On line 116, you create a variable numbers_removed and assign its value to what removed() returns. Here you have correctly passed the value of numbers to the removed() function. As I said above, the variable numbers is not available anywhere in your code except the easygame() function.
Your error actually happens on line 128, inside the removed() function:
function game=removed(numbers_removed,to_be_removed);
removed=0;
while removed ~= to_be_removed;
for r=randi(9);
for c=randi(9);
if numbers(r,c) > 0;
numbers(r,c)=0;
removed=removed+1;
else
numbers(r,c)=numbers(r,c);
end
end
end
end
end
By your function definition, the first argument is assigned to a variable named numbers_removed, and the second to a variable named to_be_removed. You also define variables removed, r, and c in the function code. Everything is going great until you get to line 128, where you reference a variable called numbers. There is no variable with that name in the removed() workspace, so Matlab throws up its hands and gives up.
Note you have also defined your function removed() such that it will return a variable named game but you never create a variable called game inside the function.
These same errors are repeated in your other function displayed().
There were a few other minor bugs, like setting the 'BackGround Color' property instead of 'BackGroundColor'. I have attached a working version of your code - everything works except the solve button. I had to leave you a little fun ;)
Hopefully this made sense. Let us know if you have any more questions about where your variables are available. These links should be a good reference to look over:
Good luck!

8 Kommentare

Hi Nick, Thank you for your response. I am just getting a chance to take a look at it now. I am confused a little now. I made the changes you talked about and I even put numbers=easygame() for my function so that numbers would I would think be spit out as a variable for use in the check or solve functions but when I went to use the check button, I got the same error that I was getting before saying that there was an undefined function or variable 'numbers'
Nick Counts
Nick Counts am 19 Nov. 2016
Bearbeitet: Nick Counts am 19 Nov. 2016
Did the SudokuGame_gui.m file that I attached work for you without errors?
Also, posting the complete text of the error messages will make this much, much easier. :)
I have attached my code so you can see what I am getting with the changes I made. To answer your question, no the check pushbutton code doesn't work even with making numbers an output of the easygame function. Not sure what is going on this time.
Undefined function or variable 'numbers'.
Error in SudokuGame_guiTest/check (line 189) index=find(user_inputs~=numbers);
Error while evaluating UIControl Callback
Nick Counts
Nick Counts am 20 Nov. 2016
Bearbeitet: Nick Counts am 20 Nov. 2016
There seems to be a fundamental misunderstanding of function definitions and variable scope. Let's start with variable scope:
in your function:
function check(~,~)
index=find(user_inputs~=numbers);
user_inputs(index)=set(Matrix,'BackgroundColor','r');
end
This function doesn't know any variables but what you pass to it as an argument or what you define inside it.
Here you define index as the output of an expression using the user_inputs() function (good so far) and a variable or function called numbers (Matlab doesn't know which you mean). See, since numbers hasn't been defined inside your function check(), Matlab looks for a function called numbers. But it can't find that either, so it gives up and throws this error:
Now you are going to say "But what about Matrix? That isn't defined inside check() and it seems to work just fine!"
Yes - this is because of the shared variable scope of nested functions. Let's have a quick example:
function mainFunction()
sharedVariable = 1;
nestedFunction();
notNestedFunction(sharedVariable);
nestedFunction();
function nestedFunction()
disp('Inside nestedFunction');
disp(sharedVariable);
end
end
function notNestedFunction(sharedVariable)
disp('Inside notNestedFunction');
disp(sharedVariable)
sharedVariable = 2;
disp(sharedVariable);
end
When you run this code (copy paste it and try it) you get the following:
>> mainFunction
Inside nestedFunction
1
Inside notNestedFunction
1
2
Inside nestedFunction
1
What's going on? Why doesn't notNestedFunction() change the value of sharedVariable?
Notice the 3 function definitions:
  1. mainFunction() - This defines the entire mainFunction()
  2. nestedFunction() - Note that this is defined inside the mainFunction() block.
  3. notNestedFunction() - Note that this is defined outside the mainFunction() block
Any variable defined inside the mainFunction() block is available to nestedFunction() without having to pass it as an argument. nestedFunction() can access any variables defined by it's parent (or enclosing) function.
When we call notNestedFunction(sharedVariable) from inside mainFunction() we are passing a copy of sharedVariable to notNestedFunction() as an argument.
function notNestedFunction(sharedVariable)
disp('Inside notNestedFunction');
disp(sharedVariable)
sharedVariable = 2;
disp(sharedVariable);
end
The function definition for notNestedFunction() above means that the first argument passed to the function will be placed in a variable called sharedVariable. This particular variable is only accessible inside notNestedFunction().
This is why you can change the value of sharedVariable inside notNestedFunction() without affecting the value of sharedVariable inside mainFunction()
Also, a function definition like:
myVariable = function myFunction
does not define myVariable! It means that myFunction() will return any variable named myVariable that is defined inside myFunction()
Ok, so what does this mean for you? Since you are already using nested functions and variables, we might as well continue that path. By defining numbers inside the SudokuGame_gui function block, it will be available to all nested functions.
Note: there are other means of sharing variables between functions within a program and they all have their own set of advantages. Nested variable scope is not always the right answer and sometimes it can lead to very hard to trace bugs. Check the documentation for:
getappdata()
setappdata()
% Use this to allow a variable to be stored and retrieved across
% multiple functions without explicitely passing the variable.
setappdata(gcf, 'numbers', numbers);
% Use this to retrieve data you stored in SudokuGame()
numbers = getappdata(gcf, 'numbers');
I have attached a fixed version of your game file that defines numbers as a shared variable and fixes your function definitions. I also renamed a few variable for clarity and to avoid overloading the names. I tried to comment the file, so hopefully you can see how this works.
Good luck!
Thank you for all your help Nick! I ended up needing to make a few changes to the test code to make every aspect of it work but it all works now. Thanks again and I'll remember for the future the things that are helpful when it comes to asking for help with debugging.
Glad you got it figured out, Morgan! These issues can be confusing when you first encounter them, but stick with it and it'll become second nature
Cheers
Hi Nick, I have one other thing that I just thought of. If I want to include a hint button that will pick a random row and column and if there is no value currently in that position or the value doesn't equal the solution value for that cell, it will display the correct value for that cell. The function will output 1 correct hint for every press of the hint button. Is there a way to do this using the getCurrentGameBoard function we created earlier or is there even a simpler way to do it? Just looking for suggestions.

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (0)

Kategorien

Mehr zu Sudoku finden Sie in Hilfe-Center und File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by