All pastes #802533 Raw Edit

RubikCube

public java v1 · immutable
#802533 ·published 2007-11-30 11:31 UTC
rendered paste body
import java.util.Random;import com.jme.app.SimpleGame;import com.jme.bounding.BoundingBox;import com.jme.light.LightNode;import com.jme.light.PointLight;import com.jme.math.FastMath;import com.jme.math.Quaternion;import com.jme.math.Vector3f;import com.jme.renderer.Camera;import com.jme.renderer.ColorRGBA;import com.jme.renderer.Renderer;import com.jme.scene.Node;import com.jme.scene.Spatial;import com.jme.scene.shape.Box;import com.jme.scene.shape.RoundedBox;import com.jme.scene.state.LightState;import com.jme.scene.state.MaterialState;import com.jme.scene.state.ZBufferState;import com.jme.system.DisplaySystem;/** * RubiksCube implementation with the jMonkey Engine *  * This implementation is non interactive and made just for fun *  * @author Thomas Åhlén 2007-11-28 */public class RubiksCube extends SimpleGame{    private final static int  LEFT   = 0;    private final static int  RIGHT  = 1;    private final static int  DOWN   = 2;    private final static int  UP     = 3;    private final static int  FRONT  = 4;    private final static int  BACK   = 5;         private final static int  GREEN  = 0;    private final static int  BLUE   = 1;    private final static int  YELLOW = 2;    private final static int  WHITE  = 3;    private final static int  RED    = 4;    private final static int  ORANGE = 5;     RubikRotator           m_rotator;        private Node           m_cubeNode;        private Node[][][]     m_cubeNodes;    private Node[]         m_rotationNodes;    private Node[][][]     m_rotationSubNodes;                private float m_scale           = 100f;    private float m_boxSize         = m_scale*1f;    private float m_gap             = m_scale*0.05f;    private float m_plateThickness  = m_scale*0.05f;    private float m_plateSize       = m_boxSize*0.9f;    private float m_plateEdge       = m_scale*0.02f;     private float m_rotationSpeed   = FastMath.PI/3.0f;        private MaterialState[] m_mStates;        private int m_counter = 0;    private Vector3f m_camPosition;    private Renderer m_renderer;        private Random m_rand;        public static void main(String[] args)     {        RubiksCube app = new RubiksCube();        app.setDialogBehaviour(NEVER_SHOW_PROPS_DIALOG);        app.start();    }    protected void simpleInitGame()     {        Camera cam;        display.setTitle("RubikCube");                m_renderer = DisplaySystem.getDisplaySystem().getRenderer();        m_rand = new Random();        ZBufferState zbuf = m_renderer.createZBufferState();        zbuf.setWritable( true );        zbuf.setEnabled( true );        zbuf.setFunction( ZBufferState.CF_LEQUAL );        m_cubeNode = new Node("TheCube");        m_cubeNode.setRenderState( zbuf );        rootNode.attachChild( m_cubeNode );                createMaterialStates();                createCubeNodes();                createRotationNodes();                       m_rotator = new RubikRotator();        Vector3f left = new Vector3f( 1, 0, 0 );        Vector3f up   = new Vector3f( 0, 1, 0 );        Vector3f dir  = new Vector3f( 0, 0, 1 );        m_camPosition = Vector3f.ZERO.clone();        m_camPosition.addLocal(  m_boxSize*4, m_boxSize*4, m_boxSize*4 );        float frustumFar = 100*m_scale;        cam = m_renderer.getCamera();        cam.setFrustumPerspective( 45.0f, 1, 1, frustumFar );        cam.setFrame( m_camPosition, left, up, dir );        cam.lookAt( Vector3f.ZERO, Vector3f.UNIT_Y );                    LightState ls = m_renderer.createLightState();        LightNode lightNode = new LightNode( "CamLight", ls );        PointLight light = new PointLight();        light.setDiffuse( new ColorRGBA( 0.8f, 0.8f, 0.8f, 1f ) );        light.setAmbient( new ColorRGBA( 0.3f, 0.3f, 0.3f, 1f ) );        light.setLocation(m_camPosition);        light.setEnabled( true );        lightNode.setLight( light );        lightNode.setTarget( m_cubeNode );          }        protected void simpleUpdate()     {        if( m_counter%100 == 0 && m_rotator.isDone() )        {            int type, turns;                        type = m_rand.nextInt( 9 );            do            {                turns = -2 + m_rand.nextInt( 5 );            }            while( turns == 0 );            m_rotator.init( type, turns );        }                m_rotator.rotate( tpf );          m_counter++;    }            private void createMaterialStates()    {        MaterialState ms;                m_mStates = new MaterialState[6];                ms = m_renderer.createMaterialState();        ms.setDiffuse( new ColorRGBA( 1, 0, 0, 0.5f ) );        ms.setEmissive( new ColorRGBA( 0.5f, 0, 0, 1 ) );        m_mStates[RED] = ms;                ms = m_renderer.createMaterialState();        ms.setDiffuse( new ColorRGBA( 0, 0, 1, 0.5f ) );        ms.setEmissive( new ColorRGBA( 0, 0, 0.5f, 1 ) );        m_mStates[BLUE] = ms;                ms = m_renderer.createMaterialState();        ms.setDiffuse( new ColorRGBA( 0, 1, 0, 0.5f ) );        ms.setEmissive( new ColorRGBA( 0, 0.5f, 0, 1 ) );        m_mStates[GREEN] = ms;        ms = m_renderer.createMaterialState();        ms.setDiffuse( new ColorRGBA( 1, 1, 0, 0.5f ) );        ms.setEmissive( new ColorRGBA( 0.5f, 0.5f, 0, 1 ) );        m_mStates[YELLOW] = ms;        ms = m_renderer.createMaterialState();        ms.setDiffuse( new ColorRGBA( 1, 1, 1, 0.5f ) );        ms.setEmissive( new ColorRGBA( 0.5f, 0.5f, 0.5f, 1 ) );        m_mStates[WHITE] = ms;        ms = m_renderer.createMaterialState();        ms.setDiffuse( new ColorRGBA( 251f/255f, 130f/255f, 0, 0.5f ) );                ms.setEmissive( new ColorRGBA( 251f/255f*0.5f, 130f/255f*0.5f, 0, 1 ) );        m_mStates[ORANGE] = ms;    }        /**     * Create 27 cube node where our cubes will reside when not rotating     */    private void createCubeNodes()    {        Node node;                m_cubeNodes = new Node[3][3][3];                for( int i = 0; i < 3; i++ )        {            for( int j = 0; j < 3; j++ )            {                for( int k = 0; k < 3; k++ )                {                    node = new Node( "cn" + i + j + k );                    node.getLocalTranslation().addLocal( (i-1)*(m_boxSize+m_gap),                                                          (j-1)*(m_boxSize+m_gap),                                                         (k-1)*(m_boxSize+m_gap) );                    m_cubeNodes[i][j][k] = node;                    node.attachChild( createBox(i,j,k) );                    m_cubeNode.attachChild( node );                }                            }                    }            }        private Spatial createBox( int i, int j, int k )    {        Node boxNode;        Spatial box;        MaterialState ms;        boxNode = new Node("bn");        boxNode.setModelBound(new BoundingBox());                box = new Box( "b" + i + j + k,                        new Vector3f(0,0,0),                       m_boxSize/2,m_boxSize/2,m_boxSize/2 );        ms = m_renderer.createMaterialState();        ms.setDiffuse( new ColorRGBA( 0.1f, 0.1f, 0.1f, 0.5f ) );        box.setRenderState(ms);        boxNode.attachChild( box );        if( i == 0 )        {            boxNode.attachChild( createBoxPlate( LEFT ) );                    }        else if( i == 2)        {            boxNode.attachChild( createBoxPlate( RIGHT ) );                                }        if( j == 0 )        {            boxNode.attachChild( createBoxPlate( DOWN ) );                                }        else if( j == 2)        {            boxNode.attachChild( createBoxPlate( UP ) );                                }        if( k == 0 )        {            boxNode.attachChild( createBoxPlate( FRONT ) );                                }        else if( k == 2)        {            boxNode.attachChild( createBoxPlate( BACK ) );                                }                return boxNode;    }        private RoundedBox createBoxPlate( int side )    {        RoundedBox rb;        MaterialState ms;        float xDim,yDim,zDim;        float dx,dy,dz;        float translation;                dx = dy = dz = 0;        xDim = yDim = zDim = m_plateSize/2;        ms = m_mStates[GREEN];        translation = m_boxSize/2 + m_plateThickness/2;                switch( side )        {            case LEFT:                ms = m_mStates[GREEN];                xDim = m_plateThickness;                dx = -translation;                break;            case RIGHT:                ms = m_mStates[BLUE];                xDim = m_plateThickness;                dx = translation;                break;            case DOWN:                ms = m_mStates[YELLOW];                yDim = m_plateThickness;                dy = -translation;                break;            case UP:                ms = m_mStates[WHITE];                yDim = m_plateThickness;                dy = translation;                break;            case FRONT:                ms = m_mStates[RED];                zDim = m_plateThickness;                dz = -translation;                break;            case BACK:                ms = m_mStates[ORANGE];                zDim = m_plateThickness;                dz = translation;                break;        }                rb = new RoundedBox( "plate",                              new Vector3f( xDim, yDim, zDim ),                              new Vector3f( m_plateEdge, m_plateEdge, m_plateEdge ),                              new Vector3f( m_plateEdge, m_plateEdge, m_plateEdge )  );        rb.getLocalTranslation().addLocal( dx, dy, dz );        rb.setRenderState(ms);        return rb;    }    /**     * Create 9 rotation nodes since that is what we need to have a fully      * functional RubiksCube     *      * We also create 9*3*3 sub-nodes where we will place 9 of our cubes when we      * need to perform a rotation.       */    private void createRotationNodes()    {        Node node;        Node subNode;        m_rotationNodes = new Node[9];        m_rotationSubNodes = new Node[9][3][3];        for( int i = 0; i < 9; i++ )        {            node = new Node( "rn" + i );                        m_rotationNodes[i] = node;            if( i < 3)            {                node.getLocalTranslation().addLocal( (i-1)*(m_boxSize+m_gap), 0, 0 );            }            else if( i < 6 )            {                node.getLocalTranslation().addLocal( 0, (i%3-1)*(m_boxSize+m_gap), 0 );                            }            else            {                node.getLocalTranslation().addLocal( 0, 0, (i%3-1)*(m_boxSize+m_gap) );                            }            for( int j = 0; j < 3; j++ )            {                for( int k = 0; k < 3; k++ )                {                    subNode = new Node( "rn" + i + "s" + j );                    m_rotationSubNodes[i][j][k] = subNode;                    node.attachChild( subNode );                    m_cubeNode.attachChild( node );                    if( i < 3)                    {                        subNode.getLocalTranslation().addLocal( 0,                                                                 (j-1)*(m_boxSize+m_gap),                                                                (k-1)*(m_boxSize+m_gap) );                    }                    else if( i < 6 )                    {                        subNode.getLocalTranslation().addLocal( (j-1)*(m_boxSize+m_gap),                                                                 0,                                                                (k-1)*(m_boxSize+m_gap) );                    }                    else                    {                        subNode.getLocalTranslation().addLocal( (j-1)*(m_boxSize+m_gap),                                                                (k-1)*(m_boxSize+m_gap),                                                                0 );                    }                }            }        }                    }            /**     * Handles all rotations      */    class RubikRotator    {        private Node rotationNode;                Quaternion fromQuat = new Quaternion();        Quaternion toQuat   = new Quaternion();                private Vector3f posX = Vector3f.UNIT_X;        private Vector3f negX = Vector3f.UNIT_X.clone().multLocal( -1 );        private Vector3f posY = Vector3f.UNIT_Y;        private Vector3f negY = Vector3f.UNIT_Y.clone().multLocal( -1 );        private Vector3f posZ = Vector3f.UNIT_Z;        private Vector3f negZ = Vector3f.UNIT_Z.clone().multLocal( -1 );                private float rotationAngle;        private float deltaAngle;        private float rotationSpeed;                private int type;        private int turns;                public RubikRotator()        {            deltaAngle = 0;        }                /**         * @param type Decides which rotation we are going to do         * @param turns A value between -2 and 2 that decide direction and          *              number of 90 degree turn we want to do         */        public void init( int type, int turns )        {            if( turns == 0 ) return;                        this.type = type;            this.turns = turns;                        rotationSpeed = m_rotationSpeed;            rotationAngle = FastMath.abs( turns )*FastMath.HALF_PI;            deltaAngle = rotationAngle;            if( type < 0 || type > 8 )            {                type=8;            }                        moveCubesToRotationNode();                        initRotation();        }        public void rotate( float dT )        {            float dA;                        if( !isDone() )            {                dA = rotationSpeed * dT;                if( dA < deltaAngle )                {                    deltaAngle -= dA;                    rotationNode.getLocalRotation().slerp( fromQuat, toQuat, ( 1 - deltaAngle / rotationAngle ) );                }                else                {                    deltaAngle = 0;                    rotationNode.getLocalRotation().slerp( fromQuat, toQuat, 1 );                    rotationNode.updateGeometricState( dT, true );                    moveCubesFromRotationNode();                }            }                                    }        /**         * Just setup the two Quaternions we are going use for this rotation         */        private void initRotation()        {            if( type < 3)            {                if( turns < 0 )                {                    fromQuat.fromAngleNormalAxis( 0, negX );                    toQuat.fromAngleNormalAxis( rotationAngle, negX );                                    }                else                {                                                          fromQuat.fromAngleNormalAxis( 0, posX );                    toQuat.fromAngleNormalAxis( rotationAngle, posX );                }               }            else if( type < 6 )            {                if( turns < 0 )                {                    fromQuat.fromAngleNormalAxis( 0, negY );                    toQuat.fromAngleNormalAxis( rotationAngle, negY );                                    }                else                {                                                          fromQuat.fromAngleNormalAxis( 0, posY );                    toQuat.fromAngleNormalAxis( rotationAngle, posY );                }               }            else            {                if( turns < 0 )                {                    fromQuat.fromAngleNormalAxis( 0, negZ );                    toQuat.fromAngleNormalAxis( rotationAngle, negZ );                                    }                else                {                                                          fromQuat.fromAngleNormalAxis( 0, posZ );                    toQuat.fromAngleNormalAxis( rotationAngle, posZ );                }               }                    }        /**         * We are about to rotate part of the cube move those cube to the         * right rotation node         */        private void moveCubesToRotationNode()        {            Node node;            rotationNode = m_rotationNodes[type];            for( int j = 0; j < 3; j++ )            {                for( int k = 0; k < 3; k++ )                {                    node = m_rotationSubNodes[type][j][k];                    if( type < 3)                    {                        node.attachChild( m_cubeNodes[type][j][k].getChild(0) );                    }                    else if( type < 6 )                    {                        node.attachChild( m_cubeNodes[j][type-3][k].getChild(0) );                    }                    else                    {                        node.attachChild( m_cubeNodes[j][k][type-6].getChild(0) );                    }                }            }                    }        /**         * Rotation is done move the cubes from the rotation node to cube node         */        private void moveCubesFromRotationNode()        {            Node node;            Spatial box = null;            for( int j = 0; j < 3; j++ )            {                for( int k = 0; k < 3; k++ )                {                    if( type < 3)                    {                        node = m_cubeNodes[type][j][k];                        if( turns == -1 )                        {                            box = m_rotationSubNodes[type][2-k][j].getChild(0);                        }                        else if( turns == 1 )                        {                            box = m_rotationSubNodes[type][k][2-j].getChild(0);                                                        }                        else if( turns == 2 || turns == -2 )                        {                            box = m_rotationSubNodes[type][2-j][2-k].getChild(0);                                                                                        }                    }                    else if( type < 6 )                    {                        node = m_cubeNodes[j][type-3][k];                        if( turns == -1 )                        {                            box = m_rotationSubNodes[type][k][2-j].getChild(0);                                                        }                        else if( turns == 1 )                        {                            box = m_rotationSubNodes[type][2-k][j].getChild(0);                                                                                        }                        else if( turns == 2 || turns == -2 )                        {                            box = m_rotationSubNodes[type][2-j][2-k].getChild(0);                                                                                        }                    }                    else                    {                        node = m_cubeNodes[j][k][type-6];                        if( turns == -1 )                        {                            box = m_rotationSubNodes[type][2-k][j].getChild(0);                                                                                        }                        else if( turns == 1 )                        {                            box = m_rotationSubNodes[type][k][2-j].getChild(0);                                                        }                        else if( turns == 2 || turns == -2 )                        {                            box = m_rotationSubNodes[type][2-j][2-k].getChild(0);                                                                                        }                    }                                        // There should be a possiblity of a tiny error accumulating                     // here that might have to be fixed.                    box.getLocalRotation().set( box.getWorldRotation() );                    node.attachChild( box );                }            }                    }                                public boolean isDone()        {            if( deltaAngle == 0 )            {                return true;            }            return false;        }    }}