{- サイコロ置換 : dice.hs -}

import List                 -- Listのモジュールを読み込む

data Obj = T | S | E | B | N | W deriving (Eq, Enum, Show)
type Perm = [(Obj, Obj)]    -- 型に名前をつける
type Cycle = [Obj]
type CyclePerm = [Cycle]

allObj :: [Obj]
allObj = [T .. W]           -- Objの全体 (リスト)

go :: Obj -> Cycle -> Obj   -- goesToの下請け 1個のサイクルでの移動
go o c = case elemIndices o c of
         []  -> o
         [i] -> cycle c !! succ i   -- cycle c は c++c++...,succ i は i + 1

goesTo :: Obj -> CyclePerm -> Obj
goesTo = foldl go           -- Obj のリストに左から go を作用させる

assoc :: Eq k => k -> [(k, v)] -> [(k, v)]      -- Lispのassocのようなもの
assoc c as = [(k, v) | (k, v) <- as, c == k]

makeCycle0 :: Perm -> CyclePerm -> CyclePerm    -- サイクル表現にする
makeCycle0 [] qs = qs
makeCycle0 ((x,y):ss) qs
  | x == y   = makeCycle0 ss qs                 -- 単一サイクル除去
  |otherwise = makeCycle1 ss ([x,y]:qs)

makeCycle1 :: Perm -> CyclePerm -> CyclePerm
makeCycle1 ss (cs:css) 
  | c == head cs  = makeCycle0 ss' (cs:css)
  | otherwise     = makeCycle1 ss' ((cs ++ [c]):css)
        where c = snd d
              d = head (assoc (last cs) ss)
              ss' = delete d ss

prodPerm :: [CyclePerm] -> CyclePerm       -- 各種の手順による置換の計算
prodPerm ops = makeCycle0 (zip allObj allObj') []
            where allObj' = map (flip goesTo (concat ops)) allObj

t,s,e,b,n,w :: CyclePerm    -- 回転の定義
t = [[S,W,N,E]]
s = [[E,B,W,T]]
e = [[B,S,T,N]]
b = [[N,W,S,E]]
n = [[W,B,E,T]]
w = [[T,S,B,N]]

