“I am participating in the nuggets Community Game Creativity Submission Contest. For details, please see: Game Creativity Submission Contest.”
Code repository, go by and click a Star ✨
Draw a checkerboard
Composition of a chessboard
Let’s start with A chess board. The board is made up of 8 x 8 alternating black and white squares. The axis is a-H from left to right at the lower left corner of the white square, and 1-8 from bottom to top.
In code
When I first conceived the checkerboard, I planned to draw an SVG checkerboard and used a two-dimensional array to describe the checkerboard, with 0 representing the white grid and 1 representing the black grid.
export const grid = [
[0.1.0.1.0.1.0.1],
[1.0.1.0.1.0.1.0],
[0.1.0.1.0.1.0.1],
[1.0.1.0.1.0.1.0],
[0.1.0.1.0.1.0.1],
[1.0.1.0.1.0.1.0],
[0.1.0.1.0.1.0.1],
[1.0.1.0.1.0.1.0]].Copy the code
So this is what it looks like when you write it in code
<svg width={8 * gridSize} height={8 * gridSize} stroke={borderColor}>
<g
width={gridSize}
height={gridSize}
key={` ${rowIndex}-The ${colIndex} `} >
<rect
x={colIndex * gridSize}
y={rowIndex * gridSize}
width={gridSize}
height={gridSize}
style={{ fill: col= = =1 ? blackGrid : whiteGrid}} / >
</g>.64A grid < / SVG >Copy the code
In SVG, line breaking is easy, just control the x and y values. The first grid of the first row is [0, 0], the second grid is [0, 50], the second grid is [50, 0], the second grid is [50, 50], and so on. ColIndex * gridSize, rowIndex * gridSize.
The resulting SVG board looks like this
<svg width={8 * gridSize} height={8 * gridSize} stroke={borderColor}>
{grid.map((row, rowIndex) = > {
return row.map((col, colIndex) = > {
return <g
width={gridSize}
height={gridSize}
key={` ${rowIndex}-The ${colIndex} `} >
<rect
x={colIndex * gridSize}
y={rowIndex * gridSize}
width={gridSize}
height={gridSize}
style={{ fill: col= = =1 ? blackGrid : whiteGrid}} / >
</g>
})
})}
</svg>
Copy the code
The second option
Since this is ultimately going to be a playable version, it’s still necessary to write divs. The easiest way to do this is in Flex: row-wrap; This property is easy to implement.
.board {
display: flex;
flex-flow: row wrap;
}
.cell {
display: inline-flex;
justify-content: center;
align-items: center;
flex-grow: 1;
flex-shrink: 0;
width: 12.5%;
height: 12.5%;
cursor: pointer;
}
Copy the code
Again, draw the grid through two loops, and let the layout do the rest, without calculating the coordinates.
<div
className='board'
style={{
width: 8 * gridSize,
height: 8 * gridSize,
border: `1px solid ${borderColor}`,
}}>
{chessboard.board().map((row: object[], rowIndex: number) = > {
return row.map((item: any, colIndex: number) = > {
return <Cell
key={getGridAxis({ row: rowIndex.col: colIndex })}
gridAxis={getGridAxis({ row: rowIndex.col: colIndex })}
item={item}
rowIndex={rowIndex}
colIndex={colIndex}
/>
})
})}
</div>
Copy the code
Change the theme of the board
In the above code, I did not hardcode the colors directly into the CSS file, because I prepared two themes, the default theme, and the wood theme, in consideration of changing themes.
export const defaultTheme = {
borderColor: 'lightgrey'.whiteGrid: '#fff'.blackGrid: 'lightgrey'.whitePieceColor: '#2b2b2b'.blackPieceColor: '#2b2b2b'.gridSize: 50.fontSize: 40,}export const woodenTheme = {
borderColor: '#AD9278'.whiteGrid: '#D1BF9D'.blackGrid: '#AD9278'.whitePieceColor: '#2b2b2b'.blackPieceColor: '#2b2b2b'.gridSize: 50.fontSize: 40,}Copy the code
The React Context API makes it easy to do this. First we create a Context object.
interface ThemeProps {
borderColor: string;
whiteGrid: string;
blackGrid: string;
whitePieceColor: string;
blackPieceColor: string;
gridSize: number;
fontSize: number;
}
interface ThemeContextProps {
theme: ThemeProps;
selectTheme: (t: string) = > void;
}
export const ThemeContext = createContext<ThemeContextProps>({} as ThemeContextProps);
Copy the code
Then we need to wrap a Provider package in the outermost layer of our App
const ThemeContenxtProvider: FC = ({ children }) = > {
const [theme, setTheme] = useState<ThemeProps>(defaultTheme);
return <ThemeContext.Provider
value={{
theme.selectTheme: (t: string) = > {
switch (t) {
case 'wooden':
setTheme(woodenTheme);
break;
default:
setTheme(defaultTheme);
break;
}
},
}}
>
{children}
</ThemeContext.Provider>
};
export default ThemeContenxtProvider;
function App() {
return (
<ThemeContenxtProvider>
<div className="container-md">
<div className="row">
<div className="sm-4 col main-container">
<h3 className=' '>Simple Chess Board</h3>
<p className=' '>Made by banana with ❤️</p>
<ChessBoard />
<ThemeSelect />
</div>
</div>
</div>
</ThemeContenxtProvider>
);
}
export default App;
Copy the code
The reason for wrapping ThemeContenxtProvider one more layer is that it is possible to use Hooks directly in the Provider to do data initialization instead of exposing ctx. Provider. This requires the data initialization logic to be maintained in the outer component.
Details can be found in the React Hooks document