我有一个名为 cube 的类型,它代表一个物理立方体。我写了一些代码,它需要一个立方体,并生成一个立方体所有可能方向的列表。
我使用了以下术语,假设立方体位于我面前的视线水平。
对于立方体的面:
对于轴,立方体可以旋转:
虽然 6 个面中的每一个都保持朝下,但立方体可以围绕其法线轴旋转 4 种不同的方式(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
然后我继续编写一个提供函数 getOrientations 的 Cube 模块。
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]
这个模块只提供了三个可能的 90 度旋转,一个使立方体通过每个可能方向的旋转列表,以及一个在给定单个立方体的情况下产生所有方向的函数。
如果我做:
cube(1, 2, 3, 4, 5, 6)
|> Cube.getOrientations
|> List.iter (printfn "%O")
我得到:
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
这就是我想要的。但是 Cube 模块被庞大的操作列表占用。
有没有更好的方法可以通过更少的操作或完全不同的方法来做到这一点?
最佳答案
一方面:考虑如果您纵向旋转立方体,然后执行其他操作,则操作的顺序更加规则。 (它变成 [long, normal, normal, normal] 次 6)。您可以想象将其压缩为 4 个操作的列表,尤其是在一秒钟内。更重要的是,在此列表的 3 次迭代之后,您最终会得到与开始时相同的多维数据集。
现在,考虑到您在旋转时看到的每个方向,还有一个“相反”的方向。 (即:对于每个方向(U、D、L、R、F、B),都有一个对应的方向(D、U、L、R、B、F)。(想象你和一个 friend 在外太空,每个向上- 相对于另一方向下,并且你们每个人都在立方体的相对两侧。)在前 12 次操作中的每一次之后([long-left, normal, normal, normal] 乘以 3),最后的三个边在你的“顶部”永远不会出现在“底部”——也就是说,你看到的和你 friend 看到的之间不会有重叠。如果你的 friend 也注意到他看到的(阅读:如果你添加你的 View 和“相反” View ),您将旋转次数减少了一半。
所以(在伪代码中,因为我不知道 F#):
ops = [rotateLongLeft, rotateNormalRight, rotateNormalRight, rotateNormalRight]
for each operation in [ops times 3]:
do the operation
add the orientation
add its opposite
最后,您应该拥有所有 24 个方向。
关于f# - 有没有更好的方法来计算 F# 中立方体的所有可能方向?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3414237/