function sudoku
global board

% basic idea
% set up game
% get custom board
% play game
% show board
% solved?
% columns, rows, quads solved? (each checked incrementally)
% make a guess and verify
% really verify
% really really verify (row, column, quad)
% ok, this time totally verify (sorted 9 digits)
% give a hint (and clean up other debugging disps)

another = true;
while another
  setUpGame();
  playGame();
  another = anotherGame();
end
return

function setUpGame()
global board
% disp('Setting Up Game');
board(1:9,1:9) = ' ';
ans = input('Custom or Default Board? (0 custom, 1 default) ');
if ans == 0
  getCustomBoard();
else
  board = ['1   9   8'
           ' 897    3'
           ' 4     7 '
           '     294 '
           '   5 1   '
           ' 243     '
           ' 1     5 '
           '8    763 '
           '7   5   4'];
end
return

function getCustomBoard()
global board
disp('Getting Custom Board');
disp('Enter each line with periods and numerals eg ..26...1.');
disp('        123456789');
for ii=1:9
  fprintf('line %1d', ii);
  board(ii,1:9) = input(': ','s');
end
mask = board == '.';
board(mask) = ' ';
return

function playGame()
global board
% disp('Playing Game');
while ~solved()
  showBoard();
  choice = showMenu();
  switch choice
    case 1,
      makeGuess();
    case 2,
      getHint();
    otherwise,
      disp('Quitting!');
      break;
  end 
end
return

function showBoard()
global board
% disp('Showing the Board');
fprintf('\n');
fprintf('+-----+-----+-----+\n');
fprintf('|%c %c %c|%c %c %c|%c %c %c|\n', board(1,1:9));
fprintf('|%c %c %c|%c %c %c|%c %c %c|\n', board(2,1:9));
fprintf('|%c %c %c|%c %c %c|%c %c %c|\n', board(3,1:9));
fprintf('+-----+-----+-----+\n');
fprintf('|%c %c %c|%c %c %c|%c %c %c|\n', board(4,1:9));
fprintf('|%c %c %c|%c %c %c|%c %c %c|\n', board(5,1:9));
fprintf('|%c %c %c|%c %c %c|%c %c %c|\n', board(6,1:9));
fprintf('+-----+-----+-----+\n');
fprintf('|%c %c %c|%c %c %c|%c %c %c|\n', board(7,1:9));
fprintf('|%c %c %c|%c %c %c|%c %c %c|\n', board(8,1:9));
fprintf('|%c %c %c|%c %c %c|%c %c %c|\n', board(9,1:9));
fprintf('+-----+-----+-----+\n');
fprintf('\n');
return

function choice = showMenu();
% disp('Showing a Menu');
choice = input('1 - Make a guess, 2 - Get a hint, other - quit: ');
return

function done = solved()
% disp('Solved?');
done = allColumnsDone() & allRowsDone() & allQuadsDone();
return

function done = allColumnsDone()
global board
% disp('Columns done?');
a = sort(board,1);
n = ['1':'9']';
n = [n n n n n n n n n];
c = a == n;
done = sum(sum(c)) == 81;
return

function done = allRowsDone()
global board
% disp('Rows done?');
a = sort(board,2);
n = ['1':'9'];
n = [n;n;n;n;n;n;n;n;n];
c = a == n;
done = sum(sum(c)) == 81;
return

function done = allQuadsDone()
global board
% disp('Quads done?');
n = ['1':'9'];
done = true;
for ii = 1:3:7
  for jj = 1:3:7
    q = board(ii:ii+2, jj:jj+2);
    q = q(1:9);
    q = sort(q);
    c = q == n;
    done = done && sum(c) == 9;
  end
end
return

function makeGuess()
global board
% disp('Making a Guess');
guess = input('Enter [row col guess]: ');
row = guess(1);
col = guess(2);
s = board(row,col);
board(row,col) = int2str(guess(3));
if ~validBoard(row,col)
  board(row,col) = s;
  disp('Invalid Numeral!');
end
return

function valid = validBoard(row,col)
global board
% disp('Check for valid board');
quad = ceil([row col]/3);
valid = validRow(row) & validCol(col) & validQuad(quad);
return

function valid = validRow(row)
global board
% disp('Check for valid row');
r = sort(board(row,:));
valid = valid9(r);
return

function valid = validCol(col)
global board
% disp('Check for valid col');
c = sort(board(:,col));
valid = valid9(c');
return

function valid = validQuad(quad)
global board
% disp('Check for valid quad');
row = quad(1)*3-2;
col = quad(2)*3-2;
q(1:9) = board(row:row+2, col:col+2);
q = sort(q);
valid = valid9(q);
return

function valid = valid9(r)
% disp('Check for 9 valid');
r = strtrim(r);
validChars = (r >= '1' & r <= '9');
dups = r(1:end-1) == r(2:end);
valid = sum(validChars) == length(r) & sum(dups) == 0;
return

function getHint()
disp('Get a Hint');
hint = false;
row = 1;
while row <= 9 && ~hint
  col = 1;
  while col <= 9 && ~hint
    hint = goodSpot(row, col);
    col = col + 1;
  end
  row = row + 1;
end
return

function hint = goodSpot(row, col)
disp('Is this a good spot?');
hint = false;
return

function another = anotherGame();
another = input('Play again?  (0 no, 1 yes) ');
return

