Wrapper pour les soumissions non Java
NOTE Le support MAP_SIZE a été ajouté. Si vous le souhaitez, veuillez mettre à jour votre soumission en conséquence.
Ceci est une entrée wiki de la communauté pour un wrapper, utilisable par ceux qui veulent jouer mais n'aiment pas / ne connaissent pas Java. S'il vous plaît utilisez-le, amusez-vous, et je suis heureux de vous aider à mettre les choses en place.
Il est assez tard pour terminer, alors les autres codeurs Java, jetez-y un coup d'œil et suggérez des améliorations. Si vous le pouvez, faites-le via mon dépôt github en déposant un problème ou en soumettant un correctif. Merci!
Cet ensemble est distribué avec UNLICENSE, suivez-le à partir de son référentiel github . Soumettez les correctifs ici si vous rencontrez des problèmes et je mettrai à jour ce post.
Exemples actuels d'utilisation de wrapper
plannapus : WolfCollectiveMemory in R
brosse à dents : brosse à dents en ECMAScript
Comment utiliser
Vous trouverez ci-dessous des instructions sur le protocole de communication inter-processus via PIPES que j'ai défini pour les loups distants. Remarque J'ai sauté MAP_SIZE car cela ne semble pas exister, malgré sa présence dans l'énoncé du problème d'OP. Si cela apparaît, je mettrai à jour ce post.
NOTES IMPORTANTES :
- Un seul appel de votre processus externe sera effectué (enveloppez donc votre logique de traitement dans une boucle infinie. Cela vous permet également de conserver tout traitement en mémoire au lieu d'utiliser un disque).
- Toutes les communications se font vers ce processus externe unique via STDIN et STDOUT
- Vous devez explicitement vider toute la sortie envoyée à STDOUT et vous assurer qu'elle est terminée par une nouvelle ligne.
spécification
Les scripts distants sont supportés par un protocole simple via les hooks STDIN et STDOUT, et sont divisés en initialisation, déplacement et attaque. Dans chaque cas, la communication avec votre processus se fera via STDIN et une réponse de STDOUT est nécessaire. Si une réponse n'est pas reçue dans la seconde, votre processus sera considéré comme mort et une exception sera levée. Tous les caractères seront encodés en UTF-8, par souci de cohérence. Chaque entrée se terminera par un caractère de nouvelle ligne et votre processus devra également terminer chaque réponse en sortie par une nouvelle ligne.
AVERTISSEMENT Assurez-vous de vider votre tampon de sortie après chaque écriture pour vous assurer que l'encapsuleur Java voit votre sortie. Si vous ne rincez pas, votre Wolf distant risque d’échouer.
Notez que seul un processus sera créé, tous les loups doivent être gérés au sein de ce processus. Lisez la suite pour savoir comment cette spécification aidera.
Initialisation
STDIN: S<id><mapsize>
\ n
STDOUT: K<id>
\ n
<id>
: 00
ou 01
ou ... ou99
Explication:
Le personnage S
sera envoyé suivi de deux chiffres 00
, 01
..., 99
indiquant que des 100 loups est en cours d' initialisation. Dans toutes les communications futures avec ce loup spécifique, la même chose <id>
sera utilisée.
Après l’ID, une séquence de caractères numériques de longueur variable sera envoyée. C'est la taille de la carte. Vous saurez que la séquence de caractères numériques est terminée lorsque vous atteignez la nouvelle ligne ( \n
).
Pour vous assurer que votre processus est actif, vous devez répondre avec le caractère K
suivi de celui que <id>
vous avez reçu. Toute autre réponse entraînera une exception, tuant vos loups.
Mouvement
STDIN: M<id><C0><C1>...<C7><C8>
\ n
STDOUT: <mv><id>
\ n
<Cn>
: W
ou
ou B
ou S
ouL
W
: Loup
: Espace vide
B
: Ours
S
: Pierre
L
: Lion
<mv>
: H
ou U
ou L
ou R
ouD
H
: Move.HOLD
U
: Move.UP
L
: Move.LEFT
R
: Move.RIGHT
D
: Move.DOWN
Explication:
Le personnage M
sera envoyé suivi des deux personnages <id>
pour indiquer quel loup doit choisir un coup. Ensuite, 9 caractères représentant l'environnement de Wolf seront envoyés dans l'ordre (rangée du haut, rang du milieu, rangée du bas de gauche à droite).
Répondez avec l'un des caractères de mouvement valides <mv>
, suivi des deux chiffres du loup <id>
pour confirmation.
Attaque
STDIN: A<id><C>
\ n
STDOUT: <atk><id>
\ n
<C>
: W
ou B
ou S
ouL
<atk>
: R
ou P
ou S
ouD
R
: Attaque.ROCK
P
: Attack.PAPER
S
: Attaque.CISSONS
D
: Attaque.SUICIDE
Explication:
Le personnage A
sera envoyé suivi des deux personnages <id>
pour indiquer quel loup participe à une attaque. Ceci est suivi d'un seul caractère <C>
indiquant quel type de chose attaque, soit un W
olf, une B
oreille, un S
son ou un L
ion.
Répondez avec l’un des <atk>
caractères énumérés ci-dessus, en indiquant quelle est votre réponse à l’attaque, suivi du chiffre à deux chiffres <id>
pour confirmation.
Et c'est tout. Il n'y a plus rien à faire. Si vous perdez une attaque, cela <id>
ne sera plus jamais envoyé à votre processus. C'est ainsi que vous saurez que votre loup est mort - si un round de Mouvement complet s'est écoulé sans que cela <id>
ait jamais été envoyé.
Conclusion
Notez que toutes les exceptions tueront tous les loups de votre type distant, puisqu'un seul "Processus" est construit à partir de votre loup distant, pour tous les loups de votre type créés.
Vous trouverez le Wolf.java
fichier dans ce référentiel . Recherchez et remplacez les chaînes suivantes pour configurer votre bot:
Remplacez <invocation>
par l'argument de ligne de commande qui exécutera correctement votre processus.
Remplacez-le <custom-name>
par un nom unique pour votre loup.
Pour un exemple, regardez le référentiel , où j'ai WolfRandomPython.java
invoqué mon exemple distant, le PythonWolf.py
(un loup Python 3+).
Renommez le fichier pour être Wolf<custom-name>.java
, où <custom-name>
est remplacé par le nom que vous avez choisi ci-dessus.
Pour tester votre Wolf, compilez le programme Java ( javac Wolf<custom-name>.java
) et suivez les instructions de Rusher pour l'inclure dans le programme de simulation.
Important: Assurez-vous de fournir des instructions claires et concises sur la manière de compiler / exécuter votre Wolf, conformément au schéma que j'ai décrit ci-dessus.
Bonne chance et que la nature soit toujours en votre faveur.
Le code d'emballage
N'oubliez pas que vous DEVEZ effectuer les recherches et les remplacements décrits pour que cela fonctionne. Si votre invocation est particulièrement poilue, veuillez me contacter pour obtenir de l'aide.
Notez qu’il existe main
dans cet emballage une méthode permettant d’effectuer des tests rudimentaires «succès / échec» sur votre machine locale. Pour ce faire, téléchargez la classe Animal.java à partir du projet et supprimez la package animals;
ligne des deux fichiers. Remplacez la ligne MAP_SIZE dans Animal.java par une constante (telle que 100). Compilez-les en utilisant javac Wolf<custom-name>.java
un exécuter via java Wolf<custom-name>
.
package animals;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.OutputStreamWriter;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
/**
* Remote Wolf<custom-name> wrapper class.
*/
public class Wolf<custom-name> extends Animal {
/**
* Simple test script that sends some typical commands to the
* remote process.
*/
public static void main(String[]args){
Wolf<custom-name>[] wolves = new Wolf<custom-name>[100];
for(int i=0; i<10; i++) {
wolves[i] = new Wolf<custom-name>();
}
char map[][] = new char[3][3];
for (int i=0;i<9;i++)
map[i/3][i%3]=' ';
map[1][1] = 'W';
for(int i=0; i<10; i++) {
wolves[i].surroundings=map;
System.out.println(wolves[i].move());
}
for(int i=0; i<10; i++) {
System.out.println(wolves[i].fight('S'));
System.out.println(wolves[i].fight('B'));
System.out.println(wolves[i].fight('L'));
System.out.println(wolves[i].fight('W'));
}
wolfProcess.endProcess();
}
private static WolfProcess wolfProcess = null;
private static Wolf<custom-name>[] wolves = new Wolf<custom-name>[100];
private static int nWolves = 0;
private boolean isDead;
private int id;
/**
* Sets up a remote process wolf. Note the static components. Only
* a single process is generated for all Wolves of this type, new
* wolves are "initialized" within the remote process, which is
* maintained alongside the primary process.
* Note this implementation makes heavy use of threads.
*/
public Wolf<custom-name>() {
super('W');
if (Wolf<custom-name>.wolfProcess == null) {
Wolf<custom-name>.wolfProcess = new WolfProcess();
Wolf<custom-name>.wolfProcess.start();
}
if (Wolf<custom-name>.wolfProcess.initWolf(Wolf<custom-name>.nWolves, MAP_SIZE)) {
this.id = Wolf<custom-name>.nWolves;
this.isDead = false;
Wolf<custom-name>.wolves[id] = this;
} else {
Wolf<custom-name>.wolfProcess.endProcess();
this.isDead = true;
}
Wolf<custom-name>.nWolves++;
}
/**
* If the wolf is dead, or all the wolves of this type are dead, SUICIDE.
* Otherwise, communicate an attack to the remote process and return
* its attack choice.
*/
@Override
public Attack fight(char opponent) {
if (!Wolf<custom-name>.wolfProcess.getRunning() || isDead) {
return Attack.SUICIDE;
}
try {
Attack atk = Wolf<custom-name>.wolfProcess.fight(id, opponent);
if (atk == Attack.SUICIDE) {
this.isDead = true;
}
return atk;
} catch (Exception e) {
System.out.printf("Something terrible happened, this wolf has died: %s", e.getMessage());
isDead = true;
return Attack.SUICIDE;
}
}
/**
* If the wolf is dead, or all the wolves of this type are dead, HOLD.
* Otherwise, get a move from the remote process and return that.
*/
@Override
public Move move() {
if (!Wolf<custom-name>.wolfProcess.getRunning() || isDead) {
return Move.HOLD;
}
try {
Move mv = Wolf<custom-name>.wolfProcess.move(id, surroundings);
return mv;
} catch (Exception e) {
System.out.printf("Something terrible happened, this wolf has died: %s", e.getMessage());
isDead = true;
return Move.HOLD;
}
}
/**
* The shared static process manager, that synchronizes all communication
* with the remote process.
*/
static class WolfProcess extends Thread {
private Process process;
private BufferedReader reader;
private PrintWriter writer;
private ExecutorService executor;
private boolean running;
public boolean getRunning() {
return running;
}
public WolfProcess() {
process = null;
reader = null;
writer = null;
running = true;
executor = Executors.newFixedThreadPool(1);
}
public void endProcess() {
running = false;
}
/**
* WolfProcess thread body. Keeps the remote connection alive.
*/
public void run() {
try {
System.out.println("Starting Wolf<custom-name> remote process");
ProcessBuilder pb = new ProcessBuilder("<invocation>".split(" "));
pb.redirectErrorStream(true);
process = pb.start();
System.out.println("Wolf<custom-name> process begun");
// STDOUT of the process.
reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
System.out.println("Wolf<custom-name> reader stream grabbed");
// STDIN of the process.
writer = new PrintWriter(new OutputStreamWriter(process.getOutputStream(), "UTF-8"));
System.out.println("Wolf<custom-name> writer stream grabbed");
while(running){
this.sleep(0);
}
reader.close();
writer.close();
process.destroy(); // kill it with fire.
executor.shutdownNow();
} catch (Exception e) {
e.printStackTrace();
System.out.println("Wolf<custom-name> ended catastrophically.");
}
}
/**
* Helper that invokes a read with a timeout
*/
private String getReply(long timeout) throws TimeoutException, ExecutionException, InterruptedException{
Callable<String> readTask = new Callable<String>() {
@Override
public String call() throws Exception {
return reader.readLine();
}
};
Future<String> future = executor.submit(readTask);
return future.get(timeout, TimeUnit.MILLISECONDS);
}
/**
* Sends an initialization command to the remote process
*/
public synchronized boolean initWolf(int wolf, int map_sz) {
while(writer == null){
try {
this.sleep(0);
}catch(Exception e){}
}
boolean success = false;
try{
writer.printf("S%02d%d\n", wolf, map_sz);
writer.flush();
String reply = getReply(5000l);
if (reply != null && reply.length() >= 3 && reply.charAt(0) == 'K') {
int id = Integer.valueOf(reply.substring(1));
if (wolf == id) {
success = true;
}
}
if (reply == null) {
System.out.println("did not get reply");
}
} catch (TimeoutException ie) {
endProcess();
System.out.printf("Wolf<custom-name> %d failed to initialize, timeout\n", wolf);
} catch (Exception e) {
endProcess();
System.out.printf("Wolf<custom-name> %d failed to initialize, %s\n", wolf, e.getMessage());
}
return success;
}
/**
* Send an ATTACK command to the remote process.
*/
public synchronized Attack fight(int wolf, char opponent) {
Attack atk = Attack.SUICIDE;
try{
writer.printf("A%02d%c\n", wolf, opponent);
writer.flush();
String reply = getReply(1000l);
if (reply.length() >= 3) {
int id = Integer.valueOf(reply.substring(1));
if (wolf == id) {
switch(reply.charAt(0)) {
case 'R':
atk = Attack.ROCK;
break;
case 'P':
atk = Attack.PAPER;
break;
case 'S':
atk = Attack.SCISSORS;
break;
case 'D':
atk = Attack.SUICIDE;
break;
}
}
}
} catch (TimeoutException ie) {
endProcess();
System.out.printf("Wolf<custom-name> %d failed to attack, timeout\n", wolf);
} catch (Exception e) {
endProcess();
System.out.printf("Wolf<custom-name> %d failed to attack, %s\n", wolf, e.getMessage());
}
return atk;
}
/**
* Send a MOVE command to the remote process.
*/
public synchronized Move move(int wolf, char[][] map) {
Move move = Move.HOLD;
try{
writer.printf("M%02d", wolf);
for (int row=0; row<map.length; row++) {
for (int col=0; col<map[row].length; col++) {
writer.printf("%c", map[row][col]);
}
}
writer.print("\n");
writer.flush();
String reply = getReply(1000l);
if (reply.length() >= 3) {
int id = Integer.valueOf(reply.substring(1));
if (wolf == id) {
switch(reply.charAt(0)) {
case 'H':
move = Move.HOLD;
break;
case 'U':
move = Move.UP;
break;
case 'L':
move = Move.LEFT;
break;
case 'R':
move = Move.RIGHT;
break;
case 'D':
move = Move.DOWN;
break;
}
}
}
} catch (TimeoutException ie) {
endProcess();
System.out.printf("Wolf<custom-name> %d failed to move, timeout\n", wolf);
} catch (Exception e) {
endProcess();
System.out.printf("Wolf<custom-name> %d failed to move, %s\n", wolf, e.getMessage());
}
return move;
}
}
}