function slick(s)

if nargin == 0
   s = 4;
end

names = getNames();

again = true;
while again
   playGame(names, s)
   again = input('another round (1 or 0)? ');
end
end

% ------------------------

function playGame(names, s)

% b = char(zeros(s)+' ');
b = randi([1,3], s);
b(b == 1) = 'X';
b(b == 2) = 'O';
b(b == 3) = ' ';

t = 1;
m.type = ' ';
dxy.x = false;
dxy.y = false;

showBoard(b);
while m.type ~= 'q' && ~dxy.x && ~dxy.y
   m = getMove(s, names{t});
   while ~validMove(b, m, t)
      disp('oops - try again')
      m = getMove(s, names{t});
   end
   b = makeMove(b, m, t);
   dxy = checkRowsCols(b);
   t = 3 - t;
   showBoard(b);
end

if dxy.x
   p = 1;
else
   p = 2;
end
fprintf('Congrats %s!  You win!\n', names{p});

end

% --------------------------
function names = getNames()
names{1} = input('first player''s name: ','s');
names{2} = input('second player''s name: ','s');
end

% --------------------------
function showBoard(b)
fprintf('\n')
s = length(b);
for col = 1:s
   fprintf('+-')
end
fprintf('+\n')
for row = 1:s
   fprintf('|%c', b(row,:))
   fprintf('|\n')
   for col = 1:s
      fprintf('+-')
   end
   fprintf('+\n')
end
fprintf('\n')
end

% ---------------------------
function m = getMove(s, n)
fprintf('%s, your move - ', n)
m.type = input('shift (nsew) place marker (m) or quit (q): ','s');
if m.type == 'm'
   m.row = input('row: ');
   m.col = input('col: ');
elseif m.type  == 'n' | m.type == 's'
   m.row = 0;
   m.col = input('col: ');
elseif m.type == 'e' | m.type  == 'w'
   m.row = input('row: ');
   m.col = 0;
end
end

% --------------------------
function v = validMove(b, m, t)
s = length(b);
mark = 'XO';
v1 = any('nsewmq' == m.type);
v2 = m.type == 'm' && m.row > 0 && m.col > 0 && m.row <= s && m.col <= s && b(m.row,m.col)==' ';
v3 = (m.type == 'n' || m.type == 's') && m.col > 0 && m.col <= s && any(b(:,m.col) == mark(t));
v4 = (m.type == 'e' || m.type == 'w') && m.row > 0 && m.row <= s && any(b(m.row,:) == mark(t));
v5 = m.type == 'q';
v = v1 && (v2 || v3 || v4 || v5);

if ~v1
   disp('invalid command')
elseif ~v && m.type == 'm'
   disp('illegal placement')
elseif ~v && m.type == 'n' || m.type == 's'
   disp('illegal column')
elseif ~v && m.type == 'e' || m.type == 'w'
   disp('illegal row')
end 
end

% ---------------------------
function b = makeMove(b, m, t)
disp('making move')
mark = 'XO';
if m.type == 'm'
   b(m.row, m.col) = mark(t);
elseif m.type == 'n'
   b(:,m.col) = [b(2:end,m.col);b(1,m.col)];
elseif m.type == 's'
   b(:,m.col) = [b(end,m.col);b(1:end-1,m.col)];
elseif m.type == 'e'
   b(m.row,:) = [b(m.row,end),b(m.row,1:end-1)];
elseif m.type == 'w'
   b(m.row,:) = [b(m.row,2:end),b(m.row,1)];
elseif m.type == 'q'
   disp('quitting!')
end
end
 
% ---------------------------
function d = checkRowsCols(b)
mark = 'XO';
d.x = straight(b, mark(1));
d.y = straight(b, mark(2));
end

% ---------------------------
function d = straight(b, m)
eyeb = eye(length(b));
d = any(all(b' == m)) || ...
    any(all(b == m)) || ...
    all(sum(b .* eyeb) == m) || ...
    all(sum(fliplr(b) .* eyeb) == m);
end

