summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/Makefile27
-rw-r--r--docs/closest_apple.py60
-rw-r--r--docs/closest_apple.tex13
-rw-r--r--docs/firstbot.py2
-rw-r--r--docs/firstbot.tex81
-rw-r--r--docs/introduction.tex61
-rwxr-xr-xdocs/jinja251
-rw-r--r--docs/look_ahead.tex9
-rw-r--r--docs/macros.tex19
-rw-r--r--docs/print_bot.py3
-rw-r--r--docs/random_avoid.py26
-rw-r--r--docs/random_avoid.tex167
-rw-r--r--docs/random_simple.py4
-rw-r--r--docs/random_simple.tex65
-rw-r--r--docs/tutorial.tex61
15 files changed, 649 insertions, 0 deletions
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 0000000..5cd4a7e
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,27 @@
+BUILD_DIR = build
+
+FILES = $(wildcard *.tex *.py)
+BUILD_FILES = $(patsubst %,${BUILD_DIR}/%,${FILES})
+
+LATEX=xelatex
+LATEX_FLAGS=-shell-escape -interaction=nonstopmode
+
+.PHONY: all
+
+all: tutorial.pdf
+
+${BUILD_DIR}:
+ mkdir -p ${BUILD_DIR}
+
+${BUILD_DIR}/%.tex: %.tex
+ ./jinja2 --latex < $< > $@
+
+${BUILD_DIR}/%.py: %.py
+ ln $< $@
+
+tutorial.pdf: ${BUILD_DIR}/tutorial.tex ${BUILD_FILES}
+ cd "${BUILD_DIR}" && \
+ ${LATEX} ${LATEX_FLAGS} tutorial && \
+ ${LATEX} ${LATEX_FLAGS} tutorial && \
+ ${LATEX} ${LATEX_FLAGS} tutorial
+ mv -f "${BUILD_DIR}/tutorial.pdf" tutorial.pdf
diff --git a/docs/closest_apple.py b/docs/closest_apple.py
new file mode 100644
index 0000000..3696bfa
--- /dev/null
+++ b/docs/closest_apple.py
@@ -0,0 +1,60 @@
+DIRECTIONS = {
+ 'L': (-1, 0),
+ 'U': (0, -1),
+ 'R': (1, 0),
+ 'D': (0, 1),
+}
+
+def closest_apple_bot(board, position):
+ x, y = position
+ height = len(board)
+ width = len(board[0])
+
+ # todo contains the squares we need to explore
+ todo = []
+ # done contains the squares we've already explored
+ done = set()
+
+ # for each initial direction
+ for direction in DIRECTIONS:
+ dx, dy = DIRECTIONS[direction]
+ # find the new position
+ nx = (x + dx) % width
+ ny = (y + dy) % height
+ # add to todo and done
+ todo.append((nx, ny, direction))
+ done.add((nx, ny))
+
+ while todo:
+ # take the first item in todo
+ x, y, direction = todo.pop(0)
+
+ cell = board[y][x]
+
+ # if we've reached an apple, we've found the shortest path
+ # and direction is the right way to go
+ if cell == '*':
+ return direction
+
+ # if we can't move into this cell, go to the next square to explore
+ if cell != '.':
+ continue
+
+ # at this square, we can go any direction,
+ # as long as it's not in our done set
+ for dx, dy in DIRECTIONS.values():
+ nx = (x + dx) % width
+ ny = (y + dy) % height
+
+ if (nx, ny) not in done:
+ # we haven't visited this square before,
+ # add it to our list of squares to visit
+ # note that the third item here is the direction we initially
+ # took to get to this square
+ todo.append((nx, ny, direction))
+ done.add((nx, ny))
+
+ # if we get here, there are no apples on the board,
+ # so we'll just move up.
+ return 'U'
+
diff --git a/docs/closest_apple.tex b/docs/closest_apple.tex
new file mode 100644
index 0000000..36b7382
--- /dev/null
+++ b/docs/closest_apple.tex
@@ -0,0 +1,13 @@
+\section{Closest apple}
+
+One interesting bot we can write is one which always moves towards the closest
+apple. Both the idea and the coding are a little tricky, but see if you can
+handle it. In order to find the closest apple, we actually want to know
+the \emph{shortest path} to the apple, and when we know that, the first step in
+that path is the direction we need to move in.
+
+To find the shortest path, we need to use an algorithm called
+\emph{breadth first search} (BFS).
+% TODO: description of the algorithm
+
+\pythonfile{closest_apple.py}
diff --git a/docs/firstbot.py b/docs/firstbot.py
new file mode 100644
index 0000000..6eb8484
--- /dev/null
+++ b/docs/firstbot.py
@@ -0,0 +1,2 @@
+def up_bot(board, position):
+ return 'U'
diff --git a/docs/firstbot.tex b/docs/firstbot.tex
new file mode 100644
index 0000000..7e95b85
--- /dev/null
+++ b/docs/firstbot.tex
@@ -0,0 +1,81 @@
+\section{Your First Bot}
+\label{sec:firstbot}
+\fasttrack{Always move up.}
+
+Alright, let’s get started.
+If you think back to when you started programming, chances are the first program
+you ever wrote was one which printed out the immortal phrase “Hello World”.
+Well we can’t print stuff here, but our first bot is going to be almost as
+useless as that: our bot is just going to continually move up.
+
+Let’s have a look at the code:
+\pythonfile{firstbot.py}
+
+Pretty simple, huh?
+It’s a function takes as input two parameters, and returns a string.
+We’ll have a look at \texttt{board} and \texttt{position} later,
+but the important thing here is that the returned value says which direction the
+snake should move in. Each time the snake is allowed to make a move, the
+function is called, it returns one of \py|'U', 'D', 'L', 'R'|
+(indicating up, down, left and right, respectively), and the snake is moved in
+that direction.
+
+\subsection{Running the code}
+
+Depending on how you have installed SnakeGame, there are a few different ways to
+run the code. If you’re in some kind of programming class, ask your instructor
+which method to use.
+
+\subsubsection{Method A: CLI interface}
+
+If you installed from the repository (using \texttt{pip}), this is the method
+you should use.
+Assuming you’ve put the \texttt{up\_bot} function in a file called
+\texttt{mybot.py}, you can run this command:
+
+\begin{shell}
+$ snakegame mybot:up_bot
+\end{shell}
+
+To use different viewers, you can supply the \texttt{-v VIEWER} argument:
+\begin{shell}
+$ snakegame -v pyglet mybot:up_bot
+$ snakegame -v pygame mybot:up_bot
+$ snakegame -v curses mybot:up_bot
+\end{shell}
+
+You can specify multiple bots, and also control the width, height and number of
+apples on the board:
+\begin{shell}
+$ snakegame -w 4 -h 20 -a 30 mybot:up_bot mybot:up_bot mybot:up_bot
+\end{shell}
+
+\subsubsection{Method B: Pyglet / Pygame}
+
+You can also add some code to the file containing your bot so that you can run
+that file as a normal Python program, which will run the game.
+At the end of the file, add this:
+\begin{pythoncode}
+if __name__ == '__main__':
+ from snakegame.engine import Engine
+ from snakegame.viewers.pyglet import Viewer
+ engine = Engine(10, 10, 25)
+ engine.add_bot(up_bot)
+ viewer = Viewer(engine)
+ viewer.run()
+\end{pythoncode}
+
+If you want to use pygame instead, change \texttt{snakegame.viewers.pyglet} to
+\texttt{snakegame.viewers.pygame}.
+
+If neither of these work, there is also a console viewer, which works if you’re
+in a terminal (it will not work in IDLE!):
+use \texttt{snakegame.viewers.curses}.
+
+\subsection{Got it running?}
+
+Great, you should see a nice big board with some apples scattered over it,
+and a snake continually moving upwards.
+
+Once you’re ready, we’ll move on to something a little more interesting.
+
diff --git a/docs/introduction.tex b/docs/introduction.tex
new file mode 100644
index 0000000..5a149b7
--- /dev/null
+++ b/docs/introduction.tex
@@ -0,0 +1,61 @@
+\section{Introduction}
+
+Before starting this tutorial, you should \emph{already} know the basics of
+Python. Specifically, you should know these bits of Python:
+\begin{itemize}
+ \item How to \py|print| things
+ \item \py|if|, \py|elif| and \py|else|
+ \item \py|for| and \py|while| loops
+ \item \py|list|s and \py|dict|ionaries
+ \item functions (\py|def|)
+\end{itemize}
+
+\subsection{Help! I don’t know what these are…}
+
+If you have no idea what any of those things are, \emph{don’t panic}.
+All that means is that you’re not quite ready to follow this tutorial yet, and
+you need to learn the basics of Python first.
+There are many excellent \emph{free} resources for doing this:
+\begin{itemize}
+ \item How to Think Like a Computer Scientist \\
+ (\url{http://openbookproject.net/thinkcs/python/english2e/})
+ \item Learn Python the Hard Way \\
+ \url{http://learnpythonthehardway.org/}
+ \item The official tutorial in the Python documentation \\
+ \url{http://docs.python.org/tutorial/}
+\end{itemize}
+
+The most important resource to learn programming, however, are the people you
+know who are learning Python with you, already know Python, or some other
+programming language.
+You can spend hours trying to understand something in books and not get it,
+but ask another person to explain it, and it will all suddenly ‘click’ and make
+sense.
+
+\subsection{Yeah, I know what those are.}
+
+Excellent! Let’s get started then.
+
+If you’re doing this in some kind of programming class, your instructor may have
+provided you with a zip file (or similar) containing SnakeGame and pyglet.
+If so, follow their instructions for setting it up, and head straight on to
+Your First Bot.
+
+Otherwise, you’ll need to first install the code. The latest version of
+SnakeGame is available in a Mercurial repository at
+\url{http://hg.flowblok.id.au/snakegame}.
+You can install it using pip:
+\begin{shell}
+$ pip install hg+http://hg.flowblok.id.au/snakegame#egg=SnakeGame
+\end{shell}
+
+If you wish to have a pretty graphical viewer for watching the game being
+played, you will also need to install pyglet\footnoteurl{http://pyglet.org/}
+and/or pygame\footnoteurl{http://pygame.org}.
+
+\subsection{Skipping ahead}
+
+If you already know Python, you will probably want to skip some sections of this
+tutorial. To make this easier, there is a \emph{Fast track} note at the start of
+each section: if you can write a bot which does what it says, you can safely
+skip that section.
diff --git a/docs/jinja2 b/docs/jinja2
new file mode 100755
index 0000000..a1c89e2
--- /dev/null
+++ b/docs/jinja2
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+
+import argparse
+import json
+from os import path
+import sys
+
+from jinja2 import Environment, FileSystemLoader
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--latex', action='store_true')
+parser.add_argument('template', nargs='?')
+parser.add_argument('data', nargs='?')
+
+args = parser.parse_args()
+
+if args.latex:
+ env = Environment(
+ block_start_string='%%',
+ block_end_string='%%',
+ variable_start_string='<',
+ variable_end_string='>',
+ comment_start_string='###',
+ comment_end_string='###',
+ )
+else:
+ env = Environment()
+
+if args.template:
+ dirname, basename = path.split(args.template)
+
+ env.loader = FileSystemLoader(dirname)
+ template = env.get_template(basename)
+
+ if args.data:
+ with open(args.data, 'rb') as f:
+ data = json.load(f)
+
+ else:
+ data = json.load(sys.stdin)
+
+else:
+ source = sys.stdin.read()
+ template = env.from_string(source.decode('utf-8'))
+ data = {}
+
+ env.loader = FileSystemLoader('.')
+
+output = template.render(data)
+
+sys.stdout.write(output.encode('utf-8'))
diff --git a/docs/look_ahead.tex b/docs/look_ahead.tex
new file mode 100644
index 0000000..d5c37c6
--- /dev/null
+++ b/docs/look_ahead.tex
@@ -0,0 +1,9 @@
+\section{Look ahead}
+
+By now you’re probably itching to try out some of your own ideas about how to
+make a good bot. Now’s a great time to take a break from following my detailed
+instructions and just play around with some ideas.
+Here’s an idea to get you started: our \texttt{random\_avoid\_bot} only looked
+one square ahead, try making a bot which looks two squares ahead and chooses the
+direction with the most free space.
+
diff --git a/docs/macros.tex b/docs/macros.tex
new file mode 100644
index 0000000..2f16900
--- /dev/null
+++ b/docs/macros.tex
@@ -0,0 +1,19 @@
+%%- macro make_board(board) %%
+\begin{verbatim}
+%% for row in board %%
+%%- if loop.first %%
+<- ' ' >
+%%- for n in range(row |length) %%
+<- ' ' ~ n >
+%%- endfor %%
+< ' +' ~ '-+' * (row | length) >
+%%- endif %%
+< loop.index0 ~ '|' >
+%%- for cell in row %%
+<- cell >|
+%%- endfor %%
+< ' +' ~ '-+' * (row | length) >
+%%- endfor %%
+\end{verbatim}
+%%- endmacro %%
+
diff --git a/docs/print_bot.py b/docs/print_bot.py
new file mode 100644
index 0000000..5adee1f
--- /dev/null
+++ b/docs/print_bot.py
@@ -0,0 +1,3 @@
+def print_bot(board, position):
+ print position
+ print board
diff --git a/docs/random_avoid.py b/docs/random_avoid.py
new file mode 100644
index 0000000..bf08eef
--- /dev/null
+++ b/docs/random_avoid.py
@@ -0,0 +1,26 @@
+from random import choice
+
+def random_avoid_bot(board, position):
+ x, y = position
+ height = len(board)
+ width = len(board[0])
+
+ valid_moves = []
+
+ left = board[y][(x - 1) % width]
+ if left == '.' or left == '*':
+ valid_moves.append('L')
+
+ right = board[y][(x + 1) % width]
+ if right == '.' or right == '*':
+ valid_moves.append('R')
+
+ up = board[(y - 1) % height][x]
+ if up == '.' or up == '*':
+ valid_moves.append('U')
+
+ down = board[(y + 1) % height][x]
+ if down == '.' or down == '*':
+ valid_moves.append('D')
+
+ return choice(valid_moves)
diff --git a/docs/random_avoid.tex b/docs/random_avoid.tex
new file mode 100644
index 0000000..90ac183
--- /dev/null
+++ b/docs/random_avoid.tex
@@ -0,0 +1,167 @@
+%%- from "macros.tex" import make_board -%%
+
+\section{Random Avoid Bot}
+\fasttrack{Choose a direction at random, but not one which will lead to immediate death.}
+
+The last bot we wrote had a big problem, it ran into its own tail.
+We don’t want our next bot to be that stupid, so we need to teach it how to not
+do that!
+
+But before we can do that, we need to know few more things about our bots.
+You might have noticed that our functions have two parameters,
+\texttt{board} and \texttt{position}.
+We haven’t had to use them so far, but we will now, so we need to know what they
+are.
+But rather than me just telling you what they are,
+why not have a look yourself?
+
+\pythonfile{print_bot.py}
+
+You should see something like this (on a 4x3 board):
+\begin{minted}{pytb}
+(1, 2)
+[['.', '.', '*', '.'], ['.', '.', '*', '.'], ['.', 'A', '.', '.']]
+Exception in bot A (<'<'>function print_bot at 0x7f61165f2e60<'>'>):
+------------------------------------------------------------
+Traceback (most recent call last):
+ File "…/snakegame/engine.py", line 132, in update_snakes
+ "Return value should be a string."
+AssertionError: Return value should be a string.
+------------------------------------------------------------
+\end{minted}
+
+Ignore all the Exception stuff, that’s just because we didn’t return one of
+\py|'L'|, \py|'U'|, \py|'D'| or \py|'R'|.
+The first line is our position: it’s a \py|tuple| of the x and y
+coordinates of our snake’s head.
+The second line is the board: it’s a list of each row in the board,
+and each row is a list of the cells in that row.
+
+Notice that if we index the board first by the y coordinate and then by the x
+coordinate, we can get the character in the board where our snake is:
+\py|board[y][x] == board[2][1] == 'A'|.
+The head of our snake is always an uppercase character in the board,
+and the rest of our body (the tail) are always lowercase characters.
+
+This is all very well, but how do we stop our bot from eating its tail?
+Well, the answer is that we need to look at each of the squares surrounding our
+snake’s head, to see if we’ll die if we move into them or not.
+
+Let’s have a look at the square to the right of our snake’s head.
+First, we need to know its coordinates: looking at
+Board~\ref{brd:right-square:normal},
+we see that if our snake is at position $(x, y)$,
+then the square on the right will be at position $(x + 1, y)$.
+
+But this isn’t the whole story: Board~\ref{brd:right-square:wrapping}
+shows that if the snake is on the rightmost column, the square on the right
+is going to wrap around to be on the leftmost column.
+
+\begin{board}
+\begin{subfigure}{.45\linewidth}
+ \begin{tabular}{l|l|l|l|l}
+ … & $x-1$ & $x$ & $x + 1$ & … \\\hline
+ $y-1$ & & & & \\\hline
+ $y$ & & $\mathbf{(x,y)}$ & $\mathbf{(x+1,y)}$ & \\\hline
+ $y+1$ & & & & \\\hline
+ … & & & & … \\
+ \end{tabular}
+\caption{Coordinate of the square to the right (ignoring wrapping).}
+\label{brd:right-square:normal}
+\end{subfigure}
+\hfill
+%
+\begin{subfigure}{.45\linewidth}
+< make_board([
+ '.....',
+ '*...A',
+ '.....',
+]) >
+\caption{%
+ The board wraps around,
+ so the square to the right of our snake $(4, 1)$
+ is the apple $(0, 1)$.
+}
+\label{brd:right-square:wrapping}
+\end{subfigure}
+
+\caption{Finding the square to the right.}
+\label{brd:right-square}
+\end{board}
+
+Fortunately for us, there’s an easy way of ‘wrapping’ around in Python,
+which is the modulo operator (\%). The modulo operator returns the
+\emph{remainder} when you divide two numbers.
+\begin{minted}{pycon}
+>>> 3 % 8
+3
+>>> 7 % 8
+7
+>>> 8 % 8
+0
+>>> 9 % 8
+1
+>>> for i in range(20):
+... print i % 8,
+...
+0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3
+\end{minted}
+
+\newcommand\mod{\,\%\,}
+
+% TODO: how do we get the width and height of the board?
+
+Looking back at Board~\ref{brd:right-square:wrapping}, we need to wrap the x
+coordinate back to $0$ when $x + 1 = width$,
+so we need $(x + 1) \mod width$.
+Taking this to a more general level, imagine we need to get the cell where
+the x coordinate is shifted by $dx$
+and the y coordinate is shifted by $dy$.
+For example, we might want to get the cell diagonally adjacent on the bottom
+left: it’s one square to the left, $dx = -1$ and one square down $dy = 1$.
+Don’t forget that moving right or down means adding
+and moving left or upwards means subtracting!
+Back to our general case, our new cell is going to be at the position
+$((x + dx) \mod width, (y + dy) \mod height)$.
+
+Don’t worry if you didn’t follow the general case there, you just need to
+remember that the cell to the right is at $((x + 1) \mod width, y)$.
+We then need to look \emph{in the board} at that position to see what’s in that
+cell.
+Remember that our board is a list of rows (stacked vertically),
+and each row is a list of cells (stacked horizontally).
+So we need to first find the right row, which we will do by using the y
+coordinate: \py|board[y]|.
+Then we need to find the right cell in the row, using the x coordinate:
+\py|board[y][(x + 1) % width]|.
+
+We’re almost at the end: all we need to do is build up a list of each cell we
+can move into. We know that we can move into cells which are
+empty (represented by a full stop)
+or have an apple (represented by an asterisk) in them,
+so we’ll test for that.
+Take a moment to write out the code we’ve managed to build so far, hopefully
+you’ll end up with something very close to what I’ve got below.
+Then you just need to add the other directions (left, up and down), and you’re
+done.
+
+\begin{pythoncode}
+from random import choice
+
+def bot(board, position):
+ x, y = position
+ height = len(board)
+ width = len(board[0])
+
+ valid_moves = []
+
+ right = board[y][(x + 1) % width]
+ if right == '.' or right == '*':
+ valid_moves.append('R')
+
+ return choice(valid_moves)
+\end{pythoncode}
+
+If you’re really stuck, or want to check your solution, here’s my solution:
+\pythonfile{random_avoid.py}
+
diff --git a/docs/random_simple.py b/docs/random_simple.py
new file mode 100644
index 0000000..f7ca03c
--- /dev/null
+++ b/docs/random_simple.py
@@ -0,0 +1,4 @@
+from random import choice
+
+def random_bot(board, position):
+ return choice('UDLR')
diff --git a/docs/random_simple.tex b/docs/random_simple.tex
new file mode 100644
index 0000000..a1ff557
--- /dev/null
+++ b/docs/random_simple.tex
@@ -0,0 +1,65 @@
+%%- from "macros.tex" import make_board -%%
+
+\section{Random Bot}
+\fasttrack{Choose a direction at random.}
+
+The next bot we’ll write is one which instead of moving in just one direction,
+chooses a direction at random to move in.
+Go on, try writing it yourself! I’ll wait here until you’re ready.
+
+Hint: check out the \texttt{random} module.
+
+Got it working? Good work!
+But you’ve probably noticed that there’s a problem:
+it doesn’t take long for our random bot to die.
+But why does it die?
+The answer is that once it eats an apple, it then has a tail, and since it
+doesn’t know any better, it will happily move into the square where its tail is.
+
+\begin{board}
+\hfill
+%
+\begin{subfigure}{.3\linewidth}
+< make_board([' *', ' A* ', ' * '])>
+\caption{Our intrepid snake heads towards an apple. Next move: \textbf{R}}
+\label{brd:random-death:1}
+\end{subfigure}
+\hfill
+%
+\begin{subfigure}{.3\linewidth}
+< make_board(['* *', ' aA ', ' * ']) >
+\caption{It has eaten the apple, and now has a tail. Next move: \textbf{L}}
+\label{brd:random-death:2}
+\end{subfigure}
+\hfill
+%
+\begin{subfigure}{.3\linewidth}
+< make_board(['* *', ' ', ' * ']) >
+\caption{It decided to move left, and ran into itself, oh no!}
+\label{brd:random-death:3}
+\end{subfigure}
+%
+\hfill
+
+\caption{The last moves of Random Bot before death.}
+\label{brd:random-death}
+\end{board}
+
+\pagebreak
+
+By the way, how long was your solution?
+If you’re still learning Python, you might like to have a peek at my solution to
+this bot, it’s only three lines long.
+Hopefully you didn’t write too much more than that!
+
+\pythonfile{random_simple.py}
+
+There are two key things that make my solution work.
+The first is the \texttt{random.choice} function,
+which returns a random item chosen from a sequence you give it.
+The second thing is that a string is a sequence:
+it is made up of the characters in it.
+So if you write \mint{python}|choice('UDLR')|,
+that’s the same as if you had written
+\mint{python}|choice(['U', 'D', 'L', 'R'])|.
+
diff --git a/docs/tutorial.tex b/docs/tutorial.tex
new file mode 100644
index 0000000..907052d
--- /dev/null
+++ b/docs/tutorial.tex
@@ -0,0 +1,61 @@
+\documentclass[12pt]{article}
+
+\usepackage{fontspec}
+
+\usepackage[pdfborder={0 0 0}]{hyperref}
+\usepackage[margin=20mm]{geometry}
+
+\usepackage{float}
+\usepackage{subcaption}
+
+\floatstyle{ruled}
+\newfloat{board}{bh}{brd}
+\floatname{board}{Board}
+\DeclareCaptionSubType{board}
+
+\usepackage{minted}
+\usemintedstyle{tango}
+
+\newmintinline[py]{python}{}
+\newminted{python}{}
+\newmintedfile{python}{}
+
+\newminted[shell]{sh}{}
+
+\setmainfont{Linux Libertine O}
+\setmonofont[AutoFakeBold]{Inconsolata}
+
+\setlength\parskip{2ex}
+\setlength\parindent{0mm}
+
+%\widowpenalty=1000
+%\clubpenalty=1000
+\newcommand\fasttrack[1]{\vspace{-2ex}\hfill\emph{Fast track: #1}\nopagebreak}
+
+\newcommand\footnoteurl[1]{\footnote{\url{#1}}}
+
+\begin{document}
+
+\title{Writing SnakeGame bots}
+\author{Peter Ward}
+\date{July 29, 2012}
+\maketitle
+
+\input{introduction.tex}
+
+\input{firstbot.tex}
+
+\input{random_simple.tex}
+
+% this section is rather long,
+% perhaps take an intermission to explain the board
+% and getting width, height
+% and modulo properly?
+\input{random_avoid.tex}
+
+\input{look_ahead.tex}
+
+\break
+\input{closest_apple.tex}
+
+\end{document}