function stratego(varargin)
% Two player game of Stratego played on two computers

% Iteration 17  - Improving open board exchange routine
%
% Arguments:
%    sharePath (string)     path to shared files
%                              URL - access via Web
%                              file path - access via DropBox
%                              default - .
%    board (string)        file name for starting board
%                              contains only the user's side of board
%                              .xls file - data in Excel file
%                              .dat file - text file, 4 rows, 10 columns
%                              default - use built-in sample board
%    startFirst (logical)  true for starting player
%                          false (default) for second player
%    hist (string)         name of history (.log) file
%                             exist - resume game from end
%                             ~exist - new game
%                             contains complete starting board
%                                and a log of plays
%                             default - create unique file name

global testing
testing = true;

args = getArgs(varargin);
% args.postLocation
% args.loadLocation
% args.loadType
% args.board
% args.startFirst
% args.logFile

board = getBoard(args);

displayBoard(board);

if ~args.startFirst
   fprintf('Please wait for other player''s move')
   move.quit = false;
else
    [move, board] = makeMove(board, 'W');
end

while ~Done(move, board)
   [move, board] = waitForOthersMove(board);
   displayBoard(board)
   if ~Done(move, board)
      [move, board] = makeMove(board, 'W');
      displayBoard(board)
   end
end

displayWinner(board)
end

% --------------------------------------------
function args  = getArgs(vargs)

disp('processing arguments')
fxls2str = @(cells) char((cells<64)*48 + cells);
args.postLocation = './';
args.loadLocation = 'file:///Users/chuckr/Dropbox/MatlabShare/Stratego/';
args.loadType = 'URL';
args.board = defaultBoard();
args.startFirst = false;
args.logFile = ['stratego' datestr(clock) '.log'];
args.logFile(20) = '-';
argCount = length(vargs);
ii = 1;
if ii <= argCount && islogical(vargs{ii})
   args.startFirst = vargs{ii};
   ii = ii + 1;
end
if ii <= argCount && isdir(vargs{ii})
   args.postLocation = vargs{ii};
   args.loadLocation = vargs{ii};
   args.loadType = 'FILE';
   ii = ii + 1;
end
if ii <= argCount && isdir(vargs{ii})
   args.loadLocation = vargs{ii};
   args.loadType = 'FILE';
   ii = ii + 1;
elseif ii <= argCount && strncmpi(vargs{ii}, 'http://', 7)
   args.loadLocation = vargs{ii};
   args.loadType = 'URL';
   ii = ii + 1;
end
for ii = ii:ii+1
   if ii < argCount
      [p, n, ext] = fileparts(vargs{ii});
      switch ext 
         case '.xls',
            [nums strs raw] = xlsread(vargs{ii});
            args.board = fxls2str(raw);
         case '.dat',
            f = fopen(vargs{ii});
            args.board = reshape(fscanf(f, '%s', 4), 4, 10);
            fclose(f)
         case '.log',
            args.logFile = vargs{ii};
            fil = dir(vargs{ii});
            if length(fil) == 1 && fil.bytes > 0
               args.logs = loadLog(vargs{ii});
            end
      end
   end
end
end

% --------------------------------------------
function board = defaultBoard()
disp('getting default board')
board = ['4696899999'
         '2987914587'
         '45B3S85B38'
         '6BFB75B7B6'];
end

% -------------------------------------------
function board = getBoard(args)
global testing

disp('getting the board')

% for testing, create the opponent's board and save it in our Web site
tboard = args.board;
save([args.postLocation 'board'], 'tboard')

% for testing, bring in opponent's board from 'their' Web site and load
status = false;
while ~status
  [f, status] = urlwrite([args.loadLocation 'board.mat'], 'tboard.mat')
end
load('tboard')

board.piece = [fliplr(flipud(tboard)); reshape(blanks(20),2,10); args.board];
board.piece(5:6, [3,4,7,8]) = '*';
board.owner = [repmat('B',4,10); reshape(blanks(20),2,10); repmat('W',4,10)];
board.owner(5:5, [3,4,7,8]) = '*';
end

% -------------------------------------------
function displayBoard(board)

global testing

disp('displaying board')
fprintf('\n\n    ')
for col = 'A':'J' 
   fprintf('  %c ', col)
end
for row = 1:10
   fprintf('\n    +')
   for col = 1:10
      fprintf('---+')
   end
   fprintf('\n %2d |', row)
   for col = 1:10
      if testing
         if board.owner(row,col) ~= 'B'
            fprintf(' %c |', board.piece(row,col))
         else
            fprintf(2,' %c ', board.piece(row,col))
            fprintf('|')
         end
      else
         if board.owner(row,col) ~= 'B'
            fprintf(' %c |', board.piece(row,col))
         else
            fprintf(2,' X ')
            fprintf('|')
         end
      end
   end
end
fprintf('\n    +')
for col = 1:10
   fprintf('---+')
end
fprintf('\n\n')
end


% -------------------------------------------
function [move, board] = waitForOthersMove(board)

global testing
disp('waiting for other player to move')
if testing
   [move, board] = makeMove(board, 'B');
else
   [move, board] = getForeignMove(board);
end
end

% -------------------------------------------
function [move, board] = makeMove(board, colour)

disp('making a move')
fprintf('Player %c, your turn (q - quit, cr-cr - from-to) ', colour)
move = parseMove(upper(input(': ','s')))
while ~move.quit && ~validPlay(board, move, colour)
   displayBoard(board)
   fprintf(2, 'Oops! Not valid! (q - quit, cr-cr - from-to) ', colour)
   move = parseMove(upper(input(': ','s')))
end
if ~move.quit
   board = movePiece(move, board)
end
end

% -------------------------------------------
function board = movePiece(move, board)

piece = board.piece(move.r1, move.c1); 
owner = board.owner(move.r1, move.c1);
board.piece(move.r1, move.c1) = ' ';
board.owner(move.r1, move.c1) = ' ';
tpiece = board.piece(move.r2, move.c2);
towner = board.owner(move.r2, move.c2);
if piece == tpiece
   board.piece(move.r2, move.c2) = ' ';
   board.owner(move.r2, move.c2) = ' ';
elseif piece < tpiece && tpiece ~= 'B' || piece == '8' && tpiece == 'B' || ...
      piece == 'S' && tpiece == '1' || tpiece == ' '
   board.piece(move.r2, move.c2) = piece;
   board.owner(move.r2, move.c2) = owner;
end
end

% -------------------------------------------
function play = parseMove(move)

disp('parse the move request')
play = regexpi(move, ...
   '(?<c1>[A-J])(?<r1>(10|[1-9])).*(?<c2>[A-J])(?<r2>(10|[1-9]))', 'names');
if length(play) > 0
   play.r1 = str2num(play.r1);
   play.r2 = str2num(play.r2);
   play.c1 = play.c1 - '@';
   play.c2 = play.c2 - '@';
   play.good = true;
else
   play(1).good = false;
end
play(1).quit = strcmp(move, 'Q');
end

% -------------------------------------------
function valid = validPlay(board, play, colour)

disp('valid play?')
     % zeroth test - play parsed correctly to cr-cr on the board
if ~play.good
   disp('bad format or off the board')
   valid = false;
   return
end
     % first test - rectilinear coordinates
valid = play.quit || play.r1 == play.r2 || play.c1 == play.c2;
if ~valid
   disp('not rectilinear')
   return
end
     % second test - distance of move is 1, or piece is scout with an open stretch
valid = (abs(play.r1 - play.r2) == 1 || abs(play.c1 - play.c2) == 1 || ...
        (board.piece(play.r1,play.c1) == '9' && openGap(board, play)));
if ~valid
   disp('illegal distance')
   return
end
     % third test - your piece is designated to move and is not a flag or bomb
valid = board.owner(play.r1,play.c1) == colour && ...
        board.piece(play.r1,play.c1) ~= 'B' && ...
        board.piece(play.r1,play.c1) ~= 'F';
if ~valid
   disp('can not move that piece - not yours or is flag/bomb')
   return
end
     % fourth test - destination does not hold one of your own pieces
valid = board.owner(play.r2,play.c2) ~= colour;
if ~valid
   disp('destination has one of your pieces')
   return
end
     % fifth test - destination is not in a lake
valid = board.owner(play.r2,play.c2) ~= '*';
if ~valid
   disp('you are not able to swim')
end
end

% -------------------------------------------
function gap = openGap(board, play)

disp('open gap?')
gap = true;
if play.r1 > play.r2
   t = play.r1;
   play.r1 = play.r2;
   play.r2 = t;
end
if play.c1 > play.c2
   t = play.c1;
   play.c1 = play.c2;
   play.c2 = t;
end
rgap = play.r2 - play.r1;
cgap = play.c2 - play.c1;
if rgap > 0
   pgap = board.piece(play.r1+1:play.r2-1, play.c1)'
   dgap = rgap-1;
else
   pgap = board.piece(play.r1, play.c1+1:play.c2-1)
   dgap = cgap-1;
end
gap = strcmp(blanks(dgap),pgap);
end

% -------------------------------------------
function board = getForeignMove(board)

disp('getting foreign move')
end

% -------------------------------------------
function done = Done(move, board)

disp('are we done?')
[r c] = find(board.piece == 'F');
done = move.quit || length(r) < 2;
end

% -------------------------------------------
function displayWinner(board)

disp('display winner')
[r c] = find(board.piece == 'F');
if length(r) == 2
   disp('The game is a tie')
else
   fprintf('The winner is player %c\n', board.owner(r,c))
end
end

