In this session, we'll use the techniques we have explored in the previous sessions in a larger combinatorial search example. Before we do so, we need to introduce one more collection type, sets. Sets are another basic abstraction in the Scala collection. A set is written analogously to a sequence. We just write val fruit equals set of apple, banana, pear, or here we have the range (1-6).toSet that would give us a set of the numbers 1-6. Most operations on sequences are also available on sets. We can map sets, s.map(_ plus 2), would add two to each element of s, giving you the set 3-8. Fruit filter starts with app, that would give you the set of fruits that consists just of apple, and s.nonEmpty would return true. Here are the principal differences between sets and sequences. There are three overall. The first difference is that sets are unordered. The elements of a set do not have a predefined order in which they appear in the set. If you print out the elements of a set, you do not know a priori which element will come first. The second difference is that sets don't have duplicate elements. For instance, if we take the set of numbers 1-6 and we map it with the division by two operation, and we get a set of numbers 1-3 and each number appears only once in that set, even though six and five both would map by division of two to three, but you don't have a duplicated three, you have a single one here. The third difference is that the fundamental operation on sets is contains. So s.contains(5) would give you true. Now, let's get to the combinatorial search problem that we want to tackle. The problem is the N-Queens problem. The eighth queens problem is to place eight queens on a chessboard so that no queen is threatened by another. In other words, there can't be two queens in the same row, column, or diagonal. We now develop a solution for a chessboard of any size, not just eight. I'll show you the example for a chessboard of size four. That's the chessboard. To find the solution you can place a queen here, and a queen here, and a queen here, and a queen here. Here you see each queen is in its own column, in its own row, and none of them checks the other by diagonal. This is not the only solution, you can find other solutions by rotating that image or taking the mirror image according to one of the axes. It turns out that for larger boards, there are many, many more solutions, so the number of solutions grows as the board grows. Let's now develop a solution for a chessboard of any size. One way to solve the problem is to place a queen on each row. We start with the first row when the queen is arbitrary. Then we go to the next row and we've picked a column there where the queen is not yet in check with the previous queen, and so on and so forth. Generally, once we have placed k minus 1 queens, you must place the kth queen in a column where it's not in check with any other queen on the board. Of course, it's possible that one can get into a dead end, that one ends up in a row where no position of a queen would be legal. In this case, you have to backtrack and change some of the previous queens so that a place becomes free in that row. For instance, if we had placed the first queen here instead of one to the left, then it would have turned out that there is no way to complete the puzzle. One would have to backtrack all the way to the first green and say no, that we can't place it here, we have to place it one field to the right. We can solve this problem with a recursive algorithm. The idea is, let's suppose that we have already generated all the solutions consisting of placing k minus 1 queens on a board of size n. Each solution is represented by a list of length k minus 1 that contains the numbers of the columns between zero and n minus one of the queens that have been placed. The column number of the queen in the k minus first row, so the last queen that was placed, comes first in the list, followed by the column number of the queen in row k minus 2 and so on. The last queen in the list is the queen on row number 1. The solution set is thus represented as a set of lists with one element for each solution. All solutions are a set and each solution is a list of column numbers. Now, to place the kth queen, we generate all possible extensions of each solution preceded by a new queen. Here's the implementation, we have this method def queens, it takes the size of the board n, and it simply consists of a col to place queens n. Place queens takes a parameter k, which says how many queens are still to be put on the board and it returns a set of list of integers. As discussed, a set of solutions is solution is a list of int. So if k equals 0, that means we don't need to place any queens, so we can respond with the empty list that's the solution and we return with a set that consists of just the solution. If k is not zero, then we recursively call place queens of k minus 1. So we have a problem that is one simpler than before, and we let queens range over the results, so place queens k minus 1 is a set of solutions. Now, each queens here is a solution, so it's a vector of column numbers. Now, the task is to place the kth queen, so we do that by letting col range from zero until n. That's a possible columns of the board where we could place the queen and we ask whether the queen would be safe in this column relative to the queens that already have been placed. If that's the case, we yield the column, the new column, preceding the queens that have been placed. That's it. It's actually surprisingly simple and concise as a solution for this problem. Well, it's not quite the solution yet, we still have to write the function isSafe. So isSafe takes a column where we want to put the new queen and a list of ints, which is the column numbers of the queens that have been placed so far, and it should test whether a queen placed in that column is secure amongst the other placed queens. It's assumed that the new queen is placed in the next available row after the other placed queens, in other words, in row queens.length. Try to come up with an implementation of isSafe as an exercise. Here's a possible solution, isSafe of column versus queens is that the column is not in check with a distance of one to the list of queens, which uses auxiliary method checks that takes an additional parameter delta. It takes a column number where the new queen is put, the queens that remain to be checked, and delta which is the distance of the row where the new queen should be placed and the last row, the first queen of the list here was placed. Initially, delta is one because we follow the queens directly by the column we place. The checks method now is implemented like this. It says, well, if the queens is empty, then the result is false, the queen is not in check. If the queen is non-empty, so let's say we have a queen column and some others, then if the queen column is the same as the column, that's a check, that's a vertical check. Or the queen column minus the column absolute value is the same as the distance delta here, that's a diagonal check. Or it might be in check with some of the remaining queens, so that's a recursive call, checks with the column delta plus 1 and the others.