CS 371 - Introduction to Artificial Intelligence
Homework #1 |
0. Reading, Starter Code, Peg Solitaire, and the Buckets Problem: Read R&N Chapter 3 through section 3.4.5. Download and study the supplied starter code (documentation). Read more about the Peg Solitaire and Buckets problems here. Give special attention to the implementation of PegSolitaireNode and BucketsNode, as these will serve as models for a SearchNode you will extend later.
1. Breadth-First Search: Complete the implementation of the Breadth-First Search (BFS) class BreadthFirstSearcher by filling in code after the given comments (in-class). Node children should enter the queue in the same order that they appear in the list returned by the expand method. With this and other search algorithms to come, test your implementation with both PegSolitaireNode and BucketsNode by uncommenting the appropriate lines in SearchTest.
2. Depth-First Search: Complete the implementation of the Depth-First Search (DFS) class DepthFirstSearcher by filling in code after the given comments (in-class). Node children should be pushed onto the stack in the same order that they appear in the list returned by the expand method.
3. Depth-Limited Search: Implement Depth-Limited Search (DLS) class DepthLimitedSearcher by modifying your DepthFirstSearcher to take an integer depth limit as the single contructor parameter, and not expanding/pushing nodes beyond the depth limit.
4. Iterative-Deepening Depth-First Search: Implement Iterative-Deepening Depth-First Search (IDDFS) class IterativeDeepeningDepthFirstSearcher by creating a new Searcher class extension that performs depth-limited searches to depth limits 1, 2, 3, etc. until successful. Remember that the node count of this Searcher is the sum of the node counts of all depth-limited searches performed.
5. Recursive Depth-First Search: In many applications of depth-first search, it is simpler to express it as a recursive algorithm. (Using a different model of a search node, this permits one to make/undo state changes easily.) Implement Search class extension RecursiveDepthFirstSearcher that performs a recursive depth-first search of each child in the order that they appear in the list returned by the expand method. Note that this implementation effectively visits a node's children in the reverse order that they would be visited in the iterative stack-based implementation of DepthFirstSearcher.
6. Designing a Reverse-Perfect-Shuffle Magic Trick: Implement class ReversePerfectShuffleNode according to this specification. Read the comments with great care to understand the specification of each Searcher method. In addition, you will add a main method that prints the results of a search, revealing the means to perform a card magic trick of my design. The printed output of the main method should simply be a sequence of printed states, one per line, from the initial state to the goal state.
ReversePerfectShuffleNode is a class modeling perfect reverse (a.k.a. anti-faro) in- and out-shuffles in order to find a means of working the four top cards into the 5th, 10th, 15th, and 20th positions. A perfect shuffle is one where the deck is cut perfectly in half and then "riffled" together alternating one card from each half like the teeth of a zipper before being pushed together. This is considered to be one of the most difficult sleights of hand in card magic, and it allows the performer to control the positions of all cards in the deck, rearranging the permutation in unexpected ways. There are two perfect shuffles that differ according to whether the first card down comes from the top or bottom half. A perfect out-shuffle leaves the top card on top, that is, outside the deck. A perfect in-shuffle leaves the top card at the second card, that is, inside the deck.
A reverse perfect shuffle is just the opposite. See Figure 3 from Magical Mathematics: The Mathematical Ideas That Animate Great Magic Tricks by Persi Diaconis and Ron Graham. After alternating cards are separated into two halves, one half is placed atop the other. While perfect shuffles are one of the most difficult sleights of hand, this simple process of alternate up- and down-jogging of cards can be performed by most anyone. As before, a reverse perfect out-shuffle leaves the top card on top, that is, outside the deck. A reverse perfect in-shuffle leaves the top card right after the middle of the deck, that is, inside the deck.
Here is an example of an integer sequence undergoing two subsequent shuffles:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51] After out-shuffle: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51] After subsequent in-shuffle: [2, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, 3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49]
Quiz/exam preview: While not required for this homework, look at the written exercises at http://cs.gettysburg.edu/~tneller/resources/ai-search/uninformed-java/index.html to get a sense of questions I commonly include on quizzes and exams.
Rubric: