Building Jason Chess — Part 1: Rendering the Board and Pieces
Jason Melton
Posted on October 26, 2020
An ongoing series about building a React app called Jason Chess, a version of chess where if your name is Jason, you can’t lose.
What Is All This?
Over quarantine, I’ve become very addicted to chess. I like how random chance plays a small role in the game. Instead, better players manifest from hours of obsessive study. Getting better at chess has been a great distraction from the world crumbling all around me, lol.
As an engineer, it’s my job to build solutions to problems, right? Right. Well I’ll identify one problem that exists: me losing at chess. My solution: Jason Chess.
Jason Chess is a version of chess where if your name is “Jason”, you can’t lose.
This blog will follow the development of Jason Chess. It’s my goal to provide you with something instructive or, at minimum, I hope you find the some humor in the idea.
I’m a junior developer so please forgive my imprecisions. If you have any feedback, please comment or to email me at jason.melton2@gmail.com
.
Rendering the Board and Pieces
Table of Contents
- Preliminary Junk
- Basic Layout and Menu
- Rendering the Board
- Rendering the Pieces
- Conclusion
Preliminary Junk
To get this bad boy started, I set up a create-react-app, deleted default junk, and created a GitHub repository. Before going further, I spent some time planning. I like to write as I plan so I’ll keep some commented out notes in the readme until the project is finished.
I think of the work for this project in two parts: the logic and the render. Very similar to the divide between a front and back end. However, in this case, I won’t have a true back end.
The logic of the chess board will be an array of eight arrays. Each array will have a length of eight to represent the 64 spaces of a chess board. Pieces will be coded with two character strings.
const boardArr = [
["br", "bn", "bb", "bq", "bk", "bb", "bn", "br"],
["bp", "bp", "bp", "bp", "bp", "bp", "bp", "bp"],
[null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null],
[null, null, null, null, null, null, null, null],
["wp", "wp", "wp", "wp", "wp", "wp", "wp", "wp"],
["wr", "wn", "wb", "wq", "wk", "wb", "wn", "wr"]
]
The render will consist of mapping boardArr
into the corresponding components.
Basic Layout and Menu
For now, I’m going to keep the app simple. There will be two main elements: a chessboard and a menu.
Later, I will also add a box above and below for entering the player’s name. Remember, if your name is “Jason”, then you cannot be checkmated.
I picked out some colors from Coolors.co and added height and width to the App
component. I also created a class called .cfb
(center flex box) that I use to center things throughout the project.
App.css
* {
margin: 0;
padding: 0;
}
.App {
width: 100%;
height: 100vh;
}
.cfb {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
The menu is a simple component, Navbar.js
:
import React from 'react';
// styling
import './Navbar.css';
const Navbar = () => {
return (
<div className="Navbar">
<h1 className="logo">Jason Chess</h1>
</div>
);
}
export default Navbar;
Navbar.css
.Navbar {
padding: 1rem;
background-color: #0A090C;
color: #F0EDEE;
}
I’ll cover the chessboard in the next two sections.
Rendering the Board
My plan for the board is this: I will map my boardArr
into 64 divs that will be evenly displayed using CSS grid.
I’ll show the whole Board component and CSS file and explain my work:
Board.js
import React from 'react';
// styling
import './Board.css';
// components
import PieceImg from './PieceImg'
const Board = props => {
const { board, setBoard, turn, setTurn } = props
// takes num, returns true if even
const isEven = n => n % 2 === 0;
// returns string of classnames for square
const squareClass = index => {
const classArr = ["cfb"]
// rank even, file odd OR rank odd, file even --> dark square
const rank = isEven(Math.floor(index/8))
const file = isEven(index % 8)
if ((rank && !file) || (!rank && file)) classArr.push("dark")
return classArr.join(" ")
};
const renderBoard = () => {
let startNum = 0
const counter = () => startNum++
return board.map(rank => rank.map(sq => {
let sqNum = counter()
return (
<div key={sqNum}
className={squareClass(sqNum)}>
<PieceImg piece={sq ? sq : false}/>
</div>
)
}))
}
return (
<div className="Board">
{renderBoard()}
</div>
);
}
export default Board;
Board.css
.Board {
margin: 2rem;
height: 35rem;
width: 35rem;
border: 1rem solid #0A090C;
border-radius: 1rem;
background-color: #F0EDEE;
display: grid;
grid: repeat(8, 1fr) / repeat(8, 1fr);
}
.dark{
width: 100%;
height: 100%;
background-color: #90DDF0;
}
.piece-img {
width: 100%;
height: 100%;
}
Board gets the boardArr
as props. The function renderBoard()
maps each rank of boardArr
and then each square of each rank to return a div. That way I get 64 divs.
I use the function squareClass()
to determine the classnames for each square. Light squares get a class of cfb
and dark squares get a class of cfb dark
.
As previously mentioned, cfb
adds a centering flex box and dark
adds a light blue background-color.
squareClass()
also determines which squares are dark squares. I use the helper function isEven()
to do this.
Starting from 0, even ranks and odd files are dark while on odd ranks, even files are dark. I find the rank and file of each square and add dark to the appropriate divs.
Rendering the Pieces
I render the pieces in two steps:
- I create a picture library that can be accessed via an object.
- I create a dynamic function that plugs in the correct image for the string code in the
boardArr
.
I found this great site for chess piece svgs. I threw the images in a folder and created a file called index.js
.
In index.js
, I created an object called pieceObject
that accesses the image based on a key corresponding to the string codes in the array.
export const pieceObject = {
wp: require('./wpawn.png'),
wn: require('./wknight.png'),
wb: require('./wbishop.png'),
wr: require('./wrook.png'),
wq: require('./wqueen.png'),
wk: require('./wking.png'),
bp: require('./bpawn.png'),
bn: require('./bknight.png'),
bb: require('./bbishop.png'),
br: require('./brook.png'),
bq: require('./bqueen.png'),
bk: require('./bking.png')
}
Next, I feed this object to a component called PieceImg
.
import React from 'react';
// images
import { pieceObject } from '../../images/index.js'
// styling
import './Board.css';
const PieceImg = props => {
const { piece } = props
return (
piece ?
<img className="piece-img" src={pieceObject[piece]} alt="piece"/>
: <div></div>
);
}
export default PieceImg;
PieceImg
takes props of piece
that will be a code like bp
for black pawn or wn
for white knight. The pieceObject
looks up the corresponding image. Also, if there isn’t a piece code on the square, piece will point be false and I will return an empty div.
const renderBoard = () => {
let startNum = 0
const counter = () => startNum++
return board.map(rank => rank.map(sq => {
let sqNum = counter()
return (
<div key={sqNum}
className={squareClass(sqNum)}
onClick={() => clickPiece(sq, sqNum)}>
<PieceImg piece={sq ? sq : false}/>
</div>
)
}))
}
Look again at the renderBoard()
function in Board. Here you can see the PieceImg
is being fed the props of a piece
code or false
.
Conclusion
Thanks a ton for reading. Again, I assume there are some great ways to make chess games. I came up with this off the top of my head, grinding out bugs along the way. I’m sure there are better ways so I’d love your feedback. Hit me with a comment or an email — jason.melton2@gmail.com.
This will be an ongoing project so I may be inconsistent with the blogs, but I appreciate you reading.
Best, Jason
Posted on October 26, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.