[Atcoder] [C ++] J'ai fait un outil d'automatisation de test qui peut être utilisé pendant le concours

Je fais Atcoder (programmation de compétition) comme passe-temps, mais cela a été lent récemment. J'ai pensé que ce serait bien d'automatiser le travail de test pendant le concours, J'ai créé un outil d'automatisation de test avec python.

introduction

Voici quelques-uns des outils les plus polyvalents que ceux que j'ai présentés dans cet article.

Veuillez également comparer ce qui précède lors de son utilisation.

1. Ce qui a été réalisé

Code source https://github.com/tks3210/autoJudge

Environnement d'exploitation

2. Exemple de fonctionnement

2.1 Test automatisé

>python autojudge.py [contest_name] [quest] Si vous spécifiez le nom du concours (abc143) et le nom de la question (abc143_a) comme indiqué dans ↑, Il se construit automatiquement, obtient des échantillons de données d'entrée / sortie et les teste. J'ai également essayé de créer une atmosphère avec la famille d'origine. AC__.png Les trois cas de test ci-dessus sont https://atcoder.jp/contests/abc143/tasks/abc143_a Il est automatiquement obtenu à partir de l'exemple d'entrée et de l'exemple de sortie de.

Je ne peux pas déranger le serveur d'Atcoder avec mes propres tests, donc L'accès est une fois pour chaque problème. (Le cas de test acquis est enregistré localement afin qu'il soit référencé dans les tests suivants et suivants.)

2.2 Faux positif

Lorsque vous écrivez le mauvais code, cela vous dira que c'est faux.

** En cas de WA (mauvaise réponse) ** WA__.png ** En cas de TLE (temps de calcul dépassé) ** Dans le paramètre actuel, s'il dépasse ** 2 secondes ** jusqu'à ce que le résultat soit sorti, il est traité comme TLE. Même si vous exécutez une boucle infinie, elle sera coupée dans environ 3 secondes et le prochain test sera effectué. TLE__.png ** En cas de CE (erreur de compilation) ** Peu importe s'il ne se compile pas en premier lieu, il se termine donc sans test. CE__.png

2.3 Authentification automatique

Si vous exécutez ce test pendant le concours, vous ne pourrez pas accéder à la page de questions sans vous connecter. En définissant le nom d'utilisateur / mot de passe, etc. avec l'option -i, l'authentification automatique et l'exécution du test pendant le concours sont activées.

>python autojudge.py abc143 abc143_d -i
Atcoder Username:tks_fj * Nom d'utilisateur du compte Atcoder
Atcoder Password:******** Mot de passe du compte Atcoder
Src Directory(Ex. ./aaa/abc140/abc140.cpp => input "./aaa"):../../02_contest
Judging abc143/abc143_d...
testcase 1: AC
testcase 2: AC
testcase 3: AC
result: AC

** Ces informations de paramétrage sont stockées dans le fichier de paramétrage local (setting.conf), ce travail ne peut donc être effectué qu'une seule fois. ** ** (Ce travail peut également être effectué en réécrivant directement le fichier de paramètres.)

2.4 Ajout d'un cas de test

Vous pouvez également ajouter de nouveaux cas de test de manière interactive Afin de prendre en charge l'entrée et la sortie de plusieurs lignes, "quitter" + Entrée est utilisé pour quitter.

(contribution:20 7 Sortie:Ajouter 6)
>python autojudge.py abc143 abc143_a -a
type test input(exit by "quit")
20 7
quit
type test output(exit by "quit")
6
quit

Si vous le testez à nouveau, il sera ajouté à testcase4.

>python autojudge.py abc143 abc143_a
Judging abc143/abc143_a...
testcase 1: AC
testcase 2: AC
testcase 3: AC
testcase 4: AC
result: AC

** Pour les paramètres initiaux, reportez-vous à Auto Judge: Initial Settings ou au chapitre suivant. ** **

3. Conception et mise en œuvre

Je présenterai également la conception et la mise en œuvre à l'intérieur, qui sert également de mémorandum.

3.1 Structure du répertoire

Les artefacts suivants sont gérés dans un référentiel appelé ** autoJudge **.

  • ** autojudge.py (corps principal du programme) **
  • ** setting.conf (fichier de configuration) **
  • ** testcase / (test case, généré lors de l'exécution) **

On suppose que ** autoJudge ** sera cloné dans le répertoire où est stocké le code source (.cpp) à tester. Il est recommandé d'utiliser la structure de répertoires et la convention de dénomination suivantes. (Mais cela fonctionne même si ce n'est pas le cas ↓ (voir 4. Option -p supplémentaire))

.
├── autoJudge * Le livrable créé cette fois
│   ├── setting.conf * Fichier de configuration
│   ├── autojudge.py * Corps du programme
│ ├── testcase * Liste des cas de test(Généré pendant le test)
│   │   ├── abc142@abc142_a.txt
│   │   └── abc143@abc143_a.txt 
│   └── design.pu * Diagramme de classe
├── abc142 * Nom du concours
│   ├── abc142_a.cpp * Nom du problème.cpp
│   ├── abc142_b.cpp
│   ├── abc142_c.cpp
│   ├── abc142_d.cpp
│   ├── abc142_e.cpp
│   └── abc142_f.cpp
├── abc143
:

3.2 Fichier de configuration (setting.conf)

Il s'agit d'un fichier de paramètres utilisé pour l'authentification et la recherche de l'emplacement de la source.

setting.conf


username:tks_fj
password:*******
srcpath:../
  • Entrez le nom d'utilisateur / mot de passe dans nom d'utilisateur / mot de passe (requis lors de la connexion)
  • Décrivez le chemin relatif de autoJudge.py vers "nom du concours / nom du problème" dans srcpath

Il peut être défini avec l'option -i introduite dans ** 2.3 Authentification automatique **, mais bien sûr, il est possible de réécrire directement.

3.3 Corps du programme (autojudge.py)

3.3.1 classe

Le programme comprend les deux classes suivantes.

  • ** ManageTestCases **: Obtenez et gérez des cas de test
  • ** ExecuteTestCases **: Exécuter des tests basés sur des cas de test autojudge.png

3.3.2 ManageTestCases: classe de gestion des tests

  • ** RegisterUser (): Modification du fichier de configuration (setting.conf) **
  • Mettez à jour le fichier de paramètres en recevant le nom d'utilisateur, le mot de passe et le chemin du code source à partir de l'entrée standard.

autojudge.py


    def RegisterUser(self):
        """paramètres utilisateur(Première fois)"""

        print("Atcoder Username:", end="")
        username = input().rstrip('\r\n')
        print("Atcoder Password:", end="")
        password = input().rstrip('\r\n')
        print("Src Directory(Ex. ./aaa/abc140/abc140.cpp => input \"./aaa\"):", end="")
        srcpath = input().rstrip('\r\n')

        with open(CONF_FILE, "w") as f:
            f.write("username:" + username + "\n")
            f.write("password:" + password + "\n")
            f.write("srcpath:" + srcpath + "\n")
  • ** GetTestCases (): Obtenez des cas de test **
  • Générer l'URI de la page de question à partir du nom du concours / nom de la question lors de la première exécution, récupérer le cas de test et l'enregistrer dans le fichier
  • Lisez le fichier et obtenez le cas de test pour la deuxième exécution et les suivantes.
  • Renvoie les cas de test et le nom du concours / nom de la question (testinfo).

autojudge.py


    def GetTestCases(self, test_name, islogin = False):
        """Obtient un cas de test à partir du nom du problème spécifié et renvoie une liste"""

        self.__UpdateConf()
        file_name = self.contest + "@" + test_name + ".txt"
        testinfo = [{"contest":self.contest, "testname":test_name}]
        #Ne grattez pas l'acquisition des mêmes informations pour réduire la charge du serveur
        if file_name in os.listdir(TESTCASES_PATH):
            testcases = self.__ReadFile(file_name)
        else:
            testcases = self.__ScrapePage(test_name, islogin)
            self.__WriteFile(file_name, testcases)
        return testinfo + testcases
  • ** AddTestCases (): Ajouter des cas de test **
  • Ajoutez de manière interactive des cas de test (entrée, sortie) pour le problème spécifié.
  • Accepter les cas de test multilignes (quitter avec "quitter" + Entrée)

autojudge.py


    def AddTestCases(self, test_name):
        """Ajoutez votre propre scénario de test au scénario de test acquis"""

        self.__UpdateConf()
        testcase = {}
        print("type test input(exit by \"quit\")")
        testcase["input"] = ""
        while(1):
            line = input()
            if (line == "quit"):
                break;
            testcase["input"] += line + "\n"
        print("type test output(exit by \"quit\")")
        testcase["output"] = ""
        while(1):
            line = input()
            if (line == "quit"):
                break;
            testcase["output"] += line + "\n"
        file_name = self.contest + "@" + test_name + ".txt"
        if file_name in os.listdir(TESTCASES_PATH):
            testcases = self.__ReadFile(file_name)
        testcases.append(testcase)
        self.__WriteFile(file_name, testcases)

3.3.3 ExecuteTestCases: classe d'exécution de test

  • ** Execute (): Exécuter le scénario de test **
  • Si la construction (\ _ \ _ Build) réussit, elle sera exécutée (\ _ \ _ Run), et finalement le résultat sera affiché (\ _ \ _ Result) (AC, WA, TLE).
  • Si le chemin relatif de la source n'est pas défini, il est automatiquement généré à partir du fichier de configuration.
  • __Run Démarre un processus enfant dans Run et détecte TLE en mesurant le temps d'exécution.

autojudge.py


    def Execute(self, srcpath = ""):
        """Lancer le test"""

        print(YELLOW + "Judging " + self.testinfo["contest"] + "/" + self.testinfo["testname"] + "..." + COLORRESET)
        if (srcpath == ""):
            srcpath = self.__GetPath()
        self.__Build(srcpath)
        if (self.result["build"] == 0):
            self.__Run()
        self.__Result()

3.4 Cas de test (testcase /)

  • Un fichier texte est généré sous le cas de test lorsque le test est exécuté pour la première fois. (nom du concours @ nom du problème.txt)
  • Le format est le suivant

abc143@abc143_a.txt


[test case 0]
---input---
12 4
---output---
4
---fin---
[test case 1]
---input---
20 15
---output---
0
---fin---

3.5 Affichage des résultats

  • Afficher les résultats et les résultats globaux pour chaque cas de test.
  • AC est affiché en vert et WA, TLE, CE sont affichés en jaune.
  • WA (Erreur dans le résultat) génère la prédiction et le résultat. WA__.png

4. Supplément

4.1 Concernant l'environnement python

Les modules suivants sont requis. Vous pouvez le mettre immédiatement avec pip, pip3, conda, etc.

pip3 install requests
pip3 install bs4, lxml

4.2 Liste des options

  • Ajouter un cas de test avec -a
  • Réglage initial avec -i (fichier de réglage de mise à jour)
  • Spécifiez le chemin du code source directement avec -p
>python autojudge.py --help
usage: autojudge.py [-h] [-p PATH] [-a] [-i] contest_name question

positional arguments:
  contest_name          set contest name(ex. abc143)
  question              set question name(ex. abc143_a)

optional arguments:
  -h, --help            show this help message and exit
  -p PATH, --path PATH  set path of source code
  -a, --addtest         add testcase
  -i, --init            set configuration

4.3 Concernant la spécification de chemin (-p)

Lorsque la structure de répertoire du code source n'est pas "3.1 Structure de répertoire" (Par exemple, dans les cas suivants)

.
├── 02_contest
│   ├── abc143
│   │   ├── abc143_a.cpp
│   │   ├── abc143_b.cpp
│   │   └── abc143_c.cpp
├── 04_autotest
│   ├── autoJudge
│   │   ├── README.md
│   │   ├── autoJudge.py
│   │   ├── autojudge.pu
│   │   ├── setting.conf
│   │   └── testcase

Vous pouvez spécifier l'emplacement du code source directement avec l'option -p.

>python autojudge.py abc143 abc143_a -p ../../02_contest/abc143/abc143_a.cpp
Judging abc143/abc143_a...
testcase 1: AC
testcase 2: AC
testcase 3: AC
testcase 4: AC
result: AC

4.4 Problèmes connus

  • Il peut devenir TLE à la première exécution (inclut le temps de grattage ??)
  • ** Non compatible avec le problème que la bonne réponse (AC) est inférieure à une certaine erreur **
  • La précision du jugement TLE est-elle subtile?
  • PermissionError est généré pendant TLE (environnement Win10 uniquement)
  • Non compatible avec l'erreur d'exécution (RE)
  • Occasionnellement des bugs

5. Post-scriptum

  • plantUML était bon (utilisé pour générer un diagramme de classes)
  • BeutifulSoup était également bon (utilisé pour l'analyse HTML)
  • argperse est également légèrement plié (utilisé pour l'analyse facultative)
  • Il y avait de nombreux pionniers
    • https://github.com/kyuridenamida/atcoder-tools
    • https://github.com/nodchip/OnlineJudgeHelper
  • Je veux devenir bleu rapidement

Recommended Posts