Build a web version of a board game
How do you build a board game using HTML, CSS, and JavaScript? Eli Goodman joins to teach us how we can build our own using web tech.
Links & Resources
Full Transcript
Click to toggle the visibility of the transcript
Captions provided by White Coat Captioning (https://whitecoatcaptioning.com/). Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.
JASON: Hello, everyone, and welcome to another episode of Learn with Jason. Today, on the show, we are going to be having a good ol' time trying to build a board game using web tech, which I'm very, very excited about. And to help us do that, I'm going to be bringing to the stage Eli. How you doing?
ELI: I'm great, Jason, how are you doing?
JASON: I'm doing great. Super excited to have you on. I think this is going to be fun. We'll talk a little bit more about the news that brought you here. Let's jump into who you are. For folks who aren't familiar with you and your work. Can you give us a bit of background on yourself?
ELI: Yeah, absolutely. I've been working with computers for about 17 years now. And so, 15 of those years, were largely in engineering capacity, I've done full stack, dev stuff, frontend roles, backend roles, management, all across the board. And worked at fun companies, Etsy, going from little to big, worked at Headspace in Los Angeles, and tiny startups. Everything, the whole gamut. I currently am in a product role, transitioned to purely product management a few years ago, and I'm actually the head of product at a company called Tuple.
JASON: What a segue that creates for me to say, I'm super excited because we have a new sponsor on Learn with Jason. And it's a new kind of sponsorship. I'm very excited because a lot of times what sponsorship on Learn with Jason meant, is that companies are paying to cover the cost of, like, the live captioning, which I so deeply appreciate. But we haven't really explored anything beyond that. And the team at Tuple came out and said, hey, what if you use Tuple as part of Learn with Jason, and I was like, I don't know, product placement is usually not my thing. But then I saw Tuple, I was like, wait a minute, this is kind of perfect for what I do. So yeah, Eli, do you want to give us a quick overview of what Tuple is?
ELI: Absolutely. In short, Tuple is a paired programming app. It is an app that runs on Mac OS and Windows. We think it's the best way to pair program. If that's something you do the a your job or your personal life. It's, especially, if you're using something like Zoom or Google Meet to do your paired programming sessions, it's got a lot of special affordances to make them smooth and seamless. Some of them will come up organically as we use Tuple today, but we think the experience of using Tuple is four clicks smoother than you might experience with the generic experience. Stay in flow, do good work with your teammates and get stuff done.
JASON: Yeah. And I was excited about it because it's got a few features that we'll end up playing with as we go through today. But the long and short of it is, huge thanks to Tuple allows me to do more with the show. Allows me to reinvest into Learn with Jason in general. So welcome, as a sponsor, thank you all for continuing to watch so that companies like Tuple want to sponsor shows like this. But let's talk a little bit more about what we're going to build today. Because we, you kind of pitched me on, let's build a board game. And I didn't question that. I was like, yeah, whatever, let's do whatever you want Because it sounded fun. I like the idea of building a board game. And then, I started thinking about it. And I got kind of intimidated. I was like, wait a minute, there are a lot of rules in a board game. There are a lot of things that we have to, like even, even simple things like Tic Tac Toe, there's a complexity hidden in how all of those different roles work. So, I'm not going to lie, I'm coming in a little bit nervous about how this is all going to come together. Maybe, give me an idea of what, how do you approach something like this?
ELI: Yeah, I think there's two things that are giving me a little bit trepidation. The first is, I think we're going to be armed with a very nice, very nice open source library that's going to give us a nice boost. There's a very cool library I found. And this is really the impetus for me to wanting to bring this to the show, as well. We'll bring it up once we get more into the thick of it. But I found this library called Boardgame.io. And what I like about it is, again, it's tailor made for board games, right? If you're going to build a board game from scratch, either traditional web technology, or using a game engine, you're starting from a blank slate, right? And there are a bunch of concepts that are, you know, common to most boardgames, a lot of them have a setup phase, and a phase where you go back and forth and do turns. Most of them have an idea of an invalid move and move validation. The nice thing, boardgame.io, structures and those things, makes it easy to come in with a general approach that's already been prethought for you and kind of just fill in the blanks without having to, you know, start from a completely blank page. And so, I'm really excited to use board game. To be clear, I haven't really done anything with it. I looked at the library. I went through a little bit of a hello, world, with it and I was like, this is going to make our lives a lot easier. I think using board game is going to, hopefully, make this less of a scary experience.
JASON: OK. I love it because this is, like, it wouldn't be an episode of Learn with Jason if we weren't taking a big leap on a half baked hunch. [ Laughter ]
ELI: Yeah, the number of decisions in my life where I've done 15 minutes of research and then just jumped in, more than I would care to name. So, you know. Common pattern for me, personally, as well. [ Laughter ]
JASON: Yeah, we're going to YOLO development is always a good time.
ELI: Yeah.
JASON: All right, so, what game did you want to make today? Are we trying to invent something? We going to make a classic? What did you have in mind?
ELI: I think a classic is probably going to yield a better result than us trying to do some realtime game design, which, again, I've done it in the past, and it's fun, but I feel like the most standard thing for us to do is checkers. I think checkers is probably one of the easier things to implement. And it's got some wrinkles, too. I actually was thinking about checkers, it's got some parts that might be a little bit of a puzzle for us, but I think it'll be just complex enough to be fun.
JASON: Yeah, if we're thinking about checkers, it has awe tensively, it's very, very easy, the pieces can move they can jump. They can move in certain places, they can jump. They can multijump as long as the chain is available. You also have the ability to get kinged and once a piece is kinged and the rules all change so really interesting stuff we're going to have to deal with on this. That's going to be a lot of fun.
ELI: For sure.
JASON: Are we going to accommodate house rules? [ Laughter ]
ELI: That would be a good feature. Yeah, I actually went and found, I found like Hasbro's old school PDF of Checkers rules, and there was a rule I've never seen before. So yeah, person that made that comment, there's obscure Checkers rules that people deviate deep into the game.
JASON: I'm so ready. I feel like, I do have a lot of questions, but it'd probably be easier to dive right in and start talking about them. Why don't we flip over into the pairing mode. And first and foremost, look at this updated sponsor banner. There's Tuple, there's Netlify. We've got live captioning today, Diane is here from White Coat Captioning, thank you so much for being here today, Diane. And, yeah. Just amazing. We're going to be building a web based board game, and here's Eli on GitHub. I asked Eli earlier, where should I direct people? And he said, I don't have a web presence on purpose. And I felt this like wave of calm come over me about, like, just not being on like, man, that must be nice. [ Laughter ]
ELI: Yeah, it's just not my style. But you know, respect to everyone who does have an internet present. I'm not organized enough for it or photogenic enough.
JASON: Well, I think we can all disagree with that. [ Laughter ] So, OK. So we've got you on GitHub. We've traced you down on the internet. You're here. And we are talking about, we're going to be using this repo today, and let's just throw a little link out to Tuple for anybody who wants to give this a shot. Maybe let's talk about this repo and what you want to start. Let me actually get this going while I'm in here. We will, what am I doing? I want to get back here. And then, I'm going to make a directory called, this is so my links work and all mirrors GitHub.
ELI: Oh, nice.
JASON: And we're getting board game react now I've got to get this back so I don't forget later where the heck I am. Open this one. We're in this repo and inside. Package JSON, and I can see, here's boardgame.io. Typescript stuff, testing stuff, React, React, DOM, React typescript. This looks pretty bare bones.
ELI: Yeah.
JASON: Anything in specific you want to kind of call out as we're getting started here?
I don't think so. Again, I made this repo sort of as it's half create React app you see some of from there, and stuffed just enough boardgame.io to get us started. Do you think it makes sense to take a peek at boardgame.io so we can grab what it is and what it does with React?
JASON: Yeah. Let's do it. Where should I go?
ELI: Well, I'm going to do a cool Tuple thing right now. Tuple has the ability for me to send you a link and open it in your browser. I'm going to do that for you.
JASON: Hands free. That's dope. All right. Heading, oh, opening the wrong one, though. Let me open my not the whole thing, just the tab. Woes of running a million browsers while trying to manage the stream. Here's boardgame.io.
ELI: Yeah. I think something that really helps me sort of grasp what this was. And I'm doing Tuple y stuff here. So the most important feature of boardgame.io is (inaudible) smiley face. Hey, you've got to have fun, got to laugh, you know what I mean? I think it's going to be taking the place of sort of what Redux would do in a more traditional React app where Redux is our canonical state store, and it's got things we can perform. Boardgame is going to store our game state and allow us to define some meaningful mutations to that. If we move a piece, we'll have to move a piece and then, itself is user agnostic, you can do this in raw JavaScript or HTML. But I've been using React for a minute and I get the sense that Jason, you have as well. And so, what I've put in this, in the repo is really like an empty shell of game state with no mutations whatsoever. And then, just an empty React element that consumes that state and spits out nothing at all. And that's what we've got in the repo right now. It would be good to keep this handy. Remote control for a second. I think having this up is going to help us help us move along but, I think for right now that's probably the most important thing to know about boardgame.io. You mentioned being daunted a the the scope here. I'm wondering, like, do you think it makes sense to do a little maybe like breakdown, make a little to do list for ourselves? What do you think about that?
JASON: Yeah, I think that probably makes a lot of sense. Why don't we hop back into here? And maybe throw it into whatever, we'll make a new one. Let's do game rules.md. If I can spell it right. What am I doing over here? There we go. So a little checklist did you want to do it like this or put it somewhere else?
ELI: Yeah, this is perfect.
JASON: OK. So we need, oh my god, this is so overwhelming. So, you have pieces can move one diagnosal space, do I remember the that's how checkers works, right? They move diagonally?
ELI: Yeah.
JASON: If there's a clear space behind, pieces can jump an opposing piece. Pieces can only move forward. If there are clear spaces, pieces can jump multiple times. What else? If a piece reaches the opposing end of the board, it is kinged, kings can move backwards. What else? Is that it?
ELI: I think that's about it. I think the only thing I would put in here, and I'm going to control for a second. I think, also, to get ourselves started and give ourselves a little bit of a mini confident boost, it might be good to set up the board. Board is 8 by 8. We can at least get that going. And also, pieces placed (inaudible). And yeah, I think that, you know, for the purposes of this stream, too. I think if we can move our way down this list and get through as much of it as we get through, I'll consider that a success. If we don't get all the way to the kingly stuff, I think that'll be chill. Just in case you're feeling overwhelmed, that's what I'm thinking.
JASON: Yeah, I think that works. So then, and then, we also have so it's an 8 by 8 board, so there are 12 pieces. Pieces are placed, does it matter if it's on the white or black? Or is it as long as they're on one or the other?
ELI: That's a great question. This is the aforementioned PDF I mentioned. It definitely comes from a different era, refer to the pieces as men.
JASON: The men.
ELI: The men. But the pieces, it looks like in the drawing, at least, are all on the dark colored squares.
JASON: OK. All right. So we'll say on black squares.
ELI: Yeah.
JASON: OK. I feel that's close. Honestly, if we can get to jumps.
ELI: Yeah.
JASON: Why don't we switch these up? [ Laughter ] Where in kind of a, we build the board, get pieces on the board, get them in the right spots, and get them to move forward, if we can get to jumps, I feel like we've sort of, that's pretty solid for how much time we have.
ELI: I think that would be a resounding victory if we could get there. That sounds great.
JASON: The beaming thing, that's part of Tuple. So let me actually pull up. Where is my Tuple window here? You can see here that Eli and I are on a call right now. I'm sharing my screen and Eli has the ability to show, he can send me links and draw on the screen and stuff like that because we're in this call together. And if I was the one watching, I would be able to draw on his screen and do a few other things. But yeah, I feel like this is all cool, this is why I got excited when the sponsorship came up is, like, this is stuff I wish I could do all the time. We're always, guests are like beaming something, or they're sending me a private link somewhere to copy/paste it. Being able to beam it. Another thing I do all the time that's a pain, there's a little bit of code they're trying to explain and I don't know what they mean, it's a framework I've never used before. If they could type it, they would take over the screen and type 3 characters and we would be done. They have to DM me code, there's a lot of cool stuff that happens here that makes the stream run a little bit better, actually, which is why I thought this was such a good partnership. But yeah, it is very cool stuff. Anytime you're working with anybody. It's cool stuff. You've got requests for other platforms.
ELI: Windows, yes.
JASON: So it does work on Mac and Windows. Hell yeah. Let's dig into this, here. Let's get ourselves a piece. So I'm looking, we've got our index.tsx, which is a pretty standard React setup. We've got our client or strict mode and all of that stuff. Why is it yelling at us? Oh, I didn't NPM install. That'll do it.
ELI: There we go, now it's happy.
JASON: And I can start the server, it's not going to yell at us anymore. Maybe I can't.
ELI: I think it might be NPM
JASON: Did I spell it wrong? Start, ah. I haven't used create React app in so long. I've gone full in on Vite.
ELI: Yeah, go ahead, sorry.
JASON: I'm going to position these up here and see if this might not be what we want. Oh, that's nice. Is this part of board game?
ELI: Yeah, it's Redux just for boardgame, Redux has this bespoke dev tool things that allow you to introspect state. And boardgame has its own idea about some of those things and allows to artificially switch whose turn it is and stuff like that. It has cool bells and whistles. It's good stuff.
Right now, our board, our board does nothing. We've got our game. Our game our cells. Doesn't do anything else. This is the core of what's going on, right?
ELI: Game.ts, that's the state store, the board is the React element. And then, this we can kind of ignore. I was also getting a little bit ambitious about what we might do here. One of the other cool thing is multiplayer for free. It's a multiplayer experience. It's are very cool thing to do, which is to take the same game logic and you can, it comes with a server component, you can run it in Node, it'll validate every move giving is valid the game state and will federate it out. It's very cool. But this is basically saying that, like, we're using local multiplayer, you could have essentially two clients running in the same browser.
JASON: OK. Got it. OK. What do you want to start start with the board maybe?
ELI: Well if the task is to set up the state, maybe we jump into game.ts, yeah, and just get. So this has got a little bit of craft in it from me setting up some, comes with a Tic Tac Toe, but I think I've expunged it. I think getting this in the right state is probably the first thing.
JASON: OK.
ELI: Hmm, so, again, if we want a grid of spaces for this state of the game, right? I feel like an array of arrays is probably the right data structure, right?
JASON: Sure.
ELI: We can talk about what those spaces should contain.
JASON: Yeah, so they would need some unique identifier. Using chess logic, it would be A1, A2 for the first row and B1, B2 for the second row if I'm remembering correctly. And then, we would need to know whether or not a piece is occupying that space. And I guess the piece would need to be identified as like which team it's on.
ELI: I think that's right, OK. I'm going to drive through it.
JASON: Yeah.
ELI: I think it'll make sense for us, and apologies if my typescript is a little bit rusty. But maybe cell, a structure that represents the information that will be in each element of the grid, right? So sounded like what you were talking about, each one might have a string identifier, which I think maybe we might be able to get away without this, just in the interest of time. I don't know if we're actually going to need that, so we can maybe circle back to that one. Also one thing might have is there's a color of the square itself, right?
JASON: Oh, right.
ELI: Not that, so, like this, right?
JASON: Yeah, I think you just do white and black.
ELI: OK, cool. Semicolon? Comma?
JASON: Great question. I think if you save, it'll autoformat that for you. Commas it is.
ELI: Cool. And I think we might have a piece out there.
JASON: Mm hmm.
ELI: Being a little bit optimistic here. But I think we also make another little... so when we think about what is intrinsic to each piece feels like maybe.
JASON: Really just the color and whether or not it's a king.
ELI: I think that's right. Do you want to have separate. Do you want to reuse this color?
JASON: I don't see why not.
ELI: Cool. That's a semicolon. And we're going to say is (inaudible) that look kosher to you?
JASON: Would it... so thinking through the is king flag as opposed to a type. Because if we have a set of rules for I don't know, they're not pawns, but for standard pieces, rules for kings. I guess it doesn't matter, the check is basically the same thing?
ELI: Yeah, that's a good point. Maybe we'll circle back. We'll see if we get to kinging stuff.
JASON: Sure, yeah.
ELI: I can see it both ways. I think a lot of the logic will be centralized inside of the state store here. I could see an argument for a bona fide class. And inherit piece, override a function, I could see that being a strategy, as well.
JASON: I gotcha.
ELI: I see merit in both ways. But yeah, I feel like for simplicity sake, we can stick this in here and change it if we want to.
JASON: OK.
ELI: And circling back to this type definition here. Feels like we want to utilize the cell type.ing it's an array of array of cells. I think this is the tactical way to represent that typescript. Does that track for you, as well?
JASON: I mean, we could fight about whether it should be an array with pointy bois or the square bois at the end, but we don't have time for that.
ELI: Being like
JASON: You can also do...
ELI: Go ahead.
JASON: Oops.
ELI: A ha, actually, maybe I'm a fan of that, it's a little bit clearer.
JASON: I find it easier to read, but, you know, I think it is more preference than anything else.
ELI: I'll see that, that sounds good. OK cool.
So we've got our grid is an array of cells.
ELI: Mm hmm.
JASON: And we would also have, like, the game state, or I guess we could call it state because we have, and that would either be, like, active or, like 1 or ended or something. I guess because we would need a way to say whether or not you can make another move.
ELI: Yeah, I think it's saying the boardgame's going to handle for us.
JASON: Oh.
ELI: All we need to say is, state that's salient to the rules of this particular game.
JASON: OK. OK. So then, I think I have to kick it back to you because you've done more reading of the boardgame docs. But to define. So our grid is an array of cells, that makes sense, are pieces, then, we'd have moves or like pieces placement or initial placement or something. Is that defined here or is that defined somewhere else?
ELI: So, I think, I'm looking at the docs myself, but I think we're going to be able to define a function inside of this guy. Whatever you're yeah, there we go. So this, these are all of the things that boardgame allows us to define about our game. The rules in the abstract. And so setup, I think is going to be the thing that we want to implement and looking at the docs, I think setup is a function that returns an initial value for that state object, right? So as long as we return a valid checker state, then it'll be happy. There we go.
JASON: And so we don't know if we need the ID, but we can do something like that to start. Color would be... does it just use a string like that? It does, OK. And then, the piece needs to be an object that's color and, OK, that's one valid cell, and we need 8 by 8 of these?
ELI: Yeah, I think that's right. Oh, and also, yep, yep, that looks like one valid cell, you're right.
JASON: OK. So we've got our one valid cell.
ELI: Yeah.
JASON: And then, we would do 2, 3, 4, 5, 6, 7, 8. And then this one would be null. In fact, why don't I get rid of these and we'll copy/paste that.
ELI: There you go.
JASON: This would give us our back row.
ELI: Jason, before we go too deep with this, I also wonder about the syntax for the string there. I'm not entirely sure about it. I don't want you to have to go back and do it, again, I think I've done color.black, I think they'll become integers and possibly JavaScript.
JASON: I gotcha.
ELI: To avoid surgery later, I think that's the syntax I've seen before.
JASON: I didn't realize it did that. That's great. This gets us one row. And we would take this and duplicate and that would let's see. Collapse this one. We end up here and all of these become B, and we need to swap our pieces.
ELI: That's right.
JASON: There's not an easy way to do that, I'm sure the VIM people are screaming, yes, there is! But I don't know what it is. [ Laughter ] But I'm going to copy this and we'll drop these in here oh, boy. And if I copy my A rack one more time, the pieces are in the right place and I can make them C. That's our first rack.
ELI: Yeah, I think that's...
JASON: For the middle two rows.
ELI: Yeah.
JASON: Everything is null.
ELI: And to save copy and pasting, you want to make a function called empty row that spits out 8 of those dudes.
JASON: What a great idea.
ELI: And I'm also going to Google something when you're doing this. I think the... there was a syntax in JavaScript for creating an array that's defaults filled with particular number values. I think it is I don't know off the top of my head, but I'll Google this in the background.
JASON: So, actually, the hmm, let's see, it's like array.fill or something.
ELI: Yeah, and I think actually I'm thinking of the constructer I may be misrepresenting something. But there's .fill, there's array, array length as a constructer. So you can say, like, array H.fill with a value, I think.
JASON: Array 8.fill. OK. Array. 8.fill.
ELI: There it is.
JASON: And the value can be any of these, however, that won't solve our ID problem.
ELI: Oh, yeah, OK.
JASON: You did bring up a good point that we might not need an ID. The only reason I was thinking if we need to specify that the moves have to match a successive piece.
ELI: I think we're going to have enough information based on the X and Y coordinates of the grid to be able to know what we need to know. If it makes your life easier to get rid of the ID, maybe now's the time to do it.
JASON: And also, the chat just mentioned that we've been making all of the cells black instead of alternating black and white.
ELI: Thank you, chat, that's true.
JASON: That's another issue to figure out, how to interweave these. Because, we could probably write a function that would, like, make 2 arrays and zip them together. But I don't know, copy/paste might be easier.
ELI: Yeah, let's do copy/paste, let's do it.
JASON: So we're going to copy/paste. Let's get this one here and then we'll get this one here. OK. And then, we're going to get one more of these make it white. Oh, that's irritating I didn't catch that earlier because now we've got to go back and do a bunch of, let's see, 4, 6, 8, OK. That's going to make this one much easier, we'll go up and replace. There's our blank row.
ELI: There it is.
JASON: We've got three. These need to alternate. All right. So that's starting white, ending black. And then we on this one would need to end on white. OK that should be right. And this one ends on black. And thank goodness I got the guess right there. Our null pieces are going to be on white squares.
ELI: Good.
JASON: Good. Good, good. And so, then, what I think we can do is take these three rows and we can drop these down here. And I believe that puts them in the right setup, and then we can drop out our IDs because we won't need them. And does that mean our pieces are in the right place? I think it does. That should put us with a complete board.
ELI: Nice.
JASON: Right?
ELI: I'm with you. I'm feeling confident. I agree, visualizing this is probably going to help us. If we work something really important.
JASON: So that is that. I'm going to finish deleting IDs because this is where we are. This is who I am now. So close. So close. Oh, my goodness, I could have written a red X to fix this way faster than it's taking me the to do this. Like ten more.
ELI: Appreciate the encouragement from the comment section.
JASON: High entertainment right now.
ELI: People say, what is programming like? And you're inserting rows of text and deleting rows of text constantly. [ Laughter ]
JASON: OK. So this is our board, and if I'm not mistaken, it should lay out a properly set up board.
ELI: Yeah, I think that's right.
JASON: For us to actually try this and test it, how do we do that?
ELI: So let's go to board.tsx.
JASON: OK. And is it in the game?
ELI: Yeah, I think the G variable, and this is copying the board games, the style, I think G, if we hover over it will also show us it is of type checker state.
JASON: Yeah, it is, OK.
ELI: We can do that to do React y stuff.
JASON: Grid.map. And that's going to give us our rows.
ELI: Yes, that's right.
JASON: Each row, I guess. And inside of here, we're going to get a we'll return row.map.cell. What am I doing? Oh, I missed. There we go. In here, what we should... wait, we need a little more. We're going to do... we'll do a div class name row.
ELI: Nice.
JASON: And then, get one of these going.
ELI: Yeah.
JASON: Get one of those going. And then, in here, we should be able to do a div class name cell and inside of it, we should be able to say I guess we can cell.color, is that come in as that is coming as a color? Equals color.black. Black or white. And do we have to import this?
ELI: Yeah, import over here.
JASON: OK. We'll get back to the board. We'll get color. And inside of it, we can do a cell.piece, and if there is a piece, we'll do, I don't know. Class name piece. And then, I guess we'll do it this way because why not? What's going on? What did I miss?
ELI: There it is.
JASON: OK. All right, everyone. Theoretically speaking, what am I we need one of... oh, we need our closing parentheses. There we go so there is our board, maybe. And we can say class name, board, and we should be able to style on that. Let's go based on what we've got here and see if it's doing what we think it's doing.
ELI: Yeah.
JASON: Board, one, two, three, four, five, six, seven, eight rows. One, two, three, four, five, six, seven, eight cells. All right. So then, let's, I guess, let's style these real quick so that we have that. Did you want to style in a certain place?
ELI: I think create rack app has CSS, I don't think it matters which one we use. There's some stuff we can blow away.
JASON: I'm going to dump that. And we're going to say board is going to be... also, let me make this CSS. There we go. We'll make this display flex, flex direction column, and row is going to be display flex. That should be fine. We'll do cells. We'll go with 100 pixels. Let's be block size and inline size. We'll max up at 100. And then, if it's black, background color of black. If it is white, background color of white. And then, we've got our pieces. And let's give these a how do we want to do this? Let's go with padding of 10pix, and we can say, these are block size 100%. And inline size of 100%. Is that actually going to work? We will find out. We'll set a background colors like that. And then, we can say border radius is 50%. And we'll give it a border just so we can see the pieces 1 pix solid red. How close did I get?
ELI: It's all looking pretty good to me. I'm glad you're driving the CSS stuff.
JASON: Did any of that actually happen?
ELI: Hold on, there may be a missing bit of glue here. Go back, I think we have to actually include the CSS file.
JASON: It's in the index. I'm going to pull it into the index, then.
ELI: Cool. We can leave that in, that looks fine.
JASON: This is not perfect by any stretch. Oh, we also screwed some of this up. [ Laughter ] Oh, I think I forgot to change.
ELI: Sorry. A little bit of Tuple magic, it allows you to throw emojis on there. Pardon me.
JASON: We got a couple things wrong here, but we're not as far off as, OK. So yeah, we've just got a few things, I think, just placement is wrong. So if we go back into our game black, white, black white, which ones are wrong so third row. We're going to collapse to here's our third row, black, white, black, white, black. So now that one's right and we screwed up here where these need to just shift. And I think the way we can do that on these is to quite literally just drop the top piece to the bottom on each of these and that should flip the rows, if I'm right. And I am because I'm a genius. [ Laughter ] And we'll go with all of these. This side will be our white side. So we're going to go with... let's get these. Piece color black. And we'll select them all. So that gets this side to white. Got to fix that. Last row has a missing one. Oh, no, that wasn't the right one. It was this. OK. This last one over here and get that set up properly. These are the right ones. OK. There we go. We got ourselves a checkerboard.
ELI: Beautiful.
JASON: Yes.
ELI: All right. Cool. Should we zoom forward to movement?
JASON: Yeah, let's give it a shot.
ELI: I was thinking this a little bit, and we think we're going to be using React state management a little bit and boardgame a little bit. I think we're going to have to implement an interaction to click to select a piece, you want to show it's selected. And then, click on a destination. So I think in boardgame's world, the actual selection of the piece is not mutating the game state, we probably want that to be a bit of state we keep on the board React component. So we can keep track of, like, oh, piece is highlighted and this thing is clicked, and then we can dispatch to board game to be like, now we want to do an actual move that mutates. Make sense?
JASON: Yes.
ELI: If you want me to code up what I'm saying, I'm happy to do that, too.
JASON: Yeah, I took a run at this, why don't you take next step?
ELI: All right, cool. I'm going to go ahead and collapse some of these rows. Just to keep things tidy. And we're going to be doing our stuff over here. What I'm thinking of is inside of here. And this will initially be null, right? Because... and then, if we want to get nice and clean with everything, I think the type of this is going to be null or, will also need to export from game over here. We use it elsewhere. There we go. All right. Very cool. Now that we've got that, let's make it so that if we, and there's a little bit of subtlety, we don't want to be able to float somebody else's pieces. So maybe put that as a subbullet right now. We do this that way and go back and make that not possible. But the essence of what we want to do is a... click...
JASON: You need curly braces around the function itself?
ELI: I do, yeah. That selected piece. Cool. And actually, let me think about this for one second. Because so this maybe I'm going to eat my words here about these things having unique IDs. Because what we're going to want to do is show a similar selected state on these things.
JASON: Right. I think if we just assign this to the state, it's going to, could do a buy value comparison of these objects. Is this going to work out if we want to do the naive thing here of saying we've got a selected piece here, if piece equals selected piece, then share the border. We could try it.
JASON: Yeah, let's see what happens.
ELI: I could see that not happening. I'm prepared for that, too. Let's grab this. And let's pace that down there, and so we can say if so that piece, the triple equals. And this actually, my JavaScript's a little bit rusty here, this actually might be a situation where we want double equal sign. I want to say if the reference is the same and not the values are the same. I've, again my rust is showing here, my rustiness, but I think that might be one.
JASON: I actually don't know I've ever tried this specific type of comparison before, so I... my paranoia would force me...
ELI: All right. Let's try that.
JASON: OK, then, I can take over from here and put just a selected on here. And we'll do border color red. Actually, why don't we do this? Let's make these like a lighter color so we don't need, like, fours and this one can be D. And then, these can be, usually, and that's a little bit easier to see.
ELI: Nice.
JASON: And we click on one, it goes red.
ELI: Cool.
JASON: Let's make that a little bit more obvious.
ELI: Yeah, that's a good suggestion, and if this for some reason doesn't work, I think that's the next place to take it.
JASON: OK, chat don't yell at me, I'm going to do CSS for a second. Border box, stop breaking my stuff. That's better. OK, now we, instead it was just kind of blowing out the sides. Now, we have our selected piece. And then, theoretically, then, what we want to do is, we need the game, these are our two viable moves. And then, so now that we've got a selected piece, we would need... so based on selected piece...
ELI: Yeah.
JASON: The available cells are this one and this one. And when I click on it, we trigger the game to move.
ELI: Yeah, I think that's right. I think that showing pieces are available as places to move might be a little bit of an embellishment we could do later. But at the very least making it so we click on one of these we attach to, like, yeah
JASON: That's more what I meant
ELI: I gotcha.
JASON: I don't think necessarily we have time to build the UI for it. But just getting it to where, like, how do we Del the game L, how do we get board game to know only these two squares are available to this piece and only these two squares are available to this piece?
ELI: Cool. Here's how I think E with might do it. So, I think we're going to need to hop back over here. And I'm going to consult the docs for one second, but cool. OK. I got it. All right. And inside the checkered state object. I'm going to set it up so you don't have to scroll down to the bottom. There's another one we can define here called moves.
JASON: Surprise, surprise, now it's a graph problem, that is true, Jacob.
ELI: I think, also, knowing we're going to have to validate the moves, the prospect of, or the strategy of storing the coordinates we clicked on as opposed to the piece object itself is going to make that a lot easier. We might go do that. All right. Cool. Moves, not a function, it's just a dictionary. I think you're missing a trailing comma is why it's yelling at you. JA.
ELI: Did you see another one I'm missing? And I'm looking at the docs here. I'm going to copy and paste stuff, and we're going to modify as we need. Qualifying piece, I'm trying to figure out what from their docs is what here. I think the first thing we get is a context object. It's going to have a bunch of different stuff we can pluck out. So we can see we get these things are just like given to us for free by boardgame.io.
JASON: Mm hmm.
ELI: This is the set of parameters we get to choose the path for. Moving piece, if you imagine clicking on a square to do this, and be like the X and Y I want to move the piece to. Right? As a matter of fact, we're going to do something like this. So I think this is going to say, I want to move the thing at this, at these coordinates to these coordinates.
JASON: Mm hmm.
ELI: And so, we can do this without any validation at first. Again, if we assume that the move is legal, then we would say NG, I think, is our state here. So very clumsy on the keyboard right now.
JASON: And webny suggested we could use the column indexes from the loop itself to identify where we are in the grid.
ELI: Yeah, I think that's a super savvy suggestion. And I think, once we've got this little bit working, we can jump back over to the board, and I think in the two map calls, we can add the indexes in there, and I think that'll set us up to be able to have these values at hand. I think that was a great suggestion. But two things will happen, assuming the move is valid, right? So, if the move is valid... we'll keep ourselves honest here, validate, move. If selecting X, selecting Y will be set to empty, right?
JASON: Well, the piece would be null.
ELI: Piece, that's right. Null piece there. There we go. Yep, we also want to update XY. Also, this important step here, which is before we null it out. Reference the piece before it's lost in the sands of time forever. We'll do that. This is our most naive version of this function.
JASON: Right. And pop back here, let's give ourselves this set of info. And... when we have the on click.
ELI: Yeah, let's also make the page, too. We'll say it's selected X and selected Y. We can probably do
JASON: Yeah, I see what you're doing. Let's keep it easy, selected X, selected Y. We'll kind of...
ELI: We could squish them together, let's keep it straightforward for now. Selected X.
JASON: That's going to be a number instead.
ELI: Number. That's right. Let's copy this. Cool. Now, we've got those. And now, we can update this, we should be happy. And what we actually want here, and this is going to become sort of gnarly here. But if we say row, row IDX equals.
JASON: That's our Y.
ELI: Selected the Y, yeah. And allow ID X equals.
JASON: Cell IDX.
ELI: Thank you. And this should be triple. OK. And I'm going to say selected X. Selected column. Rolling forward. [ Laughter ] (Inaudible) good. Keep trucking. The first thing I'm going to do now, we've made a bunch of changes. Let's make sure we didn't break the selection logic thing.
JASON: OK. Getting back out here. Selection logic works.
ELI: So now, we probably want to add another on click handler, but to the piece itself, to the square itself.
JASON: OK. And so, we can say on click and this time we're going to, whoops, do one of these. And then, if cell.piece, we will just bail. Otherwise, we will say we want to do the move, and now to do the move, do I just do a moves.... wait, how does this work?
ELI: Great question. I think we do get an object called moves, which I don't think will have the it's not going to be auto complety for us, I don't think it's that clever.
JASON: It's value is...
ELI: Yeah, record strike.
ELI: If we can do moves dot whatever we called it, move piece. I'm looking at docs right now, too. One second.
JASON: Yeah, I actually am, moves.move piece. OK.
ELI: Yeah.
JASON: Moves.move piece. This is our selected X. Do we do XY?
ELI: Yeah, I think we did XY, XY.
JASON: Selected X, selected Y, cell index, row index, and theoretically speaking, this does the thing.
ELI: Let's pop it.
JASON: Oh, and we would also want to set selected X to null, set if I can spell it right. We'll null out the Y as well. So, moment of truth.
ELI: Oh, no.
JASON: OK. Didn't work. Wait, what happened up there? Did you see that?
Eli something happened, but not at all the thing we wanted.
JASON: We're moving the wrong pieces. And the reason we're moving the wrong pieces is. Look at it go. This should be zero, zero.
ELI: Yeah. These ones are like maybe not. Oh, boy. All right. Maybe what we need to do is start logging things to understand what we've done. Where am I? Here I am. .
JASON: I guess we can get it to stop yelling at us if we get a key row. This is not ideal, but it's going to be fine. And then, we'll get this one, as well. So it doesn't yell anymore. And what I want to do is, let's have this and console.log those pieces. And maybe what we should do, as well, is just print our details in here. So we'll go row index cell index so that we can at least kind of see what's going on.
ELI: Good call.
JASON: Stop doing that. OK. What? I fixed you. OK, we've got our hold on, let me center that up or something so we can actually read it. Cell is going to have color white. Does that help? That's good enough. So this zero, one, two, three, four, five, six. OK, that gets us to each of these, one, three, five, seven, all right. So, I mostly understand that. Like, that does what I expect it to do. So then, what we should be getting is when we click here, I click...
ELI: Mm hmm.
JASON: And I click.
ELI: We swapped around the values.
JASON: We got them all backwards.
ELI: My naming sloppiness.
JASON: Wait. Y is row, row is Y. I'm so confused.
ELI: Well
JASON: Yeah, go ahead.
ELI: You might be if you have an idea, go for it, otherwise, I was going to
JASON: I don't. I was going to start getting angry. [ Laughter ] Can we swap in a move piece by chance?
ELI: I'm going to do a sweep where we name them what I think they should be named, and I think that'll make it clear where we've messed up. Does that seem like overkill?
JASON: No, I think that's fine.
ELI: OK. Cool.
JASON: Wait, I have a faster version for what you're going to do.
ELI: Can you use the rename?
JASON: I probably could, but I think what we can do, this is a way lazier way to do it. So this is going to be our X is going to be our cell.
ELI: Sure.
JASON: OK. And our Y is going to be our row. OK.
ELI: Cool.
JASON: So when we come down here, select row, selected cell, selected row. These are row, row, cell, cell, OK. So then, back here in the game.
ELI: Yeah.
JASON:... we have our selected cell.
ELI: Ah.
JASON: We got it backwards, I think Linda called it. Selected row. That's what we got wrong. Row/cell. No! We didn't get it wrong!
ELI: What?
JASON: Cell/row. Ah, this is what we did wrong. We've got these. Oh, that makes more sense. And these also are backwards. And we should probably call these what they are. Which is dest cell dest row. OK, why did it change color? All right. We're close. We're much closer.
ELI: Huh.
JASON: So down here, let's console log our piece. And this gives us, that's a proxy.
ELI: Call the JSON on it?
JASON: Is that even going to work? No, that's not a thing.
ELI: Destination point? There you go. That's what it is. That's a common link.
JASON: Why are you yelling at me? Oh, yeah, you're right. That dumps it entirely. So, I think this might be something to do with, what is this to do with? Who knows? Oh, wait, we're backwards, again. Goddamn it.
ELI: OK. I was worried something weird was happening. All right! Look at those pieces go.
JASON: Look at us goes.
ELI: Checkers Masters.
JASON: Right? And theoretically, as long as we can validate that the pieces are legal.
ELI: Yeah.
JASON: Which, we've got 14 minutes left. It is highly unlikely that we're going to get do fully functional Checkers, but we've got pieces moving. I'm feeling good about that. So I'm going to dump that bit here. OK. So then the next piece would just be we have to know depending on which color the piece is whether they can go up or down.
ELI: Mm hmm.
JASON: And know if their cell index is 6, their potential moves are the adjacent row, either up or down based on their color, and cell index minus one or plus one.
ELI: Yeah, I'm going to list some of these validation states and might be easier more methodically. (Inaudible) question. Is it diagonal? Is it one square to the right direction? Is the destination occupied? Does it seem like all the validation steps you want to go through?
JASON: Yeah. And we've got a couple. So the kind of core functionality here would be, like, next row is like, you know what we really need to do or we already did this. Let's get had this here. So then we have the next row, if the piece.color, which is, what was it color.black because we put black on top. If the piece is black, then the next row is selected row plus one.
ELI: Yeah.
JASON: Otherwise, selected row, minus one.
ELI: Nice.
JASON: I guess, we would say valid row.
ELI: Yeah.
JASON: And const valid cells. Equals. And this would be selected cell minus one. Selected cell plus one. And then, we would want to filter for value is greater than or equal to and less than or equal to 7, which is our final index.
ELI: Nice.
JASON: OK. Those are valid rows and valid cells.
ELI: Right.
JASON: So then, we could say if dest row is valid row, or I guess if it's not. We would return null or return false. We can also check if the valid cells includes dest cell. Return false. Otherwise, we can do the thing. What we don't have is who the player is.
ELI: One minor stylist thing, too, I think there's a special value you're supposed to return if something is an invalid move. And I think it is just if you type. Here, I'm going to pop this in here for one second. I think it is like this. I think it's a thing we can import from boardgame and see how unhappy this is. Pop this out.
JASON: Is it not doing the autocomplete?
ELI: Yeah, it is, I was looking at the docs for one second. A little laggy.
JASON: It's like it gave up on you entirely there.
ELI: Yeah, it's not. One second.
JASON: Yeah, let me try. Invalid.
ELI: Try with a capital I. Where is this?
JASON: Is it states or something?
ELI: I can see it being used in the docs, but I see, it's from a different library, it's OK. I'm going to bring it up. Also if this works.
JASON: I'm worried my WI FI is struggling under the burden of multiple connections here.
ELI: Yeah, that was one thing I was worried about, as well, data flowing in every which direction. I'll pop this one out.
JASON: It's weird it's letting your mouse work, but it's not taking your keyboard input.
ELI: Yeah. I'm not sure what's going on there. But here, if you want me to dictate it to you. You want to import invalid move from boardgame.io/core. There is it is. In places where the move is invalid.
JASON: OK. It should let us do that. But it shouldn't let us do that.
ELI: Boom. Validation.
JASON: And it won't let me move backwards, but it'll let me move forward.
ELI: Yeah.
JASON: Look at it go. OK. So this is far from perfect, but... see, it won't let me do that, too? Nice.
ELI: Yeah, nice.
JASON: Cool. We've got progress. We're able to kind of move in all of the directions here. Things that we're missing are the ability to do the jumps.
ELI: Yep.
JASON: But as far as being able to move the standard pieces, we're in good shape here. It feels like it's coming together. I would say the next step, then, we'd have to do logic to figure out if another piece of the opponents, see this is where it would get weird. We'd have to... if one of the valid cells contains an opponent piece, then we'd have to do an additional check for one more row up and one more piece over to see if that piece, that cell was available.
ELI: Yeah. And we would be able to do the jump. And then, we would need to remove that other piece from the board. .
ELI: Yeah, the jumping gets complex. By the way, my keyboard got turned off. [ Laughter ] Oh, man, it's always something silly, you know what I mean?
JASON: So we have a little over 5 minutes. Not even. We have 5 minutes, should we there's no way we can build this, right?
ELI: No. Here's, I think, maybe a good five minute task to close us out, let's make it so it switches whose turn it is.
JASON: Yes.
ELI: I think Boardgame gives you a nice thing for this. I think this might just work. So if it doesn't, we'll do things the old fashioned way. Also, I want to call out a cool Tuple thing, I copied this locally and pasted it on your machine.
JASON: Oh, that's neat.
ELI: This is saying, basically, if it knows we've done a move and a move is being completed, it'll switch whose turn it is.
JASON: That's slick.
ELI: Yeah, we'll see if that works.
JASON: Let's get out here. But we need to figure out whose turn it is. So we need to know who the...
ELI: I think CTX.
JASON: We have the player ID.
ELI: This is a bit of a tricky bit, sorry to step on you, player ID is a stable identifier that every player has, and CTX contains a value called current player. That's the one we want to use.
JASON: OK. So we're going to say hold on. If allowed piece color is going to be CTX current player, is it a number like that?
ELI: I think it should be a string. But a string zero.
JASON: Got it. But we're going to say color.black or color.white. And we've got allow piece color. And we're going to say if selected row, selected cell. If piece.color does not equal allowed piece color, return invalid move.
ELI: Let's see. This will be the icing on the cake.
JASON: But it did switch
ELI: It'll switch who's who.
JASON: I have to switch which player I am?
ELI: Oh, interesting.
JASON: It won't let me move my player, right? But then, when I go over to the inspector and switch which player I am, I can move, but only once and then, it swaps back. I'm impersonating players. I think because we, I saw in the game setup here somewhere here? Hard coded player.
ELI: Yeah, yeah, yeah.
JASON: Unless I'm impersonating a player, it doesn't move. So basically, we now have turn based play.
ELI: Yep.
JASON: That's slick. We got way further than I would have expected. To be completely like I said when we were first emailing about this, the level of complexity in a game is so deceptive because this game doesn't look hard until you start thinking about the fact that, actually, there's a lot that we need to know in order to determine whether or not you can move a checker from this space to this space. We get it because, visually, you go one space and diagonally, but to explain that in computer terms is actually quite a bit. So this is super cool. I love that this came together as much as it did. And I would say with another, you know, give it another session like this, we could probably get at least the jumping logic of being able to, like, do multijumps and stuff. We could get that running. Kinging might take a little bit more time. But this is dope. [ Laughter ] I had
ELI: I agree. I love it. Yeah.
JASON: So, OK. Let's see. We've got Boardgame.io, let me throw a link out to this, and this repo here, which we can push the changes to. Actually, why don't I do that now while I'm thinking about it. We'll stop here, we'll save this, we'll do a get add all. And during episode. And we'll push that. And there it is. If you want to check out that repo, you can go check out what we built today, give it a try yourself. If you want to take this even further and build your own version of checkers, want to code in your house rules, get down, do it. Before we wrap, though. What was the rule that you found? The edge rule you said was surprising?
ELI: If you scroll yeah, so right on. Remove the board... so if a person has a jump and they don't use it, you can still remove from the board the piece that should've made the jump and give it a special name, which is a huff. I love that. I feel like I'm in Checkers, I'm doing a huff right now. You don't know these things until you read the manual. And had there it is, if you're throwing down checkers with your nephew, and you want to huff, you have the right to do it.
JASON: If you can corner somebody to needing to jump and it would put them into a bad situation, you can force them to make that jump. Checkers is trickier than I thought. [ Laughter ]
ELI: That's the headline today. Checkers is trickier than we thought.
JASON: Here's the rules if you want to dig into... I huff regularly in life. [ Laughter ] Fair. Fair. All right. Eli, thank you so much, this was fantastic. Are there any parting words? Anything you want to mention to anybody before we wrap up?
ELI: No, this was super fun, Jason, I really appreciate you having me on. And again, if anyone out there thinks Tuple is interesting, give it a shot. And also, I like make myself available, if you think there's features it's missing, you can hit me up. Again, I'm not very internet available, but I'm Eli@Tuple.app. And do let me know and I hope you give Tuple a try.
JASON: Get ready for this this, I'm throwing your email up on the screen. But then, we also have, you know, the site, you can see here, thank you, again, to our sponsors, Tuple, brand new as well as Netlify, who we're kicking in to make this show more accessible, more fun, just allowing me to do more with it. Thank you very much. While you're looking at things on the site, make sure you check out the schedule because we've got an absolutely packed, excellent schedule coming up. There's even more here that is not on the site yet. So stay tuned for that. And with that, we are going to call this one all done. So Eli, thank you, again, for taking some time with us. I really appreciate you. On chat, as always, thank you for hanging out. Hope y'all go out and have fun, maybe build a board game, let me see it if you do. I want to see what you come up with. We will see you all next time.
Learn With Jason is made possible by our sponsors: