У меня есть тип с именем куб, который представляет физический куб. Я написал некоторый код, который берет куб и генерирует список всех возможных ориентаций куба.
Я использовал следующую терминологию, предполагая, что куб находится передо мной на уровне глаз.
Для граней куба:
- Верхняя часть обращена к потолку.
- Дно обращено к столу.
- Передняя часть от меня.
- Спина обращена ко мне.
- Левый лицом к стене слева от меня.
- Право обращено к стене справа от меня.
Для осей куб можно вращать вокруг:
- Нормальная ось тянется от стола к потолку.
- Продольная ось тянется от меня к стене передо мной.
- Боковая ось вытянута от левой стены к правой стене.
В то время как каждая из 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
Затем я написал модуль 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]
Этот модуль предоставляет только три возможных поворота на 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 занят этим огромным списком операций.
Есть ли лучший способ сделать это, возможно, с меньшим количеством операций или с совершенно другим подходом?