function sudoku(varargin)
% sudoku
%
% Sudoku GUI for Matlab
%
% Created 2006 by Johnny Brannbacka
% <jbrannba@gmail.com>
%
if nargin==0,
h_main=openfig(mfilename,'new');
centerfig(h_main);
handles=guihandles(h_main);
guidata(h_main,handles);
initialize(handles);
else
if nargin>1,
feval(varargin{1},varargin{2:end})
else
feval(varargin{1})
end
end
%--------------------------------------------------------------------------
function initialize(handles)
set(handles.sudoku,'buttondownfcn','sudoku(''highlight'',guidata(gcbo),0)','keypressfcn','sudoku(''keypress'',guidata(gcbo))');
axes(handles.axes1);
cla
set(handles.axes1,'nextplot','add');
h_text=[];
h_field=[];
for i=1:9,
for j=1:9,
ix=sub2ind([9 9],i,j);
h_field(ix)=fill([-1 0 0 -1]+i,[-1 -1 0 0]+j,'w','buttondownfcn',['sudoku(''highlight'',guidata(gcbo),' num2str(ix) ')']);
h_text(ix)=text(i-0.5,j-0.5,'','fontunits','normalized','fontsize',0.07,'horizontalalignment','center','buttondownfcn',['sudoku(''highlight'',guidata(gcbo),' num2str(ix) ')']);
end
end
setappdata(handles.sudoku,'h_text',h_text);
setappdata(handles.sudoku,'h_field',h_field);
for i=0:3:9,
h=plot([0 9],[i i],'k-');
set(h,'linewidth',2.5);
h=plot([i i],[0 9],'k-');
set(h,'linewidth',2.5);
end
hlbox=plot([0 1 1 0 0],[0 0 1 1 0],'r-');
set(hlbox,'linewidth',3,'visible','off');
axis([-0.03 9.03 -0.03 9.03]);
axis equal
axis off
s=zeros(9);
setappdata(handles.sudoku,'s',s);
setappdata(handles.sudoku,'s0',s);
setappdata(handles.sudoku,'ss',s);
setappdata(handles.sudoku,'hlbox',hlbox)
setappdata(handles.sudoku,'selected',0)
setappdata(handles.sudoku,'t0',clock);
setappdata(handles.sudoku,'cheated',0);
%--------------------------------------------------------------------------
function create_sudoku(handles)
t=timer('timerfcn','waitbar(mod(etime(clock,t0)/60,1),hwb)','period',1 ...
,'startfcn','hwb=waitbar(0,''Please wait...'',''windowstyle'',''modal'');t0=clock;' ...
,'stopfcn','delete(hwb)','executionmode','fixedrate');
start(t);
n=get(handles.create_slider,'value');
[s,ss]=sudoku_construct(n);
h_text=getappdata(handles.sudoku,'h_text');
for i=1:9,
for j=1:9,
ix=sub2ind([9 9],i,j);
if s(ix)==0,
str='';
else
str=num2str(s(ix));
end
set(h_text(ix),'string',str,'color','black');
end
end
stop(t);
delete(t);
setappdata(handles.sudoku,'s',s);
setappdata(handles.sudoku,'s0',s);
setappdata(handles.sudoku,'ss',ss);
setappdata(handles.sudoku,'t0',clock);
setappdata(handles.sudoku,'cheated',0);
%--------------------------------------------------------------------------
function highlight(handles,ix);
hlbox=getappdata(handles.sudoku,'hlbox');
if ix>0,
[i,j]=ind2sub([9 9],ix);
set(hlbox,'xdata',i+[-1 0 0 -1 -1],'ydata',j+[-1 -1 0 0 -1],'visible','on');
else
set(hlbox,'visible','off');
end
setappdata(handles.sudoku,'hlbox',hlbox)
setappdata(handles.sudoku,'selected',ix)
%--------------------------------------------------------------------------
function keypress(handles);
ix=getappdata(handles.sudoku,'selected');
s0=getappdata(handles.sudoku,'s0');
s=getappdata(handles.sudoku,'s');
key=get(handles.sudoku,'currentcharacter');
if ix>0 && ismember(double(key),[28:31]),
[i,j]=ind2sub([9 9],ix);
if double(key)==28,
i=i-1;
elseif double(key)==29,
i=i+1;
elseif double(key)==30,
j=j-1;
else
j=j+1;
end
if i>=1 && i<=9 && j>=1 && j<=9,
ix=sub2ind([9 9],i,j);
highlight(handles,ix);
end
return
end
ix0=find(s0==0);
if ~ismember(ix,ix0),
return
end
h_text=getappdata(handles.sudoku,'h_text');
h_field=getappdata(handles.sudoku,'h_field');
if ismember(double(key),[8 32 48 127]),
s(ix)=0;
set(h_text(ix),'string','');
setappdata(handles.sudoku,'s',s);
elseif ismember(double(key),[49:57]),
st=s;
st(ix)=str2num(key);
[i,j]=ind2sub([9 9],ix);
[rok,ind]=rulesok(st,i,j);
set(h_text(ix),'string',key,'color',0.5*[1 1 1]);
if rok,
s(ix)=str2num(key);
setappdata(handles.sudoku,'s',s);
if ~any(s(:)==0),
t0=getappdata(handles.sudoku,'t0');
dt=etime(clock,t0);
t_h=floor(dt/(60*60));
t_m=floor((dt-t_h*(60*60))/60);
t_s=round(dt-t_h*(60*60)-t_m*60);
t_str=[];
if t_h>0,
t_str=[num2str(t_h) ' h '];
end
if t_m>0,
t_str=[t_str num2str(t_m) ' min '];
end
t_str=[t_str num2str(t_s) ' s '];
cheated=getappdata(handles.sudoku,'cheated');
if cheated,
t_str=[t_str ', BUT YOU CHEATED!!'];
end
h=msgbox(['You have solved the sudoku puzzle in ' t_str],'Congratulations!','modal');
uiwait(h);
end
else
set(h_field(ind),'facecolor',[1 0.8 0.8]);
drawnow;
pause(1);
set(h_field(ind),'facecolor','white');
set(h_text(ix),'string','');
end
end
%--------------------------------------------------------------------------
function [rok,ind]=rulesok(s,i,j)
ix=sub2ind(size(s),i,j);
ix1=sub2ind(size(s),i*ones(1,9),1:9);
ix1=ix1(find(ix1~=ix));
ix2=sub2ind(size(s),1:9,j*ones(1,9));
ix2=ix2(find(ix2~=ix));
if i<=3,
xv=1:3;
elseif i<=6,
xv=4:6;
else
xv=7:9;
end
if j<=3,
yv=1:3;
elseif j<=6,
yv=4:6;
else
yv=7:9;
end
[x,y]=meshgrid(xv,yv);
ix3=sub2ind(size(s),x(:)',y(:)');
ix3=ix3(find(ix3~=ix));
rok = ~(any(s(ix)==s(ix1)) | any(s(ix)==s(ix2)) | any(s(ix)==s(ix3)));
if nargout==2,
ind=[];
i=find(ismember(s(ix1),s(ix)));
ind=[ind ix1(i)];
i=find(ismember(s(ix2),s(ix)));
ind=[ind ix2(i)];
i=find(ismember(s(ix3),s(ix)));
ind=[ind ix3(i)];
end
%--------------------------------------------------------------------------
function hint(handles);
s=getappdata(handles.sudoku,'s');
h_field=getappdata(handles.sudoku,'h_field');
s1=sudokusolve(s,0,1);
ix=find(s1-s);
set(h_field(ix),'facecolor',[0.8 1 0.8]);
waitforbuttonpress
set(h_field(ix),'facecolor','white');
setappdata(handles.sudoku,'cheated',1);
%--------------------------------------------------------------------------
function solve_number(handles);
s=getappdata(handles.sudoku,'s');
h_field=getappdata(handles.sudoku,'h_field');
h_text=getappdata(handles.sudoku,'h_text');
s1=sudokusolve(s,0,1);
ix=find(s1-s);
ix=ix(randperm(length(ix)));
s(ix(1))=s1(ix(1));
set(h_text(ix(1)),'string',num2str(s1(ix(1))),'color',0.5*[1 1 1])
setappdata(handles.sudoku,'s',s);
set(h_field(ix(1)),'facecolor',[0.8 1 0.8]);
waitforbuttonpress
set(h_field(ix(1)),'facecolor','white');
setappdata(handles.sudoku,'cheated',1);
%--------------------------------------------------------------------------
function solve_step(handles);
s=getappdata(handles.sudoku,'s');
h_field=getappdata(handles.sudoku,'h_field');
h_text=getappdata(handles.sudoku,'h_text');
s1=sudokusolve(s,0,1);
ix=find(s1-s);
s(ix)=s1(ix);
for i=1:length(ix),
set(h_text(ix(i)),'string',num2str(s1(ix(i))),'color',0.5*[1 1 1]);
end
setappdata(handles.sudoku,'s',s);
set(h_field(ix),'facecolor',[0.8 1 0.8]);
waitforbuttonpress
set(h_field(ix),'facecolor','white');
setappdata(handles.sudoku,'cheated',1);
%--------------------------------------------------------------------------
function solve_all(handles);
s=getappdata(handles.sudoku,'s');
h_field=getappdata(handles.sudoku,'h_field');
h_text=getappdata(handles.sudoku,'h_text');
s1=sudokusolve(s);
ix=find(s1-s);
s(ix)=s1(ix);
for i=1:length(ix),
set(h_text(ix(i)),'string',num2str(s1(ix(i))),'color',0.5*[1 1 1]);
end
setappdata(handles.sudoku,'s',s);
set(h_field(ix),'facecolor',[0.8 1 0.8]);
waitforbuttonpress
set(h_field(ix),'facecolor','white');
setappdata(handles.sudoku,'cheated',1);
%--------------------------------------------------------------------------
function delete_incorrect(handles);
s=getappdata(handles.sudoku,'s');
ss=getappdata(handles.sudoku,'ss');
h_field=getappdata(handles.sudoku,'h_field');
h_text=getappdata(handles.sudoku,'h_text');
ix=find((s-ss)~=0 & s~=0);
s(ix)=0;
for i=1:length(ix),
set(h_text(ix(i)),'string','','color',0.5*[1 1 1]);
end
setappdata(handles.sudoku,'s',s);
set(h_field(ix),'facecolor',[0.8 1 0.8]);
waitforbuttonpress
set(h_field(ix),'facecolor','white');
setappdata(handles.sudoku,'cheated',1);