module Rubik.Cube.Coord where
import Rubik.Cube.Cubie.Internal
import Rubik.Misc
import Control.DeepSeq
import Control.Monad.Random
import Control.Newtype
import Data.Binary.Storable
import Data.List
import qualified Data.Vector.Unboxed as U
import qualified Data.Vector.Unboxed.Mutable as MU
import qualified Data.Vector.Storable.Allocated as S
type RawCoord' = Int
newtype RawCoord a = RawCoord { unRawCoord :: RawCoord' }
deriving (Eq, Ord, Show, NFData, Binary)
newtype RawVector a b = RawVector { unRawVector :: U.Vector b }
newtype RawMove a = RawMove { unRawMove :: S.Vector RawCoord' }
deriving (Eq, Ord, Show, NFData, Binary)
instance Newtype (RawCoord a) Int where
pack = RawCoord
unpack = unRawCoord
instance Newtype (RawMove a) (S.Vector Int) where
pack = RawMove
unpack = unRawMove
(!$) :: RawMove a -> RawCoord a -> RawCoord a
RawMove v !$ RawCoord i = RawCoord (v S.! i)
(!.) :: MU.Unbox b => RawVector a b -> RawCoord a -> b
RawVector v !. RawCoord i = v U.! i
class RawEncodable a where
range :: proxy a -> Int
encode :: a -> RawCoord a
decode :: RawCoord a -> a
instance RawEncodable CornerPermu where
range _ = 40320
encode = RawCoord . encodeFact numCorners . U.toList . fromCornerPermu
decode = unsafeCornerPermu' . decodeFact numCorners numCorners . unRawCoord
instance RawEncodable EdgePermu where
range _ = 479001600
encode = RawCoord . encodeFact numEdges . U.toList . fromEdgePermu
decode = unsafeEdgePermu' . decodeFact numEdges numEdges . unRawCoord
instance RawEncodable CornerOrien where
range _ = 2187
encode = RawCoord . encodeBaseV 3 . U.tail . fromCornerOrien
decode (RawCoord x) = unsafeCornerOrien' (h : t)
where h = (3 sum t) `mod` 3
t = decodeBase 3 (numCorners 1) x
instance RawEncodable EdgeOrien where
range _ = 2048
encode = RawCoord . encodeEdgeOrien' . fromEdgeOrien
decode (RawCoord x) = unsafeEdgeOrien' (h : t)
where h = sum t `mod` 2
t = decodeBase 2 (numEdges 1) x
encodeEdgeOrien' = encodeBaseV 2 . U.tail
numUDS = numUDSliceEdges
numUDE = numEdges numUDS
instance RawEncodable UDSlicePermu where
range _ = 11880
encode = RawCoord . encodeFact numEdges . U.toList . fromUDSlicePermu
decode = unsafeUDSlicePermu' . decodeFact numEdges numUDS . unRawCoord
instance RawEncodable UDSlice where
range _ = 495
encode = RawCoord . encodeCV . fromUDSlice
decode = unsafeUDSlice . decodeCV numUDS . unRawCoord
instance RawEncodable UDSlicePermu2 where
range _ = 24
encode = RawCoord . encodeFact numUDS . U.toList . fromUDSlicePermu2
decode = unsafeUDSlicePermu2' . decodeFact numUDS numUDS . unRawCoord
instance RawEncodable UDEdgePermu2 where
range _ = 40320
encode = RawCoord . encodeFact numUDE . U.toList . fromUDEdgePermu2
decode = unsafeUDEdgePermu2' . decodeFact numUDE numUDE . unRawCoord
instance (RawEncodable a, RawEncodable b) => RawEncodable (a, b) where
range _ = range ([] :: [a]) * range ([] :: [b])
encode (a, b) = flatCoord (encode a) (encode b)
decode (splitCoord -> (a, b)) = (decode a, decode b)
flatCoord
:: (RawEncodable a, RawEncodable b)
=> RawCoord a -> RawCoord b -> RawCoord (a, b)
flatCoord (RawCoord a) b'@(RawCoord b) = RawCoord (flatIndex (range b') a b)
splitCoord
:: (RawEncodable a, RawEncodable b)
=> RawCoord (a, b) -> (RawCoord a, RawCoord b)
splitCoord (RawCoord ab_) = (a, b)
where
(RawCoord -> a, RawCoord -> b) = ab_ `divMod` range b
type Endo a = a -> a
endoVector :: RawEncodable a => Endo a -> RawMove a
endoVector f
= RawMove . S.generate (range f) $
under RawCoord (encode . f . decode)
cubeActionToEndo :: CubeAction a => Cube -> Endo a
cubeActionToEndo c = (`cubeAction` c)
moveTable :: (CubeAction a, RawEncodable a) => Cube -> RawMove a
moveTable = endoVector . cubeActionToEndo
symToEndo :: (Cube -> a -> a) -> Cube -> Endo a
symToEndo = id
symTable :: RawEncodable a => (Cube -> a -> a) -> Cube -> RawMove a
symTable conj = endoVector . symToEndo conj
checkCoord :: RawEncodable a => proxy a -> Bool
checkCoord proxy
= all (\(RawCoord -> k) -> encode (decode k `asProxyTypeOf` proxy) == k)
[0 .. range proxy 1]
randomRawCoord :: forall a m. (MonadRandom m, RawEncodable a) => m (RawCoord a)
randomRawCoord = RawCoord <$> getRandomR (0, range ([] :: [a]) 1)
encodeBase :: Int -> [Int] -> Int
encodeBase b = foldr1 (\x y -> x + b * y)
encodeBaseV :: Int -> Vector Int -> Int
encodeBaseV b = U.foldr1' (\x y -> x + b * y)
decodeBase :: Int -> Int -> Int -> [Int]
decodeBase b len = take len . unfoldr (\x -> Just (x `modDiv` b))
where modDiv = ((.).(.)) (\(x,y) -> (y,x)) divMod
encodeFact :: Int -> [Int] -> Int
encodeFact n [] = 0
encodeFact n (y : ys) = y + n * encodeFact (n 1) ys'
where
ys' = case elemIndex (n 1) ys of
Nothing -> ys
Just k -> subs k y ys
decodeFact :: Int -> Int -> Int -> [Int]
decodeFact n 0 _ = []
decodeFact n k x = y : ys
where
(q, y) = x `divMod` n
ys' = decodeFact (n 1) (k 1) q
ys = case elemIndex y ys' of
Nothing -> ys'
Just k -> subs k (n 1) ys'
cSum :: Int -> Int -> Int
cSum = \k z -> v U.! (k * n + z)
where
cSum' k z = sum [y `choose` k | y <- [k .. z1]]
v = U.generate (n * m) (uncurry cSum' . (`divMod` n))
m = cSum_mMax
n = cSum_nMax
cSum_mMax, cSum_nMax :: Int
cSum_mMax = 4
cSum_nMax = 16
encodeCV :: Vector Int -> Int
encodeCV = U.sum . U.imap cSum
decodeCV :: Int -> Int -> Vector Int
decodeCV k x = U.create (do
v <- MU.new k
let
decode' (1) _ _ = return ()
decode' k z x
| s <= x = MU.write v k z >> decode' (k1) (z1) (xs)
| otherwise = decode' k (z1) x
where
s = cSum k z
decode' (k1) (cSum_nMax1) x
return v)