Cover image for Bishop Path Traversal - Part 2

Bishop Path Traversal - Part 2

Balaji Ramasamy's profile pic
Balaji Ramasamy Full Stack Developer

Feb 25, 2022

This is part 2 of the Bishop Path Traversal series. Before starting reading this blog post make sure that you have gone through Bishop Path Traversal - Part 1 of the series.

In part 1, I have explained the problem statement and underlying logic of the solution in detail with diagrammatic representation.

Problem statement:

Create a react application to map the origin and destination point of Bishop and also the traversable path.

Chess-Example-4.png

This will be the final UI that we would be producing in this tutorial.

Check out the demo app here

Step 1:

We need to create the react application. I will be using pnpm with vite.

To install pnpm:

npm install -g pnpm

pnpm is alternative solution for npm with many advantages.

Vite:

Vite is a build tool that aims to provide a faster and leaner development experience for modern web projects. Vite combined with pnpm provides much faster and smooth developer experience compared to other options such as create-react-app.

Bootstrapping the project:

$: pnpm create vite
  √ Project name: ... bishop-move-traverse
  √ Select a framework: » react
  √ Select a variant: » react-ts
$: cd bishop-move-traverse
$: pnpm i
$: pnpm run dev

bishop-move-traverse-ui-example-1.png

Now we can do a little bit of clean up to remove all these default things that came with the project.

Delete the following:

  1. App.css
  2. logo.svg
  3. contents of index.css
  4. Delete contents of App.tsx

App.tsx

import React from 'react';

export const App: React.FC = () => {
	return <div>App</div>;
};

To keep things organized, create a components and utility folders.

Let's analyze what are all the components in our applications.

Chess-Example-4.png
  1. NumInput: It will include a label, defaultValue and an onChange method to update our state.
  2. PointInput: Since we have have 2 inputs for each point, we can easily extract that into a component.
  3. ColorCoders: To will show the meaning each color on the grid.
  4. BoardCell: To show the co-ordinates, with different background-color to represent the cells behaviour.
  5. BoardRow: To represent each row in a same line.
  6. CanTraverse: To show whether we can traverse from the given start to end point.

Most of the state of our app will be present at the root component which is App.tsx

Note: You can give your own styling with the same class names or can copy from the Github repo.

Create an interface to represent the points in the grid:

export interface IPoint {
	x: number;
	y: number;
}

Let's start by creating the state for our input fields and pass it to the PointInput component.



import React, { useState } from 'react';
import { PointInput } from './components/PointInput';
import { IPoint } from './utility/types';

export const App: React.FC = () => {
	const [startPoint, setStartPoint] = useState<IPoint>({ x: 0, y: 0 });
	const [endPoint, setEndPoint] = useState<IPoint>({ x: 2, y: 2 });

	return (
		<div className='Container'>
		   <div className='InputSection'>
	             <PointInput point={startPoint} setPoint={setStartPoint} type='Start' />
	             <PointInput point={endPoint} setPoint={setEndPoint} type='End' />
		   </div>
		   <div className='ChessboardSection'>Chessboard grid</div>
		</div>
	);
};


PointInput Component:

import { FC } from 'react';
import { IPoint,  } from '../utility/types';
import { isValidCoordinate } from '../utility/utils';
import { NumInput } from './NumInput';
export interface IPointInputProps {
	point: IPoint;
	setPoint: (ipoint: IPoint) => void;
	type: 'Start' | 'End';
}

export const PointInput: FC<IPointInputProps> = ({ point, setPoint, type }) => {
	return (
		<div className='InputGroup'>
			<NumInput
				defaultValue={point.x}
				onChange={(e) => {
					const n = parseInt(e.target.value);
					if (isValidCoordinate(n)) setPoint({ x: n, y: point.y });
				}}
				label={`${type} Point Row`}
			/>
			<NumInput
				defaultValue={point.y}
				onChange={(e) => {
					const n = parseInt(e.target.value);
					if (isValidCoordinate(n)) setPoint({ x: point.x, y: n });
				}}
				label={`${type} Point Col`}
			/>
		</div>
	);
};

And the NumInput component:

import { FC } from 'react';
import { CHESS_BOARD_SIZE } from '../utility/utils';
export interface INumInputProps {
	defaultValue: number;
	label: string;
	onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
}
export const NumInput: FC<INumInputProps> = ({
	defaultValue,
	onChange,
	label,
}) => {
	return (
		<div className='input-field'>
			<label>{label}</label>
			<input
				min={0}
				max={CHESS_BOARD_SIZE - 1}
				type='number'
				defaultValue={defaultValue}
				onChange={(e) => onChange(e)}
			/>
		</div>
	);
};