1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
#include <cassert>
#include <cstdlib>
#include <iostream>
#include <link.h>
#include <unistd.h>
#include "NimMove.hpp"
#include "NimGame.hpp"
#include "NimPlayer.hpp"

typedef NimPlayer* NimPlayerConstructor();

NimPlayer*
load_player(char* name)
{
    std::string path("./"); // look in current directory
    path += name;
    path += ".so"// add suffix
    void* handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
    if (!handle) {
        return nullptr;
    }
    NimPlayerConstructor* constructor = (NimPlayerConstructor*)
                                        dlsym(handle, "construct");
    if (!constructor) {
        dlclose(handle);
        return nullptr;
    }
    return constructor();
}

int
main(int argc, char **argv)
{
    if (argc!=3) {
        std::cerr << "usage: " << argv[0] << " player1 player2" << std::endl;
        return 1;
    }
    NimPlayer* player[2] = { load_player(argv[1]), load_player(argv[2])};
    if (!player[0] || !player[1]) {
        std::cerr << "Loading players failed!" << std::endl;
        return 2;
    }


    std::cout << "*** Game of Nim ***" << std::endl;

    // read parameters of the game
    unsigned int number_of_heaps;
    std::cout << "Number of heaps: ";
    if (!(std::cin >> number_of_heaps) || number_of_heaps == 0) {
        std::cout << "Bye!" << std::endl;
        return 1;
    }
    unsigned int maxtake;
    std::cout << "Maximal number of sticks that can be taken in one move: ";
    if (!(std::cin >> maxtake)) {
        std::cout << "Bye!" << std::endl;
        return 1;
    }

    // seed pseudo random generator
    srand(getpid() ^ time(0));
    // setup game
    NimGame game(number_of_heaps, maxtake);
    unsigned int minsize; unsigned int maxsize;
    if (maxtake) {
        minsize = maxtake * 2; maxsize = maxtake * 4;
    } else {
        minsize = 1; maxsize = 7;
    }
    unsigned int range = maxsize - minsize + 1;
    for (unsigned int i = 0; i < number_of_heaps; ++i) {
        game.set_heap_size(i, rand() % range + minsize);
    }

    while (!game.finished()) {
        // print current state
        std::cout << "Heaps:";
        for (unsigned int i = 0; i < number_of_heaps; ++i) {
            std::cout << " " << game.get_heap_size(i);
        }
        std::cout << std::endl;

        NimPlayer* next_player = player[game.get_next_player()];
        NimMove    move        = next_player->get_move(game);

        std::cout << next_player->get_name();
        if (move.has_resigned()) {
            std::cout << " resigns." << std::endl;
        } else {
            std::cout << " takes " << move.get_count() << " from heap "
                      << move.get_heap() << std::endl;
        }
        game.execute_move(move);
    }
    NimPlayer* winner = player[game.winner()];
    std::cout << winner->get_name() << " has won!" << std::endl;
}