Piece Movements in Chesslike - Part 2: Calculating Movements and the 5x5 Grid


This is part 2 of a series on piece movements in Super Chesslike Adventures, a reboot of Chesslike

Part 1 covers the basics of chess, and how Chesslike modified the rules for piece movement. 

Breaking Down the Piece Movement Rules

In Super Chesslike, we want to create some kind of deeper, richer gameplay by expanding on our current mechanics. We also want to lean more into the tactical side of what's enjoyable about the first game. One of the early ideas I spent some time with was a way to represent the piece movement rules procedurally and/or in a modular way. Especially after pawns were modified to move in four directions, it became clear that there are a limited set of options that can be used to describe all of the movement patterns in chess.

There are 5 types of movements, or actions: move on first turn only, move only, attack only, move/attack the same spot, and move/attack spots in a direction until stopped. Chesslike doesn't use the pawn's ability to have a special move on its first turn only, so we can eliminate that type, and we're left with 4.  I call the last one recurse, because the code uses recursion to calculate those tiles.


These types represent how all pieces transition from their origin to their potential destinations on a

The 5x5 Grid

 Every piece's potential move set can be defined using the 4 movement types plotted on a 5x5 grid. The center represents the origin, where the piece is standing when determining where it can move next.

A pawn's movement grid is represented in code like this: 

Pawn: [    
[-1, -1, -1, -1, -1],    
[-1, 2, 1, 2, -1],    
[-1, 1, 0, 1, -1],    
[-1, 2, 1, 2, -1],    
[-1, -1, -1, -1, -1]  
]

Calculating Legal Moves

Our movement algorithm converts the 5x5 pattern into two sets: move possibilities and attack zones. The recursive directions will also add to those sets continuously in a direction. We keep two sets because we have to keep the distinction between places a piece can move only, attack only, or do both. Not necessarily for efficiency in processing, but for visual representation to the player. It may be important for them to see the difference at a glance.

pattern.forEach((row, x) => {
      row.forEach((type, y) => {
        const dest = [x - 2, y - 2];
        if (type === PATTERN_MOVE) {
          possibilities.push({ dest });
        }
        if (type === PATTERN_ATTACK) {
          killZones.push({ dest });
        }
        if (type === PATTERN_MOVE_ATTACK) {
          let poss = { dest };
          if (Math.abs(dest[0]) === 2 || Math.abs(dest[1]) === 2) {
            const paths = knightPaths[dest[0].toString()][dest[1].toString()];
            if (paths && paths.alpha) {
              poss.alpha = paths.alpha;
            }
            if (paths && paths.beta) {
              poss.beta = paths.beta;
            }
          }
          possibilities.push(poss);
          killZones.push(poss);
        }
        if (typeof type === 'string') {
          recursiveDirections.push(recursePatterns[type]);
        }
      });
    });

Then, each possibility and each killZone tile are further validated by a few criteria:

  • The destination isn't an unwalkable tile (wall, hole, tree).
  • If the possibility is move-only, make sure the tile is not already occupied by a piece.
  • The destination isn't a locked door, or if it is, the player has a key.
  • If the piece has a possibility path, that path is valid (See Knights & Valid Paths section in Part 1)

The following code is validating the kill zones, there is another similar chunk for the move possibilities that is not shown:

killZones.forEach(possibility => {
    const { logicTile } = getTileLayers(
      possibility.dest,
      origin,
      map,
      mapWidth
    );
    if (logicTile && logicTile.index > 0 && logicTile.index !== UNWALKABLE) {
      let bluePiece = BLUE_PIECES.includes(logicTile.index);
      let redPiece = RED_PIECES.includes(logicTile.index);
      let isPiece = redPiece || bluePiece;
      let enemyColor = bluePiece ? 'blue' : 'red';
      let isDoor = DOORS.includes(logicTile.index);
      if (isPiece) {
        if ((enemyColor !== moverColor || !moverColor) && !isDoor) {
          if (possibility.alpha || possibility.beta) {
            const alphaValid =
              possibility.alpha &&
              isValidPath(possibility.alpha, origin, map, mapWidth);
            const betaValid =
              possibility.beta &&
              isValidPath(possibility.beta, origin, map, mapWidth);
            if (alphaValid || betaValid) {
              attackSet.push(logicTile);
            }
          } else {
            attackSet.push(logicTile);
          }
        }
      }
    }
  });

Finally, the legal set of move and attack destinations are returned. This movement possibility calculation is used all over the game. 

It is used to highlight to the player where they can click to move on their turn. The AI takes advantage of it to examine every possible move of every piece on a board for several simulated turns. In the world map, when a player clicks a far away tile, the movement calculation is used to determine steps in the pathfinding algorithm. Determining where the pieces can move is also crucial for the multiplayer server's for cheat-detection. 

Custom Pieces + Modification

With all of the pieces represented on the 5x5 grid, and each tile being procedurally handled, we can modify these pieces, or create all new pieces based on the same movement types as traditional chess. For example, we can make a Beast piece which can move and attack 1 tile away in all directions, but can't move or attack adjacent tiles. 

A New Piece Scoring System

The 5x5 grid also provides a way to apply point values to a piece based on its movement potential at a granular level. If we assume the following point values:

  • Move = 1
  • Attack = 2
  • Move/Attack = 3
  • Recurse Direction = 5

We get new total scores for the standard pieces:

  • Pawn: 12
  • Knight: 24
  • Bishop: 32
  • Rook: 32
  • Queen: 64
  • King: 24

As well as something applicable to new custom, or modified pieces:

  • Beast(pictured above): 48

This new point system generates results that more accurately represent the value of pieces we've modified. The king's score is much lower, but still representative of his greater move set than the modified pawn. The rook and bishop are equals. The queen's score is precisely the combination of a bishop and rook, since that is how her move set is defined. 

Super Chesslike

With this pointing system, and the procedural move set calculation, we can expand upon the basic chess mechanics. We can create richer, more fun strategic puzzles and give more personality to characters in a story. The AI will handle our custom and modified pieces in a fair and balanced way, or in a way that we can manually adjust to achieve a better balance. We're very excited about the possibilities it has unlocked.

---------

Below are some of the first sketches I made when thinking through the idea. You can see in the top left, I associated each of the types with items a character might equip in order to gain those properties. The rest has been my reference for building the 5x5 grid into Super Chesslike. Some of the custom characters may make appearances. The Blue Bishop/Grey Bishop dichotomy seems like a fun one to us.




Leave a comment

Log in with itch.io to leave a comment.