State Machine — Create a Connect 4 Online Training

In this chapter we are going to create our state machine which will allow us to control the game. We will use vitest to test the operation of this machine.

00:00 Machine definition
01:00 First “guard”
22:30 First action
25:20 Creation of functional tests
30:24 Lobby phase
33:20 Game phase

For this machine we will use Xstate and we will start by defining the possible states of our game.

  • The lobbywhich will allow players to join the game and choose their color
  • The gamewhere players can take turns depositing coins
  • Victory
  • Legality if none of the players has succeeded in aligning 4 pawns

import { createMachine } from 'xstate';
createMachine({
  id: 'game',
  context: "LOBBY",
  initial: "LOBBY",
  states: {
    LOBBY: {
      on: {
        join: {
          cond: "canJoin",
          actions: ["joinGame"],
          target: "LOBBY"
        },
        leave: {
          cond: "canLeave",
          actions: ["leaveGame"],
          target: "LOBBY"
        },
        chooseColor: {
          cond: "canChooseColor",
          target: "LOBBY",
          actions: ["chooseColor"],
        },
        start: {
          cond: "canStartGame",
          target: "PLAY",
          actions: ["setCurrentPlayer"]
        }
      }
    },
    PLAY: {
      after: {
        20000: {
          target: "PLAY",
          actions: ["switchPlayer"],
        }
      },
      on: {
        dropToken: [
          {
            cond: "isDrawMove",
            target: "DRAW",
            actions: ["dropToken"]
          },
          {
            cond: "isWiningMove",
            target: "VICTORY",
            actions: ["saveWiningPositionsActions", "dropToken"]
          },
          {
            cond: "canDrop",
            target: "PLAY",
            actions: ["dropToken", "switchPlayer"]
          }
        ]
      }
    },
    VICTORY: {
      on: {
        restart: {
          target: "LOBBY",
          actions: ["restart"]
        }
      }
    },
    DRAW: {
      on: {
        restart: {
          target: "LOBBY",
          actions: ["restart"]
        }
      }
    }
  }
})