Nibbzilla!™ - an intelligent agent that plays nibbles


Alex Elliott and Michael Schofield

Welcome to the home page of our final project for CS440 - Artificial Intelligence (a.k.a. CS440 - Death by Prolog).  After many long nights up (particularly the last few), what we have for your viewing pleasure is..... a nice explanation, some code for you to browse, and even a few pictures!

What the heck is nibbles anyway? (an introduction to a dead gaming era
So what is nibbzilla?
Pretty Pictures
 A measly few hundred lines of code

main code                  searching algorithm

 

This project made possible by notepad.exe and SICStus Prolog evaluation version 3.8.5

 

 

 

 

 

Nibbles


Nibbles is an old game from back in the dos days that ran in a qbasic interpreter.  Microsoft was kind enough to give the game away for FREE with dos.  Hidden deep in the recesses of one's c:\dos directory there was endless hours of enjoyment.

The game consists of one or two 'snakes' on a rectangular board.  Also on this board was some kind of goal, or food, which was designated by a number (this was an ansi text game, the 'graphics' were cursors and numbers).  A screenshot of this is depicted below.  Since we couldn't find a screenshot of the original ms-dos version, a mac clone shot will have to suffice.

The snake(s) are always in motion.  The player(s) decide where to steer the snake.  The primary goals are obviously to get the food, yet avoid the other snakes and any walls/obstacles, as these are losing conditions.  The snake is not allowed to double back on itself (ie, if the snake is moving right, to go left, you have to go up or down first, then turn left.  You could choose the speed of the snake when you start the game, and also decide if you want the game's difficulty to increase as you play (the game would automatically speed up the speed up the snake as you played, forcing you to think faster.

Some of the challenges of the game were to navigate the snake quickly while not having a lot of time to think about your moves.   Also, it was all to easy to wrap yourself up into a ball, blocking your movement with your own body.  This was actually a pretty big challenge for us to overcome.

Other games of note from this sorely missed era:

 

 

 

 

 

 

 

Nibbzilla!™

 

We decided it would be nice to reminisce back to the old game of nibbles and model our agent after it.  The nibzilla agent handles two players in the nibbles board.  Given two snakes (a snake consists of a name, length, and all of the positions it occupies), the location of the goal, and the snake that we're interested in, the agent will determine which path it should take to attempt to reach the food.  Depending on the opening position, this may prove to be impossible (if the other snake is closer to the food).

We started the project much like the path-finding homework, creating a data structure to represent the snake. A snake is denoted as the following:

        snake(mike, 3, [(1, 1), (1, 2), (1, 3)])

where you have the name, the length, and the positions it occupies as the parameters.

We first had the crazy idea that we would be able to use the built-in search behavior inherent to prolog to find the best 'way' to get to the food.  This was accomplished the way we had initially done the shortest path homework:  by explicitly defining what it means to have a good path to the food.  Then we tried to just give that definition two snakes, and have it fill in the path.  Prolog went into 'never return an answer mode'.  In hindsight, there were a few reasons why this happened:

We then decided that a solution similar to that of the homework was needed, where we generate the shortest path for the snake.  We started with our homework solutions and went from there.  First, we adapted the shortest path tree to the nature of our agent, taking into account obstacles placed on the board and other syntactical differences of our 'world'.  We then decided on an algorithm to decide a move which involved taking intersection of the first move of the shortest path and the snake's available freemove list (places that don't put it on top of any snake body parts and avoids obstacles).  If the shortest path and the freemove list don't match, then we'd take any freemove available as the next move.  There was a big problem with this in that the shortest path didn't take into account the snake's body.  The snake tended to wrap itself up in its body if it was blocking the shortest path with its own body.  After we had thought that we were really close to being done, we had to redesign how the snake determined its next move.

What we concluded is that we needed to look into the future and determine how 'good' the next possible moves were.  Different end scenarios have different goodness factors: for example, the best move to make leads the snake to finding the food. The worst move leads the snake to trapping itself. If one snake made a move that trapped the other, this was considered less desirable than finding food but still a win condition.  The goodness algorithm assumed that each snake would always move towards the food when replying to another snake's action. This algorithm ended up working extremely well, and we were actually able to throw at it some pretty interesting setups.  To show the result in some form other than just the lists that prolog returns, we conjured up a few animated gifs to show the path of the snakes.  Those appear below:

 

 

 

 

Pictures of Output

 

In this first picture, red is wrapped up in such a way that the first algorithms that we tried resulted in the snake winding itself up and trapping itself. This is because using the orignal algorithm didn't look ahead, and so the snake didn't see a way out of its own winding body.  However, once we used the future lookahead method, the snake was able to see that its tail clears itself in time to get to the food.

 

 

In this second picure, two snakes are in an obstacle course of sorts, both trying to find a way to the food.