Magento2: Issue with move product tabs

In catalog_product.view.xml I try move product tabs to short description area:

<move element="reviews.tab" destination="product.info.overview" after="-" />
<move element="product.attributes" destination="product.info.overview" after="-"/>

When I use this code, tabs disappear. Does anyone have any solution?

https://prnt.sc/tc42v2

java – How to make camera move with the player in 3D Libgdx

Iam trying to create a 3D game in Libgdx, so I created a 3d World with physics, and added just a small terrain and capulse (the Player) .

I want to make the game first person, so I created a player class and managed to move the player (Capulse) by joystick.

Like this :-

@Override
    public void create() {
        // load enviroment
        environment = new Environment();
        environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));
        environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));
        // setup camera
        cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        cam.position.set(10f, 10f, 10f);
        cam.lookAt(0, 0, 0);
        cam.near = 0.001f;
        cam.far = 3000f;
        cam.update();
        // setup controller for camera
        camController = new CameraInputController(cam);
        Gdx.input.setInputProcessor(camController);
        // load the models
        assets = new AssetManager();
        assets.load("ground_stairs.g3db", Model.class);
        assets.load("gathering_node.g3db", Model.class);
        loading = true;
        modelBatch = new ModelBatch();

        // setup bulletphysics
        Bullet.init();
        collisionConfig = new btDefaultCollisionConfiguration();
        dispatcher = new btCollisionDispatcher(collisionConfig);
        broadphase = new btDbvtBroadphase();
        constraintSolver = new btSequentialImpulseConstraintSolver();
        dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher, broadphase, constraintSolver, collisionConfig);
        dynamicsWorld.setGravity(new Vector3(0, -10f, 0));
        contactListener = new MyContactListener();
        loadPlayer();
        
    }

    private void loadPlayer() {
     
        // setup player/camera movement
        pc = new PlayerController(instances,cam,dynamicsWorld);
    }

    private void doneLoading() {
        loading = false;
        onDoneLoadingStatic("ground_stairs.g3db", GROUND);
        onDoneLoadingStatic("gathering_node.g3db", GATHERING_NODE);
        gatheringNode = instances.get(instances.size() - 1);
    }

    public btRigidBody onDoneLoadingStatic(String fileName, int id) {
        Model model = assets.get(fileName, Model.class);
        ModelInstance instance = new ModelInstance(model);
        instances.add(instance);

        btBvhTriangleMeshShape shape = new btBvhTriangleMeshShape(instance.model.meshParts);
        btRigidBody body = new btRigidBody(0, null, shape, new Vector3(0, 0, 0));
        body.proceedToTransform(instance.transform);
        // set id to find with collision detection
        body.setUserValue(id);
        dynamicsWorld.addRigidBody(body);
        
        return body;
    }

    @Override
    public void render() {
        if (loading && assets.update()) {
            doneLoading();
        }
        camController.update();

        pc.update();
       
        
        final float delta = Math.min(1f / 30f, Gdx.graphics.getDeltaTime());
        dynamicsWorld.stepSimulation(delta, 5, 1f / 60f);

        
        Gdx.gl20.glClearColor(0, 0.5f, 1, 1);
        Gdx.gl20.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
        modelBatch.begin(cam);
        modelBatch.render(instances, environment);
        modelBatch.end();
    }

    @Override
    public void dispose() {
        modelBatch.dispose();
    }

    

    private class MyContactListener extends ContactListener {

        @Override
        public void onContactStarted(int userValue0, int userValue1) {
            if (userValue0 == PLAYER && userValue1 == GATHERING_NODE) {
                ((ColorAttribute) gatheringNode.materials.first().get(ColorAttribute.Diffuse)).color.set(Color.RED);
            }
            if (userValue0 == PLAYER && userValue1 == GROUND) {
                PlayerController.canJump = true;
            }
        }

        @Override
        public void onContactEnded(int userValue0, int userValue1) {
            if (userValue0 == PLAYER && userValue1 == GATHERING_NODE) {
                ((ColorAttribute) gatheringNode.materials.first().get(ColorAttribute.Diffuse)).color.set(Color.BLUE);
            }
        }
    }
}




PlayerController

public class PlayerController
 {
    private btRigidBody playerBody;
    private ModelInstance player;
    private float speed = 1f;
    public static boolean canJump = true;
    private PerspectiveCamera cam;
    private List<ModelInstance> instances = new ArrayList<ModelInstance>();
    private static final int PLAYER = 1;
    public static float xposition;
    public static float yposition;
    private btDynamicsWorld dynamicsWorld;
    public static float angleX;
    
    public PlayerController(List<ModelInstance> instances,PerspectiveCamera cam,btDynamicsWorld dynamicWorld) {
        this.instances = instances;
        this.cam = cam;
        this.dynamicsWorld = dynamicWorld;
        
        player = new ModelInstance(new ModelBuilder()
                                   .createCapsule(0.25f, 3, 10, new Material(ColorAttribute.createAmbient(Color.BLACK)), Usage.Normal | Usage.Position)
                                   );
        player.transform.translate(5, 7, 0);
        instances.add(player);
        // load player rigid body
        btCapsuleShape playerShape = new btCapsuleShape(0.25f, 2.5f);
        float mass = 10;
        Vector3 localInertia = new Vector3();
        playerShape.calculateLocalInertia(mass, localInertia);
        playerBody = new btRigidBody(mass, null, playerShape, localInertia);
        playerBody.proceedToTransform(player.transform);
        playerBody.setCollisionFlags(playerBody.getCollisionFlags() | btCollisionObject.CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
        // set id to find with collision detection
        playerBody.setUserValue(PLAYER);
        dynamicsWorld.addRigidBody(playerBody);
        
        
    }

    public void update() {
        // make sure to activate the player body so bullet doesnt put it to sleep
        playerBody.activate();
        // prevent the capsule from falling over
        playerBody.setAngularFactor(new Vector3(0, 0, 0));
        playerBody.getWorldTransform(player.transform);
        
        
        Vector3 velocity = new Vector3(0, playerBody.getLinearVelocity().y, 0);
        velocity.x = xposition;
        velocity.z = yposition;
        player.transform.rotate(Vector3.Y,angleX);
        
        
        cam.update();
        
        playerBody.setLinearVelocity(velocity);
        

    }
}

And this is the output :-

the Player move perfectly with joystick

Now I want the camera to be at the top of the player (the Capulse) , and move with the player, so I added this

cam.position.add(velocity);

In update method in PlayerController

And this the output : just a blue screen
So, my question how to make the camera move we it the player like first person?

enter image description here

Magento2: How to move category description to bottom

Try this

app/design/frontend/[Company]/[theme_name]/Magento_Catalog/layout/catalog_category_view.xml

Code

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <move element="category.description" destination="content.bottom" />
    </body>
</page>

Hope this help you

Thanks …

c++ program to help find move sequences to solve Rubiks cubes

This program takes a text file and parses the initial cube start position, the pattern that the result should have and an optional start sequence. The cube is using numbers instead of colors for more exact positioning. Each face is represented by 9 numbers 3 rows of 3. The top face would be 1 2 3 4 5 6 7 8 9. The left face would be 10 11 12 13 14 15 16 17 18. etc. Speed is the most important thing to consider. On my computer with 16 cores it can solve a 7 move sequence in a couple of seconds. The time however grows by a factor of 12 with each move. So sequence of 10 moves would be hours. It will create multiple threads to find a sequence.

I can add the header files if needed.

Here is the code:

sequencefinder.cpp

#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <thread>

#include "cube.h"
#include "str.h"
#include "findsequence.h"


using namespace std;

int find_sequence(string& file_name, bool use_slice);
void read_cube_start(istream& inputstream, vector<face_val<face_val_type>>& cubestart);
void read_pattern(istream& inputstream, vector<face_val<face_val_type>>& pattern);
void read_sequence(istream& inputstream, string& sequence);
void readstring(istream& inputstream, string& str);
void readfaceval(istream& inputstream, face_val<face_val_type>& val);
int parse_args(int argc, char** argv);
int check_parameter(vector<string>& args, string searcharg, string& var);
static const vector<face_val<face_val_type>> init = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54};

static int max_depth = 8;


//************************************
// Method:    main
// FullName:  main
// Access:    public 
// Returns:   int
// Qualifier:
// Parameter: const int argc
// Parameter: char * * argv
//************************************
int main(const int argc, char** argv)
{   
    try
    {
        return parse_args(argc, argv);
    }
    catch (...)
    {
        cout << "Exception thrown." << endl;
        return  -1;
    }
}

//************************************
// Method:    parse_args
// FullName:  parse_args
// Access:    public 
// Returns:   int
// Qualifier:
// Parameter: const int argc
// Parameter: char * * argv
//
// Parse the arguments
//************************************
int parse_args(const int argc, char** argv)
{
    if (argc < 2)
    {
        cout << "No options specified." << endl;
        return -1;
    }

    string name;
    string matchpattern;
    string cubestring;
    string sequence;
    string reversesequence;
    string filename;
    string executesequence;
    string executereversesequence;
    string slice;
    string maxdepth;
    
    bool use_slice;
    
    vector<string> args;
    for (auto argindex = 1; argindex < argc; argindex++)
        args.emplace_back(argv(argindex));

    auto result = check_parameter(args, "-c", cubestring);
    if (result < 0) return result;

    result = check_parameter(args, "-slice", slice);
    if (result < 0) return result;

    result = check_parameter(args, "-f", filename);
    if (result < 0) return result;

    result = check_parameter(args, "-depth", maxdepth);
    if (result < 0) return result;

    if (!maxdepth.empty())
    {
        max_depth = stoi(maxdepth);
    }
    
    use_slice = !slice.empty();
    
    if (!args.empty())
    {
        cout << "Unknown argument(s) ";
        for (auto& arg : args)
            cout << arg << " ";
        cout << endl;
        return -1;
    }

    if (!filename.empty())
    {
        result = find_sequence(filename, use_slice);
    }
    
    return result;
}

//************************************
// Method:    check_parameter
// FullName:  check_parameter
// Access:    public 
// Returns:   int
// Qualifier: // NOLINT(performance-unnecessary-value-param)
// Parameter: vector<string> & args
// Parameter: const string searcharg
// Parameter: string & var
//
// check a single parameter
//************************************
int check_parameter(vector<string>& args, const string searcharg, string& var)  // NOLINT(performance-unnecessary-value-param)
{
    auto argindex = 0;
    const auto argc = int(args.size());
    while (argindex < argc)
    {
        if (args(argindex++) == searcharg)
        {
            if (argindex >= argc)
            {
                cout << "No sequence specified with " << args(argindex) << "." << endl;
                return -1;
            }
            var = args(argindex);
            args.erase(args.begin() + (argindex - 1ll));
            args.erase(args.begin() + (argindex - 1ll));
            return 1;
        }
    }
    return 0;
}

//************************************
// Method:    read_cube_start
// FullName:  read_cube_start
// Access:    public 
// Returns:   void
// Qualifier:
// Parameter: istream & inputstream
// Parameter: vector<face_val<face_val_type>>& cubestart
//************************************
void read_cube_start(istream& inputstream, vector<face_val<face_val_type>>& cubestart)
{
    cubestart.clear();

    while (!inputstream.eof() && cubestart.size() < 54)
    {
        face_val<face_val_type> val;
        readfaceval(inputstream, val);
        cubestart.push_back(val);
    }   
}

//************************************
// Method:    read_pattern
// FullName:  read_pattern
// Access:    public 
// Returns:   void
// Qualifier:
// Parameter: istream & inputstream
// Parameter: vector<face_val<face_val_type>> & pattern
//************************************
void read_pattern(istream& inputstream, vector<face_val<face_val_type>>& pattern)
{
    pattern.clear();

    while (!inputstream.eof() && pattern.size() < 54)
    {
        face_val<face_val_type> val;
        readfaceval(inputstream, val);
        pattern.push_back(val);
    }
}

//************************************
// Method:    read_sequence
// FullName:  read_sequence
// Access:    public 
// Returns:   void
// Qualifier:
// Parameter: istream & inputstream
// Parameter: string & sequence
//************************************
void read_sequence(istream& inputstream, string& sequence)
{
    sequence.clear();
    string temp;
    readstring(inputstream, temp);
    if (temp == "**" || temp != "*") return;

    temp.clear();
    do
    {
        readstring(inputstream, temp);
        if (temp != "*")
        {
            if (sequence.length() > 0) sequence.append(" ");
            sequence.append(temp);
        }
    } while (temp != "*");
}

//************************************
// Method:    find_sequence
// FullName:  find_sequence
// Access:    public 
// Returns:   int
// Qualifier:
// Parameter: string & file_name
// Parameter: const bool use_slice
//************************************
int find_sequence(string& file_name, const bool use_slice)
{
    ifstream inputfile;
    try
    {
        inputfile.open(file_name);
        if (!inputfile.is_open())
            throw;
    }
    catch (...)
    {
        cout << "Error opening input file." << endl;
        return -1;
    }
    
    while (!inputfile.eof())
    {
        auto cube_values = init;
        vector<face_val<face_val_type>> pattern;
        string start_seq;
        string case_name;
        
        readstring(inputfile, case_name);

        if (inputfile.eof())
            continue;
        
        read_cube_start(inputfile, cube_values);
        read_pattern(inputfile, pattern);
        read_sequence(inputfile, start_seq);

        std::cout << "<Entry> " << endl;
        std::cout << "    <Key>" << case_name << "</Key>" << endl;

        string found_sequence;
        findsequence f;
        
        const auto found = f.find_sequence(cube_values, pattern, start_seq, found_sequence, 0, max_depth, use_slice);
        if (found)
        {           
            auto seq = start_seq.append(" ") + found_sequence;
            seq = trim(seq);
            if (!seq.empty())
            {
                std::cout << "    <Value>" << seq << "</Value>" << endl;
            }
            else
            {
                std::cout << "    <Value />" << endl;
            }
        }
        else
        {
            cout << "    <!-- Not Found! -->" << endl << "    <Value />" << endl;
        }
        cout << "</Entry>" << endl << endl;
    }
    inputfile.close();
    return 0;
}

//************************************
// Method:    readstring
// FullName:  readstring
// Access:    public 
// Returns:   void
// Qualifier:
// Parameter: istream & inputstream
// Parameter: string & str
//************************************
void readstring(istream& inputstream, string& str)
{
    string temp;
    while (!inputstream.eof() && temp.empty())
    {
        inputstream >> temp;
        str = trim(temp);

        if (str.length() > 1 && str(0) == '/' && str(1) == str(0))
        {
            cout << str << " ";
            getline(inputstream, str);
            cout << str << endl;
            temp.erase();
        }
    }
}

//************************************
// Method:    readfaceval
// FullName:  readfaceval
// Access:    public 
// Returns:   void
// Qualifier:
// Parameter: istream & inputstream
// Parameter: face_val<face_val_type> val
//************************************
void readfaceval(istream& inputstream, face_val<face_val_type>& val)
{
    string temp;
    readstring(inputstream, temp);
    if (temp == "-")
    {
        val = 0;
        return;
    }
    const auto n = stoi(temp);
    val = n;
}

findsequence.cpp

#include <string>
#include <vector>
#include <iostream>
#include <thread>
#include <memory>

#include "cube.h"
#include "findsequence.h"
#include "str.h"

#ifndef __countof
#define _countof(array) (sizeof(array) / sizeof(array(0)))
#endif

//************************************
// Method:    find_sequence
// FullName:  findsequence::find_sequence
// Access:    public 
// Returns:   bool
// Qualifier:
// Parameter: cube * cube_original
// Parameter: std::vector<face_val<face_val_type>> & pattern
// Parameter: int n
// Parameter: std::vector<std::string> & data
// Parameter: std::string & out
//
// Find the moves from a given cube that
// makes the cube match the pattern. The number of moves
// will be exactly n or 0 if the cube already has the pattern.
// On exit out will be the sequence of moves or empty string.
// This will return true if the pattern is matched.
//
// This will start a thread for each possible move and wait for all to complete.
// This is the second layer of the findsequence API
//************************************
bool findsequence::find_sequence(cube* cube_original, std::vector<face_val<face_val_type>>& pattern, int n,
    std::vector<std::string>& data, std::string& out)
{
    out = "";

    // Check for initial match
    if (*cube_original == pattern)
    {
        return true;
    }

    if (n > -1)
    {
        constexpr auto buff_sz = 26;
        auto timer = time(nullptr);
        char buffer(buff_sz);
        const auto tm_info = localtime(&timer);

        strftime(buffer, _countof(buffer), "%Y-%m-%d %H:%M:%S", tm_info);
        std::cout << "    <!-- Level " << n << " " << buffer << " -->" << std::endl;
    }

    auto result = false;

    // create the thread start data
    auto threaddata = std::vector<std::unique_ptr<thread_start_data>>(data.size());
    for (auto i = 0lu; i < data.size(); i++)
    {
        threaddata(i) = std::make_unique<thread_start_data>(cube_original, pattern, n, data, data(i), this);
    }

    // Create the threads
    auto threads = std::vector<std::thread>(threaddata.size());
    for (auto i = 0lu; i < threads.size(); i++)
    {       
        threads(i) = std::thread(&find_sequence_async, threaddata(i).get());
    }

    // wait for threads to terminate
    for (auto& t : threads)
    {
        t.join();
    }

    // Check result
    for (auto& td : threaddata)
    {
        if (!result && td->result)
        {
            // save result
            out = td->out;
            result = true;
            break;
        }
    }

    return result;
}

//************************************
// Method:    find_sequence
// FullName:  findsequence::find_sequence
// Access:    public 
// Returns:   bool
// Qualifier:
// Parameter: std::vector<face_val<face_val_type>> & cube_initial_values
// Parameter: std::vector<face_val<face_val_type>> & pattern
// Parameter: std::string & start_seq
// Parameter: std::string & out
// Parameter: const int start
// Parameter: const int max_moves
// Parameter: const bool use_slice
//
// Find the moves from a given cube string that
// makes the cube match the pattern (pattern). The number of moves will up to n.
// On exit out will be the sequence of moves or empty string.
// This will return true if the pattern is matched.
// This will start a thread for each possible move and wait for all to complete.
//
// This is the topmost layer of the find_sequence API
//************************************
bool findsequence::find_sequence(std::vector<face_val<face_val_type>>& cube_initial_values, std::vector<face_val<face_val_type>>& pattern, std::string& start_seq,
                                 std::string& out, const int start, const int max_moves, const bool use_slice)
{
    static std::vector<std::string> cube_directions =
    {
        "U", "Ui", "D", "Di", "L", "Li", "R", "Ri", "B", "Bi", "F", "Fi",
        "Us", "Ds", "Ls", "Rs", "Fs", "Bs"
    };

    static std::vector<std::string> cube_directions_no_slice =
    {
        "U", "Ui", "D", "Di", "L", "Li", "R", "Ri", "B", "Bi", "F", "Fi"
    };

    auto data = use_slice ? cube_directions : cube_directions_no_slice; 

    const auto cube_original = std::make_unique<cube>();
    cube_original->set_cube(cube_initial_values);

    // if there is a start sequence execute it here
    if (!start_seq.empty())
    {
        cube_original->execute_sequence(start_seq);
    }
    
    auto found = false;
    for (auto n = start; !found && n <= max_moves; n++)
    {
        // call second layer of API
        found = find_sequence(cube_original.get(), pattern, n, data, out);
    }
    return found;
}

//************************************
// Method:    find_sequence
// FullName:  findsequence::find_sequence
// Access:    public 
// Returns:   void
// Qualifier: const
// Parameter: cube * cube_original
// Parameter: std::vector<face_val<face_val_type>> & pattern
// Parameter: const int n
// Parameter: std::vector<std::string> & data
// Parameter: std::string & out
// Parameter: std::string & start
// Parameter: bool & result
//************************************
void findsequence::find_sequence(cube* cube_original, std::vector<face_val<face_val_type>>& pattern, const int n,
                                 std::vector<std::string>& data, std::string& out, std::string& start, bool& result) const
{
    std::vector<face_val<face_val_type>> cube_initial_values;

    cube_original->get_cube(cube_initial_values);
    find_sequence(cube_initial_values, pattern, n, data, out, start, result);
}

//************************************
// Method:    find_sequence
// FullName:  findsequence::find_sequence
// Access:    public 
// Returns:   void
// Qualifier: const
// Parameter: std::string & cube_initial_values
// Parameter: std::vector<std::string> & pattern
// Parameter: const int n
// Parameter: std::vector<std::string> & data
// Parameter: std::string & out
// Parameter: std::string & start
// Parameter: bool & result
//************************************
void findsequence::find_sequence(std::vector<face_val<face_val_type>>& cube_initial_values, std::vector<face_val<face_val_type>>& pattern, 
    const int n, std::vector<std::string>& data, std::string& out, std::string& start, bool& result) const
{
    result = false;

    auto indexlist = std::vector<int>(n, 0);
    auto done = false;
    const auto end = data.size();

    std::vector<std::string> start_moves;
    std::string chars = "tnrvf ";
    split(start, chars, start_moves);
    
    auto c = std::make_unique<cube>();
    while (!done)
    {
        c->set_cube(cube_initial_values);
        auto tokens = start_moves;
        
        for (auto i = 1; i < n; i++)
        {
            tokens.push_back(data(indexlist(i)));
        }

        c->execute_sequence(tokens);
        done = true;
        if (*c == pattern)
        {
            join(tokens, out, " ");
            result = true;
        }
        else
        {
            for (auto index = 1; index < n; index++)
            {
                if (indexlist(index) + 1 < int(end))
                {
                    indexlist(index)++;
                    done = false;
                    break;
                }
                indexlist(index) = 0;
            }
        }
    }
}

//************************************
// Method:    find_sequence_async
// FullName:  findsequence::find_sequence_async
// Access:    private static 
// Returns:   void
// Qualifier:
// Parameter: thread_start_data * threadstart
//************************************
void findsequence::find_sequence_async(thread_start_data* threadstart)
{
    const auto sz = threadstart->n;
    auto data = threadstart->data;  
    auto pattern = threadstart->pattern;

    std::vector<face_val<face_val_type>> cube_initial_values;
    threadstart->cube_original->get_cube(cube_initial_values);
    
    auto c = std::make_unique<cube>();
    c->set_cube(cube_initial_values);

    std::string out;
    bool result;
    auto start = threadstart->start;
    threadstart->instance->find_sequence(cube_initial_values, pattern, sz, data, out, start, result);
    threadstart->result = result;
    threadstart->out = out;
}

cube.cpp

#include <cstdlib>
#include <cstring>
#include <ctime>
#include <string>
#include <vector>

#include "cube.h"
#include "str.h"

//************************************
// Method:    cube
// FullName:  cube::cube
// Access:    public 
// Returns:   
// Qualifier:
//
// Build a default cube.
//************************************
cube::cube()
{
    const auto time_ui = unsigned (time(nullptr));
    srand(time_ui);

    whitechars = "tnrvf ";
    record_ = true;
    init_cube();
}

//************************************
// Method:    init_cube
// FullName:  cube::init_cube
// Access:    public 
// Returns:   void
// Qualifier:
//
// Initialize the cube.
// This clears _moves and _scramble_sequence.
//************************************
void cube::init_cube()
{
    face *faces() = { &up, &left, &front, &right, &back, &down };
    auto n = 1;
    for (auto& f : faces)
        for (auto& row : f->square)
            for (auto& col : row)
                col = n++;

    moves_.clear();
    scramble_sequence_.clear();
}

//************************************
// Method:    set_cube
// FullName:  cube::set_cube
// Access:    public 
// Returns:   void
// Qualifier:
// Parameter: const char * cube_values
//
// Set cube values.
// This clears _moves and _scramble_sequence.
//************************************
void cube::set_cube(std::vector<face_val<face_val_type>>& cube_values)
{
    face *faces() = { &up, &left, &front, &right, &back, &down };
    auto n = 0;
    for (auto& f : faces)
        for (auto& row : f->square)
            for (auto& col : row)
                col = cube_values(n++);

    moves_.clear();
    scramble_sequence_.clear();
}

//************************************
// Method:    get_cube
// FullName:  cube::get_cube
// Access:    private 
// Returns:   void
// Qualifier: const
// Parameter: std::vector<face_val<face_val_type>> & pattern
//************************************
void cube::get_cube(std::vector<face_val<face_val_type>>& pattern) const
{
    pattern.clear();

    const face *faces() = { &up, &left, &front, &right, &back, &down };
    for (auto& f : faces)
        for (auto& row : f->square)
            for (auto& col : row)
                pattern.push_back(col);
}

//************************************
// Method:    clone
// FullName:  cube::clone
// Access:    public 
// Returns:   cube::cube *
// Qualifier:
// 
// This clones the cube instance
//************************************
cube * cube::clone() const
{
    auto clone_cube = std::make_unique<cube>();
    for (auto row = 0; row < cube_size; row++)
        for (auto col = 0; col < cube_size; col++)
        {
            clone_cube->up.square(row)(col) = up.square(row)(col);
            clone_cube->left.square(row)(col) = left.square(row)(col);
            clone_cube->front.square(row)(col) = front.square(row)(col);
            clone_cube->right.square(row)(col) = right.square(row)(col);
            clone_cube->back.square(row)(col) = back.square(row)(col);
            clone_cube->down.square(row)(col) = down.square(row)(col);
        }
    return clone_cube.get();
}

// ReSharper disable once CppMemberFunctionMayBeStatic
//************************************
// Method:    simple_solve
// FullName:  cube::simple_solve
// Access:    public 
// Returns:   bool
// Qualifier:
// Parameter: char * buffer
// Parameter: size_t * sz
// 
// This performs a simple solve
//************************************
bool cube::simple_solve(char* buffer, size_t* sz)
{
    // const c_simple_solver solver(this);
    // return solver.solve(buffer, sz);
    return true;
}

//************************************
// Method:    issolved
// FullName:  cube::issolved
// Access:    public 
// Returns:   bool
// Qualifier:
//
// This returns true if the cube is solved
//************************************
bool cube::issolved()
{
    return up.issolved() && left.issolved() && front.issolved() && right.issolved() && back.issolved() && down.issolved();
}

//************************************
// Method:    f
// FullName:  cube::f
// Access:    public 
// Returns:   void
// Qualifier:
//
// Rotate the front face clockwise
//************************************
void cube::f()
{
    front.rotate_clockwise();
    for (auto index = 0; index < cube_size; index++)
    {
        const auto temp = up.square(cube_size - 1)(cube_size - 1 - index);
        up.square(cube_size - 1)(cube_size - 1 - index) = left.square(index)(cube_size - 1);
        left.square(index)(cube_size - 1) = down.square(0)(index);
        down.square(0)(index) = right.square(cube_size - 1 - index)(0);
        right.square(cube_size - 1 - index)(0) = temp;
    }
    if (record_)
        moves_ += "F ";
}

//************************************
// Method:    fi
// FullName:  cube::fi
// Access:    public 
// Returns:   void
// Qualifier:
//
// Rotate the front face counter clockwise
//************************************
void cube::fi()
{
    front.rotate_counter_clockwise();
    for (auto index = 0; index < cube_size; index++)
    {
        const auto temp = up.square(cube_size -1)(cube_size -1 - index);
        up.square(cube_size - 1)(cube_size - 1 - index) = right.square(cube_size - 1 - index)(0);
        right.square(cube_size - 1 - index)(0) = down.square(0)(index);
        down.square(0)(index) = left.square(index)(cube_size -1);
        left.square(index)(cube_size - 1) = temp;
    }
    if (record_)
        moves_ += "Fi ";
}

//************************************
// Method:    u
// FullName:  cube::u
// Access:    public 
// Returns:   void
// Qualifier:
//
// Rotate the up face clockwise
//************************************
void cube::u()
{
    up.rotate_clockwise();
    for (auto index = 0; index < cube_size; index++)
    {
        const auto temp = front.square(0)(index);
        front.square(0)(index) = right.square(0)(index);
        right.square(0)(index) = back.square(0)(index);
        back.square(0)(index) = left.square(0)(index);
        left.square(0)(index) = temp;
    }
    if (record_)
        moves_ += "U ";
}

//************************************
// Method:    ui
// FullName:  cube::ui
// Access:    public 
// Returns:   void 
// Qualifier:
//
// Rotate the up face counter clockwise
//************************************
void cube::ui()
{
    up.rotate_counter_clockwise();
    for (auto index = 0; index < cube_size; index++)
    {
        const auto temp = front.square(0)(index);
        front.square(0)(index) = left.square(0)(index);
        left.square(0)(index) = back.square(0)(index);
        back.square(0)(index) = right.square(0)(index);
        right.square(0)(index) = temp;
    }
    if (record_)
        moves_ += "Ui ";
}

//************************************
// Method:    b
// FullName:  cube::b
// Access:    public 
// Returns:   void
// Qualifier:
//
// Rotate the back face clockwise
//************************************
void cube::b()
{
    back.rotate_clockwise();
    for (auto index = 0; index < cube_size; index++)
    {
        const auto temp = up.square(0)(index);
        up.square(0)(index) = right.square(index)(cube_size - 1);
        right.square(index)(cube_size - 1) = down.square(cube_size - 1)(cube_size - 1 - index);
        down.square(cube_size - 1)(cube_size - 1 - index) = left.square(cube_size - 1 - index)(0);
        left.square(cube_size - 1 - index)(0) = temp;
    }
    if (record_)
        moves_ += "B ";
}

//************************************
// Method:    bi
// FullName:  cube::bi
// Access:    public 
// Returns:   void
// Qualifier:
//
// Rotate the back face counter clockwise
//************************************
void cube::bi()
{
    back.rotate_counter_clockwise();
    for (auto index = 0; index < cube_size; index++)
    {
        const auto temp = up.square(0)(index);
        up.square(0)(index) = left.square(cube_size -1 - index)(0);
        left.square(cube_size - 1 - index)(0) = down.square(cube_size - 1)(cube_size - 1 - index);
        down.square(cube_size - 1)(cube_size - 1 - index) = right.square(index)(cube_size - 1);
        right.square(index)(cube_size - 1) = temp;
    }
    if (record_)
        moves_ += "Bi ";
}

//************************************
// Method:    l
// FullName:  cube::l
// Access:    public 
// Returns:   void
// Qualifier:
//
// Rotate the left face clockwise
//************************************
void cube::l()
{
    left.rotate_clockwise();
    for (auto index = 0; index < cube_size; index++)
    {
        const auto temp = up.square(index)(0);
        up.square(index)(0) = back.square(cube_size - 1 - index)(cube_size - 1);
        back.square(cube_size - 1 - index)(cube_size - 1) = down.square(index)(0);
        down.square(index)(0) = front.square(index)(0);
        front.square(index)(0) = temp;
    }
    if (record_)
        moves_ += "L ";
}

//************************************
// Method:    li
// FullName:  cube::li
// Access:    public 
// Returns:   void
// Qualifier:
//
// Rotate the left face counter clockwise
//************************************
void cube::li()
{
    left.rotate_counter_clockwise();
    for (auto index = 0; index < cube_size; index++)
    {
        const auto temp = up.square(index)(0);
        up.square(index)(0) = front.square(index)(0);
        front.square(index)(0) = down.square(index)(0);
        down.square(index)(0) = back.square(cube_size - 1 - index)(cube_size - 1);
        back.square(cube_size - 1 - index)(cube_size - 1) = temp;
    }
    if (record_)
        moves_ += "Li ";
}

//************************************
// Method:    r
// FullName:  cube::r
// Access:    public 
// Returns:   void
// Qualifier:
//
// Rotate the right face clockwise
//************************************
void cube::r()
{
    right.rotate_clockwise();
    for (auto index = 0; index < cube_size; index++)
    {
        const auto temp = up.square(index)(cube_size - 1);
        up.square(index)(cube_size - 1) = front.square(index)(cube_size - 1);
        front.square(index)(cube_size - 1) = down.square(index)(cube_size - 1);
        down.square(index)(cube_size - 1) = back.square(cube_size - 1 - index)(0);
        back.square(cube_size - 1 - index)(0) = temp;
    }
    if (record_)
        moves_ += "R ";
}

//************************************
// Method:    ri
// FullName:  cube::ri
// Access:    public 
// Returns:   void
// Qualifier:
//
// Rotate the right face counter clockwise
//************************************
void cube::ri()
{
    right.rotate_counter_clockwise();
    for (auto index = 0; index < cube_size; index++)
    {
        const auto temp = up.square(cube_size - 1 - index)(cube_size - 1);
        up.square(cube_size - 1 - index)(cube_size - 1) = back.square(index)(0);
        back.square(index)(0) = down.square(cube_size - 1 - index)(cube_size - 1);
        down.square(cube_size - 1 - index)(cube_size - 1) = front.square(cube_size - 1 - index)(cube_size - 1);
        front.square(cube_size - 1 - index)(cube_size - 1) = temp;
    }
    if (record_)
        moves_ += "Ri ";
}

//************************************
// Method:    d
// FullName:  cube::d
// Access:    public 
// Returns:   void
// Qualifier:
//
// Rotate the down face clockwise
//************************************
void cube::d()
{
    down.rotate_clockwise();
    for (auto index = 0; index < cube_size; index++)
    {
        const auto temp = front.square(cube_size -1)(index);
        front.square(cube_size - 1)(index) = left.square(cube_size - 1)(index);
        left.square(cube_size - 1)(index) = back.square(cube_size - 1)(index);
        back.square(cube_size - 1)(index) = right.square(cube_size - 1)(index);
        right.square(cube_size - 1)(index) = temp;
    }
    if (record_)
        moves_ += "D ";
}

//************************************
// Method:    di
// FullName:  cube::di
// Access:    public 
// Returns:   void
// Qualifier:
//
// Rotate the down face counter clockwise
//************************************
void cube::di()
{
    down.rotate_counter_clockwise();
    for (auto index = 0; index < cube_size; index++)
    {
        const auto temp = front.square(cube_size - 1)(index);
        front.square(cube_size - 1)(index) = right.square(cube_size - 1)(index);
        right.square(cube_size - 1)(index) = back.square(cube_size - 1)(index);
        back.square(cube_size - 1)(index) = left.square(cube_size - 1)(index);
        left.square(cube_size - 1)(index) = temp;
    }
    if (record_)
        moves_ += "Di ";
}

//************************************
// Method:    us
// FullName:  cube::us
// Access:    public 
// Returns:   void
// Qualifier:
//
// Rotate the cube up slice clockwise
//************************************
void cube::us()
{
    for (auto col = 0; col < cube_size; col++)
    {
        const auto temp = front.square(1)(col);
        front.square(1)(col) = right.square(1)(col);
        right.square(1)(col) = back.square(1)(col);
        back.square(1)(col) = left.square(1)(col);
        left.square(1)(col) = temp;
    }
    if (record_)
        moves_ += "Us ";
}

//************************************
// Method:    ds
// FullName:  cube::ds
// Access:    public 
// Returns:   void
// Qualifier:
//
// Rotate the cube down slice clockwise
//************************************
void cube::ds()
{
    for (auto col = 0; col < cube_size; col++)
    {
        const auto temp = front.square(1)(col);
        front.square(1)(col) = left.square(1)(col);
        left.square(1)(col) = back.square(1)(col);
        back.square(1)(col) = right.square(1)(col);
        right.square(1)(col) = temp;
    }
    if (record_)
        moves_ += "Ds ";
}

//************************************
// Method:    ls
// FullName:  cube::ls
// Access:    public 
// Returns:   void
// Qualifier:
//
// Rotate the cube left slice clockwise
//************************************
void cube::ls()
{
    for (auto row = 0; row < cube_size; row++)
    {
        const auto temp = up.square(row)(1);
        up.square(row)(1) = back.square(cube_size - row - 1)(1);
        back.square(cube_size - row - 1)(1) = down.square(row)(1);
        down.square(row)(1) = front.square(row)(1);
        front.square(row)(1) = temp;
    }
    if (record_)
        moves_ += "Ls ";
}

//************************************
// Method:    rs
// FullName:  cube::rs
// Access:    public 
// Returns:   void
// Qualifier:
//
// Rotate the cube right slice clockwise
//************************************
void cube::rs()
{
    for (auto row = 0; row < cube_size; row++)
    {
        const auto temp = up.square(row)(1);
        up.square(row)(1) = front.square(row)(1);
        front.square(row)(1) = down.square(row)(1);
        down.square(row)(1) = back.square(cube_size - row - 1)(1);
        back.square(cube_size - row - 1)(1) = temp;
    }
    if (record_)
        moves_ += "Rs ";
}

//************************************
// Method:    fs
// FullName:  cube::fs
// Access:    public 
// Returns:   void
// Qualifier:
//
// Rotate the cube front slice clockwise
//************************************
void cube::fs()
{
    for (auto index = 0; index < cube_size; index++)
    {
        const auto temp = up.square(1)(index);
        up.square(1)(index) = left.square(cube_size - index - 1)(1);
        left.square(cube_size - index - 1)(1) = down.square(1)(cube_size - index -1);
        down.square(1)(cube_size - index -1) = right.square(index)(1);
        right.square(index)(1) = temp;
    }
    if (record_)
        moves_ += "Fs ";
}

//************************************
// Method:    bs
// FullName:  cube::bs
// Access:    public 
// Returns:   void
// Qualifier:
//
// Rotate the cube back slice clockwise
//************************************
void cube::bs()
{
    for (auto index = 0; index < cube_size; index++)
    {
        const auto temp = up.square(1)(index);
        up.square(1)(index) = right.square(index)(1);
        right.square(index)(1) = down.square(1)(cube_size - index - 1);
        down.square(1)(cube_size - index - 1) = left.square(cube_size - index - 1)(1);
        left.square(cube_size - index - 1)(1) = temp;
    }
    if (record_)
        moves_ += "Bs ";
}

//************************************
// Method:    cu
// FullName:  cube::cu
// Access:    public 
// Returns:   void
// Qualifier:
//
// Rotate the cube up
//************************************
void cube::cu()
{
    left.rotate_counter_clockwise();
    right.rotate_clockwise();
    for (auto row = 0; row < cube_size; row++)
        for (auto col = 0; col < cube_size; col++)
        {
            const auto temp = up.square(row)(col);
            up.square(row)(col) = front.square(row)(col);
            front.square(row)(col) = down.square(row)(col);
            down.square(row)(col) = back.square(cube_size - 1 - row)(cube_size - 1 - col);
            back.square(cube_size - 1 - row)(cube_size - 1 - col) = temp;
        }
    if (record_)
        moves_ += "Cu ";
}

//************************************
// Method:    cd
// FullName:  cube::cd
// Access:    public 
// Returns:   void
// Qualifier:
//
// Rotate the cube down
//************************************
void cube::cd()
{
    left.rotate_clockwise();
    right.rotate_counter_clockwise();
    for (auto row = 0; row < cube_size; row++)
        for (auto col = 0; col < cube_size; col++)
        {
            const auto temp = down.square(row)(col);
            down.square(row)(col) = front.square(row)(col);
            front.square(row)(col) = up.square(row)(col);
            up.square(row)(col) = back.square(cube_size - 1 - row)(cube_size - 1 - col);
            back.square(cube_size - 1 - row)(cube_size - 1 - col) = temp;
        }
    if (record_)
        moves_ += "Cd ";
}

//************************************
// Method:    cl
// FullName:  cube::cl
// Access:    public 
// Returns:   void
// Qualifier:
//
// Rotate the cube left
//************************************
void cube::cl()
{
    down.rotate_counter_clockwise();
    up.rotate_clockwise();
    for (auto row = 0; row < cube_size; row++)
        for (auto col = 0; col < cube_size; col++)
        {
            const auto temp = front.square(row)(col);
            front.square(row)(col) = right.square(row)(col);
            right.square(row)(col) = back.square(row)(col);
            back.square(row)(col) = left.square(row)(col);
            left.square(row)(col) = temp;
        }
    if (record_)
        moves_ += "Cl ";
}

//************************************
// Method:    cr
// FullName:  cube::cr
// Access:    public 
// Returns:   void
// Qualifier:
//
// Rotate the cube face_right
//************************************
void cube::cr()
{
    down.rotate_clockwise();
    up.rotate_counter_clockwise();
    for (auto row = 0; row < cube_size; row++)
        for (auto col = 0; col < cube_size; col++)
        {
            const auto temp = front.square(row)(col);
            front.square(row)(col) = left.square(row)(col);
            left.square(row)(col) = back.square(row)(col);
            back.square(row)(col) = right.square(row)(col);
            right.square(row)(col) = temp;
        }
    if (record_)
        moves_ += "Cr ";
}

//************************************
// Method:    reverse_sequence
// FullName:  cube::reverse_sequence
// Access:    public static 
// Returns:   void
// Qualifier: const
// Parameter: const char * sequence
// Parameter: char * buffer
// Parameter: size_t * sz
//
// Create an inverse to a sequence
//************************************
void cube::reverse_sequence(const char* sequence, char* buffer, size_t* sz) const
{
    std::string result;
    reverse_sequence(sequence, result);
    if (buffer != nullptr && *sz >= result.length())
        strcpy(buffer, result.c_str());
    if (sz != nullptr) *sz = result.length();
}

//************************************
// Method:    reverse_sequence
// FullName:  cube::reverse_sequence
// Access:    public static 
// Returns:   void
// Qualifier:
// Parameter: const std::string & sequence
// Parameter: std::string & out
//
// Create an inverse to a sequence
//************************************
void cube::reverse_sequence(const std::string& sequence, std::string& out)
{
    std::string buffer;
    const std::string white = "tnrvf ";
    
    std::vector<std::string> strs;
    split(sequence, white, strs);

    for (auto str : strs)
    {
        auto lowerstr = lower(str);
        if (buffer.length() > 0)
            buffer.insert(buffer.begin(), ' ');

        if (lowerstr == "u")
        {
            buffer.insert(buffer.begin(), 'i');
            buffer.insert(buffer.begin(), str(0));
        }
        else if (lowerstr == "ui")
        {
            buffer.insert(buffer.begin(), str(0));
        }
        else if (lowerstr == "l")
        {
            buffer.insert(buffer.begin(), 'i');
            buffer.insert(buffer.begin(), str(0));
        }
        else if (lowerstr == "li")
        {
            buffer.insert(buffer.begin(), str(0));
        }
        else if (lowerstr == "f")
        {
            buffer.insert(buffer.begin(), 'i');
            buffer.insert(buffer.begin(), str(0));
        }
        else if (lowerstr == "fi")
        {
            buffer.insert(buffer.begin(), str(0));
        }
        else if (lowerstr == "r")
        {
            buffer.insert(buffer.begin(), 'i');
            buffer.insert(buffer.begin(), str(0));
        }
        else if (lowerstr == "ri")
        {
            buffer.insert(buffer.begin(), str(0));
        }
        else if (lowerstr == "b")
        {
            buffer.insert(buffer.begin(), 'i');
            buffer.insert(buffer.begin(), str(0));
        }
        else if (lowerstr == "bi")
        {
            buffer.insert(buffer.begin(), str(0));
        }
        else if (lowerstr == "d")
        {
            buffer.insert(buffer.begin(), 'i');
            buffer.insert(buffer.begin(), str(0));
        }
        else if (lowerstr == "di")
        {
            buffer.insert(buffer.begin(), 'd');
        }
        else if (lowerstr == "us")
        {
            buffer.insert(buffer.begin(), str(1));
            buffer.insert(buffer.begin(), 'D');
        }
        else if (lowerstr == "ds")
        {
            buffer.insert(buffer.begin(), str(1));
            buffer.insert(buffer.begin(), 'U');
        }
        else if (lowerstr == "ls")
        {
            buffer.insert(buffer.begin(), str(1));
            buffer.insert(buffer.begin(), 'R');
        }
        else if (lowerstr == "rs")
        {
            buffer.insert(buffer.begin(), str(1));
            buffer.insert(buffer.begin(), 'L');
        }
        else if (lowerstr == "fs")
        {
            buffer.insert(buffer.begin(), str(1));
            buffer.insert(buffer.begin(), 'B');
        }
        else if (lowerstr == "bs")
        {
            buffer.insert(buffer.begin(), str(1));
            buffer.insert(buffer.begin(), 'F');
        }
        else if (lowerstr == "cu")
        {
            buffer.insert(buffer.begin(), 'd');
            buffer.insert(buffer.begin(), str(0));
        }
        else if (lowerstr == "cd")
        {
            buffer.insert(buffer.begin(), 'u');
            buffer.insert(buffer.begin(), str(0));
        }
        else if (lowerstr == "cl")
        {
            buffer.insert(buffer.begin(), 'r');
            buffer.insert(buffer.begin(), str(0));
        }
        else if (lowerstr == "cr")
        {
            buffer.insert(buffer.begin(), 'l');
            buffer.insert(buffer.begin(), str(0));
        }
    }
    optimize_sequence(buffer, out); 
}

//************************************
// Method:    execute_move
// FullName:  cube::execute_move
// Access:    public 
// Returns:   void
// Qualifier:
// Parameter: const char * move
//
// Perform a single move
//************************************
void cube::execute_move(const char* move)
{
    if (iequals(move, "u"))         u();
    else if (iequals(move, "ui"))   ui();
    else if (iequals(move, "d"))    d();
    else if (iequals(move, "di"))   di();
    else if (iequals(move, "l"))    l();
    else if (iequals(move, "li"))   li();
    else if (iequals(move, "r"))    r();
    else if (iequals(move, "ri"))   ri();
    else if (iequals(move, "f"))    f();
    else if (iequals(move, "fi"))   fi();
    else if (iequals(move, "b"))    b();
    else if (iequals(move, "bi"))   bi();
    else if (iequals(move, "us"))   us();
    else if (iequals(move, "ds"))   ds();
    else if (iequals(move, "rs"))   rs();
    else if (iequals(move, "ls"))   ls();
    else if (iequals(move, "fs"))   fs();
    else if (iequals(move, "bs"))   bs();
    else if (iequals(move, "cu"))   cu();
    else if (iequals(move, "cd"))   cd();
    else if (iequals(move, "cl"))   cl();
    else if (iequals(move, "cr"))   cr();
}

//************************************
// Method:    execute_move
// FullName:  cube::execute_move
// Access:    public 
// Returns:   void
// Qualifier:
// Parameter: const std::string & move
//
// Perform a single move
//************************************
void cube::execute_move(const std::string& move)
{
    execute_move(move.c_str());
}

//************************************
// Method:    execute_sequence
// FullName:  cube::execute_sequence
// Access:    public 
// Returns:   void
// Qualifier:
// Parameter: const char * sequence
//
// Execute a move sequence
//************************************
void cube::execute_sequence(const char* sequence)
{
    const std::string seq = sequence;
    execute_sequence(seq);
}
 
//************************************
// Method:    execute_sequence
// FullName:  cube::execute_sequence
// Access:    public 
// Returns:   void
// Qualifier:
// Parameter: const std::string & sequence
//
// Execute a move sequence
//************************************
void cube::execute_sequence(const std::string& sequence)
{
    if (sequence.length() == 0) return;
    std::vector<std::string> tokens;
    split(sequence, whitechars, tokens);
    execute_sequence(tokens);
}

//************************************
// Method:    execute_sequence
// FullName:  cube::execute_sequence
// Access:    public 
// Returns:   void
// Qualifier:
// Parameter: const std::vector<std::string> & tokens
//************************************
void cube::execute_sequence(const std::vector<std::string>& tokens)
{
    for (const auto &token : tokens)
        execute_move(token);
}
//************************************
// Method:    scramble_cube
// FullName:  cube::scramble_cube
// Access:    public 
// Returns:   void
// Qualifier:
// Parameter: const int scramble_count
//
// Scramble the cube
//************************************
void cube::scramble_cube(const int scramble_count = 1000)
{
    const auto temp = record_;
    record_ = false;

    const auto count = scramble_count;
    const auto num_moves = 18; 
    static const std::string directions(num_moves) =
    {
        "U", "Ui", "D", "Di", "L", "Li", "R", "Ri", "B", "Bi", "F", "Fi", 
        "Us", "Ds", "Ls", "Rs", "Fs", "Bs"
    };

    std::string sequence;
    for (auto scrambleloop = 0; scrambleloop < count; scrambleloop++)
    {
        const auto rnd = rand() % num_moves;
        sequence += directions(rnd) + ' ';
    }
    optimize_sequence(sequence, scramble_sequence_);
    execute_sequence(scramble_sequence_);
    record_ = temp;
}

//************************************
// Method:    get_optimized_moves
// FullName:  cube::get_optimized_moves
// Access:    public 
// Returns:   void
// Qualifier: const
// Parameter: std::string & moves
//
// get the optimized moves as a string
//************************************
void cube::get_optimized_moves(std::string& moves) const
{
    optimize_sequence(moves_, moves);
}

//************************************
// Method:    get_moves
// FullName:  cube::get_moves
// Access:    public 
// Returns:   void
// Qualifier: const
// Parameter: std::string & moves
//
// get the moves as a string
//************************************
void cube::get_moves(std::string& moves) const
{
    moves = moves_;
    trim(moves);
}

//************************************
// Method:    get_scramble_sequence
// FullName:  cube::get_scramble_sequence
// Access:    public 
// Returns:   void
// Qualifier: const
// Parameter: std::string & scramble_sequence
//
// get the scramble sequence as a string
//************************************
void cube::get_scramble_sequence(std::string& scramble_sequence) const
{
    scramble_sequence = scramble_sequence_;
}

//************************************
// Method:    get_moves
// FullName:  cube::get_moves
// Access:    public 
// Returns:   void
// Qualifier: const
// Parameter: char * buffer
// Parameter: size_t * sz
//
// get the moves as a c string
//************************************
void cube::get_moves(char* buffer, size_t* sz) const
{
    std::string moves;
    get_moves(moves);
    if (buffer != nullptr && *sz > moves.length())
        strcpy(buffer, moves.c_str());
    if (sz != nullptr)
        *sz = moves_.length() + 1;
}

//************************************
// Method:    get_optimized_moves
// FullName:  cube::get_optimized_moves
// Access:    public 
// Returns:   void
// Qualifier: const
// Parameter: char * buffer
// Parameter: size_t * sz
//
// get the moves made as a string that are optimized
//************************************
void cube::get_optimized_moves(char* buffer, size_t* sz) const
{
    std::string moves;
    get_optimized_moves(moves);
    if (buffer != nullptr && *sz > moves.length())
        strcpy(buffer, moves.c_str());
    if (sz != nullptr)
        *sz = moves_.length() + 1;
}

//************************************
// Method:    get_scramble_sequence
// FullName:  cube::get_scramble_sequence
// Access:    public 
// Returns:   void
// Qualifier: const
// Parameter: char * buffer
// Parameter: size_t * sz
//
// get the scramble sequence
//************************************
void cube::get_scramble_sequence(char* buffer, size_t* sz) const
{
    std::string scramble_sequence;
    get_scramble_sequence(scramble_sequence);
    if (buffer != nullptr && *sz > scramble_sequence.length())
        strcpy(buffer, scramble_sequence.c_str());
    if (sz != nullptr)
        *sz = scramble_sequence_.length() + 1;
}

//************************************
// Method:    optimize_sequence
// FullName:  cube::optimize_sequence
// Access:    public static 
// Returns:   void
// Qualifier:
// Parameter: const std::string & sequence
// Parameter: std::string & out
//
// optimize a sequence
//************************************
void cube::optimize_sequence(const std::string& sequence, std::string& out)
{
    auto temp = sequence;
    size_t len1;
    size_t len2;
    do
    {
        optimize_sequence_recursion(temp, out);
        len1 = temp.length();
        len2 = out.length();
        temp = out;
    } while (len2 < len1);
}

//************************************
// Method:    optimize_sequence_recursion
// FullName:  cube::optimize_sequence_recursion
// Access:    private static 
// Returns:   void
// Qualifier:
// Parameter: const std::string & sequence
// Parameter: std::string & out
//
// optimize a sequence
//
// The basic algorithm is to track 
// how many turns there are in a given direction
// and opposite direction while keeping track of which moves can be ignored.
// Optimize the ignored moves via recursion
//************************************
void cube::optimize_sequence_recursion(const std::string& sequence, std::string& out)
{
    out.clear();
    const std::string end_marker = "****";
    std::vector<std::string>tokens;

    const std::string white = "tnrvf ";
    split(sequence, white, tokens);
    tokens.emplace_back(end_marker);

    auto index = 0u;
    auto count = 0;

    std::vector<std::string> ignore;
    std::vector<std::string> add;
    std::vector<std::string> subtract;
    std::string search;
    std::string ig_string;
    std::string add_string;
    std::string subtract_string;

    // loop through all tokens
    while (index < tokens.size())
    {
        // get the current token
        auto tok = lower(tokens(index++));

        // new sequence
        // set add subtract and ignore vectors
        if (search.length() == 0)
        {
            count = 0;
            search = tok;
            ignore.clear();
            add.clear();
            subtract.clear();
            ig_string.clear();
            search = tok;
            add_string.clear();
            subtract_string.clear();

            // left and left inverse
            if (tok == "l" || tok == "li")
            {
                add.emplace_back("l");
                subtract.emplace_back("li");
                ignore.emplace_back("r");
                ignore.emplace_back("ri");
                ignore.emplace_back("ls");
                ignore.emplace_back("rs");
                add_string = "L";
                subtract_string = "Li";
            }
            // right and right inverse
            else if (tok == "r" || tok == "ri")
            {
                add.emplace_back("r");
                subtract.emplace_back("ri");
                ignore.emplace_back("l");
                ignore.emplace_back("li");
                ignore.emplace_back("ls");
                ignore.emplace_back("rs");
                add_string = "R";
                subtract_string = "Ri";
            }
            // front and front inverse
            else if (tok == "f" || tok == "fi")
            {
                add.emplace_back("f");
                subtract.emplace_back("fi");
                ignore.emplace_back("b");
                ignore.emplace_back("bi");
                ignore.emplace_back("fs");
                ignore.emplace_back("bs");
                add_string = "F";
                subtract_string = "Fi";
            }
            // back and back inverse
            else if (tok == "b" || tok == "bi")
            {
                add.emplace_back("b");
                subtract.emplace_back("bi");
                ignore.emplace_back("f");
                ignore.emplace_back("fi");
                ignore.emplace_back("fs");
                ignore.emplace_back("bs");
                add_string = "B";
                subtract_string = "Bi";
            }
            // up and up inverse
            else if (tok == "u" || tok == "ui")
            {
                add.emplace_back("u");
                subtract.emplace_back("ui");
                ignore.emplace_back("d");
                ignore.emplace_back("di");
                ignore.emplace_back("us");
                ignore.emplace_back("ds");
                add_string = "U";
                subtract_string = "Ui";
            }
            // down and down inverse
            else if (tok == "d" || tok == "di")
            {
                add.emplace_back("d");
                subtract.emplace_back("di");
                ignore.emplace_back("u");
                ignore.emplace_back("ui");
                ignore.emplace_back("us");
                ignore.emplace_back("ds");
                add_string = "D";
                subtract_string = "Di";
            }
            // cube up and cube down
            else if (tok == "cu" || tok == "cd")
            {
                add.emplace_back("cu");
                subtract.emplace_back("cd");
                add_string = "Cu";
                subtract_string = "Cd";
            }
            // cube left and cube right
            else if (tok == "cl" || tok == "cr")
            {
                add.emplace_back("cl");
                subtract.emplace_back("cr");
                add_string = "Cl";
                subtract_string = "Cr";
            }
            // up slice, up slice inverse, down slice and down slice inverse
            else if (tok == "us" || tok == "ds")
            {
                add.emplace_back("us");
                subtract.emplace_back("ds");
                ignore.emplace_back("u");
                ignore.emplace_back("ui");
                ignore.emplace_back("d");
                ignore.emplace_back("di");
                add_string = "Us";
                subtract_string = "Ds";
            }
            // left slice, left slice inverse, right slice and right slice inverse
            else if (tok == "ls" || tok == "rs")
            {
                add.emplace_back("ls");
                subtract.emplace_back("rs");
                ignore.emplace_back("l");
                ignore.emplace_back("li");
                ignore.emplace_back("r");
                ignore.emplace_back("ri");
                add_string = "Ls";
                subtract_string = "Rs";
            }
            // front slice, front slice inverse, back slice and back slice inverse
            else if (tok == "fs" || tok == "bs")
            {
                add.emplace_back("fs");
                subtract.emplace_back("bs");
                ignore.emplace_back("f");
                ignore.emplace_back("fi");
                ignore.emplace_back("b");
                ignore.emplace_back("bi");
                add_string = "Fs";
                subtract_string = "Bs";
            }
            else  // if (tok == end_marker)
            {
                add.emplace_back(tok);
            }
        }

        // At this point add, subtract and ignore vectors are set

        // add
        auto found = false;
        for (const auto& a : add)
        {
            if (tok == a)
            {
                count++;
                found = true;
                break;
            }
        }
        // subtract
        if (!found)
            for (const auto& s : subtract)
            {
                if (tok == s)
                {
                    count--;
                    found = true;
                    break;
                }
            }
        // ignore
        if (!found)
            for (const auto& i : ignore)
            {
                if (tok == i)
                {
                    ig_string += ' ' + tok;
                    found = true;
                    break;
                }
            }

        // check for end of sequence
        if (!found)
        {
            // recurse over ignore string
            if (ig_string.length() > 0)
            {
                std::string opt;
                optimize_sequence_recursion(ig_string, opt);
                if (opt.length() > 0)
                    out += ' ' + opt;
            }

            // the numbers of moves in any direction must be mod 4
            count %= 4;
            if (count > 0)
            {
                switch (count)
                {
                case 1:
                    out += ' ' + add_string;
                    break;
                case 2:
                    out += ' ' + add_string;
                    out += ' ' + add_string;
                    break;
                case 3:  // 3 add == 1 substract
                    out += ' ' + subtract_string;
                    break;
                default:
                    break;
                }
            }
            else if (count < 0)
            {
                switch (count)
                {
                case -1:
                    out += ' ' + subtract_string;
                    break;
                case -2: // 2 subtracts == 2 adds for simplicity
                    out += ' ' + add_string;
                    out += ' ' + add_string;
                    break;
                case -3: // 3 subtracts == 1 add
                    out += ' ' + add_string;
                    break;
                default:
                    break;
                }
            }
            // trigger a new sequence by clearing it
            search.clear();

            // move 1 token backwards
            index--;
        }
    }
    trim(out);
}

//************************************
// Method:    optimize_sequence
// FullName:  cube::optimize_sequence
// Access:    public static 
// Returns:   void
// Qualifier: const
// Parameter: const char * sequence
// Parameter: char * buffer
// Parameter: size_t * sz
//
// optimize a sequence
//************************************
void cube::optimize_sequence(const char* sequence, char* buffer, size_t* sz) const
{
    std::string out;
    optimize_sequence(sequence, out);
    if (buffer != nullptr && *sz > out.length())
        strcpy(buffer, out.c_str());
    if (sz != nullptr)
        *sz = out.length() + 1;
}

Unable to move / copy files from parent to child site

We have a site and a subsite and with the copy / move functions I can see the parent site from the subsite in the “Choose a destination” window, but not the other way around. From the parent site, I can’t see the child site. I am “following” both sites. I was unable to see the parent site from the child site until I changed the privacy setting for the site to public.

I know this has to be a simple setting somewhere but I can’t figure it out.

Thanks in advance for any help you can offer.

dnd 5e – Do opportunity attacks have disadvantage if I use my action to Dodge and then move out of melee range?

Dodge:

Until the start of your next turn, any attack roll made against you has disadvantage if you can see the attacker, and you make Dexterity saving throws with advantage.

Opportunity attacks require attack rolls, so they would all have disadvantage, as long as the attackers were not invisible.

That being said, I would recommend using disengage instead of dodge:

If you take the Disengage action, your movement doesn’t provoke opportunity attacks for the rest of the turn.

Now, instead of disadvantage, your opponents can’t attack at all.

Dodge and disengage both use an action. So you could do either of those for your action and still dash with your bonus action. So disengage would likely be better than dodge, unless there’s a possibility of getting attacked from range by other enemies, then dodge might be helpful for imposing disadvantage on those ranged attacks, unless you remember this clever trick: ranged attacks have disadvantage against a prone target.

You disengage with your action, then bonus action dash and get 60 feet away from your melee attackers. Then, if there are no more melee attackers within 30-40 feet of you, drop prone, and all ranged attacks will have disadvantage. When your turn comes back around, stand up and double dash for 75 feet of movement.

itunes – iphone: move all pdfs generated from Safari page prints (which I frequently pdf-export using iBooks) from iBooks to pc in one go

I often save mobile Safari pages as ibooks which are then automatically saved (very quickly and well-formatted) as pdfs. On a website opened in Safari, you can choose the “send to”- button and then the orange Symbol for books. I have houndreds of self-generated pdfs in ibooks, and I have googled for a longer time how to transfer them to my pc.

I have tried several 3rd party programs to transfer the pdfs, but none of them find the Safari pdf prints, they only find just the commercial e-books.

iTunes does not find them either of course.

Is there any trick to move all of the pdfs in ibooks to the pc in just one go, be it with code or with a program? Please mind, I do not want to save every single pdf in iCloud Drive or Adobe Acrobat nor send each of them by mail, and afterwards delete each of them in ibooks, this costs too much time and nerves.

I would also buy a program for this purpose, if it has this feature. Naming a program that can do it would already be an accepted answer, and if there is none, perhaps someone knows a coding trick here.

##########################################################################

More details (tested in 04/2020, but the problem will still be the same)

##########################################################################

  • iPhone 7, iOS 13.4.1 transfer iBooks pdfs to Windows 10

  • either with 3rd party apps or iTunes v. 12.10.5.12

  • result: nothing works, only workaround is using Adobe Acrobat or

    iCloud Drive going through each single pdf

Unsuccessful try only using iBooks and iTunes:

In iTunes, clicking on your phone symbol, the iTunes pane that appears has a lot of options like overview, music, films… and also third party apps like kindle or acrobat in the last menu point, but there is no iBooks anywhere.

In the main menu, iBooks folder is empty. Right-click on iBooks and “transfer purchases” leads to nothing, of course: I have not bought any pdf, but just printed it from safari. In the settings, in “iTunes and App Store” make sure that “iBooks and audiobooks” are switched on for automatic download.

Third party apps fail to show iBooks’ Safari pdf prints:

  • Tested up to now (few of so many): iMazing, iExplorer, easeus, ApowerManager, Phonepaw, iTools 4.4.5.8

  • Only those pdfs that you had actually added from the pc to the phone

    are also in the books folder in the third party apps.

  • Those pdfs that are just printed pdfs from safari websites do not appear in the third party apps of iTunes.

iCloud Drive or Adobe Acrobat app: The current workaround which takes too much time and nerves:

  • Adobe Acrobat v. 20.04.00 app on the iPhone, click on every pdf’s 3 dots in the overview in iBooks, save it in Acrobat. Then use iTunes, clicking on your Phone symbol, use the last menu point to get to Acrobat 3rd party app and then mark all pdfs and save them to a folder on your pc.

  • You can also use iCloud Drive, works the same and does not need iTunes. Make sure that in your iPhone preferences, iBooks –> iCloud Drive is switched on (this is the standard anyway).

####################################################################################################
####################################################################################################

This question was first asked on https://stackoverflow.com/questions/62434692/iphone-move-all-pdfs-generated-from-safari-page-prints-which-i-frequently-pdf

During research, I realized that this Apple community would have been the better place. I now just repeat the question and answer here, I hope this is OK, or else just delete it again.

Please mind: iBooks was actually renamed to Books now, but I keep naming it iBooks for a better distinction.

dnd 5e – When a UA Wild Soul barbarian’s Wild Surge feature conjures “intangible spirits” that fly 30 feet in a random direction, do they move through walls?

Yes

From the text you linked, it says

You conjure 1d4 intangible spirits that look like flumphs in unoccupied spaces within 30 feet of you. Each spirit immediately flies 30 feet in a random direction. At the end of your turn, all spirits explode and each creature within 5 feet of one or more of them must succeed on a Dexterity saving throw or take 2d8 force damage.

As far as I know, Intangible is not a in-game term, therefore, we should interpret it in plain English.

Intangible, from Google, says:

unable to be touched or grasped; not having physical presence.

Since it “can not be touched” and does not possess any physical form, there is no reason for them to be stopped by a wall or any other object. The fact that they are spirits also supports this interpretation. Again, simply “spirits” is not an in-game term, so, we should go with usual reading: spirits are incorporeal and can move through walls.

As another indicator of this intention, as V2Blast mentioned in the comments, there is no reason to even include the term “intangible” as a description to the spirits if it was not meant to state that they ignore physical obstructions (such as walls).

PS: I am reading your question as “can the spirits”, rather than “do the spirits”, which I believe is what you meant. Ultimately, what the spirits do, in fact, depends on the DM, but they certainly can move through walls.