130 likes | 148 Views
Learn how to use recursion and look-ahead techniques to solve the Eight Queens Problem, where 8 queens need to be placed on a chessboard without being able to take each other. We will explore the implementation of the solution using data structures and the MiniMax method.
E N D
Data StructuresCSCI 132, Spring 2019Lecture 18Recursion and Look-Ahead
Recall The Eight Queens Problem Can we place 8 queens on a chessboard so that none can take another? (I.e. none share a row, column or diagonal)? Q
Recall 8 Queens solution void solve_from(Queens &configuration) { if (configuration.is_solved( )) { configuration.print( ); } else { for (int col = 0; col < configuration.board_size; col++) { if (configuration.unguarded(col)) { configuration.insert(col); solve_from(configuration); // Recursively continue to add queens. configuration.remove(col); } } } }
Print only one solution bool solve_from(Queens &configuration) //return true if solved { if (configuration.is_solved( )) { configuration.print( ); return true; } else { bool solved = false; for (int col = 0; !solved && col < configuration.board_size; col++) { if (configuration.unguarded(col)) { configuration.insert(col); solved = solve_from(configuration); configuration.remove(col); } } return solved; } }
Looking ahead recursively LookAhead() for each possible move make move answer = lookAhead() undo move keep track of best answer return best answer
Example: Tic Tac Toe class Move { //Class to represent a move for tic tac toe public: Move( ); Move( int r, int c); int row; int col; }; Move::Move( ) { row = 3; col = 3; } Move::Move(int r, int c) { row = r; col = c; }
The Playing Board class Board { public: Board( ); bool done( ) const; //true if game done void print( ) const; void instructions( ) const; bool better(int value, int old_value) const; //true if value better than old void play(Move try_it); //play given move int worst_case( ) const; //worst possible case value int evaluate( ) const; //how good is configuration? int legal_moves(Stack &moves) const; //List of legal moves private: int squares[3][3]; //0 => unoccupied, 1=> player 1, 2=>player2 int moves_done; int the_winner( ) const; };
Some Board Methods void Board :: play(Move try_it) { squares[try_it.row][try_it.col] = moves_done%2 + 1; moves_done++; } bool Board :: done( ) const { return ( moves_done == 9) || (the_winner( ) > 0); } int Board :: evaluate( ) const { int winner = the_winner( ); if (winner == 1) { return 10 - moves_done; } else if (winner == 2) { return moves_done - 10; } else { return 0; } }
Looking Ahead int look_ahead(const Board &game, int depth, Move &recommended) { if (game.done( ) || depth == 0) { return game.evaluate( ); } else { Stack moves; game.legal_moves(moves); int value, best_value = game.worst_case( ); while (!moves.empty( )) { Move try_it, reply; moves.top(try_it); //get next move Board new_game = game; //make copy of board new_game.play(try_it); //try next move value = look_ahead(new_game, depth - 1, reply); //recursively look ahead if (game.better(value, best_value)) { best_value = value; //value is new best value recommended = try_it; //recommend this move } moves.pop( ); //pop it off the stack } return best_value; //return best value found } }