Previous parts: , , Part 1 Part 2 Part 3 Hi everybody. In the previous part, we’ve prepared logic which gives us the ability to create figures. So right now we can use it to fill a game board. How can we do this? We know that in Checkers (standard variant) we have 12 figures for every player and every figure is placed on the dark cell. This knowledge is enough to fill the board. Lets update method to : addFigure addFigures // src/models/BoardModel addFigures() { this.cells.forEach((row, rowIndex) => { row.forEach((cell, cellIndex) => { if (rowIndex <= 2 && cell.label === Labels.Dark) { new FigureModel(Labels.Dark, this.getCell(cellIndex, rowIndex)); // add dark pieces to first 3 rows } else if (rowIndex >= this.cells.length - 3 && cell.label === Labels.Dark) { new FigureModel(Labels.Light, this.getCell(cellIndex, rowIndex)); // add light pieces to last 3 rows } }); }); } We iterate through our cells (which is an array of arrays) and check the row index and cell label. We need dark cells and the first 3 rows for one side and the last 3 rows for another side of the board. And than in we use this function. App.tsx Final result with the filled game board: The game board is ready and we can start to create game logic. But before this, I want to update a little bit of the game board design and add labels. In chess and checkers, rows are labelled from 1 to 8 and columns from A to H. I want to add such labels, this will help us with more easiest visualization. I decided to use the next approach - in , when we render cells, we know rows and cell indexes. Let’s pass them to the Cell component as props: Board.tsx // src/components/Board/Board.tsx {board.cells.map((row, rowIndex) => ( <Fragment key={rowIndex}> {row.map((cell, cellIndex) => ( <Cell cell={cell} key={cell.key} rowIndex={rowIndex} cellIndex={cellIndex} /> ))} </Fragment> ))} Now when the Cell component is rendered we need to check indexes and add additional divs to all cells in the first and the last row, and for all cells in the first and last column. Also let’s add additional classes based on cell position, to understand where this label will be: at the top, bottom, left or right part of the board: // src/components/Cell/Cell.tsx {(rowIndex === 0 || rowIndex === 7) && ( <div className={mergeClasses('board-label', rowIndex === 0 ? 'top' : 'bottom')}> {Letters[cellIndex]} </div> )} {(cellIndex === 0 || cellIndex === 7) && ( <div className={mergeClasses('board-label', cellIndex === 0 ? 'left' : 'right')}> {8 - rowIndex} </div> )} Letters for labels I added to new enum: // src/models/Letters.ts export enum Letters { A, B, C, D, E, F, G, H, } And the last step is to add styles to knew classes, and position: relative to base .cell class: // src/components/Cell/Cell.css .board-label { position: absolute; } .top { transform: translateY(-50px); } .bottom { transform: translateY(50px); } .left { transform: translateX(-50px); } .right { transform: translateX(50px); } After all these steps everything should work as expected and we will see labels around the game board: So, it seems that the base design is complete, and we can start to create game logic. I want to start with figure selection. In we will create the component state. It will be used to save selected Cells. And a handler will check if cell have figure, than it will be saved to state: Board.tsx // src/components/Board/Board.tsx const [selected, setSelected] = useState<CellModel>(); const handleFigureClick = (cell: CellModel) => { if (cell.figure) { setSelected(cell); } }; Than we will pass and to cells. handleFigureClick selected Full Board.tsx // src/components/Board.tsx export const Board = ({ board }: BoardProps): ReactElement => { const [selected, setSelected] = useState<CellModel>(); const handleFigureClick = (cell: CellModel) => { if (cell.figure) { setSelected(cell); } }; return ( <div className="board"> {board.cells.map((row, rowIndex) => ( <Fragment key={rowIndex}> {row.map((cell, cellIndex) => ( <Cell cell={cell} key={cell.key} rowIndex={rowIndex} cellIndex={cellIndex} selected={selected?.x === cell.x && selected.y === cell.y} // check if selected cell coords equal to rendered cell onFigureClick={handleFigureClick} /> ))} </Fragment> ))} </div> ); }; Cell component will take these props and set handler to element. Also, we will check if is selected, then add class to the element. img Cell selected Full component: Cell.tsx // src/components/Cell/Cell.tsx type CellProps = { cell: CellModel; rowIndex: number; cellIndex: number; selected: boolean; onFigureClick: (cell: CellModel) => void; }; export const Cell = ({ cell, rowIndex, cellIndex, selected, onFigureClick, }: CellProps): ReactElement => { const { figure, label } = cell; const handleFigureClick = () => onFigureClick(cell); return ( <div className={mergeClasses('cell', label, selected ? 'selected' : '')}> {figure?.imageSrc && ( <img className="icon" src={figure.imageSrc} alt={figure.name} onClick={handleFigureClick} /> )} {(rowIndex === 0 || rowIndex === 7) && ( <div className={mergeClasses('board-label', rowIndex === 0 ? 'top' : 'bottom')}> {Letters[cellIndex]} </div> )} {(cellIndex === 0 || cellIndex === 7) && ( <div className={mergeClasses('board-label', cellIndex === 0 ? 'left' : 'right')}> {8 - rowIndex} </div> )} </div> ); }; In Cell styles I want to add some animation to animate selected figure and add to icon class: cursor: pointer // src/components/Cell/Cell.css .icon { width: 64px; height: 64px; cursor: pointer; } .selected .icon { animation: scaling 0.5s infinite alternate; } @keyframes scaling { 0% { transform: scale(1); } 100% { transform: scale(1.3); } } Now when we select the figure - it will be scaling a little bit: Link to the repo