diff --git a/README.md b/README.md index a010533..b2c89dd 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,13 @@ ## Clover Edition ### Coming: Soon. -In 2016, Donald Trump ran for president on a campaign of Making Anime Real. Four years later this promise is finally being fullfilled. Behold AIDungeon(no space): Clover Edition. The only video game where you can truely Do Anything: +In 2016, Donald Trump ran for president on a campaign of Making Anime Real. Four years later this promise is finally being fullfilled. Behold AIDungeon(no space): Clover Edition. The only video game where you can truly Do Anything: --insert screenshots here-- A fork of AIDungeon2. I just wanted to change some small things and now I am worried I will end up completely rewriting it. -####Features: +#### Features: ------------------------ * Complete rewrite of the user interface @@ -19,7 +19,7 @@ A fork of AIDungeon2. I just wanted to change some small things and now I am wor * Better config file * Eventually hope to improve the AI itself, but this will take some time -###Installation Instructions: +#### Installation Instructions: ------------------------ --insert colab instructions/guide here-- @@ -36,7 +36,7 @@ python3 play.py ``` -Community +#### Community ------------------------ See that github issues page? Post any questions, requests, or problems there if you are willing to create a github account. Unless MicroAndSoft deletes us. @@ -48,6 +48,6 @@ Resources: * **Email**: cloveranon@nuke.africa -Contributing +#### Contributing ------------------------ Contributing are more than welcome. You can fork the thing and send a [pull request](https://help.github.com/articles/using-pull-requests/) from your fork. Or you can possibly just edit the files from the github page if it lets you. If not fork the thing and try to edit your fork and submit it back. diff --git a/config.ini b/config.ini new file mode 100644 index 0000000..1df4529 --- /dev/null +++ b/config.ini @@ -0,0 +1,70 @@ +[Settings] +#Temperature controls how random the AI's output is. +# Close to 0 means it always produces the most likely word. +# Usually short and boring responses, easily getting stuck in loops. +# 1 makes it as "statistically unpredictable" as real text. +# The AI isn't perfect at predicting humans, so results in very random behavior +# Lots of folk wisdom is being spread about the best choice. +# Claims that somewhere between 0.1-0.3 or even lower is optimal for coomers. +# Ok coomers. +temp = 0.4 +#The number of words the AI has to choose from. +# It always chooses the "top k" most likely next words before randomly picking one according to temperature. +# Low values reduce the randomness of the AI similar to temp. +# Claims it might affect performance if too high, seems unlikely. +topkeks = 20 +#literally no idea what this does +top_p = 0.9 +#probably related to the number of words the AI produces at a time? Possibly affects performance. +generatenum = 60 +#controls something related to tensorflows logging +loglevel = 3 + +#ECMA-48 set graphics codes +#Check out "man console_codes" +# Several attributes can be set in the same sequence, separated by semicolons. An empty parameter (between semicolons or string initiator or terminator) is interpreted as a zero. +#0 reset all attributes to their defaults +#1 set bold +#2 set half-bright (simulated with color on a color display) +#4 set underscore (simulated with color on a color display) +#5 set blink +#7 set reverse video +#... +#21 set normal intensity (ECMA-48 says "doubly underlined") +#22 set normal intensity +#24 underline off +#25 blink off +#27 reverse video off +#30 set black foreground +#31 set red foreground +#32 set green foreground +#33 set brown foreground +#34 set blue foreground +#35 set magenta foreground +#36 set cyan foreground +#37 set white foreground +#38 set underscore on, set default foreground color +#39 set underscore off, set default foreground color +#40 set black background +#41 set red background +#42 set green background +#43 set brown background +#44 set blue background +#45 set magenta background +#46 set cyan background +#47 set white background +#49 set default background color +[Colors] +default = 0 +error = 7 +loadingMessage = 34 +title = 31 +subtitle = 36 +instructions = 33 +selectionPrompt = 7;32 +selectionValue = 35 +menu = 36 +AIText = 35 +mainPrompt = 7;33;45 +userText = 36 +printStory = 37 diff --git a/interface/instructions.txt b/interface/instructions.txt new file mode 100644 index 0000000..4245120 --- /dev/null +++ b/interface/instructions.txt @@ -0,0 +1,11 @@ +AI Dungeon 2 Instructions: + Enter actions starting with a verb ex. "go to the tavern" or "attack the orc." + To speak enter 'say "(thing you want to say)"' or just "(thing you want to say)" +The following commands can be entered for any action: + "revert" Reverts the last action allowing you to pick a different action. + "quit" Quits the game and saves + "restart" Starts a new game and saves your current one + "save" Makes a new save of your game and gives you the save ID + "load" Asks for a save ID and loads the game if the ID is valid + "print" Prints a transcript of your adventure (without extra newline formatting) + "help" Prints these instructions again diff --git a/opening.txt b/interface/mainTitle.txt similarity index 66% rename from opening.txt rename to interface/mainTitle.txt index 405023e..8f2fb38 100644 --- a/opening.txt +++ b/interface/mainTitle.txt @@ -1,4 +1,3 @@ - ▄▄▄ ██▓ ▓█████▄ █ ██ ███▄ █ ▄████ ▓█████ ▒█████ ███▄ █ ▒████▄ ▓██▒ ▒██▀ ██▌ ██ ▓██▒ ██ ▀█ █ ██▒ ▀█▒▓█ ▀ ▒██▒ ██▒ ██ ▀█ █ ▒██ ▀█▄ ▒██▒ ░██ █▌▓██ ▒██░▓██ ▀█ ██▒▒██░▄▄▄░▒███ ▒██░ ██▒▓██ ▀█ ██▒ @@ -9,11 +8,3 @@ ░ ▒ ▒ ░ ░ ░ ░ ░░░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ▒ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ - _______ ___ _______ __ __ _______ ______ _______ ______ ___ _______ ___ _______ __ _ -| || | | || | | || || _ | | || | | | | || | | || | | | -| || | | _ || |_| || ___|| | || | ___|| _ || | |_ _|| | | _ || |_| | -| || | | | | || || |___ | |_||_ | |___ | | | || | | | | | | | | || | -| _|| |___ | |_| || || ___|| __ | | ___|| |_| || | | | | | | |_| || _ | -| |_ | || | | | | |___ | | | | | |___ | || | | | | | | || | | | -|_______||_______||_______| |___| |_______||___| |_| |_______||______| |___| |___| |___| |_______||_| |__| - diff --git a/interface/subTitle.txt b/interface/subTitle.txt new file mode 100644 index 0000000..aaa6c85 --- /dev/null +++ b/interface/subTitle.txt @@ -0,0 +1,7 @@ + _______ ___ _______ __ __ _______ ______ _______ ______ ___ _______ ___ _______ __ _ +| || | | || | | || || _ | | || | | | | || | | || | | | +| || | | _ || |_| || ___|| | || | ___|| _ || | |_ _|| | | _ || |_| | +| || | | | | || || |___ | |_||_ | |___ | | | || | | | | | | | | || | +| _|| |___ | |_| || || ___|| __ | | ___|| |_| || | | | | | | |_| || _ | +| |_ | || | | | | |___ | | | | | |___ | || | | | | | | || | | | +|_______||_______||_______| |___| |_______||___| |_| |_______||______| |___| |___| |___| |_______||_| |__| diff --git a/play.py b/play.py index f84dfaa..fdf341d 100644 --- a/play.py +++ b/play.py @@ -1,205 +1,173 @@ import os -import sys -import time +#import sys +#import time +#import json +import configparser +from pathlib import Path +from random import shuffle +from shutil import get_terminal_size from generator.gpt2.gpt2_generator import * from story.story_manager import * from story.utils import * -os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3" +#perhaps all the following should be put in a seperate utils file like original +config = configparser.ConfigParser() +config.read('config.ini') +settings=config["Settings"] +colors=config["Colors"] +os.environ["TF_CPP_MIN_LOG_LEVEL"] = settings["loglevel"] -def splash(): - print("0) New Game\n1) Load Game\n") - choice = get_num_options(2) +#ECMA-48 set graphics codes for the curious. Check out "man console_codes" +def colPrint(str, col='0'): + print("\x1B[{}m{}\x1B[{}m".format(col, str, colors["default"])) - if choice == 1: - return "load" +def colInput(str, col1=colors["default"], col2=colors["default"]): + val=input("\x1B[{}m{}\x1B[{}m".format(col1,str,col1)) + print('\x1B[0m', end='') + return val + +def getNumberInput(n): + val=colInput("Enter a number from above:", colors["selectionPrompt"], colors["selectionValue"]) + if val=='': + return 0 + if 0>int(val) or int(val)>=n: + colPrint("Invalid choice.", colors["error"]) + return getNumberInput(n) else: - return "new" - - -def select_game(): - with open(YAML_FILE, "r") as stream: - data = yaml.safe_load(stream) - - print("Pick a setting.") - settings = data["settings"].keys() - for i, setting in enumerate(settings): - print_str = str(i) + ") " + setting - if setting == "fantasy": - print_str += " (recommended)" - - console_print(print_str) - console_print(str(len(settings)) + ") custom") - choice = get_num_options(len(settings) + 1) - - if choice == len(settings): - - context = "" - console_print( - "\nEnter a prompt that describes who you are and the first couple sentences of where you start " - "out ex:\n 'You are a knight in the kingdom of Larion. You are hunting the evil dragon who has been " - + "terrorizing the kingdom. You enter the forest searching for the dragon and see' " - ) - prompt = input("Starting Prompt: ") - return context, prompt - - setting_key = list(settings)[choice] - - print("\nPick a character") - characters = data["settings"][setting_key]["characters"] - for i, character in enumerate(characters): - console_print(str(i) + ") " + character) - character_key = list(characters)[get_num_options(len(characters))] - - name = input("\nWhat is your name? ") - setting_description = data["settings"][setting_key]["description"] - character = data["settings"][setting_key]["characters"][character_key] - - context = ( - "You are " - + name - + ", a " - + character_key - + " " - + setting_description - + "You have a " - + character["item1"] - + " and a " - + character["item2"] - + ". " - ) - prompt_num = np.random.randint(0, len(character["prompts"])) - prompt = character["prompts"][prompt_num] - - return context, prompt + return int(val) +def selectFile(p=Path('prompts')): + if p.is_dir(): + files=[x for x in p.iterdir()] + shuffle(files) + for n in range(len(files)): + colPrint('{}: {}'.format(n, re.sub(r'\.txt$', '', files[n].name)), colors["menu"]) + return selectFile(files[getNumberInput(len(files))]) + else: + with p.open() as file: + line1=file.readline() + rest=file.read() + return (line1, rest) def instructions(): - text = "\nAI Dungeon 2 Instructions:" - text += '\n Enter actions starting with a verb ex. "go to the tavern" or "attack the orc."' - text += '\n To speak enter \'say "(thing you want to say)"\' or just "(thing you want to say)" ' - text += "\n\nThe following commands can be entered for any action: " - text += '\n "revert" Reverts the last action allowing you to pick a different action.' - text += '\n "quit" Quits the game and saves' - text += '\n "restart" Starts a new game and saves your current one' - text += '\n "save" Makes a new save of your game and gives you the save ID' - text += '\n "load" Asks for a save ID and loads the game if the ID is valid' - text += '\n "print" Prints a transcript of your adventure (without extra newline formatting)' - text += '\n "help" Prints these instructions again' - return text + with open('interface/instructions.txt', 'r', encoding='utf-8') as file: + colPrint(file.read(), colors["instructions"]) -def play_aidungeon_2(): +#"\nEnter a prompt that describes who you are and the first couple sentences of where you start " +# "out ex:\n 'You are a knight in the kingdom of Larion. You are hunting the evil dragon who has been " +# + "terrorizing the kingdom. You enter the forest searching for the dragon and see' " - upload_story = True - print("\nInitializing AI Dungeon! (This might take a few minutes)\n") - generator = GPT2Generator() + +def play(): + colPrint("\nInitializing AI Dungeon! (This might take a few minutes)\n", colors["loadingMessage"]) + generator = GPT2Generator( + generate_num=settings.getint('generatenum'), + temperature=settings.getfloat("temp"), + top_k=settings.getint("topkeks"), + top_p=settings.getfloat("top_p")) story_manager = UnconstrainedStoryManager(generator) print("\n") - with open("opening.txt", "r", encoding="utf-8") as file: - starter = file.read() - print(starter) + with open("interface/mainTitle.txt", "r", encoding="utf-8") as file: + colPrint(file.read(), colors["title"]) + + with open('interface/subTitle.txt', 'r', encoding="utf-8") as file: + cols=get_terminal_size()[0] + for line in file: + line=line[:cols] + colPrint(re.sub(r'\|[ _]*\|', lambda x: '\x1B[7m'+x.group(0)+'\x1B[27m', line), colors["subtitle"]) + while True: if story_manager.story != None: del story_manager.story print("\n\n") + + context, prompt = selectFile() - splash_choice = splash() + instructions() - if splash_choice == "new": - print("\n\n") - context, prompt = select_game() - console_print(instructions()) - print("\nGenerating story...") + colPrint("\nGenerating story...", colors["loadingMessage"]) - story_manager.start_new_story( - prompt, context=context, upload_story=upload_story - ) - print("\n") - console_print(str(story_manager.story)) - - else: - load_ID = input("What is the ID of the saved game? ") - result = story_manager.load_new_story(load_ID) - print("\nLoading Game...\n") - print(result) + story_manager.start_new_story( + prompt, context=context + ) + print("\n") + colPrint(str(story_manager.story), colors["AIText"]) while True: - sys.stdin.flush() - action = input("> ") + action = colInput("> ", colors["mainPrompt"], colors["userText"]) if action == "restart": - rating = input("Please rate the story quality from 1-10: ") - rating_float = float(rating) - story_manager.story.rating = rating_float + #rating = input("Please rate the story quality from 1-10: ") + #rating_float = float(rating) + #story_manager.story.rating = rating_float break - elif action == "quit": - rating = input("Please rate the story quality from 1-10: ") - rating_float = float(rating) - story_manager.story.rating = rating_float + #rating = input("Please rate the story quality from 1-10: ") + #rating_float = float(rating) + #story_manager.story.rating = rating_float exit() - elif action == "nosaving": - upload_story = False - story_manager.story.upload_story = False - console_print("Saving turned off.") + #elif action == "nosaving": + #upload_story = False + #story_manager.story.upload_story = False + #console_print("Saving turned off.") elif action == "help": - console_print(instructions()) + instructions() - elif action == "save": - if upload_story: - id = story_manager.story.save_to_storage() - console_print("Game saved.") - console_print( - "To load the game, type 'load' and enter the following ID: " - + id - ) - else: - console_print("Saving has been turned off. Cannot save.") + #elif action == "save": + # if upload_story: + # id = story_manager.story.save_to_storage() + # console_print("Game saved.") + # console_print( + # "To load the game, type 'load' and enter the following ID: " + # + id + # ) + # else: + # console_print("Saving has been turned off. Cannot save.") - elif action == "load": - load_ID = input("What is the ID of the saved game?") - result = story_manager.story.load_from_storage(load_ID) - console_print("\nLoading Game...\n") - console_print(result) + #elif action == "load": + # load_ID = input("What is the ID of the saved game?") + # result = story_manager.story.load_from_storage(load_ID) + # console_print("\nLoading Game...\n") + # console_print(result) - elif len(action.split(" ")) == 2 and action.split(" ")[0] == "load": - load_ID = action.split(" ")[1] - result = story_manager.story.load_from_storage(load_ID) - console_print("\nLoading Game...\n") - console_print(result) + #elif len(action.split(" ")) == 2 and action.split(" ")[0] == "load": + # load_ID = action.split(" ")[1] + # result = story_manager.story.load_from_storage(load_ID) + # console_print("\nLoading Game...\n") + # console_print(result) elif action == "print": print("\nPRINTING\n") - print(str(story_manager.story)) + colPrint(str(story_manager.story), colors["printStory"]) elif action == "revert": if len(story_manager.story.actions) is 0: - console_print("You can't go back any farther. ") + colPrint("You can't go back any farther. ", colors["error"]) continue story_manager.story.actions = story_manager.story.actions[:-1] story_manager.story.results = story_manager.story.results[:-1] - console_print("Last action reverted. ") + colPrint("Last action reverted. ", colors["loadingMessage"]) if len(story_manager.story.results) > 0: - console_print(story_manager.story.results[-1]) + colPrint(story_manager.story.results[-1], colors["AIText"]) else: - console_print(story_manager.story.story_start) + console_print(story_manager.story.story_start, colors["AIText"]) continue else: if action == "": action = "" result = story_manager.act(action) - console_print(result) + colPrint(result, colors["AIText"]) elif action[0] == '"': action = "You say " + action @@ -226,33 +194,25 @@ def play_aidungeon_2(): if similarity > 0.9: story_manager.story.actions = story_manager.story.actions[:-1] story_manager.story.results = story_manager.story.results[:-1] - console_print( - "Woops that action caused the model to start looping. Try a different action to prevent that." - ) + colPrint( "Woops that action caused the model to start looping. Try a different action to prevent that.", colors["error"]) continue if player_won(result): - console_print(result + "\n CONGRATS YOU WIN") + colPrint(result + "\n CONGRATS YOU WIN", colors["loadingMessage"]) break elif player_died(result): - console_print(result) - console_print("YOU DIED. GAME OVER") - console_print("\nOptions:") - console_print("0) Start a new game") - console_print( - "1) \"I'm not dead yet!\" (If you didn't actually die) " - ) - console_print("Which do you choose? ") - choice = get_num_options(2) + colPrint(result, colors["AIText"]) + colPrint("YOU DIED. GAME OVER", colors["error"]) + console_print("\nOptions:\n0)Start a new game\n1)\"I'm not dead yet!\" (If you didn't actually die)", colors["menu"]) + choice = getNumberInput(2) if choice == 0: break else: - console_print("Sorry about that...where were we?") - console_print(result) + colPrint("Sorry about that...where were we?", colors["menu"]) + console_print(result, colors["AIText"]) else: - console_print(result) + colPrint(result, colors["AIText"]) -if __name__ == "__main__": - play_aidungeon_2() +play() diff --git a/prompts/GNU+Linux.txt b/prompts/GNU+Linux.txt new file mode 100644 index 0000000..57dd36a --- /dev/null +++ b/prompts/GNU+Linux.txt @@ -0,0 +1 @@ +You are Linus Torvalds. You are talking about operating systems with Terry Davis. Behind you comes a big fat man, who grabs you right in your proprietary binary blobs. It is Richard Stallman. He says "I'd just like to interject for moment. What you're refering to as Linux, is in fact, GNU/Linux, or as I've recently taken to calling it, GNU plus Linux. Linux is not an operating system unto itself, but rather another free component of a fully functioning GNU system made useful by the GNU corelibs, shell utilities and vital system components comprising a full OS as defined by POSIX. diff --git a/story/utils.py b/story/utils.py index 3889cfb..0e05546 100644 --- a/story/utils.py +++ b/story/utils.py @@ -25,7 +25,7 @@ def console_print(text, width=75): def get_similarity(a, b): return SequenceMatcher(None, a, b).ratio() - +#delet this def get_num_options(num): while True: