This document provides an overview of the APIs and useful console commands for developing and testing strategies for the Othello Arena.


Table of Contents


Part 1: Othello Intelligent System API

This section covers the APIs available within your analyzeStage function.


API Overview

Your intelligent system with analyzeStage function receives access to the API via:

function analyzeStage(stageConfig, initialBoard, validMoves, api) {
    // Use the api object to call API functions
}

Templates: Check this link: https://drive.google.com/drive/folders/152y6Wg0fGpVU0YuK5upapBPeAEhdYm1D?usp=sharing

  • Intelligent systems
    • is-closure.js
    • is-api1.js
    • is-api2.js
    • is-template.js
  • Strategies
    • smart-lv1.js
    • sampleStrategy.js

API Functions

getValidMoves(board, player)

Returns valid moves for a specified player on the current board state.

Parameters:

  • board (2D array): Current board state
  • player (number): Player ID (1 = Black, 2 = White)

Returns:

  • Array of valid moves, each as an object with {row, col} properties

Example:

const validMovesForBlack = api.getValidMoves(board, 1);
console.log(`Black has ${validMovesForBlack.length} valid moves`);

simulateMove(board, player, row, col)

Simulates the result of a player making a move at a specific position.

Parameters:

  • board (2D array): Current board state
  • player (number): Player ID (1 = Black, 2 = White)
  • row (number): Row index of the move
  • col (number): Column index of the move

Returns:

  • Simulation result object:
    • valid (boolean): Whether the move is valid
    • resultingBoard (2D array): Board state after move (if valid)
    • capturedCount (number): Number of pieces captured (if valid)

Example:

const move = { row: 3, col: 2 };
const result = api.simulateMove(board, 1, move.row, move.col);

if (result.valid) {
    console.log(`Valid move. Captured ${result.capturedCount} pieces.`);
    // Use result.resultingBoard for further analysis
} else {
    console.log("Invalid move.");
}

evaluateBoard(board, player)

Evaluates the board state and calculates various metrics for the specified player.

Parameters:

  • board (2D array): Current board state
  • player (number): Player ID (1 = Black, 2 = White)

Returns:

  • Evaluation object with the following properties:
    • pieceScore (number): Difference in piece count (player - opponent)
    • mobilityScore (number): Difference in mobility (player moves - opponent moves)
    • cornerScore (number): Score based on corners occupied by player (each corner adds 100 points)
    • edgeScore (number): Score based on edge cells occupied by player (each edge adds 20 points)
    • totalScore (number): Combined score using all metrics with weighted importance

Example:

const evaluation = api.evaluateBoard(board, 1);
console.log(`Black evaluation: Piece score=${evaluation.pieceScore}, Corner score=${evaluation.cornerScore}`);

// Using evaluation metrics for decision making
if (evaluation.cornerScore > 0) {
    console.log("Captured corner(s), switching to defensive strategy");
}

Board Representation

The board is represented as a 2D array, where each cell contains one of the following values:

  • 0: Empty cell (EMPTY)
  • 1: Black piece (BLACK)
  • 2: White piece (WHITE)
  • 3: Blocked cell (BLOCKED) - present only in some stages

Example:

// Example 8x8 board
[
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 1, 2, 0, 0, 0],
  [0, 0, 0, 2, 1, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0]
]

Strategy Function

Your analyzeStage function must return a strategy function with the following signature:

/**
 * @param {Array<Array<number>>} board - Current board state
 * @param {number} player - Current player (1 = Black, 2 = White)
 * @param {Array<{row: number, col: number}>} validMoves - Valid moves for the current player
 * @param {Function} makeMove - Function to simulate moves (optional, you can use api.simulateMove instead)
 * @returns {Object|null} - Selected move as {row, col} or null if no valid moves
 */
function strategyFunction(board, player, validMoves, makeMove) {
    // Your strategy implementation
    return validMoves.length > 0 ? validMoves[0] : null;
}

The strategy function will be called during gameplay to determine your AI’s moves.


Tips for API Usage

  1. Use simulateMove to explore the consequences of potential moves before deciding.
  2. Combine multiple metrics from evaluateBoard for better decision making.
  3. The API functions consider all stage-specific rules, so you don’t need to worry about special rules like occlusion or turn order.
  4. During analyzeStage, you can maintain state or calculate values that your strategy function can access through closures.
  5. For deeper search algorithms, consider using memoization to avoid recalculating the same board positions.
  6. Your analyzeStage function has up to 60 seconds to analyze the stage.
  7. Your strategy function should return a move quickly (ideally under 500ms) during gameplay.

Part 2: Othello Console Testing Guide

This section covers functions you can use directly in the browser console for testing and debugging. These are different from the API functions used within analyzeStage.


Game State Inspection

Check the current game state:

// Current board state
console.table(OthelloCore.getBoard());

// Current player (1=Black, 2=White)
console.log("Current player:", OthelloCore.getCurrentPlayer());

// Game status
console.log({
  isRunning: OthelloCore.isGameRunning(),
  isGameOver: OthelloCore.isGameOver(),
  boardSize: OthelloCore.getBoardSize()
});

// Score information
const scores = OthelloCore.countDiscs();
console.log("Score - Black:", scores.black, "White:", scores.white);

Board Analysis

Analyze the current board position and valid moves:

// Get valid moves for current player
const currentPlayer = OthelloCore.getCurrentPlayer();
const validMoves = OthelloCore.getValidMoves(currentPlayer);
console.log(`${currentPlayer === 1 ? "Black" : "White"} has ${validMoves.length} valid moves:`, validMoves);

// Test if a specific move is valid
const testRow = 2, testCol = 3;
const isMoveValid = OthelloCore.isValidMove(testRow, testCol, currentPlayer);
console.log(`Is move (${testRow},${testCol}) valid? ${isMoveValid}`);

// Custom position evaluation function
function evaluatePosition(board, player) {
  // Piece count evaluation
  let pieceScore = 0;
  let cornerScore = 0;
  let edgeScore = 0;
  
  const opponent = player === 1 ? 2 : 1;
  const size = board.length;
  
  for (let r = 0; r < size; r++) {
    for (let c = 0; c < size; c++) {
      if (board[r][c] === player) {
        pieceScore++;
        
        // Corner bonus
        if ((r === 0 || r === size-1) && (c === 0 || c === size-1)) {
          cornerScore += 100;
        } 
        // Edge bonus
        else if (r === 0 || r === size-1 || c === 0 || c === size-1) {
          edgeScore += 20;
        }
      } else if (board[r][c] === opponent) {
        pieceScore--;
      }
    }
  }
  
  return {
    pieceScore,
    cornerScore,
    edgeScore,
    totalScore: pieceScore + cornerScore + edgeScore
  };
}

// Evaluate current board
console.log("Board evaluation:", 
  evaluatePosition(OthelloCore.getBoard(), currentPlayer));

Move Simulation

Simulate moves and their consequences:

// Function to simulate a move without permanently changing the board
function simulateMove(row, col) {
  // Save original state
  const originalBoard = OthelloCore.getBoard().map(row => [...row]);
  const originalPlayer = OthelloCore.getCurrentPlayer();
  
  // Check if valid move
  const isValid = OthelloCore.isValidMove(row, col, originalPlayer);
  console.log(`Simulating ${originalPlayer === 1 ? "Black" : "White"} move at (${row}, ${col}). Valid: ${isValid}`);
  
  if (isValid) {
    // Execute move
    OthelloCore.makeMove(row, col, originalPlayer);
    
    // Show resulting board
    console.log("Resulting board:");
    console.table(OthelloCore.getBoard());
    
    // Show next player
    const nextPlayer = OthelloCore.determineNextPlayer();
    console.log("Next player would be:", nextPlayer === 1 ? "Black" : "White");
  }
  
  // Restore original state
  OthelloCore.getBoard().forEach((row, r) => {
    row.forEach((_, c) => {
      OthelloCore.getBoard()[r][c] = originalBoard[r][c];
    });
  });
  OthelloCore.setCurrentPlayer(originalPlayer);
  
  return isValid;
}

// Try a specific move
simulateMove(2, 3); // Change coordinates as needed

Strategy Testing

Test a custom strategy directly in the console:

// Define a simple corner-prioritizing strategy
function cornerStrategy(board, player, validMoves) {
  if (validMoves.length === 0) return null;
  
  const size = board.length;
  
  // Prioritize corners
  const corners = validMoves.filter(move => 
    (move.row === 0 || move.row === size-1) && 
    (move.col === 0 || move.col === size-1)
  );
  
  if (corners.length > 0) {
    console.log("Taking corner move:", corners[0]);
    return corners[0];
  }
  
  // Next prioritize edges
  const edges = validMoves.filter(move => 
    move.row === 0 || move.row === size-1 || 
    move.col === 0 || move.col === size-1
  );
  
  if (edges.length > 0) {
    console.log("Taking edge move:", edges[0]);
    return edges[0];
  }
  
  // Otherwise take first move
  console.log("Taking regular move:", validMoves[0]);
  return validMoves[0];
}

// Test this strategy on current board state
const currentBoard = OthelloCore.getBoard();
const currentPlayer = OthelloCore.getCurrentPlayer();
const validMoves = OthelloCore.getValidMoves(currentPlayer);

console.log("Testing corner strategy...");
const selectedMove = cornerStrategy(currentBoard, currentPlayer, validMoves);
console.log("Selected move:", selectedMove);

// Simulate the selected move
if (selectedMove) {
  simulateMove(selectedMove.row, selectedMove.col);
}

Stage Configuration

Explore stage configurations:

// Get current stage
const currentStage = OthelloCore.getCurrentStage();
console.log("Current stage:", currentStage);

// Explore all available stages
console.log("Available stages:", stages.length);

// Function to analyze a specific stage
function exploreStage(index) {
  const stage = stages[index];
  console.log(`Stage ${index}: ${stage.name}`);
  console.log("Board size:", stage.boardSize);
  console.log("Initial black pieces:", stage.initialPlayer1 || []);
  console.log("Initial white pieces:", stage.initialPlayer2 || []);
  console.log("Blocked cells:", stage.initialBlocked || []);
  
  // Create initial board for this stage
  const initialBoard = OthelloCore.createInitialBoard(stage);
  console.log("Initial board:");
  console.table(initialBoard);
  
  return stage;
}

// Explore first stage (index 0)
exploreStage(0);

Performance Measurement

Measure strategy performance:

// Measure execution time of a strategy
function benchmarkStrategy(strategyFn, iterations = 10) {
  const currentBoard = OthelloCore.getBoard();
  const currentPlayer = OthelloCore.getCurrentPlayer();
  const validMoves = OthelloCore.getValidMoves(currentPlayer);
  
  console.log(`Benchmarking strategy with ${iterations} iterations...`);
  
  const times = [];
  let move;
  
  for (let i = 0; i < iterations; i++) {
    const start = performance.now();
    move = strategyFn(currentBoard, currentPlayer, validMoves);
    const end = performance.now();
    times.push(end - start);
  }
  
  // Calculate statistics
  const totalTime = times.reduce((a, b) => a + b, 0);
  const avgTime = totalTime / iterations;
  const minTime = Math.min(...times);
  const maxTime = Math.max(...times);
  
  console.log("Benchmark results:");
  console.log(`- Total time: ${totalTime.toFixed(2)}ms`);
  console.log(`- Average time: ${avgTime.toFixed(2)}ms`);
  console.log(`- Min time: ${minTime.toFixed(2)}ms`);
  console.log(`- Max time: ${maxTime.toFixed(2)}ms`);
  console.log("- Selected move:", move);
  
  return { avgTime, minTime, maxTime, move };
}

// Benchmark our corner strategy
const benchmarkResults = benchmarkStrategy(cornerStrategy);
console.log("Benchmark results:", benchmarkResults);

These console commands provide a solid foundation for exploring the Othello Arena, testing strategies, and understanding game mechanics. You can copy-paste these snippets directly into your browser console while running the Othello Arena to experiment with them.

If you are interested in knowing more, feel free to read this too!

Happy coding! 🎮