Welcome, guest | Sign In | My Account | Store | Cart

I have four cubes (in real) with different colors on their sides as a puzzle with the final goal to place each cube side by side that way that on each visible side (except the two ends) you can see four different colors.

I have placed the cubes as they are (side by side) writing down the current colors (see function main). The CubesChecker class is searching for one solution. You don't see the operation on how to rotate but knowing the final state it's really easy to do it yourself then.

Python, 178 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
"""
    @author   Thomas Lehmann
    @file     four_cubes_problem.py

    There are four cubes with concrete colors on their sides and the goal
    is to place each cube in one row that way, that along the row each side
    presents four different colors:

     -   -   -   -
    |W| |R| |G| |B| (front view)
     -   -   -   -

    Of course four different colors are also required at the top view
    at the bottom view and at the back view.

    Background: I have those four cubes in real and I have been seeking
                for the solution without manual try.

"""
import random

class Color:
    """ represents a kind of enum for all used colors """
    GREEN = 0
    RED   = 1
    WHITE = 2
    BLUE  = 3

    MAX   = 4

    @staticmethod
    def name(value):
        return ["GREEN", "RED", "WHITE", "BLUE"][value]

class Cube:
    def __init__(self, front, back, left, right, top, bottom):
        """ initializes all sides of a cube with colors """
        self.front  = front
        self.back   = back
        self.left   = left
        self.right  = right
        self.top    = top
        self.bottom = bottom

    def __eq__(self, other):
        """ compares this cube and another for to be equal """
        return self.front   == other.front  \
            and self.back   == other.back   \
            and self.left   == other.left   \
            and self.right  == other.right  \
            and self.top    == other.top    \
            and self.bottom == other.bottom

    def __hash__(self):
        """ unique key for this instance """
        return hash((self.front, self.back, self.left, self.right, self.top, self.bottom))

    def clone(self):
        """ provides a copy of this instance """
        return Cube(self.front, self.back, self.left, self.right, self.top, self.bottom)

    def __str__(self):
        """ does print the current cube setup (colors) """
        return "front:"  + Color.name(self.front)  + "," + \
               "back:"   + Color.name(self.back)   + "," + \
               "left:"   + Color.name(self.left)   + "," + \
               "right:"  + Color.name(self.right)  + "," + \
               "top:"    + Color.name(self.top)    + "," + \
               "bottom:" + Color.name(self.bottom)

    def getCombinations(self):
        """ I know: there should be 24 combinations """
        cubes = set()
        cubes.add(self.clone())

        cube = self.clone()
        while not len(cubes) == 24:
            mode = random.randint (0, 4)
            if   0 == mode:  cube.rotateLeft()
            elif 1 == mode:  cube.rotateRight()
            elif 2 == mode:  cube.rotateTop()
            elif 3 == mode:  cube.rotateBottom()
            cubes.add(cube.clone())

        return cubes

    def rotateLeft(self):
        """ does rotate the cube to the left """
        help       = self.left
        self.left  = self.front
        self.front = self.right
        self.right = self.back
        self.back  = help
        return self

    def rotateRight(self):
        """ does rotate the cube to the right """
        help       = self.right
        self.right = self.front
        self.front = self.left
        self.left  = self.back
        self.back  = help
        return self

    def rotateTop(self):
        """ does rotate the cube to the top """
        help        = self.top
        self.top    = self.front
        self.front  = self.bottom
        self.bottom = self.back
        self.back   = help
        return self

    def rotateBottom(self):
        """ does rotate the cube to the bottom """
        help        = self.bottom
        self.bottom = self.front
        self.front  = self.top
        self.top    = self.back
        self.back   = help
        return self

class CubesChecker:
    def __init__(self, cubes):
        self.originalCubes = cubes

    @staticmethod
    def isValidState(cubes):
        """ ensure the rule: four different colors on each side """
        frontColors  = set()
        backColors   = set()
        topColors    = set()
        bottomColors = set()

        for cube in cubes:
            frontColors.add(cube.front)
            backColors.add(cube.back)
            topColors.add(cube.top)
            bottomColors.add(cube.bottom)

        return  len(frontColors)  == Color.MAX \
            and len(backColors)   == Color.MAX \
            and len(topColors)    == Color.MAX \
            and len(bottomColors) == Color.MAX

    def calculate(self, position = 0, cubes = []):
        """ find the cubes final state """
        if len(cubes) == Color.MAX:
            if CubesChecker.isValidState(cubes):
                for cube in cubes:
                    print(cube)
                return True
            else:
                return False

        for cube in self.originalCubes[position].getCombinations():
            if self.calculate(position+1, cubes + [cube]):
                return True

        return False

def main():
    """ there are four cubes with concrete colors on their sides and the goal
        is to place each cube in one row that way that along the row each side
        presents four different colors """
    #              -----------  -----------  -----------  -----------  -----------  -----------
    #              front        back         left         right        top          bottom
    #              -----------  -----------  -----------  -----------  -----------  -----------
    cubes = [ Cube(Color.GREEN, Color.WHITE, Color.GREEN, Color.RED,   Color.WHITE, Color.BLUE),
              Cube(Color.WHITE, Color.RED  , Color.WHITE, Color.GREEN, Color.BLUE,  Color.RED),
              Cube(Color.RED,   Color.RED,   Color.RED  , Color.GREEN, Color.BLUE,  Color.WHITE),
              Cube(Color.BLUE,  Color.RED,   Color.GREEN, Color.GREEN, Color.WHITE, Color.BLUE) ]

    cubesChecker = CubesChecker(cubes)
    cubesChecker.calculate()

if __name__ == "__main__":
    main()

Here's the printed solution:

>C:\Python32\pythonw.exe -u "four_cubes_problem.py"
front:WHITE,back:GREEN,left:WHITE,right:BLUE,top:GREEN,bottom:RED
front:RED,back:BLUE,left:RED,right:WHITE,top:WHITE,bottom:GREEN
front:GREEN,back:RED,left:RED,right:RED,top:BLUE,bottom:WHITE
front:BLUE,back:WHITE,left:GREEN,right:GREEN,top:RED,bottom:BLUE
>Exit code: 0