有没有更好的方法来计算F#中立方体的所有可能方向?

Ale*_*rey 5 f#

我有一个名为cube的类型,它代表一个物理多维数据集.我编写了一些带有立方体的代码,并生成了多维数据集所有可能方向的列表.

我使用了以下术语,假设立方体在我眼前坐在我面前.

对于立方体的面:

  1. 顶部面向天花板.
  2. 底部朝向桌子.
  3. 正面朝我远方.
  4. 背面朝我.
  5. 左边面向我左边的墙.
  6. 右边面向我右边的墙.

对于轴,立方体可以旋转:

  1. 法线轴从桌子延伸到天花板.
  2. 纵轴从我向前延伸到我面前的墙壁.
  3. 横轴从左壁延伸到右壁.

当6个面中的每一个面朝下时,立方体可以以不同的方式(0°,90°,180°和270°)围绕其法线轴旋转.这导致24种可能的取向.

我已经开始使用立方体类型(请原谅S/O的语法着色):

type 'a cube(top:'a, bottom:'a, left:'a, right:'a, front:'a, back:'a) =
    member this.Top = top
    member this.Bottom = bottom
    member this.Left = left
    member this.Right = right
    member this.Front = front
    member this.Back = back
    override this.ToString() =
        sprintf "Top: %O, Bottom: %O, Left: %O, Right: %O Front: %O, Back: %O" top bottom left right front back
Run Code Online (Sandbox Code Playgroud)

然后我继续编写一个Cube模块,它提供了函数getOrientations.

module Cube =
    let rotateNormalRight (c:'a cube) =
        cube(c.Top, c.Bottom, c.Back, c.Front, c.Left, c.Right)
    let rotateLongitudinalRight (c:'a cube) =
        cube(c.Left, c.Right, c.Bottom, c.Top, c.Front, c.Back)
    let rotateLongitudinalLeft (c:'a cube) =
        cube(c.Right, c.Left, c.Top, c.Bottom, c.Front, c.Back)
    let private operations =
        [ rotateNormalRight; rotateNormalRight; rotateNormalRight; rotateLongitudinalRight
          rotateNormalRight; rotateNormalRight; rotateNormalRight; rotateLongitudinalRight
          rotateNormalRight; rotateNormalRight; rotateNormalRight; rotateLongitudinalLeft
          rotateNormalRight; rotateNormalRight; rotateNormalRight; rotateLongitudinalLeft
          rotateNormalRight; rotateNormalRight; rotateNormalRight; rotateLongitudinalRight
          rotateNormalRight; rotateNormalRight; rotateNormalRight ]
    let getOrientations startCube =
        let rec getCubeInner (ops:('a cube -> 'a cube) list) (cl:'a cube list) =
            match ops with
            | [] -> cl
            | op :: rest -> getCubeInner rest ((cl |> List.hd |> op) :: cl)
        getCubeInner operations [startCube]
Run Code Online (Sandbox Code Playgroud)

该模块仅提供三种可能的90度旋转,一个旋转列表,其中每个可能的方向采用立方体,以及一个在给定单个立方体的情况下产生所有方向的函数.

如果我做:

cube(1, 2, 3, 4, 5, 6)
|> Cube.getOrientations
|> List.iter (printfn "%O")
Run Code Online (Sandbox Code Playgroud)

我明白了:

Top: 3, Bottom: 4, Left: 1, Right: 2 Front: 6, Back: 5
Top: 3, Bottom: 4, Left: 6, Right: 5 Front: 2, Back: 1
Top: 3, Bottom: 4, Left: 2, Right: 1 Front: 5, Back: 6
Top: 3, Bottom: 4, Left: 5, Right: 6 Front: 1, Back: 2
Top: 6, Bottom: 5, Left: 3, Right: 4 Front: 1, Back: 2
Top: 6, Bottom: 5, Left: 1, Right: 2 Front: 4, Back: 3
Top: 6, Bottom: 5, Left: 4, Right: 3 Front: 2, Back: 1
Top: 6, Bottom: 5, Left: 2, Right: 1 Front: 3, Back: 4
Top: 2, Bottom: 1, Left: 5, Right: 6 Front: 3, Back: 4
Top: 2, Bottom: 1, Left: 3, Right: 4 Front: 6, Back: 5
Top: 2, Bottom: 1, Left: 6, Right: 5 Front: 4, Back: 3
Top: 2, Bottom: 1, Left: 4, Right: 3 Front: 5, Back: 6
Top: 4, Bottom: 3, Left: 1, Right: 2 Front: 5, Back: 6
Top: 4, Bottom: 3, Left: 5, Right: 6 Front: 2, Back: 1
Top: 4, Bottom: 3, Left: 2, Right: 1 Front: 6, Back: 5
Top: 4, Bottom: 3, Left: 6, Right: 5 Front: 1, Back: 2
Top: 5, Bottom: 6, Left: 4, Right: 3 Front: 1, Back: 2
Top: 5, Bottom: 6, Left: 1, Right: 2 Front: 3, Back: 4
Top: 5, Bottom: 6, Left: 3, Right: 4 Front: 2, Back: 1
Top: 5, Bottom: 6, Left: 2, Right: 1 Front: 4, Back: 3
Top: 1, Bottom: 2, Left: 5, Right: 6 Front: 4, Back: 3
Top: 1, Bottom: 2, Left: 4, Right: 3 Front: 6, Back: 5
Top: 1, Bottom: 2, Left: 6, Right: 5 Front: 3, Back: 4
Top: 1, Bottom: 2, Left: 3, Right: 4 Front: 5, Back: 6
Run Code Online (Sandbox Code Playgroud)

这就是我想要的.但是Cube模块被大量的操作所占据.

是否有更好的方法可以通过更少的操作或完全不同的方法来实现这一目标?

cHa*_*Hao 2

一方面:考虑一下,如果纵向旋转立方体,然后执行其他操作,操作的顺序会更加规则。(变成[长、正常、正常、正常]乘以6)。您可以想象将其压缩为 4 个操作的列表,尤其是在一秒钟内。更重要的是,在该列表迭代 3 次之后,您最终会得到与开始时相同的立方体。

现在,考虑一下您在旋转时看到的每个方向,还有一个“相反”方向。(IE:对于每个方向(U、D、L、R、F、B),都有一个相应的方向(D、U、L、R、B、F)。(想象一下你和一个朋友在外太空,每个向上-向下相对于另一个,并且你们每个人都在立方体的相对侧。)在前 12 个操作中的每一个之后([长向左,正常,正常,正常]乘以 3),最终位于立方体上的三个边你的“顶部”永远不会在“底部”——也就是说,你所看到的和你朋友所看到的之间不会有重叠。如果你的朋友也注意到他所看到的(阅读:如果你添加你的视图和同时的“相反”视图),您将旋转次数减半。

所以(在伪代码中,因为我不知道 F#):

ops = [rotateLongLeft, rotateNormalRight, rotateNormalRight, rotateNormalRight]
for each operation in [ops times 3]:
    do the operation
    add the orientation
    add its opposite
Run Code Online (Sandbox Code Playgroud)

最后,您应该拥有所有 24 个方向。