Giter VIP home page Giter VIP logo

prologin / stechec2 Goto Github PK

View Code? Open in Web Editor NEW
15.0 30.0 10.0 2.05 MB

Client-server AI match maker used for the French national programming contest Prologin

Home Page: https://gitlab.com/prologin/tech/tools/stechec2

License: GNU General Public License v2.0

C++ 17.29% Makefile 0.85% Python 43.29% Shell 0.33% Ruby 21.56% TeX 0.50% Haskell 0.38% Java 0.80% C 0.88% C# 0.78% OCaml 0.47% PHP 0.46% Rust 0.45% Jinja 11.95%

stechec2's Introduction

Stechec2

https://travis-ci.org/prologin/stechec2.svg?branch=master

What is Stechec2

Stechec2 is a client-server turn-based strategy game match maker used during the French national computing contest. It is a complete rewrite of Stechec to achieve a simpler architecture.

Copying

Free use of this software is granted under the terms of the GNU General Public License version 2 (GPLv2). For details see the files COPYING included with the Stechec2 distribution.

Requirements

  • gcc >= 4.7
  • python
  • zeromq
  • zeromq C++ wrapper
  • google-gflags
  • googletest
  • gcovr (for code coverage reports)
  • python-yaml
  • python-jinja2
  • pkg-config

Arch Linux:

pacman --needed -S gcc zeromq gtest python-yaml python-jinja gflags gcovr

Debian:

apt-get install build-essential libzmq3-dev python3-yaml \
    python3-jinja2 libgtest-dev libgflags-dev gcovr pkg-config

Ubuntu:

apt-get install build-essential libzmq3-dev libzmqpp-dev python3-yaml \
    python3-jinja2 libgtest-dev libgflags-dev gcovr pkg-config

Installation

Let's assume you want to install stechec2 with all the Prologin games, and then use it as a player.

Clone the stechec2 repository:

git clone https://github.com/prologin/stechec2
cd stechec2

Then put every game you want to install in games/:

for game in prologin{2012..2016}; do
  git clone https://github.com/prologin/${game}.git games/$game
done

A simple test game, tictactoe, is already installed in games/.

You can then configure the project using waf, while specifying the games you want to use:

./waf.py configure --with-games=tictactoe,prologin2016 --prefix=/usr

Then build and install it:

./waf.py build install

Archlinux: A PKGBUILD is available in pkg/stechec2: run makepkg && pacman -U stechec2-*.pkg.tar.xz.

Generate the player environment

To generate the player environment (different folders for each supported languages), you can use the stechec2-generator script installed by stechec2:

stechec2-generator player tictactoe player_env

Install languages dependencies

Requirements:

  • php (warning: you may need to add open_basedir=/ to your /etc/php/php.ini)
  • php-embed
  • ocaml
  • mono
  • jdk-java
  • ghc
  • rustc
  • python-dev

Archlinux:

pacman --needed -S php php-embed ocaml mono jdk11-openjdk ghc rust

Debian/Ubuntu:

apt-get install php-cli php-dev libphp-embed ocaml mono-devel ghc \
                openjdk-11-jdk rustc python3-dev

Create your AI

You should now be able to choose your favorite language folder and begin to code:

cd player_env/python/
$EDITOR prologin.py
make

To create a tarball containing all your source files (you can add some by editing the Makefile), do:

make tar

Launch a match

To launch a match, you need to launch a stechec2-server and one stechec2-client per player. There is a wrapper called stechec2-run which runs everything you need in separate child processes, and only needs a tiny YAML configuration file to work.

A simple config.yml could be:

rules: /usr/lib/libtictactoe.so
map: ./simple.map
verbose: 3
clients:
  - ./champion.so
  - /path/to/other/champion.so
names:
  - Player 1
  - Player 2

Then you can just launch the match easily:

stechec2-run config.yml

Add spectators

Spectators are players that don't take part of the game, but can watch its different states during the match (to display it or to log it, for instance).

Make sure to compile your spectator first:

cd /path/to/prologin2014/gui
make

Then you just have to add those lines to the config.yml:

spectators:
 - /path/to/prologin2014/gui/gui.so

stechec2's People

Contributors

alarsyo avatar art-w avatar audebert avatar coucou747 avatar cri-epita avatar delroth avatar dettorer avatar ejls avatar fardalem avatar gabriel-duque avatar haltode avatar jicks avatar leseulartichaut avatar lportemo avatar magicking avatar malojaffre avatar melyodas avatar multun avatar nguyentito avatar pguenezan avatar pmderodat avatar rafaelbocquet avatar remi-dupre avatar rissson avatar seirl avatar seirll avatar shaac avatar zopieux avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

stechec2's Issues

Generators: language detection shouldn't be done with the folder name

Originally posted 2014-05-11 17:59 by serialk on Bitbucket

A lot of contestants were faced to bugs of inexistant Makefiles when submitting their champions to the server.
Currently, the process of language detection is:

  • When doing make tar, a '_lang' file is created containing the name of the language (which is the name of the folder), and then deleted
  • On the server-side, the _lang file is read and Makefile-$LANG is called

If a contestant changes the folder name:

  • make tar does silently the wrong thing (puts a random name in _lang)
  • The server complains about inexistant Makefile-randomname and compilation fails.

A fix would be:

  • the generators create a hidden .stechec_lang file at the creation of the folders (and doesn't depend of the folder name)
  • make tar adds this file to the archive without deleting it, and complains if it is inexistant or has been modified
  • the server-side compile-champion.sh checks if the file is present in the archive and that the language is correct and the makefile exists

Fix C# generator

Originally posted 2012-05-09 19:28 by prologin on Bitbucket

C# generator seems to segfault due to the new sandbox using threads.

Generate a position.hh file

Each year, a position.hh file for the rules implementation is written again.
It is almost the same every year.

The best way to do this is probably something in the like of stechec2-generator helpers that could detect in the yaml that there is a position struct (a struct, named position, which is a tuple), and generate a position.hh that the people implementing the rules could use.

If it where a C++ macro, it would be:

#define DECLARE_POS(name, x, maxX, y, maxY)                              \
    constexpr inline bool operator==(const name& lhs, const name& rhs) { \
        return lhs.x == rhs.x && lhs.y == rhs.y;                         \
    }                                                                    \
    constexpr inline bool operator!=(const name& lhs, const name& rhs) { \
        return lhs.x != rhs.x || lhs.y != rhs.y;                         \
    }                                                                    \
    constexpr inline bool operator<(const name& lhs, const name& rhs) {  \
        return lhs.x < rhs.x && lhs.y < rhs.y;                           \
    }                                                                    \
    constexpr inline bool operator<=(const name& lhs, const name& rhs) { \
        return lhs.x <= rhs.x && lhs.y <= rhs.y;                         \
    }                                                                    \
    constexpr inline bool operator>(const name& lhs, const name& rhs) {  \
        return lhs.x > rhs.x && lhs.y > rhs.y;                           \
    }                                                                    \
    constexpr inline bool operator>=(const name& lhs, const name& rhs) { \
        return lhs.x >= rhs.x && lhs.y >= rhs.y;                         \
    }                                                                    \
    constexpr inline name operator+(const name& lhs, const name& rhs) {  \
        return name{lhs.x + rhs.x, lhs.y + rhs.y};                  \
    }                                                                    \
    constexpr inline name& operator+=(name& lhs, const name& rhs) {      \
        lhs.x += rhs.x;                                                  \
        lhs.y += rhs.y;                                                  \
        return lhs;                                                      \
    }                                                                    \
    constexpr inline name operator-(const name& lhs, const name& rhs) {  \
        return name{lhs.x - rhs.x, lhs.y - rhs.y};                  \
    }                                                                    \
    constexpr inline name& operator-=(name& lhs, const name& rhs) {      \
        lhs.x -= rhs.x;                                                  \
        lhs.y -= rhs.y;                                                  \
        return lhs;                                                      \
    }                                                                    \
    constexpr inline name operator-(const name& pos) {                   \
        return name{-pos.x, -pos.y};                                \
    }                                                                    \
    constexpr inline int manhanttan_distance(const name& lhs,            \
                                             const name& rhs) {          \
        /* Can not use std::abs here since it is not constexpr */        \
        return (lhs.x > rhs.x ? lhs.x - rhs.x : rhs.x - lhs.x) +         \
               (lhs.y > rhs.y ? lhs.y - rhs.y : rhs.y - lhs.y);          \
    }                                                                    \
    constexpr inline bool is_inside(const name& pos) {                   \
        return pos.x >= 0 && pos.y >= 0 && pos.x < maxX && pos.y < maxY; \
    }                                                                    \
    constexpr inline bool next_to(const name& lhs, const name& rhs) {    \
        int dx = lhs.x - rhs.x;                                          \
        int dy = lhs.y - rhs.y;                                          \
        return ((dx == -1 || dx == 1) && dy == 0) ||                     \
               ((dy == -1 || dy == 1) && dx == 0);                       \
    }

High level error interfaces

In Rust, it is idiomatic to use the Result type to propagate errors. I don't know many other high level languages but I guess some of them also have convenient built-in structures that we could use.

In Rust this would mean wrapping any type that can represent an error inside a Result<_, _> .

To illustrate the example in Rust, we currently generate this kind of API:

enum Error {
    AnError,
    OtherError,
    Ok,
}

enum Something {
    Result1,
    Result2,
    ErrorSomething,
}

fn action(...) -> Error { ... }
fn get_something(...) -> Something { ... }

Ideally, it would be nice to generate something like that:

enum Error {
    AnError,
    OtherError,
}

enum Something {
    Result1,
    Result2,
}

fn action(...) -> Result<(), Error> { ... }

// We probably don't want to do that as it would require to make
// the interface more complex for some languages.
fn get_something(...) -> Result<Something, Error> { ... }
// or
fn get_something(...) -> Result<Something, ()> { ... }

Implement generic loops

Originally posted 2013-03-24 11:00 by serialk on Bitbucket

Reimplement server_loop, client_loop and spectator_loop for each game is redundant and could be generic in stechec2

Signal handling is broken

Originally posted 2015-11-29 01:10 by serialk on Bitbucket

In src/lib/net/signal.cc:

  • handle_signals() doesn't work
  • sigs is unused
  • It is unclear what is exactly supposed to happen when receiving these signals
  • handle_signals is never even called.
  • signal.hh is never even included!

Allow the rules to export stats of the games

It would be cool if the rules had a way to export in their result some infos like:

  • Number of turns
  • Number of {action} done by each participant
  • ...

This would allow us to show cool stats to the contestants, like:

  • Shortest match
  • Match with the greatest number of {action}
  • ...

Get rid of the pub/sub socket

The pub/sub socket type from ZMQ makes the assumption that it's ok for subscribers to miss a few updates from the publisher and does not make sure they receive everything, it's a tradeoff for scalability.

This is why clients sometimes hang in the middle of a game (and more frequently at the beginning), they are actually missing an update on the pub/sub socket, for example because they started to listen on the socket just after the server sent its update.

I suggest replacing the pub/sub socket with one req/rep per client and changing the following commandline options:

client:

  • keep --req_addr addr
  • change --sub_addr addr to --rep_addr addr

server:

  • keep --rep_addr addr
  • change --pub_addr addr to --req_addrs client1,client2,...

Struct arguments for API functions don't work in some cases (name collisions)

Originally posted 2015-04-22 05:24 by nguyentito on Bitbucket

That case being when a function has both an argument of type X and an argument named X (possibly, but not necessarily, the same argument).

This seems to be related to template expansion rules.

Suggested fix: detect and reject this case in the generator script.

Steps to reproduce the bug:

  • run generator player on the attached YAML file
  • enter the c/ directory
  • run make
  • get the error given in the attachment

Note: for some reason, running make in cxx/ doesn't fail on the foobarology_fail1 function, whereas it does in c/.

Upgrade waf to python3

Originally posted 2014-05-02 21:30 by halfr on Bitbucket

It currently depends on python2, and fails on loading unitttest_gtest:

Traceback (most recent call last):
  File "/usr/lib/waf/.waf3-1.7.15-af648a117ce281087d8735a3803e0ebf/waflib/Scripting.py", line 97, in waf_entry_point
    run_commands()
  File "/usr/lib/waf/.waf3-1.7.15-af648a117ce281087d8735a3803e0ebf/waflib/Scripting.py", line 149, in run_commands
    parse_options()
  File "/usr/lib/waf/.waf3-1.7.15-af648a117ce281087d8735a3803e0ebf/waflib/Scripting.py", line 127, in parse_options
    Context.create_context('options').execute()
  File "/usr/lib/waf/.waf3-1.7.15-af648a117ce281087d8735a3803e0ebf/waflib/Options.py", line 134, in execute
    super(OptionsContext,self).execute()
  File "/usr/lib/waf/.waf3-1.7.15-af648a117ce281087d8735a3803e0ebf/waflib/Context.py", line 84, in execute
    self.recurse([os.path.dirname(g_module.root_path)])
  File "/usr/lib/waf/.waf3-1.7.15-af648a117ce281087d8735a3803e0ebf/waflib/Context.py", line 125, in recurse
    user_function(self)
  File "/root/stechec2/wscript", line 18, in options
    opt.load('unittest_gtest')
  File "/usr/lib/waf/.waf3-1.7.15-af648a117ce281087d8735a3803e0ebf/waflib/Context.py", line 78, in load
    module=load_tool(t,path)
  File "/usr/lib/waf/.waf3-1.7.15-af648a117ce281087d8735a3803e0ebf/waflib/Context.py", line 313, in load_tool
    __import__(d)
TypeError: source code string cannot contain null bytes

waf.py does not work with python3.5

Originally posted 2015-11-09 10:18 by choclate on Bitbucket

Hello got this error with python3.5:

[choclate@choclate stechec2]$ ./waf.py configure --with-games=tictactoe --prefix=/usr
Setting top to                           : /home/choclate/documents/projects/python/stechec2 
Setting out to                           : /home/choclate/documents/projects/python/stechec2/build 
Checking for 'g++' (c++ compiler)        : /usr/lib/hardening-wrapper/bin/g++ 
Unpacking gtest                          : yes 
Traceback (most recent call last):
  File "/home/choclate/documents/projects/python/stechec2/.waf3-1.6.11-aa92258099202450c3af4004c606f61b/waflib/Scripting.py", line 97, in waf_entry_point
    run_commands()
  File "/home/choclate/documents/projects/python/stechec2/.waf3-1.6.11-aa92258099202450c3af4004c606f61b/waflib/Scripting.py", line 151, in run_commands
    run_command(cmd_name)
  File "/home/choclate/documents/projects/python/stechec2/.waf3-1.6.11-aa92258099202450c3af4004c606f61b/waflib/Scripting.py", line 143, in run_command
    ctx.execute()
  File "/home/choclate/documents/projects/python/stechec2/.waf3-1.6.11-aa92258099202450c3af4004c606f61b/waflib/Configure.py", line 128, in execute
    super(ConfigurationContext,self).execute()
  File "/home/choclate/documents/projects/python/stechec2/.waf3-1.6.11-aa92258099202450c3af4004c606f61b/waflib/Context.py", line 87, in execute
    self.recurse([os.path.dirname(g_module.root_path)])
  File "/home/choclate/documents/projects/python/stechec2/.waf3-1.6.11-aa92258099202450c3af4004c606f61b/waflib/Context.py", line 128, in recurse
    user_function(self)
  File "/home/choclate/documents/projects/python/stechec2/wscript", line 36, in configure
    conf.load('unittest_gtest')
  File "/home/choclate/documents/projects/python/stechec2/.waf3-1.6.11-aa92258099202450c3af4004c606f61b/waflib/Configure.py", line 190, in load
    if type(func)is type(Utils.readf):func(self)
  File "./tools/waf/unittest_gtest.py", line 107, in configure
    conf.check_cxx(lib = 'pthread', uselib_store = 'GTEST_PTHREAD')
  File "/home/choclate/documents/projects/python/stechec2/.waf3-1.6.11-aa92258099202450c3af4004c606f61b/waflib/Configure.py", line 221, in fun
    return f(*k,**kw)
  File "/home/choclate/documents/projects/python/stechec2/.waf3-1.6.11-aa92258099202450c3af4004c606f61b/waflib/Tools/c_config.py", line 458, in check_cxx
    return self.check(*k,**kw)
  File "/home/choclate/documents/projects/python/stechec2/.waf3-1.6.11-aa92258099202450c3af4004c606f61b/waflib/Configure.py", line 221, in fun
    return f(*k,**kw)
  File "/home/choclate/documents/projects/python/stechec2/.waf3-1.6.11-aa92258099202450c3af4004c606f61b/waflib/Tools/c_config.py", line 366, in check
    ret=self.run_c_code(*k,**kw)
  File "/home/choclate/documents/projects/python/stechec2/.waf3-1.6.11-aa92258099202450c3af4004c606f61b/waflib/Configure.py", line 221, in fun
    return f(*k,**kw)
  File "/home/choclate/documents/projects/python/stechec2/.waf3-1.6.11-aa92258099202450c3af4004c606f61b/waflib/Tools/c_config.py", line 445, in run_c_code
    bld.compile()
  File "/home/choclate/documents/projects/python/stechec2/.waf3-1.6.11-aa92258099202450c3af4004c606f61b/waflib/Build.py", line 188, in compile
    self.store()
  File "/home/choclate/documents/projects/python/stechec2/.waf3-1.6.11-aa92258099202450c3af4004c606f61b/waflib/Utils.py", line 310, in f
    ret=fun(*k,**kw)
  File "/home/choclate/documents/projects/python/stechec2/.waf3-1.6.11-aa92258099202450c3af4004c606f61b/waflib/Build.py", line 162, in store
    cPickle.dump(data,f)
AttributeError: Can't pickle local object 'Context.__init__.<locals>.node_class'
Checking for library pthread             : 

It works with python3.4 waf.py configure --with-games=tictactoe --prefix=/us.

Simplify use at home

Stechec works fine in the context of Prologin’s final. But what of the people who want to code a champion at home? If someday we manage to finally host a contest website with old final games, people who want to participate will still need to install stechec, bundled with the specific game. The installation is not so easy on linux, probably not possible on windows…

And even once everything is installed, there are many generated files. For instance, a python developer would only code in a single python file, but still have the interface.cc file, a complicated makefile. Maybe all of this is not necessary

There should be some way to provide some kind of SDK, so that someone who want to code a champion, has little thing to do to start coding, and then generate a .so to upload to the website.
There is no need for the user to even download the complete rules. Just to have the interface.hh, and the wrapper for any chosen language. Something simple to be able to develop a champion at home without any kind of complicated installation.

Fix PHP generator

Originally posted 2012-05-09 19:29 by prologin on Bitbucket

Apparently PHP does not work. To investigate.

Generate more functions in `rules.{cc,hh}`

The functions in the user_function section of the YAML file should be automatically generated as class members of Rules and filled in the object by the constructor in the generated code.

spectators are not working

Originally posted 2016-02-17 10:14 by choclate on Bitbucket

I tried to spectate a prologin2013 and a prologin2015 game, but it does not seem to work.

I got a result when using stechec2-run config.yml without spectators.

With the dumper, I have no dump.json
With the gui, I got a black screen and nothing is happening.

Here is my config file:

rules: /usr/lib/libprologin2015.so
map: ../maps/map_52.txt
verbose: 1
clients:
    - ./caml_dummy_ai/champion.so
    - ./hs/champion.so
spectators:
    - ../spectators/dumper/dumper.so

Generators: JAVA_HOME is not set server side

Originally posted 2014-05-11 17:49 by serialk on Bitbucket

When worker nodes are used as a systemd service, they don't source /etc/profile before being run, so $JAVA_HOME is not set and the server makefiles don't work. We should find a way to handle this properly.

Master node should check the worker hostname

Originally posted 2012-05-10 11:38 by delroth on Bitbucket

Currently the master node accepts workers even when their hostname are not resolving propetly, causing problems when it has to send them tasks later. These workers should be refused directly when they announce themselves to the master node.

Alternatively, use something else than the hostname to handle this (remote IP).

Match dump circuitry

Originally posted 2013-03-29 20:40 by pmderodat on Bitbucket

Each year, mechanisms are re-implemented for dumping the game state at each turn for matches. As far as I know, this is done by:

  • implementing a “dump_game_state”-like function that returns a C string containing a JSON representation of the game state
  • creating a spectator that puts one JSON game state per turn in one line each in a text file
  • configure everything so the spectator produce the match dump as expected.

The “dump_game_state” part is very rules-specific: one could implement generic serializers for data structures like arrays, matrices and records, like using the Buffer protocol. But generally:

  • the JSON dump do not map physical rules data structures: JSON cells in maps can directly contain units, whereas units may be located in a dedicated data structure in C++ rules, for instance
  • the Buffer protocol is handy when both ends use the same code for buffer handlers (most of the time, a client serialize an action with the Action::handle_buffer method, and the server unpack it with the same method), but this is no longer relevant for match dumps: they are generated by rules code, but they are decoded mostly by the Python graphical viewer, so decoding code has to be written twice in two different languages.
  • dumping a game state in JSON is quite easy and implementing can be done quickly: no more than 4 hours, testing included :-)

So, it would be nice to include an option or a configuration entry somewhere in the stechec server, for example, to dump a match easily without having to write/configure a dedicated spectator for that. Rules should only have to provide the “dump_game_state” function, the rest would be the same every year and thus could be integrated to stechec2.

Thanks in advance!

JNI seems to fail with OpenJDK >=7

Originally posted 2015-10-13 12:11 by serialk on Bitbucket

Happened during the 2015 finals, but cannot be reproduced easily in the unit tests. Needs to be more extensively investigated.

Namespace the generated rules

We should generate the rules under any kind of namespace (cannot be rules, because there is already a rules::Api and we generate a Api class). Could be prolo, or even the name in the input yaml.

I’ve seen several time someone code a C++ champion, and struggling to understand why his program does not link/behaves strangely, because the champion also contains a Gamestate class.

Clean the current code

Originally posted 2012-05-09 19:27 by prologin on Bitbucket

There are lots of ugly things currently in the codebase due to the fact that Stechec 2 was written in a rush.

Recode all the generators in Jinja

Misc generators

Champions

Other

Minor issues

  • Inline api.h in the C API so that the interface.cc is self-sufficient for languages that depend on it
  • Load the correct cst_type directly when loading the constants in game.py instead of having to call a helper (#114)
  • Load the afficher_* functions (with a special attribute like fct_display: true so that we can filter them out if necessary) (#113)
  • Filter out reserved language keywords while loading the YAML (#109)

Add instructions for makepkg

Originally posted 2015-05-23 19:02 by emersion on Bitbucket

Another install method is:

#!bash
cd pkg/stechec2
makepkg
pacman -U stechec2-XXX.pkg.tar.xz

This should be documented in README.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.