Placeholder Image

Subtitles section Play video

  • [WHISTLE BLOWING]

  • Hello, and welcome to a coding challenge--

  • Tic-Tac-Toe.

  • I'm going to make Tic-Tac-Toe.

  • I'm hoping, when you look at how long this video is,

  • it's very short, because I don't have a lot of time right now.

  • So I'm going to try and make a very beginner-friendly example

  • of the game Tic-Tac-Toe without any bells and whistles,

  • without a lot of fancy code.

  • I'm not going to overengineer it.

  • I will come back and--

  • [MUSIC PLAYING]

  • (SINGING) Oh, you will refactor this later.

  • You know I will--

  • I will refactor later, because the reason why I am making this

  • is I eventually want to show you some different algorithms

  • for an AI or at least a bot to play the game Tic-Tac-Toe.

  • But that's not happening in this video.

  • We're going to make the most basic, simple, friendly version

  • of Tic-Tac-Toe right here, using JavaScript, the p5.js library,

  • and the p5 web editor.

  • Follow along, if you wish, and see what happens.

  • I have not practiced or planned for this at all.

  • All right, I need a board.

  • So I definitely need a board.

  • I'm going to say, let board-- and it's going to be an array.

  • And maybe, it'll be an array of arrays.

  • And let's use strings.

  • This is probably a terrible idea.

  • So this will be the top row.

  • This will be the middle row.

  • Tic-Tac-Toe is 3-by-3-by-3.

  • And then I need two players.

  • So player one is an X. And player 2 is an 0.

  • So now, I need to render the board.

  • Let's put some stuff in it.

  • Let's just pretend it has some stuff.

  • So I want to render the board.

  • I could use this with dom-- there's

  • so many ways I could do this.

  • I'm just going to do this with Canvas and in the Draw Loop.

  • So I'm going to say, for let i equals 0, i is less than 3,

  • i plus plus.

  • For let j equals 0, j is less than 3, j plus, plus.

  • So this is pretty tricky.

  • If you're a beginner programmer, this is a nested loop.

  • And I've basically made this a grid.

  • So every spot in this grid-- and let me actually fill it out

  • just so we see something here.

  • I'm going to pretend this has just been played.

  • So the idea is that this two-dimensional array

  • structure--

  • this list of lists--

  • is storing all the information for what

  • the current state of each cell in the Tic-Tac-Toe grid is.

  • At the beginning, they're all blank.

  • And then, as the players play, X's and O's get filled in.

  • So now I'm going to nest a loop through--

  • check every column, check every row, and render something.

  • So I could just use the Text function.

  • I could say, let spot equal the board index i index j.

  • And then I could say, text that spot at x, y.

  • So where is x and y?

  • So I need a width.

  • I'm going to fill the whole canvas.

  • So width equals the width of the canvas divided by 3.

  • And height equals the height of the canvas divided by 3.

  • It would make sense for me to have players in an array.

  • And maybe I could have 3.

  • It doesn't have to be a hardcoded number,

  • because I could make, like, a 5-by-5 tic-tac-toe board.

  • But I'm doing this in the simplest way possible.

  • So x equals width times i.

  • And y equals height times i.

  • And let's run this.

  • What's going to happen?

  • Do you see anything?-- some X's and O's?

  • They're sort of in there.

  • And then I'm going to say, text size 32, to make it bigger.

  • Why are they all on top of each other like that?

  • Oh!

  • Oh!

  • I forgot j here.

  • There we go.

  • Look!

  • There's my tic-tac-toe board.

  • But things are kind of off.

  • Oh, because of the way--

  • you know what?

  • I should just draw it as a circle.

  • Let's do this.

  • If spot equals player 1, then draw an ellipse at x, y width,

  • width.

  • And then otherwise, if spot equals player 2,

  • then draw a line from x, y to x plus w, x plus h,

  • and another line from x plus w y to x, y plus h.

  • So that's me drawing an x.

  • Whoa!

  • That looks totally wrong.

  • So first, let me say, no fill.

  • And the offset should be plus w divided by 2.

  • So we need to offset all of those spot.

  • [TRILLS TONGUE]

  • Ugh!

  • Oh, and then this would be--

  • oh, no, no, no, no.

  • No, no, no, no.

  • Oh, my god!

  • Help!

  • Let's diagram this.

  • I have a 3-by-3 board.

  • This is x equals 0.

  • This is x equals 1.

  • This is x equals 2.

  • This is y equals 0.

  • This is y equals 1.

  • This is y equals 2.

  • So an x should be drawn from here--

  • from x, y, x, y to x plus h, y plus h.

  • So the x I did correctly.

  • Let's go back to here and comment out the ellipse.

  • And let's make the board all full of X's.

  • Let's just make the top row all full of X's.

  • Oh, my goodness.

  • [BUZZING NOISE]

  • Everybody, I just lost, like, two or--

  • like, 45 minutes-- not really that long--

  • by accident, because I had an x here.

  • This needs to be y.

  • OK, so now we can see the X's.

  • I could see the X's.

  • Let's draw the grid.

  • We could see the X's.

  • Oh, those are really giant X's.

  • Now, let's put the circles back in.

  • You can see, there's-- ah!

  • The circles need to be--

  • I need to say, ellipse mode corner.

  • There we go.

  • Oh, boy!

  • So the X's are all kind of connected

  • in a way that looks weird.

  • So actually, wouldn't it make sense

  • to not draw everything relative to the corners,

  • but to draw everything relative to the centers?

  • And I could have just used text-to-line and gone back

  • with the letters.

  • But I want to draw it.

  • I want to draw it.

  • So I'm going to draw everything relative to the center.

  • You'll see.

  • This is going to improve it.

  • Boy, this is really going super well so far.

  • So what I'm going to do is say, each X

  • is it's index into its column and row times the width

  • plus width divided by 2 plus height divided by 2.

  • That offsets everything by 1/2.

  • And then I'm actually going to say, the size--

  • I'll call this the X size.

  • I'm going to have this equal to w divided 2--

  • half of that.

  • And then I'm going to say, x minus x size, y minus x size

  • to x plus x size, --let's just call

  • this xr, kind of like the X's radius.

  • And then this one will be plus xr to y minus xr

  • and then to x minus xr to y plus xr.

  • And then, width divided by 4--

  • there we go!

  • There's my X's.

  • And let's make the stroke weight 4.

  • There's my X's.

  • And now the O's--

  • no more ellipse mode.

  • And let's make this w divided by 4 or divided by 2.

  • There we go!

  • Look!

  • So this is what the tic-tac-toe board looks like.

  • Yeah!

  • I like the way it looks better now.

  • That was painful.

  • So now, let's set it up as blank.

  • Oh, and by the way, I've reversed my x's and y's.

  • So actually, the x's should be j.

  • And the y's should be i.

  • Actually, let's just do it the other way around.

  • Let's keep x's i and y's j, but do

  • the j loop as the outer loop, and the i

  • loop as the inner loop.

  • There we go.

  • OK-- whoo!

  • So now, what I want to do next is play the game.

  • So let's have a variable called currentPlayer.

  • And currentPlayer is equal to player 1.

  • Let's randomly pick between player 1 and player 2.

  • So every time we start the game, the currentPlayer--

  • and let's actually-- let's make this an array.

  • I like the idea of making this an array for some reason.

  • And let's have the currentPlayer be

  • player's index 0 or the currentPlayer

  • is players index 1.

  • And then this-- we can make--

  • 0 is a circle.

  • 0 is the x.

  • I did it right.

  • 0 is the x.

  • Index 1 is the circle.

  • What's going on here?

  • Where's my error?-- line 44--

  • too many brackets, huh?

  • Oh, I need a closing bracket for setup.

  • OK, come back, board.

  • And let's make the background a 255.

  • Oh, this is very silly, because I can say-- the whole reason

  • for me doing that is, in p5, I can say,

  • currentPlayer equals Random Players.

  • So this will pick a random player.

  • I really need to see those lines.

  • So let's draw the lines.

  • Let's draw a line from w0 to w height--

  • oh, no, no, no.

  • So to w-- the whole height.

  • Then we'll draw a line from w times 2.

  • So I just want to draw that criss-cross.

  • And we'll do the same thing for 0 to width.

  • And this will be h to h and then h times 2 to h times 2.

  • Now, really what I should do is make this now interactive,

  • so that you could click and add the x or the y.

  • I think I might leave that as a little challenge to you.

  • I'm just going to have the computer play the game

  • Tic-Tac-Toe and see if somebody wins.

  • So either the board will be full and it's

  • a tie or somebody will win.

  • And I won't use any intelligent algorithm.

  • I'm just going to have each player pick a random spot.

  • So what I'm going to do is I'm also

  • going to make an array called Available.

  • So each available spot--

  • in the beginning, I'll just say--

  • I'm going to make a nested loop.

  • So much for making me be super beginner friendly.

  • So I'm going to say, available.push--

  • an i and a j.

  • So right now, every little pair of index values for that grid

  • is available.

  • So each time through Draw, let's make a function

  • that's called nextTurn.

  • And we'll say, spot that I'm picking is a random-- oh,

  • I'm going to have to get an index--

  • index-- because I want to remove it.

  • Index is a random number that's between 0

  • and the length of how many things are available.

  • And then the Spot is going to take that array, Available,

  • and remove that index value.

  • The splice function will remove it and put it in Spot.

  • And then I'm going to say, board spot 0 spot 1--

  • oh, that's so awkward.

  • But spot is a little array with two values in it, 0 and 1.

  • And so this is not a comma.

  • It's another little bracket.

  • Ooh, look how horrible that looks.

  • Let's do, let i equal spot index 0.

  • Let j equal spot index 1.

  • And then, in the board ij, I'm going to say--

  • [TRILLING NOISE]

  • --the player-- currentPlayer And then currentPlayer should

  • equal--

  • let's just pick a random player.

  • This is not the right way to do it.

  • Let's just see if this works--

  • mousePressed, nextTurn.

  • So every time I click the mouse-- uhhh!--

  • currentPlayer is not a thing?

  • When I splice it out, does it come in an array?

  • Oh, how awful!-- it comes in an array.

  • So I need to do that.

  • There we go.

  • There we go.

  • I'm filling up the board.

  • OK, I've done this in such a super awkward way.

  • I might want to rethink this.

  • But it does work.

  • You watching this will make a nicer version of this.

  • But I want to go back and forth between the players.

  • So currentPlayer should actually be an index into that array.

  • So I actually want to say random players.length,

  • because I want that to be an index.

  • Because then, when I am adding the things to the board,

  • I want it to be players index currentPlayer,

  • because the next player should be currentPlayer plus 1 modulus

  • players.length.

  • So I've built this in a way that you could

  • have more than two players.

  • So it should be O-X-O-X-O-X-O-X-O. Hey!

  • O won that one.

  • All right-- so this works with my wacky implementation.

  • Now, I don't need mousePressed to call nextTurn.

  • I just want draw to call nextTurn.

  • So it fills up.

  • But I also want to check for a winner.

  • Check for a winner.

  • So what I'm going to do--

  • I'm going to write a function called checkWinner.

  • And what I'm going to do in checkWinner

  • is see, first of all, if available.length equals 0,

  • then console.log toe.

  • So it was a tie.

  • So if the board fills up, it was a tie.

  • But first, I need to check-- is there a winner?

  • So let winner equal a null.

  • So I'm going to say, there's a winner.

  • Now, what I'm going to do is check all of the--

  • first, I'm going to check all of the ways across.

  • So let's first check horizontal.

  • So i is now the row.

  • So if board index i--

  • well, is that the row?

  • I don't remember-- 0 equals board index i 1 equals board

  • index i 2, then winner equals board index--

  • whichever one it is.

  • OK, so if all three of those are equal,

  • then the winner is whoever you picked.

  • I could also check now the columns.

  • I don't remember which is which, but whatever.

  • I'm doing one and the other.

  • Then if they're all equal, then I've got a winner.

  • So this would be vertical--

  • except it might be the other way around.

  • And now, I need to check diagonal.

  • So that's easy.

  • I just want to say, if board 0 0 is equal to board 1 1

  • is equal to board 2 2, then the winner is board 0 0.

  • And then I can also check, if board 2 0 is equal to board 1 1

  • is equal to board 0 2-- that would be the other diagonal--

  • then the winner is board 2 0.

  • And now, if winner is still null and available

  • is length, console.log tie.

  • Otherwise, console.log winner.

  • All right-- X is the winner.

  • But if there's a winner--

  • so let result equal checkWinner.

  • If result is not equal to null, then no loop--

  • stop the looping--

  • console.log result.

  • OK-- why am I getting errors?

  • Oh, OK.

  • Is nextTurn happening?

  • Ah-- nextTurn has to happen after this.

  • No-- oh!

  • [BELL DINGS]

  • I did something so nuts.

  • Look at this!

  • I was like, that doesn't work.

  • If this equals this equals that, that doesn't work.

  • This is the concept.

  • I'm going to write a function called equals3 a, b, c.

  • And I'm going to return if a equals b and b

  • equals c and a equals c--

  • so this is really the only way--

  • there's other ways.

  • But this will actually check--

  • if a is equal to b and b is equal to c and a

  • is equal to c-- if all of them are equal,

  • then all three of them are equal.

  • So I'm sure people have been screaming at their--

  • so now I can say, equals3--

  • and like this.

  • And then same thing here--

  • so this is checking all the horizontal.

  • This is checking all the vertical,

  • even though I have this mixed up.

  • This is checking the two diagonals.

  • If the winner is null and available, length is 0.

  • We have a tie.

  • Is that redundant?

  • Yes, this is redundant.

  • Yes-- whoops!

  • Where am I-- am I console logging somewhere else?

  • Oh, I forgot them.

  • Oh, I'm not returning the winner.

  • [BELL DINGS]

  • And I'm console logging a lot of other nonsense here.

  • I'm doing a horrible job at this.

  • This should be return.

  • I'm rushing.

  • You should never code and run.

  • Take a deep breath and relax while you're coding.

  • Return tie.

  • Otherwise, return winner.

  • Now-- oh, they could be equal!

  • They can't be blank.

  • They can't all be--

  • then somebody wins.

  • They have to be full.

  • So OK-- and a is not equal to blank.

  • There we go!

  • X is the winner.

  • Let's run it again.

  • X is the winner.

  • O is the winner.

  • X is the winner.

  • So let's at least make a createP winner style color FFF.

  • Oh-- result 32 point--

  • there we go.

  • That's what I'm looking for.

  • OK, now every time I run it--

  • tie, O, X, O wins.

  • And let's changed the frame rate.

  • We're going to make this super dramatic.

  • Frame rate-- 1.

  • OK, here we go, everybody.

  • O, X, O-- where's X going to go?

  • Oh!

  • X, O, X-- oh!

  • It was a tie.

  • Oh, no-- O won.

  • O won.

  • [CELEBRATORY MUSIC]

  • Congratulations, O. Let's play this one more time.

  • [RAGTIME PIANO MUSIC]

  • Here we go--

  • X, O. What will happen?

  • Place your bets.

  • X won.

  • Congratulations, X.

  • [RAGTIME PIANO MUSIC]

  • X, O, X-- come on, X. Oh, you can do it.

  • Oh, good work, X. Wow!

  • You really won that one.

  • All right-- thanks for watching this coding challenge,

  • where I made an AI play Tic-Tac-Toe against itself.

  • You can see how well it's learning.

  • X just keeps winning over and over again.

  • I will come back in a future second part to this.

  • I know I say this for so many coding challenges.

  • You think I'm never coming back.

  • It will be sometime in the next several years.

  • I will come back and fix this up a little bit,

  • as well as implement something called the mini-max algorithm,

  • to actually make thoughtful, smart decisions for how

  • to place your X's and O's for an AI

  • to learn how to beat this game and to always win Tic-Tac-Toe.

  • Ah-- and as a challenge to you, the viewer,

  • take this version of my Tic-Tac-Toe coding challenge

  • and, when X or O wins, draw a nice little line through it,

  • to indicate the winning.

  • I don't have time for that right now.

  • I should really add this to this.

  • But please add it to this.

  • Go to the Coding Train website, where

  • you will find this challenge on the website itself

  • and a place to add your community contribution as well

  • as--

  • a video tutorial about how to add your community contribution

  • is out now as well.

  • So I hope to see lots of Tic-Tac-Toe games

  • and computers playing them, people playing them.

  • And have a lot of fun making those.

  • And I'll see you in a future coding challenge.

  • Goodbye.

  • [BLOWS WHISTLE]

  • [MUSIC PLAYING]

[WHISTLE BLOWING]

Subtitles and vocabulary

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