function blockBusterGUI(board,moves)
% BLOCKBUSTERGUI Play BLOCKBUSTER.
%
% Use left-mouse button to swap blocks by dragging them and the right-mouse
% button to pop a block and its same color neighbors.
%
% BLOCKBUSTERGUI with no inputs generates a random board.
% BLOCKBUSTERGUI(PROBLEM) PROBLEM is a struct with 'board' and 'nmoves'.
% BLOCKBUSTERGUI(BOARD,NMOVES) BOARD is a matrix and NMOVES a scalar.
% BLOCKBUSTERGUI([ROWS,COLUMNS,COLORS],NMOVES) All inputs are scalars.
% Copyright 2006 The MathWorks, Inc.
% defaults and input args
if nargin == 0; moves = 50; board = [25,15,4]; end % [rows,columns,colors]
if isstruct(board)
moves = board.nmoves;
board = board.board;
end
if numel(board)==3 %set a random board
rows = board(1); columns = board(2); colors = board(3);
S = struct('movesCtr',moves,'A',ceil(colors*rand(rows,columns)));
else
[rows,columns] = size(board); colors = max(board(:));
S = struct('movesCtr',moves,'A',board);
end
% initilize GUI
hf = figure('menubar','none','name','Blockbuster','NumberTitle','off');
set(hf,'WindowButtonDownFcn',@myClick,'WindowButtonUpFcn',@myRelease);
ha = axes('NextPlot','add','box','on','ydir','reverse');
hi = image(S.A+1);
ht = text(columns+2,0,{sprintf('Score = %d',sum(S.A(:)));...
sprintf('Moves = %d',S.movesCtr)},'vertical','top','fontsize',20);
hbpatch = patch([1 1],[1 1],1,'CdataMapping','direct');
hpatch = patch([1 1],[1 1],1,'CdataMapping','direct');
uicontrol('String','Undo','Callback',@myUndo);
colormap([0 0 0;jet(colors)])
axis equal ; axis off
rp = [0;0]; % used later to save the reference block
N = false(rows,columns); % used later to find neighbors of a block
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function myRelease(h,e)
buttonType = get(hf,'SelectionType');
set(hf,'WindowButtonMotionFcn',{});
set([hpatch,hbpatch],'visible','off')
cp = round(get(ha,'CurrentPoint').*[1 0 0;0 1 0])*[1 1 0]';
if S.movesCtr>0 && all(cp>0) && all(cp<=[columns;rows]) && S.A(cp(2),cp(1))
if strcmp(buttonType,'normal') && sum(abs(cp-rp))==1 %swapper
S.undo = S;
S.A([cp(2),rp(2)],[cp(1),rp(1)]) = S.A([rp(2),cp(2)],[rp(1),cp(1)]);
S.movesCtr = S.movesCtr - 1;
updateBoard
elseif strcmp(buttonType,'alt') %buster
N(:) = false;
findNeighbors(cp(2),cp(1),S.A(cp(2),cp(1)));
if sum(N(:))>1
S.undo = S;
for k = 1:columns
S.A(:,k) = [zeros(sum(N(:,k)),1);S.A(~N(:,k),k)];
end
S.score = sum(S.A(:));
S.movesCtr = S.movesCtr - 1;
updateBoard
end
end % of "swapper" or "buster"
end % of "it's a legal move"
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function myClick(h,e)
buttonType = get(hf,'SelectionType');
cpf = (get(ha,'CurrentPoint').*[1 0 0;0 1 0])*[1 1 0]';
cp = round(cpf);
if S.movesCtr>0 && all(cp>0) && all(cp<=[columns;rows]) && S.A(cp(2),cp(1))
if strcmp(buttonType,'normal') %start dragging
rp = cp;
cpf = min(max(cpf,[1;1]),[columns;rows]);
set(hbpatch,'XData',cp(1)-[1 -1 -1 1 1]/2,'YData',cp(2)-[1 1 -1 -1 1]/2,'visible','on')
set(hpatch,'XData',cpf(1)-[1 -1 -1 1 1]/2,'YData',cpf(2)-[1 1 -1 -1 1]/2,'Cdata',S.A(cp(2),cp(1))+1,'visible','on')
set(hf,'WindowButtonMotionFcn',@myMotion);
end
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function myMotion(h,e)
cpf = min(max(get(ha,'CurrentPoint').*[1 0 0;0 1 0]*[1 1 0]',1),[columns;rows]);
set(hpatch,'XData',cpf(1)-[1 -1 -1 1 1]/2,'YData',cpf(2)-[1 1 -1 -1 1]/2)
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function myUndo(h,e)
if isfield(S,'undo')
S = S.undo;
updateBoard
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function updateBoard
set(hi,'Cdata',S.A+1)
set(ht,'string',{sprintf('Score = %d',sum(S.A(:)));sprintf('Moves = %d',S.movesCtr)})
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function findNeighbors(i,j,c)
if ~N(i,j);
N(i,j) = true;
if i>1 && S.A(i-1,j)==c; findNeighbors(i-1,j,c), end
if j<columns && S.A(i,j+1)==c; findNeighbors(i,j+1,c), end
if i<rows && S.A(i+1,j)==c; findNeighbors(i+1,j,c), end
if j>1 && S.A(i,j-1)==c; findNeighbors(i,j-1,c), end
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
end % of blockBusterGUI and nested functions