diff --git a/.gitignore b/.gitignore index fab1f4b..f8531a6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *~ +.DS_Store .ipynb_checkpoints/ .DS_Store diff --git a/Untitled Folder/Practice with Python.ipynb b/Untitled Folder/Practice with Python.ipynb new file mode 100644 index 0000000..254b467 --- /dev/null +++ b/Untitled Folder/Practice with Python.ipynb @@ -0,0 +1,60 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'plt' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mss\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mplt\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mplot\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mss\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0mplt\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshow\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNameError\u001b[0m: name 'plt' is not defined" + ] + } + ], + "source": [ + "plt\n", + "ss = [1,2,1,2,1]\n", + "plt.plot(ss)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "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.5.0b2" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/projects/1-explications/Kwan.ipynb b/projects/1-explications/Kwan.ipynb new file mode 100644 index 0000000..b9a99b2 --- /dev/null +++ b/projects/1-explications/Kwan.ipynb @@ -0,0 +1,40 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Artificial intelligence start out as a technical endeavor, but it is always grounded in real world contexts. As a result, many AI systems seek to predict human behavior and imitate the human tendency to handle new situations based on past experiences.\n", + "\n", + "Predicting human behavior is far too large a challenge to undertake with a knowledge-based approach. As a result, Stanford University researchers Ethan Fast, William McGrath, Pranav Rajpurkar, and Michael S. Bernstein took the statistical approach, drawing upon Wattpad, a huge database of online fiction, as a training set for their AI. By analyzing actions in fiction, Augur, their AI, drew conclusions about human behavior and applied them to new situations.\n", + "\n", + "From a knowledge representation standpoint, Augur uses natural language processing to parse text into actions, and inputs those actions into a vector space model. TC, the language the researchers use to parse text, uses subject-verb relationships to detect actions. It creates associations between words, such as “grocery store” and “fruit,” according to the paper. It then maps this data onto vector maps called Activity Detection, Object Affordances, and Activity Prediction, which represent the data graphically and can detect patterns in it.\n", + "\n", + "As the paper states, statistical analysis does a much more thorough job detecting mundane human actions because no single researchers could accurately document the huge set of human activities in a knowledge-based system.\n", + "\n", + "However, fiction still has its drawbacks. The Stanford researchers assert that fiction represents a surprisingly accurate portrayal of modern life, but it still tends to be more dramatic than in real life. For instance, The Stack notes that the “Augur-based prediction system is most likely, when identifying a cat, to predict that the next thing it will do is hiss.” Until Augur can adjust its training set to include episodes from real life instead of modern fiction, its data will be fundamentally flawed." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "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.5.0b2" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/projects/1-hello-world/Kwan.ipynb b/projects/1-hello-world/Kwan.ipynb new file mode 100644 index 0000000..108926f --- /dev/null +++ b/projects/1-hello-world/Kwan.ipynb @@ -0,0 +1,51 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Hi, my name is Melissa. I'm a Bay Area native who first learned programming by taking a Python course online. Since then, I've taken classes in Java and C++, including APCS this past year.\n", + "\n", + "Though I've programmed in class, until this year I was pretty unaware of the large coding community that exists online through Firebase, Mongo.db, Github, and other platforms. My experience coding is limited to localized programs like Minesweeper and Sudoku, and I hope to expand the scope of my projects through online sharing.\n", + "\n", + "By the end of this class, I hope to have a more concrete understanding of artificial intelligence, which is currently a pretty abstract concept in my mind. I've read so much about the ethical concerns and the vague possibilities of AI, but I want to understand the actual code first before considering the implications.\n", + "\n", + "Outside of CS, I have played club volleyball for 5 years. I have played every single position (outside, right side, setter, libero) except for middle hitter. I'm also on the yearbook staff at my school, where I discovered my interest in graphic design.\n", + "\n", + "Thanks for reading!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "print(\"Melissa Kwan\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "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.5.0b2" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/projects/2-state-machines/Kwan.ipynb b/projects/2-state-machines/Kwan.ipynb new file mode 100644 index 0000000..cf314d5 --- /dev/null +++ b/projects/2-state-machines/Kwan.ipynb @@ -0,0 +1,501 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Background" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "State machines, like most transition systems, are defined in terms of their set of states, their initial state, their terminal states, and the valid transitions between the states. State machines are still used widely in game character AI, but they also show up in various guises all over computer science (for example in regular expressions, program verification, cyber-physical systems, ...). A solid understanding of transition systems is key to understanding many different research areas.\n", + "\n", + "Today's assignment is to use state machines in a couple of different ways to get used to reading and writing Python code, and to get a feel for what can be done with state machines.\n", + "\n", + "First, we want to create a data type to represent state machines. In Python, the custom data type is the `class`. We know that it will be initialized with a set of states and edges, an initial state, and some terminal states, and creating a state machine should look something like:\n", + "\n", + "```python\n", + "ab_a_ = StateMachine(\n", + " #We can define the states and edges in one go\n", + " [(\"s1\", \"a\", \"s2\"), (\"s2\", \"b\", \"s3\"), (\"s3\", \"a\", \"s3\")],\n", + " #Initial state\n", + " \"s1\",\n", + " #Terminal states\n", + " [\"s3\"]\n", + ")\n", + "```\n", + "\n", + "To recap:\n", + "\n", + "* `ab_a_ = ...` assigns the result of evaluating the right hand side to the variable `ab_a_`.\n", + "* `StateMachine(...)` creates a new object of the StateMachine class\n", + "* `[...]` is a comma-separated list of arbitrary \"things\". This list could grow or shrink but the key idea is that its length is unknown in advance to the code that's processing it (usually necessitating some kind of iteration or recursion over the length of the list).\n", + "* `(...)` without a word to its left is a \"tuple\", a fixed-length sequence of objects. Here, each 3-tuple defines the source state, the transition symbol, and the target state. (If there were a word to the left of the parentheses, it would be a function call as in the case of `StateMachine(...)`).\n", + "* `\"...\"` is a \"string\", a sequence of characters.\n", + "\n", + "Putting it all together, the line above makes a machine with three states that accepts `aba+`, if written as a regular expression (and stores the machine into the variable `ab_a_`): any string with the prefix `ab` followed by one or more `a`. Here's `ab(cab)+d`, `ab` followed by one or more repetitions of `cab` ending with a `d`:\n", + "\n", + "```python\n", + "ab_cab_d = StateMachine(\n", + " [(\"s1\", \"a\", \"s2\"),\n", + " (\"s2\", \"b\", \"s3\"), # The same so far...\n", + " (\"s3\", \"c\", \"s4\"),\n", + " (\"s4\", \"a\", \"s5\"),\n", + " (\"s5\", \"b\", \"s6\"),\n", + " (\"s6\", \"c\", \"s4\"), # Note the loop back to s4 on \"c\"\n", + " (\"s6\", \"d\", \"s7\")], # Or else the continuation to s7 on \"d\"\n", + " \"s1\",\n", + " [\"s7\"]\n", + ")\n", + "```\n", + "\n", + "We have two questions of interest for any transition system:\n", + "\n", + "* What is the current configuration?\n", + "* What configurations are accessible from the current configuration, and how?\n", + "\n", + "In our case, we can use e.g. `ab_a_.state` to get its current state identifier, and `ab_a_.out_edges()` to get a Python `dict` of the successors (with `ab_a_.out_edges().keys()` yielding the symbols and the `ab_a_.out_edgdes().values()` giving the successor states).\n", + "\n", + "There is one operation on state machines that we're interested in right now:\n", + "\n", + "* Advance the state machine along a particular available edge.\n", + "\n", + "We can write e.g. `ab_a_.advance(\"a\")` to advance the `ab_a_` machine by feeding it the symbol `\"a\"`. If it starts in state `\"s1\"`, this will put it into state `\"s2\"`. Then we can call `ab_a_.advance(\"b\")` to feed it a `\"b\"` and advance it to `\"s3\"`, and so on. It is an error to call `advance` with an unavailable or invalid symbol.\n", + "\n", + "Now that we know what the StateMachine class should look like, we can define it. Recall that Python is indentation-sensitive:" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "class StateMachine:\n", + " # __init__ defines the function to be called when `StateMachine(...)` is invoked.\n", + " # Note that, like other instance methods on `StateMachine`, the first argument is `self`:\n", + " # the particular state machine being operated upon (in this case, initialized). `self` is\n", + " # provided implicitly in most cases.\n", + " # `edges` should be a list of 3-tuples of strings, init-state should be a string, and terminals a list of strings.\n", + " def __init__(self, edges, init_state, terminals):\n", + " # We create a `states` variable on `self` to store the transition system information.\n", + " # It will be a dict whose keys are state identifiers and whose values are themselves dicts\n", + " # of successor states keyed by symbols.\n", + " self.states = dict()\n", + " # `for X in C` iterates over each member `X` of collection `C`.\n", + " # Since we know `C` (`edges`) contains 3-tuples, we can \"unpack\" them using the tuple notation in place of `X`.\n", + " for (src, symbol, dest) in edges:\n", + " # Ensure that the state referred to by `src` exists in the transition system as a dict (again, symbols->states):\n", + " if src not in self.states:\n", + " self.states[src] = dict()\n", + " # Ditto for `dest`.\n", + " if dest not in self.states:\n", + " self.states[dest] = dict()\n", + " # Ensure that the symbol is not already used in an out-edge of src. This is a deterministic state machine which\n", + " # can't make \"guesses\" in such cases.\n", + " if symbol in self.states[src]:\n", + " # Exceptions are informative failures that other code can catch and deal with; they represent exceptional\n", + " # cases which this code is not in a position to recover from.\n", + " raise Exception(\"This StateMachine only supports DFAs, so each state can have at most one out edge for each symbol.\")\n", + " # Finally, connect the `s`ou`rc`e state to the `dest`ination state along `symbol`.\n", + " self.states[src][symbol] = dest\n", + " # This state machine starts in the initial state\n", + " self.state = init_state\n", + " # And we remember the terminal states so that we know when we're accepting.\n", + " # The list is packed into a `set()`, which permits us to say `state_id in self.terminal_states` to simplify checking.\n", + " # You can think of sets as being like dicts of type Anything->True: \n", + " # The object is in the set if and only if the key is present.\n", + " self.terminal_states = set(terminals)\n", + "\n", + " # Determining the available out-edges is straightforward because of the way we've chosen to represent the\n", + " # transition system.\n", + " def out_edges(self):\n", + " # Return the out edges of the currently active state.\n", + " return self.states[self.state]\n", + " \n", + " # A state machine is in a terminal state if its current state is terminal\n", + " def is_terminal(self):\n", + " # Is the current state in the set of terminal states?\n", + " return self.state in self.terminal_states\n", + "\n", + " # A state machine is stuck if it has no out edges.\n", + " def is_stuck(self):\n", + " return len(self.out_edges()) == 0\n", + " \n", + " # Finally, to advance the state machine by a symbol...\n", + " def advance(self, symbol):\n", + " # We reassign the machine's state to be the target state denoted by that symbol, among the current out edges.\n", + " self.state = self.out_edges()[symbol]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With all that done, we can finally say:" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Initial state: s1\n", + "Accepting? False\n", + "After a: s2\n", + "After ab: s3\n", + "Next steps: {'a': 's3'}\n", + "Accepting? True\n" + ] + } + ], + "source": [ + "ab_a_ = StateMachine(\n", + " #We can define the states and edges in one go\n", + " [(\"s1\", \"a\", \"s2\"), (\"s2\", \"b\", \"s3\"), (\"s3\", \"a\", \"s3\")],\n", + " #Initial state\n", + " \"s1\",\n", + " #Terminal states\n", + " [\"s3\"]\n", + ")\n", + "print(\"Initial state:\", ab_a_.state) # note, no parens after `state` because it's a value field and not a function\n", + "print(\"Accepting?\", ab_a_.is_terminal()) # parens after `is_terminal` to _call_ it.\n", + "ab_a_.advance(\"a\")\n", + "print(\"After a:\", ab_a_.state)\n", + "ab_a_.advance(\"b\")\n", + "print(\"After ab:\", ab_a_.state)\n", + "print(\"Next steps:\", ab_a_.out_edges())\n", + "print(\"Accepting?\", ab_a_.is_terminal())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Assignment 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The first part of the assignment is to define the function `check(...)` below:" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def check(sm, string):\n", + " for i in string:\n", + " if i in sm.out_edges():\n", + " sm.advance(i)\n", + " else:\n", + " return False\n", + " return sm.is_terminal() # FIXME: if and only if `sm` accepts `string`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It should give the correct results for at least these examples, and we encourage you to try out more tests." + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Test suite 1. Should not throw any errors.\n", + "# (First, we define a function to produce the test state machine so we can use a fresh one every time.)\n", + "def test1():\n", + " # This one accepts \"h(e(llo|y) | i(hi)*)\n", + " return StateMachine(\n", + " [(\"s1\", \"h\", \"s2\"), (\"s2\", \"e\", \"s3\"), \n", + " (\"s3\", \"y\", \"s4\"), \n", + " (\"s3\", \"l\", \"s5\"), (\"s5\", \"l\", \"s6\"), (\"s6\", \"o\", \"s7\"),\n", + " (\"s2\", \"i\", \"s8\"), (\"s8\", \"h\", \"s9\"), (\"s9\", \"i\", \"s8\")\n", + " ],\n", + " \"s1\",\n", + " [\"s4\", \"s7\", \"s8\"]\n", + " )\n", + "assert check(test1(), \"hello\")\n", + "assert check(test1(), \"hey\")\n", + "assert check(test1(), \"hi\")\n", + "assert check(test1(), \"hihi\")\n", + "assert check(test1(), \"hihihi\")\n", + "assert not check(test1(), \"greetings\")\n", + "assert not check(test1(), \"hel\")\n", + "assert not check(test1(), \"helloy\")\n", + "assert not check(test1(), \"hih\")\n", + "assert not check(test1(), \"heyhey\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, define a state machine which accepts email addresses consisting only of the letter \"x\" and the symbols \"@\" and \".\" (in other words, you don't need a ton of edges). Devise tests for it below (try to be sinister---get a partner to come up with adversarial examples too)." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def test2(): \n", + " # TODO: define transition system here:\n", + " return StateMachine([(\"s1\", \"x\", \"s1\"),\n", + " (\"s1\", \"@\", \"s2\"),\n", + " (\"s2\", \"x\", \"s3\"),\n", + " (\"s3\", \"x\", \"s3\"),\n", + " (\"s3\", \".\", \"s4\"),\n", + " (\"s4\", \"x\", \"s5\"),\n", + " (\"s5\", \"x\", \"s5\"),\n", + " (\"s5\", \".\", \"s4\")],\n", + " \"s1\",\n", + " [\"s5\"])\n", + "# TODO: tests go here\n", + "assert check(test2(), \"xxx@xxxxxxx.xxxxxxx\")\n", + "assert check(test2(), \"xxx@xxx.x.x.x.x\")\n", + "assert not check(test2(), \"xxx@x@.x\")\n", + "assert not check(test2(), \"x@.x\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Assignment 2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Define a function which, given a state machine, generates all the strings of a given (exact) length that the state machine would accept.\n", + "\n", + "If you have an intuition on how to do this, feel free to try it! Insert your attempt and its tests in the empty code cell just after this one. Then come back and take a look at the approach below." + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (, line 5)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m5\u001b[0m\n\u001b[0;31m for x3 in range (1, length-1-x1-x2)\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "def try_sample(sm, length):\n", + " str = \"\"\n", + " for x1 in range (1, length-3):\n", + " for x2 in range (1, length-2-x1):\n", + " for x3 in range (1, length-1-x1-x2)\n", + " str = \"x\"*x1 + \"@\" + \"x\"*x2 + \".\" x\"*x3\n", + " return []" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that any path through a state machine ending in a terminal state is a valid string, and each step of the path is associated with a symbol (i.e., a letter). To combine symbols together into strings, you can use string concatenation:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "ab = \"a\" + \"b\"\n", + "print(ab)\n", + "abc = ab + \"c\"\n", + "print(abc)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can combine lists the same way:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "lst_abc = [\"a\",\"b\"] + [\"c\"]\n", + "print(lst_abc)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "All that's left is enumerating the valid paths of a given length and assembling those into strings. The skeleton below is a _recursive_ function that calls itself repeatedly, branching out according to each option. You can imagine that the call to `sample()` is the root of a tree of calls to `sample2`, and the paths through that tree are paths through the state machine---the path itself is \"stored\" in the third argument to `sample2`. In other words:\n", + "\n", + "* To get the possible paths of length `K` from a state machine `SM`:\n", + " * Initialize `S` to `SM`'s current state.\n", + " * Initialize the `result` to `[]`\n", + " * For each available out-edge at `S`:\n", + " * Advance `SM` along that edge\n", + " * Get the possible paths of length `K-1` from `SM` and add them to the result\n", + " * Put `SM` back into state `S` (so we can advance it along the next available out edge)\n", + " * Yield `result`\n", + "\n", + "It's up to you to figure out how to find the possible paths of length 0. Hint: How many such paths can there be for a given call to `sample2(sm, 0, sofar)`? What aspects of the state machine's status does it depend on?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Starter function that calls sample2() with an empty string as argument. This is just to \"accumulate\" paths into\n", + "# that argument without tracking a bunch of data externally.\n", + "def sample(sm, length):\n", + " return sample2(sm, length, \"\")\n", + "\n", + "# sample2 samples paths of length \"length\" from the state machine sm as of its current state.\n", + "# sofar is the path assembled so far.\n", + "# sample2 returns a list of paths.\n", + "def sample2(sm, length, sofar):\n", + " if length == 0:\n", + " # TODO: What path(s) should be returned? When?\n", + " if sm.is_terminal():\n", + " return []\n", + " else:\n", + " return [sofar]\n", + " state = sm.state\n", + " result = []\n", + " for out in sm.out_edges():\n", + " sm.advance(out)\n", + " result += sample2(sm, length-1, sofar + out)\n", + " sm.state = state\n", + " \n", + " # TODO: implement the rest of the pseudocode above\n", + " return result" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "assert len(sample(test2(), 0)) == 0\n", + "assert len(sample(test2(), 1)) == 0\n", + "assert len(sample(test2(), 2)) == 0\n", + "assert len(sample(test2(), 3)) == 0\n", + "assert len(sample(test2(), 4)) == 0\n", + "assert len(sample(test2(), 5)) == 1\n", + "assert len(sample(test2(), 6)) == 3\n", + "assert len(sample(test2(), 7)) == 7\n", + "assert len(sample(test2(), 8)) == 14\n", + "\n", + "all_samples = []\n", + "for i in range(0, 9):\n", + " all_samples = all_samples + sample(test2(), i)\n", + "print(all_samples)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# What's next?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you like (and have time), define more test state machines in new test cells (test3, test4, etc). What types of string are easy to recognize, and which seem hard---or even impossible? You might want to try some of these and determine whether they're possible within the limits of state machines:\n", + "\n", + "* Phone numbers\n", + "* URLs\n", + "* Palindromes\n", + "* HTML tags\n", + "* English-language numbers (e.g. \"seventy-one\", \"nineteen\", \"six\", \"one hundred and one\")\n", + "* Roman numerals\n", + "\n", + "Another (bigger) project might be to write a regular expression compiler to generate state machines from regular expressions---even just supporting concatenation and Kleene star would be a fun exercise for an evening!\n", + "\n", + "If you have an interest in the theory behind computer science, you might want to implement a non-deterministic automaton which can be in (or start in) several states simultaneously, may have out-edges to multiple distinct states on a given symbol, or may even have \"null\" or \"epsilon\" transitions which can be taken without consuming any input at all! Another good project here might involve taking the intersection or union of two languages (by manipulating their state machines)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "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.5.0b2" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/projects/3-mazes/Kwan.ipynb b/projects/3-mazes/Kwan.ipynb new file mode 100644 index 0000000..bebadc8 --- /dev/null +++ b/projects/3-mazes/Kwan.ipynb @@ -0,0 +1,887 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, we load up some useful libraries for visualization and data structures." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline\n", + "\n", + "import matplotlib\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import matplotlib.patches as patches\n", + "import matplotlib.axes as axes\n", + "import copy\n", + "import random\n", + "from random import randint\n", + "import functools\n", + "from queue import PriorityQueue" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next we need a Maze class for pathfinding. It will help to have read the RedBlobGames [A\\* tutorial](http://www.redblobgames.com/pathfinding/a-star/introduction.html) before continuing.\n", + "\n", + "These Mazes are defined in ASCII diagrams and can have walls (\"#\"), empty spaces (\".\"), switches (numbers), and doors (letters; closed are uppercase). The \"0\" switch toggles the open status of all the \"a\" doors, \"1\" goes to the \"b\" doors, etc. Mazes can also contain pits: \"?\" pits have a 30% chance of killing the player and \"!\" pits have a 60% chance. Every maze has one player start location \"@\" and one goal square \"X\". Walls and closed doors block movement." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[(1, 0), (0, -1), (0, 1), 'switch']\n" + ] + }, + { + "data": { + "image/png": "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\nNCK+L+mniSFZLywrMZ+UaW3FfG9ExKFi+6yko7r8mpcsayw5l5R3feeLzavV+Uyu9/127udv2HxS\nxvXZnpK0WtKXBgyZ9vqqCIlRX3xVZj5Juqs4vdple8kM55pJPaO4sKyStdlepM5ZzN6eXdnXmJhL\nyri+4lT8oKQ3JH0vIvb1DMm6thLzSXmfv89L+oz6h5E0g/VNysVU+yUtjIil6nwPZXvN9eRUydps\nz5X0DUmPFT/lKzNkrqzri4h3I+J2SVOS7qz4B0aZ+bKtz/Z9kk4VZ2dWpjOUKkLipKSFXfenisd6\nx9w4ZEy2+SLi7KXTvojYLel9tq+b4Xxl6sm1tqGqWJvtK9V50X4tInb0GZJtjcPmquq5i4ifSXpR\n0r09uyp5/gbNl3l9d0u63/arkv5O0j22t/WMmfb6qgiJ9y6+sn2VOhdf9X7KulPSOum9Kzr7XnyV\na77u91y2l6nzq9+3ZjiflE7pnGsbOl8Fa5OkL0s6EhFfGLA/5xqTc+Vcn+3rbc8rtq+V9FFJx3qG\nZVtbmflyri8iHo+IhRHx6+q8Dl6IiHU9w6a9vjJXXE630JFefFVmPklrbT8q6aKkC5Iemul8tr8u\naaWkD9j+iaSNkq6qYm1l5lPGtRXz3S3pk5IOF++lQ9Lj6vz2KOsay8yVeX0flPRVd/78wRxJzxZr\nqerCwKHzZV5fX7NdHxdTAUialA8uAcwQIQEgiZAAkERIAEgiJAAkERIAkggJAEmEBICk/wcIaVhE\n+nYwOwAAAABJRU5ErkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "@functools.total_ordering\n", + "class Maze:\n", + " SwitchMap = {\"0\":\"a\", \"1\":\"b\", \"2\":\"c\", \"3\":\"d\", \"4\":\"e\", \"5\":\"f\", \"6\":\"g\", \"7\":\"h\", \"8\":\"i\", \"9\":\"j\"}\n", + " Colors = {\"a\":\"coral\",\"b\":\"tan\",\"c\":\"palegreen\",\"d\":\"blue\",\"e\":\"cyan\",\"f\":\"magenta\",\"g\":\"yellow\",\"h\":\"olive\",\"i\":\"purple\",\"j\":\"darkgreen\",\n", + " \"0\":\"coral\",\"1\":\"tan\",\"2\":\"palegreen\",\"3\":\"blue\",\"4\":\"cyan\",\"5\":\"magenta\",\"6\":\"yellow\",\"7\":\"olive\",\"8\":\"purple\",\"9\":\"darkgreen\",\n", + " \"?\":\"orange\",\n", + " \"!\":\"red\",\n", + " \"x\":\"green\",\"@\":\"gray\",\n", + " \"#\":\"sienna\",\".\":\"white\"}\n", + " \n", + " def __init__(self,rows):\n", + " self.grid = [list(r) for r in rows]\n", + " self.grid.reverse()\n", + " \n", + " # additional variables\n", + " self.cost = 0\n", + " \n", + " height = len(self.grid)\n", + " width = len(self.grid[0])\n", + " self.exit_pos = None\n", + " self.player_pos = None\n", + " self.player_alive = True\n", + " for y in range(0,height):\n", + " assert len(self.grid[y]) == width, \"All rows must be equal length!\"\n", + " for x in range(0,width):\n", + " c = self.grid[y][x]\n", + " assert c == \"#\" or c == \".\" or c == \"!\" or c == \"?\" or c == \"@\" or c.isalnum()\n", + " if c.lower() == \"x\":\n", + " assert self.exit_pos == None\n", + " self.exit_pos = (x,y)\n", + " if c == \"@\":\n", + " assert self.player_pos == None\n", + " self.player_pos = (x,y)\n", + " self.grid[y][x] = \".\"\n", + " \n", + " def clone(self):\n", + " return copy.deepcopy(self)\n", + " \n", + " def toggle_cell(self,switchnum,c):\n", + " if c.isalpha() and Maze.SwitchMap[switchnum] == c.lower():\n", + " if c.islower():\n", + " return c.upper()\n", + " else:\n", + " return c.lower()\n", + " return c\n", + " \n", + " def toggle(self):\n", + " assert self.player_alive\n", + " height = len(self.grid)\n", + " width = len(self.grid[0])\n", + " (px,py) = self.player_pos\n", + " switchnum = self.grid[py][px]\n", + " assert switchnum.isnumeric()\n", + " for y in range(0,height):\n", + " for x in range(0,width):\n", + " self.grid[y][x] = self.toggle_cell(switchnum,self.grid[y][x])\n", + " \n", + " def is_free(self,x,y):\n", + " if y < 0 or y >= len(self.grid):\n", + " return False\n", + " if x < 0 or x >= len(self.grid[0]):\n", + " return False\n", + " cell = self.grid[y][x]\n", + " return (\n", + " cell == \".\" or cell == \"X\" or\n", + " cell == \"?\" or cell == \"!\" or \n", + " (cell.isalpha() and cell.islower()) or cell.isnumeric()\n", + " )\n", + " \n", + " def __hash__(self):\n", + " return hash(str(self.grid)) % 1000007 + hash(self.player_pos) % 1000007 + hash(self.player_alive) % 1000007\n", + " \n", + " def _is_valid_operand(self, other):\n", + " return (hasattr(other, \"grid\") and hasattr(other, \"player_pos\") and hasattr(other, \"player_alive\"))\n", + " \n", + " def __eq__(self, other):\n", + " if not self._is_valid_operand(other):\n", + " return NotImplemented\n", + " return ((self.grid, self.player_pos, self.player_alive) ==\n", + " (other.grid, other.player_pos, other.player_alive))\n", + " \n", + " def __lt__(self, other):\n", + " if not self._is_valid_operand(other):\n", + " return NotImplemented\n", + " return ((self.grid, self.player_pos, self.player_alive) <\n", + " (other.grid, other.player_pos, other.player_alive))\n", + " \n", + " def move_player(self,dx,dy):\n", + " assert self.player_alive\n", + " assert abs(dx)+abs(dy) == 1\n", + " (x,y) = self.player_pos\n", + " (newx,newy) = (x+dx,y+dy)\n", + " assert self.is_free(newx,newy)\n", + " self.player_pos = (x+dx,y+dy)\n", + " cell = self.grid[y+dy][x+dx]\n", + " if cell == \"?\" and random.random() < 0.3:\n", + " self.player_alive = False\n", + " if cell == \"!\" and random.random() < 0.6:\n", + " self.player_alive = False\n", + " \n", + " def available_moves(self):\n", + " if not self.player_alive:\n", + " return []\n", + " (x,y) = self.player_pos\n", + " can_switch = self.grid[y][x].isnumeric()\n", + " return [(dx,dy) for (dx,dy) in [(-1,0),(1,0),(0,-1),(0,1)] if self.is_free(x+dx,y+dy)] + (\n", + " [\"switch\"] if can_switch else []\n", + " )\n", + " \n", + " def is_at_exit(self):\n", + " return self.player_alive and self.player_pos == self.exit_pos\n", + " \n", + " def draw(self):\n", + " fig1 = plt.figure()\n", + " ax1 = fig1.add_subplot(1,1,1, aspect='equal')\n", + " ax1.set_axis_bgcolor('sienna')\n", + " height = len(self.grid)\n", + " width = len(self.grid[0])\n", + " ax1.set_xlim([0,width])\n", + " ax1.set_ylim([0,height])\n", + " for y in range(0,height):\n", + " for x in range(0,width):\n", + " cell = self.grid[y][x]\n", + " if cell == \"#\": continue\n", + " is_door = cell.isalpha() and cell.lower() != \"x\"\n", + " is_pit = cell == \"?\" or cell == \"!\"\n", + " is_open = is_door and cell.islower()\n", + " is_switch = cell.isnumeric()\n", + " ax1.add_patch(\n", + " patches.Rectangle((x, y),\n", + " 1,1,\n", + " fill=True,\n", + " facecolor=Maze.Colors[cell.lower()],\n", + " edgecolor=\"black\",\n", + " hatch=\"/\" if is_switch else (\"-\" if (is_door and not is_open) else None),\n", + " label=cell)\n", + " )\n", + " ax1.add_patch(\n", + " patches.Rectangle(self.player_pos,\n", + " 1,1,\n", + " fill=True,\n", + " hatch=\"x\" if not self.player_alive else None,\n", + " facecolor=Maze.Colors[\"@\"] if self.player_alive else \"black\",\n", + " edgecolor=Maze.Colors[\"@\"] if self.player_alive else \"white\")\n", + " )\n", + " plt.show(fig1)\n", + " \n", + " def update_move(self,path):\n", + " for pos in path:\n", + " self.grid[pos[1]][pos[0]] = \"g\"\n", + "\n", + "sample=Maze([\n", + " \"##X#\",\n", + " \"#.A#\",\n", + " \"#0?#\",\n", + " \"a@##\"\n", + " ])\n", + "sample.move_player(0,1)\n", + "print(sample.available_moves())\n", + "sample.move_player(1,0)\n", + "sample.draw()\n", + "\n", + "sample2 = Maze([\n", + " \"##X#\",\n", + " \"#.A#\",\n", + " \"#0?#\",\n", + " \"a@##\"\n", + " ])\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Assignment 1\n", + "\n", + "Write a function to solve pathfinding and switch-and-door puzzles with one of the heuristic search algorithms described during the lecture. Try it on the provided sample puzzles; if a puzzle gives your algorithm trouble, try to explain why that happens. Make sure the path you're getting is the actual shortest path!\n", + "\n", + "Try to get this assignment done by Friday; the other two may take a little longer but the sooner you attempt them the earlier you can get feedback!\n", + "\n", + "You may also try visualizing paths through the maze, implementing several different heuristic searches, comparing against aheuristic search, etc.\n", + "\n", + "Generating mazes automatically would also be a great exercise!" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def manhattan(goal, current):\n", + " (x1, y1) = goal\n", + " (x2, y2) = current\n", + " return abs(x1-x2) + abs(y1-y2)\n", + "\n", + "def heuristic(maze):\n", + " # Return a path which solves the maze: a sequence of elements like (dx,dy) or \"switch\".\n", + " # You can use maze.exit_pos and query maze.grid[row][column] to investigate the maze.\n", + " path = [maze.player_pos]\n", + " \n", + " frontier = PriorityQueue()\n", + " frontier.put((0, maze, path))\n", + " \n", + " mazes_used = {} # key is maze and value is maze previous to it\n", + " mazes_used[maze] = None\n", + " \n", + " new_path = []\n", + " \n", + " while not frontier.empty():\n", + " current = frontier.get()\n", + " \n", + " if not current[1].is_at_exit(): # if not at exit\n", + " for m in current[1].available_moves():\n", + " successor = current[1].clone()\n", + " if m == \"switch\":\n", + " successor.toggle()\n", + " new_path = list(current[2])\n", + " else:\n", + " (x,y) = m\n", + " successor.move_player(x,y)\n", + " next_pos = (current[1].player_pos[0] + m[0], current[1].player_pos[1] + m[1])\n", + " new_path = list(current[2]) + [next_pos]\n", + " successor.cost = current[1].cost + 1\n", + " \n", + " if successor not in mazes_used or successor.cost < current[1].cost:\n", + " priority = successor.cost + manhattan(successor.exit_pos, successor.player_pos)\n", + " frontier.put((priority, successor, new_path))\n", + " mazes_used[successor] = current # current is the predecessor of successor\n", + " else: # if reached exit\n", + " current[2].pop()\n", + " return current[2]\n", + " return []" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false, + "scrolled": true + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAOIAAAEACAYAAACu66rqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAADgdJREFUeJzt3V+MXHd5xvHvs3bi3fU2Cy12CpiYoMpKgoIcq00iTFqo\nAzUBBWGpgoAUOaroRWkdpTUQ5SbxRS9AQjRSK1UREAM1EGW7blIp0BiCQFA1dmI72cTr0sZJ7fyz\njQBbazvIjt9ezHHlrnc9Z9fnN3l3z/ORVjuzOvP7vWfGj8+Zc2beo4jAzN5YfW90AWbmIJql4CCa\nJeAgmiXgIJol4CCaJVAriJJulzRW/WwoXZRZ23QNoqR3A38G/D6wEviopHeVLsysTepsEa8EHo+I\n30TE68BPgHVlyzJrlzpBfAa4QdKbJQ0CNwHvKFuWWbss7LZAROyV9EVgGzAB7AJeL12YWZtopp81\nlfS3wIGI+MdJf/eHVs2mEBHqtkzXLSKApCURcVjSZcDHgeunWm7zuqtnVuEMbN1zkI9fdWmx8T1H\nrjnmwzoArB8dq7VcrSAC/yzpt4GTwF9ExNHZFmZm56oVxIj4w9KFmLXZnPlkzRVLFnuOFs0xH9Zh\nJmZ8sGbagaQo+R7RbC5aPzpW62DNnNkims1nDqJZAg6iWQIOolkCDqJZAg6iWQIOolkCDqJZAg6i\nWQIOolkCDqJZAg6iWQIOolkCDqJZAnUbDN8h6RlJT0vaIuni0oWZtUmdBsNvA/4KWBUR76Hzrf5P\nli7MrE3q9qxZACyWdBoYBF4uV5JZ+3TdIkbEy8CXgf3AS8CvI+IHpQsza5OuW0RJbwI+BiwHjgAj\nkj4VEd+evOzWPQf/7/YVSxZz5ZKhxgrd8G/jHD12qrHxpjLQ38+J114rOsfS4SG+tObyonN8/ofP\nc+jIRNE5Bgb6OXGi3HNVenwo81qMH55g7+FjM35cnV3TG4F9EfFLAEmjwHuBc4JYskfk0WOn4J5i\nwwNw4p7XaKqHz3Skru1LLtihIxM9WY+Sc5Qe/8wcTbtyydD/2wA9tPdQrcfVOWq6H7heUr86la8B\nxmdTpJlNrc57xO3ACJ1rXjwFCLivcF1mrVK3wfAmYFPhWsxay5+sMUvAQTRLwEE0S8BBNEvAQTRL\nwEE0S8BBNEvAQTRLwEE0S8BBNEvAQTRLwEE0S8BBNEvAQTRLwEE0S8BBNEugTl/TFZJ2SdpZ/T4i\naUMvijNri67f0I+InwPXAEjqA14Ethauy6xVZrpreiPwXEQcKFGMWVvNNIifAL5TohCzNqvbch9J\nFwE3A3dOt0zJBsO6COKexoab0qL+RcX7ji4dbu45mc7AQH/x9ejvLztH6fGh8zw1rWSD4TM+DDwZ\nEYenW6Bkg+E4SU8azm5ed3XROXrhxIneNEou+VytHx1zg+Fp3IJ3S82KqHt9xEE6B2pGy5Zj1k51\nGwwfB5YUrsWstfzJGrMEHESzBBxEswQcRLMEHESzBBxEswQcRLMEHESzBBxEswQcRLMEHESzBBxE\nswQcRLMEHESzBBxEswQcRLME6n5Df1jSg5LGJT0r6brShZm1Sd3mUfcCj0TEn0paCAwWrMmsdboG\nUdIlwA0RsR4gIk4BRwvXZdYqdXZNLwd+Ien+6voX90kaKF2YWZvU2TVdCKwCPhsRT0j6OzpNhu+e\nvGDJBsO9aJpbouHsZJ//4fMcOjJRdI652px38vhzcR1KNhh+ETgQEU9U90eAL0y1YMkGw71qmlva\noSMTPVmPuf5czdXXu1iD4Yg4CByQtKL60xpgzyxqNLNp1D1qugHYUl3/Yh9wW7mSzNqnboPhp4A/\nKFyLWWv5kzVmCTiIZgk4iGYJOIhmCTiIZgk4iGYJOIhmCTiIZgk4iGYJOIhmCTiIZgk4iGYJOIhm\nCTiIZgk4iGYJ1Po+oqQXgCPAaeBkRFxbsiiztqn7Df3TwPsj4lclizFrq7q7pprBsmY2Q3XDFcA2\nSTskfaZkQWZtVHfXdHVEvCJpCZ1AjkfET0sWZtYmdZtHvVL9PixpK3AtcE4Q53qD4f7+ftaPjhWf\noxfrMReb804efy6uQ7EGw5IGgb6ImJC0GPgQsGmqZedDg2HPUX+OktrWYLjOFvFSYKukqJbfEhGP\nzqZIM5ta1yBGxPPAyh7UYtZaPiVhloCDaJaAg2iWgINoloCDaJaAg2iWgINoloCDaJaAg2iWgINo\nloCDaJaAg2iWgINoloCDaJaAg2iWgINolkDtIErqk7RT0sMlCzJro5lsEW8H9pQqxKzNagVR0jLg\nJuCrZcsxa6e6W8SvAJ+j02jYzBrWNYiSPgIcjIjddFrvl+2jZ9ZCddoprgZulnQTMAD8lqRvRsSt\nkxecDw2Ge9HUdj6sR+lmzHO1SXKxBsMRcRdwF4CkPwL+ZqoQwvxoMLx53dVF5+iF9aNjc76J8Vxt\nkjzbBsM+j2iWQN2L0AAQET8GflyoFrPW8hbRLAEH0SwBB9EsAQfRLAEH0SwBB9EsAQfRLAEH0SwB\nB9EsAQfRLAEH0SwBB9EsAQfRLAEH0SwBB9EsAQfRLIGuXwyWtAj4CXBxtfxIRGwqXZhZm9TpWfMb\nSR+IiOOSFgA/k/S9iNjeg/rMWqHWrmlEHK9uLqITXvc3NWtQ3U7ffZJ2Aa8C2yJiR9myzNqlVvOo\niDgNXCPpEuBfJF0VEedcB2M+9DUt2asTYOnwEF9ac3nROeZD79Re9DVdOtzcv88zivU1PVtEHJX0\nI2AtU1yQZj70NZ2LvTQnmw/P1VztMVusr6mkt0garm4PAB8E9s6uTDObSp0t4luBb0jqoxPcByLi\nkbJlmbVLndMXY8CqHtRi1lr+ZI1ZAg6iWQIOolkCDqJZAg6iWQIOolkCDqJZAg6iWQIOolkCDqJZ\nAg6iWQIOolkCDqJZAg6iWQIOolkCDqJZAnVaZSyT9JikZyWNSdrQi8LM2qROq4xTwF9HxG5JQ8CT\nkh6NCPetMWtI1y1iRLwaEbur2xPAOPD20oWZtcmM3iNKeiewEni8RDFmbVW7r2m1WzoC3F5tGc9R\nssHw0uGhOd80FzrNf0ubDw2GN27cyAtDzTcAPtvxY8e46rnvNzpm0QbDkhbSCeG3IuKh6ZYr2WC4\ndHdsgPWjY24wXFPpBsObNpW/4Njg4sWNj1mswXDl68CeiLh35qWZWTd1Tl+sBj4N/LGkXZJ2Slpb\nvjSz9qjTYPhnwIIe1GLWWv5kjVkCDqJZAg6iWQIOolkCDqJZAg6iWQIOolkCDqJZAg6iWQIOolkC\nDqJZAg6iWQIOolkCDqJZAg6iWQIOolkCdb6h/zVJByU93YuCzNqozhbxfuBPShdi1mZ1Ggz/FPhV\nD2oxay2/RzRLoHaD4TpKNhjuhV40MV46XP456cV6lG5ivHHjRoZ60GC4abNtMKw6TWIlLQf+NSLe\nc55lYvO6q2dcgNl8VjWt7vo/Vt1dU1U/ZlZAndMX3wb+HVghab+k28qXZdYudRoMf6oXhZi1mY+a\nmiXgIJol4CCaJeAgmiXgIJol4CCaJeAgmiXgIJol4CCaJeAgmiXgIJol4CCaJeAgmiXgIJol4CCa\nJVAriJLWStor6eeSvlC6KLO2qfMN/T7g7+n0Nn03cIukK0oXNtn44QnP0aI55sM6zESdLeK1wH9F\nxP9ExEngu8DHypZ1rtl0xvIcc3eO+bAOM1EniG8HDpx1/8Xqb2bWEB+sMUuga19TSdcD90TE2ur+\nnUBExBcnLde9QapZC9Xpa1oniAuA/wTWAK8A24FbImK8iSLNrF47xdcl/SXwKJ1d2a85hGbNqtVy\n38zKuuCDNaVP9vfiQqmSlkl6TNKzksYkbSgwxyJJj0vaVc1xd9NzVPP0Sdop6eFC478g6alqPbYX\nmmNY0oOSxqvX5LqGx19R1b+z+n2k6ddc0h2SnpH0tKQtki4+7wMiYtY/dIL838By4CJgN3DFhYw5\nxRzvA1YCTzc57qQ5fhdYWd0eovOeuNH1qMYerH4vAP4DuLbAHHcA/wQ8XOi52ge8udRrUc2xGbit\nur0QuKTgXH3Ay8A7GhzzbdXzdHF1/wHg1vM95kK3iMVP9kcPLpQaEa9GxO7q9gQwToFzpRFxvLq5\niM4/sEbfF0haBtwEfLXJcSdPQ8HTXpIuAW6IiPsBIuJURBwtNR9wI/BcRBzouuTMLAAWS1oIDNIJ\n+7Qu9Amddyf7Jb2Tzhb48QJj90naBbwKbIuIHQ1P8RXgczQc8EkC2CZph6TPFBj/cuAXku6vdh3v\nkzRQYJ4zPgF8p8kBI+Jl4MvAfuAl4NcR8YPzPcYn9M8iaQgYAW6vtoyNiojTEXENsAy4TtJVTY0t\n6SPAwWrLXvIyeqsjYhWdLe9nJb2v4fEXAquAf6jmOQ7c2fAcAEi6CLgZeLDhcd9EZ89wOZ3d1CFJ\n572Y04UG8SXgsrPuL6v+NudUuxAjwLci4qGSc1W7Wj8C1jY47GrgZkn76PwP/wFJ32xwfAAi4pXq\n92FgK523J016ETgQEU9U90foBLOEDwNPVuvSpBuBfRHxy4h4HRgF3nu+B1xoEHcAvydpeXVU6JNA\niaN1vbhQ6teBPRFxb4nBJb1F0nB1ewD4ILC3qfEj4q6IuCwi3kXndXgsIm5tanwASYPVXgOSFgMf\nAp5pco6IOAgckLSi+tMaYE+Tc5zlFhreLa3sB66X1K/O9c3X0DnuMK2uJ/TPJ3pwsr+6UOr7gd+R\ntB+4+8wb+QbnWA18Ghir3sMFcFdEfL/Bad4KfKP6Wlkf8EBEPNLg+L1wKbC1+jjjQmBLRDxaYJ4N\nwJZq13Ef0PjFcSUN0tly/XnTY0fEdkkjwC7gZPX7vvPWUx1eNbM3kA/WmCXgIJol4CCaJeAgmiXg\nIJol4CCaJeAgmiXgIJol8L9rYl7TkKjgYwAAAABJRU5ErkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAU8AAAD7CAYAAADq4RYlAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAADv1JREFUeJzt3X9s3PV9x/HXC9LKxh5pJzlBNCqk3Wgc1I5F2sqKqmkN\niKyVSKk0idKpNftv6hrUVm0p+6P0n4pGVB37KaFSyiZYpaaJgqYysjRSpa5aGYVAwDZDAzUBhu2q\nbZDdZCLlvT/uktmObcL7+/n6PoefDynS3eX8udfd+V73/d6d7+2IEADg9Tmv1wEAoB9RngCQQHkC\nQALlCQAJlCcAJFCeAJCwru0LsM1noQD0rYjwUqe3Xp6S9K2PvHs1LiZt3/iUrt+6sdcxllV7Pqn+\njLXnk+rPWHs+qXzGsb1Hlv0/dtsBIIHyBIAEylPSlpGhXkdYUe35pPoz1p5Pqj9j7fmk1c3otv+2\n3XbU/ponACxlbO+RZd8wYssTABIoTwBIoDwBIIHyBIAEyhMAEihPAEigPAEggfIEgATKEwASXrM8\nbd9te8r2E/NOe6vtA7aftv2Q7fXtxgSAupzLluc9kq5ddNotkg5GxLskHZL0xdLBAKBmr1meEfFD\nSb9YdPJOSfd2D98r6cOFcwFA1bKveW6IiClJioiXJG0oFwkA6lfqDSNGbQBYU7JjOKZsb4yIKdsX\nSZpe6cz7xqfOHN4yMqTRkeHkxUq7HprQy3On0j+/lAuH1umvrx0ttt74O3fogqFy3ys4OzurO+64\no9h6G9YPa/f2zcXWk6TPf/85TR+fLbZe6Yyl80nS4OCATpw4We16a/E2bHqdJ2ZmNTkzd07nPdfy\ndPffaQ9IGpP0VUmfkLR/pR8uOVPk5blT0m3FluuseVvZMi5ZnJI0PDyskt+7ai/59YSNTB+frTpj\n6XxSJ2Pp68xt2Hy9JkZHhhds3O2fXH678Fw+qnS/pB9Jusz2Uds3Sbpd0jW2n5a0vXscANaM19zy\njIgbl/mvqwtnAYC+wV8YAUAC5QkACZQnACRQngCQQHkCQALlCQAJlCcAJFCeAJBAeQJAAuUJAAmU\nJwAkUJ4AkEB5AkAC5QkACZQnACRQngCQkJ1h1DN+kxS3lV+zpF/NzRWfYVRypMLAwIDG9h4ptt7p\nNWvOWDpfG2tyGzY3ODhQbK3X0nflGa+olTkqJW39738tut7Y3iNVz8ppY83a1zu95rc+8u5i69V+\nP/fL781qYbcdABIoTwBIoDwBIIHyBIAEyhMAEihPAEigPAEggfIEgATKEwASKE8ASKA8ASCB8gSA\nBMoTABIoTwBIaFSetj9t+0nbT9i+z/abSwUDgJqly9P2xZI+JWlbRLxHne8GvaFUMACoWdMvQz5f\n0pDtVyVdIOnF5pEAoH7pLc+IeFHS1yQdlfSCpF9GxMFSwQCgZuktT9tvkbRT0iWSjkvaY/vGiLh/\n8Xn3jU+dObxlZEijI8PZi9XgYPk5KqXnnnz++89p+vhssfVKX+d+mEVT+3pS+d+b2u/nfvi9aXqf\nTMzManJm7pzO22S3/WpJz0bEzyXJ9l5J75N0Vnlev3Vjg4tZ6MSJk9XPMJo+Plt8LkvNs3Kk+jO2\nNX+npNK/223MByp5H0vt3M9NjI4ML9i42z85vex5m7zbflTSlbYH3Em8XdJEg/UAoG80ec3zYUl7\nJD0m6XFJlnRXoVwAULVG77ZHxJclfblQFgDoG/yFEQAkUJ4AkEB5AkAC5QkACZQnACRQngCQQHkC\nQALlCQAJlCcAJFCeAJBAeQJAAuUJAAmUJwAkUJ4AkEB5AkAC5QkACU1HD6+6NgbADQwMaGzvkaLr\n1TTUaqn1GIZWZs2af2/a+D0seX2l+h8rK+m78mxrAFztg7dK6ocherUPQ2tjzdoHtrU1OLDmx8pK\n2G0HgATKEwASKE8ASKA8ASCB8gSABMoTABIoTwBIoDwBIIHyBIAEyhMAEihPAEigPAEggfIEgATK\nEwASGpWn7fW2v2N7wvZTtt9bKhgA1Kzp93neKel7EfEnttdJuqBAJgCoXro8bV8o6f0RMSZJEXFK\n0suFcgFA1Zrstm+W9DPb99h+1PZdtgdLBQOAmjXZbV8naZukT0bEI7b/StItkr60+Iz7xqfOHN4y\nMqTRkeH0hbY1w6j22TElrcU5UG3NMKo5Y+33SRtrNn2sTMzManJm7pzO26Q8n5d0LCIe6R7fI+kL\nS53x+q0bG1zMQm3N36l51kvt84Gk/pjnw3Wua7021mz6WBkdGV6wcbd/cnrZ86Z32yNiStIx25d1\nT9ouaTy7HgD0k6bvtu+SdJ/tN0l6VtJNzSMBQP0alWdEPC7p9wplAYC+wV8YAUAC5QkACZQnACRQ\nngCQQHkCQALlCQAJlCcAJFCeAJBAeQJAAuUJAAmUJwAkUJ4AkEB5AkAC5QkACZQnACQ0/TLkVdfG\n/J3aZwSVzrdh/XD1s2hqX6+NNdfaem2sWfqxspK+K8+25u+UVDpj6Xy7t28uup7UztymmudKSe3M\n36n5Oq+FGUavB7vtAJBAeQJAAuUJAAmUJwAkUJ4AkEB5AkAC5QkACZQnACRQngCQQHkCQALlCQAJ\nlCcAJFCeAJBAeQJAQuPytH2e7UdtP1AiEAD0gxJbnjdLGi+wDgD0jUblaXuTpA9K+kaZOADQH5pu\neX5d0ucklf16aQCoXLo8bX9I0lREHJbk7j8AWBOcnR9i+yuS/lTSKUmDkn5D0t6I+Pii88XOLRvO\nHN8yMqTRkeF04D9/8BmdOHEy/fNLGRgY0MmT5dasfb3BwYHit2HpNUuvV/o2bGPN2q9zv9yG//DH\nv53++YmZWU3OzJ05vn9yWhGx5IZhegBcRNwq6VZJsv2Hkj67uDhPu37rxuzFnKWtAXA1D8qqfb3T\na67F4WVr6TqXvr5SO9e5idGR4QUbd/snp5c9L5/zBICEIqOHI+IHkn5QYi0A6AdseQJAAuUJAAmU\nJwAkUJ4AkEB5AkAC5QkACZQnACRQngCQQHkCQALlCQAJlCcAJFCeAJBAeQJAAuUJAAmUJwAkUJ4A\nkFDky5BX04b1w42/an+xwcGBomvWvt7AQNn1Tq85tvdI0fVqv86Dg2vrOpe+j0+vWfqxslr6rjx3\nb9/c6wh9r/TcGKn+OUv9Mn9nLa3XxpqlnyBXwm47ACRQngCQQHkCQALlCQAJlCcAJFCeAJBAeQJA\nAuUJAAmUJwAkUJ4AkEB5AkAC5QkACZQnACRQngCQkC5P25tsH7L9lO0jtneVDAYANWvyfZ6nJH0m\nIg7bHpb0E9sHImKyUDYAqFZ6yzMiXoqIw93Ds5ImJL2tVDAAqFmR1zxtXyrpCkk/LrEeANSu8RiO\n7i77Hkk3d7dAz7JvfOrM4S0jQxodGW56sWhgrc6Bqn3+Tu3rlb5P2lhzw/pm3TIxM6vJmblzOq+b\nzA+xvU7Sv0h6MCLuXOY8UXp2DPB6MbcJGd3fmyXbvelu+zcljS9XnADwRtXko0pXSfqYpA/Yfsz2\no7Z3lIsGAPVKv+YZEf8u6fyCWQCgb/AXRgCQQHkCQALlCQAJlCcAJFCeAJBAeQJAAuUJAAmUJwAk\nUJ4AkEB5AkAC5QkACZQnACRQngCQQHkCQALlCQAJlCcAJDQeAAf0g7U49K7pMDSsjPLEmrB7++Ze\nR8AbDLvtAJBAeQJAAuUJAAmUJwAkUJ4AkEB5AkAC5QkACZQnACRQngCQQHkCQALlCQAJlCcAJFCe\nAJDQqDxt77A9afu/bH+hVCgAqF26PG2fJ+lvJV0r6XJJH7W9pVSw1TQxM9vrCCuqPZ9Uf8ba80n1\nZ6w9n7S6GZtsef6+pGci4qcR8Yqkb0vaWSbW6pqcmet1hBXVnk+qP2Pt+aT6M9aeT1rdjE3K822S\njs07/nz3NAB4w+MNIwBIcETkftC+UtJtEbGje/wWSRERX110vtwFAEAFImLJwVJNyvN8SU9L2i7p\nfyQ9LOmjETGRDQkA/SI9AC4ifm37LyQdUGf3/26KE8Bakd7yBIC1rLU3jGr/AL3tTbYP2X7K9hHb\nu3qdaSm2z7P9qO0Hep1lKbbX2/6O7YnubfneXmdazPanbT9p+wnb99l+cwWZ7rY9ZfuJeae91fYB\n20/bfsj2+sry7e7ez4dtf9f2hb3Kt1zGef/3Wduv2v7Nti6/lfLskw/Qn5L0mYi4XNIfSPpkhRkl\n6WZJ470OsYI7JX0vIkYl/Y6kql66sX2xpE9J2hYR71HnpaobeptKknSPOo+P+W6RdDAi3iXpkKQv\nrnqq/7dUvgOSLo+IKyQ9o97mk5bOKNubJF0j6adtXnhbW57Vf4A+Il6KiMPdw7PqPOir+pxq95fg\ng5K+0essS+luebw/Iu6RpIg4FREv9zjWUs6XNGR7naQLJL3Y4zyKiB9K+sWik3dKurd7+F5JH17V\nUPMslS8iDkbEq92j/yFp06oHW5hnqdtQkr4u6XNtX35b5dlXH6C3famkKyT9uLdJznL6l6DWF6Y3\nS/qZ7Xu6Ly3cZXuw16Hmi4gXJX1N0lFJL0j6ZUQc7G2qZW2IiCmp8+QuaUOP86zkzyQ92OsQi9m+\nTtKxiDjS9mWt+Q/J2x6WtEfSzd0t0CrY/pCkqe7Wsbv/arNO0jZJfxcR2yT9Sp1dz2rYfos6W3SX\nSLpY0rDtG3ub6pxV+aRp+y8lvRIR9/c6y3zdJ+5bJX1p/sltXV5b5fmCpLfPO76pe1pVurtxeyT9\nU0Ts73WeRa6SdJ3tZyX9s6Q/sv2PPc602PPqPMs/0j2+R50yrcnVkp6NiJ9HxK8l7ZX0vh5nWs6U\n7Y2SZPsiSdM9znMW22PqvJRU4xPQOyVdKulx28+p0zs/sd3KFnxb5fmfkn7L9iXddzZvkFTju8Xf\nlDQeEXf2OshiEXFrRLw9It6hzu13KCI+3utc83V3MY/Zvqx70nbV9+bWUUlX2h6wbXUy1vKm1uI9\nigckjXUPf0JSr5/QF+SzvUOdl5Gui4j/7Vmqhc5kjIgnI+KiiHhHRGxW58n9dyOilSehVsqz+wx/\n+gP0T0n6dm0foLd9laSPSfqA7ce6r9nt6HWuPrRL0n22D6vzbvtXepxngYh4WJ0t4sckPa7OA+2u\nnoaSZPt+ST+SdJnto7ZvknS7pGtsn/7Lvdsry/c3koYl/Vv38fL3vcq3Qsb5Qi3utvMheQBIWPNv\nGAFABuUJAAmUJwAkUJ4AkEB5AkAC5QkACZQnACRQngCQ8H/AGJvttLXzoQAAAABJRU5ErkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def maze1():\n", + " return Maze([\n", + " \"########\",\n", + " \"#X.#...#\",\n", + " \"#.##.#.#\",\n", + " \"#.#..#.#\",\n", + " \"#....#.#\",\n", + " \"#.##...#\",\n", + " \"#..#..##\",\n", + " \"##.#..@#\",\n", + " \"########\"\n", + " ])\n", + "\n", + "maze1().draw()\n", + "\n", + "def maze2():\n", + " return Maze([\n", + " \"###############\",\n", + " \"#X#@.#.#...#..#\",\n", + " \"#.##.....#....#\",\n", + " \"#.#.#.#..#..#.#\",\n", + " \"#...#.#....#..#\",\n", + " \"#.#.#.........#\",\n", + " \"#.#.##.#..#...#\",\n", + " \"#.....#..#..#.#\",\n", + " \"#####...#.....#\",\n", + " \"########...####\",\n", + " \"###############\"\n", + " ])\n", + "\n", + "maze2().draw()\n", + "\n", + "def mazeUnsolvable1():\n", + " return Maze([\n", + " \"###############\",\n", + " \"#X#@.#.#...#..#\",\n", + " \"#.##.....#....#\",\n", + " \"#.#.#.#..#..#.#\",\n", + " \"#.#.#.#....#..#\",\n", + " \"#..##...#.....#\",\n", + " \"#.#.##....#...#\",\n", + " \"#.#...#..#..#.#\",\n", + " \"#####...#.....#\",\n", + " \"########...####\",\n", + " \"###############\"\n", + " ])\n", + "\n", + "mazeUnsolvable1().draw()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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\nu2H11UVr9MKaTWM9GsZcroikVg0Y9uuIZgnUPQkNABHxE+AnhXoxay3vEc0ScBDNEnAQzRJwEM0S\ncBDNEnAQzRJwEM0ScBDNEnAQzRJwEM0ScBDNEnAQzRJwEM0ScBDNEnAQzRJwEM0S6PrBYEnzgZ8C\nF1fbj0bE+tKNmbVJnZk1xyV9KCKOSJoH/FzSv0XE1h70Z9YKtQ5NI+JIdXE+nfB6vqlZg+pO+u6T\ntAN4FdgSEdvKtmXWLrWGR0XEKeAaSZcA/yLpqog46zwYZeealp9zOTAwUHRWJ8CikWG+svLyojV6\nMzt1ftHfRy/mmi4aae7/52nF5pqeKSIOS/oxsIopTkhTdq7psZ7MuZyNszQn68yALVtDOl58ruls\nnDFbbK6ppLdJGqkuDwIfBnafX5tmNpU6e8S3A9+S1EcnuA9ExCNl2zJrlzovX4wBy3vQi1lr+Z01\nZgk4iGYJOIhmCTiIZgk4iGYJOIhmCTiIZgk4iGYJOIhmCTiIZgk4iGYJOIhmCTiIZgk4iGYJOIhm\nCTiIZgnUGZWxWNJjkp6VNCZpbS8aM2uTOqMyTgJ/HRE7JQ0DT0p6NCI8t8asIV33iBHxakTsrC5P\nAOPAO0s3ZtYmM3qMKOndwDLg8RLNmLVV7bmm1WHpKHB7tWc8S8kBw4tGhnsyYLh0jcHBgaLrd2rM\n/gHD69at44Xh5gcAn+nIaxNc9dwPGl2z6IBhSf10QvidiHhouu1KDhguPR0bYM2mMQ8YrqkzYLjc\n+uvXlw0hwNCC5msUGzBc+SawKyLunXlrZtZNnZcvVgCfAf5Y0g5J2yWtKt+aWXvUGTD8c2BeD3ox\nay2/s8YsAQfRLAEH0SwBB9EsAQfRLAEH0SwBB9EsAQfRLAEH0SwBB9EsAQfRLAEH0SwBB9EsAQfR\nLAEH0SwBB9EsgTqf0P+GpP2Snu5FQ2ZtVGePeD/wJ6UbMWuzOgOGfwb8pge9mLWWHyOaJVB7wHAd\nJQcM90IvhhgvGil/nywa6Uc6WbRG6SHG69ZNMNyDAcNNO98Bw6ozUFfSEuBfI+J959gmNqy+esYN\nmM1l1dDqrn+y6h6aqvpnZgXUefniu8B/AEsl7ZV0W/m2zNqlzoDhT/eiEbM287OmZgk4iGYJOIhm\nCTiIZgk4iGYJOIhmCTiIZgk4iGYJOIhmCTiIZgk4iGYJOIhmCTiIZgk4iGYJOIhmCdQKoqRVknZL\n+qWkL5Vuyqxt6nxCvw/4ezqzTd8L3CLpitKNTTZ+sPlBP66Rt8ZcuA0zUWePeC3wXxHxPxFxAvg+\n8PGybZ3tfCZjucbsrTEXbsNM1AniO4F9Z3z/YvUzM2uIn6wxS6DrXFNJ1wP3RMSq6vs7gYiIL0/a\nrvuAVLMWqjPXtE4Q5wH/CawEXgG2ArdExHgTTZpZvXGKr0v6S+BROoey33AIzZpVa+S+mZV1wU/W\nlH6xvxcnSpW0WNJjkp6VNCZpbYEa8yU9LmlHVePupmtUdfokbZf0cKH1X5D0VHU7thaqMSLpQUnj\n1e/kuobXX1r1v736eqjp37mkOyQ9I+lpSRslXXzOK0TEef+jE+T/BpYAFwE7gSsuZM0panwAWAY8\n3eS6k2r8LrCsujxM5zFxo7ejWnuo+joP+AVwbYEadwD/BDxc6L7aA7y51O+iqrEBuK263A9cUrBW\nH/Ay8K4G13xHdT9dXH3/AHDrua5zoXvE4i/2Rw9OlBoRr0bEzuryBDBOgddKI+JIdXE+nf9gjT4u\nkLQYuAn4epPrTi5DwZe9JF0C3BAR9wNExMmIOFyqHnAj8FxE7Ou65czMAxZI6geG6IR9Whd6h865\nF/slvZvOHvjxAmv3SdoBvApsiYhtDZf4GvAFGg74JAFskbRN0ucKrH858CtJ91eHjvdJGixQ57RP\nAt9rcsGIeBn4KrAXeAn4bUT88FzX8Qv6Z5A0DIwCt1d7xkZFxKmIuAZYDFwn6aqm1pb0MWB/tWcv\neRq9FRGxnM6e9/OSPtDw+v3AcuAfqjpHgDsbrgGApIuAm4EHG173TXSODJfQOUwdlnTOkzldaBBf\nAi474/vF1c9mneoQYhT4TkQ8VLJWdaj1Y2BVg8uuAG6WtIfOX/gPSfp2g+sDEBGvVF8PApvpPDxp\n0ovAvoh4ovp+lE4wS/go8GR1W5p0I7AnIn4dEa8Dm4D3n+sKFxrEbcDvSVpSPSv0KaDEs3W9OFHq\nN4FdEXFvicUlvU3SSHV5EPgwsLup9SPiroi4LCLeQ+f38FhE3NrU+gCShqqjBiQtAD4CPNNkjYjY\nD+yTtLT60UpgV5M1znALDR+WVvYC10saUOdc8CvpPO8wra4v6J9L9ODF/upEqR8E3ippL3D36Qfy\nDdZYAXwGGKsewwVwV0T8e4Nl3g58q/pYWR/wQEQ80uD6vXApsLl6O2M/sDEiHi1QZy2wsTp03AM0\nfnJcSUN09lx/3vTaEbFV0iiwAzhRfb3vnP1UT6+a2RvIT9aYJeAgmiXgIJol4CCaJeAgmiXgIJol\n4CCaJeAgmiXwv+JZVmKTcKCBAAAAAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAU8AAAD7CAYAAADq4RYlAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAD4BJREFUeJzt3X+MZXV5x/HPB1a5l52y2mRmCW4EtMUdiJZu0kolpqkL\ngWoCYtIEsdGl/zVWiBoV6R/iPwY3GEt/JkRcaQM1cd3NkkYCXUlMrKkUYWFhZqgpxOVHmRmjLpl1\ndsPK0z/u3e3s7Mzs8pzvmfu9zPuVbHLv3TPPec69cz/3nHvu3McRIQDA63PGoBsAgGFEeAJAAuEJ\nAAmEJwAkEJ4AkEB4AkDCurZXYJvPQgEYWhHhpW5vPTwl6VsfefdqrCZt98S0rrt446DbWFbt/Un1\n91h7f1L9Pdben1S+x2279i/7fxy2A0AC4QkACYSnpM2j6wfdwopq70+qv8fa+5Pq77H2/qTV7dFt\n/2277aj9PU8AWMq2XfuXPWHEnicAJBCeAJBAeAJAAuEJAAmEJwAkEJ4AkEB4AkAC4QkACYQnACSc\nMjxt32172vaTC257q+2HbD9j+0HbG9ptEwDqcjp7njskXbXotlsk7Y2Id0l6WNIXSzcGADU7ZXhG\nxA8l/XLRzddKuqd/+R5JHy7cFwBULfue51hETEtSRLwsaaxcSwBQv1InjBi1AWBNyY7hmLa9MSKm\nbZ8raWalhXdPTB+/vHl0vcZHR5KrlW56cFKvHDqa/vmlnLN+nf72qvFi9SbeeZXOXp/fxsXm5uZ0\nxx13FKs3tmGdtm8tt72S9PnvP6eZg3PF6o1tGNH2rRcWq1e6P0nqdjuanz9cbb21eB823ebJ2TlN\nzR46rWVPNzzd/3fM/ZK2SfqqpE9I2rPSD5ecKfLKoaPSbcXK9WreVjaMSwanJI2MjKjk167aZbdX\nkmYOzqnkd8PaS36FYlrp/qRej6W3mfuweb0mxkdHTti52zO1/H7h6XxU6T5JP5J0ke0Dtm+UdLuk\nK20/I2lr/zoArBmn3POMiBuW+a8rCvcCAEODvzACgATCEwASCE8ASCA8ASCB8ASABMITABIITwBI\nIDwBIIHwBIAEwhMAEghPAEggPAEggfAEgATCEwASCE8ASCA8ASAhO8NoYPwmKW4rX7OkXx+aKz7D\nqOREhU5H2rZrf7mCkjqdTtGxD51Op2iPpftroyb3YXPdbqdYrVMZuvCMV1V0no+kosEkSRf/z4NF\n623btb/wDKM27sPD1c/zaWP+zrc+8u5i9XqPc73b3NZ9WNMMo9eDw3YASCA8ASCB8ASABMITABII\nTwBIIDwBIIHwBIAEwhMAEghPAEggPAEggfAEgATCEwASCE8ASCA8ASChUXja/rTtp2w/afte228u\n1RgA1CwdnrbPk/QpSVsi4j3qfTfo9aUaA4CaNf0y5DMlrbf9mqSzJb3UvCUAqF96zzMiXpL0NUkH\nJL0o6VcRsbdUYwBQs/Sep+23SLpW0vmSDkraafuGiLhv8bK7J6aPX948ul7jo/n5Pt1u+bEZ3W7Z\nep///nOaOThXrF7pbe50yt+Hnc5Z1c/zKT2iofS8nG637m1eCzOMJmfnNDV76LSWbXLYfoWkZyPi\nF5Jke5ek90k6KTyvu3hjg9WcaH6+/hlGMwfnis9lKT8rp1g5SZJ9ZE3N8zlWs6T5+frnQJV8jKV2\nHucmxkdHTti52zM1s+yyTc62H5B0me2Oex1vlTTZoB4ADI0m73k+ImmnpMclPSHJku4q1BcAVK3R\n2faI+LKkLxfqBQCGBn9hBAAJhCcAJBCeAJBAeAJAAuEJAAmEJwAkEJ4AkEB4AkAC4QkACYQnACQQ\nngCQQHgCQALhCQAJhCcAJBCeAJBAeAJAQtPRw6uujQFwnU5vlkq5enUNtTq5Xv1D9GofhnasZs2/\nN238HpbcXqn+58pKhi482xoAV/vgrZKGYYhe7cPQ2qhZ+8C20sPapPqfKyvhsB0AEghPAEggPAEg\ngfAEgATCEwASCE8ASCA8ASCB8ASABMITABIITwBIIDwBIIHwBIAEwhMAEghPAEhoFJ62N9j+ju1J\n20/bfm+pxgCgZk2/z/NOSd+LiD+zvU7S2QV6AoDqpcPT9jmS3h8R2yQpIo5KeqVQXwBQtSaH7RdK\n+rntHbYfs32X7cLDGACgTk0O29dJ2iLpkxHxqO2/kXSLpC8tXnD3xPTxy5tH12t8dCS90nZmGJ1V\n/eyYkoZjDlTdj0kbNduoV/OMpTZqNn2uTM7OaWr20Gkt2yQ8X5D0fEQ82r++U9IXllrwuos3NljN\nidqZv3Ok6lkvwzLDqGRN+0jheodb2Oa65yzVXq+Nmk2fK+OjIyfs3O2Zmll22fRhe0RMS3re9kX9\nm7ZKmsjWA4Bh0vRs+02S7rX9JknPSrqxeUsAUL9G4RkRT0j6g0K9AMDQ4C+MACCB8ASABMITABII\nTwBIIDwBIIHwBIAEwhMAEghPAEggPAEggfAEgATCEwASCE8ASCA8ASCB8ASABMITABKafhnyqmtj\n/k638Ni6breuuSyLjW1YJ/to0ZqdTtnHpfZ6vZp1z1mqvV4bNUs/V1YydOHZ1vydkubny8+2KWn7\n1vGi9aR25jaVnytVrJykY3OWat9mZhi1hcN2AEggPAEggfAEgATCEwASCE8ASCA8ASCB8ASABMIT\nABIITwBIIDwBIIHwBIAEwhMAEghPAEggPAEgoXF42j7D9mO27y/REAAMgxJ7njdLmihQBwCGRqPw\ntL1J0gclfaNMOwAwHJrueX5d0uckFf6ObgCoWzo8bX9I0nRE7JPk/j8AWBOcnR9i+yuS/lzSUUld\nSb8laVdEfHzRcnHt5rHj1zePrtf46Ei64b98YL/m59M/vqRORzp8uGS9s3T48JFq63W7Kn4fdrsd\nzc+XuxNL1yv9GPdqln5cSm9zR4cLbnTpem3U7HY7+qc//d30z0/Ozmlq9tDx63umZhQRS+4YpgfA\nRcStkm6VJNt/LOmzi4PzmOsu3phdzUnaGgBXsmZvMFjN9dq4Dw9XPbCtnW0+sqYGtpUeUCe1s81N\njI+OnLBzt2dqZtll+ZwnACQUGT0cET+Q9IMStQBgGLDnCQAJhCcAJBCeAJBAeAJAAuEJAAmEJwAk\nEJ4AkEB4AkAC4QkACYQnACQQngCQQHgCQALhCQAJhCcAJBCeAJBAeAJAQpEvQ15NYxvWyT5atGa3\n2xvTsFbqdTpl6x2ruW3X/qL1at/mbrf0Nncaj5Fou17J7T1Ws2SP3W6nWK1TGbrw3L51fNAtDL3S\n84GkNuZAla83DPN31lK9NmqWDOJT4bAdABIITwBIIDwBIIHwBIAEwhMAEghPAEggPAEggfAEgATC\nEwASCE8ASCA8ASCB8ASABMITABIITwBISIen7U22H7b9tO39tm8q2RgA1KzJ93kelfSZiNhne0TS\nT2w/FBFThXoDgGql9zwj4uWI2Ne/PCdpUtLbSjUGADUr8p6n7QskXSrpxyXqAUDtGo/h6B+y75R0\nc38P9CS7J6aPX948ul7joyNNV4sG1uocqNrn79Rer9stW6+NmmMbmmXL5OycpmYPndaybjI/xPY6\nSf8m6YGIuHOZZaL07Bjg9So9b0iqf0aQ7eJzm9aa/u/Nkune9LD9m5ImlgtOAHijavJRpcslfUzS\nB2w/bvsx21eXaw0A6pV+zzMi/kPSmQV7AYChwV8YAUAC4QkACYQnACQQngCQQHgCQALhCQAJhCcA\nJBCeAJBAeAJAAuEJAAmEJwAkEJ4AkEB4AkAC4QkACYQnACQQngCQ0HgAHDAMxjaMVD+8rLZhaFgZ\n4Yk1YfvWCwfdAt5gOGwHgATCEwASCE8ASCA8ASCB8ASABMITABIITwBIIDwBIIHwBIAEwhMAEghP\nAEggPAEggfAEgIRG4Wn7attTtv/b9hdKNQUAtUuHp+0zJP29pKskXSLpo7Y3l2psNU3Ozg26hRXV\n3p9Uf4+19yfV32Pt/Umr22OTPc8/lPTTiPhZRLwq6duSri3T1uqamj006BZWVHt/Uv091t6fVH+P\ntfcnrW6PTcLzbZKeX3D9hf5tAPCGxwkjAEhwROR+0L5M0m0RcXX/+i2SIiK+umi53AoAoAIRseRg\nqSbheaakZyRtlfS/kh6R9NGImMw2CQDDIj0ALiJ+Y/uvJD2k3uH/3QQngLUivecJAGtZayeMav8A\nve1Nth+2/bTt/bZvGnRPS7F9hu3HbN8/6F6WYnuD7e/Ynuzfl+8ddE+L2f607adsP2n7XttvrqCn\nu21P235ywW1vtf2Q7WdsP2h7Q2X9be8/zvtsf9f2OYPqb7keF/zfZ22/Zvu321p/K+E5JB+gPyrp\nMxFxiaQ/kvTJCnuUpJslTQy6iRXcKel7ETEu6fckVfXWje3zJH1K0paIeI96b1VdP9iuJEk71Ht+\nLHSLpL0R8S5JD0v64qp39f+W6u8hSZdExKWSfqrB9ict3aNsb5J0paSftbnytvY8q/8AfUS8HBH7\n+pfn1HvSV/U51f4vwQclfWPQvSylv+fx/ojYIUkRcTQiXhlwW0s5U9J62+sknS3ppQH3o4j4oaRf\nLrr5Wkn39C/fI+nDq9rUAkv1FxF7I+K1/tX/lLRp1Rs7sZ+l7kNJ+rqkz7W9/rbCc6g+QG/7AkmX\nSvrxYDs5ybFfglrfmL5Q0s9t7+i/tXCX7e6gm1ooIl6S9DVJByS9KOlXEbF3sF0taywipqXei7uk\nsQH3s5K/kPTAoJtYzPY1kp6PiP1tr2vNf0je9oiknZJu7u+BVsH2hyRN9/eO3f9Xm3WStkj6h4jY\nIunX6h16VsP2W9Tboztf0nmSRmzfMNiuTluVL5q2/1rSqxFx36B7Waj/wn2rpC8tvLmt9bUVni9K\nevuC65v6t1Wlfxi3U9K/RMSeQfezyOWSrrH9rKR/lfQntv95wD0t9oJ6r/KP9q/vVC9Ma3KFpGcj\n4hcR8RtJuyS9b8A9LWfa9kZJsn2upJkB93MS29vUeyupxhegd0q6QNITtp9TL3d+YruVPfi2wvO/\nJP2O7fP7Zzavl1Tj2eJvSpqIiDsH3chiEXFrRLw9It6h3v33cER8fNB9LdQ/xHze9kX9m7aqvpNb\nByRdZrtj2+r1WMtJrcVHFPdL2ta//AlJg35BP6E/21er9zbSNRFxZGBdneh4jxHxVEScGxHviIgL\n1Xtx//2IaOVFqJXw7L/CH/sA/dOSvl3bB+htXy7pY5I+YPvx/nt2Vw+6ryF0k6R7be9T72z7Vwbc\nzwki4hH19ogfl/SEek+0uwbalCTb90n6kaSLbB+wfaOk2yVdafvYX+7dXll/fydpRNK/958v/zio\n/lbocaFQi4ftfEgeABLW/AkjAMggPAEggfAEgATCEwASCE8ASCA8ASCB8ASABMITABL+D5KIhcMV\noLraAAAAAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAU8AAAD7CAYAAADq4RYlAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAADutJREFUeJzt3W+MnXWZxvHrgmo6zCzVTaYl2AjVDXZKdNkmKisxm3Ug\nNJiAmGyCmGjZt64lalTEF+KbDTYYl/33gogVN7AmdtuUbHTp1iYmrllZhEJhZlizEFtgmRmjlsxY\nDJV7X5wz3ZnpzLS9n98z53eY7ydpcub09Pdc50+v8zznnDm3I0IAgPNzQa8DAEA/ojwBIIHyBIAE\nyhMAEihPAEigPAEgYV3bG7DNZ6EA9K2I8FLnt16ekvTtj757NTaTtn9sUjdv29TrGMuqPZ9Uf8ba\n80n1Z6w9n1Q+4859R5f9Ow7bASCB8gSABMpT0tbhwV5HWFHt+aT6M9aeT6o/Y+35pNXN6LZ/t912\n1P6aJwAsZee+o8u+YcSeJwAkUJ4AkEB5AkAC5QkACZQnACRQngCQQHkCQALlCQAJlCcAJJy1PG3f\nb3vS9lPzznur7YO2n7X9iO0N7cYEgLqcy57nHknXLzrvDkmHIuJdkg5L+lLpYABQs7OWZ0T8WNKv\nF519k6QHuqcfkPSRwrkAoGrZ1zw3RsSkJEXEy5I2losEAPUr9YYRozYArCnZMRyTtjdFxKTtSyRN\nrXTh/WOTp09vHR7UyPBQcrPSrkfG9crsqfS/X8rFg+v0t9ePFFtv7J07dNFgue8VnJmZ0T333FNs\nvY0bhrR7dEux9STpCz98XlMnZoqtVzpj6XySNDCwXidPvlrtemvxNmx6ncenZzQxPXtOlz3X8nT3\nz5yHJe2U9DVJn5R0YKV/XHKmyCuzp6S7ii3XWfOusmVcsjglaWhoSCW/d9Ve8usJG5k6MVN1xtL5\npE7G0teZ27D5ek2MDA8t2Lk7MLH8fuG5fFTpIUk/kXSF7WO2b5N0t6TrbD8rabT7MwCsGWfd84yI\nW5f5q2sLZwGAvsFvGAFAAuUJAAmUJwAkUJ4AkEB5AkAC5QkACZQnACRQngCQQHkCQALlCQAJlCcA\nJFCeAJBAeQJAAuUJAAmUJwAkUJ4AkJCdYdQzfpMUd5Vfs6Tfzs4Wn2FUcqTC+vXrtXPf0WLrza1Z\nc8bS+dpYk9uwuYGB9cXWOpu+K894Ta3MUSlp2//8W9H1du47WvWsnDbWrH29uTW//dF3F1uv9vu5\nXx43q4XDdgBIoDwBIIHyBIAEyhMAEihPAEigPAEggfIEgATKEwASKE8ASKA8ASCB8gSABMoTABIo\nTwBIoDwBIKFRedr+jO2nbT9l+0Hbby4VDABqli5P25dK+rSk7RHxHnW+G/SWUsEAoGZNvwz5QkmD\ntl+XdJGkl5pHAoD6pfc8I+IlSV+XdEzSi5J+ExGHSgUDgJql9zxtv0XSTZIuk3RC0l7bt0bEQ4sv\nu39s8vTprcODGhkeym5WAwPl56iUnnvyhR8+r6kTM8XWK32d+2EWTe3rSeUfN7Xfz/3wuGl6n4xP\nz2hievacLtvksP1aSc9FxK8kyfY+SR+QdEZ53rxtU4PNLHTy5KvVzzCaOjFTfC5LzbNypPoztjV/\np6TSj+025gOVvI+ldu7nJkaGhxbs3B2YmFr2sk3ebT8m6Wrb691JPCppvMF6ANA3mrzm+aikvZKe\nkPSkJEu6r1AuAKhao3fbI+Krkr5aKAsA9A1+wwgAEihPAEigPAEggfIEgATKEwASKE8ASKA8ASCB\n8gSABMoTABIoTwBIoDwBIIHyBIAEyhMAEihPAEigPAEggfIEgISmo4dXXT8MgCudsfZ8c2uWXq8f\nhpft3He06Ho1X+eBgbLXV6pvANz56Lvy7IcBcG0M8ipprd6GbVznmjPWPpRPauc6rxYO2wEggfIE\ngATKEwASKE8ASKA8ASCB8gSABMoTABIoTwBIoDwBIIHyBIAEyhMAEihPAEigPAEggfIEgIRG5Wl7\ng+3v2R63/Yzt95cKBgA1a/p9nvdK+n5E/IXtdZIuKpAJAKqXLk/bF0v6YETslKSIOCXplUK5AKBq\nTQ7bt0j6pe09th+3fZ/tgVLBAKBmTQ7b10naLulTEfGY7b+RdIekryy+4P6xydOntw4PamR4KL3R\nNubvlJ5FUzrjxg3522sp/XAb1j7Pp40121iv5vukjTWbzjAan57RxPTsOV22SXm+IOl4RDzW/Xmv\npC8udcGbt21qsJmF2pq/U/PsmNL65Tas/T4pPdOnH27DfnjcNDEyPLRg5+7AxNSyl00ftkfEpKTj\ntq/onjUqaSy7HgD0k6bvtu+S9KDtN0l6TtJtzSMBQP0alWdEPCnpvYWyAEDf4DeMACCB8gSABMoT\nABIoTwBIoDwBIIHyBIAEyhMAEihPAEigPAEggfIEgATKEwASKE8ASKA8ASCB8gSABMoTABKafhny\nqmtr/k7pOSolZ8ds3DCk3aNbiq5X+21Y+zyfuTVrv841r9fGmk1nGJ2PvivPtubvlJxv08Zsm5JK\nFvGctTbPp401++Fx2A+34WrhsB0AEihPAEigPAEggfIEgATKEwASKE8ASKA8ASCB8gSABMoTABIo\nTwBIoDwBIIHyBIAEyhMAEihPAEhoXJ62L7D9uO2HSwQCgH5QYs/zdkljBdYBgL7RqDxtb5Z0g6Rv\nlokDAP2h6Z7nNyR9XlLZr5cGgMqly9P2hyVNRsQRSe7+AYA1ockMo2sk3Wj7BkkDkv7A9nci4hOL\nL7h/bPL06a3DgxoZHkpvtI0BcKWHRpXOWHp42cDAep08+Wqx9ebWrHnYWL8MLyt5P6/V27CJ8ekZ\nTUzPntNl0+UZEXdKulOSbP+ZpM8tVZySdPO2TdnNnKGtAXAllc7YL8PQ1uLwsrV0nUtfX6m+YYkj\nw0MLdu4OTEwte1k+5wkACUVGD0fEjyT9qMRaANAP2PMEgATKEwASKE8ASKA8ASCB8gSABMoTABIo\nTwBIoDwBIIHyBIAEyhMAEihPAEigPAEggfIEgATKEwASKE8ASKA8ASChyJchr6aNG4aKj83YuCE/\nU2m59UrPZemHWTRrbf7OWps5VPo+nluzphlG56PvynP36JZeRzir2jOWnhsj1T9nqV/m76yl9dpY\ns/QT5Eo4bAeABMoTABIoTwBIoDwBIIHyBIAEyhMAEihPAEigPAEggfIEgATKEwASKE8ASKA8ASCB\n8gSABMoTABLS5Wl7s+3Dtp+xfdT2rpLBAKBmTb7P85Skz0bEEdtDkn5m+2BETBTKBgDVSu95RsTL\nEXGke3pG0rikt5UKBgA1K/Kap+3LJV0l6acl1gOA2jUew9E9ZN8r6fbuHugZ9o9Nnj69dXhQI8Nl\nZwbh/LQxB6r0nKU21qt9/k7t65W+T9pYs+k8svHpGU1Mz57TZd1kfojtdZL+VdIPIuLeZS4TpWfH\nAOeLuU3I6D5ulmz3poft35I0tlxxAsAbVZOPKl0j6eOSPmT7CduP295RLhoA1Cv9mmdE/IekCwtm\nAYC+wW8YAUAC5QkACZQnACRQngCQQHkCQALlCQAJlCcAJFCeAJBAeQJAAuUJAAmUJwAkUJ4AkEB5\nAkAC5QkACZQnACRQngCQ0HgAHNAP1uLQu6bD0LAyyhNrwu7RLb2OgDcYDtsBIIHyBIAEyhMAEihP\nAEigPAEggfIEgATKEwASKE8ASKA8ASCB8gSABMoTABIoTwBIoDwBIKFRedreYXvC9n/b/mKpUABQ\nu3R52r5A0t9Lul7SlZI+ZntrqWCraXx6ptcRVlR7Pqn+jLXnk+rPWHs+aXUzNtnzfJ+kn0fELyLi\nNUnflXRTmVira2J6ttcRVlR7Pqn+jLXnk+rPWHs+aXUzNinPt0k6Pu/nF7rnAcAbHm8YAUCCIyL3\nD+2rJd0VETu6P98hKSLia4sul9sAAFQgIpYcLNWkPC+U9KykUUn/K+lRSR+LiPFsSADoF+kBcBHx\ne9t/JemgOof/91OcANaK9J4nAKxlrb1hVPsH6G1vtn3Y9jO2j9re1etMS7F9ge3HbT/c6yxLsb3B\n9vdsj3dvy/f3OtNitj9j+2nbT9l+0PabK8h0v+1J20/NO++ttg/aftb2I7Y3VJZvd/d+PmL7X2xf\n3Kt8y2Wc93efs/267T9sa/utlGeffID+lKTPRsSVkv5U0qcqzChJt0sa63WIFdwr6fsRMSLpjyVV\n9dKN7UslfVrS9oh4jzovVd3S21SSpD3q/P+Y7w5JhyLiXZIOS/rSqqf6f0vlOyjpyoi4StLP1dt8\n0tIZZXuzpOsk/aLNjbe151n9B+gj4uWIONI9PaPOf/qqPqfafRDcIOmbvc6ylO6exwcjYo8kRcSp\niHilx7GWcqGkQdvrJF0k6aUe51FE/FjSrxedfZOkB7qnH5D0kVUNNc9S+SLiUES83v3xPyVtXvVg\nC/MsdRtK0jckfb7t7bdVnn31AXrbl0u6StJPe5vkDHMPglpfmN4i6Ze293RfWrjP9kCvQ80XES9J\n+rqkY5JelPSbiDjU21TL2hgRk1LnyV3Sxh7nWclfSvpBr0MsZvtGSccj4mjb21rzH5K3PSRpr6Tb\nu3ugVbD9YUmT3b1jd//UZp2k7ZL+ISK2S/qtOoee1bD9FnX26C6TdKmkIdu39jbVOavySdP2lyW9\nFhEP9TrLfN0n7jslfWX+2W1tr63yfFHS2+f9vLl7XlW6h3F7Jf1TRBzodZ5FrpF0o+3nJP2zpD+3\n/Z0eZ1rsBXWe5R/r/rxXnTKtybWSnouIX0XE7yXtk/SBHmdazqTtTZJk+xJJUz3OcwbbO9V5KanG\nJ6B3Srpc0pO2n1end35mu5U9+LbK878k/ZHty7rvbN4iqcZ3i78laSwi7u11kMUi4s6IeHtEvEOd\n2+9wRHyi17nm6x5iHrd9RfesUdX35tYxSVfbXm/b6mSs5U2txUcUD0va2T39SUm9fkJfkM/2DnVe\nRroxIn7Xs1QLnc4YEU9HxCUR8Y6I2KLOk/ufREQrT0KtlGf3GX7uA/TPSPpubR+gt32NpI9L+pDt\nJ7qv2e3oda4+tEvSg7aPqPNu+1/3OM8CEfGoOnvET0h6Up3/aPf1NJQk2w9J+omkK2wfs32bpLsl\nXWd77jf37q4s399JGpL0793/L//Yq3wrZJwv1OJhOx+SB4CENf+GEQBkUJ4AkEB5AkAC5QkACZQn\nACRQngCQQHkCQALlCQAJ/wcU+HVoCQewRQAAAABJRU5ErkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "m1 = maze1()\n", + "m1.update_move(heuristic(m1))\n", + "m1.draw()\n", + "\n", + "m2 = maze2()\n", + "m2.update_move(heuristic(m2))\n", + "m2.draw()\n", + "\n", + "mu1 = mazeUnsolvable1()\n", + "mu1.update_move(heuristic(mu1))\n", + "mu1.draw()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You also have to be able to handle switch and door puzzles:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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\nG6OvTDFBAAAAAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def maze3():\n", + " return Maze([\n", + " \"###############\",\n", + " \"#X#@.#.#...#.1#\",\n", + " \"#.##.....#....#\",\n", + " \"#A#.#.#..#..#.#\",\n", + " \"#.a.#C#....#..#\",\n", + " \"#.#.#0C.......#\",\n", + " \"#.#.##.#..#...#\",\n", + " \"#.B...#.2#..#.#\",\n", + " \"#####...#.....#\",\n", + " \"########...####\",\n", + " \"###############\"\n", + " ])\n", + "\n", + "maze3().draw()\n", + "\n", + "def maze4():\n", + " return Maze([\n", + " \"########\",\n", + " \"#@0#.01#\",\n", + " \"#A1#C#a#\",\n", + " \"#0#..#.#\",\n", + " \"#aBc2#.#\",\n", + " \"#B##c..#\",\n", + " \"#..#bb##\",\n", + " \"##1#..X#\",\n", + " \"########\"\n", + " ])\n", + "\n", + "maze4().draw()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAU8AAAD7CAYAAADq4RYlAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAD+FJREFUeJzt3X+M5HV9x/HXCxaY4baeNtk7ghcBbfEWoqUkrVRimnoQ\nqER+mDRBbPToXzZWiBoRaVqgTQxeMJb+TIiItIGaeD08rBIokJhYUynCwcHtUlOIx4+yu0Y9sufe\nlZN3/5i5696yu3e8v5/vzmfY5yO5ZGZu9j3vmfnOaz7f+fV2RAgA8PocM+gGAGAYEZ4AkEB4AkAC\n4QkACYQnACQQngCQMNL2Bdjms1AAhlZEeLHTWw9PSfrah961EheTdveuKV12xvpBt7Gk2vuT6u+x\n9v6k+nusvT+pfI+bt+1c8v/YbQeABMITABIIT0kbx9YMuoVl1d6fVH+Ptfcn1d9j7f1JK9uj2/5u\nu+2o/TVPAFjM5m07l3zDiJUnACQQngCQQHgCQALhCQAJhCcAJBCeAJBAeAJAAuEJAAmEJwAkHDE8\nbd9me8r2E/NOe4vt+20/bfs+22vbbRMA6nI0K8/bJV2w4LRrJT0QEe+U9JCkz5duDABqdsTwjIjv\nSfrZgpMvkXRH//Adki4t3BcAVC37mue6iJiSpIh4SdK6ci0BQP1KvWHEqA0Aq0p2DMeU7fURMWX7\nJEnTy5357l1Thw5vHFuj8bHR5MVKV903oZf3Hkj//WLetGZEf33BeLF6u95xgU5ck7+OC83Ozurm\nm28uVm/d2hFt2VTu+krSNQ8+q+k9s8XqrVs7qi2bTitW75oHJzS9p+x20+1Kc3P11it9Pw/Dbdj0\nOk/MzGpyZu9Rnfdow9P9fwfdI2mzpC9K+pik7cv9ccmZIi/vPSDdUKxcr+YNZTeIksEpSaOjoyr5\ns6t22esrSdN7ZlXyt2HtRX9CMW16z4Git6Ek2Sp8v5SuV/Z+Ho7bsNl1Hh8bPWxxt31y6XXh0XxU\n6S5J35d0uu3dtq+UdJOk820/LWlT/zgArBpHXHlGxBVL/Nd5hXsBgKHBN4wAIIHwBIAEwhMAEghP\nAEggPAEggfAEgATCEwASCE8ASCA8ASCB8ASABMITABIITwBIIDwBIIHwBIAEwhMAEghPAEjIzjAa\nGB8nxQ3la5b0i72zxWcYlZxK0elIm7ftLFdQUqdzQtHRGZ3OCUV77HRU9DZso2Yb9Vbbbdjtlqt1\nJEMXnvFK2ZknUvkN4oz/vq9ovc3bdlY9K6dXc3/hHkvXa2e7+dqH3lWsXu33c1u3Yc2zr5bDbjsA\nJBCeAJBAeAJAAuEJAAmEJwAkEJ4AkEB4AkAC4QkACYQnACQQngCQQHgCQALhCQAJhCcAJBCeAJDQ\nKDxtf8r2k7afsH2n7eNLNQYANUuHp+2TJX1S0tkR8W71fhv08lKNAUDNmv4Y8rGS1th+VdKJkl5s\n3hIA1C+98oyIFyV9SdJuSS9I+nlEPFCqMQCoWXrlafvNki6RdIqkPZK22r4iIu5aeN67d00dOrxx\nbI3Gx/Lzfbrd8mMzSs89uebBZzW9Z7ZYvdLXeRhm0dReTyq/3dR+P7ez3ZSdfdXtdhr9/cTMrCZn\n9h7VeZvstp8n6ZmI+Kkk2d4m6b2SXhOel52xvsHFHG5urv4ZRtN7ZovPZSk/K6fsjVh7j7ar3256\n23bp61zvdii1cz83MT42etjibvvk9JLnbfJu+25J59juuNfxJkkTDeoBwNBo8prnw5K2SnpM0uOS\nLOnWQn0BQNUavdseETdKurFQLwAwNPiGEQAkEJ4AkEB4AkAC4QkACYQnACQQngCQQHgCQALhCQAJ\nhCcAJBCeAJBAeAJAAuEJAAmEJwAkEJ4AkEB4AkAC4QkACU1HD6+4NgbAdTq9WSrl6nWqGmq1WL2S\n/R2sWbpeyR7bGnpX83bTxnZY8vpK9T9WljN04dnWALi4/tJy9W78ZlVDrRaam9uni/7soqI1v/2X\n3y5ab25u31AMgFtNA9vaGhxY82NlOey2A0DC0K08UcYH//yDReuVXnkCtWPlCQAJhCcAJBCeAJBA\neAJAAuEJAAmEJwAkEJ4AkEB4AkAC4QkACXzDaJX61l98a9AtAEONlScAJLDyXKX4bjvQTKOVp+21\ntr9he8L2U7bfU6oxAKhZ05XnLZK+ExF/YHtE0okFegKA6qXD0/abJL0vIjZLUkQckPRyob4AoGpN\ndttPk/QT27fbftT2rba7pRoDgJo12W0fkXS2pE9ExCO2/0rStZKuX3jGu3dNHTq8cWyNxsdG0xfa\nygyjkWPkG79Zrl7lc1mO7x6njx/38aI1j+uMFJ7nc8IQzDAq3WP5GUY1z1hqo2bTx8rEzKwmZ/Ye\n1XmbhOfzkp6LiEf6x7dK+txiZ7zsjPUNLuZw7cwwerXqWS+lN9j/nXulhdvwQNGa9v7C9drYbvZX\nP8Oo5npt1Gz6WBkfGz1scbd9cnrJ86Z32yNiStJztk/vn7RJ0q5sPQAYJk3fbb9K0p22j5P0jKQr\nm7cEAPVrFJ4R8bik3yrUCwAMDb6eCQAJhCcAJBCeAJBAeAJAAuEJAAmEJwAkEJ4AkEB4AkAC4QkA\nCYQnACQQngCQQHgCQALhCQAJhCcAJBCeAJDQ9MeQV1wbM4y6hcfWdbt1zWVZaN3aEdkHitYsPSOo\n9nq9mvXPMKq5Xhs1Sz9WljN04dnODKOy9ebm9lU1l2WhLZvGi9aT2pnbVH6uVLFyktqZYVT7LK03\n+gyj14PddgBIIDwBIIHwBIAEwhMAEghPAEggPAEggfAEgATCEwASCE8ASCA8ASCB8ASABMITABII\nTwBIIDwBIKFxeNo+xvajtu8p0RAADIMSK8+rJe0qUAcAhkaj8LS9QdIHJH2lTDsAMByarjy/LOmz\nkgr/RjcA1C0dnrYvkjQVETskuf8PAFYFZ+eH2P6CpD+UdEBSV9KvSNoWER9dcL64ZOO6Q8c3jq3R\n+NhouuE/vnen5ubSf76oTkfat69kvRO0b9/+aut1uyp+G3a7Hc3NlbsRS9crfR/3apa+X0pf5472\nFbzSpeu1UbPb7egffv/X038/MTOryZm9h45vn5xWRCy6MEwPgIuI6yRdJ0m2f1fSZxYG50GXnbE+\nezGv0dYAuJI1e4PBaq7Xxm24r+qBbe1c5/2ramBb6QF1UjvXuYnxsdHDFnfbJ6eXPC+f8wSAhCKj\nhyPiu5K+W6IWAAwDVp4AkEB4AkAC4QkACYQnACQQngCQQHgCQALhCQAJhCcAJBCeAJBAeAJAAuEJ\nAAmEJwAkEJ4AkEB4AkAC4QkACYQnACQU+THklbRu7YjsA0Vrdru9MQ2rpV6nU7bewZqbt+0sWq/2\n69ztlr7OncZjJNquV/L6HqxZssdut1Os1pEMXXhu2TQ+6BaGXun5QFIbc6DK1xuG+TurqV4bNUsG\n8ZGw2w4ACYQnACQQngCQQHgCQALhCQAJhCcAJBCeAJBAeAJAAuEJAAmEJwAkEJ4AkEB4AkAC4QkA\nCYQnACSkw9P2BtsP2X7K9k7bV5VsDABq1uT3PA9I+nRE7LA9KumHtu+PiMlCvQFAtdIrz4h4KSJ2\n9A/PSpqQ9NZSjQFAzYq85mn7VElnSfpBiXoAULvGYzj6u+xbJV3dX4G+xt27pg4d3ji2RuNjo00v\nFg2s1jlQtc/fqb1et1u2Xhs1161tli0TM7OanNl7VOd1k/khtkck/aukeyPiliXOE6VnxwCvV+l5\nQ1L9M4JsF5/btNr0t5tF073pbvtXJe1aKjgB4I2qyUeVzpX0EUnvt/2Y7UdtX1iuNQCoV/o1z4j4\nd0nHFuwFAIYG3zACgATCEwASCE8ASCA8ASCB8ASABMITABIITwBIIDwBIIHwBIAEwhMAEghPAEgg\nPAEggfAEgATCEwASCE8ASCA8ASCh8QA4YBisWzta/fCy2oahYXmEJ1aFLZtOG3QLeINhtx0AEghP\nAEggPAEggfAEgATCEwASCE8ASCA8ASCB8ASABMITABIITwBIIDwBIIHwBIAEwhMAEhqFp+0LbU/a\n/i/bnyvVFADULh2eto+R9LeSLpB0pqQP295YqrGVNDEzO+gWllV7f1L9Pdben1R/j7X3J61sj01W\nnr8t6UcR8eOIeEXS1yVdUqatlTU5s3fQLSyr9v6k+nusvT+p/h5r709a2R6bhOdbJT037/jz/dMA\n4A2PN4wAIMERkftD+xxJN0TEhf3j10qKiPjigvPlLgAAKhARiw6WahKex0p6WtImSf8j6WFJH46I\niWyTADAs0gPgIuKXtv9E0v3q7f7fRnACWC3SK08AWM1ae8Oo9g/Q295g+yHbT9neafuqQfe0GNvH\n2H7U9j2D7mUxttfa/obtif5t+Z5B97SQ7U/ZftL2E7bvtH18BT3dZnvK9hPzTnuL7fttP237Pttr\nK+tvS/9+3mH7X2y/aVD9LdXjvP/7jO1Xbf9qW5ffSngOyQfoD0j6dEScKel3JH2iwh4l6WpJuwbd\nxDJukfSdiBiX9BuSqnrpxvbJkj4p6eyIeLd6L1VdPtiuJEm3q/f4mO9aSQ9ExDslPSTp8yve1f9b\nrL/7JZ0ZEWdJ+pEG25+0eI+yvUHS+ZJ+3OaFt7XyrP4D9BHxUkTs6B+eVe9BX9XnVPsbwQckfWXQ\nvSymv/J4X0TcLkkRcSAiXh5wW4s5VtIa2yOSTpT04oD7UUR8T9LPFpx8iaQ7+ofvkHTpijY1z2L9\nRcQDEfFq/+h/SNqw4o0d3s9it6EkfVnSZ9u+/LbCc6g+QG/7VElnSfrBYDt5jYMbQa0vTJ8m6Se2\nb++/tHCr7e6gm5ovIl6U9CVJuyW9IOnnEfHAYLta0rqImJJ6T+6S1g24n+X8kaR7B93EQrYvlvRc\nROxs+7JW/YfkbY9K2irp6v4KtAq2L5I01V8du/+vNiOSzpb0dxFxtqRfqLfrWQ3bb1ZvRXeKpJMl\njdq+YrBdHbUqnzRt/6mkVyLirkH3Ml//ifs6SdfPP7mty2srPF+Q9LZ5xzf0T6tKfzduq6R/iojt\ng+5ngXMlXWz7GUn/LOn3bP/jgHta6Hn1nuUf6R/fql6Y1uQ8Sc9ExE8j4peStkl674B7WsqU7fWS\nZPskSdMD7uc1bG9W76WkGp+A3iHpVEmP235Wvdz5oe1WVvBthed/Svo126f039m8XFKN7xZ/VdKu\niLhl0I0sFBHXRcTbIuLt6t1+D0XERwfd13z9XcznbJ/eP2mT6ntza7ekc2x3bFu9Hmt5U2vhHsU9\nkjb3D39M0qCf0A/rz/aF6r2MdHFE7B9YV4c71GNEPBkRJ0XE2yPiNPWe3H8zIlp5EmolPPvP8Ac/\nQP+UpK/X9gF62+dK+oik99t+rP+a3YWD7msIXSXpTts71Hu3/QsD7ucwEfGweivixyQ9rt4D7daB\nNiXJ9l2Svi/pdNu7bV8p6SZJ59s++M29myrr728kjUr6t/7j5e8H1d8yPc4XanG3nQ/JA0DCqn/D\nCAAyCE8ASCA8ASCB8ASABMITABIITwBIIDwBIIHwBICE/wM/kYRBZenfkAAAAABJRU5ErkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\nAABJRU5ErkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "m3 = maze3()\n", + "m3.update_move(heuristic(m3))\n", + "m3.draw()\n", + "\n", + "m4 = maze4()\n", + "m4.update_move(heuristic(m4))\n", + "m4.draw()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Assignment 2\n", + "\n", + "Once you have this working, write an agent which finds a policy for a \"blind\" puzzle using MCTS. \"Blind\" puzzles are just like the puzzles above, only (a) you don't get to see the whole puzzle or know the goal states in advance, and (b) some nodes are trap doors with a chance of dropping the player into a bottomless pit! Try different policies for deciding between exploit/explore and for doing rollouts and compare them. Plot graphs on how learning improves with more rollouts.\n", + "\n", + "Of course, it should also be able to solve the earlier maze puzzles!" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "class TreeNode:\n", + " \n", + " def __init__(self, maze, action = None, val = 0):\n", + " # instance variables: maze, action to get to the tree, expected value (to be updated),\n", + " # parent, array of children, visit count\n", + " self.maze = maze\n", + " self.expected_val = val\n", + " self.move = action\n", + " self.parent = None\n", + " self.children = []\n", + " self.unvisited_moves = self.maze.available_moves()\n", + " self.visit_count = 0\n", + " \n", + " if self.maze.is_at_exit():\n", + " self.reward = 1\n", + " else: # if it's not the exit, there is no reward\n", + " self.reward = 0\n", + " \n", + " def add_child(self, tree_node):\n", + " self.children.append(tree_node)\n", + " tree_node.parent = self\n", + " \n", + " def visit(self, r): # reward\n", + " # visit count has been updated, this averages the expected value\n", + " net_reward = self.expected_val * self.visit_count\n", + " self.visit_count += 1\n", + " new_reward = (net_reward + r)/self.visit_count\n", + " \n", + " # recursively calls\n", + " r *= 0.999\n", + " if (self.parent != None):\n", + " self.parent.visit(r)\n", + " \n", + " def best_child(): # return chosen move based on UCT algorithm\n", + " # will return a node if it is unvisited\n", + " max_val = -1\n", + " best_child = self\n", + " for move in self.maze.available_moves():\n", + " if move in self.unvisited_moves():\n", + " unvisited_moves.remove(move)\n", + " return move # returns new move if not yet tried\n", + " \n", + " # if all the children have been visited\n", + " for child in self.children:\n", + " visits = child.visit_count\n", + " child_val = (child.expected_val/visits) + 2*0.707(Math.sqrt(2*ln(node.visit_count)/visits))\n", + " if child_val > max_val:\n", + " best_child = child\n", + " max_val = child_val\n", + " return best_child.move # return most advantageous child\n", + "\n", + "def tree_policy(node): # output is a node just added OR a terminal node\n", + " # checks if the node is terminal\n", + " \n", + " if len(node.children) == 0:\n", + " return node # if the node has no children that are on the tree\n", + " \n", + " # chooses which action out of the available moves to complete\n", + " child_move = node.best_move() \n", + " copy = node.maze.clone() \n", + " # perform the move\n", + " if child_move == \"switch\":\n", + " copy.toggle()\n", + " else:\n", + " copy.move_player(child_move[0], child_move[1])\n", + " \n", + " # if the child has been visited (is one of the children),\n", + " # will continue tree policy\n", + " \n", + " # if the child's maze is new to that layer, it will make a new TreeNode\n", + " for n in node.children:\n", + " if n.maze == copy:\n", + " return tree_policy(n) # recursive\n", + " new_node = TreeNode(copy, child_move)\n", + " node.add_child(new_node)\n", + " return new_node\n", + "\n", + "def default_policy(node, bound):\n", + " # track number of steps\n", + " # return (terminal_reward, num_steps)\n", + " copy = node.maze.clone()\n", + " steps = 0\n", + " while (copy.is_at_exit() == False and len(copy.available_moves()) > 0 \n", + " and copy.player_alive and steps < bound):\n", + " poss_moves = copy.available_moves()\n", + " random_move = poss_moves[randint(0, len(poss_moves)-1)]\n", + " if random_move == \"switch\":\n", + " copy.toggle()\n", + " else:\n", + " copy.move_player(random_move[0], random_move[1]) # need to account for switches\n", + " steps += 1\n", + " if (copy.is_at_exit()):\n", + " return (1, steps)\n", + " return (0, steps)\n", + "\n", + "def backpropagate(node, reward, num_steps):\n", + " # while loop\n", + " # reducing_factor gamma is 0.999, to the power of num_steps * reward\n", + " node.visit(reward*0.999^num_steps)\n", + " \n", + " \n", + "def mcts(maze,iterations):\n", + " # Return the expected value (a number between 0 for \"player dead\", 1 for \"made it to the end\")\n", + " # for a budget of `iterations` rollouts.\n", + " # Should also return the best found path (the one most likely to lead to success).\n", + " # Here, don't look at maze.exit_pos or maze.grid:\n", + " # you're only allowed to query `maze.available_moves()`, `maze.player_alive`, and `maze.is_at_exit`.\n", + "\n", + " # After training for `iterations` rollouts, run an agent through the maze using that learned policy \n", + " # for a large number of times and return the average reward:\n", + " # (best_path, expected_reward, test_reward)\n", + " \n", + " \n", + " \n", + " \n", + " # Training\n", + " node = TreeNode(maze) # 1. Initialize tree\n", + " solution_times = []\n", + " for i in range (0, iterations):\n", + " bottom_child = tree_policy(node)\n", + " (reward, steps) = default_policy(node, 200)\n", + " if reward == 1:\n", + " solution_times.append(i)\n", + " node.visit(reward*0.999**steps)\n", + " return (solution_times, 0)\n", + " \n", + " # 1. Initialize tree\n", + " # 2. Until out of time\n", + " # Pick a tree node T and action A using Tree Policy\n", + " # Add S = successor(T, A)\n", + " # Simulate from S until time/terminal node is reached (Track number of steps N, reward R)\n", + " # Backup reward R to S, T, and T's ancestor\n", + "\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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\nYII=\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\nu6Redfm8S9J+SdsiYkfbm2o8JOlezfHwHyckbbO9w/bdbY9p4EuS/mV7Y3UJ/Uvb/W2P6sJ3JD0z\n3QHF/Ol2uqsu9zdLuqc6U53TIuLTiLhC0lJJK2wvb3vTydi+WdJEdSXg6p8SrIyIKzV1Zv396nbW\nXNYn6UpJv6h2H5R0X7uTmrE9X9JqSc9Nd9xMg/oPSRcc9fHS6veQqLrXtFnSUxGxpe093agu6V6S\ntKrtLdNYKWl1dU/yGUnX2n6y5U21ImJf9eukpBFN3YKby96XtDci/lB9vFlTgS3BtyW9UX2tT2qm\nQd0h6Su2L7R9pqTbJJXwCmlJZyGS9Jik0Yh4uO0hTdg+2/bi6nG/pOslzdkX0SLi/oi4ICIu1tT3\n8PaIuKPtXdOxvai6apHtAUk3SPpTu6umFxETkvbavqT6reskjbY4qRu3q+ZyX2rwxv7plPimf9tP\nS7pG0hdtvyfpgc9uks9FtldKWitpT3VPMiTdHxG/bXfZtM6T9ET1qug8Sc9GxIstbzrVLJE0Uv2V\n7z5JmyJia8ubmlgnaVN1Cf2OpLta3lPL9iJNvSD1vdpjeWM/AOTgRSkASEJQASAJQQWAJAQVAJIQ\nVABIQlABIAlBBYAkBBUAkvwP11nYeNEt3bUAAAAASUVORK5CYII=\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def maze5():\n", + " return Maze([\n", + " \"#######\",\n", + " \"#@???X#\",\n", + " \"#.....#\",\n", + " \"#######\"\n", + " ])\n", + "\n", + "maze5().draw()\n", + "\n", + "def maze6():\n", + " return Maze([\n", + " \"#######\",\n", + " \"#@?!?X#\",\n", + " \"#.???.#\",\n", + " \"#.....#\",\n", + " \"#######\"\n", + " ])\n", + "\n", + "maze6().draw()\n", + "\n", + "def maze7():\n", + " return Maze([\n", + " \"########\",\n", + " \"#@0#?01#\",\n", + " \"#A1#C#a#\",\n", + " \"#0#.?#!#\",\n", + " \"#aBc2#.#\",\n", + " \"#B##c.?#\",\n", + " \"#.!#bb##\",\n", + " \"##1#.?X#\",\n", + " \"########\"\n", + " ])\n", + "\n", + "maze7().draw()" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "([], 0)\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# m5 = maze5()\n", + "# print(mcts(m5, 1000))\n", + "# m5.draw()\n", + "\n", + "# m6 = maze6()\n", + "# print(mcts(m6, 1000))\n", + "# m6.draw()\n", + "\n", + "m7 = maze7()\n", + "print(mcts(m7, 4000))\n", + "m7.draw()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Assignment 3\n", + "\n", + "Do assignment 2 again, but with reinforcement learning! Compare various approaches and parameters (e.g.\\ different discounting rates, Sarsa vs Q-learning, etc) against your MCTS agents in terms of iterations required to reach certain levels of performance. Plot graphs showing how learning improves with more iterations. Print or draw out (at least some of) the state-value or action-value matrix.\n", + "\n", + "Read as much as you care to of Sutton & Barto---[section 2](https://webdocs.cs.ualberta.ca/~sutton/book/ebook/node39.html) is especially useful.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def rl(maze,iterations):\n", + " # Return the best path (most likely to lead to success) along with its expected value and a validated value\n", + " # for a budget of `iterations` experiments.\n", + " # As above, don't look at maze.exit_pos or maze.grid:\n", + " # you're only allowed to query `maze.available_moves()`, `maze.player_alive`, and `maze.is_at_exit`.\n", + "\n", + " # After training for `iterations` experiments, run an agent through the maze using that learned policy \n", + " # for a large number of times and return the average reward:\n", + " # (best_path, expected_reward, test_reward)\n", + "\n", + " return ([],0,0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Bonus Assignment\n", + "\n", + "Make an adversary for the maze who is trying to eat the player. Try to get the best performing adversary possible!" + ] + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python [Root]", + "language": "python", + "name": "Python [Root]" + }, + "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.5.2" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/projects/4-evaluations/eval.md b/projects/4-evaluations/eval.md index bb1cb85..bd152bd 100644 --- a/projects/4-evaluations/eval.md +++ b/projects/4-evaluations/eval.md @@ -2,31 +2,31 @@ Hello, and thanks for your interest in the class! I've been really impressed with everyone's level of engagement and pace with the material, and I wanted to get a sense of how everyone is feeling about the course at the end of the first week. Here are a few short questions. Please fill the multiple-choice questions out by replacing the placeholder `(_)` with your choice (among A, B, etc), and put your answers to the free-form questions on the subsequent line. When you're done, email this to a TA and they'll compile them together, anonymize them, and send them to me. -The amount of reading is (_) +The amount of reading is (B) A. not enough B. about right C. too much -I’d prefer the lectures to (_) +I’d prefer the lectures to (B) A. go slower B. remain the same C. go faster -The assignments so far (_) +The assignments so far (C) A. are too short—we need more to do. B. are just right. C. are too long/difficult—we need more time/help to complete them. -I’d find it useful to have (_) +I’d find it useful to have (B) A. more discussion in general B. the same amount of discussion C. less discussion in general -I’d find it useful if we discussed specific readings for (_) +I’d find it useful if we discussed specific readings for (M) A. more time B. about the same amount of time @@ -38,4 +38,4 @@ Are there any topics you would like to see covered in the course that are not al Are there any topics that we’ve covered in class that you would have liked to have spent more time on? -(_) +(MCTS) diff --git a/projects/4-project-ideas/Kwan.ipynb b/projects/4-project-ideas/Kwan.ipynb new file mode 100644 index 0000000..ee7a5bd --- /dev/null +++ b/projects/4-project-ideas/Kwan.ipynb @@ -0,0 +1,52 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Project proposal\n", + "\n", + "Group: Melissa Kwan (individual)\n", + "Goal: To explore novelty search and compare its performance on mazes compared to MCTS\n", + "\n", + "Steps\n", + "- Finish writing MCTS and testing it\n", + "- Research novelty search (Long step)\n", + "- Write pseudocode (Long step)\n", + "- Code it based on researched steps (Long step)\n", + "- Test novelty search's performance on different mazes\n", + "- Compare results with MCTS\n", + "- Come up with conclusion\n", + "\n", + "Testing\n", + "- Data has already been provided (Mazes from assignment 3)\n", + "\n", + "Halfway there\n", + "- MCTS finished and tested\n", + "- Pseudocode for novelty search written\n", + "- Basic outline for novelty search written" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python [Root]", + "language": "python", + "name": "Python [Root]" + }, + "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.5.2" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/projects/6-perceptron/Kwan.ipynb b/projects/6-perceptron/Kwan.ipynb new file mode 100644 index 0000000..0905fd2 --- /dev/null +++ b/projects/6-perceptron/Kwan.ipynb @@ -0,0 +1,309 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "from random import uniform, choice\n", + "import matplotlib.pyplot as plt\n", + "from numpy import dot\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def plot_xys(xy_l_tuples,sz=15):\n", + " t_yes = [a[0] for a in xy_l_tuples if a[1] == 1]\n", + " t_no = [a[0] for a in xy_l_tuples if a[1] == 0]\n", + " plt.plot([x for (x,y) in t_yes],[y for (x,y) in t_yes],'go',markersize=sz)\n", + " plt.plot([x for (x,y) in t_no],[y for (x,y) in t_no],'ro',markersize=sz)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def tuple_append(tpl,elt):\n", + " return tuple(list(tpl)+[elt])\n", + "\n", + "def perceptron(training, epochs):\n", + " # some parameters, maybe interesting to make these arguments\n", + " rate = 1.0\n", + " # how many weights do we need?\n", + " feature_count = len(training[0][0])\n", + " # pad each training example with a dummy 1 input\n", + " training = [(tuple_append(ins,1), label) for (ins,label) in training]\n", + " # initialize weights to random values\n", + " weights = [uniform(0,0.05) for _r in range(0,feature_count+1)]\n", + " # store the errors found during training\n", + " errors = []\n", + " for i in range(0,epochs):\n", + " # in each epoch, pick a subset of the training set (just one for now)\n", + " (example,actual) = choice(training)\n", + " # calculate the perceptron activation and the predicted category\n", + " activation = dot(example, weights)\n", + " # Note: You can use dot(vec1, vec2) to get the dot product between two sequential collections.\n", + " \n", + " predicted = 0\n", + " if activation >= 0:\n", + " predicted = 1\n", + " \n", + " # calculate the error between predicted and actual and add it to errors\n", + " error = actual-predicted\n", + " errors.append(error)\n", + " \n", + " # update each weight according to the perceptron update rule\n", + " for i in range (0, feature_count + 1):\n", + " weights[i] += example[i]*error\n", + " \n", + " return (errors,weights)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXkAAAEACAYAAABWLgY0AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAADzpJREFUeJzt3H+I3Hedx/Hnq8ZKDW2hFgMmtnfXXCyKNYomAQs3tnJN\nBYn4z7X1KhaVwF1U8A9TK22X1qr548Bri0rugiKnRLDC5TzFinSR3jUxQrbRM+kmVWKTSrz6o8Ze\neqThfX/sXDpdk8zs7uxs9pPnAwb2O/PZ77z5svvMN9+Z2VQVkqQ2XbDQA0iS5o+Rl6SGGXlJapiR\nl6SGGXlJapiRl6SG9Y18km1JjibZe5Y19yc5kGQiyerhjihJmq1BzuS/DNxwpgeT3AhcVVV/CWwE\nvjSk2SRJc9Q38lX1KPC7syzZAHy1u3YXcGmSZcMZT5I0F8O4Jr8ceKpn+0j3PknSAvOFV0lq2JIh\n7OMI8Nqe7RXd+/5EEv9QjiTNQlVlNt836Jl8urfT2QG8HyDJOuD3VXX0TDuqM9weWrqUiYkJquq8\nuN19990LPsO5cvNYeCzO92OxZ88eXvm3r4QxTn+bg75n8km+DnSAVyX5JXA3cCFQVbW1qr6T5F1J\nDgLPAbfNZpA9y5dz46pVs/lWSVrUXve617Hif1YwyeTQ99038lV1ywBrNs1liD8AL1+3josuumgu\nu5GkRemiiy5i7WvXMvm/k/CK4e77nHjh9Z+XLeN9d9650GOMVKfTWegRzhkeixd5LF50vh2Luzbd\nxbInhv/u81SN7rXQJH/ybDsuuYT/3ryZD95xx8jmkKRz0X3/eB9bJrZw7M+OvfSBsfl/4XXo/gD8\nw7JlBl6Suj71sU9x++rbWbZ3GTw/nH2O/Ez+oaVLmVixgpevXcstd97JVStXjuz5JWkxOHjwIPc+\neC87f7mTI0uP8Ny/PDfrM/mRR35iYoJVq1b5Iqsk9XH8+HEmJydZvXr14on8KJ9PklqQZPFdk5ck\nzT8jL0kNM/KS1DAjL0kNM/KS1DAjL0kNM/KS1DAjL0kNM/KS1DAjL0kNM/KS1DAjL0kNM/KS1DAj\nL0kNM/KS1DAjL0kNM/KS1DAjL0kNM/KS1DAjL0kNM/KS1DAjL0kNM/KS1DAjL0kNM/KS1DAjL0kN\nM/KS1DAjL0kNM/KS1DAjL0kNGyjySdYn2Z9kMsnm0zx+SZIdSSaS/CTJB4Y+qSRpxlJVZ1+QXABM\nAtcDTwO7gZuqan/Pmk8Cl1TVJ5NcDjwBLKuqF6btq/o9nyTppZJQVZnN9w5yJr8GOFBVh6rqBLAd\n2DBtTQEXd7++GPjN9MBLkkZvkMgvB57q2T7cva/Xg8DrkzwNPA58bDjjSZLmYsmQ9nMDsKeqrkty\nFfD9JNdU1R+nLxwbGzv1dafTodPpDGkESWrD+Pg44+PjQ9nXINfk1wFjVbW+u307UFW1pWfNt4HP\nVtV/dLd/AGyuqh9P25fX5CVphub7mvxuYGWSK5NcCNwE7Ji25hDwzu4wy4BVwM9nM5AkaXj6Xq6p\nqpNJNgEPM/WPwraq2pdk49TDtRX4NPCVJHu73/aJqvrtvE0tSRpI38s1Q30yL9dI0ozN9+UaSdIi\nZeQlqWFGXpIaZuQlqWFGXpIaZuQlqWFGXpIaZuQlqWFGXpIaZuQlqWFGXpIaZuQlqWFGXpIaZuQl\nqWFGXpIaZuQlqWFGXpIaZuQlqWFGXpIaZuQlqWFGXpIaZuQlqWFGXpIaZuQlqWFGXpIaZuQlqWFG\nXpIaZuQlqWFGXpIaZuQlqWFGXpIaZuQlqWFGXpIaZuQlqWFGXpIaNlDkk6xPsj/JZJLNZ1jTSbIn\nyU+TPDLcMSVJs5GqOvuC5AJgErgeeBrYDdxUVft71lwK/Cfw11V1JMnlVfXMafZV/Z5PkvRSSaiq\nzOZ7BzmTXwMcqKpDVXUC2A5smLbmFuChqjoCcLrAS5JGb5DILwee6tk+3L2v1yrgsiSPJNmd5NZh\nDShJmr0lQ9zPW4DrgKXAY0keq6qDQ9q/JGkWBon8EeCKnu0V3ft6HQaeqarngeeT/BB4E/AnkR8b\nGzv1dafTodPpzGxiSWrc+Pg44+PjQ9nXIC+8vgx4gqkXXn8F/Ai4uar29ay5GngAWA+8AtgF/E1V\n/WzavnzhVZJmaC4vvPY9k6+qk0k2AQ8zdQ1/W1XtS7Jx6uHaWlX7k3wP2AucBLZOD7wkafT6nskP\n9ck8k5ekGZvvt1BKkhYpIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPy\nktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQw\nIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9J\nDRso8knWJ9mfZDLJ5rOse1uSE0neO7wRJUmz1TfySS4AHgRuAN4A3Jzk6jOs+xzwvWEPKUmanUHO\n5NcAB6rqUFWdALYDG06z7iPAN4FfD3E+SdIcDBL55cBTPduHu/edkuQ1wHuq6otAhjeeJGkuhvXC\n6+eB3mv1hl6SzgFLBlhzBLiiZ3tF975ebwW2JwlwOXBjkhNVtWP6zsbGxk593el06HQ6MxxZkto2\nPj7O+Pj4UPaVqjr7guRlwBPA9cCvgB8BN1fVvjOs/zLwb1X1rdM8Vv2eT5L0UkmoqlldIel7Jl9V\nJ5NsAh5m6vLOtqral2Tj1MO1dfq3zGYQSdLw9T2TH+qTeSYvSTM2lzN5P/EqSQ0z8pLUMCMvSQ0z\n8pLUMCMvSQ0z8pLUMCMvSQ0z8pLUMCMvSQ0z8pLUMCMvSQ0z8pLUMCMvSQ0z8pLUMCMvSQ0z8pLU\nMCMvSQ0z8pLUMCMvSQ0z8pLUMCMvSQ0z8pLUMCMvSQ0z8pLUMCMvSQ0z8pLUMCMvSQ0z8pLUMCMv\nSQ0z8pLUMCMvSQ0z8pLUMCMvSQ0z8pLUMCMvSQ0z8pLUsIEin2R9kv1JJpNsPs3jtyR5vHt7NMkb\nhz+qJGmmUlVnX5BcAEwC1wNPA7uBm6pqf8+adcC+qno2yXpgrKrWnWZf1e/5JEkvlYSqymy+d5Az\n+TXAgao6VFUngO3Aht4FVbWzqp7tbu4Els9mGEnScA0S+eXAUz3bhzl7xD8EfHcuQ0mShmPJMHeW\n5B3AbcC1Z1ozNjZ26utOp0On0xnmCJK06I2PjzM+Pj6UfQ1yTX4dU9fY13e3bweqqrZMW3cN8BCw\nvqqePMO+vCYvSTM039fkdwMrk1yZ5ELgJmDHtAGuYCrwt54p8JKk0et7uaaqTibZBDzM1D8K26pq\nX5KNUw/XVuBO4DLgC0kCnKiqNfM5uCSpv76Xa4b6ZF6ukaQZm+/LNZKkRcrIS1LDjLwkNczIS1LD\njLwkNczIS1LDjLwkNczIS1LDjLwkNczIS1LDjLwkNczIS1LDjLwkNczIS1LDjLwkNczIS1LDjLwk\nNczIS1LDjLwkNczIS1LDjLwkNczIS1LDjLwkNczIS1LDjLwkNczIS1LDjLwkNczIS1LDjLwkNczI\nS1LDjLwkNczIS1LDRh75iYkJjh8/PuqnlaRF5/jx40xMTMxpH0uGNMvAfvH2t/OtFStYsnYt77vr\nLq5auXLUI0jSOe3Jgwf52j338MKuXbz58OE57StVNaSxBniy5NSzHQP+adkyLv3oR/ngHXeMbAZJ\nOpdtu+8+nn3gAT589CgXd+8LUFWZzf4GulyTZH2S/Ukmk2w+w5r7kxxIMpFkdb99Xgx8/OhRXv25\nz7HtM5+Z4diS1J5t993Hq7ds4eM9gZ+rvpFPcgHwIHAD8Abg5iRXT1tzI3BVVf0lsBH40qADvPvY\nMZ69/36ePHhwRoMvduPj4ws9wjnDY/Eij8WLzrdj8eTBgzz7wAO8+9ixoe53kDP5NcCBqjpUVSeA\n7cCGaWs2AF8FqKpdwKVJlg06xIeOHuVr99476PImnG8/wGfjsXiRx+JF59ux+No99/Dho0eHvt9B\nIr8ceKpn+3D3vrOtOXKaNWd0CXBi507fdSPpvHT8+HFe2LVraJdoep0z75N/85EjTE5OLvQYkjRy\nTzzxxJzfRXMmfd9dk2QdMFZV67vbtwNVVVt61nwJeKSqvtHd3g/8VVUdnbav0b2VR5IaMtt31wzy\nPvndwMokVwK/Am4Cbp62Zgfw98A3uv8o/H564OcypCRpdvpGvqpOJtkEPMzU5Z1tVbUvycaph2tr\nVX0nybuSHASeA26b37ElSYMY6YehJEmjNS8vvM7Hh6cWq37HIsktSR7v3h5N8saFmHMUBvm56K57\nW5ITSd47yvlGacDfkU6SPUl+muSRUc84KgP8jlySZEe3FT9J8oEFGHPeJdmW5GiSvWdZM/NuVtVQ\nb0z9w3EQuBJ4OTABXD1tzY3Av3e/XgvsHPYc58JtwGOxDri0+/X68/lY9Kz7AfBt4L0LPfcC/lxc\nCvwXsLy7fflCz72Ax+KTwGf//zgAvwGWLPTs83AsrgVWA3vP8PisujkfZ/Lz/uGpRaTvsaiqnVX1\nbHdzJzP4fMEiM8jPBcBHgG8Cvx7lcCM2yLG4BXioqo4AVNUzI55xVAY5FgWn3kJ+MfCbqnphhDOO\nRFU9CvzuLEtm1c35iPy8f3hqERnkWPT6EPDdeZ1o4fQ9FkleA7ynqr7I1N9katUgPxergMuSPJJk\nd5JbRzbdaA1yLB4EXp/kaeBx4GMjmu1cM6tujvxPDev0kryDqXclXbvQsyygzwO912RbDn0/S4C3\nANcBS4HHkjxWVefXH3macgOwp6quS3IV8P0k11TVHxd6sMVgPiJ/BLiiZ3tF977pa17bZ00LBjkW\nJLkG2Aqsr6qz/XdtMRvkWLwV2J4kTF17vTHJiaraMaIZR2WQY3EYeKaqngeeT/JD4E1MXb9uySDH\n4jbgswBV9WSSXwBXAz8eyYTnjll1cz4u15z68FSSC5n68NT0X9IdwPvh1CdqT/vhqQb0PRZJrgAe\nAm6tqicXYMZR6Xssquovurc/Z+q6/N81GHgY7HfkX4Frk7wsySuZeqFt34jnHIVBjsUh4J0A3WvQ\nq4Cfj3TK0Qln/h/srLo59DP58sNTpwxyLIA7gcuAL3TPYE9U1ZqFm3p+DHgsXvItIx9yRAb8Hdmf\n5HvAXuAksLWqfraAY8+LAX8uPg18peethZ+oqt8u0MjzJsnXgQ7wqiS/BO4GLmSO3fTDUJLUsHPm\nr1BKkobPyEtSw4y8JDXMyEtSw4y8JDXMyEtSw4y8JDXMyEtSw/4P4LBAXZvwSAcAAAAASUVORK5C\nYII=\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\nAJL+H6gY1shybUU9AAAAAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "and_set = [((0,0),0), ((0,1),0), ((1,0),0), ((1,1),1)]\n", + "plot_xys(and_set)\n", + "\n", + "(errs,_) = perceptron(and_set,100)\n", + "plt.figure()\n", + "plt.plot(errs)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXkAAAEACAYAAABWLgY0AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAD1ZJREFUeJzt3X+M3HWdx/HnC3sYJECC5JrYWu6OWohGqEbbJhBvBHMU\nkwvGfw644yI5kyZngeRysYgBNyAqf1yi0KjppdGYO4OJmNjzNGIMG4JHa01Y0LNlu+hhW0wN/iAI\n7aWS9/2xc+2wtp3Z3dnZ7qfPR7JhZ+az33nnk93nTr8zs6SqkCS16azFHkCStHCMvCQ1zMhLUsOM\nvCQ1zMhLUsOMvCQ1rG/kk2xPcijJ06dY80CSfUkmkqwd7oiSpLka5JH8l4BrT3ZjkuuAS6rqLcAm\n4ItDmk2SNE99I19VjwO/PcWS64GvdNfuAi5Isnw440mS5mMY5+RXAPt7Lh/sXidJWmQ+8SpJDVs2\nhGMcBN7cc3ll97o/ksQ/lCNJc1BVmcvXDRr5dD9OZAfwEeBrSTYAv6uqQyc90tiJrz536lx+8M8/\n4IorrhhwpKVtbGyMsbGxxR7jtOBeHOdeHHcm7cXExARX/suVvLL6lRMvGJv7sftGPslXgQ7wxiS/\nAD4BnA1UVW2rqm8neX+SKeBl4Ja5DLLi5RWsWbNmLl8qSUvapZdeyspXVjLJ5NCP3TfyVXXTAGs2\nz2uKI7Bh1QbOOeeceR1Gkpaic845h/VvXs/k/07C64d77NPiidflk8u5a/Ndiz3GSHU6ncUe4bTh\nXhznXhx3pu3F3ZvvZvkzw3/1+aJH/vyfn89t77mN1atXL/YoI3WmfQOfintxnHtx3Jm2F6tXr+bW\n99zKef9z3lCPu3iRPwLLn1rOlnds4c7b71y0MSTpdPHx2z/OHWvvYPnTy+HIcI6ZUf7v/5LUuX93\nLitfWcn6Veu56yN3nXGP4CWpn6mpKe7dei87f7GTg+ce5OV/e3nOL6EceeQnJiZYs2aNT7JKUh+H\nDx9mcnKStWvXLp3I+z8Ol6TZSTLnyC/6E6+SpIVj5CWpYUZekhpm5CWpYUZekhpm5CWpYUZekhpm\n5CWpYUZekhpm5CWpYUZekhpm5CWpYUZekhpm5CWpYUZekhpm5CWpYUZekhpm5CWpYUZekhpm5CWp\nYUZekhpm5CWpYUZekhpm5CWpYUZekhpm5CWpYUZekhpm5CWpYUZekhpm5CWpYQNFPsnGJHuTTCbZ\ncoLbz0+yI8lEkh8n+dDQJ5UkzVqq6tQLkrOASeAa4HlgN3BDVe3tWfMx4Pyq+liSi4BngOVV9YcZ\nx6p+9ydJeq0kVFXm8rWDPJJfB+yrqueq6ijwEHD9jDUFnNf9/Dzg1zMDL0kavUEivwLY33P5QPe6\nXluBtyZ5HngKuH0440mS5mPZkI5zLfBkVV2d5BLge0kur6rfz1w4NjZ27PNOp0On0xnSCJLUhvHx\nccbHx4dyrEHOyW8AxqpqY/fyHUBV1f09a74FfLqqftC9/H1gS1X9aMaxPCcvSbO00OfkdwOrk1yc\n5GzgBmDHjDXPAe/rDrMcWAP8bC4DSZKGp+/pmqp6Nclm4BGmfylsr6o9STZN31zbgE8CX07ydPfL\nPlpVv1mwqSVJA+l7umaod+bpGkmatYU+XSNJWqKMvCQ1zMhLUsOMvCQ1zMhLUsOMvCQ1zMhLUsOM\nvCQ1zMhLUsOMvCQ1zMhLUsOMvCQ1zMhLUsOMvCQ1zMhLUsOMvCQ1zMhLUsOMvCQ1zMhLUsOMvCQ1\nzMhLUsOMvCQ1zMhLUsOMvCQ1zMhLUsOMvCQ1zMhLUsOMvCQ1zMhLUsOMvCQ1zMhLUsOMvCQ1zMhL\nUsOMvCQ1zMhLUsMGinySjUn2JplMsuUkazpJnkzykySPDndMSdJcpKpOvSA5C5gErgGeB3YDN1TV\n3p41FwD/BfxVVR1MclFVvXCCY1W/+5MkvVYSqipz+dpBHsmvA/ZV1XNVdRR4CLh+xpqbgIer6iDA\niQIvSRq9QSK/Atjfc/lA97pea4ALkzyaZHeSm4c1oCRp7pYN8TjvBK4GzgWeSPJEVU0N6fiSpDkY\nJPIHgVU9l1d2r+t1AHihqo4AR5I8BlwB/FHkx8bGjn3e6XTodDqzm1iSGjc+Ps74+PhQjjXIE6+v\nA55h+onXXwI/BG6sqj09ay4DHgQ2Aq8HdgF/U1U/nXEsn3iVpFmazxOvfR/JV9WrSTYDjzB9Dn97\nVe1Jsmn65tpWVXuTfBd4GngV2DYz8JKk0ev7SH6od+YjeUmatYV+CaUkaYky8pLUMCMvSQ0z8pLU\nMCMvSQ0z8pLUMCMvSQ0z8pLUMCMvSQ0z8pLUMCMvSQ0z8pLUMCMvSQ0z8pLUMCMvSQ0z8pLUMCMv\nSQ0z8pLUMCMvSQ0z8pLUMCMvSQ0z8pLUMCMvSQ0z8pLUMCMvSQ0z8pLUMCMvSQ0z8pLUMCMvSQ0z\n8pLUMCMvSQ0z8pLUMCMvSQ0z8pLUMCMvSQ0z8pLUsIEin2Rjkr1JJpNsOcW6dyc5muSDwxtRkjRX\nfSOf5CxgK3At8DbgxiSXnWTdZ4DvDntISdLcDPJIfh2wr6qeq6qjwEPA9SdYdyvwdeBXQ5xPkjQP\ng0R+BbC/5/KB7nXHJHkT8IGq+gKQ4Y0nSZqPYT3x+lmg91y9oZek08CyAdYcBFb1XF7Zva7Xu4CH\nkgS4CLguydGq2jHzYGNjY8c+73Q6dDqdWY4sSW0bHx9nfHx8KMdKVZ16QfI64BngGuCXwA+BG6tq\nz0nWfwn4j6r6xgluq373J0l6rSRU1ZzOkPR9JF9VrybZDDzC9Omd7VW1J8mm6Ztr28wvmcsgkqTh\n6/tIfqh35iN5SZq1+TyS9x2vktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQw\nIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9J\nDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPy\nktQwIy9JDRso8kk2JtmbZDLJlhPcflOSp7ofjyd5+/BHlSTNVqrq1AuSs4BJ4BrgeWA3cENV7e1Z\nswHYU1UvJtkIjFXVhhMcq/rdnyTptZJQVZnL1w7ySH4dsK+qnquqo8BDwPW9C6pqZ1W92L24E1gx\nl2EkScM1SORXAPt7Lh/g1BH/MPCd+QwlSRqOZcM8WJL3ArcAV51szdjY2LHPO50OnU5nmCNI0pI3\nPj7O+Pj4UI41yDn5DUyfY9/YvXwHUFV1/4x1lwMPAxur6tmTHMtz8pI0Swt9Tn43sDrJxUnOBm4A\ndswYYBXTgb/5ZIGXJI1e39M1VfVqks3AI0z/UtheVXuSbJq+ubYBdwEXAp9PEuBoVa1byMElSf31\nPV0z1DvzdI0kzdpCn66RJC1RRl6SGmbkJalhRl6SGmbkJalhRl6SGmbkJalhRl6SGmbkJalhRl6S\nGmbkJalhRl6SGmbkJalhRl6SGmbkJalhRl6SGmbkJalhRl6SGmbkJalhRl6SGmbkJalhRl6SGmbk\nJalhRl6SGmbkJalhRl6SGmbkJalhRl6SGmbkJalhRl6SGmbkJalhRl6SGjbyyE9MTHD48OFR360k\nLTmHDx9mYmJiXsdYNqRZBvbzK6/kGytXsmz9ev727ru5ZPXqUY8gSae1qakp7tl6D7v27+LAGw7M\n61ipqiGNNcCdJcfu7SXgX5cv54LbbuMf7rxzZDNI0unsvs/dx4OPPcihSw/B67tXjkFVZS7HG+h0\nTZKNSfYmmUyy5SRrHkiyL8lEkrX9jnke8E+HDvGnn/kM2z/1qVmOLUntue9z93H/xP0curwn8PPU\nN/JJzgK2AtcCbwNuTHLZjDXXAZdU1VuATcAXBx3gr196iRcfeIBnp6ZmNfhSNz4+vtgjnDbci+Pc\ni+POtL2Ympriwcce5KU/e2moxx3kkfw6YF9VPVdVR4GHgOtnrLke+ApAVe0CLkiyfNAhPnzoEP9+\n772DLm/CmfYNfCruxXHuxXFn2l7cs/We6VM0QzZI5FcA+3suH+hed6o1B0+w5qTOB47u3OmrbiSd\nkQ4fPsyu/buGdoqm12nzOvl3HDzI5OTkYo8hSSP3zDPPzPtVNCfT99U1STYAY1W1sXv5DqCq6v6e\nNV8EHq2qr3Uv7wX+sqoOzTjW6F7KI0kNmeurawZ5nfxuYHWSi4FfAjcAN85YswP4CPC17i+F380M\n/HyGlCTNTd/IV9WrSTYDjzB9emd7Ve1Jsmn65tpWVd9O8v4kU8DLwC0LO7YkaRAjfTOUJGm0FuSJ\n14V489RS1W8vktyU5Knux+NJ3r4Yc47CIN8X3XXvTnI0yQdHOd8oDfgz0knyZJKfJHl01DOOygA/\nI+cn2dFtxY+TfGgRxlxwSbYnOZTk6VOsmX03q2qoH0z/4pgCLgb+BJgALpux5jrgP7ufrwd2DnuO\n0+FjwL3YAFzQ/XzjmbwXPeu+D3wL+OBiz72I3xcXAP8NrOhevmix517EvfgY8On/3wfg18CyxZ59\nAfbiKmAt8PRJbp9TNxfikfyCv3lqCem7F1W1s6pe7F7cySzeX7DEDPJ9AXAr8HXgV6McbsQG2Yub\ngIer6iBAVb0w4hlHZZC9KKb/Egrd//66qv4wwhlHoqoeB357iiVz6uZCRH7B3zy1hAyyF70+DHxn\nQSdaPH33IsmbgA9U1ReAll+JNcj3xRrgwiSPJtmd5OaRTTdag+zFVuCtSZ4HngJuH9Fsp5s5dXPk\nf2pYJ5bkvUy/KumqxZ5lEX0W6D0n23Lo+1kGvBO4GjgXeCLJE1V1Zv2Rp2nXAk9W1dVJLgG+l+Ty\nqvr9Yg+2FCxE5A8Cq3our+xeN3PNm/usacEge0GSy4FtwMaqOtU/15ayQfbiXcBDScL0udfrkhyt\nqh0jmnFUBtmLA8ALVXUEOJLkMeAKps9ft2SQvbgF+DRAVT2b5OfAZcCPRjLh6WNO3VyI0zXH3jyV\n5Gym3zw184d0B/D3cOwdtSd881QD+u5FklXAw8DNVfXsIsw4Kn33oqr+ovvx50yfl//HBgMPg/2M\nfBO4KsnrkryB6Sfa9ox4zlEYZC+eA94H0D0HvQb42UinHJ1w8n/BzqmbQ38kX7556phB9gK4C7gQ\n+Hz3EezRqlq3eFMvjAH34jVfMvIhR2TAn5G9Sb4LPA28Cmyrqp8u4tgLYsDvi08CX+55aeFHq+o3\nizTygknyVaADvDHJL4BPAGczz276ZihJathp81coJUnDZ+QlqWFGXpIaZuQlqWFGXpIaZuQlqWFG\nXpIaZuQlqWH/B+0+jLk322bvAAAAAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "or_set = [((0,0),0), ((0,1),1), ((1,0),1), ((1,1),1)]\n", + "plot_xys(or_set)\n", + "\n", + "(errs,_) = perceptron(or_set,100)\n", + "plt.figure()\n", + "plt.plot(errs)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXkAAAEACAYAAABWLgY0AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAADzZJREFUeJzt3H+I3Hedx/Hnq+YqbWkLvWLAxPTumkuLYq2iScDCja1c\n0wOJeH9cW61YlAtoVLg/TK20XVqr5p9D26JeJCiCEsEKl/MUK9Kl9GxihGyrZ9JNaolJKpH6oxd7\nKcTwvj92Lp2uSWZ2d3Y2+8nzAUP3O/PZ77z5svvMt9+Z2VQVkqQ2nbfQA0iS5o+Rl6SGGXlJapiR\nl6SGGXlJapiRl6SG9Y18kq1JjiR56gxrHkiyL8lEkmuHO6IkabYGOZP/KnDj6R5MchNwZVX9LbAB\n+PKQZpMkzVHfyFfV48Dvz7BkPfD17tqdwKVJlg5nPEnSXAzjmvwy4GDP9uHufZKkBeYLr5LUsCVD\n2Mdh4HU928u79/2ZJP6hHEmaharKbL5v0DP5dG+nsh14P0CStcAfqurIafc0durbRe+7iImJCarq\nnLjdc889Cz7D2XLzWHgszvVjsXv3br5z4YUUnPI2F4O8hfKbwI+BVUl+leT2JBuS/DNAVX0PeDbJ\nfuDfgA/PZpBlLy5j1apVs/lWSVrUrrrqKnYvXz4v++57uaaqbh1gzcY5TfESrF2xlgsuuGBOu5Gk\nxeiCCy5gyZo1HJ2c5OIh7/useOF16eRS7tp410KPMVKdTmehRzhreCxe5rF42bl2LN579918Zenw\n332eqtG9FpqkGHvlfZc8ewmb3ryJOz9+58jmkKSz0db77+c1mzfzrqNHX3F/mP8XXofvJVj65FID\nL0ldH/zUp/jNHXfwr0uX8j9D2ufIz+Qvet9FLP/f5axZsYa7PnIXK1euHNnzS9Ji8Mz+/Xzjvvs4\nvmMHbz58mH988cVZn8mPPPITExOsWrXKF1klqY9jx44xOTnJtddeu3giP8rnk6QWJFmE1+QlSfPO\nyEtSw4y8JDXMyEtSw4y8JDXMyEtSw4y8JDXMyEtSw4y8JDXMyEtSw4y8JDXMyEtSw4y8JDXMyEtS\nw4y8JDXMyEtSw4y8JDXMyEtSw4y8JDXMyEtSw4y8JDXMyEtSw4y8JDXMyEtSw4y8JDXMyEtSw4y8\nJDXMyEtSw4y8JDXMyEtSwwaKfJJ1SfYmmUyy6RSPX5Jke5KJJD9L8oGhTypJmrFU1ZkXJOcBk8AN\nwHPALuDmqtrbs+aTwCVV9ckklwNPA0ur6k/T9lX9nk+S9EpJqKrM5nsHOZNfDeyrqgNVdRzYBqyf\ntqaAi7tfXwz8dnrgJUmjN0jklwEHe7YPde/r9RDw+iTPAU8CHx/OeJKkuVgypP3cCOyuquuTXAn8\nMMk1VfXH6QvHxsZOft3pdOh0OkMaQZLaMD4+zvj4+FD2Ncg1+bXAWFWt627fAVRVbe5Z813gs1X1\nX93tHwGbquqn0/blNXlJmqH5via/C1iZ5Iok5wM3A9unrTkAvLM7zFJgFfDL2QwkSRqevpdrqupE\nko3AI0z9o7C1qvYk2TD1cG0BPg18LclT3W/7RFX9bt6mliQNpO/lmqE+mZdrJGnG5vtyjSRpkTLy\nktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQw\nIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9J\nDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDTPyktQwIy9JDRso8knWJdmbZDLJptOs6STZneTn\nSR4d7piSpNlIVZ15QXIeMAncADwH7AJurqq9PWsuBX4M/H1VHU5yeVU9f4p9Vb/nkyS9UhKqKrP5\n3kHO5FcD+6rqQFUdB7YB66etuRV4uKoOA5wq8JKk0Rsk8suAgz3bh7r39VoFXJbk0SS7ktw2rAEl\nSbO3ZIj7eQtwPXAR8ESSJ6pq/5D2L0mahUEifxhY0bO9vHtfr0PA81X1EvBSkseANwF/FvmxsbGT\nX3c6HTqdzswmlqTGjY+PMz4+PpR9DfLC66uAp5l64fXXwE+AW6pqT8+aq4EHgXXAq4GdwD9V1S+m\n7csXXiVphubywmvfM/mqOpFkI/AIU9fwt1bVniQbph6uLVW1N8kPgKeAE8CW6YGXJI1e3zP5oT6Z\nZ/KSNGPz/RZKSdIiZeQlqWFGXpIaZuQlqWFGXpIaZuQlqWFGXpIaZuQlqWFGXpIaZuQlqWFGXpIa\nZuQlqWFGXpIaZuQlqWFGXpIaZuQlqWFGXpIaZuQlqWFGXpIaZuQlqWFGXpIaZuQlqWFGXpIaZuQl\nqWFGXpIaZuQlqWFGXpIaZuQlqWFGXpIaZuQlqWFGXpIaZuQlqWFGXpIaZuQlqWFGXpIaZuQlqWED\nRT7JuiR7k0wm2XSGdW9LcjzJe4Y3oiRptvpGPsl5wEPAjcAbgFuSXH2adZ8DfjDsISVJszPImfxq\nYF9VHaiq48A2YP0p1n0U+DbwmyHOJ0mag0Eivww42LN9qHvfSUleC7y7qr4EZHjjSZLmYlgvvH4e\n6L1Wb+gl6SywZIA1h4EVPdvLu/f1eiuwLUmAy4Gbkhyvqu3TdzY2Nnby606nQ6fTmeHIktS28fFx\nxsfHh7KvVNWZFySvAp4GbgB+DfwEuKWq9pxm/VeB/6iq75ziser3fJKkV0pCVc3qCknfM/mqOpFk\nI/AIU5d3tlbVniQbph6uLdO/ZTaDSJKGr++Z/FCfzDN5SZqxuZzJ+4lXSWqYkZekhhl5SWqYkZek\nhhl5SWqYkZekhhl5SWqYkZekhhl5SWqYkZekhhl5SWqYkZekhhl5SWqYkZekhhl5SWqYkZekhhl5\nSWqYkZekhhl5SWqYkZekhhl5SWqYkZekhhl5SWqYkZekhhl5SWqYkZekhhl5SWqYkZekhhl5SWqY\nkZekhhl5SWqYkZekhhl5SWqYkZekhhl5SWqYkZekhg0U+STrkuxNMplk0ykevzXJk93b40neOPxR\nJUkzlao684LkPGASuAF4DtgF3FxVe3vWrAX2VNULSdYBY1W19hT7qn7PJ0l6pSRUVWbzvYOcya8G\n9lXVgao6DmwD1vcuqKodVfVCd3MHsGw2w0iShmuQyC8DDvZsH+LMEf8Q8P25DCVJGo4lw9xZkncA\ntwPXnW7N2NjYya87nQ6dTmeYI0jSojc+Ps74+PhQ9jXINfm1TF1jX9fdvgOoqto8bd01wMPAuqp6\n5jT78pq8JM3QfF+T3wWsTHJFkvOBm4Ht0wZYwVTgbztd4CVJo9f3ck1VnUiyEXiEqX8UtlbVniQb\nph6uLcBdwGXAF5MEOF5Vq+dzcElSf30v1wz1ybxcI0kzNt+XayRJi5SRl6SGGXlJapiRl6SGGXlJ\napiRl6SGGXlJapiRl6SGGXlJapiRl6SGGXlJapiRl6SGGXlJapiRl6SGGXlJapiRl6SGGXlJapiR\nl6SGGXlJapiRl6SGGXlJapiRl6SGGXlJapiRl6SGGXlJapiRl6SGGXlJapiRl6SGGXlJapiRl6SG\nGXlJapiRl6SGjTzyExMTHDt2bNRPK0mLzrFjx5iYmJjTPpYMaZaBPfv2t/Od5ctZsmYN7737bq5c\nuXLUI0jSWW3//v3c+9C97Dy4k0MXHprTvlJVQxprgCdLTj7bUeArS5dy6cc+xgfvvHNkM0jS2ez+\nL9zPg489yJGrjsCru3eOQVVlNvsb6HJNknVJ9iaZTLLpNGseSLIvyUSSa/vt82LgX44c4TWf+xxb\nP/OZGY4tSe25/wv3s3liM0eu6Qn8HPWNfJLzgIeAG4E3ALckuXrampuAK6vqb4ENwJcHHeBdR4/y\nwgMP8Mz+/TMafLEbHx9f6BHOGh6Ll3ksXnauHYv9+/fz4GMPcvSvjg51v4Ocya8G9lXVgao6DmwD\n1k9bsx74OkBV7QQuTbJ00CE+dOQI37jvvkGXN+Fc+wE+E4/FyzwWLzvXjsW9D907dYlmyAaJ/DLg\nYM/2oe59Z1pz+BRrTusS4PiOHb7rRtI56dixY+w8uHNol2h6nTXvk3/z4cNMTk4u9BiSNHJPP/30\nnN9Fczp9312TZC0wVlXrutt3AFVVm3vWfBl4tKq+1d3eC/xdVR2Ztq/RvZVHkhoy23fXDPI++V3A\nyiRXAL8GbgZumbZmO/AR4FvdfxT+MD3wcxlSkjQ7fSNfVSeSbAQeYeryztaq2pNkw9TDtaWqvpfk\nH5LsB14Ebp/fsSVJgxjph6EkSaM1Ly+8zseHpxarfsciya1JnuzeHk/yxoWYcxQG+bnorntbkuNJ\n3jPK+UZpwN+RTpLdSX6e5NFRzzgqA/yOXJJke7cVP0vygQUYc94l2ZrkSJKnzrBm5t2sqqHemPqH\nYz9wBfAXwARw9bQ1NwH/2f16DbBj2HOcDbcBj8Va4NLu1+vO5WPRs+5HwHeB9yz03Av4c3Ep8N/A\nsu725Qs99wIei08Cn/3/4wD8Fliy0LPPw7G4DrgWeOo0j8+qm/NxJj/vH55aRPoei6raUVUvdDd3\nMIPPFywyg/xcAHwU+Dbwm1EON2KDHItbgYer6jBAVT0/4hlHZZBjUUz9JRS6//1tVf1phDOORFU9\nDvz+DEtm1c35iPy8f3hqERnkWPT6EPD9eZ1o4fQ9FkleC7y7qr4EtPxOrEF+LlYBlyV5NMmuJLeN\nbLrRGuRYPAS8PslzwJPAx0c029lmVt0c+Z8a1qkleQdT70q6bqFnWUCfB3qvybYc+n6WAG8Brgcu\nAp5I8kRVnVt/5GnKjcDuqro+yZXAD5NcU1V/XOjBFoP5iPxhYEXP9vLufdPXvK7PmhYMcixIcg2w\nBVhXVWf637XFbJBj8VZgW5Iwde31piTHq2r7iGYclUGOxSHg+ap6CXgpyWPAm5i6ft2SQY7F7cBn\nAarqmSTPAlcDPx3JhGePWXVzPi7XnPzwVJLzmfrw1PRf0u3A++HkJ2pP+eGpBvQ9FklWAA8Dt1XV\nMwsw46j0PRZV9Tfd218zdV3+ww0GHgb7Hfl34Lokr0pyIVMvtO0Z8ZyjMMixOAC8E6B7DXoV8MuR\nTjk64fT/Bzurbg79TL788NRJgxwL4C7gMuCL3TPY41W1euGmnh8DHotXfMvIhxyRAX9H9ib5AfAU\ncALYUlW/WMCx58WAPxefBr7W89bCT1TV7xZo5HmT5JtAB/jLJL8C7gHOZ47d9MNQktSws+avUEqS\nhs/IS1LDjLwkNczIS1LDjLwkNczIS1LDjLwkNczIS1LD/g9SqDiemnPSywAAAABJRU5ErkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "xor_set = [((0,0),0), ((0,1),1), ((1,0),1), ((1,1),0)]\n", + "plot_xys(xor_set)\n", + "\n", + "(errs,_) = perceptron(xor_set,100)\n", + "plt.figure()\n", + "plt.plot(errs)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Validation error: 0.0\n" + ] + }, + { + "data": { + "image/png": "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\nZcT/A/ycXVwv+LGPAAAAAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\nPobebYIBAGY1Jhjmungz+AwA1Us+GPp1JY2LSfQAoFhjgoFJ9ABgMpIPBibRA4DJalwwDEIwAEA5\nlQSD7fNs77G91/bGgjLftb3P9i7bpw17bCbRA4DJKh0MthdJul7SuZJOlXSx7ZN7ypwv6dMR8RlJ\nl0m6cdjjM4keAExWFS2GNZL2RcQLEfGepNskresps07SrZIUEdslLbe9YpiDM4keAEzW4gqOcZyk\n/R3bLyoLi35lDuT7Dg46+P78VYcPZ8v778+WO3dKS5Zk63fdNVt+587u7U4HDmTLJ5/Mlg8/LL36\nqvT009n2I49Ir7wy6B0BwMJWRTBUbunSTXr33Wz9/fdbklofPrdhQ7Z86y3p0KFs/corpbPOkrZv\nl26/XXr9dWnZsv7nWLNG2rpV+trXpBNOkM48U5qZyR4AkLLXXpvR66/P1HeCiCj1kLRW0n0d21dJ\n2thT5kZJX+nY3iNpRcHxYmYmQoq4/vqIiIgrrsi277gjW37uc9lyz55sed11Wblrrsm29+6NQmec\nkZWJiHjuuWx948bi8gCQuuxSXu5a3vmoYoxhh6QTba+2vUTSeklbe8pslXSJJNleK+mtiCjsRmoP\nLPcuFy3qXvYOQA9zNzTjCADQX+mupIg4bPtySduUDWbfHBG7bV+WPR03RcS9ti+w/aykdyRt6HfM\nomAYdTnIqOUBYBpUMsYQEfdJOqln3/d6ti8f9/hFF3CCAQCql+Sdz8N2JfV2KQ1zoe/sSiIYAOBI\njQiGtmGDgBYDAIyvEcEwbIuAwWcAKC/JYOg1qGuJMQYAqE6SwTBuEBAMAFBeI4KhbdCgc+/r58Lg\nMwD014hgGLZlwBgDAJSXZDD04gY3AJicJINh2DEGBp8BoHqNCIY27mMAgPo1IhiYRA8AJqdRwcAY\nAwDUL8lg6MUkegAwOUkGA5PoAcD8aUQwtFUx+EwwAEB/jQiGKifRAwD0l2Qw9GISPQCYnCSDgUn0\nAGD+NCIY2phEDwDq14hgYBI9AJicJIOhFze4AcDkJBkMjDEAwPxpRDC0DRpb6H39uOcBgGnWiGAo\najkUva4fxhgAoL+kg6F3e9jBZ1oMADC+JIOhbVBLgTEGAKheksEw6n0MRa+fC/cxAEB/jQiGKudK\nYowBAPpLOhh6t/m5KgDUL8lgaBv3xjaCAQDGl2QwDPurI36VBADVa2QwMPgMAPVpZDAw+AwA9Uk6\n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\nQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "noise_chance = 0.0\n", + "N = 100\n", + "xys = [(uniform(0,10),uniform(0,10)) for _r in range(0,N)]\n", + "secret_f = lambda x: x*2 - 1\n", + "dataset = [(xy,(1 if (secret_f(xy[0]) <= xy[1] or uniform(0,1)" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# how many examples to look at during each training iteration\n", + "batch_size = 10000\n", + "\n", + "# how many times to run through the full set of examples\n", + "n_epochs = 10\n", + "\n", + "# the training may be slow depending on your computer\n", + "model.fit(X_train, # n-dimensional array whose outer dimension is each example\n", + " y_train, # n-dimensional array of arrays of 0/1 values for categorical encoding\n", + " batch_size=batch_size,\n", + " nb_epoch=n_epochs,\n", + " validation_data=(X_test, y_test))" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "import matplotlib as plt;\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "10000/10000 [==============================] - 11s \n", + "loss: 0.113181793923\n", + "accuracy: 0.9649\n" + ] + } + ], + "source": [ + "# how'd we do?\n", + "loss, accuracy = model.evaluate(X_test, y_test)\n", + "print('loss:', loss)\n", + "print('accuracy:', accuracy)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[3, 2]" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import random\n", + "random.sample(set([1, 2, 3, 4, 5, 6]), 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "a = set([1,2,3,4,5])" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[5, 4, 1]" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "random.sample(a, 3)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3, 4, 5]" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(a)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'b', 'a', 'c'}\n", + "{'c', 'a', 'w', 'b', 'x', 'z'}\n" + ] + } + ], + "source": [ + "d = {\"a\": \"apple\", \"b\": \"banana\", \"c\": \"cuttlefish\"}\n", + "s = set(d)\n", + "print(s)\n", + "s1 = {\"z\", \"w\", \"x\"}\n", + "s2 = s | s1 | {\"z\"}\n", + "print(s2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python [Root]", + "language": "python", + "name": "Python [Root]" + }, + "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.5.2" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/projects/7-dnns/Kwan.ipynb b/projects/7-dnns/Kwan.ipynb new file mode 100644 index 0000000..78fb19e --- /dev/null +++ b/projects/7-dnns/Kwan.ipynb @@ -0,0 +1,294 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Using Theano backend.\n" + ] + }, + { + "ename": "AssertionError", + "evalue": "Model weights not found (see \"weights_path\" variable in script).", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 101\u001b[0m \u001b[0;31m# note: when there is a complete match between your model definition\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 102\u001b[0m \u001b[0;31m# and your weight savefile, you can simply call model.load_weights(filename)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 103\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexists\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mweights_path\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'Model weights not found (see \"weights_path\" variable in script).'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 104\u001b[0m \u001b[0mf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mh5py\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mweights_path\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 105\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mk\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mattrs\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'nb_layers'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mAssertionError\u001b[0m: Model weights not found (see \"weights_path\" variable in script)." + ] + } + ], + "source": [ + "'''This script goes along the blog post\n", + "\"Building powerful image classification models using very little data\"\n", + "from blog.keras.io.\n", + "It uses data that can be downloaded at:\n", + "https://www.kaggle.com/c/dogs-vs-cats/data\n", + "In our setup, we:\n", + "- created a data/ folder\n", + "- created train/ and validation/ subfolders inside data/\n", + "- created cats/ and dogs/ subfolders inside train/ and validation/\n", + "- put the cat pictures index 0-999 in data/train/cats\n", + "- put the cat pictures index 1000-1400 in data/validation/cats\n", + "- put the dogs pictures index 12500-13499 in data/train/dogs\n", + "- put the dog pictures index 13500-13900 in data/validation/dogs\n", + "So that we have 1000 training examples for each class, and 400 validation examples for each class.\n", + "In summary, this is our directory structure:\n", + "```\n", + "data/\n", + " train/\n", + " dogs/\n", + " dog001.jpg\n", + " dog002.jpg\n", + " ...\n", + " cats/\n", + " cat001.jpg\n", + " cat002.jpg\n", + " ...\n", + " validation/\n", + " dogs/\n", + " dog001.jpg\n", + " dog002.jpg\n", + " ...\n", + " cats/\n", + " cat001.jpg\n", + " cat002.jpg\n", + " ...\n", + "```\n", + "'''\n", + "\n", + "import os\n", + "import h5py\n", + "import numpy as np\n", + "from keras.preprocessing.image import ImageDataGenerator\n", + "from keras import optimizers\n", + "from keras.models import Sequential\n", + "from keras.layers import Convolution2D, MaxPooling2D, ZeroPadding2D\n", + "from keras.layers import Activation, Dropout, Flatten, Dense\n", + "\n", + "# path to the model weights files.\n", + "weights_path = '../keras/examples/vgg16_weights.h5'\n", + "top_model_weights_path = 'fc_model.h5'\n", + "# dimensions of our images.\n", + "img_width, img_height = 150, 150\n", + "\n", + "train_data_dir = 'data/train'\n", + "validation_data_dir = 'data/validation'\n", + "nb_train_samples = 2000\n", + "nb_validation_samples = 800\n", + "nb_epoch = 50\n", + "\n", + "# build the VGG16 network\n", + "model = Sequential()\n", + "model.add(ZeroPadding2D((1, 1), input_shape=(3, img_width, img_height)))\n", + "\n", + "model.add(Convolution2D(64, 3, 3, activation='relu', name='conv1_1'))\n", + "model.add(ZeroPadding2D((1, 1)))\n", + "model.add(Convolution2D(64, 3, 3, activation='relu', name='conv1_2'))\n", + "model.add(MaxPooling2D((2, 2), strides=(2, 2)))\n", + "\n", + "model.add(ZeroPadding2D((1, 1)))\n", + "model.add(Convolution2D(128, 3, 3, activation='relu', name='conv2_1'))\n", + "model.add(ZeroPadding2D((1, 1)))\n", + "model.add(Convolution2D(128, 3, 3, activation='relu', name='conv2_2'))\n", + "model.add(MaxPooling2D((2, 2), strides=(2, 2)))\n", + "\n", + "model.add(ZeroPadding2D((1, 1)))\n", + "model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_1'))\n", + "model.add(ZeroPadding2D((1, 1)))\n", + "model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_2'))\n", + "model.add(ZeroPadding2D((1, 1)))\n", + "model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_3'))\n", + "model.add(MaxPooling2D((2, 2), strides=(2, 2)))\n", + "\n", + "model.add(ZeroPadding2D((1, 1)))\n", + "model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_1'))\n", + "model.add(ZeroPadding2D((1, 1)))\n", + "model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_2'))\n", + "model.add(ZeroPadding2D((1, 1)))\n", + "model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_3'))\n", + "model.add(MaxPooling2D((2, 2), strides=(2, 2)))\n", + "\n", + "model.add(ZeroPadding2D((1, 1)))\n", + "model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_1'))\n", + "model.add(ZeroPadding2D((1, 1)))\n", + "model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_2'))\n", + "model.add(ZeroPadding2D((1, 1)))\n", + "model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_3'))\n", + "model.add(MaxPooling2D((2, 2), strides=(2, 2)))\n", + "\n", + "# load the weights of the VGG16 networks\n", + "# (trained on ImageNet, won the ILSVRC competition in 2014)\n", + "# note: when there is a complete match between your model definition\n", + "# and your weight savefile, you can simply call model.load_weights(filename)\n", + "assert os.path.exists(weights_path), 'Model weights not found (see \"weights_path\" variable in script).'\n", + "f = h5py.File(weights_path)\n", + "for k in range(f.attrs['nb_layers']):\n", + " if k >= len(model.layers):\n", + " # we don't look at the last (fully-connected) layers in the savefile\n", + " break\n", + " g = f['layer_{}'.format(k)]\n", + " weights = [g['param_{}'.format(p)] for p in range(g.attrs['nb_params'])]\n", + " model.layers[k].set_weights(weights)\n", + "f.close()\n", + "print('Model loaded.')\n", + "\n", + "# build a classifier model to put on top of the convolutional model\n", + "top_model = Sequential()\n", + "top_model.add(Flatten(input_shape=model.output_shape[1:]))\n", + "top_model.add(Dense(256, activation='relu'))\n", + "top_model.add(Dropout(0.5))\n", + "top_model.add(Dense(1, activation='sigmoid'))\n", + "\n", + "# note that it is necessary to start with a fully-trained\n", + "# classifier, including the top classifier,\n", + "# in order to successfully do fine-tuning\n", + "top_model.load_weights(top_model_weights_path)\n", + "\n", + "# add the model on top of the convolutional base\n", + "model.add(top_model)\n", + "\n", + "# set the first 25 layers (up to the last conv block)\n", + "# to non-trainable (weights will not be updated)\n", + "for layer in model.layers[:25]:\n", + " layer.trainable = False\n", + "\n", + "# compile the model with a SGD/momentum optimizer\n", + "# and a very slow learning rate.\n", + "model.compile(loss='binary_crossentropy',\n", + " optimizer=optimizers.SGD(lr=1e-4, momentum=0.9),\n", + " metrics=['accuracy'])\n", + "\n", + "# prepare data augmentation configuration\n", + "train_datagen = ImageDataGenerator(\n", + " rescale=1./255,\n", + " shear_range=0.2,\n", + " zoom_range=0.2,\n", + " horizontal_flip=True)\n", + "\n", + "test_datagen = ImageDataGenerator(rescale=1./255)\n", + "\n", + "train_generator = train_datagen.flow_from_directory(\n", + " train_data_dir,\n", + " target_size=(img_height, img_width),\n", + " batch_size=32,\n", + " class_mode='binary')\n", + "\n", + "validation_generator = test_datagen.flow_from_directory(\n", + " validation_data_dir,\n", + " target_size=(img_height, img_width),\n", + " batch_size=32,\n", + " class_mode='binary')\n", + "\n", + "# fine-tune the model\n", + "model.fit_generator(\n", + " train_generator,\n", + " samples_per_epoch=nb_train_samples,\n", + " nb_epoch=nb_epoch,\n", + " validation_data=validation_generator,\n", + " nb_val_samples=nb_validation_samples)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "ename": "ImportError", + "evalue": "No module named 'nolearn'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mImportError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 13\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mlasagne\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mlayers\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mlasagne\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mupdates\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mnesterov_momentum\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 15\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mnolearn\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlasagne\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mNeuralNet\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 16\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mnolearn\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlasagne\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mvisualize\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0msklearn\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmetrics\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mclassification_report\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mImportError\u001b[0m: No module named 'nolearn'" + ] + } + ], + "source": [ + "# Experimenting with deep neural networks\n", + "\n", + "import matplotlib\n", + "import matplotlib.pyplot as plt\n", + "import matplotlib.cm as cm\n", + "# from urllib import urlretrieve\n", + "# import cPickle as pickle\n", + "import os\n", + "import gzip\n", + "import numpy as np\n", + "import theano\n", + "import lasagne\n", + "from lasagne import layers\n", + "from lasagne.updates import nesterov_momentum\n", + "from nolearn.lasagne import NeuralNet\n", + "from nolearn.lasagne import visualize\n", + "from sklearn.metrics import classification_report\n", + "from sklearn.metrics import confusion_matrix\n", + "\n", + "def load_dataset():\n", + " url = 'http://deeplearning.net/data/mnist/mnist.pkl.gz'\n", + " filename = 'mnist.pkl.gz'\n", + " if not os.path.exists(filename):\n", + " print(\"Downloading MNIST dataset...\")\n", + " urlretrieve(url, filename)\n", + " with gzip.open(filename, 'rb') as f:\n", + " data = pickle.load(f)\n", + " X_train, y_train = data[0]\n", + " X_val, y_val = data[1]\n", + " X_test, y_test = data[2]\n", + " X_train = X_train.reshape((-1, 1, 28, 28))\n", + " X_val = X_val.reshape((-1, 1, 28, 28))\n", + " X_test = X_test.reshape((-1, 1, 28, 28))\n", + " y_train = y_train.astype(np.uint8)\n", + " y_val = y_val.astype(np.uint8)\n", + " y_test = y_test.astype(np.uint8)\n", + " return X_train, y_train, X_val, y_val, X_test, y_test\n", + "\n", + "X_train, y_train, X_val, y_val, X_test, y_test = load_dataset()\n", + "plt.imshow(X_train[0][0], cmap=cm.binary)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "anaconda-cloud": {}, + "kernelspec": { + "display_name": "Python [Root]", + "language": "python", + "name": "Python [Root]" + }, + "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.5.2" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/projects/8-novelty/Novelty Search.ipynb b/projects/8-novelty/Novelty Search.ipynb new file mode 100644 index 0000000..32365ac --- /dev/null +++ b/projects/8-novelty/Novelty Search.ipynb @@ -0,0 +1,516 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Novelty Search" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "%matplotlib inline\n", + "\n", + "import matplotlib\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import matplotlib.patches as patches\n", + "import matplotlib.axes as axes\n", + "import copy\n", + "import random\n", + "import functools\n", + "from random import randint\n", + "from queue import PriorityQueue" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "@functools.total_ordering\n", + "class Maze:\n", + " SwitchMap = {\"0\":\"a\", \"1\":\"b\", \"2\":\"c\", \"3\":\"d\", \"4\":\"e\", \"5\":\"f\", \"6\":\"g\", \"7\":\"h\", \"8\":\"i\", \"9\":\"j\"}\n", + " Colors = {\"a\":\"coral\",\"b\":\"tan\",\"c\":\"palegreen\",\"d\":\"blue\",\"e\":\"cyan\",\"f\":\"magenta\",\"g\":\"yellow\",\"h\":\"olive\",\"i\":\"purple\",\"j\":\"darkgreen\",\n", + " \"0\":\"coral\",\"1\":\"tan\",\"2\":\"palegreen\",\"3\":\"blue\",\"4\":\"cyan\",\"5\":\"magenta\",\"6\":\"yellow\",\"7\":\"olive\",\"8\":\"purple\",\"9\":\"darkgreen\",\n", + " \"?\":\"orange\",\n", + " \"!\":\"red\",\n", + " \"x\":\"green\",\"@\":\"gray\",\n", + " \"#\":\"sienna\",\".\":\"white\"}\n", + " \n", + " def __init__(self,rows):\n", + " self.grid = [list(r) for r in rows]\n", + " self.grid.reverse()\n", + " self.cost = 0\n", + " self.action = None\n", + " self.predecessor = None\n", + " \n", + " height = len(self.grid)\n", + " width = len(self.grid[0])\n", + " self.exit_pos = None\n", + " self.player_pos = None\n", + " self.player_alive = True\n", + " for y in range(0,height):\n", + " assert len(self.grid[y]) == width, \"All rows must be equal length!\"\n", + " for x in range(0,width):\n", + " c = self.grid[y][x]\n", + " assert c == \"#\" or c == \".\" or c == \"!\" or c == \"?\" or c == \"@\" or c.isalnum()\n", + " if c.lower() == \"x\":\n", + " assert self.exit_pos == None\n", + " self.exit_pos = (x,y)\n", + " if c == \"@\":\n", + " assert self.player_pos == None\n", + " self.player_pos = (x,y)\n", + " self.grid[y][x] = \".\"\n", + " \n", + " # precondition: other_maze must be of same height and width as self\n", + " # difference is subjective\n", + " def diff(self,other_maze):\n", + " diff_count = 0\n", + " height = len(self.grid)\n", + " width = len(self.grid[0])\n", + " for y in range(0,height):\n", + " for x in range(0,width):\n", + " cell = self.grid[y][x]\n", + " cell2 = other_maze.grid[y][x]\n", + " if (cell != cell2):\n", + " diff_count += 1 # for every distance in the string\n", + " \n", + " # calculates manhattan distance between this maze and the other maze\n", + " (x1, y1) = self.player_pos\n", + " (x2, y2) = other_maze.player_pos\n", + " manhattan_distance = abs(x1-x2) + abs(y1-y2)\n", + " return diff_count + manhattan_distance # weighted combination of manhattan distance and string diff\n", + " \n", + " def set_past(self, cost, predecessor, action):\n", + " self.cost = cost\n", + " self.predecessor = predecessor\n", + " self.action = action\n", + " \n", + " def clone(self):\n", + " return copy.deepcopy(self)\n", + " \n", + " def toggle_cell(self,switchnum,c):\n", + " if c.isalpha() and Maze.SwitchMap[switchnum] == c.lower():\n", + " if c.islower():\n", + " return c.upper()\n", + " else:\n", + " return c.lower()\n", + " return c\n", + " \n", + " def toggle(self):\n", + " assert self.player_alive\n", + " height = len(self.grid)\n", + " width = len(self.grid[0])\n", + " (px,py) = self.player_pos\n", + " switchnum = self.grid[py][px]\n", + " assert switchnum.isnumeric()\n", + " for y in range(0,height):\n", + " for x in range(0,width):\n", + " self.grid[y][x] = self.toggle_cell(switchnum,self.grid[y][x])\n", + " \n", + " def is_free(self,x,y):\n", + " if y < 0 or y >= len(self.grid):\n", + " return False\n", + " if x < 0 or x >= len(self.grid[0]):\n", + " return False\n", + " cell = self.grid[y][x]\n", + " return (\n", + " cell == \".\" or cell == \"X\" or\n", + " cell == \"?\" or cell == \"!\" or \n", + " (cell.isalpha() and cell.islower()) or cell.isnumeric()\n", + " )\n", + " \n", + " def __hash__(self):\n", + " return hash(str(self.grid)) % 1000007 + hash(self.player_pos) % 1000007 + hash(self.player_alive) % 1000007\n", + " \n", + " def _is_valid_operand(self, other):\n", + " return (hasattr(other, \"grid\") and hasattr(other, \"player_pos\") and hasattr(other, \"player_alive\"))\n", + " \n", + " def __eq__(self, other):\n", + " if not self._is_valid_operand(other):\n", + " return NotImplemented\n", + " return ((self.grid, self.player_pos, self.player_alive) ==\n", + " (other.grid, other.player_pos, other.player_alive))\n", + " \n", + " def __lt__(self, other):\n", + " if not self._is_valid_operand(other):\n", + " return NotImplemented\n", + " return ((self.grid, self.player_pos, self.player_alive) <\n", + " (other.grid, other.player_pos, other.player_alive))\n", + " \n", + " def move_player(self,dx,dy):\n", + " assert self.player_alive\n", + " assert abs(dx)+abs(dy) == 1\n", + " (x,y) = self.player_pos\n", + " (newx,newy) = (x+dx,y+dy)\n", + " assert self.is_free(newx,newy)\n", + " self.player_pos = (x+dx,y+dy)\n", + " cell = self.grid[y+dy][x+dx]\n", + " if cell == \"?\" and random.random() < 0.3:\n", + " self.player_alive = False\n", + " if cell == \"!\" and random.random() < 0.6:\n", + " self.player_alive = False\n", + " \n", + " def available_moves(self):\n", + " if not self.player_alive:\n", + " return []\n", + " (x,y) = self.player_pos\n", + " can_switch = self.grid[y][x].isnumeric()\n", + " return [(dx,dy) for (dx,dy) in [(-1,0),(1,0),(0,-1),(0,1)] if self.is_free(x+dx,y+dy)] + (\n", + " [\"switch\"] if can_switch else []\n", + " )\n", + " \n", + " def is_at_exit(self):\n", + " return self.player_alive and self.player_pos == self.exit_pos\n", + " \n", + " def draw(self):\n", + " fig1 = plt.figure()\n", + " ax1 = fig1.add_subplot(1,1,1, aspect='equal')\n", + " ax1.set_axis_bgcolor('sienna')\n", + " height = len(self.grid)\n", + " width = len(self.grid[0])\n", + " ax1.set_xlim([0,width])\n", + " ax1.set_ylim([0,height])\n", + " for y in range(0,height):\n", + " for x in range(0,width):\n", + " cell = self.grid[y][x]\n", + " if cell == \"#\": continue\n", + " is_door = cell.isalpha() and cell.lower() != \"x\"\n", + " is_pit = cell == \"?\" or cell == \"!\"\n", + " is_open = is_door and cell.islower()\n", + " is_switch = cell.isnumeric()\n", + " ax1.add_patch(\n", + " patches.Rectangle((x, y),\n", + " 1,1,\n", + " fill=True,\n", + " facecolor=Maze.Colors[cell.lower()],\n", + " edgecolor=\"black\",\n", + " hatch=\"/\" if is_switch else (\"-\" if (is_door and not is_open) else None),\n", + " label=cell)\n", + " )\n", + " ax1.add_patch(\n", + " patches.Rectangle(self.player_pos,\n", + " 1,1,\n", + " fill=True,\n", + " hatch=\"x\" if not self.player_alive else None,\n", + " facecolor=Maze.Colors[\"@\"] if self.player_alive else \"black\",\n", + " edgecolor=Maze.Colors[\"@\"] if self.player_alive else \"white\")\n", + " )\n", + " plt.show(fig1)\n", + " \n", + " def update_move(self,path):\n", + " for pos in path:\n", + " self.grid[pos[1]][pos[0]] = \"g\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Novelty search" + ] + }, + { + "cell_type": "code", + "execution_count": 103, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def average_novelty(maze_state, other_mazes):\n", + " sum = 0\n", + " for i in other_mazes:\n", + " sum += maze_state.diff(i) # difference method written inside Maze\n", + " return float(sum) / len(other_mazes)\n", + "\n", + "def choose_random(other_mazes, amt): # takes a set and returns a set with <= amt random samples of mazes\n", + " if (amt >= len(other_mazes)):\n", + " return other_mazes\n", + " return set(random.sample(other_mazes, amt))\n", + "\n", + "# returns the maze state from next_states that is the most novel\n", + "# compared to the other members of next_states and the members of past_mazes\n", + "def most_novel(queue, maze_set):\n", + " highest_novelty = -1\n", + " most_novel = list(queue)\n", + " for i in queue:\n", + " temp = average_novelty(i, maze_set)\n", + " if (temp > highest_novelty):\n", + " most_novel = [i]\n", + " highest_novelty = temp\n", + " elif (temp == highest_novelty):\n", + " most_novel.append(i)\n", + " return random.choice(most_novel)\n", + "\n", + "def novelty_search(maze, iterations):\n", + " # Return a path which solves the maze: a sequence of elements like (dx,dy) or \"switch\".\n", + " # You can use maze.exit_pos and query maze.grid[row][column] to investigate the maze.\n", + " \n", + " past_mazes = {maze: (0, None, None)} # maze : (cost, predecessor, action to get there)\n", + " queue = set([maze])\n", + " i = 0\n", + " cost = 0\n", + " \n", + " while not len(queue) == 0 and i < iterations:\n", + " total_considered = queue | set(past_mazes) # set(dictionary) returns a set with the keys\n", + " rand_sample = choose_random(total_considered, 100000) # will choose a random sample so testing doesn't get too slow\n", + " \n", + " # testing purposes\n", + " # ls = []\n", + " # for j in queue:\n", + " # ls.append(average_novelty(j, rand_sample))\n", + " # print(ls)\n", + " \n", + " cur_maze = most_novel(queue, rand_sample) # chooses the most novel of the queue\n", + " cost = past_mazes[cur_maze][0] # accesses the cost of the current maze\n", + " queue.remove(cur_maze)\n", + " \n", + " if cur_maze.is_at_exit(): # is finished\n", + " print (\"Got to the end\")\n", + " return i\n", + " \n", + " # has not reached exit\n", + " for m in cur_maze.available_moves():\n", + " successor = cur_maze.clone()\n", + " \n", + " if m == \"switch\":\n", + " successor.toggle()\n", + " else:\n", + " (x,y) = m\n", + " successor.move_player(x,y) # makes the move\n", + " \n", + " if successor not in past_mazes or past_mazes[successor][0] > cost+1:\n", + " past_mazes[successor] = (cost+1, cur_maze, m)\n", + " if successor not in queue: # successor.cost < past_mazes[successor][0]:\n", + " queue |= {successor}\n", + " \n", + " i += 1 # increments i\n", + " return []\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Testing novelty search" + ] + }, + { + "cell_type": "code", + "execution_count": 102, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAOIAAAEACAYAAACu66rqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAADgdJREFUeJzt3V+MXHd5xvHvs3bi3fU2Cy12CpiYoMpKgoIcq00iTFqo\nAzUBBWGpgoAUOaroRWkdpTUQ5SbxRS9AQjRSK1UREAM1EGW7blIp0BiCQFA1dmI72cTr0sZJ7fyz\njQBbazvIjt9ezHHlrnc9Z9fnN3l3z/ORVjuzOvP7vWfGj8+Zc2beo4jAzN5YfW90AWbmIJql4CCa\nJeAgmiXgIJol4CCaJVAriJJulzRW/WwoXZRZ23QNoqR3A38G/D6wEviopHeVLsysTepsEa8EHo+I\n30TE68BPgHVlyzJrlzpBfAa4QdKbJQ0CNwHvKFuWWbss7LZAROyV9EVgGzAB7AJeL12YWZtopp81\nlfS3wIGI+MdJf/eHVs2mEBHqtkzXLSKApCURcVjSZcDHgeunWm7zuqtnVuEMbN1zkI9fdWmx8T1H\nrjnmwzoArB8dq7VcrSAC/yzpt4GTwF9ExNHZFmZm56oVxIj4w9KFmLXZnPlkzRVLFnuOFs0xH9Zh\nJmZ8sGbagaQo+R7RbC5aPzpW62DNnNkims1nDqJZAg6iWQIOolkCDqJZAg6iWQIOolkCDqJZAg6i\nWQIOolkCDqJZAg6iWQIOolkCDqJZAnUbDN8h6RlJT0vaIuni0oWZtUmdBsNvA/4KWBUR76Hzrf5P\nli7MrE3q9qxZACyWdBoYBF4uV5JZ+3TdIkbEy8CXgf3AS8CvI+IHpQsza5OuW0RJbwI+BiwHjgAj\nkj4VEd+evOzWPQf/7/YVSxZz5ZKhxgrd8G/jHD12qrHxpjLQ38+J114rOsfS4SG+tObyonN8/ofP\nc+jIRNE5Bgb6OXGi3HNVenwo81qMH55g7+FjM35cnV3TG4F9EfFLAEmjwHuBc4JYskfk0WOn4J5i\nwwNw4p7XaKqHz3Skru1LLtihIxM9WY+Sc5Qe/8wcTbtyydD/2wA9tPdQrcfVOWq6H7heUr86la8B\nxmdTpJlNrc57xO3ACJ1rXjwFCLivcF1mrVK3wfAmYFPhWsxay5+sMUvAQTRLwEE0S8BBNEvAQTRL\nwEE0S8BBNEvAQTRLwEE0S8BBNEvAQTRLwEE0S8BBNEvAQTRLwEE0S8BBNEugTl/TFZJ2SdpZ/T4i\naUMvijNri67f0I+InwPXAEjqA14Ethauy6xVZrpreiPwXEQcKFGMWVvNNIifAL5TohCzNqvbch9J\nFwE3A3dOt0zJBsO6COKexoab0qL+RcX7ji4dbu45mc7AQH/x9ejvLztH6fGh8zw1rWSD4TM+DDwZ\nEYenW6Bkg+E4SU8azm5ed3XROXrhxIneNEou+VytHx1zg+Fp3IJ3S82KqHt9xEE6B2pGy5Zj1k51\nGwwfB5YUrsWstfzJGrMEHESzBBxEswQcRLMEHESzBBxEswQcRLMEHESzBBxEswQcRLMEHESzBBxE\nswQcRLMEHESzBBxEswQcRLME6n5Df1jSg5LGJT0r6brShZm1Sd3mUfcCj0TEn0paCAwWrMmsdboG\nUdIlwA0RsR4gIk4BRwvXZdYqdXZNLwd+Ien+6voX90kaKF2YWZvU2TVdCKwCPhsRT0j6OzpNhu+e\nvGDJBsO9aJpbouHsZJ//4fMcOjJRdI652px38vhzcR1KNhh+ETgQEU9U90eAL0y1YMkGw71qmlva\noSMTPVmPuf5czdXXu1iD4Yg4CByQtKL60xpgzyxqNLNp1D1qugHYUl3/Yh9wW7mSzNqnboPhp4A/\nKFyLWWv5kzVmCTiIZgk4iGYJOIhmCTiIZgk4iGYJOIhmCTiIZgk4iGYJOIhmCTiIZgk4iGYJOIhm\nCTiIZgk4iGYJ1Po+oqQXgCPAaeBkRFxbsiiztqn7Df3TwPsj4lclizFrq7q7pprBsmY2Q3XDFcA2\nSTskfaZkQWZtVHfXdHVEvCJpCZ1AjkfET0sWZtYmdZtHvVL9PixpK3AtcE4Q53qD4f7+ftaPjhWf\noxfrMReb804efy6uQ7EGw5IGgb6ImJC0GPgQsGmqZedDg2HPUX+OktrWYLjOFvFSYKukqJbfEhGP\nzqZIM5ta1yBGxPPAyh7UYtZaPiVhloCDaJaAg2iWgINoloCDaJaAg2iWgINoloCDaJaAg2iWgINo\nloCDaJaAg2iWgINoloCDaJaAg2iWgINolkDtIErqk7RT0sMlCzJro5lsEW8H9pQqxKzNagVR0jLg\nJuCrZcsxa6e6W8SvAJ+j02jYzBrWNYiSPgIcjIjddFrvl+2jZ9ZCddoprgZulnQTMAD8lqRvRsSt\nkxecDw2Ge9HUdj6sR+lmzHO1SXKxBsMRcRdwF4CkPwL+ZqoQwvxoMLx53dVF5+iF9aNjc76J8Vxt\nkjzbBsM+j2iWQN2L0AAQET8GflyoFrPW8hbRLAEH0SwBB9EsAQfRLAEH0SwBB9EsAQfRLAEH0SwB\nB9EsAQfRLAEH0SwBB9EsAQfRLAEH0SwBB9EsAQfRLIGuXwyWtAj4CXBxtfxIRGwqXZhZm9TpWfMb\nSR+IiOOSFgA/k/S9iNjeg/rMWqHWrmlEHK9uLqITXvc3NWtQ3U7ffZJ2Aa8C2yJiR9myzNqlVvOo\niDgNXCPpEuBfJF0VEedcB2M+9DUt2asTYOnwEF9ac3nROeZD79Re9DVdOtzcv88zivU1PVtEHJX0\nI2AtU1yQZj70NZ2LvTQnmw/P1VztMVusr6mkt0garm4PAB8E9s6uTDObSp0t4luBb0jqoxPcByLi\nkbJlmbVLndMXY8CqHtRi1lr+ZI1ZAg6iWQIOolkCDqJZAg6iWQIOolkCDqJZAg6iWQIOolkCDqJZ\nAg6iWQIOolkCDqJZAg6iWQIOolkCDqJZAnVaZSyT9JikZyWNSdrQi8LM2qROq4xTwF9HxG5JQ8CT\nkh6NCPetMWtI1y1iRLwaEbur2xPAOPD20oWZtcmM3iNKeiewEni8RDFmbVW7r2m1WzoC3F5tGc9R\nssHw0uGhOd80FzrNf0ubDw2GN27cyAtDzTcAPtvxY8e46rnvNzpm0QbDkhbSCeG3IuKh6ZYr2WC4\ndHdsgPWjY24wXFPpBsObNpW/4Njg4sWNj1mswXDl68CeiLh35qWZWTd1Tl+sBj4N/LGkXZJ2Slpb\nvjSz9qjTYPhnwIIe1GLWWv5kjVkCDqJZAg6iWQIOolkCDqJZAg6iWQIOolkCDqJZAg6iWQIOolkC\nDqJZAg6iWQIOolkCDqJZAg6iWQIOolkCdb6h/zVJByU93YuCzNqozhbxfuBPShdi1mZ1Ggz/FPhV\nD2oxay2/RzRLoHaD4TpKNhjuhV40MV46XP456cV6lG5ivHHjRoZ60GC4abNtMKw6TWIlLQf+NSLe\nc55lYvO6q2dcgNl8VjWt7vo/Vt1dU1U/ZlZAndMX3wb+HVghab+k28qXZdYudRoMf6oXhZi1mY+a\nmiXgIJol4CCaJeAgmiXgIJol4CCaJeAgmiXgIJol4CCaJeAgmiXgIJol4CCaJeAgmiXgIJol4CCa\nJVAriJLWStor6eeSvlC6KLO2qfMN/T7g7+n0Nn03cIukK0oXNtn44QnP0aI55sM6zESdLeK1wH9F\nxP9ExEngu8DHypZ1rtl0xvIcc3eO+bAOM1EniG8HDpx1/8Xqb2bWEB+sMUuga19TSdcD90TE2ur+\nnUBExBcnLde9QapZC9Xpa1oniAuA/wTWAK8A24FbImK8iSLNrF47xdcl/SXwKJ1d2a85hGbNqtVy\n38zKuuCDNaVP9vfiQqmSlkl6TNKzksYkbSgwxyJJj0vaVc1xd9NzVPP0Sdop6eFC478g6alqPbYX\nmmNY0oOSxqvX5LqGx19R1b+z+n2k6ddc0h2SnpH0tKQtki4+7wMiYtY/dIL838By4CJgN3DFhYw5\nxRzvA1YCTzc57qQ5fhdYWd0eovOeuNH1qMYerH4vAP4DuLbAHHcA/wQ8XOi52ge8udRrUc2xGbit\nur0QuKTgXH3Ay8A7GhzzbdXzdHF1/wHg1vM95kK3iMVP9kcPLpQaEa9GxO7q9gQwToFzpRFxvLq5\niM4/sEbfF0haBtwEfLXJcSdPQ8HTXpIuAW6IiPsBIuJURBwtNR9wI/BcRBzouuTMLAAWS1oIDNIJ\n+7Qu9Amddyf7Jb2Tzhb48QJj90naBbwKbIuIHQ1P8RXgczQc8EkC2CZph6TPFBj/cuAXku6vdh3v\nkzRQYJ4zPgF8p8kBI+Jl4MvAfuAl4NcR8YPzPcYn9M8iaQgYAW6vtoyNiojTEXENsAy4TtJVTY0t\n6SPAwWrLXvIyeqsjYhWdLe9nJb2v4fEXAquAf6jmOQ7c2fAcAEi6CLgZeLDhcd9EZ89wOZ3d1CFJ\n572Y04UG8SXgsrPuL6v+NudUuxAjwLci4qGSc1W7Wj8C1jY47GrgZkn76PwP/wFJ32xwfAAi4pXq\n92FgK523J016ETgQEU9U90foBLOEDwNPVuvSpBuBfRHxy4h4HRgF3nu+B1xoEHcAvydpeXVU6JNA\niaN1vbhQ6teBPRFxb4nBJb1F0nB1ewD4ILC3qfEj4q6IuCwi3kXndXgsIm5tanwASYPVXgOSFgMf\nAp5pco6IOAgckLSi+tMaYE+Tc5zlFhreLa3sB66X1K/O9c3X0DnuMK2uJ/TPJ3pwsr+6UOr7gd+R\ntB+4+8wb+QbnWA18Ghir3sMFcFdEfL/Bad4KfKP6Wlkf8EBEPNLg+L1wKbC1+jjjQmBLRDxaYJ4N\nwJZq13Ef0PjFcSUN0tly/XnTY0fEdkkjwC7gZPX7vvPWUx1eNbM3kA/WmCXgIJol4CCaJeAgmiXg\nIJol4CCaJeAgmiXgIJol8L9rYl7TkKjgYwAAAABJRU5ErkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\nR8AbDLvtAJBAeQJAAuUJAAmUJwAkUJ4AkEB5AkAC5QkACZQnACRQngCQQHkCQALlCQAJlCcAJFCe\nAJDQqDxt77A9afu/bH+hVCgAqF26PG2fJ+lvJV0r6XJJH7W9pVSw1TQxM9vrCCuqPZ9Uf8ba80n1\nZ6w9n7S6GZtsef6+pGci4qcR8Yqkb0vaWSbW6pqcmet1hBXVnk+qP2Pt+aT6M9aeT1rdjE3K822S\njs07/nz3NAB4w+MNIwBIcETkftC+UtJtEbGje/wWSRERX110vtwFAEAFImLJwVJNyvN8SU9L2i7p\nfyQ9LOmjETGRDQkA/SI9AC4ifm37LyQdUGf3/26KE8Bakd7yBIC1rLU3jGr/AL3tTbYP2X7K9hHb\nu3qdaSm2z7P9qO0Hep1lKbbX2/6O7YnubfneXmdazPanbT9p+wnb99l+cwWZ7rY9ZfuJeae91fYB\n20/bfsj2+sry7e7ez4dtf9f2hb3Kt1zGef/3Wduv2v7Nti6/lfLskw/Qn5L0mYi4XNIfSPpkhRkl\n6WZJ470OsYI7JX0vIkYl/Y6kql66sX2xpE9J2hYR71HnpaobeptKknSPOo+P+W6RdDAi3iXpkKQv\nrnqq/7dUvgOSLo+IKyQ9o97mk5bOKNubJF0j6adtXnhbW57Vf4A+Il6KiMPdw7PqPOir+pxq95fg\ng5K+0essS+luebw/Iu6RpIg4FREv9zjWUs6XNGR7naQLJL3Y4zyKiB9K+sWik3dKurd7+F5JH17V\nUPMslS8iDkbEq92j/yFp06oHW5hnqdtQkr4u6XNtX35b5dlXH6C3famkKyT9uLdJznL6l6DWF6Y3\nS/qZ7Xu6Ly3cZXuw16Hmi4gXJX1N0lFJL0j6ZUQc7G2qZW2IiCmp8+QuaUOP86zkzyQ92OsQi9m+\nTtKxiDjS9mWt+Q/J2x6WtEfSzd0t0CrY/pCkqe7Wsbv/arNO0jZJfxcR2yT9Sp1dz2rYfos6W3SX\nSLpY0rDtG3ub6pxV+aRp+y8lvRIR9/c6y3zdJ+5bJX1p/sltXV5b5fmCpLfPO76pe1pVurtxeyT9\nU0Ts73WeRa6SdJ3tZyX9s6Q/sv2PPc602PPqPMs/0j2+R50yrcnVkp6NiJ9HxK8l7ZX0vh5nWs6U\n7Y2SZPsiSdM9znMW22PqvJRU4xPQOyVdKulx28+p0zs/sd3KFnxb5fmfkn7L9iXddzZvkFTju8Xf\nlDQeEXf2OshiEXFrRLw9It6hzu13KCI+3utc83V3MY/Zvqx70nbV9+bWUUlX2h6wbXUy1vKm1uI9\nigckjXUPf0JSr5/QF+SzvUOdl5Gui4j/7Vmqhc5kjIgnI+KiiHhHRGxW58n9dyOilSehVsqz+wx/\n+gP0T0n6dm0foLd9laSPSfqA7ce6r9nt6HWuPrRL0n22D6vzbvtXepxngYh4WJ0t4sckPa7OA+2u\nnoaSZPt+ST+SdJnto7ZvknS7pGtsn/7Lvdsry/c3koYl/Vv38fL3vcq3Qsb5Qi3utvMheQBIWPNv\nGAFABuUJAAmUJwAkUJ4AkEB5AkAC5QkACZQnACRQngCQ8H/AGJvttLXzoQAAAABJRU5ErkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAU8AAAD7CAYAAADq4RYlAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAADutJREFUeJzt3W+MnXWZxvHrgmo6zCzVTaYl2AjVDXZKdNkmKisxm3Ug\nNJiAmGyCmGjZt64lalTEF+KbDTYYl/33gogVN7AmdtuUbHTp1iYmrllZhEJhZlizEFtgmRmjlsxY\nDJV7X5wz3ZnpzLS9n98z53eY7ydpcub09Pdc50+v8zznnDm3I0IAgPNzQa8DAEA/ojwBIIHyBIAE\nyhMAEihPAEigPAEgYV3bG7DNZ6EA9K2I8FLnt16ekvTtj757NTaTtn9sUjdv29TrGMuqPZ9Uf8ba\n80n1Z6w9n1Q+4859R5f9Ow7bASCB8gSABMpT0tbhwV5HWFHt+aT6M9aeT6o/Y+35pNXN6LZ/t912\n1P6aJwAsZee+o8u+YcSeJwAkUJ4AkEB5AkAC5QkACZQnACRQngCQQHkCQALlCQAJlCcAJJy1PG3f\nb3vS9lPzznur7YO2n7X9iO0N7cYEgLqcy57nHknXLzrvDkmHIuJdkg5L+lLpYABQs7OWZ0T8WNKv\nF519k6QHuqcfkPSRwrkAoGrZ1zw3RsSkJEXEy5I2losEAPUr9YYRozYArCnZMRyTtjdFxKTtSyRN\nrXTh/WOTp09vHR7UyPBQcrPSrkfG9crsqfS/X8rFg+v0t9ePFFtv7J07dNFgue8VnJmZ0T333FNs\nvY0bhrR7dEux9STpCz98XlMnZoqtVzpj6XySNDCwXidPvlrtemvxNmx6ncenZzQxPXtOlz3X8nT3\nz5yHJe2U9DVJn5R0YKV/XHKmyCuzp6S7ii3XWfOusmVcsjglaWhoSCW/d9Ve8usJG5k6MVN1xtL5\npE7G0teZ27D5ek2MDA8t2Lk7MLH8fuG5fFTpIUk/kXSF7WO2b5N0t6TrbD8rabT7MwCsGWfd84yI\nW5f5q2sLZwGAvsFvGAFAAuUJAAmUJwAkUJ4AkEB5AkAC5QkACZQnACRQngCQQHkCQALlCQAJlCcA\nJFCeAJBAeQJAAuUJAAmUJwAkUJ4AkJCdYdQzfpMUd5Vfs6Tfzs4Wn2FUcqTC+vXrtXPf0WLrza1Z\nc8bS+dpYk9uwuYGB9cXWOpu+K894Ta3MUSlp2//8W9H1du47WvWsnDbWrH29uTW//dF3F1uv9vu5\nXx43q4XDdgBIoDwBIIHyBIAEyhMAEihPAEigPAEggfIEgATKEwASKE8ASKA8ASCB8gSABMoTABIo\nTwBIoDwBIKFRedr+jO2nbT9l+0Hbby4VDABqli5P25dK+rSk7RHxHnW+G/SWUsEAoGZNvwz5QkmD\ntl+XdJGkl5pHAoD6pfc8I+IlSV+XdEzSi5J+ExGHSgUDgJql9zxtv0XSTZIuk3RC0l7bt0bEQ4sv\nu39s8vTprcODGhkeym5WAwPl56iUnnvyhR8+r6kTM8XWK32d+2EWTe3rSeUfN7Xfz/3wuGl6n4xP\nz2hievacLtvksP1aSc9FxK8kyfY+SR+QdEZ53rxtU4PNLHTy5KvVzzCaOjFTfC5LzbNypPoztjV/\np6TSj+025gOVvI+ldu7nJkaGhxbs3B2YmFr2sk3ebT8m6Wrb691JPCppvMF6ANA3mrzm+aikvZKe\nkPSkJEu6r1AuAKhao3fbI+Krkr5aKAsA9A1+wwgAEihPAEigPAEggfIEgATKEwASKE8ASKA8ASCB\n8gSABMoTABIoTwBIoDwBIIHyBIAEyhMAEihPAEigPAEggfIEgISmo4dXXT8MgCudsfZ8c2uWXq8f\nhpft3He06Ho1X+eBgbLXV6pvANz56Lvy7IcBcG0M8ipprd6GbVznmjPWPpRPauc6rxYO2wEggfIE\ngATKEwASKE8ASKA8ASCB8gSABMoTABIoTwBIoDwBIIHyBIAEyhMAEihPAEigPAEggfIEgIRG5Wl7\ng+3v2R63/Yzt95cKBgA1a/p9nvdK+n5E/IXtdZIuKpAJAKqXLk/bF0v6YETslKSIOCXplUK5AKBq\nTQ7bt0j6pe09th+3fZ/tgVLBAKBmTQ7b10naLulTEfGY7b+RdIekryy+4P6xydOntw4PamR4KL3R\nNubvlJ5FUzrjxg3522sp/XAb1j7Pp40121iv5vukjTWbzjAan57RxPTsOV22SXm+IOl4RDzW/Xmv\npC8udcGbt21qsJmF2pq/U/PsmNL65Tas/T4pPdOnH27DfnjcNDEyPLRg5+7AxNSyl00ftkfEpKTj\ntq/onjUqaSy7HgD0k6bvtu+S9KDtN0l6TtJtzSMBQP0alWdEPCnpvYWyAEDf4DeMACCB8gSABMoT\nABIoTwBIoDwBIIHyBIAEyhMAEihPAEigPAEggfIEgATKEwASKE8ASKA8ASCB8gSABMoTABKafhny\nqmtr/k7pOSolZ8ds3DCk3aNbiq5X+21Y+zyfuTVrv841r9fGmk1nGJ2PvivPtubvlJxv08Zsm5JK\nFvGctTbPp401++Fx2A+34WrhsB0AEihPAEigPAEggfIEgATKEwASKE8ASKA8ASCB8gSABMoTABIo\nTwBIoDwBIIHyBIAEyhMAEihPAEhoXJ62L7D9uO2HSwQCgH5QYs/zdkljBdYBgL7RqDxtb5Z0g6Rv\nlokDAP2h6Z7nNyR9XlLZr5cGgMqly9P2hyVNRsQRSe7+AYA1ockMo2sk3Wj7BkkDkv7A9nci4hOL\nL7h/bPL06a3DgxoZHkpvtI0BcKWHRpXOWHp42cDAep08+Wqx9ebWrHnYWL8MLyt5P6/V27CJ8ekZ\nTUzPntNl0+UZEXdKulOSbP+ZpM8tVZySdPO2TdnNnKGtAXAllc7YL8PQ1uLwsrV0nUtfX6m+YYkj\nw0MLdu4OTEwte1k+5wkACUVGD0fEjyT9qMRaANAP2PMEgATKEwASKE8ASKA8ASCB8gSABMoTABIo\nTwBIoDwBIIHyBIAEyhMAEihPAEigPAEggfIEgATKEwASKE8ASKA8ASChyJchr6aNG4aKj83YuCE/\nU2m59UrPZemHWTRrbf7OWps5VPo+nluzphlG56PvynP36JZeRzir2jOWnhsj1T9nqV/m76yl9dpY\ns/QT5Eo4bAeABMoTABIoTwBIoDwBIIHyBIAEyhMAEihPAEigPAEggfIEgATKEwASKE8ASKA8ASCB\n8gSABMoTABLS5Wl7s+3Dtp+xfdT2rpLBAKBmTb7P85Skz0bEEdtDkn5m+2BETBTKBgDVSu95RsTL\nEXGke3pG0rikt5UKBgA1K/Kap+3LJV0l6acl1gOA2jUew9E9ZN8r6fbuHugZ9o9Nnj69dXhQI8Nl\nZwbh/LQxB6r0nKU21qt9/k7t65W+T9pYs+k8svHpGU1Mz57TZd1kfojtdZL+VdIPIuLeZS4TpWfH\nAOeLuU3I6D5ulmz3poft35I0tlxxAsAbVZOPKl0j6eOSPmT7CduP295RLhoA1Cv9mmdE/IekCwtm\nAYC+wW8YAUAC5QkACZQnACRQngCQQHkCQALlCQAJlCcAJFCeAJBAeQJAAuUJAAmUJwAkUJ4AkEB5\nAkAC5QkACZQnACRQngCQ0HgAHNAP1uLQu6bD0LAyyhNrwu7RLb2OgDcYDtsBIIHyBIAEyhMAEihP\nAEigPAEggfIEgATKEwASKE8ASKA8ASCB8gSABMoTABIoTwBIoDwBIKFRedreYXvC9n/b/mKpUABQ\nu3R52r5A0t9Lul7SlZI+ZntrqWCraXx6ptcRVlR7Pqn+jLXnk+rPWHs+aXUzNtnzfJ+kn0fELyLi\nNUnflXRTmVira2J6ttcRVlR7Pqn+jLXnk+rPWHs+aXUzNinPt0k6Pu/nF7rnAcAbHm8YAUCCIyL3\nD+2rJd0VETu6P98hKSLia4sul9sAAFQgIpYcLNWkPC+U9KykUUn/K+lRSR+LiPFsSADoF+kBcBHx\ne9t/JemgOof/91OcANaK9J4nAKxlrb1hVPsH6G1vtn3Y9jO2j9re1etMS7F9ge3HbT/c6yxLsb3B\n9vdsj3dvy/f3OtNitj9j+2nbT9l+0PabK8h0v+1J20/NO++ttg/aftb2I7Y3VJZvd/d+PmL7X2xf\n3Kt8y2Wc93efs/267T9sa/utlGeffID+lKTPRsSVkv5U0qcqzChJt0sa63WIFdwr6fsRMSLpjyVV\n9dKN7UslfVrS9oh4jzovVd3S21SSpD3q/P+Y7w5JhyLiXZIOS/rSqqf6f0vlOyjpyoi4StLP1dt8\n0tIZZXuzpOsk/aLNjbe151n9B+gj4uWIONI9PaPOf/qqPqfafRDcIOmbvc6ylO6exwcjYo8kRcSp\niHilx7GWcqGkQdvrJF0k6aUe51FE/FjSrxedfZOkB7qnH5D0kVUNNc9S+SLiUES83v3xPyVtXvVg\nC/MsdRtK0jckfb7t7bdVnn31AXrbl0u6StJPe5vkDHMPglpfmN4i6Ze293RfWrjP9kCvQ80XES9J\n+rqkY5JelPSbiDjU21TL2hgRk1LnyV3Sxh7nWclfSvpBr0MsZvtGSccj4mjb21rzH5K3PSRpr6Tb\nu3ugVbD9YUmT3b1jd//UZp2k7ZL+ISK2S/qtOoee1bD9FnX26C6TdKmkIdu39jbVOavySdP2lyW9\nFhEP9TrLfN0n7jslfWX+2W1tr63yfFHS2+f9vLl7XlW6h3F7Jf1TRBzodZ5FrpF0o+3nJP2zpD+3\n/Z0eZ1rsBXWe5R/r/rxXnTKtybWSnouIX0XE7yXtk/SBHmdazqTtTZJk+xJJUz3OcwbbO9V5KanG\nJ6B3Srpc0pO2n1end35mu5U9+LbK878k/ZHty7rvbN4iqcZ3i78laSwi7u11kMUi4s6IeHtEvEOd\n2+9wRHyi17nm6x5iHrd9RfesUdX35tYxSVfbXm/b6mSs5U2txUcUD0va2T39SUm9fkJfkM/2DnVe\nRroxIn7Xs1QLnc4YEU9HxCUR8Y6I2KLOk/ufREQrT0KtlGf3GX7uA/TPSPpubR+gt32NpI9L+pDt\nJ7qv2e3oda4+tEvSg7aPqPNu+1/3OM8CEfGoOnvET0h6Up3/aPf1NJQk2w9J+omkK2wfs32bpLsl\nXWd77jf37q4s399JGpL0793/L//Yq3wrZJwv1OJhOx+SB4CENf+GEQBkUJ4AkEB5AkAC5QkACZQn\nACRQngCQQHkCQALlCQAJ/wcU+HVoCQewRQAAAABJRU5ErkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\nG6OvTDFBAAAAAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def maze1():\n", + " return Maze([\n", + " \"########\",\n", + " \"#X.#...#\",\n", + " \"#.##.#.#\",\n", + " \"#.#..#.#\",\n", + " \"#....#.#\",\n", + " \"#.##...#\",\n", + " \"#..#..##\",\n", + " \"##.#..@#\",\n", + " \"########\"\n", + " ])\n", + "\n", + "maze1().draw()\n", + "\n", + "def maze2():\n", + " return Maze([\n", + " \"###############\",\n", + " \"#X#@.#.#...#..#\",\n", + " \"#.##.....#....#\",\n", + " \"#.#.#.#..#..#.#\",\n", + " \"#...#.#....#..#\",\n", + " \"#.#.#.........#\",\n", + " \"#.#.##.#..#...#\",\n", + " \"#.....#..#..#.#\",\n", + " \"#####...#.....#\",\n", + " \"########...####\",\n", + " \"###############\"\n", + " ])\n", + "\n", + "maze2().draw()\n", + "\n", + "def mazeUnsolvable1():\n", + " return Maze([\n", + " \"###############\",\n", + " \"#X#@.#.#...#..#\",\n", + " \"#.##.....#....#\",\n", + " \"#.#.#.#..#..#.#\",\n", + " \"#.#.#.#....#..#\",\n", + " \"#..##...#.....#\",\n", + " \"#.#.##....#...#\",\n", + " \"#.#...#..#..#.#\",\n", + " \"#####...#.....#\",\n", + " \"########...####\",\n", + " \"###############\"\n", + " ])\n", + "\n", + "mazeUnsolvable1().draw()\n", + "\n", + "def maze3():\n", + " return Maze([\n", + " \"###############\",\n", + " \"#X#@.#.#...#.1#\",\n", + " \"#.##.....#....#\",\n", + " \"#A#.#.#..#..#.#\",\n", + " \"#.a.#C#....#..#\",\n", + " \"#.#.#0C.......#\",\n", + " \"#.#.##.#..#...#\",\n", + " \"#.B...#.2#..#.#\",\n", + " \"#####...#.....#\",\n", + " \"########...####\",\n", + " \"###############\"\n", + " ])\n", + "\n", + "maze3().draw()\n", + "\n", + "def maze4():\n", + " return Maze([\n", + " \"########\",\n", + " \"#@0#.01#\",\n", + " \"#A1#C#a#\",\n", + " \"#0#..#.#\",\n", + " \"#aBc2#.#\",\n", + " \"#B##c..#\",\n", + " \"#..#bb##\",\n", + " \"##1#..X#\",\n", + " \"########\"\n", + " ])\n", + "\n", + "maze4().draw()" + ] + }, + { + "cell_type": "code", + "execution_count": 106, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Got to the end\n", + "49\n" + ] + } + ], + "source": [ + "# m1 = maze1()\n", + "# print(novelty_search(m1, 100))\n", + "# 12 iterations\n", + "\n", + "# m2 = maze2()\n", + "# print(novelty_search(m2, 140))\n", + "# 72 iterations\n", + "\n", + "# m3 = maze3()\n", + "# print(novelty_search(m3, 500))\n", + "# 274 iterations\n", + "\n", + "m4 = maze4()\n", + "print(novelty_search(m4, 1000))\n", + "# 49 iterations" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python [Root]", + "language": "python", + "name": "Python [Root]" + }, + "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.5.2" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/projects/class-projects/Kwan b/projects/class-projects/Kwan new file mode 100644 index 0000000..8f078f6 --- /dev/null +++ b/projects/class-projects/Kwan @@ -0,0 +1,20 @@ +Project Proposal + +Group: Melissa Kwan (individual) +Goal: To explore novelty search and compare its performance on mazes compared to MCTS + +Steps +Finish writing MCTS and testing it +Research novelty search (Long step) +Write pseudocode (Long step) +Code it based on researched steps (Long step) +Test novelty search's performance on different mazes +Compare results with MCTS +Come up with conclusion + +Testing +Data has already been provided (Mazes from assignment 3) + +Halfway there +MCTS finished and tested +Pseudocode for novelty search written \ No newline at end of file