WEBVTT

00:00:01.550 --> 00:00:03.920
The following content is
provided under a Creative

00:00:03.920 --> 00:00:05.310
Commons license.

00:00:05.310 --> 00:00:07.520
Your support will help
MIT OpenCourseWare

00:00:07.520 --> 00:00:11.610
continue to offer high quality
educational resources for free.

00:00:11.610 --> 00:00:14.180
To make a donation or to
view additional materials

00:00:14.180 --> 00:00:18.140
from hundreds of MIT courses,
visit MIT OpenCourseWare

00:00:18.140 --> 00:00:19.026
at ocw.mit.edu.

00:00:22.140 --> 00:00:27.390
INSTRUCTOR: So today, we
start on project 4, which is,

00:00:27.390 --> 00:00:29.640
as you know, the big project.

00:00:29.640 --> 00:00:35.430
And Helen is going to do a
walkthrough of the project,

00:00:35.430 --> 00:00:37.920
and the code, and
the organization,

00:00:37.920 --> 00:00:41.400
because this is a pretty
big sized project.

00:00:41.400 --> 00:00:44.400
It's got about
4,500 lines of code.

00:00:44.400 --> 00:00:50.460
And it's not code that is
kind of like simple code.

00:00:50.460 --> 00:00:53.070
It's all content-bearing code.

00:00:53.070 --> 00:00:57.630
So I think having a bit
of an orientation to it,

00:00:57.630 --> 00:00:59.910
more than we give for the
other codes that you work,

00:00:59.910 --> 00:01:03.670
on which are pretty
small, this will be great.

00:01:03.670 --> 00:01:05.650
So, Helen, take it away.

00:01:05.650 --> 00:01:07.900
HELEN XU: Hi, everyone.

00:01:07.900 --> 00:01:09.445
Can you hear me?

00:01:09.445 --> 00:01:11.820
Awesome, so today we're going
to be doing the walkthrough

00:01:11.820 --> 00:01:12.750
for the final project.

00:01:12.750 --> 00:01:16.050
You can look at the code
and clone it publicly here.

00:01:16.050 --> 00:01:19.110
And please remember to fill up
your team's by 7:00 PM today,

00:01:19.110 --> 00:01:23.380
so we can populate the
list and get your repos.

00:01:23.380 --> 00:01:25.530
Yeah, and if there are
any issues accessing this,

00:01:25.530 --> 00:01:26.800
just let me know.

00:01:26.800 --> 00:01:30.570
Or put it on Piazza
and then we can fix it.

00:01:30.570 --> 00:01:33.270
So we just had a
game of Lesierchess.

00:01:33.270 --> 00:01:34.860
But in case you
missed it, we'll go

00:01:34.860 --> 00:01:37.630
into more details about
what the game actually does.

00:01:37.630 --> 00:01:40.290
So first, we're going to
go through the game rules.

00:01:40.290 --> 00:01:42.960
So you saw that there
are these pieces.

00:01:42.960 --> 00:01:44.030
There's these triangles.

00:01:44.030 --> 00:01:44.780
And there's kings.

00:01:44.780 --> 00:01:46.440
So the triangles are pawns.

00:01:46.440 --> 00:01:48.320
And the kings, they
look like crowns.

00:01:48.320 --> 00:01:49.320
And there are two teams.

00:01:49.320 --> 00:01:52.050
There's orange and lavender,
or tangerine and lavender.

00:01:52.050 --> 00:01:55.830
And each side starts out with
seven pawns and one king.

00:01:55.830 --> 00:01:57.280
And this is the
starting position.

00:01:57.280 --> 00:01:59.280
So you can see like the
kings are in the corner.

00:01:59.280 --> 00:02:02.040
And they're just lined
up like in the middle.

00:02:02.040 --> 00:02:04.600
And each piece has
four orientations.

00:02:04.600 --> 00:02:09.880
So you can see that the pawn
is up, down, left, right.

00:02:09.880 --> 00:02:12.510
And then the king
is also like that.

00:02:12.510 --> 00:02:18.600
And in general, the game starts
with tangerine moving first.

00:02:18.600 --> 00:02:21.090
And then the play alternates
between the two players.

00:02:21.090 --> 00:02:23.613
Each piece moves the same,
whether it's king or pawn.

00:02:23.613 --> 00:02:24.780
And each turn has two parts.

00:02:24.780 --> 00:02:26.050
So you saw the demo.

00:02:26.050 --> 00:02:27.582
But you move first.

00:02:27.582 --> 00:02:29.790
When you pick one of your
pieces, and you move first.

00:02:29.790 --> 00:02:32.850
And then at the end, your
King has to fire the laser.

00:02:32.850 --> 00:02:35.280
And the laser reflects off
the long edge of the pawn.

00:02:35.280 --> 00:02:38.220
And they'll kill the pawn if
it shoots the short edges.

00:02:38.220 --> 00:02:40.470
And one side wins when
the king gets shot,

00:02:40.470 --> 00:02:43.800
or when the opposing king gets
shot, whether by themselves

00:02:43.800 --> 00:02:47.107
or by your own king.

00:02:47.107 --> 00:02:48.690
And so I talked a
little about moving.

00:02:48.690 --> 00:02:51.510
And at the beginning of each
turn, the player to move

00:02:51.510 --> 00:02:53.340
chooses a piece to move.

00:02:53.340 --> 00:02:55.475
And you can move your
King or any of your pawns.

00:02:55.475 --> 00:02:56.850
And there are two
types of moves.

00:02:56.850 --> 00:03:00.210
There's basic moves,
and swat moves.

00:03:00.210 --> 00:03:03.720
And basic moves are just,
basically, shifts or rotations.

00:03:03.720 --> 00:03:07.990
So in the example, you can
rotate 90, 180, or 270 degrees.

00:03:07.990 --> 00:03:10.340
So in the top, row
you just rotate.

00:03:10.340 --> 00:03:11.920
This is the example
of moving a pawn.

00:03:11.920 --> 00:03:13.290
So you rotate your pawn.

00:03:13.290 --> 00:03:15.390
Or you can move to an
empty adjacent square.

00:03:15.390 --> 00:03:16.800
So those are the
bottom two rows.

00:03:16.800 --> 00:03:19.300
And there are eight adjacent
squares in this example.

00:03:19.300 --> 00:03:20.513
So there are eight shifts.

00:03:20.513 --> 00:03:21.930
But there would
be less than eight

00:03:21.930 --> 00:03:26.130
if you were, for example,
like at the edge of the board.

00:03:26.130 --> 00:03:29.203
And on a move, you can
either shift or rotate.

00:03:29.203 --> 00:03:30.120
But you can't do both.

00:03:32.840 --> 00:03:34.500
There are also these swap loops.

00:03:34.500 --> 00:03:38.668
So if you're adjacent
to an opposing piece,

00:03:38.668 --> 00:03:39.710
you can switch with them.

00:03:39.710 --> 00:03:41.543
And then you have to
make another basic move

00:03:41.543 --> 00:03:43.190
after that, that is not a swap.

00:03:43.190 --> 00:03:45.518
So, basically, you can either--

00:03:45.518 --> 00:03:47.060
and it has to be
with that same piece

00:03:47.060 --> 00:03:48.200
that you just swapped with.

00:03:48.200 --> 00:03:51.380
So you just either
shift or rotate.

00:03:51.380 --> 00:03:52.630
Is everyone good on the rules?

00:03:56.570 --> 00:03:58.040
Just a couple more things.

00:03:58.040 --> 00:03:59.600
So there's this
Ko rule, which is

00:03:59.600 --> 00:04:02.240
from Go, which ensures that
the game makes progress.

00:04:02.240 --> 00:04:06.258
So it makes a move illegal if
it undoes the opponent's most

00:04:06.258 --> 00:04:08.550
recent move by just moving
back to where you just were.

00:04:11.223 --> 00:04:12.140
So this is an example.

00:04:12.140 --> 00:04:13.820
Let's say you're tangerine.

00:04:13.820 --> 00:04:16.070
And you swapped with the
purple one right next to you.

00:04:16.070 --> 00:04:21.740
And then you shifted
left and bottom.

00:04:21.740 --> 00:04:26.360
And so lavender can
return by swapping back

00:04:26.360 --> 00:04:29.930
with your orange piece,
and shifting again.

00:04:29.930 --> 00:04:32.180
But this is actually,
illegal because now

00:04:32.180 --> 00:04:34.880
you just got to your
original position.

00:04:34.880 --> 00:04:37.520
So you're not allowed to just
keep cycling back and forth.

00:04:41.520 --> 00:04:44.850
And so a draw occurs if there
have been 50 moves by each side

00:04:44.850 --> 00:04:47.730
without a pawn being
zapped, the same position

00:04:47.730 --> 00:04:49.632
repeats itself by
the side on move,

00:04:49.632 --> 00:04:51.090
or the two players
agree to a draw.

00:04:56.140 --> 00:04:58.040
So just kind of like
in chess, a chess clock

00:04:58.040 --> 00:05:00.457
limits the amount of time the
players have to make a move.

00:05:00.457 --> 00:05:02.500
So you can't just keep
competing indefinitely.

00:05:02.500 --> 00:05:04.810
When it's your moves,
your clock counts down.

00:05:04.810 --> 00:05:07.780
When it's your opponent's
moves, your clock stops.

00:05:07.780 --> 00:05:09.097
So it's not counting your time.

00:05:09.097 --> 00:05:10.430
And we used Fisher time control.

00:05:10.430 --> 00:05:12.013
There's a picture
of Bobby Fisher, who

00:05:12.013 --> 00:05:15.970
made it, up which used an
initial time budget and a time

00:05:15.970 --> 00:05:16.600
increment.

00:05:16.600 --> 00:05:20.212
So in this example,
there's fis60 and 0.5,

00:05:20.212 --> 00:05:21.670
which means that,
in the beginning,

00:05:21.670 --> 00:05:23.840
each player has 60 seconds.

00:05:23.840 --> 00:05:26.050
And you get to use the 60
seconds however you want.

00:05:26.050 --> 00:05:30.520
And when you end your move,
you get 0.5 extra seconds.

00:05:30.520 --> 00:05:34.152
But the 60 and 0.5
could be anything.

00:05:34.152 --> 00:05:35.110
That's just an example.

00:05:38.572 --> 00:05:40.530
So we'll go into an
example of how you actually

00:05:40.530 --> 00:05:41.520
play this game.

00:05:41.520 --> 00:05:43.290
For a king to zap
the enemy king,

00:05:43.290 --> 00:05:46.020
it risks opening itself
to counter-attack.

00:05:46.020 --> 00:05:47.730
So look at this example.

00:05:47.730 --> 00:05:51.370
And how can tangerine zap
the lavender pawn in F5,

00:05:51.370 --> 00:05:52.650
by moving one of its pieces?

00:06:03.430 --> 00:06:05.140
AUDIENCE: [INAUDIBLE]

00:06:06.800 --> 00:06:07.550
HELEN XU: Move C4.

00:06:11.410 --> 00:06:13.690
AUDIENCE: Tangerine,
that's lavender.

00:06:13.690 --> 00:06:16.440
HELEN XU: You're
tangerine in this example.

00:06:16.440 --> 00:06:18.580
And you're trying to
zap the one on F5.

00:06:26.060 --> 00:06:27.990
Yep?

00:06:27.990 --> 00:06:33.290
AUDIENCE: You move the
tangerine piece at E22 to F1.

00:06:33.290 --> 00:06:34.235
HELEN XU: E2 to F1.

00:06:41.120 --> 00:06:43.500
Oh, sorry, by zap, it
means shoot the backside.

00:06:46.290 --> 00:06:49.960
That would shoot the long side.

00:06:49.960 --> 00:06:52.450
Good point.

00:06:52.450 --> 00:06:56.348
Yeah, so you're trying
to kill the piece on F5.

00:06:56.348 --> 00:06:59.330
AUDIENCE: [INAUDIBLE]

00:06:59.330 --> 00:07:01.060
HELEN XU: Yeah, exactly.

00:07:01.060 --> 00:07:07.090
So in this, you can move
C2 to B1, as you just said.

00:07:07.090 --> 00:07:09.210
And then you draw the path.

00:07:09.210 --> 00:07:14.190
And you can see that
you've just killed--

00:07:14.190 --> 00:07:17.460
or if you're tangerine, you've
just killed the piece at F5.

00:07:17.460 --> 00:07:18.930
Now, how can lavender counter?

00:07:18.930 --> 00:07:21.660
By counter, we mean
lavender can win

00:07:21.660 --> 00:07:22.860
the game from this position.

00:07:29.210 --> 00:07:30.875
AUDIENCE: Is it A4 to A3?

00:07:35.460 --> 00:07:36.280
HELEN XU: A4 to A3.

00:07:40.680 --> 00:07:42.570
No, I don't think so.

00:07:42.570 --> 00:07:43.706
Yep?

00:07:43.706 --> 00:07:46.580
AUDIENCE: [INAUDIBLE]

00:07:46.580 --> 00:07:48.640
HELEN XU: Sorry, what?

00:07:48.640 --> 00:07:52.135
King, like the orange one?

00:07:52.135 --> 00:07:53.010
Oh, the lavender one.

00:07:57.120 --> 00:07:59.030
You're trying to
shoot the orange king.

00:08:02.720 --> 00:08:05.190
Oh, yes, you're right.

00:08:05.190 --> 00:08:08.180
You can, actually.

00:08:08.180 --> 00:08:10.490
Yes, good, that's not
the one that we had,

00:08:10.490 --> 00:08:13.080
but apparently
there are two ways.

00:08:13.080 --> 00:08:14.540
Good.

00:08:14.540 --> 00:08:16.060
So if you notice
you could also--

00:08:16.060 --> 00:08:17.360
that's another way
to get that path.

00:08:17.360 --> 00:08:18.985
But you can also move
one of the pawns.

00:08:21.570 --> 00:08:26.830
Cool, so this is
just pointing out

00:08:26.830 --> 00:08:29.440
one of the subtleties of
the game, which is you

00:08:29.440 --> 00:08:33.309
should watch out for
just naively killing

00:08:33.309 --> 00:08:35.559
all the pieces you can,
because that might open you up

00:08:35.559 --> 00:08:39.520
to the opponent.

00:08:39.520 --> 00:08:41.159
Yeah?

00:08:41.159 --> 00:08:42.890
AUDIENCE: [INAUDIBLE]

00:08:42.890 --> 00:08:45.233
HELEN XU: Yes, it can
be from any direction.

00:08:45.233 --> 00:08:46.900
But the pawns only
die if you shoot them

00:08:46.900 --> 00:08:48.570
from not on the long edge.

00:08:48.570 --> 00:08:49.450
Yep?

00:08:49.450 --> 00:08:52.750
AUDIENCE: What if you
shoot your own block?

00:08:52.750 --> 00:08:54.550
HELEN XU: By block,
you mean your own pawn?

00:08:54.550 --> 00:08:55.120
AUDIENCE: Yeah.

00:08:55.120 --> 00:08:55.995
HELEN XU: You'll die.

00:08:55.995 --> 00:08:57.435
AUDIENCE: Oh.

00:08:57.435 --> 00:08:58.060
HELEN XU: Yeah?

00:09:00.590 --> 00:09:02.238
AUDIENCE: [INAUDIBLE]

00:09:07.000 --> 00:09:09.880
HELEN XU: Yes, but only one
piece can be on each square.

00:09:09.880 --> 00:09:13.450
But you can have
as many near you.

00:09:13.450 --> 00:09:16.120
But do you have a question?

00:09:16.120 --> 00:09:20.120
AUDIENCE: Can you make it
impossible to kill your person?

00:09:20.120 --> 00:09:21.990
HELEN XU: Like your King?

00:09:21.990 --> 00:09:24.510
Like if you barricaded
it by pawns.

00:09:24.510 --> 00:09:27.080
But then the opponent can
come in and swap with them,

00:09:27.080 --> 00:09:30.990
so it will open your barricade.

00:09:30.990 --> 00:09:33.610
AUDIENCE: Can the purple
king shoot upward?

00:09:33.610 --> 00:09:35.018
HELEN XU: If it wanted to.

00:09:35.018 --> 00:09:37.435
But then in this example, it
would shoot up off the board,

00:09:37.435 --> 00:09:38.477
and nothing would happen.

00:09:38.477 --> 00:09:39.703
Yeah?

00:09:39.703 --> 00:09:41.620
AUDIENCE: When you kill
a pawn, does the laser

00:09:41.620 --> 00:09:44.427
stop at the place where
the pawn is or does it

00:09:44.427 --> 00:09:45.260
go through the pawn?

00:09:45.260 --> 00:09:49.110
HELEN XU: No, it
just shoots one.

00:09:49.110 --> 00:09:52.445
Good questions.

00:09:52.445 --> 00:09:53.320
Everyone good so far?

00:09:56.550 --> 00:09:57.690
OK, great.

00:09:57.690 --> 00:10:00.330
PROFESSOR: This year,
it shoots only one.

00:10:00.330 --> 00:10:03.854
Last year, it kept shooting.

00:10:03.854 --> 00:10:05.967
AUDIENCE: Can the
king shoot itself?

00:10:05.967 --> 00:10:06.550
HELEN XU: Yes.

00:10:09.330 --> 00:10:10.788
It should try not
to, but it can.

00:10:10.788 --> 00:10:11.830
So you should be careful.

00:10:21.890 --> 00:10:26.150
So moving on-- we use force
Fosythe-Edwards Notation,

00:10:26.150 --> 00:10:30.290
which is a representation of a
chess position using a string.

00:10:30.290 --> 00:10:33.860
So you can see an example
of the starting position.

00:10:33.860 --> 00:10:35.888
And the bottom
includes the string

00:10:35.888 --> 00:10:37.430
that describes the
starting position.

00:10:40.610 --> 00:10:42.670
If you look at the
representation,

00:10:42.670 --> 00:10:45.310
the arrow corresponds
to one of the rows.

00:10:45.310 --> 00:10:50.860
And that points to the substring
that has a bubble over it.

00:10:50.860 --> 00:10:55.360
So in this row, there is
one purple pawn at B3,

00:10:55.360 --> 00:10:59.470
and two orange
ones at F3 and G3.

00:10:59.470 --> 00:11:01.170
So this is row three.

00:11:01.170 --> 00:11:04.090
And the slashes separate
the rows in the string.

00:11:04.090 --> 00:11:06.190
And the one represents
there's an empty space.

00:11:06.190 --> 00:11:07.990
And then there's a
pawn facing southeast.

00:11:07.990 --> 00:11:10.690
And then there's three
empty spaces, and one facing

00:11:10.690 --> 00:11:13.090
northwest, and then one
facing southeast, and then

00:11:13.090 --> 00:11:14.806
an empty space.

00:11:14.806 --> 00:11:16.740
AUDIENCE: [INAUDIBLE]

00:11:16.740 --> 00:11:19.382
HELEN XU: Oh, yeah,
it's animated.

00:11:25.990 --> 00:11:26.890
What do you mean?

00:11:30.710 --> 00:11:34.560
Yeah, so at the end of the
string, there's also a--

00:11:34.560 --> 00:11:37.547
it just tells you which
side's move it is.

00:11:37.547 --> 00:11:38.880
So this is the opening position.

00:11:38.880 --> 00:11:42.550
But you can use any
position in this notation.

00:11:42.550 --> 00:11:44.010
And this is useful
for debugging,

00:11:44.010 --> 00:11:46.110
because if you, for example,
you're running a bot,

00:11:46.110 --> 00:11:47.527
and it crashes at some position.

00:11:47.527 --> 00:11:49.110
And you can get back
to that position.

00:11:49.110 --> 00:11:50.250
You can start up
the game and just

00:11:50.250 --> 00:11:52.708
go there without having to make
all the moves to get there.

00:11:59.783 --> 00:12:01.450
And this is how you
represent the games.

00:12:01.450 --> 00:12:03.760
So each of these is one move.

00:12:03.760 --> 00:12:07.330
And the left column
is tangerine.

00:12:07.330 --> 00:12:10.780
And the right
column is lavender.

00:12:10.780 --> 00:12:13.090
And an example,
you can see E6, E7,

00:12:13.090 --> 00:12:17.340
means they moved a
piece from E6 to E7.

00:12:17.340 --> 00:12:22.390
B3L, so you rotated
the piece on B3 left.

00:12:22.390 --> 00:12:25.780
There's D5, E4, F5, which
means that you swapped.

00:12:25.780 --> 00:12:28.180
So your original
piece was on D5.

00:12:28.180 --> 00:12:29.590
You swapped with the one at E4.

00:12:29.590 --> 00:12:33.130
And now you moved
that piece to F5.

00:12:33.130 --> 00:12:36.240
So the one that was
E4 is now on F5.

00:12:36.240 --> 00:12:39.070
And the opposing piece is now
on D5, because you swapped.

00:12:41.900 --> 00:12:43.490
You can swap and then rotate.

00:12:43.490 --> 00:12:46.160
So instead of just
having a third square,

00:12:46.160 --> 00:12:48.620
you would just have a rotation.

00:12:48.620 --> 00:12:50.280
And at the end, you
could see who won.

00:12:50.280 --> 00:12:53.560
So in this one, lavender
one because it's 0-1.

00:12:53.560 --> 00:12:55.393
But 1-0 would mean
tangerine wins.

00:12:55.393 --> 00:12:56.810
And half and half
would be a draw.

00:12:59.660 --> 00:13:02.450
So you can look at the
logs for your games.

00:13:02.450 --> 00:13:03.189
Yes?

00:13:03.189 --> 00:13:05.145
AUDIENCE: [INAUDIBLE]

00:13:07.983 --> 00:13:09.900
HELEN XU: There's a
rotate up and rotate down.

00:13:12.545 --> 00:13:15.300
AUDIENCE: [INAUDIBLE]
do a U-turn?

00:13:15.300 --> 00:13:16.800
HELEN XU: Oh, is that what U is?

00:13:16.800 --> 00:13:19.405
AUDIENCE: Yeah, U-turn.

00:13:19.405 --> 00:13:21.780
HELEN XU: Oh I, see because
there's only three rotations.

00:13:21.780 --> 00:13:24.200
Yes, sorry, so left is 90.

00:13:24.200 --> 00:13:25.320
Then right is 270.

00:13:25.320 --> 00:13:27.680
And U is 180,
because you flip it.

00:13:34.420 --> 00:13:36.193
Is everyone good
on the notation?

00:13:36.193 --> 00:13:37.860
This is just how you
describe the games,

00:13:37.860 --> 00:13:39.318
if you wanted to
look at your logs,

00:13:39.318 --> 00:13:40.620
and if there are some issues.

00:13:43.758 --> 00:13:46.050
So you can test your bot with
other teams in the class,

00:13:46.050 --> 00:13:48.420
as well as with staff bots
on the scrimmage server.

00:13:48.420 --> 00:13:51.900
And we have a reference,
which is here, which

00:13:51.900 --> 00:13:53.820
is just the additional release.

00:13:53.820 --> 00:13:56.595
But we will be optimizing
our bots while we're

00:13:56.595 --> 00:13:57.470
optimizing your bots.

00:13:57.470 --> 00:13:59.970
And we'll release a reference
plus, and maybe an even better

00:13:59.970 --> 00:14:02.680
one later, which you can play
with on the scrimmage sever.

00:14:02.680 --> 00:14:04.930
So I'll just do a
really quick demo.

00:14:04.930 --> 00:14:09.030
So right now, since we haven't
done the team formation yet,

00:14:09.030 --> 00:14:10.905
you are not able
to log into this.

00:14:10.905 --> 00:14:12.780
But once you do your
team formation, probably

00:14:12.780 --> 00:14:15.000
by tomorrow, you'll
be able to log in.

00:14:15.000 --> 00:14:17.260
And, basically, you can see
the general functionality.

00:14:17.260 --> 00:14:19.680
So this updates your
player, pulls your player

00:14:19.680 --> 00:14:23.380
from your repo, whatever's
on the master branch.

00:14:23.380 --> 00:14:26.160
And then right now,
there's only reference,

00:14:26.160 --> 00:14:28.310
and reference plus,
and reference TAs.

00:14:28.310 --> 00:14:30.480
And here's a team
with me and Jess.

00:14:30.480 --> 00:14:33.030
But later on, we'll
populate this list

00:14:33.030 --> 00:14:34.180
with everyone in the class.

00:14:34.180 --> 00:14:35.310
And then you can
challenge anybody else

00:14:35.310 --> 00:14:36.910
in the class to see how you do.

00:14:36.910 --> 00:14:38.740
You can also challenge us.

00:14:38.740 --> 00:14:41.080
So you would just
pick, for example,

00:14:41.080 --> 00:14:43.020
let's say I wanted to
challenge reference.

00:14:43.020 --> 00:14:45.300
And then a hit send challenge.

00:14:45.300 --> 00:14:48.220
Now, you can see that there's
some new matches spawned.

00:14:48.220 --> 00:14:51.030
And this is how I look at all
the matches that I've played.

00:14:51.030 --> 00:14:52.793
So each time you
hit send challenge,

00:14:52.793 --> 00:14:54.960
it spawns off two games,
one where you're tangerine,

00:14:54.960 --> 00:14:55.960
and one you're lavender.

00:14:58.270 --> 00:15:00.660
So that's how you can watch
the matches on the scrimmage

00:15:00.660 --> 00:15:01.160
server.

00:15:03.467 --> 00:15:04.050
Everyone good?

00:15:11.683 --> 00:15:13.600
I'm going to move on so
don't run out of town.

00:15:16.120 --> 00:15:18.500
You can watch them later.

00:15:18.500 --> 00:15:19.840
And you can even play your own.

00:15:30.270 --> 00:15:30.770
OK.

00:15:34.120 --> 00:15:35.870
And, in addition to
the scrimmage server--

00:15:35.870 --> 00:15:36.860
so the scrimmage
server, you can only

00:15:36.860 --> 00:15:38.068
spawn off one game at a time.

00:15:38.068 --> 00:15:39.140
But you can do more.

00:15:39.140 --> 00:15:42.290
And you don't have
to necessarily do it

00:15:42.290 --> 00:15:45.290
on your master branch,
or against opposing teams

00:15:45.290 --> 00:15:46.160
in the class.

00:15:46.160 --> 00:15:48.860
So there's something called the
Cloud autotester, which you can

00:15:48.860 --> 00:15:50.443
run by going to your Athena.

00:15:50.443 --> 00:15:51.860
And then you type
in this command.

00:15:51.860 --> 00:15:52.970
You do autotest run.

00:15:52.970 --> 00:15:55.388
And then you do
the time control.

00:15:55.388 --> 00:15:57.680
And you give it a number of
games that you want to run.

00:15:57.680 --> 00:15:59.630
And then you give it
a list of binaries.

00:15:59.630 --> 00:16:01.590
So I'll go into each of
these in more detail.

00:16:01.590 --> 00:16:04.490
So the time control is just what
I talked about earlier, which

00:16:04.490 --> 00:16:07.550
is if you use Fisher time
control, these are some set,

00:16:07.550 --> 00:16:08.510
preset things.

00:16:08.510 --> 00:16:10.427
So you would type in one
of the preset things.

00:16:10.427 --> 00:16:14.630
So you would talk in blitz to
do 60 and 0.5, for example.

00:16:14.630 --> 00:16:17.780
And the number of games is
just whatever you want to do.

00:16:17.780 --> 00:16:19.310
And the list of
binaries-- so let's

00:16:19.310 --> 00:16:21.800
say you had a
reference invalidation,

00:16:21.800 --> 00:16:23.120
and then you made some change.

00:16:23.120 --> 00:16:25.670
So I called it
Lesierchess with changes.

00:16:25.670 --> 00:16:27.800
And then you would
just put those

00:16:27.800 --> 00:16:30.165
after the number of games,
separated by spaces.

00:16:30.165 --> 00:16:31.790
And then it would
upload your binaries,

00:16:31.790 --> 00:16:34.130
and play them in the
cloud auto tester.

00:16:34.130 --> 00:16:37.520
And once you submit your
job, you get a link.

00:16:37.520 --> 00:16:39.200
And you follow the
link in your browser.

00:16:39.200 --> 00:16:40.993
And you can view
the game running.

00:16:40.993 --> 00:16:42.410
And then after the
games are done,

00:16:42.410 --> 00:16:45.950
you will get some output saying
like, which bot, one more?

00:16:45.950 --> 00:16:50.950
And how many times have
won, and some rankings.

00:16:50.950 --> 00:16:52.181
Yep?

00:16:52.181 --> 00:16:54.830
AUDIENCE: How fast do they run?

00:16:54.830 --> 00:16:57.200
HELEN XU: How fast do they run?

00:16:57.200 --> 00:16:58.427
AUDIENCE: [INAUDIBLE]

00:17:04.550 --> 00:17:06.819
HELEN XU: So it depends on
how many other games are

00:17:06.819 --> 00:17:07.819
queued at the same time.

00:17:07.819 --> 00:17:09.579
So if a lot of people
are running tests,

00:17:09.579 --> 00:17:10.579
it might take some time.

00:17:10.579 --> 00:17:13.732
But blitz is just how long
the game itself will take.

00:17:13.732 --> 00:17:15.440
And it might take
longer than 60 seconds,

00:17:15.440 --> 00:17:19.819
because if you use less than
0.5 seconds in your move,

00:17:19.819 --> 00:17:22.190
and then you add 0.5 seconds
at the end of the move,

00:17:22.190 --> 00:17:25.579
then you would
increase your time.

00:17:25.579 --> 00:17:29.630
But 60 is just the time control.

00:17:29.630 --> 00:17:31.465
Each side starts
with 60 seconds.

00:17:31.465 --> 00:17:33.840
And depending on how they use
it, they have more or less.

00:17:33.840 --> 00:17:34.820
Good question.

00:17:40.220 --> 00:17:41.137
Well, I'll keep going.

00:17:41.137 --> 00:17:43.762
And if there's time at the end,
I'll do a demo of this one too.

00:17:43.762 --> 00:17:46.190
But it basically looks the
same as the scrimmage server.

00:17:46.190 --> 00:17:48.148
Like, you just watch the
games in the same way.

00:17:50.530 --> 00:17:53.030
So now, I'm going to go into
the project organization, which

00:17:53.030 --> 00:17:54.613
is the organization
of the directories

00:17:54.613 --> 00:17:56.850
that we handed out in this repo.

00:17:56.850 --> 00:17:58.100
So there are some directories.

00:17:58.100 --> 00:17:59.850
The first one is doc,
which just includes

00:17:59.850 --> 00:18:02.760
the rules and documentation
for the interface.

00:18:02.760 --> 00:18:05.840
There's the auto tester, which
is the Java local auto tester.

00:18:05.840 --> 00:18:08.000
So if the cloud--

00:18:08.000 --> 00:18:10.740
we recommend that you run tests
using the cloud auto tester.

00:18:10.740 --> 00:18:15.730
But if there's some small
change, or if you think that--

00:18:15.730 --> 00:18:18.560
if the cue is too long,
then you can do local tests.

00:18:18.560 --> 00:18:21.530
And you can also
run these overnight.

00:18:21.530 --> 00:18:23.990
There's pgnstates, which
just parses your statistics

00:18:23.990 --> 00:18:26.420
from the auto test results,
like how many times you won,

00:18:26.420 --> 00:18:27.860
stuff like that.

00:18:27.860 --> 00:18:30.230
There's tests, which is
how you specify tests.

00:18:30.230 --> 00:18:34.627
And I'll go into more detail
about how you define this.

00:18:34.627 --> 00:18:36.710
There's the player, which
is where you're actually

00:18:36.710 --> 00:18:37.668
going to be optimizing.

00:18:37.668 --> 00:18:39.860
So player is the
code that actually

00:18:39.860 --> 00:18:41.540
runs the bot to play the game.

00:18:41.540 --> 00:18:44.960
And the webgui is a local webgui
where you can watch the game

00:18:44.960 --> 00:18:45.500
and play it.

00:18:45.500 --> 00:18:49.100
So in the webgui, you can even
play it yourself as a human

00:18:49.100 --> 00:18:51.270
so you can get a better
sense of how the game works.

00:18:54.027 --> 00:18:56.110
To go into more detail,
the Java local auto tester

00:18:56.110 --> 00:18:57.080
is an auto tester.

00:19:00.107 --> 00:19:02.690
You can make your changes, and
then you can test your changes.

00:19:02.690 --> 00:19:06.270
And the test directory, which is
parallel, holds configurations.

00:19:06.270 --> 00:19:09.260
So you can specify the
number of games and the bots

00:19:09.260 --> 00:19:11.270
that you want to use,
and the time control,

00:19:11.270 --> 00:19:12.830
and other things too.

00:19:12.830 --> 00:19:14.600
So this an example
of the configuration

00:19:14.600 --> 00:19:16.670
file that you would use
to run your auto tester.

00:19:16.670 --> 00:19:19.292
So this is saying that
you run it on 12 CPUs.

00:19:19.292 --> 00:19:20.750
And book means that
you're pointing

00:19:20.750 --> 00:19:23.640
to open a book, which
I'll talk about later.

00:19:23.640 --> 00:19:26.140
Game rounds is how many games
you're going to spawn off.

00:19:26.140 --> 00:19:28.840
Title is just the title of
the test that you're running.

00:19:28.840 --> 00:19:30.840
And after that, you have
the player definitions.

00:19:30.840 --> 00:19:33.860
So player reference
is just the binary.

00:19:33.860 --> 00:19:37.250
And invoke is the
path to the binary.

00:19:37.250 --> 00:19:39.770
And then fis is
the time control.

00:19:39.770 --> 00:19:42.042
And the next one is
just a second binary,

00:19:42.042 --> 00:19:44.000
if you made a change and
you want to test them.

00:19:47.470 --> 00:19:48.470
Yeah, that's the binary.

00:19:52.600 --> 00:19:54.510
To interface with auto
tester, Lesierchess

00:19:54.510 --> 00:19:57.730
uses the universal
chest interface, or UCI,

00:19:57.730 --> 00:20:00.010
which is a communication
protocol for automatic games.

00:20:00.010 --> 00:20:03.100
And you pass information between
the auto tester and your bot.

00:20:03.100 --> 00:20:05.530
And it allows the programmer
or the auto tester

00:20:05.530 --> 00:20:07.590
to enter moves to
the game engine.

00:20:07.590 --> 00:20:10.060
So you could use UCI
to start up your bot.

00:20:10.060 --> 00:20:11.860
And then you type in
the moves that you

00:20:11.860 --> 00:20:14.290
want to make to see the
changes in the state.

00:20:14.290 --> 00:20:16.420
And you could use this to
debug to get to a state

00:20:16.420 --> 00:20:17.462
that you want to look at.

00:20:21.570 --> 00:20:23.790
We'll measure the bots
using Elo ratings.

00:20:23.790 --> 00:20:26.880
So Elo is a rating system
that measures relative skill

00:20:26.880 --> 00:20:29.010
level in zero sum games.

00:20:29.010 --> 00:20:32.550
The Elo rating depends on the
Elo rating of your opponents.

00:20:32.550 --> 00:20:35.550
And on the bottom, you
can see an example output.

00:20:35.550 --> 00:20:38.040
So I had three binaries.

00:20:38.040 --> 00:20:41.100
And I ran about 100 games.

00:20:41.100 --> 00:20:43.710
And you can see that
the Elo of the top one

00:20:43.710 --> 00:20:45.360
is much higher than
the other ones.

00:20:45.360 --> 00:20:47.940
And so higher Elo is good.

00:20:47.940 --> 00:20:50.490
And we'll be comparing
the performance.

00:20:50.490 --> 00:20:53.100
We'll be comparing the Elo of
your bot against our reference,

00:20:53.100 --> 00:20:56.520
and improved reference
implementations.

00:20:56.520 --> 00:20:59.730
So notice that this
is not, as before,

00:20:59.730 --> 00:21:01.680
just a straight measure of time.

00:21:01.680 --> 00:21:03.750
So like before, in
previous projects,

00:21:03.750 --> 00:21:07.170
if you used less time,
than you would get a higher

00:21:07.170 --> 00:21:08.935
grade or better performance.

00:21:08.935 --> 00:21:10.560
In general, I'll show
you a graph later

00:21:10.560 --> 00:21:12.477
that actually shows if
you searched the higher

00:21:12.477 --> 00:21:15.250
depth, which means that you
are faster, you do improve.

00:21:15.250 --> 00:21:17.230
But it's not an
exact correlation.

00:21:17.230 --> 00:21:19.290
And you can look at
the nodes per second

00:21:19.290 --> 00:21:22.380
that you search using the UCI.

00:21:25.730 --> 00:21:28.700
And just above here, to local
webgui lets you watch a game,

00:21:28.700 --> 00:21:31.100
or play one, without sending
it to the scrimmage server.

00:21:31.100 --> 00:21:32.767
So if you wanted to
play one as a human,

00:21:32.767 --> 00:21:34.550
you would use the local webgui.

00:21:34.550 --> 00:21:38.610
And you can run it using
the commands in the readme.

00:21:38.610 --> 00:21:41.128
OK, so is everyone good so far?

00:21:41.128 --> 00:21:43.670
Now, I'm going to go into more
details about how you actually

00:21:43.670 --> 00:21:44.253
play the game.

00:21:49.580 --> 00:21:52.843
So first, every
player, or every bot,

00:21:52.843 --> 00:21:54.260
needs to generate
the moves, which

00:21:54.260 --> 00:21:55.970
means that once you
have a position,

00:21:55.970 --> 00:21:58.810
you need to look at the
moves that you can do.

00:21:58.810 --> 00:22:01.070
And to do that, you need a
board representation, which

00:22:01.070 --> 00:22:03.380
is to represent what
pieces are on the board,

00:22:03.380 --> 00:22:06.290
and how big the board is,
and where the pieces are.

00:22:06.290 --> 00:22:09.500
And the reference implantation
uses a 16 by 16 board

00:22:09.500 --> 00:22:11.300
to store an 8 by 8 board.

00:22:11.300 --> 00:22:14.300
So you can see that the inner
squares is actually the board.

00:22:14.300 --> 00:22:16.940
And the outer dark
square is sentinels.

00:22:16.940 --> 00:22:18.380
So you use sentinels
to keep track

00:22:18.380 --> 00:22:19.855
of when you go off the board.

00:22:19.855 --> 00:22:21.980
And then the inner square
is just the actual board.

00:22:24.980 --> 00:22:26.870
We store the position
using this struct.

00:22:26.870 --> 00:22:31.010
So you can see the fields in the
position, which are the board.

00:22:31.010 --> 00:22:32.900
And the array size
is just representing

00:22:32.900 --> 00:22:34.730
the board, plus the sentinels.

00:22:34.730 --> 00:22:36.450
And there's the history
of the position,

00:22:36.450 --> 00:22:38.060
which is, how did we get here?

00:22:38.060 --> 00:22:40.960
And there's a key, which is
a hash key for this position.

00:22:40.960 --> 00:22:43.550
There is ply, which tells
you what side it is.

00:22:43.550 --> 00:22:44.840
So even means white.

00:22:44.840 --> 00:22:46.282
And odd means black.

00:22:46.282 --> 00:22:47.990
There is, what was
the last move that was

00:22:47.990 --> 00:22:49.930
made to get to this position?

00:22:49.930 --> 00:22:52.790
There's a victim struct,
which is the pieces destroyed

00:22:52.790 --> 00:22:55.030
by when you shot the laser.

00:22:55.030 --> 00:22:58.310
And there is the
location of the kings.

00:22:58.310 --> 00:23:00.102
The position struct
and Lesierchess struct

00:23:00.102 --> 00:23:02.060
stores the border
presentation and other things

00:23:02.060 --> 00:23:03.102
that I just went through.

00:23:07.870 --> 00:23:13.030
So I talked about this move,
which means just like a move

00:23:13.030 --> 00:23:14.990
that you make for
one of your pieces.

00:23:14.990 --> 00:23:16.750
And I'll go into how
it's represented.

00:23:16.750 --> 00:23:19.390
So right now, we already
do the packing for you.

00:23:19.390 --> 00:23:21.190
So we use 28 bits.

00:23:21.190 --> 00:23:25.420
And the first two
are the piece type.

00:23:25.420 --> 00:23:28.930
So there's a number of
moves that you can make.

00:23:28.930 --> 00:23:31.300
And the first two bits
represents the piece type,

00:23:31.300 --> 00:23:35.212
which is empty, pawn,
king, or invalid.

00:23:35.212 --> 00:23:36.670
The orientation of
the piece, which

00:23:36.670 --> 00:23:39.910
is just how you rotated it.

00:23:39.910 --> 00:23:44.177
The from square, which is where
your piece already started.

00:23:44.177 --> 00:23:45.760
There's the intermediate
square, which

00:23:45.760 --> 00:23:48.220
is used when you do a swap.

00:23:48.220 --> 00:23:50.770
And there's a two square,
which is the final position

00:23:50.770 --> 00:23:52.990
that your piece will end up in.

00:23:52.990 --> 00:23:55.780
So if you're not doing a swap,
then the intermediate and from

00:23:55.780 --> 00:23:56.892
should be the same.

00:23:56.892 --> 00:23:58.600
But if you are doing
a swap, then there's

00:23:58.600 --> 00:23:59.830
some skipping that happens.

00:24:03.050 --> 00:24:04.940
At each turn, you
need to see what

00:24:04.940 --> 00:24:06.410
moves you could possibly make.

00:24:06.410 --> 00:24:10.520
And in move gen, which is one
of the files in the handout,

00:24:10.520 --> 00:24:12.440
we generate all the
moves, given a position,

00:24:12.440 --> 00:24:13.690
depending on whose turn it is.

00:24:13.690 --> 00:24:15.065
So depending on
whose turn it is,

00:24:15.065 --> 00:24:16.333
you can make different moves.

00:24:16.333 --> 00:24:17.750
And in the reference
implantation,

00:24:17.750 --> 00:24:19.550
we iterate through
the entire board.

00:24:19.550 --> 00:24:22.430
And once we find a piece,
we generate all the moves

00:24:22.430 --> 00:24:23.210
from that piece.

00:24:26.790 --> 00:24:28.560
You can also debug
using move generation.

00:24:28.560 --> 00:24:31.710
So there's something
called perft,

00:24:31.710 --> 00:24:33.600
which is a debugging
function that enumerates

00:24:33.600 --> 00:24:35.220
all moves at a certain depth.

00:24:35.220 --> 00:24:37.830
So use perft to make sure that
if you make changes to the move

00:24:37.830 --> 00:24:39.205
generation that
you're generating

00:24:39.205 --> 00:24:41.080
the same number of moves.

00:24:41.080 --> 00:24:42.763
And if you modify
the move generated,

00:24:42.763 --> 00:24:44.430
just make sure that
it returns the same,

00:24:44.430 --> 00:24:46.110
because regardless
of what optimizations

00:24:46.110 --> 00:24:48.735
you do, you still should see the
same moves from each position

00:24:48.735 --> 00:24:49.860
that you can possibly make.

00:24:58.500 --> 00:25:01.200
OK, so now that we talked
about move generation,

00:25:01.200 --> 00:25:03.960
I'll talk about how you
tell that a move is good.

00:25:03.960 --> 00:25:07.350
And for that, we use something
called static evaluation.

00:25:07.350 --> 00:25:09.505
So we use static
evaluation to determine

00:25:09.505 --> 00:25:11.130
which positions are
better than others,

00:25:11.130 --> 00:25:13.230
and which moves
that we should make.

00:25:13.230 --> 00:25:16.590
And the function eval,
which is in eval.c,

00:25:16.590 --> 00:25:18.450
generate a score
based on a position,

00:25:18.450 --> 00:25:20.280
using some heuristics.

00:25:20.280 --> 00:25:23.203
And at first, we suggest,
instead of making up

00:25:23.203 --> 00:25:24.870
your own heuristics,
we suggest focusing

00:25:24.870 --> 00:25:28.290
on optimizing the existing
structs and evaluation

00:25:28.290 --> 00:25:30.150
heuristics before
coming up with new ones,

00:25:30.150 --> 00:25:31.890
because it's kind of hard
to come up with new ones.

00:25:31.890 --> 00:25:33.420
And there's a lot
of optimizations

00:25:33.420 --> 00:25:35.045
that you can make to
the existing ones.

00:25:39.460 --> 00:25:41.410
So I've just grouped
these into categories.

00:25:41.410 --> 00:25:43.193
So there's a few
regarding the king.

00:25:43.193 --> 00:25:44.610
So there's one
called KFACE, which

00:25:44.610 --> 00:25:47.220
is a bonus for your king
facing the enemy king.

00:25:47.220 --> 00:25:48.720
There's KAGGRESSIVE,
which gives you

00:25:48.720 --> 00:25:50.550
a bonus for if
your King is closer

00:25:50.550 --> 00:25:51.870
to the center of the board.

00:25:51.870 --> 00:25:54.190
And there's MOBILITY,
which counts up, basically,

00:25:54.190 --> 00:25:57.840
how many squares around
your king are free.

00:25:57.840 --> 00:26:02.195
You want to be able to
move your king freely.

00:26:02.195 --> 00:26:03.570
And there's some
regarding pawns.

00:26:03.570 --> 00:26:07.330
So there's PCENTRAL, which gives
you a bonus if your pawns are

00:26:07.330 --> 00:26:08.520
in the center of the board.

00:26:08.520 --> 00:26:11.550
And there's PBETWEEN, which
basically draw a bounding box

00:26:11.550 --> 00:26:13.110
with both kings at the corner.

00:26:13.110 --> 00:26:14.805
And then you count
how many pawns

00:26:14.805 --> 00:26:15.930
are in the center of those.

00:26:19.400 --> 00:26:22.520
And then there's points
based on distance.

00:26:22.520 --> 00:26:25.460
So there's LCOVERAGE, which
means laser coverage, which

00:26:25.460 --> 00:26:28.460
is basically you make all
the possible moves that you

00:26:28.460 --> 00:26:29.630
can make from your position.

00:26:29.630 --> 00:26:31.880
And then you draw
the laser path.

00:26:31.880 --> 00:26:34.640
And then you do some
scaling to determine

00:26:34.640 --> 00:26:37.608
how well you can
possibly cover the board,

00:26:37.608 --> 00:26:38.900
based on your current position.

00:26:41.970 --> 00:26:44.800
So that's basically how you tell
if a position is good or not,

00:26:44.800 --> 00:26:46.861
with these heuristics.

00:26:50.020 --> 00:26:53.590
So I'll just go through the
high level of how you actually

00:26:53.590 --> 00:26:54.850
play the game using search.

00:26:57.640 --> 00:26:59.260
So at the very
highest level, there's

00:26:59.260 --> 00:27:01.120
something called game
search trees, which

00:27:01.120 --> 00:27:02.873
is we've invented in search.c.

00:27:02.873 --> 00:27:04.540
But, basically, this
is a representation

00:27:04.540 --> 00:27:06.400
of how you play the game.

00:27:06.400 --> 00:27:08.050
At the top, there's
an orange square,

00:27:08.050 --> 00:27:10.480
which is the orange side,
which is the opening

00:27:10.480 --> 00:27:13.900
position, and then the arrows.

00:27:13.900 --> 00:27:16.000
So the top square--

00:27:16.000 --> 00:27:19.180
actually, all the nodes
are positions in the tree.

00:27:19.180 --> 00:27:21.760
And you use move generation
that I just talked about,

00:27:21.760 --> 00:27:25.690
to enumerate all the possible
moves from a single position.

00:27:25.690 --> 00:27:27.910
And each edge is a move.

00:27:27.910 --> 00:27:30.790
So to get from position
to position, you do moves.

00:27:30.790 --> 00:27:34.870
And you can see that
circle is the position

00:27:34.870 --> 00:27:37.450
after you've made the move.

00:27:37.450 --> 00:27:40.690
And you do this tree
to some depth d.

00:27:40.690 --> 00:27:45.000
And then you do static
evaluation of the leaves.

00:27:45.000 --> 00:27:48.062
So this is at a really high
level how game playing programs

00:27:48.062 --> 00:27:49.020
actually play the game.

00:27:49.020 --> 00:27:50.750
They enumerate all
the possible moves.

00:27:50.750 --> 00:27:52.000
And then they have a position.

00:27:52.000 --> 00:27:54.450
And then they pick which one
is best, based on evaluation.

00:27:54.450 --> 00:27:56.358
But you can see that
there's a lot of nodes.

00:27:56.358 --> 00:27:57.900
Like, if you do this
naively, there'd

00:27:57.900 --> 00:28:03.060
be number of moves raised to
d, which is a huge number,

00:28:03.060 --> 00:28:04.357
and too many to generate.

00:28:04.357 --> 00:28:06.690
So we're going to talk about
how you reduce those later.

00:28:09.720 --> 00:28:12.293
There's something that you have
to do on search series, which

00:28:12.293 --> 00:28:13.710
is called Quiescence
search, which

00:28:13.710 --> 00:28:17.400
is if you fix your depth--

00:28:17.400 --> 00:28:22.430
let's say you fix depth, and
then you go down to the leaves,

00:28:22.430 --> 00:28:24.762
and you just captured a piece.

00:28:24.762 --> 00:28:26.970
But it's dangerous to just
stop there at fixed depth,

00:28:26.970 --> 00:28:29.510
because maybe if you
searched one level deeper,

00:28:29.510 --> 00:28:32.010
you would see that the opponent
would capture your piece.

00:28:32.010 --> 00:28:34.590
And so if you do
your search, and you

00:28:34.590 --> 00:28:36.493
see that you capture
a piece at the leaves,

00:28:36.493 --> 00:28:38.910
or your opponent captures the
piece at the leaves, we say,

00:28:38.910 --> 00:28:39.618
that's not quiet.

00:28:39.618 --> 00:28:41.610
And you keep searching
the tree until there

00:28:41.610 --> 00:28:42.762
are no more captures.

00:28:42.762 --> 00:28:44.220
So that's called
Quiescence search,

00:28:44.220 --> 00:28:46.037
because you quiet the position.

00:28:46.037 --> 00:28:47.870
And that's implemented
in the search column.

00:28:51.190 --> 00:28:53.590
So this is a graph
that I generated

00:28:53.590 --> 00:28:56.860
by doing the reference
spot to different depths.

00:28:56.860 --> 00:28:59.500
And you can see that
the Elo increases as you

00:28:59.500 --> 00:29:01.420
increase the search depth.

00:29:01.420 --> 00:29:03.420
So you just search
the search tree.

00:29:03.420 --> 00:29:06.955
And so if you optimize
your bot to make it faster,

00:29:06.955 --> 00:29:09.330
you can search deeper, which
means that you'll do better.

00:29:16.320 --> 00:29:21.220
So next, I'll talk about
min-max search, which

00:29:21.220 --> 00:29:26.380
is a more complex
version of searching

00:29:26.380 --> 00:29:30.520
that can improve the amount
of nodes you have to evaluate.

00:29:30.520 --> 00:29:34.063
So at a high level, there's
two players, max and min.

00:29:34.063 --> 00:29:35.980
And in our example,
there's orange and purple.

00:29:35.980 --> 00:29:37.570
And orange is a square.

00:29:37.570 --> 00:29:38.710
And purple is a circle.

00:29:38.710 --> 00:29:40.690
And the game trees
represents all moves

00:29:40.690 --> 00:29:44.872
from the current position from
a given ply, which means depth.

00:29:44.872 --> 00:29:46.330
And if the leaves,
like I said, you

00:29:46.330 --> 00:29:48.190
play a static
evaluation function.

00:29:48.190 --> 00:29:50.860
And max chooses the maximum
score among its children.

00:29:50.860 --> 00:29:52.277
And min chooses
the minimum score.

00:29:52.277 --> 00:29:53.693
So one side is
trying to maximize,

00:29:53.693 --> 00:29:55.353
and one side is
trying to minimize.

00:29:58.460 --> 00:30:01.100
To evaluate the
search try, I'll first

00:30:01.100 --> 00:30:03.200
talk about an algorithm
called alpha beta, which

00:30:03.200 --> 00:30:06.440
is that each search from a
node has a window alpha beta.

00:30:06.440 --> 00:30:08.780
And if the value of the
search falls below alpha,

00:30:08.780 --> 00:30:11.260
the move is not good enough,
and you keep searching.

00:30:11.260 --> 00:30:13.878
And if the value falls
within alpha and beta,

00:30:13.878 --> 00:30:16.170
then you increase your alpha,
which is the lower bound,

00:30:16.170 --> 00:30:17.270
and you keep searching,
because you know

00:30:17.270 --> 00:30:18.890
you can do at least that well.

00:30:18.890 --> 00:30:22.430
And if the value of the
search falls above beta,

00:30:22.430 --> 00:30:24.440
than you generate a
beta cut off in return.

00:30:24.440 --> 00:30:26.870
Beta basically means one
side is trying to maximize,

00:30:26.870 --> 00:30:28.328
and one side is
trying to minimize.

00:30:28.328 --> 00:30:30.950
So beta is basically
saying, the opponent

00:30:30.950 --> 00:30:33.620
would never let you do that
move, because it'd be too good.

00:30:33.620 --> 00:30:35.995
So you don't need to keep
searching there, because you're

00:30:35.995 --> 00:30:38.930
not going to get there anyway.

00:30:38.930 --> 00:30:40.410
So I'll do an example.

00:30:40.410 --> 00:30:41.840
Let's say you have this tree.

00:30:41.840 --> 00:30:46.253
And if max discovered a
move that min wouldn't

00:30:46.253 --> 00:30:47.670
let you do, because
it's too good,

00:30:47.670 --> 00:30:49.170
then max's other
children don't need

00:30:49.170 --> 00:30:51.640
to be searched, which is
what a beta cut off is.

00:30:51.640 --> 00:30:53.780
So you'd start at the root.

00:30:53.780 --> 00:30:57.650
And then you go down to
the lowest left leaf.

00:30:57.650 --> 00:31:00.060
And you see that it's three.

00:31:00.060 --> 00:31:01.648
So you propagate three up.

00:31:01.648 --> 00:31:03.440
And then you can see
that in this sub-tree,

00:31:03.440 --> 00:31:06.200
you can do at least three.

00:31:06.200 --> 00:31:08.390
And then you keep
searching your children.

00:31:08.390 --> 00:31:10.130
And then you see six.

00:31:10.130 --> 00:31:12.440
And then you say, OK, now
you update your alpha value

00:31:12.440 --> 00:31:14.902
to be six.

00:31:14.902 --> 00:31:16.330
Now, you search four.

00:31:16.330 --> 00:31:18.555
But four is worse than six.

00:31:18.555 --> 00:31:19.930
So you don't have
to do anything.

00:31:19.930 --> 00:31:22.960
So you first search
the leftmost subtree.

00:31:22.960 --> 00:31:25.210
And then you see the best
move that you could possibly

00:31:25.210 --> 00:31:27.760
make there.

00:31:27.760 --> 00:31:31.810
So you propagate
six up to the root.

00:31:31.810 --> 00:31:34.700
And then you search
your other subtrees.

00:31:34.700 --> 00:31:36.190
But now, you have
this value of six

00:31:36.190 --> 00:31:38.780
that you basically use
in the other subtrees.

00:31:38.780 --> 00:31:40.457
So you look at two.

00:31:40.457 --> 00:31:42.040
And you see that two
is less than six.

00:31:42.040 --> 00:31:44.190
So you propagate it up.

00:31:44.190 --> 00:31:45.520
But now, you look at nine.

00:31:45.520 --> 00:31:48.880
And you see that nine
is greater than six.

00:31:48.880 --> 00:31:52.780
So you say that this subtree
would let purple do nine,

00:31:52.780 --> 00:31:54.520
which is greater than six.

00:31:54.520 --> 00:32:00.100
And so that would be too good,
because orange would never

00:32:00.100 --> 00:32:01.420
let purple do that well.

00:32:01.420 --> 00:32:04.090
So you don't have to
evaluate five anymore.

00:32:04.090 --> 00:32:06.235
So you cut off five.

00:32:06.235 --> 00:32:07.110
Does that make sense?

00:32:11.140 --> 00:32:13.580
OK, so, basically, now
you apply the same thing

00:32:13.580 --> 00:32:15.003
to the regular subtree.

00:32:15.003 --> 00:32:15.920
And you look at seven.

00:32:15.920 --> 00:32:18.150
And you see that seven
is greater than six.

00:32:18.150 --> 00:32:19.208
So you propagate that up.

00:32:19.208 --> 00:32:21.500
And now you're done, because
seven is greater than six.

00:32:21.500 --> 00:32:24.810
So you don't have to search
the rest of the subtree.

00:32:24.810 --> 00:32:27.830
So that's how you evaluate fewer
moves than the entire tree.

00:32:35.290 --> 00:32:38.280
And there's a theorem
that says for a game tree

00:32:38.280 --> 00:32:41.220
with branching factor b and
depth d, and alpha beta search

00:32:41.220 --> 00:32:43.140
with moves searched
in best-first order

00:32:43.140 --> 00:32:46.470
examines exactly b
raised to the d over 2,

00:32:46.470 --> 00:32:50.580
plus b raised to the d over
2 minus 1 nodes apply d.

00:32:50.580 --> 00:32:53.760
So best first order means that
you sorted the moves in terms

00:32:53.760 --> 00:32:55.273
of your static evaluation.

00:32:58.340 --> 00:33:00.680
The naive algorithm
examines b to the d nodes.

00:33:00.680 --> 00:33:04.190
And in the example I did,
you can see how you prune.

00:33:04.190 --> 00:33:06.427
And for the same work, the
search stuff is doubled.

00:33:06.427 --> 00:33:08.510
And for the same depth,
the work is square rooted.

00:33:08.510 --> 00:33:13.846
So this is a huge benefit
over the naive evaluation.

00:33:13.846 --> 00:33:15.240
Is everyone good on alpha beta?

00:33:19.890 --> 00:33:23.210
Great, so the code
is pretty short.

00:33:23.210 --> 00:33:25.610
So I'll just go through
some pseudocode for it.

00:33:25.610 --> 00:33:28.443
Basically, the main
point is that at line 11,

00:33:28.443 --> 00:33:30.235
one side is trying to
minimize and one side

00:33:30.235 --> 00:33:31.152
is trying to maximize.

00:33:31.152 --> 00:33:33.080
But if you negate, then
that's just the same

00:33:33.080 --> 00:33:34.880
as minimizing and maximizing.

00:33:34.880 --> 00:33:38.360
And you get all
the possible moves

00:33:38.360 --> 00:33:40.550
that you could possibly
make using gen moves.

00:33:40.550 --> 00:33:42.920
And you go through
the entire move list.

00:33:42.920 --> 00:33:44.720
And then you make
each of the children.

00:33:44.720 --> 00:33:47.480
And you search for the score.

00:33:47.480 --> 00:33:49.820
And then you see whether
you had a beta cut off.

00:33:49.820 --> 00:33:52.195
And then you don't need to
search the subtree If you did.

00:34:00.160 --> 00:34:02.080
So that was basic alpha beta.

00:34:02.080 --> 00:34:04.630
And we actually implement a
variation of alpha beta called

00:34:04.630 --> 00:34:06.072
principle variation search.

00:34:06.072 --> 00:34:08.530
And the main idea is that you
assume that the first move is

00:34:08.530 --> 00:34:09.639
the best one.

00:34:09.639 --> 00:34:13.739
And you run scout search, which
is also called zero window

00:34:13.739 --> 00:34:16.840
search, on the remaining moves
to verify that they're worse.

00:34:16.840 --> 00:34:19.880
So in this example, you,
again, search the most leftmost

00:34:19.880 --> 00:34:20.380
subtree.

00:34:20.380 --> 00:34:23.420
And you see that the best you
can do in the left-most subtree

00:34:23.420 --> 00:34:24.610
is three.

00:34:24.610 --> 00:34:27.030
And you evaluate the
ones to the right

00:34:27.030 --> 00:34:31.750
of it using scout search,
which is not a full search.

00:34:31.750 --> 00:34:33.340
You're basically
assuming that you

00:34:33.340 --> 00:34:35.139
can do no better than three.

00:34:35.139 --> 00:34:38.080
And then now you're kind of
doing an initial search to see

00:34:38.080 --> 00:34:40.489
whether or not that's true.

00:34:40.489 --> 00:34:43.230
And see you see that
some of them are--

00:34:43.230 --> 00:34:46.532
the one after that is seven.

00:34:46.532 --> 00:34:47.949
The first one after
that is seven.

00:34:47.949 --> 00:34:50.215
And the one after that in
the other subtree is six.

00:34:54.600 --> 00:34:59.255
So then you can prune them,
because those are better--

00:34:59.255 --> 00:35:00.630
because you know
already in those

00:35:00.630 --> 00:35:02.430
subtrees that you can
do better than three.

00:35:02.430 --> 00:35:06.120
So you don't have to
keep evaluating them.

00:35:06.120 --> 00:35:08.364
And you don't have to-- yeah?

00:35:08.364 --> 00:35:10.930
AUDIENCE: How do we know
the score of the subtree

00:35:10.930 --> 00:35:14.430
before we evaluate?

00:35:14.430 --> 00:35:17.340
How can we prune something?

00:35:20.020 --> 00:35:21.920
HELEN XU: So you actually
had to find seven.

00:35:21.920 --> 00:35:23.212
Like, zero and eight are there.

00:35:23.212 --> 00:35:25.990
But you haven't found them yet.

00:35:25.990 --> 00:35:29.430
So, basically, if you thought
about doing it serially,

00:35:29.430 --> 00:35:32.790
you do the leftmost subtree,
which has 2, 3, and 0.

00:35:32.790 --> 00:35:34.220
And then you would find seven.

00:35:34.220 --> 00:35:35.970
And that would be a
cut off, because seven

00:35:35.970 --> 00:35:36.900
is bigger than three.

00:35:39.570 --> 00:35:41.490
So you're not actually
finding zero and eight.

00:35:48.260 --> 00:35:50.390
The point is that you
wouldn't get to that subtree,

00:35:50.390 --> 00:35:54.323
because the opponent
wouldn't let you get there,

00:35:54.323 --> 00:35:55.490
because you can do too well.

00:35:55.490 --> 00:36:00.590
So they would just not
let you go down that path.

00:36:00.590 --> 00:36:04.160
Like, let's say you were purple,
and the opponent is orange.

00:36:04.160 --> 00:36:06.500
And you want to get 7 and 8.

00:36:06.500 --> 00:36:08.615
But the opponent can
also search that, and see

00:36:08.615 --> 00:36:09.740
that you would get 7 and 8.

00:36:09.740 --> 00:36:12.320
So they would prefer you to do
something like two or three.

00:36:19.700 --> 00:36:21.320
AUDIENCE: So what
do you do instead?

00:36:26.620 --> 00:36:29.170
HELEN XU: You're not always
making the best move that you

00:36:29.170 --> 00:36:32.690
could possibly do, because--

00:36:32.690 --> 00:36:35.320
like, if you just searched
without this pruning,

00:36:35.320 --> 00:36:37.150
and you just picked--

00:36:37.150 --> 00:36:40.420
let's say you wanted
to make the best move.

00:36:40.420 --> 00:36:42.833
Like, if you don't take
into account the opponent,

00:36:42.833 --> 00:36:44.500
then you're never
going to get to there.

00:36:44.500 --> 00:36:45.940
So you're basically
trying to find a move

00:36:45.940 --> 00:36:47.398
that the opponent
would let you get

00:36:47.398 --> 00:36:53.080
to that's also good for
you, because you switch off.

00:36:59.056 --> 00:37:00.550
Yes?

00:37:00.550 --> 00:37:02.542
AUDIENCE: [INAUDIBLE]

00:37:06.050 --> 00:37:10.120
HELEN XU: I guess in this
example, you're purple.

00:37:10.120 --> 00:37:13.760
No, sorry, you're orange,
because you're cutting off--

00:37:13.760 --> 00:37:15.590
no, you're purple,
because you're

00:37:15.590 --> 00:37:18.513
trying to maximize what
you get at the leaves.

00:37:18.513 --> 00:37:20.395
AUDIENCE: [INAUDIBLE]

00:37:20.395 --> 00:37:20.978
HELEN XU: Yes.

00:37:33.310 --> 00:37:36.368
The main point of-- sorry.

00:37:36.368 --> 00:37:36.910
AUDIENCE: Oh.

00:37:41.502 --> 00:37:42.960
We're trying to
minimize the score.

00:37:46.270 --> 00:37:47.470
HELEN XU: Yes.

00:37:47.470 --> 00:37:49.490
So orange is trying
to minimize the score.

00:37:49.490 --> 00:37:51.282
And purple is trying
to maximize the score.

00:37:53.950 --> 00:37:55.450
AUDIENCE: So we're
cutting that off,

00:37:55.450 --> 00:37:58.932
you're saying you don't need to
search this because we already

00:37:58.932 --> 00:38:01.680
know they're the same here.

00:38:01.680 --> 00:38:03.535
So we shouldn't go
down this path anyway.

00:38:11.790 --> 00:38:13.860
HELEN XU: Does anyone
have questions?

00:38:13.860 --> 00:38:14.850
Does that make sense?

00:38:14.850 --> 00:38:16.558
Yeah, it's basically
exactly as you said.

00:38:16.558 --> 00:38:22.710
So there's kind of this balance
between one side trying--

00:38:22.710 --> 00:38:24.235
both sides are just
trying to make--

00:38:24.235 --> 00:38:25.610
you're trying to
make good moves.

00:38:25.610 --> 00:38:27.960
But you're also trying
to make the opponent make

00:38:27.960 --> 00:38:30.850
not good moves, if
that makes sense.

00:38:30.850 --> 00:38:33.530
So you're not only
searching for your maximum.

00:38:33.530 --> 00:38:37.550
But you're also searching
to minimize the opponent.

00:38:37.550 --> 00:38:38.534
Good question.

00:38:44.974 --> 00:38:46.555
AUDIENCE: [INAUDIBLE]

00:38:58.180 --> 00:39:00.580
HELEN XU: Sorry?

00:39:00.580 --> 00:39:02.150
AUDIENCE: So we
don't want to choose

00:39:02.150 --> 00:39:04.220
either of those orange ones.

00:39:04.220 --> 00:39:06.090
We don't want to let--

00:39:06.090 --> 00:39:06.860
I think it's OK.

00:39:06.860 --> 00:39:08.180
I think you can move on.

00:39:08.180 --> 00:39:10.860
HELEN XU: Oh, OK.

00:39:10.860 --> 00:39:11.775
Yes?

00:39:11.775 --> 00:39:13.400
AUDIENCE: What if
you and your opponent

00:39:13.400 --> 00:39:15.870
have different reward criteria?

00:39:15.870 --> 00:39:19.100
Like, you guys evaluate--

00:39:19.100 --> 00:39:21.140
HELEN XU: That's OK.

00:39:21.140 --> 00:39:23.145
It's fine.

00:39:23.145 --> 00:39:24.770
The actual evaluation,
like what number

00:39:24.770 --> 00:39:28.070
you assign to each position,
is not exposed to the opponent.

00:39:28.070 --> 00:39:30.710
The main point is that, at the
end of each move, you pick one.

00:39:30.710 --> 00:39:34.398
And they can do with
it what they want.

00:39:34.398 --> 00:39:36.440
Like, that may not have
been the one they picked.

00:39:36.440 --> 00:39:37.050
But it's OK.

00:39:51.420 --> 00:39:54.560
Sorry, I think you're
orange in this one,

00:39:54.560 --> 00:39:57.370
because the root is orange.

00:39:57.370 --> 00:39:58.590
AUDIENCE: [INAUDIBLE]

00:40:21.100 --> 00:40:22.470
HELEN XU: So let's start over.

00:40:22.470 --> 00:40:25.770
So I think that we are orange.

00:40:25.770 --> 00:40:28.290
So remember that
each edge is a move.

00:40:28.290 --> 00:40:30.030
And each node is a position.

00:40:30.030 --> 00:40:31.020
And so you're orange.

00:40:31.020 --> 00:40:32.580
And you start at the root.

00:40:32.580 --> 00:40:35.370
And now you, for example,
make the move left.

00:40:35.370 --> 00:40:39.300
And purple now can make moves
whatever three after that.

00:40:39.300 --> 00:40:40.590
And now, you're orange again.

00:40:40.590 --> 00:40:42.215
And then you can make
moves after that.

00:40:42.215 --> 00:40:45.120
And now, you evaluate the
position after that as a leaf.

00:40:48.700 --> 00:40:51.190
And so, basically,
you're searching

00:40:51.190 --> 00:40:53.680
past like the second
level of orange.

00:40:53.680 --> 00:40:57.732
And you are cutting off if you
see that you would do better,

00:40:57.732 --> 00:40:59.440
because you think that
purple would never

00:40:59.440 --> 00:41:02.620
let you get to that
orange node right above.

00:41:02.620 --> 00:41:03.417
Yes?

00:41:03.417 --> 00:41:05.310
AUDIENCE: [INAUDIBLE]

00:41:08.867 --> 00:41:10.950
HELEN XU: Yeah, I guess
that's the score that you,

00:41:10.950 --> 00:41:13.420
as orange would receive.

00:41:13.420 --> 00:41:14.594
Yes?

00:41:14.594 --> 00:41:17.700
AUDIENCE: [INAUDIBLE]

00:41:24.520 --> 00:41:27.317
HELEN XU: You're
not trying to give--

00:41:27.317 --> 00:41:29.650
it's not so much like you're
trying to give purple zero,

00:41:29.650 --> 00:41:33.000
as you think that purple would
not give you seven and eight,

00:41:33.000 --> 00:41:35.332
because purple would have
to go down the left subtree

00:41:35.332 --> 00:41:36.040
to give you that.

00:41:46.798 --> 00:41:47.940
Any other questions?

00:41:52.660 --> 00:41:54.160
I'm going to move
on with the search

00:41:54.160 --> 00:41:58.192
then, if there are no questions.

00:41:58.192 --> 00:41:59.800
[INTERPOSING VOICES]

00:42:11.510 --> 00:42:14.420
HELEN XU: Is everyone good?

00:42:14.420 --> 00:42:16.620
Can I keep going?

00:42:16.620 --> 00:42:22.600
OK, so just going back to
principal variations pruning,

00:42:22.600 --> 00:42:25.870
the main idea is
that you go down

00:42:25.870 --> 00:42:28.300
the first path on the
left side, thinking

00:42:28.300 --> 00:42:31.330
that that's the best path.

00:42:31.330 --> 00:42:33.247
And then you're basically
doing initial passes

00:42:33.247 --> 00:42:35.497
through the trees to make
sure that your assumption is

00:42:35.497 --> 00:42:36.040
correct.

00:42:36.040 --> 00:42:37.030
And if they're not
correct, then you

00:42:37.030 --> 00:42:38.590
have to search the
entire subtree.

00:42:38.590 --> 00:42:40.360
But if they are correct,
then you kind of

00:42:40.360 --> 00:42:44.350
fail, you early exit.

00:42:44.350 --> 00:42:47.230
So you search down
the left subtree.

00:42:47.230 --> 00:42:50.007
And you find three in
the leftmost subtree.

00:42:50.007 --> 00:42:52.090
And now, you search the
ones to the right of that.

00:42:52.090 --> 00:42:53.530
And those are seven and eight.

00:42:53.530 --> 00:42:56.500
So those produce a cutoff,
because seven and eight

00:42:56.500 --> 00:42:57.513
is higher than three.

00:42:57.513 --> 00:42:58.930
So you think that
purple would not

00:42:58.930 --> 00:43:00.097
let you get to that subtree.

00:43:03.040 --> 00:43:08.640
And now, you do a scout search
again on the middle subtree.

00:43:08.640 --> 00:43:11.630
And then you see that--

00:43:11.630 --> 00:43:14.280
you find this first node of
each one of those subtrees

00:43:14.280 --> 00:43:15.660
underneath the middle subtree.

00:43:15.660 --> 00:43:18.300
And you see that they're
all higher than three.

00:43:18.300 --> 00:43:24.990
So it turns out that you
failed to prove that you

00:43:24.990 --> 00:43:26.603
can do no better than three.

00:43:26.603 --> 00:43:28.020
The main point of
the scout search

00:43:28.020 --> 00:43:29.970
is that you assume that your
first move that you search

00:43:29.970 --> 00:43:31.170
is the best you can do.

00:43:31.170 --> 00:43:34.530
And then you do initial passes
to verify that assumption.

00:43:34.530 --> 00:43:37.375
And if you search later
subtrees, and you find that--

00:43:37.375 --> 00:43:39.000
for example, in this
one in the middle,

00:43:39.000 --> 00:43:40.292
they're all higher than threes.

00:43:40.292 --> 00:43:41.650
So your assumption is not true.

00:43:41.650 --> 00:43:43.320
So now you have to
do a full search

00:43:43.320 --> 00:43:46.765
of that entire middle subtree.

00:43:46.765 --> 00:43:48.745
Is that OK?

00:43:48.745 --> 00:43:50.725
Are there questions?

00:43:56.170 --> 00:44:00.280
So once you find that you
have to actually search

00:44:00.280 --> 00:44:02.950
the middle subtree, you can
recursively apply scout search.

00:44:02.950 --> 00:44:05.530
So you have to search the
left subtree in the middle.

00:44:05.530 --> 00:44:09.610
But now, you apply scout
search to the lower middle

00:44:09.610 --> 00:44:11.867
and the lower right.

00:44:11.867 --> 00:44:13.450
And you do a zero
window search there.

00:44:13.450 --> 00:44:16.210
And, again, you assume that
you can do no better than six.

00:44:16.210 --> 00:44:17.918
And now, you're trying
to verify that you

00:44:17.918 --> 00:44:19.570
can do better than six.

00:44:19.570 --> 00:44:20.620
But you actually can.

00:44:20.620 --> 00:44:23.780
So you have to search them.

00:44:23.780 --> 00:44:27.320
And then you apply the same
thing again to the subtree.

00:44:27.320 --> 00:44:29.450
And you see that you
can do better than six

00:44:29.450 --> 00:44:30.640
on the left one.

00:44:30.640 --> 00:44:34.660
But you do worse than
six on the right one.

00:44:34.660 --> 00:44:38.510
And you cut off two, because the
middle subtree already gave you

00:44:38.510 --> 00:44:40.660
two.

00:44:40.660 --> 00:44:43.220
And so you don't have
to search that one.

00:44:43.220 --> 00:44:46.822
So in this example, there
were 13 leaves pruned.

00:44:46.822 --> 00:44:48.530
And the point of scout
search is that you

00:44:48.530 --> 00:44:51.340
can improve pruning a
little bit over alpha beta,

00:44:51.340 --> 00:44:53.090
and that you process
most of the game tree

00:44:53.090 --> 00:44:54.507
with zero window searches.

00:44:54.507 --> 00:44:56.840
The main point is that it
reduces your work, because you

00:44:56.840 --> 00:44:57.770
have to process less.

00:45:02.234 --> 00:45:03.226
Questions?

00:45:08.700 --> 00:45:11.430
So now we're going to talk
about-- so I kind of glossed

00:45:11.430 --> 00:45:12.870
over how you order the moves.

00:45:12.870 --> 00:45:15.660
So the ordering
determines which order

00:45:15.660 --> 00:45:18.360
you explore the subtrees in.

00:45:18.360 --> 00:45:20.360
Alpha-beta search and
principal variation search

00:45:20.360 --> 00:45:22.320
depend on putting the
best moves in the front

00:45:22.320 --> 00:45:24.240
to trigger an early cut off.

00:45:24.240 --> 00:45:25.990
And the main question
is, how do we

00:45:25.990 --> 00:45:27.630
determine moves,
which moves are good,

00:45:27.630 --> 00:45:29.588
without doing static
evaluation at every level?

00:45:29.588 --> 00:45:31.650
Like, for example, we
only did static evaluation

00:45:31.650 --> 00:45:32.790
with the leaves.

00:45:32.790 --> 00:45:34.590
And we can't get
sortable move list,

00:45:34.590 --> 00:45:36.510
which is a function in search.

00:45:36.510 --> 00:45:40.043
And sortable move
lists, kind of talk

00:45:40.043 --> 00:45:41.460
about how you
populate that later.

00:45:45.060 --> 00:45:47.410
As I said before, moves are
represented in 128 bits.

00:45:47.410 --> 00:45:49.260
So you can use it in 32.

00:45:49.260 --> 00:45:51.760
And to make them sortable,
you store a sort key

00:45:51.760 --> 00:45:54.510
in the upper 32 bits in 64.

00:45:54.510 --> 00:45:58.060
And then you sort,
based on that key.

00:45:58.060 --> 00:45:58.820
That make sense?

00:46:05.940 --> 00:46:09.420
So I'll just go over some search
optimizations that you can do.

00:46:09.420 --> 00:46:10.920
We actually implement
these already.

00:46:10.920 --> 00:46:11.940
So I'm just going
to go through them

00:46:11.940 --> 00:46:14.640
so it's not super confusing
when you look at the code.

00:46:14.640 --> 00:46:17.940
The most important one is
called the transposition table.

00:46:17.940 --> 00:46:20.070
The main idea in the
transposition table

00:46:20.070 --> 00:46:22.650
is that chess programs often
encounter the same positions

00:46:22.650 --> 00:46:24.450
repeatedly during a search.

00:46:24.450 --> 00:46:27.150
And you can store those results
in a transposition table

00:46:27.150 --> 00:46:29.642
to avoid unnecessary
feature searches.

00:46:29.642 --> 00:46:31.350
And I've listed where
you can find those.

00:46:35.590 --> 00:46:37.370
There's something
called Zobrist hashing,

00:46:37.370 --> 00:46:39.760
which is a technique for
hashing a board position which

00:46:39.760 --> 00:46:42.142
you use to index the
transmission table.

00:46:42.142 --> 00:46:44.350
And it's a table of random
numbers, indexed by piece,

00:46:44.350 --> 00:46:45.700
orientation, and square.

00:46:45.700 --> 00:46:49.948
So each position
has a unique hash.

00:46:49.948 --> 00:46:51.490
And it produces the
hash by exporting

00:46:51.490 --> 00:46:53.560
all of these random
numbers together.

00:46:53.560 --> 00:46:55.660
And the advantage
of Zobrist hashing

00:46:55.660 --> 00:46:58.330
is that the hash function can
be updated incrementally, which

00:46:58.330 --> 00:47:00.670
is like if you move a
position-- if you move a piece,

00:47:00.670 --> 00:47:01.630
you just xor it out.

00:47:01.630 --> 00:47:03.670
And then you xor
the new one, so you

00:47:03.670 --> 00:47:06.244
don't have to recompute
the hash each time.

00:47:11.330 --> 00:47:14.660
So the transposition table
saves you a lot of work

00:47:14.660 --> 00:47:17.697
by preventing you from
researching things.

00:47:17.697 --> 00:47:20.030
And there's also something
called the killer move table.

00:47:20.030 --> 00:47:21.613
So the transposition
table is like how

00:47:21.613 --> 00:47:25.430
you determine how to
do sorting at things

00:47:25.430 --> 00:47:27.860
that are not the leaves, and
also the killing moves table.

00:47:27.860 --> 00:47:29.770
So the killer
moves people stores

00:47:29.770 --> 00:47:32.270
moves that are really good so
that the opponent wouldn't let

00:47:32.270 --> 00:47:34.160
you go down that path,
so you have to keep

00:47:34.160 --> 00:47:36.410
recomputing the same values.

00:47:36.410 --> 00:47:38.480
And the table is indexed
by ply, because you

00:47:38.480 --> 00:47:41.960
tend to see the same
moves at the same depth.

00:47:41.960 --> 00:47:44.180
So the killer move table,
basically, just stores

00:47:44.180 --> 00:47:46.870
move that trigger the beta
cut off before in your search.

00:47:53.270 --> 00:47:55.967
There's a best move
table, which is stored

00:47:55.967 --> 00:47:57.050
at the root of the search.

00:47:57.050 --> 00:48:00.230
And it is the move that
got the maximum score

00:48:00.230 --> 00:48:01.820
in your evaluation.

00:48:01.820 --> 00:48:04.040
And the best move table
is indexed by color,

00:48:04.040 --> 00:48:06.560
piece, square, and orientation.

00:48:06.560 --> 00:48:09.715
And there's a history
table in the code.

00:48:09.715 --> 00:48:11.090
So these are all,
basically, just

00:48:11.090 --> 00:48:12.757
things to help you
optimize your search,

00:48:12.757 --> 00:48:14.400
and produce early cut offs.

00:48:17.862 --> 00:48:20.070
And there's something called
null-move pruning, which

00:48:20.070 --> 00:48:22.463
tries to reduce your
search space by first

00:48:22.463 --> 00:48:24.630
not moving, and then doing
a shallower search to see

00:48:24.630 --> 00:48:26.760
if this subtree is
worth further exploring.

00:48:29.318 --> 00:48:31.110
Basically, it says,
don't move, and then do

00:48:31.110 --> 00:48:32.830
a little bit of evaluation.

00:48:32.830 --> 00:48:35.520
And if you're still
doing really well,

00:48:35.520 --> 00:48:37.350
even if you didn't
move in the subtree,

00:48:37.350 --> 00:48:39.642
then it's not worth exploring,
because the opponent

00:48:39.642 --> 00:48:41.850
would never let you go there,
because the position is

00:48:41.850 --> 00:48:42.350
too good.

00:48:45.890 --> 00:48:47.990
There's futility
pruning, which explores

00:48:47.990 --> 00:48:51.050
moves that only have the
potential to increase alpha.

00:48:51.050 --> 00:48:52.550
And it calculates
that possibility

00:48:52.550 --> 00:48:54.320
by adding a futility
margin, which

00:48:54.320 --> 00:48:57.770
is the most you could possibly
gain from going there, and then

00:48:57.770 --> 00:48:59.380
evaluating a little bit.

00:48:59.380 --> 00:49:01.380
And if the result does
not go higher than alpha,

00:49:01.380 --> 00:49:03.298
then you skip it,
because there's

00:49:03.298 --> 00:49:05.090
no point in even going
that way, because it

00:49:05.090 --> 00:49:06.298
wouldn't increase your alpha.

00:49:11.410 --> 00:49:13.600
There's late move
reduction, which

00:49:13.600 --> 00:49:15.880
is after you order the
moves at a position,

00:49:15.880 --> 00:49:19.090
you explore the-- the-- ones in
front are likely to be better.

00:49:19.090 --> 00:49:20.890
So you explore those
in higher depth.

00:49:20.890 --> 00:49:24.102
And then you explore the ones
later with shallower depth,

00:49:24.102 --> 00:49:25.810
because those are less
likely to be good.

00:49:29.770 --> 00:49:33.340
And some things that
you can optimize

00:49:33.340 --> 00:49:37.480
are implementing a
better opening book.

00:49:37.480 --> 00:49:40.000
I think we have produced
a very basic opening

00:49:40.000 --> 00:49:41.365
book in the handout.

00:49:41.365 --> 00:49:43.240
But this is something
that you can definitely

00:49:43.240 --> 00:49:44.710
work on, and make better,
because it doesn't have

00:49:44.710 --> 00:49:46.450
many positions in it right now.

00:49:46.450 --> 00:49:47.500
And the main point
of an opening book

00:49:47.500 --> 00:49:49.540
is that you store the positions
at the beginning of the game

00:49:49.540 --> 00:49:51.052
that you've already
pre-computed.

00:49:51.052 --> 00:49:53.260
And that saves time and
search, and can store results

00:49:53.260 --> 00:49:54.670
to a higher depth.

00:49:54.670 --> 00:49:57.310
And the KM75 theorem
implies it's better

00:49:57.310 --> 00:50:00.220
to keep separate opening books
than to keep the same opening

00:50:00.220 --> 00:50:01.570
book for both sides.

00:50:01.570 --> 00:50:03.070
So opening books
are really helpful,

00:50:03.070 --> 00:50:05.650
because in the beginning,
there's a huge number of moves

00:50:05.650 --> 00:50:06.910
that you could possibly make.

00:50:06.910 --> 00:50:08.720
And searching those
takes a lot of time.

00:50:08.720 --> 00:50:11.710
But if you pre-compute them,
you can save them for later.

00:50:14.930 --> 00:50:16.705
And another useful
table you can keep

00:50:16.705 --> 00:50:18.080
is an end game
database, which is

00:50:18.080 --> 00:50:21.710
a table for guiding your chess
program through the end game.

00:50:21.710 --> 00:50:24.050
For end game positions,
the distance from the end

00:50:24.050 --> 00:50:26.060
might be too far
to search entirely.

00:50:26.060 --> 00:50:27.570
So you can pre-compute them.

00:50:27.570 --> 00:50:29.570
And then you store who
will win, and how far you

00:50:29.570 --> 00:50:31.130
are from the end of the game.

00:50:31.130 --> 00:50:34.960
And we've given you a c file
that you can implement it in.

00:50:44.270 --> 00:50:46.400
OK, so I'll just go
through some guidelines,

00:50:46.400 --> 00:50:48.950
some tips for the project.

00:50:48.950 --> 00:50:50.960
I was giving links
at most of the bottom

00:50:50.960 --> 00:50:54.770
of the slides for where you can
read up more on these topics.

00:50:54.770 --> 00:50:56.550
But there's a chess
programming wiki.

00:50:56.550 --> 00:51:00.170
The link is there, which has
many more pages about reading

00:51:00.170 --> 00:51:03.933
about chess playing programs.

00:51:03.933 --> 00:51:05.600
Just in general, it's
a really good idea

00:51:05.600 --> 00:51:07.142
to test your code
often, because it's

00:51:07.142 --> 00:51:09.290
easy to make a mistake
with your optimizations.

00:51:09.290 --> 00:51:12.320
And it doesn't appear when
you search to fixed depth.

00:51:12.320 --> 00:51:15.470
So if you start up your
bot, you can say, like,

00:51:15.470 --> 00:51:17.700
search to depth 5, for example.

00:51:17.700 --> 00:51:20.628
And then it will tell you like
how many nodes per seconds

00:51:20.628 --> 00:51:21.170
you searched.

00:51:21.170 --> 00:51:24.320
And then I'll tell you the best
move at the end of that search.

00:51:24.320 --> 00:51:27.298
But you should test
full games using

00:51:27.298 --> 00:51:29.090
the auto tester, and
the cloud auto tester,

00:51:29.090 --> 00:51:32.090
and the script server,
just to watch your bot

00:51:32.090 --> 00:51:34.280
to make sure that it
doesn't do anything weird.

00:51:34.280 --> 00:51:36.950
And the testing methodology,
I went through some of it.

00:51:36.950 --> 00:51:37.730
There's a webgui.

00:51:37.730 --> 00:51:38.870
There's a Java autotester.

00:51:38.870 --> 00:51:40.343
There's a cloud autotester.

00:51:40.343 --> 00:51:42.260
And you can do node
counts, which is basically

00:51:42.260 --> 00:51:44.960
just counting the number
of nodes in the tree

00:51:44.960 --> 00:51:45.740
that you searched.

00:51:45.740 --> 00:51:47.407
And there's function
comparison testing,

00:51:47.407 --> 00:51:49.160
which is, if you
optimize a function,

00:51:49.160 --> 00:51:51.290
you should save the
old version, and then

00:51:51.290 --> 00:51:52.370
just compare the results.

00:51:55.990 --> 00:52:01.710
PROFESSOR: Let me make
a comment about testing.

00:52:01.710 --> 00:52:03.750
I can't tell you how
often in this class

00:52:03.750 --> 00:52:09.090
we've had student groups
who discover that they've

00:52:09.090 --> 00:52:11.610
made a whole bunch of changes.

00:52:11.610 --> 00:52:14.700
And then there's something
wrong with their bot.

00:52:14.700 --> 00:52:17.310
And they can't get
back to a stable place

00:52:17.310 --> 00:52:18.420
when things were correct.

00:52:18.420 --> 00:52:20.100
They discover the problem.

00:52:20.100 --> 00:52:23.430
But they've made 30 changes.

00:52:23.430 --> 00:52:27.130
And now, which of those 30 is
responsible for the problem?

00:52:27.130 --> 00:52:32.010
So it's really
important to test,

00:52:32.010 --> 00:52:33.780
and have a good
test infrastructure

00:52:33.780 --> 00:52:34.803
for this project.

00:52:34.803 --> 00:52:36.720
If you have a really
good test infrastructure,

00:52:36.720 --> 00:52:40.290
it's really easy to be
innovative in the kinds

00:52:40.290 --> 00:52:42.870
of optimizations that
you do, because then you

00:52:42.870 --> 00:52:45.055
know that what you're
doing is right.

00:52:45.055 --> 00:52:46.680
And then you can make
forward progress.

00:52:46.680 --> 00:52:50.400
Otherwise, you'll find yourself
self debugging like crazy,

00:52:50.400 --> 00:52:53.130
and not being able
to find the bugs.

00:52:53.130 --> 00:52:57.060
Some other tips
are, especially when

00:52:57.060 --> 00:52:58.650
we get to the
parallel part, it's

00:52:58.650 --> 00:53:02.220
non-deterministic programming.

00:53:02.220 --> 00:53:03.690
And the reason is
because as you're

00:53:03.690 --> 00:53:07.350
executing you're going
to be looking up things

00:53:07.350 --> 00:53:10.620
in transposition table that
you're going to want to share,

00:53:10.620 --> 00:53:15.060
so that if one branch
discovers a value then

00:53:15.060 --> 00:53:18.450
another branch can use that.

00:53:18.450 --> 00:53:20.520
So it's really important
to be able to turn that

00:53:20.520 --> 00:53:23.880
off so that you're, for
example, able to search

00:53:23.880 --> 00:53:25.920
without a transposition
table to get all

00:53:25.920 --> 00:53:29.040
the searching stuff right,
and be able to turn that

00:53:29.040 --> 00:53:30.220
on independently.

00:53:30.220 --> 00:53:34.360
So that's another really
important place to do it.

00:53:34.360 --> 00:53:38.670
Another thing is that when
you do timed searches,

00:53:38.670 --> 00:53:42.120
the time it takes to do
the search will vary.

00:53:42.120 --> 00:53:44.070
And what you'll end
up exploring varies.

00:53:44.070 --> 00:53:49.020
So as much as possible, you
wanted to fix depth searches.

00:53:49.020 --> 00:53:52.980
Search to five ply
to test something,

00:53:52.980 --> 00:53:56.670
rather than searching
for a minute,

00:53:56.670 --> 00:53:59.190
or whatever the
amount of time is,

00:53:59.190 --> 00:54:01.800
because when you start
searching for time,

00:54:01.800 --> 00:54:04.290
that's, in fact, what you're
going to end up doing.

00:54:04.290 --> 00:54:08.580
But you can't repeat what
just happened if you end up

00:54:08.580 --> 00:54:10.020
searching for that
amount of time

00:54:10.020 --> 00:54:14.220
again, because the machines
are not deterministic.

00:54:14.220 --> 00:54:16.380
And there may be
something else going

00:54:16.380 --> 00:54:21.000
on that causes the amount
of time to be different.

00:54:21.000 --> 00:54:26.130
And so, for example, if
you're making a change that

00:54:26.130 --> 00:54:28.410
doesn't affect the
logic of the program,

00:54:28.410 --> 00:54:31.710
it's just strictly
an optimization,

00:54:31.710 --> 00:54:33.750
you should get exactly
the same result

00:54:33.750 --> 00:54:36.930
if you do a five ply
search, for example.

00:54:36.930 --> 00:54:39.660
Shouldn't have changed
the five ply search.

00:54:39.660 --> 00:54:42.512
Just a five ply search
should be faster.

00:54:42.512 --> 00:54:44.470
And so that's a good
way-- as much as possible,

00:54:44.470 --> 00:54:48.300
you want to check things that
are deterministic and so forth.

00:54:48.300 --> 00:54:52.680
And, really, as I say, I
can't emphasize this enough,

00:54:52.680 --> 00:54:54.750
how having a good
test infrastructure,

00:54:54.750 --> 00:54:58.410
the ability to control
turn off non-determinism,

00:54:58.410 --> 00:55:03.160
the ability to test various
parts of this program,

00:55:03.160 --> 00:55:05.430
this is a pretty
big piece of code

00:55:05.430 --> 00:55:09.300
for a project of this nature.

00:55:09.300 --> 00:55:11.430
And you'll feel pretty
overwhelmed by it

00:55:11.430 --> 00:55:12.540
to begin with.

00:55:12.540 --> 00:55:14.580
Once you settle,
you'll discover,

00:55:14.580 --> 00:55:17.970
it's this wonderful thing,
where by the end of the project

00:55:17.970 --> 00:55:21.420
everybody feels really confident
about their ability to handle

00:55:21.420 --> 00:55:23.243
a decent sized piece of code.

00:55:23.243 --> 00:55:25.660
But when you first get into
it, it's like, oh my goodness.

00:55:25.660 --> 00:55:26.577
There's move ordering.

00:55:26.577 --> 00:55:28.050
And there's static evaluation.

00:55:28.050 --> 00:55:29.310
And there's the search.

00:55:29.310 --> 00:55:31.770
And what's going on with
that transposition table?

00:55:31.770 --> 00:55:34.200
Because every one of
these things has got

00:55:34.200 --> 00:55:35.910
cleverness in it.

00:55:35.910 --> 00:55:39.240
OK, so it's really
hard code to deal with.

00:55:39.240 --> 00:55:41.490
But you guys are
going to just fine.

00:55:41.490 --> 00:55:48.240
HELEN XU: So this is the
eval.c file in the handout.

00:55:48.240 --> 00:55:51.430
So this in 32 here is
the evaluation score.

00:55:51.430 --> 00:55:54.510
And the main function
is called eval.

00:55:54.510 --> 00:55:56.430
And it takes in a position.

00:55:56.430 --> 00:56:01.020
And it outputs two scores, one
for white and one for black.

00:56:03.720 --> 00:56:05.280
And right now, it does--

00:56:08.720 --> 00:56:10.920
I guess it does counts
of the number of pawns.

00:56:10.920 --> 00:56:15.220
OK, so I was talking before
about, p between and p central,

00:56:15.220 --> 00:56:17.050
which are you pawn heuristics.

00:56:17.050 --> 00:56:18.730
And so basically,
right now, it iterates

00:56:18.730 --> 00:56:20.440
through the entire board.

00:56:20.440 --> 00:56:23.680
You can see for rank and
file are just row and column.

00:56:23.680 --> 00:56:26.890
And it looks at each
square in the iteration.

00:56:26.890 --> 00:56:30.190
And then it looks at the piece
and the color of the piece.

00:56:30.190 --> 00:56:33.152
And based on the type of the
piece, it does some evaluation.

00:56:33.152 --> 00:56:35.110
So if it's a pawn, it
does the pawn heuristics.

00:56:35.110 --> 00:56:38.380
If it's a fits king, it
does these king heuristics.

00:56:38.380 --> 00:56:40.860
And otherwise, or both--

00:56:40.860 --> 00:56:43.900
or not otherwise, I guess--

00:56:43.900 --> 00:56:47.122
yeah, in both cases it'll do--

00:56:47.122 --> 00:56:48.080
this is an old version.

00:56:48.080 --> 00:56:49.163
So it's not there anymore.

00:56:49.163 --> 00:56:51.430
But this is laser
coverage, which

00:56:51.430 --> 00:56:55.030
we talked about
earlier, which doesn't

00:56:55.030 --> 00:56:56.690
depend on what piece it is.

00:56:56.690 --> 00:57:01.570
This is after you iterate
through the entire board.

00:57:01.570 --> 00:57:04.350
And then this isn't
here anymore either.

00:57:04.350 --> 00:57:06.100
But we can look at
each of these in depth.

00:57:06.100 --> 00:57:07.517
So right now, for
example, there's

00:57:07.517 --> 00:57:18.500
p between, which goes
through every single pawn

00:57:18.500 --> 00:57:19.280
in your iteration.

00:57:19.280 --> 00:57:21.230
And then it will
determine whether or not

00:57:21.230 --> 00:57:26.300
it's between both kings,
and the return slide.

00:57:26.300 --> 00:57:30.980
So it will add it to the score,
if you find that it's true.

00:57:30.980 --> 00:57:38.920
And there's p central, which
takes in a rank and a file.

00:57:38.920 --> 00:57:41.913
And, basically, it
increments something,

00:57:41.913 --> 00:57:43.330
or it gives you a
bonus, depending

00:57:43.330 --> 00:57:46.863
on how close you are to
the center of the board.

00:57:46.863 --> 00:57:47.530
So look at this.

00:57:47.530 --> 00:57:49.630
There's a board with--

00:57:49.630 --> 00:57:51.740
and F as your file.

00:57:51.740 --> 00:57:52.600
And R is your rank.

00:57:56.860 --> 00:57:59.380
PROFESSOR: I think you have
a slightly older version.

00:57:59.380 --> 00:58:01.740
HELEN XU: Potentially.

00:58:01.740 --> 00:58:04.530
PROFESSOR: It's
correct on the screen.

00:58:04.530 --> 00:58:06.125
HELEN XU: Is
correct in this one?

00:58:06.125 --> 00:58:06.750
AUDIENCE: Yeah.

00:58:25.930 --> 00:58:28.310
HELEN XU: OK, so
this is just the--

00:58:28.310 --> 00:58:29.810
I guess is the most
updated version.

00:58:29.810 --> 00:58:31.070
The first one is p central.

00:58:31.070 --> 00:58:33.680
So this just count
the difference

00:58:33.680 --> 00:58:35.930
between where you are and
the center of the board.

00:58:35.930 --> 00:58:38.750
And it gives you some
bonus, depending on how far

00:58:38.750 --> 00:58:40.430
you are from the center.

00:58:40.430 --> 00:58:42.750
And this one is between.

00:58:42.750 --> 00:58:45.472
Yeah, so this is between, which
is a helper for p between.

00:58:45.472 --> 00:58:47.180
And it tells you
whether or not your pawn

00:58:47.180 --> 00:58:51.200
is in the bounding box
determined by the kings.

00:58:51.200 --> 00:58:57.580
And this one is k face,
which is given a king,

00:58:57.580 --> 00:59:00.020
you look at its orientation.

00:59:00.020 --> 00:59:02.240
And then you give it
a bonus, depending

00:59:02.240 --> 00:59:05.840
on which way you're
facing, and how far you

00:59:05.840 --> 00:59:07.730
are from the center, I think--

00:59:07.730 --> 00:59:10.250
no, how far you are
from the opponent.

00:59:10.250 --> 00:59:12.140
So f and r where you are.

00:59:12.140 --> 00:59:18.140
And now it does the delta
between you and the opposing

00:59:18.140 --> 00:59:20.520
king.

00:59:20.520 --> 00:59:23.300
And then you do some scaling,
depending on which direction

00:59:23.300 --> 00:59:23.960
you're facing.

00:59:23.960 --> 00:59:25.668
So this is just
your orientation.

00:59:28.360 --> 00:59:30.790
And then this is k
aggressive, which

00:59:30.790 --> 00:59:33.070
gives you a bonus
for how far you

00:59:33.070 --> 00:59:35.380
are from the edge of the board.

00:59:35.380 --> 00:59:41.740
So you can see here op square is
where do the opposing king is.

00:59:41.740 --> 00:59:47.020
And delta file and
delta rank are how far

00:59:47.020 --> 00:59:49.150
you are from the opposing king.

00:59:49.150 --> 00:59:54.130
And then you add the bonus,
depending on which case

00:59:54.130 --> 00:59:55.400
the deltas fall into.

00:59:59.700 --> 01:00:04.180
And this gives you a
bonus if you're farther

01:00:04.180 --> 01:00:07.180
from the edge of the board.

01:00:07.180 --> 01:00:12.520
Yeah, and there's
l coverage, which

01:00:12.520 --> 01:00:15.970
is the most complicated
one, probably.

01:00:15.970 --> 01:00:19.090
And, basically, what laser
coverage does is that,

01:00:19.090 --> 01:00:20.560
basically, it takes a position.

01:00:20.560 --> 01:00:22.120
And depending on
what side you are,

01:00:22.120 --> 01:00:24.203
it generates all the moves
that you could possibly

01:00:24.203 --> 01:00:25.300
make from that position.

01:00:25.300 --> 01:00:30.310
So you generate all
with color, which

01:00:30.310 --> 01:00:31.720
means that, given
your color, you

01:00:31.720 --> 01:00:34.030
generate all the possible
moves that you can make.

01:00:34.030 --> 01:00:35.260
And you get a list of moves.

01:00:35.260 --> 01:00:37.060
And you iterate through it.

01:00:37.060 --> 01:00:38.890
And then you make each of them.

01:00:38.890 --> 01:00:40.510
And you draw a laser path.

01:00:40.510 --> 01:00:43.990
And what the laser path
does is, basically, it

01:00:43.990 --> 01:00:45.760
bounces off some pause.

01:00:45.760 --> 01:00:49.240
And for each square, you
increment the distance,

01:00:49.240 --> 01:00:51.410
basically, along the path.

01:00:51.410 --> 01:00:54.163
And if it takes the
minimum distance

01:00:54.163 --> 01:00:56.080
over all these possible
paths for each square.

01:00:56.080 --> 01:00:59.290
And if it doesn't touch a
square, then it's just 0.

01:00:59.290 --> 01:01:00.710
And it divides it.

01:01:00.710 --> 01:01:01.870
I can go into this.

01:01:04.620 --> 01:01:08.390
So it draws the path
through this while true.

01:01:11.970 --> 01:01:14.100
Or this is just
changing the orientation

01:01:14.100 --> 01:01:16.290
if you need to
bounce off a pawn.

01:01:16.290 --> 01:01:19.990
But this one is setting the--

01:01:19.990 --> 01:01:21.000
you keep a laser map.

01:01:21.000 --> 01:01:23.670
And you keep the
minimum path of a laser

01:01:23.670 --> 01:01:26.250
that would possibly touch that.

01:01:26.250 --> 01:01:31.290
And, no, this is just
changing the orientation.

01:01:34.117 --> 01:01:36.450
So then you generate this map
for all the possible moves

01:01:36.450 --> 01:01:37.680
that you could do.

01:01:37.680 --> 01:01:39.660
And then you do some scaling.

01:01:39.660 --> 01:01:44.350
So, depending on the distance
from the opposing king,

01:01:44.350 --> 01:01:46.350
you iterate through
the entire board.

01:01:46.350 --> 01:01:52.110
And you divide the
minimum distance

01:01:52.110 --> 01:01:54.670
by the actual distance
from the laser.

01:01:54.670 --> 01:01:58.710
So the maximum that
this ratio can be is 1.

01:01:58.710 --> 01:02:06.000
And then you multiply it
by 1 over the distance.

01:02:08.583 --> 01:02:10.000
So this one is
really complicated.

01:02:10.000 --> 01:02:11.790
And there's a lot
to optimize here.

01:02:11.790 --> 01:02:13.740
For example, you
probably don't have

01:02:13.740 --> 01:02:15.700
to iterate through
the entire board

01:02:15.700 --> 01:02:23.280
each time, because even
in eval, like here, you

01:02:23.280 --> 01:02:25.290
have to iterate through
the entire board

01:02:25.290 --> 01:02:27.092
to find each piece.

01:02:27.092 --> 01:02:28.800
And if you start a
better representation,

01:02:28.800 --> 01:02:30.360
you might not have to do
that, like if you just

01:02:30.360 --> 01:02:32.010
kept track of where
the pawns were,

01:02:32.010 --> 01:02:34.538
because you already keep
track of the king separately.

01:02:34.538 --> 01:02:35.830
So that's one thing you can do.

01:02:40.080 --> 01:02:42.000
PROFESSOR: There are
two basic strategies

01:02:42.000 --> 01:02:44.820
for changing the
representation of the board.

01:02:44.820 --> 01:02:46.740
And maybe there are more.

01:02:46.740 --> 01:02:49.770
But the two basic
ones are, instead

01:02:49.770 --> 01:02:55.590
of keeping the whole board
with a piece on each square,

01:02:55.590 --> 01:02:58.890
and then having to go and
search for where the pieces are,

01:02:58.890 --> 01:03:02.400
you can keep just a list
of where the pawns are,

01:03:02.400 --> 01:03:05.010
and what the locations
of the kings are,

01:03:05.010 --> 01:03:06.670
so that when you
want to make a move,

01:03:06.670 --> 01:03:09.690
you can just go
through where they are,

01:03:09.690 --> 01:03:12.420
rather than having to search
through all 64 squares

01:03:12.420 --> 01:03:13.800
on the board.

01:03:13.800 --> 01:03:15.570
Then the other strategy
that you can do

01:03:15.570 --> 01:03:18.150
is use what's called
bit boards, where

01:03:18.150 --> 01:03:27.480
you have a 64-bit word
for which, if there's

01:03:27.480 --> 01:03:32.460
a pawn in a given
position, you set that bit.

01:03:32.460 --> 01:03:35.970
And so there are different
ways of representing

01:03:35.970 --> 01:03:41.860
things that could possibly be,
definitely be, more efficient.

01:03:41.860 --> 01:03:43.440
But you have some choices there.

01:03:43.440 --> 01:03:46.260
And also, one of the
complexities of this

01:03:46.260 --> 01:03:48.630
is that to change
the representation,

01:03:48.630 --> 01:03:50.940
there's going to be
places in the code you

01:03:50.940 --> 01:03:56.700
need to find out where they're
assuming that things are.

01:03:56.700 --> 01:03:59.310
So you say, oh, I'll change
the board representation.

01:03:59.310 --> 01:04:01.530
Oh, I didn't realize
that over here, there's

01:04:01.530 --> 01:04:04.410
another place that it's using
the board representation,

01:04:04.410 --> 01:04:05.340
and so forth.

01:04:05.340 --> 01:04:08.820
A good strategy for changing
board representation

01:04:08.820 --> 01:04:15.720
is to actually keep both
representations around

01:04:15.720 --> 01:04:18.600
while you migrate
functionality from the old one

01:04:18.600 --> 01:04:20.940
to the new one.

01:04:20.940 --> 01:04:25.620
And then the advantage of
that is that you can actually

01:04:25.620 --> 01:04:28.560
then use assertions
to say, you know,

01:04:28.560 --> 01:04:32.860
the old one and the
new one are the same.

01:04:32.860 --> 01:04:38.385
So implementing conversion
functions is really good.

01:04:38.385 --> 01:04:39.760
For example, if
you decide you're

01:04:39.760 --> 01:04:42.460
going to use a bit
board representation,

01:04:42.460 --> 01:04:45.700
have a function that
converts the bit board

01:04:45.700 --> 01:04:50.050
to the standard board
so that then you

01:04:50.050 --> 01:04:55.660
can compare whether
you've got the same thing.

01:04:55.660 --> 01:05:00.678
And, eventually, you'll
want to get rid of that.

01:05:00.678 --> 01:05:02.470
And, of course, that'll
slow down you down,

01:05:02.470 --> 01:05:04.480
because you're
doing more things.

01:05:04.480 --> 01:05:06.640
But it will allow
you to get it correct

01:05:06.640 --> 01:05:08.880
with a new representation.

01:05:08.880 --> 01:05:11.290
And once you've got it correct
with a new representation

01:05:11.290 --> 01:05:14.710
with the old one gone,
that's when you have a chance

01:05:14.710 --> 01:05:17.320
to make things go fast.

01:05:17.320 --> 01:05:21.430
But it kind of is taking
two steps backwards

01:05:21.430 --> 01:05:23.260
to take five steps forward.

01:05:23.260 --> 01:05:27.640
I say not one step and two
steps, because really, often,

01:05:27.640 --> 01:05:31.870
you really are slowing things
down considerably in order

01:05:31.870 --> 01:05:35.350
to convert from one
representation to another.

01:05:35.350 --> 01:05:38.560
The most important thing is
you maintain the invariant

01:05:38.560 --> 01:05:41.235
of correctness in your code.

01:05:41.235 --> 01:05:42.610
You do not want
to make something

01:05:42.610 --> 01:05:45.340
that goes faster, but
is wrong, and have

01:05:45.340 --> 01:05:47.620
to debug the correctness.

01:05:47.620 --> 01:05:52.262
You'd much rather ensure
that things are correct,

01:05:52.262 --> 01:05:54.220
are moving to the place
that you want to do it.

01:05:54.220 --> 01:05:58.600
And then you can
optimize for performance.

01:05:58.600 --> 01:06:00.250
So the most important
thing is keep

01:06:00.250 --> 01:06:02.122
that invariant of correctness.

01:06:02.122 --> 01:06:03.580
And that's where
the testing and so

01:06:03.580 --> 01:06:06.700
forth comes in, having
good test infrastructure,

01:06:06.700 --> 01:06:09.400
and having assertions
littered throughout your code.

01:06:09.400 --> 01:06:12.820
HELEN XU: And then we can
go through the [INAUDIBLE]..

01:06:17.010 --> 01:06:20.760
Actually, OK, so,
just as an example

01:06:20.760 --> 01:06:23.610
of how you would
possibly, one way

01:06:23.610 --> 01:06:27.000
of determining whether or
not you state correct--

01:06:27.000 --> 01:06:31.560
so this is an example of a
place where I compiled the code.

01:06:31.560 --> 01:06:33.857
See the binary code
is called Lesierchess.

01:06:33.857 --> 01:06:35.940
And if you look at help,
it gives you some options

01:06:35.940 --> 01:06:37.596
for what you can do.

01:06:40.490 --> 01:06:41.890
For example, there's display.

01:06:41.890 --> 01:06:43.430
And that's the opening position.

01:06:43.430 --> 01:06:45.410
And let's say I want to search.

01:06:45.410 --> 01:06:49.460
So I do a fixed depth,
and go depth three.

01:06:49.460 --> 01:06:52.910
And it tells me
the number of nodes

01:06:52.910 --> 01:06:55.790
that I searched at each depth.

01:06:55.790 --> 01:06:59.660
And so if you make changes,
if they are deterministic,

01:06:59.660 --> 01:07:01.752
these node counts
should stay the same.

01:07:01.752 --> 01:07:02.960
So that's one way of telling.

01:07:02.960 --> 01:07:04.335
So you should keep
track of this,

01:07:04.335 --> 01:07:05.960
and make sure that
they're the same.

01:07:05.960 --> 01:07:09.020
And also, you can
do perft, which

01:07:09.020 --> 01:07:12.680
gives you the number of
possible moves you can make.

01:07:12.680 --> 01:07:16.270
And that should be the
same, no matter what you do.

01:07:19.312 --> 01:07:20.520
So that's one way of testing.

01:07:20.520 --> 01:07:23.150
There's other ways.

01:07:23.150 --> 01:07:27.150
So if you go to higher depth,
you'll get more node counts.

01:07:30.600 --> 01:07:35.430
And here, this is nodes that
you searched at this depth.

01:07:35.430 --> 01:07:37.150
And this is nodes per second.

01:07:37.150 --> 01:07:38.650
So you want to make
this one faster.

01:07:47.638 --> 01:07:48.930
So that's how you run the code.

01:07:52.220 --> 01:07:55.100
And I was supposed to do a
demo for the auto tester.

01:07:57.790 --> 01:07:59.210
So let's say I wanted to do--

01:08:02.010 --> 01:08:05.325
so when I made it, it's in
a binary called Lesierchess.

01:08:08.620 --> 01:08:11.390
And then here, you
can type in commands.

01:08:11.390 --> 01:08:13.710
So you're basically just
typing commands from this.

01:08:13.710 --> 01:08:16.470
Like, you run your binary.

01:08:16.470 --> 01:08:20.310
PROFESSOR: This is the UCI
interface that we talked about.

01:08:20.310 --> 01:08:25.240
And in Lesierchess.c is
the implementation of that.

01:08:25.240 --> 01:08:29.670
And so if you want to add your
commands to it to help debug,

01:08:29.670 --> 01:08:32.550
you can enter-- if we
go into Lesierchess.c,

01:08:32.550 --> 01:08:34.350
you can see the table.

01:08:39.941 --> 01:08:41.399
What I want to do
is show the table

01:08:41.399 --> 01:08:45.270
of all the options, which is--

01:08:45.270 --> 01:08:46.560
there we go, OK.

01:08:46.560 --> 01:08:48.350
HELEN XU: This is
just the heuristics.

01:08:48.350 --> 01:08:51.149
PROFESSOR: So these are
tables of heuristics

01:08:51.149 --> 01:08:56.460
and so forth, which
allow you to set

01:08:56.460 --> 01:09:02.939
the values of the
various things,

01:09:02.939 --> 01:09:05.729
and to say, how much
is this heuristic

01:09:05.729 --> 01:09:08.069
worth to the static evaluation?

01:09:10.950 --> 01:09:12.600
And through these,
all these can be

01:09:12.600 --> 01:09:15.569
set, so you don't
have to recompile

01:09:15.569 --> 01:09:20.100
the binary if you want to try
out things with different--

01:09:20.100 --> 01:09:22.830
if you want to
auto test with, let

01:09:22.830 --> 01:09:25.229
me count this as worth
a third of a pawn.

01:09:25.229 --> 01:09:29.580
Let me count this as worth
half a pawn, or whatever.

01:09:29.580 --> 01:09:32.790
You can just enter it
through the UCI interface.

01:09:32.790 --> 01:09:35.383
And in the auto tester,
you can specify that.

01:09:35.383 --> 01:09:37.800
So it will just test those
without you having to recompile

01:09:37.800 --> 01:09:40.710
binaries for every one of them.

01:09:40.710 --> 01:09:43.600
And so there's a table
here which basically says,

01:09:43.600 --> 01:09:45.210
what's the name
of the heuristic?

01:09:45.210 --> 01:09:48.330
What's the variable
that is going to be

01:09:48.330 --> 01:09:52.109
set what the default value is?

01:09:52.109 --> 01:09:55.770
And pawn ev value is
the value of a pawn.

01:09:55.770 --> 01:09:59.790
And if there's any restrictions
on the range of those values,

01:09:59.790 --> 01:10:01.440
what's the smallest it can be?

01:10:01.440 --> 01:10:03.990
What's the largest it can be?

01:10:03.990 --> 01:10:07.470
So you can edit this
table, and so forth.

01:10:07.470 --> 01:10:11.570
And as I say, you can set it
through the UCI interface.

01:10:11.570 --> 01:10:14.730
So it's really a
very flexible way

01:10:14.730 --> 01:10:18.630
of getting access to
anything that you want to do.

01:10:18.630 --> 01:10:21.360
You can put your own
commands in there,

01:10:21.360 --> 01:10:24.030
including new
heuristics, or whatever.

01:10:27.870 --> 01:10:29.430
And there's some
things in there.

01:10:29.430 --> 01:10:32.370
For example, if we
go to the other part

01:10:32.370 --> 01:10:41.500
where they actually are
passing the UCI stuff,

01:10:41.500 --> 01:10:43.090
so it basically takes it.

01:10:43.090 --> 01:10:45.760
It parses it, figures out
what the command is, and then

01:10:45.760 --> 01:10:47.080
implements the command.

01:10:47.080 --> 01:10:50.220
So all that kind of stuff,
you have control over.

01:10:50.220 --> 01:10:55.970
So that that will help you in
choosing to do other things.

01:10:55.970 --> 01:10:59.030
So, for example, if you
search for perft or something

01:10:59.030 --> 01:10:59.530
in there--

01:11:02.500 --> 01:11:04.630
so if you have
perft, here's what

01:11:04.630 --> 01:11:06.220
the correct outputs should be.

01:11:06.220 --> 01:11:09.910
And now, here's the
code that it executes.

01:11:09.910 --> 01:11:11.682
And perft is in
a different file.

01:11:11.682 --> 01:11:13.390
I think it's in the
move generation file.

01:11:21.262 --> 01:11:24.070
HELEN XU: Do I have
the wrong output?

01:11:24.070 --> 01:11:26.080
PROFESSOR: That may be
for the older game, yeah.

01:11:26.080 --> 01:11:28.420
I actually noticed a couple
of other bugs in there

01:11:28.420 --> 01:11:31.960
that hadn't been fixed.

01:11:31.960 --> 01:11:34.450
So we will make sure
that those are--

01:11:34.450 --> 01:11:36.810
basically, it's just dead
code, is what's in there.

01:11:36.810 --> 01:11:38.560
We need to clean up
some of the dead code.

01:11:38.560 --> 01:11:40.030
Some of the code
is from last year.

01:11:40.030 --> 01:11:41.830
And we changed the game.

01:11:41.830 --> 01:11:43.900
And not all the dead
code got eliminated.

01:11:43.900 --> 01:11:46.150
HELEN XU: That'll be fixed
for when I make the repost.

01:11:46.150 --> 01:11:46.817
PROFESSOR: Yeah.

01:11:49.660 --> 01:11:53.530
So we're just
finishing up some--

01:11:53.530 --> 01:11:56.710
right now, I think
it's all cleanliness.

01:11:56.710 --> 01:11:59.080
But if you find any bugs
like that, let us know.

01:11:59.080 --> 01:12:02.080
We'll fix them, and so forth.

01:12:02.080 --> 01:12:08.260
Appreciate if you do see
other inconsistencies,

01:12:08.260 --> 01:12:09.374
or what have you.

01:12:13.110 --> 01:12:18.360
Good, so great project,
this is like lots of fun.

01:12:18.360 --> 01:12:21.005
Next month is going to be
lots of fun for all of you.

01:12:21.005 --> 01:12:23.130
You may not think it's fun
every minute of the day.

01:12:23.130 --> 01:12:26.310
But you'll have a good time.

01:12:26.310 --> 01:12:28.160
It is fun.