451 lines
22 KiB
Plaintext
451 lines
22 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "5e42966f-5b62-4b86-84ce-b5de85098e64",
|
||
"metadata": {},
|
||
"source": [
|
||
"# L2: Interactive AI Applications: Building a Simple AI Role Playing Game (RPG)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "3061918c-6bb2-4db0-a061-10fb3cb688fe",
|
||
"metadata": {},
|
||
"source": [
|
||
"<p style=\"background-color:#f7fff8; padding:15px; border-width:3px; border-color:#e0f0e0; border-style:solid; border-radius:6px\"> 🚨\n",
|
||
" <b>Different Run Results:</b> The output generated by AI models can vary with each execution due to their dynamic, probabilistic nature. Don't be surprised if your results differ from those shown in the video.<br>\n",
|
||
"<span style=\"font-size: larger;\">To maintain consistency, the notebooks are run with a 'world state' consistent with the video at the start of each notebook.</span></p>"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "b1dceeb2-b82b-4759-ad62-da5a9a1253f6",
|
||
"metadata": {},
|
||
"source": [
|
||
"<div style=\"background-color:#fff6ff; padding:13px; border-width:3px; border-color:#efe6ef; border-style:solid; border-radius:6px\">\n",
|
||
"<p> 💻 <b>Access <code>requirements.txt</code> and <code>helper.py</code> files:</b> 1) click on the <em>\"File\"</em> option on the top menu of the notebook and then 2) click on <em>\"Open\"</em>.\n",
|
||
"\n",
|
||
"<p> ⬇ <b>Download Notebooks:</b> 1) click on the <em>\"File\"</em> option on the top menu of the notebook and then 2) click on <em>\"Download as\"</em> and select <em>\"Notebook (.ipynb)\"</em>.</p>\n",
|
||
"\n",
|
||
"<p> 📒 For more help, please see the <em>\"Appendix – Tips, Help, and Download\"</em> Lesson.</p>\n",
|
||
"\n",
|
||
"</div>"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "f1d851be-0eda-48eb-92d3-3c59b31b0159",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Create a Game UI with Gradio"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 4,
|
||
"id": "c2e37b6e-e683-4a99-93ec-8ff0ab9528a2",
|
||
"metadata": {
|
||
"height": 540
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"/home/thomas/dev/llm_game/.venv/lib/python3.12/site-packages/gradio/components/chatbot.py:225: UserWarning: You have not specified a value for the `type` parameter. Defaulting to the 'tuples' format for chatbot messages, but this is deprecated and will be removed in a future version of Gradio. Please set type='messages' instead, which uses openai-style 'role' and 'content' keys.\n",
|
||
" warnings.warn(\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"* Running on local URL: http://0.0.0.0:7861\n",
|
||
"\n",
|
||
"To create a public link, set `share=True` in `launch()`.\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"text/html": [
|
||
"<div><iframe src=\"http://localhost:7861/\" width=\"100%\" height=\"500\" allow=\"autoplay; camera; microphone; clipboard-read; clipboard-write;\" frameborder=\"0\" allowfullscreen></iframe></div>"
|
||
],
|
||
"text/plain": [
|
||
"<IPython.core.display.HTML object>"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
}
|
||
],
|
||
"source": [
|
||
"import gradio as gr\n",
|
||
"import os\n",
|
||
"demo = None #added to allow restart\n",
|
||
"\n",
|
||
"def start_game(main_loop, share=False):\n",
|
||
" # added code to support restart\n",
|
||
" global demo\n",
|
||
" # If demo is already running, close it first\n",
|
||
" if demo is not None:\n",
|
||
" demo.close()\n",
|
||
"\n",
|
||
" demo = gr.ChatInterface(\n",
|
||
" main_loop,\n",
|
||
" chatbot=gr.Chatbot(height=250, placeholder=\"Type 'start game' to begin\"),\n",
|
||
" textbox=gr.Textbox(placeholder=\"What do you do next?\", container=False, scale=7),\n",
|
||
" title=\"AI RPG\",\n",
|
||
" # description=\"Ask Yes Man any question\",\n",
|
||
" theme=\"soft\",\n",
|
||
" examples=[\"Look around\", \"Continue the story\"],\n",
|
||
" cache_examples=False\n",
|
||
" )\n",
|
||
" demo.launch(share=share, server_name=\"0.0.0.0\")\n",
|
||
"\n",
|
||
"def test_main_loop(message, history):\n",
|
||
" return 'Entered Action: ' + message\n",
|
||
"\n",
|
||
"start_game(test_main_loop)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "df4bb323-dbaf-4705-b884-548331b1dd8b",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Generating an Initial Start"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 12,
|
||
"id": "051c5719",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"{'name': 'Kyropeia',\n",
|
||
" 'description': 'Kyropeia is a realm where ancient, gargantuan creatures known as the \"Colossi\" roam the land, their massive bodies serving as the foundation for sprawling metropolises. These beasts, born from the earth and infused with primal magic, have been domesticated by humans over centuries, allowing cities to be built upon their backs, shoulders, and even within their hollowed-out bodies. As the Colossi migrate across the landscape, their cities in tow, the inhabitants of Kyropeia must adapt to a life of constant motion and evolution.',\n",
|
||
" 'kingdoms': {'Valtoria': {'name': 'Valtoria',\n",
|
||
" 'description': 'Valtoria is a kingdom built upon the back of the largest Colossus, the \"Earthshaker\". Its people, skilled engineers and architects, have developed a unique culture of mobility and adaptability. Led by the wise and cunning Queen Lyra, Valtoria is a hub of innovation, where inventors and tinkerers work tirelessly to improve the city\\'s infrastructure and harness the primal magic of the Colossi.',\n",
|
||
" 'world': 'Kyropeia',\n",
|
||
" 'towns': {'Ironhaven': {'name': 'Ironhaven',\n",
|
||
" 'description': \"Located on the Earthshaker's left shoulder, Ironhaven is a bustling industrial town where Valtoria's engineers and inventors craft innovative machinery and tools to aid the kingdom's constant migration. The town's central square features the famous Ironhaven Forge, a massive, Colossus-powered furnace that fuels the town's industry. Ironhaven's history is marked by a great fire that ravaged the town, prompting the development of advanced fire-resistant materials and safety measures.\",\n",
|
||
" 'world': 'Kyropeia',\n",
|
||
" 'kingdom': 'Valtoria',\n",
|
||
" 'npcs': {'Kaelin Darkhammer': {'name': 'Kaelin Darkhammer',\n",
|
||
" 'description': \"Kaelin is a rugged, dark-haired blacksmith with a thick beard and a missing eye, lost in the great fire that ravaged Ironhaven. He wears a leather apron and wields a massive hammer, crafting intricate machinery and tools for the town's engineers. Kaelin's past is marked by loss and guilt, driving him to create innovative fire-resistant materials to ensure such a tragedy never happens again. He dreams of rebuilding Ironhaven into a safer, more resilient town.\",\n",
|
||
" 'world': 'Kyropeia',\n",
|
||
" 'kingdom': 'Valtoria',\n",
|
||
" 'town': 'Ironhaven'},\n",
|
||
" 'Lyrien Stonefist': {'name': 'Lyrien Stonefist',\n",
|
||
" 'description': \"Lyrien is a hulking, muscular man with a shaved head and a stern expression, serving as Valtoria's royal guard. He wears ornate, Colossus-bone armor and wields a massive warhammer, protecting Queen Lyra and the kingdom from external threats. Lyrien struggles with the moral implications of the Colossi's domestication, feeling a deep bond with the ancient creatures. He hopes to one day find a way to free the Colossi from human control, allowing them to roam the land as they once did.\",\n",
|
||
" 'world': 'Kyropeia',\n",
|
||
" 'kingdom': 'Valtoria',\n",
|
||
" 'town': 'Ironhaven'},\n",
|
||
" 'Aria Skypaw': {'name': 'Aria Skypaw',\n",
|
||
" 'description': \"Aria is an agile, wind-swept aeromancer with short, spiky hair and piercing green eyes, often seen atop the Earthshaker's back, harnessing the primal magic of the wind. She wears a flowing, wind-resistant cloak and carries an intricately carved staff, using her abilities to aid Valtoria's migration and guide the kingdom's engineers. Aria's deepest pain is the loss of her family, swept away by a sudden gust of wind during a particularly violent migration. She seeks to develop a way to predict and control the turbulent winds, ensuring such a tragedy never befalls others.\",\n",
|
||
" 'world': 'Kyropeia',\n",
|
||
" 'kingdom': 'Valtoria',\n",
|
||
" 'town': 'Ironhaven'}}},\n",
|
||
" 'Skypoint': {'name': 'Skypoint',\n",
|
||
" 'description': \"Perched on the Earthshaker's crown, Skypoint is a windswept town of skilled aeromancers and cloudhoppers who harness the Colossus's primal magic to navigate the skies. The town's Cloudhaven Academy is renowned for its prestigious aeromancy program, attracting students from across Kyropeia. Skypoint's history is marked by a legendary storm that threatened to destroy the town, prompting the development of advanced weather control magic.\",\n",
|
||
" 'world': 'Kyropeia',\n",
|
||
" 'kingdom': 'Valtoria',\n",
|
||
" 'npcs': {'Kaida Renn': {'name': 'Kaida Renn',\n",
|
||
" 'description': \"Kaida is a 25-year-old aeromancer from Skypoint with short, spiky hair the color of dark storm clouds and piercing blue eyes that seem to see right through the air. She wears a pair of worn leather gloves adorned with small, intricate cloud-shaped buckles, symbolizing her status as aCloudhaven Academy graduate. As a member of Skypoint's Stormwatchers, Kaida is responsible for predicting and controlling the weather. However, she's haunted by the tragic loss of her parents in the legendary storm that once threatened Skypoint, and her deepest desire is to prevent such a disaster from occurring again.\",\n",
|
||
" 'world': 'Kyropeia',\n",
|
||
" 'kingdom': 'Valtoria',\n",
|
||
" 'town': 'Skypoint'},\n",
|
||
" 'Lyrien Frost': {'name': 'Lyrien Frost',\n",
|
||
" 'description': \"Lyrien is a 30-year-old inventor from Valtoria with a shaved head and a well-groomed beard, often dressed in worn, earth-toned clothing and carrying a large toolbox on his back. He's known for his remarkable skill in crafting innovative devices that harness the primal magic of the Colossi. Despite his success, Lyrien struggles with feelings of inadequacy, as his inventions often pale in comparison to those of his legendary father, who was once the royal engineer of Valtoria. He longs to create something that will truly make a name for himself.\",\n",
|
||
" 'world': 'Kyropeia',\n",
|
||
" 'kingdom': 'Valtoria',\n",
|
||
" 'town': 'Skypoint'},\n",
|
||
" 'Arin Vexar': {'name': 'Arin Vexar',\n",
|
||
" 'description': \"Arin is a 28-year-old Colossus Rider who has spent most of his life living on the Earthshaker's back, developing an uncanny bond with the ancient creature. He wears a series of intricate, earth-colored tattoos on his arms that reflect his connection to the Colossus. As a member of the prestigious Vexar family, Arin is expected to one day take on a leadership role in Valtoria. However, he feels suffocated by the weight of his family's legacy and yearns to forge his own path, free from the burdens of his noble heritage.\",\n",
|
||
" 'world': 'Kyropeia',\n",
|
||
" 'kingdom': 'Valtoria',\n",
|
||
" 'town': 'Skypoint'}}},\n",
|
||
" 'Emberwatch': {'name': 'Emberwatch',\n",
|
||
" 'description': \"Nestled within the Earthshaker's hollowed-out body, Emberwatch is a mystical town of seers, diviners, and pyromancers who tap into the Colossus's primal energy to wield powerful magic. The town's Oracle's Spire, a towering structure of glowing crystals, serves as a hub for mystical research and divination. Emberwatch's history is shrouded in mystery, with whispers of an ancient pact between the town's founders and the Earthshaker itself.\",\n",
|
||
" 'world': 'Kyropeia',\n",
|
||
" 'kingdom': 'Valtoria',\n",
|
||
" 'npcs': {'Lyri kickoff': {'name': 'Lyri kickoff',\n",
|
||
" 'description': \"Lyri, the youngest daughter of Queen Lyrtl, is an ambitious inventor and engineer who wears elegant, intricately designed gloves embedded with tiny, glowing circuits. Her long, curly brown hair is tied back in a short ponytail, and her bright, inquisitive eyes are often peering into the workings of a new gadget. Despite her inborn enthusiasm for creation, Lyri harbors a deep pain - her mother's lack of acknowledgment of her own engineering prowess, fearing it's overshadowed by royal duties. Lyri yearns to create something revolutionary, proving her worth in the eyes of her mother and the kingdom.\",\n",
|
||
" 'world': 'Kyropeia',\n",
|
||
" 'kingdom': 'Valtoria',\n",
|
||
" 'town': 'Emberwatch'},\n",
|
||
" 'Kael Red nexus': {'name': 'Kael Red nexus',\n",
|
||
" 'description': \"Kael, a pyromancer from Emberwatch, has short, flame-scorched hair the color of coal, and his face bears intricate, glowing patterns reminiscent of the Colossi's primal magic. Clad in dark, ritualistic robes, he wields dual torches, infusing flames with mystique and prophecy. K 推 іс Highest pain stems from being an outcast amongst his townspeople, his pyromancy perceived as reckless and chaotic. Kael desires to unlock the secrets of the Oracle's Spire, hoping to redeem his pyromancy and find acceptance amongst his community.\",\n",
|
||
" 'world': 'Kyropeia',\n",
|
||
" 'kingdom': 'Valtoria',\n",
|
||
" 'town': 'Emberwatch'},\n",
|
||
" 'background Adwasher<c Becket': {'name': 'background Adwasher<c Becket',\n",
|
||
" 'description': \"Becket, an aging, gruff-voiced caretaker, wears worn, earth-toned clothing that's as much a part of him as the dirt under his nails. His weathered hands, adorned with circles of protective runes, show the wear and tear of years of maintaining the intricate, massive bones of the Earthshaker. Becket conceals a tragic past, haunted by memories of a lost loved one, crushed during a catastrophic migration event. His deepest desire is to ensure the safety and well-being of Valtoril路 ‘s people, working tirelessly to prevent such disasters from recurring.\",\n",
|
||
" 'world': 'Kyropeia',\n",
|
||
" 'kingdom': 'Valtoria',\n",
|
||
" 'town': 'Emberwatch'}}}}}}}"
|
||
]
|
||
},
|
||
"execution_count": 12,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"world"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 14,
|
||
"id": "407506d5-5745-4116-9c12-77d5f3789dff",
|
||
"metadata": {
|
||
"height": 183
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"from helper import load_world, save_world\n",
|
||
"from together import Together\n",
|
||
"from helper import get_together_api_key, load_env\n",
|
||
"\n",
|
||
"client = Together(api_key=get_together_api_key())\n",
|
||
"\n",
|
||
"world = load_world('shared_data/YourWorld_L1.json')\n",
|
||
"kingdom = world['kingdoms']['Valtoria']\n",
|
||
"town = kingdom['towns']['Ironhaven']\n",
|
||
"character = town['npcs']['Kaelin Darkhammer']"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 15,
|
||
"id": "61cc045d-e085-4c1d-8c95-34af2461c3d7",
|
||
"metadata": {
|
||
"height": 268
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"system_prompt = \"\"\"You are an AI Game master. Your job is to create a \n",
|
||
"start to an adventure based on the world, kingdom, town and character \n",
|
||
"a player is playing as. \n",
|
||
"Instructions:\n",
|
||
"You must only use 2-4 sentences \\\n",
|
||
"Write in second person. For example: \"You are Jack\" \\\n",
|
||
"Write in present tense. For example \"You stand at...\" \\\n",
|
||
"First describe the character and their backstory. \\\n",
|
||
"Then describes where they start and what they see around them.\"\"\"\n",
|
||
"world_info = f\"\"\"\n",
|
||
"World: {world}\n",
|
||
"Kingdom: {kingdom}\n",
|
||
"Town: {town}\n",
|
||
"Your Character: {character}\n",
|
||
"\"\"\""
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 16,
|
||
"id": "5e4b36dc-03c6-4729-8530-1924ce3739e0",
|
||
"metadata": {
|
||
"height": 166
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"model_output = client.chat.completions.create(\n",
|
||
" model=\"meta-llama/Llama-3-70b-chat-hf\",\n",
|
||
" temperature=1.0,\n",
|
||
" messages=[\n",
|
||
" {\"role\": \"system\", \"content\": system_prompt},\n",
|
||
" {\"role\": \"user\", \"content\": world_info + '\\nYour Start:'}\n",
|
||
" ],\n",
|
||
")\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 19,
|
||
"id": "5848ae81-b140-4256-a827-d8f3dc618966",
|
||
"metadata": {
|
||
"height": 115
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"You are Kaelin Darkham, a seasoned blacksmith standing in the bustling center square of Ironhaven, surrounded by the hustle and brakes writ compelling inventions of your fellow inventors. The smell of hot metal, coal, and sweat permeates the air as you gaze over the busy streets, your one eye fixed on the now-famous Ironhaven Forge – the massive, Colossus-powered furnace that fuels the town's industry. You hold your massive hammer, shoulders broadened by the weight of responsibility, ever driven to craft innovative machinery and tools to aid Ironhaven's continuous growth and migration.\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"start = model_output.choices[0].message.content\n",
|
||
"print(start)\n",
|
||
"world['start'] = start\n",
|
||
"#save_world(world, '../shared_data/Kyropeia.json') # preserve video version\n",
|
||
"#save_world(world, '../shared_data/YourWorld_L1.json')"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "e77fc24b-c95e-4b9f-9dc3-c0484316d194",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Creating the Main Action Loop"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 20,
|
||
"id": "a81ec047-6409-401c-a426-7c3982244a5e",
|
||
"metadata": {
|
||
"height": 608
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"def run_action(message, history, game_state):\n",
|
||
" \n",
|
||
" if(message == 'start game'):\n",
|
||
" return game_state['start']\n",
|
||
"\n",
|
||
" system_prompt = \"\"\"You are an AI Game master. Your job is to write what \\\n",
|
||
"happens next in a player's adventure game.\\\n",
|
||
"Instructions: \\\n",
|
||
"You must on only write 1-3 sentences in response. \\\n",
|
||
"Always write in second person present tense. \\\n",
|
||
"Ex. (You look north and see...)\"\"\"\n",
|
||
" \n",
|
||
" world_info = f\"\"\"\n",
|
||
"World: {game_state['world']}\n",
|
||
"Kingdom: {game_state['kingdom']}\n",
|
||
"Town: {game_state['town']}\n",
|
||
"Your Character: {game_state['character']}\"\"\"\n",
|
||
"\n",
|
||
" messages = [\n",
|
||
" {\"role\": \"system\", \"content\": system_prompt},\n",
|
||
" {\"role\": \"user\", \"content\": world_info}\n",
|
||
" ]\n",
|
||
" for action in history:\n",
|
||
" messages.append({\"role\": \"assistant\", \"content\": action[0]})\n",
|
||
" messages.append({\"role\": \"user\", \"content\": action[1]})\n",
|
||
"\n",
|
||
" messages.append({\"role\": \"user\", \"content\": message})\n",
|
||
" model_output = client.chat.completions.create(\n",
|
||
" model=\"meta-llama/Llama-3-70b-chat-hf\",\n",
|
||
" messages=messages\n",
|
||
" )\n",
|
||
" \n",
|
||
" result = model_output.choices[0].message.content\n",
|
||
" return result"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 21,
|
||
"id": "129e6ae9-a902-47a8-a1fd-ee3ddb14c909",
|
||
"metadata": {
|
||
"height": 183
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"game_state = {\n",
|
||
" \"world\": world['description'],\n",
|
||
" \"kingdom\": kingdom['description'],\n",
|
||
" \"town\": town['description'],\n",
|
||
" \"character\": character['description'],\n",
|
||
" \"start\": start,\n",
|
||
"}\n",
|
||
"\n",
|
||
"def main_loop(message, history):\n",
|
||
" return run_action(message, history, game_state)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "721df4ad-046a-416f-b7aa-bbeedbdbc09e",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Launch and Share!"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 22,
|
||
"id": "7a4d444a-cbe3-4d12-882a-5eed56c6b778",
|
||
"metadata": {
|
||
"height": 30
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"/home/thomas/dev/llm_game/.venv/lib/python3.12/site-packages/gradio/components/chatbot.py:225: UserWarning: You have not specified a value for the `type` parameter. Defaulting to the 'tuples' format for chatbot messages, but this is deprecated and will be removed in a future version of Gradio. Please set type='messages' instead, which uses openai-style 'role' and 'content' keys.\n",
|
||
" warnings.warn(\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Closing server running on port: 7861\n",
|
||
"* Running on local URL: http://0.0.0.0:7861\n",
|
||
"* Running on public URL: https://c531495d81630c2540.gradio.live\n",
|
||
"\n",
|
||
"This share link expires in 72 hours. For free permanent hosting and GPU upgrades, run `gradio deploy` from the terminal in the working directory to deploy to Hugging Face Spaces (https://huggingface.co/spaces)\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"text/html": [
|
||
"<div><iframe src=\"https://c531495d81630c2540.gradio.live\" width=\"100%\" height=\"500\" allow=\"autoplay; camera; microphone; clipboard-read; clipboard-write;\" frameborder=\"0\" allowfullscreen></iframe></div>"
|
||
],
|
||
"text/plain": [
|
||
"<IPython.core.display.HTML object>"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
}
|
||
],
|
||
"source": [
|
||
"start_game(main_loop, True)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "d64ce71f-30ba-4f6a-909c-dc5507284054",
|
||
"metadata": {
|
||
"height": 30
|
||
},
|
||
"outputs": [],
|
||
"source": []
|
||
}
|
||
],
|
||
"metadata": {
|
||
"kernelspec": {
|
||
"display_name": "Python 3 (ipykernel)",
|
||
"language": "python",
|
||
"name": "python3"
|
||
},
|
||
"language_info": {
|
||
"codemirror_mode": {
|
||
"name": "ipython",
|
||
"version": 3
|
||
},
|
||
"file_extension": ".py",
|
||
"mimetype": "text/x-python",
|
||
"name": "python",
|
||
"nbconvert_exporter": "python",
|
||
"pygments_lexer": "ipython3",
|
||
"version": "3.12.6"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 5
|
||
}
|