Commit c9b44646 authored by XingyuChen's avatar XingyuChen
Browse files

minor fix: put back Rubk.cpp

parent b25af341
Loading
Loading
Loading
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