// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  // Move table for the three edges UB,DR and DF in phase1.
  private void loadUBtoDFMoves(boolean force) {
    if (!force && UBtoDF_Move != null) return;
    UBtoDF_Move = new short[N_UBtoDF][N_MOVE];

    CubieCube a = new CubieCube();
    for (short i = 0; i < N_UBtoDF; i++) {
      a.setUBtoDF(i);
      for (int j = 0; j < 6; j++) {
        for (int k = 0; k < 3; k++) {
          a.edgeMultiply(CubieCube.moveCube[j]);
          UBtoDF_Move[i][3 * j + k] = a.getUBtoDF();
        }
        a.edgeMultiply(CubieCube.moveCube[j]);
      }
    }
  }
  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  // Move table for the four UD-slice edges FR, FL, Bl and BR
  // FRtoBRMove < 11880 in phase 1
  // FRtoBRMove < 24 in phase 2
  // FRtoBRMove = 0 for solved cube
  private void loadFRtoBRMoves(boolean force) {
    if (!force && FRtoBR_Move != null) return;
    FRtoBR_Move = new short[N_FRtoBR][N_MOVE];

    CubieCube a = new CubieCube();
    for (short i = 0; i < N_FRtoBR; i++) {
      a.setFRtoBR(i);
      for (int j = 0; j < 6; j++) {
        for (int k = 0; k < 3; k++) {
          a.edgeMultiply(CubieCube.moveCube[j]);
          FRtoBR_Move[i][3 * j + k] = a.getFRtoBR();
        }
        a.edgeMultiply(CubieCube.moveCube[j]);
      }
    }
  }
  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  // Move table for the flips of the edges
  // flip < 2048 in phase 1
  // flip = 0 in phase 2.
  private void loadFlipMoves(boolean force) {
    if (!force && flipMove != null) return;
    flipMove = new short[N_FLIP][N_MOVE];

    CubieCube a = new CubieCube();
    for (short i = 0; i < N_FLIP; i++) {
      a.setFlip(i);
      for (int j = 0; j < 6; j++) {
        for (int k = 0; k < 3; k++) {
          a.edgeMultiply(CubieCube.moveCube[j]);
          flipMove[i][3 * j + k] = a.getFlip();
        }
        a.edgeMultiply(CubieCube.moveCube[j]); // a
      }
    }
  }
  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  // Move table for the twists of the corners
  // twist < 2187 in phase 2.
  // twist = 0 in phase 2.
  private void loadTwistMoves(boolean force) {
    /* only load if not already loaded */
    if (!force && twistMove != null) return;
    twistMove = new short[N_TWIST][N_MOVE];

    CubieCube a = new CubieCube();
    for (short i = 0; i < N_TWIST; i++) {
      a.setTwist(i);
      for (int j = 0; j < 6; j++) {
        for (int k = 0; k < 3; k++) {
          a.cornerMultiply(CubieCube.moveCube[j]);
          twistMove[i][3 * j + k] = a.getTwist();
        }
        a.cornerMultiply(CubieCube.moveCube[j]); // 4. faceturn restores a
      }
    }
  }
  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  // Table to merge the coordinates of the UR,UF,UL and UB,DR,DF edges at the beginning of phase2
  private void mergeURtoULandUBtoDF(boolean force) {
    if (!force && MergeURtoULandUBtoDF != null) return;
    MergeURtoULandUBtoDF = new short[336][336];

    /* for i, j < 336 the six edges UR,UF,UL,UB,DR,DF are not in the UD-slice and the index is < 20160 */
    for (short uRtoUL = 0; uRtoUL < 336; uRtoUL++) {
      for (short uBtoDF = 0; uBtoDF < 336; uBtoDF++) {
        MergeURtoULandUBtoDF[uRtoUL][uBtoDF] = (short) CubieCube.getURtoDF(uRtoUL, uBtoDF);
      }
    }
  }
  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  // Move table for the permutation of six U-face and D-face edges in phase2. The positions of the
  // DL and DB edges are
  // determined by the parity.
  // URtoDF < 665280 in phase 1
  // URtoDF < 20160 in phase 2
  // URtoDF = 0 for solved cube.
  private void loadURtoDFMoves(boolean force) {
    if (!force && URtoDF_Move != null) return;
    URtoDF_Move = new short[N_URtoDF][N_MOVE];

    CubieCube a = new CubieCube();
    for (short i = 0; i < N_URtoDF; i++) {
      a.setURtoDF(i);
      for (int j = 0; j < 6; j++) {
        for (int k = 0; k < 3; k++) {
          a.edgeMultiply(CubieCube.moveCube[j]);
          URtoDF_Move[i][3 * j + k] =
              (short)
                  a
                      .getURtoDF(); // Table values are only valid for phase 2 moves! For phase 1
                                    // moves, casting to short is not possible.
        }
        a.edgeMultiply(CubieCube.moveCube[j]);
      }
    }
  }