Skip to content

matyalatte/reversi-core

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

reversi-core

Build Status, GitHub Actions License: MIT

About

reversi-core is a simple reversi library for C.
It's not the fastest library but fast enough for the monte carlo search.
It's not feature rich but sufficient for demo apps of libraries.

Requirements

  • A 64-bit processor
  • Meson for building

Documentation

Most of the functions are here.
reversi-core: RevBoard Struct Reference

Rest of them are here.
reversi-core: include/reversi.h File Reference

Building

Build Whole Project

meson setup build
meson compile -C build
meson test -C build

Build Library Only

meson setup build -Dexamples=false -Dtests=false
meson compile -C build

Build as Subproject

You don't need to clone the git repo if you build your project with meson.
Save the following text as subprojects/reversi.wrap.

[wrap-git]
url = https://github.com/matyalatte/reversi-core.git
revision = head
depth=1

[provide]
reversi = reversi_dep

Then, you can use reversi-core in your meson project.

reversi_dep = dependency('reversi', fallback : ['reversi', 'reversi_dep'])
executable('your_exe_name', ['your_code.cpp'], dependencies : [reversi_dep])
meson setup build -Dreversi:examples=false -Dreversi:tests=false
meson compile -C build

Examples

Initialization

int main() {
    // Create a new board
    RevBoard *board = revNewBoard();
    if (board == NULL) {
        printf("Failed to create a reversi board.\n");
        return 1;
    }

    // Need this if you use methods that require a random number generator.
    revInitGenRandom((unsigned)time(NULL));

    // do something to play reversi

    // Free a board
    revFreeBoard(board);
}

Bitboard to Array

You can get xy coordinates from bitboards.

// Get black disks
int *black_disks = revGetBitboardAsArray(board, DISK_BLACK);
for (int i = 0; i < revCountDisks(board, DISK_BLACK); i++) {
    int pos = black_disks[i];
    int x = pos % 8;
    int y = pos / 8;
    printf("disk%d: %d, %d", i, x, y);
}
free(black_disks);

// Get legal moves
int *mobility = revGetMobilityAsArray(board);
for (int i = 0; i < revGetMobilityCount(board); i++) {
    int pos = mobility[i];
    int x = pos % 8;
    int y = pos / 8;
    printf("move%d: %d, %d", i, x, y);
}
free(mobility);

Get a Disk

You can get a disk from a board.

// Get a disk at (4, 1)
RevDiskType disk_type = revGetDiskXY(board, 4, 1);
if (disk_type == DISK_BLACK) {
    // Black
} else if (disk_type == DISK_WHITE) {
    // White
} else {
    // Empty
}

Check a Move

You can check if a move is legal or not.

if (revIsLegalMoveXY(board, 4, 2)) {
    // (4, 2) is a legal move.
} else {
    // Illegal!
}

Execute a Move

// Set a disk to (2, 3) and get flipped disks
RevBitboard flipped = revMoveXY(board, 2, 3);
int *flipped_array = revBitboardToArray(flipped);
for (int i = 0; i < revCountOnes(flipped); i++) {
    int pos = flipped_array[i];
    int x = pos % 8;
    int y = pos / 8;
    printf("flipped%d: %d, %d", i, x, y);
}
free(flipped_array);

Generate a Move

You can use revGenMove*() to generate a move.

// Pick a move randomly.
int move = revGenMoveRandom(board);
printf("move: %d, %d\n", move % 8, move / 8);
revMove(board, move);

// Play 20000 games randomly and use the best move that has the highest win rate.
move = revGenMoveMonteCarlo(board, 20000);
printf("move: %d, %d\n", move % 8, move / 8);
revMove(board, move);

CLI App

Command-line app to play reversi.

#include <stdio.h>
#include <time.h>
#include "reversi.h"

int inputInt(const char* msg) {
    int x = -1;
    while ((x < 0) | (x >= 8)) {
        printf("%s", msg);
        scanf("%d", &x);
        fflush(stdin);
    }
    return x;
}

int main() {
    // Initialize
    RevBoard *board = revNewBoard();
    if (board == NULL) {
        printf("Failed to create a reversi board.\n");
        return 1;
    }
    revInitGenRandom((unsigned)time(NULL));

    // Iterate until no one can put disks.
    while (revHasLegalMoves(board)) {
        int move;
        if (revGetCurrentPlayer(board) == DISK_BLACK) {
            printf("Your turn.\n");
            revPrintBoardWithMobility(board);
            int x = -1;
            int y = -1;
            while ((x == -1) | !revIsLegalMoveXY(board, x, y)) {
                x = inputInt("x? ");
                y = inputInt("y? ");
            }
            move = revXYToPos(x, y);
        } else {
            // CPU uses the monte carlo search.
            printf("CPU's turn.\n");
            revPrintBoardWithMobility(board);
            // Finish 20000 games and use the best move that has the highest win rate.
            move = revGenMoveMonteCarlo(board, 20000);
        }

        printf("move: %d, %d\n\n", move % 8, move / 8);
        revMove(board, move);

        if (!revHasLegalMoves(board)) {
            // Pass
            revChangePlayer(board);
        }
    }

    RevDiskType winner = revGetWinner(board);
    if (winner == DISK_BLACK) {
        printf("You win!\n");
    } else if (winner == DISK_WHITE) {
        printf("You lose.\n");
    } else {
        printf("Draw.\n");
    }

    revFreeBoard(board);
    return 0;
}

GUI App

There is a GUI demo for reversi-core.
matyalatte/libui-reversi-demo: Demo app to play reversi using libui-ng and reversi-core

GUI app