“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 ✨

Move these pieces correctly

Use wheels flexibly

The son once said: wheels are not cute.

Here we use a good third-party library chess.js

It is not necessary to write every line of code, there are readily available third-party libraries to use, there is no psychological burden, after all, not all programs can start from 0101, we are standing on the shoulders of giants, don’t jump down.

Before using the wheel, you need to decide what your purpose is. Do I want to learn or do I want to finish this task? Okay, I did it to finish this little game. To be honest, I have never heard of many Edge cases. I may write a wrong judgment at the beginning and then go further and further.

Record the chip

Algebraic Notation

// 1. For the first round, the white team takes the lead and arches its pawns to the grid e4, while the black team arches its pawns to the grid E5Copy the code

// In the second turn, white vault to c3, black vault to d6 2.Nc3 d6Copy the code

Common symbols Stand for For example
+ Check the general Ra8+
# Checkmate will die Qxf7#
x Take to eat R7xf5
O-O Kingside Castling short translocation
O-O-O Queenside Castling long translocation

Basically memorize the symbols, and you can record an entire game.

⚠️ Note here that the names of the pieces need to be capitalized, such as rook R, horse N, elephant B, etc., while the grid coordinates to be moved to are lowercase.

Forsyth-Edwards Notation FEN

FEN is a record of a certain time on the board. This notation contains enough information to restart the game, which can be understood as a game save.

/ / this is the format of the starting position RNBQKBNR PPPPPPPP / 8/8/8/8 / PPPPPPPP/RNBQKBNR w KQkq - 0 1 / / 1. The e4 rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1 // 1.c5 rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR w KQkq c6 0 2Copy the code

Use in code

import React, { useContext } from 'react';
import { BoardContext } from 'src/context/board';
import chunk from 'lodash/chunk';
import djs from 'dayjs';
import { toPiece } from 'src/operations';
​
const ChessManual = () = > {
    const { chessboard } = useContext(BoardContext);
    const history: any[] = chunk(chessboard.history({ verbose: true }), 2);
    return <article className='article'>
        <h4 className=' '>Chess Manual</h4>
        <p className="article-meta">Created At {djs().format('YYYY-MM-DD')}</p>
        <div className="row">
            <div className="col-12 padding-none">
                <table>
                    <thead>
                        <tr>
                            <th>#</th>
                            <th>Player 1</th>
                            <th>Player 2</th>
                            <th>Notation</th>
                        </tr>
                    </thead>
                    <tbody>
                        {history.map(([first, second], idx: number) => {
                            return <tr key={idx}>
                                <td>{idx + 1}</td>
                                <td>{first ? `${toPiece({ color: first.color, type: first.piece })} from ${first.from} to ${first.to}` : ``}</td>
                                <td>{second ? `${toPiece({ color: second.color, type: second.piece })} from ${second.from} to ${second.to}` : ``}</td>
                                <td>{first? .san} {second? .san}</td>
                            </tr>
                        })}
                    </tbody>
                </table>
            </div>
​
            <div className="col-12">
                <pre>
                    <code>
                        {chessboard.fen()}
                    </code>
                </pre>
            </div>
        </div>
​
    </article>
};
​
export default ChessManual;
Copy the code

The chessboard.history() method returns information for each step, but we want to display it on a row in the table. To give you an idea, the table has rows of black and white squares, and this method only returns one at a time, so I need to split the array two at a time into a smaller array that I can display only once through the loop. Do not foolishly write the loop twice, or write a separate method to handle the array. Learn to go back to the first part and use the wheels wisely! With Lodash, there are some common array manipulation methods that you might or might not think of.

Import chunk from ‘lodash/chunk’ is used; This method:

_.chunk(['a'.'b'.'c'.'d'].2);
// => [['a', 'b'], ['c', 'd']]
 
_.chunk(['a'.'b'.'c'.'d'].3);
// => [['a', 'b', 'c'], ['d']]// So here I can do this with the history array.
const history: any[] = chunk(chessboard.history({ verbose: true }), 2);
history.map(([first, second], idx: number) = > {});
Copy the code

In ES6, there are many common array manipulation methods, such as Map Filter Reduce, which can reduce the number of for loops. Because I am a fan of functions, and I think loops are too overwritten, I think the code needs to be expressed in a more understandable way. That’s the key. There are also many core methods in Clojure that have these built-in operations, called partitions in Clojure

;; partition a list of 20 items into 5 (20/4) lists of 4 items (partition 4 (range 20)) ;; => ((0 12 3) (4 5 6 7) (8 9 10 11) (12 13 14 15) (16 17 18 19)); partition a list of 22 items into 5 (20/4) lists of 4 items ;; the last two items do not make a complete partition and are dropped. (partition 4 (range 22)) ;; => ((0 12 3) (4 5 6 7) (8 9 10 11) (12 13 14 15) (16 17 18 19))Copy the code

Another use of pseudo-elements

Cue whose turn it is

<div className="flex-center align-middle">
  <div className="col">
    Current Move: {chessboard.turn() === 'w' ? 'White' : 'Black'}
  </div>
</div>
Copy the code

There’s not much logic in this section, because the turn method is built-in.

Indicates which squares the currently selected piece can go to

<fieldset className="form-group"> <label htmlFor="showTips" className="paper-switch-label"> Show Availble Moves </label>  <label className="paper-switch"> <input id="showTips" name="showTips" type="checkbox" checked={showTips} onChange={() => setShowTips(s => ! s)} /> <span className="paper-switch-slider round"></span> </label> </fieldset>Copy the code

What is interesting here is that PaperCSS uses a large number of to express the styles under different states. Checked is one style, but not checked is another style, and this process does not need JS to participate in at all, it can be expressed through styles.

.tabs {
  .content {
    display: none;
    flex-basis: 100%;
    padding: 0.75 rem 0 0;
  }

  input {
    display: none;

    &:checked + label {
      @include color(color.'primary');
      @include color('border-bottom-color'.'secondary');
      border-bottom-style: solid;
      border-bottom-width: 3px;
    }

    @for $num from 1 through 5{&[id$='tab#{$num}']:checked~div[id$='content#{$num}'] {
        display: block; }}}label {
    @include color('color', primary-light);
    display: inline-block;
    font-weight: 600;
    margin: 0 0 -1px;
    padding: 0.75 rem;
    text-align: center;

    &:hover {
      @include color('color', muted);
      cursor: pointer; }}Copy the code

Using &: Checked as pseudo-classes is a very decent way to control styles. Slider and Collapse components in PaperCSS are realized in this way. Take a look at the PaperCSS source code if you are interested.

Game over cue

// Alert Context
import React, { FC, createContext, useState } from 'react';
interface AlertContextProps {
    show: boolean;
    text: string;
    toast: (str: string) = > void;
    clear: () = > void;
}
export const AlertContext = createContext<AlertContextProps>({} as AlertContextProps);
​
const AlertContenxtProvider: FC = ({ children }) = > {
    const [show, setShow] = useState(false);
    const [text, setText] = useState('Hello Chess! ');
    return <AlertContext.Provider
        value={{
            show.text.toast: (str: string) = > {
                setText(str);
                setShow(true);
            },
            clear: () =>{
                setText('');
                setShow(false);
            },
        }}
    >
        {children}
    </AlertContext.Provider>
​
};
export default AlertContenxtProvider;
/ / Alert component
import React from 'react';
import { AlertContext } from 'src/context/alert/index';
import './style.scss';
​
const Alert = () = > {
    const { text, clear, show } = React.useContext(AlertContext);
    return show ? <>
        <div className="col fixed-alert" onClick={clear}>
            <span className="alert alert-primary">
                {text}
            </span>
        </div>
    </> : <></>
}
​
export default Alert;
Copy the code

Use Provider, which contains hooks like useEffect and so on. Add another layer of encapsulation including initialization data. I can also return methods in the Context so that my component can call directly, rather than just using the Context as a state store and then updating the Context with setState somewhere else, which would violate the SOLID principle and be dirty to write.