Обгортка для подання без Java
ПРИМІТКА Додано підтримку MAP_SIZE. Якщо вам все одно, будь ласка, оновіть подання відповідно.
Це запис у вікі спільноти для обгортки, який можна використовувати тим, хто хоче грати, але не любить / не знає Java. Будь ласка, використовуйте це, веселіться, і я радий допомогти вам налаштувати речі.
Тут досить пізно, коли я закінчу, тому інші кодери Java, будь ласка, перегляньте це та запропонуйте вдосконалення. Якщо ви можете, зробіть це через моє сховище github, подавши проблему або подавши виправлення. Дякую!
Це все розповсюджується за допомогою UNLICENSE, будь ласка, слідкуйте за ним / видобувайте його зі свого сховища github . Надішліть там патчі, якщо знайдете проблеми, і я оновлю цю публікацію.
Поточні приклади обгортки, що використовується
plannapus : WolfCollectiveMemory in R
зубна щітка : зубна щітка в ECMAScript
Як користуватись
Далі йдуть інструкції щодо протоколу для міжпроцесового зв’язку через PIPES, який я визначив для віддалених Вовків. Примітка: Я пропустив MAP_SIZE, оскільки, схоже, це не існує, незважаючи на його наявність у заяві проблеми ОП. Якщо вона з’явиться, я оновлю цю публікацію.
ВАЖЛИВІ ПРИМІТКИ :
- Буде зроблено лише одне виклик вашого зовнішнього процесу (тому оберніть свою логіку обробки у нескінченний цикл. Це також дозволяє зберігати будь-яку обробку в пам'яті замість використання диска)
- Вся комунікація полягає в цьому єдиному зовнішньому процесі через STDIN та STDOUT
- Ви повинні явно вимити весь результат, надісланий до STDOUT, і переконатися, що він закінчується новим рядком
Специфікація
Віддалені сценарії підтримуються простим протоколом через гачки STDIN і STDOUT і розділяються на ініціалізацію, Move та Attack. У кожному випадку зв'язок з вашим процесом буде здійснюватися через STDIN, і відповідь необхідна від STDOUT. Якщо відповідь не буде отримана протягом 1 секунди, ваш процес вважатиметься мертвим, і буде викинуто виняток. Усі символи будуть закодовані в UTF-8, для послідовності. Кожен вхід закінчується символом нового рядка, і ваш процес повинен також припиняти кожну вихідну відповідь новим рядком.
ПОПЕРЕДЖЕННЯ Не забудьте промити вихідний буфер після кожного запису, щоб переконатися, що обгортка Java бачить ваш вихід. Незмивання води може призвести до виходу з ладу вашого віддаленого Вовка.
Зауважте, що буде створено лише один процес, усіма Вовками слід керувати в рамках одного цього процесу. Прочитайте далі про те, як допоможе ця специфікація.
Ініціалізація
STDIN: S<id><mapsize>
\ n
STDOUT: K<id>
\ n
<id>
: 00
або 01
або ... або99
Пояснення:
Персонаж S
буде відправлений слідують два цифрових символів 00
, 01
..., 99
вказуючи , які з 100 вовків инициализируется. У всьому майбутньому спілкуванні з цим конкретним вовком <id>
буде використано те саме.
Після ідентифікатора буде надіслана послідовність числових символів змінної довжини. Це розмір карти. Ви знаєте, що послідовність числових символів закінчена, коли ви досягнете нового рядка ( \n
).
Щоб переконатися, що ваш процес живий, ви повинні відповісти з символом, K
а за ним - тим самим, який <id>
ви отримали. Будь-яка інша відповідь призведе до винятку, убивши ваших вовків.
Рух
STDIN: M<id><C0><C1>...<C7><C8>
\ n
STDOUT: <mv><id>
\ n
<Cn>
: W
або
або B
або S
абоL
W
: Вовк
: Порожній пробіл
B
: Ведмідь
S
: Камінь
L
: Лев
<mv>
: H
або U
або L
або R
абоD
H
: Перемістіть
U
: Move.UP
L
: Переміщення.LEFT
R
: Рух.праворуч
D
: Рух.ДОЛУ
Пояснення:
Персонаж M
буде надісланий, а потім два символи, <id>
щоб вказати, якому Вовку потрібно вибрати хід. Після цього буде надіслано 9 символів, що представляють оточення Вовка в порядку рядків (верхній рядок, середній ряд, нижній ряд з крайнього лівого вправо).
Відповідь з одним із дійсних символів руху <mv>
, після чого дві цифри Вовка <id>
для підтвердження.
Атака
STDIN: A<id><C>
\ n
STDOUT: <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
буде надісланий, а потім два символи, <id>
щоб вказати, який Вовк бере участь у нападі. Далі йде один символ, <C>
який вказує на тип речі, що атакує, або W
ельф, B
вухо, S
тон або L
іон.
Дайте відповідь одному з <atk>
перерахованих вище символів, вказуючи, яка ваша відповідь на напад, слідуючи двозначною <id>
для підтвердження.
І це все. Більше цього немає. Якщо ви програєте атаку, вона <id>
більше ніколи не буде надіслана вашому процесу, ось так ви дізнаєтесь, що ваш Вовк загинув - якщо повний раунд Руху пройшов без того, щоб він <id>
ніколи був відправлений.
Висновок
Зверніть увагу, що будь-які винятки знищать усіх Вовків вашого віддаленого типу, оскільки лише один "Процес" побудований з вашого віддаленого вовка для всіх вовків вашого типу, які створюються.
У цьому сховищі ви знайдете 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;
рядок з обох файлів. Замініть рядок MAP_SIZE в Animal.java на деяку константу (наприклад, 100). Скомпілюйте їх за javac Wolf<custom-name>.java
допомогою Execute через 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;
}
}
}