Presentation is loading. Please wait.

Presentation is loading. Please wait.

Data Structures Chapter 5 Recursion Andreas Savva.

Similar presentations


Presentation on theme: "Data Structures Chapter 5 Recursion Andreas Savva."— Presentation transcript:

1 Data Structures Chapter 5 Recursion Andreas Savva

2 2 Stack Frames for Subprograms DD BCCCDDD AAAAAAADDDDD MMMMMMMMMMMMMMM Tree of Subprogram Calls M AD BC D D D Start Finish Time

3 3 Tree-Diagram Definitions The circles in a tree diagram are called vertices or nodes. The circles in a tree diagram are called vertices or nodes. The top of the tree is called its root. The top of the tree is called its root. The vertices immediately below a given vertex are called the children of that vertex. The vertices immediately below a given vertex are called the children of that vertex. The (unique) vertex immediately above a given vertex is called its parent. (The root is the only vertex in the tree that has no parent) The (unique) vertex immediately above a given vertex is called its parent. (The root is the only vertex in the tree that has no parent) The line connecting two vertices is called a branch. The line connecting two vertices is called a branch. Siblings are vertices with the same parent. Siblings are vertices with the same parent. A vertex with no children is called a leaf or an external vertex. A vertex with no children is called a leaf or an external vertex. Two branches of a tree are adjacent if the lower vertex of the first branch is the upper vertex of the second. A sequence of branches in which each is adjacent to its successor is called a path. Two branches of a tree are adjacent if the lower vertex of the first branch is the upper vertex of the second. A sequence of branches in which each is adjacent to its successor is called a path. The height of a tree is the number of vertices on a longest possible path from the root to a leaf. (Hence a tree containing only one vertex has height 1.) The height of a tree is the number of vertices on a longest possible path from the root to a leaf. (Hence a tree containing only one vertex has height 1.) The depth or level of a vertex is the number of branches on a path from the root to the vertex. The depth or level of a vertex is the number of branches on a path from the root to the vertex.

4 4 Every recursive process consists of two parts: A base case that is processed without recursion. A base case that is processed without recursion. A general method that reduces a particular case to one or more of the smaller cases, making progress towards eventually reducing the problem all the way to the base case. A general method that reduces a particular case to one or more of the smaller cases, making progress towards eventually reducing the problem all the way to the base case. Recursion

5 5 Mathematical Recursion Base case: f(0) = 0 Base case: f(0) = 0 Recursion: f(n) = n + f(n-1) for n > 0 Recursion: f(n) = n + f(n-1) for n > 0 f(5)= 5 + f(4) = f(3) = f(2) = f(1) = f(0) = = 15

6 6 A Recursive Definition - Factorial int factorial(int n) // Pre: n is a nonnegative integer // Post: Return the value of the factorial of n { if (n == 0) return 1; else return n * factorial(n - 1); }

7 7MemoryFactorial(4) int factorial(int n) { if (n == 0) return 1; else return n * factorial(n-1); } void main() { cout << factorial(4); }main() 24 f(4)n4 f(3)n3 f(2)n2 f(1)n1 f(0)n0 = 4 * f(3) = 3 * f(2) = 2 * f(1) = 1* f(0) = 1 1 = 1 * 1 = 1 = 2 * 1 = 2 2 = 3 * 2 = 6 6 = 4 * 6 = 24 24

8 8Memory Recursive Procedure void Display() { int n; cin >> n; if (n != -999) { Display(); cout << n << ; } void main() { Display(); } main Display n1 n3 n12 n8 n

9 9Memory Recursive Procedure #include void display(int n, char c) { if (n != 0) { cout << c; display(n-1,c+1); } void main() { display(4,A); } mainABCD displayn4cA n3cB n2cC n1cD n0cE

10 10 Exercise #include void display(int n, int m, char c) { if (n==1 && m==1) cout << c; else if (n > 1) { cout << endl; display(n-1,m,c); } else if (m > 1) { cout << ; display(n,m-1,c); } void main() { display(3,4,7); }

11 11 Function Power – n r Base case: Key step: int power(int n, int r) // Pre: r is a nonnegative integer // Post: Return the value of n to the power r { if (r == 0) return 1; else return n * power(n, r - 1); }

12 12Memory Function Power #include int power(int n, int r) { if (r == 0) return 1; else return n * power(n,r-1); } void main() { cout << power(2,4); } main() 16 f(2,4)n2r4 f(2,3)n2r3 f(2,2)n2r2 f(2,1)n2r1 f(2,0)n2r0 = 2 * f(2,3) = 2 * f(2,2) = 2 * f(2,1) = 2 * f(2,0) = 1 1 = 2 * 1 = 2 2 = 2 * 2 = 4 4 = 2 * 4 = 8 8 = 2 * 8 = 16 16

13 13 Divide and Conquer: The Towers of Hanoi Developed in the 19 th century. Developed in the 19 th century. The problem: The problem: At the creation of the world, the priests in the temple of Brahma were given a brass platform on which were 3 diamond needles. On the first needle there were stacked 64 golden disks, each one slightly smaller than the one under it. The priests were assigned the task of moving all the golden disks from the first needle to the third, subject to the conditions that: only one disk can be moved at a time, and only one disk can be moved at a time, and no disk is allowed to be placed on top of a smaller disk. no disk is allowed to be placed on top of a smaller disk. The priest were told that when they had finished moving the 64 disks, it would be the end of the world.

14 14 The Towers of Hanoi 1 23 move(64,1,3,2)means Move 64 disks from tower 1 to tower 3 using tower 2 as temporary

15 15 The Solution move(63,1,2,3) // Move 63 disks from tower 1 to tower 2 cout << Move disk 64 from tower 1 to tower 3 << endl; move(63,2,3,1) // Move 63 disks from tower 2 to tower

16 16 disks = The Program const int disks = 64; void move( int count, int start, int finish, int temp) { if (count > 0) { move(count – 1, start, temp, finish); cout << Move disk << count << from << start << to << finish << endl; move(count – 1, temp, finish, start); } int main() { move(disks, 1, 3, 2); return 0; }

17 17 Analysis (disks = 3) Move disk 1 from tower 1 to tower 3 Move disk 2 from tower 1 to tower 2 Move disk 1 from tower 3 to tower 2 Move disk 3 from tower 1 to tower 3 Move disk 1 from tower 2 to tower 1 Move disk 2 from tower 2 to tower 3 Move disk 1 from tower 1 to tower 3 move(3,1,3,2) move(2,1,2,3) move(1,1,3,2) move(0,1,2,3) move(0,2,3,1) move(1,3,2,1) move(0,3,1,2)move(0,1,2,3) move(2,2,3,1) move(1,2,1,3) move(0,2,3,1) move(0,3,1,2) move(1,1,3,2) move(0,1,2,3) move(0,2,3,1) move(3,1,3,2) move(2,1,2,3) move(2,2,3,1) move(1,1,3,2) move(1,3,2,1 ) move(1,2,1,3) move(1,1,3,2) move(0,1,2,3) move(0,2,3,1) move(0,3,1,2) move(0,1,2,3) move(0,2,3,1) move(0,3,1,2) move(0,1,2,3) move(0,2,3,1)

18 18 No of Moving Disks (disks=64) No of recursions: No of recursions: … = … = 2 65 – 1 = 36,893,488,147,419,103,231 No of moving disks: No of moving disks: Excluding the calls with count == 0, which do nothing: Excluding the calls with count == 0, which do nothing: … = 2 64 – 1 = 18,446,744,073,709,551,615 No of Seconds in a year: No of Seconds in a year: 32,000,000 32,000,000 No of years the priests need to solve the problem if they move one disk in every second: No of years the priests need to solve the problem if they move one disk in every second: 576,460,752, ,460,752,303

19 19 Designing Recursive Algorithms Find the key step. Begin by asking yourself, How can this problem be divided into parts? Find the key step. Begin by asking yourself, How can this problem be divided into parts? Find a stopping rule. This stopping rule is usually the small, special case that is trivial or easy to handle without recursion. Find a stopping rule. This stopping rule is usually the small, special case that is trivial or easy to handle without recursion. Combine the stopping rule and the key step, using an if- statement to select between them. Combine the stopping rule and the key step, using an if- statement to select between them. Check termination. Verify that the recursion will always terminate. Be sure that your algorithm correctly handles extreme cases. Check termination. Verify that the recursion will always terminate. Be sure that your algorithm correctly handles extreme cases. Draw a recursion tree. The height of the tree is closely related to the amount of memory that the program will require, and the total size of the tree reflects the number of times the key step will be done. Draw a recursion tree. The height of the tree is closely related to the amount of memory that the program will require, and the total size of the tree reflects the number of times the key step will be done.

20 20 When not to use Recursion Consider the following two functions for calculating factorial: Recursive: int factorial(int n) { if (n == 0) return 1; else return n * factorial(n 1); }Non-recursive: int factorial(int n) { int count, product = 1; for (count = 1; count <= n; count++) product *= count; return product; }

21 21 factorial(5) - Recursive Example: factorial(5)= 5 * factorial(4) = 5 * (4 * factorial(3)) = 5 * (4 * (3 * factorial(2))) = 5 * (4 * (3 * (2 * factorial(1)))) = 5 * (4 * (3 * (2 * (1 * factorial(0))))) = 5 * (4 * (3 * (2 * (1 * 1)))) = 5 * (4 * (3 * (2 * 1))) = 5 * (4 * (3 * 2)) = 5 * (4 * 6) = 5 * 24 = 120

22 22 Question Which of the two functions uses less storage space? Which of the two functions uses less storage space? The recursive one has one variable The recursive one has one variable The iterative one has three variables The iterative one has three variables But actually the recursive program will set up a stack and fill it in with n+1 numbers: But actually the recursive program will set up a stack and fill it in with n+1 numbers: n, n-1, n-2, …, 2, 1, 0 Thus, the recursive function keeps more storage, and it will take more time as well, since it must store and retrieve all the numbers as well as multiply them. Thus, the recursive function keeps more storage, and it will take more time as well, since it must store and retrieve all the numbers as well as multiply them.

23 23 Fibonacci recursive function Definition: Fibonacci numbers are denoted by the recurrence relation Fibonacci numbers are denoted by the recurrence relation F 0 = 0, F 1 = 1, F n = F n1 + F n2 for n 2 int fibonacci(int n) { if (n == 0) return 0; else if (n == 1) return 1; else return fibonacci(n-1) + fibonacci(n-2); } 0 th 1 st 2 nd 3 rd 4 th 5 th 6 th 7 th 8 th … … term term

24 24 fibonacci(7) No of calculations of F(n) grows exponentially with n

25 25 Fibonacci iterative function int fibonacci(int n) { } No of calculations of F(n) increases linearly in n

26 26 Comparison between Recursion and Iteration RecursionIteration Readability Duplicate tasks

27 27 Towers of Hanoi without tail recursion const int disks = 64; void move( int count, int start, int finish, int temp) { int swap; // temporary storage to swap towers while (count > 0) { // Replace the if statement with a loop. move(count – 1, start, temp, finish); // first recursive call cout << Move disk << count << from << start << to << finish << endl; count--; // Change parameters to mimic the second recursive call. swap = start ; start = temp ; temp = swap ; } int main() { move(disks, 1, 3, 2); return 0; }

28 28 Towers of Hanoi (disks=64) With one recursive call: With one recursive call: No of recursions = … + 1 = 2080 No of recursions = … + 1 = 2080 No of variables = No of Recursions * 5 = 10,400 No of variables = No of Recursions * 5 = 10,400 No of variables needed at one time = tree height * 5 No of variables needed at one time = tree height * 5 = 64 * 5 = 320 With two recursive calls: With two recursive calls: No of recursions = 36,893,488,147,419,103,231 No of recursions = 36,893,488,147,419,103,231 No of variables = No of Recursions * 4 No of variables = No of Recursions * 4 = 147,573,952,589,676,412,924 No of variables needed at one time = tree height * 4 No of variables needed at one time = tree height * 4 = 65 * 4 = 260

29 29 Exercise 1 What is the output of the following program? What is the output of the following program? #include using namespace std; void display(int n) { if (n != 0) { cout << n; display(n-1); cout << n; } void main() { display(5); }

30 30 Exercise 2 Write a recursive function Sum that will take an integer number n and it will return the summation of all the numbers between 1 and n. If n 0 the function should return zero. Write a recursive function Sum that will take an integer number n and it will return the summation of all the numbers between 1 and n. If n 0 the function should return zero. Examples: Sum(4) = = 10 Sum(4) = = 10 Sum(0) = 0 Sum(0) = 0 Sum(-4) = 0 Sum(-4) = 0 Write the same function without recursion. Write the same function without recursion.

31 31 Exercise 3 Write a recursive function Summation that will take two integer numbers n and m and it will return the summation of all the numbers between n and m. If n > m the function should return zero. Write a recursive function Summation that will take two integer numbers n and m and it will return the summation of all the numbers between n and m. If n > m the function should return zero. Examples: Summation(3, 7) = = 25 Summation(3, 7) = = 25 Summation(7, 2) = 0 Summation(7, 2) = 0 Summation(4,4) = 4 Summation(4,4) = 4 Summation(-3,1) = -5 Summation(-3,1) = -5 Write the same function without recursion. Write the same function without recursion.

32 32 Exercise 4 Write a recursive procedure Display that will take an integer number n and display all the numbers between 1 and n in reverse order. If n 0 it should not display anything. Write a recursive procedure Display that will take an integer number n and display all the numbers between 1 and n in reverse order. If n 0 it should not display anything. Examples: Display(5);will display: Display(5);will display: Display(3);will display: Display(3);will display: Write the same function without recursion. Write the same function without recursion.

33 33 Exercise 5 Write a recursive function Multiply that will take two integer numbers n and m and it will return the multiplication of all the numbers between n and m. If n > m the function should return zero. Write a recursive function Multiply that will take two integer numbers n and m and it will return the multiplication of all the numbers between n and m. If n > m the function should return zero. Examples: Multiply(2, 5) = 2 × 3 × 4 × 5 = 120 Multiply(2, 5) = 2 × 3 × 4 × 5 = 120 Multiply(7, 2) = 0 Multiply(7, 2) = 0 Multiply(4, 4) = 4 Multiply(4, 4) = 4 Multiply(-3, 1) = 0 Multiply(-3, 1) = 0 Write the same function without recursion. Write the same function without recursion.

34 34 Exercise 6 Write a recursive function SumEven that will take two integer numbers n and m and it will return the summation of all the even numbers between n and m. If n > m the function should return zero. Write a recursive function SumEven that will take two integer numbers n and m and it will return the summation of all the even numbers between n and m. If n > m the function should return zero. Examples: SumEven(3, 10) = = 28 SumEven(3, 10) = = 28 SumEven(7, 2) = 0 SumEven(7, 2) = 0 SumEven(4,4) = 4 SumEven(4,4) = 4 SumEven(3,3) = 0 SumEven(3,3) = 0 Write the same function without recursion. Write the same function without recursion.

35 35 Exercise 7 The greatest common divisor (gcd) of two positive integers is the largest integer that divides both of them. i.e. The greatest common divisor (gcd) of two positive integers is the largest integer that divides both of them. i.e. gcd(8,12) = 4 gcd(9,18) = 9 gcd(16,25) = 1 a) Write a non-recursive function, gcd(x,y) that searches through the positive integers until it finds the largest integer dividing both x and y. b) Write a recursive function, gcd(x,y) that implements Euclids algorithm: if y = 0, then the gcd of x and y is x; otherwise the gcd of x and y is the same as the gcd of y and x % y. c) Rewrite the function of part (b) into iterative form. d) Discuss the advantages and disadvantages of each of these methods.

36 36 Exercise 8 The binomial coefficients can be defined by the following recurrence relation, which is the idea of Pascals triangle. The binomial coefficients can be defined by the following recurrence relation, which is the idea of Pascals triangle. C(n, 0) = 1 C(n, n) = 1 for n 0 C(n, k) = C(n-1, k) + C(n-1, k-1) for n > k > 0

37 37 Exercise 8 (continue) a) Write a recursive function to generate C(n, k) by the formula. b) Draw the recursion tree for calculating C(6, 4). c) Use the square array with n indicating the row and k the column, and write a non-recursive program to generate Pascals triangle in the lower left half of the array, that is, in the entries for which k n. d) Write a non recursive program that uses neither an array nor a stack to calculate C(n, k) for arbitrary n k 0. e) Determine the approximate space and time requirements for each of the algorithms devised in (a), (c), and (d).

38 38 Exercise 9 What is the output of the following program? What is the output of the following program? #include using namespace std; void display(int n) { if (n > 0) { display(n-1); cout << n; display(n-1); } void main() { display(4); }

39 39 Exercise 10 What is the output of the following program? What is the output of the following program? #include using namespace std; void display(int n) { if (n > 0) { display(n-1); cout << n; } void main() { display(4); }

40 40 Exercise 11 What is the output of the following program? What is the output of the following program? #include using namespace std; void display(int n) { if (n > 0) { display(n-1); display(n-2); cout << n; } void main() { display(4); }

41 41 Exercise 12 What is the output of the following program? What is the output of the following program? #include using namespace std; void display(int n) { if (n > 0) { display(n-1); display(n-2); cout << n; display(n-1); } void main() { display(4); }

42 Exercise 13 An integer is printed with commas inserted every 3 positions from the right. That is, to print the number as 12,345,678, the 678 cannot be printed until after the preceding part of the number is printed. Write a recursive function PrintWithCommas that will print its long integer parameter with commas inserted properly. An integer is printed with commas inserted every 3 positions from the right. That is, to print the number as 12,345,678, the 678 cannot be printed until after the preceding part of the number is printed. Write a recursive function PrintWithCommas that will print its long integer parameter with commas inserted properly. You must be careful with leading zeros to ensure, for example, that the number 12,003 is printed properly. You must be careful with leading zeros to ensure, for example, that the number 12,003 is printed properly. 42

43 43 Backtracking – The Eight-Queen Puzzle Problem: How to place eight queens on a chessboard so that no queen can take another. Problem: How to place eight queens on a chessboard so that no queen can take another. Even the great C. F. Gauss did not obtain a complete solution when he considered it in Even the great C. F. Gauss did not obtain a complete solution when he considered it in 1850.Solutions

44 44 Algorithm A more complex recursive application A more complex recursive application The choice of data structure can affect a recursive program The choice of data structure can affect a recursive program Example: 4 Queens (4 x 4 Board)

45 45 Analysis of Backtracking 8 Queens Check all the cells Check all the cells Amount of work = = 4,426,165,368 Amount of work = = 4,426,165,368 Only one queen in each row Only one queen in each row Amount of work = … = 8 8 = 16,777,216 Amount of work = … = 8 8 = 16,777,216 Only one queen in each column Only one queen in each column Amount of work = … = 8! = 40,320 Amount of work = … = 8! = 40, times

46 46 The Main Program void main() { int board_size; cout << What is the size of the board? ; cin >> board_size; if (board_size max_board) cout << The number must be between 1 and << max_board << endl; else { Queens configuration(board_size); solve(configuration) ; }

47 47 The Recursion void solve(Queens &configuration) { if (configuration.is_solved()) { confiquration.print(); cout << endl; } else for ( int col = 0; col < configuration.board_size; col++) if (configuration.unguarded(col)) { configuration.insert(col); solve (configuration); // Recursively continue to add queens configuration.remove(col); }

48 48 The Queens class const max_board = 30; class Queens { public : Queens( int size); bool is_solved() const ; void print() const ; bool unguarded( int col) const ; void insert( int col); void remove( int col); int board_size; private : int count; // current number of queens = first unoccupied row bool queen_square[max_board][max_board]; }

49 49 The Constructor Queens::Queens( int size) { board_size = size; count = 0; for ( int row = 0; row < board_size; row++) for ( int col = 0; col < board_size; col++) queen_square[row][col] = false ; }

50 50 Is_Solved & Print bool Queens::is_solved() const { return count == board_size; } void Queens::print() const { for ( int row = 0; row < board_size; row++) { for ( int col = 0; col < board_size; col++) if (queen_square[row][col]) cout << Q; else cout << +; cout << endl; } +Q++ +++Q Q+++ ++Q+

51 51 Insert & Remove void Queens::insert( int col) { queen_square[count++][col] = true ; } void Queens::remove( int col) { queen_square[--count][col] = false ; }

52 52 Unguarded

53 53 Unguarded bool Queens::unguarted( int col) const { int i; bool ok = true; for (i = 0; ok && i < count; i++) ok = !queen_square[i][col]; // check upper part of column for (i = 1; ok && count – i >= 0 && col – i >= 0; i++) ok = !queen_square[count – i][col – i]; // check upper-left diagonal for (i = 1; ok && count – i >= 0 && col + i < board_size; i++) ok = !queen_square[count – i][col + i]; // check upper-right diagonal return ok; }

54 54 Review and Refinement Size Number of solutions ,68014,20073,712 Time (seconds) Time per solution (ms.)

55 55 The Revised Queens class const max_board = 30; class Queens { public : Queens( int size); bool is_solved() const ; void print() const ; bool unguarded( int col) const ; void insert( int col); void remove( int col); int board_size; private : int count; bool col_free[max_board]; bool upwart_free[2 * max_board – 1]; bool downward_free[2 * max_board – 1]; int queen_in_row[max_board]; // column number of queen in each row }

56 56 The Constructor Queens::Queens( int size) { int i; board_size = size; count = 0; for (i = 0; i < board_size; i++) col_free[i] = true ; for (i = 0; i < (2 * board_size – 1); i++) upward_free[i] = downward_free[i] = true ; }

57 57 Insert void Queens::insert( int col) { queen_in_row[count] = col; col_free[col] = false ; upward_free[count + col] = false ; downward_free[count – col + board_size – 1] = false ; count++; }

58 58 Remove void Queens::remove( int col) { count--; col_free[col] = true ; upward_free[count + col] = true ; downward_free[count – col + board_size – 1] = true ; }

59 59 Unguarded bool Queens::unguarted( int col) const { return col_free[col] && upward_free[count + col] && downward_free[count – col + board_size – 1]; } Homework: is_solved() print()

60 60 Review and Refinement Size Number of solutions ,68014,20073,712 Time (seconds) Time per solution (ms.) Size Number of solutions ,68014,20073,712 Time (seconds) Time per solution (ms.) First program: Second program:

61 61 Artificial Intelligence Look-ahead in Games Game-tree (two players) Game-tree (two players) Even levels denote the legal moves of the first player (root is at level 0) Even levels denote the legal moves of the first player (root is at level 0) Odd levels denote the legal moves of the second player Odd levels denote the legal moves of the second player Example: The game of Eight: Example: The game of Eight: The first player chooses one of the numbers 1, 2, or 3. At each later turn the appropriate player chooses one of 1, 2, or 3, but the number chosen by the previous player is not allowed. The first player chooses one of the numbers 1, 2, or 3. At each later turn the appropriate player chooses one of 1, 2, or 3, but the number chosen by the previous player is not allowed. A running sum of the numbers chosen is kept, and if a player brings this sum to exactly eight, then the player wins. A running sum of the numbers chosen is kept, and if a player brings this sum to exactly eight, then the player wins. If the player takes the sum over eight, then the other player wins. If the player takes the sum over eight, then the other player wins.

62 62 Tree for the game of Eight 1 9 F 10 F 9 S F 9 S 12 9 S 10 S 8 S F 10 S 8 S F 3 9 S 10 S ST 2 ND

63 63 Evaluation Function Examine the current situation and return a value assessing its benefits. Examine the current situation and return a value assessing its benefits. Usually large integers reflect favorable situations for the first player, and small (or more negative) show an advantage for the second player. Usually large integers reflect favorable situations for the first player, and small (or more negative) show an advantage for the second player.

64 64 2 F The Minimax Method 1 1 F 1 F -2 S F -2 S S -2 S -3 S S -3 S F 3 -2 S -2 S ST 2 ND Evaluation function 1 st win +ve1 st win +ve 2 nd win -ve2 nd win -ve The move

65 65 The Minimax Method ST (max) 2 ND (min) Should play

66 66 Tic-Tac-Toe

67 67 The Board class Board { public: Board(); bool done() const; void print() const; void Instructions() const; bool better(int value,int old_value) const; void play(Move try_it); int worst_case() const; int evaluate() const; int legal_moves(Stack &moves) const; void operator = (const Board &original); int the_winner() const; private: int squares[3][3]; int moves_done; }; class Move { public: Move(int r, int c); int row; int col; }; Move::Move(int r, int c) { row = r; col = c; }

68 68 Data Structure 0 – Empty 0 – Empty 1 – Player 1 1 – Player 1 2 – Player 2 2 – Player 2 moves_done = 6 moves_done =

69 69 Board methods Board::Board() { for (int i=0; i<3; i++) for (int j=0; j<3; j++) squares[i][j] = 0; moves_done = 0; } void Board::play(Move try_it) { squares[try_it.row][try_it.col] = moves_done % 2 + 1; moves_done++; } bool Board::better(int a, int b) const { if (moves_done % 2 == 0) return a>=b; else return a<=b; } int Board::worst_case() const { if (moves_done % 2 == 0) return -10; else return 10; } Player 1 always starts first

70 70 int Board::the_winner() const { int i; for(i = 0; i < MaxBoard; i++) if (squares[i][0] && squares[i][0] == squares[i][1] && squares[i][0] == squares[i][2]) return squares[i][0]; for(i = 0; i < MaxBoard; i++) if (squares[0][i] && squares[0][i] == squares[1][i] && squares[0][i] == squares[2][i]) return squares[0][i]; if (squares[0][0] && squares[0][0] == squares[1][1] && squares[0][0] == squares[2][2]) return squares[0][0]; if (squares[0][2] && squares[0][2] == squares[1][1] && squares[2][0] == squares[0][2]) return squares[0][2]; return 0; }

71 71 int Board::legal_moves(Stack &moves) const { int count = 0; while(!moves.empty()) moves.pop(); for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) if (squares[i][j] == 0) { Move can_play(i,j); moves.push(can_play); count++; } return count; } 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; } void Board::print() const { cout << "Move " << moves_done << endl; for (int i=0; i<3; i++) { for (int j=0; j<3; j++) cout << squares[i][j]; cout << endl; } void Board::operator = (const Board &original) { for (int i=0;i<3;i++) for (int j=0;j<3;j++) squares[i][j] = original.squares[i][j]; moves_done = original.moves_done; }

72 72 Look Ahead int look_ahead(const Board &game, int depth, Move &recommented) { 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); Board new_game = game; new_game.play(try_it); value = look_ahead(new_game,depth - 1, reply); if (game.better(value,best_value)) { best_value = value; recommented = try_it; } moves.pop(); } return best_value; }

73 73 The main program void main() { Board game; int depth = 5; Move recomented; int count = 0; while (!game.done()) { if (count % 2 == 0) { cout << "Enter a Move: "; cin >> recomented.row >> recomented.col; game.play(recomented); } else { look_ahead(game,depth,recomented); game.play(recomented); } count++; game.print(); } if (game.the_winner() == 1) cout << "You Won" << endl; else if (game.the_winner()==2) cout << "You Lost" << endl; else cout << It is a Draw" << endl; } Player 1 is a human player Player 2 is the computer


Download ppt "Data Structures Chapter 5 Recursion Andreas Savva."

Similar presentations


Ads by Google