Code covered by the BSD License  

Highlights from
ChessPeace

image thumbnail
from ChessPeace by Zachary Danziger
Software for playing Chess and Chess Variants

ChessPeace(action)
function ChessPeace(action)
% Performs the action related-request for the game.
%
% % To start the main game GUI:
% >> ChessPeace
%
% For other instructions on game play, how pieces move, setting up games,
% computer opponents, making your own games, or loading and saving your
% games see the in-game help in the 'Help' menu.
%
%
% %%% Zachary Danziger, April 2012 %%%
% All rights reserved.
%



% recall the value of the menu handles
persistent uih fs

% if action is empty:
if nargin==0
    action = 'initialize';
end

% obtain file separator in case of Mac or UNIX platforms
fs = filesep;

% the case for each action
switch action
    case 'initialize'
%% initialization
        
% make sure we are in this directory
ChessPeaceDir = mfilename('fullpath');
cd( ChessPeaceDir(1:max(strfind(ChessPeaceDir,fs))) )


% reset all menu items for the new figure

% create main figure window
uih.f1 = figure('Name',mfilename,'Unit','normalized',...
    'Position',[0.1729    0.1975    0.6292    0.6625],'color','k',...
    'NumberTitle','off','Menubar','none');
% 'ResizeFcn',{@DynTitleSize 16}

% do some menus for the figure
% the uih structure will contain all the menu handles
uih.Game = uimenu('label','Game');
    uih.Play = uimenu(uih.Game,'Label','Play',      'callback',[mfilename '(''buildboard'')']);
    uih.Save = uimenu(uih.Game,'Label','Save',      'callback',[mfilename '(''save'')']);
    uih.Load = uimenu(uih.Game,'Label','Load',      'callback',[mfilename '(''load'')']);
    uih.Resign = uimenu(uih.Game,'Label','Resign',  'callback',[mfilename '(''resign'')']);

uih.Setup = uimenu('label','Setup');
    uih.GameType = uimenu(uih.Setup,'Label','Game Type');
        uimenu(uih.GameType,'Label','Contemporary',     'callback',[mfilename '(''checkmarks'')'],'checked','on')
        uimenu(uih.GameType,'Label','ChessPeace',       'callback',[mfilename '(''checkmarks'')'])
        uimenu(uih.GameType,'Label','FischerRandom',    'callback',[mfilename '(''checkmarks'')'])
        uimenu(uih.GameType,'Label','Omega',            'callback',[mfilename '(''checkmarks'')'])
        uimenu(uih.GameType,'Label','ChessPeaceMadness','callback',[mfilename '(''checkmarks'')'])
        uimenu(uih.GameType,'Label','Capablanca',       'callback',[mfilename '(''checkmarks'')'])
        uimenu(uih.GameType,'Label','MinorSwap',        'callback',[mfilename '(''checkmarks'')'])
        uimenu(uih.GameType,'Label','Elena',            'callback',[mfilename '(''checkmarks'')'])
        uimenu(uih.GameType,'Label','ChessPeaceMini',	'callback',[mfilename '(''checkmarks'')'])
        uimenu(uih.GameType,'Label','AshPash',      	'callback',[mfilename '(''checkmarks'')'])
        uimenu(uih.GameType,'Label','Custom',           'callback',[mfilename '(''checkmarks'')'])
        uimenu(uih.GameType,'Label','DebugPositions',   'callback',[mfilename '(''checkmarks'')'])
        
    uih.White = uimenu(uih.Setup,'Label','White');
        uimenu(uih.White,'Label','Human',               'callback',[mfilename '(''checkmarks'')'],'checked','on')
        uimenu(uih.White,'Label','ComputerAlpha',       'callback',[mfilename '(''checkmarks'')'])
        uimenu(uih.White,'Label','ComputerBeta',        'callback',[mfilename '(''checkmarks'')'])
        uimenu(uih.White,'Label','ComputerGamma',       'callback',[mfilename '(''checkmarks'')'])
    uih.Black = uimenu(uih.Setup,'Label','Black');
        uimenu(uih.Black,'Label','Human',               'callback',[mfilename '(''checkmarks'')'])
        uimenu(uih.Black,'Label','ComputerAlpha',       'callback',[mfilename '(''checkmarks'')'],'checked','on')
        uimenu(uih.Black,'Label','ComputerBeta',        'callback',[mfilename '(''checkmarks'')'])
        uimenu(uih.Black,'Label','ComputerGamma',       'callback',[mfilename '(''checkmarks'')'])
    uih.ThinkTime = uimenu(uih.Setup,'Label','Max Computer Thinking Time: 60s',...
        'Callback',[mfilename '(''thinktime'')'],'userdata',60,'Tag','ThinkTime');
    uih.GameClock = uimenu(uih.Setup,'Label','GameClock',...
        'Callback',[mfilename '(''gameclock'')'],'userdata',[inf inf 1 0],'Tag','GameClock');
        
    uih.Help = uimenu('label','Help');
        uimenu(uih.Help,'Label','About',                'callback','PrintHelp(''about'')')
        uimenu(uih.Help,'Label','Rules',                'callback','PrintHelp(''rules'')')
        uimenu(uih.Help,'Label','GamePlay',             'callback','PrintHelp(''gameplay'')')
        uimenu(uih.Help,'Label','Pieces',               'callback','PrintHelp(''pieces'')')

    


    case 'checkmarks'
%% checkmarks        

        
% uncheck all other types and check the clicked type
hp = get(gcbo,'Parent');                % parent of this submenu
hc = get(hp,'children');                % all other checkable items in this submenu
label = get(gcbo,'Label');              % label of executing calback
for i=1:length(hc)
    if strcmp(label,get(hc(i),'Label'))    % compare all labels to the label of gcbo
        set(hc(i), 'Checked', 'on');
    else
        set(hc(i), 'Checked', 'off');
    end
end


    case 'buildboard'
%% PLAY THE GAME


% Get the type of game we're playing
ix = strcmp(get(get(uih.GameType,'Children'),'checked'),'on');   % which one is checked?
if any(ix)
    labels = get(get(uih.GameType,'Children'),'Label');
    gameType = labels{ix};
    B = BoardInitialization(gameType);
    if isempty(B), return; end
else
    % if there are no checked game types, that indicates a user is loading
    % a game
    B = get(uih.f1,'userdata');
end


% ======= BOARD GRAPHICS =======
% clear the figure
delete(findobj(uih.f1,'type','axes'))


% obtain size of playable area (in squares)
tmp = size(B.top)-B.info.pad;
% rename variables for clarity
rows = tmp(1); cols = tmp(2); 

% second axes for piece rules
axRules = axes('color','w','xlim',[0 1],'ylim',[0 1],...
    'xtick',[],'ytick',[],'NextPlot','replacechildren',...
    'Layer','bottom','DataAspectRatio',[1 1 1],...
    'XColor',[0.3 0.3 0.3],'YColor',[0.3 0.3 0.3],...
    'Position',[0.70 0.10 0.200 0.302],...
    'Box','on','LineWidth',2,'Tag','RulesAx');
% load the null-image there
X  = imread( strrep('ImageSet\pieceRules-01.png','\',fs) );
hr = image([0 1],[0 1],mirrorImage(X));


% 3rd axis for game clock
axClock = axes('color','k','xlim',[0 1],'ylim',[0 1],...
    'Position',[0.7 0.6 0.2 0.2],'Tag','ClockAx');
title('- Game Clock -','color','w','fontsize',16,'fontweight','bold')
initGC = get(uih.GameClock,'userdata');
uih.hgcW = text(0.3,0.3,formatTimeStr(initGC(1)),'fontsize',24,...
    'backgroundcolor','w','fontweight','bold');
uih.hgcB = text(0.3,0.8,formatTimeStr(initGC(2)),'fontsize',24,...
    'fontweight','bold','backgroundcolor',([194 207 214]-30)/225);


% create axes object for plotting
axBoard = axes('color','none', ...
    'xlim',[0 cols]+[-.1 .1],'ylim',[0 rows]+[-.1 .1],...
    'xtick',[],'ytick',[],...
    'NextPlot','add',...
    'Layer','bottom',...
    'DataAspectRatio',[1 1 1],...
    'XColor',([194 207 214]-30)/225,'YColor',([194 207 214]-30)/225,...
    'Box','On','LineWidth',2,...
    'Position',[0.05 0.10 0.650 0.815],...
    'Tag','BoardAx');
title('Game State: play','color','w','fontsize',16,'fontweight','bold')

% store axes handles
hax = [axBoard axRules];

% Create chess board tiles
hsq = zeros(cols,rows);
for i = 1:cols
    for j=1:rows
        % if this square is on the playable area only, make a square patch
        if ~strcmpi(B.top(j+B.info.pad/2,i+B.info.pad/2).type,'OOB')
            if mod(i+j,2),  color = ([194 207 214]-30)/225; %black
            else            color = [1 1 1]; %white
            end
            hsq(i,j) = patch(i-1+[0 1 1 0], rows-j+[0 0 1 1], [1 1 1 1]*(0.9-2), color);
        end
    end
end


% box/highlight under the last moved piece
hlastmove = rectangle('position',[0 0 1 1],'facecolor','none',...
    'linewidth',1,'visible','off','edgecolor',[0.2 0.8 0.2],'linewidth',3);
% good yellow color if rectangle uistack works again: [0.95 0.95 0]

% if we click on a board tile, reset the rules display to the null image
set(hsq(:),'UserData',strrep('ImageSet\pieceRules-01.png','\',fs))
set(hsq(:),'ButtonDownFcn',{@ClickPiece,uih.f1,hlastmove,hax})

drawnow;

% load in images to various squares
for r=1:rows
    for c=1:cols
        % if there is an image associated with this square, render it
        if ~isempty(B.top(r+B.info.pad/2,c+B.info.pad/2).image)
            % load the image
            [X, map, alpha]  = imread(B.top(r+B.info.pad/2,c+B.info.pad/2).image);
            % draw the image
            imHdls(r,c) = image(c+[0 1]-1,[rows-1 rows]-r+1,...
                mirrorImage(X),'AlphaData',mirrorImage(alpha),...
                'ButtonDownFcn',{@ClickPiece,uih.f1,hlastmove,hax});
            % each image has a corresponding rules file, upload that file
            % path to the user data of this image
            set(imHdls(r,c),'UserData',B.top(r+B.info.pad/2,c+B.info.pad/2).rules)
            
            % store the handle of this image in its piece object - 
            % this information is stored so that graphics procedures can
            % occur in "MakeMove" for captures and castles, etc...
            B.top(r+B.info.pad/2,c+B.info.pad/2).himg = imHdls(r,c);
        end
    end
end

% draw up the board and get going
drawnow;

% assign the board object to the figure so that other functions have access
set(uih.f1,'userdata',B);

% call the function that sets the game loop in motion
ChessPeace('play')


    case 'play'
%% === MAIN GAME LOOP === %

% load in the board object stored in the figure window
B = get(gcf,'userdata');
% Get the type of game we're playing
ix = strcmp(get(get(uih.GameType,'Children'),'checked'),'on');   % which one is checked?
labels = get(get(uih.GameType,'Children'),'Label');
if any(ix)
    gameType = labels{ix};
else
    gameType = B.info.format;
end
    

% Get the names of the players
ix = strcmp(get(get(uih.White,'Children'),'checked'),'on');   % which one is checked?
labels = get(get(uih.White,'Children'),'Label');
ue{1} = labels{ix};
ix = strcmp(get(get(uih.Black,'Children'),'checked'),'on');   % which one is checked?
labels = get(get(uih.Black,'Children'),'Label');
ue{2} = labels{ix};

% disable the load and play commands to avoid errors
set(uih.Play,'enable','off')
set(uih.Load,'enable','off')
set(uih.GameType,'enable','off')
set(uih.White,'enable','off')
set(uih.Black,'enable','off')
set(uih.GameClock,'enable','off')

% create and start the game clock timer object
timerGC = timer('TimerFcn',{@clockCallback 'run' [uih.hgcW uih.hgcB]},...
    'Period',0.2,'ExecutionMode','FixedRate',...
    'UserData',get(uih.GameClock,'userdata'),'Tag','ChessPeaceTimer');
start(timerGC)

while 1
    
    % update the whose move indicator
    if B.info.turn==1; moveStr='White'; else moveStr='Black'; end
    set(uih.f1,'name',[moveStr ' to play (' gameType ')'])
    drawnow;
    
    % check for resignation
    if get(uih.Resign,'userdata')
        title('User Resigns','color','w','fontsize',16,'fontweight','bold')
        set(uih.Resign,'userdata',0)    % reset for next game
        break;
    end
        
    
    % get the next move
    if B.info.turn==1
        [move state] = RequestMove(ue{1},B);
    elseif B.info.turn==-1
        [move state] = RequestMove(ue{2},B);
    end
    
    % check for time forfiets
    clockState = get(timerGC,'userdata');
    if clockState(clockState(3))<=0
        if clockState(3)==1
            utitle = 'Game State: 0-1, White forfeits on time';
        else
            utitle = 'Game State: 1-0, Black forfeits on time';
        end
        title(utitle,'color','w','fontsize',16,'fontweight','bold')
        set(uih.f1,'name','Time Expired')
        break;
    else
        % otherwise switch the player's time
        clockCallback(timerGC,[],'swap')
    end
    
    % win conditions
    if ~strcmp(state,'play')
        fprintf(['Game Over - Outcome: ' state '\n\n'])
        title(['Game State: ' state],'color','w','fontsize',16,'fontweight','bold')
        set(uih.f1,'name',state)
        break;
    end
    
    % execute move (the final input 1 indicates that this move should be
    % considered by the graphics updater in MakeMove)
    B = MakeMove([move(1) move(2)],[move(3) move(4)],B,move(5),1);
    
    % assign the board object to the figure in case of saving
    set(uih.f1,'userdata',B);
    
end

% after the game, activate all menu objects for selection
set(uih.Play,'enable','on')
set(uih.Load,'enable','on')
set(uih.GameType,'enable','on')
set(uih.White,'enable','on')
set(uih.Black,'enable','on')
set(uih.GameClock,'enable','on')

% stop and delete the clock
stop(timerGC)
delete(timerGC)

    case 'save'
%% save a game

% pick up the game object
Bsv = get(uih.f1,'userdata');
% save the game to a file
uisave('Bsv',strrep('SavedGames\YourGame.mat','\',fs))
        

    case 'load'
%% load a saved game

% prompt user
[FileName,PathName,FilterIndex] = uigetfile(['SavedGames' fs '*.mat'],'Choose Your Game');

if FilterIndex==1
    % load chosen game object
    load([PathName FileName])
    % assign the board object to the figure in case of saving
    set(uih.f1,'userdata',Bsv);
    % uncheck all gametypes to indicate that we want to load a game from
    % file
    hc = get(uih.GameType,'Children');
    for i=1:length(hc)
        set(hc(i),'Checked','off')
    end
    % fire it up
    ChessPeace('buildboard')
end


    case 'resign'
%% end this game
        
set(uih.Resign,'userdata',1);
title('After This Move Resignation Will Take Effect','color','w','fontsize',12)

    case 'thinktime'
%% set the max amount of seconds the computer may take per move

% it is set to 60s upon startup

prompt = 'Enter tha maximum allowable thinking time available for computer opponents in seconds (no less than 10):';
dlgtitle = 'Set think time';
def = {int2str(get(uih.ThinkTime,'userdata'))};
answer = inputdlg(prompt,dlgtitle,1,def);

if ~isempty(answer)
    resp = str2double(answer{1});
    if isnan(resp)
        msgbox('Your entry was not valid.','Notice','help')
    else
        resp = round(max([resp 10]));  % we need at least 10s
        % update data with the user's response
        set(uih.ThinkTime,'userdata',resp)
        % update display
        ttlabel = ['Max Computer Thinking Time: ' num2str(resp) 's'];
        set(uih.ThinkTime,'Label',ttlabel)
    end
end

    case 'gameclock'
        
prompt = {'Enter time for White (min):'; 'Enter time for Black (min):'; 'Enter increment time (sec):'};
dlgtitle = 'Clock';
ud = cellstr(int2str(get(uih.GameClock,'userdata')'));
def = [ud(1) ud(2) ud(4)];
answer = inputdlg(prompt,dlgtitle,1,def);

if ~isempty(answer)
    resp = str2double(answer)'.*[60 60 1];
    if resp(1)<1 || resp(2)<1
        msgbox('Times must be greater than 1 second for both players','Notice','help')
    elseif ~isreal(resp(3)) && ~isnan(resp(3)) && resp(3)>=0
        msgbox('Your increment entry was not valid.','Notice','help')
    else
        set(uih.GameClock,'userdata',[resp(1:2) 1 resp(3)]);
    end
end
        
        
        
        
    otherwise
        error('unrecognized action')
end

Contact us