Australia/Sydney
BlogNovember 30, 2024

Create a Free Local AI Dungeon Game with Ollama

Fahd Mirza
n

  This video shows how to create a dungeon and dragon game with help of local models with Ollama easily.


Code:


conda create -n ai python=3.10 -y && conda activate ai

mkdir mygame && cd mygame

pip install pydantic==2.8.2 gradio==4.44.1 ollama

system_prompt = f"""
Your job is to help create interesting futuristic worlds that
players would love to explore.
Instructions:
- Only generate in plain text without formatting.
- Use simple clear language without being overly technical.
- You must stay below 3-5 sentences for each description.
"""

world_prompt = f"""
Generate a creative description for a unique futuristic world with an
interesting concept around humans colonizing new planets in a distant galaxy.

Output content in the form:
World Name: <WORLD NAME>
World Description: <WORLD DESCRIPTION>

World Name:"""

import os
import json
from ollama import chat
from ollama import ChatResponse

response: ChatResponse = chat(model='llama3.2',
    messages=[
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": world_prompt}
    ]
)

world_output = response['message']['content']
print(world_output)

world_output = world_output.strip()
world = {
    "name": world_output.split('n')[0].strip()
    .replace('World Name: ', ''),
    "description": 'n'.join(world_output.split('n')[1:])
    .replace('World Description:', '').strip()
}

kingdom_prompt = f"""
Create 3 different colonies for a futuristic world.
For each colony describe the leaders, societal structures, and notable achievements.

Output content in the form:
Colony 1 Name: <COLONY NAME>
Colony 1 Description: <COLONY DESCRIPTION>
Colony 2 Name: <COLONY NAME>
Colony 2 Description: <COLONY DESCRIPTION>
Colony 3 Name: <COLONY NAME>
Colony 3 Description: <COLONY DESCRIPTION>

World Name: {world['name']}
World Description: {world['description']}

Colony 1"""

response: ChatResponse = chat(model='llama3.2',
    messages=[
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": kingdom_prompt}
    ]
)

kingdoms = {}
kingdoms_output = response['message']['content']

for output in kingdoms_output.split('nn'):
  kingdom_name = output.strip().split('n')[0]
    .split('Name: ')[1].strip()
  print(f'Created colony "{kingdom_name}" in {world["name"]}')
  kingdom_description = output.strip().split('n')[1]
    .split('Description: ')[1].strip()
  kingdom = {
      "name": kingdom_name,
      "description": kingdom_description,
      "world": world['name']
  }
  kingdoms[kingdom_name] = kingdom
world['kingdoms'] = kingdoms

print(f'nColony 1 Description:
{kingdom["description"]}')


def get_town_prompt(world, kingdom):
    return f"""
    Create 3 different starports for a futuristic colony and world.
    Describe the region they're in, important facilities,
    and notable history.
   
    Output content in the form:
    Starport 1 Name: <STARPORT NAME>
    Starport 1 Description: <STARPORT DESCRIPTION>
    Starport 2 Name: <STARPORT NAME>
    Starport 2 Description: <STARPORT DESCRIPTION>
    Starport 3 Name: <STARPORT NAME>
    Starport 3 Description: <STARPORT DESCRIPTION>
   
    World Name: {world['name']}
    World Description: {world['description']}
   
    Colony Name: {kingdom['name']}
    Colony Description {kingdom['description']}
   
    Starport 1 Name:"""


def create_towns(world, kingdom):
    print(f'nCreating starports for colony: {kingdom["name"]}...')
    response: ChatResponse = chat(model='llama3.2',
        messages=[
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": get_town_prompt(world, kingdom)}
        ]
    )  
    towns_output = response['message']['content']
   
    towns = {}
    for output in towns_output.split('nn'):
        town_name = output.strip().split('n')[0]
        .split('Name: ')[1].strip()
        print(f'- {town_name} created')
       
        town_description = output.strip().split('n')[1]
        .split('Description: ')[1].strip()
       
        town = {
          "name": town_name,
          "description": town_description,
          "world": world['name'],
          "kingdom": kingdom['name']
        }
        towns[town_name] = town
    kingdom["towns"] = towns
   
for kingdom in kingdoms.values():
    create_towns(world, kingdom)  

town = list(kingdom['towns'].values())[0]
print(f'nStarport 1 Description:
{town["description"]}')

def get_npc_prompt(world, kingdom, town):
    return f"""
    Create 3 different characters based on the world, colony,
    and starport they're in. Describe the character's appearance and
    role, as well as their motivations and challenges.
   
    Output content in the form:
    Character 1 Name: <CHARACTER NAME>
    Character 1 Description: <CHARACTER DESCRIPTION>
    Character 2 Name: <CHARACTER NAME>
    Character 2 Description: <CHARACTER DESCRIPTION>
    Character 3 Name: <CHARACTER NAME>
    Character 3 Description: <CHARACTER DESCRIPTION>
   
    World Name: {world['name']}
    World Description: {world['description']}
   
    Colony Name: {kingdom['name']}
    Colony Description: {kingdom['description']}
   
    Starport Name: {town['name']}
    Starport Description: {town['description']}
   
    Character 1 Name:"""

def create_npcs(world, kingdom, town):
    print(f'nCreating characters for the starport of: {town["name"]}...')
    response: ChatResponse = chat(model='llama3.2',
        messages=[
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": get_npc_prompt(world, kingdom, town)}
        ]
    )
       
    npcs_output = response['message']['content']
    npcs = {}
    for output in npcs_output.split('nn'):
        lines = output.strip().split('n')
        if len(lines) < 2:
            print(f"Warning: skipping invalid NPC output - {output}")
            continue
        npc_name_line = lines[0]
        if "Name: " not in npc_name_line:
            print(f"Warning: skipping invalid NPC output - {output}")
            continue
        npc_name = npc_name_line.split('Name: ')[1].strip()
        npc_description = ""
        for line in lines[1:]:
            if "Description: " in line:
                npc_description = line.split('Description: ')[1].strip()
            elif "Motivations and Challenges: " in line:
                npc_description += "n" + line.split('Motivations and Challenges: ')[1].strip()
        print(f'- "{npc_name}" created')
       
        npc = {
        "name": npc_name,
        "description": npc_description,
        "world": world['name'],
        "kingdom": kingdom['name'],
        "town": town['name']
        }
        npcs[npc_name] = npc
    town["npcs"] = npcs


for kingdom in kingdoms.values():
    for town in kingdom['towns'].values():
        create_npcs(world, kingdom, town)
  # For now we'll only generate npcs for one kingdom
    break

npc = list(town['npcs'].values())[0]

print(f'nNPC 1 in {town["name"]},
{kingdom["name"]}:n{npc["description"]}')
   

def save_world(world, filename):
    with open(filename, 'w') as f:
        json.dump(world, f)

def load_world(filename):
    with open(filename, 'r') as f:
        return json.load(f)

save_world(world, 'MyWorld.json')

import gradio as gr
import os
demo = None #added to allow restart

def start_game(main_loop, share=False):
    # added code to support restart
    global demo
    # If demo is already running, close it first
    if demo is not None:
        demo.close()

    demo = gr.ChatInterface(
        main_loop,
        chatbot=gr.Chatbot(height=250, placeholder="Type 'start game' to begin"),
        textbox=gr.Textbox(placeholder="What do you do next?", container=False, scale=7),
        title="AI RPG",
        # description="Ask Yes Man any question",
        theme="soft",
        examples=["Look around", "Continue the story"],
        cache_examples=False,
        retry_btn="Retry",
        undo_btn="Undo",
        clear_btn="Clear",
                           )
    demo.launch(share=share, server_name="0.0.0.0")

def test_main_loop(message, history):
    return 'Entered Action: ' + message

start_game(test_main_loop)


world = load_world('MyWorld.json')
kingdom = world['kingdoms']['Aurora Isles']
town = kingdom['towns']["Helios Landing"]
character = town['npcs']['Dr. Lyra Flynn']

system_prompt = """You are an AI Game master. Your job is to create a
start to an adventure based on the world, colony, starport, and character
a player is playing as.
Instructions:
You must only use 2-4 sentences
Write in second person. For example: "You are Alex"
Write in present tense. For example "You are standing..."
First describe the character and their background.
Then describe where they start and what they see around them."""
world_info = f"""
World: {world}
Kingdom: {kingdom}
Town: {town}
Your Character: {character}
"""

response: ChatResponse = chat(model='llama3.2',
    messages=[
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": world_info + 'nYour Start:'}
    ]
)

start = response['message']['content']
print(start)
world['start'] = start
save_world(world, 'MyWorld.json')


def run_action(message, history, game_state):
   
    if(message == 'start game'):
        return game_state['start']

    system_prompt = """You are an AI Game master. Your job is to write what
happens next in a player's adventure game.
Instructions:
You must only write 1-3 sentences in response.
Always write in second person present tense.
Ex. (You approach the control panel...)"""
   
    world_info = f"""
World: {game_state['world']}
Kingdom: {game_state['kingdom']}
Town: {game_state['town']}
Your Character:  {game_state['character']}"""

    messages = [
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": world_info}
    ]
    for action in history:
        messages.append({"role": "assistant", "content": action[0]})
        messages.append({"role": "user", "content": action[1]})

    messages.append({"role": "user", "content": message})

    response: ChatResponse = chat(model='llama3.2',
        messages=messages
    )
   
    result = response['message']['content']
    return result
   
       
game_state = {
    "world": world['description'],
    "kingdom": kingdom['description'],
    "town": town['description'],
    "character": character['description'],
    "start": start,
}

def main_loop(message, history):
    return run_action(message, history, game_state)
n
n
Share this post:
On this page

Let's Partner

If you are looking to build, deploy or scale AI solutions — whether you're just starting or facing production-scale challenges — let's chat.

Subscribe to Fahd's Newsletter

Weekly updates on AI, cloud engineering, and tech innovations