using System;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Linq;
namespace PLL
{
// just to make it easier to print
public class Output
{
public void print(string s)
{
Console.WriteLine(s);
}
}
// handy routines, in this case swapCharacters
public class Util
{
// Swaps characters in a string. Must copy the characters and reallocate the string.
public static string swapCharacters(string value, int position1, int position2)
{
char[] array = value.ToCharArray();
char temp = array[position1];
array[position1] = array[position2];
array[position2] = temp;
return new string(array);
}
}
// A move consists of a face and a count, like "R2"
public class Move
{
public string face;
public int count;
public Move(string f, int c) {
face = f;
count = c;
}
// clone
public Move(Move original) {
face = original.face;
count = original.count;
}
// return a move as string face+count
public override string ToString()
{
//return "move: " + face + Environment.NewLine + "count: " + count;
return face + count.ToString();
}
public void print() {
Console.WriteLine(this);
}
}
// Algorithm works on strings representing cube algorithms
public class Algorithm
{
public string alg;
public Algorithm(string s)
{
this.alg=s;
}
public string clean(){
if (alg=="") {
return alg;
}
string tokens = " ()-\'";
string input_clean = "";
char prevCh = '\0';
foreach(char ch in alg)
{
if (tokens.IndexOf(ch)==-1) {
input_clean += ch;
}
// only add prime when not right after a move token, e.g. R'
// so skip R2' (becomes R2)
if (ch=='\'' && prevCh!='2') {
input_clean += ch;
}
prevCh = ch;
}
return input_clean;
}
public string normalize(){
char prevCh='\0';
string temp = this.alg.Replace("\'", "3");
string alg_normal="";
if (this.alg=="")
return "";
foreach(char ch in temp)
{
// when both ch and prev are moves, insert a 1 between them
// RL becomes R1L
if (prevCh!='\0' && !char.IsDigit(prevCh) && !char.IsDigit(ch)) {
alg_normal += '1';
}
alg_normal += ch;
prevCh = ch;
}
if (!char.IsDigit(prevCh)) {
alg_normal += '1';
}
return alg_normal;
}
public string denormalize(){
string alg = this.alg.Replace("3", "'");
alg = alg.Replace("1", "");
return alg;
}
public string inverse(){
return "";
}
public string compact(){
string face;
int count;
Move prevMove = new Move("",0);
// clean input leaves only the moves
alg = this.clean();
// process to get normalized alg (e.g. R2F1L3)
alg = this.normalize();
// convert to array of Move objects {R,2},{F,1},{L,3}
var moves = new List();
var newMoves = new List();
for (int i=0; i < alg.Length; i+=2) {
face = alg.Substring(i,1);
count = Convert.ToInt32(alg.Substring(i+1,1));
moves.Add(new Move(face, count));
}
// merge Moves to remove duplicates
// e.g. D2D2 => D4 => D0
int last;
foreach(Move move in moves)
{
// if a duplicate is found
if (move.face == prevMove.face) {
last = newMoves.Count-1;
// add the moves
newMoves[last].count += move.count;
// mod 4 to remove 360 turns
newMoves[last].count %= 4;
if (newMoves[last].count == 0)
newMoves.RemoveAt(last);
}
else
newMoves.Add(move);
prevMove = new Move(move);
}
// convert to string again
string s = "";
foreach(Move move in newMoves)
s += move;
return s;
}
}
public class Cases
{
public static string Aa,Ab,E,F,Ga,Gb,Gc,Gd,H,Ja,Jb,Na,Nb,Ra,Rb,T,Ua,Ub,V,Y,Z;
public static void Init() {
Aa = "(y) R2 F2 (R' B' R) F2 (R' B R')";
Ab = "R B' R F2 R' B R F2 R2";
E = "(x) U R' U' L U R U' r2 U' R U L U' R' U x";
F = "R' U R U' R2 y' R' U' R U y x R U R' U' R2 x' U'";
Ga = "(y) R2' u R' U R' U' R u' R2 y' R' U R y'";
Gb = "L' U' L F2 z' R U' L U L' U R' F2 z";
Gc = "(y) R2' u' R U' R U R' u R2 y R U' R'";
Gd = "(y2) R U R' F2 D' L U' L' U L' D F2";
H = "M2 U M2 U2 M2 U M2";
Ja = "(y2) x U2 r' U' r U2 l' U R' U' R2 x2 y2";
Jb = "(y2) F2 R U R' F2 L D' L D L2";
Na = "z U R' D R2 U' R (D' U) R' D R2 U' R D' R z'";
Nb = "R' U L' U2 R U' L R' U L' U2 R U' L";
Ra = "(y2) z U R2 U' R2 U F' U' R' U R U F U2 R z' y2";
Rb = "R' U2 R U' y' R' F R B' R' F' R z x' R' U R' z' y2";
T = "R U R' U' R' F R2 U' R' U' R U R' F'";
Ua = "(y2) R U' R U R U R U' R' U' R2";
Ub = "R' U R' U' R' U' R' U R U R2";
V = "y L' U R U' L U L' U R' U' L U2 R U2 R'";
Y = "F R U' R' U' R U R' F' R U R' U' R' F R F'";
Z = "y U R' U' R U' R U R U' R' U R U R2 U' R' U";
}
public static Dictionary All() {
var algs = new Dictionary() {};
algs.Add("Aa", Aa);
algs.Add("Ab", Ab);
algs.Add("E", E);
algs.Add("F", F);
algs.Add("Ga", Ga);
algs.Add("Gb", Gb);
algs.Add("Gc", Gc);
algs.Add("Gd", Gd);
algs.Add("H", H);
algs.Add("Ja", Ja);
algs.Add("Jb", Jb);
algs.Add("Na", Na);
algs.Add("Nb", Nb);
algs.Add("Ra", Ra);
algs.Add("Rb", Rb);
algs.Add("T", T);
algs.Add("Ua", Ua);
algs.Add("Ub", Ub);
algs.Add("V", V);
algs.Add("Y", Y);
algs.Add("Z", Z);
return algs;
}
public static Dictionary NonSym() {
var algs = new Dictionary();
algs.Add("E", E);
algs.Add("F", F);
algs.Add("H", H);
algs.Add("Ja", Ja);
algs.Add("Jb", Jb);
algs.Add("Na", Na);
algs.Add("Nb", Nb);
algs.Add("Ra", Ra);
algs.Add("Rb", Rb);
algs.Add("T", T);
algs.Add("V", V);
algs.Add("Y", Y);
algs.Add("Z", Z);
return algs; }
public static string[] Rotations() {
return new string[] { "", "y", "y'", "y2", "U", "U'", "U2", "yU", "yU'", "yU2", "y'U", "y'U'", "y'U2", "y2U", "y2U'", "y2U2" };
}
}
public class Cube
{
const string defaultStickers = "rrrrrrrrrgggggggggwwwwwwwwwooooooooobbbbbbbbbyyyyyyyyy";
string stickers;
// constructor
public Cube()
{
// initialize stickers
stickers = defaultStickers;
}
public void executePermutation(int a, int b, int c, int d){
stickers = Util.swapCharacters(stickers, a, b);
stickers = Util.swapCharacters(stickers, a, c);
stickers = Util.swapCharacters(stickers, a, d);
}
public void move(string token){
var moveTransforms = new Dictionary
{
{"u","UEEE"}, {"d","DE"}, {"f","FS"}, {"b","BSSS"}, {"l","LM"}, {"r","RMMM"}, {"x","rLLL"}, {"y","uDDD"}, {"z","fBBB"}
};
// recursive calls to walk through the translated lowercase moves
//Console.WriteLine(token.Length);
if (token.Length > 1) {
foreach (char ch in token)
this.move(ch.ToString());
return;
}
try {
switch (token) {
case "U":
//one of the elementary move functions. Uses the executePermutation function
//five times to make five 4-cycles of stickers:
this.executePermutation(53, 51, 45, 47);
// top layer
this.executePermutation(50, 52, 48, 46);
this.executePermutation(2, 38, 29, 11);
this.executePermutation(1, 37, 28, 10);
this.executePermutation(0, 36, 27, 9);
break;
case "D":
this.executePermutation(20, 26, 24, 18);
this.executePermutation(23, 25, 21, 19);
this.executePermutation(8, 17, 35, 44);
this.executePermutation(7, 16, 34, 43);
this.executePermutation(6, 15, 33, 42);
break;
case "F":
this.executePermutation(2, 8, 6, 0);
this.executePermutation(5, 7, 3, 1);
this.executePermutation(9, 20, 44, 51);
this.executePermutation(12, 19, 41, 52);
this.executePermutation(15, 18, 38, 53);
break;
case "B":
this.executePermutation(29, 35, 33, 27);
this.executePermutation(32, 34, 30, 28);
this.executePermutation(47, 36, 24, 17);
this.executePermutation(46, 39, 25, 14);
this.executePermutation(45, 42, 26, 11);
break;
case "R":
this.executePermutation(11, 17, 15, 9);
this.executePermutation(14, 16, 12, 10);
this.executePermutation(2, 47, 33, 20);
this.executePermutation(5, 50, 30, 23);
this.executePermutation(8, 53, 27, 26);
break;
case "L":
this.executePermutation(38, 44, 42, 36);
this.executePermutation(41, 43, 39, 37);
this.executePermutation(0, 18, 35, 45);
this.executePermutation(3, 21, 32, 48);
this.executePermutation(6, 24, 29, 51);
break;
case "M":
this.executePermutation(4, 22, 31, 49 );
this.executePermutation(1, 19, 34, 46 );
this.executePermutation(7, 25, 28, 52 );
break;
case"E":
this.executePermutation(4, 13, 31, 40);
this.executePermutation(5, 14, 32, 41);
this.executePermutation(3, 12, 30, 39);
break;
case "S":
this.executePermutation(49, 13, 22, 40);
this.executePermutation(50, 16, 21, 37);
this.executePermutation(48, 10, 23, 43);
break;
default:
// u,d,f,b,l,r,x,y,z
this.move(moveTransforms[token]);
break;
}
}
catch (Exception e){
Console.WriteLine("{0} Exception caught.", e);
}
}
public void setMode(string mode){
}
public string execute(string alg, string mode){
string face;
int count;
// prepare with a certain mode if given
if (mode!="") {
this.setMode(mode);
}
if (alg=="")
return this.stickers;
// walk through all moves in a normalized alg
for (int i=0; i < alg.Length; i+=2) {
// define Move (move) and quantifier
face = alg[i].ToString();
count = Convert.ToInt16(alg[i+1].ToString());
// move a face n times
foreach (int j in Enumerable.Range(1,count))
this.move(face);
}
return this.stickers;
}
public string execute(string alg) {
this.execute(alg, "");
return this.stickers;
}
public string toAppletStickers(bool delta, string separator, bool outputAsPositions){
return "";
}
public string toImageCubeStickers(){
string[] faces;
string up, front, right;
faces = new string[6];
foreach (int i in Enumerable.Range(0,5))
faces[i]=stickers.Substring(i*9, 9);
up = faces[5];
front = faces[0];
right = faces[1];
return up + front + right;
}
public string getSticker(string position){
return "";
}
public bool stickersMatch(string s1, string s2){
return false;
}
public string[] getPieceOrientations(string piece){
return null;
}
public bool isPieceSolved(string piece){
return false;
}
public string[] getStickers(string position){
return null;
}
public string locatePiece(string piece){
return "";
}
public void performAlg(string input, bool inverse){
// clean input leaves only the moves
Algorithm a = new Algorithm(input);
a.alg = a.compact();
// process inverse of alg
if (inverse) {
a.alg = a.inverse();
}
// perform inverse on the stickers
this.stickers = this.execute(a.alg);
}
public void performAlg(string input)
{
this.performAlg(input, false);
}
public bool findMatches()
{
int n;
string tab;
string[] auf, rotations;
var o = new Output();
string alg, def;
tab = "\t";
Cases.Init();
Dictionary algs = Cases.All();
n = algs.Count;
long sentinel = 2000000;
auf = Cases.Rotations();
rotations = new string[] {"","y","y'","y2"};
foreach (KeyValuePairalg1 in algs)
foreach (KeyValuePairalg2 in algs)
foreach (string adjust in auf)
foreach(KeyValuePairalg4 in algs)
foreach (string rotation in rotations)
{
Cube c = new Cube();
//if (alg1.Value==alg2.Value || alg1.Value==alg4.Value || alg2.Value==alg4.Value )
// continue;
alg = alg1.Value + " " + alg2.Value + " " + adjust + " " + alg4.Value + " " + rotation;
def = alg1.Key + tab + alg2.Key + tab + adjust + tab + alg4.Key + tab + rotation
c.performAlg(alg);
if (c.stickers == Cube.defaultStickers)
o.print(def);
if (sentinel % 1000 == 0 && false)
o.print("n:" + s.ToString());
if (sentinel-- < 1)
return false;
}
return false;
}
// search for a sequence of PLLs that end in a solved state
public string findPath()
{
}
public static void Main()
{
Cube c = new Cube();
c.findMatches();
}
}
}