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

标签 f#

我有一个名为 cube 的类型,它代表一个物理立方体。我写了一些代码,它需要一个立方体,并生成一个立方体所有可能方向的列表。

我使用了以下术语,假设立方体位于我面前的视线水平。

对于立方体的面:

  • 顶部面向天花板。
  • 底部朝向 table 。
  • 前面背对着我。
  • 背对着我。
  • 左边是我左边的墙。
  • 右边是我右边的墙。

  • 对于轴,立方体可以旋转:
  • 法线轴从 table 延伸到天花板。
  • 纵轴从我向我面前的墙壁延伸。
  • 横轴从左壁延伸到右壁。

  • 虽然 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/

    相关文章:

    f# - 为什么 F# 的 Collections.Seq 模块基本上重新实现了所有的 Enumerable 扩展方法?

    f# - F# 中的 AutoOpen 属性

    xml - 如何将 XmlProvider<...>.DomainTypes 自动提供的选择类型转换为 F# 中的枚举?

    f# - 有没有办法嵌套调用 F# 事件模式?

    F#引用生成非常奇怪的编译错误

    f# - 如何确定两种类型之间的单一属性差异?

    .net - 是否有可能在 F Sharp 下使用 CUDA 编写 GPU 应用程序?

    entity-framework - Entity Framework 的类型提供程序

    f# - F# 中 EF C# ToListAsync 的等价物是什么?

    design-patterns - F# 命令模式