Kamień, papier, nożyczki, jaszczurka, Spock Tour of Epicness

98

Najnowszy ranking @ 02.08.2014 12:00

| Pos # | Author               | Name                    | Language   | Score | Win   | Draw  | Loss  | Avg. Dec. Time |
+-------+----------------------+-------------------------+------------+-------+-------+-------+-------+----------------+
| 1st   | Emil                 | Pony                    | Python2    | 064   | 064   | 000   | 005   | 0026.87 ms     |
| 2nd   | Roy van Rijn         | Gazzr                   | Java       | 062   | 062   | 001   | 006   | 0067.30 ms     |
| 2nd   | Emil                 | Dienstag                | Python2    | 062   | 062   | 001   | 006   | 0022.19 ms     |
| 4th   | ovenror              | TobiasFuenke            | Python2    | 061   | 061   | 001   | 007   | 0026.89 ms     |
| 5th   | PhiNotPi             | BayesianBot             | Perl       | 060   | 060   | 000   | 009   | 0009.27 ms     |
| 6th   | Claudiu              | SuperMarkov             | Python2    | 058   | 058   | 001   | 010   | 0026.77 ms     |
| 7th   | histocrat            | Alternator              | Ruby       | 057   | 057   | 001   | 011   | 0038.53 ms     |
| 8th   | histocrat            | LeonardShelby           | Ruby       | 053   | 053   | 000   | 016   | 0038.55 ms     |
| 9th   | Stretch Maniac       | SmarterBot              | Java       | 051   | 051   | 002   | 016   | 0070.02 ms     |
| 9th   | Martin Büttner       | Markov                  | Ruby       | 051   | 051   | 003   | 015   | 0038.45 ms     |
| 11th  | histocrat            | BartBot                 | Ruby       | 049   | 049   | 001   | 019   | 0038.54 ms     |
| 11th  | kaine                | ExcitingishBot          | Java       | 049   | 049   | 001   | 019   | 0065.87 ms     |
| 13th  | Thaylon              | UniformBot              | Ruby       | 047   | 047   | 001   | 021   | 0038.61 ms     |
| 14th  | Carlos Martinez      | EasyGame                | Java       | 046   | 046   | 002   | 021   | 0066.44 ms     |
| 15th  | Stretch Maniac       | SmartBot                | Java       | 045   | 045   | 001   | 023   | 0068.65 ms     |
| 16th  | Docopoper            | RoboticOboeBotOboeTuner | Python2    | 044   | 044   | 000   | 025   | 0156.55 ms     |
| 17th  | Qwix                 | Analyst                 | Java       | 043   | 043   | 001   | 025   | 0069.06 ms     |
| 18th  | histocrat            | Analogizer              | Ruby       | 042   | 042   | 000   | 027   | 0038.58 ms     |
| 18th  | Thaylon              | Naan                    | Ruby       | 042   | 042   | 004   | 023   | 0038.48 ms     |
| 20th  | Thaylon              | NitPicker               | Ruby       | 041   | 041   | 000   | 028   | 0046.21 ms     |
| 20th  | bitpwner             | AlgorithmBot            | Python2    | 041   | 041   | 001   | 027   | 0025.34 ms     |
| 22nd  | histocrat            | WereVulcan              | Ruby       | 040   | 040   | 003   | 026   | 0038.41 ms     |
| 22nd  | Ourous               | QQ                      | Cobra      | 040   | 040   | 003   | 026   | 0089.33 ms     |
| 24th  | Stranjyr             | RelaxedBot              | Python2    | 039   | 039   | 001   | 029   | 0025.40 ms     |
| 25th  | JoshDM               | SelfLoathingBot         | Java       | 038   | 038   | 001   | 030   | 0068.75 ms     |
| 25th  | Ourous               | Q                       | Cobra      | 038   | 038   | 001   | 030   | 0094.04 ms     |
| 25th  | Ourous               | DejaQ                   | Cobra      | 038   | 038   | 001   | 030   | 0078.31 ms     |
| 28th  | Luis Mars            | Botzinga                | Java       | 037   | 037   | 002   | 030   | 0066.36 ms     |
| 29th  | kaine                | BoringBot               | Java       | 035   | 035   | 000   | 034   | 0066.16 ms     |
| 29th  | Docopoper            | OboeBeater              | Python2    | 035   | 035   | 002   | 032   | 0021.92 ms     |
| 29th  | Thaylon              | NaanViolence            | Ruby       | 035   | 035   | 003   | 031   | 0038.46 ms     |
| 32nd  | Martin Büttner       | SlowLizard              | Ruby       | 034   | 034   | 004   | 031   | 0038.32 ms     |
| 33rd  | Kyle Kanos           | ViolentBot              | Python3    | 033   | 033   | 001   | 035   | 0032.42 ms     |
| 34th  | HuddleWolf           | HuddleWolfTheConqueror  | .NET       | 032   | 032   | 001   | 036   | 0029.86 ms     |
| 34th  | Milo                 | DogeBotv2               | Java       | 032   | 032   | 000   | 037   | 0066.74 ms     |
| 34th  | Timmy                | DynamicBot              | Python3    | 032   | 032   | 001   | 036   | 0036.81 ms     |
| 34th  | mccannf              | YAARBot                 | JS         | 032   | 032   | 002   | 035   | 0100.12 ms     |
| 38th  | Stranjyr             | ToddlerProof            | Java       | 031   | 031   | 010   | 028   | 0066.10 ms     |
| 38th  | NonFunctional User2..| IHaveNoIdeaWhatImDoing  | Lisp       | 031   | 031   | 002   | 036   | 0036.26 ms     |
| 38th  | john smith           | RAMBOBot                | PHP        | 031   | 031   | 002   | 036   | 0014.53 ms     |
| 41st  | EoinC                | SimpleRandomBot         | .NET       | 030   | 030   | 005   | 034   | 0015.68 ms     |
| 41st  | Martin Büttner       | FairBot                 | Ruby       | 030   | 030   | 006   | 033   | 0038.23 ms     |
| 41st  | Docopoper            | OboeOboeBeater          | Python2    | 030   | 030   | 006   | 033   | 0021.93 ms     |
| 44th  | undergroundmonorail  | TheGamblersBrother      | Python2    | 029   | 029   | 000   | 040   | 0025.55 ms     |
| 45th  | DrJPepper            | MonadBot                | Haskel     | 028   | 028   | 002   | 039   | 0008.23 ms     |
| 46th  | Josef E.             | OneBehind               | Java       | 027   | 027   | 007   | 035   | 0065.87 ms     |
| 47th  | Ourous               | GitGudBot               | Cobra      | 025   | 025   | 001   | 043   | 0053.35 ms     |
| 48th  | ProgramFOX           | Echo                    | .NET       | 024   | 024   | 004   | 041   | 0014.81 ms     |
| 48th  | JoshDM               | SelfHatingBot           | Java       | 024   | 024   | 005   | 040   | 0068.88 ms     |
| 48th  | Trimsty              | Herpetologist           | Python3    | 024   | 024   | 002   | 043   | 0036.93 ms     |
| 51st  | Milo                 | DogeBot                 | Java       | 022   | 022   | 001   | 046   | 0067.86 ms     |
| 51st  | William Barbosa      | StarWarsFan             | Ruby       | 022   | 022   | 002   | 045   | 0038.48 ms     |
| 51st  | Martin Büttner       | ConservativeBot         | Ruby       | 022   | 022   | 001   | 046   | 0038.25 ms     |
| 51st  | killmous             | MAWBRBot                | Perl       | 022   | 022   | 000   | 047   | 0016.30 ms     |
| 55th  | Mikey Mouse          | LizardsRule             | .NET       | 020   | 020   | 007   | 042   | 0015.10 ms     |
| 55th  | ja72                 | BlindForesight          | .NET       | 020   | 020   | 001   | 048   | 0024.05 ms     |
| 57th  | robotik              | Evolver                 | Lua        | 019   | 019   | 001   | 049   | 0008.19 ms     |
| 58th  | Kyle Kanos           | LexicographicBot        | Python3    | 018   | 018   | 003   | 048   | 0036.93 ms     |
| 58th  | William Barbosa      | BarneyStinson           | Lua        | 018   | 018   | 005   | 046   | 0005.11 ms     |
| 60th  | Dr R Dizzle          | BartSimpson             | Ruby       | 017   | 017   | 001   | 051   | 0038.22 ms     |
| 60th  | jmite                | IocainePowder           | Ruby       | 017   | 017   | 003   | 049   | 0038.50 ms     |
| 60th  | ArcticanAudio        | SpockOrRock             | PHP        | 017   | 017   | 001   | 051   | 0014.19 ms     |
| 60th  | Dr R Dizzle          | BetterLisaSimpson       | Ruby       | 017   | 017   | 000   | 052   | 0038.23 ms     |
| 64th  | Dr R Dizzle          | LisaSimpson             | Ruby       | 016   | 016   | 002   | 051   | 0038.29 ms     |
| 65th  | Martin Büttner       | Vulcan                  | Ruby       | 015   | 015   | 001   | 053   | 0038.26 ms     |
| 65th  | Dr R Dizzle          | Khaleesi                | Ruby       | 015   | 015   | 005   | 049   | 0038.29 ms     |
| 67th  | Dr R Dizzle          | EdwardScissorHands      | Ruby       | 014   | 014   | 002   | 053   | 0038.21 ms     |
| 67th  | undergroundmonorail  | TheGambler              | Python2    | 014   | 014   | 002   | 053   | 0025.47 ms     |
| 69th  | cipher               | LemmingBot              | Python2    | 011   | 011   | 002   | 056   | 0025.29 ms     |
| 70th  | Docopoper            | ConcessionBot           | Python2    | 007   | 007   | 000   | 062   | 0141.31 ms     |
+-------+----------------------+-------------------------+------------+-------+-------+-------+-------+----------------+
Total Players: 70
Total Matches Completed: 2415
Total Tourney Time: 06:00:51.6877573

Notatki z turnieju

Wykluczone boty

  • BashRocksBot - wciąż nie ma radości ze .net wykonującego skrypty bash cygwin
  • CounterPreferenceBot - oczekuje na naprawę błędu
  • RandomlyWeighted - oczekuje na naprawę błędu
  • CasinoShakespeare - wykluczone, ponieważ wymaga aktywnego połączenia z Internetem

Oryginalne wysłane pytanie

Udałeś się do domu swoich znajomych, by wziąć udział w najbardziej epickich bitwach pokazowych: Rock, Paper, Scissors, Lizard, Spock. W prawdziwym stylu kujonowym BigBanga, żaden z graczy nie gra sam, ale stworzył boty konsolowe, aby grać w ich imieniu. Wyciągasz klucz USB i oddajesz go Sheldorowi Zdobywcy w celu włączenia go do showdownu. Penny mdleje. A może Howard mdleje. Nie oceniamy tutaj w mieszkaniu Leonarda.

Zasady

Obowiązują standardowe zasady dotyczące kamieni, papieru, nożyczek, jaszczurki, Spocka.

  • Nożyczki do cięcia papieru
  • Papierowe okładki Rock
  • Skała miażdży Jaszczurkę
  • Jaszczurka zatruwa Spocka
  • Spock rozbija nożyczki
  • Nożyce dekapitują Jaszczurkę
  • Jaszczurka je papier
  • Papier obala Spocka
  • Spock waporyzuje skałę
  • Skała miażdży nożyczki

Zasady RPSLV

Bot każdego gracza rozegra jeden mecz przeciwko sobie nawzajem w turnieju.

Każdy mecz będzie się składał ze 100 powtórzeń gry RPSLV.

Po każdym meczu zwycięzcą zostaje gracz, który wygrał najwięcej gier / rozdań na 100.

Jeśli wygrasz mecz, otrzymasz 1 punkt w tabeli ligowej. W wyniku remisu żaden z graczy nie zdobędzie punktu.

Wymagania dotyczące botów

Twój bot musi być uruchamialny z linii poleceń.

Pudełko Sheldora * nix umarło, więc uruchamiamy go z jego laptopa z systemem Windows 8, więc upewnij się, że dostarczone rozwiązanie może działać w systemie Windows. Sheldor z wdzięcznością zaoferował zainstalowanie wszystkich wymaganych środowisk uruchomieniowych (w rozsądnym zakresie), aby móc uruchomić twoje rozwiązanie. (.NET, Java, Php, Python, Ruby, Powershell ...)

Wejścia

W pierwszej grze każdego meczu Twoi bot nie otrzymuje żadnych argumentów. W każdej kolejnej grze każdego meczu: - Arg1 będzie zawierać historię twoich rąk / decyzji botów w tym meczu. - Arg2 będzie zawierać historię układów / decyzji twoich przeciwników w tym meczu.

Historia będzie reprezentowana przez ciąg pojedynczych wielkich liter reprezentujących możliwe ręce, w które możesz zagrać.

 | R | Rock     |
 | P | Paper    |
 | S | Scissors |
 | L | Lizard   |
 | V | Spock    |

Na przykład

  • Gra 1: MyBot.exe
  • Gra 2: MyBot.exe SV
  • Gra 3: MyBot.exe SS VL
  • Gra 4: MyBot.exe SSR VLS

Wynik

Twój bot musi napisać odpowiedź jednej postaci reprezentującą jego „rękę” dla każdej gry. Wynik należy zapisać w STDOUT, a następnie bot powinien wyjść. Prawidłowe pojedyncze wielkie litery są poniżej.

 | R | Rock     |
 | P | Paper    |
 | S | Scissors |
 | L | Lizard   |
 | V | Spock    |

W przypadku, gdy twój bot nie zwróci prawidłowej ręki (tj. 1 z powyższych 5 pojedynczych wielkich liter, wtedy automatycznie tracisz tę rękę i dopasowanie jest kontynuowane.

W przypadku, gdy oba boty nie zwrócą prawidłowego układu, gra jest uważana za remis i mecz jest kontynuowany.

Dopasuj format

Każdy zgłoszony bot rozegra jeden mecz przeciwko sobie w turnieju.

Każdy mecz potrwa dokładnie 100 gier.

Mecze będą rozgrywane anonimowo, nie będziesz miał zaawansowanej wiedzy na temat konkretnego bota, z którym grasz, jednak możesz wykorzystać dowolne i wszystkie informacje, które możesz zdobyć na podstawie jego decyzji podczas historii bieżącego meczu, aby zmienić strategię przeciwko twojej przeciwnik. Możesz także śledzić historię swoich poprzednich gier, aby budować wzorce / heurystykę itp. (Zobacz zasady poniżej)

Podczas pojedynczej gry silnik orkiestracji uruchomi twojego bota, a twoi przeciwnicy rozdzielą 100 milisekund od siebie, a następnie porównają wyniki, aby uniknąć kolizji PRNG w tym samym języku / środowisku uruchomieniowym. (faktycznie tak się stało podczas testów).

Sędziowanie i ograniczenia

Dr Sheldon Cooper w przebraniu Sheldora Zdobywcy uprzejmie zaproponował nadzorowanie przebiegu turnieju. Sheldor Zdobywca jest uczciwym i sprawiedliwym nadzorcą (głównie). Wszystkie decyzje Sheldora są ostateczne.

Gry będą prowadzone w uczciwy i właściwy sposób:

  • Twój skrypt / program bot zostanie zapisany w silniku orkiestracji w podfolderze Players\[YourBotName]\
  • Możesz użyć tego podfolderu, Players\[YourBotName]\dataaby zapisać dowolne dane lub historię gry z bieżącego turnieju w trakcie jego trwania. Katalogi danych zostaną usunięte na początku każdego przebiegu turnieju.
  • Nie możesz uzyskać dostępu do katalogu Gracza innego gracza w turnieju
  • Twój bot nie może mieć określonego kodu, który jest ukierunkowany na zachowanie innego konkretnego bota
  • Każdy gracz może zgłosić więcej niż jednego bota do gry, o ile nie wchodzi w interakcje ani nie pomaga sobie wzajemnie.

Edycja - dodatkowe ograniczenia

  • Jeśli chodzi o przepadki, nie będą one obsługiwane. Twój bot musi zagrać w jednym z 5 ważnych rozdań. Przetestuję każdego bota poza turniejem z losowymi danymi, aby upewnić się, że się zachowują. Wszelkie boty, które zgłaszają błędy (tj. Błędy przepadku), zostaną wykluczone z turnieju, dopóki nie zostaną naprawione.
  • Boty mogą być pochodnymi, o ile zwięźle różnią się zachowaniem. Boty (w tym w innych językach), które zachowują się dokładnie tak samo jak istniejący bot, zostaną zdyskwalifikowane
  • Istnieją już roboty spamujące dla następujących elementów, więc nie przesyłaj ponownie
    • Rock - BartSimpson
    • Papier - LisaSimpson
    • Scissor - EdwardScissorhands
    • Spock - Vulcan
    • Jaszczurka - Khaleesi
    • Pseudo losowy - SimpleRandomBot i FairBot
    • Psuedo Random RPS - ConservativeBot
    • Psuedo Random LV - Barney Stinson
  • Boty nie mogą wywoływać usług zewnętrznych ani zasobów internetowych (ani niczego innego, co znacznie spowalnia szybkość / czas podejmowania decyzji przez mecze). CasinoShakespearejest jedynym wyjątkiem, ponieważ bot został zgłoszony przed dodaniem tego ograniczenia.

Sheldor będzie aktualizował to pytanie tak często, jak to możliwe, z wynikami Turnieju, w miarę zgłaszania kolejnych botów.

Program orkiestracji / kontroli

Program do aranżacji wraz z kodem źródłowym dla każdego bota jest dostępny na github.

https://github.com/eoincampbell/big-bang-game

Szczegóły zgłoszenia

Twoje zgłoszenie powinno zawierać

  • Imię twojego bota
  • Twój kod
  • Polecenie do
    • uruchom bota z powłoki np
    • ruby myBot.rb
    • python3 myBot.py
    • LUB
    • najpierw skompiluj oba, a następnie uruchom je. na przykład
    • csc.exe MyBot.cs
    • MyBot.exe

Przesłanie próbki

BotName: SimpleRandomBot
Compile: "C:\Program Files (x86)\MSBuild\12.0\Bin\csc.exe" SimpleRandomBot.cs
Run:     SimpleRandomBot [Arg1] [Arg2]

Kod:

using System;
public class SimpleRandomBot
{
    public static void Main(string[] args)
    {
        var s = new[] { "R", "P", "S", "L", "V" };
        if (args.Length == 0)
        {
            Console.WriteLine("V"); //always start with spock
            return;
        }
        char[] myPreviousPlays = args[0].ToCharArray();
        char[] oppPreviousPlays = args[1].ToCharArray();
        Random r = new Random();
        int next = r.Next(0, 5);
        Console.WriteLine(s[next]);
    }
}

Wyjaśnienie

Wszelkie pytania zadaj w komentarzach poniżej.

Eoin Campbell
źródło
7
Jak wygląda historia, gdy gracz stracił rękę?
histokrata
1
Zamierzałem pójść na całość z podejściem analitycznym, ale większość botów jest na tyle głupia, by pokonać inteligentną sztuczną inteligencję.
puszysty
1
Tylko dlatego, że nigdy nie prowadzę żadnego wyzwania KotH, w którym brałem udział, zrobiłem zrzut ekranu jako pamiątkę.
Kyle Kanos
3
Dziś wieczorem poprowadzę kolejny turniej i opublikuję wyniki pełnego meczu na pastebin ... następna partia będzie miała około 450 gier, ale powinna być nieco szybsza, ponieważ zaimplementowałem pewne elementy paralelizacji w sterowaniu
Eoin Campbell
3
Jeśli się nie mylę, wydaje się, że w skrypcie aranżacyjnym występuje poważny błąd: historia gracza 1 i 2 jest zawsze przekazywana botom jako odpowiednio pierwszy i drugi argument, podczas gdy zgodnie z zasadami boty powinny zawsze otrzymywać swoje najpierw własna historia. Teraz gracz 2 skutecznie próbuje się pokonać. (Byłem trochę podejrzliwy, ponieważ mój bot wygrał każdy mecz, w którym był gracz 1, przegrywając połowę pozostałych meczów.)
Emil

Odpowiedzi:

26

Kucyk (Python 2)

Opiera się to na bocie rock-paper-scissors, który napisałem jakiś czas temu dla wyzwania programistycznego pod koniec internetowej klasy Udacity . Zmieniłem to, aby uwzględnić Spocka i jaszczurkę, i wprowadziłem kilka ulepszeń.

Program ma 11 różnych prostych strategii, każda z 5 wariantami. Wybiera spośród nich na podstawie tego, jak dobrze by się spisali w ostatnich rundach.

Usunąłem strategię awaryjną, która grała losowo przeciwko silniejszym przeciwnikom. Myślę, że jest to bardziej zabawne.

import sys

# just play Spock for the first two rounds
if len(sys.argv)<2 or len(sys.argv[1])<2: print 'V'; sys.exit()

# initialize and translate moves to numbers for better handling:
my_moves, opp_moves = sys.argv[1], sys.argv[2]
moves = ('R', 'P', 'S', 'V', 'L')   
history = zip([moves.index(i) for i in my_moves],
              [moves.index(i) for i in opp_moves])

# predict possible next moves based on history
def prediction(hist):
    N = len(hist)    

    # find longest match of the preceding moves in the earlier history
    cand_m = cand_o = cand_b = range(N-1)
    for l in xrange(1,min(N, 20)):
        ref = hist[N-l]
        cand_m = ([c for c in cand_m if c>=l and hist[c-l+1][0]==ref[0]]
                  or cand_m[-1:])
        cand_o = ([c for c in cand_o if c>=l and hist[c-l+1][1]==ref[1]]
                  or cand_o[-1:])
        cand_b = ([c for c in cand_b if c>=l and hist[c-l+1]==ref]
                  or cand_b[-1:])

    # analyze which moves were used how often
    freq_m, freq_o = [0]*5, [0]*5
    for m in hist:
        freq_m[m[0]] += 1
        freq_o[m[1]] += 1

    # return predictions
    return ([hist[-i][p] for i in 1,2 for p in 0,1]+   # repeat last moves
            [hist[cand_m[-1]+1][0],     # history matching of my own moves
             hist[cand_o[-1]+1][1],     # history matching of opponent's moves
             hist[cand_b[-1]+1][0],     # history matching of both
             hist[cand_b[-1]+1][1],
             freq_m.index(max(freq_m)), # my most frequent move
             freq_o.index(max(freq_o)), # opponent's most frequent move
             0])                        # good old rock (and friends)


# what would have been predicted in the last rounds?
pred_hist = [prediction(history[:i]) for i in xrange(2,len(history)+1)]

# how would the different predictions have scored?
n_pred = len(pred_hist[0])
scores = [[0]*5 for i in xrange(n_pred)]
for pred, real in zip(pred_hist[:-1], history[2:]):
    for i in xrange(n_pred):
        scores[i][(real[1]-pred[i]+1)%5] += 1
        scores[i][(real[1]-pred[i]+3)%5] += 1
        scores[i][(real[1]-pred[i]+2)%5] -= 1
        scores[i][(real[1]-pred[i]+4)%5] -= 1

# return best counter move
best_scores = [list(max(enumerate(s), key=lambda x: x[1])) for s in scores]
best_scores[-1][1] *= 1.001   # bias towards the simplest strategy    
if best_scores[-1][1]<0.4*len(history): best_scores[-1][1] *= 1.4
strat, (shift, score) = max(enumerate(best_scores), key=lambda x: x[1][1])
print moves[(pred_hist[-1][strat]+shift)%5]

Uruchom jako:

python Pony.py

Edycja : Wprowadziłem niewielką zmianę, nastawiając się na najprostszą strategię (tj. Zawsze wykonuj ten sam ruch) w niepewnych przypadkach. To pomaga trochę nie próbować znaleźć zbyt skomplikowanych wzorców tam, gdzie ich nie ma, np. W botach takich jak ConservativeBot.

Uwaga : Próbowałem wyjaśnić podstawową strategię dopasowywania historii, której ten bot używa w poście dla mojego innego bota Dienstagu .

Emil
źródło
3
Współczynnik wygranych wynoszący 96 procent jest znakomity.
AndoDaan
Bardzo dobrze. Możesz polubić Iocaine Powder , jeśli jeszcze go nie widziałeś.
wchargin
@WChargin, oczywiście. :) Kiedy napisałem swój oryginalny kod, czytałem o Iocaine Powder kilka lat wcześniej i niejasno pamiętałem ogólny pomysł. Tak więc Pony rzeczywiście jest nim zainspirowany, jeśli nie bardzo bezpośrednio. Jak się okazuje, są bardzo podobne. Myślę, że mój ma szerszy repertuar strategii, podczas gdy proszek z Iocaine ma sprytny poziom rozumowania meta-meta, którego nie uwzględniłem.
Emil
20

Markov, Ruby

Patrzy na dwa ostatnie ruchy przeciwnika i określa możliwe (i najprawdopodobniej) kontynuacje. Jeśli kombinacja nie została wcześniej wybrana, po prostu wykorzystuje zamiast tego wszystkie ruchy przeciwnika (jak dotąd). Następnie zbiera wszystkie możliwe odpowiedzi i wybiera losową.

responses = {
  'R' => ['P', 'V'],
  'P' => ['S', 'L'],
  'S' => ['R', 'V'],
  'L' => ['S', 'R'],
  'V' => ['P', 'L']
}

if ARGV.length == 0 || (history = ARGV[1]).length < 3
    choices = ['R','P','S','L','V']
else
    markov = Hash.new []
    history.chars.each_cons(3) { |chars| markov[chars[0..1].join] += [chars[2]] }

    choices = []
    likely_moves = markov.key?(history[-2,2]) ? markov[history[-2,2]] : history.chars
    likely_moves.each { |move| choices += responses[move] }
end

puts choices.sample

Biegnij jak

markov.rb
Martin Ender
źródło
A potem używam tego programu, aby określić najbardziej możliwy ruch, który zrobię dalej, a następnie dowiedzieć się, co zrobisz, i wreszcie znaleźć sposób na pokonanie tego, co zrobisz, i nieskończoną pętlę wszystkiego raz po raz.
Jamie
@Jamie Masz na myśli tego faceta? codegolf.stackexchange.com/a/35295/8478
Martin Ender
zgadnij. (komentarz nie był wystarczająco długi, aby go opublikować)
Jamie
19

ConservativeBot, Ruby

Nowe rzeczy są złe.

puts ['R','P','S'].sample

Biegnij jak

ruby conservative.rb
Martin Ender
źródło
Wersja OG jest najlepszą wersją.
maxywb
13

Fan Star Wars - Ruby

Pieprzyć cię, Spock

puts ['R','P','L','S'].sample

Uruchom to jak:

ruby starwarsfan.rb
William Barbosa
źródło
Dodano do kontrolera
Eoin Campbell,
możesz cofnąć edycję odpowiedzi - po prostu dodam komentarz, gdy je dodam.
Eoin Campbell,
Dlaczego R i S? : P
cjfaure
@mardavi Jest fanem Star Wars, ponieważ nie używa Spocka.
William Barbosa
ah, masz rację (oczywiście). Przeczytałem to zbyt szybko, mój błąd (ale bez konsekwencji na szczęście)
mardavi
13

Barney Stinson - Lua

Mam tylko jedną zasadę: nowe zawsze są lepsze. Pieprzyć starą Jo Ken Po lub jakkolwiek to nazwiesz.

math.randomseed(os.time())
print(math.random() > 0.5 and "V" or "L")

Uruchom to jak:

lua legenwaitforitdary.lua
William Barbosa
źródło
8

Boring Bot (Java)

Zakłada, że ​​wszyscy zawsze grają to samo i odpowiednio planuje. Zazwyczaj jednak wybiera kamienie w więzach, bo czy wszyscy mają rację?

public class BoringBot
{
    public static void main(String[] args)
    {
        int Rock=0;
        int Paper=0;
        int Scissors=0;
        int Lizard=0;
        int Spock=0;

        if (args.length == 0)
        {
            System.out.print("P");
            return;
        }

        char[] oppPreviousPlays = args[1].toCharArray();

        for (int j=0; j<oppPreviousPlays.length; j++) {
            switch(oppPreviousPlays[j]){
                case 'R': Rock++; break;
                case 'P': Paper++; break;
                case 'S': Scissors++; break;
                case 'L': Lizard++; break;
                case 'V': Spock++;
            }
        }

        int Best = Math.max(Math.max(Lizard+Scissors-Spock-Paper,
                                     Rock+Spock-Lizard-Scissors),
                            Math.max(Math.max(Paper+Lizard-Spock-Rock,
                                              Paper+Spock-Rock-Scissors),
                                     Rock+Scissors-Paper-Lizard));

        if (Best== Lizard+Scissors-Spock-Paper){
            System.out.print("R"); return;
        } else if (Best== Rock+Spock-Lizard-Scissors){
            System.out.print("P"); return;
        } else if (Best== Paper+Lizard-Spock-Rock){
            System.out.print("S"); return;
        } else if(Best== Paper+Spock-Rock-Scissors){
            System.out.print("L"); return;
        } else {
            System.out.print("V"); return;
        }
    }
}
kaine
źródło
Pamiętaj, że jeśli jest to strategia, z której korzysta już ktoś inny, daj mi znać, a ja ją usunę. Po prostu wydaje się to oczywiste, którego jeszcze nie widziałem.
kaine
jest to C #. Twoje właściwości .length są nieprawidłowe. i nie ma metodymax
Eoin Campbell
@EoinCampbell To java, bawiłem się nimi i najwyraźniej zapomniałem, do których poleceń należą.
kaine
a, fajnie. zostaw to ze mną, a dostanę to.
Eoin Campbell,
wciąż złamany. działa jre8 - java BoringBot.java - Błąd: Nie można znaleźć lub załadować głównej klasy D: \ My Software Dev \ big-bang-game \ BigBang.Orchestrator \ bin \ Debug \ Players \ BoringBot \ BoringBot.java -
Eoin Campbell
8

IocainePowder, Ruby

wprowadź opis zdjęcia tutaj

Oparta na (bezwstydnie skradzionej) strategii RPS tutaj . Wygląd bota wybiera przypuszczenie identyczne z botem Markowa, ale następnie zakłada, że ​​przeciwnik odgadł, co zamierza wybrać, i wybiera ruch, aby go odpowiednio pokonać.

Zauważ, że właśnie dostosowałem podstawową ideę połączonej strategii, nie podążając za nią szczegółowo.

responses = {
  'R' => ['P', 'V'],
  'P' => ['S', 'L'],
  'S' => ['R', 'V'],
  'L' => ['S', 'R'],
  'V' => ['P', 'L']
}

if ARGV.length == 0 || (history = ARGV[1]).length < 3
    choices = ['R','P','S','L','V']
else
    markov = Hash.new []
    history.chars.each_cons(3) { |chars| markov[chars[0..1].join] += [chars[2]] }

    choices = []
    likely_moves = markov.key?(history[-2,2]) ? markov[history[-2,2]] : history.chars
    likely_moves.each { |move| choices += responses[move] }
end

myChoice = choices.sample 
theirChoice = responses[myChoice].sample
actualChoice = responses[theirChoice].sample
puts actualChoice

Biegnij jak

iocaine.rb
jmite
źródło
5
Ciągle używasz tego słowa. Nie sądzę, żeby to znaczyło, co myślisz.
JoshDM
2
Prawdziwą mocą Proszku Iocaine było przełączanie między używaniem markowa i bicie markowa. Zaczyna się jako inteligentny markow, ale gdy wyczuje (zaczyna przegrywać), przechodzi w tryb bicia-markowa. Powinien być łatwy do dodania.
Roy van Rijn
Ach, sprytne! Nie będę kłamał, słyszałem tylko, jak opisała mi Iocaine, a nie szczegółowo na to patrzyłem. Zmodyfikuj mój kod, jeśli chcesz lub prześlij swój własny, a otrzymasz kredyt!
jmite
8

HuddleWolfTheConqueror - C #

HuddleWolf powraca i jest lepszy niż kiedykolwiek. Pokona Sheldora Zdobywcę we własnej głupiej grze. HuddleWolf jest wystarczająco inteligentny, aby identyfikować i zwalczać spamerów. Bardziej inteligentni przeciwnicy HuddleWolf wykorzystuje swoją wiedzę na temat podstawowych statystyk piątej klasy i wykorzystuje ważony rzut kostką na podstawie historii rozgrywek przeciwnika.

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

public class HuddleWolfTheConqueror
{

    public static readonly char[] s = new[] { 'R', 'P', 'S', 'L', 'V' };

    public static void Main(string[] args)
    {
        if (args.Length == 0)
        {
            Console.WriteLine(pickRandom());
            return;
        }

        char[] myPlays = args[0].ToCharArray();
        char[] oppPlays = args[1].ToCharArray();

        char tryPredict = canPredictCounter(oppPlays);
        if (tryPredict != '^')
        {
            Console.WriteLine(tryPredict);
        }
        else
        {
            Console.WriteLine(pickRandom());
        }
        return;
    }


    public static char canPredictCounter(char[] history)
    {
        // don't predict if insufficient data
        if (history.Length < 5)
        {
            return '^';
        }

        // calculate probability of win for each choice
        Dictionary<char, double> dic = getBestProabability(history);

        // get item with highest probability of win
        List<char> maxVals = new List<char>();
        char maxVal = '^';
        double mostFreq = 0;
        foreach (var kvp in dic)
        {
            if (kvp.Value > mostFreq)
            {
                mostFreq = kvp.Value;
            }
        }
        foreach (var kvp in dic)
        {
            if (kvp.Value == mostFreq)
            {
                maxVals.Add(kvp.Key);
            }
        }

        // return error
        if (maxVals.Count == 0)
        {
            return maxVal;
        }

        // if distribution is not uniform, play best play
        if (maxVals.Count <= 3)
        {
            Random r = new Random(Environment.TickCount);
            return maxVals[r.Next(0, maxVals.Count)];
        }

        // if probability is close to uniform, use weighted dice roll
        if (maxVals.Count == 4)
        {
            return weightedRandom(dic);
        }

        // if probability is uniform, use random dice roll
        if (maxVals.Count >= 5)
        {
            return pickRandom();
        }

        // return error
        return '^';
    }

    public static Dictionary<char, double> getBestProabability(char[] history)
    {
        Dictionary<char, double> dic = new Dictionary<char, double>();
        foreach (char c in s)
        {
            dic.Add(c, 0);
        }
        foreach (char c in history)
        {
            if (dic.ContainsKey(c))
            {
                switch(c)
                {
                    case 'R' : 
                        dic['P'] += (1.0/(double)history.Length);
                        dic['V'] += (1.0/(double)history.Length);
                        break;
                    case 'P' : 
                        dic['S'] += (1.0/(double)history.Length);
                        dic['L'] += (1.0/(double)history.Length);
                        break;
                    case 'S' : 
                        dic['V'] += (1.0/(double)history.Length);
                        dic['R'] += (1.0/(double)history.Length);
                        break;
                    case 'L' : 
                        dic['R'] += (1.0/(double)history.Length);
                        dic['S'] += (1.0/(double)history.Length);
                        break;
                    case 'V' : 
                        dic['L'] += (1.0/(double)history.Length);
                        dic['P'] += (1.0/(double)history.Length);
                        break;
                    default : 
                        break;

                }
            }
        }
        return dic;
    }

    public static char weightedRandom(Dictionary<char, double> dic)
    {
        Random r = new Random(Environment.TickCount);
        int next = r.Next(0, 100);
        int curVal = 0;
        foreach (var kvp in dic)
        {
            curVal += (int)(kvp.Value*100);
            if (curVal > next)
            {
                return kvp.Key;
            }
        }
        return '^';
    }

    public static char pickRandom()
    {
        Random r = new Random(Environment.TickCount);
        int next = r.Next(0, 5);
        return s[next];
    }
}
HuddleWolf
źródło
8

ToddlerProof

Ten dość głupi bot zakłada, że ​​gra z małym dzieckiem, które będzie „ścigało” jego ruchy, zawsze próbując pokonać to, co zostało ostatnio rzucone. Jeśli bot zostanie pokonany kilka razy z rzędu, przeskakuje do nowego punktu wzoru. Opiera się na mojej strategii bicia mojego dużo młodszego brata. :)

EDYCJA :: Zmieniono długość serii strat wymaganych do skoku w losowe rzuty. Naprawiono także poważny błąd losowego skoku.

Zapisz jako ToddlerProof.java, skompiluj, a następnie uruchomjava ToddlerProof [me] [them]

import java.util.HashMap;
public class ToddlerProof
{
    char[] moves = new char[]{'R', 'P', 'S', 'L', 'V'};
    public static void main(String[] args)
    {
        if(args.length<1) //first Round
        {
            System.out.print('V');//Spock is best
            return;
        }
        else
        {
            String them = args[1];
            String me = args[0];
            int streak = 0;

            HashMap<Character, Character> nextMove = new HashMap<Character, Character>();
            //Next move beats things that beat my last move
            nextMove.put('L', 'V');
            nextMove.put('V', 'S');
            nextMove.put('S', 'P');
            nextMove.put('P', 'R');
            nextMove.put('R', 'L');
            //Check if last round was a tie or the opponent beat me
            int lastResult = winner(me.charAt(me.length()-1), them.charAt(them.length()-1));
            if(lastResult == 0)
            {
                //tie, so they will chase my last throw
                System.out.print(nextMove.get(me.charAt(me.length()-1)));

                return;
            }
            else if(lastResult == 1)
            {
                //I won, so they will chase my last throw
                System.out.print(nextMove.get(me.charAt(me.length()-1)));


                return;
            }

            else{
                //I lost
                //find streak
                for(int i = 0; i<me.length(); i++)
                {
                    int a = winner(me.charAt(i), them.charAt(i));
                    if(a >= 0) streak = 0;
                    else streak++;
                }
                //check lossStreak
                //If the streak is 2, then a rotation will make it even.
                //if it is >2, something bad has happened and I need to adjust.
                if(streak>2)
                {
                    //if they are on to me, do something random-ish
                    int r = (((them.length()+me.length()-1)*13)/7)%4;
                    System.out.print(move[r]);
                    return;
                }
                //otherwise, go on with the plan
                System.out.print(nextMove.get(me.charAt(me.length()-1)));
                return;
            }
        }
    }
    public static int winner(char me, char them)
    {
        //check for tie
        if(me == them) return 0;
        //check if they won
        if(me=='V' && (them == 'L' || them == 'P')) return -1;
        if(me=='S' && (them == 'V' || them == 'R')) return -1;
        if(me=='P' && (them == 'S' || them == 'L')) return -1;
        if(me=='R' && (them == 'P' || them == 'V')) return -1;
        if(me=='L' && (them == 'R' || them == 'S')) return -1;
        //otherwise, I won
        return 1;
    }
}
Stranjyr
źródło
1
Czy powinniśmy używać print czy println? ... nie byłem pewien.
kaine
Hmmm. Wyobrażam sobie, że oba zadziałałyby, ale widziałem bałagan println, gdyby program sterujący przechwycił nową linię zamiast znaku. Dzięki za zwrócenie na to uwagi, na wszelki wypadek będę edytować swój kod
Stranjyr
@Stranjyr było kilka błędów w ostatnim uruchomieniu. Nie zbombardował programu sterującego, ale jeśli przeszukasz historię dla „ToddlerProof gra n”, wygląda na to, że twój bot zwrócił wartość zero dla niektórych rąk, a następnie automatycznie zakończył układ. Przykładową grą jest „Echo & ToddlerProof”, w której Echo grał w „LVSPRLV”, zanim Twój bot zaczął się bić.
Eoin Campbell
@Eion Campbell Dzięki, że o tym wspomniałeś. Widziałem to wcześniej, kiedy opublikowałeś dzienniki z nieudanego turnieju i myślę, że mam to naprawione. Wystąpił błąd polegający na tym, że jeśli stracił więcej niż 5 stritów, zamiast przejść do losowej gry, po prostu rzucił nieprawidłową wartość. A potem, ponieważ to sprawiło, że przegrał, rzucił kolejną nieprawidłową wartość. Błędne koło.
Stranjyr
Chłodny. Zaktualizuj go teraz w programie sterującym.
Eoin Campbell
8

Bart Simpson

„Dobry stary kamień! Nic nie przebije rocka!”

puts 'R'

Uruchom jako

ruby DoTheBartman.rb

Lisa Simpson

„Biedny, przewidywalny Bart. Zawsze wybiera kamień.”

puts 'P'

Uruchom jako

ruby LisaSimpson.rb

Lepiej Lisa Simpson

Czułam się źle, robiąc Lisę tak głupią, więc pozwoliłem jej losowo wybierać jedną z rąk, które pokonają rock. Wciąż głupia, ale w końcu jest Simpsonem. Może kredka utknęła w jej mózgu?

puts ['P','V'].sample

Uruchom jako

ruby BetterLisaSimpson.rb
Dr R Dizzle
źródło
2
Zderzenie mniejszej nazwy . W każdym razie +1.
Martin Ender
@ MartinBüttner Damn, nie zauważył tego. Programy nadal wydają się robić różne rzeczy - a przynajmniej Lisa tutaj może czuć się lepsza, pokonując dwie różne wersje swojego brata.
Dr R Dizzle
1
Sheldor zgadza się ... będzie BartBot i BartSimpson :)
Eoin Campbell
3
Mamy tylko BortBot.
JoshDM
1
Zostaną zabite przez markowa :)
Cruncher
7

Echo

Napisane w C #. Kompiluj z csc Echo.cs. Biegnij jak Echo.exe ARG1 ARG2.

Przy pierwszym uruchomieniu Echo wybiera losową opcję. Za każdym razem po pierwszym Echo po prostu powtarza ostatnią akcję przeciwnika.

using System;

namespace Echo
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                Random r = new Random();
                string[] options = new string[] { "R", "P", "S", "L", "V" };
                Console.WriteLine(options[r.Next(0, options.Length)]);
            }
            else if (args.Length == 2)
            {
                string opponentHistory = args[1];
                Console.WriteLine(opponentHistory[opponentHistory.Length - 1]);
            }
        }
    }
}
ProgramFOX
źródło
7

Vulcan, Ruby

Moje palce są sklejone.

puts 'V'

Biegnij jak

ruby vulcan.rb

(Myślę, że jest to jedyna strategia postaci dla twojego tła).

Martin Ender
źródło
Musisz spojrzeć wstecz na odcinki, aby sprawdzić, czy ktoś urodził się z rozwidlonym językiem. LizardMan FTW !!!
Eoin Campbell,
3
Ale czy tak nie gra każdy w Big Bang?
kaine
2
@ anotherguest To właśnie miałem na myśli przez „to jedyna strategia postaci”.
Martin Ender
6

Tyrannosaurus, Godzilla, Barney ... Reguła jaszczurek. Czasami mają kłopoty i muszą zadzwonić do Spocka lub rzucić Kamieniem

using System;
public class LizardsRule
{
    public static void Main(string[] args)
    {
        if (args.Length == 0)
        {
            Console.WriteLine("L");
            return;
        }
        char[] oppPreviousPlays = args[1].ToCharArray();
        var oppLen = oppPreviousPlays.Length;
        if (oppPreviousPlays.Length > 2
            && oppPreviousPlays[oppLen - 1] == 'R'
            && oppPreviousPlays[oppLen - 2] == 'R'
            && oppPreviousPlays[oppLen - 3] == 'R')
        {
            //It's an avalance, someone call Spock
            Console.WriteLine("V");
            return;
        }

        if (oppPreviousPlays.Length > 2
                && oppPreviousPlays[oppLen - 1] == 'S'
                && oppPreviousPlays[oppLen - 2] == 'S'
                && oppPreviousPlays[oppLen - 3] == 'S')
        {
            //Scissors, Drop your tail and pick up a rock
            Console.WriteLine("R");
            return;
        }

        //Unleash the Fury Godzilla
        Console.WriteLine("L");     
    }
}
Mikey Mouse
źródło
6

BayesianBot, Perl (teraz v2!)

Przede wszystkim jest to wyjątkowy program. Zobaczysz w nim genialne połączenie statystyki i okropnej formy programowania. Ponadto ten bot prawdopodobnie łamie wiele zasad statystyki bayesowskiej, ale nazwa brzmi fajniej.

Podstawową istotą tego bota jest stworzenie 250 różnych modeli predykcyjnych. Każdy model ma postać „Biorąc pod uwagę, że grałem w kamień w ostatniej turze, a mój przeciwnik grał nożyczkami dwie tury temu, jest to rozkład prawdopodobieństwa dla następnego ruchu mojego przeciwnika”. Każdy rozkład prawdopodobieństwa ma postać wielowymiarowego rozkładu Dirichleta.

Każdej turze prognozy wszystkich odpowiednich modeli (zwykle 10) są mnożone razem, tworząc ogólną prognozę, która jest następnie wykorzystywana do ustalenia, które ruchy mają najwyższą oczekiwaną wypłatę.

Edycja 1: W tej wersji zmieniłem poprzednią dystrybucję i uczyniłem bota bardziej losowym, gdy przegrywa.

Istnieje kilka rzeczy, które mogą ulec poprawie, takich jak liczba modeli (250 to tylko 3 cyfry), wybór wcześniejszej dystrybucji (obecnie Dir (3,3,3,3,3)) i metoda łączenia prognoz. Poza tym nigdy nie zadałem sobie trudu znormalizowania rozkładów prawdopodobieństwa, co jest w tej chwili w porządku, ponieważ je mnożę.

Nie mam bardzo wysokich oczekiwań, ale mam nadzieję, że ten bot da sobie radę.

my ($phist, $ohist) = @ARGV;

my %text2num = ('R',0,'V',1,'P',2,'L',3,'S',4);  #the RVPLS ordering is superior
my @num2text = ('R','V','P','L','S');

@phist = map($text2num{$_},split(//,$phist));
@ohist = map($text2num{$_},split(//,$ohist));

$lowerlimit = 0;
for($lowerlimit..~~@phist-3){$curloc=$_;
 $result = $ohist[$curloc+2];
 @moveset = ($ohist[$curloc],$ohist[$curloc+1],$phist[$curloc],$phist[$curloc+1]);
 for(0..3){$a=$_;
  for(0..$a){$b=$_;
   $predict[$a][$b][$moveset[$a]][$moveset[$b]][$result]++;
  }
 }
}

@recentmoves = ($ohist[-2],$ohist[-1],$phist[-2],$phist[-1]);

@curpred = (1,1,1,1,1);

for(0..3){$a=$_;
 for(0..$a){$b=$_;
  for(0..4){$move=$_;
   $curpred[$move] *= $predict[$a][$b][$recentmoves[$a]][$recentmoves[$b]][$move]/3+1;
  }
 }
}

@bestmove = (0,0,0,0,0);
for(0..4){
 $bestmove[$_] = $curpred[$_]/2+$curpred[$_-1]+$curpred[$_-2];
}

$max = 0;
for(0..4){
 if($bestmove[$_]>$max){
  $max = $bestmove[$_];
 }
}
@options=();
$offset=0;
if(($ohist[-1] - $phist[-1])%5 < 2 && ($ohist[-2] - $phist[-2])%5 < 2 && ($ohist[-3] - $phist[-3])%5 < 2){  #frequentist alert!
 $offset=int(rand(3));
}
for(0..4){
 if($bestmove[$_] == $max){
  push(@options,$num2text[($_+$offset)%5]);
 }
}
$outputb = $options[int(rand(~~@options))];

print "$outputb";

Uruchomiłem ten program tak:

perl BayesianBot.plx
PhiNotPi
źródło
5

DynamicBot

Dynamiczny bot prawie zawsze się zmienia. Naprawdę nie znosi się powtarzać

import sys, random
choices = ['L','V','S','P','R'] * 20
if len(sys.argv) > 1:
    my_history = sys.argv[1]
    [choices.remove(my_history[-1]) for i in range(15)]
print(choices[random.randrange(len(choices))])

Język: Python 3.4.1

Polecenie: python dynamicbot.py <history>lub w python3 dynamicbot.py <history>zależności od systemu

Tymric
źródło
Tak, pomyślałem o tym.
patrz
5

SmartBot - Java

Mój pierwszy wpis na cokolwiek na tej stronie!

Choć niezbyt kreatywna nazwa ...

SmartBot wyszukuje sekwencje ruchów, w których ruchy przeciwnika i / lub siebie są podobne do ruchów ostatnio wykonanych i odpowiednio planuje.

name = SmartBot

Myślę, że go uruchomię, popraw mnie, jeśli się mylę.

java -jar SmartBot.jar

import java.util.ArrayList;
public class SmartBot {
    public static void main(String[] args) {
        if(args.length ==0){
            System.out.print("L");
            return;
        }
        if(args[0].length()<3){
            String[] randLetter = new String[]{"R","P","S","L","V"};
            System.out.print(randLetter[(int) Math.floor(Math.random()*5)]);
            return;
        }
        String myHistory = args[0];
        String otherHistory = args[1];

        double rScore,pScore,sScore,lScore,vScore;//score - highest = highest probability of next opponent move
        rScore = pScore = sScore = lScore = vScore = 0;
        lScore = .001;
        ArrayList<ArrayList<Integer>> moveHits = new ArrayList<ArrayList<Integer>>();
        for(int g = 0;g<2;g++){
            for(int i=1;i<(myHistory.length() / 2) + 1;i++){
                if(g==0){
                    moveHits.add(findAll(myHistory.substring(myHistory.length() - i),myHistory));
                }
                else{
                    moveHits.add(findAll(otherHistory.substring(otherHistory.length() - i),otherHistory));
                }
            }
            for(int i = 0; i < moveHits.size();i++){
                int matchingMoves = i+1;
                ArrayList<Integer> moveIndexes = moveHits.get(i);
                for(Integer index:moveIndexes){
                    if(index+matchingMoves +1<= otherHistory.length()){
                        char nextMove = otherHistory.charAt(index + matchingMoves-1);
                        if(nextMove=='R'){rScore = rScore + matchingMoves;}
                        if(nextMove=='P'){pScore = pScore + matchingMoves;}
                        if(nextMove=='S'){sScore = sScore + matchingMoves;}
                        if(nextMove=='L'){lScore = lScore + matchingMoves;}
                        if(nextMove=='V'){vScore = vScore + matchingMoves;}
                    }
                }
            }
        }
        if(rScore >= pScore && rScore >= sScore && rScore >= lScore && rScore >= vScore){
            System.out.print("V");
            return;
        }
        if(pScore >= rScore && pScore >= sScore && pScore >= lScore && pScore >= vScore){
            System.out.print("L");
            return;
        }
        if(sScore >= pScore && sScore >= rScore && sScore >= lScore && sScore >= vScore){
            System.out.print("R");
            return;
        }
        if(vScore >= pScore && vScore >= sScore && vScore >= lScore && vScore >= rScore){
            System.out.print("L");
            return;
        }
        if(lScore >= pScore && lScore >= sScore && lScore >= rScore && lScore >= vScore){
            System.out.print("S");
        }
        return;
    }
    public static ArrayList<Integer> findAll(String substring,String realString){
        ArrayList<Integer> ocurrences = new ArrayList<Integer>();
        Integer index = realString.indexOf(substring);
        if(index==-1){return ocurrences;}
        ocurrences.add(index+1);
        while(index!=-1){
            index = realString.indexOf(substring,index + 1);
            if(index!=-1){
                ocurrences.add(index+1);
            }
        }
        return ocurrences;
    }
}

Przypisuje ocenę za każdy możliwy następny ruch według liczby podobnych zdarzeń.

Lekko faworyzuje jaszczurki.

Stretch Maniac
źródło
Sądzę, że tak to działa, jeśli najpierw zgrzeszysz. Jeśli po prostu skompilujesz go jako pierwszy, to java ABotpowinien działać (pamiętaj, aby nazwać ten sam plik co klasa publiczna)
Justin
Dzięki! Jako stosunkowo nowy programista nie zdawałem sobie z tego sprawy.
Stretch Maniac
5

SpockOrRock - PHP

SpockOrRock

W prawdziwym świecie większość ludzi instynktownie wybiera nożyczki. Ten bot wybiera Spocka lub Rocka, aby pokonać przeciętnego gracza. Nie przejmuj się poprzednimi rundami.

Biegnij z php spockorrock.php

<?php

//Pick either Spock or Rock
if (rand(0,1) == 0)     echo("R\n");
else                    echo("V\n");


?>
ArcticanAudio
źródło
4

SlowLizard, Ruby

Po rozpoczęciu z Jaszczurką zawsze wybiera losowy ruch, który przewyższa poprzedni ruch przeciwnika.

responses = {
  'R' => ['P', 'V'],
  'P' => ['S', 'L'],
  'S' => ['R', 'V'],
  'L' => ['S', 'R'],
  'V' => ['P', 'L']
}

if ARGV.length == 0
  puts 'L'
else
  puts responses[ARGV[1][-1]].sample
end

Biegnij jak

ruby slowlizard.rb
Martin Ender
źródło
4

LexicographicBot

Ten bot lubi porządkować swoje listy, więc wybierze odpowiedź o 1 wyższą niż jego przeciwnik w poprzedniej rundzie - chyba że przeciwnik wybrał Vulcan, wtedy losowo wybiera odpowiedź.

import sys
import random

choices = ["L", "P", "R", "S", "V"]

total = len(sys.argv)
if total==1:
    print("L")
    sys.exit()

opponent = sys.argv[2]
opponent_last = opponent[-1]

if opponent_last == choices[-1]:
    print(random.choice(choices))
else:
    next = choices.index(opponent_last)+1
    print(choices[next])

Oczekuje to, że ręka przeciwnika otrzyma drugie:

                           me
                            v
python LexicographicBot.py SR RV
                              ^
                            opponent
Kyle Kanos
źródło
@ MartinBüttner: Dodano polecenie! Byłem bardzo zajęty pracą, próbując opublikować coś, stąd zniknięcie.
Kyle Kanos
psuje się przy pierwszym uruchomieniu bez argumentów. Traceback (ostatnie połączenie ostatnio): Plik „LexicographicBot \ LexicographicBot.py”, wiersz 10, w <module> przeciwnik = sys.argv [2] IndexError: indeks listy poza zakresem
Eoin Campbell
@EoinCampbell: Zapomniałem klauzuli wyjścia przy pierwszym uruchomieniu, została dodana i powinna już działać poprawnie.
Kyle Kanos
4

Werevulcan - Ruby

Uruchom jako ruby werevulcan.rb

@rules = {

  'L' => %w[V P],
  'P' => %w[V R],
  'R' => %w[L S],
  'S' => %w[P L],
  'V' => %w[R S]
}

@moves = @rules.keys

def defeats?(move1, move2)
  @rules[move1].include?(move2)
end

def score(move1, move2)
  if move1 == move2
    0
  elsif defeats?(move1, move2)
    1
  else
    -1
  end
end

def move
  player, opponent = ARGV

  # For the first 30 rounds, pick a random move that isn't Spock
  if player.to_s.size < 30
    %w[L P R S].sample
  elsif opponent.chars.to_a.uniq.size < 5
    exploit(opponent)
  else
    # Pick a random move that's biased toward Spock and against lizards
    %w[L P P R R S S V V V].sample
  end

end

def exploit(opponent)
  @moves.shuffle.max_by{ |m| opponent.chars.map{|o| score(m,o) }.reduce(:+) }
end

puts move

Wilkołak wygląda normalnie za dnia, ale kiedy księżyc wschodzi, jego uszy stają się spiczaste, a jego ruchy bardziej logiczne.

histocrat
źródło
4

Analogizer - Ruby

Uruchom z ruby analogizer.rb. Poprawiłem logikę kodu, ale nie mam pojęcia, dlaczego wystąpiły błędy.

@rules = {

  'L' => %w[V P],
  'P' => %w[V R],
  'R' => %w[L S],
  'S' => %w[P L],
  'V' => %w[R S]
}

@moves = @rules.keys

def defeats?(move1, move2)
  @rules[move1].include?(move2)
end

def score(move1, move2)
  if move1 == move2
    0
  elsif defeats?(move1, move2)
    1
  else
    -1
  end
end

def move
  player, opponent = ARGV

  case player.to_s.size
  # Throw six lizards in the beginning to confuse opponent
  when 0..5
    'L'
  when 6
    'V'
  when 7
    'S'
  when 8
    'P'
  when 9
    'R'
  else
    analyze_history(player.chars.to_a, opponent.chars.to_a)
  end

end

def analyze_history(player, opponent)
  my_last_move = player.last
  predicted_moves = Hash.new {0}
  opponent_reactions = player.zip(opponent.drop(1))

  # Check whether opponent tended to make a move that would've beaten, lost, or tied my last move
  opponent_reactions.each do |my_move, reaction|
    score = score(reaction, my_move)
    analogous_moves = @moves.select { |move| score == score(move, my_last_move) }
    analogous_moves.each { |move| predicted_moves[move] += 1 }
  end

  # Assume if an opponent has never made a certain move, it never will
  @moves.each { |m| predicted_moves[m] = 0 unless opponent.include?(m) }

  # Pick the move with the best score against opponent's possible moves, weighted by their likelihood, picking randomly for ties
  @moves.shuffle.max_by{ |m| predicted_moves.map { |predicted, freq| score(m, predicted) * freq }.reduce(0,:+) }

end

puts move

Zakłada, że ​​przeciwny bot zawsze reaguje na mój poprzedni ruch i albo wybiera coś, co by go pokonało, coś, co by go przegrało, lub ten sam ruch, być może z ograniczonego zestawu możliwych ruchów. Następnie wybiera najlepszy ruch, biorąc pod uwagę to założenie.

Tyle że pierwsze dziesięć ruchów jest zakodowanych na stałe: najpierw udaję, że znam tylko jaszczurkę, potem zakładam, że mój przeciwnik zawsze rzuca czymś, co pokonał ostatnią rzecz, którą rzuciłem, dopóki nie mam wystarczającej ilości danych do właściwej analizy.

histocrat
źródło
4

Java - SelfLoathingBot

BotName: SelfLoathingBot
Compile: Save as 'SelfLoathingBot.java'; compile.
Run:     java SelfLoathingBot [me] [them]

Bot rozpoczyna się losowo, następnie ~ 33%, aby przejść losowo, lub ~ 33%, aby zagrać zwycięską taktykę przeciwko którejkolwiek z wcześniejszych zagrań, z 50% wyborem zwycięskiej taktyki.

import java.util.Random;

public class SelfLoathingBot {

    static final Random RANDOM = new Random();

    private static char randomPlay() {

        switch (RANDOM.nextInt(5)) {

            case 0 : return 'R';

            case 1 : return 'P';

            case 2 : return 'S';

            case 3 : return 'L';

            default : return 'V';
        }
    }

    private static char antiPlay(String priorPlayString) {

        char[] priorPlays = priorPlayString.toCharArray();

        int choice = RANDOM.nextInt(2);

        switch (priorPlays[priorPlays.length - 1]) {

            case 'R' : return choice == 0 ? 'P' : 'V'; 

            case 'P' : return choice == 0 ? 'S' : 'L';

            case 'S' : return choice == 0 ? 'V' : 'R';

            case 'L' : return choice == 0 ? 'R' : 'S';

            default : return choice == 0 ? 'L' : 'P'; // V        
        }
    }

    public static void main(String[] args) {

        int choice = args.length == 0 ? 0 : RANDOM.nextInt(3);

        char play;

        switch (choice) {

            case 1 :

                // 33.3% chance Play myself
                play = antiPlay(args[0]);
                break;

            case 2 :

                // 33.3% chance Play opponent just in case opponent is screwy like that
                play = antiPlay(args[1]);
                break;

            default :

                // 33.3% chance 100% Random
                play = randomPlay();
        }

        System.out.print(play);
        return;
    }
}
JoshDM
źródło
4

Analityk

Analityk analizuje niektóre rzeczy i robi pewne rzeczy, aby spróbować cię pokonać.

skompiluj javac Analyst.javai uruchom jakojava Analyst

import java.util.Random;

public class Analyst{
    public static void main(String[] args){
        char action = 'S';

        try{
            char[] enemyMoves = null, myMoves = null;

            //first move is random
            if(args.length == 0){
                System.out.print(randomMove());
                System.exit(0);
            //moves 2-3 will beat their last move
            }else if(args[0].length() < 8){
                System.out.print(counterFor(args[1].charAt(args[1].length()-1)));
                System.exit(0);
            //following moves will execute some analyzation stuff
            }else{
                //get previous moves
                myMoves = args[0].toCharArray();
                enemyMoves = args[1].toCharArray();
            }

            //test if they're trying to beat our last move
            if(beats(enemyMoves[enemyMoves.length-1], myMoves[myMoves.length-2])){
                action = counterFor(counterFor(myMoves[myMoves.length-1]));
            }
            //test if they're copying our last move
            else if(enemyMoves[enemyMoves.length-1] == myMoves[myMoves.length-2]){
                action = counterFor(myMoves[myMoves.length-1]);
            }
            //else beat whatever they've done the most of
            else{
                action = counterFor(countMost(enemyMoves));
            }

            //if they've beaten us for the first 40 moves, do the opposite of what ive been doing
            if(theyreSmarter(myMoves, enemyMoves)){
                action = counterFor(action);
            }

        //if you break my program do something random
        }catch (Exception e){
            action = randomMove();
        }

        System.out.print(action);
    }

    private static char randomMove(){
        Random rand = new Random(System.currentTimeMillis());
        int randomMove = rand.nextInt(5);

        switch (randomMove){
            case 0: return 'R';
            case 1: return 'P';
            case 2: return 'S';
            case 3: return 'L';
            default: return 'V';
        }
    }

    private static char counterFor(char move){
        Random rand = new Random(System.currentTimeMillis());
        int moveSet = rand.nextInt(2);

        if(moveSet == 0){
            switch (move){
                case 'R': return 'P'; 
                case 'P': return 'S'; 
                case 'S': return 'R'; 
                case 'L': return 'R'; 
                default: return 'P';
            }
        }else{
            switch (move){
                case 'R': return 'V'; 
                case 'P': return 'L'; 
                case 'S': return 'V'; 
                case 'L': return 'S'; 
                default: return 'L';
            }
        }
    }

    private static boolean beats(char move1, char move2){
        if(move1 == 'R'){
            if((move2 == 'S') || (move2 == 'L')){
                return true;
            }else{
                return false;
            }
        }else if(move1 == 'P'){
            if((move2 == 'R') || (move2 == 'V')){
                return true;
            }else{
                return false;
            }
        }else if(move1 == 'S'){
            if((move2 == 'L') || (move2 == 'P')){
                return true;
            }else{
                return false;
            }
        }else if(move1 == 'L'){
            if((move2 == 'P') || (move2 == 'V')){
                return true;
            }else{
                return false;
            }
        }else{
            if((move2 == 'R') || (move2 == 'S')){
                return true;
            }else{
                return false;
            }
        }
    }

    private static char countMost(char[] moves){
        int[] enemyMoveList = {0,0,0,0,0};

        for(int i=0; i<moves.length; i++){
            if(moves[i] == 'R'){
                enemyMoveList[0]++;
            }else if(moves[i] == 'P'){
                enemyMoveList[1]++;
            }else if(moves[i] == 'S'){
                enemyMoveList[2]++;
            }else if(moves[i] == 'L'){
                enemyMoveList[3]++;
            }else if(moves[i] == 'V'){
                enemyMoveList[4]++;
            }
        }

        int max = 0, maxIndex = 0;
        for(int i=0; i<5; i++){
            if(enemyMoveList[i] > max){
                max = enemyMoveList[i];
                maxIndex = i;
            }
        }

        switch (maxIndex){
            case 0: return 'R';
            case 1: return 'P';
            case 2: return 'S';
            case 3: return 'L';
            default: return 'V';
        }
    }

    private static boolean theyreSmarter(char[] myMoves, char[] enemyMoves){
        int loseCounter = 0;

        if(enemyMoves.length >= 40){
            for(int i=0; i<40; i++){
                if(beats(enemyMoves[i],myMoves[i])){
                    loseCounter++;
                }
            }
        }else{
            return false;
        }

        if(loseCounter > 20){
            return true;
        }else{
            return false;
        }
    }
}
Qwix
źródło
4

Hazardzista - Python 2

import sys
import random

MODE = 1

moves = 'RSLPV'

def element_sums(a, b):
    return [a[i] + b[i] for i in xrange(len(a))]

def move_scores(p):
    def calc(to_beat):
        return ['LDW'.find('DLLWW'[moves.find(m)-moves.find(to_beat)]) for m in moves]

    return dict(zip(moves, element_sums(calc(p[0]), calc(p[1]))))

def move_chooser(my_history, opponent_history):
    predict = sorted(moves, key=opponent_history.count, reverse=MODE)[-2:]
    scores = move_scores(predict)
    return max(scores, key=lambda k:scores[k])

if __name__ == '__main__':
    if len(sys.argv) == 3:
        print move_chooser(*sys.argv[1:])
    elif len(sys.argv) == 1:
        print random.choice(moves)

Wbrew nazwie, w tym programie losowość jest używana tylko w pierwszej rundzie, gdy nie ma żadnych informacji. Zamiast tego, jego nazwa pochodzi od błędu gracza - przekonania, że ​​jeśli zdarzenie losowe zdarzało się rzadziej w przeszłości, bardziej prawdopodobne jest, że w przyszłości. Na przykład, jeśli rzucisz uczciwą monetą 20 razy, a pierwsze 15 to główki, błąd gracza oznacza, że ​​szanse na pozostałe rzuty są ogonami. Oczywiście jest to nieprawda; niezależnie od poprzednich rzutów, szanse pojawienia się reszki na uczciwej monecie wynoszą zawsze 50%.

Ten program analizuje historię przeciwnika, znajduje 2 ruchy, których użył najmniej do tej pory, i zakłada, że ​​tym razem ruch przeciwnika będzie jednym z nich. Przypisując 2 do wygranej, 1 do remisu i 0 do przegranej, znajduje ruch z maksymalnym wynikiem w stosunku do tych dwóch przewidywanych ruchów i rzuca nim.

Brat hazardzisty - Python 2

import sys
import random

MODE = 0

moves = 'RSLPV'

def element_sums(a, b):
    return [a[i] + b[i] for i in xrange(len(a))]

def move_scores(p):
    def calc(to_beat):
        return ['LDW'.find('DLLWW'[moves.find(m)-moves.find(to_beat)]) for m in moves]

    return dict(zip(moves, element_sums(calc(p[0]), calc(p[1]))))

def move_chooser(my_history, opponent_history):
    predict = sorted(moves, key=opponent_history.count, reverse=MODE)[-2:]
    scores = move_scores(predict)
    return max(scores, key=lambda k:scores[k])

if __name__ == '__main__':
    if len(sys.argv) == 3:
        print move_chooser(*sys.argv[1:])
    elif len(sys.argv) == 1:
        print random.choice(moves)

Po przełączeniu MODEzmiennej na 0, program ten będzie działał w oparciu o powiązany błąd, czasami określany również mianem błędu gracza. Stwierdza, że ​​jeśli zdarzenie losowe zdarzało się częściej w przeszłości, bardziej prawdopodobne jest, że w przyszłości. Na przykład, jeśli rzucisz monetą 20 razy, a pierwsze 15 to główki, ten błąd mówi, że pozostałe rzuty są bardziej prawdopodobne, ponieważ obecnie występuje seria. W trybie 0 program działa w ten sam sposób, z tym wyjątkiem, że zakłada, że ​​przeciwnik wykona jeden z dwóch najczęściej wykonywanych ruchów.

Tak więc, te dwa programy różnią się tylko jedną postacią. :)

podziemny monorail
źródło
Pod jakim warunkiem TheGambler zmienia TRYB?
Dr R Dizzle
@DrRDizzle Nie, wygląda na to, że jest to przesłanie dwóch botów w jednym.
Paŭlo Ebermann
2
Czy ten program nie byłby bardziej skuteczny, gdyby zmienił się TRYB, jeśli stracisz więcej niż pewną liczbę razy z rzędu?
Dr R Dizzle
4

Dienstag (Python 2)

Mój pierwszy wpis, Pony, wydaje się całkiem nieźle z całym drugim zgadywaniem (potrójne zgadywanie, ...) i meta rozumowaniem. Ale czy to w ogóle konieczne?

Oto Dienstag, mały przyjaciel Pony, z jedną z 55 strategii: Przewiduj następny ruch przeciwnika i pokonaj go.

Na dłuższą metę Dienstag wygrywa lub łączy się z każdym botem w pierwszej dziesiątce obecnej tabeli liderów. Z wyjątkiem Kucyka.

import sys
if len(sys.argv)<2 or len(sys.argv[1])<2: print 'L'; sys.exit()
hist = [map('RPSVL'.index, p) for p in zip(sys.argv[1], sys.argv[2])]
N = len(hist)
cand = range(N-1)
for l in xrange(1,N):
    cand = ([c for c in cand if c>=l and hist[c-l+1]==hist[-l]] or cand[-1:])
print 'RPSVL'[(hist[cand[-1]+1][1]+(1,3)[N%2==0])%5]

Uruchom jako:

python Dienstag.py

Przyznaję, że kod jest nieco zaciemniony. Jeśli ktoś chciałby dowiedzieć się więcej na ten temat, mogę dodać wyjaśnienia.

Edycja: Oto krótki przykładowy przewodnik wyjaśniający pomysł:

  • Program pobiera własną historię i ruchy przeciwnika:

    sys.arg[1] = 'LLVLLVL', sys.arg[2] = 'RPSPSSP'

  • Historia jest łączona w listę par, a ruchy są tłumaczone na liczby (R = 0, ...):

    hist = [[4, 0], [4, 1], [3, 2], [4, 1], [4, 2], [3, 2], [4, 1]]

  • Liczba rozegranych do tej pory rund jest ustalana:

    N = 7

  • Podstawową ideą jest teraz poszukiwanie najdłuższego nieprzerwanego łańcucha dokładnie ostatnich ruchów we wcześniejszej historii. Program śledzi, gdzie taki łańcuch kończy się na liście cand(dla „kandydatów”). Na początku, bez sprawdzania, bierze się pod uwagę każdą pozycję w historii z wyjątkiem ostatniej:

    cand = [0, 1, 2, 3, 4, 5]

  • Teraz długość możliwych łańcuchów zwiększa się krok po kroku. Dla długości łańcucha l = 1szuka poprzednich wystąpień ostatniej pary ruchów [4, 1]. Można to znaleźć w pozycji historii 1i 3. Tylko te są przechowywane na candliście:

    cand = [1, 3]

  • Następnie l = 2sprawdza, który z potencjalnych kandydatów został poprzedzony parą ruchów od drugiego do ostatniego [3, 2]. Dotyczy to tylko pozycji 3:

    cand = [3]

  • Co l = 3więcej, nie ma wcześniejszych łańcuchów o tej długości i candbyłyby puste. W tym przypadku zachowany jest ostatni element cand:

    cand = [3]

  • Bot zakłada, że ​​historia się powtórzy. Po ostatnim [3, 2], [4, 1]wystąpieniu kaina nastąpił po nim [4, 2]. Zatem przeciwnik grał 2(nożyczkami), które mogą zostać pokonane przez (2+1)%5 = 3(Spock) lub (2+3)%5 = 0(rock). Bot odpowiada, z pierwszą lub drugą alternatywą, zależnie od tego, czy Njest nieparzysty, czy nawet po prostu wprowadza pewną wariancję.

  • Tutaj 3wybierany jest ruch, który jest następnie tłumaczony z powrotem:

    print 'V'

Uwaga: Dienstag ma złożoność czasową O ( N 2 ) do powrotu następnego ruchu po N rundach. Kuc ma złożoność czasową O ( N 3 ). W tym aspekcie są one prawdopodobnie znacznie gorsze niż większość innych pozycji.

Emil
źródło
proszę zrób. to dla mnie niesamowite doświadczenie edukacyjne. Zwykle mieszkam w krainie C # / Java, więc szaleństwo lua, ruby, python, haskell jest dla mnie bardzo interesujące.
Eoin Campbell
Kusi mnie również, aby dodać do gry dodatkowy egzemplarz Pony. To będzie jak walka z lustrem na 3 do ostatnich poziomów śmiertelnej walki ;-)
Eoin Campbell
@EoinCampbell :-) Przynajmniej bezpośredni mecz Pony vs. Pony byłby idealnym remisem. W obu moich botach nie ma elementu losowości.
Emil
3

Bash Rocks

Czy cygwin to zbyt wiele, by prosić o środowisko uruchomieniowe?

bashrocks.sh:

#!/bin/bash
HAND=(R P S L V)
RAND=`od -A n -t d -N 1 /dev/urandom | xargs`
echo ${HAND[ $RAND  % 5 ]}

i uruchom tak:

sh bashrocks.sh
mccannf
źródło
5
Po przeczytaniu tytułu jestem nieco rozczarowany, że robisz coś innego niż R. ;)
Martin Ender
@mccannf. mam pewne problemy z tym ... Zainstalowałem cygwin i zmodyfikowałem twoje skrypty w pełni kwalifikowanymi ścieżkami do C: \ Cygwin \ bin for od.exe, xargs.exe i echo.exe. nadal pojawia się następujący błąd. C: / Cygwin / bin / xargs: echo: Nie ma takiego pliku lub katalogu% 5 ”) błąd składni: oczekiwany operand (token błędu to„
Eoin Campbell
@EoinCampbell - czy po utworzeniu pliku w systemie Windows można uruchomić dos2unixplik w cygwinie przed jego uruchomieniem?
mccannf
pewnie. Spróbuję.
Eoin Campbell
Myślę, że problem może dotyczyć stwierdzenia / dev / urandom
Eoin Campbell
3

Algorytm

Algorytm dla samego posiadania.

Ponieważ zawsze robi się coś bezpieczniej, im bardziej skomplikowane, tym lepiej.

Nie zrobiłem jeszcze poważnej matematyki, więc ten algorytm może nie być tak skuteczny.

import random, sys

if __name__ == '__main__':

    # Graph in adjacency matrix here
    graph = {"S":"PL", "P":"VR", "R":"LS", "L":"VP", "V":"SR"}
    try:
        myHistory = sys.argv[1]
        opHistory = sys.argv[2]
        choices = ""

        # Insert some graph stuff here. Newer versions may include advanced Math.
        for v in graph:
            if opHistory[-1] == v:
                for u in graph:
                    if u in graph[v]:
                        choices += graph[u]

        print random.choice(choices + opHistory[-1])

    except:
        print random.choice("RPSLV")

Program Python 2: python algorithm.py

Vectorized
źródło
1
Podsumowanie tego algorytmu: spójrz na to, co ostatnio grał przeciwnik, a następnie losowo zagraj jeden z dwóch ruchów, które straciłyby w stosunku do ostatniego ruchu przeciwnika, gdyby ponownie go zagrał. Lepiej więc w przypadku botów, które nie wykonują tego samego ruchu dwa razy z rzędu.
Rory O'Kane
Ha ha. Naprawdę nie wiem, czy udało mi się to w ten sposób. Jeśli się nie mylę, jest to po prostu skomplikowany sposób losowego wybierania któregokolwiek z 5 ruchów. ;)
Vectorized
3

FairBot, Ruby

Zacznijmy prosto.

puts ['R','P','S','L','V'].sample

Biegnij jak

ruby fairbot.rb
Martin Ender
źródło
mała literówka na ostatnim parametrze „V”. naprawiłem to na myside, jeśli chcesz zaktualizować dla kompletności
Eoin Campbell
@EoinCampbell dzięki, naprawiono!
Martin Ender
1
Interesujące jest to, że ma dokładnie takie same szanse na wygraną ze WSZYSTKIMI strategiami.
Cruncher
3

ViolentBot

Ten bot wybiera najbardziej brutalną opcję w oparciu o poprzedni wybór przeciwników:

import sys

choice_dict = {"L" : "S", "P" : "S", "R" : "V", "S" : "V", "V" : "L"}

total = len(sys.argv)
if total==1:
    print("L")
    sys.exit()

opponent = sys.argv[2]
opponent_last = opponent[-1]

print(choice_dict[opponent_last])

Uruchom jako

python ViolentBot.py (me) (opp)
Kyle Kanos
źródło
zrywa bez parametrów. Traceback (najnowsza wezwanie ostatni): File "ViolentBot \ ViolentBot.py", linia 9, w <module> przeciwnik = sys.argv [2] IndexError: Index Lista poza zasięgiem
Eoin Campbell
zrywa z params. Traceback (ostatnie ostatnie połączenie): Plik „ViolentBot \ ViolentBot.py”, wiersz 12, w <module> drukowaniu (choice_dict [opponent_last]) KeyError: 'S'
Eoin Campbell
@EoinCampbell: Dodałem klauzulę wyjścia dla pierwszego uruchomienia, powinieneś być w stanie ją uruchomić teraz.
Kyle Kanos
3

Haskell - MonadBot

Nie wiem, czy ghc jest uważany za „w granicach rozsądku”, ale załóżmy, że tak. Strategią tego bota jest przeciwstawienie się najpopularniejszemu ruchowi przeciwnika.

Compile: ghc monadbot.hs
Run:     ./monadbot [Arg1] [Arg2]

Kod:

import System.Environment
import Data.List
import Data.Ord

main :: IO ()
main = do
  args <- getArgs
  let moves = if not (null args) then args !! 1 else ""
      fave = if not (null moves) then head $ maximumBy (comparing length) (group $ sort moves) else 'V'
  putChar $ case fave of 'R' -> 'P'
                         'P' -> 'S'
                         'S' -> 'R'
                         'L' -> 'R'
                         'V' -> 'P'
                         _   -> 'V'
DrJPepper
źródło