www.gusucode.com > demos工具箱matlab源码程序 > demos/soma.m
function soma(Action) %SOMA display precomputed solutions to Piet Hein's soma cube % A solution is represented by a vector of locations within % the 3x3 cube, 1 being lower left front, 27 being upper right back. % This gui allows the user to look at one solution at a time. % W. M. McKeeman % Copyright 1984-2014 The MathWorks, Inc. switch nargin, case 0, LocalInitFig case 1, fig = gcf; Data = get(fig,'UserData'); switch Action, case 'Info', ttlStr = mfilename; hlpStr1 = ... {' The soma cube is a puzzle consisting of seven pieces that ' ' can be assembled into a 3x3x3 cube. It is a special case of ' ' space-filling puzzles. ' ' ' ' The seven pieces of the soma cube are all pieces that can be ' ' made by gluing four or less cubes together at their faces, ' ' producing a piece with an inside corner. That is, three ' ' cubes forming a "V" are included but three cubes making an ' ' "I" are excluded. ' ' ' ' The seven pieces are named V L T Z S R Y, all but S and R ' ' approximating the shape of the assembled cubes. The S piece ' ' is "screw shaped" and the R piece is its reflection. The R ' ' piece is a "right-handed screw". Pictures of these pieces are' ' displayed when soma.m runs. ' ' ' ' There are 240 unique ways to assemble the 7 pieces into a ' ' 3x3x3 cube, discounting reflections and rotations. ' ' '}; hlpStr2 = ... {' The combinatorics of brute force computation are on the ' ' order of 100^7, since each piece can fit into the cube in ' ' about 100 different ways. Fortunately, there are some ' ' theories which reduce the computation to a feasible task. ' ' ' ' The simplest theorem involves examining the 8 vertices of the' ' completed solution. The V Z S R Y pieces can occupy at most ' ' 1 of these 8 vertices. The T piece can touch 2 or 0 ' ' vertices, and the L piece can touch 2, 1 or 0. If you add ' ' up the maximum number of vertices touchable by the pieces, ' ' it comes out to 1+2+2+1+1+1+1=9. Therefore, exactly one ' ' piece contributes 1 less than its maximum. That cannot be T,' ' because it cannot touch 1 vertex. One concludes that T ' ' always touches 2 vertices, and therefore is always in exactly' ' the same position in the finished cube (after rotation). The' ' soma cube is really only a 6 piece puzzle! ' ' '}; hlpStr3 = ... {' A more general theorem accounts for classes VEFC, standing ' ' for the 8 Vertices, 12 Edges, 6 Faces and 1 Center. Any ' ' solution has to fill each of the VEFC classes exactly. To ' ' carry out the analysis, first classify the pieces themselves ' ' by VEFC. V, for example, can be 1200, meaning 1 vertex, 2 ' ' edges, 0 faces and 0 centers. The sum of the VEFC vectors ' ' has to add up to 8 12 6 1, and therefore the search can be ' ' restricted to class of piece positions for which the VEFC sum' ' holds. This leads to 11 combinations of piece position ' ' classes, for which the combinatoric is more like 10^7, which ' ' can be computed in about an hour. ' ' ' ' This program could be modified to solve other objects that ' ' can be built out of the 7 pieces (commercial puzzles come ' ' with dozens of suggestions), or to solve puzzles made of ' ' other pieces (The double soma cube consists of L T Z S R Y ' ' plus two length 4 "I" pieces plus 2 size 4 "O" pieces gives ' ' 24+24+4+4+4+4=64, making a 4x4x4 cube possible). The eight ' ' queens problem can be thought of as filling a space ' ' consisting of rows, columns and diagonals of the chessboard ' ' (8+8+14+14) where each queen takes a row, a column and two ' ' diagonals. '}; helpwin(cat(1,hlpStr1, hlpStr2, hlpStr3), ttlStr); case 'Next', if Data.sn < 240, Data.sn = Data.sn+1; else Data.sn = 1; end set(Data.pn,'string',getString(message('MATLAB:demos:soma:LabelNOf240',num2str(Data.sn)))); Data.sol = Data.sols(Data.sn,:); LocalRepaint(Data) set(fig,'UserData',Data); case 'Previous', if Data.sn > 1, Data.sn = Data.sn-1; else Data.sn = 240; end set(Data.pn,'string',getString(message('MATLAB:demos:soma:LabelNOf240',num2str(Data.sn)))); Data.sol = Data.sols(Data.sn,:); LocalRepaint(Data) set(fig,'UserData',Data); case 'Close', delete(gcf) case 'RotateXY', Data.sol = LocalRXY(Data.sol); LocalRepaint(Data) set(fig,'UserData',Data); case 'RotateYZ', Data.sol = LocalRYZ(Data.sol); LocalRepaint(Data) set(fig,'UserData',Data); otherwise, error('MATLAB:soma:NoInputs','%s',... getString(message('MATLAB:demos:soma:NoInputs'))); end % switch otherwise, error('MATLAB:soma:NoInputs','%s',... getString(message('MATLAB:demos:soma:NoInputs'))); end % switch %%%%%%%%%%%%%%%%%%%%%%%% %%%%% LocalRepaint %%%%% %%%%%%%%%%%%%%%%%%%%%%%% function LocalRepaint(Data) % FUNCTION: LocalRepaint % PURPOSE: callback to repaint the soma cube % METHOD: run from stage4.m % facelet -- cubie correlation % R L T R L T R L T face = [1 1 19 10 10 22 19 19 25,... 2 4 20 11 13 23 20 22 26,... 3 7 21 12 16 24 21 25 27]; % the standard VLTZSRY order of display, 3 V, 4 L, etc. % r g b purple = [.4 0 .6]; % V -- piece colors blue = [0 0 1]; % L green = [0 1 .2]; % T yellow = [1 1 0]; % Z orange = [.9 .5 0]; % S red = [1 0 0]; % R violet = [1 0 1]; % Y white = [1 1 1]; % empty pc = [purple; purple; purple blue; blue; blue; blue green; green; green; green yellow; yellow; yellow; yellow orange; orange; orange; orange red; red; red; red violet; violet; violet; violet]; for c = 1:27 soltn = Data.sol(c); set(Data.squarelet(soltn), 'facecolor', pc(c,:)); for d = 1:27 if soltn == face(d) set(Data.trp(d), 'facecolor', pc(c,:)); end end end %%%%%%%%%%%%%%%%%%%% %%%%% LocalRXY %%%%% %%%%%%%%%%%%%%%%%%%% function newp = LocalRXY(oldp) % FUNCTION: LocalRXY % PURPOSE: rotate a cube in the xy plane tx = [ 3 6 9 2 5 8 1 4 7,... 12 15 18 11 14 17 10 13 16,... 21 24 27 20 23 26 19 22 25]; newp = tx(oldp); %%%%%%%%%%%%%%%%%%%% %%%%% LocalRYZ %%%%% %%%%%%%%%%%%%%%%%%%% function newp = LocalRYZ(oldp) % FUNCTION: LocalRYZ % PURPOSE: rotate a cube in the xy plane tx = [7 8 9 16 17 18 25 26 27,... 4 5 6 13 14 15 22 23 24,... 1 2 3 10 11 12 19 20 21]; % rotation y to z newp = tx(oldp); %%%%%%%%%%%%%%%%%%%%%%%% %%%%% LocalInitFig %%%%% %%%%%%%%%%%%%%%%%%%%%%%% function LocalInitFig cubie = [0 0; 0 1; 1 1; 1 0; 0 0]; % to draw a little square % physical layout of cubies to form sliced display of 3x3 cube cube = [0 0; 1 0; 2 0; 0 1; 1 1; 2 1; 0 2; 1 2; 2 2 4 0; 5 0; 6 0; 4 1; 5 1; 6 1; 4 2; 5 2; 6 2 8 0; 9 0; 10 0; 8 1; 9 1; 10 1; 8 2; 9 2; 10 2]; % r g b purple = [.4 0 .6]; % V -- piece colors blue = [0 0 1]; % L green = [0 1 .2]; % T yellow = [1 1 0]; % Z orange = [.9 .5 0]; % S red = [1 0 0]; % R violet = [1 0 1]; % Y white = [1 1 1]; % empty v = [1 0; 0 0; 0 1]; % to draw a V l = [v; 0 2]; % add a cubie and get an L t = [0 1; 1 1; 2 1; 1 0]; % to draw a T z = [0 1; 1 1; 1 0; 2 0]; % to draw a Z s = [v; 1.2 .2]; % add a cubie and get an S r = [v; .2 1.2]; % add a cubie and get an R y = [v; .2 .2]; % add a cubie and get a Y xv = cubie(:,1); % x vector to drive patch() yv = cubie(:,2); % y vector to drive patch() backcolor = [1 1 1]; % white backcolor = [.8 .8 .8]; % grey screenpos = 300; % about the middle screenx = 700; % about half screeny = 500; % about half axescolor = [1 1 1]; figh = figure(... 'Color' , backcolor,... 'NumberTitle','off', ... 'Toolbar', 'none', ... 'CloseRequestFcn','soma Close', ... 'Name' , getString(message('MATLAB:demos:soma:TitleSomaCubeSolutions'))); ax2 = axes(... 'Units' , 'normalized',... 'Position', [0.05 .05 0.7 0.25] ,... 'Color' , axescolor); axis([0 1 0 1]); set(gca,'XTick',[],'YTick',[]); text(.5,.5,{getString(message('MATLAB:demos:soma:LabelSomaCube'));' '; ... getString(message('MATLAB:demos:soma:LabelLongDescription'))}, ... 'HorizontalAlignment','center', ... 'color', 'black'); ax = axes(... 'Units' , 'normalized',... 'Position', [0.05 .3 0.7 0.7] ,... 'Color' , axescolor); axis image ; axis([0 1 0 .6]); set(gca,'XTick',[],'YTick',[]); buttonx = .80; buttony = .95; buttonwidth = 0.15; buttonheight = 0.08; spacing = 0.03; sn = 1; % following are the active elements for user control uicontrol(figh,... % decrement solution selection 'Style' , 'frame',... 'Units' , 'normalized',... 'Position', [buttonx-0.01,0.05,buttonwidth+0.02,0.9]); pt = uicontrol(figh,... % slider title 'Style', 'text',... 'String', getString(message('MATLAB:demos:soma:LabelSolutionNumber')),... 'Units', 'normalized',... 'Position',[buttonx,buttony-buttonheight-spacing, ... buttonwidth,buttonheight]); pn = uicontrol(figh,... % visible solution number 'Style', 'text',... 'String', getString(message('MATLAB:demos:soma:LabelNOf240',num2str(1))),... 'Units', 'normalized',... 'Position',[buttonx, buttony-2*buttonheight-spacing, ... buttonwidth,buttonheight]); decr = uicontrol(figh,... % decrement solution selection 'Style' , 'pushbutton',... 'Units' , 'normalized',... 'String' , getString(message('MATLAB:demos:shared:LabelPrevious')),... 'Position',[buttonx, buttony-3*buttonheight-2*spacing, ... buttonwidth,buttonheight], ... 'Callback', 'soma Previous'); incr = uicontrol(figh,... % increment solution selection 'Style' , 'pushbutton',... 'Units' , 'normalized',... 'String' , getString(message('MATLAB:demos:shared:LabelNext')),... 'Position',[buttonx, buttony-4*buttonheight-3*spacing, ... buttonwidth,buttonheight], ... 'Callback', 'soma Next'); pq = uicontrol(figh ,... % the [quit] button 'Style' , 'pushbutton',... 'Units' , 'normalized',... 'String' , getString(message('MATLAB:demos:shared:LabelClose')),... 'Position' , [buttonx, 0.05+spacing,buttonwidth,buttonheight],... 'Callback' ,'soma Close'); pq = uicontrol(figh ,... % the info button 'Style' , 'pushbutton',... 'Units' , 'normalized',... 'String' , getString(message('MATLAB:demos:shared:LabelInfo')),... 'Position' , [buttonx, 0.05+2*spacing+buttonheight, ... buttonwidth,buttonheight],... 'Callback' ,'soma Info'); rot1 = uicontrol(figh,... % rotate solution xy 'Style', 'pushbutton',... 'Units', 'normalized',... 'String', getString(message('MATLAB:demos:soma:LabelRotateRight')),... 'Position', [.575, .72, .15, .08],... 'Callback','soma RotateXY'); rot2 = uicontrol(figh,... % rotate solution yz 'Style', 'pushbutton',... 'Units', 'normalized',... 'Position', [.44, .58, .15, .08],... 'String', getString(message('MATLAB:demos:soma:LabelRotateDown')),... 'Callback', 'soma RotateYZ'); sqsize = 0.03; % edge of a squarelet dy3 = 1; % y posit for sample title dy2 = dy3+1; % y posit for name of sample dy = dy2+1; % y posit for sample pieces dx = 4; % x posit for sample pieces text('position', [dx+.5 dy2]*sqsize, 'string', 'V', 'color', 'black'); for c = 1:3 % paint a sample V xx = xv+v(c,1)+dx; yy = yv+v(c,2)+dy; pv = patch(xx*sqsize, yy*sqsize, purple); end dx = dx + 4; text('position', [dx+.5 dy2]*sqsize, 'string', 'L', 'color', 'black'); for c = 1:4 % paint a sample L xx = xv+l(c,1)+dx; yy = yv+l(c,2)+dy; ph = patch(xx*sqsize, yy*sqsize, blue); end dx = dx + 4; text('position', [dx+1 dy2]*sqsize, 'string', 'T', 'color', 'black'); for c = 1:4 % paint a sample T xx = xv+t(c,1)+dx; yy = yv+t(c,2)+dy; pt = patch(xx*sqsize, yy*sqsize, green); end dx = dx + 4; text('position', [dx+1 dy2]*sqsize, 'string', 'Z', 'color', 'black'); for c = 1:4 % paint a sample Z xx = xv+z(c,1)+dx; yy = yv+z(c,2)+dy; pz = patch(xx*sqsize, yy*sqsize, yellow); end dx = dx + 4; text('position', [dx+.5 dy2]*sqsize, 'string', 'S', 'color', 'black'); for c = 1:4 % paint a sample S xx = xv+s(c,1)+dx; yy = yv+s(c,2)+dy; ps = patch(xx*sqsize, yy*sqsize, orange); end dx = dx + 4; text('position', [dx+.5 dy2]*sqsize, 'string', 'R', 'color', 'black'); for c = 1:4 % paint a sample R xx = xv+r(c,1)+dx; yy = yv+r(c,2)+dy; pr = patch(xx*sqsize, yy*sqsize, red); end dx = dx + 4; text('position', [dx+.5 dy2]*sqsize, 'string', 'Y', 'color', 'black'); for c = 1:4 % paint a sample Y xx = xv+y(c,1)+dx; yy = yv+y(c,2)+dy; py = patch(xx*sqsize, yy*sqsize, violet); end text('position', [14.5 dy3]*sqsize,... 'string', getString(message('MATLAB:demos:soma:LabelSomaCubePieces')),... 'color', 'black'); % paint an empty solution in three layers % cube(i,1) is a sequence of x positions outlining squarelet i [1:27] % cube(i,2) is a sequence of y positions outlining squarelet 1 [1:27] for c = 1:27 % cycle through cubies xx = xv+cube(c,1)+5; % x trace for cubie c yy = yv+cube(c,2)+12; % y trace + move image up 6 squarelet(c) = patch(xx*sqsize, yy*sqsize, white); end % paint an empty cube in 3 d c = cos(pi/6); % 30 degrees s = sin(pi/6); x1 = [0 c c 0 0]; % trace a facelet on right y1 = [0 s c+s c 0]; x2 = -x1; % trace a facelet on left x3 = [0 c 0 -c 0]; % trace a facelet on top y3 = [ 0 s 2*s s 0]+3*c; dx3 = 22; % place 3d image on screen dy3 = 11; x1 = x1 + dx3; x2 = x2 + dx3; x3 = x3 + dx3; y1 = y1 + dy3; y3 = y3 + dy3; k = 1; % 27 visible facelets for x = 0:2 for y = 0:2 px = x1+x*c; py = y1+y*c+x*s; trp(k) = patch(px*sqsize, py*sqsize, [1 1 1]); % on right R k = k + 1; px = x2-x*c; trp(k) = patch(px*sqsize, py*sqsize, [1 1 1]); % on left L k = k + 1; px = x3+x*c-y*c; py = y3+y*s+x*s; trp(k) = patch(px*sqsize, py*sqsize, [1 1 1]); % on top T k = k + 1; end end gox = 11*sqsize; goy = .48; line1 = text(gox, goy,'',... 'HorizontalAlignment','center', ... 'color', 'black', ... 'String',getString(message('MATLAB:demos:soma:LabelSolutionInThreeLayers'))); line2 = text(.5, .58,... getString(message('MATLAB:demos:soma:TitleSolutionsForTheSomaCubePuzzleOfPietHein')),... 'HorizontalAlignment','center', ... 'color', 'black'); layerx = .15; layery = .32; lw = sqsize*4; line3 = text(layerx+.005, layery, getString(message('MATLAB:demos:soma:LabelBottom')), 'color', 'black'); line4 = text(layerx+lw+.01, layery, getString(message('MATLAB:demos:soma:LabelMiddle')), 'color', 'black'); line5 = text(layerx+2*lw+.025, layery, getString(message('MATLAB:demos:soma:LabelTop')), 'color', 'black'); Patches = findobj(figh,'Type','patch'); Data.pn = pn; Data.sn = sn; Data.sols = somasols; Data.sol = Data.sols(1,:); Data.squarelet = squarelet; Data.trp = trp; set(figh,'UserData',Data); LocalRepaint(Data)