Showing posts with label random. Show all posts
Showing posts with label random. Show all posts

Wednesday, 14 May 2025

[Dev Diary] The Tool Jam 5 - Creating a Random Lore Generator + Fun with Markov Chains

It's about time I took part in a game jam but this one really intrigued me. I think it's because I tend to work on the developer tools these days rather than the game itself; I find it more interesting. Therefore, this game jam caught my eye.

I've always been fascinated with random generators. The kind from the early internet days like Seventh Sanctum. I've long wondered how these worked and I've created some simple generators using the basic idea over on my playground using HTML, CSS and *shudder* JavaScript. I thought this would be the perfect jam though to do some research and really dig into how random generators used to be made convincingly and do it using my favourite C++ and SFML combo.

Warning, this is a long post.

Research - Ask ChatGPT
First off, I had a great conversation with ChatGPT about how those sorts of generators were made and what kind of algorithms they used. It started off explaining 3 ways to implement my game jam idea:

Grammar-based using rules and templates
Basically recursive string placement and you supply a whole load of word types.
The [adjective] [noun] of [proper-noun or abstract-concept]

Mad-libs approach
A more basic version of the grammar based approach, where different types of sentences are supplied.
Long ago, in the time of the #adjective# #noun#, the #faction# waged war against the #enemy#

Layered Abstraction
Basically structured nonsense. Here, the word types are already built up from other approaches to create something that sounds more AI generated.
[Proper Noun] was last wielded by the [Faction], a cult that believes [Purpose].

I found this really interesting, especially as the word types like [adjective] and [Purpose] could easily equate to an enum. I could create a list of enum word types, store everything in text documents and then "build" sentences from these word types. Add in some logic using rules and templates, like adjectives must always be before a noun, and I could quickly create something quite random.

Markov Chains
I then asked if all this data was really just stored in text files and it said yes, but ChatGPT always says yes. But in its explanation it started talking about Markov Chains. This is the kind of computer science mumbo jumbo I was hoping to get from GPT. I went off and researched Markov Chains and it turns out they are basically a way to generate sequences of stuff. You seed them, and the next item in the sequence is based off the item before it but they don't have full context over the entire sequence. Kind of like ChatGPT itself. 

Markov Chains are statistical mimicry. They have no concept of grammar templates or meaning. In essence you could say they are the spiritual ancestor of LLM's. 

Armed with this knowledge, I then started wondering if you could give Markov Chains more context. ChatGPT informed me that my best bet would be to implement Conditional Markov Chains mixed with Probabilistic Grammar and Weights. This involves different Markov models like religiousMarkov or plantMarkov mixed with assigned weighted probabilities. So if a weapon name is "Cursed", you're more likely to get a backstory involving betrayal or a wielder with a tragic fate over a backstory where the goddess bestowed it due to kindness.

V1 - Basic C++ Lore Generator
Armed with some fun research, I then went off and made a basic console version of what I wanted. To start off I made a simple enum of word types, created a map of word types to strings. Then 'built' sentences using those word types and created a random sentence by filling in the word type with one of those strings:


All good stuff. 

V2 - Basic C++ Lore Generator
I expanded slightly on this version and moved over to using text files so I could easily get GPT to generate a load of words or phrases for me that I could add to the files. I added a way to load those in to be used instead of hardcoding it in main.


V3 - Creating a Basic Markov Chain Model
This is where shit got fun. With the help of ChatGPT, I got a very simple Markov generator going that takes in a text file of words and then "trains" itself on that data set. Then, in the place where it gets a random word from the "word pool" of that specific type, it would request a word from the generator instead. These words were actually plausible and looked 'right'.

You can see here my full list of names I created and the name the generator created. I also cleaned up the code at this point and moved everything out into seperate classes as it was getting messy in main and I hate having global variables and static classes just hanging around.

At this point, it kind of felt like I had created baby's first LLM and I was very happy. It then occurred to me that I could then chain the markov chains together to create the initial lore template itself, essentially creating a fully generative 'lore engine' so to speak.

I put this to ChatGPT and it started talking about word tokens instead of using individual characters and it was like a lightbulb went off in my head. ChatGPT itself works on tokens instead of characters (you've probably seen this from the infamous 'how many r's are there in strawberry'). I would now be recreating this, albeit in a very basic and crude manner.


V4 - Markov Based Word Chain Generator

First, I turned my initial Markov generator class into a pure virtual class, and created MarkovWordGenerator which inherited from it. The Markov Word Chain generator still needs an order and train/generate functions but they need to be slightly different. This would then allow me to have Word generators and Sentence Generators.

This did work...somewhat. The markov model was too accurate given my limited data set I was feeding it. This meant that it always returned the exact sentence as found in the training text file. Giving it an order of 1, gave the model less context but the sentences produced lacked context and so the sentences were jumbled and didn't make sense (in English anyway).

I also wanted more control over the types of sentences created. So I ended up making a text file that had sentence templates for item lore.

I then "trained" a markov model on a large text file that ChatGPT produced for me of item lore sentences. Then created functions that allow the user to just call "generateItemLore()", and it goes off, chooses a random item lore template, then replaces the bracketed sections with something from a word pool or in the case of {{sentence}}, replaces it with a markov-generated sentence.

I then added a way to have the user input a name for the item or generate one randomly:
Creating a random Lore Generator using pure C++ and Markov Chains

Even with a larger "data set", I still have to set the model to the lowest setting (1). The sentences make more sense than previously but can still seem 'off'. It'll do though.


V5 - Creating the UI

Now with a simple item lore generator pretty much created, I wanted to move away from the console for a bit. I kept them as separate projects so I could continue working in the console one to prove out ideas then move it over to the UI version.

So I created a window, added a nice background image and some background music, then I got to creating the text boxes and remembered that SFML and text is not great. This is a program that is mainly reliant on entering text and displaying text. So I switched out SFML for FLTK. FLTK is a fantastic little library that is way more suited for this kind of task than SFML. The only issue is that I have my own wrapper around the library and I haven't turned that into a library yet so I had to pull every single file across.

Honestly, the thought of having to create a scrolling text box class in SFML just had me noping out within 5 seconds. FLTK was made for this kind of program.

The weekend then happened. Also it was sunny, which is rare for england, so I forgot about it until an hour before the jam closed. I considered not submitting but for once I was seeing a jam through. And I managed to submit with 11 minutes left to go:


Overall Thoughts
This was a lot of fun. Especially as I've come to understand how LLMs were initially created. There's is so much power in having a "locally trained" generator though. I'd be interested in making this do other things like generate documentation on code bases. But for the moment, I'd like to add a proper UI using a library and then expand it to creating lore for places and people. Also, allow more modding capabilities.


Monday, 22 March 2021

Misc // New PC!


*This is a bit of a long one; I apologise. tldr; New pc with a 3090. Runs perfectly.

So I originally had no plans to upgrade my computer. My boy Kyoya (named after Kyoya Ootori from Ouran Highschool Host Club) was getting dated but still ran Visual Studio and could play most games on high settings with temperatures reaching around 70/75. He has an i7-4790k (base 4ghz) with 16gb DDR3 1600mhz ram and a GTX 980. I bought him back in September 2015 and up till then, he was the beefiest pc I have ever owned. He cost a whopping £1700 and was a pre-built from HP. 

However, in January, Scan had a shipment of Nvidia 3090 FEs and so I impulse bought one because it was in stock. It would not fit in Kyoya's case due to the drive cage and optical drives but also, he has no ventilation (other than exhaust) and pretty much relies on negative pressure. Also, it would've been severely bottlenecked by the 4790k. And so began the hunt for pc parts in a time where there are no pc parts.

I knew immediately I wanted an AMD 5950x but at this point I'm not sure they exist so I settled for the 3950x. I also wanted 128gb of ram but that also didn't exist so I had to settle for 64 (oh no). I did get the motherboard I wanted and the Noctua Chromax Black NH-D15 but failed to research properly and that fan actually blocks the first pcie lane on the Crosshair VIII Formula. I really wanted an air cooler because I think they look cool (pun intended) but ended up with a Corsair Hydro H150i all in one. I've never had an aio before but it's growing on me.


I spent a ridiculous amount of time on the cable management, even though you can't really see it due to the dark tinted glass; I love that you can just see the little bits of rgb in the case from the cooler, gpu and motherboard display.




The new pc is called Archer (after Jonathan Archer from Star Trek Enterprise) and here he is with his little big brother Kyoya who has now become my "minimum specs" testing pc. Side note: This is not the final setup; I was transferring files.

Parts list:
CPU: AMD Ryzen 9 3950X 3.5 GHz 16-Core Processor
CPU Cooler: Corsair iCUE H150i RGB PRO XT 75 CFM Liquid CPU Cooler
Motherboard: Asus ROG Crosshair VIII Formula ATX AM4
Memory: Corsair Vengeance LPX 64 GB (4 x 16 GB) DDR4-3600 CL18
Storage: x2 Samsung 970 Evo 1 TB M.2-2280 NVME Solid State Drive
Storage: Samsung 870 QVO 4 TB 2.5" Solid State Drive
Storage: Seagate BarraCuda Pro 10 TB 3.5" 7200RPM Internal Hard Drive
Video Card: NVIDIA GeForce RTX 3090 24 GB Founders Edition
Case: Fractal Design Define 7 XL Dark ATX Full Tower Case
Power Supply: Fractal Design Ion+ 860 W 80+ Platinum Certified Fully Modular ATX Power Supply 
Case Fans: x3 Noctua Industrial 3000rpm 140mm 
OS: Microsoft Windows 10 Home OEM 64-bit

After some research, I decided to set the ram to a speed of 3200mhz as the 3950x can only work with 3600 when overclocking and I want nothing to do with that; I need this pc to be as stable as possible so OC has been disabled. The ram was running at 2144 when first booted and that speed was painful. My ddr3 1600mhz felt lightning fast compared to it.

This computer was built specifically to handle Unreal Engine 4, Blender and Creative Cloud workloads and boy does it deliver. Eventually I may upgrade to 128gb ram but I really don't need it right now; it runs perfectly with 2 instances of Unreal open, several chrome tabs, PhotoShop and Blender. 

For benchmarks, I tested Unreal Engine 4, Blender and two of my most demanding games; House Flipper and Planet Coaster.

In Blender, my gtx 980 took 2 minutes 14 seconds to render this final doughnut scene using CUDA. The 3090 did it in 9 seconds with the new optix renderer and 14 seconds using CUDA. Every person I talk to has raised their eyebrows at me for spending £1400 on a graphics card but it's sped up my workflow by 1000%. I have zero regrets.

When it comes to Unreal Engine, my i7-4790k usually took 25 minutes to compile 5000 shaders. The 3950x took 2 minutes. Out of the bag UE4 will try its best to utilise all of the cores you have and when I opened up one of my biggest projects, the editor hung for a good 5 minutes but task manager showed it was using every core to compile shaders. Moving round the scene is buttery smooth and landscape editing is no longer a chore.

Photoshop can still be a bit jittery when doing certain things and I've even got it installed on one of the NVME's but Adobe applications will happily take up all your ram and demand more so I'm not too bothered. I am now running CC 2021 now though which is nice. I stayed at 2017 on Kyoya as he was struggling.

I'm impressed with the CPU cooler; even at 100% load the fans stay around 700-1000rpm with the temperature reaching highs of 42 degrees. The highest I saw it was 49 whilst playing Planet Coaster. That game actually turned out to be a great stress tester as one of my worlds has thousands of items. I stopped playing it on Kyoya a year ago because he just couldn't handle all the objects anymore. The 3090 reached up to 70 but I've noticed that it won't even turn the fan on under 60 degrees. It seems Nvidia have made their new cards run happily at temps of 60/70 degrees.


Playing House Flipper on max settings for the first time in 6 months was glorious though. The 980 was getting dangerously close to 90 degrees with all the latest additions and amount of items you can add (also I don't think this game has been optimised well...if at all). I had to limit the game to 60 fps and keep everything on medium. The 3090 happily sits at 60 degrees with max settings and 120fps. I can finally stick as much shit as I want in houses and not worry about my gpu.

On scenes like this, the 980 really struggled on max settings


My most played game is Minecraft but that can pretty much run on a potato. I did turn RTX on and the 3090 didn't even care.


A quick note on some of the other items:

Noctua Industrial case fans -  When these are running at 3000rpm you'll know about it. They sound like jet engines taking off. I keep them around 400 rpm, ramping up to 1500 when the cpu is at max load but even the lower speeds are more than enough to keep the case cool. Plus they look beautiful.

Fractal Design Define 7 XL - I don't know what made me buy the XL. The standard Define 7 would've been more than enough but it was a joy to build in. It's absolutely huge but looks fantastic. Airflow is great, storage solutions are insane (can hold up 20 drives) and it has a fan control center as you can fit an absurd amount of fans in it.

Fractal Ion 860w PSU - I really wanted at least a 1000 watt psu after watching several videos on the 3090 just to be on the safe side but there were no power supplies with a platinum rating going at the time I was buying. I eventually settled on this one as it was the highest platinum wattage I could find and Fractal offers a 10 year warranty. I'm glad I did. The cables are smart and easy to work with and it runs completely silent. I've had no problems with it and seen the 3090 spike several times with no power outages.

Asus Crosshair VIII Formula - Completely unnecessary but it's beautiful. I love the little oled display; it's well worth the price jump from the Crosshair VIII Hero. I like to have it display the CPU temp but it can display custom gifs. Very easy to build on and the IO shield was already installed. I am extremely happy with this purchase. One little thing; I've been using the same speakers from Philips for 15 years and the sound difference from this PC is astonishing. 

Overall; I'm very happy. Even more so for building it myself (it was my first time!) I'm still keeping an eye out for a 5950x but Archer has already exceeded my expectations for a personal dev PC so I probably won't.