Partisan, combinatorial games such as Checkers, Chess and Othello are easily implemented on a matrix implemented as a square array; however, the enumeration of feasible game moves on the game board is a laborious coding effort if implemented naively.

I will illustrate a method for decomposing combinatorial game moves to basis vectors on a matrix. The advantage of this method is that the code becomes concise relative to the naive method for representing potential game moves.

Problem & Definitions

We will begin with definitions which are required to describe our problem.

  • A game board is a 2D matrix (for the games we are considering).
  • A position is identified by its corresponding row and column on the game board.
  • A piece has a type (e.g. Queen in Chess) and and a position on the board.
  • A move consists of a piece and a target position for the specified piece to move towards.

Now, we may describe the problem of enumerating game moves: for every piece on the game board, return a list of available moves.

Suppose that we would like to enumerate the game moves for a Queen piece in Chess. Recall that a Queen may slide along eight directions; hence, we must enqueue all available moves by iterating through all eight directions.

Naively, we could code a for-loop for each possible direction that the Queen could move and then queue up available positions. Unfortunately, this would require eight loops for each direction (four if you utilize symmetry). The method I will illustrate will utilize only a single loop.

Combinatorial Game Representation and Visualization

First, we will note the representation and visualization of the game board. A game board can be visualized as

Furthermore, the same game board in C may be declared as

char board[8][8];

Subsequently, we may access individual positions on the board by using the corresponding array indices. For example, to access the piece on position $(2, 4)$, we would write board[2][4].

By the nature of matrices as arrays in most programming languages, the y-axis of the board may appear to be inverted. Consequently, we will use this convention in the representation of our game board.

Game Piece and Coordinate System Representation

The game piece can be visualized as a character on the position which it lies on the game board. The coordinate system defined on the local neighborhood of the Queen has its origin on the Queen's position.

The relative coordinate system shows that for our Queen to move up, it would subtract one from its current y-position.

Game Move Enumeration Method with Basis Vectors

To begin enumerating the possible moves, we will begin by restricting ourselves to a single direction, upwards, for our Queen. The intuitive notion is that we enqueue all possible moves as there are available positions on the game board in the direction we specify. So, we begin by enqueueing the first position above our Queen.

Then, we continue in the same direction until there are no more available positions that we can enqueue as a feasible move.

Notice that all we did here was scale an upwards-pointing vector, $(0, -1)$, to obtain all of the available moves in the upwards direction from the Queen. We call such a vector a basis vector since the set of all possible moves can be obtained by scaling it.

We will exploit this notion of scaling a basis vectors for all directions now.

We can describe the algorithm simply: for each basis vector, we would enqueue all positions as it scales using the Queen's position as an origin. Hence, the potential moves would be enqueued as follows:

Note that if there were potential obstacles at say $(1, 0)$ and $(0, 1)$, then we should halt the vector scaling at that position. An instance of this would be when there is a piece blocking the Queen's movement.

Now that we have an intuition of the basis vector representation, we may design an algorithm using one loop for all directions.

Concise Game Move Enumeration Algorithm

I use Python for the pseudo code for its readability. The bases vectors shall be defined in terms of (row, column) which are the (y, x) values respectively. Furthermore, Move is a hypothetical data structure that contains information regarding a potential move by a specified piece.

def enumerate_moves(board, piece):
    moves = []
    bases = [(-1, 0), (-1, 1), (0, 1), (1, 1), 
        (1, 0), (1, -1), (0, -1), (-1, -1)]
    for basis in bases:
        row, col = basis[0], basis[1]
        scale = 2
        while board[row][col] is EMPTY:
            moves.append(Move(piece, (row, col)))
            row, col = row * scale, col * scale
            scale += scale + 1
    return moves

Conclusion

The method I have proposed for the enumeration of game moves has proven to be significantly shorter than the naive method which would have required eight loops of similar length (or four loops of similar length if you exploited symmetry). Also worthy of note is that piece which appear to jump discretely across the board (e.g. a knight) can also have its moves described by basis vectors.

This method is a particularly useful component in conjunction with a concise Minimax framework for solving partisan, combinatorial games. These two recent topics of interest also nudge a potential theory for concise frameworks; however, differentiating from code golf in that the framework is readable. I may explore this topic further.