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)
% more hint - good spot to fill in group of 8?
% more hint - good spot to fill by elimination?

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, 3 - 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 = [row col] - mod([row col] - 1, 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);
col = quad(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()
global board
disp('Get a Hint');
hint = false;
row = 1;
while row <= 9 && ~hint
  col = 1;
  while col <= 9 && ~hint
    if board(row,col) == ' '
      hint = goodSpot(row, col);
    end
    col = col + 1;
  end
  row = row + 1;
end
if ~hint
  disp('Sorry - no hint!');
end
return

function hint = goodSpot(row, col)
disp('Is this a good spot?');
quad = [row col] - mod([row col] - 1, 3);
hint = checkRowColQuad(row, col, quad);
return

function hint = checkRowColQuad(row, col, quad)
global board
disp('Checking row/col/quad');
qr = quad(1);
qc = quad(2);
q(1:9) = board(qr:qr+2, qc:qc+2)
r = board(row,:)
c = board(:,col);
c = c'
q = strtrim(sort(q))
r = strtrim(sort(r))
c = strtrim(sort(c))
hint = length(q) == 8 | length(r) == 8 | length(c) == 8;
if hint
  disp('Simple complete 9');
end
s = sort([q r c])
df = s(2:end) - s(1:end-1)
spread = s(end) - s(1)
bigGap = df > 1
tBigGap = sum(df(bigGap))
hint2 = (spread == 8 & tBigGap == 2) || (spread == 7 & tBigGap == 0)
if hint2
  disp('More complicated multiway complete 9');
end
if spread == 8 & tBigGap == 0
  disp('Inconsistancy!!!!');
end
hint = hint | hint2;
if hint
  fprintf('Look at row %d, col %d\n', row, col);
end
return


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

