www.gusucode.com > demos工具箱matlab源码程序 > demos/fifteen.m

    function fifteen(action)
%FIFTEEN A sliding puzzle of fifteen squares and sixteen slots.
%   This example shows how to use SWITCH statements to control the flow of
%   program execution. Here, a SWITCH statement is used in conjunction
%   with a GUI to drive a puzzle program. Based on the action of the GUI,
%   the program will call itself using different inputs that switch among
%   tasks.
%
%   Solve the puzzle by sequentially lining all fifteen squares up, leaving
%   the last square empty.
%
%   Moves are made by clicking on a tile which lies in either the
%   same row or column as the open slot.

% Copyright 1984-2014 The MathWorks, Inc.

if nargin<1
   % Set up a working figure window and store it in the UserData for
   % action 'setup' to use.
   figure_h = figure;
   set(figure_h,'Units','points')
   set(figure_h,'UserData',figure_h);
   action = 'initialize';
end

% Actions to be switched on are: initialize, scramble, move, help.
switch action
   
   case 'initialize';
      % Set up the screen.
      figure_h = get(gcf,'UserData');
      
      set(figure_h,...
         'Color',[0.4 0.4 0.4],...
         'Menubar','none',...
         'Name',getString(message('MATLAB:demos:fifteen:TitleTheSlidingPuzzle')),...
         'NumberTitle','off',...
         'Position',[200 200 310 255],...
         'Resize','off');
      axis off
      
      % Create status bar.
      % Set the tag to 'click' mode (set to 'winner' mode is user has won).
      uicontrol(figure_h,...
         'BackgroundColor',[0.4 0.4 0.4],...
         'ForegroundColor',[1 1 1], ...
         'HorizontalAlignment','center',...
         'FontSize',18,...
         'Units','points',...
         'Position',[15 10 215 25],...
         'String',getString(message('MATLAB:demos:fifteen:LabelClickOnATileToSlideIt')),...
         'Style','text',...
         'Tag','click');
      
      % Create utility buttons (new game, help, close).
      % New game.
      uicontrol(figure_h,...
         'Callback','fifteen scramble',...
         'FontSize',12, ...
         'Units','points',...
         'Position',[235 175 65 30],...
         'String',getString(message('MATLAB:demos:fifteen:LabelNewGame')),...
         'Style','pushbutton');
      
      % Help.
      uicontrol(figure_h,...
         'Callback','fifteen help',...
         'Fontsize',12, ...
         'Units','points',...
         'Position',[235 110 65 30],...
         'String',getString(message('MATLAB:demos:shared:LabelHelp')),...
         'Style','pushbutton');
      
      % Close.
      uicontrol(figure_h,...
         'Callback','close(gcf)',...
         'Fontsize',12, ...
         'Units','points',...
         'Position',[235 45 65 30],...
         'String',getString(message('MATLAB:demos:shared:LabelClose')),...
         'Style','pushbutton');
      
      % Set up the game board.
      irows = 1;
      for counter = 1:16
         jcols = rem(counter,4);
         if jcols == 0
            jcols = 4;
         end
         position = [40*jcols 205-40*irows 40 40];
         index = (irows-1)*4+jcols;
         if jcols == 4
            irows = irows+1;
         end
         board.squares(index) = uicontrol(figure_h,...
            'FontSize',18,...
            'FontWeight','bold',...
            'Units','points',...
            'Position',position,...
            'Style','pushbutton',...
            'Tag',num2str(index));
      end
      
      % Save all the handles in the figure windows UserData (over-writing the
      % handle of the figure window since we do not need it anymore).
      set(figure_h,'userdata',board);
      fifteen('scramble')
      
   case 'scramble'
      score_board = randperm(16);
      % Wherever the location of '16' is is where we will start our open slot.
      num_16 = find(score_board == 16);
      board = get(gcf,'UserData');
      set(board.squares,...
         'BackgroundColor',[0.701961 0.701961 0.701961],...
         'Enable','on',...
         'Visible','on')
      set(board.squares,{'string'},num2cell(score_board)')
      
      % Change the value 16 (set it to black, disable it, and set the
      % string to empty; the color change will not take effect on the PC) and
      % turn the visibility of the board on.
      set(board.squares(num_16),...
         'BackgroundColor','black',...
         'Enable','off',...
         'String',' ');
      % Keep track of where the current free square is by storing it in
      % the board struct. We also want to keep track of the 'score'; this
      % way we know when we have won (i.e., when score(1:15) == 1:15).
      [board.free_square.x, board.free_square.y] = LocalGetXY(num_16);
      board.score = score_board;
      set(board.squares,...
         'Callback','fifteen move',...
         'Visible','on',...
         'UserData',board)
      
      % Since we could be restarting an old game (i.e., winner) we need to
      % check whether the 'winner' banner is up and, if so, change it.
      old_handle = findobj(gcf,'Tag','winner');
      if isempty(old_handle) == 0
         % We are in 'winner' mode; set back to 'click' mode.
         set(old_handle,...
            'String',getString(message('MATLAB:demos:fifteen:LabelClickOnATileToSlideIt')),...
            'Tag','click');
      end
      
      % Hide the object's handle from all other functions called at
      % the command line.
      set(gcf,'HandleVisibility','callback');
      
   case 'move'
      % Check that the move is legal.
      square_tag = str2double(get(gcbo,'Tag'));
      % Determine the x and y coordinates of the selected tile.
      [current.x, current.y] = LocalGetXY(square_tag);
      data = get(gcbo,'UserData');
      % Determine the x and y coordinates of the open tile.
      open.x = data.free_square.x;
      open.y = data.free_square.y;
      open_square = (open.x-1)*4+open.y;
      inc_by = 0;
      if current.x == open.x
         % The selected tile is on the same row as the open tile.
         loop = abs(current.y-open.y);  % 'loop' tells us how many tiles away we are
         inc_by = open.y<current.y;     % We need to know if we are moving right -> left or left -> right
         if inc_by == 0
            inc_by = -1;                 % We are moving right -> left
         end
      elseif current.y == open.y
         % The selected tile is in the same column as the open tile.
         loop = abs(current.x-open.x);  % 'loop' tells us how many tiles away we are
         direction = open.x<current.x;  % We need to know if we are moving up or moving down
         if direction == 1
            inc_by = 4;                  % We are moving up.
         else
            inc_by = -4;                 % We are moving down.
         end
      end
      
      if inc_by ~= 0
         % There was a legal move.
         square_handles = data.squares;
         score_board = data.score;
         set(square_handles(open_square),...
            'BackgroundColor',[0.701961 0.701961 0.701961],...
            'Enable','on');
         to_square = open_square;
         
         % Make the move.
         for index = 1:loop
            % Now slide over all the tiles between the selected tile and the
            % open tile.
            from_square = to_square+inc_by;
            from_value = get(square_handles(from_square),'String');
            set(square_handles(to_square),...
               'String',from_value);
            score_board(to_square) = str2double(from_value);
            to_square = from_square;
         end
         
         data.score = score_board;
         % Set up new free square.
         set(gcbo,...
            'BackgroundColor','black',...
            'Enable','off',...
            'String',' ');
         
         % Update the free square x and y coordinates.
         data.free_square.x = current.x;
         data.free_square.y = current.y;
         set(square_handles,'userdata',data);
         
         % Check for winner.
         if data.score(1:15) == 1:15
            % Change from 'click' mode to 'winner' mode.
            old_handle = findobj(gcf,'Tag','click');
            set(old_handle,...
               'String',getString(message('MATLAB:demos:fifteen:LabelWINNER')),...
               'Tag','winner');
         end
         
      end   % There was a legal move.
      
   case 'help'
      doc(mfilename);
      
   otherwise
      disp(getString(message('MATLAB:demos:fifteen:WarningUnknownAction',mfilename,action)))
      
end

% Calculate the xrow and ycol< of the tile.
function [x,y] = LocalGetXY(tile)

x = ceil(tile/4);
y = rem(tile,4);
if y == 0
   y = 4;
end