Dragons and Data: Update #2

The most wonderful thing about computer science is that the smallest change to a program can throw the entire thing off balance.

Did you catch the sarcasm?

In the past few weeks, as I’ve continued to code and test and code and test (don’t worry, I’m sure the cycle will end eventually), I’ve learned a few practical lessons about programming and research procedure in general. The most important lesson is that of iteration: it’s better to make small adjustments and test until those adjustments are completely free of major bugs. That way, the entire code is still intact even after a failed run. It seems like a pretty intuitive lesson, but it was always so easy for me to get carried away and try to code multiple facets at once rather than focus on slightly improving one until it was solid. My research process has also changed following this revelation- I spend more time planning out one section, writing a very specific goal to accomplish, and then carrying it out to fruition before writing down another (much more far-out) goal. This has led to a greater sense of accomplishment upon reaching each goal and a more efficient use of my time.

As for the status of my project, I’ve spent a lot of time looking at what I’ve done, what I think I have the knowledge and ability to do within my timespan, and what needs to be done. In order for the development of a ‘player’ bot to happen, I needed to have a generalized program that can play the games normally (and allow human users to play the games). So, I created a program called ‘Play_Game’ that takes in a script and turns it into a playable choice-based game. For simplicity’s sake, at any ‘choice juncture,’ there are only two options. Those options can be any two, such as turning LEFT or RIGHT, or choosing whether to RUN or FIGHT from a threat, but the choice must remain binary. In order to save myself the pain of having to write multitudes of programs every time I want a new script, this one program can take any script, so long as it is formatted a certain way, and read it as intended. In order for the script to be valid, there are a few requirements: since each choice is either a 0 (first option) or a 1 (second option), there must be some string[s] of 0s and 1s that leads to a WIN, and some string[s] that lead to a LOSS. Each section of the script (a bit of text before a choice) must contain two all-uppercase keywords, or the words that the player would type to choose that option, and each section must also have a sequence of 0s and 1s to denote its position in the flow of the game. Ultimately, this means that each script follows a very basic flowchart shape, with a root in the chart denoting a choice and a branch denoting either a 0 or 1. The program is able to read the codes, separate and organize the sections by their order in the sequence, and let a human user play through the script. Since the program is generalized, it works with scripts of any size; it can play a script with only one choice, or a script with dozens!

In my last update (see here), I mentioned that the ‘Player.py’ program (here on out referred to simply as Player) pre-processes the script and sorts the important words by part of speech. Although this is an interesting bit of knowledge for my coding repository, I realized that it doesn’t actually seem to be doing much for the benefit of my project. I also realized that it’s kind of cheating for the Player to have the script before it plays the game, and seeing as I want to treat the Player as an implementable program in other programs, it doesn’t make sense for the Player to be secluded to its own program. So, I changed everything I had previously done and turned the Player into its own ‘Class’. This means that a Player object (and all of its methods, i.e. the things it can do) is accessible by any other program, like my Play_Game program.

I’ve changed the Player program’s universal dictionary to contain two types of words: WIN words, and LOSS words. Rather than updating the dictionary with words by their part of speech, the dictionary is updated with all of the words the Player encountered in its path towards success or failure. I also updated the script processing aspect of the Player to only look at the script it’s currently playing. That way, it has no knowledge of the script’s flow, and it can piece together paths one choice at a time. Of course, for this to work, I had to implement code so that the Player program can actually play the games made in the Play_Game program, while maintaining the ability for a human user to play the game. Finally, I’ve given the computer two possible ways of selecting a choice: random choice, and educated choice. The educated choice is where things start to become more complex, since the computer cannot technically make an “educated” guess, because it cannot read. So what the Player does is look through its dictionary of WIN and LOSS words, assigning points to each phrase in the game’s script based on whether it contains any words from the WIN/LOSS dictionary. So, a phrase like

“…and down the dark cave on the LEFT was a dangerous dragon,” would earn +1 points for ‘down’, ‘cave’, and ‘left’, and -1 points for ‘dark’, dangerous,’ and ‘dragon,’ for a net score of 0. Then, if the other choice phrase scores higher, that would be the choice the computer makes. This is where multiple tests and multiple scripts are needed. First, the computer needs to build a developed dictionary containing enough examples of WIN/LOSS words to actually score the phrases, meaning it must play the games by making random choices until it has learned enough to make an educated choice. Secondly, because some words are found along both WIN and LOSS paths, the computer’s choices might be skewed by them. Words like ‘left,’ ‘cave,’ and ‘is’ don’t carry inherently negative or positive connotations, meaning they could appear as either WIN or LOSS words. I implemented the scoring system to account for such words, since a word in both categories will have a net effect of 0, but if I train the computer on scripts with dragons constantly down the left side of a cave, it might start to associate leftness with losing.

These kinds of discoveries are along the lines of what I set out to find. I began with one big question to guide my project: how does a computer learn? I’ve had to simplify my path a bit to reach some semblance of an answer, but along the way I’ve learned more about coding, language processing, and machine learning than I ever thought I could in one summer. I’ve still got a few more things in mind, namely developing an algorithm that tells the computer when to make a random choice or when to make an educated choice, and writing a lot more scripts to test the Player, but I’ve certainly gleaned a ton of new information. For now, I’ve got computers to teach!

Link to update #1, abstract


  1. Hey Alex!

    I think this is a super cool project you have. I know that some parts of coding are really confusing and complex, so good on you for being able to take an organized approach to creating this program (I still haven’t figured out how to write any code without being all over the place).

    I have a question about the scripts you are using. I know that most machine learning algorithms need a good bit of data to really start working well, and I imagine writing a script can take some time. Are you writing scripts out for the computer to test on, or do you have a outside dataset? If you’re making the script, about how long is it?

  2. dsweishar says:

    This sounds like a promising project and I often find that many iterative processes are. I was wondering if you kept track of how the player performed in any simulations, as in correct choice or win/loss statistics. Those may be a good metric for measuring progress in your optimizing and debugging of the code. I also was wondering if you were considering adding a third dictionary, a neutral word one, for words such as left/right/is etc. Although I recognize that any statistical improvement from that might be to slight to justify the time spent coding. Finally, I had not considered that a program would not be able to differentiate words or potentially ‘time in game’ but I like your approaches to providing it the knowledge base and isolating it to the players actions to add a timeline.