www.gusucode.com > 三维模仿源码程序 > 三维模仿源码程序/MathRubik2/SSSsolver.m
function [sol,Nparts]=SSSsolver(varargin) % SSSsolver - Singmasters Step by Step Solution % sol=SSSsolver[(Cube)] % % One of the many "step-by-step" solution where each step % solves one layer. % Some changes to the method from the book were done. % too much calls of CheckCube --- a problem? % also a lot of RotateCube's for "easy alignment" % when looking for a starting layer, with possible layer rotations: % getting a full layer, only turned is a fully bad layer % while it is "almost good" % ?a test to be added in CheckCube? % or using the loops options=varargin; hAxesBase=[]; if nargin&isstruct(varargin{1}) Cube=varargin{1}; options(1)=[]; else hAxesBase=FindRubikAxes; Cube=get(hAxesBase,'UserData'); end NbfMax=1; Anime=0; bAnimeSepWin=1; bCloseWin=1; iAltSol=1; bPostOptim=true; % if ~isempty(varargin) % setoptions({'NbfMax','Anime','bAnimeSepWin','iAltSol','bPostOptim'},options) % end if Anime if bAnimeSepWin f=findobj('Tag','SSSshow'); if isempty(f) [f,hAxes]=Rubik; set(f,'Tag','SSSshow','Name','Singmasters Step by Step'); set(hAxes,'Tag','SSSshowAxes') else hAxes=findobj(f,'Tag','SSSshowAxes'); end PlotCube(hAxes,Cube); else hAxes=FindRubikAxes; end else hAxes=[]; end Cube.sol=[]; Nparts=zeros(1,9); %%%% check for some easy to find solutions. OK=false; n=0; while ~OK n=n+1; [sol,OK]=solverbbf(Cube,n); % search by a "brute force" method if n>=NbfMax break; end end if ~OK sol=zeros(0,2); D=CheckCube(Cube); % Since brute force methods are checkd, D.OK will be false Rstart=[2 1;2 -1;1 -1;1 1;1 2;1 0]; MidLayer=[10 12 16 18]; %%Which layer to start with? iStart=find(D.NOK(:,1)==8); if isempty(iStart) % dummy search for a better start after one turn [mx,iStart]=FindBestStart(D); R=[1 0 0]; while R(1)&mx<8 R(1)=0; for Axe=1:3 for Side=[-1 1] for Direction=[-1 1 2] C1=RotateLayer([],Cube,Axe,Side,Direction,0); D1=CheckCube(C1); [mx1,iMx1]=FindBestStart(D1); mx1=floor(mx1); %!!!!no rotation only for corner if mx1>mx R(:)=[Axe Side Direction]; mx=mx1; iStart=iMx1; if mx>=4 % also here it is better to look to "the best second layer"! break end end end % for Direction if mx>=4 break end end % for Side if mx>=4 break end end % for Axe if R(1) Cube=RotateLayer(hAxes,Cube,R(1),R(2),R(3),Anime); sol(end+1,:)=FRU2Color(R,Cube); end end else mx=5; if length(iStart)>1 % A complex method to look for the best starting layer. % The best mid layer is searched by a lot of rotations and CheckCubes! Cube1=Cube; Nok=zeros(1,length(iStart)); for i=1:length(iStart) if Rstart(iStart(i),2) Cube1=RotateCube(hAxes,Cube,Rstart(iStart(i),1),Rstart(iStart(i),2),0); else Cube1.Color=Cube.Color; end D=CheckCube(Cube1); Nok(i)=sum(D.P(MidLayer)==-10); end [n,i]=max(Nok); iStart=iStart(i); end end Nparts(1)=size(sol,1); % Rotate cube to set starting layer to the top (Up) % (this is in fact only necessary if mx<4) if Rstart(iStart,2) Cube=RotateCube(hAxes,Cube,Rstart(iStart,1),Rstart(iStart,2),Anime); end % !!!!!behoud zoveel mogelijk tweede laag bij opbouwen eerste laag RrotToDF=[1 2 0 -1]; RrotToRU=[2 1 -1 0]; RrotToFU=[-1 2 0 1]; SetTitle(hAxes,'Correct edges of first layer'); Clayer1=Cube.Color(6,Cube.RotLayerCube(6,5)); while mx<4 % edges to do % (by the selection of the starting layer, there are no easy % turns to get edges at the right position) % from bottom (with top color at the bottom) iC=find(Cube.Color(5,Cube.RotLayerCube(5,2:2:8))==Clayer1); D=CheckCube(Cube); % ?first test if an edge of the second layer needs only one turn? if ~isempty(iC) iCube=Cube.RotLayerCube(5,iC*2); if any(D.P(iCube)==iCube+18) % right above % this is not possible the first time, but maybe after some rotations iCube=iCube(find(D.P(iCube)==iCube+18)); else % just take the first (for now), a better choice can be made % (this is done always, so don't do anything) end % to make it easy, the cube is rotated to an easy position. iCube=iCube(1); [Cube,iCube]=RotateTo(D.P(iCube),24,iCube,hAxes,3,Cube,Anime); R=[3,-1,RrotToDF(iCube/2);1 1 2]; mx=mx+1; elseif any(D.P(2:2:8)>19) % from bottom layer (but rotated) iCube=find(D.P(2:2:8)>19)*2; iCube=iCube(1); [Cube,iCube]=RotateTo(D.P(iCube),24,iCube,hAxes,3,Cube,Anime); R=[3 -1 RrotToDF(iCube/2);1,1,-1;3,1,-1;2,1,1;3,1,1]; mx=mx+1; elseif any(D.P(MidLayer)>19) % from middle layer iC=find(D.P(MidLayer)>19); iC=iC(1); iCube=MidLayer(iC); [Cube,iNew]=RotateTo(iCube,18,D.P(iCube),hAxes,3,Cube,Anime); if Cube.Color(2,18)==Clayer1 n=RrotToRU((iNew-18)/2); A=[2 1 1]; else n=RrotToFU((iNew-18)/2); A=[1 1 -1]; end R=[3 1 n;A;3 1 -n]; mx=mx+1; else % from top layer % just rotate (!without looking to a possible best solution!) iCube=find(D.P(20:2:26)>19|D.P(20:2:26)==-5)*2+18; iSurf=find(Cube.Color(:,iCube(1))>0); iSurf=iSurf(1); R=[floor((iSurf+1)/2) rem(iSurf-1,2)*2-1 1]; end Cube=RotateLayer(R,Anime,hAxes,Cube); R=FRU2Color(R,Cube); sol(end+1:end+size(R,1),:)=R; end Nparts(2)=size(sol,1); SetTitle(hAxes,'Correct corners of first layer'); %% now the corners of the first layer RrotToFRD=[2 0 1 0 0 0 -1 0 0]; D=CheckCube(Cube); nOK=sum(D.P(19:27)==-10); while nOK<8 iC=find(D.P(1:9)>18); if ~isempty(iC) iCube=find(Cube.Color(5,iC)~=Clayer1); if isempty(iCube) iCube=iC(1); else iCube=iC(iCube(1)); end [Cube,iCube]=RotateTo(D.P(iCube),27,iCube,hAxes,3,Cube,Anime); R=[3 -1 RrotToFRD(iCube)]; if R(3) Cube=RotateLayer(R,Anime,hAxes,Cube); R=FRU2Color(R,Cube); sol(end+1,:)=R; end if Cube.Color(2,9)==Clayer1 R=[1 1 1;3 -1 1;1 1 -1]; elseif Cube.Color(4,9)==Clayer1 R=[2 1 -1;3 -1 -1;2 1 1]; else R=[1 1 1;3 -1 2;1 1 -1;3 -1 2;2 1 -1;3 -1 1;2 1 1]; end nOK=nOK+1; else % all corners in upper layer iC=find(D.P(19:27)==-5|D.P(19:27)>18); iC=iC(1)+18; Cube=RotateTo(iC,27,[],hAxes,3,Cube,Anime); R=[2 1 -1;3 -1 -1;2 1 1]; if Cube.Color(2,27)==Clayer1 R(2,3)=1; end end Cube=RotateLayer(R,Anime,hAxes,Cube); R=FRU2Color(R,Cube); sol(end+1:end+size(R,1),:)=R; D=CheckCube(Cube); end Nparts(3)=size(sol,1); if iAltSol==0 % Rotate cube with full layer to the bottom (Down) Cube=RotateCube(hAxes,Cube,1, 2,Anime); D=CheckCube(Cube); Rmid={string2hist('LU''F2U2F2U2F2U''L'''), ... string2hist('B''UR2U2R2U2R2UB')}; RrotForMiddle=[0 -1 1 2; % if F-side on top 1 0 2 -1]; else Rmid={string2hist('F''D''FDLDL'''), ... string2hist('FDF''D''R''D''R')}; RrotToBack=[-1 0 2 1]; end SetTitle(hAxes,'Correct middle layer'); % middle layer nOK=sum(D.P(MidLayer)==-10); while nOK<4 if iAltSol==0 iC=find(D.P(20:2:26)<19&D.P(20:2:26)>0); if ~isempty(iC) iCube=iC(1)*2+18; [Cube,iCube]=RotateTo(D.P(iCube),18,iCube,hAxes,3,Cube,Anime); i=(Cube.Color(6,iCube)~=Cube.Color(2,Cube.RotLayerCube(2,5)))+1; R=[3 1 RrotForMiddle(i,(iCube-18)/2); Rmid{i}]; nOK=nOK+1; elseif any(D.P(MidLayer)==-5) iC=find(D.P(MidLayer)==-5); iCube=MidLayer(iC(1)); Cube=RotateTo(iCube,18,[],hAxes,3,Cube,Anime); R=[Rmid{2};3 1 -1;Rmid{1}]; nOK=nOK+1; else % change from one mid-edge to another iC=find(D.P(MidLayer)~=-10); iCube=MidLayer(iC(1)); [Cube,iCube]=RotateTo(D.P(iCube),18,iCube,hAxes,3,Cube,Anime); R=Rmid{1}; end else % iAltSol iC=find(D.P(2:2:8)>9); if isempty(iC) iC=find(D.P(MidLayer)~=-10); Cube=RotateTo(MidLayer(iC(1)),18,[],hAxes,3,Cube,Anime); R=Rmid{2}; else iCube=iC(1)*2; i=1; c=Cube.Color(Cube.Color(:,iCube)>0,iCube); while Cube.Color(2,15)~=c(2) Cube=RotateCube(hAxes,Cube,3,-1,Anime); iCube=Cube.RotCubeCube(6,iCube); end if c(1)==Cube.Color(3,11) i=1; else i=2; end R=[3 -1 RrotToBack(iCube/2);Rmid{i}]; nOK=nOK+1; end end Cube=RotateLayer(R,Anime,hAxes,Cube); R=FRU2Color(R,Cube); sol(end+1:end+size(R,1),:)=R; D=CheckCube(Cube); end Nparts(4)=size(sol,1); if iAltSol>0 % Rotate cube with full layer to the bottom (Down) Cube=RotateCube(hAxes,Cube,1, 2,Anime); end Rorient1=string2hist('BLUL''U''B'''); Rorient2=string2hist('BULU''L''B'''); SetTitle(hAxes,'Correct orientation of edges of last layer'); Clayer3=Cube.Color(6,Cube.RotLayerCube(6,5)); iC=find(Cube.Color(6,20:2:26)~=Clayer3); if ~isempty(iC) if length(iC)==4 Cube=RotateLayer(Rorient1,Anime,hAxes,Cube); R=FRU2Color(Rorient1,Cube); sol(end+1:end+size(R,1),:)=R; Cube=RotateCube(hAxes,Cube,3,2,Anime); R=Rorient2; else iCube=iC*2+18; [Cube,iCube]=RotateTo(iCube(1),22,iCube(2),hAxes,3,Cube,Anime); if iCube==24 R=Rorient1; else if iCube==26 Cube=RotateCube(hAxes,Cube,3,1,Anime); end R=Rorient2; end end Cube=RotateLayer(R,Anime,hAxes,Cube); R=FRU2Color(R,Cube); sol(end+1:end+size(R,1),:)=R; end Nparts(5)=size(sol,1); RotEdges1=string2hist('R2D''U2R''LF2RL''DR2'); RotEdges2=string2hist('R2D''R''LF2RL''U2DR2'); RotEdges3=string2hist('R2D2B2D,(L2F2)3,D''B2D2R2'); SetTitle(hAxes,'Correct positions of edges of last layer'); D=CheckCube(Cube); iNOK=find(D.P(20:2:26)>0); while length(iNOK)==4 R=[3 1 1]; Cube=RotateLayer(R,Anime,hAxes,Cube); R=FRU2Color(R,Cube); sol(end+1,:)=R; D=CheckCube(Cube); iNOK=find(D.P(20:2:26)>0); end if length(iNOK)==2 R=[3 1 1]; Cube=RotateLayer(R,Anime,hAxes,Cube); R=FRU2Color(R,Cube); sol(end+1,:)=R; D=CheckCube(Cube); iNOK=find(D.P(20:2:26)>0); end if length(iNOK) % because of not working RotEdges3 if length(iNOK)==3 iCube=find(D.P(20:2:26)<0)*2+18; [Cube,D]=RotateTo(iCube,20,[],hAxes,3,Cube,Anime); if D.P(22)==26 R=RotEdges1; else R=RotEdges2; end else if D.P(20)==24 Cube=RotateCube(hAxes,Cube,3,1,Anime); end R=RotEdges3; end Cube=RotateLayer(R,Anime,hAxes,Cube); R=FRU2Color(R,Cube); sol(end+1:end+size(R,1),:)=R; end Nparts(6)=size(sol,1); Corners=[19 21 25 27]; Rcorners1=string2hist('L'',URU''R'',L,RUR''U'''); Rcorners2=string2hist('URU''R'',L'',RUR''U'',L'); Rcorners3=string2hist('B,LUL''U'',LUL''U'',LUL''U'',B'''); Rcorners4=string2hist('R''B2,FRF''R'',FRF''R'',FRF''R'',B2R'); SetTitle(hAxes,'Correct positions of corners of last layer'); D=CheckCube(Cube); iNOK=find(D.P(Corners)>0); if length(iNOK) if length(iNOK)==3 iCube=Corners(D.P(Corners)<0); [Cube,D]=RotateTo(iCube,27,[],hAxes,3,Cube,Anime); if D.P(21)==19 R=Rcorners1; else R=Rcorners2; end elseif length(iNOK)==4 if D.P(21)==19|D.P(21)==27 if D.P(21)==19 Cube=RotateCube(hAxes,Cube,3,1,Anime); end R=Rcorners3; else R=Rcorners4; end else error('Impossible cube') end Cube=RotateLayer(R,Anime,hAxes,Cube); R=FRU2Color(R,Cube); sol(end+1:end+size(R,1),:)=R; end Nparts(7)=size(sol,1); RRcornersPart1=string2hist('(FDF''D'')2'); RRcornersPart2=string2hist('(DFD''F'')2'); SetTitle(hAxes,'Correct orientation of corners of last layer'); nUp=0; nNOK=sum(Cube.Color(6,Corners)~=Clayer3); %!!!!!bij het volgende is ook 3 x CW of 3 x CCW mogelijk!!!! while ~all(Cube.Color(6,Corners)==Clayer3) while Cube.Color(6,27)==Clayer3 Cube=RotateCube(hAxes,Cube,3,1,Anime); end Rtop=FRU2Color([3 1 1],Cube); if Cube.Color(2,27)==Clayer3 R=RRcornersPart1; iSide=4; R2=RRcornersPart2; else R=RRcornersPart2; iSide=2; R2=RRcornersPart1; end Cube=RotateLayer(R,Anime,hAxes,Cube); sol(end+1:end+size(R,1),:)=FRU2Color(R,Cube); nNOK=nNOK-1; while Cube.Color(iSide,27)~=Clayer3&(nNOK~=2|Cube.Color(6,27)==Clayer3) Cube=RotateLayer(Rtop,Anime,hAxes,Cube); sol(end+1,:)=Rtop; nUp=nUp+1; end if Cube.Color(iSide,27)==Clayer3 nNOK=nNOK-1; end Cube=RotateLayer(R2,Anime,hAxes,Cube); sol(end+1:end+size(R2,1),:)=FRU2Color(R2,Cube); end nUp=rem(nUp,4); if nUp>1 nUp=nUp-4; end if nUp nUp=-nUp; Cube=RotateLayer(hAxes,Cube,3,1,nUp,Anime); sol(end+1,:)=FRU2Color([3 1 nUp],Cube); end Nparts(8)=size(sol,1); if Cube.bFullCube SetTitle(hAxes,'Correct orientations of middle cubes'); % combinations from Mark Jeays Rmid180=string2hist('URLU2R''L''URLU2R''L'''); RmidUF=string2hist('FB''LR''UD''F''U''DL''RF''BU'); RmidUD=string2hist('RL''F2B2RL''URL''F2B2RL''D'''); % Full cube solver added, just at the end of the real Singmaster-solution!!! loop=true; while loop N=zeros(1,6); MyColor = Cube.Color; for iFace=1:6 iCube=Cube.iMid(iFace); z=Cube.iExtraFaces(iFace,1); c=Cube.Color(Cube.iMidInd(z)); % count needed rotations while MyColor(z,iCube)~=c N(iFace)=N(iFace)+1; MyColor(Cube.RotCubeFlat(iFace,:),iCube) = ... MyColor(:,iCube); if N(iFace)>4 error('!!Impossible cube!!! - full cube with impossible mid cube colors!!') end end end if any(N) if any(N==2) i=find(N==2); Cube=RotateTo(i(1),23,[],hAxes,[],Cube,Anime); R=Rmid180; else if all(N<2)|all(N<1|N>2) % oorspronkelijk niet voorzien!!! i=find(N); N(i(1))=0; j=find(N); else i=find(N==1); j=find(N==3); % normaal altijd (toch als er geen 2's meer zijn) end i=i(1); j=j(1); [Cube,iCube]=RotateTo(i,23,Cube.iMid(j),hAxes,[],Cube,Anime); if floor((i-1)/2)==floor((j-1)/2) R=RmidUD; else Cube=RotateTo(iCube,15,[],hAxes,3,Cube,Anime); R=RmidUF; end end Cube=RotateLayer(R,Anime,hAxes,Cube); sol(end+1:end+size(R),:)=FRU2Color(R,Cube); else loop=false; end end end Nparts(9)=size(sol,1); SetTitle(hAxes,''); if bPostOptim sol=optimhist(sol,Cube); end end if Anime Cube.sol=sol; set(hAxes,'UserData',Cube) end if Anime&bAnimeSepWin&bCloseWin close(f) end function [mx,i]=FindBestStart(D) % not really finding the best, but an easy guess: % as much edges as possible, and then the maximum number of corners % (it is possible that "good corners" have to be removed to set the % right edges, and therefore this method is too easy) [mx,i]=max(D.NOK(:,2)); j=find(D.NOK(:,2)==mx); if length(j)>1 [mx2,k]=max(D.NOK(j,3)); i=j(k); mx=mx+mx2/5; else mx=mx+D.NOK(i,3)/5; end function [Cube,iCubes]=RotateTo(iCube0,toCube,iCubes,hAxes,Axe,Cube,Anime) n=0; if isempty(Axe) % search for a direction %!!!!only for mid cubes, assigned by an index rather than a cube number! % and only for rotating mid cube to upper layer a1=floor((iCube0-1)/2); a2=2; if a1==a2 Axe=3-a1; else Axe=setdiff(0:2,[a1 a2])+1; end iCube0=Cube.iMid(iCube0); end i=Axe*2; while iCube0~=toCube n=n+1; iCube0=Cube.RotCubeCube(i,iCube0); if n>3 error('Something is wrong ---- no rotation exist for requested search') end iCubes=Cube.RotCubeCube(i,iCubes); end switch n case 1 Cube=RotateCube(hAxes,Cube,Axe,-1,Anime); case 2 Cube=RotateCube(hAxes,Cube,Axe,2,Anime); case 3 Cube=RotateCube(hAxes,Cube,Axe,1,Anime); end if nargout>1&isempty(iCubes) iCubes=CheckCube(Cube); end function SetTitle(hAxes,s) if ~isempty(hAxes) set(get(hAxes,'Title'),'String',s) end