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

Before moving

Our purpose is to move the pieces, in fact, we are on the board of a state, and just let the React to render out again, if want to consider the problem of performance, I don’t believe a big eat me hundreds of megabytes of memory of modern browsers render even hundreds of Dom node can card, return to the word, So what we’re doing with the checkerboard is essentially doing with this two-dimensional array.

Move these pieces

The first click selects a piece regardless of whether the move is correct, the second time we select a target cell, and then we process the two values in the array, updating the original cell to empty, and updating the pieces on the target cell to the ones we previously selected.

// Before // -> ' +------------------------+ // 8 | r n b q k b n r | // 7 | p p p p . p p p | // 6 | . . . . . . . . | // 5 | . . . . p . . . | // 4 | . . . . P P . . | // 3 | . . . . . . . . | // 2 | P P P P . . P P | // 1 | R N B Q K B N  R | // +------------------------+ // a b c d e f g h' // After // -> ' +------------------------+ // 8 | r n b q k b n r | // 7 | p p . p . p p p | // 6 | . . . . . . . . | // 5 | . . p . p . . . | // 4 | . . . . P P . . | // 3 | . . . . .  . . . | // 2 | P P P P . . P P | // 1 | R N B Q K B N R | // +------------------------+ // a b c d e f g h'Copy the code

Eventually the movement of the pieces becomes an array processing problem.

export const initMap = [ [BLACK.rock, BLACK.knight, BLACK.bishop, BLACK.queen, BLACK.king, BLACK.bishop, BLACK.knight, BLACK.rock], [BLACK.pawn, BLACK.pawn, BLACK.pawn, BLACK.pawn, BLACK.pawn, BLACK.pawn, BLACK.pawn, BLACK.pawn], [FUNC.blank, FUNC.blank, FUNC.blank, FUNC.blank, FUNC.blank, FUNC.blank, FUNC.blank, FUNC.blank,], [FUNC.blank, FUNC.blank, FUNC.blank, FUNC.blank, FUNC.blank, FUNC.blank, FUNC.blank, FUNC.blank,], [FUNC.blank, FUNC.blank, FUNC.blank, FUNC.blank, FUNC.blank, FUNC.blank, FUNC.blank, FUNC.blank,], [FUNC.blank, FUNC.blank, FUNC.blank, FUNC.blank, FUNC.blank, FUNC.blank, FUNC.blank, FUNC.blank,], [WHITE.pawn, WHITE.pawn, WHITE.pawn, WHITE.pawn, WHITE.pawn, WHITE.pawn, WHITE.pawn, WHITE.pawn], [WHITE.rock, WHITE.knight, WHITE.bishop, WHITE.queen, WHITE.king, WHITE.bishop, WHITE.knight, WHITE.rock], ]; interface CellProps { col: number; row: number; } export const move = (board: string[][], startPos: CellProps, endPos: CellProps) => { const startPiece = board[startPos.row][startPos.col] if (isEqual(startPos, endPos)) { return board; } return board.map((row, rowIndex) => { return row.map((col, colIndex) => { if (rowIndex === endPos.row && colIndex === endPos.col) { return startPiece; } if (rowIndex === startPos.row && colIndex === startPos.col) { return FUNC.blank; } else { return col; }})})}Copy the code

It’s a good habit to write some tests

You’ve probably heard the words TDD, Behavior Driven Development, and you probably haven’t actually written a couple of tests, so maybe you put testing behind you, you write the code that implements it, In fact, you fall into a trap. In order to pass the test, you will deliberately ignore some edge cases. In fact, this violates the principle of TDD, which requires you to define the boundary of the function, write the test, and think through the possible situations thoroughly. And then write your function. So called test driven development. So you need to do this front, although at first you’re going to feel bad, you’re going to feel like I don’t have time to write functions and write tests. When you finally make changes to the entire project code, you will know how wise and painful these tests were at the time. If your project has detailed tests, you will be much more confident in making changes to your functionality. And don’t worry about the following extreme situation.

So I’m going to write a test for this move function, and it’s not that hard to write a test, but the essence of the test is what do I expect the output of this input to be in various situations? As long as you keep this question in mind, you can write tests.

Create-react-app uses the jest framework in create-React-app to perform a simple test. You only need NPM run test to run the test. Create-react-app also includes watch mode. So I can write and save and see the result without having to run the command repeatedly on the command line. There won’t be much description of how to configure it here, but the official documentation is quite detailed, covering each environment and language, enough to run a simple test on the Cover.

The move function is in SRC /operations/index.ts. First we create a new file in the same directory called index.test.ts. If you are using TypeScript you need to add “@types/jest”: “^27.4.0”. This dePS will do.

So then we can write the test, and going back to that, what do I expect from this input in various situations? So Jest’s DSLS are pretty straightforward

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});
Copy the code

expect(sum(1, 2)).toBe(3); And this is actually pretty straightforward, because I expect 1 plus 2 to be equal to 3.

Going back to our move function, what do we expect?

test('board: from [0][0] to [0][0] did not move', () => {});
​
test('board: from [0][0] to [0][3] did move', () => {});
Copy the code

So the expectation above is to move from [0, 0] to [0, 0], is that not moving? Yeah, this one didn’t move. So when I go from [0, 0] to [0, 3] is this moving? Yes, it’s that simple. Then we need to implement this test

import { move } from './index';
test('board: from [0][0] to [0][0] did not move', () => {
    const startPos = { col: 0, row: 0 }
    const endPos = { col: 0, row: 0 }
    const newBoard = move(initMap, startPos, endPos);
    expect(newBoard).toEqual(initMap);
});
​
test('board: from [0][0] to [0][3] did move', () => {
    const startPos = { col: 0, row: 0 }
    const endPos = { col: 0, row: 3 }
    const newBoard = move(initMap, startPos, endPos);
    expect(newBoard[startPos.row][startPos.col]).toBe(FUNC.blank);
    expect(newBoard[endPos.row][endPos.col]).toBe(initMap[startPos.row][startPos.col]);
});
Copy the code

So there you have two tests.

Use the Scenario

Look closely at the above two tests, I wrote board: from… In this case, it can be seen that the two tests belong to the same test scenario, so we can transform the above code into the following form

describe('moves on board', () => {
  const startPos = { col: 0, row: 0 }
  const endPosA = { col: 0, row: 0 }
  const endPosB = { col: 0, row: 3 }
  
  test('from [0][0] to [0][0] did not move', () => {
      const newBoard = move(initMap, startPos, endPosA);
      expect(newBoard).toEqual(initMap);
  });
​
  test('from [0][0] to [0][3] did move', () => {
      const newBoard = move(initMap, startPos, endPosB);
      expect(newBoard[startPos.row][startPos.col]).toBe(FUNC.blank);
      expect(newBoard[endPosB.row][endPosB.col]).toBe(initMap[startPos.row][startPos.col]);
  });
})
Copy the code

You might end up with something like this because I’ve written other tests.

PASS the SRC/operations/index. Test. Ts get pieces ✓ white pieces (2 ms) ✓ black pieces (1 ms) ✓ empty grid get grid axis ✓ grid axis (1 ms) Test Suites: 1 passed, 1 total Tests: 4 passed, 4 total Snapshots: 0 total Time: 2.113 S Ran all test suites. Watch Usage: Press w to show more.Copy the code