SRINI DEVADAS: So today, we're going
to look at that classic puzzle.
It's called the eight queens puzzle,
and it's very easy to describe.
I'll write down the rules, if you happen not to know chess
and how a queen moves on a chess board, in a moment.
But before I get into that, I just
wanted to mention that the programming paradigms
that we're going to be looking at today are--
is, I should say the programming paradigm--
is one of exhaustive enumeration.
And what we want to do algorithmically
is to look at all possible cases,
all possible combinations, possibilities,
because we want to exhaust the space
to determine if there's a solution
to this particular instance of the problem or not.
And one of the problems, as I mentioned,
is the eight queen's problem.
But you could say, I'd like to solve a smaller
problem, the five queens problem or the three queens problem.
And you'd like, obviously, to be able to write code that
solves this generalized problem, where
you can vary the number of rows and columns on a board.
It's no longer a chessboard if it's not eight rows and eight
columns, but you can still obviously concoct
a puzzle associated with an arbitrary-sized board.
And then the other thing that we'll do
today is look at data structures,
and so this obviously is going to be a data structure that's
immediately clear from what I have
up there on the board, a matrix data structure
to solve the problem.
But can you do things more efficiently
with a different selection of a data structure?
All right?
So the eight queens problem simply
says, place eight queens on a chessboard--
and that implies immediately that it's eight by eight,
as I've drawn over there--
such that no queen attacks any other queen.
Now, if you had no background in solving this problem,
perhaps you knew chess, and you might think there's a solution.
You might think there's not.
I mean, a queen is pretty powerful.
This implies, because a queen can move horizontally.
It can move vertically.
It can move diagonally, back and forth, in both directions,
up and down, left and right, and I guess up and down diagonally.
It's a powerful piece.
It's the most powerful piece in chess.
And first time I heard about this problem,
my guess was that there wasn't a solution to the eight queens
problem.
And you know, how many of you think there's
a solution to this problem?
Do you know there's a solution, or do you
think there's a solution?
AUDIENCE: For sure, because knights,
because they can't move like in the way
a knight can, so it's got to be--
SRINI DEVADAS: So Ganatra says there's a solution.
How many of you, before you heard him,
thought there wasn't a solution?
Well, you know, years ago, I was convinced
that there was no solution, because I tried very hard
and I couldn't find one.
I tried very hard for a half hour, OK?
And then I decided there wasn't one.
But then, you know, now at this point, it got to the point
where I could write a computer program in about a half hour
or an hour to solve this problem,
and I did discover a solution.
So I'm giving it away.
It turns out there's many solutions,
and there's certainly a slightly different code
for finding one solution versus finding all of them,
and we'll do both.
So without further ado, you want to translate
the movement of the queens into a set of rules
that tell you if you have found a solution or not.
And there's essentially three rules,
because a queen can move in three different ways.
No two queens can be on the same column.
No two queens can be in the same row.
No two queens can be in the same diagonal.
And remember, there's two diagonals, one of which
that goes this way, and the other one that goes that way.
Right, so there's a lot of combinations here.
If you think about this and you look at this board over here,
I have eight different rows and eight different columns.
And the way that someone might try to solve this problem
is go either left or right or top down.
And I've written the constraint no two queens can
be in the same column first.
So you can imagine, then, this is what we're going to do.
You could certainly modify the code and modify our strategy,
but we're going to go left to right.
So what we're going to do is, we know if we put a queen up here,
we can't put a queen in any other row on that first column,
obviously, because of the first constraint.
So maybe I'll put a queen up here.
And then at that point, I can move to the second column
in my manual strategy.
And I couldn't put a queen up here
because of the second constraint,
no two queens can be on the same row.
And if I had a queen up here-- let me just write that out.
So I can't put one here, I can't put one here.
I could put one here, and this goes
back to what Ganatra said, about this
is how a knight moves in chess.
And so that gets me two queens.
And obviously, not a solution to the problem of the eight
queens, but maybe I'm a quarter of the way there, right?
And it turns out that you have to do
what is called backtracking.
And backtracking simply means you
may have to undo a decision you made
with respect to the placement of a particular queen
in this exhaustive search strategy, right?
And the important thing when you do
a search, as I mentioned early on,
you have to convince yourself that the code you've written
is going to exhaust all of the possibilities,
and that it won't miss solutions.
And if you don't exhaust all the possibilities,
your code will terminate, and you
may throw up your hands, because you had buggy code,
or because you had a buggy search strategy,
and say, there's no solution to the problem,
whereas there is a solution to the problem.
All right?
And the way you do this search, this exhaustive search--
because it's quite intense, there's a lot of combinations,
and they grow exponentially with the number of rows and columns
on our board--
is important.
And so you want to be careful that you
don't do redundant work, that you don't do things
that you don't really have to, because the combinations blow
up.
So there's hundreds of millions of combinations with respect
to putting queens up here, so if you really think about it,
there's like eight different places
you can put a queen here, eight, eight, eight et cetera.
So you know, that's 8 raised to 8 right?
If you think about that.
And that's a large number, right?
And if you translate that, I don't even know what that is.
But you could do--
you know, this is 2 raised to 3, raised to 8,
so that's 2 raised to 24, which is in the millions.
And if you had larger board--
it isn't a chessboard-- then it would be much, much larger
as you grew the size of the board.
But that 2 raised to 24 doesn't scare us these days,
because computers are so fast.
But back when I was your age, that was a large number, OK?
And you didn't want to write code
that took 2 raised to 24 steps to solve problems.
Now it takes a matter of fractions of seconds
to run through those kinds of combinations,
because you're running at a gigahertz on computers.
But before we dive into the specifics
of a particular strategy, let's look at smaller problems.
You always get intuition about problems
by shrinking them and making them simpler.
So let's look at the case of a two-by-two board.
Can I solve the two queens problem on a two-by-two board?
No.
So if I put a queen here, well, immediately I cannot put
a queen--
it attacks all of these other positions.
So the two-by-two does not have a solution.
Let's look at a three-by-three.
Right.
So let's say I put a queen up here.
So the way I'm doing this, by the way, is column by column,
and that's kind of going to be our strategy.
As I said, you could flip it to row by row,
but no reason to do both.
Just pick one.
And so I put a queen up here.
I can't put one here, I can't put one here,
I can't put one here, right?
So I go ahead and put that over here.
Can I put a queen here?
No, because that attacks it.
Can I put a queen here?
No, because this attacks it.
And clearly, I can't do it over here.
So am I done?
Can I just give up now?
What should I do?
I don't want to give up now.
I don't want to say that a three-by-three-- at this point,
I don't know what the answer is in terms
of whether a solution exists for a three-by-three or not.
But at this point, given that I put a queen up here,
and I went through this process, I cannot give up, right?
And why cannot I give up?
What should I do next, once I've failed here?
I put a queen here and a queen here, and I said, um, you know,
I can't put a queen anywhere here.
What do I do?
Right?
Yeah, go ahead, Fadi.
AUDIENCE: You can change the position of the first queen.
SRINI DEVADAS: You can change the position
of the first queen.
That's exactly right.
So I need to backtrack, and so I tried a few different things
here.
And it was exactly the same thing,
where I had a queen here.
And let's say I have a very straightforward strategy that
is going to put queens down and run a piece of code that is
going to check for conflicts.
This is going to be our most important subroutine that we're
going to write, and it's going to be dependent on the data
structure that we picked, but that is our fundamental check,
you know, the conflict checker.
So I could put a queen here.
And obviously, with one queen, there's
no reason to run the conflict checker.
When I put a queen here, I run the conflict checker,
and it says, conflict.
Here, conflict.
Here, no conflict.
Right?
And then I move on to the next, and I get conflict
for all three of them, right?
So at this point, I have to have a way in my code--
this is exactly the enumeration that I need in my code,
to go back and say, just like I tried different combinations
for the second column before I converged
on putting a queen down here, I need
to go back and change this to do this.
So I put a queen here, then can I put a queen here?
Here?
No, right?
So that doesn't work either.
So then I go up and put a queen here,
and now you know where this is headed, because of symmetry.
The only place I can put a queen is over here.
And once I put the queen over there,
I can't put a queen in any of these spots.
So it turns out a three-by-three does not have a solution.
At this point, because I've gone through all of the combinations
with respect to the starting points on the first column,
and then with each of those starting points,
I've gone through all of the combinations
in the second column and the third column,
I've effectively done the 3 raised
to 3, which was basically what I described to you previously
with respect to these different combinations.
Now I don't know if the 8--
we kind of think at this point that there
is a solution in those 8 raised to 8 combinations for the eight
queens problem.
But there was no solution in the 2 raised
to 2 combinations for the two queens problem.
And there were no solutions in the 3 raised
to 3 combinations or placements for the three queens problem.
OK?
So let's do four queens.
And the reason I'm doing this is I
want to point out one thing, which is an efficiency
trick that is going to be important to make sure
that our code runs in a reasonable amount of time.
Right?
And which is kind of implicit in what we've done here,
but I want to point it out.
So in the case of four queens, I'm going to go off
and I'm going to put a queen up here.
And I'm going to run through this fairly quickly.
No, no, yes.
And so I move on.
No, no, no, no, no.
Right?
So oops-- but now, I don't need to go back
all the way to the first.
I can put a queen here, right?
So now, no, yes, so I get a little further.
And then I could move to the fourth column.
No, no, no, no.
I mean, they attacked from here or attack from there.
Oops, all right.
Let's just go-- can I put it over here?
No, no.
I went back to the most recently placed queen, OK?
So one thing that is important, which you kind of get a sense
for when you increase the size of the board,
is when you fail, when check conflicts returns false,
when you fail, you go back to the most recent decision, most
recent column that you've placed your queen,
and you change that, and you enumerate those possibilities.
OK?
And when you do that--
the other thing that we've done, by the way,
is for the first queen, we put a queen down with impunity.
For the second queen, we check that lone, existing queen
on the board for a conflict, right?
For the third queen, what am I doing here for the third queen?
What conflicts am I checking when
I place the third queen on one of the rows
of the third column, specifically?
What conflicts am I checking?
I mean, who am I checking with?
Yeah, go ahead back there.
AUDIENCE: The two queens that you--
SRINI DEVADAS: Yeah, the two queens.
And what am I doing for the existing queens
that are already on the board?
Do I do anything for them?
No.
So I guess it doesn't seem like much,
but it's an important notion.
OK?
The notion here is I'm doing a certain amount
of incremental checking when I place a new queen,
and it's only the new relationships that
the new queen--
or the conflicts that the new queen would have that
need to be checked.
And in general, you know, if I had seven queens up
on the board, and I've set it up nicely
with these seven queens-- they're all happy, right?
They're non-conflicting.
No reason to go look at each of those pairs of seven queens
when I put an eighth queen down, as I change the position
of the eighth queen.
All I care about is that the eighth queen doesn't conflict
with the first seven queens.
So I have to check, in general, if I'm putting the k-th queen
down, and I'm effectively checking
for k minus 1 pairs of conflicts, or k minus 1 queens
were already put down.
The k-th queen is being put down,
and I need to check for the ones that already existed.
I don't have to do k minus 1 squared, right?
You know, because the k minus 1 were in there.
There's different pairs over there.
I'm all done with that, all right?
I'm all done with that.
All right, so let's keep going here.
So where was I?
I forget exactly where I was at, but we
decided that this didn't work, because I
failed on column four.
But I can put it over here, and I can put it over here, right?
So now, at this point, I've gone through and I've said,
look, what it means now is that for these two positions
for the first two columns, there's
no solution to the four queens problem.
OK?
And so I exhausted the positions, for this position.
I've also exhausted-- so I can say something even stronger
than that, because for this position,
I looked at the two possibilities, which
were this and that, and neither of them work as well, right?
So the stronger statement now is that there's
no solution to the four queens problem
if you put a queen on the top-left corner, right?
But it doesn't mean that there's no solution to the four queens
problem.
Ganatra you had a question.
AUDIENCE: Can't you also say there's
no solution when you put the queen on the bottom one?
SRINI DEVADAS: Symmetry, yes, wonderful.
So it turns out that you can do rotations and reflections,
and if you are willing to take your code.
Remember that computers are dumb.
You have to explain to them what a rotation is
and what a reflection is.
But if you do that, then it turns out
you can get significant reductions in 8 raised to 8,
or what have you.
Right?
And I'll go back and I'll tell you
about the number of solutions to the eight queens problem,
if you just looked at it this way,
without rotating yourself or reflecting,
and then tell you how many unique solutions there actually
are, if you took into account the symmetries associated
with rotation and reflection.
And the last part is important, because it can cut down
your combinatorial search, if you do take that into account,
right?
But as I said, you know, for our purposes, 2 raised to 24
is not a large number anymore, so we can just
blast through and not have to do that.
All right?
But now what I need to do is I've erased everything.
You know, I tried that first queen in the corner.
It's probably not going to work here, right?
And so because of--
well, no probably.
It will not work here.
Sorry about that.
But you know, this is different, right?
I mean, that clearly we have to check, right?
So here, no.
Here, no.
Yes.
Right?
And then here, yes, right?
So I could put that over here.
And then I move on.
Here, no.
Here, yes.
That's right.
So we don't know if there's not another solution.
And in fact, there is.
There's two solutions.
We won't go there, but 4 by 4--
I'm sorry, four queens has a solution.
OK?
So now we're ready to code, OK?
Now we're ready to code.
The one thing we need to do is decide on a data structure.
But before I show you the code, or even talk
about the data structure, I do want
you to keep in mind this search strategy that we employed,
right?
And the search strategy was a column-by-column search
strategy, and it requires enumeration and changing
positions of queens.
And deciding when to do that is going
to be based on whether check conflicts gives you back
true or false.
And we can set up check conflicts,
so it's not checking--
there's two ways you could do this.
You could say, here's a board.
I'm going to check all pairs of conflicts associated
with all the queens on the board,
and I'm going to just use that procedure over and over.
That's not what we did in our search strategy.
What we did was we have a check conflict strategy that really
takes a new queen as an argument and the existing board
as the second argument, right?
And it's really checking for the new queen's conflicts
with the existing queens, and that cuts down
on the amount of computation that you want to do.
All right?
So given that, what is the most natural data structure that you
can think of that would be applicable to the eight queens
problem or the four queens problem?
What's the most natural data structure
that you can think of?
Someone?
Yeah, go ahead, Ryan.
AUDIENCE: Two-dimensional array.
SRINI DEVADAS: Two-dimensional array.
Two-dimensional list, and that's exactly right.
So let's say that I decided to do exactly what Ryan suggested,
and what I'm going to do is, I'm going
to have a two-dimensional array, or two-dimensional list.
In Python, you know, we call them lists,
which looks like this.
And this is going to look exactly like the board
that you have there.
Two-dimensional.
This is the list of lists, and you have lists in here.
And so the important thing, people--
all of you, if you haven't already,
will spend some debugging time in your programming careers,
figuring out why things don't work,
to try and figure out why things don't work.
And it'll be because you flipped the I and J
indices of a two-dimensional array, or a list, OK?
Because you'll think that some things are rows and some things
are columns, and you'll flip them around.
So I don't want to do that.
I already did that enough times in my life,
so I don't want to do that.
And so right here, I think of B0 as the first row.
Right?
So this thing here is B0.
So when I say something like B 2, 3,
what is the value of B 2, 3 in my list B?
1.
All right?
And B 3, 2 is 0,
OK?
So that's-- I mean, I could obviously have confused myself.
There'd be a bug in the code if I'd
switched the identities of rows and columns, right?
That's exactly the point.
So I can now imagine that check conflicts, given
what we said about incremental checking--
but it still has to do, obviously,
computation on the B array, or look at the B array,
and decide what's going on.
I'm going to be putting in 1s and 0s inside of the B array.
And the first two--
I mean, they're all straightforward.
I mean, it's not complicated code here.
But the first two checks are slightly easier
than the third check.
No two Queens on the same column implies
that I need to actually look at the first index changing,
you know, from 0 to 3.
And for some particular--
I could just write this out here.
So no two Queens on the same coin
them would mean that I want to go 0 through--
let's just call it--
7, because I have the 8 Queens problem.
And then I need to look at i where i varies--
actually, let me just call that j.
I like i for rows and j for columns.
And j varies-- j would be 0.
And then you check that B 0, 7, 0 only has one 1, all right?
That's essentially what I need to check for.
And then I need to check it for j equals 0.
I need to check it for j equals 1.
I need to check it for j equals 2, et cetera, right?
That make sense?
And then, no two Queens on the same row,
I need to check that B i and i can go from 0 to 7.
I'm sorry, no two Queens can be on the same row.
Yeah, that's right.
So this goes from 0 to 7.
And then I fix the value of the column.
This is fixed.
So right now, let's just say that I look at the first row.
I'd go 0 here.
And then I go 0 through 7 here.
And then I make sure that, on B 0, there's exactly one 1,
right?
All right.
So we're good here?
Yeah?
OK.
The diagonal is the i and j both change, all right?
And the thing with the diagonal is--
and I'll show you the code for this.
I think it's much easier to explain the code as opposed
to drawing things now.
Because it's about the specifics of things.
And so here it is.
So what I have here is--
I call it noConflicts().
noConflicts() has the board, which is our B array here,
or B list.
In general, we're going to be working incrementally
on the current column.
So that's what that is.
So you move from 0 to all the way down.
And then you have something that we're
going to call qindex, which is where you are.
So you have two things that you need to worry about.
You're working on a column that's current.
And then you also have the position
that corresponds to the row where
you're putting the Queen down.
So you obviously need two of these values for--
to point into the 2-dimensional list.
So that's your qindex over here.
And this simply is setting n to be 4.
I mean, I could--
this is a general procedure.
But because I'm calling this in a 4-Queens procedure,
we're going to do iteratively now.
So I need to know exactly how many rows and columns they
are on my board.
So I've just set that up to be n equals 4.
But that's essentially that dimension.
So as you can, I'm going to check
that there's a single 1 in the current column.
This is what I was trying to go over over there.
But I think this code is probably more evocative.
I'm simply checking to see that the number of 1s
in the current column is not greater than 1.
If it is greater than 1, then, immediately, I'd return False.
And then here, this is a little bit easier.
I check that the current Queen--
this is-- the row on which the current Queen is on only
has one Queen on it.
And for the-- remember, as I'm going,
there's a single 1 in the current column.
And this thing here says I need to check
that, when I put a Queen down here, that this is the--
I need to check this entire row to make sure that this Queen is
the only one on it, all right?
And then I also need to check this and that, OK?
And so those two checks are over here, this and that.
So the diagonal, the left diagonal,
is the first one, the first check.
And then the one that goes over to the right
is the second check, all right?
And again-- yeah, go ahead, Fadi.
AUDIENCE: In the first procedure,
like, when we were checking for that only one Queen
was in one column-- so I see in my mind that
is qindex equal to i.
Why is that line added?
Like here, we're checking that if we
add the Queen in that position, that there's no conflict.
SRINI DEVADAS: Are you talking about this line here?
AUDIENCE: Yes, exactly.
And also, because our algorithm makes sure that as we progress,
we add, at each stack, one Queen per column,
why do we have, in the first place,
to check for column conflict?
SRINI DEVADAS: Beautiful.
That's a great question.
So I'm going to answer that in a minute or so, all right?
So Fadi was asking about whether the checks are redundant
or not.
And he was pointing to a particular piece of code.
Let me explain this code.
And then I'll answer Fadi's question, OK?
So what I have here is our--
this is actually the search algorithm, all right?
And this is exactly what we've talked
about up until this point.
You're going to go over--
you're going to go column by column, right?
And then you're going to go row by row.
And so that's essentially what the two loops are.
There's lots of loops here, obviously, right?
You know, this is horrible code, right?
I mean, I'm not saying this is pretty code, right?
But this is horrible code.
And what happens here is, over here, I'm
going to go ahead and say, this is--
I'm starting with--
I'm going to vary--
I'm starting with the first column.
So the column is fixed here, OK?
Remember, I'm going to column by column.
So that's why this is a 0.
And then I'm going to vary the position of the Queen
on the row, OK?
And that i varies, all right?
And then the next thing I'm going to do
is I'm going to go to the second column.
And I'm going to--
so that's why this is a 1.
And then I'm going to vary the position of the Queen
on each of the rows corresponding
to the second column, and so on and so forth, all right?
That's it, all right?
It's brutal code, OK?
And I'll show you, I wrote code for eight Queens.
It goes all the way to there, right?
So that's it.
I mean, you know, you can see it's simple code.
I'm not-- you know, sometimes brutish means simple--
not always.
And so this no conflicts thing is essentially something that
is calling this noConflicts() procedure that is doing all
of the things that I just described to you, right?
And so if I go ahead and run this,
and run this with four Queens--
oh yikes, this always happens.
After a while, it's going to come back.
But when I run this with four Queens--
let me-- let's see if this is what we want.
One more time.
Ah, sorry.
I've been fighting this system bug ever since I installed
macOS Sierra on my laptop.
There you go.
So this gave me my two solutions, one of which
is up there on the board.
And this is the second solution for the four Queens problem,
all right?
So let me go back to answer Fadi's question, right?
So the idea here--
and the way I described this was, look,
as I go column by column, I only put one Queen down
on this particular column, the current column
that I'm working on.
And the way I have this code set up,
notice that I'm setting this to be 1,
and then I'm resetting it down below here, the j, i, 0,
whether it's i--
whether it's this line of code and this line of code,
they're paired together-- or this line of code
and this line of code.
These two things are ensuring that there's exactly
one Queen on any given column.
Because I'm only putting that Queen down.
And then I'm taking it out and putting it in another spot,
right?
And that's how I described this entire procedure
to you manually, right?
That's how we worked through it.
So your contention, Fadi, is that this check is redundant,
right?
And you're right, right?
You're absolutely right.
And so if I comment out that check,
everything works exactly--
it's a little bit faster.
But everything works exactly the same, all right?
So there was a reason I put the check in there.
You asked the question.
I was going to ask you the question.
But that is a good question, all right?
So that's kind of the summary of four Queens.
You can clearly imagine generalizing this
to eight Queens.
It looks even more ugly.
This is what that looks like, OK?
And in fact, it would look worse,
except I decided that I'd employ the continue statement, right?
So I don't know how many of you know of the continue statement.
But the continue statement essentially
says, if there's an F predicate followed by continue,
and the predicate is true, then you immediately
start the next iteration of the loop, OK?
So there's two ways that you could
say, I don't want to do anything for the rest of the loop,
right?
There's two ways you could do this.
One is you could say--
so I have a for loop here, dot, dot, dot.
And if I say if condition, then you do stuff, right?
And so this do is indented inside of the if.
Compare that with, for if not condition, continue.
And here you would have do stuff,
the same do stuff, all right?
Now, if this do stuff has indentations in it,
then you're better off--
I mean, just because I have so many indentations-- you're
better off doing this strategy, right?
Because if do stuff goes on and has a bunch of ifs in it,
then you at least started at this level as opposed
to starting at this level, which is 2D, all right?
So that's absolutely the only reason
why I used continue over here.
Because it would look even more ugly if I hadn't use
continue, all right?
So if we run this--
and the only other thing--
I'm going to get back to no conflicts in a second.
But we'll go ahead and run this.
And you see that there's 92 different solutions
to the eight Queens problem if you don't take into account
rotations and reflections, OK?
And all of those solutions are being printed out.
And so then, the question is, what does that mean, right?
What does that mean?
And that comes to our selection of the data structure,
all right?
So we did this.
This was the data structure that you picked,
which is a natural data structure.
You can imagine that you could do
something that is more compact, much more compact.
And I want to show you how you could optimize this code,
both for succinctness as well as memory efficiency,
by picking a different data structure, all right?
So let's exploit the fact that each column has only one Queen
allowed, all right?
So we want to exploit the fact that each column only
has one Queen allowed, right?
So if you think about it, and you say,
well, I have this big thing here, but each of the columns
has exactly one Queen, then sure, I could use a bit,
like I did before, of 0 and 1 to specify it.
But I do know that this thing is going to be all 0s and a 1,
followed by all 0s, or 1 followed by all 0s, et cetera,
et cetera, all right?
So it's very constrained, if I look at that first column,
as to what the value of that column is, right?
And so I kind of gave it away by running this.
But what could I do now with respect
to representing the configuration of the board
by doing some amount of compaction, all right?
What can I do?
Those of you, look at the screen and--
yeah, go ahead.
AUDIENCE: variable for a row
SRINI DEVADAS: I could just have a single variable that
corresponds to the row number that this particular Queen is
on, right, in that column, right?
And that's exactly what's going on out there, all right?
So if I just take that, and I take--
I'll do the bottom one, because that's
the easiest for me to see.
But the rows go 0 through 7.
So what that says is that, on the first column,
I have a Queen up here, OK?
And then the third one, I have a Queen.
So I have a Queen here.
And 0-- uh-oh, I messed up.
Thank you.
Whew, that would have been bad.
So 3, and then over here--
and then, what do I have?
2, right?
So 2 is over here.
I'm going to have a panic attack if I end up getting a conflict.
Because I drew these--
I put these Queens up here.
My name will be Mud, OK?
So 5 is over here.
And then 1 is this one over here, all right?
And 6 is out here.
And then finally, 4 is out here, OK?
All right, don't tell me there's a conflict.
Even if there's one, I refuse to--
I will refuse to admit that, all right?
So that's one of the solutions to the eight Queens problem.
And as I mentioned, there's really 12 distinct ones.
And so it turns out you don't need
to muck with a 2-dimensional list, which is confusing.
And you start flipping I's and J's, and your life
is miserable, right?
So let's just go with a single-dimensional list, right?
Let's just say that if I had something
like this-- and in fact, I'm not putting a Queen down
on this second column.
This is not something we would do in this algorithm,
but I just want to show you a generality, right?
I'm going to take that, and I'm going to represent this,
as you can imagine, as a single-dimensional Python list.
And I'm just going to put--
what am I going to put down here according to what I just
described to you?
I'm going to put 1.
And what do you think I should put down here?
Should I put 0?
No, no, no, a 0 would be bad, right?
Because that would imply that there's a Queen here.
I could put minus 1, right?
Minus 1 could imply that there's no Queen on that column.
And I could start with a board that is empty,
which is all minus 1s, right?
And then this one would be--
this is minus 1, yep.
Sorry, I wrote 1s.
Let me write this like that, minus 1.
That's 1.
And then I would have 2 here, and then 0 there, OK?
So what's cool about this is the overall procedure in terms
of the column by column incremental checking,
that control flow of the algorithm can stay the same.
I mean, if it were four Queens, the code
would look slightly different.
Because obviously, our board data structure
is a little bit different.
I'm going to show you the eight Queens code in a minute.
But it's effectively the same algorithm, right?
There's eight loops for eight Queens.
There's four loops for four Queens.
And a little bit of bookkeeping with respect
to putting the Queen on a column would
imply that I'm changing minus 1 to 0, or I'm changing 2 to 3,
or something like that, as opposed
to doing what I did previously, which was putting in a 1
for a particular element in the 2-dimensional list,
and then making it a 0, and then putting a 1
in a different spot, right?
So even that gets a little simpler,
because I'm just overwriting.
When I go 2 the 3, it means that I'm moving this Queen from here
to there, OK?
So there's that, which is fairly minor.
What is much more interesting is our checkConflicts() procedure
or our noConflicts() procedure and what that would look like,
right?
And we had a bunch of code--
some of it was redundant--
for noConflicts().
But let's look at the code for noConflicts() in this case.
And that's it.
It's four lines of code, OK?
And this is not redundant, right?
So if you guys can make this code smaller,
A plus right off the bat, OK?
Well, it is a pass-fail class, but I'll write you a letter,
OK?
So this is essentially the code that
would take this new data structure
and check conflicts in an incremental way,
OK-- same thing.
You know, I'm going to add a new Queen to the mix.
And I'm going to be checking the conflicts
of this new Queen versus the existing Queens, all right?
And so let's go through this.
Because I have some time, and that's the last thing
I want to do.
So what I have here is, I'm not going to be checking anything
about the columns, all right?
Because I know that the number is going to--
basically, the invariant here is there's
going to be some number here.
It it's a negative number, there's nothing on that column.
And if there's a positive number,
it better be between 0 and the number of rows minus 1.
And that is going to tell me where
the one Queen is, all right?
So I'm done with that.
But I do have to check that there's a row--
if there's a row problem.
There could be a row problem, all right?
So I could put a Queen up here.
And obviously, I have to detect that, correct?
So the way I detect that is by the highlighted code, where
I'm just going to check to see whether there's
two numbers that are repeated corresponding to--
well, the current-- so I know what the value of current is.
It's not going to be minus 1, because current
is going to be a real Queen put into a particular position.
I mean, the last thing you want is
to check two minus 1s for equality
and throw up a conflict.
Because I mean, that's just empty versus empty.
You know, there's no conflict.
But board current is guaranteed, by the invocation procedure,
to be a positive number--
I should say a non-negative number,
either is 0 up until 7 in our case of our eight Queens
problem.
And I just need to check to see that that value--
let's call it 4--
doesn't exist in any of the other columns, correct?
So that's it.
It's a little loop, but it's three lines of code.
And in that same loop, we're going
to be actually checking for, it turns out,
both classes of diagonal conflicts, OK?
In this line of code here, can someone explain me--
explain to me what this line of code is doing, all right?
What am I doing here?
I mean, even pictorially would be fine.
Or you know, use your arms and wave, right?
What is that line of code doing?
I mean, roughly, it's checking for diagonal conflicts,
but I want more, all right?
How is it checking for diagonal conflicts?
Yeah, go ahead.
AUDIENCE: I think the difference between the index
numbers of that one we had is that the values have
the same difference.
SRINI DEVADAS: That's exactly right.
So if you think about what's going on, remember,
we're talking squares here.
You know, no rectangles, right?
Maybe we could have a homework assignment where
we have rectangular chessboards, and do things,
and confuse everybody, right?
But the good news here is that it's a square, right?
I like squares, OK?
And squares are easy to deal with,
because you end up in a situation
where you know that how much you move in this direction
should be exactly the same that you
move in the other direction, all right?
That's what a diagonal in a chessboard
is, right-- you know, on a square board is.
You need to move in the same amount of movement, all right?
So you're not talking about diagonals
that look like that, right?
That's not what you're talking about.
So what this means is-- if you go look at this line of code,
what it says is--
my current is telling me--
for this particular column, it's telling me what row I'm on, OK?
That's really what the value--
the value-- I'm sorry, this is the column number.
Excuse me, I misspoke.
Current is telling me what the column number is, OK?
And this board current is telling me
what row number there is.
So board current gives me the row number
for the current column, all right?
And i is whatever column that I'm comparing against.
I need to enumerate the different columns that I'm
comparing against, all right?
So if I look at this and that, you'll
find that the difference between--
this is 1, 1--
2, 1, right?
So this column is 2, and the row is 1, right?
So I'll just say 2 equals column,
and row equals 1 for this thing over here, all right?
And then I'll use a different color for this one.
Here I have, the column 3--
the column is equal to 3.
And the row equals 0, OK?
Right?
Clearly, that's a conflict, correct?
And the reason there's a conflict, mathematically
speaking, is because the difference in the columns
is the same as the difference in the rows, OK?
3 minus 2-- well 2 minus 3--
2 happens to be greater than--
sorry, 2 happens to be less than 3.
3 happens to be greater than 2.
But the absolute value of the difference
is something that you need to take into account.
Because you could have diagonals in both directions, right?
So that ABS-- the absolute value over there
is key, because it tells you that it's
checking for both this diagonal as well as this diagonal,
right?
And so that's it.
So if you think about this being a square,
and you go look at the comparisons between the values
on the rows, and if that value, the difference,
is the same, in absolute terms, as the difference
in the columns, you have a conflict.
Otherwise, you don't have a conflict, right?
Because then you're going off.
The diagonal is going away, through the board,
but a Queen is not on it, all right?
So I guess I did run it, so I won't run it again.
But I'll leave you with the thought--
and we'll talk about this next time--
is how in heck can we make this code look prettier, all right?
And we will go and at a--
from here on out, we'll be looking at a programming
paradigm that's very powerful.
I won't give it away.
You probably know what it is.
But we'll talk about it first thing tomorrow.
And one of the things we will do,
we'll do a different puzzle tomorrow as well.
But we'll take a look at the eight Queens code,
make it prettier, and also get it
to the point where it solves the n Queen's problem where n is
an input to do the procedure.
The problem with this code is it only solves eight Queens.
I showed you code for four Queens
that only solved four Queens.
If I told you that I needed you to write code that
solves n Queens where n is an argument to the procedure,
you wouldn't be able to do that with this iterative strategy
unless you bounded and wrote n different pieces of code,
right, one of which has four loops,
and the other one has five loops,
and the other one has six loops.
And you would still need to know what n is, OK?
All right, so see you next time.