Othello API Reference and Console Guide
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
- Use
simulateMove
to explore the consequences of potential moves before deciding. - Combine multiple metrics from
evaluateBoard
for better decision making. - The API functions consider all stage-specific rules, so you don’t need to worry about special rules like occlusion or turn order.
- During
analyzeStage
, you can maintain state or calculate values that your strategy function can access through closures. - For deeper search algorithms, consider using memoization to avoid recalculating the same board positions.
- Your
analyzeStage
function has up to 60 seconds to analyze the stage. - 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! 🎮