{-|
	Defines a 3-layered Vector and relative utilties.
-}
module Game.TicTacToe3D.Vector3 where
	import Data.List (unfoldr)
	import Data.Vector (Vector)
	import qualified Data.Vector as V

	{-|
		Represents a 3-layered structure.
	-}
	type Dim3 a b = a (a (a b))

	{-|
		Represents a 3-layered vector.
	-}
	type V3 a = Dim3 Vector a

	{-|
		Represents an index of a 3-layered vector.
	-}
	type I3 = (Int, Int, Int)

	{-|
		>>> base 2 10
		[0, 1, 0, 1]
	-}
	base :: Int -> Int -> [Int]
	base i n = unfoldr f n ++ repeat 0 where
		f b = if b /= 0 then Just (pair b i) else Nothing where
			pair n i = (n `mod` i, n `div` i)

	{-|
		>>> i3 1
		(1, 0, 0)
		
		>>> i3 26
		(1, 1, 1)
	-}
	i3 :: Int -> I3
	i3 i = t $ base 3 i where t (x:y:z:_) = (x, y, z)

	{-|
		Retrieves the specified location's element.
	-}
	(!) :: V3 a -> I3 -> a
	v ! (x, y, z) = v V.! x V.! y V.! z

	{-|
		Replaces the specified location's element
		and retrieves the updated vector.
	-}
	(//) ::V3 a -> (I3, a) -> V3 a
	v // ((x, y, z), n) = (setf x $ setf y $ setv z n) v where
		setf i f y = setv i (f $ y V.! i) y
		setv i m y = y V.// [(i, m)]

	{-|
		Initializes a vector with the given values.
	-}
	init :: Int -> (I3 -> a) -> V3 a
	init i f =
		V.generate i $ \x ->
			V.generate i $ \y ->
				V.generate i $ \z ->
					f (x, y, z)