-- | A game requires the engine provided by the library, perhaps customized,
-- and game content, defined completely afresh for the particular game.
-- The possible kinds of content are fixed in the library and all defined
-- within the library source code directory. On the other hand, game content,
-- is defined in the directory hosting the particular game definition.
--
-- Content of a given kind is just a list of content items.
-- After the list is verified and the data preprocessed, it's held
-- in the @ContentData@ datatype.
module Game.LambdaHack.Definition.ContentData
  ( ContentData
  , validateRarity, validFreqs
  , emptyContentData, makeContentData
  , okind, omemberGroup, oexistsGroup, oisSingletonGroup, ouniqGroup, opick
  , ofoldlWithKey', ofoldlGroup', omapVector, oimapVector, olength
  ) where

import Prelude ()

import Game.LambdaHack.Core.Prelude

import           Data.Function
import qualified Data.Map.Strict as M
import qualified Data.Set as S
import qualified Data.Text as T
import qualified Data.Vector as V

import Game.LambdaHack.Core.Frequency
import Game.LambdaHack.Core.Random
import Game.LambdaHack.Definition.Defs
import Game.LambdaHack.Definition.DefsInternal

-- | Verified and preprocessed content data of a particular kind.
data ContentData c = ContentData
  { ContentData c -> Vector c
contentVector :: V.Vector c
  , ContentData c -> Map (GroupName c) [(Int, (ContentId c, c))]
groupFreq     :: M.Map (GroupName c) [(Int, (ContentId c, c))]
  }

maxContentId :: ContentId k
maxContentId :: ContentId k
maxContentId = Word16 -> ContentId k
forall c. Word16 -> ContentId c
toContentId Word16
forall a. Bounded a => a
maxBound

validateRarity :: Rarity -> [Text]
validateRarity :: Rarity -> [Text]
validateRarity Rarity
rarity =
  -- @SortOn@ less efficient here, because function cheap.
  let sortedRarity :: Rarity
sortedRarity = ((Double, Int) -> (Double, Int) -> Ordering) -> Rarity -> Rarity
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (((Double, Int) -> Double)
-> (Double, Int) -> (Double, Int) -> Ordering
forall a b. Ord a => (b -> a) -> b -> b -> Ordering
comparing (Double, Int) -> Double
forall a b. (a, b) -> a
fst) Rarity
rarity
  in [ Text
"rarity not sorted" | Rarity
sortedRarity Rarity -> Rarity -> Bool
forall a. Eq a => a -> a -> Bool
/= Rarity
rarity ]
     [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ [ Text
"rarity depth thresholds not unique"
        | (Rarity -> (Double, Int)) -> [Rarity] -> Rarity
forall a b. (a -> b) -> [a] -> [b]
map Rarity -> (Double, Int)
forall a. [a] -> a
head (((Double, Int) -> (Double, Int) -> Bool) -> Rarity -> [Rarity]
forall a. (a -> a -> Bool) -> [a] -> [[a]]
groupBy (Double -> Double -> Bool
forall a. Eq a => a -> a -> Bool
(==) (Double -> Double -> Bool)
-> ((Double, Int) -> Double)
-> (Double, Int)
-> (Double, Int)
-> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` (Double, Int) -> Double
forall a b. (a, b) -> a
fst) Rarity
sortedRarity) Rarity -> Rarity -> Bool
forall a. Eq a => a -> a -> Bool
/= Rarity
sortedRarity ]
     [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ [ Text
"rarity depth not positive"
        | case Rarity
sortedRarity of
            ((Double
lowest, Int
_) : Rarity
_) -> Double
lowest Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
<= Double
0
            Rarity
_ -> Bool
False ]

validFreqs :: Freqs a -> Bool
validFreqs :: Freqs a -> Bool
validFreqs Freqs a
freqs =
  -- Greater or equal to 0 permitted, e.g., to cover embedded template UNKNOWN
  -- items not yet identified by the client, but triggerable nevertheless.
  ((GroupName a, Int) -> Bool) -> Freqs a -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all ((Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0) (Int -> Bool)
-> ((GroupName a, Int) -> Int) -> (GroupName a, Int) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (GroupName a, Int) -> Int
forall a b. (a, b) -> b
snd) Freqs a
freqs
  Bool -> Bool -> Bool
&& let groups :: [GroupName a]
groups = [GroupName a] -> [GroupName a]
forall a. Ord a => [a] -> [a]
sort ([GroupName a] -> [GroupName a]) -> [GroupName a] -> [GroupName a]
forall a b. (a -> b) -> a -> b
$ ((GroupName a, Int) -> GroupName a) -> Freqs a -> [GroupName a]
forall a b. (a -> b) -> [a] -> [b]
map (GroupName a, Int) -> GroupName a
forall a b. (a, b) -> a
fst Freqs a
freqs
         tailOfGroups :: [GroupName a]
tailOfGroups = if [GroupName a] -> Bool
forall a. [a] -> Bool
null [GroupName a]
groups then [GroupName a]
groups else [GroupName a] -> [GroupName a]
forall a. [a] -> [a]
tail [GroupName a]
groups
     in ((GroupName a, GroupName a) -> Bool)
-> [(GroupName a, GroupName a)] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all ((GroupName a -> GroupName a -> Bool)
-> (GroupName a, GroupName a) -> Bool
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry GroupName a -> GroupName a -> Bool
forall a. Eq a => a -> a -> Bool
(/=)) ([(GroupName a, GroupName a)] -> Bool)
-> [(GroupName a, GroupName a)] -> Bool
forall a b. (a -> b) -> a -> b
$ [GroupName a] -> [GroupName a] -> [(GroupName a, GroupName a)]
forall a b. [a] -> [b] -> [(a, b)]
zip [GroupName a]
groups [GroupName a]
tailOfGroups

emptyContentData :: ContentData a
emptyContentData :: ContentData a
emptyContentData = Vector a
-> Map (GroupName a) [(Int, (ContentId a, a))] -> ContentData a
forall c.
Vector c
-> Map (GroupName c) [(Int, (ContentId c, c))] -> ContentData c
ContentData Vector a
forall a. Vector a
V.empty Map (GroupName a) [(Int, (ContentId a, a))]
forall k a. Map k a
M.empty

makeContentData :: Show c
                => String
                -> (c -> Text)
                     -- ^ name of the content itme, used for validation
                -> (c -> Freqs c)
                     -- ^ frequency in groups, for validation and preprocessing
                -> (c -> [Text])
                     -- ^ validate a content item and list all offences
                -> ([c] -> ContentData c -> [Text])
                     -- ^ validate the whole defined content of this type
                     -- and list all offence
                -> [c]  -- ^ all content of this type
                -> [GroupName c]  -- ^ singleton group names for this content
                -> [GroupName c]  -- ^ remaining group names for this content
                -> ContentData c
{-# INLINE makeContentData #-}
makeContentData :: String
-> (c -> Text)
-> (c -> Freqs c)
-> (c -> [Text])
-> ([c] -> ContentData c -> [Text])
-> [c]
-> [GroupName c]
-> [GroupName c]
-> ContentData c
makeContentData String
contentName c -> Text
getName c -> Freqs c
getFreq c -> [Text]
validateSingle [c] -> ContentData c -> [Text]
validateAll
                [c]
content [GroupName c]
groupNamesSingleton [GroupName c]
groupNames =
  -- The @force@ is needed for @GHC.Compact@.
  let contentVector :: Vector c
contentVector = Vector c -> Vector c
forall a. Vector a -> Vector a
V.force (Vector c -> Vector c) -> Vector c -> Vector c
forall a b. (a -> b) -> a -> b
$ [c] -> Vector c
forall a. [a] -> Vector a
V.fromList [c]
content
      groupFreq :: Map (GroupName c) [(Int, (ContentId c, c))]
groupFreq =
        let tuples :: [(GroupName c, (Int, (ContentId c, c)))]
tuples = [ (GroupName c
cgroup, (Int
n, (ContentId c
i, c
k)))
                     | (ContentId c
i, c
k) <- [ContentId c] -> [c] -> [(ContentId c, c)]
forall a b. [a] -> [b] -> [(a, b)]
zip ((Word16 -> ContentId c) -> [Word16] -> [ContentId c]
forall a b. (a -> b) -> [a] -> [b]
map Word16 -> ContentId c
forall c. Word16 -> ContentId c
toContentId [Word16
0..]) [c]
content
                     , (GroupName c
cgroup, Int
n) <- c -> Freqs c
getFreq c
k
                     , Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0 ]
            f :: Map k [a] -> (k, a) -> Map k [a]
f !Map k [a]
m (!k
cgroup, !a
nik) = ([a] -> [a] -> [a]) -> k -> [a] -> Map k [a] -> Map k [a]
forall k a. Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a
M.insertWith [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
(++) k
cgroup [a
nik] Map k [a]
m
        in (Map (GroupName c) [(Int, (ContentId c, c))]
 -> (GroupName c, (Int, (ContentId c, c)))
 -> Map (GroupName c) [(Int, (ContentId c, c))])
-> Map (GroupName c) [(Int, (ContentId c, c))]
-> [(GroupName c, (Int, (ContentId c, c)))]
-> Map (GroupName c) [(Int, (ContentId c, c))]
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' Map (GroupName c) [(Int, (ContentId c, c))]
-> (GroupName c, (Int, (ContentId c, c)))
-> Map (GroupName c) [(Int, (ContentId c, c))]
forall k a. Ord k => Map k [a] -> (k, a) -> Map k [a]
f Map (GroupName c) [(Int, (ContentId c, c))]
forall k a. Map k a
M.empty [(GroupName c, (Int, (ContentId c, c)))]
tuples
      contentData :: ContentData c
contentData = ContentData :: forall c.
Vector c
-> Map (GroupName c) [(Int, (ContentId c, c))] -> ContentData c
ContentData {Map (GroupName c) [(Int, (ContentId c, c))]
Vector c
groupFreq :: Map (GroupName c) [(Int, (ContentId c, c))]
contentVector :: Vector c
groupFreq :: Map (GroupName c) [(Int, (ContentId c, c))]
contentVector :: Vector c
..}
      singleOffenders :: [([Text], c)]
singleOffenders = [ ([Text]
offences, c
a)
                        | c
a <- [c]
content
                        , let offences :: [Text]
offences = c -> [Text]
validateSingle c
a
                                         [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ [Text
"empty name" | Text -> Bool
T.null (c -> Text
getName c
a)]
                        , Bool -> Bool
not ([Text] -> Bool
forall a. [a] -> Bool
null [Text]
offences) ]
      allOffences :: [Text]
allOffences = [c] -> ContentData c -> [Text]
validateAll [c]
content ContentData c
contentData
      freqsOffenders :: [c]
freqsOffenders = (c -> Bool) -> [c] -> [c]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (c -> Bool) -> c -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Freqs c -> Bool
forall a. Freqs a -> Bool
validFreqs (Freqs c -> Bool) -> (c -> Freqs c) -> c -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. c -> Freqs c
getFreq) [c]
content
      allGroupNamesEmpty :: [GroupName c]
allGroupNamesEmpty = (GroupName c -> Bool) -> [GroupName c] -> [GroupName c]
forall a. (a -> Bool) -> [a] -> [a]
filter (Text -> Bool
T.null (Text -> Bool) -> (GroupName c -> Text) -> GroupName c -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GroupName c -> Text
forall c. GroupName c -> Text
fromGroupName)
                           ([GroupName c] -> [GroupName c]) -> [GroupName c] -> [GroupName c]
forall a b. (a -> b) -> a -> b
$ [GroupName c]
groupNamesSingleton [GroupName c] -> [GroupName c] -> [GroupName c]
forall a. [a] -> [a] -> [a]
++ [GroupName c]
groupNames
      allGroupNamesTooLong :: [GroupName c]
allGroupNamesTooLong = (GroupName c -> Bool) -> [GroupName c] -> [GroupName c]
forall a. (a -> Bool) -> [a] -> [a]
filter ((Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
30) (Int -> Bool) -> (GroupName c -> Int) -> GroupName c -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Int
T.length (Text -> Int) -> (GroupName c -> Text) -> GroupName c -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GroupName c -> Text
forall c. GroupName c -> Text
fromGroupName)
                             ([GroupName c] -> [GroupName c]) -> [GroupName c] -> [GroupName c]
forall a b. (a -> b) -> a -> b
$ [GroupName c]
groupNamesSingleton [GroupName c] -> [GroupName c] -> [GroupName c]
forall a. [a] -> [a] -> [a]
++ [GroupName c]
groupNames
      allGroupNamesSorted :: [GroupName c]
allGroupNamesSorted = [GroupName c] -> [GroupName c]
forall a. Ord a => [a] -> [a]
sort ([GroupName c] -> [GroupName c]) -> [GroupName c] -> [GroupName c]
forall a b. (a -> b) -> a -> b
$ [GroupName c]
groupNamesSingleton [GroupName c] -> [GroupName c] -> [GroupName c]
forall a. [a] -> [a] -> [a]
++ [GroupName c]
groupNames
      allGroupNamesUnique :: [GroupName c]
allGroupNamesUnique = [GroupName c] -> [GroupName c]
forall a. Eq a => [a] -> [a]
nub [GroupName c]
allGroupNamesSorted
      allGroupNamesNonUnique :: [GroupName c]
allGroupNamesNonUnique = [GroupName c]
allGroupNamesSorted [GroupName c] -> [GroupName c] -> [GroupName c]
forall a. Eq a => [a] -> [a] -> [a]
\\ [GroupName c]
allGroupNamesUnique
      missingGroups :: [GroupName c]
missingGroups = (GroupName c -> Bool) -> [GroupName c] -> [GroupName c]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (GroupName c -> Bool) -> GroupName c -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ContentData c -> GroupName c -> Bool
forall a. ContentData a -> GroupName a -> Bool
omemberGroup ContentData c
contentData)
                             ([GroupName c]
groupNamesSingleton [GroupName c] -> [GroupName c] -> [GroupName c]
forall a. [a] -> [a] -> [a]
++ [GroupName c]
groupNames)
      groupsMoreThanOne :: [GroupName c]
groupsMoreThanOne = (GroupName c -> Bool) -> [GroupName c] -> [GroupName c]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (GroupName c -> Bool) -> GroupName c -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ContentData c -> GroupName c -> Bool
forall a. ContentData a -> GroupName a -> Bool
oisSingletonGroup ContentData c
contentData)
                                 [GroupName c]
groupNamesSingleton
      groupsDeclaredSet :: Set (GroupName c)
groupsDeclaredSet = [GroupName c] -> Set (GroupName c)
forall a. Eq a => [a] -> Set a
S.fromAscList [GroupName c]
allGroupNamesUnique
      groupsNotDeclared :: [GroupName c]
groupsNotDeclared = (GroupName c -> Bool) -> [GroupName c] -> [GroupName c]
forall a. (a -> Bool) -> [a] -> [a]
filter (GroupName c -> Set (GroupName c) -> Bool
forall a. Ord a => a -> Set a -> Bool
`S.notMember` Set (GroupName c)
groupsDeclaredSet)
                          ([GroupName c] -> [GroupName c]) -> [GroupName c] -> [GroupName c]
forall a b. (a -> b) -> a -> b
$ Map (GroupName c) [(Int, (ContentId c, c))] -> [GroupName c]
forall k a. Map k a -> [k]
M.keys Map (GroupName c) [(Int, (ContentId c, c))]
groupFreq
  in Bool -> ContentData c -> ContentData c
forall a. (?callStack::CallStack) => Bool -> a -> a
assert ([GroupName c] -> Bool
forall a. [a] -> Bool
null [GroupName c]
allGroupNamesEmpty
             Bool -> (String, [GroupName c]) -> Bool
forall a. Show a => Bool -> a -> Bool
`blame` String
contentName String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": some group names empty"
             String -> [GroupName c] -> (String, [GroupName c])
forall v. String -> v -> (String, v)
`swith` [GroupName c]
allGroupNamesEmpty) (ContentData c -> ContentData c) -> ContentData c -> ContentData c
forall a b. (a -> b) -> a -> b
$
     Bool -> ContentData c -> ContentData c
forall a. (?callStack::CallStack) => Bool -> a -> a
assert ([GroupName c] -> Bool
forall a. [a] -> Bool
null [GroupName c]
allGroupNamesTooLong
             Bool -> (String, [GroupName c]) -> Bool
forall a. Show a => Bool -> a -> Bool
`blame` String
contentName String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": some group names too long"
             String -> [GroupName c] -> (String, [GroupName c])
forall v. String -> v -> (String, v)
`swith` [GroupName c]
allGroupNamesTooLong) (ContentData c -> ContentData c) -> ContentData c -> ContentData c
forall a b. (a -> b) -> a -> b
$
     Bool -> ContentData c -> ContentData c
forall a. (?callStack::CallStack) => Bool -> a -> a
assert ([GroupName c] -> Bool
forall a. [a] -> Bool
null [GroupName c]
allGroupNamesNonUnique
             Bool -> (String, [GroupName c]) -> Bool
forall a. Show a => Bool -> a -> Bool
`blame` String
contentName String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": some group names duplicated"
             String -> [GroupName c] -> (String, [GroupName c])
forall v. String -> v -> (String, v)
`swith` [GroupName c]
allGroupNamesNonUnique) (ContentData c -> ContentData c) -> ContentData c -> ContentData c
forall a b. (a -> b) -> a -> b
$
     Bool -> ContentData c -> ContentData c
forall a. (?callStack::CallStack) => Bool -> a -> a
assert ([GroupName c] -> Bool
forall a. [a] -> Bool
null [GroupName c]
missingGroups
             Bool -> (String, [GroupName c]) -> Bool
forall a. Show a => Bool -> a -> Bool
`blame` String
contentName String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": some group names pertain to no content"
             String -> [GroupName c] -> (String, [GroupName c])
forall v. String -> v -> (String, v)
`swith` [GroupName c]
missingGroups) (ContentData c -> ContentData c) -> ContentData c -> ContentData c
forall a b. (a -> b) -> a -> b
$
     Bool -> ContentData c -> ContentData c
forall a. (?callStack::CallStack) => Bool -> a -> a
assert ([GroupName c] -> Bool
forall a. [a] -> Bool
null [GroupName c]
groupsMoreThanOne
             Bool -> (String, [GroupName c]) -> Bool
forall a. Show a => Bool -> a -> Bool
`blame` String
contentName String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": some group names refer to more than one content, while they shouldn't"
             String -> [GroupName c] -> (String, [GroupName c])
forall v. String -> v -> (String, v)
`swith` [GroupName c]
groupsMoreThanOne) (ContentData c -> ContentData c) -> ContentData c -> ContentData c
forall a b. (a -> b) -> a -> b
$
     Bool -> ContentData c -> ContentData c
forall a. (?callStack::CallStack) => Bool -> a -> a
assert ([GroupName c] -> Bool
forall a. [a] -> Bool
null [GroupName c]
groupsNotDeclared
             Bool -> (String, [GroupName c]) -> Bool
forall a. Show a => Bool -> a -> Bool
`blame` String
contentName String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": some group names are not included in group name lists, neither singleton nor duplicable"
             String -> [GroupName c] -> (String, [GroupName c])
forall v. String -> v -> (String, v)
`swith` [GroupName c]
groupsNotDeclared) (ContentData c -> ContentData c) -> ContentData c -> ContentData c
forall a b. (a -> b) -> a -> b
$
     Bool -> ContentData c -> ContentData c
forall a. (?callStack::CallStack) => Bool -> a -> a
assert ([c] -> Bool
forall a. [a] -> Bool
null [c]
freqsOffenders
             Bool -> (String, [c]) -> Bool
forall a. Show a => Bool -> a -> Bool
`blame` String
contentName String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": some Freqs values not valid"
             String -> [c] -> (String, [c])
forall v. String -> v -> (String, v)
`swith` [c]
freqsOffenders) (ContentData c -> ContentData c) -> ContentData c -> ContentData c
forall a b. (a -> b) -> a -> b
$
     Bool -> ContentData c -> ContentData c
forall a. (?callStack::CallStack) => Bool -> a -> a
assert ([([Text], c)] -> Bool
forall a. [a] -> Bool
null [([Text], c)]
singleOffenders
             Bool -> (String, [([Text], c)]) -> Bool
forall a. Show a => Bool -> a -> Bool
`blame` String
contentName String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": some content items not valid"
             String -> [([Text], c)] -> (String, [([Text], c)])
forall v. String -> v -> (String, v)
`swith` [([Text], c)]
singleOffenders) (ContentData c -> ContentData c) -> ContentData c -> ContentData c
forall a b. (a -> b) -> a -> b
$
     Bool -> ContentData c -> ContentData c
forall a. (?callStack::CallStack) => Bool -> a -> a
assert ([Text] -> Bool
forall a. [a] -> Bool
null [Text]
allOffences
             Bool -> (String, [Text]) -> Bool
forall a. Show a => Bool -> a -> Bool
`blame` String
contentName String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": the content set is not valid"
             String -> [Text] -> (String, [Text])
forall v. String -> v -> (String, v)
`swith` [Text]
allOffences) (ContentData c -> ContentData c) -> ContentData c -> ContentData c
forall a b. (a -> b) -> a -> b
$
     Bool -> ContentData c -> ContentData c
forall a. (?callStack::CallStack) => Bool -> a -> a
assert (Vector c -> Int
forall a. Vector a -> Int
V.length Vector c
contentVector Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= ContentId Any -> Int
forall c. ContentId c -> Int
contentIdIndex ContentId Any
forall k. ContentId k
maxContentId
             Bool -> String -> Bool
forall a. Show a => Bool -> a -> Bool
`blame` String
contentName String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": the content has too many elements")
     ContentData c
contentData

-- | Content element at given id.
okind :: ContentData a -> ContentId a -> a
{-# INLINE okind #-}
okind :: ContentData a -> ContentId a -> a
okind ContentData{Vector a
contentVector :: Vector a
contentVector :: forall c. ContentData c -> Vector c
contentVector} !ContentId a
i = Vector a
contentVector Vector a -> Int -> a
forall a. Vector a -> Int -> a
V.! ContentId a -> Int
forall c. ContentId c -> Int
contentIdIndex ContentId a
i

omemberGroup :: ContentData a -> GroupName a -> Bool
omemberGroup :: ContentData a -> GroupName a -> Bool
omemberGroup ContentData{Map (GroupName a) [(Int, (ContentId a, a))]
groupFreq :: Map (GroupName a) [(Int, (ContentId a, a))]
groupFreq :: forall c.
ContentData c -> Map (GroupName c) [(Int, (ContentId c, c))]
groupFreq} GroupName a
cgroup = GroupName a
cgroup GroupName a -> Map (GroupName a) [(Int, (ContentId a, a))] -> Bool
forall k a. Ord k => k -> Map k a -> Bool
`M.member` Map (GroupName a) [(Int, (ContentId a, a))]
groupFreq

oexistsGroup :: ContentData a -> GroupName a -> Bool
oexistsGroup :: ContentData a -> GroupName a -> Bool
oexistsGroup ContentData{Map (GroupName a) [(Int, (ContentId a, a))]
groupFreq :: Map (GroupName a) [(Int, (ContentId a, a))]
groupFreq :: forall c.
ContentData c -> Map (GroupName c) [(Int, (ContentId c, c))]
groupFreq} GroupName a
cgroup = case GroupName a
-> Map (GroupName a) [(Int, (ContentId a, a))]
-> Maybe [(Int, (ContentId a, a))]
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup GroupName a
cgroup Map (GroupName a) [(Int, (ContentId a, a))]
groupFreq of
  Maybe [(Int, (ContentId a, a))]
Nothing -> Bool
False
  Just [(Int, (ContentId a, a))]
l -> ((Int, (ContentId a, a)) -> Bool)
-> [(Int, (ContentId a, a))] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all ((Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0) (Int -> Bool)
-> ((Int, (ContentId a, a)) -> Int)
-> (Int, (ContentId a, a))
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int, (ContentId a, a)) -> Int
forall a b. (a, b) -> a
fst) [(Int, (ContentId a, a))]
l

oisSingletonGroup :: ContentData a -> GroupName a -> Bool
oisSingletonGroup :: ContentData a -> GroupName a -> Bool
oisSingletonGroup ContentData{Map (GroupName a) [(Int, (ContentId a, a))]
groupFreq :: Map (GroupName a) [(Int, (ContentId a, a))]
groupFreq :: forall c.
ContentData c -> Map (GroupName c) [(Int, (ContentId c, c))]
groupFreq} GroupName a
cgroup =
  case GroupName a
-> Map (GroupName a) [(Int, (ContentId a, a))]
-> Maybe [(Int, (ContentId a, a))]
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup GroupName a
cgroup Map (GroupName a) [(Int, (ContentId a, a))]
groupFreq of
    Just [(Int, (ContentId a, a))
_] -> Bool
True
    Maybe [(Int, (ContentId a, a))]
_ -> Bool
False

-- | The id of the unique member of a singleton content group.
ouniqGroup :: Show a => ContentData a -> GroupName a -> ContentId a
ouniqGroup :: ContentData a -> GroupName a -> ContentId a
ouniqGroup ContentData{Map (GroupName a) [(Int, (ContentId a, a))]
groupFreq :: Map (GroupName a) [(Int, (ContentId a, a))]
groupFreq :: forall c.
ContentData c -> Map (GroupName c) [(Int, (ContentId c, c))]
groupFreq} !GroupName a
cgroup =
  let freq :: [(Int, (ContentId a, a))]
freq = let assFail :: [(Int, (ContentId a, a))]
assFail = String -> [(Int, (ContentId a, a))]
forall a. (?callStack::CallStack) => String -> a
error (String -> [(Int, (ContentId a, a))])
-> String -> [(Int, (ContentId a, a))]
forall a b. (a -> b) -> a -> b
$ String
"no unique group"
                                   String
-> (GroupName a, Map (GroupName a) [(Int, (ContentId a, a))])
-> String
forall v. Show v => String -> v -> String
`showFailure` (GroupName a
cgroup, Map (GroupName a) [(Int, (ContentId a, a))]
groupFreq)
             in [(Int, (ContentId a, a))]
-> GroupName a
-> Map (GroupName a) [(Int, (ContentId a, a))]
-> [(Int, (ContentId a, a))]
forall k a. Ord k => a -> k -> Map k a -> a
M.findWithDefault [(Int, (ContentId a, a))]
assFail GroupName a
cgroup Map (GroupName a) [(Int, (ContentId a, a))]
groupFreq
  in case [(Int, (ContentId a, a))]
freq of
    [(Int
n, (ContentId a
i, a
_))] | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0 -> ContentId a
i
    [(Int, (ContentId a, a))]
l -> String -> ContentId a
forall a. (?callStack::CallStack) => String -> a
error (String -> ContentId a) -> String -> ContentId a
forall a b. (a -> b) -> a -> b
$ String
"not unique" String -> (GroupName a, [(Int, (ContentId a, a))]) -> String
forall v. Show v => String -> v -> String
`showFailure` (GroupName a
cgroup, [(Int, (ContentId a, a))]
l)

-- | Pick a random id belonging to a group and satisfying a predicate.
opick :: Show a
      => ContentData a
      -> GroupName a -> (a -> Bool) -> Rnd (Maybe (ContentId a))
opick :: ContentData a
-> GroupName a -> (a -> Bool) -> Rnd (Maybe (ContentId a))
opick ContentData{Map (GroupName a) [(Int, (ContentId a, a))]
groupFreq :: Map (GroupName a) [(Int, (ContentId a, a))]
groupFreq :: forall c.
ContentData c -> Map (GroupName c) [(Int, (ContentId c, c))]
groupFreq} !GroupName a
cgroup !a -> Bool
p =
  case GroupName a
-> Map (GroupName a) [(Int, (ContentId a, a))]
-> Maybe [(Int, (ContentId a, a))]
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup GroupName a
cgroup Map (GroupName a) [(Int, (ContentId a, a))]
groupFreq of
    Just [(Int, (ContentId a, a))]
freqRaw ->
      let freq :: Frequency (ContentId a, a)
freq = Text -> [(Int, (ContentId a, a))] -> Frequency (ContentId a, a)
forall a. Text -> [(Int, a)] -> Frequency a
toFreq Text
"opick" ([(Int, (ContentId a, a))] -> Frequency (ContentId a, a))
-> [(Int, (ContentId a, a))] -> Frequency (ContentId a, a)
forall a b. (a -> b) -> a -> b
$ ((Int, (ContentId a, a)) -> Bool)
-> [(Int, (ContentId a, a))] -> [(Int, (ContentId a, a))]
forall a. (a -> Bool) -> [a] -> [a]
filter (a -> Bool
p (a -> Bool)
-> ((Int, (ContentId a, a)) -> a)
-> (Int, (ContentId a, a))
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ContentId a, a) -> a
forall a b. (a, b) -> b
snd ((ContentId a, a) -> a)
-> ((Int, (ContentId a, a)) -> (ContentId a, a))
-> (Int, (ContentId a, a))
-> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int, (ContentId a, a)) -> (ContentId a, a)
forall a b. (a, b) -> b
snd) [(Int, (ContentId a, a))]
freqRaw
      in if Frequency (ContentId a, a) -> Bool
forall a. Frequency a -> Bool
nullFreq Frequency (ContentId a, a)
freq
         then Maybe (ContentId a) -> Rnd (Maybe (ContentId a))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (ContentId a)
forall a. Maybe a
Nothing
         else ContentId a -> Maybe (ContentId a)
forall a. a -> Maybe a
Just (ContentId a -> Maybe (ContentId a))
-> ((ContentId a, a) -> ContentId a)
-> (ContentId a, a)
-> Maybe (ContentId a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ContentId a, a) -> ContentId a
forall a b. (a, b) -> a
fst ((ContentId a, a) -> Maybe (ContentId a))
-> StateT SMGen Identity (ContentId a, a)
-> Rnd (Maybe (ContentId a))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Frequency (ContentId a, a)
-> StateT SMGen Identity (ContentId a, a)
forall a. Show a => Frequency a -> Rnd a
frequency Frequency (ContentId a, a)
freq
    Maybe [(Int, (ContentId a, a))]
_ -> Maybe (ContentId a) -> Rnd (Maybe (ContentId a))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (ContentId a)
forall a. Maybe a
Nothing

-- | Fold strictly over all content @a@.
ofoldlWithKey' :: ContentData a -> (b -> ContentId a -> a -> b) -> b -> b
ofoldlWithKey' :: ContentData a -> (b -> ContentId a -> a -> b) -> b -> b
ofoldlWithKey' ContentData{Vector a
contentVector :: Vector a
contentVector :: forall c. ContentData c -> Vector c
contentVector} b -> ContentId a -> a -> b
f b
z =
  (b -> Int -> a -> b) -> b -> Vector a -> b
forall a b. (a -> Int -> b -> a) -> a -> Vector b -> a
V.ifoldl' (\ !b
a !Int
i !a
c -> b -> ContentId a -> a -> b
f b
a (Word16 -> ContentId a
forall c. Word16 -> ContentId c
toContentId (Word16 -> ContentId a) -> Word16 -> ContentId a
forall a b. (a -> b) -> a -> b
$ Int -> Word16
forall a. Enum a => Int -> a
toEnum Int
i) a
c) b
z Vector a
contentVector

-- | Fold over the given group only.
ofoldlGroup' :: ContentData a
             -> GroupName a
             -> (b -> Int -> ContentId a -> a -> b) -> b -> b
ofoldlGroup' :: ContentData a
-> GroupName a -> (b -> Int -> ContentId a -> a -> b) -> b -> b
ofoldlGroup' ContentData{Map (GroupName a) [(Int, (ContentId a, a))]
groupFreq :: Map (GroupName a) [(Int, (ContentId a, a))]
groupFreq :: forall c.
ContentData c -> Map (GroupName c) [(Int, (ContentId c, c))]
groupFreq} GroupName a
cgroup b -> Int -> ContentId a -> a -> b
f b
z =
  case GroupName a
-> Map (GroupName a) [(Int, (ContentId a, a))]
-> Maybe [(Int, (ContentId a, a))]
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup GroupName a
cgroup Map (GroupName a) [(Int, (ContentId a, a))]
groupFreq of
    Just [(Int, (ContentId a, a))]
freq -> (b -> (Int, (ContentId a, a)) -> b)
-> b -> [(Int, (ContentId a, a))] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (\ !b
acc (!Int
p, (!ContentId a
i, !a
a)) -> b -> Int -> ContentId a -> a -> b
f b
acc Int
p ContentId a
i a
a) b
z [(Int, (ContentId a, a))]
freq
    Maybe [(Int, (ContentId a, a))]
_ -> String -> b
forall a. (?callStack::CallStack) => String -> a
error (String -> b) -> String -> b
forall a b. (a -> b) -> a -> b
$ String
"no group '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ GroupName a -> String
forall a. Show a => a -> String
show GroupName a
cgroup
                              String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"' among content that has groups "
                              String -> String -> String
forall a. [a] -> [a] -> [a]
++ [GroupName a] -> String
forall a. Show a => a -> String
show (Map (GroupName a) [(Int, (ContentId a, a))] -> [GroupName a]
forall k a. Map k a -> [k]
M.keys Map (GroupName a) [(Int, (ContentId a, a))]
groupFreq)
                 String -> () -> String
forall v. Show v => String -> v -> String
`showFailure` ()

omapVector :: ContentData a -> (a -> b) -> V.Vector b
omapVector :: ContentData a -> (a -> b) -> Vector b
omapVector ContentData a
d a -> b
f = (a -> b) -> Vector a -> Vector b
forall a b. (a -> b) -> Vector a -> Vector b
V.map a -> b
f (Vector a -> Vector b) -> Vector a -> Vector b
forall a b. (a -> b) -> a -> b
$ ContentData a -> Vector a
forall c. ContentData c -> Vector c
contentVector ContentData a
d

oimapVector :: ContentData a -> (ContentId a -> a -> b) -> V.Vector b
oimapVector :: ContentData a -> (ContentId a -> a -> b) -> Vector b
oimapVector ContentData a
d ContentId a -> a -> b
f = (Int -> a -> b) -> Vector a -> Vector b
forall a b. (Int -> a -> b) -> Vector a -> Vector b
V.imap (\Int
i a
a -> ContentId a -> a -> b
f (Word16 -> ContentId a
forall c. Word16 -> ContentId c
toContentId (Word16 -> ContentId a) -> Word16 -> ContentId a
forall a b. (a -> b) -> a -> b
$ Int -> Word16
forall a. Enum a => Int -> a
toEnum Int
i) a
a)
                         (ContentData a -> Vector a
forall c. ContentData c -> Vector c
contentVector ContentData a
d)

-- | Size of content @a@.
olength :: ContentData a -> Int
olength :: ContentData a -> Int
olength ContentData{Vector a
contentVector :: Vector a
contentVector :: forall c. ContentData c -> Vector c
contentVector} = Vector a -> Int
forall a. Vector a -> Int
V.length Vector a
contentVector