Placeholder Image

Subtitles section Play video

  • The following content is provided under a Creative

  • Commons license.

  • Your support will help MIT OpenCourseWare

  • continue to offer high quality educational resources for free.

  • To make a donation or to view additional materials

  • from hundreds of MIT courses, visit MIT OpenCourseWare

  • at ocw.mit.edu.

  • INSTRUCTOR: So today, we start on project 4, which is,

  • as you know, the big project.

  • And Helen is going to do a walkthrough of the project,

  • and the code, and the organization,

  • because this is a pretty big sized project.

  • It's got about 4,500 lines of code.

  • And it's not code that is kind of like simple code.

  • It's all content-bearing code.

  • So I think having a bit of an orientation to it,

  • more than we give for the other codes that you work,

  • on which are pretty small, this will be great.

  • So, Helen, take it away.

  • HELEN XU: Hi, everyone.

  • Can you hear me?

  • Awesome, so today we're going to be doing the walkthrough

  • for the final project.

  • You can look at the code and clone it publicly here.

  • And please remember to fill up your team's by 7:00 PM today,

  • so we can populate the list and get your repos.

  • Yeah, and if there are any issues accessing this,

  • just let me know.

  • Or put it on Piazza and then we can fix it.

  • So we just had a game of Lesierchess.

  • But in case you missed it, we'll go

  • into more details about what the game actually does.

  • So first, we're going to go through the game rules.

  • So you saw that there are these pieces.

  • There's these triangles.

  • And there's kings.

  • So the triangles are pawns.

  • And the kings, they look like crowns.

  • And there are two teams.

  • There's orange and lavender, or tangerine and lavender.

  • And each side starts out with seven pawns and one king.

  • And this is the starting position.

  • So you can see like the kings are in the corner.

  • And they're just lined up like in the middle.

  • And each piece has four orientations.

  • So you can see that the pawn is up, down, left, right.

  • And then the king is also like that.

  • And in general, the game starts with tangerine moving first.

  • And then the play alternates between the two players.

  • Each piece moves the same, whether it's king or pawn.

  • And each turn has two parts.

  • So you saw the demo.

  • But you move first.

  • When you pick one of your pieces, and you move first.

  • And then at the end, your King has to fire the laser.

  • And the laser reflects off the long edge of the pawn.

  • And they'll kill the pawn if it shoots the short edges.

  • And one side wins when the king gets shot,

  • or when the opposing king gets shot, whether by themselves

  • or by your own king.

  • And so I talked a little about moving.

  • And at the beginning of each turn, the player to move

  • chooses a piece to move.

  • And you can move your King or any of your pawns.

  • And there are two types of moves.

  • There's basic moves, and swat moves.

  • And basic moves are just, basically, shifts or rotations.

  • So in the example, you can rotate 90, 180, or 270 degrees.

  • So in the top, row you just rotate.

  • This is the example of moving a pawn.

  • So you rotate your pawn.

  • Or you can move to an empty adjacent square.

  • So those are the bottom two rows.

  • And there are eight adjacent squares in this example.

  • So there are eight shifts.

  • But there would be less than eight

  • if you were, for example, like at the edge of the board.

  • And on a move, you can either shift or rotate.

  • But you can't do both.

  • There are also these swap loops.

  • So if you're adjacent to an opposing piece,

  • you can switch with them.

  • And then you have to make another basic move

  • after that, that is not a swap.

  • So, basically, you can either--

  • and it has to be with that same piece

  • that you just swapped with.

  • So you just either shift or rotate.

  • Is everyone good on the rules?

  • Just a couple more things.

  • So there's this Ko rule, which is

  • from Go, which ensures that the game makes progress.

  • So it makes a move illegal if it undoes the opponent's most

  • recent move by just moving back to where you just were.

  • So this is an example.

  • Let's say you're tangerine.

  • And you swapped with the purple one right next to you.

  • And then you shifted left and bottom.

  • And so lavender can return by swapping back

  • with your orange piece, and shifting again.

  • But this is actually, illegal because now

  • you just got to your original position.

  • So you're not allowed to just keep cycling back and forth.

  • And so a draw occurs if there have been 50 moves by each side

  • without a pawn being zapped, the same position

  • repeats itself by the side on move,

  • or the two players agree to a draw.

  • So just kind of like in chess, a chess clock

  • limits the amount of time the players have to make a move.

  • So you can't just keep competing indefinitely.

  • When it's your moves, your clock counts down.

  • When it's your opponent's moves, your clock stops.

  • So it's not counting your time.

  • And we used Fisher time control.

  • There's a picture of Bobby Fisher, who

  • made it, up which used an initial time budget and a time

  • increment.

  • So in this example, there's fis60 and 0.5,

  • which means that, in the beginning,

  • each player has 60 seconds.

  • And you get to use the 60 seconds however you want.

  • And when you end your move, you get 0.5 extra seconds.

  • But the 60 and 0.5 could be anything.

  • That's just an example.

  • So we'll go into an example of how you actually

  • play this game.

  • For a king to zap the enemy king,

  • it risks opening itself to counter-attack.

  • So look at this example.

  • And how can tangerine zap the lavender pawn in F5,

  • by moving one of its pieces?

  • AUDIENCE: [INAUDIBLE]

  • HELEN XU: Move C4.

  • AUDIENCE: Tangerine, that's lavender.

  • HELEN XU: You're tangerine in this example.

  • And you're trying to zap the one on F5.

  • Yep?

  • AUDIENCE: You move the tangerine piece at E22 to F1.

  • HELEN XU: E2 to F1.

  • Oh, sorry, by zap, it means shoot the backside.

  • That would shoot the long side.

  • Good point.

  • Yeah, so you're trying to kill the piece on F5.

  • AUDIENCE: [INAUDIBLE]

  • HELEN XU: Yeah, exactly.

  • So in this, you can move C2 to B1, as you just said.

  • And then you draw the path.

  • And you can see that you've just killed--

  • or if you're tangerine, you've just killed the piece at F5.

  • Now, how can lavender counter?

  • By counter, we mean lavender can win

  • the game from this position.

  • AUDIENCE: Is it A4 to A3?

  • HELEN XU: A4 to A3.

  • No, I don't think so.

  • Yep?

  • AUDIENCE: [INAUDIBLE]

  • HELEN XU: Sorry, what?

  • King, like the orange one?

  • Oh, the lavender one.

  • You're trying to shoot the orange king.

  • Oh, yes, you're right.

  • You can, actually.

  • Yes, good, that's not the one that we had,

  • but apparently there are two ways.

  • Good.

  • So if you notice you could also--

  • that's another way to get that path.

  • But you can also move one of the pawns.

  • Cool, so this is just pointing out

  • one of the subtleties of the game, which is you

  • should watch out for just naively killing

  • all the pieces you can, because that might open you up

  • to the opponent.

  • Yeah?

  • AUDIENCE: [INAUDIBLE]

  • HELEN XU: Yes, it can be from any direction.

  • But the pawns only die if you shoot them

  • from not on the long edge.

  • Yep?

  • AUDIENCE: What if you shoot your own block?

  • HELEN XU: By block, you mean your own pawn?

  • AUDIENCE: Yeah.

  • HELEN XU: You'll die.

  • AUDIENCE: Oh.

  • HELEN XU: Yeah?

  • AUDIENCE: [INAUDIBLE]

  • HELEN XU: Yes, but only one piece can be on each square.

  • But you can have as many near you.

  • But do you have a question?

  • AUDIENCE: Can you make it impossible to kill your person?

  • HELEN XU: Like your King?

  • Like if you barricaded it by pawns.

  • But then the opponent can come in and swap with them,

  • so it will open your barricade.

  • AUDIENCE: Can the purple king shoot upward?

  • HELEN XU: If it wanted to.

  • But then in this example, it would shoot up off the board,

  • and nothing would happen.

  • Yeah?

  • AUDIENCE: When you kill a pawn, does the laser

  • stop at the place where the pawn is or does it

  • go through the pawn?

  • HELEN XU: No, it just shoots one.

  • Good questions.

  • Everyone good so far?

  • OK, great.

  • PROFESSOR: This year, it shoots only one.

  • Last year, it kept shooting.

  • AUDIENCE: Can the king shoot itself?

  • HELEN XU: Yes.

  • It should try not to, but it can.

  • So you should be careful.

  • So moving on-- we use force Fosythe-Edwards Notation,

  • which is a representation of a chess position using a string.

  • So you can see an example of the starting position.

  • And the bottom includes the string

  • that describes the starting position.

  • If you look at the representation,

  • the arrow corresponds to one of the rows.

  • And that points to the substring that has a bubble over it.

  • So in this row, there is one purple pawn at B3,

  • and two orange ones at F3 and G3.

  • So this is row three.

  • And the slashes separate the rows in the string.

  • And the one represents there's an empty space.

  • And then there's a pawn facing southeast.

  • And then there's three empty spaces, and one facing

  • northwest, and then one facing southeast, and then

  • an empty space.

  • AUDIENCE: [INAUDIBLE]

  • HELEN XU: Oh, yeah, it's animated.

  • What do you mean?

  • Yeah, so at the end of the string, there's also a--

  • it just tells you which side's move it is.

  • So this is the opening position.

  • But you can use any position in this notation.

  • And this is useful for debugging,

  • because if you, for example, you're running a bot,

  • and it crashes at some position.

  • And you can get back to that position.

  • You can start up the game and just

  • go there without having to make all the moves to get there.

  • And this is how you represent the games.

  • So each of these is one move.

  • And the left column is tangerine.

  • And the right column is lavender.

  • And an example, you can see E6, E7,

  • means they moved a piece from E6 to E7.

  • B3L, so you rotated the piece on B3 left.

  • There's D5, E4, F5, which means that you swapped.

  • So your original piece was on D5.

  • You swapped with the one at E4.

  • And now you moved that piece to F5.

  • So the one that was E4 is now on F5.

  • And the opposing piece is now on D5, because you swapped.

  • You can swap and then rotate.

  • So instead of just having a third square,

  • you would just have a rotation.

  • And at the end, you could see who won.

  • So in this one, lavender one because it's 0-1.

  • But 1-0 would mean tangerine wins.

  • And half and half would be a draw.

  • So you can look at the logs for your games.

  • Yes?

  • AUDIENCE: [INAUDIBLE]

  • HELEN XU: There's a rotate up and rotate down.

  • AUDIENCE: [INAUDIBLE] do a U-turn?

  • HELEN XU: Oh, is that what U is?

  • AUDIENCE: Yeah, U-turn.

  • HELEN XU: Oh I, see because there's only three rotations.

  • Yes, sorry, so left is 90.

  • Then right is 270.

  • And U is 180, because you flip it.

  • Is everyone good on the notation?

  • This is just how you describe the games,

  • if you wanted to look at your logs,

  • and if there are some issues.

  • So you can test your bot with other teams in the class,

  • as well as with staff bots on the scrimmage server.

  • And we have a reference, which is here, which

  • is just the additional release.

  • But we will be optimizing our bots while we're

  • optimizing your bots.

  • And we'll release a reference plus, and maybe an even better

  • one later, which you can play with on the scrimmage sever.

  • So I'll just do a really quick demo.

  • So right now, since we haven't done the team formation yet,

  • you are not able to log into this.

  • But once you do your team formation, probably

  • by tomorrow, you'll be able to log in.

  • And, basically, you can see the general functionality.

  • So this updates your player, pulls your player

  • from your repo, whatever's on the master branch.

  • And then right now, there's only reference,

  • and reference plus, and reference TAs.

  • And here's a team with me and Jess.

  • But later on, we'll populate this list

  • with everyone in the class.

  • And then you can challenge anybody else

  • in the class to see how you do.

  • You can also challenge us.

  • So you would just pick, for example,

  • let's say I wanted to challenge reference.

  • And then a hit send challenge.

  • Now, you can see that there's some new matches spawned.

  • And this is how I look at all the matches that I've played.

  • So each time you hit send challenge,

  • it spawns off two games, one where you're tangerine,

  • and one you're lavender.

  • So that's how you can watch the matches on the scrimmage

  • server.

  • Everyone good?

  • I'm going to move on so don't run out of town.

  • You can watch them later.

  • And you can even play your own.

  • OK.

  • And, in addition to the scrimmage server--

  • so the scrimmage server, you can only

  • spawn off one game at a time.

  • But you can do more.

  • And you don't have to necessarily do it

  • on your master branch, or against opposing teams

  • in the class.

  • So there's something called the Cloud autotester, which you can

  • run by going to your Athena.

  • And then you type in this command.

  • You do autotest run.

  • And then you do the time control.

  • And you give it a number of games that you want to run.

  • And then you give it a list of binaries.

  • So I'll go into each of these in more detail.

  • So the time control is just what I talked about earlier, which

  • is if you use Fisher time control, these are some set,

  • preset things.

  • So you would type in one of the preset things.

  • So you would talk in blitz to do 60 and 0.5, for example.

  • And the number of games is just whatever you want to do.

  • And the list of binaries-- so let's

  • say you had a reference invalidation,

  • and then you made some change.

  • So I called it Lesierchess with changes.

  • And then you would just put those

  • after the number of games, separated by spaces.

  • And then it would upload your binaries,

  • and play them in the cloud auto tester.

  • And once you submit your job, you get a link.

  • And you follow the link in your browser.

  • And you can view the game running.

  • And then after the games are done,

  • you will get some output saying like, which bot, one more?

  • And how many times have won, and some rankings.

  • Yep?

  • AUDIENCE: How fast do they run?

  • HELEN XU: How fast do they run?

  • AUDIENCE: [INAUDIBLE]

  • HELEN XU: So it depends on how many other games are

  • queued at the same time.

  • So if a lot of people are running tests,

  • it might take some time.

  • But blitz is just how long the game itself will take.

  • And it might take longer than 60 seconds,

  • because if you use less than 0.5 seconds in your move,

  • and then you add 0.5 seconds at the end of the move,

  • then you would increase your time.

  • But 60 is just the time control.

  • Each side starts with 60 seconds.

  • And depending on how they use it, they have more or less.

  • Good question.

  • Well, I'll keep going.

  • And if there's time at the end, I'll do a demo of this one too.

  • But it basically looks the same as the scrimmage server.

  • Like, you just watch the games in the same way.

  • So now, I'm going to go into the project organization, which

  • is the organization of the directories

  • that we handed out in this repo.

  • So there are some directories.

  • The first one is doc, which just includes

  • the rules and documentation for the interface.

  • There's the auto tester, which is the Java local auto tester.

  • So if the cloud--

  • we recommend that you run tests using the cloud auto tester.

  • But if there's some small change, or if you think that--

  • if the cue is too long, then you can do local tests.

  • And you can also run these overnight.

  • There's pgnstates, which just parses your statistics

  • from the auto test results, like how many times you won,

  • stuff like that.

  • There's tests, which is how you specify tests.

  • And I'll go into more detail about how you define this.

  • There's the player, which is where you're actually

  • going to be optimizing.

  • So player is the code that actually

  • runs the bot to play the game.

  • And the webgui is a local webgui where you can watch the game

  • and play it.

  • So in the webgui, you can even play it yourself as a human

  • so you can get a better sense of how the game works.

  • To go into more detail, the Java local auto tester

  • is an auto tester.

  • You can make your changes, and then you can test your changes.

  • And the test directory, which is parallel, holds configurations.

  • So you can specify the number of games and the bots

  • that you want to use, and the time control,

  • and other things too.

  • So this an example of the configuration

  • file that you would use to run your auto tester.

  • So this is saying that you run it on 12 CPUs.

  • And book means that you're pointing

  • to open a book, which I'll talk about later.

  • Game rounds is how many games you're going to spawn off.

  • Title is just the title of the test that you're running.

  • And after that, you have the player definitions.

  • So player reference is just the binary.

  • And invoke is the path to the binary.

  • And then fis is the time control.

  • And the next one is just a second binary,

  • if you made a change and you want to test them.

  • Yeah, that's the binary.

  • To interface with auto tester, Lesierchess

  • uses the universal chest interface, or UCI,

  • which is a communication protocol for automatic games.

  • And you pass information between the auto tester and your bot.

  • And it allows the programmer or the auto tester

  • to enter moves to the game engine.

  • So you could use UCI to start up your bot.

  • And then you type in the moves that you

  • want to make to see the changes in the state.

  • And you could use this to debug to get to a state

  • that you want to look at.

  • We'll measure the bots using Elo ratings.

  • So Elo is a rating system that measures relative skill

  • level in zero sum games.

  • The Elo rating depends on the Elo rating of your opponents.

  • And on the bottom, you can see an example output.

  • So I had three binaries.

  • And I ran about 100 games.

  • And you can see that the Elo of the top one

  • is much higher than the other ones.

  • And so higher Elo is good.

  • And we'll be comparing the performance.

  • We'll be comparing the Elo of your bot against our reference,

  • and improved reference implementations.

  • So notice that this is not, as before,

  • just a straight measure of time.

  • So like before, in previous projects,

  • if you used less time, than you would get a higher

  • grade or better performance.

  • In general, I'll show you a graph later

  • that actually shows if you searched the higher

  • depth, which means that you are faster, you do improve.

  • But it's not an exact correlation.

  • And you can look at the nodes per second

  • that you search using the UCI.

  • And just above here, to local webgui lets you watch a game,

  • or play one, without sending it to the scrimmage server.

  • So if you wanted to play one as a human,

  • you would use the local webgui.

  • And you can run it using the commands in the readme.

  • OK, so is everyone good so far?

  • Now, I'm going to go into more details about how you actually

  • play the game.

  • So first, every player, or every bot,

  • needs to generate the moves, which

  • means that once you have a position,

  • you need to look at the moves that you can do.

  • And to do that, you need a board representation, which

  • is to represent what pieces are on the board,

  • and how big the board is, and where the pieces are.

  • And the reference implantation uses a 16 by 16 board

  • to store an 8 by 8 board.

  • So you can see that the inner squares is actually the board.

  • And the outer dark square is sentinels.

  • So you use sentinels to keep track

  • of when you go off the board.

  • And then the inner square is just the actual board.

  • We store the position using this struct.

  • So you can see the fields in the position, which are the board.

  • And the array size is just representing

  • the board, plus the sentinels.

  • And there's the history of the position,

  • which is, how did we get here?

  • And there's a key, which is a hash key for this position.

  • There is ply, which tells you what side it is.

  • So even means white.

  • And odd means black.

  • There is, what was the last move that was

  • made to get to this position?

  • There's a victim struct, which is the pieces destroyed

  • by when you shot the laser.

  • And there is the location of the kings.

  • The position struct and Lesierchess struct

  • stores the border presentation and other things

  • that I just went through.

  • So I talked about this move, which means just like a move

  • that you make for one of your pieces.

  • And I'll go into how it's represented.

  • So right now, we already do the packing for you.

  • So we use 28 bits.

  • And the first two are the piece type.

  • So there's a number of moves that you can make.

  • And the first two bits represents the piece type,

  • which is empty, pawn, king, or invalid.

  • The orientation of the piece, which

  • is just how you rotated it.

  • The from square, which is where your piece already started.

  • There's the intermediate square, which

  • is used when you do a swap.

  • And there's a two square, which is the final position

  • that your piece will end up in.

  • So if you're not doing a swap, then the intermediate and from

  • should be the same.

  • But if you are doing a swap, then there's

  • some skipping that happens.

  • At each turn, you need to see what

  • moves you could possibly make.

  • And in move gen, which is one of the files in the handout,

  • we generate all the moves, given a position,

  • depending on whose turn it is.

  • So depending on whose turn it is,

  • you can make different moves.

  • And in the reference implantation,

  • we iterate through the entire board.

  • And once we find a piece, we generate all the moves

  • from that piece.

  • You can also debug using move generation.

  • So there's something called perft,

  • which is a debugging function that enumerates

  • all moves at a certain depth.

  • So use perft to make sure that if you make changes to the move

  • generation that you're generating

  • the same number of moves.

  • And if you modify the move generated,

  • just make sure that it returns the same,

  • because regardless of what optimizations

  • you do, you still should see the same moves from each position

  • that you can possibly make.

  • OK, so now that we talked about move generation,

  • I'll talk about how you tell that a move is good.

  • And for that, we use something called static evaluation.

  • So we use static evaluation to determine

  • which positions are better than others,

  • and which moves that we should make.

  • And the function eval, which is in eval.c,

  • generate a score based on a position,

  • using some heuristics.

  • And at first, we suggest, instead of making up

  • your own heuristics, we suggest focusing

  • on optimizing the existing structs and evaluation

  • heuristics before coming up with new ones,

  • because it's kind of hard to come up with new ones.

  • And there's a lot of optimizations

  • that you can make to the existing ones.

  • So I've just grouped these into categories.

  • So there's a few regarding the king.

  • So there's one called KFACE, which

  • is a bonus for your king facing the enemy king.

  • There's KAGGRESSIVE, which gives you

  • a bonus for if your King is closer

  • to the center of the board.

  • And there's MOBILITY, which counts up, basically,

  • how many squares around your king are free.

  • You want to be able to move your king freely.

  • And there's some regarding pawns.

  • So there's PCENTRAL, which gives you a bonus if your pawns are

  • in the center of the board.

  • And there's PBETWEEN, which basically draw a bounding box

  • with both kings at the corner.

  • And then you count how many pawns

  • are in the center of those.

  • And then there's points based on distance.

  • So there's LCOVERAGE, which means laser coverage, which

  • is basically you make all the possible moves that you

  • can make from your position.

  • And then you draw the laser path.

  • And then you do some scaling to determine

  • how well you can possibly cover the board,

  • based on your current position.

  • So that's basically how you tell if a position is good or not,

  • with these heuristics.

  • So I'll just go through the high level of how you actually

  • play the game using search.

  • So at the very highest level, there's

  • something called game search trees, which

  • is we've invented in search.c.

  • But, basically, this is a representation

  • of how you play the game.

  • At the top, there's an orange square,

  • which is the orange side, which is the opening

  • position, and then the arrows.

  • So the top square--

  • actually, all the nodes are positions in the tree.

  • And you use move generation that I just talked about,

  • to enumerate all the possible moves from a single position.

  • And each edge is a move.

  • So to get from position to position, you do moves.

  • And you can see that circle is the position

  • after you've made the move.

  • And you do this tree to some depth d.

  • And then you do static evaluation of the leaves.

  • So this is at a really high level how game playing programs

  • actually play the game.

  • They enumerate all the possible moves.

  • And then they have a position.

  • And then they pick which one is best, based on evaluation.

  • But you can see that there's a lot of nodes.

  • Like, if you do this naively, there'd

  • be number of moves raised to d, which is a huge number,

  • and too many to generate.

  • So we're going to talk about how you reduce those later.

  • There's something that you have to do on search series, which

  • is called Quiescence search, which

  • is if you fix your depth--

  • let's say you fix depth, and then you go down to the leaves,

  • and you just captured a piece.

  • But it's dangerous to just stop there at fixed depth,

  • because maybe if you searched one level deeper,

  • you would see that the opponent would capture your piece.

  • And so if you do your search, and you

  • see that you capture a piece at the leaves,

  • or your opponent captures the piece at the leaves, we say,

  • that's not quiet.

  • And you keep searching the tree until there

  • are no more captures.

  • So that's called Quiescence search,

  • because you quiet the position.

  • And that's implemented in the search column.

  • So this is a graph that I generated

  • by doing the reference spot to different depths.

  • And you can see that the Elo increases as you

  • increase the search depth.

  • So you just search the search tree.

  • And so if you optimize your bot to make it faster,

  • you can search deeper, which means that you'll do better.

  • So next, I'll talk about min-max search, which

  • is a more complex version of searching

  • that can improve the amount of nodes you have to evaluate.

  • So at a high level, there's two players, max and min.

  • And in our example, there's orange and purple.

  • And orange is a square.

  • And purple is a circle.

  • And the game trees represents all moves

  • from the current position from a given ply, which means depth.

  • And if the leaves, like I said, you

  • play a static evaluation function.

  • And max chooses the maximum score among its children.

  • And min chooses the minimum score.

  • So one side is trying to maximize,

  • and one side is trying to minimize.

  • To evaluate the search try, I'll first

  • talk about an algorithm called alpha beta, which

  • is that each search from a node has a window alpha beta.

  • And if the value of the search falls below alpha,

  • the move is not good enough, and you keep searching.

  • And if the value falls within alpha and beta,

  • then you increase your alpha, which is the lower bound,

  • and you keep searching, because you know

  • you can do at least that well.

  • And if the value of the search falls above beta,

  • than you generate a beta cut off in return.

  • Beta basically means one side is trying to maximize,

  • and one side is trying to minimize.

  • So beta is basically saying, the opponent

  • would never let you do that move, because it'd be too good.

  • So you don't need to keep searching there, because you're

  • not going to get there anyway.

  • So I'll do an example.

  • Let's say you have this tree.

  • And if max discovered a move that min wouldn't

  • let you do, because it's too good,

  • then max's other children don't need

  • to be searched, which is what a beta cut off is.

  • So you'd start at the root.

  • And then you go down to the lowest left leaf.

  • And you see that it's three.

  • So you propagate three up.

  • And then you can see that in this sub-tree,

  • you can do at least three.

  • And then you keep searching your children.

  • And then you see six.

  • And then you say, OK, now you update your alpha value

  • to be six.

  • Now, you search four.

  • But four is worse than six.

  • So you don't have to do anything.

  • So you first search the leftmost subtree.

  • And then you see the best move that you could possibly

  • make there.

  • So you propagate six up to the root.

  • And then you search your other subtrees.

  • But now, you have this value of six

  • that you basically use in the other subtrees.

  • So you look at two.

  • And you see that two is less than six.

  • So you propagate it up.

  • But now, you look at nine.

  • And you see that nine is greater than six.

  • So you say that this subtree would let purple do nine,

  • which is greater than six.

  • And so that would be too good, because orange would never

  • let purple do that well.

  • So you don't have to evaluate five anymore.

  • So you cut off five.

  • Does that make sense?

  • OK, so, basically, now you apply the same thing

  • to the regular subtree.

  • And you look at seven.

  • And you see that seven is greater than six.

  • So you propagate that up.

  • And now you're done, because seven is greater than six.

  • So you don't have to search the rest of the subtree.

  • So that's how you evaluate fewer moves than the entire tree.

  • And there's a theorem that says for a game tree

  • with branching factor b and depth d, and alpha beta search

  • with moves searched in best-first order

  • examines exactly b raised to the d over 2,

  • plus b raised to the d over 2 minus 1 nodes apply d.

  • So best first order means that you sorted the moves in terms

  • of your static evaluation.

  • The naive algorithm examines b to the d nodes.

  • And in the example I did, you can see how you prune.

  • And for the same work, the search stuff is doubled.

  • And for the same depth, the work is square rooted.

  • So this is a huge benefit over the naive evaluation.

  • Is everyone good on alpha beta?

  • Great, so the code is pretty short.

  • So I'll just go through some pseudocode for it.

  • Basically, the main point is that at line 11,

  • one side is trying to minimize and one side

  • is trying to maximize.

  • But if you negate, then that's just the same

  • as minimizing and maximizing.

  • And you get all the possible moves

  • that you could possibly make using gen moves.

  • And you go through the entire move list.

  • And then you make each of the children.

  • And you search for the score.

  • And then you see whether you had a beta cut off.

  • And then you don't need to search the subtree If you did.

  • So that was basic alpha beta.

  • And we actually implement a variation of alpha beta called

  • principle variation search.

  • And the main idea is that you assume that the first move is

  • the best one.

  • And you run scout search, which is also called zero window

  • search, on the remaining moves to verify that they're worse.

  • So in this example, you, again, search the most leftmost

  • subtree.

  • And you see that the best you can do in the left-most subtree

  • is three.

  • And you evaluate the ones to the right

  • of it using scout search, which is not a full search.

  • You're basically assuming that you

  • can do no better than three.

  • And then now you're kind of doing an initial search to see

  • whether or not that's true.

  • And see you see that some of them are--

  • the one after that is seven.

  • The first one after that is seven.

  • And the one after that in the other subtree is six.

  • So then you can prune them, because those are better--

  • because you know already in those

  • subtrees that you can do better than three.

  • So you don't have to keep evaluating them.

  • And you don't have to-- yeah?

  • AUDIENCE: How do we know the score of the subtree

  • before we evaluate?

  • How can we prune something?

  • HELEN XU: So you actually had to find seven.

  • Like, zero and eight are there.

  • But you haven't found them yet.

  • So, basically, if you thought about doing it serially,

  • you do the leftmost subtree, which has 2, 3, and 0.

  • And then you would find seven.

  • And that would be a cut off, because seven

  • is bigger than three.

  • So you're not actually finding zero and eight.

  • The point is that you wouldn't get to that subtree,

  • because the opponent wouldn't let you get there,

  • because you can do too well.

  • So they would just not let you go down that path.

  • Like, let's say you were purple, and the opponent is orange.

  • And you want to get 7 and 8.

  • But the opponent can also search that, and see

  • that you would get 7 and 8.

  • So they would prefer you to do something like two or three.

  • AUDIENCE: So what do you do instead?

  • HELEN XU: You're not always making the best move that you

  • could possibly do, because--

  • like, if you just searched without this pruning,

  • and you just picked--

  • let's say you wanted to make the best move.

  • Like, if you don't take into account the opponent,

  • then you're never going to get to there.

  • So you're basically trying to find a move

  • that the opponent would let you get

  • to that's also good for you, because you switch off.

  • Yes?

  • AUDIENCE: [INAUDIBLE]

  • HELEN XU: I guess in this example, you're purple.

  • No, sorry, you're orange, because you're cutting off--

  • no, you're purple, because you're

  • trying to maximize what you get at the leaves.

  • AUDIENCE: [INAUDIBLE]

  • HELEN XU: Yes.

  • The main point of-- sorry.

  • AUDIENCE: Oh.

  • We're trying to minimize the score.

  • HELEN XU: Yes.

  • So orange is trying to minimize the score.

  • And purple is trying to maximize the score.

  • AUDIENCE: So we're cutting that off,

  • you're saying you don't need to search this because we already

  • know they're the same here.

  • So we shouldn't go down this path anyway.

  • HELEN XU: Does anyone have questions?

  • Does that make sense?

  • Yeah, it's basically exactly as you said.

  • So there's kind of this balance between one side trying--

  • both sides are just trying to make--

  • you're trying to make good moves.

  • But you're also trying to make the opponent make

  • not good moves, if that makes sense.

  • So you're not only searching for your maximum.

  • But you're also searching to minimize the opponent.

  • Good question.

  • AUDIENCE: [INAUDIBLE]

  • HELEN XU: Sorry?

  • AUDIENCE: So we don't want to choose

  • either of those orange ones.

  • We don't want to let--

  • I think it's OK.

  • I think you can move on.

  • HELEN XU: Oh, OK.

  • Yes?

  • AUDIENCE: What if you and your opponent

  • have different reward criteria?

  • Like, you guys evaluate--

  • HELEN XU: That's OK.

  • It's fine.

  • The actual evaluation, like what number

  • you assign to each position, is not exposed to the opponent.

  • The main point is that, at the end of each move, you pick one.

  • And they can do with it what they want.

  • Like, that may not have been the one they picked.

  • But it's OK.

  • Sorry, I think you're orange in this one,

  • because the root is orange.

  • AUDIENCE: [INAUDIBLE]

  • HELEN XU: So let's start over.

  • So I think that we are orange.

  • So remember that each edge is a move.

  • And each node is a position.

  • And so you're orange.

  • And you start at the root.

  • And now you, for example, make the move left.

  • And purple now can make moves whatever three after that.

  • And now, you're orange again.

  • And then you can make moves after that.

  • And now, you evaluate the position after that as a leaf.

  • And so, basically, you're searching

  • past like the second level of orange.

  • And you are cutting off if you see that you would do better,

  • because you think that purple would never

  • let you get to that orange node right above.

  • Yes?

  • AUDIENCE: [INAUDIBLE]

  • HELEN XU: Yeah, I guess that's the score that you,

  • as orange would receive.

  • Yes?

  • AUDIENCE: [INAUDIBLE]

  • HELEN XU: You're not trying to give--

  • it's not so much like you're trying to give purple zero,

  • as you think that purple would not give you seven and eight,

  • because purple would have to go down the left subtree

  • to give you that.

  • Any other questions?

  • I'm going to move on with the search

  • then, if there are no questions.

  • [INTERPOSING VOICES]

  • HELEN XU: Is everyone good?

  • Can I keep going?

  • OK, so just going back to principal variations pruning,

  • the main idea is that you go down

  • the first path on the left side, thinking

  • that that's the best path.

  • And then you're basically doing initial passes

  • through the trees to make sure that your assumption is

  • correct.

  • And if they're not correct, then you

  • have to search the entire subtree.

  • But if they are correct, then you kind of

  • fail, you early exit.

  • So you search down the left subtree.

  • And you find three in the leftmost subtree.

  • And now, you search the ones to the right of that.

  • And those are seven and eight.

  • So those produce a cutoff, because seven and eight

  • is higher than three.

  • So you think that purple would not

  • let you get to that subtree.

  • And now, you do a scout search again on the middle subtree.

  • And then you see that--

  • you find this first node of each one of those subtrees

  • underneath the middle subtree.

  • And you see that they're all higher than three.

  • So it turns out that you failed to prove that you

  • can do no better than three.

  • The main point of the scout search

  • is that you assume that your first move that you search

  • is the best you can do.

  • And then you do initial passes to verify that assumption.

  • And if you search later subtrees, and you find that--

  • for example, in this one in the middle,

  • they're all higher than threes.

  • So your assumption is not true.

  • So now you have to do a full search

  • of that entire middle subtree.

  • Is that OK?

  • Are there questions?

  • So once you find that you have to actually search

  • the middle subtree, you can recursively apply scout search.

  • So you have to search the left subtree in the middle.

  • But now, you apply scout search to the lower middle

  • and the lower right.

  • And you do a zero window search there.

  • And, again, you assume that you can do no better than six.

  • And now, you're trying to verify that you

  • can do better than six.

  • But you actually can.

  • So you have to search them.

  • And then you apply the same thing again to the subtree.

  • And you see that you can do better than six

  • on the left one.

  • But you do worse than six on the right one.

  • And you cut off two, because the middle subtree already gave you

  • two.

  • And so you don't have to search that one.

  • So in this example, there were 13 leaves pruned.

  • And the point of scout search is that you

  • can improve pruning a little bit over alpha beta,

  • and that you process most of the game tree

  • with zero window searches.

  • The main point is that it reduces your work, because you

  • have to process less.

  • Questions?

  • So now we're going to talk about-- so I kind of glossed

  • over how you order the moves.

  • So the ordering determines which order

  • you explore the subtrees in.

  • Alpha-beta search and principal variation search

  • depend on putting the best moves in the front

  • to trigger an early cut off.

  • And the main question is, how do we

  • determine moves, which moves are good,

  • without doing static evaluation at every level?

  • Like, for example, we only did static evaluation

  • with the leaves.

  • And we can't get sortable move list,

  • which is a function in search.

  • And sortable move lists, kind of talk

  • about how you populate that later.

  • As I said before, moves are represented in 128 bits.

  • So you can use it in 32.

  • And to make them sortable, you store a sort key

  • in the upper 32 bits in 64.

  • And then you sort, based on that key.

  • That make sense?

  • So I'll just go over some search optimizations that you can do.

  • We actually implement these already.

  • So I'm just going to go through them

  • so it's not super confusing when you look at the code.

  • The most important one is called the transposition table.

  • The main idea in the transposition table

  • is that chess programs often encounter the same positions

  • repeatedly during a search.

  • And you can store those results in a transposition table

  • to avoid unnecessary feature searches.

  • And I've listed where you can find those.

  • There's something called Zobrist hashing,

  • which is a technique for hashing a board position which

  • you use to index the transmission table.

  • And it's a table of random numbers, indexed by piece,

  • orientation, and square.

  • So each position has a unique hash.

  • And it produces the hash by exporting

  • all of these random numbers together.

  • And the advantage of Zobrist hashing

  • is that the hash function can be updated incrementally, which

  • is like if you move a position-- if you move a piece,

  • you just xor it out.

  • And then you xor the new one, so you

  • don't have to recompute the hash each time.

  • So the transposition table saves you a lot of work

  • by preventing you from researching things.

  • And there's also something called the killer move table.

  • So the transposition table is like how

  • you determine how to do sorting at things

  • that are not the leaves, and also the killing moves table.

  • So the killer moves people stores

  • moves that are really good so that the opponent wouldn't let

  • you go down that path, so you have to keep

  • recomputing the same values.

  • And the table is indexed by ply, because you

  • tend to see the same moves at the same depth.

  • So the killer move table, basically, just stores

  • move that trigger the beta cut off before in your search.

  • There's a best move table, which is stored

  • at the root of the search.

  • And it is the move that got the maximum score

  • in your evaluation.

  • And the best move table is indexed by color,

  • piece, square, and orientation.

  • And there's a history table in the code.

  • So these are all, basically, just

  • things to help you optimize your search,

  • and produce early cut offs.

  • And there's something called null-move pruning, which

  • tries to reduce your search space by first

  • not moving, and then doing a shallower search to see

  • if this subtree is worth further exploring.

  • Basically, it says, don't move, and then do

  • a little bit of evaluation.

  • And if you're still doing really well,

  • even if you didn't move in the subtree,

  • then it's not worth exploring, because the opponent

  • would never let you go there, because the position is

  • too good.

  • There's futility pruning, which explores

  • moves that only have the potential to increase alpha.

  • And it calculates that possibility

  • by adding a futility margin, which

  • is the most you could possibly gain from going there, and then

  • evaluating a little bit.

  • And if the result does not go higher than alpha,

  • then you skip it, because there's

  • no point in even going that way, because it

  • wouldn't increase your alpha.

  • There's late move reduction, which

  • is after you order the moves at a position,

  • you explore the-- the-- ones in front are likely to be better.

  • So you explore those in higher depth.

  • And then you explore the ones later with shallower depth,

  • because those are less likely to be good.

  • And some things that you can optimize

  • are implementing a better opening book.

  • I think we have produced a very basic opening

  • book in the handout.

  • But this is something that you can definitely

  • work on, and make better, because it doesn't have

  • many positions in it right now.

  • And the main point of an opening book

  • is that you store the positions at the beginning of the game

  • that you've already pre-computed.

  • And that saves time and search, and can store results

  • to a higher depth.

  • And the KM75 theorem implies it's better

  • to keep separate opening books than to keep the same opening

  • book for both sides.

  • So opening books are really helpful,

  • because in the beginning, there's a huge number of moves

  • that you could possibly make.

  • And searching those takes a lot of time.

  • But if you pre-compute them, you can save them for later.

  • And another useful table you can keep

  • is an end game database, which is

  • a table for guiding your chess program through the end game.

  • For end game positions, the distance from the end

  • might be too far to search entirely.

  • So you can pre-compute them.

  • And then you store who will win, and how far you

  • are from the end of the game.

  • And we've given you a c file that you can implement it in.

  • OK, so I'll just go through some guidelines,

  • some tips for the project.

  • I was giving links at most of the bottom

  • of the slides for where you can read up more on these topics.

  • But there's a chess programming wiki.

  • The link is there, which has many more pages about reading

  • about chess playing programs.

  • Just in general, it's a really good idea

  • to test your code often, because it's

  • easy to make a mistake with your optimizations.

  • And it doesn't appear when you search to fixed depth.

  • So if you start up your bot, you can say, like,

  • search to depth 5, for example.

  • And then it will tell you like how many nodes per seconds

  • you searched.

  • And then I'll tell you the best move at the end of that search.

  • But you should test full games using

  • the auto tester, and the cloud auto tester,

  • and the script server, just to watch your bot

  • to make sure that it doesn't do anything weird.

  • And the testing methodology, I went through some of it.

  • There's a webgui.

  • There's a Java autotester.

  • There's a cloud autotester.

  • And you can do node counts, which is basically

  • just counting the number of nodes in the tree

  • that you searched.

  • And there's function comparison testing,

  • which is, if you optimize a function,

  • you should save the old version, and then

  • just compare the results.

  • PROFESSOR: Let me make a comment about testing.

  • I can't tell you how often in this class

  • we've had student groups who discover that they've

  • made a whole bunch of changes.

  • And then there's something wrong with their bot.

  • And they can't get back to a stable place

  • when things were correct.

  • They discover the problem.

  • But they've made 30 changes.

  • And now, which of those 30 is responsible for the problem?

  • So it's really important to test,

  • and have a good test infrastructure

  • for this project.

  • If you have a really good test infrastructure,

  • it's really easy to be innovative in the kinds

  • of optimizations that you do, because then you

  • know that what you're doing is right.

  • And then you can make forward progress.

  • Otherwise, you'll find yourself self debugging like crazy,

  • and not being able to find the bugs.

  • Some other tips are, especially when

  • we get to the parallel part, it's

  • non-deterministic programming.

  • And the reason is because as you're

  • executing you're going to be looking up things

  • in transposition table that you're going to want to share,

  • so that if one branch discovers a value then

  • another branch can use that.

  • So it's really important to be able to turn that

  • off so that you're, for example, able to search

  • without a transposition table to get all

  • the searching stuff right, and be able to turn that

  • on independently.

  • So that's another really important place to do it.

  • Another thing is that when you do timed searches,

  • the time it takes to do the search will vary.

  • And what you'll end up exploring varies.

  • So as much as possible, you wanted to fix depth searches.

  • Search to five ply to test something,

  • rather than searching for a minute,

  • or whatever the amount of time is,

  • because when you start searching for time,

  • that's, in fact, what you're going to end up doing.

  • But you can't repeat what just happened if you end up

  • searching for that amount of time

  • again, because the machines are not deterministic.

  • And there may be something else going

  • on that causes the amount of time to be different.

  • And so, for example, if you're making a change that

  • doesn't affect the logic of the program,

  • it's just strictly an optimization,

  • you should get exactly the same result

  • if you do a five ply search, for example.

  • Shouldn't have changed the five ply search.

  • Just a five ply search should be faster.

  • And so that's a good way-- as much as possible,

  • you want to check things that are deterministic and so forth.

  • And, really, as I say, I can't emphasize this enough,

  • how having a good test infrastructure,

  • the ability to control turn off non-determinism,

  • the ability to test various parts of this program,

  • this is a pretty big piece of code

  • for a project of this nature.

  • And you'll feel pretty overwhelmed by it

  • to begin with.

  • Once you settle, you'll discover,

  • it's this wonderful thing, where by the end of the project

  • everybody feels really confident about their ability to handle

  • a decent sized piece of code.

  • But when you first get into it, it's like, oh my goodness.

  • There's move ordering.

  • And there's static evaluation.

  • And there's the search.

  • And what's going on with that transposition table?

  • Because every one of these things has got

  • cleverness in it.

  • OK, so it's really hard code to deal with.

  • But you guys are going to just fine.

  • HELEN XU: So this is the eval.c file in the handout.

  • So this in 32 here is the evaluation score.

  • And the main function is called eval.

  • And it takes in a position.

  • And it outputs two scores, one for white and one for black.

  • And right now, it does--

  • I guess it does counts of the number of pawns.

  • OK, so I was talking before about, p between and p central,

  • which are you pawn heuristics.

  • And so basically, right now, it iterates

  • through the entire board.

  • You can see for rank and file are just row and column.

  • And it looks at each square in the iteration.

  • And then it looks at the piece and the color of the piece.

  • And based on the type of the piece, it does some evaluation.

  • So if it's a pawn, it does the pawn heuristics.

  • If it's a fits king, it does these king heuristics.

  • And otherwise, or both--

  • or not otherwise, I guess--

  • yeah, in both cases it'll do--

  • this is an old version.

  • So it's not there anymore.

  • But this is laser coverage, which

  • we talked about earlier, which doesn't

  • depend on what piece it is.

  • This is after you iterate through the entire board.

  • And then this isn't here anymore either.

  • But we can look at each of these in depth.

  • So right now, for example, there's

  • p between, which goes through every single pawn

  • in your iteration.

  • And then it will determine whether or not

  • it's between both kings, and the return slide.

  • So it will add it to the score, if you find that it's true.

  • And there's p central, which takes in a rank and a file.

  • And, basically, it increments something,

  • or it gives you a bonus, depending

  • on how close you are to the center of the board.

  • So look at this.

  • There's a board with--

  • and F as your file.

  • And R is your rank.

  • PROFESSOR: I think you have a slightly older version.

  • HELEN XU: Potentially.

  • PROFESSOR: It's correct on the screen.

  • HELEN XU: Is correct in this one?

  • AUDIENCE: Yeah.

  • HELEN XU: OK, so this is just the--

  • I guess is the most updated version.

  • The first one is p central.

  • So this just count the difference

  • between where you are and the center of the board.

  • And it gives you some bonus, depending on how far

  • you are from the center.

  • And this one is between.

  • Yeah, so this is between, which is a helper for p between.

  • And it tells you whether or not your pawn

  • is in the bounding box determined by the kings.

  • And this one is k face, which is given a king,

  • you look at its orientation.

  • And then you give it a bonus, depending

  • on which way you're facing, and how far you

  • are from the center, I think--

  • no, how far you are from the opponent.

  • So f and r where you are.

  • And now it does the delta between you and the opposing

  • king.

  • And then you do some scaling, depending on which direction

  • you're facing.

  • So this is just your orientation.

  • And then this is k aggressive, which

  • gives you a bonus for how far you

  • are from the edge of the board.

  • So you can see here op square is where do the opposing king is.

  • And delta file and delta rank are how far

  • you are from the opposing king.

  • And then you add the bonus, depending on which case

  • the deltas fall into.

  • And this gives you a bonus if you're farther

  • from the edge of the board.

  • Yeah, and there's l coverage, which

  • is the most complicated one, probably.

  • And, basically, what laser coverage does is that,

  • basically, it takes a position.

  • And depending on what side you are,

  • it generates all the moves that you could possibly

  • make from that position.

  • So you generate all with color, which

  • means that, given your color, you

  • generate all the possible moves that you can make.

  • And you get a list of moves.

  • And you iterate through it.

  • And then you make each of them.

  • And you draw a laser path.

  • And what the laser path does is, basically, it

  • bounces off some pause.

  • And for each square, you increment the distance,

  • basically, along the path.

  • And if it takes the minimum distance

  • over all these possible paths for each square.

  • And if it doesn't touch a square, then it's just 0.

  • And it divides it.

  • I can go into this.

  • So it draws the path through this while true.

  • Or this is just changing the orientation

  • if you need to bounce off a pawn.

  • But this one is setting the--

  • you keep a laser map.

  • And you keep the minimum path of a laser

  • that would possibly touch that.

  • And, no, this is just changing the orientation.

  • So then you generate this map for all the possible moves

  • that you could do.

  • And then you do some scaling.

  • So, depending on the distance from the opposing king,

  • you iterate through the entire board.

  • And you divide the minimum distance

  • by the actual distance from the laser.

  • So the maximum that this ratio can be is 1.

  • And then you multiply it by 1 over the distance.

  • So this one is really complicated.

  • And there's a lot to optimize here.

  • For example, you probably don't have

  • to iterate through the entire board

  • each time, because even in eval, like here, you

  • have to iterate through the entire board

  • to find each piece.

  • And if you start a better representation,

  • you might not have to do that, like if you just

  • kept track of where the pawns were,

  • because you already keep track of the king separately.

  • So that's one thing you can do.

  • PROFESSOR: There are two basic strategies

  • for changing the representation of the board.

  • And maybe there are more.

  • But the two basic ones are, instead

  • of keeping the whole board with a piece on each square,

  • and then having to go and search for where the pieces are,

  • you can keep just a list of where the pawns are,

  • and what the locations of the kings are,

  • so that when you want to make a move,

  • you can just go through where they are,

  • rather than having to search through all 64 squares

  • on the board.

  • Then the other strategy that you can do

  • is use what's called bit boards, where

  • you have a 64-bit word for which, if there's

  • a pawn in a given position, you set that bit.

  • And so there are different ways of representing

  • things that could possibly be, definitely be, more efficient.

  • But you have some choices there.

  • And also, one of the complexities of this

  • is that to change the representation,

  • there's going to be places in the code you

  • need to find out where they're assuming that things are.

  • So you say, oh, I'll change the board representation.

  • Oh, I didn't realize that over here, there's

  • another place that it's using the board representation,

  • and so forth.

  • A good strategy for changing board representation

  • is to actually keep both representations around

  • while you migrate functionality from the old one

  • to the new one.

  • And then the advantage of that is that you can actually

  • then use assertions to say, you know,

  • the old one and the new one are the same.

  • So implementing conversion functions is really good.

  • For example, if you decide you're

  • going to use a bit board representation,

  • have a function that converts the bit board

  • to the standard board so that then you

  • can compare whether you've got the same thing.

  • And, eventually, you'll want to get rid of that.

  • And, of course, that'll slow down you down,

  • because you're doing more things.

  • But it will allow you to get it correct

  • with a new representation.

  • And once you've got it correct with a new representation

  • with the old one gone, that's when you have a chance

  • to make things go fast.

  • But it kind of is taking two steps backwards

  • to take five steps forward.

  • I say not one step and two steps, because really, often,

  • you really are slowing things down considerably in order

  • to convert from one representation to another.

  • The most important thing is you maintain the invariant

  • of correctness in your code.

  • You do not want to make something

  • that goes faster, but is wrong, and have

  • to debug the correctness.

  • You'd much rather ensure that things are correct,

  • are moving to the place that you want to do it.

  • And then you can optimize for performance.

  • So the most important thing is keep

  • that invariant of correctness.

  • And that's where the testing and so

  • forth comes in, having good test infrastructure,

  • and having assertions littered throughout your code.

  • HELEN XU: And then we can go through the [INAUDIBLE]..

  • Actually, OK, so, just as an example

  • of how you would possibly, one way

  • of determining whether or not you state correct--

  • so this is an example of a place where I compiled the code.

  • See the binary code is called Lesierchess.

  • And if you look at help, it gives you some options

  • for what you can do.

  • For example, there's display.

  • And that's the opening position.

  • And let's say I want to search.

  • So I do a fixed depth, and go depth three.

  • And it tells me the number of nodes

  • that I searched at each depth.

  • And so if you make changes, if they are deterministic,

  • these node counts should stay the same.

  • So that's one way of telling.

  • So you should keep track of this,

  • and make sure that they're the same.

  • And also, you can do perft, which

  • gives you the number of possible moves you can make.

  • And that should be the same, no matter what you do.

  • So that's one way of testing.

  • There's other ways.

  • So if you go to higher depth, you'll get more node counts.

  • And here, this is nodes that you searched at this depth.

  • And this is nodes per second.

  • So you want to make this one faster.

  • So that's how you run the code.

  • And I was supposed to do a demo for the auto tester.

  • So let's say I wanted to do--

  • so when I made it, it's in a binary called Lesierchess.

  • And then here, you can type in commands.

  • So you're basically just typing commands from this.

  • Like, you run your binary.

  • PROFESSOR: This is the UCI interface that we talked about.

  • And in Lesierchess.c is the implementation of that.

  • And so if you want to add your commands to it to help debug,

  • you can enter-- if we go into Lesierchess.c,

  • you can see the table.

  • What I want to do is show the table

  • of all the options, which is--

  • there we go, OK.

  • HELEN XU: This is just the heuristics.

  • PROFESSOR: So these are tables of heuristics

  • and so forth, which allow you to set

  • the values of the various things,

  • and to say, how much is this heuristic

  • worth to the static evaluation?

  • And through these, all these can be

  • set, so you don't have to recompile

  • the binary if you want to try out things with different--

  • if you want to auto test with, let

  • me count this as worth a third of a pawn.

  • Let me count this as worth half a pawn, or whatever.

  • You can just enter it through the UCI interface.

  • And in the auto tester, you can specify that.

  • So it will just test those without you having to recompile

  • binaries for every one of them.

  • And so there's a table here which basically says,

  • what's the name of the heuristic?

  • What's the variable that is going to be

  • set what the default value is?

  • And pawn ev value is the value of a pawn.

  • And if there's any restrictions on the range of those values,

  • what's the smallest it can be?

  • What's the largest it can be?

  • So you can edit this table, and so forth.

  • And as I say, you can set it through the UCI interface.

  • So it's really a very flexible way

  • of getting access to anything that you want to do.

  • You can put your own commands in there,

  • including new heuristics, or whatever.

  • And there's some things in there.

  • For example, if we go to the other part

  • where they actually are passing the UCI stuff,

  • so it basically takes it.

  • It parses it, figures out what the command is, and then

  • implements the command.

  • So all that kind of stuff, you have control over.

  • So that that will help you in choosing to do other things.

  • So, for example, if you search for perft or something

  • in there--

  • so if you have perft, here's what

  • the correct outputs should be.

  • And now, here's the code that it executes.

  • And perft is in a different file.

  • I think it's in the move generation file.

  • HELEN XU: Do I have the wrong output?

  • PROFESSOR: That may be for the older game, yeah.

  • I actually noticed a couple of other bugs in there

  • that hadn't been fixed.

  • So we will make sure that those are--

  • basically, it's just dead code, is what's in there.

  • We need to clean up some of the dead code.

  • Some of the code is from last year.

  • And we changed the game.

  • And not all the dead code got eliminated.

  • HELEN XU: That'll be fixed for when I make the repost.

  • PROFESSOR: Yeah.

  • So we're just finishing up some--

  • right now, I think it's all cleanliness.

  • But if you find any bugs like that, let us know.

  • We'll fix them, and so forth.

  • Appreciate if you do see other inconsistencies,

  • or what have you.

  • Good, so great project, this is like lots of fun.

  • Next month is going to be lots of fun for all of you.

  • You may not think it's fun every minute of the day.

  • But you'll have a good time.

  • It is fun.

The following content is provided under a Creative

Subtitles and vocabulary

Click the word to look it up Click the word to find further inforamtion about it