function tetris(action) % TETRIS for MATLAB % % To begin, simply type: tetris % % Only one game can be run at a time. % UN-PAUSE (I know that's not a word) the game by hitting RETURN % in the Matlab command window. % % Please feel free to modify, improve, rewrite, cleanup the code etc. % Written and tested on a SUN running Matlab 4.2c, but should work with % Matlab 4.0, if not you can debug/modify it. % This is FREEWARE, enjoy! - Peace & Love % % Author: Maurice Smith, 1/19/95 (msmith@bme.jhu.edu) global CENTER_X CENTER_Y POS STUCK USED_SPACE H; global WIDTH1 HEIGHT1 LEVEL TIME_DELAY SQ_X SQ_Y; global H_SLIDER_LEVEL H_SLIDER_WIDTH H_SLIDER_HEIGHT; global H_TEXT_LEVEL H_TEXT_WIDTH H_TEXT_HEIGHT H_TEXT_SCORE; global START_HANDLE STOP_HANDLE STOP_GAME EXIT_HANDLE; global H_A H_B BOX H_LINE MIN_DELAY MAX_DELAY; if nargin < 1, action = 'initialize'; end; if strcmp(action,'initialize'), default_width = 10; % default width of tetris play-field default_height = 25; % default hieght of tetris play-field default_level = 5; % default skill level default_box = 1; % default play field outline (on=1, off=0) WIDTH1 = default_width; HEIGHT1 = default_height; LEVEL = default_level; BOX = default_box; MIN_DELAY = 0.1; % delay corresponding to skill level 9 MAX_DELAY = 1; % delay corresponding to skill level 0 TIME_DELAY = MAX_DELAY*exp((LEVEL/9)*log(MIN_DELAY/MAX_DELAY)); fig=figure( ... 'Name','Tetris for Matlab', 'NumberTitle','off', ... 'Visible','off', 'BackingStore','off'); SQ_X = [0 -1 -1 0]'; % vertex coordinates of unit square (for "patch" command) SQ_Y = [0 0 -1 -1]'; on = 'set(go_handle,''back'',''cyan''), '; off = 'set(go_handle,''back'',''default''), '; figure(fig); H_A = axes( ... 'Units','normalized', 'Position', [.1 .18 .4 .8], ... 'Visible','off', 'DrawMode','fast', ... 'NextPlot','replace', 'XLim',[1 WIDTH1+1],'YLim',[0 HEIGHT1]); H_B = axes( ... 'Units','normalized', 'Position', [.1 .18 .4 .8],... 'Visible','off', 'DrawMode','fast', ... 'NextPlot','replace', 'XLim',[1 WIDTH1+1],'YLim',[0 HEIGHT1]); if BOX == 1, % draw outline box initially BOX = ~BOX; tetris('box'); end pause_handle = uicontrol('units','normalized',... 'position', [.7 .04 .1 .05],'string','pause', ... 'callback','disp(''press RETURN to continue''); pause;', ... 'interruptible','no'); box_handle = uicontrol('units','normalized',... 'position', [.7 .15 .1 .05],'string','box', ... 'callback','tetris(''box'');', ... 'interruptible','yes'); STOP_HANDLE = uicontrol('units','normalized',... 'position', [.55 .04 .1 .05],'string','stop', ... 'callback','tetris(''stop'')', ... 'interruptible','yes','visible','off'); EXIT_HANDLE = uicontrol('units','normalized',... 'position', [.85 .04 .1 .05],'string','exit', ... 'callback','delete(gcf)', ... 'interruptible','no'); START_HANDLE = uicontrol('units','normalized',... 'position', [.55 .04 .1 .05],'string','start', ... 'callback','tetris(''start'')', ... 'interruptible','yes','visible','on'); left_handle = uicontrol('units','normalized',... 'position', [.18 .07 .1 .05 ],'string','<---', ... 'callback','tetris(''left'')', ... 'interruptible','yes'); right_handle = uicontrol('units','normalized',... 'position', [.32 .07 .1 .05 ],'string','--->', ... 'callback','tetris(''right'')', ... 'interruptible','yes'); drop_handle = uicontrol('units','normalized',... 'position',[.25 .01 .1 .05 ],'string','drop', ... 'callback','tetris(''drop'')'); rotate_handle = uicontrol('units','normalized',... 'position',[.25 .13 .1 .05],'string','rotate', ... 'callback','tetris(''rotate'')'); H_TEXT_SCORE = uicontrol(... 'ForegroundColor',[ 1 1 1 ],... 'Position',[ 0.65 0.85 0.2 0.07 ],... 'String','Score: xxxxx',... 'Units','normalized'); v = version; if str2num(v(1:3)) >= 4.2, % if Matlab 4.2 or later, create slider controls H_SLIDER_LEVEL = uicontrol(... 'CallBack', 'tetris(''level''); ', 'Max',[ 9 ], 'Min',[ 0 ],... 'val', LEVEL, 'Position', [ 0.6 0.3 0.04 0.4 ],... 'Style', 'slider', 'Units', 'normalized'); H_SLIDER_HEIGHT = uicontrol(... 'CallBack', 'tetris(''height''); ', 'Max', [ 50 ], 'Min', [ 10 ],... 'val', HEIGHT1, 'Position', [ 0.78 0.3 0.04 0.4 ],... 'Style', 'slider', 'Units', 'normalized'); H_SLIDER_WIDTH = uicontrol(... 'CallBack','tetris(''width''); ','Max',[ 20 ],'Min',[ 6 ],... 'val',WIDTH1,'Position',[ 0.9 0.3 0.04 0.4 ],... 'Style','slider','Units','normalized'); H_label_width = uicontrol(... 'ForegroundColor',[ 0 1 1 ], 'Position',[0.87 .72 .1 .06],... 'String','Width', 'Style','text', 'Units','normalized'); H_label_Height = uicontrol(... 'ForegroundColor',[ 1 1 0 ], 'Position',[ 0.75 0.72 0.1 0.06 ],... 'String','Height', 'Style','text', 'Units','normalized'); H_label_level = uicontrol(... 'ForegroundColor',[ 1 0 0 ], 'Position',[ 0.57 0.72 0.1 0.06 ],... 'String','Level', 'Style','text', 'Units','normalized'); H_TEXT_WIDTH = uicontrol(... 'ForegroundColor',[ 0 1 1 ], 'Position',[0.87 .22 .1 .06],... 'String',num2str(WIDTH1), 'Style','text', 'Units','normalized'); H_TEXT_HEIGHT = uicontrol(... 'ForegroundColor',[ 1 1 0 ], 'Position',[ 0.75 0.22 0.1 0.06 ],... 'String',num2str(HEIGHT1), 'Style','text', 'Units','normalized'); H_TEXT_LEVEL = uicontrol(... 'ForegroundColor',[ 1 0 0 ], 'Position',[ 0.57 0.22 0.1 0.06 ],... 'String',num2str(LEVEL), 'Style','text', 'Units','normalized'); end; % end version 4.2 extras (slider controls & labels) end; % end initialization routine if strcmp(action,'level'), % set skill level LEVEL = round(get(H_SLIDER_LEVEL,'val')); set(H_TEXT_LEVEL,'string',LEVEL); TIME_DELAY = MAX_DELAY*exp((LEVEL/9)*log(MIN_DELAY/MAX_DELAY)); end; if strcmp(action,'height'), % set play-field height HEIGHT1 = round(get(H_SLIDER_HEIGHT,'val')); set(H_TEXT_HEIGHT,'string',HEIGHT1); end; if strcmp(action,'width'), % set play-field width WIDTH1 = round(get(H_SLIDER_WIDTH,'val')); set(H_TEXT_WIDTH,'string',WIDTH1); end; if strcmp(action,'box'), % toggle display of play-field outline BOX = ~BOX; if BOX == 1, H_LINE = line ([1 WIDTH1+1 WIDTH1+1 1 1], [1 1 HEIGHT1 HEIGHT1 1]); else, delete(H_LINE); end end; if strcmp(action,'left'), % Move Left stopped = 0; for i=1:4, if USED_SPACE(POS(i,1)-1,POS(i,2)) == 1, stopped=1; end; end; if stopped == 0, POS(:,1) = POS(:,1) - 1; CENTER_X = CENTER_X - 1; for i=1:4, set(H(i),'XData',SQ_X+POS(i,1),'YData',SQ_Y+POS(i,2)); end; drawnow; end; end; if strcmp(action,'right'), % Move Right stopped = 0; for i=1:4, if USED_SPACE(POS(i,1)+1,POS(i,2)) == 1, stopped=1; end; end; if stopped == 0, POS(:,1) = POS(:,1) + 1; CENTER_X = CENTER_X + 1; for i=1:4, set(H(i),'XData',SQ_X+POS(i,1),'YData',SQ_Y+POS(i,2)); end; drawnow; end; end; if strcmp(action,'drop'), % Drop Piece Down while STUCK==0, for i=1:4, if USED_SPACE(POS(i,1),POS(i,2)-1) == 1, STUCK=1; end; end; if STUCK == 0, POS(:,2) = POS(:,2) -1; end; end; for i=1:4, set(H(i),'XData',SQ_X+POS(i,1),'YData',SQ_Y+POS(i,2)); end; drawnow; end; if strcmp(action,'rotate'), % Rotate new_x = -(POS(:,2) - CENTER_Y) + CENTER_X; new_y = (POS(:,1) - CENTER_X) + CENTER_Y; stopped = 0; for i=1:4, if ((new_x>1) & (new_x<(WIDTH1+2)) & (new_y>1)), if USED_SPACE(new_x(i), new_y(i)) == 1, stopped=1; end; else, stopped=1; end; end; if stopped == 0, % space not occupied POS = [new_x new_y]; for i=1:4, set(H(i),'XData',SQ_X+POS(i,1),'YData',SQ_Y+POS(i,2)); end; drawnow; end; end; if strcmp(action,'stop'), % stop game STOP_GAME = 1; end; % start tetris game if strcmp(action,'start'), % start game STOP_GAME = 0; score = 0; set(START_HANDLE, 'visible', 'off'); set(STOP_HANDLE, 'visible', 'on'); set(EXIT_HANDLE, 'visible', 'off'); set(H_TEXT_SCORE, 'string', ['Score: ' num2str(score)]); h_matb = zeros(WIDTH1+2,HEIGHT1); USED_SPACE = zeros(WIDTH1+2,HEIGHT1); USED_SPACE(:,1) = ones(WIDTH1+2,1); USED_SPACE ([1 WIDTH1+2],:) = ones(2,HEIGHT1); %USED_SPACE drawnow; axes(H_A); % shape definitions a_shape = [-1 0 1 2; 0 0 0 0]'; % rectangle 1x4 b_shape = [-1 0 0 1; 0 0 1 0]'; % Z mirror c_shape = [-1 0 0 1; 0 0 1 1]'; % Z normal d_shape = [-1 0 0 1; 1 1 0 0]'; % truncated T e_shape = [0 0 1 1; 0 1 0 1]'; % square 2x2 f_shape = [-1 0 1 1; 0 0 0 1]'; % L normal g_shape = [-1 -1 0 1; 1 0 0 0]'; % L mirror shape_matrix = [a_shape b_shape c_shape d_shape e_shape f_shape g_shape]; s = size(shape_matrix); num_shapes = s(2) / 2; color_matrix = [ 0 0 1; 0 1 0; 0 1 1; 1 0 0; 1 0 1; 1 1 0; 1 1 1]; home_pos = ones(4,1) * [(WIDTH1/2) (HEIGHT1-2)]; POS = a_shape + home_pos; for i=1:4, H(i) = patch(SQ_X+POS(i,1),SQ_Y+POS(i,2),'r'); end; while ((sum(USED_SPACE(2:WIDTH1+1,HEIGHT1-4)) == 0) & (STOP_GAME == 0)), shape_index = ceil(num_shapes*rand(1)); % choose random shape current_color = color_matrix(shape_index,:); % associated color POS = shape_matrix(:,(2*shape_index - 1):(2*shape_index)) + home_pos; % set initial postion of shape CENTER_X = home_pos(1,1); % set origin of rotation CENTER_Y = home_pos(1,2); for i = 1:4, set(H(i),'XData',SQ_X+POS(i,1), 'YData',SQ_Y+POS(i,2), ... 'FaceColor', current_color, 'Visible', 'on'); end; drawnow; STUCK = 0; t0 = clock; while ((STUCK == 0) & (STOP_GAME == 0)), drawnow; if etime(clock,t0) > TIME_DELAY, % move piece down one unit %etime(clock,t0) for i=1:4, if USED_SPACE(POS(i,1),POS(i,2)-1) == 1, STUCK=1; end; end; if STUCK == 0, t0 = clock; POS(:,2) = POS(:,2) - 1; CENTER_Y = CENTER_Y - 1; for i = 1:4, set(H(i),'YData',SQ_Y+POS(i,2)); end; drawnow; %etime(clock,t0) end end; drawnow; end for i=1:4, USED_SPACE(POS(i,1),POS(i,2)) = 1; end; % retire piece for i = 1:4, set(H(i),'Visible', 'off'); end; % hide active piece axes(H_B); for i=1:4, h_matb(POS(i,1),POS(i,2)) = patch(SQ_X+POS(i,1),SQ_Y+POS(i,2),current_color); end; i=2; while i < HEIGHT1, % check if any lines are complete if sum(USED_SPACE(2:WIDTH1+1,i)) == WIDTH1, score = score + 10*(LEVEL+1); % add score for completing line set(H_TEXT_SCORE, 'string', ['Score: ' num2str(score)]); for k1=2:WIDTH1+1, delete(h_matb(k1,i)); end; for k2=(i+1):HEIGHT1, for k1=2:WIDTH1+1, if h_matb(k1,k2) ~= 0, %disp([k1 k2 h_matb(k1,k2)]); set(h_matb(k1,k2),'YData',k2-1+SQ_Y); end; end; end; h_matb(2:WIDTH1+1,i:(HEIGHT1-1)) = h_matb(2:WIDTH1+1,(i+1):HEIGHT1); h_matb(2:WIDTH1+1,HEIGHT1) = zeros(WIDTH1,1); USED_SPACE(2:WIDTH1+1,i:(HEIGHT1-1)) = USED_SPACE(2:WIDTH1+1,(i+1):HEIGHT1); USED_SPACE(2:WIDTH1+1,HEIGHT1) = zeros(WIDTH1,1); else i = i+1; end end axes(H_A); end % end while loop for k2=2:HEIGHT1, % delete objects and clear play-field for k1=2:WIDTH1+1, if h_matb(k1,k2) ~= 0, delete(h_matb(k1,k2)); end; end; end; set(START_HANDLE, 'visible', 'on'); set(STOP_HANDLE, 'visible', 'off'); set(EXIT_HANDLE, 'visible', 'on'); end % end 'start' command (end game)