How to get all 24 rotations of a 3-dimensional array?

后端 未结 4 1327
既然无缘
既然无缘 2021-01-30 18:34

I have a 3-dimensional array. Think of it as a brick. There are 24 possible rotations of this brick (that keep its edges parallel to coordinate axes). How do I generate all corr

4条回答
  •  不知归路
    2021-01-30 19:36

    James Waldby's answer is inspiring, and I want to add a slightly improved version with only two for-loops.

    We know that there are 24 unique orientations. I calculated this by imagining a dice: there are 6 possible choices for the top face, and 4 possible rotations for each face on top.

    What if we iterate with that idea? I thought. If we can figure out a way to travel all 6 faces of the dice, then we only need to observe the 4 rotations on each face, and we are done!

    So I grabbed the nearest "brick" (in my case, a Vitasoy carton) and started rotating to see what would be the easiest pattern to visit all 6 faces. If we introduce an additional counter-clockwise turn, such that our operations are:

    • Roll (in a fixed direction, e.g. so that the face facing you is now rotated downwards)
    • Turn CW (along a fixed axis, e.g. so that the face facing you is turned clockwise, but still facing you)
    • Turn CCW (along the same axis as the last one)

    Then we can visit all faces by doing:

    Roll -> Turn CW -> Roll -> Turn CCW -> Roll -> Turn CW -> Roll -> Turn CCW -> Roll -> Turn CW -> Roll -> Turn CCW

    With the last roll and turn, we are back to the original orientation. As you can see, it is a repeated sequence of roll + alternating CW turns and CCW turns.

    Now, if we expand this to include all rotations of each face we visit, this becomes:

    Roll -> 3x Turn CW -> Roll -> 3x Turn CCW -> Roll -> 3x Turn CW -> Roll -> 3x Turn CCW -> Roll -> 3x Turn CW -> Roll -> 3x Turn CCW

    ...and we are back to where we started! This can be translated into two for-loops (one fewer!):

    def sequence(m):
      for roll_index in range(6):
        m = roll(m)
        yield(m)
        for turn_index in range(3):
          m = turn_cw(m) if roll_index % 2 == 0 else turn_ccw(m)
          yield(m)
    

提交回复
热议问题