From c56b7ad77626a100dcf443c48991e6935d69d2d6 Mon Sep 17 00:00:00 2001 From: Howard T Date: Thu, 27 Apr 2017 19:00:57 +0100 Subject: [PATCH] Replace "transferring_deck" to "previously_selected_deck". Add comments --- sulitear.m | 209 +++++++++++++++++++++++++++++------------------------ 1 file changed, 115 insertions(+), 94 deletions(-) diff --git a/sulitear.m b/sulitear.m index 085b307..6d799ac 100644 --- a/sulitear.m +++ b/sulitear.m @@ -1,16 +1,20 @@ -function sulitear() % Original author: En Yi % A solitaire game on MATLAB, very self-explanatory % Not optimised though % Have fun! % Anyone can modify it, just need to give credits to the original author +% Future considerations: +% -Add dragging functions +% -Add card animations +% -Find a better way to render the game for better resolution +% -Allow deck customisation? +function sulitear() clc; -% Construct the window with the axes +% Get information about the screen scrsz = get(0,'ScreenSize'); -%TODO Find new method to draw the window -%start_dim = min(scrsz(3)/1.5,scrsz(4)/1.5);%Used for rescaling win_ratio = scrsz(3:4)/scrsz(3); win_size = scrsz(3:4)*0.8; +% Construct the window win = figure('ToolBar','none','Name','Solitaire',... 'NumberTitle','off','MenuBar','none',... 'Resize','off','Visible','off','Color',[0 0 0]/255,... @@ -18,37 +22,41 @@ win = figure('ToolBar','none','Name','Solitaire',... 'ButtonDownFcn',@check_clicked_deck,... 'KeyPressFcn',@restart); -%Prepare card decks and the playing field +% Prepare a variable to indicate which deck are selected +previous_selected_deck = 0; +% Prepare cards and the playing field playing_cards = prepare_playing_cards(); -[playing_decks,draw_deck,discard_deck,goal_decks,playfield_size] = prepare_cardHolders(playing_cards,win_ratio); - +[playing_decks,draw_deck,discard_deck,goal_decks,playfield_size] = prepare_playfield(playing_cards,win_ratio); +% Prepare the drawing axes disp_axes = axes('Parent',win,'Position',[0 0 1 1]); set(disp_axes,'Xlim',[0 playfield_size(1)],'Ylim',[0 playfield_size(2)],... 'XLimMode','manual','YLimMode','manual','Visible','off','NextPlot','add'); -set(win,'Visible','on') -% Prepare some variable to indicate cards are selected HERE -transferring_deck = 0; -% draw it on the axes +% Draw the playing field on the axes draw_playfield(); +set(win,'Visible','on') + %% Callback functions -%%% Idea: can optimise by splitting the window into regions +%%% Idea: can optimise by splitting the window into regions and check only +%%% the decks in that region function check_clicked_deck(~,~) - if ~strcmp(get(win,'selectiontype'),'normal') + % Only allow left clicks, subject to changes + if ~strcmp(get(win,'selectiontype'),{'normal','open'}) return end [Xx,Yy] = get_mouse_pos(); if draw_deck.check_Deck_Collision(Xx,Yy,'first') reset_card_selection(); - if draw_deck.get_Number_Of_Cards() + discard_deck.get_Number_Of_Cards()>0 - if draw_deck.get_Number_Of_Cards()>0 % If there's cards - transferring_deck = draw_deck; + % Check for the draw pile collision + if draw_deck.get_Number_Of_Cards() + discard_deck.get_Number_Of_Cards()>0 % If not all cards are taken away + if draw_deck.get_Number_Of_Cards()>0 % If there's cards to be drawn + previous_selected_deck = draw_deck; draw_deck.selected_start_index = min(draw_deck.get_Number_Of_Cards(),3); discard_deck.set_Current_Display(draw_deck.selected_start_index); % Set the discard to show that amount of cards transferred draw_deck.transfer_Selected_Cards(discard_deck,'flip'); % Transfer cards to discard pile, up to 3 reset_card_selection(); - else - transferring_deck = discard_deck; % Transfer back the cards from discard pile + else + previous_selected_deck = discard_deck; % Transfer back the cards from discard pile discard_deck.selected_start_index = discard_deck.get_Number_Of_Cards(); discard_deck.transfer_Selected_Cards(draw_deck,'flip'); reset_card_selection(); @@ -59,72 +67,75 @@ draw_playfield(); return end - if discard_deck.check_Deck_Collision(Xx,Yy,'first') % Else check for discard deck - if transferring_deck == discard_deck + % Check for the draw pile collision + if discard_deck.check_Deck_Collision(Xx,Yy,'first') + if previous_selected_deck == discard_deck reset_card_selection(); return end reset_card_selection(); - if discard_deck.get_Number_Of_Cards() > 0 % Only allow selection, up to one card - discard_deck.selected_start_index = 1; - transferring_deck = discard_deck; + if discard_deck.get_Number_Of_Cards() > 0 + discard_deck.selected_start_index = 1; % Only allow selection, up to one card + previous_selected_deck = discard_deck; discard_deck.update_Deck_Graphics(disp_axes); end return end + % Check for the playing deck for i = 1:length(playing_decks) - % This part is only for the playing deck - if playing_decks(i).check_Deck_Collision(Xx,Yy,'full') %Check if any deck is clicked + if playing_decks(i).check_Deck_Collision(Xx,Yy,'full') selected_deck = playing_decks(i); - s_index = selected_deck.check_selection(Xx,Yy); %If so, check which card is selected - %If no selection was before or more than a card is - %selected and there are cards remaining in the deck -% if playing_decks(i).check_Deck_Collision(Xx,Yy,'first') && s_index == -1 -% reset_card_selection(); -% selected_deck.reveal_Hidden_Card(1) -% selected_deck.update_Deck_Graphics(disp_axes); -% break -% end + s_index = selected_deck.check_selection(Xx,Yy); %Check which card is selected - if (transferring_deck ~= 0) - %if s_index>=0 - if transferring_deck ~= selected_deck % If the selected deck is not the previously selected deck - [transferring_num,transferring_col]= determine_card(get_bottom_selected(transferring_deck)); + % Manually open a hidden card, not used + % if playing_decks(i).check_Deck_Collision(Xx,Yy,'first') && s_index == -1 + % reset_card_selection(); + % selected_deck.reveal_Hidden_Card(1) + % selected_deck.update_Deck_Graphics(disp_axes); + % return + % end + + % If a deck is previously selected + if (previous_selected_deck ~= 0) + if previous_selected_deck ~= selected_deck + [transferring_num,transferring_col]= determine_card(get_bottom_selected(previous_selected_deck)); [destination_num,destination_col] = determine_card(selected_deck.get_Last_Cards()); - if (transferring_col ~= destination_col &&... % If the colour alternates - transferring_num == destination_num-1) % If the number are in sequence - transfer_Selected_Cards(transferring_deck,selected_deck); + if (transferring_col ~= destination_col &&... % If the colour alternates + transferring_num == destination_num-1) % If the number are in sequence + transfer_Selected_Cards(previous_selected_deck,selected_deck); end - % Reveal a hidden card if there is one - auto_open_hiddencard(); + auto_open_hiddencard(); % Reveal a hidden card if there is one end - %end reset_card_selection(); else - % Otherwise move previously selected cards to the currently selected deck - if s_index>0 - %Get the selected cards to be transfered + if ~selected_deck.is_Empty() reset_card_selection(); selected_deck.selected_start_index = s_index; - transferring_deck = selected_deck; + previous_selected_deck = selected_deck; end end selected_deck.update_Deck_Graphics(disp_axes); return end end + + % Check for the goal decks for i = 1:length(goal_decks) if goal_decks(i).check_Deck_Collision(Xx,Yy,'first') selected_deck = goal_decks(i); - if (transferring_deck ~= 0) - if transferring_deck.selected_start_index == 1 - [transferring_num,~,transferring_suit]= determine_card(get_bottom_selected(transferring_deck)); - [destination_num,~,destination_suit] = determine_card(selected_deck.get_Last_Cards()); - if (transferring_suit == destination_suit && transferring_num == destination_num+1)... - || transferring_num == 1 - transfer_Selected_Cards(transferring_deck,selected_deck); + if (previous_selected_deck ~= 0) + if previous_selected_deck.selected_start_index == 1 % Only allow one card transfer + [transferring_num,~,transferring_suit]= ... + determine_card(get_bottom_selected(previous_selected_deck)); + [destination_num,~,destination_suit] = ... + determine_card(selected_deck.get_Last_Cards()); + + if (transferring_suit == destination_suit ... % If card is same suit + && transferring_num == destination_num+1 )... % Must be consecutive number + || transferring_num == 1 % Or is the ace + transfer_Selected_Cards(previous_selected_deck,selected_deck); end end auto_open_hiddencard(); @@ -133,34 +144,38 @@ draw_playfield(); if ~selected_deck.is_Empty() reset_card_selection(); selected_deck.selected_start_index = 1; - transferring_deck = selected_deck; + previous_selected_deck = selected_deck; end end selected_deck.update_Deck_Graphics(disp_axes); + % Check for winning condition total_goal_cards = 0; for j = 1:length(goal_decks) total_goal_cards = total_goal_cards+goal_decks(j).get_Number_Of_Cards(); end if total_goal_cards == 52 uiwait(msgbox('You Won! Press R to Try Again!','YAY!','modal')); + reset_card_selection(); end + return end end - %%% TODO: check for winning condition + end %% Non-Callback functions -%Prepare the card holders +% Prepare the card holders function restart(~,evtdata) + % Press R to try again if strcmp(evtdata.Key,'r') reset_entire_game(playing_cards); end end - function [playing_decks,draw_deck,discard_deck,goal_decks,playfield_size] = prepare_cardHolders(cards,win_ratio) - %%% TODO: Automate the draw, discard piles and the goal pile +% Prepare the playing field dimension with the card holders + function [playing_decks,draw_deck,discard_deck,goal_decks,playfield_size] = prepare_playfield(cards,win_ratio) card_size = size(cards(1).get_Card_Image('front')); card_width = card_size(2); card_height = card_size(1); @@ -168,18 +183,17 @@ draw_playfield(); n = 7; border_offset = 10; playfield_width = round((card_size(2)+offset)*n-offset+2*border_offset); - i = 1; - while(playfield_width-card_width*i>=0) - i = i+1; - end - playfield_width = card_width*i; - i = 1; +% i = 1; +% while(playfield_width-card_width*i>=0) +% i = i+1; +% end +% playfield_width = card_width*i; +% i = 1; playfield_size = round([playfield_width playfield_width].*win_ratio); - while(playfield_size(2)-card_height*i>=0) - i = i+1; - end - playfield_size(2) = card_height*i; - % Input the number of decks and offset between deck position +% while(playfield_size(2)-card_height*i>=0) +% i = i+1; +% end +% playfield_size(2) = card_height*i; % Compute the position and dimensions start_x = border_offset; @@ -187,7 +201,6 @@ draw_playfield(); card_offset = (start_y-card_height-offset)/18; % Initialise the card holders - % Manually initialise for testing purposes draw_deck = cardHolder(start_x,playfield_size(2)-border_offset,... [],card_width,card_height,card_offset,'horizontal',1,1,1,0); discard_deck = cardHolder(start_x+card_width+offset,playfield_size(2)-border_offset,... @@ -197,9 +210,10 @@ draw_playfield(); goal_decks(i-3) = cardHolder(start_x+(card_width+offset)*(i-1),... playfield_size(2)-border_offset,[],card_width,card_height,card_offset,'vertical',1,0,0,1); end + % Shuffle the cards a = randperm(length(cards)); remaining_cards = cards(a); - %Loop method, which will be used + for i = 1:n dealt_cards = remaining_cards(1:i); playing_decks(i) = cardHolder(start_x+(card_width+offset)*(i-1),... @@ -225,18 +239,21 @@ draw_playfield(); catch disp('Load failed') close all + % Should maybe have a variable for loading failure end end -% Distribute the playing cards - function [dealt_cards,remaining_cards] = deal_cards(cards,amount) - remaining_cards = cards; - for i = 1:amount - n_of_cards = length(remaining_cards); - index = randi(n_of_cards); - dealt_cards(i) = remaining_cards(index); - remaining_cards = [remaining_cards(1:index-1) remaining_cards(index+1:end)]; - end - end +% % Distribute the playing cards, not used +% function [dealt_cards,remaining_cards] = deal_cards(cards,amount) +% remaining_cards = cards; +% for i = 1:amount +% n_of_cards = length(remaining_cards); +% index = randi(n_of_cards); +% dealt_cards(i) = remaining_cards(index); +% remaining_cards = [remaining_cards(1:index-1) remaining_cards(index+1:end)]; +% end +% end + +% Reset the game function reset_entire_game(cards) a = randperm(length(cards)); remaining_cards = cards(a); @@ -263,18 +280,19 @@ draw_playfield(); reset_card_selection(); end + % Reset the card selection to none and updating the deck graphic function reset_card_selection() - if transferring_deck ~= 0 - transferring_deck.selected_start_index = 0; - transferring_deck.update_Deck_Graphics(disp_axes) - transferring_deck = 0; + if previous_selected_deck ~= 0 + previous_selected_deck.selected_start_index = 0; + previous_selected_deck.update_Deck_Graphics(disp_axes) + previous_selected_deck = 0; end end % Draw the play field function draw_playfield() - cla(disp_axes); % Clear the play field axes + cla(disp_axes); % Clear the play field axes, not that it is needed since it is only called during initialisation for i = 1:length(playing_decks) playing_decks(i).render_deck_outline(disp_axes); playing_decks(i).update_Deck_Graphics(disp_axes); @@ -297,23 +315,26 @@ draw_playfield(); else if card == 0 if ~isempty(varargin) - num = varargin{1}; + num = varargin{1}; % Specify the value an empty deck should take else - num = 14; + num = 14; % Allow king to go into empty slots by default end else - num = -1; + num = -1; % The deck is having hidden cards end suit = -1; colour = -1; end end + +% Open hidden cards automatically function auto_open_hiddencard() - if (transferring_deck.hidden_start_index >0 ... - && transferring_deck.get_Number_Of_Cards() == transferring_deck.hidden_start_index) - transferring_deck.reveal_Hidden_Card(1) + if (previous_selected_deck.hidden_start_index >0 ... + && previous_selected_deck.get_Number_Of_Cards() == previous_selected_deck.hidden_start_index) + previous_selected_deck.reveal_Hidden_Card(1) end end + % Get the mouse position function[X,Y]= get_mouse_pos() mpos = get(disp_axes,'CurrentPoint');