SkillAgentSearch skills...

Binbo

Chess representation written in Erlang using Bitboards, ready for use on game servers

Install / Use

/learn @DOBRO/Binbo

README

= Binbo :toc: macro :toclevels: 4

image:https://img.shields.io/hexpm/v/binbo.svg?color=yellow["Binbo on Hex.pm", link="https://hex.pm/packages/binbo"] image:https://github.com/DOBRO/binbo/actions/workflows/main.yml/badge.svg?branch=master["CI Status", link="https://github.com/DOBRO/binbo/actions?query=workflow%3ABuild+branch%3Amaster"] image:https://codecov.io/gh/DOBRO/binbo/branch/master/graph/badge.svg["Code coverage", link="https://codecov.io/gh/DOBRO/binbo"] image:https://img.shields.io/badge/erlang-%3E%3D%2020.0-0d6e8c.svg["Erlang", link="https://www.erlang.org/"] image:https://img.shields.io/badge/license-Apache%202.0-blue.svg["License", link="LICENSE"]

Binbo is a full-featured Chess representation written in pure Erlang using https://www.chessprogramming.org/Bitboards[Bitboards]. It is basically aimed to be used on game servers where people play chess online.

It's called Binbo because its ground is a binary board containing only zeros and ones (0 and 1) since this is the main meaning of Bitboards as an internal chessboard representation.

Binbo also uses the https://www.chessprogramming.org/Magic_Bitboards[Magic Bitboards] approach for a blazing fast move generation of sliding pieces (rook, bishop, and queen).

Note: it's not a chess engine but it could be a good starting point for it. It can play the role of a core (regarding move generation and validation) for multiple chess engines running on distributed Erlang nodes, since Binbo is an OTP application itself.

In addition, the application is able to communicate with https://www.chessprogramming.org/Category:UCI[chess engines that support UCI protocol] (https://www.chessprogramming.org/UCI[Universal Chess Interface]) such as Stockfish, Shredder, Houdini, etc. You can therefore write your own client-side or server-side chess bot application on top of Binbo, or just play with engine right in Erlang shell. TCP connections to remote chess engines are also supported.

Binbo is part of the https://github.com/h4cc/awesome-elixir[Awesome Elixir] list.

image::https://user-images.githubusercontent.com/296845/61208986-40792d80-a701-11e9-93c8-d2c41c5ef00d.png[Binbo sample]

'''

toc::[]

'''

== Features

  • Blazing fast move generation and validation.
  • No bottlenecks. Every game is an Erlang process (gen_server) with its own game state.
  • Ability to create as many concurrent games as many Erlang processes allowed in VM.
  • Support for PGN loading.
  • All the chess rules are completely covered including: ** https://en.wikipedia.org/wiki/En_passant[En-passant move]; ** https://en.wikipedia.org/wiki/Castling[Castling]; ** https://en.wikipedia.org/wiki/Fifty-move_rule[Fifty-move rule]; ** https://en.wikipedia.org/wiki/Threefold_repetition[Threefold repetition]; ** Draw by insufficient material: *** King versus King, *** King and Bishop versus King, *** King and Knight versus King, *** King and Bishop versus King and Bishop with the bishops on the same color;
  • Unicode chess symbols support for the board visualization right in Erlang shell: + ♙{nbsp}♘{nbsp}♗{nbsp}♖{nbsp}♕{nbsp}♔{nbsp}{nbsp}{nbsp}{nbsp}♟{nbsp}♞{nbsp}♝{nbsp}♜{nbsp}♛{nbsp}♚
  • UCI protocol support.
  • Support for TCP connections to remote UCI chess engines.
  • Passes all https://www.chessprogramming.org/Perft_Results[perft] tests.
  • Cross-platform application. It can run on Linux, Unix, Windows, and macOS.
  • Ready for use on game servers.

== Requirements

** https://www.erlang.org/[Erlang/OTP] 20.0 or higher. ** https://www.rebar3.org/[rebar3]

== Installation

=== For Erlang projects

Add Binbo as a dependency to your rebar.config file:

[source,erlang]

{deps, [ {binbo, "4.0.3"} ]}.

=== For Elixir projects

Add Binbo as a dependency to your mix.exs file:

[source,elixir]

defp deps do [ {:binbo, "~> 4.0"} ] end

== Quick start

Clone repository, change directory to binbo and run rebar3 shell (or make shell):

[source,bash]

$ git clone https://github.com/DOBRO/binbo.git $ cd binbo $ rebar3 shell

=== Common example

.In the Erlang shell: [source,erlang]

%% Start Binbo application first: binbo:start().

%% Start new process for the game: {ok, Pid} = binbo:new_server().

%% Start new game in the process: binbo:new_game(Pid).

%% Or start new game with a given FEN: binbo:new_game(Pid, <<"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1">>).

%% Look at the board with ascii or unicode pieces: binbo:print_board(Pid). binbo:print_board(Pid, [unicode]).

%% Make move for White and Black: binbo:move(Pid, <<"e2e4">>). binbo:move(Pid, <<"e7e5">>).

%% Have a look at the board again: binbo:print_board(Pid). binbo:print_board(Pid, [unicode]).

[[quickstart-play-with-engine]] === Play with engine on local machine

.In the Erlang shell: [source,erlang]

%% Start Binbo application first:

binbo:start(). {ok,[compiler,syntax_tools,uef,binbo]}

%% Start new process for the game:

{ok, Pid} = binbo:new_server(). {ok,<0.157.0>}

%% Set full path to the engine's executable file:

EnginePath = "/usr/local/bin/stockfish". "/usr/local/bin/stockfish"

%% Start new game in the process:

binbo:new_uci_game(Pid, #{engine_path => EnginePath}). {ok,continue}

%% Which side is to move?

binbo:side_to_move(Pid). {ok,white}

%% Say, you want to play Black. Tell the engine to make move for White.

binbo:uci_play(Pid, #{}). {ok,continue,<<"e2e4">>}

%% Make your move for Black and get the engine's move immediately:

binbo:uci_play(Pid, #{}, <<"e7e5">>). {ok,continue,<<"g1f3">>} % the engine's move was "g1f3"

%% Make your next move for Black and, again, get the engine's move at once:

binbo:uci_play(Pid, #{}, <<"b8c6">>). {ok,continue,<<"b1c3">>} % the engine's move was "b1c3"

%% Look at the board with ascii or unicode pieces. %% Flip the board to see Black on downside: binbo:print_board(Pid, [flip]). binbo:print_board(Pid, [unicode, flip]).

%% It's your turn now. Let the engine search for the best move for you with default options. %% No move actually done, just hint:

binbo:uci_bestmove(Pid, #{}). {ok,<<"g8f6">>}

%% Tell the engine to search for the best move at depth 20:

binbo:uci_bestmove(Pid, #{depth => 20}). {ok,<<"g8f6">>}

%% To make the gameplay more convenient, introduce new function:

Play = fun(Move) -> Result = binbo:uci_play(Pid, #{}, Move), binbo:print_board(Pid, [unicode, flip]), Result end.

%% Now, with this function, go through three steps at once: %% - make move "g8f6", %% - get the engine's move, %% - see how the position was changed.

Play("g8f6").


… engine's move was "d2d4": [source]

+---+---+---+---+---+---+---+---+ 1 | ♖ | | ♗ | ♔ | ♕ | ♗ | | ♖ | +---+---+---+---+---+---+---+---+ 2 | ♙ | ♙ | ♙ | | | ♙ | ♙ | ♙ | +---+---+---+---+---+---+---+---+ 3 | | | ♘ | | | ♘ | | | +---+---+---+---+---+---+---+---+ 4 | | | | ♙ | ♙ | | | | +---+---+---+---+---+---+---+---+ 5 | | | | ♟ | | | | | +---+---+---+---+---+---+---+---+ 6 | | | ♞ | | | ♞ | | | +---+---+---+---+---+---+---+---+ 7 | ♟ | ♟ | ♟ | | ♟ | ♟ | ♟ | ♟ | +---+---+---+---+---+---+---+---+ 8 | ♜ | | ♝ | ♚ | ♛ | ♝ | | ♜ | +---+---+---+---+---+---+---+---+ H G F E D C B A

Side to move: Black Lastmove: d2-d4, WHITE_PAWN Fullmove: 4 Halfmove: 0 FEN: "r1bqkb1r/pppp1ppp/2n2n2/4p3/3PP3/2N2N2/PPP2PPP/R1BQKB1R b KQkq d3 0 4" Status: continue

{ok,continue,<<"d2d4">>}

[[quickstart-uci-over-tcp]] === Connect to remote engine over TCP

The examples below assume that Stockfish is used as the chess engine and its path is /usr/local/bin/stockfish, change it according to your environment. TCP service starts on local machine on port 9010.

If you are on Linux, install socat and start TCP service. On macOS just use file org.stockfish.x86.plist (for Intel-based devices) or org.stockfish.arm.plist (for Apple silicon) provided in the test folder (see below).

.On Ubuntu/Debian: [source,bash]

$ apt install socat -y $ socat TCP-LISTEN:9010,reuseaddr,fork EXEC:/usr/local/bin/stockfish & $ git clone https://github.com/DOBRO/binbo.git $ cd binbo $ rebar3 shell

.On Centos/Fedora: [source,bash]

$ dnf install socat -y $ socat TCP-LISTEN:9010,reuseaddr,fork EXEC:/usr/local/bin/stockfish & $ git clone https://github.com/DOBRO/binbo.git $ cd binbo $ rebar3 shell

.On macOS (Intel x86 Architecture): [source,bash]

$ git clone https://github.com/DOBRO/binbo.git $ cd binbo $ launchctl load test/helper-files/org.stockfish.x86.plist $ rebar3 shell

.On macOS (Apple silicon): [source,bash]

$ git clone https://github.com/DOBRO/binbo.git $ cd binbo $ launchctl load test/helper-files/org.stockfish.arm.plist $ rebar3 shell

.Now in the Erlang shell: [source,erlang]

%% Start Binbo application first:

binbo:start(). {ok,[compiler,syntax_tools,uef,binbo]}

%% Start new process for the game:

{ok, Pid} = binbo:new_server(). {ok,<0.282.0>}

%% Set path to the remote engine as tuple {Host, Port, Timeout}:

EnginePath = {"localhost", 9010, 5000}. {"localhost",9010,5000}

%% Start new game in the process:

binbo:new_uci_game(Pid, #{engine_path => EnginePath}). {ok,continue}

%% UCI-over-TCP connection made, start playing:

binbo:uci_play(Pid, #{movetime => 100}, <<"e2e4">>). {ok,continue,<<"c7c5">>} % the engine's move was "c7c5"


== Interface

There are three steps to be done before making game moves:

. Start Binbo application. . Create process for the game. . Initialize game state in the process.

Note: process creation and game initialization are separated for the following reason: since Binbo is aimed to handle a number of concurrent games, the game process should be started as quick as possible leaving the http://erlang.org/doc/design_principles/sup_princ.html[supervisor] doing the

Related Skills

View on GitHub
GitHub Stars133
CategoryDevelopment
Updated28d ago
Forks16

Languages

Erlang

Security Score

100/100

Audited on Mar 3, 2026

No findings