Skip to main content

othellopy

PyPI Python License CI

othellopy is a small Python package for Othello/Reversi exercises. It provides a board model, a game runner, player test helpers, and sample players ranging from random play to alpha-beta search.

The package is currently 0.x alpha software. Public APIs may change before 1.0.0.

Official distribution:

Requirements

  • Python 3.10 or later
  • No runtime dependencies

Installation

Install with pip:

pip install othellopy

Or add it to a uv project:

uv add othellopy

Quick Start

Run a complete game between two sample players:

from othellopy.board import display_board
from othellopy.game import OthelloGame
from othellopy.players import BeginnerPlayer, IntermediatePlayer

result = OthelloGame(BeginnerPlayer, IntermediatePlayer).play()

print(result.winner_name)
print(result.black_score, result.white_score)
display_board(result.board)

Writing a Player

Subclass BasePlayer and implement next_move().

from othellopy.core import Board, Cell, Move
from othellopy.players import BasePlayer


class MyPlayer(BasePlayer):
    def next_move(self, board: Board) -> Move:
        return self.get_moves(board)[0]

Coordinates are zero-based (row, col) pairs. next_move() is called only when the player has at least one legal move.

Runtime Player Check

Use test_player() in Google Colab to check that a custom player actually runs correctly. This is the dynamic part of validation; browser-side static analysis can separately check imports and source-code rules before students run Colab.

from othellopy.validation import test_player, test_player_detail

if test_player(MyPlayer):
    print("Basic player tests passed")
else:
    result = test_player_detail(MyPlayer)
    for issue in result.errors:
        print(issue.code, issue.message)

The runtime player tests check that the class inherits from BasePlayer, can be constructed for black and white, returns legal moves on many board states, and returns within two seconds by default. print() and display_board() are allowed, so students can debug in Google Colab while running the tests.

The board passed to next_move() is an isolated copy during player tests and game play, so accidental board edits do not change the real game state. Students should still treat the board as read-only because only the returned move is used.

Normal games also limit each next_move() call to two seconds by default. A player that exceeds the limit forfeits, and the opponent wins. Pass move_timeout_seconds=None when you intentionally need no timeout, such as manual terminal play.

On Linux environments such as Google Colab, the timeout can interrupt next_move() when it exceeds the limit. On Windows, a running next_move() cannot always be stopped forcibly; if it eventually returns, elapsed time is checked afterward, but an infinite loop may hang the check. Evaluation servers should run submitted players in an isolated process or sandbox with their own timeout.

Runtime player tests do not inspect source code and do not enforce import policy. Use a separate static analyzer, for example in a Next.js client, to reject external packages such as numpy or risky APIs such as open(), input(), eval(), and exec().

This is a runtime screen, not a security sandbox. Evaluation servers should run the same runtime player tests again and execute submitted players in an isolated sandbox.

Manual CLI Play

Use ManualPlayer to enter moves interactively from a terminal. Input is two digits in row-column order, such as 07.

from othellopy.game import OthelloGame
from othellopy.players import BeginnerPlayer, ManualPlayer

result = OthelloGame(
    ManualPlayer,
    BeginnerPlayer,
    move_timeout_seconds=None,
).play()

Equivalent one-off command:

uv run python - <<'PY'
from othellopy.game import OthelloGame
from othellopy.players import BeginnerPlayer, ManualPlayer

result = OthelloGame(
    ManualPlayer,
    BeginnerPlayer,
    move_timeout_seconds=None,
).play()
print(result.winner_name, result.black_score, result.white_score)
PY

Sample Players

Import sample players from othellopy.players:

from othellopy.players import (
    AdvancedPlayer,
    BeginnerPlayer,
    IntermediatePlayer,
    ManualPlayer,
)
  • BeginnerPlayer: chooses a legal move randomly.
  • IntermediatePlayer: scores legal moves with a simple one-ply heuristic.
  • AdvancedPlayer: searches ahead with alpha-beta pruning.
  • ManualPlayer: asks for row-column input in a CLI.

Board Display

Board helpers render stones as ⚫️ and ⚪️ when the output encoding supports them. If the output cannot encode those emoji, display falls back to B and W.

Use display_board() for both notebooks and terminals. In Google Colab or Jupyter, it renders a fixed HTML table so emoji stones stay aligned even when the notebook font gives emoji a different display width from ASCII characters. In a terminal, it falls back to readable text output.

from othellopy.board import display_board, initial_board

display_board(initial_board())

print_board() is kept as a compatibility helper when you explicitly want text output.

from othellopy.board import initial_board, print_board

print_board(initial_board())

Use board_to_str(..., use_emoji=False) when you need stable ASCII output.

Invalid Moves and Forfeits

If a player returns an invalid move, the player forfeits and the opponent wins. The same happens when next_move() exceeds the two-second default timeout. The game still returns a GameResult.

result = OthelloGame(
    black_player=MyPlayer,
    white_player=BeginnerPlayer,
).play()

if result.forfeit is not None:
    print(result.winner_name)
    print(result.forfeit.color)
    print(result.forfeit.move)
    print(result.forfeit.valid_moves)

API Overview

othellopy.core

Cell : IntEnum representing board cell values.

Cell.EMPTY
Cell.BLACK
Cell.WHITE

Board : Type alias for list[list[Cell]].

Move : Type alias for tuple[int, int].

opponent(cell: Cell) -> Cell : Returns Cell.WHITE for Cell.BLACK, and Cell.BLACK for Cell.WHITE. Passing Cell.EMPTY raises ValueError.

othellopy.board

initial_board() -> Board : Returns the standard 8x8 initial Othello board.

copy_board(board: Board) -> Board : Returns a row-by-row copy of a board.

board_to_str(board: Board, *, use_emoji: bool | None = None) -> str : Converts a board to readable text.

board_to_html(board: Board, *, use_emoji: bool | None = None) -> str : Converts a board to a fixed-cell HTML table for notebook display.

display_board(board: Board, *, use_emoji: bool | None = None, output: TextIO | None = None) -> None : Displays a board as HTML in IPython notebooks, falling back to text output in terminals. When output is provided, writes text output to that stream. Prefer this for examples and student code.

print_board(board: Board, *, use_emoji: bool | None = None) -> None : Prints a readable board as text. Kept for compatibility and explicit text output.

othellopy.players

BasePlayer : Base class for custom players. Provides:

  • color
  • opponent_color
  • get_moves(board)
  • is_valid_move(board, row, col)
  • get_flips(board, row, col)

BeginnerPlayer : Random legal move player.

IntermediatePlayer : Simple heuristic player.

AdvancedPlayer : Alpha-beta search player. Accepts depth= in the constructor.

ManualPlayer : Interactive CLI player. Accepts optional input_func, output, and use_emoji parameters for testing or custom IO.

othellopy.game

OthelloGame(black_player, white_player, *, move_timeout_seconds=2.0) : Runs one game between two BasePlayer subclasses. Keyword arguments black_player=... and white_player=... are recommended for notebooks. move_timeout_seconds=None disables the per-move timeout.

GameResult : Return value from OthelloGame(...).play().

Fields:

  • winner: Cell
  • winner_name: str
  • black_score: int
  • white_score: int
  • board: Board
  • moves: list[tuple[Cell, int, int]]
  • turns: list[TurnRecord]
  • forfeit: ForfeitRecord | None

TurnRecord : Per-turn debug information.

Fields:

  • color: Cell
  • board: Board
  • valid_moves: list[tuple[int, int]]
  • move: tuple[int, int] | None
  • black_score: int
  • white_score: int

ForfeitRecord : Invalid-move or timeout forfeit information.

Fields:

  • color: Cell
  • move: object
  • valid_moves: list[tuple[int, int]]
  • board: Board
  • message: str

othellopy.validation

test_player(player_class, *, max_seconds=2.0) -> bool : Returns True when a submitted player class passes runtime player tests.

test_player_detail(player_class, *, max_seconds=2.0) -> ValidationResult : Returns detailed runtime errors and runtime case details.

validate(...) / validate_detail(...) : Compatibility aliases for test_player(...) and test_player_detail(...).

ValidationResult : Detailed validation result.

Fields:

  • passed: bool
  • issues: list[ValidationIssue]
  • errors: list[ValidationIssue]
  • warnings: list[ValidationIssue]
  • details: dict[str, object]

ValidationIssue : One validation issue.

Fields:

  • code: str
  • message: str
  • severity: ValidationSeverity

Development

uv venv
uv pip install -e ".[dev]"

Run checks:

uv run --extra dev ruff format --check .
uv run --extra dev ruff check .
uv run --extra dev mypy .
uv run --extra dev pytest
uv build

Release Policy

othellopy is published on PyPI from GitHub tags named vX.Y.Z. Published PyPI files are immutable, so a broken release is fixed by publishing a newer version instead of replacing an existing one.

The release checklist is documented in RELEASE.md.

Contributing

Contributions must follow the GitFlow rules in CONTRIBUTING.md:

  • feat/* pull requests target dev.
  • release/* pull requests target main.
  • Direct pushes to main and dev are not allowed.
  • Required checks must pass before merge.

Security

Please do not report vulnerabilities in public issues. See SECURITY.md.

License

Licensed under the Apache License, Version 2.0. See LICENSE.

Metadata

Release files for othellopy 0.2.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for othellopy 0.2.5
File Size Uploaded
othellopy-0.2.5.tar.gz 57.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for othellopy 0.2.5
File Interpreter ABI Platform
othellopy-0.2.5-py3-none-any.whl Python 3 none any Details

Total release size: 81.1 kB

Release files / othellopy-0.2.5.tar.gz

Download URL othellopy-0.2.5.tar.gz
Size 57.6 kB
Tags Source
SHA-256 checksum
How to use checksums
742c83fdbb75167b86308e2c02279db24e4fccf132d8ff36c7b90cbe466096c1
BLAKE2b-256 checksum
How to use checksums
faa9e7972f886fa25b973a4bda59a2a71cbf7ebee51e943ad3e12da0a1a1ffdb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / othellopy-0.2.5-py3-none-any.whl

Download URL othellopy-0.2.5-py3-none-any.whl
Size 23.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2cf919ff51b56c26cbfeb5b74933d385a5e6dcc885502e420c9a81385195229f
BLAKE2b-256 checksum
How to use checksums
0feebcbf07e949a0442396f4f4a51eb48955bcbacb610ac2e7e197072c7eb2fc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.2.5 This release

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page