<h2 id="intro">Intro</h2>
<p>In the two previous episodes we built a weighted list and used that to build markov chains. This time we’re going to use them to generate some names based on examples. I’m skipping over a lot of uninteresting code in this episode, concentrating only the parts that deal with names.</p>
<h2 id="idea">Idea</h2>
<p>Person in game might hear scurrying sounds inside walls of their quarters. Then they have option of getting a cat, taming a rat or letting someone else deal with the problem. Depending on their choice, they might end up with a cat or a rat, that of course needs a name. Game offers 3 different options of names that haven’t been used before and person can always opt for completely random one.</p>
<h2 id="config">Config</h2>
<p>While we’re not going to dig very deep into making configurations for markov chains, we can have look at the overall process.</p>
<p>We have list of names to serve as examples and three functions, which implementation I won’t delve into:</p>
<ul>
<li><code>start</code> for adding starting element</li>
<li><code>links</code> for recording link between two elements</li>
<li><code>end</code> adds ending element</li>
</ul>
<p><code>addName</code> function is used to add single name into config:</p>
<pre><code>addName :: Int -&gt; Text -&gt; Config Text -&gt; Config Text
addName n s config =
    links pairs $
            end elements $
            start elements config
    where
        elements = chunksOf n s
        pairs = zip elements (safeTail elements)</code></pre>
<p>First <code>s</code> (name) is split into strings of length <code>n</code>. These <code>elements</code> are then combined into pairs, where consecutive elements form a pair. Final step is to add start and ending elements into config, followed by links between elements of pairs.</p>
<p>We can then fold a list of examples into config:</p>
<pre><code>nameConfig :: [Text] -&gt; Int -&gt; Config Text
nameConfig xs n =
    foldr (addName n) emptyConfig xs</code></pre>
<p>This starts with <code>emptyConfig</code> and calls <code>addName</code> repeatedly until all elements of list containing examples have been processed.</p>
<h2 id="implementation">Implementation</h2>
<p>Now that we have configuration, we can start generating names. As usual, I like to keep things specific and generate <code>PetName</code> instead of just <code>Text</code>. I happened to have list of ancient greek names at hand, so I used that. Later on we’ll have to add more cultures, like Romans, Parthians, Persians, Germans, Phoenicians and so on.</p>
<p>General implementation of generating infinite list of strings of specific kind is shown below:</p>
<pre><code>names :: (RandomGen g, Eq b) =&gt; (Text -&gt; b) -&gt; Config Text -&gt; g -&gt; [b]
names t config g =
    nub $ (t . toTitle . concat) &lt;$&gt; chains config g</code></pre>
<p>It’s easier to read if you start from right. <code>chains config g</code> generates infinite list of markov chains with given configuration. Next we create a new function <code>(t . toTitle . concat)</code>, which uses <code>concat</code> to combine list of <code>Text</code> into single <code>Text</code>, <code>toTitle</code> to capitalize is correctly and <code>t</code> to transform it to something (<code>PetName</code> in our case). <code>&lt;$&gt;</code> is then used to apply this function to each element of our infinite list. Finally <code>nub</code> is used to remove duplicate entries.</p>
<p>With <code>names</code> we can then define <code>petNames</code>:</p>
<pre><code>petNames :: (RandomGen g) =&gt; g -&gt; [PetName]
petNames =
    names MkPetName greekNameConfig</code></pre>
<p><code>MkPetName</code> is value constructor that turns <code>Text</code> into <code>PetName</code> (this is <code>t</code> used by <code>names</code> function).</p>
<h2 id="pets">Pets</h2>
<p>Pets are currently very much work in progress. They have few attributes and there can be two different kinds of pets:</p>
<pre><code>Pet json
    name PetName
    type PetType
    dateOfBirth StarDate
    dateOfDeath StarDate Maybe
    ownerId PersonId
    deriving Show Read Eq</code></pre>
<pre><code>data PetType
    = Cat
    | Rat
    deriving (Show, Read, Eq, Ord, Enum, Bounded)</code></pre>
<p>The actual beef is <code>namingPetEvent</code> function. When applied with <code>Entity Person</code>, <code>Entity Pet</code> and <code>StarDate</code>, it will create <code>News</code> that can be saved into database and later on showed to player. While the code is shown below, I’m not going to go over it line by line:</p>
<pre><code>namingPetEvent :: (PersistQueryRead backend, MonadIO m,
    BaseBackend backend ~ SqlBackend) =&gt;
    Entity Person -&gt; Entity Pet -&gt; StarDate -&gt; ReaderT backend m News
namingPetEvent personE petE date = do
    pets &lt;- selectList [ PetOwnerId ==. (entityKey personE)
                       , PetDateOfDeath ==. Nothing
                       ] []
    let names = (petName . entityVal) &lt;$&gt; pets
    g &lt;- liftIO getStdGen
    let availableNames = take 3 $ filter (\x -&gt; not (x `elem` names)) $ petNames g
    let content = NamingPet (NamingPetEvent { namingPetEventPersonId = entityKey personE
                                            , namingPetEventPetId = entityKey petE
                                            , namingPetEventPetType = (petType . entityVal) petE
                                            , namingPetEventDate = date
                                            , namingPetNameOptions = availableNames
                                            })
                            [] Nothing
    return $ mkPersonalSpecialNews date (entityKey personE) content</code></pre>
<p>General idea is to use <code>selectList</code> to load living pets of given person and then extract their names. With random generator <code>g</code>, we create a infinite list of <code>PetName</code>s, remove already used names from it and take 3 first ones. These names are then used to create <code>NamingPetEvent</code>.</p>
<h2 id="in-closing">In closing</h2>
<p>Names are probably one of the most common applications of markov chains in games. Same technique can be used to generate nonsense books and articles that look realistic on a glance.</p>
<p>Questions, comments and feedback is welcomed, best way to reach is email or in fediverse where I’m <code>Tuula@mastodon.social</code>. Or even better, record your own episode for Hacker Public Radio.</p>
<p>ad astra!</p>
