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