BitBully 0.0.78
A fast, perfect-play Connect-4 engine in modern C++
Loading...
Searching...
No Matches
BitBully::Board Class Reference

Connect-4 position represented as a pair of 64-bit bitboards. More...

#include <Board.h>

Classes

struct  RawState
 Plain-data snapshot of the board's internal state. More...

Public Types

enum  Player { P_EMPTY = 0 , P_YELLOW = 1 , P_RED = 2 }
 Player identifiers used by the board's array view. More...
using TBitBoard = uint64_t
 64-bit type used for any bitboard value.
using TMovesCounter = int
 Type used to count remaining moves on a position.
using TBoardArray = std::array<std::array<int32_t, N_ROWS>, N_COLUMNS>
 Column-major 2D representation of the board (Board representation[col][row]).
using TBoardArrayT = std::array<std::array<int32_t, N_COLUMNS>, N_ROWS>
 Row-major 2D representation of the board (Board representation[row][col]).

Public Member Functions

 Board ()
 Construct an empty board with player Yellow to move.
Board playBitMaskOnCopy (const TBitBoard mv) const
 Apply a move (already encoded as a single-bit mask) on a copy of this board.
Board playMoveOnCopy (const int mv) const
 Apply a move given by column index on a copy of this board.
Board copy () const
 Return a deep copy of this board.
TBitBoard legalMovesMask () const
 Bitboard whose set bits mark the next reachable cell of every non-full column.
std::vector< int > legalMoves (bool nonLosing, bool orderMoves) const
 Enumerate legal moves as column indices.
auto popCountBoard () const
 Number of stones currently on the board.
bool isLegalMove (int column) const
 Check whether dropping a stone in column is legal.
uint64_t uid () const
 Unique 64-bit identifier of the position.
uint64_t hash () const
 64-bit hash of the position derived from uid().
bool operator== (const Board &b) const
 Compare two positions for equality (same stones, same side to move).
bool operator!= (const Board &b) const
 Inequality counterpart of operator==.
TBitBoard findOddThreats (TBitBoard moves)
 Identify candidate moves that introduce a new "odd" threat.
bool setBoard (const TBoardArray &board)
 Replace the current position with the one described by board.
bool setBoard (const TBoardArrayT &board)
 Row-major variant of setBoard(const TBoardArray&).
bool setBoard (const std::vector< int > &moveSequence)
 Replay a move sequence onto a fresh board and copy the result.
bool play (int column)
 Drop a stone of the player to move into column.
bool play (const std::vector< int > &moveSequence)
 Apply a sequence of column-index moves.
bool play (const std::string &moveSequence)
 Apply a sequence of moves encoded as digit characters.
bool setBoard (const std::string &moveSequence)
 String-based variant of setBoard(const std::vector<int>&).
TBoardArray toArray () const
 Convert the bitboard representation into a column-major array.
bool canWin () const
 Does the player to move have an immediately winning move?
bool canWin (int column) const
 Variant of canWin() restricted to a particular column.
bool hasWin () const
 Did the player who just moved form a four-in-a-row?
std::string toString () const
 Pretty-printed ASCII representation of the board.
TMovesCounter movesLeft () const
 Number of plies remaining until the board is full.
TMovesCounter countTokens () const
 Number of stones currently placed on the board.
Board mirror () const
 Mirror the board around its central column.
MoveList sortMoves (TBitBoard moves) const
 Sort candidate moves into a MoveList using a threat-based heuristic.
TBitBoard findThreats (TBitBoard moves)
 Identify candidate moves that yield a tactical advantage.
int getColumnHeight (const int column) const
 Number of stones currently stacked in column.
TBitBoard generateNonLosingMoves () const
 Compute moves that do not lose immediately.
TBitBoard doubleThreat (const TBitBoard moves) const
 Identify moves that create a "double threat" (forced win).
int toHuffman () const
 Encode the position as a compact Huffman-like integer.
std::vector< BoardallPositions (const int upToNPly, bool exactlyN) const
 Enumerate every reachable position from this board within a depth.
RawState rawState () const noexcept
 Snapshot the internal state.
void setRawState (const RawState &s) noexcept
 Restore an internal state previously captured with rawState().

Static Public Member Functions

static constexpr int popCountBoard (uint64_t x)
 Software popcount fallback used when no intrinsic is available.
static uint64_t hash (uint64_t x)
 Splittable-mix-style hash for a 64-bit integer.
static TBitBoard nextMove (TBitBoard allMoves)
 Pick the best-ranked move from a candidate set using a fixed priority order.
static bool isValid (const TBoardArray &board)
 Validate a board layout.
static TBitBoard lsb (const TBitBoard x)
 Isolate the least significant set bit of a bitboard.
static std::pair< Board, std::vector< int > > randomBoard (const int nPly, const bool forbidDirectWin=true)
 Generate a random reachable position with a fixed number of plies.

Static Public Attributes

static constexpr int N_COLUMNS = 7
 Number of columns in a Connect-4 grid.
static constexpr int N_ROWS = 6
 Number of rows in a Connect-4 grid.
static constexpr int COLUMN_BIT_OFFSET = 9
 Bit-offset between two columns inside the 64-bit board representation.
static constexpr size_t N_VALID_BOARD_VALUES = 3
 Number of distinct cell values: empty, yellow, red.

Friends

class BoardTest

Detailed Description

Connect-4 position represented as a pair of 64-bit bitboards.

The board uses two 64-bit integers to encode an entire 7×6 position:

  • m_bAllTokens has a bit set for every occupied cell.
  • m_bActivePTokens has a bit set for every cell occupied by the player whose turn it is. The opponent mask is therefore obtained as m_bActivePTokens ^ m_bAllTokens.

Encoding the position this way removes any branching when switching the side to move — m_bActivePTokens is simply XOR'ed with m_bAllTokens after each ply. The internal bit layout is:

[ *, *, *, *, *, *, *] <- guard row (never set)
[ *, *, *, *, *, *, *]
[ *, *, *, *, *, *, *]
[ 5, 14, 23, 32, 41, 50, 59] <- top row
[ 4, 13, 22, 31, 40, 49, 58]
[ 3, 12, 21, 30, 39, 48, 57]
[ 2, 11, 20, 29, 38, 47, 56]
[ 1, 10, 19, 28, 37, 46, 55]
[ 0, 9, 18, 27, 36, 45, 54] <- bottom row

Bit indices for a column c and row r are c * 9 + r.

Examples
quick_solve.cpp, score_all_moves.cpp, and with_opening_book.cpp.

Definition at line 204 of file Board.h.

Member Typedef Documentation

◆ TBitBoard

using BitBully::Board::TBitBoard = uint64_t

64-bit type used for any bitboard value.

Definition at line 230 of file Board.h.

◆ TBoardArray

using BitBully::Board::TBoardArray = std::array<std::array<int32_t, N_ROWS>, N_COLUMNS>

Column-major 2D representation of the board (Board representation[col][row]).

Definition at line 234 of file Board.h.

◆ TBoardArrayT

using BitBully::Board::TBoardArrayT = std::array<std::array<int32_t, N_COLUMNS>, N_ROWS>

Row-major 2D representation of the board (Board representation[row][col]).

Definition at line 236 of file Board.h.

◆ TMovesCounter

Type used to count remaining moves on a position.

Definition at line 232 of file Board.h.

Member Enumeration Documentation

◆ Player

Player identifiers used by the board's array view.

Enumerator
P_EMPTY 

Empty cell.

P_YELLOW 

Yellow stone (player who moves first).

P_RED 

Red stone (player who moves second).

Definition at line 222 of file Board.h.

Constructor & Destructor Documentation

◆ Board()

BitBully::Board::Board ( )

Construct an empty board with player Yellow to move.

Definition at line 18 of file Board.cpp.

Here is the caller graph for this function:

Member Function Documentation

◆ allPositions()

std::vector< Board > BitBully::Board::allPositions ( const int upToNPly,
bool exactlyN ) const
inlinenodiscard

Enumerate every reachable position from this board within a depth.

Performs a recursive expansion via addAfterStates() and deduplicates positions by their uid().

Parameters
upToNPlyMaximum number of plies to play from the current board.
exactlyNIf true, return only positions with exactly upToNPly stones placed; if false, include all intermediate positions as well.
Returns
Vector of distinct boards.
See also
https://oeis.org/A212693

Definition at line 719 of file Board.h.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ canWin() [1/2]

bool BitBully::Board::canWin ( ) const
nodiscard

Does the player to move have an immediately winning move?

Definition at line 407 of file Board.cpp.

Here is the caller graph for this function:

◆ canWin() [2/2]

bool BitBully::Board::canWin ( int column) const
nodiscard

Variant of canWin() restricted to a particular column.

Parameters
columnColumn index to inspect.
Returns
true if dropping the next stone in column wins immediately.

Definition at line 412 of file Board.cpp.

Here is the call graph for this function:

◆ copy()

Board BitBully::Board::copy ( ) const
inlinenodiscard

Return a deep copy of this board.

Definition at line 265 of file Board.h.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ countTokens()

TMovesCounter BitBully::Board::countTokens ( ) const
inlinenodiscard

Number of stones currently placed on the board.

Definition at line 506 of file Board.h.

Here is the caller graph for this function:

◆ doubleThreat()

TBitBoard BitBully::Board::doubleThreat ( const TBitBoard moves) const
inlinenodiscard

Identify moves that create a "double threat" (forced win).

A double threat is a stone that produces two immediate vertical threats stacked on top of each other — the opponent can only block one of them.

Parameters
movesCandidate move bitboard.
Returns
Sub-set of moves whose execution yields a double threat.

Definition at line 619 of file Board.h.

Here is the caller graph for this function:

◆ findOddThreats()

Board::TBitBoard BitBully::Board::findOddThreats ( TBitBoard moves)
nodiscard

Identify candidate moves that introduce a new "odd" threat.

A threat sitting in an odd-numbered row (rows 3 and 5 from below) is particularly valuable for the first player due to Connect-4's even/odd-row strategy theory.

Parameters
movesSet of candidate moves (bitboard).
Returns
Sub-set of moves that increase the number of odd threats.

Definition at line 344 of file Board.cpp.

Here is the call graph for this function:

◆ findThreats()

Board::TBitBoard BitBully::Board::findThreats ( TBitBoard moves)

Identify candidate moves that yield a tactical advantage.

Returns either:

  • the first move that creates two simultaneous immediate threats (a forced win in two plies), or
  • the bit-OR of all moves that strictly increase the active player's number of threats.
Parameters
movesCandidate move bitboard.
Returns
Selected sub-set of moves.

Definition at line 313 of file Board.cpp.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ generateNonLosingMoves()

TBitBoard BitBully::Board::generateNonLosingMoves ( ) const
inlinenodiscard

Compute moves that do not lose immediately.

Inspired by Pascal Pons' Connect-4 solver (http://blog.gamesolver.org/). The function returns a bitboard of legal moves whose execution does not let the opponent finish the game on the next ply.

Note
If the active player has only losing replies, the returned bitboard is empty.
Direct winning moves are not included when the opponent has a double threat; callers that need them should add the result of winningPositions() explicitly.
Returns
Bitboard of safe moves.

Definition at line 591 of file Board.h.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getColumnHeight()

int BitBully::Board::getColumnHeight ( const int column) const
nodiscard

Number of stones currently stacked in column.

Parameters
columnColumn index (must be in 0…N_COLUMNS-1).
Returns
Stack height between 0 and N_ROWS.

Definition at line 512 of file Board.cpp.

Here is the caller graph for this function:

◆ hash() [1/2]

uint64_t BitBully::Board::hash ( ) const
inlinenodiscard

64-bit hash of the position derived from uid().

Equivalent positions (same m_bAllTokens and m_bActivePTokens) map to the same hash value; mirror-symmetric positions do not.

Definition at line 358 of file Board.h.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hash() [2/2]

uint64_t BitBully::Board::hash ( uint64_t x)
inlinestaticnodiscard

Splittable-mix-style hash for a 64-bit integer.

Implementation of David Stafford's "Mix13" finaliser. Used internally to derive transposition-table indices from board UIDs.

Parameters
x64-bit input.
Returns
Avalanche-mixed 64-bit hash of x.

Definition at line 334 of file Board.h.

Here is the caller graph for this function:

◆ hasWin()

bool BitBully::Board::hasWin ( ) const
nodiscard

Did the player who just moved form a four-in-a-row?

Returns
true if the position is a win for the player who is currently not to move.

Definition at line 254 of file Board.cpp.

Here is the caller graph for this function:

◆ isLegalMove()

bool BitBully::Board::isLegalMove ( int column) const
nodiscard

Check whether dropping a stone in column is legal.

Parameters
columnColumn index.
Returns
true if column is in range and not yet full.
Examples
score_all_moves.cpp.

Definition at line 170 of file Board.cpp.

Here is the caller graph for this function:

◆ isValid()

bool BitBully::Board::isValid ( const TBoardArray & board)
staticnodiscard

Validate a board layout.

Checks that all cells contain a known value, that gravity is respected, and that the stone count satisfies 0 <= yellow - red <= 1.

Parameters
Board representationColumn-major array to validate.
Returns
true if board could appear in a real game.

Definition at line 97 of file Board.cpp.

Here is the caller graph for this function:

◆ legalMoves()

std::vector< int > BitBully::Board::legalMoves ( bool nonLosing,
bool orderMoves ) const
nodiscard

Enumerate legal moves as column indices.

Parameters
nonLosingIf true, restrict the result to moves that do not immediately allow the opponent to win. Direct winning moves of the active player are always included.
orderMovesIf true, sort the moves by the heuristic implemented in sortMoves() (best first).
Returns
Vector of column indices (0…N_COLUMNS-1).

Definition at line 448 of file Board.cpp.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ legalMovesMask()

Board::TBitBoard BitBully::Board::legalMovesMask ( ) const
nodiscard

Bitboard whose set bits mark the next reachable cell of every non-full column.

For each column the lowest empty cell receives a 1-bit, all other bits are zero. The result has between 0 and N_COLUMNS bits set.

Definition at line 418 of file Board.cpp.

Here is the caller graph for this function:

◆ lsb()

TBitBoard BitBully::Board::lsb ( const TBitBoard x)
inlinestatic

Isolate the least significant set bit of a bitboard.

Parameters
xInput bitboard.
Returns
x with all bits cleared except for its lowest set bit. If x is zero, the result is zero as well.

Definition at line 570 of file Board.h.

Here is the caller graph for this function:

◆ mirror()

Board BitBully::Board::mirror ( ) const
nodiscard

Mirror the board around its central column.

Useful for transposition lookups: a position and its mirror image have identical theoretical value, so storing only one of them roughly halves the effective table size.

Definition at line 501 of file Board.cpp.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ movesLeft()

TMovesCounter BitBully::Board::movesLeft ( ) const
inlinenodiscard

Number of plies remaining until the board is full.

Definition at line 503 of file Board.h.

Here is the caller graph for this function:

◆ nextMove()

TBitBoard BitBully::Board::nextMove ( TBitBoard allMoves)
inlinestaticnodiscard

Pick the best-ranked move from a candidate set using a fixed priority order.

The static priority lists BB_MOVES_PRIO1BB_MOVES_PRIO6 encode a center-first ordering. The first priority class that has a non-empty intersection with allMoves wins; among the remaining candidates the one with the smallest bit index (i.e. lower row, leftmost column) is returned.

Parameters
allMovesBitboard of candidate moves (one bit per cell).
Returns
Bitboard with exactly one bit set selecting the chosen move, or 0 if allMoves is empty.

Definition at line 376 of file Board.h.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ operator!=()

bool BitBully::Board::operator!= ( const Board & b) const
inlinenodiscard

Inequality counterpart of operator==.

Definition at line 397 of file Board.h.

Here is the call graph for this function:

◆ operator==()

bool BitBully::Board::operator== ( const Board & b) const
inlinenodiscard

Compare two positions for equality (same stones, same side to move).

Definition at line 387 of file Board.h.

Here is the call graph for this function:

◆ play() [1/3]

bool BitBully::Board::play ( const std::string & moveSequence)
nodiscard

Apply a sequence of moves encoded as digit characters.

Each character must be in '0'..'0'+N_COLUMNS-1.

Parameters
moveSequenceString of column-index digits.
Returns
true on success, false on the first illegal move; on failure the board is left unchanged.

Definition at line 156 of file Board.cpp.

Here is the call graph for this function:

◆ play() [2/3]

bool BitBully::Board::play ( const std::vector< int > & moveSequence)
nodiscard

Apply a sequence of column-index moves.

Parameters
moveSequenceSequence of column indices.
Returns
true if every move was legal, false otherwise; on failure the board is left unchanged.

Definition at line 146 of file Board.cpp.

Here is the call graph for this function:

◆ play() [3/3]

bool BitBully::Board::play ( int column)

Drop a stone of the player to move into column.

Parameters
columnColumn index.
Returns
true if the move was legal and applied, false otherwise.
Examples
quick_solve.cpp, and score_all_moves.cpp.

Definition at line 137 of file Board.cpp.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ playBitMaskOnCopy()

Board BitBully::Board::playBitMaskOnCopy ( const TBitBoard mv) const
inlinenodiscard

Apply a move (already encoded as a single-bit mask) on a copy of this board.

Parameters
mvBitboard with exactly one bit set, representing the cell to occupy. Must be a legal move; behaviour is undefined otherwise.
Returns
The new board after the move was played.

Definition at line 245 of file Board.h.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ playMoveOnCopy()

Board BitBully::Board::playMoveOnCopy ( const int mv) const
inlinenodiscard

Apply a move given by column index on a copy of this board.

Parameters
mvColumn index (0…N_COLUMNS-1).
Returns
A new Board with the move applied. If mv is illegal a freshly-constructed empty board is returned instead.

Definition at line 258 of file Board.h.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ popCountBoard() [1/2]

auto BitBully::Board::popCountBoard ( ) const
inlinenodiscard

Number of stones currently on the board.

Equivalent to countTokens() but exposes the raw popcount of the internal bitboard.

Definition at line 313 of file Board.h.

◆ popCountBoard() [2/2]

constexpr int BitBully::Board::popCountBoard ( uint64_t x)
inlinestaticnodiscardconstexpr

Software popcount fallback used when no intrinsic is available.

Parameters
x64-bit input.
Returns
Number of set bits in x.

Definition at line 298 of file Board.h.

Here is the caller graph for this function:

◆ randomBoard()

std::pair< Board, std::vector< int > > BitBully::Board::randomBoard ( const int nPly,
const bool forbidDirectWin = true )
inlinestatic

Generate a random reachable position with a fixed number of plies.

Plays random legal moves until nPly stones are on the board. If forbidDirectWin is true the function reroutes around positions where the side to move can win immediately (useful when generating benchmark positions).

Parameters
nPlyNumber of plies to play (0…N_ROWS*N_COLUMNS).
forbidDirectWinReject positions where the active player has an immediate win.
Returns
Pair of the generated board and the move sequence used to reach it. Returns an empty pair if nPly is out of range.

Definition at line 689 of file Board.h.

Here is the caller graph for this function:

◆ rawState()

RawState BitBully::Board::rawState ( ) const
inlinenodiscardnoexcept

Snapshot the internal state.

Definition at line 749 of file Board.h.

Here is the caller graph for this function:

◆ setBoard() [1/4]

bool BitBully::Board::setBoard ( const std::string & moveSequence)
nodiscard

String-based variant of setBoard(const std::vector<int>&).

Definition at line 41 of file Board.cpp.

Here is the call graph for this function:

◆ setBoard() [2/4]

bool BitBully::Board::setBoard ( const std::vector< int > & moveSequence)
nodiscard

Replay a move sequence onto a fresh board and copy the result.

Parameters
moveSequenceSequence of column indices to play in order.
Returns
true on success, false if the sequence contains an illegal move; the object is unchanged on failure.

Definition at line 30 of file Board.cpp.

Here is the call graph for this function:

◆ setBoard() [3/4]

bool BitBully::Board::setBoard ( const TBoardArray & board)
nodiscard

Replace the current position with the one described by board.

Parameters
Board representationColumn-major array using P_EMPTY / P_YELLOW / P_RED values. Stones must respect gravity (no floating cells).
Returns
true on success, false if board is malformed; the object is unchanged on failure.

Definition at line 67 of file Board.cpp.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setBoard() [4/4]

bool BitBully::Board::setBoard ( const TBoardArrayT & board)
nodiscard

Row-major variant of setBoard(const TBoardArray&).

Definition at line 62 of file Board.cpp.

Here is the call graph for this function:

◆ setRawState()

void BitBully::Board::setRawState ( const RawState & s)
inlinenoexcept

Restore an internal state previously captured with rawState().

Warning
No validity checks are performed. Callers must ensure that the provided state corresponds to a real Connect-4 position; otherwise subsequent operations on the board are undefined.

Definition at line 760 of file Board.h.

Here is the caller graph for this function:

◆ sortMoves()

MoveList BitBully::Board::sortMoves ( TBitBoard moves) const
nodiscard

Sort candidate moves into a MoveList using a threat-based heuristic.

Each move is scored by the number of new threats (winning lines) it introduces, with a penalty for moves placed directly under one of the active player's existing threats.

Parameters
movesBitboard of candidate moves.
Returns
Priority queue ordered from best to worst.

Definition at line 285 of file Board.cpp.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ toArray()

Board::TBoardArray BitBully::Board::toArray ( ) const
nodiscard

Convert the bitboard representation into a column-major array.

Returns
2D array of P_EMPTY / P_YELLOW / P_RED values.

Definition at line 463 of file Board.cpp.

Here is the caller graph for this function:

◆ toHuffman()

int BitBully::Board::toHuffman ( ) const
inlinenodiscard

Encode the position as a compact Huffman-like integer.

Used as a key for the opening-book tables. The encoding is only defined for positions with an even number of tokens and at most 12 placed stones (i.e. m_movesLeft is even and at least 30).

Each column is encoded by walking from the bottom up: every stone contributes two bits (10 for the active player, 11 for the opponent), and the stack is terminated by a single 0 bit.

Returns
Huffman-encoded position, or 0 if the position does not qualify for encoding.

Definition at line 650 of file Board.h.

Here is the caller graph for this function:

◆ toString()

std::string BitBully::Board::toString ( ) const
nodiscard

Pretty-printed ASCII representation of the board.

Yellow stones are rendered as X, Red stones as O, and empty cells as _. Rows are printed from top to bottom.

Examples
quick_solve.cpp.

Definition at line 481 of file Board.cpp.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ uid()

uint64_t BitBully::Board::uid ( ) const
inlinenodiscard

Unique 64-bit identifier of the position.

Combines the "all tokens" bitboard with the "active player" bitboard in a way that ensures every legal Connect-4 position maps to a distinct value. Suitable as a key for transposition tables.

Returns
Unique identifier of the current position.

Definition at line 350 of file Board.h.

Here is the caller graph for this function:

◆ BoardTest

friend class BoardTest
friend

Definition at line 205 of file Board.h.

Member Data Documentation

◆ COLUMN_BIT_OFFSET

int BitBully::Board::COLUMN_BIT_OFFSET = 9
staticconstexpr

Bit-offset between two columns inside the 64-bit board representation.

Each column gets one extra "guard" bit on top of the playable rows so that operations such as m_bAllTokens + BB_BOTTOM_ROW cannot leak from one column into the next.

Definition at line 219 of file Board.h.

◆ N_COLUMNS

int BitBully::Board::N_COLUMNS = 7
staticconstexpr

Number of columns in a Connect-4 grid.

Examples
score_all_moves.cpp.

Definition at line 211 of file Board.h.

◆ N_ROWS

int BitBully::Board::N_ROWS = 6
staticconstexpr

Number of rows in a Connect-4 grid.

Definition at line 213 of file Board.h.

◆ N_VALID_BOARD_VALUES

size_t BitBully::Board::N_VALID_BOARD_VALUES = 3
staticconstexpr

Number of distinct cell values: empty, yellow, red.

Definition at line 228 of file Board.h.


The documentation for this class was generated from the following files: