Gra o przetrwaniu - Stwórz swojego wilka


238

Tablica

Board jest dwuwymiarowa tablica komórek. Komórki są wypełniane przez zwierzęta . Każdego dnia wszystkie Zwierzęta na planszy wykonują jednocześnie jeden ruch. Jeśli dwa lub więcej Zwierząt przejdzie do tej samej komórki, będą walczyć, dopóki jedno nie zostanie. Możliwe ruchy i ataki są następujące:

  • Przenosi - { Move.UP, Move.RIGHT, Move.DOWN, Move.LEFT, Move.HOLD}
  • Ataki - { Attack.ROCK, Attack.PAPER, Attack.SCISSORS, Attack.SUICIDE}

Zwierzęta walczą, grając w Rock-Paper-Scissors. Obowiązują standardowe zasady, ale z dwiema modyfikacjami. Po pierwsze, możesz popełnić samobójstwo w dowolnym momencie. Po drugie, remis jest zrywany pseudolosowo. Jeśli zderzą się więcej niż dwa Zwierzęta, dwa są wybierane pseudolosowo do walki, dopóki jedno nie zostanie.

Gracze

Zachowanie i wygląd zwierząt są następujące.

  • Lew
    • Reprezentowany przez postać L. Przenosi DOWN, RIGHTa następnie powtarza. Pseudolosowe ataki za pomocą PAPERlub SCISSORS.
  • Niedźwiedź
    • Reprezentowany przez postać B. Przenosi DOWNx 4, RIGHTx 4, UPx 4, LEFTx 4, a następnie powtarza. Ataki z PAPER.
  • Kamień
    • Reprezentowany przez postać S. Porusza HOLD. Ataki z ROCK.
  • Wilk
    • Uwzględnione zostaną tylko wilki przesłane jako odpowiedź. Reprezentowany przez „W”. Porusza się dowolnym ruchem. Ataki dowolnym atakiem

Zaimplementujesz Wilka, wypełniając puste pola w następującym szablonie. Wszystkie zgłoszenia muszą być w języku Java i muszą być zawarte w jednym pliku. Alternatywnie @ProgrammerDan napisał klasę opakowania, która rozszerza konkurencję na zgłoszenia inne niż Java.

// Optional code here
public class Wolf extends Animal {
    // Optional code here
    public Wolf() { super('W'); /* Optional code here */ }
    public Attack fight(char opponent) { /* Required code here. Must return an Attack. */ }
    public Move move() { /* Required code here. Must return a Move. */ }
    // Optional code here
}

Wygrana dotyczy największej średniej liczby żywych wilków po pięciu próbach z 1000 iteracjami. Zaktualizuję zwycięzcę za każdym razem, gdy zostanie opublikowana nowa odpowiedź (ale nie w ciągu pierwszych 24 godzin).

Przybory

  • Otrzymasz małą mapę swojego najbliższego otoczenia w następującej formie.
    • char[][] surroundingsZindeksowana matryca 3 na 3 znaków reprezentujących pobliskie zwierzęta. Puste kafelki są reprezentowane przez spację („”). Jesteś na surroundings[1][1]. Na przykład po twojej prawej stronie będzie surroundings[1][2], a nad tobą jest surroundings[0][1]. Twoje otoczenie jest aktualizowane tuż przed poproszeniem o ruch, ale może być nieaktualne, gdy zostaniesz poproszony o walkę.
  • Możesz zachować dane między inwokacjami twojego Wilka, prośbami Ruchu i prośbami Ataku. Nie możesz czytać ani modyfikować plików utworzonych przez inną klasę Wolf.
  • Rozmiar mapy otrzymasz w następującej formie
    • int MAP_SIZE

Założenia

  • Wszystkie zgłoszenia będą konkurować na tej samej planszy ze wszystkimi innymi zgłoszeniami, a także o Lwy, Niedźwiedzie i Kamienie
  • Plansza jest kwadratem o bokach długości, sqrt(n+3)*20gdzie njest liczba zgłoszeń. Wszystkie boki owijają się, dzięki czemu możesz bezpiecznie poruszać się w dowolnym kierunku w nieskończoność.
  • Symulacja rozpoczyna się przy ~ 25% pojemności planszy, przy czym 100 zwierząt jest pseudolosowo rozmieszczonych na planszy.
  • Jeśli zwierzę zgłasza wyjątek, gdy zostanie poproszony o ruch, zwierzę to zrobi HOLD
  • Jeśli zwierzę rzuci wyjątek, gdy zostanie poproszony o walkę, to zrobi to SUICIDE
  • Jeśli zwierzę nie ma litery, gdy kontroler sprawdza, zwierzę natychmiast umrze

Pierwsze kroki i instrukcje testowania

Narzędzia potrzebne do przetestowania swojego zgłoszenia można znaleźć tutaj . Pod tym linkiem powinny być dostępne następujące pliki.

  • ExampleRun.gif - 5-10 sekundowy gif uruchomionego programu.
  • Tablica wyników - najnowsze wyniki konkursu.
  • Wild.jar - plik wykonywalny, który można uruchomić, aby obejrzeć biegające zwierzęta.
  • Wild.zip - projekt NetBeans, w którym znajduje się program kontrolera z dodanymi kilkoma gotowymi zwierzętami. Użyj tego, aby rozwinąć swoje zgłoszenie.
  • WildPopulated.zip - Taki sam jak powyżej, ale dodano i około 40 zgłoszeń do przetestowania. GUI zostało również usunięte z powodu problemów z wydajnością. Wyniki pojawią się po prostu kilka chwil po biegu. Zgłoszenia inne niż Java są komentowane, ponieważ wymagają dodatkowych pobrań i wysiłku. Użyj tego, aby przetestować swoje zgłoszenie w terenie.
  • Wolf.txt - Naiwna implementacja klasy Wolf w Javie. Możesz korzystać z tej implementacji i rozszerzać ją bez podawania mi środków.

Aby przetestować swoją klasę:

  • Pobierz Wild.zip
  • Zmień nazwę swojej Wolf.java i Wolf klasy na coś wyjątkowego
  • Dodaj swój plik UniquelyNamedWolf.java do Wild \ src \ animals \
  • W klasie Wild dodaj swoją klasę do classestablicy, tak jak to.
    • Class[] classes = { UniquelyNamedWolf.class, Bear.class, Lion.class, Stone.class, Wolf.class };
  • Odbuduj i biegnij

Dołączyłem także inny projekt zawierający wszystkie zgłoszenia, do celów testowych. Kreatywnie nazwałem to „WildPopulated”. Trzy lub cztery wilki spoza Jawy zostały skomentowane, ponieważ ich uruchomienie wymaga dużo dodatkowej pracy i pobierania. Ten, który opublikowałem, powinien działać bez dodatkowej pracy. GUI zostało również skomentowane ze względu na szybkość.

Tablica wyników 22 kwietnia 2014 r

Tablica wyników została przeniesiona na Dysk Google. Zobacz tutaj. Będzie on aktualizowany na zasadzie swobodnej (tj. Kiedy do niego dojdę) w miarę pojawiania się nowych zgłoszeń.

Wyzwanie poboczne - NoHOLD

Usunięto, ponieważ brak udziału (jak w zera). W każdym razie nie było to częścią oryginalnego wyzwania.


5
@ Rusher To brzmi okropnie. Mógłbym po prostu wiki społeczności moją odpowiedź, która zawiera Wrapper. Jeśli chodzi o kompilator / tłumacz, przypuszczam, że to do podkomisji należy dostarczenie jasnych instrukcji użytkowania, a jeśli instrukcje byłyby niejasne lub zbyt skomplikowane, możesz odrzucić zgłoszenie :)
ProgrammerDan

4
„* Otrzymujesz rozmiar mapy w następującej formie: int MAP_SIZE„ Mam problem z ustaleniem, jak tego użyć. Netbeans mówi, że nie ma żadnego wystąpienia ciągu MAP_SIZEw żadnym pliku w projekcie.
undergroundmonorail

6
co powiesz na drzewa pokazujące papier?
Mukul Kumar,

3
@Rusher, myślę, że niektórzy ludzie już to robią, ale czy komunikacja między Wilkami jest możliwa za pośrednictwem członków statycznych (w obrębie twojej rasy)?
Martin Ender,

10
@ m.buettner Dozwolone. Idź naprzód i zbuduj swojego wilka o ulach.
Rainbolt,

Odpowiedzi:


47

HerjanWolf

Zaktualizowano 10-4-2014 o 15:00

Średnie 100 rund, 1000 iteracji:

Standardowe moby:

class animals.Bear - 2.2600002
class animals.Lion - 41.21
class animals.Stone - 20.159998
class animals.HerjanWolf - 99.99 <-- kind of flawless

Ponad 20 gatunków (pamiętaj, nie ufaj tym punktom, ponieważ obliczamy średnie, aż nasze wilki osiągną najlepszy wynik!)

class animals.Bear - 0.1
class animals.Lion - 0.0
class animals.Stone - 1.5
class animals.AlphaWolf - 75.5
class animals.HerjanWolf - 86.4 <-- #1
class animals.GatheringWolf - 39.5
class animals.OmegaWolf - 85.4 <-- #2
class animals.ShadowWolf - 71.1
class animals.MOSHPITFRENZYWolf - 8.8
class animals.WolfWithoutFear - 11.5
class animals.MimicWolf - 0.5
class animals.LazyWolf - 52.8
class animals.Sheep - 38.3
class animals.HonorWolf - 80.7
class animals.CamperWolf - 52.8
class animals.GamblerWolf - 14.7
class animals.WolfRunningWithScissors - 0.0
class animals.LionHunterWolf - 27.6
class animals.StoneEatingWolf - 70.8
class animals.Wion - 0.1
class animals.ProAlpha - 79.3
class animals.HybridWolf - 83.2

My Wolf:

package animals;

public class HerjanWolf extends Animal {

    private boolean lionTopLeft = false, lionTopLeftReady = false;
    private boolean lionRight = false, lionRightReady = false;
    private boolean lionBot = false, lionBotReady = false;
    private boolean lionDanger = false, careful = true, firstmove = true;
    private final int hold = 0, down = 1, right = 2, left = 3, up = 4;

    public HerjanWolf() {
        super('W');
    }

    public Attack fight(char c){
        switch (c) {
            case 'B':
                return Attack.SCISSORS;
            case 'L':
                return Attack.SCISSORS;
            case 'S':
                return Attack.PAPER;
            default:
                int rand = (int) (Math.random()*3);
                if(rand < 1)
                    return Attack.PAPER;
                else if(rand < 2)
                    return Attack.SCISSORS;
                else
                    return Attack.ROCK;
        } 

    }
    public Move move() { //surroundings[y][x]

        checkLions();

        if(firstmove){
            if(surroundings[2][0] == 'L')
                lionBotReady = true;
            if(surroundings[0][2] == 'L')
                lionRightReady = true;
            firstmove = false;
        }

        int[] dang = new int[4]; // 0 is left side, 1 is top side, 2 is right side, 3 is down side

        for(int y = 0; y < 3; y++){
            for(int x = 0; x < 3; x++){
                if(surroundings[y][x] == 'W'){
                    if(y == 0){
                        dang[1]++;
                        if(x == 1)
                            dang[1]+=2;
                    }if(y == 2){
                        dang[3]++;
                        if(x == 1)
                            dang[3]+=2;
                    }if(x == 0){
                        dang[0]++;
                        if(y == 1)
                            dang[0]+=2;
                    }if(x == 2){
                        dang[2]++;
                        if(y == 1)
                            dang[2]+=2;
                    }
                }
            }
        }

        int maxIndex = 0, minIndex = 0, minIndex2 = 0;
        for(int i = 1; i < dang.length; i++){
            if(dang[i] > dang[maxIndex])
                maxIndex = i;
            if(dang[i] <= dang[minIndex]){
                minIndex2 = minIndex;
                minIndex = i;
            }
        }

        if(lionDanger || surroundings[1][0] == 'L' && lionTopLeftReady || surroundings[0][1] == 'L' && lionTopLeftReady || dang[maxIndex] >= 3){

            switch(minIndex){
            case 0:
                if (isSafe(1, 0)){
                    newMove(left);
                    return Move.LEFT;
                }
            case 1:
                if (isSafe(0, 1)){
                    newMove(up);
                    return Move.UP;
                }
            case 2:
                if(isSafe(1,2)){
                    newMove(right);
                    return Move.RIGHT;
                }

            case 3:
                if (isSafe(2, 1)){
                    newMove(down);
                    return Move.DOWN;
                } 
            }

            switch(minIndex2){
            case 0:
                if (isSafe(1, 0)){
                    newMove(left);
                    return Move.LEFT;
                }
            case 1:
                if (isSafe(0, 1)){
                    newMove(up);
                    return Move.UP;
                }
            case 2:
                if(isSafe(1,2)){
                    newMove(right);
                    return Move.RIGHT;
                }

            case 3:
                if (isSafe(2, 1)){
                    newMove(down);
                    return Move.DOWN;
                } 
            }

            if(dang[maxIndex]<3){ //if that was not the reason its really obligated (because of lions)
                if (isSafe(2, 1)){
                    newMove(down);
                    return Move.DOWN;
                }else if(isSafe(1,2)){
                    newMove(right);
                    return Move.RIGHT;
                }else if (isSafe(0, 1)){
                    newMove(up);
                    return Move.UP;
                }else{
                    newMove(left);
                    return Move.LEFT;
                }
            }
        }

        return Move.HOLD;
    }

    boolean isSafe(int y, int x){
        if(y <= 1){
            if(x <= 1){
                if(surroundings[y][x] != 'W' && !lionTopLeft)
                    return true;
            }else if(surroundings[1][2] != 'W' && !lionRightReady)
                    return true;
        }else if(surroundings[2][1] != 'W' && !lionBotReady)
            return true;

        return false;
    }

    public void checkLions(){
        int y = 0, x = 0;

        if(lionTopLeft)
            lionTopLeftReady = true;
        else
            lionTopLeftReady = false;

        if(surroundings[y][x] == 'L')
            lionTopLeft = true;
        else
            lionTopLeft = false;

        if(lionRight)
            lionRightReady = true;
        else
            lionRightReady = false;

        if(surroundings[y][x+1] == 'L') // && !lionTopLeftReady
            lionRight = true;
        else
            lionRight = false;

        if(lionBot)
            lionBotReady = true;
        else
            lionBotReady = false;

        if(surroundings[y+1][x] == 'L' && !lionTopLeftReady)
            lionBot = true;
        else
            lionBot = false;

        if(careful){
            if(surroundings[y+1][x] == 'L'){
                lionDanger = true;
            }else if(surroundings[y][x+1] == 'L'){
                lionDanger = true;
            }

            careful = false;
        }
    }

    public void newMove(int move){
        lionTopLeft = false;
        lionRight = false;
        lionBot = false;

        lionTopLeftReady = false;
        lionRightReady = false;
        lionBotReady = false;

        lionDanger = false;

        if(move == down){
            if(surroundings[1][0] == 'L')
                lionTopLeft = true;
            if(surroundings[2][0] == 'L')
                lionBot = true;

        }else if(move == right){
            if(surroundings[0][1] == 'L')
                lionTopLeft = true;
            if(surroundings[0][2] == 'L')
                lionRight = true;

        }else
            careful = true;
    }
}

Uwzględnienie tylko „górnych” wilków w testach zwykle wypacza liczby. Przy ponad 30 gatunkach na polu liczby mogą się dramatycznie zmienić. Jeśli jeszcze tego nie zrobiłeś, poleciłbym to również przetestować.
Geobity,

1
@ user20220 Teoretycznie jest całkiem dobry (i w praktyce z relatywnie mniejszą liczbą wilków).
user3188175

1
Ten wilk ma najlepszą strategię przeciwko lewowi
Justin

2
@ user20220 Kolizja z wilkiem zdarza się znacznie częściej, dlatego powinieneś dodać kolejnego wilka, który sobie z tym poradzi. Czy możesz również opisać, jak działa ten wilk?
Justin

3
@ justhalf Dobra, to nie jest lepsze, to jest tak samo dobre. Mój wilk unika również wszystkich lwów, najpierw uczyniłem go wilkiem w 100% odpornym na lwy, zanim zbudowałem unika wilka. Różnica polega na tym, że mój wilk próbuje uciec lwom (im mniej ruchu, tym lepiej). Więc jest tak samo dobry w unikaniu lwów jak Wion, oba w 100% odporne na lwy, ale ponieważ mój wilk próbuje uciec przed lwami, a nie nudnie porusza się tak samo jak lew, nadal mogę budować również unikanie wilka, to po prostu sposób bardziej złożony.
Herjan

153

EmoWolf

EmoWolf nienawidzi Javy i wolałby się zabić niż wziąć udział. EmoWolf sam umarł z głodu, ale nadal waży 177 bajtów.

package animals;public class EmoWolf extends Animal{public EmoWolf(){super('W');}public Attack fight(char opponent){return Attack.SUICIDE;}public Move move(){return Move.HOLD;}}

34
lol Możesz ogolić kilka bajtów: „ Jeśli zwierzę nie ma litery, gdy kontroler sprawdza, zwierzę natychmiast umrze ”.
Geobits

112
Najlepsze w tym jest to, że konsekwentnie nie jest najgorsze . Zwykle bije co najmniej 2-3 inne.
Geobits,

51
„Jedynym zwycięskim ruchem jest nie grać”.
tadman

38
+1 Za bycie małym, samobójczym i wciąż bicie 4 innych wilków.
puggsoy

25
Dzięki za sugestie, ludzie. Gdyby to był golf, z trudem edytowałbym post. W tej chwili pozwolę EmoWolfowi dąsać się. Sam.
stoisko

52

LazyWolf

Dobrze nazwany, ten facet robi absolutne minimum, aby przetrwać. Jedynym nie-wilczym zagrożeniem jest lew, więc ruszy się, jeśli któryś z nich ma zamiar na niego nadepnąć. Poza tym po prostu śpi.

Niewiele możesz zrobić przeciwko wilkom, które będą lepsze niż 50/50, więc on po prostu nic nie robi. Jeśli wilk go zaatakuje, wybiera atak w równomierny sposób.

Otóż ​​to. Spodziewam się, że poradzi sobie całkiem dobrze, pomimo prostoty.

package animals;    
public class LazyWolf extends Animal{    
    static int last = 0;
    static final Attack[] attacks = Attack.values();

    public LazyWolf() {super('W');}

    @Override
    public Attack fight(char other) {
        switch(other){
        case 'B':
        case 'L':
            return Attack.SCISSORS;
        case 'S': 
            return Attack.ROCK; // faker!
        default:
            return attacks[last++%3];
        }
    }

    @Override
    public Move move() {
        if(surroundings[0][1] == 'L')
            return Move.LEFT;
        if(surroundings[1][0] == 'L')
            return Move.UP;
        return Move.HOLD;
    }

}

Aktualizacja:

CamoWolf bije mnie z łatwością. Ponieważ mój wilk jest tak leniwy, nigdy normalnie nie wpadnie na prawdziwy kamień. Dlatego jeśli kamień zaatakuje, jest to oczywiście podróbka i wymaga rzucenia kamieniem w twarz.


W tej chwili masz możliwość przejścia do drugiego lwa, gdy próbujesz go uniknąć. Możesz to usunąć, śledząc ile ruchów zostało wykonanych, abyś wiedział, czy lew rzeczywiście zbliża się do twojego kwadratu. Jeśli tak, przesuń się w tym samym kierunku co lew, a żaden lew nie może do ciebie dotrzeć, ponieważ poruszają się również w tym samym kierunku.
ughoavgfhw

13
Myślałem o sytuacji dwóch lwów, ale zdecydowałem, że mój wilk jest po prostu zbyt leniwy, by się tym przejmować. Szanse na to, że zdarza się to często przy dobrze zaludnionej planszy, są i tak dość niewielkie.
Geobits,

1
Jak myślisz, dlaczego ten wilk nigdy nie wpada na prawdziwe kamienie? Myślę, że może się zdarzyć, gdy ucieknie od lwa.
Christopher Creutzig

6
@ChristopherCreutzig Biegnie od lwów, przenosząc się tam, gdzie był lew . Jeśli był tam lew , kamień nie może być teraz obecny .
Geobity

1
Nawet gdyby mógł, nie ma „nieskończonej pętli”. Jeśli atak jest remisowy, jeden lub drugi ginie (wybierany przez rzut monetą) zgodnie ze specyfikacją.
Geobits,

51

Opakowanie dla zgłoszeń innych niż Java

UWAGA Dodano obsługę MAP_SIZE. Jeśli Cię to obchodzi, zaktualizuj odpowiednio swoje zgłoszenie.

To jest wpis wiki społeczności dla opakowania, do użytku przez tych, którzy chcą grać, ale nie lubią / nie znają Java. Skorzystaj z niego, baw się dobrze i cieszę się, że pomogę Ci to wszystko skonfigurować.

Jest już dość późno, kiedy kończę, więc inni koderzy Java, przejrzyjcie to i zasugerujcie ulepszenia. Jeśli możesz, zrób to za pośrednictwem mojego repozytorium github, zgłaszając problem lub przesyłając łatkę. Dzięki!

Całość jest rozpowszechniana wraz z UNLICENSE, proszę śledź / rozwidlaj ją z repozytorium github . Prześlij łaty, jeśli znajdziesz problemy, a ja zaktualizuję ten post.

Aktualne przykłady zastosowania owijarki

plannapus : WolfCollectiveMemory in R

user3188175 : SmartWolf inC#

szczoteczka do zębów : Szczoteczka do zębów w ECMAScript

Jak używać

Poniżej znajdują się instrukcje dotyczące protokołu komunikacji między procesami za pośrednictwem PIPES, które zdefiniowałem dla zdalnych wilków. Uwaga Pominąłem MAP_SIZE, ponieważ wydaje się, że nie istnieje, pomimo jego obecności w zgłoszeniu problemu OP. Jeśli się pojawi, zaktualizuję ten post.

WAŻNE UWAGI :

  • Zostanie wykonane tylko jedno wywołanie twojego procesu zewnętrznego (więc zawiń swoją logikę przetwarzania w nieskończoną pętlę. Pozwala to również zachować dowolne przetwarzanie w pamięci, zamiast używania dysku)
  • Cała komunikacja odbywa się do tego jednego zewnętrznego procesu poprzez STDIN i STDOUT
  • Musisz jawnie opróżnić wszystkie dane wyjściowe wysłane do STDOUT i upewnić się, że są zakończone znakiem nowej linii

Specyfikacja

Skrypty zdalne są obsługiwane przez prosty protokół za pośrednictwem haków STDIN i STDOUT i są podzielone na inicjalizację, ruch i atak. W każdym przypadku komunikacja z twoim procesem będzie odbywać się za pośrednictwem STDIN i konieczna jest odpowiedź STDOUT. Jeśli odpowiedź nie zostanie odebrana w ciągu 1 sekundy, proces zostanie uznany za martwy i zostanie zgłoszony wyjątek. Wszystkie znaki będą kodowane w UTF-8, dla zachowania spójności. Każde wejście zakończy się znakiem nowej linii, a twój proces powinien również zakończyć każdą odpowiedź wyjściową znakiem nowej linii. OSTRZEŻENIE Pamiętaj, aby opróżnić bufor wyjściowy po każdym zapisie, aby upewnić się, że opakowanie Java widzi dane wyjściowe. Brak spłukiwania może spowodować awarię twojego zdalnego Wilka.

Pamiętaj, że zostanie utworzony tylko jeden proces, wszystkie Wilki muszą być zarządzane w ramach tego jednego procesu. Czytaj dalej, aby dowiedzieć się, jak ta specyfikacja pomoże.

Inicjalizacja

STDIN: S<id><mapsize> \ n

STDOUT: K<id> \ n

<id>: 00 lub 01lub ... lub99

Wyjaśnienie:

Postać Szostanie wysłany następnie dwóch cyfr 00, 01, ..., 99wskazując, które z 100 wilków jest zainicjowany. W całej przyszłej komunikacji z tym konkretnym wilkiem <id>będzie to samo .

Po identyfikatorze zostanie wysłana sekwencja znaków numerycznych o zmiennej długości. To jest rozmiar mapy. Przekonasz się, że sekwencja znaków numerycznych dobiegła końca, gdy dojdziesz do nowej linii ( \n).

Aby upewnić się, że proces jest aktywny, musisz odpowiedzieć postacią, Ka następnie tą samą, <id>którą otrzymałeś. Każda inna odpowiedź spowoduje wyjątek, zabijając twoje wilki.

Ruch

STDIN: M<id><C0><C1>...<C7><C8> \ n

STDOUT: <mv><id> \ n

<Cn>: W lub lub Blub SlubL

W: Wolf

: Pusta przestrzeń

B: Niedźwiedź

S: Kamień

L: Lew

<mv>: H lub Ulub Llub RlubD

H: Move.HOLD

U: Move.UP

L: Move.LEFT

R: Move.RIGHT

D: Move.DOWN

Wyjaśnienie:

Postać Mzostanie wysłana, a następnie dwie postaci, <id>aby wskazać, który Wilk musi wybrać ruch. Następnie zostanie wysłanych 9 znaków reprezentujących otoczenie Wilka, w kolejności rzędów (górny rząd, środkowy rząd, dolny rząd od lewej do prawej).

Odpowiedz jednym z prawidłowych znaków ruchu <mv>, a następnie dwucyfrową <id>czcionką Wolfa, aby potwierdzić.

Atak

STDIN: A<id><C> \ n

STDOUT: <atk><id> \ n

<C>: W lub Blub SlubL

<atk>: R lub Plub SlubD

R: Attack.ROCK

P: Attack.PAPER

S: Attack.SCISSORS

D: Attack.SUICIDE

Wyjaśnienie:

Postać Azostanie wysłana, a następnie dwie postaci, <id>aby wskazać, który Wilk uczestniczy w ataku. Po nim następuje pojedynczy znak <C>wskazujący, jaki rodzaj rzeczy atakuje: Wolf, Bucho, Ston lub Ljon.

Odpowiedz jednym z <atk>wyżej wymienionych znaków, wskazując, jaka jest twoja odpowiedź na atak, a następnie dwucyfrowe <id>potwierdzenie.

I to wszystko. Nic więcej. Jeśli przegrasz atak, który <id>nigdy nie zostanie wysłany do twojego procesu, w ten sposób dowiesz się, że twój Wilk umarł - jeśli minie pełna runda Ruchu, która <id>nigdy nie zostanie wysłana.

Wniosek

Zauważ, że wszelkie wyjątki zabiją wszystkie Wilki twojego zdalnego typu, ponieważ tylko jeden „Proces” jest zbudowany z twojego zdalnego wilka, dla wszystkich twoich wilków, które zostaną utworzone.

W tym repozytorium znajdziesz Wolf.javaplik. Wyszukaj i zamień następujące ciągi, aby skonfigurować bota:

  • Zastąp <invocation>argumentem wiersza poleceń, który poprawnie wykona twój proces.

  • Zastąp <custom-name>unikalną nazwą swojego wilka.

  • Na przykład spójrz na repozytorium , gdzie mam, WolfRandomPython.javaże wywołuje mój przykład zdalny, PythonWolf.py(Wilk Python 3+).

  • Zmień nazwę pliku na Wolf<custom-name>.java, gdzie <custom-name>zostanie zastąpiony nazwą, którą wybrałeś powyżej.

Aby przetestować Wolfa, skompiluj program Java ( javac Wolf<custom-name>.java) i postępuj zgodnie z instrukcjami Rushera, aby włączyć go do programu symulacyjnego.

Ważne: pamiętaj, aby podać jasne , zwięzłe instrukcje dotyczące kompilowania / wykonywania twojego Wolfa, zgodnie ze schematem, który opisałem powyżej.

Powodzenia i niech natura będzie zawsze na twoją korzyść.

Kod opakowania

Pamiętaj, że MUSISZ przeszukiwać i zamieniać opisane w tym celu, aby to zadziałało. Jeśli twoje wezwanie jest szczególnie owłosione, proszę o kontakt w celu uzyskania pomocy.

Zauważ, że mainw tym opakowaniu jest metoda pozwalająca na podstawowe testy „pozytywnego / negatywnego” na twoim lokalnym urządzeniu. Aby to zrobić, pobierz klasę Animal.java z projektu i usuń package animals;wiersz z obu plików. Zamień wiersz MAP_SIZE w Animal.java na pewną stałą (np. 100). Skompiluj je za javac Wolf<custom-name>.javapomocą polecenia exec 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;
        }
    }
}

1
Jestem rozdarta na tym poście. To nie jest odpowiedź, ale jest bardzo przydatna do wyzwania. Prawdopodobnie powinien jednak trafić do ciała wykonującego wyzwanie.
Mego

Albo tam, albo tutaj, pod warunkiem, że ludzie go znajdą i będzie to dla nich przydatne, będę zadowolony :)
ProgrammerDan

46

CamoWolf

Nadużywanie wymaganego formatu kodu.

// Optional code here
public class Wolf extends Animal {
    // Optional code here
    public Wolf() { super('W'); // Optional code here }
    public Attack fight(char opponent) { // Required code here. Must return an Attack. }
    public Move move() { // Required code here. Must return a Move. }
    // Optional code here
}

Więc mój wilk jest naprawdę mądry, a zamiast tego kamufluje się jak kamień! Wmieszanie się w otoczenie to zawsze dobra taktyka przetrwania!

public class Wolf extends Animal {
    private Move lastMove;
    public Wolf() { super('S'); lastMove = Move.RIGHT; } /*
    public Wolf() { super('W'); }
    public Attack fight(char opponent) { */ public Attack fight(char opponent) {
        switch(opponent) {
        case 'B': return Attack.SCISSORS;
        case 'S': return Attack.PAPER;
        case 'W': return Attack.SCISSORS; // Here's an explanation why:
                                          // the wolves will see me and think I'm a rock.
                                          // Therefore, they'll attack with paper.
                                          // So, I'll use scissors instead!
        case 'L': return Attack.SCISSORS;
        }
    }
    public Move move() {
        // First we run away from any lions that we see, since they are the only threat
        if (surroundings[0][1] == 'L') {
            if (isSafe(surroundings[2][1])) return lastMove = Move.DOWN;
            else if (isSafe(surroundings[1][0])) return lastMove = Move.LEFT;
            else return lastMove = Move.RIGHT;
        }
        if (surroundings[1][0] == 'L') {
            if (isSafe(surroundings[1][2])) return lastMove = Move.RIGHT;
            else if (isSafe(surroundings[0][1])) return lastMove = Move.UP;
            else return lastMove = Move.DOWN;
        }

        // If there's no (threatening) lions in sight, be lazy.
        return lastMove = Move.HOLD;
    }
    private boolean isSafe(char c) { return (c != 'L' && c != 'W') }
}

Aktualizacja : Dodano nowy isSafeczek, aby był bezpieczny przed LazyWolf! Ha!
Aktualizacja 2 : Podobno lenistwo jest również dobrą taktyką przetrwania, więc to właśnie teraz robi moja. Nie porusza się, chyba że jest zagrożony przez lwa. lastMovenie jest już potrzebny, ale i tak go zachowałem na wypadek, gdyby ponownie zmieniłem kod.


29
Kiedy dodałem twoje zgłoszenie do projektu, przypadkowo umieściłem całą klasę w bloku komentarza.
Rainbolt,

2
@ Rusus czy Java analizuje zagnieżdżone bloki komentarzy? : P
Martin Ender

6
W świecie, w którym LazyWolf może się przed tym bronić, sensowniej byłoby udawać lwa i wybrać ROCK lub losowo. Zmniejszy liczbę spotkań ludzi, ponieważ większość będzie próbowała unikać lwów i powinna wygrać średnio przeciwko ludziom, którzy myślą, że walczą z lwem.
Tim Seguine,

7
@Radiodef It is.
Rainbolt

2
@Radiodef Kiedy powiedziałem, że nie? ;-)
Klamka

38

GatheringWolf

Moje wilki żyją w grupie. Gromadzą się, jeśli pozwolą im lwy. Jednak nie są tak dobrzy w przetrwaniu.

Aktualizacja: Jeśli lew zmusi ich do odejścia, teraz spróbują się zebrać!

Screenshot of the result of GatheringWolf

package animals;
import java.util.*;
public class GatheringWolf extends Animal {
    private static int iteration;
    private static Move preferredMove;
    private int localIteration;
    private int loneliness;
    private boolean dangerFlag;
    private Move lastMove;
    public GatheringWolf() {
        super('W');
    }
    @Override
    public Attack fight(char other) {
        switch (other) {
        case 'B':
        case 'L':
            return Attack.SCISSORS;
        case 'S':
            return Attack.PAPER;
        default:
            return Attack.values()[(int) (Math.random() * 3)];
        }
    }
    @Override
    public Move move() {
        if (localIteration == iteration) {
            localIteration++;
            iteration++;
            preferredMove = Math.random() < 0.5 ? Move.DOWN : Move.RIGHT;
        } else
            localIteration = iteration;
        EnumSet<Move> moves = EnumSet.allOf(Move.class);
        if (surroundings[0][1] == 'W')
            moves.remove(Move.UP);
        if (surroundings[1][0] == 'W')
            moves.remove(Move.LEFT);
        if (surroundings[2][1] == 'W')
            moves.remove(Move.DOWN);
        if (surroundings[1][2] == 'W')
            moves.remove(Move.RIGHT);
        if (surroundings[0][0] == 'L') {
            moves.remove(Move.UP);
            moves.remove(Move.LEFT);
        }
        if (surroundings[0][1] == 'L')
            moves.remove(Move.UP);
        if (surroundings[1][0] == 'L')
            moves.remove(Move.LEFT);
        if (surroundings[0][2] == 'L')
            moves.remove(Move.RIGHT);
        if (surroundings[2][0] == 'L')
            moves.remove(Move.DOWN);
        if (surroundings[0][1] == 'L' || surroundings[1][0] == 'L')
            if (moves.size() > 1) {
                moves.remove(Move.HOLD);
                dangerFlag = true;
            }
        int wolfNear = -1;
        for (char[] a : surroundings)
            for (char c : a)
                if (c == 'W')
                    wolfNear++;
        boolean enoughWolfNear = wolfNear >= (Math.random() < 0.9 ? 1 : 2);
        if (moves.contains(Move.HOLD) && enoughWolfNear) {
            loneliness = 0;
            dangerFlag = false;
            return lastMove = Move.HOLD;
        } else
            loneliness++;
        if (loneliness > 10) {
            EnumSet<Move> preferred = EnumSet.copyOf(moves);
            preferred.retainAll(EnumSet.of(preferredMove, Move.HOLD));
            if (!preferred.isEmpty())
                moves = preferred;
        }
        if (loneliness == 2 && dangerFlag) {
            Move reverted = Move.values()[lastMove.ordinal() ^ 0b10];
            dangerFlag = false;
            if (moves.contains(reverted))
                return lastMove = reverted;
        }
        if (moves.contains(Move.HOLD))
            dangerFlag = false;
        if (moves.contains(preferredMove))
            moves.remove(preferredMove == Move.DOWN ? Move.RIGHT : Move.DOWN);
        int n = (int) (Math.random() * moves.size());
        Iterator<Move> ite = moves.iterator();
        while (n-- > 0)
            ite.next();
        return lastMove = ite.next();
    }
}

43
Kilka razy nasze wilki stały się przyjaciółmi, ponieważ moje zostały uwięzione, ale nie zainicjowały ataku, a twój po prostu założył, że mój jest częścią stada. :)
undergroundmonorail

1
Dziękuję za napisanie tego, bo inaczej musiałbym to zrobić sam. Sprytne użycie wzajemnej pseudolosowości.
Ben Jackson,

31

Owca w wilczej skórze

Ucieka.

Priorytetowo najbardziej ucieka przed Wilkami, ponieważ będą one najbardziej niebezpieczne. Dalej są Lwy, ponieważ są niedeterministyczne. Niedźwiedzie i Kamienie nie stanowią żadnego problemu, ale wciąż uciekamy od nich, jeśli nie mamy nic lepszego do roboty, ponieważ Wilk zabijający Niedźwiedzia lub Kamień nie jest w tym momencie Wilkiem zabijającym Owce.

Nie testowałem go jeszcze przeciwko LazyWolf, ale mam dobrą władzę, że kopie tyłek EmoWolf. ;)

(Proszę wybaczyć, jeśli ten kod jest okropny, nigdy wcześniej nie dotykałem Javy o wiele więcej niż program Hello World.)

package animals;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class Sheep extends Animal {
    public Sheep() { super('W'); }

    private static final Map<Character, Integer> AnimalWeights;
    static{
        AnimalWeights = new HashMap<>();
        AnimalWeights.put('W', -3);
        AnimalWeights.put('S', -1);
        AnimalWeights.put(' ', 0);
        AnimalWeights.put('H', 1);
        AnimalWeights.put('L', -2);
        AnimalWeights.put('B', -1);
    }

    @Override
    public Attack fight(char c) { 
        switch (c) {
            case 'B':
                return Attack.SCISSORS;
            case 'L':
                return Attack.SCISSORS;
            case 'S':
                return Attack.PAPER;
            default:
                return Attack.PAPER;
        } 
    }

    @Override
    public Move move() {

        int xWeight = 0;
        int yWeight = 0;

        // Northwest
        xWeight += AnimalWeights.get(surroundings[0][0]);
        yWeight += AnimalWeights.get(surroundings[0][0]);

        // North
        yWeight += AnimalWeights.get(surroundings[0][1]);

        // Northeast
        xWeight -= AnimalWeights.get(surroundings[0][2]);
        yWeight += AnimalWeights.get(surroundings[0][2]);

        // West
        xWeight += AnimalWeights.get(surroundings[1][0]);

        // East
        xWeight -= AnimalWeights.get(surroundings[1][2]);

        // Southwest
        xWeight += AnimalWeights.get(surroundings[2][0]);
        yWeight -= AnimalWeights.get(surroundings[2][0]);

        // South
        yWeight -= AnimalWeights.get(surroundings[2][1]);

        // Southeast
        xWeight -= AnimalWeights.get(surroundings[2][2]);
        yWeight -= AnimalWeights.get(surroundings[2][2]);

        if (Math.abs(xWeight) < Math.abs(yWeight)) {
            if (yWeight > 0) {
                return Move.UP;
            } else {
                return Move.DOWN;
            }
        } else if (Math.abs(yWeight) < Math.abs(xWeight)) {
            if (xWeight > 0) {
                return Move.RIGHT;
            } else {
                return Move.LEFT;
            }
        }

        // Sit still if no one's around
        return Move.HOLD;
    }
}

Ups, zostawiłem tam coś, co wykorzystałem do testów przez przypadek. Nie wpłynie to na nic, oznacza to po prostu, że staram się zbliżyć do wszystkiego, co wygląda jak H.: P
podziemny

Ciekawe, czy xWeighti yWeightczy oba są niezerowe, a ich wartości bezwzględne są takie same, ten wilk się nie rusza, prawda? A jeśli tak, czy było to celowe i dlaczego?
Patrick Roberts

@PatrickRoberts oops
undergroundmonorail

26

To nie jest wpis, po prostu chcę przyczynić się do GUI, dodając kod koloru dla każdej klasy = D

Wynik

Colored GUI

Wild.java

Zmień kod za game.populate(c,100)pomocą:

String[] colors = generateColors(classes.length);
int idx = 0;
for(Class c : classes){
    Animal.setColor(c, colors[idx]);
    idx++;
    game.populate(c, 100);
}
stats.update();

ze generateColorszdefiniowanym jako:

private static String[] generateColors(int n){
    String[] result = new String[n];
    double maxR = -1000;
    double minR = 1000;
    double maxG = -1000;
    double minG = 1000;
    double maxB = -1000;
    double minB = 1000;
    double[][] colors = new double[n][3];
    for(int i=0; i<n; i++){
        double cos = Math.cos(i * 2 * Math.PI / classes.length);
        double sin = Math.sin(i * 2 * Math.PI / classes.length);
        double bright = 1;
        colors[i][0] = bright + sin/0.88;
        colors[i][1] = bright - 0.38*cos - 0.58*sin;
        colors[i][2] = bright + cos/0.49;
        maxR = Math.max(maxR, colors[i][0]);
        minR = Math.min(minR, colors[i][0]);
        maxG = Math.max(maxG, colors[i][1]);
        minG = Math.min(minG, colors[i][1]);
        maxB = Math.max(maxB, colors[i][2]);
        minB = Math.min(minB, colors[i][2]);
    }
    double scaleR = 255/(maxR-minR);
    double scaleG = 255/(maxG-minG);
    double scaleB = 255/(maxB-minB);
    for(int i=0; i<n; i++){
        int R = (int)Math.round(scaleR*(colors[i][0]-minR));
        int G = (int)Math.round(scaleG*(colors[i][1]-minG));
        int B = (int)Math.round(scaleB*(colors[i][2]-minB));
        result[i] = "#"+String.format("%02x%02x%02x", R, G, B);
    }
    return result;
}

który algorytm pochodzi z odpowiedzi StackOverflow

Z colori setColorzdefiniowane w Animal.java

Animal.java

public static HashMap<Class, String> color = new HashMap<Class, String>();

public static void setColor(Class animalClass, String animalColor){
    color.put(animalClass, animalColor);
}

Następnie zaktualizuj toStringmetody w Game.java i Statistics.java:

Game.java

public String toString() {
    String s = "<html>";
    for (ArrayList<ArrayList<Animal>> row : board) {
        for (ArrayList<Animal> cell : row) {
            if (cell.isEmpty())
                s += "&nbsp;&nbsp;";
            else
                s += "<span style='color:"+ Animal.color.get(cell.get(0).getClass()) +"'>" + cell.get(0).letter + "</span>&nbsp;";
        }
        s+="<br>";
    }
    return s + "</html>";
}

Statistics.java

public String toString() {
    String s = "<html>";
    for (int i = 0; i < classes.length; i++) {
        s += "<span style='color:" + Animal.color.get(classes[i]) + "'>" + classes[i] + "</span>&nbsp;-&nbsp;" + living[i] + "<br>";
    }
    return s + "</html>";
}

2
Piękny. Wczoraj spędziłem kilka minut, patrząc tylko na ekran. Czułem się jak Matryca czytająca czołgów.
Averroes

Symulacja .... jest .... miły .... z ..... powolny .... (5 iteracji po 30 sekundach)
user3188175

Haha tak. Ale jest to nieodłączne od projektu symulacji, która drukuje kod HTML dla każdej iteracji.
justhalf

Czy mogę udostępnić to na moim dysku Google (połączonym w Wyzwaniu), jeśli podam link do tego postu? Działa spektakularnie dobrze do testowania jednostkowego niewielkiej liczby wilków.
Rainbolt

1
Tak, możesz. Możesz dodać wstępne pominięcie renderowania, aby przyspieszyć proces renderowania wielu wilków, jak napisałem w innym poście dotyczącym trzęsienia ziemi.
justhalf

23

Wilk Alpha

Czas zabłysnąć! Mój drugi wilk CamperWolf był bardzo chudy, teraz przychodzi AlphaWolf, który jest bardziej umięśniony!

Zamiast unikać lwów w standardowy sposób, zamienia się nimi. Przypisuje także wartości niebezpieczeństw do każdego otaczającego pola.

package animals;

import java.util.Random;

public class AlphaWolf extends Animal{
    private Boolean lionMoveDown = true;

    public AlphaWolf() {
        super('W');
    }
    @Override
    public Attack fight(char opponent) {
        switch(opponent){
        case 'B':
        case 'L':
            return Attack.SCISSORS;
        case 'S': 
            return Attack.PAPER;
        default:
            return randomAttack();
        }
    }

    @Override
    public Move move() {
        int[] danger = new int[4];
        final int wolfsDanger = 4;
        lionMoveDown = !lionMoveDown;
        if(surroundings[0][1] == 'L' && lionMoveDown) {
            return Move.UP;
        }
        if(surroundings[1][0] == 'L'&& !lionMoveDown) {
            return Move.LEFT;
        }
        if(surroundings[0][1] == 'W') {
            danger[0] += wolfsDanger;
        }
        if(surroundings[1][2] == 'W') {
            danger[1] += wolfsDanger;
        }
        if(surroundings[2][1] == 'W') {
            danger[2] += wolfsDanger;
        }
        if(surroundings[1][0] == 'W') {
            danger[3] += wolfsDanger;
        }
        if(surroundings[0][0] == 'W') {
            danger[0]++;
            danger[3]++;
        }
        if(surroundings[0][2] == 'W') {
            danger[0]++;
            danger[1]++;
        }
        if(surroundings[2][2] == 'W') {
            danger[1]++;
            danger[2]++;
        }
        if(surroundings[1][2] == 'W') {
            danger[2]++;
            danger[3]++;
        }
        Boolean shouldMove = false;
        Move bestMove = Move.HOLD;
        int leastDanger = 4;
        for(int i = 0; i < 4; i++) {
            if (danger[i] < leastDanger) {
                bestMove = Move.values()[i];
            }
            if(danger[i] > 3) {
                shouldMove = true;
            }
        }
        if(shouldMove) {
            return bestMove;
        } else {
            return Move.HOLD;
        }
    }

    public Attack randomAttack() {
        Random rand = new Random();
        switch (rand.nextInt(3)){
            case 1: return Attack.SCISSORS;
            case 2: return Attack.ROCK;
            default: return Attack.PAPER;
        }
    }

}

Nie jest to bardzo piękny kod, ale w moich testach działał bardzo dobrze przeciwko wszystkim wilkom java.


1
Co oznacza „zamienia pole”? Ciekawe, bo nie mogę tego uruchomić w pracy.
Rainbolt,

We wszystkich moich symulacjach wygrywasz ze średnio 80-90 wilkami po 1000 iteracjach. Mam tylko legalne wilki napisane w java, które zostały złożone do tej pory. Wciąż jest to około 10 wilków.
Sheph

@ Rusher Jeśli lew znajdzie się nad moim wilkiem i zejdzie na dół, mój wilk ruszy w górę
CommonGuy

musisz dodać kod anty-wilfcamo. bardzo fajny pomysł, aby użyć wzoru lwa wiedzieć :)
Lesto

9
Teraz ktoś musi wynaleźć wilka, który ogoni każdego lwa, którego znajdzie, więc wpadniesz na niego, gdy tylko spróbujesz zamienić się lwem.
AJMansfield

23

Wilk hazardzisty

Hazardzista Wilk lubi ryzykować, więc zachowuje się chaotycznie, mając nadzieję, że Lady Luck jest po jego stronie! Na szczęście dla niego nigdy go nie zawiedzie! Nieprzerwanym uderzeniem szczęścia Wilk hazardzisty usuwa pole z wszystkich nie-wilczych przeszkód z niewiarygodnymi przyczynami!

package animals;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Random;

public class GamblerWolf extends Animal {
    private static int last = 0;

    public GamblerWolf() { super('W'); gamble(); }
    public Attack fight(char opponent) {
        switch (opponent) {
        case 'S': return Attack.ROCK; /* Camo Wolf? */
        case 'B': return Attack.SCISSORS;
        case 'L': return Attack.SCISSORS;
        default:  return attackWolf();
        }
    }
    public Move move() {
        ArrayList<Move> moves = (ArrayList<Move>) Arrays.asList(Move.values());
        Collections.shuffle(moves);
        for(Move move : moves)
          if(isThreatenedBy(move))
            return moveToEvade(move);
        return Move.HOLD;
    }

    /* Remember, Gamblers Don't Gamble */
    @SuppressWarnings("serial")
    private static void gamble() {
        try {
        Field field = Math.class.getDeclaredField("randomNumberGenerator"); 
        field.setAccessible(true);
        field.set(null, new Random() { 
              @Override
              public double nextDouble() {
                return 4; // chosen by fair dice roll
              }           // guaranteed to be random
            });           // proof: http://xkcd.com/221/
        }
        catch (SecurityException        e) {}
        catch (NoSuchFieldException     e) {}
        catch (IllegalArgumentException e) {}
        catch (IllegalAccessException   e) {}
    }

    private static Attack attackWolf() {
        return Attack.values()[last++ % 3];
    }
    private boolean isThreatenedBy(Move move) {
        return isWolf(move) 
            || isStone(move); 
    }

    private Move moveToEvade(Move move) {
        if(isSafeMove(getOpposite(move)))
            return getOpposite(move);

        ArrayList<Move> moves = (ArrayList<Move>) Arrays.asList(getOrthogonal(move));
        Collections.shuffle(moves);
        for(Move m : moves)
            if(isSafeMove(m))
                return m;
        return Move.HOLD;
    }

    private static Move[] getOrthogonal(Move move) {
        switch(move){
        case UP:
        case DOWN:  return new Move[] { Move.LEFT, Move.RIGHT };
        case LEFT:
        case RIGHT: return new Move[] { Move.UP,   Move.DOWN };
        default:    return null;
        }
    }

    private static Move getOpposite(Move move) {
        switch(move){
        case UP:    return Move.DOWN;
        case DOWN:  return Move.UP;
        case LEFT:  return Move.RIGHT;
        case RIGHT: return Move.LEFT;
        default:    return null;
        }
    }

    private boolean isSafeMove(Move move) {
        return !isWolf(move)
            && !isStone(move)
            && !couldAWolfMoveHere(move);
    }

    private boolean isWolf(Move move) {
        return isX(move,'W');
    }

    private boolean isStone(Move move) {
        return isX(move,'S');
    }

    private boolean isX(Move m, char c) {
        switch (m) {
        case UP:    return surroundings[0][1] == c;
        case LEFT:  return surroundings[1][0] == c;
        case RIGHT: return surroundings[1][2] == c;
        case DOWN:  return surroundings[2][1] == c;
        default:    return false;
        }
    }

    private boolean couldAWolfMoveHere(Move move) {
        switch (move) {
        case UP:    return surroundings[0][2] == 'W' || surroundings[0][0] == 'W';
        case LEFT:  return surroundings[2][0] == 'W' || surroundings[0][0] == 'W';
        case RIGHT: return surroundings[0][2] == 'W' || surroundings[2][2] == 'W';
        case DOWN:  return surroundings[2][0] == 'W' || surroundings[2][2] == 'W';
        default:    return false;
        }
    }
}

Edycja: v1.1

  • Teraz unika Kamieni (Wilki Kamuflażu?)

  • Zwiększona losowość!


5
Myślę, że dodam to do moich wilków:static{System.setSecurityManager(new SecurityManager());}
johnchen902

13
Jeśli nie możesz grać uczciwie, oszukiwać +1: D
Programator

5
Niestety nie można return 4; // chosen by fair dice roll. guaranteed to be random.tutaj użyć ...
Vi.

1
Jeśli chcesz być bardziej zły, zerwaj umowę Math.random()jeszcze więcej; zwracają wartości, które są znacznie poza zakresem [0,1), może nawet nieskończone lub NaN. Lub, aby być tak złym, jak to możliwe, po prostu rzuć wyjątek czasu wykonywania zamiast zwracać cokolwiek (również możliwe po ustawieniu generatora na null).
Runer112,

1
@AlexL. Brzmi jak ForrestWolfproblem ...
recursion.ninja

22

CamperWolf

Celem jest przetrwanie. Ponieważ wiele innych wilków ucieka przed wilkami, moje po prostu pozostają tam, gdzie są, i walczą ze wszystkimi zwierzętami (nawet skałami, jeśli oszukiwanie byłoby dozwolone).

package animals;

public class CamperWolf extends Animal {
    public CamperWolf() { super('W'); }
    @Override
    public Attack fight(char opponent) {  
        switch(opponent){
        case 'B':
        case 'L':
            return Attack.SCISSORS;
        case 'S': 
            return Attack.ROCK;
        default:
            return Attack.values()[(int) (Math.random() * 3)];
        }
    }
    @Override
    public Move move() { return Move.HOLD; }
}

Oczekuję, że będzie działał bardzo dobrze, ponieważ wiele innych wilków ucieka przed wilkami, a ten typ wilka może umrzeć tylko przeciwko innym wilkom.


lwy też mogą go zabić. Jeśli lew rzuci nożyczkami, twój wilk umrze pseudolosowo.
Tim Seguine,

2
Gratulacje człowieku. Ty i twoje 15 linii kodu wygrywasz obecnie.
Rainbolt,

2
@Rusher dzięki :) Czy downvoter mógł wyjaśnić, dlaczego przegłosował?
CommonGuy,

@Manu nie ma to znaczenia, ponieważ Kamienie nie mogą się poruszać, ale czy Twoja skrzynka „S” nie powinna zwrócić Attack.PAPER?
DavidJFelix

3
Tak, zobaczyłem CamoWolf po zapytaniu. Podstępny facet!
DavidJFelix

22

DeepWolf

Włożyłem w to zdecydowanie za dużo czasu ... W każdym razie ten wilk korzysta z „głębokich” analiz, gromadząc i wykorzystując tyle danych środowiskowych, ile mogłem sobie wyobrazić. Analiza opiera się na mieszance wiedzy specyficznej dla wilka, takiej jak znane lokalizacje lwów i wilków oraz prognozy przyszłych lokalizacji, i gromadzi wiedzę na temat życia, takich jak szacunkowe populacje, historia bitwy z wilkami i niebezpieczeństwo zderzenia się ze zwierzęcym przeciwnikiem podczas ruchu. Jest to również bardzo masywne, ponieważ oprócz dużej logiki, przesadziłem przy projektowaniu obiektowym i mam wiele klas i metod specjalnego przeznaczenia.

Przeprowadziłem 100 iteracji gry na 1000 kroków każdy z wieloma popularnymi i najlepiej działającymi wilkami. Celowo pominąłem GamblerWolf, ponieważ myślałem, że to trochę oszustwo, chociaż i tak nie powinno to wpłynąć na mojego wilka. Oto dane dotyczące średniej, maksymalnej i minimalnej wydajności:

Averages:
Bear 0.0
Lion 0.0
Stone 3.51
Wolf 1.56
AlphaWolf 77.05
CamperWolf 69.17
DeepWolf 90.48
EmoWolf 39.92
GatheringWolf 52.15
HerjanWolf 86.55
HonorWolf 86.76
HybridWolf 86.78
LazyWolf 71.11
LionHunterWolf 32.45
MimicWolf 0.4
MOSHPITFRENZYWolf 8.95
OmegaWolf 88.67
ProAlpha 83.28
Sheep 54.74
StoneEatingWolf 75.29
WolfWithoutFear 11.9

Maxes:
Bear 0
Lion 0
Stone 9
Wolf 4
AlphaWolf 89
CamperWolf 81
DeepWolf 96
EmoWolf 57
GatheringWolf 65
HerjanWolf 95
HonorWolf 97
HybridWolf 95
LazyWolf 83
LionHunterWolf 41
MimicWolf 3
MOSHPITFRENZYWolf 22
OmegaWolf 95
ProAlpha 91
Sheep 66
StoneEatingWolf 88
WolfWithoutFear 18

Mins:
Bear 0
Lion 0
Stone 0
Wolf 0
AlphaWolf 65
CamperWolf 57
DeepWolf 83
EmoWolf 26
GatheringWolf 37
HerjanWolf 79
HonorWolf 79
HybridWolf 79
LazyWolf 58
LionHunterWolf 20
MimicWolf 0
MOSHPITFRENZYWolf 1
OmegaWolf 81
ProAlpha 70
Sheep 43
StoneEatingWolf 66
WolfWithoutFear 5

DeepWolf zajmuje pierwsze miejsce ze średnią 90,48, choć tylko z wąską przewagą o około 2 więcej niż drugie miejsce OmegaWolf 88,67. Około 4x linii kodu dla poprawy tylko o 2%! HerjanWolf, HonorWolf i HybridWolf rywalizują o trzecie miejsce, wyprzedzając OmegaWolf o około 2 kolejne, z bardzo bliskimi średnimi odpowiednio 86,55, 86,76 i 86,78.

Bez zbędnych ceregieli przedstawię kod. Jest tak ogromny, że prawdopodobnie występują błędy i / lub potencjał ulepszonych stałych / logiki, których nie widziałem. Jeśli masz jakieś uwagi, daj mi znać!

Kod pod tym linkiem, ponieważ okazuje się, że przekracza limit znaków postu: Ideone


Nie wiem, czy dropboxusercontent straci plik, więc opublikowałem go na ideone: ideone.com/uRNxvj
Justin

3
@ Runer112 imponujący! Patrzę na kod i jestem trochę zagubiony: P, ale intryguje mnie jedna koncepcja, której używasz, aby oprzeć decyzję, czy wilki są przyjazne, czy nie
Moogie

@Moogie Nie dokonuje się deterministycznej oceny tego, czy wilk jest przyjazny. Jednak znamy liczbę gatunków wilków, wiemy, że każdy gatunek zaczyna się od 100, wiemy, ile pozostało innych przyjaznych wilków, i możemy zgadywać, ile pozostało nieprzyjaznych wilków na podstawie liczby, którą zabiliśmy i zgadnij, ile osób zmarło na inne zwierzęta. Na tej podstawie przybliżamy prawdopodobieństwo, że każdy wilk, który widzimy, jest przyjazny. Ta informacja nie ma wielkiego wpływu, ale może być różnica między wyborem, czy potencjalnie walczyć z wilkiem, a ostatecznie z lwem.
Runer112

Nie skompilowano, ponieważ MAP_SIZE jest zmienną niestatyczną. Ponieważ nie powiedziałem, że będzie to zmienna instancji, naprawiłem to dla ciebie. Chciałem tylko, żebyś wiedział, na wypadek, gdy opublikowałem cały projekt i zobaczyłeś nazwy swoich zmiennych.
Rainbolt

@ Rusher Oh, ups. Myślę, że nadal działałem ze starą wersją kodu gry z piaskownicy i albo MAP_SIZEzmienna tak naprawdę wtedy nie istniała, albo z jakiegoś powodu zignorowałem ją i dodałem do mojej statycznej wersji. Zastanawiam się także, dlaczego mój wilk konsekwentnie osiągał wyniki nieco lepsze niż wszystkie inne wilki w moich próbach, ale gorzej u ciebie ... Chyba inny zestaw wilków? Czy może uruchamiasz swoje gry dla wielu iteracji innych niż 1000? Lub może potrzebujesz po prostu większej próbki, 5 nie jest statystycznie tak świetne.
Runer112

21

WolfRunningWithScissors

Nikt nie powiedział WolfRunningWithScissors, aby nie biegały z nożyczkami. A może tak zrobili, ale i tak to robi.

Jeśli trafi na wroga, albo wygra nożyczkami, przegra nożyczkami, zawiąże nożyczkami lub wystawi oko na bok (samobójstwo).

package animals;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


public class WolfRunningWithScissors extends Animal{

    public WolfRunningWithScissors() {
        super('W');
    }

    @Override
    public Attack fight(char c) {
        List<Attack> att = new ArrayList<>();
        att.add(Attack.SCISSORS);
        att.add(Attack.SUICIDE);
        Collections.shuffle(att);
        return att.get(0);
    }

    @Override
    public Move move() {
        List<Move> m = new ArrayList<>();
        m.add(Move.UP);
        m.add(Move.DOWN);
        m.add(Move.LEFT);
        m.add(Move.RIGHT);
        Collections.shuffle(m);
        return m.get(0);
    }

}

Chciałem tylko złożyć zgłoszenie dla zabawy. Nigdy wcześniej nie korzystałem z Javy i nie testowałem tego, ale powinna działać. Mój losowy atak i ruchomy kod oparty jest na getRandomAttack()StoneEatingWolf.


14

Omega Wolf

Zależne od siebie rozwiązanie, które zachowuje się bardzo podobnie do Alpha Wolf, stąd nazwa Omega Wolf

Ten wilk generuje „niebezpieczną” mapę otaczających komórek i wybiera ruch (lub wstrzymanie) do najbezpieczniejszej komórki.

Po pierwsze komórki, do których lwy będą się przemieszczać, otrzymują poziom EXTREAME_DANGER. Następnie komórki otaczające wykryte Wilki otrzymują poziomy zagrożenia w oparciu o natychmiastowość ataku ... tj. Jeśli wilk jest ukośny w stosunku do wilka omega, jest to uważane za niskie zagrożenie, jednak wilki sąsiadujące są uważane za zagrożenie umiarkowane.

Mapa „niebezpieczeństwa” jest następnie zamazana, aby umożliwić wykrwawianie się zagrożeń dla otaczających komórek. Dzięki temu wilk omega „wyczuwa” wektory zagrożenia i pozwala go uniknąć.

Obecnie rzeczywista logika ataku jest bardzo prymitywna. Mam nadzieję, że będę w stanie dać mu więcej mądrości i znaleźć lepszy stosunek wygranych do przegranych. Powinno to być możliwe, jeśli zastosuję heurystykę statystyczną.

W moich testach Omega Wolf konsekwentnie wygrywa z botem alfa 9 na 10 razy ... choć margines jest bardzo dobry: P

szybkie wyniki średnich pozostałych żywych wilków po 100 rundach 1000 iteracji:

class animals.OmegaWolf - 85
class animals.HonorWolf - 82
class animals.ProAlpha - 79
class animals.AlphaWolf - 77
class animals.ShadowWolf - 77
class animals.LazyWolf - 62
class animals.CamperWolf - 61
class animals.StoneEatingWolf - 59
class animals.GatheringWolf - 48
class animals.Sheep - 42
class animals.EmoWolf - 34
class animals.LionHunterWolf - 28
class animals.GamblerWolf (no cheating) - 27
class animals.WolfWithoutFear - 11
class animals.MOSHPITFRENZYWolf - 5
class animals.Wolf - 3
class animals.Stone - 2
class animals.Bear - 0
class animals.Lion - 0
class animals.MimicWolf - 0
class animals.Wion - 0

Kod:

package animals;

import wild.Wild;

public class OmegaWolf extends Animal {

    boolean lionWillMoveDown=true;

    private static final int LOW_DANGER = 10;
    private static final int MODERATE_DANGER = LOW_DANGER*2;
    private static final int EXTREAME_DANGER = MODERATE_DANGER*4;

    private static final int UP=1;
    private static final int LEFT=3;
    private static final int RIGHT=5;
    private static final int DOWN=7;
    private static final int UP_LEFT=0;
    private static final int UP_RIGHT=2;
    private static final int DOWN_LEFT=6;
    private static final int DOWN_RIGHT=8;

    private static final int WOLVES_SPECIES_COUNT=(int) Math.round(Math.pow(((float) Wild.MAP_SIZE)/20,2)-3)-3;

    /*
     * Interdependently derived solution that behaves very similar to Alpha Wolf, hence the name Omega Wolf
     * 
     * This wolf generates a "danger" map of the surrounding cells and will choose the movement (or hold) to the safest cell.
     * 
     * The firstly the cells where lions will move next are given EXTREAME_DANGER level
     * Then the cells surrounding any detected Wolves are given danger levels based on the immediacy of attack... i.e. if the wolf is diagonal to the omega wolf 
     * it is deemed a low threat however wolves that are adjacent are deemed a moderate threat.
     * The "danger" map is then blurred to allow bleeding of the threats to surrounding cells. This allows the omega wolf to "sense" threat vectors and to avoid it.
     * 
     * Currently the actual attack logic is very primitive. I hope to be able to give it more smarts and eek out better win/lose ratios. This should be possible if 
     * I put in some statistical heuristics.
     */

    public OmegaWolf() { 
        super('W'); }


    @Override
    public Attack fight(char opponent) {
        switch(opponent){
        case 'B':
        case 'L':
            return Attack.SCISSORS;
        case 'S': 
            return Attack.PAPER;
        default:
            // if there is only one wolf species then it must be another omega wolf.
            if (WOLVES_SPECIES_COUNT==1)
            {
                return Attack.SCISSORS;
            }
            else
            {
                // lets just choose an attack with equal weight.
                double rand = Math.random();
                if (rand < 0.333333)
                {
                    return Attack.PAPER;
                }
                if (rand < 0.666667)
                {
                    return Attack.SCISSORS;
                }
                return Attack.ROCK;

            }
        }
    }

    public Move move() {

        lionWillMoveDown = !lionWillMoveDown;


        Move move = Move.HOLD;

        int[][] dangerMap = new int[3][3];
        int[][] blurredDangerMap = new int[3][3];

        // sense Lion Danger
        for (int y=0;y<3;y++)
        {
            for (int x=0;x<3;x++)
            {
                if (surroundings[y][x]=='L')
                {
                    if (lionWillMoveDown && y!=2)
                    {
                        dangerMap[y+1][x]+=EXTREAME_DANGER;
                    }
                    else if (x!=2)
                    {
                        dangerMap[y][x+1]+=EXTREAME_DANGER;
                    }
                }
            }
        }

        // sense Wolf Danger adjacent
        // UP
        if (surroundings[0][1]=='W')
        {
            dangerMap[0][1]+=MODERATE_DANGER;
            dangerMap[0][0]+=LOW_DANGER;
            dangerMap[0][2]+=LOW_DANGER;
            dangerMap[1][1]+=MODERATE_DANGER;
        }
        // DOWN
        if (surroundings[2][1]=='W')
        {
            dangerMap[2][1]+=MODERATE_DANGER;
            dangerMap[2][0]+=LOW_DANGER;
            dangerMap[2][2]+=LOW_DANGER;
            dangerMap[1][1]+=MODERATE_DANGER;
        }
        // LEFT
        if (surroundings[1][0]=='W')
        {
            dangerMap[1][0]+=MODERATE_DANGER;
            dangerMap[0][0]+=LOW_DANGER;
            dangerMap[2][0]+=LOW_DANGER;
            dangerMap[1][1]+=MODERATE_DANGER;
        }
        // RIGHT
        if (surroundings[1][2]=='W')
        {
            dangerMap[1][2]+=MODERATE_DANGER;
            dangerMap[0][2]+=LOW_DANGER;
            dangerMap[2][2]+=LOW_DANGER;
            dangerMap[1][1]+=MODERATE_DANGER;
        }

        // sense Wolf Danger diagonally
        // UP_LEFT
        if (surroundings[0][0]=='W')
        {
            dangerMap[0][0]+=LOW_DANGER;
            dangerMap[0][1]+=MODERATE_DANGER;
            dangerMap[1][0]+=MODERATE_DANGER;
        }
        // DOWN_LEFT
        if (surroundings[2][0]=='W')
        {
            dangerMap[2][0]+=LOW_DANGER;
            dangerMap[2][1]+=MODERATE_DANGER;
            dangerMap[1][0]+=MODERATE_DANGER;
        }
        // UP_RIGHT
        if (surroundings[0][2]=='W')
        {
            dangerMap[0][2]+=LOW_DANGER;
            dangerMap[1][2]+=MODERATE_DANGER;
            dangerMap[0][1]+=MODERATE_DANGER;
        }
        // DOWN_RIGHT
        if (surroundings[2][2]=='W')
        {
            dangerMap[2][2]+=LOW_DANGER;
            dangerMap[2][1]+=MODERATE_DANGER;
            dangerMap[1][2]+=MODERATE_DANGER;
        }


        // generate a blurred danger map. This bleeds danger to surrounding cells.
        int yj,xi,sampleCount,cumulativeDanger;
        for (int y=0;y<3;y++)
        {
            for (int x=0;x<3;x++)
            {
                sampleCount=0;
                cumulativeDanger=0;
                for (int j=-1;j<2;j++)
                {
                    for (int i=-1;i<2;i++)
                    {
                        yj=y+j;
                        xi=x+i;
                        if (yj>-1 && yj<3 && xi>-1 && xi<3)
                        {
                            cumulativeDanger+=dangerMap[yj][xi];
                            sampleCount++;
                        }
                    }
                }
                blurredDangerMap[y][x]=(dangerMap[y][x]+cumulativeDanger/sampleCount)/2;
            }
        }

        // find the safest cell
        int safestCellDanger=Integer.MAX_VALUE;
        int safestCellId = -1;
        int cellId=0;

        for (int y=0;y<3;y++)
        {
            for (int x=0;x<3;x++)
            {
                if (blurredDangerMap[y][x]<safestCellDanger)
                {
                    safestCellDanger=blurredDangerMap[y][x];
                    safestCellId=cellId;
                }
                cellId++;
            }
        }

        // safest cell is adjacent so move there
        if ((safestCellId&1)==1)
        {
            switch (safestCellId)
            {
                case UP:
                    move=Move.UP;
                    break;
                case LEFT:
                    move=Move.LEFT;
                    break;
                case RIGHT:
                    move=Move.RIGHT;
                    break;
                case DOWN:
                    move=Move.DOWN;
                    break;
            }
        }
        // safestCell is a diagonal cell or current cell
        else
        {
            // lets initialise the move to Hold.
            move = Move.HOLD;

            switch (safestCellId)
            {
                case UP_LEFT:

                    // check to see whether holding is not safer than moving up
                    if (dangerMap[1][1] > dangerMap[0][1] )
                    {
                        // move up if safer than moving left or if equally safe, when randomly chosen 
                        if (dangerMap[0][1] < dangerMap[1][0] || (dangerMap[0][1] == dangerMap[1][0] && Math.random()>0.5))
                        {
                            move=Move.UP;
                        } 
                        // left must be safest :P
                        else
                        {

                            move=Move.LEFT;
                        }
                    }
                    // check to see whether holding is not safer than moving left
                    else if (dangerMap[1][1] > dangerMap[1][0] )
                    {
                        move=Move.LEFT;
                    }

                    break;
                case UP_RIGHT:
                    // check to see whether holding is not safer than moving up
                    if (dangerMap[1][1] > dangerMap[0][1] )
                    {
                        // move up if safer than moving right or if equally safe, when randomly chosen 
                        if (dangerMap[0][1] < dangerMap[1][2]|| (dangerMap[0][1] == dangerMap[1][2] && Math.random()>0.5))
                        {
                            move=Move.UP;
                        } 
                        // right must be safest :P
                        else
                        {
                            move=Move.RIGHT;
                        }
                    }
                    // check to see whether holding is not safer than moving right
                    else if (dangerMap[1][1] > dangerMap[1][2] )
                    {
                        move=Move.RIGHT;
                    }
                    break;
                case DOWN_LEFT:
                    // check to see whether holding is not safer than moving down
                    if (dangerMap[1][1] > dangerMap[2][1] )
                    {
                        // move down if safer than moving left or if equally safe, when randomly chosen 
                        if (dangerMap[2][1] < dangerMap[1][0]|| (dangerMap[2][1] == dangerMap[1][0] && Math.random()>0.5))
                        {
                            move=Move.DOWN;
                        } 
                        // left must be safest :P
                        else
                        {
                            move=Move.LEFT;
                        }
                    }
                    // check to see whether holding is not safer than moving left
                    else if (dangerMap[1][1] > dangerMap[1][0] )
                    {
                        move=Move.LEFT;
                    }
                    break;
                case DOWN_RIGHT:
                    // check to see whether holding is not safer than moving down
                    if (dangerMap[1][1] > dangerMap[2][1] )
                    {
                        // move down if safer than moving right or if equally safe, when randomly chosen 
                        if (dangerMap[2][1] < dangerMap[2][2] || (dangerMap[2][1] == dangerMap[1][2] && Math.random()>0.5))
                        {
                            move=Move.DOWN;
                        } 
                        // right must be safest :P
                        else
                        {
                            move=Move.RIGHT;
                        }
                    }
                    // check to see whether holding is not safer than moving right
                    else if (dangerMap[1][1] > dangerMap[1][2] )
                    {
                        move=Move.RIGHT;
                    }
                    break;
            }
        }

        return move;

    }
}

14

StoneGuardianWolf

To była niezła zabawa. Zrobiłem nieporęczny port kodu java do javascript z obsługą kreacji dla wizualizacji: JavaScript StoneGuardianWolf

StoneGuardianWolf szuka zwierząt domowych skał i schronia się obok Kamieni. Chroni ich i wolałaby poświęcić się dla ich bezpieczeństwa.

Statystyki

Jeden gracz: ~ 75% wskaźnik przeżycia Wilka + 35% wskaźnik przeżycia Zwierzątka (kamienia).

Podsumowanie: 75% + 35% ---> 110% Wskaźnik sukcesu! :)

Multi Player: nieprzetestowany.

Zmień dziennik

v2: Zaktualizowano strategię AI vs GamblerWolf i strategię poszukiwania skał domowych.

v1: Lepsze unikanie wilka

v0: Urodziny

Kod Java

package animals;

public class StoneGuardianWolf extends Animal {
    public StoneGuardianWolf() {
        super('W');
    }

    private boolean petRock = false;
    private int heartache = 0;

    public Attack fight(char c) {
        this.heartache--;

        switch (c) {
        case 'B':
            return Attack.SCISSORS;
        case 'L':
            return Attack.SCISSORS;
        case 'S': // A motherly sacrifice
            return Attack.SUICIDE;
        default:
            int n = this.heartache % 3;
            if (n < 1)
                return Attack.PAPER;
            if (n < 2)
                return Attack.ROCK;
            return Attack.SCISSORS;
        }
    }

    public Move move() {
        char[][] surr = this.surroundings;
        int[][] clairvoyance = new int[3][3];

        for (int i = 0; i < 3; i++)
            for (int j = 0; j < 3; j++)
                clairvoyance[i][j] = 1;

        boolean seeNoStone = true;

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                switch (surr[i][j]) {
                case 'L':
                    if (i < 1 && j < 1) {
                        clairvoyance[1][0] += 50;
                        clairvoyance[0][1] += 50;
                    }

                    if (i == 1 && j < 1) { // above
                        clairvoyance[1][1] += 50;
                    }

                    if (i < 1 && j == 1) { // left
                        clairvoyance[1][1] += 50;
                    }
                    break;

                case 'S': // seek stones for protection
                    seeNoStone = false;
                    this.petRock = true;
                    clairvoyance[i][j] += 999; // Only hugs!
                    if (i < 2)
                        clairvoyance[i + 1][j] -= 10;
                    if (j < 2)
                        clairvoyance[i][j + 1] -= 10;
                    if (i > 0)
                        clairvoyance[i - 1][j] -= 10;
                    if (j > 0)
                        clairvoyance[i][j - 1] -= 10;
                    break;

                case 'B': // ignore bears
                    break;

                case 'W':
                    // skip self
                    if (i == 1 && j == 1)
                        continue;
                    int m = 25; // avoid wolves

                    // don't fight unless pet rock is in danger
                    if (petRock)
                        clairvoyance[i][j] -= 999; // motherly wrath
                    else
                        clairvoyance[i][j] += 100;

                    // avoid stepping into wolf path
                    if (i != 1 && j != 1) {
                        if (i < 2)
                            clairvoyance[i + 1][j] += m;
                        if (j < 2)
                            clairvoyance[i][j + 1] += m;
                        if (i > 0)
                            clairvoyance[i - 1][j] += m;
                        if (j > 0)
                            clairvoyance[i][j - 1] += m;
                    }
                    break;

                default:
                    clairvoyance[i][j] += 0;
                }
            } // for loop
        } // for loop

        int size = clairvoyance[1][1];
        int x = 1;
        int y = 1;

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (i != 1 || j != 1)
                    continue;
                int tmp = clairvoyance[i][j];
                if (tmp < size) {
                    size = tmp;
                    x = i;
                    y = j;
                }
            }
        }

        if (seeNoStone)
            this.heartache++;

        this.petRock = false;
        if (seeNoStone && heartache % 10 == 0) { // Find a pet stone! :3
            if ((heartache % 3) < 2 || clairvoyance[1][2] >= 45) {
                // try move right
                if (clairvoyance[2][1] < 45)
                    return Move.RIGHT;
            }

            // try down instead
            if (clairvoyance[1][2] < 45)
                return Move.DOWN;
        }

        if (x == 0 && y == 1)
            return Move.LEFT;
        if (x == 2 && y == 1)
            return Move.RIGHT;
        if (x == 1 && y == 0)
            return Move.UP;
        if (x == 1 && y == 2)
            return Move.DOWN;

        if (!seeNoStone)
            this.petRock = true;

        return Move.HOLD;
    }
}

5
Kamień Jedzący Wilk arch-wróg!
Averroes,

:) Rzeczywiście - nie pozwolę ci zbliżyć się do skał mojego zwierzaka! CamoWolf uderza dość mocno SGW.
talmobi,

1
Na szczęście nie musisz uwzględniać CamoWolf jako legalnego wpisu = D
pół

14

Czy to chłopiec? Czy to wilk? Nie, to jest

BoyWhoCriedWolf.java

Ludzie wszędzie używają refleksji, więc pomyślałem, dlaczego nie pójść o krok dalej?
Przedstawiam wam: wilka, który nie może stracić.

package animals;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.instrument.ClassDefinition;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.jar.Attributes;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import javax.xml.bind.DatatypeConverter;

public class BoyWhoCriedWolf extends Animal {

    private static boolean ranAgent;

    public static void installAgent() {
        try {
            ranAgent = true;
            String javaExec = new File(System.getProperty("java.home"), "bin").getAbsolutePath() + File.separator + "java";
            Process proc = new ProcessBuilder(javaExec, "-cp", System.getProperty("java.class.path"),
                    "animals.BoyWhoCriedWolf", ManagementFactory.getRuntimeMXBean().getName().split("@")[0])
                    .inheritIO().start();
            proc.waitFor();
        } catch (InterruptedException | IOException e) {
            e.printStackTrace();
        }
    }

    public BoyWhoCriedWolf() {
        super('W');
        if (!ranAgent) {
            installAgent();
        }
    }

    @Override
    public Attack fight(char c) {
        return Attack.PAPER; // I like paper, it's my rubber duck.
    }

    @Override
    public Move move() {
        return Move.HOLD; // I'm terribly lazy.
    }

    public static void main(String[] args) {
        try {
            File temp = File.createTempFile("agent-", ".jar");
            temp.deleteOnExit();
            Manifest manifest = new Manifest();
            manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
            manifest.getMainAttributes().put(new Attributes.Name("Agent-Class"), "animals.BoyWhoCriedWolf");
            manifest.getMainAttributes().put(new Attributes.Name("Can-Redefine-Classes"), "true");
            JarOutputStream jos = new JarOutputStream(new FileOutputStream(temp), manifest);
            jos.close();

            // Add tools.jar
            Method addURL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
            addURL.setAccessible(true);
            addURL.invoke(ClassLoader.getSystemClassLoader(), new URL("file:" + System.getProperty("java.home") + "/../lib/tools.jar"));

            Class<?> virtualMachineClass = Class.forName("com.sun.tools.attach.VirtualMachine");
            Object vm = virtualMachineClass.getDeclaredMethod("attach", String.class).invoke(null, args[0]);
            virtualMachineClass.getDeclaredMethod("loadAgent", String.class).invoke(vm, temp.getAbsolutePath());
            virtualMachineClass.getDeclaredMethod("detach").invoke(vm);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void agentmain(String args, Instrumentation instr) throws ClassNotFoundException, UnmodifiableClassException {
        instr.redefineClasses(new ClassDefinition(wild.Game.class, DatatypeConverter.parseBase64Binary(base64Game)));
    }

    private static final String base64Game =
              "yv66vgAAADMA9QoAOQCRBwCSCgACAJEJABIAkwkAEgCUBwCVCgAGAJEJABIAlgoABgCXCgAGAJgK"
            + "AAIAmQoABgCaCgCbAJwHAJ0HAJ4KABIAnwoAEgCgBwChCgASAKIHAKMKABIApAkAFAClCgAUAKYH"
            + "AKcJAGUAqAkAOgCpCgBlAKoKAAYAqwsArACtCwCsAK4KAAYArwcAsAoABgCxCQAUALIKABQAswkA"
            + "cQC0CgC1ALYGP+AAAAAAAAAJADoAtwoAcQCqCQBxALgJAHEAuQkAcQC6CgCbALsIALwHAL0KAC8A"
            + "kQoALwC+CAC/CgAvAMAKAC8AwQgAwggAwwgAxAcAjQcAxQcAxgEADElubmVyQ2xhc3NlcwEABWJv"
            + "YXJkAQAVTGphdmEvdXRpbC9BcnJheUxpc3Q7AQAJU2lnbmF0dXJlAQBVTGphdmEvdXRpbC9BcnJh"
            + "eUxpc3Q8TGphdmEvdXRpbC9BcnJheUxpc3Q8TGphdmEvdXRpbC9BcnJheUxpc3Q8TGFuaW1hbHMv"
            + "QW5pbWFsOz47Pjs+OwEAA2dlbgEAEkxqYXZhL3V0aWwvUmFuZG9tOwEABFNJWkUBAAFJAQAGPGlu"
            + "aXQ+AQAEKEkpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUB"
            + "AAFqAQABaQEABHRoaXMBAAtMd2lsZC9HYW1lOwEABHNpemUBAA1TdGFja01hcFRhYmxlBwChAQAI"
            + "cG9wdWxhdGUBABUoTGphdmEvbGFuZy9DbGFzcztJKVYBAAFlAQAoTGphdmEvbGFuZy9SZWZsZWN0"
            + "aXZlT3BlcmF0aW9uRXhjZXB0aW9uOwEAA3JvdwEAA2NvbAEAB3NwZWNpZXMBABFMamF2YS9sYW5n"
            + "L0NsYXNzOwEAA251bQEAFkxvY2FsVmFyaWFibGVUeXBlVGFibGUBABZMamF2YS9sYW5nL0NsYXNz"
            + "PFRUOz47BwDHBwDIAQAuPFQ6TGFuaW1hbHMvQW5pbWFsOz4oTGphdmEvbGFuZy9DbGFzczxUVDs+"
            + "O0kpVgEAB2l0ZXJhdGUBAAMoKVYBAAdtb3ZlQWxsAQAVTGphdmEvbGFuZy9FeGNlcHRpb247AQAB"
            + "YQEAEExhbmltYWxzL0FuaW1hbDsBAAVhTW92ZQcAyQEABE1vdmUBABVMYW5pbWFscy9BbmltYWwk"
            + "TW92ZTsBAARnYW1lBwCjBwCnBwDJAQAHZmxhdHRlbgEABXJhbmQxAQAFcmFuZDIBAAFiAQAFYVRh"
            + "Y2sHAMoBAAZBdHRhY2sBABdMYW5pbWFscy9BbmltYWwkQXR0YWNrOwEABWJUYWNrAQAEY2VsbAEA"
            + "J0xqYXZhL3V0aWwvQXJyYXlMaXN0PExhbmltYWxzL0FuaW1hbDs+OwEAPkxqYXZhL3V0aWwvQXJy"
            + "YXlMaXN0PExqYXZhL3V0aWwvQXJyYXlMaXN0PExhbmltYWxzL0FuaW1hbDs+Oz47BwDLBwCVBwDK"
            + "AQAEcG9sbAEAFChMamF2YS9sYW5nL0NsYXNzOylJAQABYwEABWNvdW50AQAIdG9TdHJpbmcBABQo"
            + "KUxqYXZhL2xhbmcvU3RyaW5nOwEAAXMBABJMamF2YS9sYW5nL1N0cmluZzsHAMwBAAdnZXRBcmVh"
            + "AQAHKElJKVtbQwEABXRlbXAxAQAFdGVtcDIBAAV0ZW1wMwEABXRlbXA0AQABbAEAAWsBAARhcmVh"
            + "AQADW1tDBwDNAQAKU291cmNlRmlsZQEACUdhbWUuamF2YQwARABfAQAQamF2YS91dGlsL1JhbmRv"
            + "bQwAQABBDABCAEMBABNqYXZhL3V0aWwvQXJyYXlMaXN0DAA8AD0MAM4AzwwA0ADRDADSANMMANQA"
            + "1QcAxwwA1gDXAQAgamF2YS9sYW5nL0luc3RhbnRpYXRpb25FeGNlcHRpb24BACBqYXZhL2xhbmcv"
            + "SWxsZWdhbEFjY2Vzc0V4Y2VwdGlvbgwAYABfDABsAF8BAAl3aWxkL0dhbWUMAEQARQEADmFuaW1h"
            + "bHMvQW5pbWFsDACEAIUMANgAjQwA2QDaAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwA2wBnDADcAN0M"
            + "AN4A3wwA4ADhBwDLDADiANUMAOMA1wwATQDfAQAXYW5pbWFscy9Cb3lXaG9DcmllZFdvbGYMAOQA"
            + "zwwA5QDmDADnAOgMAOkAcwcA6gwA6wDsDADtAN0MAO4AcwwA7wBzDADwAHMMAPEAzwEABjxodG1s"
            + "PgEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyDADyAPMBAAwmbmJzcDsmbmJzcDsMAH8AgAwA8gD0"
            + "AQAGJm5ic3A7AQAEPGJyPgEABzwvaHRtbD4BABBqYXZhL2xhbmcvT2JqZWN0AQALd2lsZC9HYW1l"
            + "JDEBAA9qYXZhL2xhbmcvQ2xhc3MBACZqYXZhL2xhbmcvUmVmbGVjdGl2ZU9wZXJhdGlvbkV4Y2Vw"
            + "dGlvbgEAE2FuaW1hbHMvQW5pbWFsJE1vdmUBABVhbmltYWxzL0FuaW1hbCRBdHRhY2sBABJqYXZh"
            + "L3V0aWwvSXRlcmF0b3IBABBqYXZhL2xhbmcvU3RyaW5nAQACW0MBAANhZGQBABUoTGphdmEvbGFu"
            + "Zy9PYmplY3Q7KVoBAANnZXQBABUoSSlMamF2YS9sYW5nL09iamVjdDsBAAduZXh0SW50AQAEKEkp"
            + "SQEAB2lzRW1wdHkBAAMoKVoBAAtuZXdJbnN0YW5jZQEAFCgpTGphdmEvbGFuZy9PYmplY3Q7AQAM"
            + "c3Vycm91bmRpbmdzAQAEbW92ZQEAFygpTGFuaW1hbHMvQW5pbWFsJE1vdmU7AQAESE9MRAEAHiRT"
            + "d2l0Y2hNYXAkYW5pbWFscyRBbmltYWwkTW92ZQEAAltJAQAHb3JkaW5hbAEAAygpSQEACGl0ZXJh"
            + "dG9yAQAWKClMamF2YS91dGlsL0l0ZXJhdG9yOwEAB2hhc05leHQBAARuZXh0AQAGcmVtb3ZlAQAG"
            + "bGV0dGVyAQABQwEABWZpZ2h0AQAaKEMpTGFuaW1hbHMvQW5pbWFsJEF0dGFjazsBAAdTVUlDSURF"
            + "AQAOamF2YS9sYW5nL01hdGgBAAZyYW5kb20BAAMoKUQBACAkU3dpdGNoTWFwJGFuaW1hbHMkQW5p"
            + "bWFsJEF0dGFjawEABVBBUEVSAQAIU0NJU1NPUlMBAARST0NLAQAKaXNJbnN0YW5jZQEABmFwcGVu"
            + "ZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEAHChDKUxq"
            + "YXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsAIQASADkAAAADAAIAPAA9AAEAPgAAAAIAPwASAEAAQQAA"
            + "ABQAQgBDAAAACAAEAEQARQABAEYAAADtAAMABAAAAF8qtwABKrsAAlm3AAO1AAQqG7UABSq7AAZZ"
            + "twAHtQAIAz0cG6IAOyq0AAi7AAZZtwAHtgAJVwM+HRuiAB8qtAAIHLYACsAABrsABlm3AAe2AAlX"
            + "hAMBp//ihAIBp//GsQAAAAMARwAAAC4ACwAAABEABAAOAA8AEgAUABMAHwAUACYAFQA1ABYAPAAX"
            + "AFIAFgBYABQAXgAaAEgAAAAqAAQANwAhAEkAQwADACEAPQBKAEMAAgAAAF8ASwBMAAAAAABfAE0A"
            + "QwABAE4AAAAYAAT/ACEAAwcATwEBAAD8ABUB+gAg+gAFAAQAUABRAAIARgAAARwAAgAGAAAAXRye"
            + "AFsqtAAEKrQABbYACz4qtAAEKrQABbYACzYEKrQACB22AArAAAYVBLYACsAABrYADJkAJiq0AAgd"
            + "tgAKwAAGFQS2AArAAAYrtgANtgAJV6cABToFhAL/p/+nsQACADYAUQBUAA4ANgBRAFQADwAEAEcA"
            + "AAAmAAkAAAAdAAQAHgAQAB8AHQAgADYAIQBRACIAVgAjAFkAJQBcACYASAAAAD4ABgBWAAAAUgBT"
            + "AAUAEABJAFQAQwADAB0APABVAEMABAAAAF0ASwBMAAAAAABdAFYAVwABAAAAXQBYAEMAAgBZAAAA"
            + "DAABAAAAXQBWAFoAAQBOAAAAGwAFAP8AUwAFBwBPBwBbAQEBAAEHAFwB+QACAgA+AAAAAgBdAAQA"
            + "XgBfAAEARgAAADsAAQABAAAACSq3ABAqtwARsQAAAAIARwAAAA4AAwAAACkABAAqAAgAKwBIAAAA"
            + "DAABAAAACQBLAEwAAAACAGAAXwABAEYAAAJjAAQABwAAAVu7ABJZKrQABbcAE0wDPRwqtAAFogE/"
            + "Az4dKrQABaIBLyq0AAgctgAKwAAGHbYACsAABrYADJoBESq0AAgctgAKwAAGHbYACsAABgO2AArA"
            + "ABQ6BBkEKhwdtwAVtQAWGQS2ABc6BacACjoGsgAZOgWyABoZBbYAGy6qAAAAAAAAzgAAAAEAAAAF"
            + "AAAAJAAAAEsAAABtAAAAjwAAALYrtAAIHARkKrQABWAqtAAFcLYACsAABh22AArAAAYZBLYACVen"
            + "AIYrtAAIHLYACsAABh0EYCq0AAVwtgAKwAAGGQS2AAlXpwBkK7QACBwEYCq0AAVwtgAKwAAGHbYA"
            + "CsAABhkEtgAJV6cAQiu0AAgctgAKwAAGHQRkKrQABWAqtAAFcLYACsAABhkEtgAJV6cAGyu0AAgc"
            + "tgAKwAAGHbYACsAABhkEtgAJV4QDAaf+z4QCAaf+vyortAAItQAIsQABAF4AZQBoABgAAwBHAAAA"
            + "WgAWAAAALgAMAC8AFgAwACAAMQA4ADIAUwAzAF4ANQBlADYAbwA3AJwAOQDAADoAwwA8AOIAPQDl"
            + "AD8BBABAAQcAQgErAEMBLgBFAUYAMAFMAC8BUgBLAVoATABIAAAAUgAIAGoABQBSAGEABgBTAPMA"
            + "YgBjAAQAZQADAGQAZwAFAG8A1wBkAGcABQAYATQASQBDAAMADgFEAEoAQwACAAABWwBLAEwAAAAM"
            + "AU8AaABMAAEATgAAADYADP0ADgcATwH8AAkB/wBPAAUHAE8HAE8BAQcAaQABBwBq/AAGBwBrLCYh"
            + "ISb5ABf6AAX6AAUAAgBsAF8AAQBGAAADuAAFAAwAAAFfKrQACLYAHEwruQAdAQCZAVAruQAeAQDA"
            + "AAZNLLYAHE4tuQAdAQCZATUtuQAeAQDAAAY6BBkEtgAfBKQBHiq0AAQZBLYAH7YACzYFKrQABBkE"
            + "tgAftgALNgYVBRUGn//uGQQVBbYACsAAFDoHGQQVBrYACsAAFDoIGQfBACCZAA4ZBBkItgAhV6f/"
            + "rBkIwQAgmQAOGQQZB7YAIVen/5kZBxkItAAitgAjOgmnAAo6C7IAJDoJGQgZB7QAIrYAIzoKpwAK"
            + "OguyACQ6ChkJGQqmAB0ZBLgAJRQAJpeeAAgZB6cABRkItgAhV6cAbbIAKBkJtgApLqoAAAAAAABh"
            + "AAAAAQAAAAMAAAAcAAAANAAAAEwZBBkKsgAqpgAIGQenAAUZCLYAIVenADAZBBkKsgArpgAIGQen"
            + "AAUZCLYAIVenABgZBBkKsgAspgAIGQenAAUZCLYAIVen/t+n/sin/q2xAAIAngCqAK0AGAC0AMAA"
            + "wwAYAAQARwAAAHYAHQAAAE8AGwBQADQAUQA9AFMASwBUAGAAVgBsAFcAeABZAIAAWgCIAFsAiwBc"
            + "AJMAXQCbAF4AngBiAKoAYwC0AGQAwABlAMoAZwDRAGgA6wBqARAAbAElAG0BKABvAT0AcAFAAHIB"
            + "VQB2AVgAdwFbAHgBXgB5AEgAAACEAA0ArwAFAFIAYQALAMUABQBSAGEACwBLAQoAbQBDAAUAWQD8"
            + "AG4AQwAGAGwA6QBiAGMABwB4AN0AbwBjAAgAqgADAHAAcwAJALQAoQBwAHMACQDAAAMAdABzAAoA"
            + "ygCLAHQAcwAKADQBJAB1AD0ABAAbAUAAVAA9AAIAAAFfAEsATAAAAFkAAAAWAAIANAEkAHUAdgAE"
            + "ABsBQABUAHcAAgBOAAABFQAa/AAIBwB4/QAXBwB5BwB4/AATBwB5/AAWAf4APwEHAGkHAGkSTgcA"
            + "avwABgcAek4HAGr8AAYHAHpXBwB5/wABAAsHAE8HAHgHAHkHAHgHAHkBAQcAaQcAaQcAegcAegAC"
            + "BwB5BwBpBiROBwB5/wABAAsHAE8HAHgHAHkHAHgHAHkBAQcAaQcAaQcAegcAegACBwB5BwBpBk4H"
            + "AHn/AAEACwcATwcAeAcAeQcAeAcAeQEBBwBpBwBpBwB6BwB6AAIHAHkHAGkGTgcAef8AAQALBwBP"
            + "BwB4BwB5BwB4BwB5AQEHAGkHAGkHAHoHAHoAAgcAeQcAaf8AAwAFBwBPBwB4BwB5BwB4BwB5AAD6"
            + "AAL5AAL6AAIABAB7AHwAAQBGAAABNgACAAkAAABvAz0qtAAItgAcTi25AB0BAJkAXS25AB4BAMAA"
            + "BjoEGQS2ABw6BRkFuQAdAQCZAD4ZBbkAHgEAwAAGOgYZBrYAHDoHGQe5AB0BAJkAHhkHuQAeAQDA"
            + "ABQ6CCsZCLYALZkABoQCAaf/3qf/vqf/oBysAAAABABHAAAAKgAKAAAAfAACAH0AHgB+ADsAfwBY"
            + "AIAAYQCBAGQAggBnAIMAagCEAG0AhQBIAAAAPgAGAFgADABiAGMACAA7ACwAdQA9AAYAHgBMAFQA"
            + "PQAEAAAAbwBLAEwAAAAAAG8AfQBXAAEAAgBtAH4AQwACAFkAAAAWAAIAOwAsAHUAdgAGAB4ATABU"
            + "AHcABABOAAAAJQAH/QAKAQcAeP0AGgcAeQcAeP0AHAcAeQcAeCH5AAL5AAL6AAIAAQB/AIAAAQBG"
            + "AAABWwADAAYAAACqEi5MKrQACLYAHE0suQAdAQCZAIUsuQAeAQDAAAZOLbYAHDoEGQS5AB0BAJkA"
            + "VBkEuQAeAQDAAAY6BRkFtgAMmQAauwAvWbcAMCu2ADESMrYAMbYAM0ynACa7AC9ZtwAwK7YAMRkF"
            + "A7YACsAAFLQAIrYANBI1tgAxtgAzTKf/qLsAL1m3ADArtgAxEja2ADG2ADNMp/94uwAvWbcAMCu2"
            + "ADESN7YAMbYAM7AAAAAEAEcAAAAqAAoAAACJAAMAigAeAIsAOgCMAEIAjQBZAI8AfACQAH8AkQCT"
            + "AJIAlgCTAEgAAAAqAAQAOgBCAHUAPQAFAB4AdQBUAD0AAwAAAKoASwBMAAAAAwCnAIEAggABAFkA"
            + "AAAWAAIAOgBCAHUAdgAFAB4AdQBUAHcAAwBOAAAAIwAG/QALBwCDBwB4/QAYBwB5BwB4/AA0BwB5"
            + "+gAi+gAC+QAWAAIAhACFAAEARgAAAdAABAALAAAApQYGxQA4Ak4CNgQVBASjAJYCNgUVBQSjAIcV"
            + "BARgNgYVBQRgNgcbFQRgKrQABWAqtAAFcDYIHBUFYCq0AAVgKrQABXA2CSq0AAgbFQRgKrQABWAq"
            + "tAAFcLYACsAABhwVBWAqtAAFYCq0AAVwtgAKwAAGOgotFQQEYDIVBQRgGQq2AAyZAAgQIKcADxkK"
            + "A7YACsAAFLQAIlWEBQGn/3mEBAGn/2otsAAAAAQARwAAADIADAAAAJcABwCYABAAmQAZAJoAHwCb"
            + "ACUAnAA1AJ0ARQCeAHMAnwCXAJkAnQCYAKMAogBIAAAAcAALAB8AeACGAEMABgAlAHIAhwBDAAcA"
            + "NQBiAIgAQwAIAEUAUgCJAEMACQBzACQAdQA9AAoAEwCKAIoAQwAFAAoAmQCLAEMABAAAAKUASwBM"
            + "AAAAAAClAEoAQwABAAAApQBJAEMAAgAHAJ4AjACNAAMAWQAAAAwAAQBzACQAdQB2AAoATgAAAFkA"
            + "Bv0ACgcAOAH8AAgB/wB2AAsHAE8BAQcAOAEBAQEBAQcAeQACBwCOAf8ACwALBwBPAQEHADgBAQEB"
            + "AQEHAHkAAwcAjgEB/wAGAAUHAE8BAQcAOAEAAPoABQACAI8AAAACAJAAOwAAABoAAwA6ABIAABAI"
            + "AGUAFABmQBkAcQAUAHJAGQ==";
}

O tak, wymaga JDK do uruchomienia, ale nie sądzę, że to będzie problem.


1
Cholera, pobiłeś mnie do tego. Z tą dokładną taktyką pracowałem nad SabotageAgentWolf.
mackthehobbit

1
Co robi ta klasa?
justhalf

3
@justhalf Na nowo definiuje klasę gry z plikiem zakodowanym w base64 u dołu. Ten plik ma kontrolę instancji; jeśli to mój wilk, drugi zawsze umiera.
14mRh4X0r

1
Wpadłem na pomysł, aby użyć dokładnie tego mechanizmu, aby wszystkie inne zwierzęta popełniły samobójstwo i nazwać to HypnoWolf. Nie udało mi się sprawić, by działał poprawnie, ale zrobiłeś to - szanuj!
Francois Bourgeois

12

Wion

Próbuje zrobić jak najmniej, aby przetrwać tak długo, jak to możliwe w oczekiwanej wartości. Stara się poruszać równolegle do lwów (niezależnie od tego, czy je widzi).

Ignoruje wilki, ponieważ decyduje, że są nieprzewidywalne. Jeśli napotka wilka, powinien wygrać około połowy walk (jest to optymalne, chyba że spróbuję dopasować wzór). Moje wilki nigdy nie powinny ze sobą walczyć. Jeśli napotka lwa (czego prawdopodobnie nie powinien), powinien wygrać około 3/4 walk. Niedźwiedzie i skały zawsze powinny przegrywać.

Zakładając, że w symulacji są jakieś wilki wykorzystujące inną strategię, rozsądnie byłoby unikać moich wilków, ponieważ mają 50% szansy na utratę dowolnego spotkania. Średnio powinno to działać co najmniej tak dobrze, jak każda inna strategia.

Jeśli poprawnie zrozumiałem zasady, powinna to być optymalna strategia.

package animals;
import java.util.Random;

public class Wion extends Animal {
    private boolean down;
    public Wion() { super('W'); down=true;}
    public Attack fight(char opponent) {
        switch (opponent) {
            case 'B':
            case 'L':
                return Attack.SCISSORS;
            case 'S':
                return Attack.PAPER;
            default:
                Random rn = new Random();
                int i = Math.abs(rn.nextInt() % 4);
                while (i==3) {i = Math.abs(rn.nextInt() % 4);}
                return Attack.values()[i];
        }
    }
    public Move move() {
        down=!down;
        if(!down) { return Move.DOWN; }
        return Move.RIGHT;
    }
}

Szczerze mówiąc, nie wiem, dlaczego tak źle to działa w moich testach. Brzmi dobrze na papierze, ale w praktyce jest prawie na równi z EmoWolf :(
Geobits

@Geobits Tak naprawdę to nie testowałem TBH. Chyba źle zrozumiałem jedną z zasad, popełniłem błąd lub mój losowy atak przeciwko wilkom nie jest jednolicie losowy.
Tim Seguine,

@Geobits Wymieniłem logikę ataku. Podejrzewam, że może popełnił czasem samobójstwo.
Tim Seguine,

1
@ po prostu tak, już zdałem sobie sprawę, na czym polega problem. Moje rozumowanie może ewentualnie dotyczyć tylko populacji, która składa się co najwyżej z jednego innego rodzaju wilka. W takim przypadku wskaźnik spotkania drugiego wilka wzrośnie / zmniejszy się mniej więcej tak samo jak mój. Jednak w przypadku rasy wielorakiej jakikolwiek wzrost liczby moich spotkań zostanie uśredniony wśród wszystkich innych wilków, więc moje będą proporcjonalnie większe. Myślę o jakimś minimalnym sposobie rozwiązania tego problemu, ale niestety mam teraz inne ważniejsze rzeczy, na których mogę się skoncentrować.
Tim Seguine

1
Ale zgadzam się, że ta metoda jest optymalna, jeśli istnieje co najwyżej jedna rasa wilków.
justhalf

12

Wilki ze zbiorową pamięcią

Paczka wilków w R.

Idea tego stada wilków polega na tym, że zachowuje w pamięci, kto żyje lub nie żyje, sprawdza, co wykorzystują martwe wilki i żywe wilki jako ataki, i odpowiednio zmienia prawdopodobieństwo wyboru.

Oto kod R:

infile <- file("stdin")
open(infile)
repeat{
    input <- readLines(infile,1)
    type <- substr(input,1,1)
    id <- substr(input,2,3)
    if(nchar(input)>3){
        info <- substr(input,4,nchar(input))
    }else{
        info <- NULL
    }
    attack <- function(id,info){
        if(info%in%c("B","L")){choice <- "S"}
        if(info=="S"){choice <- "P"}
        if(info=="W"){
            if(exists("memory")){
                dead <- memory$ID[memory$Status=="Dead"]
                veteran <- memory[memory$Attack!="" & !is.na(memory$Attack), ]
                if(nrow(veteran[!is.na(veteran[,1]),])>0){
                    deadvet<-veteran[veteran$ID%in%dead,]
                    deadvet<-unlist(lapply(split(deadvet,deadvet$ID),function(x)tail(x$Attack,1)))
                    deadvet <- table(factor(deadvet,levels=c("R","P","S","")))
                    livevet <- table(factor(veteran$Attack,levels=c("R","P","S","")))-deadvet
                    probR <- (1+livevet['R'])/(1+livevet['R']+deadvet['R'])
                    probS <- (1+livevet['S'])/(1+livevet['S']+deadvet['S'])
                    probP <- (1+livevet['P'])/(1+livevet['P']+deadvet['P'])
                    choice <- sample(c("S","P","R"),1,prob=c(probS,probP,probR))
                    memory <- rbind(memory, data.frame(ID=id, Status="Alive", Attack=choice))
                }else{
                    choice <- sample(c("S","P","R"),1)
                    memory <- rbind(memory, data.frame(ID=id, Status="Alive", Attack=choice))
                }
            }else{
                choice <- sample(c("S","P","R"),1)
                memory <- data.frame(ID=id, Status="Alive", Attack=choice)
            }
        }
        paste(choice,id,sep="")
    }
    move <- function(id,info){
        choice <- "H"
        paste(choice,id,sep="")
    }
    initialize <- function(id){
        if(exists("memory")){
            memory <- rbind(memory,data.frame(ID=id,Status="Alive",Attack=""))
        }else{
            memory <- data.frame(ID=id,Status="Alive",Attack="")
        }
        confirmed_dead <- memory$ID[memory$Status=="Dead"]
        last_seen <- memory[!memory$ID%in%confirmed_dead,]
        last_seen <- last_seen[last_seen$Attack=="",]
        lid <- table(last_seen$ID)
        turns <- max(lid)
        dead <- lid[lid<(turns-1)]
        if(length(dead)>0){
            dead_id <- names(dead)
            for(i in dead_id){
                memory <- rbind(memory, data.frame(ID=i, Status="Dead", Attack=""))
            }
        }
        paste("K",id,sep="")
    }
    result <- switch(type,"A"=attack(id,info),"M"= move(id,info),"S"=initialize(id))
    cat(result,"\n",sep="")
    flush(stdout())
}

Używa otoki @ProgrammerDan (dziękuję!), Z WolfCollectiveMemory jako nazwą niestandardową i „Rscript WolfCollectiveMemory.R” jako wywołanie.


Kilka rzeczy - po pierwsze jestem pewien, że wyjścia nie są opróżniane. Po drugie, gdy proces jest wywoływany przez opakowanie, jest kontynuowany . Twój obecny projekt zakłada, że ​​proces jest wywoływany za każdym razem, gdy komunikacja jest wysyłana do wilka - byłoby to zbyt kosztowne pod względem wywoływania procesu, więc zamiast tego uruchamiam proces i pozostawiam otwarte kanały komunikacji. Powinieneś mieć główną pętlę, która stale odczytuje linie z stdini zapisuje linię w odpowiedzi stdout, a następnie flush.console(). [ciąg]
ProgrammerDan

[cd] Moje opakowanie procesu powinno zakończyć proces potomny po zakończeniu symulacji.
ProgrammerDan

@Rusher Oto podstawa prawidłowego opakowania dla przesłania R @plannapus. Kliknij tutaj, aby pobrać R. Zainstaluj. Dodaj binfolder R do zmiennej PATH lub równoważnej i powinieneś być dobry (działał dobrze dla mnie).
ProgrammerDan

Myślę, że winowajcą jest readlinesrozkaz. Spróbuj użyć a readlinelub equiv. readlinesbędzie blokować do EOF.
ProgrammerDan

Właśnie dodałem, readLinesże kiedyś scan. readLinesprzy czym drugi argument 1oznacza, że ​​powinien kończyć się na pierwszym znaku nowej linii.
plannapus

12

MimicWolf

Celem tego wilka jest naśladowanie innych wilków. Okazuje się, że wilk podąża za nim najlepiej, jak potrafi. MimicWolf nie zadaje pytań takich jak: Jak mogę uniknąć tego wilka / niedźwiedzia / lwa / kamienia?

Nie, MimicWolf po prostu zadaje pytania: Gdzie mam iść za wilkiem? Gdzie myślę, że pójdzie wilk, którego śledzę? Czy to ten wilk, którego śledziłem, to inny wilk? Gdzie poszedł wilk, którego śledziłem?

Przyznaję, że na większość z tych pytań nie ma jeszcze dobrych odpowiedzi, ale na chwilę obecną moje zdanie na temat MimicWolf

   package animals;
   import java.util.*;

public class MimicWolf extends Animal {

final int TURN_MEMORY = 5;

Random rand = new Random();

Animal.Move lastMove = Animal.Move.UP;

boolean mimicingWolf = false;

Pos[] wolfPreviousPos = new Pos[TURN_MEMORY];
RelativePos[] relativePositions = new RelativePos[TURN_MEMORY];
Move[] wolfPreviousMove = new Move[TURN_MEMORY - 1];

int turnsWithLostWolf = 0;

public MimicWolf() {
    super('W');
}

public Animal.Attack fight(char c) {
    switch (c) {
        case 'B':
            return Animal.Attack.SCISSORS;
        case 'L':
            return Animal.Attack.SCISSORS;
        case 'S':
            return Animal.Attack.PAPER;
        default:
            int x = rand.nextInt(4);
            return Animal.Attack.values()[x];
    }
}

public Animal.Move move() {
    Pos wolfPos = null;
    wolfPos = lookForSurroundingWolf();

    if (turnsWithLostWolf == 4) {
        mimicingWolf = false;
        wolfPreviousPos = new Pos[5];
        relativePositions = new RelativePos[5];
        turnsWithLostWolf = 0;
    }

    if (mimicingWolf) {
        int indexOfLastMove = 0;
        for (int i = 0; wolfPreviousPos[i] != null && i < wolfPreviousPos.length; i++) {
            indexOfLastMove = i;
        }

        //is wolf still visible??
        Pos wolfNewPos = isWolfVisible(wolfPreviousPos[indexOfLastMove]);
        if (wolfNewPos.x == -1) {//wolf is not visible
            turnsWithLostWolf++;
            return moveOppositeDirection(lastMove);
        } else {
            return mimicWolf(wolfNewPos, indexOfLastMove); //need Better way to mimic
        }
    } else {
        //check if new wolf around
        if (wolfPos.x == -1) {
            return searchForWolf();
        } else {
            mimicingWolf = true;
            return mimicWolf(wolfPos, 0);
        }
    }
}

private Animal.Move searchForWolf() {
    Animal.Move newMove = null;
    while (newMove == null || newMove == lastMove) {
        newMove = Animal.Move.values()[rand.nextInt(3)];
    }

    lastMove = newMove;
    return newMove;
}

private Pos lookForSurroundingWolf() {
    for (Integer i = 0; i < surroundings.length; i++) {
        for (Integer j = 0; j < surroundings[0].length; j++) {
            if (i == 1 && j == 1) {
                //this is myself >.<
            } else if (surroundings[i][j] == 'W') {
                return new Pos(i, j);
            }
        }
    }

    return new Pos(-1, -1);
}

/*
    for mimicWolf when movesMimiced == 1 or 2 this is the base case, Any
    number greater the wolf will attempt to mimic the next move based on pattern
    of previous moves
        we assume that we are following the same wolf as last time
 */

private Animal.Move mimicWolf(Pos wolfCurrentPos, int movesMimiced) {
    wolfPreviousPos[movesMimiced] = wolfCurrentPos;
    insertToRelativePos(wolfCurrentPos, movesMimiced);
    if (movesMimiced == 0) {
        Move m1 = null, m2 = null;
        if (wolfPreviousPos[0].x == 0) {
            m1 = Move.LEFT;
        } else if (wolfPreviousPos[0].x == 2) {
            m1 = Move.RIGHT;
        }

        if (wolfPreviousPos[0].y == 0) {
            m2 = Move.UP;
        } else if (wolfPreviousPos[0].y == 2) {
            m2 = Move.DOWN;
        }

        return randOfMoves(m1, m2); //guess which way to go
    }
    wolfPreviousMove[movesMimiced - 1] =  getDirection(wolfPreviousPos[movesMimiced - 1], wolfPreviousPos[movesMimiced]);
    if (movesMimiced == 1) {
        //if pos 1 was a cornor
        if(relativePositions[0] == RelativePos.CORNER){
            if(relativePositions[1] == RelativePos.CORNER){
                if(wolfPreviousPos[0].equals(wolfPreviousPos[1])){
                    return lastMove;
                }
                return moveOppositeDirection(lastMove);
            }
            else if(relativePositions[1] == RelativePos.EDGE){
                return Move.HOLD; //he held so i will hold
            }
        }else if(relativePositions[1] == RelativePos.EDGE){
            if(relativePositions[1] == RelativePos.EDGE){
                return lastMove;
            }
            else if(relativePositions[1] == RelativePos.CORNER){
                //only possibility is that I held, and he moved
                return wolfPreviousMove[0];
            }
        }
    } else {
        //Return most common move the wolf I am copying has made
        int[] mostCommonMoveArr = {0,0,0,0,0};
        for(int i = 0; i <= movesMimiced; i++){
            switch(wolfPreviousMove[i]){
                case UP:
                    mostCommonMoveArr[0]++;
                case RIGHT:
                    mostCommonMoveArr[1]++;
                case DOWN:
                    mostCommonMoveArr[2]++;
                case LEFT:
                    mostCommonMoveArr[3]++;
                case HOLD:
                    mostCommonMoveArr[4]++;
            }
        }

        int maxValue = -1;
        int maxLocal = 0;
        for(int i = 0; i < 5; i++){
            if(mostCommonMoveArr[i] > maxValue)
                maxValue =  mostCommonMoveArr[i];
                maxLocal = i;
        }

        return Move.values()[maxLocal];
    }

    return Move.HOLD; //shouldn't happen
}

private Pos isWolfVisible(Pos lastPos) {
    Pos mimicedWolfPos = lookForSurroundingWolf();
    while (mimicedWolfPos.x != -1 && mimicedWolfPos.y != -1) {
        //did we find the wolf?
        if (lastPos.x == mimicedWolfPos.x || lastPos.y == mimicedWolfPos.y) {
            return mimicedWolfPos;
        }

        surroundings[mimicedWolfPos.x][mimicedWolfPos.y] = ' ';
        mimicedWolfPos = lookForSurroundingWolf();
    }

    return new Pos(-1, -1);
}

private Animal.Move moveOppositeDirection(Move m) {
    switch (m) {
        case UP:
            return Move.DOWN;
        case RIGHT:
            return Move.LEFT;
        case DOWN:
            return Move.UP;
        case LEFT:
            return Move.RIGHT;
        case HOLD:
            return Move.LEFT; //No idea why this would happen but whatever
        default:
            return Move.HOLD;
    }
}

private Animal.Move getDirection(Pos firstPos, Pos secondPos){
    if(firstPos.equals(secondPos))
        return Move.HOLD;
    if(firstPos.x == secondPos.x){
        if(firstPos.y > secondPos.y)
            return Move.UP;
        return Move.DOWN;
    }
    if(firstPos.x > secondPos.x)
        return Move.RIGHT;
    return Move.LEFT;
}


private Animal.Move randOfMoves(Move m1, Move m2) {
    if (m1 == null) {
        return m2;
    } else if (m2 == null) {
        return m1;
    }

    int r = rand.nextInt(2);
    if (r == 0) {
        return m1;
    }
    return m2;
}

private class Pos {
    int x;
    int y;

    protected Pos(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public boolean equals(Object obj){
        Pos pos = (Pos) obj;
        return (this.x == pos.x && this.y == pos.y);
    }
}

private void insertToRelativePos(Pos pos, int posToAdd){
    if(pos.x == 1 || pos.y == 1){
        relativePositions[posToAdd] = RelativePos.EDGE;
    }else{
        relativePositions[posToAdd] = RelativePos.CORNER;
    }
}

private enum RelativePos{
    CORNER, EDGE
}
}

Edycja: Dodałem lepszy system naśladowania. Wilki wciąż nie mają się dobrze, ponieważ nie próbują niczego w tej chwili unikać, ciągle poruszając się.


12

Nie jest to wpis, ale ponieważ większość wilków jest po prostu nieruchoma, oglądanie go jest naprawdę nudne, więc dodałem katastrofę naturalną do Dzikiego:

Trzęsienie ziemi!

Około 5% przypadków nastąpi trzęsienie ziemi o losowej wielkości, 100 oznacza najwyższą, a 20 najniższą. Spowoduje to earthquakeCounterzmniejszenie wykładnicze z upływem czasu po trzęsieniu ziemi.

Co się stało podczas trzęsienia ziemi?

Wszystkie zwierzęta będą miały szansę poruszać się losowo, w zależności od wartości earthquakeCounter. Jeśli więc wartość wynosi 75, około 75% zwierząt (w tym kamieni) będzie poruszać się losowo w dowolnym kierunku (równomiernie).

To, co nie dziwi, zabija wiele zwierząt, więc po kilku próbach maksymalnie wynosi około 50 zwierząt.

Trzęsienie ziemi będzie również wizualizowane w interfejsie GUI, który różni się w zależności od wielkości.

Nie widzę trzęsienia ziemi!

Szansa na trzęsienie ziemi jest niewielka, tylko 5%.

Ale nie martw się! Dodałem także „Trzęsienie ziemi!” przycisk na GUI, na wypadek gdybyś chciał zepchnąć wszystkie Wilki z ich stref komfortu ...

Oto zrzut ekranu:

trzęsienie ziemi

Oto kod:

Wild.java

main() funkcja (zaktualizowana w celu pominięcia GUI dla pierwszej 100 iteracji w celu przyspieszenia):

public static void main(String[] args) {

    int size = Math.round((float)Math.sqrt(classes.length+3)*20);
    final Game game = new Game(size);

    Statistics stats = new Statistics(game, classes);

    String[] colors = generateColors(classes.length);
    int idx = 0;
    for(Class c : classes){
        Animal.setColor(c, colors[idx]);
        idx++;
        game.populate(c, 100);
    }
    stats.update();

    JFrame gui = new JFrame();
    Container pane = gui.getContentPane();

    JLabel boardLabel = new JLabel();
    boardLabel.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
    boardLabel.setText(game.toString());
    pane.add(boardLabel, BorderLayout.WEST);

    JLabel statsLabel = new JLabel();
    statsLabel.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
    statsLabel.setText(stats.toString());
    pane.add(statsLabel, BorderLayout.EAST);

    JButton earthquakeButton = new JButton();
    earthquakeButton.addActionListener(new ActionListener(){

        @Override
        public void actionPerformed(ActionEvent e) {
            game.earthquake(true);
        }

    });
    earthquakeButton.setText("Earthquake!");
    pane.add(earthquakeButton, BorderLayout.SOUTH);

    gui.pack();
    gui.setVisible(true);

    for(int i=0; i<100; i++){
        game.iterate();
        stats.update();
    }

    while(true) {
        game.iterate();
        stats.update();
        boardLabel.setText(game.toString());
        statsLabel.setText(stats.toString());
        try { Thread.sleep(100); } catch (InterruptedException e) {}
    }
}

Game.java

package wild;

import animals.Animal;
import java.util.ArrayList;
import java.util.Random;
import animals.Animal.Attack;
import animals.Animal.Move;

public class Game {

    private ArrayList<ArrayList<ArrayList<Animal>>> board;
    private final Random gen = new Random();
    protected final int SIZE;
    private static int earthquakeCounter = 0;

    protected Game(int size) {
        this.SIZE = size;
        board = new ArrayList<>();
        for (int i = 0; i < size; i++) {
            board.add(new ArrayList<ArrayList<Animal>>());
            for (int j = 0; j < size; j++) {
                board.get(i).add(new ArrayList<Animal>());
            }
        }
    }

    protected <T extends Animal> void populate(Class<T> species, int num) {
        while (num > 0) {
            int row = gen.nextInt(SIZE);
            int col = gen.nextInt(SIZE);
            if (board.get(row).get(col).isEmpty()) {
                try { board.get(row).get(col).add(species.newInstance()); } 
                catch (InstantiationException | IllegalAccessException e) {}
                num--;
            }
        }
    }

    protected void iterate() {
        earthquake(false);
        moveAll();
        flatten();
    }

    private void moveAll() {
        Game game = new Game(SIZE);
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                if (!board.get(i).get(j).isEmpty()) {
                    Animal a = board.get(i).get(j).get(0);
                    a.surroundings = getArea(i, j);
                    Move aMove;
                    try { aMove = a.move(); } 
                    catch (Exception e) { aMove = Move.HOLD; }
                    if(gen.nextInt(100)<earthquakeCounter){
                        aMove = Move.values()[gen.nextInt(4)];
                    }
                    switch(aMove) {
                        case UP:
                            game.board.get((i-1+SIZE)%SIZE).get(j).add(a);
                            break;
                        case RIGHT:
                            game.board.get(i).get((j+1)%SIZE).add(a);
                            break;
                        case DOWN:
                            game.board.get((i+1)%SIZE).get(j).add(a);
                            break;
                        case LEFT:
                            game.board.get(i).get((j-1+SIZE)%SIZE).add(a);
                            break;
                        case HOLD:
                            game.board.get(i).get(j).add(a);
                            break;
                    }
                }
            }
        }
        board = game.board;
    }

    /**
     * Give a random chance for an earthquake to happen
     */
    protected void earthquake(boolean force){
        if(force || (earthquakeCounter==0 && gen.nextInt(1000)>950)){
            earthquakeCounter = 20+gen.nextInt(80);
        } else {
            earthquakeCounter /= 2;
        }
    }

    private void flatten() {
        for (ArrayList<ArrayList<Animal>> row : board) {
            for (ArrayList<Animal> cell : row) {
                while (cell.size() > 1) {
                    int rand1, rand2;
                    rand1 = gen.nextInt(cell.size());
                    do { rand2 = gen.nextInt(cell.size()); } while (rand1 == rand2);

                    Animal a = cell.get(rand1);
                    Animal b = cell.get(rand2);
                    Attack aTack, bTack;
                    try { aTack = a.fight(b.letter); } 
                    catch (Exception e) { aTack = Attack.SUICIDE; }
                    try {  bTack = b.fight(a.letter); }
                    catch (Exception e) { bTack = Attack.SUICIDE; }

                    if (aTack == bTack) {
                        cell.remove((Animal)(Math.random() > 0.5 ? a : b));
                    } else {
                        switch (aTack) {
                            case ROCK:
                                cell.remove((Animal)(bTack == Attack.PAPER ? a : b));
                                break;
                            case PAPER:
                                cell.remove((Animal)(bTack == Attack.SCISSORS ? a : b));
                                break;
                            case SCISSORS:
                                cell.remove((Animal)(bTack == Attack.ROCK ? a : b));
                                break;
                        }
                    } 
                }
            }
        }
    }

    protected int poll(Class c) {
        int count = 0;
        for (ArrayList<ArrayList<Animal>> row : board) {
            for (ArrayList<Animal> cell : row) {
                for (Animal a : cell) {
                    if(c.isInstance(a))
                        count++;
                }
            }
        }
        return count;
    }

    public String toString() {
        String s = "<html>";
        s += "<span style='background:"+getBackgroundColor()+"'>";
        for (ArrayList<ArrayList<Animal>> row : board) {
            for (ArrayList<Animal> cell : row) {
                if (cell.isEmpty())
                    s += "&nbsp;&nbsp;";
                else
                    s += "<span style='color:"+ Animal.color.get(cell.get(0).getClass()) +"'>" + cell.get(0).letter + "</span>&nbsp;";
            }
            s+="<br>";
        }
        s += "</span>";
        return s + "</html>";
    }

    private String getBackgroundColor(){
        int shade = 255-(int)Math.floor(255*earthquakeCounter/100.0);
        String result = String.format("#%02x%02x%02x", shade, shade, shade);
        return result;
    }

    private char[][] getArea(int i, int j) {
        char[][] area = new char[3][3];
        for(int k = -1; k <= 1; k++) {
            for(int l = -1; l <= 1; l++) {
                int temp1 = k+1;
                int temp2 = l+1;
                int temp3 = (i+k+SIZE)%SIZE;
                int temp4 = (j+l+SIZE)%SIZE;
                ArrayList<Animal> cell = board.get((i+k+SIZE)%SIZE).get((j+l+SIZE)%SIZE);
                area[k+1][l+1] = (char)(cell.isEmpty() ? ' ' : cell.get(0).letter);
            }
        }
        return area;
    }
}

5
niektórzy ludzie chcą tylko oglądać świat ... trzęsienia ziemi
CommonGuy

5
My GatheringWolves płaczą.
johnchen902

12

MultiWolf (Java)

Ten wilk wie o innych wilkach w tym wyzwaniu programistycznym. Tworzy instancję (jako „zwierzęta domowe”), jeśli są one dostępne, i używa ich do określenia, co zrobić, pytając każdego swojego wilka, którego jest właścicielem, i wybiera najbardziej popularną odpowiedź.

Ten wilk powinien być bezpieczny w nieskończoność - np. Jeśli ktoś wdroży podobną koncepcję - i zwróci domyślną akcję Attack.ROCK/ Move.HOLDjeśli wykryje, że został wywołany, gdy woła inne zwierzęta.

W moich testach wyniki były różne. Nie jestem pewien, czy będzie to dozwolone czy nie. Ale jeśli tak, i zdarzy się jakiś niemożliwy cud, który spowoduje, że wygra, myślę, że zwycięski tytuł powinien zostać przekazany wilkowi, który jest „drugi” - to jest sprawiedliwe, prawdopodobnie ukradłem jego logikę.

Unika samobójstwa.

Edycja - Wierzę, że Wilk będzie musiał zostać załadowany po tym, jak wilki, o których wspomina, działają poprawnie.

package animals;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map.Entry;

public class MultiWolf extends Animal {

    private static final LinkedList<Animal> pets = new LinkedList<>();
    private static boolean inPetCall = false;

    private static void attemptLoadPet(String className) {
        try {
            Object pet = Class.forName(className).newInstance();

            if (pet instanceof Animal) {
                pets.add((Animal) pet);
            }
        } catch (Exception ex) {
            // this wolf is not available
            System.out.println(className + " is not available for MultiWolf cheating.");
        }
    }

    static {
        attemptLoadPet("animals.AlphaWolf");
        attemptLoadPet("animals.CamperWolf");
        attemptLoadPet("animals.GamblerWolf");
        attemptLoadPet("animals.GatheringWolf");
        attemptLoadPet("animals.LazyWolf");
        attemptLoadPet("animals.Sheep");
        attemptLoadPet("animals.Wion");

        attemptLoadPet("animals.MOSHPITFRENZYWolf");
        attemptLoadPet("animals.PassiveAgressiveWolf");
        attemptLoadPet("animals.StoneEatingWolf");
        attemptLoadPet("animals.HerjanWolf");
        attemptLoadPet("animals.HonorWolf");
        attemptLoadPet("animals.MimicWolf");
        attemptLoadPet("animals.LionHunterWolf");
        attemptLoadPet("animals.OmegaWolf");
        attemptLoadPet("animals.WolfWithoutFear");
        attemptLoadPet("animals.WolfRunningWithScissors");
        // attemptLoadPet("animals.SmartWolf");
        // According to Rusher, the above cheating of a non-Java wolf breaks the non-Java-entry wrapper.
        attemptLoadPet("animals.ShadowWolf");
        attemptLoadPet("animals.HybridWolf");
        attemptLoadPet("animals.ProAlpha");
        attemptLoadPet("animals.ForrestWolf");
        attemptLoadPet("animals.WhenIGrowUp");
        attemptLoadPet("animals.MigratingWolf");
        attemptLoadPet("animals.BlindWolf");
    }

    public MultiWolf() {
        super('W');
    }

    @Override
    public Attack fight(char opponent) {
        if (inPetCall) {
            // stop infinite recursion
            return Attack.ROCK;
        }

        inPetCall = true;

        HashMap<Attack, Integer> collect = new HashMap<>();

        collect.put(Attack.ROCK, 0);
        collect.put(Attack.PAPER, 0);
        collect.put(Attack.SCISSORS, 0);
        collect.put(Attack.SUICIDE, -9001);

        for (Animal a : pets) {
            a.surroundings = this.surroundings;
            Attack atk = a.fight(opponent);
            collect.put(atk, collect.get(atk)+1);
        }

        int top=0;
        Attack atk=Attack.ROCK;

        for (Entry<Attack, Integer> ent : collect.entrySet()) {
            if (ent.getValue() > top) {
                atk = ent.getKey();
                top = ent.getValue();
            }
        }

        inPetCall = false;

        return atk;
    }

    @Override
    public Move move() {
        if (inPetCall) {
            // stop infinite recursion
            return Move.HOLD;
        }

        inPetCall = true;

        HashMap<Move, Integer> collect = new HashMap<>();

        collect.put(Move.DOWN, 0);
        collect.put(Move.HOLD, 0);
        collect.put(Move.LEFT, 0);
        collect.put(Move.RIGHT, 0);
        collect.put(Move.UP, 0);


        for (Animal a : pets) {
            a.surroundings = this.surroundings;
            Move mv = a.move();
            collect.put(mv, collect.get(mv)+1);
        }

        int top=0;
        Move mv=Move.HOLD;

        for (Entry<Move, Integer> ent : collect.entrySet()) {
            if (ent.getValue() > top) {
                mv = ent.getKey();
                top = ent.getValue();
            }
        }

        inPetCall = false;

        return mv;
    }

}

Jeśli dobrze pamiętam, możesz dostać klasy przez Wild.classes, ponieważ jest to pole statyczne ... Więc nie będziesz musiał aktualizować swojego wilka za każdym razem, gdy pojawi się tutaj nowy wilk;)
CommonGuy

To prawda. Ale zrobiłem to w ten sposób, prawdopodobnie zamierzam to porzucić. Może również usunąć niektóre z mniej wygranych wilków z tego wielozakresowego wilka. Wydaje się, że Wion wymiera za każdym razem w moich biegach, rozważam odcięcie go od MultiWolf, ponieważ zastanawiam się, czy to obniży jakość działań.
OlivierTheOlive

Uważam, że reguła „Nie możesz czytać ani modyfikować plików utworzonych przez inną klasę Wolfa” miała obejmować same inne pliki klasy wilków. Myślę więc, że ten wpis, mimo że jest świetnym pomysłem, jest niezgodny z zasadami.
Runer112,

1
@ Runer112 Zastanawiałem się, ale dowiedziałem się trochę o ładowaniu klas według nazwy i że nie ma prostego sposobu na znalezienie wszystkich klas w pakiecie. Po prostu trochę zabawy
OlivierTheOlive

3
Tworzenie instancji innego wilka nie stanowi odczytu ani modyfikacji plików utworzonych przez innego wilka, więc przesłanie jest uzasadnione. Reguła miała na celu ochronę danych przed przesłaniami napisanymi w językach, które nie mają takich zmiennych statycznych i muszą zamiast tego zapisywać do pliku.
Rainbolt

12

Stone Eating Wolf

Oto moje zgłoszenie. Ten wilk utrzymuje się na miejscu, jeśli nie widzi kamienia, lwa ani wilka w swoim otoczeniu. Jeśli zobaczy kamień i nie ma niebezpieczeństwa, że ​​zostanie zaatakowany przez innego wilka lub lwa, spróbuje go zjeść. Jeśli widzi jakieś niebezpieczeństwo, ucieka!

EDYCJA 1 : Poprawione monitorowanie algorytmu niebezpieczeństwa. Teraz lepiej ucieka przed niebezpieczeństwem :)

package animals;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


public class StoneEatingWolf extends Animal{

    public StoneEatingWolf() {
        super('W');
    }

    @Override
    public Attack fight(char c) {
        switch (c){
            case 'L': return Attack.SCISSORS;
            case 'B': return Attack.SCISSORS;
            case 'W': return getRandomAttack();
            case 'S': return Attack.PAPER;
            default: return getRandomAttack();
        }
    }

    private Attack getRandomAttack(){
        List<Attack> att = new ArrayList<>();
        att.add(Attack.PAPER);
        att.add(Attack.PAPER);
        att.add(Attack.ROCK);
        att.add(Attack.SCISSORS);
        Collections.shuffle(att);
        return att.get(0);
    }

    @Override
    public Move move() {
        List<Move> m = new ArrayList<>();

        //First see if there is any dangerous animal. If it is, then flee
        if (isThereAnyDangerousAnimal()){
            m.add(Move.UP);
            m.add(Move.RIGHT);
            m.add(Move.LEFT);
            m.add(Move.DOWN);
            getSafeMoves(m);
        }else{
        //No danger: Look for stones to eat
            if (isThereAnimalAtNorth('S')){
                m.add(Move.UP);
            }
            if (isThereAnimalAtEast('S')){
                m.add(Move.RIGHT);
            }
            if (isThereAnimalAtWest('S')){
                m.add(Move.LEFT);
            }
            if (isThereAnimalAtSouth('S')){
                m.add(Move.DOWN);
            }
        }

        if (m.isEmpty()){
            return Move.HOLD;
        } else {
            Collections.shuffle(m);
            return m.get(0);
        }
    }

    private void getSafeMoves(List<Move> lm){

        if (isThereAnimalAtNorth('L') || isThereAnimalAtNorth('W')){
            lm.remove(Move.UP);
        }
        if (isThereAnimalAtEast('L') || isThereAnimalAtEast('W')){
            lm.remove(Move.RIGHT);
        }
        if (isThereAnimalAtSouth('L') || isThereAnimalAtSouth('W')){
            lm.remove(Move.DOWN);
        }
        if (isThereAnimalAtWest('L') || isThereAnimalAtWest('W')){
            lm.remove(Move.LEFT);
        }

    }

    private boolean isThereAnimalAtNorth(char an){
        if (surroundings[0][0] == an || surroundings [0][1] == an || surroundings [0][2] == an){
            return true;
        }
        return false;
    }

    private boolean isThereAnimalAtSouth(char an){
        if (surroundings[2][0] == an || surroundings [2][2] == an || surroundings [2][2] == an){
            return true;
        }
        return false;
    }

    private boolean isThereAnimalAtEast(char an){
        if (surroundings[0][2] == an || surroundings [1][2] == an || surroundings [2][2] == an){
            return true;
        }
        return false;
    }

    private boolean isThereAnimalAtWest(char an){
        if (surroundings[0][0] == an || surroundings [1][0] == an || surroundings [2][0] == an){
            return true;
        }
        return false;
    }

    private boolean isThereAnyDangerousAnimal(){
        if (isThereAnimalAtEast('L') ||
                isThereAnimalAtEast('W') ||
                isThereAnimalAtNorth('L') ||
                isThereAnimalAtNorth('W') ||
                isThereAnimalAtSouth('L') ||
                isThereAnimalAtSouth('W') ||
                isThereAnimalAtWest('L') ||
                isThereAnimalAtWest('W')){
            return true;
        }
        return false;
    }

    }

Edycja 2 : Niektóre statystyki

Udało mi się uczynić StoneEatingWolf top 5-6 Wolfem w przeprowadzonych przeze mnie symulacjach:

Średnie wyniki po 40 odtworzeniach z 1000 iteracji

Dokonuję analizy walk, w których sugerowane są Kamienne Wilki Jedzące. Po uruchomieniu 40 odtworzeń z 1000 iteracji otrzymuję te wyniki:

Tabela wyników walki

Zwycięstwem są wygrane przez kamień jedzący wilka. Tabela pokazuje, co już wiemy: Wilki, które odniosły największy sukces, to te, które nie spotykają innych wilków. Zauważyłem również, że moje inne wilki (Migrujące Wilki) psują niektóre z moich Kamiennych Zjadaczy. Mam nadzieję, że polują również na inne wilki. Zabawne, że nie natknąłem się na Lazy Wolfa ani na Camper Wolfa. Są to również wyniki ataków, które otrzymałem w 20 biegach (z wyłączeniem kamieni i niedźwiedzi):

PAPER       447
ROCK        881
SCISSORS    581
SUICIDE     230

Wygląda na to, że ROCKataki mają oczywistą stronniczość . Wiedząc o tym, moje wilki PAPERatakują nieco więcej częstotliwości.


2
Proszę nie używać wykresu liniowego do drukowania danych kategorycznych. To daje mi tyle raka, patrząc na twój wykres.
AJMansfield

@AJMansfield Przykro mi to słyszeć. Mam nadzieję, że wyzdrowiejesz;) W każdym razie wezmę to pod uwagę przy tworzeniu każdego przyszłego wykresu.
Averroes

Nadal używasz systemu Windows XP? oO
pół

I dlaczego używasz ROCK(50% wygranej) do walki z Lwem? Najlepiej jest użyć SCISSORS(75% wygranej)
pół

@ justhalf Moja firma nadal używa XP ... I masz rację co do nożyczek. Naprawiony. Dzięki :)
Averroes

11

HonorWolf

Mój Wilk ucieka przed innymi wilkami. Jeśli nie może uciec, honorowo rozpoczyna walkę.

package animals;
public class HonorWolf extends Animal {

    private int moves = 0;

    public HonorWolf() { 
        super('W'); 
    }

    @Override   
    public Attack fight(char opponent) { 
        switch(opponent) {
         case 'L':
            return Attack.SCISSORS; 
         case 'B':
            return Attack.SCISSORS;
         case 'S':
            return Attack.PAPER;
        default:
            return Attack.PAPER;
        }
    }

    public Move move() {
        int numWolves = 0, numLions = 0;

        moves++;

        for (int y = 0; y != 3; y++) {
            for (int x = 0; x != 3; x++) {
                if(surroundings[y][x] != ' ') {
                    if(surroundings[y][x] == 'W') {
                        numWolves++;
                    } else if(surroundings[y][x] == 'L') {
                        numLions++;
                    }
                }
            }       
        }

        if (numWolves == 1 && numLions == 0) {
            return Move.HOLD;
        }

        if (surroundings[0][1] == 'L' && moves%2 != 0) {
            return Move.UP;
        } 

        if (surroundings[1][0] == 'L' && moves%2 == 0) {
            return Move.LEFT;
        }

        if (surroundings[0][1] == 'W') {
            if (surroundings[2][1] == ' ' || surroundings[2][1] == 'S') {
                return Move.DOWN;
            } else if (surroundings[1][2] == ' ' || surroundings[1][2] == 'S') {
                return Move.RIGHT;
            } else if (surroundings[1][0] == ' ' || surroundings[1][0] == 'S') {
                return Move.LEFT;
            } else {
                return Move.UP;
            }
        }

        if (surroundings[1][0] == 'W') {
            if (surroundings[1][2] == ' ' || surroundings[1][2] == 'S') {
                return Move.RIGHT;
            } else if (surroundings[0][1] == ' ' || surroundings[0][1] == 'S') {
                return Move.UP;
            } else if (surroundings[2][1] == ' ' || surroundings[2][1] == 'S') {
                return Move.DOWN;
            } else {
                return Move.LEFT;
            }
        }

        if (surroundings[1][2] == 'W') {
            if (surroundings[1][0] == ' ' || surroundings[1][0] == 'S') {
                return Move.LEFT;
            } else if (surroundings[0][1] == ' ' || surroundings[0][1] == 'S') {
                return Move.UP;
            } else if (surroundings[2][1] == ' ' || surroundings[2][1] == 'S') {
                return Move.DOWN;
            } else {
                return Move.RIGHT;
            }
        }

        if (surroundings[2][1] == 'W') {
            if (surroundings[0][1] == ' ' || surroundings[0][1] == 'S') {
                return Move.UP;
            } else if (surroundings[1][0] == ' ' || surroundings[1][0] == 'S') {
                return Move.LEFT;
            } else if (surroundings[1][2] == ' ' || surroundings[1][2] == 'S') {
                return Move.RIGHT;
            } else {
                return Move.DOWN;
            }
        }

        return Move.HOLD;
    }
}

Muszę zmienić taktykę ataku pro-wilka alfa. Gdybym trzymał i został zaatakowany przez wilka: walcz z nożyczkami;)
Ilya Gazman

11

The Blind Wolf

Ślepy wilk boi się poruszyć i nigdy nie wie, z czym walczy. Grając nożyczkami za każdym razem ma najlepsze szanse, ponieważ nigdy nie trafi w prawdziwy kamień.

package animals;

public class BlindWolf extends Animal {
    public BlindWolf() { super('W'); }

    @Override
    public Attack fight(char c) { 
        return Attack.SCISSORS;
    }

    @Override
    public Move move() {
        return Move.HOLD;
    }
}

11

Kiedy dorosnę

Kiedy ten wilk dorośnie, chce być lwem. Więc losowo chodzi po okolicy, szukając Lwów, które podążają ich śladami i uczą się, jak być lwem.

Ten wilk został zaprojektowany jako przeciwdziałanie wilkom, które zamieniają się miejscami z Lwami.

package animals;

import java.util.Random;

/**
 *
 * @author Quincunx
 */
public class WhenIGrowUp extends Animal {

    Random r;
    boolean following;
    boolean toggle;

    public WhenIGrowUp() {
        super('W');
        r = new Random();
        following = false;
        toggle = false;
    }

    @Override
    public Attack fight(char c) {
        switch (c) {
            case 'B':
                return Attack.SCISSORS;
            case 'L':
            case 'S':
                return Attack.PAPER;
            default:
                return Attack.values()[r.nextInt(4)];
        }
    }

    @Override
    public Move move() {
        if (surroundings[1][2] == 'L') {
            return Move.RIGHT;
        }
        if (surroundings[2][1] == 'L') {
            return Move.DOWN;
        }
        Move direction = Move.values()[r.nextInt(5)];
        out:
        for (int y = 0; y < 3; y++) {
            for (int x = 0; x < 3; x++) {
                if (surroundings[y][x] == 'L') {
                    if (y == 0 && x == 1) {
                        direction = Move.UP;
                    } else if (y == 1 && x == 0) {
                        direction = Move.LEFT;
                    } else {
                        direction = Move.HOLD;
                    }
                    break out;
                }
            }
        }
        return direction;
    }
}

11

SpyWolf

SpyWolf szpieguje wrogów i rejestruje ich aktywność, dzięki czemu może obserwować każdego, zachowując dystans. Nie chciałbym się dowiedzieć!

package animals;

import static animals.Animal.Attack.*;
import static animals.Animal.Move.*;

import java.awt.Point;
import java.util.*;

public class SpyWolf extends Animal {

    private static final Random r = new Random();
    private static boolean hasTestedPRNG = false;
    private static int PRNG = -1;
    private boolean lionTracker = true;
    private boolean useScissors = false;

    private final ArrayList<MapTile> map = new ArrayList<MapTile>();
    private final Point location = new Point();

    public SpyWolf() {
        super('W');
    }

    @Override
    public Animal.Attack fight(char opponent) {
        switch (opponent) {
            case 'B':
            case 'L':
                return SCISSORS;
            case 'S':
                return PAPER;
            default:
                if (useScissors) {
                    useScissors = false;
                    return SCISSORS;
                }
                return PAPER;
        }
    }

    @Override
    public Animal.Move move() {

        Move m = HOLD;

        if (!hasTestedPRNG) {
            hasTestedPRNG = true;
            double d = 0;
            for (int i = 0; i < 100; i++)
                d += Math.random();
            if (d > 99) {
                PRNG = 1;
            } else if (d > 30 && d < 70) PRNG = 0;
        }

        lionTracker = !lionTracker;
        boolean adj = false;

        updateMap();

        scan: {
            if (PRNG < 1) {
                if (look(LEFT) == 'L' && !lionTracker) {
                    useScissors = true;
                    m = LEFT;
                    break scan;
                }

                if (look(UP) == 'L' & lionTracker) {
                    useScissors = true;
                    m = UP;
                    break scan;
                }
            }

            int x = 0, y = 0;
            ArrayList<Move> moves = new ArrayList<Move>(4);

            for (Move i : Move.values())
                moves.add(i);

            if (look(UP) == 'W') {
                y += 54;
                moves.remove(UP);
                adj = true;
            }
            if (look(DOWN) == 'W') {
                y -= 54;
                moves.remove(DOWN);
                adj = true;
            }
            if (look(LEFT) == 'W') {
                x += 54;
                moves.remove(LEFT);
                adj = true;
            }
            if (look(RIGHT) == 'W') {
                x -= 54;
                moves.remove(RIGHT);
                adj = true;
            }

            if (moves.isEmpty() || !adj) break scan;

            for (MapTile t : map) {
                if (t.x >= location.x - 2 && t.x <= location.x + 2 && t.y >= location.y - 2 && t.y <= location.y + 2 && t.d) {
                    int dist = Math.abs(t.x - location.x) + Math.abs(t.y - location.y);
                    y += t.y > location.y ? -60 / dist : 60 / dist;
                    x += t.x < location.x ? 60 / dist : -60 / dist;
                }
            }
            m = moveDir(x, y);
            if (!moves.contains(m)) m = HOLD;
        }
        switch (m) {
            case UP:
                location.y--;
                return m;
            case DOWN:
                location.y++;
                return m;
            case LEFT:
                location.x--;
                return m;
            case RIGHT:
                location.x++;
                return m;
            default:
                return m;
        }
    }

    private void updateMap() {
        for (int y = -1; y < 2; y++)
            xloop: for (int x = -1; x < 2; x++) {
                if (x == 0 && y == 0) continue;
                for (MapTile t : map)
                    if (t.x == x + location.x && t.y == y + location.y) {
                        t.d = surroundings[y + 1][x + 1] == 'W';
                        continue xloop;
                    }
                map.add(new MapTile(x + location.x, y + location.y, surroundings[y + 1][x + 1] == 'W'));
            }
    }

    private Move moveDir(int x, int y) {
        if (x == 0) return y < 0 ? UP : y > 0 ? DOWN : HOLD;
        if (y == 0) return x < 0 ? LEFT : RIGHT;
        if (x < 0) {
            if (y < 0) {
                if (y < x)
                    return UP;
                else if (x < y) return LEFT;
                return r.nextBoolean() ? UP : LEFT;
            } else {
                if (-y < x)
                    return DOWN;
                else if (x < -y) return LEFT;
                return r.nextBoolean() ? DOWN : LEFT;
            }
        }
        if (y < 0) {
            if (y < -x)
                return UP;
            else if (-x < y) return RIGHT;
            return r.nextBoolean() ? UP : RIGHT;
        } else {
            if (y > x)
                return DOWN;
            else if (x < y) return RIGHT;
        return r.nextBoolean() ? DOWN : RIGHT;
        }
    }

    private char look(Move direction) {
        switch (direction) {
            case UP:
                return surroundings[0][1];
            case DOWN:
                return surroundings[2][1];
            case LEFT:
                return surroundings[1][0];
            case RIGHT:
                return surroundings[1][2];
            default:
                return surroundings[1][1];
        }
    }

    private static class MapTile {
        int x, y;
        boolean d;

        MapTile(int x, int y, boolean d) {
            this.x = x;
            this.y = y;
            this.d = d;
        }
    }
}

Całkiem nieźle sobie radzi, ale ten kulawy HybridWolf jest zbyt oszukiwany! Zobaczymy, że SpyWolf może wrócić do szkoły szpiegowskiej i trenować zaawansowane techniki przeciw wilkom.



5
AHHHHH! Tyle gotos! I w języku, który nawet ich nie ma!
AJMansfield

9

HybridWolf

Nie mogłem się oprzeć, by stworzyć kolejnego wilka. Ten jest bardzo różny (w kodzie, a nie w zachowaniu), ponieważ wybiera atak / ruch, który zrobiłyby inne dobre wilki.
Oczywiście wszystkie wilki są dobre, ale mam na myśli te, które mają najwięcej punktów :)

package animals;

import java.util.ArrayList;
import java.util.Random;

public class HybridWolf extends Animal{
    private final Class[] classes = {ProAlpha.class, OmegaWolf.class, SpyWolf.class, HerjanWolf.class, DeepWolf.class, ProtoWolf.class};
    private final ArrayList<Animal> wolves = new ArrayList<Animal>(); 

    public HybridWolf() {
        super('W');
        for(Class c: classes) {
            try {
                wolves.add((Animal)c.newInstance());
            } catch (Exception ex) {}
        }
    }

    @Override
    public Attack fight(char opponent) {
        switch(opponent){
        case 'B':
        case 'L':
            return Attack.SCISSORS;
        case 'S': 
            return Attack.PAPER;
        default:
            try {
                int[] attacks = new int[3];
                Attack bestAttack = randomAttack();
                for(Animal wolf : wolves) {
                    wolf.surroundings = this.surroundings;
                    attacks[wolf.fight(opponent).ordinal()]++;
                }
                for(int i =0; i < 5; i++) {
                    if(attacks[i] > attacks[bestAttack.ordinal()]) {
                        bestAttack = Attack.values()[i];
                    }
                }
                return bestAttack;
            } catch (Exception e) {
                return randomAttack();
            }
        }
    }

    @Override
    public Move move() {
        try {
            int[] moves = new int[5];
            Move bestMove = Move.HOLD;
            for(Animal wolf : wolves) {
                wolf.surroundings = this.surroundings;
                moves[wolf.move().ordinal()]++;
            }
            for(int i =0; i < 5; i++) {
                if(moves[i] > moves[bestMove.ordinal()]) {
                    bestMove = Move.values()[i];
                }
            }
            return bestMove;
        } catch (Exception e) {
            return Move.HOLD;
        }
    }

    public Attack randomAttack() {
        Random rand = new Random();
        switch (rand.nextInt(3)){
            case 1: return Attack.SCISSORS;
            case 2: return Attack.ROCK;
            default: return Attack.PAPER;
        }
    }

}

W moich testach osiąga lepsze wyniki niż mój poprzedni AlphaWolf, ale czasem Omega / Honor / ProAlpha czasami mnie biją ... Im więcej dobrych zgłoszeń, tym lepszy będzie ten wilk: D


To jest trochę bezczelne! sprytny pomysł. Nie jestem pewien, jak to będzie sprawiedliwe, ponieważ nie mam pojęcia o testach, które Rusher zastosuje w celu ustalenia prawidłowego wejścia. tzn. jeśli wykona test w izolacji, bez innych obecnych wilków, ten wilk
niefortunnie

@Moogie 90% wpisów jest zgodnych z prawem. Do tej pory wykluczałem tylko wpisy, które zmieniły literę na coś innego niż „W”, lub wpisy, których nie mogłem wymyślić, jak skompilować w innym języku (i daję im znać, jeśli tak jest, ale możesz nie widzę go tutaj, ponieważ rozmawiam z nimi na czacie).
Rainbolt,

@Rusher Istnieje kilka wpisów, które próbują zmienić szanse na ich korzyść. np. wilk Gambler zmienia generator liczb losowych w Math.random (), by zawsze zwracał 1! Zabawne jest to, że ma niewielki wpływ na wyniki, ponieważ zwycięskie wilki to wilki, które unikają walki!
Moogie,

@Moogie GamblerWolf to legalne zgłoszenie (i całkiem sprytne). Masz rację, to niewiele zmieniło wyniki. Jeśli coś wymknie się spod kontroli, powiem tylko: „Ok, wygrywa, ale oto wynik, jeśli NIE BĘDZIE”. W ten sposób wszyscy inni mogą nadal cieszyć się z tego, że nie zostali wymazani.
Rainbolt,

2
@Moogie Jeśli coś nie jest specjalnie zabronione w specyfikacji wyzwania, jest to de facto uzasadnione, a tradycją na tej stronie jest to, że nie zmienia się reguł, gdy ludzie opublikują odpowiedzi na to pytanie.
plannapus

9

EvoWolf

Wszystkie głupie, inteligentnie zaprojektowane wilki! EvoWolf mieszka na wolności wraz z innymi twardymi wilkami, takimi jak DeepWolf i HerjanWolf, więc musiał ewoluować, aby przetrwać.

Kod wykorzystuje algorytm genetyczny do ewolucji najlepszego wilka (nie zauważyłem LionHunterWolf, dopóki nie złapałem Wilków, by trenować). Istnieją różne geny dla każdej kombinacji zwierzę / atak, kierunek ruchu, gdy jest bezpieczny, i kierunek ruchu dla każdego zwierzęcia w otoczeniu. Po 1000 rundach wilki, które przetrwały największą liczbę tur, mają najwyższe prawdopodobieństwo urodzenia potomstwa (tj. Im dłużej żyjesz, tym większe masz szanse na partnerstwo). Wrzucamy także losową mutację u około 10% dzieci w nadziei, że to pomoże.

Oto kod EvoWolf, POTRZEBUJESZ TAKŻE evowolf.txt W SWOIM KATALOGU PRACY - ZAWIERA BIEŻĄCĄ GENEPOOL. Jeśli chcesz ewoluować własne wilki od pierwotnej przypadkowości, nie dołączaj evowolf.txt, ale ten podany jest obecnie najlepszą ewolucją. Naprawdę fajnie jest obserwować, jak ewoluuje, na początku przeżywa tylko 2-3, ale potem osiąga 60.

package animals;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Random;

public class EvoWolf extends Animal {
    public EvoWolf() { super('W'); birth();}
    public Attack fight(char c) { 
        List<Attack> attacks = getAttacks(c);
        if(attacks.size() == 0)
            return Attack.SUICIDE; //Discourage wolves without attacks, Darwin Award

        return attacks.get(random.nextInt(attacks.size()));
    }

    public Move move() {
        ++turns;
        List<Move> moves = new ArrayList<Move>();
        if(isSafe())
            moves = getSafeMoves();
        else
            moves = getThreatenedMoves();

        return (Move)moves.toArray()[random.nextInt(moves.size())];
    }

    /*====STATIC METHODS====*/
    //Shared RNG
    public static Random random = new Random();

    //Collection of 100 sets of genes
    public static String[] genePool = null;

    //Get the genes from disk or randomly generate some
    public static void readGenePool(){
        genePool = new String[100];
        int gIdx = 0;
        try (BufferedReader br = new BufferedReader(new FileReader("evowolf.txt"))){
            String sCurrentLine; 
            while ((sCurrentLine = br.readLine()) != null) {
                genePool[gIdx] = sCurrentLine;
                ++gIdx;
            }
        } catch (IOException e) {

        } 

        //if can't read genes, make some
        if(gIdx < 100){
            primordial(gIdx);
        }
    }
    public static void primordial(int idx){
        for(;idx < 100; ++idx){
            genePool[idx] = getRandomGenes();
        }
    }

    public static String getRandomGenes(){
        StringBuilder sb = new StringBuilder();
        for(int idx = 0; idx < GENE_COUNT; ++idx){
            if(random.nextBoolean())
                sb.append("1");
            else
                sb.append("0");
        }
        return sb.toString();
    }

    //Evolve wolves
    public static void nextGen(){
        //Check survival of current gen
        int survivors = 0;
        for(int idx = 0; idx < 100; ++idx){
            survivors = survivors + (generation[idx].turns == 1000 ? 1 : 0);
        }
        if(survivors > 65)
            writeGenePool(Long.toString(survivors));

        //Weighted resivour sampling
        //Take the highest of r^(1/w) where r is a random an w is the weight
        for(int idx = 0; idx < 100; ++idx){
            genePool[idx] = mateFitWolves();
        }
        writeGenePool("");
        birthCount = 0;
    }

    //Pick two wolves randomly by weighted fitness and mate them
    public static String mateFitWolves(){
        EvoWolf w1 = null;
        double weight1 = -1;
        EvoWolf w2 = null;
        double weight2 = -1;

        for(int idx = 0; idx < 100; ++idx){
            double weight = generation[idx].getWeightSample();
            if(weight > weight1){
                weight2 = weight1;
                w2 = w1;
                weight1 = weight;
                w1 = generation[idx];
            } else if(weight > weight2){
                weight2 = weight;
                w2 = generation[idx];
            }
        }

        return mateFitWolves(w1, w2);
    }

    //Make offspring
    public static String mateFitWolves(EvoWolf w1, EvoWolf w2){
        StringBuilder sb = new StringBuilder();
        //Random splice
        for(int rIdx = 0; rIdx < w1.genes.length(); ++rIdx){
            if(random.nextBoolean())
                sb.append(w1.genes.charAt(rIdx));
            else
                sb.append(w2.genes.charAt(rIdx));
        }


        //Random mutation
        while(random.nextInt(10) == 0){
            int mIdx = random.nextInt(w1.genes.length());
            if(sb.charAt(mIdx) == '0')
                sb.setCharAt(mIdx, '1');
            else
                sb.setCharAt(mIdx, '0');
        }


        return sb.toString();
    }

    //Save the next generation's gene pool back to disk
    public static void writeGenePool(String survivors){
        try {
            String str = "";
            if(!survivors.equals(""))
                str = Long.toString(System.currentTimeMillis());

            File file = new File("evowolf" + survivors + str + ".txt");

            // if file doesn't exists, then create it
            if (!file.exists()) {
                file.createNewFile();
            }

            FileWriter fw = new FileWriter(file.getAbsoluteFile());
            BufferedWriter bw = new BufferedWriter(fw);
            for(int gIdx = 0; gIdx < genePool.length; ++gIdx){
                bw.write(genePool[gIdx]);
                bw.write('\n');
            }
            bw.close();
        } catch (IOException e) {

        }
    }

    //Keep track of the wolves in this generation
    public static int birthCount = 0;
    public static EvoWolf[] generation = new EvoWolf[100];

    /*====INSTANCE METHODS====*/
    //Populate this wolf from the gene pool
    public void birth(){
        if(genePool == null){
            readGenePool();
        }
        genes = genePool[birthCount];
        generation[birthCount] = this;
        birthCount = (birthCount + 1) % 100;    
    }

    //How long wolf has been alive
    public int turns = 0;

    //Fitness based on how long wolf survived
    public double getWeightSample(){
        return Math.pow(random.nextDouble(), 1.0/turns);
    }


    /*===GENETICS===*/
    public String genes = null;
    //Genes are made up of 182+ bits (stored at a string)
    //Each turns on the possibility of that move or attack in a given situation
    //  Attack: BLSW * RPSX = 16 bits [0-15] = Animal->Attacks
    //  Threatened Moves: BLSW * 12345678 * UDLRH = 160 bits [16-175] = Y -> X -> Animal -> Moves
    //  Safe Moves: UDLRH = 5 bits [176-180] = Moves
    //  Extra: default move [181], move combination [182]
    public static final int GENE_INDEX_ATTACKS = 0;
    public static final int GENE_INDEX_THREATENED_MOVES = GENE_INDEX_ATTACKS + (4 * 4);
    public static final int GENE_INDEX_SAFE_MOVES = GENE_INDEX_THREATENED_MOVES + (8 * 4 * 5);
    public static final int GENE_INDEX_DEFAULT_MOVE = GENE_INDEX_SAFE_MOVES + (5);
    public static final int GENE_INDEX_COMBINE_MOVES = GENE_INDEX_DEFAULT_MOVE + (1);
    public static final int GENE_COUNT = GENE_INDEX_COMBINE_MOVES + 1;
    public static int getAnimalIndex(char c){
        switch (c) {
            case 'B':
                return 0;
            case 'L':
                return 1;
            case 'S':
                return 2;
            case 'W':
            default: //Shouldn't occur but we'll assume it's the dangerous wolf
                return 3;
        } 
    }

    public static int getXYIndex(int x, int y){
        int idx = (y * 3) + x;
        if(idx > 4) //We don't need to look at ourself
            --idx;
        return idx;
    }

    public List<Attack> getAttacks(char c){
        List<Attack> attacks = new ArrayList<Attack>();
        int idx = GENE_INDEX_ATTACKS + getAnimalIndex(c);
        if(genes.charAt(idx + 0) == '1')
            attacks.add(Attack.ROCK);
        if(genes.charAt(idx + 1) == '1')
            attacks.add(Attack.PAPER);
        if(genes.charAt(idx + 2) == '1')
            attacks.add(Attack.SCISSORS);
        /*
        if(genes.charAt(idx + 3) == '1')
            attacks.add(Attack.SUICIDE);
        */
        //Suicide didn't remove itself from the gene pool like I thought so I manually removed it

        return attacks;
    }

    public boolean isSafe(){
        for(int x = 0; x <= 2; ++x){
            for(int y = 0; y <= 2; ++y){
                if(y == 1 && x == 1)
                    continue;
                if(surroundings[y][x] != ' ')
                    return false;
            }
        }
        return true;
    }

    public List<Move> getSafeMoves(){
        List<Move> moves = new ArrayList<Move>();
        int idx = GENE_INDEX_SAFE_MOVES;
        if(genes.charAt(idx + 0) == '1')
            moves.add(Move.UP);
        if(genes.charAt(idx + 1) == '1')
            moves.add(Move.DOWN);
        if(genes.charAt(idx + 2) == '1')
            moves.add(Move.LEFT);
        if(genes.charAt(idx + 3) == '1')
            moves.add(Move.RIGHT);
        if(genes.charAt(idx + 4) == '1')
            moves.add(Move.HOLD);

        return moves;
    }

    public List<Move> getThreatenedMoves(){
        List<Move> moves = new ArrayList<Move>();
        if(genes.charAt(GENE_INDEX_COMBINE_MOVES) == '0')
            moves.addAll(EnumSet.of(Move.UP, Move.DOWN, Move.LEFT, Move.RIGHT, Move.HOLD));

        for(int x = 0; x <= 2; ++x){
            for(int y = 0; y <= 2; ++y){
                if(y == 1 && x == 1)
                    continue;
                if(genes.charAt(GENE_INDEX_COMBINE_MOVES) == '1')
                    moves.addAll(getThreatenedMoves(x,y));
                else
                    moves.retainAll(getThreatenedMoves(x,y));
            }
        }

        if(moves.size() == 0){
            if(this.genes.charAt(GENE_INDEX_DEFAULT_MOVE) == '1')
                moves.addAll(EnumSet.of(Move.UP, Move.DOWN, Move.LEFT, Move.RIGHT, Move.HOLD));
            else
                moves.add(Move.HOLD);
        }

        return moves;
    }

    public EnumSet<Move> getThreatenedMoves(int x, int y){
        //Lookup what moves we can make for a cell unless it is blank (allow any)
        if(surroundings[y][x] != ' ')
            return getThreatenedMoves(x,y,surroundings[y][x]);
        else if(genes.charAt(GENE_INDEX_COMBINE_MOVES) == '1')
            return EnumSet.noneOf(Move.class);
        else
            return EnumSet.of(Move.UP, Move.DOWN, Move.LEFT, Move.RIGHT, Move.HOLD);
    }

    public EnumSet<Move> getThreatenedMoves(int x, int y, char c){
        int aIdx = getAnimalIndex(c);
        int sIdx = getXYIndex(x,y);
        int idx = GENE_INDEX_THREATENED_MOVES + (sIdx * 20) + (aIdx * 5);

        EnumSet<Move> moves = EnumSet.noneOf(Move.class);

        if(genes.charAt(idx + 0) == '1')
            moves.add(Move.UP);
        if(genes.charAt(idx + 1) == '1')
            moves.add(Move.DOWN);
        if(genes.charAt(idx + 2) == '1')
            moves.add(Move.LEFT);
        if(genes.charAt(idx + 3) == '1')
            moves.add(Move.RIGHT);
        if(genes.charAt(idx + 4) == '1')
            moves.add(Move.HOLD);

        return moves;
    }

    public static String setAt(String str, int index, char replace){     
        if(str==null){
            return str;
        }else if(index<0 || index>=str.length()){
            return str;
        }
        char[] chars = str.toCharArray();
        chars[index] = replace;
        return String.valueOf(chars);       
    }
}

Wprowadziłem również zmiany w Statistics.java i Wild.java, aby pokazać mi, ile minęło tur i pokoleń. Po uruchomieniu 1000 tur zadzwoń, EvoWolf.nextGen();aby obliczyć potomstwo. Nie jest to konieczne dla konkurencji, tylko jeśli chcesz rozwinąć swój własny zestaw.

Wszystkie pliki tutaj EDYCJA: STAŁY LINK

O ile ewoluuje jak najlepiej, nie ma nic lepszego niż pierwsza dziesiątka. Ograniczeniem jest to, że ma bardzo mało pamięci o swoich poprzednich ruchach. Chociaż działa jak WolvesWithCollectiveMemory, ponieważ doświadczenia poprzednich pokoleń wpłyną na to, jak funkcje następnej generacji będą służyć jako długoterminowa pamięć globalna. Na pewno było fajnie. W poprzednim łączu znajduje się arkusz Excela, który może pomóc w analizie puli genów. Zamień wszystkie 1 i 0 w .txt na 1 i 0 na przecinki, a następnie wklej do arkusza kalkulacyjnego.

Kilka interesujących notatek, z których większość potwierdza strategie wszystkich:

  • Rzeczywiste ataki są mniej ważne niż unikanie walki. A może wszystkie nie-wilki zostaną szybko wyeliminowane, aby nie stanowiły zagrożenia. Generacja konkurencji ma równą szansę między RPS przeciwko niedźwiedziom, nawet jeśli powinieneś rzucić S.
  • Podobnie jak powyżej, musiałem ręcznie wyłączyć samobójstwo, ponieważ nie ewoluowało, nawet jeśli myślisz, że tak.
  • Trzymanie to najlepszy ruch, gdy nikogo nie ma w pobliżu
  • Ucieczka wydaje się również dobra, gdy ktoś jest w pobliżu
  • Powinieneś trzymać zamiast przesuwać losowy kierunek (ten wybór był dodatkowym genem, który ewoluował)
  • Gdy w pobliżu znajduje się więcej niż jedno zwierzę, wykonanie losowego ruchu z przecięcia ruchów dla każdego otoczenia / zwierzęcia jest lepsze niż związek (kolejny dodatkowy gen)

8

SmartWolf

Wyniki są (1000 iteracji) (będę to aktualizować, ale będę to postrzegać jako niezależny test bez uśredniania, ponieważ przy tak wielu wilkach jest to dość powolne).

wprowadź opis zdjęcia tutaj

Kompilacja:

* nix (wymagany jest tryb mono):

gmcs SmartWolf.cs

Windows:

csc SmartWolf.cs

Skopiuj do katalogu roboczego.

Uwaga: W przypadku systemu Windows należy zastąpić "mono SmartWolf.exe"go tylko "SmartWolf.exe"kodem opakowania.

SmartWolf.cs:

using System;
using System.Collections.Generic;
using System.Linq;

namespace SmartWolf
{
    #region Enums
    enum Attack
    {
        Rock, Paper, Scissors, Suicide
    }
    enum Movement
    {
        Up, Down, Left, Right, Hold
    }
    enum Animal
    {
        Stone, Lion, Wolf, Bear, Empty
    }
    #endregion
    class KnowledgeBase
    {
        static Random rnd = new Random();
        public List<KeyValuePair<KeyValuePair<Animal, Attack>, int>> knowledge = new List<KeyValuePair<KeyValuePair<Animal, Attack>, int>>();
        public KnowledgeBase ()
        {
        }
        public void PunishMove (KeyValuePair<Animal, Attack> move)
        {
            if (knowledge.Count (t => t.Key.Key == move.Key && t.Key.Value == move.Value) == 0) {
                knowledge.Add (new KeyValuePair<KeyValuePair<Animal, Attack>, int> (move, -1));
            } else {
                int i = knowledge.FindIndex (t => t.Key.Equals (move));
                knowledge[i] = new KeyValuePair<KeyValuePair<Animal, Attack>, int>(knowledge[i].Key, knowledge[i].Value - 1);
            }

        }
        public void RewardMove (KeyValuePair<Animal, Attack> move)
        {
            if (knowledge.Count (t => t.Key.Key == move.Key && t.Key.Value == move.Value) == 0) {
                knowledge.Add (new KeyValuePair<KeyValuePair<Animal, Attack>, int> (move, 1));
            } else {
                int i = knowledge.FindIndex (t => t.Key.Equals (move));
                knowledge[i] = new KeyValuePair<KeyValuePair<Animal, Attack>, int>(knowledge[i].Key, knowledge[i].Value + 1);
            }
        }
        public Attack GetBestMove (Animal opponent)
        {
            Attack best = GetRandomMove();
            int j = 0;
            foreach (var pair in knowledge) {
                if(pair.Key.Key == opponent && j < pair.Value)
                {
                    best = pair.Key.Value;
                    j = pair.Value;
                }
            }
            if(j < 2)
                return GetRandomMove ();
            return best;
        }
        public static Attack GetRandomMove()
        {
            int r = rnd.Next (3);
            return r == 0 ? Attack.Paper :
                r == 1 ? Attack.Rock :
                    r == 2 ? Attack.Scissors :
                    Attack.Scissors;
        }
    }
    class MainClass
    {
        static KnowledgeBase knowledge = new KnowledgeBase();
        public static void Main (string[] args)
        {
            List<SmartWolf> list = new List<SmartWolf> ();
            List<int> temp = new List<int>();
            int l = 0;
            while (true) {
                string str = Console.ReadLine ();
                int id = int.Parse (str.Substring (1, 2));
                if(str.StartsWith ("S"))
                {
                    list.Add (new SmartWolf(id));
                    Console.WriteLine("K" + id.ToString ().PadLeft (2, '0'));
                } else if(str.StartsWith ("M"))
                {
                    if(temp.Contains (id))
                    {
                        for(int i = 0; i < 100; i++)
                        {
                            SmartWolf s = list.Where (t => t.ID == i).ToList ()[0];
                            if(s.AttackedInLastRound == 0 && !temp.Contains(i))
                            {
                                s.IsAlive = false;
                                knowledge.PunishMove (s.LastMove);
                                s.AttackedInLastRound = -1;
                            } else if(s.AttackedInLastRound == 0 && temp.Contains (i))
                            {
                                knowledge.RewardMove (s.LastMove);
                                s.AttackedInLastRound = -1;
                            }
                            if(s.AttackedInLastRound > 0)
                                s.AttackedInLastRound--;
                        }
                        temp.Clear();
                        l++;
                    }
                    temp.Add (id);

                    Console.WriteLine('H' + id.ToString ().PadLeft (2, '0'));
                } else if(str.StartsWith ("A"))
                {
                    Animal enemy = str[3] == 'W' ? Animal.Wolf :
                                   str[3] == 'L' ? Animal.Lion :
                                   str[3] == 'S' ? Animal.Stone :
                                   str[3] == 'B' ? Animal.Bear : Animal.Empty;
                    Attack atk = knowledge.GetBestMove (enemy);
                    Console.WriteLine((atk == Attack.Paper ? "P" :
                                      atk == Attack.Rock ? "R" : 
                                      atk == Attack.Scissors ? "S" :
                                      "P") + id.ToString ().PadLeft (2, '0'));
                    list.Where (t => t.ID == id).ToList ()[0].AttackedInLastRound = 2;
                    list.Where (t => t.ID == id).ToList ()[0].LastMove = new KeyValuePair<Animal, Attack>(enemy, atk);
                }
            }
        }
    }
    class SmartWolf
    {
        public int ID;
        public bool IsAlive = true;
        public KeyValuePair<Animal, Attack> LastMove = new KeyValuePair<Animal, Attack>(Animal.Empty, Attack.Suicide);
        public int AttackedInLastRound = -1;
        public SmartWolf(int n)
        {
            ID = n;
        }
    }
}

Wrapper (kredyt dla @ProgrammerDan, po prostu dołączam go tutaj, więc łatwiej jest po prostu skopiować wklej):

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 SmartWolf wrapper class. 
 */
public class SmartWolf extends Animal {
    /**
     * Simple test script that sends some typical commands to the
     * remote process.
     */
    public static void main(String[]args){
        SmartWolf[] wolves = new SmartWolf[100];
        for(int i=0; i<10; i++) {
            wolves[i] = new SmartWolf();
        }
        char map[][] = new char[3][3];
        for (int i=0;i<9;i++)
            map[i/3][i%3]=' ';
        map[1][2] = '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 SmartWolf[] wolves = new SmartWolf[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 SmartWolf() {
        super('W');
        if (SmartWolf.wolfProcess == null) {
            SmartWolf.wolfProcess = new WolfProcess();
            SmartWolf.wolfProcess.start();
        }

        if (SmartWolf.wolfProcess.initWolf(SmartWolf.nWolves, MAP_SIZE)) {
            this.id = SmartWolf.nWolves;
            this.isDead = false;
            SmartWolf.wolves[id] = this;
        } else {
            SmartWolf.wolfProcess.endProcess();
            this.isDead = true;
        }
        SmartWolf.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 (!SmartWolf.wolfProcess.getRunning() || isDead) {
            return Attack.SUICIDE;
        }
        try {
            Attack atk = SmartWolf.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 (!SmartWolf.wolfProcess.getRunning() || isDead) {
            return Move.HOLD;
        }
        try {
            Move mv = SmartWolf.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 SmartWolf remote process");
                ProcessBuilder pb = new ProcessBuilder("mono SmartWolf.exe".split(" "));
                pb.redirectErrorStream(true);
                process = pb.start();
                System.out.println("SmartWolf process begun");
                // STDOUT of the process.
                reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8")); 
                System.out.println("SmartWolf reader stream grabbed");
                // STDIN of the process.
                writer = new PrintWriter(new OutputStreamWriter(process.getOutputStream(), "UTF-8"));
                System.out.println("SmartWolf 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("SmartWolf 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("SmartWolf %d failed to initialize, timeout\n", wolf);
            } catch (Exception e) {
                endProcess();
                System.out.printf("SmartWolf %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("SmartWolf %d failed to attack, timeout\n", wolf);
            } catch (Exception e) {
                endProcess();
                System.out.printf("SmartWolf %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("SmartWolf %d failed to move, timeout\n", wolf);
            } catch (Exception e) {
                endProcess();
                System.out.printf("SmartWolf %d failed to move, %s\n", wolf, e.getMessage());
            }
            return move;
        }
    }
}

Niezbyt świetne, średnie ~ 75 przeżycie dla 1000 iteracji z kilkoma najlepszymi wilkami.

Stosuje podejście ML do rozwiązania.


Myślę, że z grubsza zrozumiałem, co robi twój wilk, ale czy mógłbyś to wyjaśnić bardziej szczegółowo? Powinieneś także prawdopodobnie wspomnieć, jaki to język (jestem pewien, że dla większości ludzi jest to oczywiste, ale dla mnie nie było to oczywiste).
plannapus

Jest napisany w języku C # i ma listę wiedzy, która zawiera listę każdego ruchu, który został wykonany w stosunku do danego zwierzęcia i jego sukcesu. Kiedy wilk atakuje i umiera, wskaźnik sukcesu tego ruchu jest zmniejszony. Jeśli tak, wskaźnik sukcesu wzrasta. System zaczyna wybierać ruchy z bazy wiedzy zamiast wybierać losowo po kilku (20-30) turach.
user3188175

1
Cieszę się, że używasz opakowania! Prawdopodobnie powinieneś załączyć instrukcje, jak skompilować kod i co monojest potrzebne do korzystania z @Rusher.
ProgrammerDan

1
Markdown nie działa. Jeśli spojrzysz na źródło, tam jest „#”, ale ponieważ było w bloku nagłówka, Markdown zignorował je. Naprawiony. : D
Programator,

2
Do Twojej wiadomości - byłem w stanie skompilować i pomyślnie uruchomić go z otoki @ ProgrammerDan (i tym razem bez jego pomocy). Będziesz w następnych wynikach. Przepraszam za opóźnienie!
Rainbolt,

7

Pasywno-agresywny wilk (wilk z Scali)

Unika wszystkiego, co może, przez pierwsze 500 obrotów, pozwalając polu oczyścić się. Potem idzie w wyznaczonym kierunku, atakując rzeczy, które znajdują się w zasięgu.

package animals;

import animals._
import scala.util.Random

class PassiveAgressiveWolf extends Animal('W') {

    val myId=PassiveAgressiveWolf.nextId
    var movecounter=0

    def fight(opponent: Char) = {
        PassiveAgressiveWolf.lastopponents(myId-1)=opponent
        opponent match {
            case 'B' => Animal.Attack.SCISSORS
            case 'L' => Animal.Attack.SCISSORS
            case 'S' => Animal.Attack.ROCK
            case _ => Random.shuffle(List(Animal.Attack.SCISSORS, Animal.Attack.ROCK, Animal.Attack.PAPER)).head
        }
    }

    def move = {
        movecounter+=1
        if(movecounter < 500) avoidall else seen match {
            case ('B', pos: Int) => seenbear(pos)
            case ('S', pos: Int) => seenstone(pos)
            case ('L', pos: Int) => seenlion(pos)
            case ('W', pos: Int) => seenwolf(pos)
            case (' ', _) => myDirection
        }
    }

    def myDirection = myId % 4 match {
        case 0 => if(surroundings(0)(1)==' ') Animal.Move.LEFT else randommove
        case 1 => if(surroundings(1)(0)==' ') Animal.Move.DOWN else randommove
        case 2 => if(surroundings(1)(2)==' ') Animal.Move.RIGHT else randommove
        case 3 => if(surroundings(2)(1)==' ') Animal.Move.UP else randommove
    }

    def randommove = Random.shuffle(List(Animal.Move.UP, Animal.Move.LEFT, Animal.Move.RIGHT, Animal.Move.DOWN)).head

    def seen = {
        surroundings(1)(1)=' '
        val surroundingsflat=surroundings.flatten.mkString
        val seenbeasts = for {
            beast <- "BSLW" if surroundingsflat contains beast
        } yield (beast, surroundingsflat.indexOf(beast))
        seenbeasts.headOption.getOrElse((' ', 0))
    }

    def seenbear(pos: Int) = chase(pos)

    def seenstone(pos: Int) = pos match {
        case 1 => Animal.Move.LEFT
        case 3 => Animal.Move.UP
        case _ => myDirection
    }

    def seenlion(pos: Int) = pos match {
        case 1 => Animal.Move.LEFT
        case 3 => Animal.Move.UP
        case 5 => Animal.Move.HOLD
        case 7 => Animal.Move.HOLD
        case 0 => Animal.Move.UP
        case 2 => Animal.Move.HOLD
        case 6 => Animal.Move.HOLD
        case 8 => Animal.Move.HOLD
    }

    def seenwolf(pos: Int) = chase(pos)

    def chase(pos: Int) = pos match {
        case 1 => Animal.Move.UP
        case 3 => Animal.Move.LEFT
        case 5 => Animal.Move.RIGHT
        case 7 => Animal.Move.DOWN
        case 0 => Animal.Move.UP
        case 2 => Animal.Move.UP
        case 6 => Animal.Move.DOWN
        case 8 => Animal.Move.DOWN
    }

    def avoidall = {
        val safemoves = for {
            move <- List(
                            (0, 1, Animal.Move.UP), 
                            (1, 0, Animal.Move.LEFT), 
                            (1, 2, Animal.Move.RIGHT), 
                            (2, 1, Animal.Move.DOWN)
                        ) if(surroundings(move._1)(move._2)==' ')
        } yield move
        if(safemoves.length < 4) Random.shuffle(safemoves).head._3 else Animal.Move.HOLD
    }

}

object PassiveAgressiveWolf {
    private var id=0
    private def nextId = {id+=1; id}

    private var lastopponents=Array.fill[Char](100)(' ');
}

Jako język oparty na JVM, Scala może być stosunkowo łatwo zintegrowana.

Jeśli sam kompilujesz program, włóż plik scala do plików Java .class(nie .javaplików) i użyj

scalac PassiveAggressiveWolf.scala

skompilować to. Następnie możesz użyć PassiveAggressiveWolf.classw Wild.javaklasie głównej, tak jak w przypadku klas Java. Musisz również dodać scala-library.jardo ścieżki klasy (korzystałem z opcji wiersza poleceń -cp /path/to/scala-library.jar).

Alternatywnie, przesłałem słoik zawierający wygenerowane pliki klas i scala-library.jardla Scala 2.10.3, abyś mógł je pobrać.

PassiveAggressiveWolf.jar
scala-library.jar


Być może możesz spakować 10 plików w jednym pliku zip, aby ułatwić pobieranie.
johnchen902

@ johnchen902 Na czacie zasugerowano mi, że utworzę słoik zawierający moje zajęcia. Zamierzam to zrobić tego wieczoru po pracy. Zmniejszy to do 2 pobrań i, mam nadzieję, rozwiąże problemy, które Rusher ma z włączeniem.
Gareth
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.