Wrapper für Nicht-Java-Übermittlungen
HINWEIS MAP_SIZE Unterstützung wurde hinzugefügt. Wenn Sie interessiert sind, aktualisieren Sie bitte Ihren Beitrag entsprechend.
Dies ist ein Community-Wiki-Eintrag für einen Wrapper, der von Benutzern verwendet werden kann, die Java nicht mögen oder nicht kennen. Bitte benutzen Sie es, haben Sie Spaß und ich helfe Ihnen gerne, die Dinge in Ordnung zu bringen.
Es ist ziemlich spät hier, als ich fertig bin, also schauen Sie sich andere Java-Codierer an und schlagen Sie Verbesserungen vor. Wenn Sie können, tun Sie dies über mein Github-Repository, indem Sie eine Ausgabe einreichen oder einen Patch einreichen. Vielen Dank!
Das Ganze wird mit der UNLICENSE verteilt, bitte folgen Sie ihr aus dem Github-Repository . Reichen Sie dort Patches ein, wenn Sie Probleme finden, und ich werde diesen Beitrag aktualisieren.
Aktuelle Beispiele für verwendete Wrapper
plannapus : WolfCollectiveMemory in R
Zahnbürste : Zahnbürste in ECMAScript
Wie benutzt man
Im Folgenden finden Sie Anweisungen zum Protokoll für die prozessübergreifende Kommunikation über PIPES, das ich für entfernte Wölfe definiert habe. Hinweis: Ich habe MAP_SIZE übersprungen, da dies anscheinend nicht vorhanden ist, obwohl es in der Problembeschreibung von OP enthalten ist. Wenn es erscheint, aktualisiere ich diesen Beitrag.
WICHTIGE HINWEISE :
- Es wird nur ein einziger Aufruf Ihres externen Prozesses ausgeführt (binden Sie also Ihre Verarbeitungslogik in eine Endlosschleife ein. Auf diese Weise können Sie die Verarbeitung auch im Arbeitsspeicher belassen, anstatt die Festplatte zu verwenden).
- Die gesamte Kommunikation zu diesem einzelnen externen Prozess erfolgt über STDIN und STDOUT
- Sie müssen alle an STDOUT gesendeten Ausgaben explizit leeren und sicherstellen, dass die Zeilenumbrüche abgeschlossen sind
Spezifikation
Remote-Skripte werden von einem einfachen Protokoll über STDIN- und STDOUT-Hooks unterstützt und sind in Initialisierung, Verschieben und Angriff unterteilt. In jedem Fall erfolgt die Kommunikation mit Ihrem Prozess über STDIN, und eine Antwort von STDOUT ist erforderlich. Wenn innerhalb von 1 Sekunde keine Antwort eingeht, wird davon ausgegangen, dass Ihr Prozess beendet ist, und es wird eine Ausnahme ausgelöst. Alle Zeichen werden aus Konsistenzgründen in UTF-8 codiert. Jede Eingabe wird mit einem Zeilenumbruch beendet, und Ihr Prozess sollte auch jede Ausgabeantwort mit einem Zeilenumbruch beenden.
WARNUNG Stellen Sie sicher, dass Sie Ihren Ausgabepuffer nach jedem Schreibvorgang leeren, damit der Java-Wrapper Ihre Ausgabe sieht. Wenn Sie nicht spülen, kann Ihr entfernter Wolf ausfallen.
Beachten Sie, dass nur ein einzelner Prozess erstellt wird. Alle Wölfe müssen innerhalb dieses einen Prozesses verwaltet werden. Lesen Sie weiter, wie diese Spezifikation helfen wird.
Initialisierung
STDIN: S<id><mapsize>
\ n
STDOUT: K<id>
\ n
<id>
: 00
oder 01
oder ... oder99
Erläuterung:
Das Zeichen S
wird gesendet, gefolgt von zwei numerischen Zeichen 00
, 01
..., die 99
angeben, welcher der 100 Wölfe initialisiert wird. In der gesamten zukünftigen Kommunikation mit diesem speziellen Wolf wird dasselbe <id>
verwendet.
Nach der ID wird eine Sequenz mit variabler Länge von numerischen Zeichen gesendet. Dies ist die Größe der Karte. Sie werden wissen, dass die Folge der numerischen Zeichen vorbei ist, wenn Sie die neue Zeile ( \n
) erreichen.
Um sicherzustellen, dass Ihr Prozess am Leben ist, müssen Sie mit dem Zeichen antworten, K
dem dasselbe folgt, das <id>
Sie erhalten haben. Jede andere Antwort führt zu einer Ausnahme, bei der Ihre Wölfe getötet werden.
Bewegung
STDIN: M<id><C0><C1>...<C7><C8>
\ n
STDOUT: <mv><id>
\ n
<Cn>
: W
oder
oder B
oder S
oderL
W
: Wolf
: Leerer Raum
B
: Bär
S
: Stein
L
: Löwe
<mv>
: H
oder U
oder L
oder R
oderD
H
: Move.HOLD
U
: Move.UP
L
: Move.LEFT
R
: Nach RECHTS bewegen
D
: Move.DOWN
Erläuterung:
Der Charakter M
wird gesendet, gefolgt von den beiden Charakteren, <id>
um anzuzeigen, welcher Wolf einen Zug wählen muss. Anschließend werden 9 Zeichen gesendet, die die Umgebung des Wolfs in der Reihenfolge (obere Reihe, mittlere Reihe, untere Reihe von ganz links nach ganz rechts) darstellen.
Antworten Sie mit einem der gültigen Bewegungszeichen <mv>
, gefolgt von der zweistelligen <id>
Zahl des Wolfs zur Bestätigung.
Attacke
STDIN: A<id><C>
\ n
STDOUT: <atk><id>
\ n
<C>
: W
oder B
oder S
oderL
<atk>
: R
oder P
oder S
oderD
R
: Attack.ROCK
P
: Attack.PAPER
S
: Attack.SCISSORS
D
: Attack.SUICIDE
Erläuterung:
Der Charakter A
wird gesendet, gefolgt von den beiden Charakteren, <id>
um anzuzeigen, welcher Wolf an einem Angriff beteiligt ist. Darauf folgt ein einzelnes Zeichen <C>
, das angibt, welche Art von Sache angreift, entweder ein W
Olf, ein B
Ohr, ein S
Ton oder ein L
Ion.
Antworten Sie mit einem der <atk>
oben aufgelisteten Zeichen und geben Sie an, wie Sie auf den Angriff reagiert haben, gefolgt von der zweistelligen <id>
Bestätigung.
Und das ist es. Mehr gibt es nicht. Wenn Sie einen Angriff verlieren, der <id>
nie wieder an Ihren Prozess gesendet wird, wissen Sie, dass Ihr Wolf gestorben ist - wenn eine komplette Bewegungsrunde verstrichen ist, ohne dass dies <id>
jemals gesendet wurde.
Fazit
Beachten Sie, dass alle Ausnahmen alle Wölfe Ihres Remote-Typs töten, da nur ein einziger "Prozess" Ihres Remote-Wolfs für alle Wölfe Ihres Typs erstellt wird, die erstellt werden.
In diesem Repository finden Sie die Wolf.java
Datei. Suchen und ersetzen Sie die folgenden Zeichenfolgen, um Ihren Bot einzurichten:
Ersetzen Sie <invocation>
durch das Befehlszeilenargument, das Ihren Prozess ordnungsgemäß ausführt.
Ersetzen Sie <custom-name>
durch einen eindeutigen Namen für Ihren Wolf.
Ein Beispiel finden Sie im Repository , in WolfRandomPython.java
dem meine Beispielfernbedienung PythonWolf.py
(ein Python 3+ Wolf) aufgerufen wird.
Benennen Sie die Datei in um Wolf<custom-name>.java
, wobei sie <custom-name>
durch den Namen ersetzt wird, den Sie oben gewählt haben.
Um Ihren Wolf zu testen, kompilieren Sie das Java-Programm ( javac Wolf<custom-name>.java
) und folgen Sie den Anweisungen von Rusher, um es in das Simulationsprogramm aufzunehmen.
Wichtig: Stellen Sie sicher, dass Sie klare , präzise Anweisungen zum Kompilieren / Ausführen Ihres tatsächlichen Wolfs geben, die dem oben beschriebenen Schema folgen.
Viel Glück und möge die Natur immer zu Ihren Gunsten sein.
Der Wrapper-Code
Denken Sie daran, dass Sie die beschriebenen Suchen und Ersetzen durchführen MÜSSEN, damit dies funktioniert. Wenn Ihr Anruf besonders haarig ist, wenden Sie sich bitte an mich, um Unterstützung zu erhalten.
Beachten Sie, dass main
in diesem Wrapper eine Methode enthalten ist, mit der rudimentäre "Pass / Fail" -Tests für Ihre lokale Box durchgeführt werden können. Laden Sie dazu die Animal.java-Klasse aus dem Projekt herunter und entfernen Sie die package animals;
Zeile aus beiden Dateien. Ersetzen Sie die MAP_SIZE-Zeile in Animal.java durch eine Konstante (wie 100). Übersetzen Sie diese mit javac Wolf<custom-name>.java
einem Execute 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;
}
}
}