Visual C# 2005 Guide
Floppy Cube Project - Main Program

Global Variables For The Console Program

As explained in the previous page, our global variables for this program would be,

// solved positions
private static string solvedPosition = "abcd0000";
private static int[,] mapPositions = { { 1, 0, 2, 3 }, { 0, 2, 1, 3 },
{ 0, 1, 3, 2 }, { 3, 1, 2, 0 } };
// dictionary to store moves
private static Dictionary<string,string> moveTable = new Dictionary<string,string>();
// list to store moves at each depth
private static List<string>[] positionsAtDepth = new List<string>[15];

Making The Turn

A turn is a transformation of a cube position. We need to know which turn to make and which position to use. These are the parameters for our turn function. We will return a new string representing the position created by the turn. We can use a loop from 0 -7 to build a string of the new cube position. The first 4 characters are written using our transition table. The last 4 are the edges with their states written as 0 or 1, depending on their current state and whether or not they are flipped. The turn axis matches the subscript of the edge that gets flipped by that turn. Finally we return the new cube position. Code is below,

private static string doMove(int axis, string cubeString)
{
   string newCubeString = "";
   for (int i = 0; i < 8; i++)
   {
      if (i < 4)
      {
         newCubeString += System.Convert.ToString(cubeString[mapPositions[axis, i]]);
      }
      else
      {
         if ((i - 4) == axis)
         {
            if (System.Convert.ToInt32(System.Convert.ToString(cubeString[i])) == 0)
            {
               newCubeString += "1";
            }
            else
            {
               newCubeString += "0";
            }
         }
         else
         {
            newCubeString += System.Convert.ToString(cubeString[i]);
         }
      }
   }
   return newCubeString;
}

Exploring All Positions At Distance 1 From A Given Position

This procedure performs all 4 turns and stores the new positions (if any) that are generated from those turns. The parameter for the procedure is a strin representing the postion of the puzzle. We need to get the sequence of moves up to this point and find out what the last move was. If the position is the solved position, we assume a last turn of -1 so that it will not be equal to any possible turn. We can use a loop from 0 to 3 to represent each of our 4 turns. If each turn was not the turn we did last time, we do the turn and, if it generates a new position, we add it to the move table dictionary and the list array. We do the move again to reverse the position and then try the next turn.

private static void exploreOnwardsFrom(string cubeString)
{
   string sequence = moveTable[cubeString];
   int last = -1;
   //find lastmove or leave as -1 if not
   if (sequence.Length > 0)
   {
      last = System.Convert.ToInt32(sequence[sequence.Length - 1]);
   }
   string newCubeString = cubeString;
   //try each axis from here
   for (int thisAxis = 0; thisAxis < 4; thisAxis++)
   {
      if (thisAxis != last)
      {
         newCubeString = doMove(thisAxis, newCubeString);
         try
         {
            moveTable.Add(newCubeString, sequence + thisAxis.ToString());
            positionsAtDepth[sequence.Length + 1].Add(newCubeString);
         }
         catch (ArgumentException)
         {
            // this block catches duplicate positions

         }
         // now do the move again to restore the puzzle
         newCubeString = doMove(thisAxis, newCubeString);
      }
   }
}

Building The Table

Using the two procedures that we have created, it's relatively simple to build up the move table. We start by adding the solved position and finding the positions 1 move from that. We take each of these positions and perform a move from there and so on. We do a little bit of output at the console so that we know things are working.

private static void calculateGodsAlgorithm()
{
   moveTable.Add(solvedPosition, "");
   positionsAtDepth[0].Add(solvedPosition);
   for (int i = 0; i < 14; i++)
   {
      Console.WriteLine("Depth: {0}, Positions: {1}", i, positionsAtDepth[i].Count);
      foreach (string s in positionsAtDepth[i])
      {
         exploreOnwardsFrom(s);
      }
   }
   Console.WriteLine("Depth: 14, Positions: {0}", positionsAtDepth[14].Count);
   Console.WriteLine("Finished Calculating: {0} Positions Found.", moveTable.Count);
}

Main Procedure

The main part of the program doesn't need to do too much. We need to initialise our list array, run the table-building procedure and then wait for input from the console.

static void Main(string[] args)
{
   // create the lists we need
   for (int i = 0; i < 15; i++)
   {
      positionsAtDepth[i] = new List<string>();
   }
   calculateGodsAlgorithm();
   Console.ReadLine();
}

That's it for now.