## Rubik's Cube Simulation ## MTH 44101 Fall 2011-Spring 2013 ## A. O. Hausknecht ## Department of Mathematics ## UMass Dartmouth ## Udated for Visual Python 6.0.4 Spring 2013 from __future__ import division, print_function from visual import * from visual.controls import * from visual.graph import * import wx import wx.lib.buttons as buttons class RubikColorGlobals(object): """ A class to to share the colors used throughout the program.""" _cubeColor = color.black _orange = (1, 0.2, 0) _orangeStr = '#ff8c00' _markerColor = (0.5, 0, 0.5) _faceColors = {'left': color.blue, 'front': color.white, 'right': color.green, 'back': color.yellow, 'up':color.red, 'down': _orange} _faceColorNames = { color.blue: 'Blue', color.white: 'White', color.green: 'Green', color.yellow: 'Yellow', color.red: 'Red', _orange: _orangeStr} def __init__(self): pass class RubikCubePart(RubikColorGlobals): '''A generic part of a rubik's cube.''' partTypes = {'FLU': 'frontLeftUpCorner', 'FRU': 'frontRightUpCorner', 'FLD': 'frontLeftDownCorner', 'FRD': 'frontRightDownCorner', 'BLU': 'backLeftUpCorner', 'BRU': 'backRightUpCorner', 'BLD': 'backLeftDownCorner', 'BRD': 'backRightDownCorner', 'FLE': 'frontLeftEdge', 'FRE': 'frontRightEdge', 'FUE': 'frontUpEdge', 'FDE': 'frontDownEdge', 'BLE': 'backLeftEdge', 'BRE': 'backRightEdge', 'BUE': 'backUpEdge', 'BDE': 'backDownEdge', 'LUE': 'leftUpEdge', 'RUE': 'rightUpEdge', 'LDE': 'leftDownEdge', 'RDE': 'rightDownEdge', 'FCE': 'frontCenter', 'BCE': 'backCenter', 'LCE': 'frontCenter', 'RCE': 'backCenter', 'UCE': 'upCenter', 'DCE': 'downCenter' } __stickerPos = 0.5025 __stickerSize = 0.9 __stickerThickness = 0.05 __markerPos = 0.5525 __markerThickness = 0.05 __markerRadius = 0.3 def __init__(self): self.partType = None self.itsFrame = frame() self.cube = box( frame = self.itsFrame, pos = (0, 0, 0), length = 1, height = 1, width = 1, color = RubikCubePart._cubeColor) self.stickers = []; self.fSticker = None; self.bSticker = None self.lSticker = None; self.rSticker = None self.uSticker = None; self.dSticker = None self.markers = [] self.fMarker = None; self.bMarker = None self.lMarker = None; self.rMarker = None self.uMarker = None; self.dMarker = None def _createFrontSticker(self, mark): sticker = box( frame = self.itsFrame, pos = (0, 0, RubikCubePart.__stickerPos), length = RubikCubePart.__stickerSize, height = RubikCubePart.__stickerSize, width = RubikCubePart.__stickerThickness, color = RubikCubePart._faceColors['front']) sticker.partName = 'fSticker' self.stickers.append(sticker) self.fSticker = sticker marker = cylinder( frame = self.itsFrame, pos = (0, 0, RubikCubePart.__markerPos), axis = (0, 0, 1), length = RubikCubePart.__markerThickness, radius = RubikCubePart.__markerRadius, color = RubikCubePart._markerColor) marker.partName = 'fMarker' marker.visible = mark self.fMarker = marker self.markers.append(marker) def _createBackSticker(self, mark): sticker = box( frame = self.itsFrame, pos = (0, 0, -RubikCubePart.__stickerPos), length = RubikCubePart.__stickerSize, height = RubikCubePart.__stickerSize, width = RubikCubePart.__stickerThickness, color = RubikCubePart._faceColors['back']) sticker.partName = 'bSticker' self.stickers.append(sticker) self.fSticker = sticker marker = cylinder( frame = self.itsFrame, pos = (0, 0, -RubikCubePart.__markerPos), axis = (0,0,1), length = RubikCubePart.__markerThickness, radius = RubikCubePart.__markerRadius, color = RubikCubePart._markerColor) marker.partName = 'bMarker' marker.visible = mark self.fMarker = marker self.markers.append(marker) def _createLeftSticker(self, mark): sticker = box( frame = self.itsFrame, pos = (-RubikCubePart.__stickerPos, 0, 0), length = RubikCubePart.__stickerThickness, height = RubikCubePart.__stickerSize, width = RubikCubePart.__stickerSize, color = RubikCubePart._faceColors['left'] ) sticker.partName = 'lSticker' self.lSticker = sticker self.stickers.append(sticker) marker = cylinder(frame = self.itsFrame, pos = (-RubikCubePart.__markerPos, 0, 0), axis = (1,0,0), length = RubikCubePart.__markerThickness, radius = RubikCubePart.__markerRadius, color = RubikCubePart._markerColor) marker.partName = 'lMarker' marker.visible = mark self.lMarker = marker self.markers.append(marker) def _createRightSticker(self, mark): sticker = box( frame = self.itsFrame, pos = (RubikCubePart.__stickerPos, 0, 0), length = RubikCubePart.__stickerThickness, height = RubikCubePart.__stickerSize, width = RubikCubePart.__stickerSize, color = RubikCubePart._faceColors['right'] ) sticker.partName = 'rSticker' self.rSticker = sticker self.stickers.append(sticker) marker = cylinder( frame = self.itsFrame, pos = (RubikCubePart.__markerPos, 0, 0), axis = (1,0,0), length = RubikCubePart.__markerThickness, radius = RubikCubePart.__markerRadius, color = RubikCubePart._markerColor) marker.partName = 'rMarker' marker.visible = mark self.rMarker = marker self.markers.append(marker) def _createUpSticker(self, mark): sticker = box( frame = self.itsFrame, pos = (0, RubikCubePart.__stickerPos, 0), length = RubikCubePart.__stickerSize, height = RubikCubePart.__stickerThickness, width = RubikCubePart.__stickerSize, color = RubikCubePart._faceColors['up']) sticker.partName = 'uSticker' self.uSticker = sticker self.stickers.append(sticker) marker = cylinder( frame = self.itsFrame, pos = (0, RubikCubePart.__markerPos, 0), axis = (0,1,0), length = RubikCubePart.__markerThickness, radius = RubikCubePart.__markerRadius, color = RubikCubePart._markerColor) marker.partName = 'uMarker' marker.visible = mark self.uMarker = marker self.markers.append(marker) def _createDownSticker(self, mark): sticker = box( frame = self.itsFrame, pos = (0, -RubikCubePart.__stickerPos, 0), length = RubikCubePart.__stickerSize, height = RubikCubePart.__stickerThickness, width = RubikCubePart.__stickerSize, color = RubikCubePart._faceColors['down'] ) sticker.partName = 'dSticker' self.dSticker = sticker self.stickers.append(sticker) marker = cylinder( frame = self.itsFrame, pos = (0, -RubikCubePart.__markerPos, 0), axis = (0,1,0), length = RubikCubePart.__markerThickness, radius = RubikCubePart.__markerRadius, color = RubikCubePart._markerColor) marker.partName = 'dMarker' marker.visible = mark self.dMarker = marker self.markers.append(marker) def setColors(self, colors): for s in self.stickers: if s.partName == 'fSticker': s.color = colors['front'] elif s.partName == 'bSticker': s.color = colors['back'] elif s.partName == 'rSticker': s.color = colors['right'] elif s.partName == 'lSticker': s.color = colors['left'] elif s.partName == 'uSticker': s.color = colors['up'] elif s.partName == 'dSticker': s.color = colors['down'] def showHideMarkers(self, show): for m in self.markers: m.visible = show class CornerPart(RubikCubePart): '''A corner part of a Rubik's cube.''' def __init__(self, which, mark=False): RubikCubePart.__init__(self) self.partType = RubikCubePart.partTypes[which] if which == 'FLU': self._createFrontCorner(True, True, mark) elif which == 'FRU': self._createFrontCorner(False, True, mark) elif which == 'FLD': self._createFrontCorner(True, False, mark) elif which == 'FRD': self._createFrontCorner(False, False, mark) elif which == 'BLU': self._createBackCorner(True, True, mark) elif which == 'BRU': self._createBackCorner(False, True, mark) elif which == 'BLD': self._createBackCorner(True, False, mark) elif which == 'BRD': self._createBackCorner(False, False, mark) def _createFrontCorner(self, isLeft, isTop, mark): '''Create a front corner a Rubik's cube.''' self._createFrontSticker(mark) if isLeft: self._createLeftSticker(mark) cX = -1 else: self._createRightSticker(mark) cX = 1 if isTop: self._createUpSticker(mark) cY = 1 else: self._createDownSticker(mark) cY = -1 self.itsFrame.pos = (cX, cY, 1) self.initPos = (cX, cY, 1) self.initAxis = vector(self.itsFrame.axis) def _createBackCorner(self, isLeft, isTop, mark): '''Create a back corner a Rubik's cube.''' self._createBackSticker(mark) if isLeft: self._createLeftSticker(mark) cX = -1 else: self._createRightSticker(mark) cX = 1 if isTop: self._createUpSticker(mark) cY = 1 else: self._createDownSticker(mark) cY = -1 self.itsFrame.pos = (cX, cY, -1) self.initPos = (cX, cY, -1) self.initAxis = vector(self.itsFrame.axis) class EdgePart(RubikCubePart): '''Create an edge part of a rubik's cube.''' def __init__(self, which, mark=False): RubikCubePart.__init__(self) self.partType = RubikCubePart.partTypes[which] if which.startswith('F'): self._createFrontEdge(which, mark) elif which.startswith('B'): self._createBackEdge(which, mark) else: self._createLeftRightEdge(which, mark) def _createFrontEdge(self, which, mark): '''Create a front edge part of a rubik's cube.''' self._createFrontSticker(mark) if which=='FLE': self._createLeftSticker(mark) cX = -1; cY = 0 elif which=='FRE': self._createRightSticker(mark) cX = 1; cY = 0 elif which=='FUE': self._createUpSticker(mark) cX = 0; cY = 1 elif which=='FDE': self._createDownSticker(mark) cX = 0; cY = -1 self.itsFrame.pos = (cX, cY, 1) self.initPos = (cX, cY, 1) self.initAxis = vector(self.itsFrame.axis) def _createBackEdge(self, which, mark): self._createBackSticker(mark) if which == 'BLE': self._createLeftSticker(mark) cX = -1; cY = 0 elif which == 'BRE': self._createRightSticker(mark) cX = 1; cY = 0 elif which == 'BUE': self._createUpSticker(mark) cX = 0; cY = 1 elif which == 'BDE': self._createDownSticker(mark) cX = 0; cY = -1 self.itsFrame.pos = (cX, cY, -1) self.initPos = (cX, cY, -1) self.initAxis = vector(self.itsFrame.axis) def _createLeftRightEdge(self, which, mark): if which.startswith('L'): self._createLeftSticker(mark) cX = -1 elif which.startswith('R'): self._createRightSticker(mark) cX = 1 else: print("Error in '_createLeftRightEdge'") if which.endswith('UE'): self._createUpSticker(mark) cY = 1 elif which.endswith('DE'): self._createDownSticker(mark) cY = -1 else: print("Error in '_createLeftRightEdge'") self.itsFrame.pos = (cX, cY, 0) self.initPos = (cX, cY, 0) self.initAxis = vector(self.itsFrame.axis) class CenterPart(RubikCubePart): '''Create center part of a rubik's cube.''' def __init__(self, which, mark=False): RubikCubePart.__init__(self) self.partType = RubikCubePart.partTypes[which] cX = cY = cZ = 0 if which == 'LCE': self._createLeftSticker(mark) cX = -1 elif which == 'RCE': self._createRightSticker(mark) cX = 1 elif which == 'UCE': self._createUpSticker(mark) cY = 1 elif which == 'DCE': self._createDownSticker(mark) cY = -1 elif which == 'FCE': self._createFrontSticker(mark) cZ = 1 elif which == 'BCE': self._createBackSticker(mark) cZ = -1 self.itsFrame.pos = (cX, cY, cZ) self.initPos = (cX, cY, cZ) self.initAxis = vector(self.itsFrame.axis) class RubiksCube(RubikColorGlobals): '''A class representing a Rubik's cube.''' _frontFacePerm ={'FLU': 'FRU', 'FRU': 'FRD', 'FRD': 'FLD', 'FLD': 'FLU', 'FLE': 'FUE', 'FUE': 'FRE', 'FRE': 'FDE', 'FDE': 'FLE', 'FCE': 'FCE'} _backFacePerm = {'BLU': 'BLD', 'BLD': 'BRD', 'BRD': 'BRU', 'BRU': 'BLU', 'BLE': 'BDE', 'BDE': 'BRE', 'BRE': 'BUE', 'BUE': 'BLE', 'BCE': 'BCE'} _leftFacePerm = {'FLU': 'FLD', 'FLD': 'BLD', 'BLD': 'BLU', 'BLU': 'FLU', 'FLE': 'LDE', 'LDE': 'BLE', 'BLE': 'LUE', 'LUE': 'FLE', 'LCE': 'LCE'} _rightFacePerm ={'FRU': 'BRU', 'BRU': 'BRD', 'BRD': 'FRD', 'FRD': 'FRU', 'FRE': 'RUE', 'RUE': 'BRE', 'BRE': 'RDE', 'RDE': 'FRE', 'RCE': 'RCE'} _upFacePerm = {'FLU': 'BLU', 'BLU': 'BRU', 'BRU': 'FRU', 'FRU': 'FLU', 'LUE': 'BUE', 'BUE': 'RUE', 'RUE': 'FUE', 'FUE': 'LUE', 'UCE': 'UCE'} _downFacePerm = {'FLD': 'FRD', 'FRD': 'BRD', 'BRD': 'BLD', 'BLD': 'FLD', 'LDE': 'FDE', 'FDE': 'RDE', 'RDE': 'BDE', 'BDE': 'LDE', 'DCE': 'DCE'} def __init__(self): self.cFrontLeftUp = CornerPart('FLU') self.cFrontLeftDown = CornerPart('FLD') self.cFrontRightUp = CornerPart('FRU') self.cFrontRightDown = CornerPart('FRD') fColor = self._faceColors['back'] self.cBackLeftUp = CornerPart('BLU') self.cBackLeftDown = CornerPart('BLD') self.cBackRightUp = CornerPart('BRU') self.cBackRightDown = CornerPart('BRD') fColor = self._faceColors['front'] self.cFrontLeftEdge = EdgePart('FLE') self.cFrontRightEdge = EdgePart('FRE') self.cFrontUpEdge = EdgePart('FUE') self.cFrontDownEdge = EdgePart('FDE') self.cBackLeftEdge = EdgePart('BLE') self.cBackRightEdge = EdgePart('BRE') self.cBackUpEdge = EdgePart('BUE') self.cBackDownEdge = EdgePart('BDE') self.cLeftUpEdge = EdgePart('LUE') self.cLeftDownEdge = EdgePart('LDE') self.cRightUpEdge = EdgePart('RUE') self.cRightDownEdge = EdgePart('RDE') self.cFrontCenter = CenterPart('FCE') self.cBackCenter = CenterPart('BCE') self.cLeftCenter = CenterPart('LCE') self.cRightCenter = CenterPart('RCE') self.cUpCenter = CenterPart('UCE') self.cDownCenter = CenterPart('DCE') self.frontFace = [self.cFrontLeftUp, self.cFrontRightUp, self.cFrontRightDown, self.cFrontLeftDown, self.cFrontLeftEdge, self.cFrontUpEdge, self.cFrontRightEdge, self.cFrontDownEdge, self.cFrontCenter] self.backFace = [self.cBackLeftUp, self.cBackLeftDown, self.cBackRightDown, self.cBackRightUp, self.cBackLeftEdge, self.cBackDownEdge, self.cBackRightEdge, self.cBackUpEdge, self.cBackCenter] self.upFace = [self.cFrontLeftUp, self.cBackLeftUp, self.cBackRightUp, self.cFrontRightUp, self.cLeftUpEdge, self.cBackUpEdge, self.cRightUpEdge, self.cFrontUpEdge, self.cUpCenter] self.downFace = [self.cFrontLeftDown, self.cFrontRightDown, self.cBackRightDown, self.cBackLeftDown, self.cLeftDownEdge, self.cFrontDownEdge, self.cRightDownEdge, self.cBackDownEdge, self.cDownCenter] self.leftFace = [self.cFrontLeftUp, self.cFrontLeftDown, self.cBackLeftDown, self.cBackLeftUp, self.cFrontLeftEdge, self.cLeftDownEdge, self.cBackLeftEdge, self.cLeftUpEdge, self.cLeftCenter] self.rightFace = [self.cFrontRightUp, self.cBackRightUp, self.cBackRightDown, self.cFrontRightDown, self.cFrontRightEdge, self.cRightUpEdge, self.cBackRightEdge, self.cRightDownEdge, self.cRightCenter] self._rCubeD = { 'FLU': self.cFrontLeftUp, # 1 'FLD': self.cFrontLeftDown, # 2 'FRU': self.cFrontRightUp, # 3 'FRD': self.cFrontRightDown, # 4 'FLE': self.cFrontLeftEdge, # 5 'FRE': self.cFrontRightEdge, # 6 'FUE': self.cFrontUpEdge, # 7 'FDE': self.cFrontDownEdge, # 8 'FCE': self.cFrontCenter, # 9 'BLU': self.cBackLeftUp, #10 'BLD': self.cBackLeftDown, #11 'BRU': self.cBackRightUp, #12 'BRD': self.cBackRightDown, #13 'BLE': self.cBackLeftEdge, #14 'BRE': self.cBackRightEdge, #15 'BUE': self.cBackUpEdge, #16 'BDE': self.cBackDownEdge, #17 'BCE': self.cBackCenter, #18 'LUE': self.cLeftUpEdge, #19 'LDE': self.cLeftDownEdge, #20 'LCE': self.cLeftCenter, #21 'RUE': self.cRightUpEdge, #22 'RDE': self.cRightDownEdge, #23 'RCE': self.cRightCenter, #24 'UCE': self.cUpCenter, #25 'DCE': self.cDownCenter #26 } self._undoList = [] self._redo = None self._currentFacePerm = None self._animationKeys = [] self._tempParts = [] self._currentAngle = 0 self._endingAngle = 0 self._permAxis = None self._shouldAnimate = False self._dt = 0 self._permPower = 0 def _resetCubeD(self): self._rCubeD['FLU'] = self.cFrontLeftUp # 1 self._rCubeD['FLD'] = self.cFrontLeftDown # 2 self._rCubeD['FRU'] = self.cFrontRightUp # 3 self._rCubeD['FRD'] = self.cFrontRightDown # 4 self._rCubeD['FLE'] = self.cFrontLeftEdge # 5 self._rCubeD['FRE'] = self.cFrontRightEdge # 6 self._rCubeD['FUE'] = self.cFrontUpEdge # 7 self._rCubeD['FDE'] = self.cFrontDownEdge # 8 self._rCubeD['FCE'] = self.cFrontCenter # 9 self._rCubeD['BLU'] = self.cBackLeftUp #10 self._rCubeD['BLD'] = self.cBackLeftDown #11 self._rCubeD['BRU'] = self.cBackRightUp #12 self._rCubeD['BRD'] = self.cBackRightDown #13 self._rCubeD['BLE'] = self.cBackLeftEdge #14 self._rCubeD['BRE'] = self.cBackRightEdge #15 self._rCubeD['BUE'] = self.cBackUpEdge #16 self._rCubeD['BDE'] = self.cBackDownEdge #17 self._rCubeD['BCE'] = self.cBackCenter #18 self._rCubeD['LUE'] = self.cLeftUpEdge #19 self._rCubeD['LDE'] = self.cLeftDownEdge #20 self._rCubeD['LCE'] = self.cLeftCenter #21 self._rCubeD['RUE'] = self.cRightUpEdge #22 self._rCubeD['RDE'] = self.cRightDownEdge #23 self._rCubeD['RCE'] = self.cRightCenter #24 self._rCubeD['UCE'] = self.cUpCenter #25 self._rCubeD['DCE'] = self.cDownCenter #26 rCubeD = self._rCubeD keys = rCubeD.keys() for k in keys: f = rCubeD[k].itsFrame f.pos = rCubeD[k].initPos f.axis = (1, 0, 0) f.up = (0, 1, 0) ## def _showHidePartMarkers(show, parts): ## for p in parts: p.showHideMarkers(show) def showHideUpFaceMarkers(self, showIt, which): for x in self.upFace: if x.partType.endswith(which): x.showHideMarkers(showIt) def showHideUpFaceMarker(self, showIt, which): if which == 'FUE': self.cFrontUpEdge.showHideMarkers(showIt) elif which == 'BUE': self.cBackUpEdge.showHideMarkers(showIt) elif which == 'LUE': self.cLeftUpEdge.showHideMarkers(showIt) elif which == 'RUE': self.cLeftUpEdge.showHideMarkers(showIt) elif which == 'FLU': self.cFrontLeftUp.showHideMarkers(showIt) elif which == 'FRU': self.cFrontRightUp.showHideMarkers(showIt) elif which == 'BLU': self.cBackLeftUp.showHideMarkers(showIt) elif which == 'BRU': self.cBackRightUp.showHideMarkers(showIt) def applyPerm(self, perm, power): if type(power) == int and power in (-1, 1, 2): if perm =='F': self._rotateFrontFace(power) elif perm == 'B': self._rotateBackFace(power) elif perm == 'U': self._rotateUpFace(power) elif perm == 'D': self._rotateDownFace(power) elif perm == 'L': self._rotateLeftFace(power) elif perm == 'R': self._rotateRightFace( power) def doPerm(self, facePerm, pAxis, power): self._currentFacePerm = facePerm self._animationKeys = facePerm.keys() self._permAxis = pAxis self._permPower = power self._tempParts = {} for k in self._animationKeys: self._tempParts[k] = self._rCubeD[k] self._currentAngle = 0 self._shouldAnimate = True if power == -1: self._endingAngle = -pi/2 self._dt = -pi/8 else: self._endingAngle = power*pi/2 self._dt = pi/8 def doAnimation(self): if self._shouldAnimate: aKeys = self._animationKeys for k in aKeys: self._tempParts[k].itsFrame.rotate(angle = self._dt, axis = self._permAxis, origin = (0,0,0)) self._currentAngle += self._dt if (abs(self._currentAngle - self._endingAngle) < 0.01): self._currentAngle = self._endingAngle self._shouldAnimate = False self.finishPermAnimation() def finishPermAnimation(self): perm = self._currentFacePerm tempParts = self._tempParts if self._permPower == -1: for k in self._animationKeys: self._rCubeD[k] = tempParts[perm[k]] elif self._permPower == 1: for k in self._animationKeys: self._rCubeD[perm[k]] = tempParts[k] else: for k in self._animationKeys: self._rCubeD[perm[perm[k]]] = tempParts[k] def _postUndo(self, which, power): self._redo = None if power == -1: self._undoList.append((which,1)) elif power == 1: self._undoList.append((which,-1)) elif power == 2: self._undoList.append((which,2)) def _doFacePerm(self, which, power): if which == 'front': self.doPerm(self._frontFacePerm, (0, 0, -1), power) elif which == 'back': self.doPerm(self._backFacePerm, (0, 0, 1), power) elif which == 'left': self.doPerm(self._leftFacePerm, (1, 0, 0), power) elif which == 'right': self.doPerm(self._rightFacePerm, (-1, 0, 0), power) elif which == 'up': self.doPerm(self._upFacePerm, (0, -1, 0), power) elif which == 'down': self.doPerm(self._downFacePerm, (0, 1, 0), power) def _doUndo(self): if len(self._undoList)>0: which, power = self._undoList.pop() self._doFacePerm(which, power) if power == -1: self._redo = (which, 1) elif power == 1: self._doRedo = (which, -1) elif power == 2: self._redo = (which, 2) def _doRedo(self): if self._redo != None: which, power = self._redo self._doFacePerm(which, power) self._postUndo(which, power) def rotateFrontFace(self, power): self._doFacePerm('front',power) self._postUndo('front', power) def rotateBackFace(self, power): self._doFacePerm('back',power) self._postUndo('back', power) def rotateUpFace(self, power): self._doFacePerm('up',power) self._postUndo('up', power) def rotateDownFace(self, power): self._doFacePerm('down',power) self._postUndo('down', power) def rotateLeftFace(self, power): self._doFacePerm('left',power) self._postUndo('left', power) def rotateRightFace(self, power): self._doFacePerm('right',power) self._postUndo('right', power) def getFaceColor(self, which): if which in self._faceColors.keys(): return self._faceColors[which] else: return color.black def getFaceColorForNewButtons(self, which): if which in self._faceColors.keys(): c = self._faceColors[which] return self._faceColorNames[c] else: return 'Black' def resetFaceColors(self): self._faceColors['left'] = color.blue self._faceColors['front'] = color.white self._faceColors['right'] = color.green self._faceColors['back'] = color.yellow self._faceColors['up'] = color.red self._faceColors['down'] = _orange def rotateFaceColorsAroundZAxis(self): self._resetCubeD() zPerm = {'left':'front', 'front':'right', 'right': 'back', 'back':'left', 'up': 'up', 'down':'down'} fColors = self._faceColors colors = fColors.copy() for k in zPerm.keys(): colors[zPerm[k]] = fColors[k] for k in fColors.keys(): fColors[k] = colors[k] rCube = self._rCubeD for k in rCube.keys(): rCube[k].setColors(fColors) def rotateFaceColorsAroundXAxis(self): self._resetCubeD() xPerm = {'front':'down', 'down':'back', 'back': 'up', 'up':'front', 'left':'left', 'right':'right'} fColors = self._faceColors colors = fColors.copy() for k in xPerm.keys(): colors[xPerm[k]] = fColors[k] for k in fColors.keys(): fColors[k] = colors[k] rCube = self._rCubeD for k in rCube.keys(): rCube[k].setColors(fColors) class Frame(wx.Frame): def __init__(self, parent, title, width, height): wx.Frame.__init__(self, parent, -1, title, pos = (801, 20), size = (width,height)) class RubiksCubeScene(RubikColorGlobals): '''Class to setup and control a Visual Python scene containting a Rubik's cube.''' _bSize = 30 _minX = -80; _maxY = 80 _deltaX = 32; _deltaY = 32 _cWindowX = 700; _cWindowY = 0 _cWindowWidth = 600; _cWindowHeignt = 600 _mainWindow = None def __init__(self): self._viewLabel = None sWidth = 800 sHeight = 800 _mainWindow = window(menus=False, title="Rubik's Cube", x=0, y=0, width=sWidth, height=sWidth) scene1 = display(window = _mainWindow, title="", x=0, y=0, width=sWidth, height=sHeight, background=(0.7,0.7,0.7)) scene1.range = 4 self._scene = scene1 scene1.forward = (cos(pi/4), -cos(pi/4), -cos(pi/4)) distant_light(direction=(-1, -1, -1), color=color.white) distant_light(direction=( 1, -1, -1), color=color.white) distant_light(direction=(-1, 1, -1), color=color.white) distant_light(direction=(-1, -1, 1), color=color.white) distant_light(direction=( 1, 1, 1), color=color.white) self._rubiksCube = RubiksCube() self._viewLabel = label(pos=(0,3,0), height=36, text='FLU-View', color=color.white, linecolor = color.black) self._createNewControlWindow(_mainWindow.win) def _showView(self, which): vlPos = (0,3,0) if which == 'flu': self._scene.forward = (1, -1, -1) elif which == 'fru': self._scene .forward = (-1, -1, -1) elif which == 'blu': self._scene.forward = (1, -1, 1) elif which == 'bru': self._scene.forward = (-1, -1, 1) elif which == 'fld': self._scene.forward = (1, 1, -1) vlPos = (0, 6, 0) elif which == 'frd': self._scene.forward = (-1, 1, -1) vlPos = (0, 6, 0) elif which == 'bld': self._scene.forward = (1, 1, 1) vlPos = (0, 6, 0) elif which == 'brd': self._scene.forward = (-1, 1, 1) vlPos = (0, 6, 0) self._viewLabel.text = which.upper()+'-View' self._viewLabel.pos = vlPos def _setNewButtonsColor(self, faceButtons, which): c = self._rubiksCube.getFaceColorForNewButtons(which) if c == RubiksCube._orange: c = RubiksCube._orangeStr; for b in faceButtons.values(): b.SetBackgroundColour(c) if c =='Blue': b.SetForegroundColour("White") else: b.SetForegroundColour("Black") b.Refresh() if which == "front": self._viewLabel.color = self._rubiksCube.getFaceColor(which) def doRotateColorsAroundZAxis(self): self._rubiksCube.rotateFaceColorsAroundZAxis() self._setNewButtonsColor(self.frontFaceButtons, 'front') self._setNewButtonsColor(self.rightFaceButtons, 'right') self._setNewButtonsColor( self.backFaceButtons, 'back' ) self._setNewButtonsColor( self.leftFaceButtons, 'left' ) def doRotateColorsAroundXAxis(self): self._rubiksCube.rotateFaceColorsAroundXAxis() self._setNewButtonsColor(self.frontFaceButtons, 'front') self._setNewButtonsColor( self.downFaceButtons, 'down' ) self._setNewButtonsColor( self.backFaceButtons, 'back' ) self._setNewButtonsColor( self.upFaceButtons, 'up' ) def _createNewButton(self, panel, name, color): b = buttons.GenButton(panel, -1, name) b.SetFont(wx.Font(16, wx.SWISS, wx.NORMAL, wx.BOLD, False)) b.SetBezelWidth(5) b.SetMinSize(wx.DefaultSize) b.SetBackgroundColour(color) b.SetForegroundColour(wx.BLACK) return b def _createGridOfButtons(self, panel, buttonNames, buttonColors, rows, cols): gridS = wx.GridSizer(rows, cols, 5, 5) buttons = {} for name, color in zip(buttonNames, buttonColors): if name == '': b = wx.StaticText(panel, label='') else: b = self._createNewButton(panel, name, color) if color=='Blue': b.SetForegroundColour(wx.WHITE) buttons[name] = b gridS.Add(b, proportion=1, flag=wx.ALL|wx.EXPAND, border=5) return (buttons, gridS) def _createSliderBox(self, panel, prompt, sMin, sMax, sValue): slider = wx.Slider(panel, size=(200,30), minValue=sMin, maxValue=sMax) slider.SetValue(sValue) label = wx.StaticText(panel, label=prompt) label.SetForegroundColour('white') label.SetFont(wx.Font(20, wx.SWISS, wx.NORMAL, wx.BOLD, False)) hbox = wx.BoxSizer(wx.HORIZONTAL) hbox.Add(label, flag=wx.ALL, border = 10) hbox.Add(slider, flag=wx.ALL, border = 10) return (slider, hbox) def _bindButton(self, buttons, name, callback): if name == 'animationRate': self.animationSlider.Bind(wx.EVT_SCROLL, callback) else: buttons[name].Bind(wx.EVT_BUTTON,callback) def _createNewControlWindow(self, win): rCube = self._rubiksCube ctlFrame = Frame(win, "Transform Controls", 625,475) panel = wx.Panel(ctlFrame) ##panel.SetBackgroundColour("black") bNames = ['F', 'F^2', 'F^(-1)', 'B', 'B^2', 'B^(-1)', 'L', 'L^2', 'L^(-1)', 'R', 'R^2', 'R^(-1)', 'U', 'U^2', 'U^(-1)', 'D', 'D^2', 'D^(-1)'] orangeStr = RubiksCube._orangeStr bColors = ['White', 'White', 'White', 'Yellow', 'Yellow', 'Yellow', 'Blue', 'Blue', 'Blue', 'Green', 'Green', 'Green', 'Red', 'Red', 'Red', orangeStr, orangeStr, orangeStr] rotateButtons, rotateGrid = self._createGridOfButtons(panel, bNames, bColors, 6, 3) self.rotateButtons = rotateButtons rotateButtons['F'].Bind(wx.EVT_BUTTON, lambda event: rCube.rotateFrontFace(1)) rotateButtons['F^2'].Bind(wx.EVT_BUTTON, lambda event: rCube.rotateFrontFace(2)) rotateButtons['F^(-1)'].Bind(wx.EVT_BUTTON, lambda event: rCube.rotateFrontFace(-1)) self.frontFaceButtons = {'F': rotateButtons['F'], 'F2': rotateButtons['F^2'], 'F3': rotateButtons['F^(-1)']} rotateButtons['B'].Bind(wx.EVT_BUTTON, lambda event: rCube.rotateBackFace(1)) rotateButtons['B^2'].Bind(wx.EVT_BUTTON, lambda event: rCube.rotateBackFace(2)) rotateButtons['B^(-1)'].Bind(wx.EVT_BUTTON, lambda event: rCube.rotateBackFace(-1)) self.backFaceButtons = {'B': rotateButtons['B'], 'B2': rotateButtons['B^2'], 'B3': rotateButtons['B^(-1)']} rotateButtons['L'].Bind(wx.EVT_BUTTON, lambda event: rCube.rotateLeftFace(1)) rotateButtons['L^2'].Bind(wx.EVT_BUTTON, lambda event: rCube.rotateLeftFace(2)) rotateButtons['L^(-1)'].Bind(wx.EVT_BUTTON, lambda event: rCube.rotateLeftFace(-1)) self.leftFaceButtons = {'L': rotateButtons['L'], 'L2': rotateButtons['L^2'], 'L3': rotateButtons['L^(-1)']} rotateButtons['R'].Bind(wx.EVT_BUTTON, lambda event: rCube.rotateRightFace(1)) rotateButtons['R^2'].Bind(wx.EVT_BUTTON, lambda event: rCube.rotateRightFace(2)) rotateButtons['R^(-1)'].Bind(wx.EVT_BUTTON, lambda event: rCube.rotateRightFace(-1)) self.rightFaceButtons = {'R': rotateButtons['R'], 'R2': rotateButtons['R^2'], 'R3': rotateButtons['R^(-1)']} rotateButtons['U'].Bind(wx.EVT_BUTTON, lambda event: rCube.rotateUpFace(1)) rotateButtons['U^2'].Bind(wx.EVT_BUTTON, lambda event: rCube.rotateUpFace(2)) rotateButtons['U^(-1)'].Bind(wx.EVT_BUTTON, lambda event: rCube.rotateUpFace(-1)) self.upFaceButtons = {'U': rotateButtons['U'], 'U2': rotateButtons['U^2'], 'U3': rotateButtons['U^(-1)']} rotateButtons['D'].Bind(wx.EVT_BUTTON, lambda event: rCube.rotateDownFace(1)) rotateButtons['D^2'].Bind(wx.EVT_BUTTON, lambda event: rCube.rotateDownFace(2)) rotateButtons['D^(-1)'].Bind(wx.EVT_BUTTON, lambda event: rCube.rotateDownFace(-1)) self.downFaceButtons = {'D': rotateButtons['D'], 'D2': rotateButtons['D^2'], 'D3': rotateButtons['D^(-1)']} bNames = ['FLU', 'FRU', 'BLU', 'BRU', 'FLD', 'FRD', 'BLD', 'BRD'] bColors = ['Pink', 'Pink', 'Pink', 'Pink', 'Pink', 'Pink','Pink', 'Pink'] viewButtons, viewGrid = self._createGridOfButtons(panel, bNames, bColors, 4, 2) self.viewButtons = viewButtons viewButtons['FLU'].Bind(wx.EVT_BUTTON, lambda event: self._showView('flu')) viewButtons['FRU'].Bind(wx.EVT_BUTTON, lambda event: self._showView('fru')) viewButtons['BLU'].Bind(wx.EVT_BUTTON, lambda event: self._showView('blu')) viewButtons['BRU'].Bind(wx.EVT_BUTTON, lambda event: self._showView('bru')) viewButtons['FLD'].Bind(wx.EVT_BUTTON, lambda event: self._showView('fld')) viewButtons['FRD'].Bind(wx.EVT_BUTTON, lambda event: self._showView('frd')) viewButtons['BLD'].Bind(wx.EVT_BUTTON, lambda event: self._showView('bld')) viewButtons['BRD'].Bind(wx.EVT_BUTTON, lambda event: self._showView('brd')) bNames = ['Undo', 'Redo', 'Reset'] bColors = ['Magenta', 'Magenta', 'Cyan'] editButtons, editGrid = self._createGridOfButtons(panel, bNames, bColors, 1, 3) self.editButtons = editButtons editButtons['Undo'].Bind(wx.EVT_BUTTON, lambda event: rCube._doUndo()) editButtons['Redo'].Bind(wx.EVT_BUTTON, lambda event: rCube._doRedo()) editButtons['Reset'].Bind(wx.EVT_BUTTON, lambda event: rCube._resetCubeD()) bNames = ['FRBL', 'FDBU'] bColors = ['Cyan', 'Cyan'] colorButtons, colorGrid = self._createGridOfButtons(panel, bNames, bColors, 1, 2) self.colorButtons = colorButtons colorButtons['FRBL'].Bind(wx.EVT_BUTTON, lambda event: self.doRotateColorsAroundZAxis()) colorButtons['FDBU'].Bind(wx.EVT_BUTTON, lambda event: self.doRotateColorsAroundXAxis()) box = wx.StaticBox(panel,-1,"Edit") editbox = wx.StaticBoxSizer(box, wx.HORIZONTAL) editbox.Add(editGrid) box = wx.StaticBox(panel,-1,"Transforms") rotationbox = wx.StaticBoxSizer(box, wx.HORIZONTAL) rotationbox.Add(rotateGrid) editRotationbox = wx.BoxSizer(wx.VERTICAL) editRotationbox.Add(editbox, flag=wx.EXPAND|wx.ALL, border=5) editRotationbox.Add(rotationbox, flag=wx.EXPAND|wx.ALL, border=5) box = wx.StaticBox(panel,-1,"Change View") viewbox = wx.StaticBoxSizer(box, wx.HORIZONTAL) viewbox.Add(viewGrid) box = wx.StaticBox(panel,-1,"Cycle Cube Colors") colorbox = wx.StaticBoxSizer(box, wx.HORIZONTAL) colorbox.Add(colorGrid) viewColorbox = wx.BoxSizer(wx.VERTICAL) viewColorbox.Add(viewbox, flag=wx.EXPAND|wx.ALL, border=5) viewColorbox.Add(colorbox, flag=wx.EXPAND|wx.ALL, border=5) hbox = wx.BoxSizer(wx.HORIZONTAL) hbox.Add(editRotationbox, flag=wx.EXPAND|wx.ALL, border=5) hbox.Add(viewColorbox, flag=wx.EXPAND|wx.ALL, border=5) vbox = wx.BoxSizer(wx.VERTICAL) vbox.Add(hbox, flag=wx.EXPAND|wx.ALL, border=5) panel.SetSizer(vbox) ctlFrame.Show() return ctlFrame def _handleKey(self): if scene.kb.keys: s = scene.kb.getkey() power = 1 if s.isupper(): power = -1 s = s.lower() if s == 'f': rotateFrontFace(power) elif s == 'b': rotateBackFace(power) elif s == 'l': rotateLeftFace(power) elif s == 'r': rotateRightFace(power) elif s == 'u': rotateUpFace(power) else: rotateDownFace(power) def doEventLoop(self): ##self._rubiksCube.showHideUpFaceMarkers(True, 'Edge') self._rubiksCube.showHideUpFaceMarker(True, 'FUE') while True: rate(10) self._rubiksCube.doAnimation() self._handleKey() rbs = RubiksCubeScene() rbs.doEventLoop()