Skip to content

Commit

Permalink
AiCups #4
Browse files Browse the repository at this point in the history
  • Loading branch information
Kislenko Maksim committed Jul 18, 2019
1 parent 9313d95 commit 0ca4153
Show file tree
Hide file tree
Showing 67 changed files with 37,204 additions and 0 deletions.
60 changes: 60 additions & 0 deletions paperio/QUICKSTART.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
## Быстрый старт

## Установка необходимых пакетов

Если у вас не установлен `Python`, то вам нужно будет установить `Python` >= `3.6` вместе с требованиями по пакетам, описанными в `requirements.txt`.

Для того чтобы установить из списка **requirements** пакеты, вам понадобится менеджер пакетов Pip и виртуальное окружение **virtualenv**. Подробная инструкция установки - [здесь](https://packaging.python.org/guides/installing-using-pip-and-virtualenv/).

Если у вас уже все установлено, то переходим к настройке окружения.

1. **Создаем виртуальное окружение**
```$ virtualenv <название_окружения>```
Название окружения может быть любым.

2. **Активируем созданное виртуальное окружение**
```$ source <название_окружения>/bin/activate```

3. **Устанавливаем все зависимости из requirements.txt**
```$ pip install -r requirements.txt```

После всех установленных пакетов, чтобы запустить **Local Runner**, необходимо перейти в папку с файлом **localrunner.py** и исполнить команду

```$ python3 localrunner.py```

У вас должен запуститься визуализатор. Поздравляем!

**Внимание!** Подробнее про работу с LocalRunner вы можете прочитать в [правилах](README.md) в разделе [3](README.md#3-особенности-запуска-local-runner).

## Загрузка решения на сайт
Для примера возьмем решение, написанное на Python:

```python
import json
import random

config = input() # получение конфигурации игры

while True:
state = input() # получение тика
commands = ['left', 'right', 'up', 'down'] # доступные команды
cmd = random.choice(commands) # случайный выбор действия
print(json.dumps({"command": cmd, 'debug': cmd}) # отправка результата
```

* Сохраняем данное решение как main.py;
* Переходим на [сайт](https://aicups.ru/profile/);
* Нажимаем на кнопку `Отправить решение`;
* Выбираем язык `Python 3.6` и решение;
* Нажимаем `Отправить`.

Ваше решение отправится в тестирующую систему. При возникновении каких-либо ошибок в синтаксисе и других ошибках, система вам об этом сообщит.

После этого вам необходимо на [этой](https://aicups.ru/profile/#solutions) же странице выбрать решение, которое будет участвовать в рейтинговых и нерейтинговых играх.

На этом все! Теперь можно сыграть с кем-либо, нажав на кнопку `Играть`.

Мы обязательно рекомендуем вам прочитать [правила](README.md).

Желаем удачи!

201 changes: 201 additions & 0 deletions paperio/README.md

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions paperio/dockers/base/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
FROM ubuntu:16.04
MAINTAINER Kislenko Maksim <[email protected]>

ENV MOUNT_POINT=/opt/client/code
ENV SOLUTION_CODE_PATH=/opt/client/solution

RUN apt-get update && \
apt-get install -y unzip curl software-properties-common language-pack-en-base build-essential qt5-default python && \
apt-get clean && \
apt-get autoclean && \
apt-get autoremove

WORKDIR /opt/client
COPY ./sources ./
RUN qmake ./client.pro -r CONFIG+=x86_64 && make && rm -f Makefile client.pro constants.h main.cpp main.o moc_tcp_client.cpp moc_tcp_client.o tcp_client.h
RUN mkdir /opt/client/solution && chmod 777 /opt/client/solution

CMD ["bash", "run.sh"]
20 changes: 20 additions & 0 deletions paperio/dockers/base/sources/client.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
QT += core network
QT -= gui

CONFIG += c++11 warn_off

TARGET = client
CONFIG += console
CONFIG -= app_bundle

TEMPLATE = app

SOURCES += main.cpp

DISTFILES += \
../Dockerfile \
run.sh

HEADERS += \
tcp_client.h \
constants.h
11 changes: 11 additions & 0 deletions paperio/dockers/base/sources/compile_output_processor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import sys
import json
data = sys.stdin.readlines()
strings = []
for s in data:
try:
string = unicode(s)
except UnicodeDecodeError:
string = "Can't parse string\n"
strings.append(string)
print json.dumps(''.join(strings)[:100000])
13 changes: 13 additions & 0 deletions paperio/dockers/base/sources/constants.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef CONSTANTS_H
#define CONSTANTS_H

#include <QVector>
#include <QString>
#include <QDebug>
#include <QByteArray>

const int PORT = 8000;
const int MAX_RESP_LEN = 10000;


#endif // CONSTANTS_H
85 changes: 85 additions & 0 deletions paperio/dockers/base/sources/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#include "tcp_client.h"

#include <QProcessEnvironment>
#include <QCoreApplication>

#include <cstdlib>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>


int lookup_host(const char* host, char* addrstr) {
struct addrinfo hints, *res;
int errcode;
void *ptr;

memset(&hints, 0, sizeof (hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags |= AI_CANONNAME;

errcode = getaddrinfo(host, NULL, &hints, &res);
if (errcode != 0) {
return -1;
}
printf("Host: %s\n", host);
while (res) {
inet_ntop(res->ai_family, res->ai_addr->sa_data, addrstr, 100);

switch (res->ai_family) {
case AF_INET:
ptr = &((struct sockaddr_in *) res->ai_addr)->sin_addr;
break;
case AF_INET6:
ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
break;
}
inet_ntop(res->ai_family, ptr, addrstr, 100);
printf("IPv%d address: %s (%s)\n", res->ai_family == PF_INET6 ? 6 : 4, addrstr, res->ai_canonname);
res = res->ai_next;
}
return 0;
}


int main(int argc, char *argv[]) {
if (argc < 3) {
qDebug() << "Usage: ./client <abs path to run.sh> <work_dir for run.sh>";
return 0;
}
QString exec_path = argv[1];
QString work_dir = argv[2];

QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
QString solution_id = env.value("SOLUTION_ID");
if (solution_id == "") {
qDebug() << "solution_id must be specified!";
return 0;
}

QString HOST = "127.0.0.1";
QString env_value = env.value("WORLD_NAME");
char host_ip[100];
if (lookup_host(env_value.toStdString().c_str(), host_ip) == 0) {
HOST = QString(host_ip);
}
else {
qDebug() << "Can't determine host";
}
int PORT = 8000;

QCoreApplication a(argc, argv);
TcpClient client(HOST, PORT, solution_id.toInt(), exec_path, work_dir);
qDebug() << "Sleeping (5 secs)...";
sleep(5);

qDebug() << "Starting client...";
client.start();

QObject::connect(&client, SIGNAL(finished()), &a,SLOT(quit()));
return a.exec();
}
26 changes: 26 additions & 0 deletions paperio/dockers/base/sources/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env bash
COP_PATH="$(pwd)/compile_output_processor.py"

if [ "$ZIPPED" = True ]; then
yes | unzip -n $MOUNT_POINT -d $SOLUTION_CODE_PATH
else
yes | cp $MOUNT_POINT $SOLUTION_CODE_PATH/$SOLUTION_CODE_ENTRYPOINT
fi

if [ "$COMPILE" = True ]; then
STATUS="ok"
MESSAGE="compilation done"
FILE_PATH=$COMPILED_FILE_PATH

ERRORS="$(eval $COMPILATION_COMMAND)"

if [ $? -ne 0 ]; then
STATUS="error"
FILE_PATH=""
MESSAGE="$ERRORS"
fi
echo "{\"status\": \"$STATUS\",\"message\": `echo "$MESSAGE" | python $COP_PATH`,\"path_to_compiled_file\": \"$FILE_PATH\"}" > $COMPILE_LOG_LOCATION

else
./client "$(eval echo $RUN_COMMAND)" $SOLUTION_CODE_PATH
fi
135 changes: 135 additions & 0 deletions paperio/dockers/base/sources/tcp_client.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
#ifndef TCP_CLIENT_H
#define TCP_CLIENT_H

#include "constants.h"
#include <unistd.h>

#include <QTcpSocket>
#include <QProcess>
#include <QFile>
#include <QJsonObject>
#include <QJsonValue>
#include <QJsonDocument>


class TcpClient : public QObject
{
Q_OBJECT

private:
QTcpSocket *socket;
QString host;
int port;
int solution_id;
bool first_read;

QString solution_run;
QProcess *solution;

signals:
void finished();

public:
TcpClient(const QString& _host, int _port, int _solution_id, QString exec, QString work_dir) :
host(_host),
port(_port),
solution_id(_solution_id),
first_read(true)
{
socket = new QTcpSocket(this);
solution = new QProcess(this);
solution->setWorkingDirectory(work_dir);

solution_run = exec;
// QFile run_file;
// run_file.setFileName(exec);
// if (run_file.open(QFile::ReadOnly)) {
// solution_run = QString(run_file.readAll());
// }
// run_file.close();
}

virtual ~TcpClient() {
if (socket) delete socket;
if (solution) delete solution;
}

void start() {
connect(socket, SIGNAL(connected()), SLOT(on_connected()));
connect(socket, SIGNAL(readyRead()), SLOT(on_ready_read()));
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(on_error(QAbstractSocket::SocketError)));

connect(solution, SIGNAL(readyReadStandardOutput()), SLOT(on_solution_out()));
connect(solution, SIGNAL(readyReadStandardError()), SLOT(on_solution_error()));
connect(solution, SIGNAL(finished(int)), SLOT(on_solution_finished(int)));
socket->connectToHost(host, port);
}

private slots:
void on_connected() {
QString greeting = "{\"solution_id\": \"" + QString::number(solution_id) + "\"}\n";
int sent = socket->write(greeting.toStdString().c_str());
if (sent == -1) {
qDebug() << "Can not send solution_id";
}
}

void on_ready_read() {
QByteArray &&data = socket->readLine(0);
qDebug() << data;
// qDebug() << "Data:" << data;
if (first_read) {
solution->start(solution_run);
first_read = false;
}
int written = solution->write(data);
// qDebug() << "Written" << written;
if (written == -1) {
qDebug() << "Can not write to solution";
}
}

void on_error(QAbstractSocket::SocketError error) {
qDebug() << "Socket error:" << error;
solution->close();
socket->disconnectFromHost();
emit finished();
}

public slots:
void on_solution_out() {
QByteArray &&cmd = solution->readLine(MAX_RESP_LEN);
// qDebug() << cmd;

int sent = socket->write(cmd);
if (sent == -1) {
qDebug() << "Can not send command";
}
}

void on_solution_error() {
QByteArray error = solution->readAllStandardError();
qDebug() << "Error:" << error;

QJsonObject jsonError;
jsonError.insert("error", QJsonValue(QString(error)));
QJsonDocument jsonDoc(jsonError);
QString cmd = QString(jsonDoc.toJson(QJsonDocument::Compact)) + "\n";

int sent = socket->write(cmd.toStdString().c_str());
if (sent == -1) {
qDebug() << "Can not send error";
}
}

void on_solution_finished(int code) {
qDebug() << "Solution finished: code" << code;
sleep(5);
socket->disconnectFromHost();
emit finished();
}
};



#endif // TCP_CLIENT_H
18 changes: 18 additions & 0 deletions paperio/dockers/c_sharp/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
FROM stest.tech-mail.ru/aicups/paperio_base
MAINTAINER Boris Kolganov <[email protected]>

ENV MONO_GC_PARAMS max-heap-size=256M

ENV SOLUTION_CODE_ENTRYPOINT=main.cs
ENV COMPILED_FILE_PATH=/opt/client/csharpStrategy
ENV COMPILATION_COMMAND='csc /unsafe /reference:Newtonsoft.Json.dll `find $SOLUTION_CODE_PATH -name "*.cs"` -out:$COMPILED_FILE_PATH'
ENV RUN_COMMAND='mono $MOUNT_POINT'

RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
RUN echo "deb http://download.mono-project.com/repo/ubuntu stable-trusty main" > /etc/apt/sources.list.d/mono-official-stable.list && \
apt-get update && \
apt-get install -y mono-complete zip && \
rm -rf /var/lib/apt/lists/* /tmp/* && \
export MONO_GC_PARAMS=max-heap-size=256M

COPY Newtonsoft.Json.dll ./
Loading

0 comments on commit 0ca4153

Please sign in to comment.