Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
334 views

Matlab Connect4 Code

This document provides code for a Connect 4 game application in MATLAB. It includes functions to initialize the game board, handle user input, detect wins/losses, and reset the game. Key features include: - Defines functions for initializing the game board graphics, setting colors, and handling click/mouse events. - Stores the game state (board, current player, etc.) in a callback structure. - Validates user input for legal moves and color selections. - Animates piece placement and detects/displays win/loss conditions. - Includes options to customize board properties and reset the game.

Uploaded by

api-292892066
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
334 views

Matlab Connect4 Code

This document provides code for a Connect 4 game application in MATLAB. It includes functions to initialize the game board, handle user input, detect wins/losses, and reset the game. Key features include: - Defines functions for initializing the game board graphics, setting colors, and handling click/mouse events. - Stores the game state (board, current player, etc.) in a callback structure. - Validates user input for legal moves and color selections. - Animates piece placement and detects/displays win/loss conditions. - Includes options to customize board properties and reset the game.

Uploaded by

api-292892066
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 30

function varargout = connect4(varargin)

% Play Connect 4!
%
% If you want to edit the board colors, you may input your own.
%
%
Acceptable Input Properties:
%
'BoardColor'
%
'BoardAccentColor'
%
'Player1Color'
%
'Player2Color'
%
'Bounce'
%
'AnimateDrop'
%
%
Acceptable Inputs are the standard color strings
%
white
-- 'w'
%
black
-- 'k'
%
yellow
-- 'y'
%
magenta -- 'm'
%
cyan
-- 'c'
%
red
-- 'r'
%
green
-- 'g'
%
blue
-- 'b'
%
%
or RGB color vectors.
%
% You may also turn off:
%
The physical dynamics by specifying 'Bounce','off'
%
The Board Clearing Animation by specifying 'AnimateDrop','off'
%
%
% Created By: Steven Terrana
%
Date: March 19th, 2015

%---------------- BEGIN INPUT ERROR PROOFING ----------------------------%


% even number of inputs, they come in pairs.
if rem(nargin,2)
error('There must be an even number of inputs.')
end
% cell of acceptable properties
props = {'BoardColor',...
'BoardAccentColor',...
'Player1Color',...
'Player2Color',...
'Bounce',...
'AnimateDrop'};
% make sure property inputs are acceptable
%
Note: case insensitive
for i = 1:2:length(varargin)
if ~sum(strcmpi(varargin{i},props))
error('''%s'' is not an accessable property.',varargin{i})
end
end
% Cell of acceptable color inputs
color_options = {'r','b','m','c','w','k','g','y'};
% check the inputs
for i = 2:2:length(varargin)
% the input is for a color property
if sum(strcmpi(varargin(i-1),props(1:4)))
if ischar(varargin{i}) % the user is trying to do a color string
if ~sum(strcmp(color_options,varargin{i}))
error('''%s'' is not an acceptable color input.',varargin{i})

end
else % the user is trying to do a RGB vector
if ~isequal(size(varargin{i}),[1 3]) || sum( varargin{i} < 0 ) || sum( varargin{i} > 1 )
error('RGB Vectors are [1X3] vectors containing values between [0,1]')
end
end
else % the input is for bounce or animatedrop
if ~sum(strcmp({'on','off'},varargin{i}))
error('''%s'' is not an option.

''%s'' must either be ''on'' or ''off''',varargin{i},varargin{i-1})

end
end
end
% -- Set the properties if specified, otherwise set defaults -- %
if sum(strcmpi('BoardColor',varargin))
callback.colors.BoardColor = varargin{find(strcmpi('BoardColor',varargin)==1)+1};
else
callback.colors.BoardColor = [0 0.5 0.8];
end
if sum(strcmpi('BoardAccentColor',varargin))
callback.colors.BoardAccentColor =
varargin{find(strcmpi('BoardAccentColor',varargin)==1)+1};
else
callback.colors.BoardAccentColor = 'k';
end
if sum(strcmpi('Player1Color',varargin))
callback.colors.Player1Color = varargin{find(strcmpi('Player1Color',varargin)==1)+1};
else
callback.colors.Player1Color = 'r';
end

if sum(strcmpi('Player2Color',varargin))
callback.colors.Player2Color = varargin{find(strcmpi('Player2Color',varargin)==1)+1};
else
callback.colors.Player2Color = 'y';
end
if sum(strcmpi('Bounce',varargin))
callback.bounce = varargin{find(strcmpi('bounce',varargin)==1)+1};
else
callback.bounce = 'on';
end
if sum(strcmpi('AnimateDrop',varargin))
callback.AnimateDrop = varargin{find(strcmpi('AnimateDrop',varargin)==1)+1};
else
callback.AnimateDrop = 'on';
end
%-------------------------------------------------------------------------%
% Define a custom "invisible" pointer
%
"callback" is a structure containing the variables that must be
%
accessible in the various callbacks.
callback.pointer_array = nan(16);

% define the figure window for the game


%
- invisible, for now
%
- default invisible pointer
%
- Not Resizable
%
- Normalize the units for programming on multiple screen sizes
%
- Get rid of the menubar
%
- Set the callbacks and only do one thing at a time.
fig = figure(...
'Pointer','custom',...
'Visible','off',...
'PointerShapeCData',callback.pointer_array,...
'Resize','off',...
'MenuBar','none',...
'Units','normalized',...
'Name', 'Connect 4!',...
'NumberTitle','off');
set(fig,
'WindowButtonMotionFcn',{@mousemoving,fig},...
'WindowButtonDownFcn',{@click,fig},...
'Interruptible','off',...
'BusyAction','cancel');
fig.Position(3:4) = [910 / 1600, 715/900]; % define size of window
movegui('center')
% center the figure window on the screen
callback.hAxes = gca; % grab the handle to the figure window axes
set(callback.hAxes,...
'XLim',[ 0 9 ],...
set x axis limits
'YLim',[ 0 10],...
set y axis limits
'XTick',[],...
no x tick marks
'YTick',[],...
no y tick marks
'Box','on')
% show axes border
axis('square')
% for aesthetics

% Define the two buttons in the game.


%
1. a reset button to start the game over
%
2. a "play again" button for when the game's over.
callback.button = uicontrol(...
'Style','PushButton',...
'Units','normalized',...
'Position',[0.37 0.0280 0.3 0.05],...
'String','Reset',...
'Visible','off',...
'Callback',{@button_push,fig});
callback.play_again = uicontrol(...
'Style','Pushbutton',...
'String','Play Again',...
'Units','normalized',...
'Position',[0.417 0.8 0.2 0.05],...
'Visible','off',...
'Callback',{@play_again,fig});
% flag for making the reset
% button visible after a turn has been made
callback.reset_flag = 0;
% Define the size of the marker by
% how much of the slot you would like
% it to fill and back-calculate the
% corresponding radius required.
percent_of_slot = 0.50;
callback.radius = sqrt(percent_of_slot / pi);

% create the board:


%
in order for the piece to "fall" through the board
%
it was necessary to create the board using many patches
%
and then assign the marker as the "first" child.
border = 0.6;
% define the x and y vectors for the patch components of the board.
%
each circular slot is composed of two patches that represent the
%
top half of the slot and the bottom half of the slot.
bx = linspace(-callback.radius,callback.radius);
by = sqrt(callback.radius^2 - (bx).^2);
board_piece_x = [bx,fliplr(bx)];
top_y = [border * ones(1,100),by];
bottom_y = [-border * ones(1,100),- by];
% construct the board
for j = 1.5:6.5
for i = 1.5:7.5
patch(board_piece_x +
patch(board_piece_x +
end
end

% x data for patches


% y data for top patch
% y data for bottom patch

i, top_y
+ j,callback.colors.BoardColor,'EdgeAlpha',0);
i, bottom_y + j,callback.colors.BoardColor,'EdgeAlpha',0);

% Fill in the vertical gaps in the board;


for i = -1:6
patch([ i + 1.8989 i + 2.1011 i + 2.1011 i + 1.8989],[0.9 0.9 7.1
7.1],callback.colors.BoardColor,'EdgeAlpha',0)
end

% Boarder the board (--> |_| <--)with a black line


patch([0.8989 0.8989],
[0.9 7.1],
callback.colors.BoardAccentColor,
'EdgeColor',callback.colors.BoardAccentColor,
'LineWidth',2);
patch([0.8989 8.1011],
[0.9 0.9],
callback.colors.BoardAccentColor,
'EdgeColor',callback.colors.BoardAccentColor,
'LineWidth',2);
patch([8.1011 8.1011],
[0.9 7.1],
callback.colors.BoardAccentColor,
'EdgeColor',callback.colors.BoardAccentColor,
'LineWidth',2);
% Define the interval from 0 to 2*pi for circle construction
callback.t = linspace(0,2*pi);
% Add transparent circular patches where the slots are
% to give them a border.
for i = 1.5:6.5
for j = 1.5:7.5
patch( j + callback.radius*cos(callback.t),
i+callback.radius*sin(callback.t),
callback.colors.BoardAccentColor,
'EdgeColor',callback.colors.BoardAccentColor,
'FaceAlpha',0,
'LineWidth',1)
end
end

% get the location of the mouse in the units of the axes


coords = get_coords(callback.hAxes);
% find the axis bounds
xl = xlim;
yl = ylim;
% this if-statement structure:
%
- keeps the circle inside the figure but above the game board
%
- changes what type of pointer is displayed
%
- invisible if moving the circle
%
- a hand if otherwise
set(fig,'Pointer','custom','PointerShapeCData',callback.pointer_array)
if coords(1) < (xl(1)+callback.radius)
set(fig,'Pointer','hand')
coords(1) = xl(1) + callback.radius;
end
if coords(1) > (xl(2) - callback.radius);
set(fig,'Pointer','hand')
coords(1) = xl(2) - callback.radius;
end
if coords(2) < 7.5
set(fig,'Pointer','hand')
coords(2) = 7.5;
end
if coords(2) > (yl(2) - callback.radius);
set(fig,'Pointer','hand')
coords(2) = yl(2) - callback.radius;
end
% construct a circle around the mouse
cx = coords(1) + callback.radius * cos(callback.t);
cy = coords(2) + callback.radius * sin(callback.t);

% create the patch


callback.current_marker =
patch(cx,cy,callback.colors.Player1Color,'EdgeColor','k','LineWidth',1.5);
% make it appear "behind" the board patches.
uistack(callback.current_marker,'bottom')
% Prep the necessary game variables
callback.turn = 1;
callback.column_count = ones(1,7);
callback.player1 = zeros(6,7);
callback.player2 = zeros(6,7);
callback.marker_idx = 1;

%
%
%
%
%

players turn
number of chips in each column
array with player one's chips
array with player two's chips
index for storing marker handles

% set callback as the figures application data for


% retrieval in the callbacks
guidata(fig,callback);
% let the user see the board
set(fig,'Visible','on')
% if the user want's the handle, give it to them.
if nargout == 1
varargout = {fig};
end
end

function mousemoving(~,~,fig)
% grab the data
callback = guidata(fig);
% get the mouse location in units of the axes
coords = get_coords(callback.hAxes);
% find the axis bounds
xl = xlim;
yl = ylim;
% this if-statement structure:
%
- keeps the circle inside the figure but above the game board
%
- changes what type of pointer is displayed
%
- invisible if moving the circle
%
- a hand if otherwise
set(fig,'Pointer','custom','PointerShapeCData',callback.pointer_array)
if coords(1) < (xl(1)+callback.radius)
set(fig,'Pointer','hand')
coords(1) = xl(1) + callback.radius;
end
if coords(1) > (xl(2) - callback.radius);
set(fig,'Pointer','hand')
coords(1) = xl(2) - callback.radius;
end
if coords(2) < 7.5
set(fig,'Pointer','hand')
coords(2) = 7.5;
end
if coords(2) > (yl(2) - callback.radius);
set(fig,'Pointer','hand')
coords(2) = yl(2) - callback.radius;
end

% move the location of the marker


set(callback.current_marker,'XData',coords(1) + callback.radius *
cos(callback.t),'YData',coords(2) + callback.radius * sin(callback.t))
% update the data
guidata(fig,callback)
end
function click(~,~,fig)
% grab the data
callback = guidata(fig);
% go determines if the click activates anything
go = 0;
% grab the mouse location in units of the Axes
coords = get_coords(callback.hAxes);

% to activate, pointer must be over the board (ie. 7.5)


if coords(2) >= 7.5
% define how close to the center of the column one must click to
% activate an event and then check if the mouse is above a column
% within the allowable window.
%
% This loop also determines which column the mouse is over and makes
% sure that the column isn't already full.
allowance = 0.3;
for i = 1.5:7.5
if coords(1)>= i - allowance && coords(1) <= i + allowance
col = i - 0.5;
if callback.column_count(col) < 7; % otherwise column full
go = 1;
end
end
end
if go
if ~callback.reset_flag
callback.reset_flag = 1;
set(callback.button,'Visible','on')
end
% add the current marker to the markers matrix and increase the
% index.
callback.markers(callback.marker_idx) = callback.current_marker;
callback.marker_idx = callback.marker_idx + 1;
guidata(fig,callback);

% temp_y_start is where the mouse is vertically.


temp_y_start = get(callback.current_marker,'YData');
% Where the marker will drop from, to 1 decimal
y_start = round(temp_y_start(1),1);
% drop the marker from its starting position and funnel it into the
% column
if strcmpi(callback.bounce,'off')
for i = y_start:-0.1:callback.column_count(col)+0.5
if i <= 7+round(callback.radius,1)
set(callback.current_marker,'XData',(col+0.5) + callback.radius*cos(callback.t));

end
set(callback.current_marker,'YData', i + callback.radius * sin(callback.t));

pause(0.01)
end
else
bounce(y_start,callback.column_count(col), callback.current_marker, callback.radius,col)

end

% update the player marker matrix


% if the last move resulted in a victory
%
- display a message
%
- display the play again button
%
- remove the reset button
%
- reset the game if necessary
if callback.turn == 1
callback.player1(7-callback.column_count(col),col) = 1;
result = CheckForWinner(callback.player1,7-callback.column_count(col),col);
if result
callback.messagehandle = CreateMessage(fig,'Player 1 Wins!!',callback.colors.Player1Color);

guidata(fig,callback)
uiwait

end
callback.turn = 2;
color = callback.colors.Player2Color;
else
callback.player2(7-callback.column_count(col),col) = 1;
result = CheckForWinner(callback.player2,7-callback.column_count(col),col);
if result == 1
callback.messagehandle = CreateMessage(fig,'Player 2 Wins!!',callback.colors.Player2Color);

guidata(fig,callback)
uiwait
end
callback.turn = 1;
color = callback.colors.Player1Color;
end
% assuming there was no victory and play continues then add the
% previous marker to the column count
callback.column_count(col) = callback.column_count(col) + 1;

% if someone wins or if the board is full


%
- clear the board
%
- reset the game
if result || isequal(callback.player1+callback.player2,ones(6,7))
if isequal(callback.player1+callback.player2,ones(6,7))
callback.messagehandle = CreateMessage(fig,'The Game is Drawn.',callback.colors.BoardColor);

guidata(fig,callback)
uiwait
end
if strcmp(callback.AnimateDrop,'on')
drop(fig)
end
delete(callback.markers)

callback = rmfield(callback,'markers');
callback.marker_idx = 1;
callback.player1 = zeros(6,7);
callback.player2 = zeros(6,7);
callback.column_count = ones(1,7);
callback.turn = 1;
end
% if the game's continuing, createa new marker and place it where
% the mouse is
coords = get_coords(callback.hAxes);
% find the axis bounds
xl = xlim;
yl = ylim;
% this if-statement structure:
%
- keeps the circle inside the figure but above the game board
%
- changes what type of pointer is displayed
%
- invisible if moving the circle
%
- a hand if otherwise
set(fig,'Pointer','custom','PointerShapeCData',callback.pointer_array)
if coords(1) < (xl(1)+callback.radius)
set(fig,'Pointer','hand')
coords(1) = xl(1) + callback.radius;
end
if coords(1) > (xl(2) - callback.radius);
set(fig,'Pointer','hand')
coords(1) = xl(2) - callback.radius;
end
if coords(2) < 7.5
set(fig,'Pointer','hand')
coords(2) = 7.5;
end

if coords(2) > (yl(2) - callback.radius);


set(fig,'Pointer','hand')
coords(2) = yl(2) - callback.radius;
end
cx = coords(1) + callback.radius * cos(callback.t);
cy = coords(2) + callback.radius * sin(callback.t);
callback.current_marker = patch(cx,cy,color,'EdgeColor','k','LineWidth',1.5,'Visible','off');

if result
set(callback.current_marker,
'FaceColor',callback.colors.Player1Color,
'EdgeColor','k',
'LineWidth',1.5);
end
uistack(callback.current_marker,'bottom')
end
end
% update the data
guidata(fig,callback)
% to avoid a delay in marker visibility and being able to move the marker
% make the marker visible now.
set(callback.current_marker,'Visible','on')
end
function button_push(~,~,fig)
% reset the game
% grab the data
callback = guidata(fig);
set(callback.button,'Visible','off')
callback.reset_flag = 0;

if strcmp(callback.AnimateDrop,'on')
set(callback.current_marker,'Visible','off')
drop(fig)
set(callback.current_marker,'Visible','on')
end
pause(0.1)
% delete all the markers and set game vars to new
delete(callback.markers) % clear the board
callback = rmfield(callback,'markers');
callback.player1 = zeros(6,7); % reset the game data
callback.player2 = zeros(6,7);
callback.column_count = ones(1,7);
callback.turn = 1;
callback.marker_idx = 1;
% change the marker to red if it was player 2's turn when you reset
set(callback.current_marker,'FaceColor',callback.colors.Player1Color,'EdgeColor','k','Lin
eWidth',1.5);
% update the game data
guidata(fig,callback);

end
function play_again(~,~,fig)
% grab the data
callback = guidata(fig);

% delete the message


delete(callback.messagehandle)
% reassign the callbacks
set(fig,'WindowButtonMotionFcn',{@mousemoving,fig},'WindowButtonDownFcn',{@click,fig})
% hide play again button
set(callback.play_again,'Visible','off')
% show reset button
set(callback.button,'Visible','on')
% change the pointer back to invisible, continue the code.
set(fig,'Pointer','custom','PointerShapeCData',nan*ones(16,16))
uiresume
end
function coords = get_coords(hAxes)
%# Get the screen coordinates:
coords = get_in_units(0,'PointerLocation','pixels');
%# Get the figure position, axes position, and axes limits:
hFigure = get(hAxes,'Parent');
figurePos = get_in_units(hFigure,'Position','pixels');
axesPos = get_in_units(hAxes,'Position','pixels');
axesLimits = [get(hAxes,'XLim').' get(hAxes,'YLim').'];
%# Compute an offset and scaling for coords:
offset = figurePos(1:2)+axesPos(1:2);
axesScale = diff(axesLimits)./axesPos(3:4);
%# Apply the offsets and scaling:

coords = (coords-offset).*axesScale+axesLimits(1,:);

function [value]=get_in_units(hObject,propName,unitType)
oldUnits = get(hObject,'Units');
set(hObject,'Units',unitType);
value = get(hObject,propName);
set(hObject,'Units',oldUnits);

%#
%#
%#
%#

Get the
Set the
Get the
Restore

current units for hObject


units to unitType
propName property of hObject
the previous units

end
end
function t = CreateMessage(fig,str,bgColor)
callback = guidata(fig);
t(1) = text(4.55,9.55,str,'HorizontalAlignment','center','FontSize',18);
x = xlim; y = ylim;
t(2) = line( [ (0.37 * diff(x))+x(1) - 0.9, 0.04 * diff(x) + 6.28] , ((0.87 *
diff(y)) + y(1)+0.6)*ones(1,2)
,'color','k','LineWidth',2);
t(3) = line( ( (0.37 * diff(x))+x(1) - 0.94) * ones(1,2), [ (0.87 * diff(y)) +
y(1)+0.6,(0.87 * diff(y)) + y(1)+1.11 ]
,'color','k','LineWidth',2);
t(4) = line( (0.04 * diff(x) + 6.315) * ones(1,2), [ (0.87 * diff(y)) +
y(1)+0.6,(0.87 * diff(y)) + y(1)+1.1 ]
,'color','k','LineWidth',2);
t(5) = line( [ (0.37 * diff(x))+x(1) - 0.93, 0.04 * diff(x) + 6.31] , ((0.87 *
diff(y)) + y(1)+1.14)*ones(1,2)
,'color','k','LineWidth',2);
if str(1) == 'P'
cx = 2.95 + 0.2 * cos(linspace(0,2*pi));
cy = 9.57 + 0.2 * sin(linspace(0,2*pi));
t(6) = patch(cx,cy,bgColor,'EdgeColor','k','LineWidth',1.5);
end
set(callback.play_again,'Visible','on')

set(callback.button,'Visible','off')
set(fig,'Pointer','arrow')
set(fig,'WindowButtonMotionFcn',[],'WindowButtonDownFcn',[])
end
function result = CheckForWinner(player,row,col)
% The purpose of this script is to determine whether or not
% the marker that was just placed results in a player victory.
%
% The methodology for determining this is simple.
%
Each marker can be a part of 16 different
%
vectors that result in 4 in a row.
%
%
These 16 combinations are created and then checked
%
against the players marker position matrix to see if
%
they have four markers in any of these vectors.
%
If they do, they win.
% defines the location of the last placed marker
% inside the frame array.
%
% Framing the board with zeros is necessary as to
% avoid errors when searching for a winning vector
% that falls outside the board (on the edges)
pos = [row + 3,col + 3];
frame = zeros(3 * 2 + 6, 3 * 2 + 7);
frame(4:9,4:10) = player;
% Initializes the directions matrix.
% This will store the 16 possible array vectors
% that could result in a victory.
directions = zeros(4,2,16);
i = 1; % an index to successfully add to this array.

%% start defining directions


%
Each direction will have a diagram where | represents other markers
%
and 0 represents the marker that was just placed.
%
%
the variable a represents the location of the other markers with
%
respect to the most recently placed marker.
%% Possible Vertical Combinations For Victory
%
|
%
|
%
|
%
0
a =[1 0 ; 2 0 ; 3 0];
directions(:,:,i) = [pos; [pos(1) + a(:,1), pos(2) + a(:,2)]];
i = i + 1;
%
|
%
|
%
0
%
|
a =[-1 0 ; 1 0 ; 2 0];
directions(:,:,i) = [pos; [pos(1) + a(:,1), pos(2) + a(:,2)]];
i = i + 1;
%
|
%
0
%
|
%
|
a =[-2 0 ; -1 0 ; 1 0];
directions(:,:,i) = [pos; [pos(1) + a(:,1), pos(2) + a(:,2)]];
i = i + 1;

%
0
%
|
%
|
%
|
a =[-3 0 ; -2 0 ; -1 0];
directions(:,:,i) = [pos; [pos(1) + a(:,1), pos(2) + a(:,2)]];
i = i + 1;
%% Possible Horizontal Combinations For Victory
% 0 | | |
a =[0 1 ; 0 2 ; 0 3];
directions(:,:,i) = [pos; [pos(1) + a(:,1), pos(2) + a(:,2)]];
i = i + 1;
% | 0 | |
a =[0 -1 ; 0 1 ; 0 2];
directions(:,:,i) = [pos; [pos(1) + a(:,1), pos(2) + a(:,2)]];
i = i + 1;
% | | 0 |
a =[0 -2 ; 0 -1 ; 0 1];
directions(:,:,i) = [pos; [pos(1) + a(:,1), pos(2) + a(:,2)]];
i = i + 1;
% | | | 0
a =[0 -3 ; 0 -2 ; 0 -1];
directions(:,:,i) = [pos; [pos(1) + a(:,1), pos(2) + a(:,2)]];
i = i + 1;
%% Possible Diagonal (/) Combinations For Victory
%
|
%
|
%
|
%
0

a =[1 1 ; 2 2 ; 3 3];
directions(:,:,i) = [pos; [pos(1) + a(:,1), pos(2) + a(:,2)]];
i = i + 1;
%
|
%
|
%
0
%
|
a =[-1 -1 ; 1 1 ; 2 2];
directions(:,:,i) = [pos; [pos(1) + a(:,1), pos(2) + a(:,2)]];
i = i + 1;
%
|
%
0
%
|
%
|
a =[-2 -2 ; -1 -1 ; 1 1];
directions(:,:,i) = [pos; [pos(1) + a(:,1), pos(2) + a(:,2)]];
i = i + 1;
%
0
%
|
%
|
%
|
a =[-3 -3 ; -2 -2 ; -1 -1];
directions(:,:,i) = [pos; [pos(1) + a(:,1), pos(2) + a(:,2)]];
i = i + 1;
%% Possible Diagonal (\) Combinations For Victory
% |
%
|
%
|
%
0
a =[-1 1 ; -2 2 ; -3 3];

directions(:,:,i) = [pos; [pos(1) + a(:,1), pos(2) + a(:,2)]];


i = i + 1;
% |
%
|
%
0
%
|
a =[-2 2 ; -1 1 ; 1 -1];
directions(:,:,i) = [pos; [pos(1) + a(:,1), pos(2) + a(:,2)]];
i = i + 1;
% |
%
0
%
|
%
|
a =[-1 1 ; 1 -1 ; 2 -2];
directions(:,:,i) = [pos; [pos(1) + a(:,1), pos(2) + a(:,2)]];
i = i + 1;
% 0
%
|
%
|
%
|
a =[1 -1 ; 2 -2 ; 3 -3];
directions(:,:,i) = [pos; [pos(1) + a(:,1), pos(2) + a(:,2)]];
%% Check for a winning vector
winning_combination= zeros(1,4); % initialize
result = 0; % loss by default
for i = 1:16
x = directions(:,:,i);
for j = 1:4;
winning_combination(j) = frame(x(j,1),x(j,2));

end
if sum(winning_combination) == 4
result = 1;
end
end

end
function bounce(H,endloc,ball,radius,col)
% coefficient of restitution.
% max cor based on how high you hold the marker before you drop it
Max_COR = 0.3 + (0.1)/(9.6-7.5) * (H - 7.5);
% cor reduced based on how many markers are already in the column
COR = Max_COR - (Max_COR - 0.05)/6 * (endloc-1);
% grab the bouncing data
h = ballbounce(H,COR,3);

h = h + endloc + 0.49;
h = h( h<=H );

for i = 1:19:length(h)
if h(i) <= 7.3

ball.XData = col+0.5 + radius*cos(linspace(0,2*pi));


end
cy = h(i) + radius*sin(linspace(0,2*pi));
ball.YData = cy;
pause(0.001)
end
ball.YData = endloc + 0.5 + radius * sin(linspace(0,2*pi));
end
function h=ballbounce(H,COR,n)
% Define constants
g=9.81; % gravity (m/sec^2)
dt=0.001; % time step[temporal resolution] (sec)
% Assign initial conditions
h(1)=H; % h(t0=0)=H=1m
v_previous = 0; % v(t0=0)=0 (no initial velocity)
a = -g;
% a=-g, and always constant
% set index number i to 1 (initial condition for i=1)
i=2;
% repeat calculating velocity and height of the ball
% until the ball hits n times on the ground
for nbounce=1:n
% if current height h(i) has negative number, terminate 'while' loop
% (it does not physically make sense.)
while h(i-1)>=0

% calculate velocity of the ball at given time t(i+1)


v = v_previous+a*dt;
% calculate height of the ball at given time t(i+1)
h(i)=h(i-1) + v * dt;
v_previous = v;
% index 'i' increases by 1 to calculate next height
i=i+1;
end
% delete current height related values and
% go back to the last height by decreasing i by 1
% (The last position where the ball is above the ground)
i=i-1;
h(i)=[];
% Assume that the ball bounce slightly above the ground,
% the initial velocity of the ball after bouncing is calculated with
% the final velocity of the ball before bouncing
% and coefficient of restitution
v_previous = -COR * v_previous;
% index 'i' increases by 1 to calculate next height
% with new condition after the ball bouncing.
end
end
function drop(fig)
callback = guidata(fig);
Row = { [], [], [], [], [], [] };
Row_h = { [], [], [], [], [], [] };
L = zeros(1,6);

max_row = 0;
for i = 1:length(callback.markers)
H = mean(callback.markers(i).YData);
idx = round(H - 0.5,0);
if idx > max_row
max_row = idx;
Max_COR = 0.5;
COR = Max_COR - (Max_COR - 0.1)/6 * (H-1.5);
h = ballbounce(H,COR,3);
h = h + callback.radius;
Row_h(idx) = {h( h <= H )};
L(idx) = length(Row_h{idx});
end
Row{idx} = [Row{idx}, callback.markers(i)];
end
ideal_pause_length = [ 1/200 1/175 1/150 1/125 1/100 1/50];
a = tic;
for h_idx = 1:max(L)
for r = 1:max_row
if h_idx <= L(r)
h = Row_h{r};
set(Row{r},'YData',h(h_idx) + callback.radius*sin(linspace(0,2*pi)))
if toc(a) > ideal_pause_length(max_row)
pause(0.001)
a = tic;
end
end
end
end

% update the game data


guidata(fig,callback);
end

You might also like