Loading impl/Rubk.cpp 0 → 100644 +274 −0 Original line number Diff line number Diff line // // Created by Ari on 2/4/17. // #include "../include/Rubk.h" #include "../include/Enums.h" #include <algorithm> #include <cctype> #include <iostream> #include <stdexcept> // HELPER FUNCTIONS /** * @param line The line to examine * @return true iff line consists only of space-like characters */ bool isBlank(string line) { return all_of(line.begin(), line.end(), // keep going until a blank line or eof [](unsigned char ch) { return std::isspace(ch); }); } void faceHelper(Rubk &result, istringstream &fps, FaceName theFace, string line) { int col = 0, row = 0; bool lineOk; do { // look for a non-blank line while (isBlank(line)) getline(fps, line); for (auto ch : line) { if (!std::isspace(ch)) { result.setCellColor(theFace, Face::Row(row), Face::Column(col), CharToColor(ch)); col++; } } row++; col = 0; // reset for next line lineOk = static_cast<bool>(getline(fps, line)); } while (lineOk && row < result.getLen()); } /** * Cycles through four positions for a single index (based on ChatGPT * optimization). */ void cycle4(const Rubk &src, Rubk &dst, FaceName f1, Face::Row r1, Face::Column c1, FaceName f2, Face::Row r2, Face::Column c2, FaceName f3, Face::Row r3, Face::Column c3, FaceName f4, Face::Row r4, Face::Column c4) { Color tmp = src.getCellColor(f1, r1, c1); dst.setCellColor(f1, r1, c1, src.getCellColor(f2, r2, c2)); dst.setCellColor(f2, r2, c2, src.getCellColor(f3, r3, c3)); dst.setCellColor(f3, r3, c3, src.getCellColor(f4, r4, c4)); dst.setCellColor(f4, r4, c4, tmp); } /** * Concatenates 4 faces to the output stream. * Output is undefined if the faces do not have the same dimensions. * @param os The stream onto which the faces are output. */ void concatFaces(std::ostream &os, const Face &face1, const Face &face2, const Face &face3, const Face &face4) { for (int xx = 0; xx < face1.faceLen(); xx++) { Face::Row xxRow(xx); os << face1.printRow(xxRow) << " " << face2.printRow(xxRow) << " " << face3.printRow(xxRow) << " " << face4.printRow(xxRow) << " " << endl; } } std::ostream &operator<<(std::ostream &os, const Rubk &cube) { return os << cube.printFlattened(); } // RUBK IMPLEMENTATIONS Rubk::Rubk(int len) : cubeLen(len) { _faces.emplace(FaceName::TOP, Face(Color::RED, cubeLen)); _faces.emplace(FaceName::LEFT, Face(Color::BLUE, cubeLen)); _faces.emplace(FaceName::FRONT, Face(Color::WHITE, cubeLen)); _faces.emplace(FaceName::RIGHT, Face(Color::RED, cubeLen)); _faces.emplace(FaceName::AFT, Face(Color::BLUE, cubeLen)); _faces.emplace(FaceName::BOTTOM, Face(Color::WHITE, cubeLen)); } Rubk::Rubk(Rubk const &other) { cubeLen = other.cubeLen; _faces = other._faces; } Rubk::Rubk(const string &flatProfile) { std::istringstream fps(flatProfile); // a stream version of the flatProfile // get cube dimensions and setup faces string line; // dimension length is the number of non-space characters in the non-blank // first line while (isBlank(line)) { getline(fps, line); } cubeLen = static_cast<int>(count_if(line.begin(), line.end(), [](unsigned char ch) { return !std::isspace(ch); })); _faces.emplace(FaceName::TOP, Face(Color::RED, cubeLen)); _faces.emplace(FaceName::LEFT, Face(Color::BLUE, cubeLen)); _faces.emplace(FaceName::FRONT, Face(Color::WHITE, cubeLen)); _faces.emplace(FaceName::RIGHT, Face(Color::RED, cubeLen)); _faces.emplace(FaceName::AFT, Face(Color::BLUE, cubeLen)); _faces.emplace(FaceName::BOTTOM, Face(Color::WHITE, cubeLen)); // read the top tranche faceHelper(*this, fps, FaceName::TOP, line); // read the middle tranche getline(fps, line); int col = 0, row = 0; bool lineOk; do { // look for a non-blank line while (isBlank(line)) getline(fps, line); // read the characters of the line auto theFace = FaceName::LEFT; for (auto ch : line) { if (!std::isspace(ch)) { setCellColor(theFace, Face::Row(row), Face::Column(col), CharToColor(ch)); if (++col == cubeLen) { col = 0; switch (theFace) { case FaceName::LEFT: theFace = FaceName::FRONT; break; case FaceName::FRONT: theFace = FaceName::RIGHT; break; case FaceName::RIGHT: theFace = FaceName::AFT; break; default: break; } } } } row++; col = 0; // reset for next line lineOk = static_cast<bool>(getline(fps, line)); } while (lineOk && row < cubeLen); // read the bottom tranche getline(fps, line); faceHelper(*this, fps, FaceName::BOTTOM, line); } bool Rubk::isUnscrambled() const { throw logic_error("Rubk::isUnscrambled() has not yet been implemented"); } Rubk Rubk::rotate(bool direction, FaceName theFaceName) const { Rubk result(*this); for (int xx = 0; xx < cubeLen; xx++) for (int yy = 0; yy < cubeLen; yy++) result.setCellColor( theFaceName, Face::Row(direction ? xx : cubeLen - 1 - xx), Face::Column(direction ? cubeLen - 1 - yy : yy), getCellColor(theFaceName, Face::Row(yy), Face::Column(xx))); return result; } Rubk Rubk::makeMove(CubeMoves theMove) const { constexpr Face::Column leftCol(0); constexpr Face::Row topRow(0); const Face::Column rightCol(cubeLen - 1); const Face::Row bottomRow(cubeLen - 1); Rubk result(*this); switch (theMove) { case LeftDown: { // front left column goes down for (int yy = 0; yy < cubeLen; ++yy) { Face::Row r(yy); Face::Row rr(cubeLen - 1 - yy); cycle4(*this, result, FaceName::FRONT, r, leftCol, FaceName::TOP, r, leftCol, FaceName::AFT, rr, rightCol, // reversed FaceName::BOTTOM, r, leftCol); } result = result.rotate(true, FaceName::LEFT); break; } case RightDown: { // front right column goes down for (int yy = 0; yy < cubeLen; ++yy) { const Face::Row r(yy); const Face::Row rr(cubeLen - 1 - yy); cycle4(*this, result, FaceName::FRONT, r, rightCol, FaceName::TOP, r, rightCol, FaceName::AFT, rr, leftCol, // back reversed FaceName::BOTTOM, r, rightCol); } result = result.rotate(false, FaceName::RIGHT); break; } case TopLeft: { // top row goes left for (int yy = 0; yy < cubeLen; ++yy) { Face::Column c(yy); cycle4(*this, result, FaceName::FRONT, topRow, c, FaceName::RIGHT, topRow, c, FaceName::AFT, topRow, c, FaceName::LEFT, topRow, c); } result = result.rotate(true, FaceName::TOP); break; } case BottomLeft: { // bottom row goes left for (int yy = 0; yy < cubeLen; ++yy) { const Face::Column c(yy); cycle4(*this, result, FaceName::FRONT, bottomRow, c, FaceName::RIGHT, bottomRow, c, FaceName::AFT, bottomRow, c, FaceName::LEFT, bottomRow, c); } result = result.rotate(false, FaceName::BOTTOM); break; } default: throw out_of_range("ERR: I don't know how to do that yet ... sorry!"); } return result; } Color Rubk::getCellColor(FaceName theFaceName, Face::Row theRow, Face::Column theColumn) const { return getFace(theFaceName).get(theRow, theColumn); } void Rubk::setCellColor(FaceName theFaceName, Face::Row theRow, Face::Column theColumn, Color newColor) { getFace(theFaceName).set(theRow, theColumn, newColor); } string Rubk::printFlattened() const { stringstream os; // the output stream Face BLANK_FACE(Color::BLANK_, cubeLen); // a blank face // output the cube // ... row 0 concatFaces(os, BLANK_FACE, getFace(FaceName::TOP), BLANK_FACE, BLANK_FACE); os << endl; // ... row 1 concatFaces(os, getFace(FaceName::LEFT), getFace(FaceName::FRONT), getFace(FaceName::RIGHT), getFace(FaceName::AFT)); os << endl; // ... row 2 concatFaces(os, BLANK_FACE, getFace(FaceName::BOTTOM), BLANK_FACE, BLANK_FACE); os << endl; return os.str(); } No newline at end of file Loading
impl/Rubk.cpp 0 → 100644 +274 −0 Original line number Diff line number Diff line // // Created by Ari on 2/4/17. // #include "../include/Rubk.h" #include "../include/Enums.h" #include <algorithm> #include <cctype> #include <iostream> #include <stdexcept> // HELPER FUNCTIONS /** * @param line The line to examine * @return true iff line consists only of space-like characters */ bool isBlank(string line) { return all_of(line.begin(), line.end(), // keep going until a blank line or eof [](unsigned char ch) { return std::isspace(ch); }); } void faceHelper(Rubk &result, istringstream &fps, FaceName theFace, string line) { int col = 0, row = 0; bool lineOk; do { // look for a non-blank line while (isBlank(line)) getline(fps, line); for (auto ch : line) { if (!std::isspace(ch)) { result.setCellColor(theFace, Face::Row(row), Face::Column(col), CharToColor(ch)); col++; } } row++; col = 0; // reset for next line lineOk = static_cast<bool>(getline(fps, line)); } while (lineOk && row < result.getLen()); } /** * Cycles through four positions for a single index (based on ChatGPT * optimization). */ void cycle4(const Rubk &src, Rubk &dst, FaceName f1, Face::Row r1, Face::Column c1, FaceName f2, Face::Row r2, Face::Column c2, FaceName f3, Face::Row r3, Face::Column c3, FaceName f4, Face::Row r4, Face::Column c4) { Color tmp = src.getCellColor(f1, r1, c1); dst.setCellColor(f1, r1, c1, src.getCellColor(f2, r2, c2)); dst.setCellColor(f2, r2, c2, src.getCellColor(f3, r3, c3)); dst.setCellColor(f3, r3, c3, src.getCellColor(f4, r4, c4)); dst.setCellColor(f4, r4, c4, tmp); } /** * Concatenates 4 faces to the output stream. * Output is undefined if the faces do not have the same dimensions. * @param os The stream onto which the faces are output. */ void concatFaces(std::ostream &os, const Face &face1, const Face &face2, const Face &face3, const Face &face4) { for (int xx = 0; xx < face1.faceLen(); xx++) { Face::Row xxRow(xx); os << face1.printRow(xxRow) << " " << face2.printRow(xxRow) << " " << face3.printRow(xxRow) << " " << face4.printRow(xxRow) << " " << endl; } } std::ostream &operator<<(std::ostream &os, const Rubk &cube) { return os << cube.printFlattened(); } // RUBK IMPLEMENTATIONS Rubk::Rubk(int len) : cubeLen(len) { _faces.emplace(FaceName::TOP, Face(Color::RED, cubeLen)); _faces.emplace(FaceName::LEFT, Face(Color::BLUE, cubeLen)); _faces.emplace(FaceName::FRONT, Face(Color::WHITE, cubeLen)); _faces.emplace(FaceName::RIGHT, Face(Color::RED, cubeLen)); _faces.emplace(FaceName::AFT, Face(Color::BLUE, cubeLen)); _faces.emplace(FaceName::BOTTOM, Face(Color::WHITE, cubeLen)); } Rubk::Rubk(Rubk const &other) { cubeLen = other.cubeLen; _faces = other._faces; } Rubk::Rubk(const string &flatProfile) { std::istringstream fps(flatProfile); // a stream version of the flatProfile // get cube dimensions and setup faces string line; // dimension length is the number of non-space characters in the non-blank // first line while (isBlank(line)) { getline(fps, line); } cubeLen = static_cast<int>(count_if(line.begin(), line.end(), [](unsigned char ch) { return !std::isspace(ch); })); _faces.emplace(FaceName::TOP, Face(Color::RED, cubeLen)); _faces.emplace(FaceName::LEFT, Face(Color::BLUE, cubeLen)); _faces.emplace(FaceName::FRONT, Face(Color::WHITE, cubeLen)); _faces.emplace(FaceName::RIGHT, Face(Color::RED, cubeLen)); _faces.emplace(FaceName::AFT, Face(Color::BLUE, cubeLen)); _faces.emplace(FaceName::BOTTOM, Face(Color::WHITE, cubeLen)); // read the top tranche faceHelper(*this, fps, FaceName::TOP, line); // read the middle tranche getline(fps, line); int col = 0, row = 0; bool lineOk; do { // look for a non-blank line while (isBlank(line)) getline(fps, line); // read the characters of the line auto theFace = FaceName::LEFT; for (auto ch : line) { if (!std::isspace(ch)) { setCellColor(theFace, Face::Row(row), Face::Column(col), CharToColor(ch)); if (++col == cubeLen) { col = 0; switch (theFace) { case FaceName::LEFT: theFace = FaceName::FRONT; break; case FaceName::FRONT: theFace = FaceName::RIGHT; break; case FaceName::RIGHT: theFace = FaceName::AFT; break; default: break; } } } } row++; col = 0; // reset for next line lineOk = static_cast<bool>(getline(fps, line)); } while (lineOk && row < cubeLen); // read the bottom tranche getline(fps, line); faceHelper(*this, fps, FaceName::BOTTOM, line); } bool Rubk::isUnscrambled() const { throw logic_error("Rubk::isUnscrambled() has not yet been implemented"); } Rubk Rubk::rotate(bool direction, FaceName theFaceName) const { Rubk result(*this); for (int xx = 0; xx < cubeLen; xx++) for (int yy = 0; yy < cubeLen; yy++) result.setCellColor( theFaceName, Face::Row(direction ? xx : cubeLen - 1 - xx), Face::Column(direction ? cubeLen - 1 - yy : yy), getCellColor(theFaceName, Face::Row(yy), Face::Column(xx))); return result; } Rubk Rubk::makeMove(CubeMoves theMove) const { constexpr Face::Column leftCol(0); constexpr Face::Row topRow(0); const Face::Column rightCol(cubeLen - 1); const Face::Row bottomRow(cubeLen - 1); Rubk result(*this); switch (theMove) { case LeftDown: { // front left column goes down for (int yy = 0; yy < cubeLen; ++yy) { Face::Row r(yy); Face::Row rr(cubeLen - 1 - yy); cycle4(*this, result, FaceName::FRONT, r, leftCol, FaceName::TOP, r, leftCol, FaceName::AFT, rr, rightCol, // reversed FaceName::BOTTOM, r, leftCol); } result = result.rotate(true, FaceName::LEFT); break; } case RightDown: { // front right column goes down for (int yy = 0; yy < cubeLen; ++yy) { const Face::Row r(yy); const Face::Row rr(cubeLen - 1 - yy); cycle4(*this, result, FaceName::FRONT, r, rightCol, FaceName::TOP, r, rightCol, FaceName::AFT, rr, leftCol, // back reversed FaceName::BOTTOM, r, rightCol); } result = result.rotate(false, FaceName::RIGHT); break; } case TopLeft: { // top row goes left for (int yy = 0; yy < cubeLen; ++yy) { Face::Column c(yy); cycle4(*this, result, FaceName::FRONT, topRow, c, FaceName::RIGHT, topRow, c, FaceName::AFT, topRow, c, FaceName::LEFT, topRow, c); } result = result.rotate(true, FaceName::TOP); break; } case BottomLeft: { // bottom row goes left for (int yy = 0; yy < cubeLen; ++yy) { const Face::Column c(yy); cycle4(*this, result, FaceName::FRONT, bottomRow, c, FaceName::RIGHT, bottomRow, c, FaceName::AFT, bottomRow, c, FaceName::LEFT, bottomRow, c); } result = result.rotate(false, FaceName::BOTTOM); break; } default: throw out_of_range("ERR: I don't know how to do that yet ... sorry!"); } return result; } Color Rubk::getCellColor(FaceName theFaceName, Face::Row theRow, Face::Column theColumn) const { return getFace(theFaceName).get(theRow, theColumn); } void Rubk::setCellColor(FaceName theFaceName, Face::Row theRow, Face::Column theColumn, Color newColor) { getFace(theFaceName).set(theRow, theColumn, newColor); } string Rubk::printFlattened() const { stringstream os; // the output stream Face BLANK_FACE(Color::BLANK_, cubeLen); // a blank face // output the cube // ... row 0 concatFaces(os, BLANK_FACE, getFace(FaceName::TOP), BLANK_FACE, BLANK_FACE); os << endl; // ... row 1 concatFaces(os, getFace(FaceName::LEFT), getFace(FaceName::FRONT), getFace(FaceName::RIGHT), getFace(FaceName::AFT)); os << endl; // ... row 2 concatFaces(os, BLANK_FACE, getFace(FaceName::BOTTOM), BLANK_FACE, BLANK_FACE); os << endl; return os.str(); } No newline at end of file