Article

# WPF Rubik's Cube

, 31 Jan 2012
 Rate this:
A WPF 3-D Rubik's Cube application
Prize winner in Competition "Best VB.NET article of February 2012"

## Introduction

I find the Rubik's Cube to be a really captivating and fascinating puzzle and since WPF has 3-D capabilities, I decided to try making a Rubik's cube application that would closely replicate the real thing, both visually and interactively.

## Background

3-D support in WPF is not designed to provide full-featured game development capabilities but it is possible to emulate some simple games/toys, like the Rubik's cube. Please note that this article is not an introduction to 3-D graphics support in WPF, so I hope that you are at least conversant with the relevant details in this area. (I'm not exactly familiar with all the intricate details of 3-D support in WPF but I know enough to have made this application). If you are unfamiliar with the details of WPF 3-D support, or want to know more, then you can take a look at the various resources that are available online, like here on CodeProject.

Another thing that I hope you are also familiar with is some of the cubing terms. Just in case, this is how you denote the faces of a cube,

## Using the Application

To turn a layer of the cube hold down the left mouse button and swipe in the direction you intend to rotate the layer. Once you let go of the left-mouse button the layer will rotate as intended.

Rotating the U layer anti-clockwise

You can also rotate the whole cube using the right-mouse button. Just hold down the right-mouse button and swipe across the intended axis of rotation. The cube will rotate once you let go off the right-mouse button.

Rotating the cube around the Z-axis

Note that to rotate a layer, or the whole cube; you only interact with the F and R faces of the cube. Also note that rotations will only occur if the swipe is along a particular layer, horizontally or vertically, and crosses two or more cubies/cubelets.

To scramble the cube, just click on the Scramble button.

## Design & Layout

Designing the cube by hand-coding XAML would have been torture. Instead I opted to model the cube in Blender. After studying a few important Blender details; like moving, rotating, scaling, and applying materials to objects, I played around with the application for a while and ended up with a model that looks like a Rubik's cube.

Modelling of the cube in progress

The final result

After modeling of the cube was complete I exported the model as a Wavefront (.obj) file and then added the object (.obj) file and the material (.mtl) file that was generated to the WPF project, in Expression Blend. The object file and the material file can be found in the 3D_Cube folder.

The material and object files

Once the material and object file were added to the project it was just a matter of right-clicking the object file and selecting Insert, from the context-menu, to add the 3-D content to the artboard, in Expression Blend. The `Viewport3D` object that was created contained quite a number of `ModelVisual3D` objects, including a `PerspectiveCamera` and several lights.

In order for the cube not to appear like just a black mass with coloured stickers, I added a good number of lights for adequate illumination.

"All of the lights, all of the lights..."

The `Viewport3D` object is overlaid with 18 `Path` objects that are used to respond to mouse events. I could have opted to use `ModelUIElement3D` objects; that support input, focus, and events, but opted to stick with `ModelVisual3D` objects.

Each of the `ModelVisual3D` objects that represent cubies is named according to the colors of its 'stickers' e.g. `WGR_Cubie` is the White-Green-Red corner piece.

## The Code

The `Location` enumeration contains members representing the location of a cubie in 3-D space.

```Enum Location
' Layers viewed from U-to-D
' =========================
'
' First layer locations.
FUL
FU
FUR
RU
BUR
BU
BUL
LU
UC

' Second layer locations.
FL
FC
FR
RC
BR
BC
BL
LC

' Last layer locations.
FDL
FD
FDR
RD
BDR
BD
BDL
LD
DC
End Enum
```

Each cubie in the `Viewport3D` is associated with an object of class `Cubie`, which contains methods for rotating the cubelet around a particular axis,

```Imports System.Windows.Media.Media3D
Imports System.Windows.Media.Animation

Public Class Cubie

Public cubelet As ModelVisual3D

Private _cubieLocation As Location

Private axisPoint As New Point3D(0, 0, 0)
Private axisAngleRtn3D As New AxisAngleRotation3D(New Vector3D(0, 0, 1), 0)

Private dblAnim As DoubleAnimation
Private rtnTrans3D As RotateTransform3D
Private transGroup As New Transform3DGroup

Private milliSec As Short = 280

''' <span class="code-SummaryComment"><summary>
</span>    ''' Location of the cubie in 3D space; in terms
''' of an enum Location value.
''' <span class="code-SummaryComment"></summary>
</span>    Friend Property CubieLocation() As Location
Get
Return _cubieLocation
End Get
Set(ByVal value As Location)
_cubieLocation = value
End Set
End Property

''' <span class="code-SummaryComment"><summary>
</span>    ''' Rotate cubie around the X-axis.
''' <span class="code-SummaryComment"></summary>
</span>    ''' <span class="code-SummaryComment"><param name="angle">The angle of rotation; -90 or 90.</param>
</span>    Public Sub RotateAround_X_Axis(ByVal angle As Double)
axisAngleRtn3D = New AxisAngleRotation3D(New Vector3D(1, 0, 0), 0)
rtnTrans3D = New RotateTransform3D(axisAngleRtn3D, axisPoint)
dblAnim = New DoubleAnimation(CDbl(angle), TimeSpan.FromMilliseconds(milliSec), FillBehavior.HoldEnd)

axisAngleRtn3D.BeginAnimation(AxisAngleRotation3D.AngleProperty, dblAnim)
cubelet.Transform = transGroup

' Change value of _cubeLocation accordingly.
ChangeLocationOn_X_AxisRtn(angle)
End Sub

''' <span class="code-SummaryComment"><summary>
</span>    ''' Rotate cubie around the Y-axis.
''' <span class="code-SummaryComment"></summary>
</span>    ''' <span class="code-SummaryComment"><param name="angle">The angle of rotation; -90 or 90.</param>
</span>    Public Sub RotateAround_Y_Axis(ByVal angle As Double)
axisAngleRtn3D = New AxisAngleRotation3D(New Vector3D(0, 1, 0), 0)
rtnTrans3D = New RotateTransform3D(axisAngleRtn3D, axisPoint)
dblAnim = New DoubleAnimation(CDbl(angle), TimeSpan.FromMilliseconds(milliSec), FillBehavior.HoldEnd)

axisAngleRtn3D.BeginAnimation(AxisAngleRotation3D.AngleProperty, dblAnim)
cubelet.Transform = transGroup

' Change value of _cubeLocation accordingly.
ChangeLocationOn_Y_AxisRtn(angle)
End Sub

''' <span class="code-SummaryComment"><summary>
</span>    ''' Rotate cubie around the Z-axis.
''' <span class="code-SummaryComment"></summary>
</span>    ''' <span class="code-SummaryComment"><param name="angle">The angle of rotation; -90 or 90.</param>
</span>    Public Sub RotateAround_Z_Axis(ByVal angle As Double)
axisAngleRtn3D = New AxisAngleRotation3D(New Vector3D(0, 0, 1), 0)
rtnTrans3D = New RotateTransform3D(axisAngleRtn3D, axisPoint)
dblAnim = New DoubleAnimation(CDbl(angle), TimeSpan.FromMilliseconds(milliSec), FillBehavior.HoldEnd)

axisAngleRtn3D.BeginAnimation(AxisAngleRotation3D.AngleProperty, dblAnim)
cubelet.Transform = transGroup

' Change value of _cubeLocation accordingly.
ChangeLocationOn_Z_AxisRtn(angle)
End Sub

Private Sub ChangeLocationOn_X_AxisRtn(ByVal angle As Integer)
' Looking from R-to-L
' ===================
' 90 degree angle (anti-clockwise rotation).
If angle >```

The `ModelVisual3D` objects that make up a particular cubie are associated with a `Cubie` object when the `PopulateList()` method in class `Rotater` is called by its constructor.

```    Private Sub PopulateList()
' Layers viewed from U-to-D
' =========================
' CubieLocations are the initial locations of cubies
' in 3D space with White-U, Green-F, & Red-R.
' ==================================================
'
' First layer.
cubiesList.Add(New Cubie With {.CubieLocation = Location.FUL, .cubelet = mainWin.WGO_Cubie})
cubiesList.Add(New Cubie With {.CubieLocation = Location.FU, .cubelet = mainWin.WG_Cubie})
cubiesList.Add(New Cubie With {.CubieLocation = Location.FUR, .cubelet = mainWin.WGR_Cubie})
cubiesList.Add(New Cubie With {.CubieLocation = Location.RU, .cubelet = mainWin.WR_Cubie})
cubiesList.Add(New Cubie With {.CubieLocation = Location.BUR, .cubelet = mainWin.WRB_Cubie})
cubiesList.Add(New Cubie With {.CubieLocation = Location.BU, .cubelet = mainWin.WB_Cubie})
cubiesList.Add(New Cubie With {.CubieLocation = Location.BUL, .cubelet = mainWin.WBO_Cubie})
cubiesList.Add(New Cubie With {.CubieLocation = Location.LU, .cubelet = mainWin.WO_Cubie})
cubiesList.Add(New Cubie With {.CubieLocation = Location.UC, .cubelet = mainWin.WC_Cubie})

' Second layer.
cubiesList.Add(New Cubie With {.CubieLocation = Location.FL, .cubelet = mainWin.GO_Cubie})
cubiesList.Add(New Cubie With {.CubieLocation = Location.FC, .cubelet = mainWin.GC_Cubie})
cubiesList.Add(New Cubie With {.CubieLocation = Location.FR, .cubelet = mainWin.GR_Cubie})
cubiesList.Add(New Cubie With {.CubieLocation = Location.RC, .cubelet = mainWin.RC_Cubie})
cubiesList.Add(New Cubie With {.CubieLocation = Location.BR, .cubelet = mainWin.RB_Cubie})
cubiesList.Add(New Cubie With {.CubieLocation = Location.BC, .cubelet = mainWin.BC_Cubie})
cubiesList.Add(New Cubie With {.CubieLocation = Location.BL, .cubelet = mainWin.BO_Cubie})
cubiesList.Add(New Cubie With {.CubieLocation = Location.LC, .cubelet = mainWin.OC_Cubie})

' Third layer.
cubiesList.Add(New Cubie With {.CubieLocation = Location.FDL, .cubelet = mainWin.YGO_Cubie})
cubiesList.Add(New Cubie With {.CubieLocation = Location.FD, .cubelet = mainWin.YG_Cubie})
cubiesList.Add(New Cubie With {.CubieLocation = Location.FDR, .cubelet = mainWin.YGR_Cubie})
cubiesList.Add(New Cubie With {.CubieLocation = Location.RD, .cubelet = mainWin.YR_Cubie})
cubiesList.Add(New Cubie With {.CubieLocation = Location.BDR, .cubelet = mainWin.YRB_Cubie})
cubiesList.Add(New Cubie With {.CubieLocation = Location.BD, .cubelet = mainWin.YB_Cubie})
cubiesList.Add(New Cubie With {.CubieLocation = Location.BDL, .cubelet = mainWin.YBO_Cubie})
cubiesList.Add(New Cubie With {.CubieLocation = Location.LD, .cubelet = mainWin.YO_Cubie})
cubiesList.Add(New Cubie With {.CubieLocation = Location.DC, .cubelet = mainWin.YC_Cubie})
End Sub
```

As I mentioned earlier, the `Path` objects that overlay the `Viewport3D` are used to detect mouse events in order to carry out the required rotation.

```    Private Sub Paths_PreviewMouseLeftButtonDown(ByVal sender As Object, _
ByVal e As System.Windows.Input.MouseButtonEventArgs) _
Handles FU_1.PreviewMouseLeftButtonDown, FU_2.PreviewMouseLeftButtonDown, FU_3.PreviewMouseLeftButtonDown, _
FM_1.PreviewMouseLeftButtonDown, FM_2.PreviewMouseLeftButtonDown, FM_3.PreviewMouseLeftButtonDown, _
FD_1.PreviewMouseLeftButtonDown, FD_2.PreviewMouseLeftButtonDown, FD_3.PreviewMouseLeftButtonDown, _
RU_1.PreviewMouseLeftButtonDown, RU_2.PreviewMouseLeftButtonDown, RU_3.PreviewMouseLeftButtonDown, _
RM_1.PreviewMouseLeftButtonDown, RM_2.PreviewMouseLeftButtonDown, RM_3.PreviewMouseLeftButtonDown, _
RD_1.PreviewMouseLeftButtonDown, RD_2.PreviewMouseLeftButtonDown, RD_3.PreviewMouseLeftButtonDown

cPath_1 = CType(sender, Path)

End Sub

Private Sub Paths_PreviewMouseLeftButtonUp(ByVal sender As Object, _
ByVal e As System.Windows.Input.MouseButtonEventArgs) _
Handles FU_1.PreviewMouseLeftButtonUp, FU_2.PreviewMouseLeftButtonUp, FU_3.PreviewMouseLeftButtonUp, _
FM_1.PreviewMouseLeftButtonUp, FM_2.PreviewMouseLeftButtonUp, FM_3.PreviewMouseLeftButtonUp, _
FD_1.PreviewMouseLeftButtonUp, FD_2.PreviewMouseLeftButtonUp, FD_3.PreviewMouseLeftButtonUp, _
RU_1.PreviewMouseLeftButtonUp, RU_2.PreviewMouseLeftButtonUp, RU_3.PreviewMouseLeftButtonUp, _
RM_1.PreviewMouseLeftButtonUp, RM_2.PreviewMouseLeftButtonUp, RM_3.PreviewMouseLeftButtonUp, _
RD_1.PreviewMouseLeftButtonUp, RD_2.PreviewMouseLeftButtonUp, RD_3.PreviewMouseLeftButtonUp

cPath_2 = CType(sender, Path)

If (cPath_1 IsNot cPath_2) Then
rt.RotateLayer(cPath_1, cPath_2)
End If

End Sub

Private Sub Paths_PreviewMouseRightButtonDown(ByVal sender As Object, _
ByVal e As System.Windows.Input.MouseButtonEventArgs) _
Handles FU_1.PreviewMouseRightButtonDown, FU_2.PreviewMouseRightButtonDown, FU_3.PreviewMouseRightButtonDown, _
FM_1.PreviewMouseRightButtonDown, FM_2.PreviewMouseRightButtonDown, FM_3.PreviewMouseRightButtonDown, _
FD_1.PreviewMouseRightButtonDown, FD_2.PreviewMouseRightButtonDown, FD_3.PreviewMouseRightButtonDown, _
RU_1.PreviewMouseRightButtonDown, RU_2.PreviewMouseRightButtonDown, RU_3.PreviewMouseRightButtonDown, _
RM_1.PreviewMouseRightButtonDown, RM_2.PreviewMouseRightButtonDown, RM_3.PreviewMouseRightButtonDown, _
RD_1.PreviewMouseRightButtonDown, RD_2.PreviewMouseRightButtonDown, RD_3.PreviewMouseRightButtonDown

cPath_1 = CType(sender, Path)

End Sub

Private Sub Paths_PreviewMouseRightButtonUp(ByVal sender As Object, _
ByVal e As System.Windows.Input.MouseButtonEventArgs) _
Handles FU_1.PreviewMouseRightButtonUp, FU_2.PreviewMouseRightButtonUp, FU_3.PreviewMouseRightButtonUp, _
FM_1.PreviewMouseRightButtonUp, FM_2.PreviewMouseRightButtonUp, FM_3.PreviewMouseRightButtonUp, _
FD_1.PreviewMouseRightButtonUp, FD_2.PreviewMouseRightButtonUp, FD_3.PreviewMouseRightButtonUp, _
RU_1.PreviewMouseRightButtonUp, RU_2.PreviewMouseRightButtonUp, RU_3.PreviewMouseRightButtonUp, _
RM_1.PreviewMouseRightButtonUp, RM_2.PreviewMouseRightButtonUp, RM_3.PreviewMouseRightButtonUp, _
RD_1.PreviewMouseRightButtonUp, RD_2.PreviewMouseRightButtonUp, RD_3.PreviewMouseRightButtonUp

cPath_2 = CType(sender, Path)

If (cPath_1 IsNot cPath_2) Then
rt.RotateCube(cPath_1, cPath_2)
End If

End Sub
```

The `RotateLayer()` method in class `Rotater` calls several methods which determine which `Path` objects the user interacted with so as to respond accordingly.

```    Public Sub RotateLayer(ByVal path_1 As Path, ByVal path_2 As Path)
HorizontalSwipeAcross_F_Paths(path_1, path_2)
HorizontalSwipeAcross_R_Paths(path_1, path_2)
HorizontalSwipeAcross_FandR_Paths(path_1, path_2)

VerticalSwipeOn_F_Paths(path_1, path_2)
VerticalSwipeOn_R_Paths(path_1, path_2)
End Sub

''' <span class="code-SummaryComment"><summary>
</span>    ''' Check which horizontal layer the user intends to rotate when
''' the user swipes horizontally across the front face of the
''' cube, and rotate the layer.
''' <span class="code-SummaryComment"></summary>
</span>    Private Sub HorizontalSwipeAcross_F_Paths(ByVal path_1 As Path, ByVal path_2 As Path)
' Horizontal swipe on FU... Paths; L-to-R mouse swipe.
If (path_1 Is mainWin.FU_1 AndAlso path_2 Is mainWin.FU_2) Then
RotateFU_RU_LayerAroundY_Axis(ANTICLOCKWISE_ANGLE)
ElseIf (path_1 Is mainWin.FU_1 AndAlso path_2 Is mainWin.FU_3) Then
RotateFU_RU_LayerAroundY_Axis(ANTICLOCKWISE_ANGLE)
ElseIf (path_1 Is mainWin.FU_2 AndAlso path_2 Is mainWin.FU_3) Then
RotateFU_RU_LayerAroundY_Axis(ANTICLOCKWISE_ANGLE)
End If
' Horizontal swipe on FU... Paths; R-to-L mouse swipe.
If (path_1 Is mainWin.FU_3 AndAlso path_2 Is mainWin.FU_2) Then
RotateFU_RU_LayerAroundY_Axis(CLOCKWISE_ANGLE)
ElseIf (path_1 Is mainWin.FU_3 AndAlso path_2 Is mainWin.FU_1) Then
RotateFU_RU_LayerAroundY_Axis(CLOCKWISE_ANGLE)
ElseIf (path_1 Is mainWin.FU_2 AndAlso path_2 Is mainWin.FU_1) Then
RotateFU_RU_LayerAroundY_Axis(CLOCKWISE_ANGLE)
End If
...
End Sub

''' <span class="code-SummaryComment"><summary>
</span>    ''' Check which horizontal layer the user intends to rotate when
''' the user swipes horizontally across the right face of the
''' cube, and rotate the layer.
''' <span class="code-SummaryComment"></summary>
</span>    Private Sub HorizontalSwipeAcross_R_Paths(ByVal path_1 As Path, ByVal path_2 As Path)
...
' =======================================================
' Horizontal swipe on RM... Paths; L-to-R mouse swipe.
If (path_1 Is mainWin.RM_1 AndAlso path_2 Is mainWin.RM_2) Then
RotateFM_RM_LayerAroundY_Axis(ANTICLOCKWISE_ANGLE)
ElseIf (path_1 Is mainWin.RM_1 AndAlso path_2 Is mainWin.RM_3) Then
RotateFM_RM_LayerAroundY_Axis(ANTICLOCKWISE_ANGLE)
ElseIf (path_1 Is mainWin.RM_2 AndAlso path_2 Is mainWin.RM_3) Then
RotateFM_RM_LayerAroundY_Axis(ANTICLOCKWISE_ANGLE)
End If
' Horizontal swipe on RM... Paths; R-to-L mouse swipe.
If (path_1 Is mainWin.RM_3 AndAlso path_2 Is mainWin.RM_2) Then
RotateFM_RM_LayerAroundY_Axis(CLOCKWISE_ANGLE)
ElseIf (path_1 Is mainWin.RM_3 AndAlso path_2 Is mainWin.RM_1) Then
RotateFM_RM_LayerAroundY_Axis(CLOCKWISE_ANGLE)
ElseIf (path_1 Is mainWin.RM_2 AndAlso path_2 Is mainWin.RM_1) Then
RotateFM_RM_LayerAroundY_Axis(CLOCKWISE_ANGLE)
End If
...
End Sub

''' <span class="code-SummaryComment"><summary>
</span>    ''' Check for horizontal swipes that cross from the front face of
''' the cube to the right face, and vice-versa, and rotate the
''' appopriate layer.
''' <span class="code-SummaryComment"></summary>
</span>    Private Sub HorizontalSwipeAcross_FandR_Paths(ByVal path_1 As Path, ByVal path_2 As Path)
' Horizontal swipe crossing from FU Paths to RU Paths
' and vice-versa.
If (path_1 Is mainWin.FU_2 AndAlso path_2 Is mainWin.RU_1) Then
RotateFU_RU_LayerAroundY_Axis(ANTICLOCKWISE_ANGLE)
ElseIf (path_1 Is mainWin.FU_3 AndAlso path_2 Is mainWin.RU_1) Then
RotateFU_RU_LayerAroundY_Axis(ANTICLOCKWISE_ANGLE)
ElseIf (path_1 Is mainWin.RU_2 AndAlso path_2 Is mainWin.FU_3) Then
RotateFU_RU_LayerAroundY_Axis(CLOCKWISE_ANGLE)
ElseIf (path_1 Is mainWin.RU_1 AndAlso path_2 Is mainWin.FU_3) Then
RotateFU_RU_LayerAroundY_Axis(CLOCKWISE_ANGLE)
End If
...
End Sub
```

The methods called by the various methods highlighted above determine which cubies to rotate to create the illusion of a layer rotation e.g. the following methods lead to layer rotation around the Y-axis,

```    Public Sub RotateFU_RU_LayerAroundY_Axis(ByVal angle As Double)
Dim cubiesToMove = cubiesList.Where _
(Function(c) c.CubieLocation = Location.FUL Or c.CubieLocation = Location.FU Or _
c.CubieLocation = Location.FUR Or c.CubieLocation = Location.RU Or _
c.CubieLocation = Location.BUR Or c.CubieLocation = Location.BU Or _
c.CubieLocation = Location.BUL Or c.CubieLocation = Location.LU Or _
c.CubieLocation = Location.UC)

For Each c In cubiesToMove
c.RotateAround_Y_Axis(angle)
Next
End Sub

Private Sub RotateFM_RM_LayerAroundY_Axis(ByVal angle As Double)
Dim cubiesToMove = cubiesList.Where _
(Function(c) c.CubieLocation = Location.FL Or c.CubieLocation = Location.FC Or _
c.CubieLocation = Location.FR Or c.CubieLocation = Location.RC Or _
c.CubieLocation = Location.BR Or c.CubieLocation = Location.BC Or _
c.CubieLocation = Location.BL Or c.CubieLocation = Location.LC)

For Each c In cubiesToMove
c.RotateAround_Y_Axis(angle)
Next
End Sub

Public Sub RotateFD_RD_LayerAroundY_Axis(ByVal angle As Double)
Dim cubiesToMove = cubiesList.Where _
(Function(c) c.CubieLocation = Location.FDL Or c.CubieLocation = Location.FD Or _
c.CubieLocation = Location.FDR Or c.CubieLocation = Location.RD Or _
c.CubieLocation = Location.BDR Or c.CubieLocation = Location.BD Or _
c.CubieLocation = Location.BDL Or c.CubieLocation = Location.LD Or _
c.CubieLocation = Location.DC)

For Each c In cubiesToMove
c.RotateAround_Y_Axis(angle)
Next
End Sub
```

The class `Scrambler` deals with the scrambling of the cube.

```Imports System.Windows.Threading

Public Class Scrambler

Private rtr As Rotater
Private mainWin As MainWindow

Private rotations() As String = {"F", "F'", "F2", "R", "R'", "R2", _
"B", "B'", "B2", "L", "L'", "L2", _
"U", "U'", "U2", "D", "D'", "D2"}

Private rndIndex As Integer = -1
Private index As Integer
Private listIndex As Integer
Private isScrambling As Boolean

Private Const CLOCKWISE_ANGLE As Double = -90
Private Const ANTICLOCKWISE_ANGLE As Double = 90

Private rnd As New Random
Private scrambleTimer As DispatcherTimer
Private rotationsList As New List(Of String)

Public Sub New(ByRef rt As Rotater, ByRef win As MainWindow)
rtr = rt
mainWin = win

scrambleTimer = New DispatcherTimer
scrambleTimer.Interval = New TimeSpan(0, 0, 0, 0, 400)
End Sub

Public Sub ScrambleCube()
If (isScrambling = False) Then
rotationsList.Clear()

For i As Integer = 0 To 24
PopulateRotationsList()
Next
' Disable Grid containing the Viewport and Path
' elements for rotating layers.
mainWin.ViewportAndCanvasGrid.IsEnabled = False

isScrambling = True
scrambleTimer.Start()
Else
MessageBox.Show("Scrambling of cube already in progress", _
"WPF Rubiks", MessageBoxButton.OK, MessageBoxImage.Exclamation)
End If
End Sub

''' <span class="code-SummaryComment"><summary>
</span>    ''' Populate rotationsList with disimillar Strings following
''' each other, and the next String in the List is not an
''' inverse or double of the preceding String e.g. F' does
''' not come after F, or F2 after F.
''' <span class="code-SummaryComment"></summary>
</span>    Private Sub PopulateRotationsList()
Dim n As Integer = rnd.Next(0, 18)
Dim lastString As String = String.Empty

If (rotationsList.Count >```

## Conclusion

That's it. I hope you'll have a fun time solving the WPF Rubik's Cube. I have scrambled and solved it several times and it is quite as thrilling as the real thing.

## History

• 1st Feb, 2012: Initial post

## Share

Software Developer
Kenya
Meshack is an avid programmer with a bias towards WPF and VB.NET. He has about 5 years of programming experience initially starting off with Java before shifting to .NET, thanks to the allure of WPF. He has developed several applications, and written several articles about them, which can be viewed here on CodeProject. He currently resides in a small town in Kiambu county, Kenya.

Awards;
• CodeProject MVP 2013
• CodeProject MVP 2012
• Best VB.NET article of August 2013
• Best VB.NET article of February 2013
• Best VB.NET article of October 2012
• Best VB.NET article of July 2012
• Best VB.NET article of February 2012
• Best VB.NET article of January 2012
• Best VB.NET article of November 2011
• Best VB.NET article of June 2011
• Best VB.NET article of May 2011
• Best VB.NET article of March 2011
• Best VB.NET article of February 2011
• Best VB.NET article of January 2011
• Best VB.NET article of December 2010
• Best VB.NET article of November 2010

 First PrevNext
 scramble algorithm jrobb229 22-Nov-13 16:58
 My vote of 5 Michael Haephrati 15-Mar-13 2:49
 Re: My vote of 5 Meshack Musundi 15-Mar-13 4:47
 My vote of 5 Barry Lapthorn 25-Feb-13 1:57
 Re: My vote of 5 Meshack Musundi 26-Feb-13 2:42
 My vote of 5 Duncan Edwards Jones 30-Dec-12 9:40
 Re: My vote of 5 Meshack Musundi 30-Dec-12 19:37
 My vote of 5 Tarun Y Mangukiya 11-Aug-12 16:56
 Re: My vote of 5 Meshack Musundi 20-Aug-12 20:50
 My vote of 5 Farhan Ghumra 22-Jun-12 2:07
 Re: My vote of 5 Meshack Musundi 26-Jul-12 21:49
 Thanks Farhan. "As beings of finite lifespan, our contributions to the sum of human knowledge is one of the greatest endeavors we can undertake and one of the defining characteristics of humanity itself"
 My vote of 5 michael azzar 1-Jun-12 5:20
 You're very Distinctive [modified] michael azzar 1-Jun-12 5:18
 Re: You're very Distinctive Meshack Musundi 1-Jun-12 21:18
 Re: You're very Distinctive michael azzar 2-Jun-12 10:49
 Rubik's Cube VishalvPatil 17-Apr-12 5:30
 Re: Rubik's Cube Meshack Musundi 17-Apr-12 20:33
 My vote of 5 G-Tek 3-Apr-12 3:49
 Re: My vote of 5 Meshack Musundi 12-Apr-12 4:25
 My vote of 5 Brian Pendleton 2-Apr-12 7:39
 Re: My vote of 5 Meshack Musundi 12-Apr-12 4:22
 My vote of 5 Reza Ahmadi 2-Apr-12 5:45
 Re: My vote of 5 Meshack Musundi 12-Apr-12 4:21
 My vote of 5 manoj kumar choubey 19-Mar-12 19:35
 Re: My vote of 5 Meshack Musundi 20-Mar-12 23:09
 Last Visit: 31-Dec-99 18:00     Last Update: 20-Aug-14 18:16 Refresh 1234 Next »