Assignment 2: Python & Uninformed Search
CS 440
Fall 2015

Due: September 18, 2015 by noon MDT

Part 1: Coding [80 pts]

The purpose of this assignment is to bring you up to speed on python programming and uninformed tree search algorithms: breadth first search and iterative deepening search.

Hint: The code in this assignment will form the basis for the next assignment as well. So you might want to put some effort into creating an extendible framework.

Hint: I found the code for the two uninformed search algorithms to be relatively straightforward, but the game required considerable thought and debugging! Make sure you start the game first... and early!

The Game of Rush Hour

The target problem is the game Rush Hour. You can play Rush Hour by visiting http://www.thekidzpage.com/freekidsgames/games/rush/index.htm . The standard game comes with 40 puzzles in increasing order of difficulty. Most of the test cases I'll give you are significantly easier than even the first "real" game (which is provided as test4.text) -- you'll see why!

Rush Hour consists of a 6x6 grid and a set of 1x2 cars and 1x3 trucks positioned on the grid. The goal is to move a designated 1x2 goal vehicle out of traffic and off the board. The goal vehicle will always be in a row (can move right or left) and must move off the board to the right.

A vehicle can only move along its axis of orientation (i.e., the goal vehicle and other horizontally aligned vehicles can only move left or right, and vertically aligned vehicles can only move up or down). In order to move a vehicle, the position it is moving into must be empty.

The following is the board from the file test2.text

   0     0     0     0     0     0

   0     0     0     0     0     0

   0    0     0     g     g    t1

   0     0     0     0     0    t1

   0     0     0     0     0    t1

   0     0     0     0     0     0

In this puzzle, there is one other vehicle in addition to the goal vehicle g. (Spaces marked '0' are empty.) In order to solve the puzzle, t1 needs to be moved down one step, and then g needs to be moved to the right one step. When g reaches the end of the row, the goal has been achieved.

Trucks are designated by strings with 't' as the first letter followed by a number. Cars are designated by strings with 'c' as the first letter followed for a number.

Representing the Problem in Your Program

The state of the search should be represented by two elements: a board and a path. The board is implemented as a nested list in which each position is a vehicle or '0'. You will need to keep a distinct copy of the board for each state that search progresses through (this is why the provided code includes a copy_game function).

The path will be a list of the moves that were taken to arrive at the current board state. A move is represented as a list of two elements: position and direction. Position is [x, y] where x is the row and y is the column. The position should designate the cell that will become empty if the vehicle moves in the indicated direction. Direction is a member of the set {0, 1, 2, 3} where 0 is up, 1 is right, 2 is down and 3 is left. So a legal move for the board above is [[2, 5], 2] which would slide the truck (t1) one space down. A solution path is a list that ends in ['exit']. So a solution to test2 is [[2, 5], 2], [[2, 3], 1], ['exit']].

To support your game player, you will need to implement all of the necessary functionality for the game, e.g., modifying the board when a move is taken. I suggest writing four functions (MOVE-UP, MOVE-DOWN, MOVE-RIGHT, and MOVE-LEFT), each of which can be applied to a blank square on the board. These operators are analogous to the move operators for the 8-puzzle, but instead of moving a single tile, you need to move the adjoining vehicle, which will take either 2 or 3 spaces. You should also write a function to collect which moves are possible from a given state.

You should download the file rush-hour-basics.py (Note: when you save it out, you need to put .py on the end of the filename.) The file includes a function to load a game specification from a file and a number of utility functions for managing the game state (i.e., the board) and performing simple tests. The idea is to get you started on your programming.

To aid in debugging, the first line of the game files will be the dimensions of the board. Hint: while I was developing my code to implement the game, I created several tiny game boards of 1x4 and 4x1.

 

Uninformed Search Code

You need to implement two algorithms: breadth first search and iterative deepening search. I recommend following the algorithms in the Russell and Norvig text. The reference implementation follows them fairly carefully. You should uncomment the RushHour function from the basics file and fill in the parts that will call the two different search algorithms. Your code should return a solution consisting of a tuple of a path and the number of nodes that were expanded (checked) during search. The number of nodes is expected to be longer than the path in most cases.

An example of my code running looks as follows. Note: I have added an extra print ("new state") to show which states are being explored (to show how the number explored is being computed); you should not have these lines in the output of your code.

In [5]: RushHour('test2.text', 'bfs', 0)

new state: [[2, 4], 3]

new state: [[2, 5], 2]

new state: [[4, 5], 0]

new state: [[2, 3], 3]

new state: [[2, 5], 2]

new state: [[4, 5], 0]

new state: [[2, 3], 1]

Out[5]: ([[[2, 5], 2], [[2, 3], 1], ['exit']], 8)

In [6]: RushHour('test2.text', 'ids', 3)

new state: [[2, 4], 3]

new state: [[2, 5], 2]

new state: [[4, 5], 0]

new state: [[2, 4], 3]

new state: [[2, 2], 1]

new state: [[2, 3], 3]

new state: [[2, 5], 2]

new state: [[4, 5], 0]

new state: [[2, 5], 2]

new state: [[2, 3], 1]

Out[6]: ([[[2, 5], 2], [[2, 3], 1], ['exit']], 10)

Hint: Make sure you keep track of what states have already been visited or you will create code with infinite loops.

To expedite our testing of your code, we need you to implement your search such that the positions are checked like you would read a book (iterate over the rows and for each row iterate over the columns). The possible actions are considered in the order of their numbers: 0 through 3. So in the test2 initial state, your code should find 3 possible moves: move goal left, move truck down and move truck up; IN THAT ORDER, as their positions are [2,4], [2, 5] and [4, 5], respectively.

Part 2: Discussion [20 pts]

You need to write short essays (~1 page) in answer to the following:

  1. Compare and contrast your program's performance. How did the run time (measured in number of nodes expanded) and length of solution path compare for breadth-first search and iterative deepening search? How did it vary over the cases that you tested? What is the most complicated case that you were able to solve?
  2. Analyze the search spaces for these problems. Start by showing a legal state and an illegal state for Test 3. How many legal states are there in the state space for test cases 1, 2 and 3? Give exact values for test1 and test2. For test3, you may give an estimate, along with a discussion of whether your estimate is an upper or lower bound, and how one might compute an exact number of legal states.

What to Hand In

  1. A python file called rush-hour.py which includes all the python code needed to run your program.
  2. A text file showing runs of test1.text, test2.text and test3.text with solutions.
  3. A pdf file with your answers to part 2.