[work 108] Rubik’s Cube

[work 108] Rubik’s Cube

Movie

Source code

about

  • ルービックキューブをシャッフルした状態から6面そろうまで

file

  • 上部にあるファイル名が表示されているボタンを押すと、表示されるファイルが切り替わります
  • 別ウィンドウ表示したい時や行番号などが無いRawMode表示したい時は、コード内右上のボタンを押してください(ボタンはマウスオーバーすると表示されます)
#include "ofMain.h"
#include "ofApp.h"

//================================
int main( ){

    // 4K:4096x2160
    // 2K:2048x1080
    // FullHD:1920x1080
    // HD:1440x1080
    // HD720p:1280x720
    // DVD:720x480
    // setup the GL context
    ofSetupOpenGL(1280, 720, OF_WINDOW);

	// this kicks off the running of my app
	// can be OF_WINDOW or OF_FULLSCREEN
	// pass in width and height too:
	ofRunApp( new ofApp());

}
#pragma once

#include "ofMain.h"
#include "Cube.hpp"


class ofApp : public ofBaseApp{
public:
    ofApp();
    ~ofApp();
    
    void setup();
    void update();
    void draw();
    
    void keyPressed(int key);
    void keyReleased(int key);
    void mouseMoved(int x, int y);
    void mouseDragged(int x, int y, int button);
    void mousePressed(int x, int y, int button);
    void mouseReleased(int x, int y, int button);
    void mouseEntered(int x, int y);
    void mouseExited(int x, int y);
    void windowResized(int w, int h);
    void dragEvent(ofDragInfo dragInfo);
    void gotMessage(ofMessage msg);
    
private:
    ofEasyCam cam;
    std::shared_ptr<Cube> cube;
};
#include "ofApp.h"


ofApp::ofApp(){
    
}

ofApp::~ofApp(){
    
}

//--------------------------------------------------------------
void ofApp::setup(){
    double fps = 30;
    
    ofSetFrameRate(fps);
    ofBackground(0);
    ofSetBackgroundAuto(true);
    ofSetVerticalSync(true);
    
    ofEnableDepthTest();
    
    cube = make_shared<Cube>();
    cube->setup();
    
    cam.setPosition(400, 400, 400);
    cam.lookAt(glm::vec3(0, 0, 0));
}

//--------------------------------------------------------------
void ofApp::update(){
    cube->update();
}

//--------------------------------------------------------------
void ofApp::draw(){
    cam.begin();
    cube->display();
    cam.end();
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){
    if (key == 's') {
        ofImage img;
        img.grabScreen(0, 0, ofGetWidth(), ofGetHeight());
        img.save("screenshot.png");
    }
}
#ifndef Cube_hpp
#define Cube_hpp

#include <stdio.h>
#include "ofMain.h"


struct Command {
    int rotDir;
    int rotPosition;
    glm::vec3 rotAxis;
};


class Cube {
public:
    Cube();
    ~Cube();
    void setup();
    void update();
    void display();
    
private:
    void shuffle();
    
    std::vector<ofBoxPrimitive> boxes;
    float size;
    float offset;
    int rotAngle;
    int rotDir;
    int rotPosition;
    glm::vec3 rotAxis;
    std::vector<Command> cmd;
};
#endif /* Cube_hpp */
#include "Cube.hpp"


Cube::Cube()
{
    
}


Cube::~Cube()
{
    
}


void Cube::setup()
{
    size = 100;
    offset = 3;
    for (int x = -1; x <= 1; x++) {
        for (int y = -1; y <= 1; y++) {
            for (int z = -1; z <= 1; z++) {
                ofBoxPrimitive b;
                b.set(size);
                b.setPosition(x, y, z);
                b.setSideColor(0, ofColor(255, 255, 255));
                b.setSideColor(1, ofColor(0, 255, 0));
                b.setSideColor(2, ofColor(0, 0, 255));
                b.setSideColor(3, ofColor(255, 255, 0));
                b.setSideColor(4, ofColor(255, 102, 12));
                b.setSideColor(5, ofColor(255, 0, 0));
                boxes.push_back(b);
            }
        }
    }
    
    shuffle();
    
    rotAngle = 0;
}


void Cube::update()
{
    if (rotAngle == 0) {
        if (!cmd.empty()) {
            Command c = cmd.back();
            rotPosition = c.rotPosition;
            rotAxis = c.rotAxis;
            rotDir = c.rotDir * (-1); // reverse
            cmd.pop_back();
        } else {
            rotDir = 0; // pause
        }
    } else {
        for (ofBoxPrimitive &b : boxes) {
            glm::vec3 loc = b.getPosition();
            
            glm::vec3 m, n;
            // for ignore errors
            m.x = (int)(loc * rotAxis).x;
            m.y = (int)(loc * rotAxis).y;
            m.z = (int)(loc * rotAxis).z;
            n.x = (int)(rotAxis * rotPosition).x;
            n.y = (int)(rotAxis * rotPosition).y;
            n.z = (int)(rotAxis * rotPosition).z;
            if (m == n) {
                loc = glm::vec4(loc, 0) * glm::rotate(glm::mat4(), ofDegToRad(rotDir), rotAxis);
                b.setPosition(loc);
                b.rotateDeg(rotDir * (-1), rotAxis);
            }
            
            b.setPosition(loc);
        }
    }

    rotAngle = (rotAngle + 1) % 91;
}


void Cube::display()
{
    for (ofBoxPrimitive &b : boxes) {
        glm::vec3 loc = b.getPosition();
        glm::vec3 drawPos = loc * (size + offset);
        b.setPosition(drawPos);
        b.draw();

        b.setPosition(loc);
    }
}

void Cube::shuffle()
{
    for (int i = 0; i < 10; i++) {
        Command c;
        std::array<int, 3> a{-1, 0, 1};
        c.rotPosition = a.at((int)ofRandom(a.size()));
        
        float p = ofRandom(1);
        if (p < (1.0 / 3.0)) {
            c.rotAxis = glm::vec3(1, 0, 0);
        } else if (p < (2.0 / 3.0)) {
            c.rotAxis = glm::vec3(0, 1, 0);
        } else {
            c.rotAxis = glm::vec3(0, 0, 1);
        }
        
        std::array<int, 2> d{-1, 1};
        c.rotDir = d.at((int)ofRandom(d.size()));
        
        for (ofBoxPrimitive &b : boxes) {
            glm::vec3 loc = b.getPosition();
            
            glm::vec3 m, n;
            // for ignore errors
            m.x = (int)(loc * c.rotAxis).x;
            m.y = (int)(loc * c.rotAxis).y;
            m.z = (int)(loc * c.rotAxis).z;
            n.x = (int)(c.rotAxis * c.rotPosition).x;
            n.y = (int)(c.rotAxis * c.rotPosition).y;
            n.z = (int)(c.rotAxis * c.rotPosition).z;
            if (m == n) {
                loc = glm::vec4(loc, 0) * glm::rotate(glm::mat4(), ofDegToRad(c.rotDir * 90), c.rotAxis);
                // for ignore errors
                loc.x = std::round(loc.x);
                loc.y = std::round(loc.y);
                loc.z = std::round(loc.z);
                
                b.setPosition(loc);
                b.rotateDeg((c.rotDir * 90) * (-1), c.rotAxis);
            }
        }
        
        cmd.push_back(c);
    }
}

Link to the reference page

ソースコードで使用したAPIの中から要点になりそうなものをいくつか選んでリストアップしました。

categoryAPI/Lib
openframeworksofBoxPrimitive
openframeworksglm::vec3
openframeworksglm::rotate

Development environment

  • openframeworks 0.10.1
  • c++
  • macOS
  • Xcode