非Java提出用のラッパー
注 MAP_SIZEサポートが追加されました。気になる場合は、それに応じて提出物を更新してください。
これはラッパーのコミュニティwikiエントリで、Javaを好きではない/知らない人が使用できます。それを使用して、楽しんでください、そして、私はあなたが物事を準備するのを手伝ってうれしいです。
私が仕上げているので、ここではかなり遅いので、他のJavaコーダーはこれを見て、改善を提案してください。可能であれば、私のgithubリポジトリを使用して、問題を報告するか、パッチを提出してください。ありがとう!
この全体はUNLICENSEと共に配布されています。github リポジトリからフォロー/フォークしてください。問題が見つかった場合は、パッチを送信してください。この投稿を更新します。
使用中のラッパーの現在の例
plannapus:RのWolfCollectiveMemory
歯ブラシ:ECMAScriptの歯ブラシ
使い方
以下は、リモートオオカミ用に定義したPIPESを介したプロセス間通信のプロトコルに関する説明です。注:OPの問題ステートメントに存在するにもかかわらず、MAP_SIZEは存在しないように見えるため、MAP_SIZEをスキップしました。表示される場合は、この投稿を更新します。
重要事項:
- 外部プロセスの呼び出しは1回だけです(処理ロジックを無限ループにラップします。これにより、ディスクを使用する代わりに、処理をメモリ内に保持することもできます)
- すべての通信は、STDINおよびSTDOUTを介したこの単一の外部プロセスに対するものです。
- STDOUTに送信されたすべての出力を明示的にフラッシュし、改行で終了していることを確認する必要があります
仕様
リモートスクリプトは、STDINおよびSTDOUTフックを介した単純なプロトコルによってサポートされ、初期化、移動、および攻撃に分割されます。いずれの場合も、プロセスとの通信はSTDINを介して行われ、STDOUTからの返信が必要です。応答が1秒以内に受信されない場合、プロセスは停止していると見なされ、例外がスローされます。一貫性を保つため、すべての文字はUTF-8でエンコードされます。すべての入力は改行文字で終了し、プロセスはすべての出力応答も改行で終了する必要があります。
警告 Javaラッパーが出力を認識できるように、書き込みのたびに必ず出力バッファーをフラッシュしてください。フラッシュに失敗すると、リモートWolfが失敗する可能性があります。
単一のプロセスのみが作成されることに注意してください。すべてのオオカミはその1つのプロセス内で管理する必要があります。この仕様がどのように役立つかについて読んでください。
初期化
標準: S<id><mapsize>
\ n
標準出力: K<id>
\ n
<id>
: 00
または01
または...または99
説明:
文字S
が送信され、その後に2つの数字が続きます00
。01
、...、99
100匹のオオカミのどれが初期化されているかを示します。その特定のオオカミとの今後のすべての通信では、同じオオカミ<id>
が使用されます。
IDに続いて、数字の可変長シーケンスが送信されます。これはマップのサイズです。改行(\n
)に到達すると、数字のシーケンスが終了したことがわかります。
あなたのプロセスが生きていることを確認するために、あなたは受け取っK
たもの<id>
が続くキャラクターで返信する必要があります。他の返信は例外となり、狼を殺します。
移動
標準: M<id><C0><C1>...<C7><C8>
\ n
標準出力: <mv><id>
\ n
<Cn>
: W
または
またはB
またはS
またはL
W
:オオカミ
:空のスペース
B
:くま
S
:ストーン
L
:ライオン
<mv>
: H
またはU
またはL
またはR
またはD
H
: Move.HOLD
U
: Move.UP
L
: Move.LEFT
R
: Move.RIGHT
D
: Move.DOWN
説明:
キャラクターM
が送信され、その後に2人のキャラクター<id>
が移動を選択する必要があるウルフを示します。それに続いて、ウルフの周囲を表す9文字が行順に(一番上の行、真ん中の行、一番下の行から一番左の行へ)送信されます。
有効な移動文字のいずれかで返信し<mv>
、その後<id>
に確認のためにオオカミの2桁の数字を続けます。
攻撃
標準: A<id><C>
\ n
標準出力: <atk><id>
\ n
<C>
: W
またはB
またはS
またはL
<atk>
: R
またはP
またはS
またはD
R
: Attack.ROCK
P
: Attack.PAPER
S
: Attack.SCISSORS
D
: Attack.SUICIDE
説明:
キャラクターA
に続いて2つのキャラクターが送信され、<id>
どの狼が攻撃に参加しているかが示されます。これに続いて、<C>
攻撃しているものの種類を示す1つの文字、W
olf、B
耳、S
音、またはL
イオンが続きます。
<atk>
上記の文字のいずれかで返信し、攻撃に対するあなたの応答を示し<id>
、確認のために2桁の数字を続けます。
以上です。それ以上はありません。あなたが攻撃に負けた場合、それ<id>
はあなたのプロセスに再び送られることはありません、それはあなたのオオカミが死んだことを知る方法です-それ<id>
が送信されずに完全なMovementラウンドが過ぎた場合。
結論
作成されたタイプのすべてのオオカミに対して、リモートウルフの単一の「プロセス」のみが構築されるため、例外はリモートタイプのすべてのオオカミを殺すことに注意してください。
このリポジトリにWolf.java
ファイルがあります。次の文字列を検索および置換して、ボットをセットアップします。
<invocation>
プロセスを適切に実行するコマンドライン引数に置き換えます。
<custom-name>
ウルフの一意の名前に置き換えます。
例については、リポジトリをご覧ください。ここWolfRandomPython.java
では、リモートPythonWolf.py
(Python 3+ Wolf)を呼び出します。
ファイルの名前をに変更しますWolf<custom-name>.java
。ここ<custom-name>
で、上記で選択した名前に置き換えられます。
Wolfをテストするには、Javaプログラムをコンパイルし(javac Wolf<custom-name>.java
)、Rusherの指示に従ってシミュレーションプログラムに含めます。
重要:実際のWolfをコンパイル/実行する方法について、上記で概説したスキームに従って、明確で簡潔な指示を必ず提供してください。
幸運を祈ります。そして、自然があなたの好意によりますように。
ラッパーコード
覚えておいて、これが機能するために概説された検索と置換を行わなければなりません。あなたの呼び出しが特に毛深い場合は、支援のために私に連絡してください。
main
このラッパーには、ローカルボックスでの基本的な「合格/不合格」テストを許可するメソッドがあります。これを行うには、プロジェクトからAnimal.javaクラスをダウンロードし、package animals;
両方のファイルから行を削除します。Animal.javaのMAP_SIZE行をいくつかの定数(100など)に置き換えます。javac Wolf<custom-name>.java
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;
}
}
}