Advertisement
Guest User

Cube Puzzle solver

a guest
Jun 28th, 2019
417
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
MatLab 8.29 KB | None | 0 0
  1. % solves this puzzle: https://i0.wp.com/famousartisan.com/wp-content/uploads/2017/10/puzzle-cube.jpg?fit=800%2C470&ssl=1
  2.  
  3. %% define puzzle pieces
  4. pieces = repmat({false(3,3,3)} ,7,1) ;
  5. pieces{1}(:,:,1) = [ 1 1 1 ; 1 0 0 ; 0 0 0] ;
  6. pieces{2}(:,:,1) = [ 1 1 1 ; 0 1 0 ; 0 0 0] ;
  7. pieces{3}(:,:,1) = [ 1 1 0 ; 0 1 1 ; 0 0 0] ;
  8. pieces{4}(:,:,1) = [ 1 1 0 ; 1 0 0 ; 0 0 0] ;
  9. pieces{5}(:,:,1) = [ 1 1 0 ; 1 0 0 ; 0 0 0] ;
  10. pieces{5}(:,:,2) = [ 1 0 0 ; 0 0 0 ; 0 0 0] ;
  11. pieces{6}(:,:,1) = [ 1 1 0 ; 1 0 0 ; 0 0 0] ;
  12. pieces{6}(:,:,2) = [ 0 0 0 ; 1 0 0 ; 0 0 0] ;
  13. pieces{7}(:,:,1) = [ 1 1 0 ; 1 0 0 ; 0 0 0] ;
  14. pieces{7}(:,:,2) = [ 0 1 0 ; 0 0 0 ; 0 0 0] ;
  15. %% make all possible permutations of transformations of pieces
  16.  
  17. %rotations and offsets
  18. rotateA = 0: pi/2 : 3 * pi/2 ;
  19. ofsetA = 0 : 2 ;
  20.  
  21. % precalculate all rotation matrices
  22. rotateIA = 1 : numel(rotateA) ;
  23. RX = [] ;
  24. RY = [] ;
  25. RZ = [] ;
  26. for i = rotateIA
  27.     RX(:,:,i) =  makehgtform('xrotate',rotateA(i))  ;
  28.     RY(:,:,i) =  makehgtform('yrotate',rotateA(i))  ;
  29.     RZ(:,:,i) =  makehgtform('zrotate',rotateA(i))  ;
  30. end
  31. RX = RX(1:3,1:3,:) ;
  32. RY = RY(1:3,1:3,:) ;
  33. RZ = RZ(1:3,1:3,:) ;
  34.  
  35. rotComb = combvec(rotateIA,rotateIA,rotateIA) ;
  36. RM = zeros(3,3,size(rotComb,2))  ;
  37. for ri =1 : size(rotComb,2)
  38.     RM(:,:,ri) = RX(:,:,rotComb(1,ri)) * RY(:,:,rotComb(2,ri)) * RZ(:,:,rotComb(3,ri))  ;
  39. end
  40.  
  41. %All combinations of rotation matrices and x,y,z offsets
  42. [allComb] = combvec(ofsetA,ofsetA,ofsetA,1:size(RM,3)) ;
  43.  
  44. tPieces = cell(7,size(allComb,2)) ;
  45.  
  46. for ci = 1 : 7
  47.     piece = pieces{ci}  ;
  48.    
  49.     [xi,yi,zi] = ind2sub([3,3,3],find(piece)) ;
  50.    
  51.     X = [xi,yi,zi] - 1  ;
  52.     for oi = 1 : size(allComb,2)
  53.         xo = allComb(1,oi) ;
  54.         yo = allComb(2,oi) ;
  55.         zo = allComb(3,oi) ;
  56.         ri = allComb(4,oi) ;
  57.        
  58.         R = RM(:,:,ri) ;
  59.         newX = X * R+ [xo yo zo] +1 ;
  60.        
  61.         %Check if in bounds
  62.         if all(newX(:) > 0) && all(newX(:) < 4)
  63.             tPieces{ci,oi} = accumarray(newX,1,[3 3 3]) ;
  64.         end
  65.     end
  66. end
  67.  
  68. % because each solution (whole cube) can be rotated such that the first
  69. % piece is in any rotation, we only put the first piece in the first
  70. % rotation by discarding the rest.
  71. tPieces(1,allComb(4,:)>1) = cell(size(tPieces(1,allComb(4,:)>1))) ;
  72.  
  73. %% remove duplicates and invalid solutions (empties) from list
  74. goodPieces = cell(1,7);
  75. for ci = 1 : 7
  76.     thesePieces = tPieces(ci,~cellfun(@isempty,tPieces(ci,:))) ;
  77.    
  78.     uPieces = unique(cell2mat(cellfun(@(t) t(:)',thesePieces,'uni',0)'),'rows') ;
  79.     goodPieces{ci} = uPieces ;
  80. end
  81.  
  82. %% verify goodPieces:
  83. %{
  84. [x,y,z] = meshgrid(1:3,1:3,1:3) ;
  85. for ci = 1 %1 : 7
  86.    
  87.     figure(ci*100)
  88.     plotPlacer(16)
  89.     for oi = 1 : size(goodPieces{ci},1)
  90.         piece = goodPieces{ci}(oi,:) ;
  91.        
  92.         [xi,yi,zi] = ind2sub([3,3,3],find(piece)) ;
  93.         plotPlacer
  94.        
  95.         scatter3(xi,yi,zi,'fill')
  96.         hold on  ;
  97.         plot3(xi,yi,zi,'-')
  98.         scatter3(x(:),y(:),z(:))
  99.         axis equal
  100.     end
  101. end
  102. %}
  103.  
  104. %% now check all combinations of all options wether they overlap?
  105. NaPiece = cellfun(@(g) size(g,1),goodPieces) ;
  106.  
  107. thisTry = zeros(7,27) ;
  108. altTry = zeros(27,7) ;
  109. indexA = ones(1,7) ;
  110. ci =1 ;
  111. si = 1;
  112. indexS = [] ;
  113. solutions = [] ;
  114. goingDown = false ;
  115. while ci > 0
  116.     %          disp([ci indexA])  % show iterations in
  117.     thisTry(ci,:) = goodPieces{ci}(indexA(ci),:) ;
  118.    
  119.     indexA(ci) = indexA(ci)+1 ;
  120.     if any(sum(thisTry)>1)
  121.         %if we tried all, reset this piece and go back to the last
  122.         %while ensures you can do that twice in a row
  123.         while indexA(ci) > NaPiece(ci)
  124.             thisTry(ci,:) = 0 ;
  125.             indexA(ci) = 1 ;
  126.             ci = ci - 1 ;
  127.             %when it rolls back all the way to before the first piece  all
  128.             %combinations have been tested
  129.             if ci == 0
  130.                 break
  131.             end
  132.         end
  133.     else
  134.         if ci == 7
  135.             %if this try works and its the seventh, a sollution is found
  136.             indexS(:,si) = indexA ; solutions(:,:,si) = thisTry ; si =si + 1; %#ok
  137.             %spoof going to the previous piece, ci will increase again
  138.             ci = ci - 1 ;
  139.            
  140.             %break ; %if you only want to see one solution, break here
  141.         end
  142.         %if this try works, continue with another piece
  143.         ci = ci + 1 ;
  144.     end
  145. end
  146. %correct index increase before solution storage
  147. indexS(:,end) = indexS(:,end) -1 ;
  148.  
  149. %% Show solution (there are 480 :O )
  150.  
  151. [x,y,z] = meshgrid(1:3,1:3,1:3) ;
  152. figure(555) ;
  153. if size(solutions,3) > 0
  154.     plotPlacer(8,10)
  155. else
  156.     plotPlacer(1) ;
  157. end
  158. for si = 1 : size(solutions,3)
  159.     solution = solutions(:,:,si)
  160.    
  161.     plotPlacer ;
  162.     for ci = 1 : 7
  163.         piece = reshape(solution(ci,:),[3 3 3]) ;
  164.         [xi,yi,zi] = ind2sub([3,3,3],find(piece)) ;
  165.         scatter3(xi,yi,zi,'fill')
  166.         hold on  ;
  167.         %     plot3(xi,yi,zi,'-') %gets messy, might help
  168.         axis equal
  169.     end
  170. end
  171.  
  172. %% PlotPlacer function i made when i started using matlab bc subplot is anoying
  173. %enjoy the spagetti
  174.  
  175. function hout = plotPlacer(varargin)
  176. %PLOTPLACER Interface to subplot.
  177. %   Subplot is tedious. plotPlacer only takes arguments the first call, and
  178. %   remembers those for placing all other subplots. Every call without
  179. %   arguments spawns a new subplot, starting anew in the current figure.
  180. %
  181. %   --Input (first call only!)
  182. %      plotPlacer(nPlotx,nPloty).  %plots in this rectangle
  183. %      plotPlacer(nPlot). %plot on a rectangle in 1 figure
  184. %      plotPlacer(...,'vert') draws subsequent axes vertically ('horz' also
  185. %      works. Because of legacy and horizontal and vertical are confusing)
  186.  
  187. % September 2014
  188.  
  189. %Todo?
  190. %add support for non regular placement
  191. %Force overwrite new figures as option?
  192. %add option to supply number of plots and number of figures
  193.  
  194. %now, with output handles :O
  195. hout = [] ;
  196. persistent nPlotx nPloty fn sp nsp next ;
  197. %place a plot
  198. if nargin == 0
  199.     if(sp == nsp)
  200.         fn = fn + 1 ;
  201.         %call figure here for clf ;
  202.         figure(fn) ;
  203.         clf ;
  204.     end
  205.     %try catches when inplots == 0 and do nothing
  206.     try
  207.         %always call figre for more robust plot placement
  208.         figure(fn);
  209.         sp = next(sp,nPlotx,nPloty) ;
  210.         hout = subplot(nPloty,nPlotx,sp) ;
  211.     catch
  212.     end
  213. else
  214.     %process inputs
  215.     if ischar( varargin{end} )
  216.         options = varargin{end} ;
  217.         varargin = varargin(1:end-1) ;
  218.     end
  219.     %initialize
  220.     inSizes = cellfun(@numel,varargin) ;
  221.    
  222.     %non-vararr input
  223.     if all(inSizes==1) && numel(inSizes) < 3
  224.         %add 'horz' to plot them vertically. Now vert also works
  225.         if exist('options','var') && (strcmp(options,'horz') || strcmp(options,'vert') )
  226.             next = @(n,nx,ny) ((n+nx)>nx*ny)*(-nx*ny+1) + n + nx + (n==(nx*ny))*(-nx) ;
  227.             %O yes he just did
  228.         else
  229.             next =  @(n,nx,ny) mod(n, nx * ny)+1 ;
  230.         end
  231.        
  232.         switch numel(varargin)  %~= nargin! bc above the options is removed
  233.             case 1
  234.                 nPlotx = ceil(sqrt(varargin{1})) ;
  235.                 nPloty = ceil(varargin{1}/nPlotx) ;
  236.             case 2
  237.                 nPlotx = varargin{2} ;
  238.                 nPloty = varargin{1} ;
  239.         end
  240.     else
  241.         %Hiddem feature. To unify the input with that of parPicker (deprec)
  242.         if exist('options','var') && ~strcmp(options,'horz')
  243.             names= strsplit(options) ;
  244.             varnames = arrayfun(@inputname,1:numel(varargin) ,'uni',0) ;
  245.            
  246.             intmp = cellfun(@(x) strcmp(names,x),varnames,'uni',0) ;
  247.             intmp = cell2mat(reshape(intmp,[numel(intmp),1])) ;
  248.            
  249.             pioritySizes = arrayfun(@(x) inSizes(intmp(:,x)),1:size(intmp,2)) ;
  250.         else
  251.             pioritySizes = inSizes(find(inSizes>1,2,'first'));
  252.         end
  253.        
  254.         next =  @(n,nx,ny) mod(n, nx * ny)+1 ;
  255.         if numel(pioritySizes)>0, nPlotx = pioritySizes(1) ; else  nPlotx = 1 ; end
  256.         if numel(pioritySizes)>1, nPloty = pioritySizes(2) ; else  nPloty = 1 ; end
  257.     end
  258.     fig = gcf ;
  259.     fn = get(fig,'Number') ;
  260.     if ischar(fn)
  261.         %Old matlab compatibility
  262.         fn = fig ;
  263.     end
  264.     fn = fn - 1 ;%-1 because we want a call to figure first time
  265.     nsp = nPlotx * nPloty;
  266.     sp = nsp ;
  267. end
  268. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement