22
MATLAB Minesweep er Development of a MATLAB GUI

MATLAB Minesweeper Development of a MATLAB GUI. Start with an empty function function MineSweeper_GUI() end % of MineSweeper() While not strictly required,

Embed Size (px)

Citation preview

MATLAB Minesweeper

Development of a MATLAB GUI

Start with an empty function

function MineSweeper_GUI()

end % of MineSweeper()

While not strictly required, a function that creates the GUI provides flexibility for your program. If you have multiple frames in your interface, functions permit separation of code by allowing a main program to instantiate the frames independently.

Create a basic figurefunction MineSweeper_GUI()

fh = figure('Position', [400, 400, 250, 300]);

% Adjust appearanceset(fh, 'Resize', 'off');set(fh, 'MenuBar', 'none');set(fh, 'NumberTitle', 'off');set(fh, 'Name', 'MATLAB MineSweeper');

end % of MineSweeper_GUI()

These are common attributes, although not every GUI will necessarily set them.

Provide the controls% Text will be provided and covered up by a button. The button % will disappear when clicked.

% Control to hold text (to display after button is pushed)tbh = uicontrol('Units', 'normalized', 'Style', 'text');set(tbh, 'String', '8', 'FontSize', 16);set(tbh, 'Position', [0, 0, 0.1, 0.1]);

Now that we have one box, let’s make the code repeat it.

Provide the rest of textboxes

c = 1;for xpos = 1:9

for ypos = 1:9 % Control to hold text (to display after button is pushed) tb(c) = uicontrol('Style', 'text', 'Units', 'normalized'); set(tb(c), 'String', '8', 'FontSize', 16); set(tb(c), 'Position', [0.11*(xpos-1),0.11*(ypos-1),0.1,0.1]); c = c+1;

end % of for yposend % of for xpos

(We assume a 9x9 grid – this can become a feature selected by the user) These all show the number ‘8’. We will change that after we have a visually complete GUI – then we can make it fully functional.

Provide pushbuttons to cover% Cover with buttonsc = 1;for xpos = 1:9 for ypos = 1:9 % These are drawn on the figure, not any panel u(c)=uicontrol('Style', 'pushbutton', 'Units', 'normalized'); set(u(c), 'Position', [0.11*(xpos-1),0.11*(ypos-1), 0.1, 0.1]); c = c + 1; endend

We now have a visually-complete game. Now we can focus on the functionality.

Add button functionality

When actions are to be performed as a result of clicking on a control, MATLAB places a call to a “callback function”. It is the responsibility of the programmer to provide that function, and to tell MATLAB how to call that function.

The syntax for this is a little different from typical function usage.

Defining a callback function

To define a callback function, simply make a function in the same file as the GUI frame. The name can be any legal function name. The first two parameters of the function are required by MATLAB – you can add any others you wish afterwards:

function my_callback(H, E, a, b, c)...

end % of my_callback()

Our callback function% Callback (cb) for PushButtons (pb)function cb_pb(H, E, bh, th, c, sz)

% What string is "under" the button that was pressed?s = get(th(c), 'String'); if strcmp(s, '9') hit_mine(c, sz, bh, th); elseif length(s)==0 || strcmp(s, ' ') hit_empty(c, sz, bh, th); else delete(bh(c)); uicontrol(th(c)); % set focus to current text end % of ifend % of cb_pb

Tell MATLAB to use the callback function

% Because clicking a button can mean deleting other buttons in this% program, we want to send the entire array of button handles and text% handles to the callback functions. That is why this loop is AFTER % the original creation loop - if we had tried to set the callbacks in % the creation loop, the early buttons would know nothing about buttons % defined later.

for c = 1:n^2 % Handle a left-click set(u(c), 'callback', {@cb_pb, u, th, cnt, n});end % of for c

function MineSweeper_demo()clc;n=9;

fh = figure('Position', [400, 400, 250, 300]); % Adjust appearanceset(fh, 'Resize', 'off');set(fh, 'MenuBar', 'none');set(fh, 'NumberTitle', 'off');set(fh, 'Name', 'MATLAB MineSweeper'); c = 1;for xpos = 1:9 for ypos = 1:9 % Control to hold text (to display after button is pushed) tb(c) = uicontrol('Style', 'text', 'Units', 'normalized'); set(tb(c), 'String', '8', 'FontSize', 16); set(tb(c), 'Position', [0.11*(xpos-1),0.11*(ypos-1),0.1,0.1]); c = c+1; end % of for yposend % of for xpos % Cover with buttonsc = 1;for xpos = 1:9 for ypos = 1:9 % These are drawn on the figure, not any panel u(c)=uicontrol('Style', 'pushbutton', 'Units', 'normalized'); set(u(c), 'Position', [0.11*(xpos-1),0.11*(ypos-1), 0.1, 0.1]); c = c + 1; endend

% Attach callback function for c = 1:n^2 % Handle a left-click set(u(c), 'callback', {@cb_pb, u, tb, c, n});end % of for c end % of MineSweeper_demo()

% Callback functionfunction cb_pb(H, E, bh, th, c, sz) % What string is "under" the button?s = get(th(c), 'String'); if strcmp(s, '9') hit_mine(c, sz, bh, th); elseif length(s)==0 || strcmp(s, ' ') hit_empty(c, sz, bh, th); else delete(bh(c)); uicontrol(th(c)); % set focus to current text end end % of cb_pb()

Finishing off the code

At this point, most of the GUI code is complete. We now provide code that will perform the tasks desired upon certain events.

If a mine is beneath a clicked button:hit_mine(c, sz, bh, th);

If a space is beneath a clicked button:hit_empty(c, sz, bh, th);

hit_mine()% What to do if a mine is hitfunction hit_mine(i, sz, bh, th) % Get rid of ALL buttons and show the minesfor r=1:sz for c=1:sz

% Since using vectors to hold handles v = (c-1)*sz + r; % Is there still a button here? if ishandle(bh(v)) % What is the textbox string? ts = get(th(v), 'String'); % Change textbox to show an image of a mine exploding if strcmp(ts, '9') mineimg = imread('mine10.jpg'); set(bh(v), 'cdata', mineimg); else % Get rid of the button delete(bh(v)); end end end % of for c end % of for r

Add a grid for testing hit_mine()

function MineSweeper_demo()

% -----------------------------% Testing valuesn = 9;for i=1:n^2 M(i) = num2str(randi(9,1)); r = randi(2)-1; if r M(i) = ' '; endend% ------------------------------

And we will change this line:set(tb(c), 'String', '8', 'FontSize', 16);

To display the testing values:set(tb(c), 'String', num2str(M(c)), 'FontSize', 16);

After adding the test values

With the mine images

hit_empty()

function hit_empty(pos, sz, bh, th) % Find all of the surrounding empties and remove the buttonsrecursive_remove(pos, pos, sz, bh, th, 1); end % of hit_empty()

(see next slide)

recursive_remove()% Remove all buttons over empty strings and over numbers that touch one of% those empty strings (but don't remove over mines)function recursive_remove(from, to, sz, bh, th, level)

if ~(to<=0 || to>sz^2 ||(mod(from, sz)==1 && mod(to, sz)==0) ||(mod(from, sz)==0 && mod(to, sz)==1) to_s = get(th(to), 'String'); from_s = get(th(from), 'String'); % Empty or contains a number (but not a mine) if strcmp(to_s, ' ') || (~strcmp(to_s, ' ') && str2num(to_s)>0 && str2num(to_s)<9) % Does the button still exist? if ishandle(bh(to)) % Remove the button

delete(bh(to)); % If it's empty, recurse to check the surrounding buttons if strcmp(to_s, ' ') level = level + 1;

recursive_remove(to, to-sz-1, sz, bh, th, level); recursive_remove(to, to-sz, sz, bh, th, level);

recursive_remove(to, to-sz+1, sz, bh, th, level); recursive_remove(to, to-1, sz, bh, th, level); recursive_remove(to, to+1, sz, bh, th, level); recursive_remove(to, to+sz-1, sz, bh, th, level); recursive_remove(to, to+sz, sz, bh, th, level); recursive_remove(to, to+sz+1, sz, bh, th, level);

level = level - 1; end end % of if end % of else end % of recursive_remove()

Last Details

One other property of the game (other than scoring) involves allowing the user to mark a location as “containing a mine” or “might contain a mine”.

We will do this by allowing the user to right-click on a button and placing “?” for “might be a mine”, or “!” for “containing a mine”.

Right-click Callbacks

A separate callback function must be placed for handling “alternative clicks”. Note the added line:

for c = 1:n^2

% Handle a left-click set(u(c), 'callback', {@cb_pb, u, tb, c, n}); % Handle a right-click set(u(cnt), 'ButtonDownFcn', {@right_click, c, u}); end % of for c

right_click()% This function is executed when a button is right-clickedfunction right_click(h, e, pos, bh) % The button we pressed is in a figure. Only the figure knows the type of% click that was made:fh = ancestor(h, 'figure')clickType = get(fh, 'SelectionType') % 'Alt' is a right-click%% This will allow using the right-click to cycle through the optionsbs = get(h, 'String');if strcmp(clickType, 'alt') if strcmp(bs, '!') % Option 1: Clear the button label set(bh(pos), 'String', ''); end if strcmp(bs, '') % Option 2: Put a query (?) on the button - user isn't sure set(bh(pos), 'String', '?'); set(bh(pos), 'FontSize', 16, 'ForegroundColor', [1, 0, 0]); end if strcmp(bs, '?') % Option 3 : Put a bang (!) on the button - user thinks this is a mine set(bh(pos), 'String', '!'); set(bh(pos), 'FontSize', 16, 'ForegroundColor', [1, 0, 0]); end end % of if end % of right_click()

Source Code

Function:

http://kindy.egr115.com/MineSweeper.zip