Récemment, la programmation compétitive est devenue populaire parmi les étudiants programmeurs et les programmeurs actifs (expérience). Je ne participe pas à des concours, mais je résous souvent des problèmes de compétition professionnelle comme un coup d'essai lors de l'apprentissage d'une nouvelle langue. C'est assez intéressant.
Le problème est généralement ** un exemple d'entrée est fourni, mais n'est-il pas compliqué ** de le saisir en standard? Je souhaite l'automatiser si possible. ** Si vous l'automatisez, vous pouvez vous attendre à des essais et des erreurs plus efficaces et à un score plus élevé **! Il existe de nombreuses façons de l'automatiser, mais cet article vous montrera comment utiliser la commande make. Makefile est pour C ++, Java, Python comme exemple. Si vous fournissez des exemples de langages de compilation, de langages Java et de langages de script, l'utilisateur les réécrira en fonction de la langue. Il y a une âme.
Le Makefile et la structure des répertoires de cet article ont été téléchargés sur github. Veuillez utiliser quand c'est bon. https://github.com/aoi-stoic/AtcorderTemplate
OS
$ cat /etc/os-release | head -n 2
NAME="Ubuntu"
VERSION="20.04.1 LTS (Focal Fossa)"
J'utilise ubuntu. Les autres systèmes d'exploitation et distributions sont omis, veuillez donc les lire comme il convient.
C++
gcc version 9.3.0 (Ubuntu 9.3.0-10ubuntu2)
Java
$ echo `javac -version` `java -version`
javac 1.8.0_265
openjdk version "1.8.0_265"
OpenJDK Runtime Environment (build 1.8.0_265-8u265-b01-0ubuntu2~20.04-b01)
OpenJDK 64-Bit Server VM (build 25.265-b01, mixed mode)
Java convient car je l'ai à peine écrit. Si vous contestez le concours avec Java, veuillez choisir la version qui convient au concours.
Python3
$ python3 --version
Python 3.8.2
Choses qui ne sont pas utilisées comme l'environnement virtuel
Pseudo-concours ABCXXX Un problème "Recevoir quatre entrées standard et sortir la somme en standard" est utilisé comme thème pour présenter une construction de répertoire de travail et faire un exemple d'exécution de commande. Résolvez en C ++.
Un exemple d'entrée de problème et un exemple de sortie sont les suivants ** Exemple d'entrée 1 ** 1 1 1 1 ** Exemple de sortie 1 ** 4
** Exemple d'entrée 2 ** 1 2 3 4 ** Exemple de sortie 2 ** 10
** Exemple d'entrée 3 ** 1000 100 10 1 ** Exemple de sortie 3 ** 1111
faire l'installation de la commande
sudo apt isntall make
Construire un répertoire de travail
#Créer et déplacer un répertoire de travail
mkdir ABCXXX && cd ABCXXX
#Clone du répertoire de modèles (--depth=Cloner avec 1 pour un historique minimal)
git clone --depth=1 https://github.com/aoi-stoic/AtcorderTemplate.git
#Modèle Atcorder pour un problème/Copier le modèle Cpp&Bouge toi
cp AtcorderTemplate/TemplateCpp/ problemA -r && cd problemA
À ce stade, le contenu du répertoire problemmA ressemble à ceci Si vous souhaitez reproduire cette configuration, vous pouvez la générer manuellement sans clonage à partir de git et copier uniquement le Makefile de cet article.
$ tree
.
├── main.cpp #Fichier source pour la réponse
├── Makefile # C++Pour Makefile
└── Testfiles #Répertoire des fichiers de test
├── test1.test #Fichier de test de l'exemple d'entrée 1
├── test2.test
├── test3.test
└── test4.test
Copiez l'exemple d'entrée dans chaque fichier de test. Le résultat est: Puisqu'il n'y a que 1 à 3 exemples d'entrée d'ABCXXX Un problème, test4.test est un fichier vide.
$ cat Testfiles/test1.test
1 1
1 1
$ cat Testfiles/test2.test
1 2
3 4
$ cat Testfiles/test3.test
1000 100
10 1
$ cat Testfiles/test4.test
Comme d'habitude, j'ai écrit le code de réponse dans main.cpp.
// main.cpp
#include <iostream>
int main(){
int a, b, c, d;
std::cin >> a >> b >> c >> d;
std::cout << a + b + c + d << std::endl;
}
Lorsque vous exécutez la commande make dans le répertoire problemA, Après la compilation, il sera exécuté automatiquement pour chaque exemple d'entrée. Puisque test4.test est vide, l'exemple d'entrée 4 ne sera pas exécuté.
$ make
g++ -std=c++11 -Wall main.cpp -o main.out
----------------------
exec Testfiles/test1.test
input:
1 1
1 1
output:
4
----------------------
exec Testfiles/test2.test
input:
1 2
3 4
output:
10
----------------------
exec Testfiles/test3.test
input:
1000 100
10 1
output:
1111
Assurez-vous que la correspondance entre les exemples d'entrée et de sortie est correcte et soumettez-la lorsque vous êtes certain que le code est correct. Si vous souhaitez passer au problème B suivant, copiez le répertoire TemplateCpp pour créer le problèmeB et travaillez également dans ce répertoire.
Les cibles suivantes sont préparées pour le Makefile publié cette fois. Comme python n'a pas de travail de compilation, il n'a pas de cibles telles que build et clean.
cible | commander | Aperçu |
---|---|---|
(Aucun) | make | Exécuter make test |
build | make build | Compiler uniquement |
run | make run | Compilez et exécutez selon vos besoins. La saisie standard se fait manuellement. |
test | make test | Compilez et exécutez selon vos besoins. Entrez le contenu du fichier de test par défaut. |
clean | make clean | Supprimez le produit compilé. |
clean_test | make clean_test | Videz le contenu du fichier de test. Il est utilisé lors de la copie du répertoire de la question A et de sa réutilisation pour la réponse à la question B. |
Makefile
COMP = g++ -std=c++11 -Wall
SRC = main.cpp
BIN = main.out
TESTDIR = Testfiles
#Désactiver les règles implicites,Désactiver la sortie lors du déplacement de répertoires
MAKEFLAGS :=+ --no-builtin-rules --no-print-directory
#Test cible sans exécution d'argument (cible)
all: test
$(BIN): $(SRC)
$(COMP) $(SRC) -o $(BIN)
#make run est une exécution manuelle de l'entrée standard
.phony:run
run: $(BIN)
./$(BIN)
# make test
#Exécuter pour saisir le contenu du fichier de test dans TESTDIR en standard (ignorer les fichiers vides)
.phony:test
test: $(BIN)
@for testfile in $(wildcard $(TESTDIR)/*.test) ; \
do \
if [ -s $$testfile ]; then \
echo ---------------------- ;\
echo "exec $$testfile " ;\
echo "input: "; \
cat $$testfile ; \
echo "" ;\
echo "output: " ;\
cat $$testfile | ./$(BIN) ;\
fi \
done
.phony:clean
clean:
-rm $(BIN)
#Vider tous les fichiers de test
.phony:clean_test
clean_test:
@for testfile in $(wildcard $(TESTDIR)/*.test) ; \
do \
: > $$testfile ;\
done
J'ai à peine écrit Java.
COMP = javac
EXEC = java
SRC = Main.java
CLASS = Main.class
# Main.class -> Main
APP = $(basename $(CLASS) .class)
TESTDIR = Testfiles
#Désactiver les règles implicites,Désactiver la sortie lors du déplacement de répertoires
MAKEFLAGS :=+ --no-builtin-rules --no-print-directory
#
#Test cible sans exécution d'argument (cible)
all: test
$(CLASS): $(SRC)
$(COMP) $(SRC)
#make run est une exécution manuelle de l'entrée standard
run: $(CLASS)
$(EXEC) $(APP)
# make test
#Exécuter pour saisir le contenu du fichier de test dans TESTDIR en standard (ignorer les fichiers vides)
test: $(CLASS)
@for testfile in $(wildcard $(TESTDIR)/*.test) ; \
do \
if [ -s $$testfile ]; \
then \
echo ---------------------- ;\
echo "exec $$testfile" ;\
echo "input: " ; \
cat $$testfile ; \
echo "" ;\
echo "output: " ;\
cat $$testfile | $(EXEC) $(APP) ;\
fi \
done \
.phony:clean
clean:
-rm $(CLASS)
#Vider tous les fichiers de test
.phony:clean_test
clean_test:
@for testfile in $(wildcard $(TESTDIR)/*.test) ; \
do \
: > $$testfile ;\
done
En termes de Makefile, le langage de script Makefile semble étrange.
SRC = main.py
EXEC = python3
TESTDIR = Testfiles
#Désactiver les règles implicites,Désactiver la sortie lors du déplacement de répertoires
MAKEFLAGS :=+ --no-builtin-rules --no-print-directory
#Test cible sans exécution d'argument (cible)
all: test
#make run est une exécution manuelle de l'entrée standard
.phony:run
run:
$(EXEC) $(SRC)
# make test
#Exécuter pour saisir le contenu du fichier de test dans TESTDIR en standard (ignorer les fichiers vides)
.phony:test
test:
@for testfile in $(wildcard $(TESTDIR)/*.test) ; \
do \
if [ -s $$testfile ]; then \
echo ---------------------- ;\
echo "exec $$testfile " ;\
echo "input: "; \
cat $$testfile ; \
echo "" ;\
echo "output: " ;\
cat $$testfile | $(EXEC) $(SRC) ;\
fi \
done
#Vider tous les fichiers de test
.phony:clean_test
clean_test:
@for testfile in $(wildcard $(TESTDIR)/*.test) ; \
do \
: > $$testfile ;\
done
Vous pouvez utiliser le pipeline (|) pour relier la sortie d'une commande à l'entrée de la commande suivante.
$ cat Testfiles/test1.test
1 1
1 1
$ cat Testfiles/test1.test | ./main.out #Sortir la commande cat./main.entrée de sortie
4
Vous pouvez l'utiliser pour créer un script sur l'entrée standard d'un fichier exécutable.
make test
Profite de cette fonctionnalité.
Lors de la création d'un nouveau fichier vide
touch empty_file
Cela suffit, mais cette méthode ne fonctionne pas pour les fichiers existants. La méthode "supprimer et toucher" comme indiqué ci-dessous n'est pas mon passe-temps
rm empty_file & touch empty_file #Cela ne convient pas à mon goût
J'utilise souvent les deux types suivants.
#Commande de ne rien faire(:)Rediriger le résultat de
: > empty_file
# /dev/cp nul
cp /dev/null empty_file
Il semble y avoir diverses autres méthodes.
exactement. Cependant, compte tenu de la définition de raccourcis pour les commandes d'exécution dans l'éditeur, je pense qu'il est préférable de définir des raccourcis pour la commande make plus polyvalente que pour l'exécution de scripts shell.
exactement. Veuillez colorier en fonction de l'environnement.
Certaines distributions ubuntu utilisent dash au lieu de bash pour exécuter des scripts shell. Il existe quelques différences dans le comportement de certaines commandes entre bash et dash. Par exemple, dans bash vous pouvez utiliser un code d'échappement pour colorer la sortie de echo comme ```echo -e "\ 033 [31m GREEN \ 033 [m" `` `, mais dans dash vous n'avez pas besoin de l'option -e. N'analyse pas les options. Je n'ai pas colorié la sortie d'écho cette fois car on s'attendait à ce que cette différence soit un problème lors de la publication cette fois.