CS440/ECE448 Fall 2022, Homework 2: A* Search

Due: Friday, September 30, 11:59pm

I. Overview

In this assignment you will be implementing the A* search algorithm for solving 3 different search problems - EightPuzzle, WordLadder, and GridSearch. Your single implementation of the algorithm will work for all 3 problems, by properly instantiating an AbstractState class for each of them. You will see both the power of A* as an algorithm that applies to arbitrary discrete state spaces, and the power of heuristics to speed up search.

II. Getting Started

To get started on this assignment, download the template code. The template contains the following files and directories:

Please ONLY submit search.py and state.py.

For each of the remaining parts of the assignment you will find TODOs in search.py and state.py where you need to write your own code. For example, for part III you will find TODOs marked # TODO(III). We’ve provided many comments and instructions in the code under those TODOs.

III. Implementing Best First Search (and WordLadder)

WordLadder: find a sequence of English words from some starting word (i.e., “head”) to some goal word (i.e., “tail”), where consecutive words differ by only one letter

There are 2 “TODO(III)” in search.py.

Your first task is to implement a generic best first search algorithm in the method best_first_search(starting_state) in search.py. Your implementation should:

Notice that the input to best_first_search is just a starting state. You may be wondering:

Now you should look at state.py, there are 3 “TODO(III)” in state.py. These questions should be answered by the comments in the code under those TODOs. You should first read through our AbstractState class, then look at an instantiation of this class called WordLadderState.

In order to test your search code we’ve provided almost all of WordLadderState. Once you’ve filled in the missing code, and implemented the search code, you should be able to test your algorithm. Make sure your algorithm works on all the provided tests before moving on to the next parts. If it works you will not have to touch it again!

Run best_first_search on all WordLadder problems:

python3 main.py --problem_type=WordLadder 

IV. EightPuzzle

EightPuzzle: find a sequence of tile moves that put each number in its final position (right) from some example starting position (left). You can only move a tile that is adjacent to the empty square into the empty square.

Now move on to EightPuzzleState, we’ve provided some but not all of the code you’ll need here. There are 4 “TODO(IV)” in state.py.

Run best_first_search on EightPuzzle problems (all puzzles with puzzle_len=N can be solved in N steps):

python3 main.py --problem_type=EightPuzzle --puzzle_len=5 

You can choose any puzzle length among [5, 10, 27].

Please add neighbors in this move order (a,b,c,d) to be consistent with our implementation. The manhattan heuristic for this example is: 3 (number of moves 1 is away from its goal location) + 1 + 2 + 2 + 2 + 3 + 3 + 2 (number of moves 8 is away from its goal location) = 18. This means this puzzle takes at least 18 moves to solve.
In grid search we find a path through a 2D maze from some starting location to a single goal location. Each state is a discrete (x,y) location in the maze, and the goal is an additional location in the maze. From any location you can transition to a neighboring location assuming there is no obstacle there (colored black). In the visualization above green indicates the end of the path and red indicates the beginning.

Finally we come to GridSearch.

Run the following to see mazes and navigate them yourself with the arrow keys:

python3 main.py --problem_type=GridSingle --human --maze_file=[path_to_maze_file in data/mazes/grid_single] 

Now you will need to implement the SingleGoalGridState class. If you would like to see how the maze is built navigate to maze.py, but otherwise we’ve provided you everything you need and instructions in state.py where you have 4 “TODO(V)” to complete. The heuristic we use for grid search is the manhattan distance from the current location to the goal.

You can test your code with:

python3 main.py --problem_type=GridSingle --maze_file=[path_to_maze_file in data/mazes/grid_single] 

If you would like to also visualize the resulting solution in PyGame add the --show_maze_vis flag.

Now we consider grid search problems with multiple goals that can be reached in any order

We now generalize single goal grid search to multi goal grid search. There are 5 “TODO(VI)” for you to complete in state.py.

Multiple goals requires a new heuristic. The one we use is the Minimum Spanning Tree (MST). Specifically, given a state and a set of goals, the heuristic cost for visiting all the goals is computed as follows:

We provide you with most of the code you need to compute this MST heuristic, you can call compute_mst_cost(self.goal, manhattan) to compute the cost of the minimum spanning tree for a set of goals. Note that because computing the mst takes some time, you should store the computed mst values in the cache we provide you.

You can test your code with:

python3 main.py --problem_type=GridMulti --maze_file=[path_to_maze_file in data/mazes/grid_multi]

You can also check backwards compatibility by running GridMulti on a maze file with only one goal.

VII Submission Instructions

Submit the main part of this assignment by uploading search.py and state.py to Gradescope.

Policies

You are expected to be familiar with the general policies on the course syllabus (e.g. academic integrity) and on the top-level MP page (e.g. code style). In particular, notice that this is an individual assignment.