Камень, Бумага, Ножницы, Ящерица, Спок Турнир на эпичность

98

Последняя таблица лидеров @ 2014-08-02 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

Турнирные заметки

  • WOO HOO 70 БОТОВ
  • Эмиль все еще с KOTH, Ponyи его новый бот Dienstagзанимает 3 место
  • Поздравляю Роя за то, что он прыгнул на 2-е место со своим Gazzrботом
  • Уильям Барбоза получает награду Quick Draw за своего ботаBarneyStinson
  • И Slow Poke награда вручается Docopoper за его боты R.O.B.O.Tи Concessionbotкоторые оба были> 140мса в руку

  • Доступные журналы @ https://github.com/eoincampbell/big-bang-game/blob/master/tourneys/Tournament-2014-08-01-23-24-00.zip?raw=true

Исключенные боты

  • BashRocksBot - до сих пор не радует .net за исключением сценариев Cygwin Bash
  • CounterPreferenceBot - ожидание исправления ошибки
  • RandomlyWeighted - ожидание исправления ошибки
  • CasinoShakespeare - исключено, поскольку требуется активное подключение к Интернету

Оригинальный вопрос

Вы отправились в дом своих друзей на самую эпическую битву за всю историю Рок, Бумага, Ножницы, Ящерица, Спок. В истинном стиле BigBang, ни один из игроков не играет сам, но создал консольных ботов, чтобы играть от их имени. Вы достаете свой USB-ключ и передаете его Шелдору Завоевателю для включения в битву . Пенни падает в обморок. Или, возможно, Говард обморок. Мы не судим здесь, в квартире Леонарда.

правила

Применяются стандартные правила: камень, бумага, ножницы, ящерица, спок.

  • Ножницы вырезанные из бумаги
  • Бумажные обложки Rock
  • Каменная крошка Ящерица
  • Ящерица отравляет Спока
  • Спок разбивает ножницы
  • Ножницы обезглавливают Ящерицу
  • Ящерица ест бумагу
  • Бумага опровергает Спока
  • Спок испаряет камень
  • Камень давит Ножницы

Правила RPSLV

Бот каждого игрока сыграет один матч против другого бота в турнире.

Каждый Матч будет состоять из 100 итераций игры RPSLV.

После каждого матча победителем становится игрок, выигравший наибольшее количество игр / раздач из 100.

Если вы выиграете матч, вам будет присвоено 1 очко в таблице лиги. В результате ничьей ни один из игроков не получит очко.

Требования к боту

Ваш бот должен быть запущен из командной строки.

* Шелдор * nix box умер, поэтому мы запускаем его с его игрового ноутбука Windows 8, поэтому убедитесь, что ваше решение может работать на Windows. Шелдор любезно предложил установить любые необходимые среды выполнения (в пределах разумного), чтобы иметь возможность запустить ваше решение. (.NET, Java, Php, Python, Ruby, Powershell ...)

входные

В первой игре каждого матча вашему боту не приводятся аргументы. В каждой последующей игре каждого матча: - Arg1 будет содержать историю ваших рук / решений ботов в этом матче. - Arg2 будет содержать историю рук / решений ваших оппонентов в этом матче.

История будет представлена ​​последовательностью отдельных заглавных букв, обозначающих возможные руки, которые вы можете сыграть.

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

Например

  • Игра 1: MyBot.exe
  • Игра 2: MyBot.exe SV
  • Игра 3: MyBot.exe SS VL
  • Игра 4: MyBot.exe SSR VLS

Выход

Ваш бот должен написать отдельный ответ персонажа, представляющий его «руку» для каждой игры. Результат должен быть записан в STDOUT, а затем бот должен выйти. Допустимые одиночные заглавные буквы ниже.

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

В том случае, если ваш бот не возвращает действительную руку (т.е. 1 из 5 вышеуказанных заглавных букв), вы автоматически лишаетесь этой руки, и матч продолжается.

В случае, когда оба бота не возвращают действительную руку, игра считается ничьей, и матч продолжается.

Формат матча

Каждый представленный бот сыграет один матч против другого бота в турнире.

Каждый матч продлится ровно 100 игр.

Матчи будут разыгрываться анонимно, вы не будете иметь глубоких знаний о конкретном боте, с которым вы играете, однако вы можете использовать любую информацию, которую вы можете получить из его решений в течение истории текущего матча, чтобы изменить свою стратегию против вашего. противник. Вы также можете отслеживать историю ваших предыдущих игр для создания шаблонов / эвристики и т. Д. (См. Правила ниже)

В течение одной игры движок оркестровки будет запускать вашего бота, а ваши оппоненты - на расстоянии 100 миллисекунд, а затем сравнивать результаты, чтобы избежать любых столкновений PRNG на одном языке / времени выполнения. (это на самом деле случилось со мной во время тестирования).

Судья и ограничения

Доктор Шелдон Купер под видом Шелдора Завоевателя любезно предложил присмотреть за ходом турнира. Шелдор Завоеватель - честный и просто надзиратель (в основном). Все решения Шелдора являются окончательными.

Игры будут проводиться честно и правильно:

  • Ваш скрипт / программа для бота будет храниться в движке оркестровки в подпапке Players\[YourBotName]\
  • Вы можете использовать подпапку Players\[YourBotName]\dataдля регистрации любых данных или истории игр текущего турнира по мере его продолжения. Каталоги данных будут очищаться в начале каждого турнира.
  • Вы не можете получить доступ к каталогу Игрока другого игрока в турнире.
  • У вашего бота не может быть определенного кода, нацеленного на другое поведение конкретного бота
  • Каждый игрок может отправить в игру более одного бота, если они не взаимодействуют и не помогают друг другу.

Изменить - Дополнительные ограничения

  • Что касается штрафов, они не будут поддерживаться. Ваш бот должен сыграть одну из 5 действительных рук. Я протестирую каждого бота вне турнира с некоторыми случайными данными, чтобы убедиться, что они ведут себя. Любые боты, которые выбрасывают ошибки (т.е. теряют ошибки), будут исключены из турнира, пока они не исправят ошибку.
  • Боты могут быть производными, если они кратко отличаются по своему поведению. Боты (в том числе на других языках), которые ведут себя точно так же, как и существующие боты, будут дисквалифицированы
  • Уже есть спам-боты, поэтому, пожалуйста, не отправляйте повторно
    • Рок - БартСимпсон
    • Бумага - ЛизаСимпсон
    • Scissor - EdwardScissorhands
    • Спок - Вулкан
    • Ящерица - Халиси
    • Псевдослучайный - SimpleRandomBot & FairBot
    • Psuedo Random RPS - ConservativeBot
    • Psuedo Random LV - Барни Стинсон
  • Боты не могут вызывать сторонние сервисы или веб-ресурсы (или что-либо еще, что значительно замедляет скорость / время принятия решений в матчах). CasinoShakespeareэто единственное исключение, так как этот бот был представлен до добавления этого ограничения.

Шелдор будет обновлять этот вопрос так часто, как он может с результатами Турнира, так как будет представлено больше ботов.

Программа оркестровки / управления

Программа оркестровки вместе с исходным кодом для каждого бота доступна на github.

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

Детали представления

Ваша заявка должна включать

  • Имя вашего бота
  • Ваш код
  • Команда для
    • выполнить свой бот из оболочки, например
    • ruby myBot.rb
    • python3 myBot.py
    • ИЛИ ЖЕ
    • сначала скомпилируйте оба, а затем выполните. например
    • csc.exe MyBot.cs
    • MyBot.exe

Образец представления

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

Код:

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]);
    }
}

осветление

Любые вопросы задавайте в комментариях ниже.

Эойн Кэмпбелл
источник
7
Как выглядит история, когда игрок потерял руку?
гистократ
1
Я собирался сделать все возможное с аналитическим подходом, но большинство ботов здесь достаточно глупы, чтобы победить умный ИИ.
пушистый
1
Просто потому , что я никогда не нахожусь в лидерстве для любой KOTH вызов я соревновался, я взял скриншот на память.
Кайл Канос
3
Сегодня вечером я проведу еще один турнир и опубликую полные результаты матчей на pastebin ... следующая партия будет иметь около 450 игр, но должна быть немного быстрее, так как я реализовал некоторые вещи с распараллеливанием в управляющей проге
Eoin Campbell
3
Если я не ошибаюсь, в скрипте оркестровки, похоже, есть серьезная ошибка: истории игрока 1 и 2 всегда передаются ботам в качестве первого и второго аргумента соответственно, в то время как согласно правилам боты должны всегда получать свои первая собственная история Теперь игрок 2 эффективно пытается победить себя. (Я стал немного подозрительным, потому что мой бот выигрывал каждый матч, где он был игроком 1, в то же время проигрывая половину других матчей.)
Эмиль

Ответы:

26

Пони (Питон 2)

Это основано на боте «камень-ножницы-бумага», который я написал некоторое время назад для программирования в конце онлайн-класса Udacity . Я изменил его, чтобы включить Спока и ящерицу, и сделал некоторые улучшения.

Программа имеет 11 различных простых стратегий, каждая с 5 вариантами. Он выбирает среди них, основываясь на том, насколько хорошо они выступили бы в последних раундах.

Я удалил запасную стратегию, которая просто играла случайно против более сильных противников. Я думаю, что это веселее, как это.

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]

Беги как:

python Pony.py

Изменить : я сделал небольшое изменение, вставив уклон в сторону самой простой стратегии (то есть всегда играть один и тот же ход) в неуверенных случаях. Это немного помогает не пытаться найти слишком сложные паттерны там, где их нет, например, в таких ботах, как ConservativeBot.

Примечание : я попытался объяснить основную стратегию сопоставления истории, которую этот бот использует в посте для моего другого бота Dienstag .

Эмиль
источник
3
Процент побед 96 процентов является выдающимся.
AndoDaan
Очень хорошо. Вам может понравиться Порошок Иокаина , если Вы еще не видели это.
wchargin
@WChargin, конечно. :) Когда я писал свой оригинальный код, я читал о порошке Iocaine несколькими годами ранее и смутно помнил общую идею. Итак, Пони действительно вдохновлен этим, если не очень напрямую. Как оказалось, они очень похожи. Я думаю, что у меня есть более широкий спектр стратегий, в то время как у Порошка Иокаина есть умный уровень метамета, который я не включил.
Эмиль
20

Марков, Рубин

Рассматривает последние два хода противника и определяет возможные (и наиболее вероятные) последующие действия. Если комбинация не была выбрана раньше, он просто использует все ходы противника (пока). Затем он собирает все возможные ответы на них и выбирает случайный.

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

Беги как

markov.rb
Мартин Эндер
источник
И затем я использую эту программу, чтобы определить наиболее вероятный ход, который я сделаю следующим, затем выяснить, что вы будете делать, и, наконец, найти способ превзойти то, что вы будете делать, и снова и снова делать бесконечный цикл.
Джейми
@ Джейми Ты имеешь в виду, как этот парень? codegolf.stackexchange.com/a/35295/8478
Мартин Эндер
ты угадаешь это. (комментарий не был достаточно длинным для публикации)
Джейми
19

ConservativeBot, Ruby

Новые вещи плохие.

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

Беги как

ruby conservative.rb
Мартин Эндер
источник
OG версия - лучшая версия.
maxywb
13

Фанат Звездных Войн - Рубин

Винт ты, Спок

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

Запустите это как:

ruby starwarsfan.rb
Уильям Барбоза
источник
Добавлено в контроллер
Эойн Кэмпбелл
вы можете откатить ответом - я просто прокомментирую здесь, когда добавлю их.
Эойн Кэмпбелл
Почему Р и С? : P
cjfaure
@mardavi Это фанат Star Wars, потому что он не использует Спока.
Уильям Барбоза,
ах, ты прав (конечно). Я читаю это слишком быстро, моя ошибка (но без последствий, к счастью)
mardavi
13

Барни Стинсон - Луа

У меня только одно правило: новое всегда лучше. Винт старый Джо Кен По или как вы это называете.

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

Запустите это как:

lua legenwaitforitdary.lua
Уильям Барбоза
источник
8

Скучный бот (Java)

Он предполагает, что каждый всегда играет одно и то же и планирует соответственно. Хотя он обычно выбирает камни в галстуках, потому что так ли все остальные правы?

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
это C #. вы. Длина свойства неверны. и нет никакого способаmax
Эоин Кэмпбелл
@EoinCampbell Это Java, я играл с обоими и, очевидно, забыл, какие команды принадлежат к какой.
Кейн
ах классно оставь это со мной, и я включу это.
Эоин Кэмпбелл
все еще сломан. выполняется jre8 - java BoringBot.java - ошибка: не удается найти или загрузить основной класс D: \ My Software Dev \ big-bang-game \ BigBang.Orchestrator \ bin \ Debug \ Players \ BoringBot \ BoringBot.java -
Eoin Campbell
8

IocainePowder, Рубин

введите описание изображения здесь

Основанный на (бесстыдно украденной) стратегии RPS здесь . Похоже, бот выбирает предположение, идентичное марковскому, но предполагает, что противник угадал, что он выберет, и выбирает ход, чтобы превзойти его.

Обратите внимание, что я только что адаптировал основную идею связанной стратегии, а не следовал ей подробно.

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

Беги как

iocaine.rb
jmite
источник
5
Вы продолжаете использовать это слово. Я не думаю, что это означает, что вы думаете, что это значит.
JoshDM
2
Настоящая сила Iocaine Powder заключалась в том, что он переключается между использованием markov и beating-markov. Он начинается как умный марков, но как только он чувствует (начинает проигрывать), он переходит в режим биений-марков. Должно быть легко добавить.
Рой ван Рейн
Ааа, умно! Не собираюсь лгать, я только слышал, как мне описали Иокаина, а не рассматривал это подробно. Не стесняйтесь изменять мой код, если хотите, или отправьте свой собственный и получите кредит!
jmite
8

HuddleWolfTheConqueror - C #

HuddleWolf вернулся и лучше, чем когда-либо. Он победит Шелдора Завоевателя в своей глупой игре. HuddleWolf достаточно умен, чтобы выявлять и противостоять спаммерботам. Для более умных противников HuddleWolf использует свои знания базовой статистики 5-го класса и использует взвешенный бросок костей, основанный на истории игр противника.

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
источник
8

ToddlerProof

Этот довольно глупый бот предполагает, что он играет малыша, который будет «преследовать» свои ходы, всегда пытаясь побить то, что было брошено последним. Если бота бьют несколько раз подряд, он переходит на новую точку в паттерне. Это основано на моей стратегии всегда побеждать моего намного младшего брата. :)

EDIT :: Изменена длина полосы проигрыша, необходимая для прыжка в случайные броски. Также исправлена ​​серьезная ошибка со случайным прыжком.

Сохранить как ToddlerProof.java, скомпилировать, затем запустить сjava 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
источник
1
Мы должны использовать print или println? ... Я не был уверен.
Кейн
Хммм. Я думаю, что оба будут работать, но я мог видеть, что println портится, если управляющая программа захватывает символ новой строки вместо символа. Спасибо за указание на это, я на всякий случай отредактирую свой код
Странджир
@ Stranjyr были некоторые ошибки в вашем последнем запуске. Он не бомбил управляющую программу, но если вы ищете в истории «ToddlerProof plays n», похоже, что ваш бот возвращал ноль для определенных рук, а затем автоматически терял руку. Примером игры является «Echo & ToddlerProof», где Echo играл в «LVSPRLV» до того, как ваш бот начал дурачиться.
Эойн Кэмпбелл
@Eion Campbell Спасибо за упоминание этого. Я видел это раньше, когда вы публиковали логи неудачного турнира, и я думаю, что я исправил это. Он столкнулся с ошибкой, когда, если он проиграл более 5 раз подряд, вместо прыжка в случайную игру он просто выбрасывал недопустимое значение. А потом, потому что это заставило его проиграть, он бросил еще одно недействительное значение. Замкнутый круг
Странджир
Здорово. Обновите его в управляющей проге сейчас.
Эойн Кэмпбелл
8

Барт Симпсон

"Старый добрый рок! Ничто не сравнится с рок!"

puts 'R'

Беги как

ruby DoTheBartman.rb

Лиза Симпсон

«Бедный, предсказуемый Барт. Всегда выбирает рок».

puts 'P'

Беги как

ruby LisaSimpson.rb

Лучше Лиза Симпсон

Я чувствовал себя плохо из-за того, что сделал Лизу такой глупой, поэтому позволил ей случайным образом выбирать одну из рук, которые будут бить рок. Все еще глупо, но она все-таки Симпсон. Может быть, карандаш застрял в ее мозгу?

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

Беги как

ruby BetterLisaSimpson.rb
Доктор Р Диззл
источник
2
Незначительное столкновение имен . +1 в любом случае.
Мартин Эндер
@ MartinBüttner Черт, не заметил этого. Программы все еще, кажется, делают разные вещи - и, по крайней мере, Лиза здесь может чувствовать себя лучше, победив две разные версии своего брата.
Доктор Р. Диззл
1
Шелдор соглашается ... должен быть BartBot и BartSimpson :)
Eoin Campbell
3
У нас есть только BortBot.
JoshDM
1
Они будут убиты Марковым :)
Cruncher
7

эхо

Написано на C #. Компилировать с csc Echo.cs. Беги как Echo.exe ARG1 ARG2.

При первом запуске Echo выбирает случайный вариант. Каждый раз после первого Echo просто повторяет последнее действие противника.

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
источник
7

Вулкан, Рубин

Мои пальцы склеены.

puts 'V'

Беги как

ruby vulcan.rb

(Я думаю, что это единственная в своем роде стратегия для вашей фоновой настройки.)

Мартин Эндер
источник
Нужно оглянуться назад на эпизоды, чтобы увидеть, родился ли кто-нибудь с раздвоенным языком. LizardMan FTW !!!
Эойн Кэмпбелл
3
Но разве не так все играют на большом взрыве?
Кейн
2
@anotherguest Вот что я имел в виду под «это единственная в своем роде стратегия».
Мартин Эндер
6

Тиранозавр, Годзилла, Барни ... Правило ящериц. Иногда они попадают в беду и должны позвонить Споку или бросить Камни

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");     
    }
}
Майки маус
источник
6

BayesianBot, Perl (теперь v2!)

Помимо всего прочего, это уникальная программа. В нем вы увидите блестящее слияние статистики и ужасной формы программирования. Также этот бот, вероятно, нарушает многие правила байесовской статистики, но название звучит круче.

Суть этого бота заключается в создании 250 различных прогнозирующих моделей. Каждая модель принимает форму «Учитывая, что в последний ход я играл рок, а мой оппонент играл два шага назад, это распределение вероятностей для следующего хода моего оппонента». Каждое распределение вероятностей принимает форму многомерного распределения Дирихле.

Каждый ход прогнозы всех применимых моделей (обычно 10) умножаются вместе для формирования общего прогноза, который затем используется для определения того, какие ходы имеют наибольшую ожидаемую отдачу.

Редактировать 1: В этой версии я изменил предыдущий дистрибутив и сделал бота более рандомизированным, когда он проигрывает.

Есть несколько вещей, которые могут быть улучшены, такие как количество моделей (250 - это только трехзначное число), выбор предварительного распределения (в настоящее время Dir (3,3,3,3,3)) и метод слияния предсказаний. Кроме того, я никогда не удосужился нормализовать какое-либо из распределений вероятности, что пока нормально, потому что я их умножаю.

У меня нет супер высоких ожиданий, но я надеюсь, что этот бот сможет преуспеть.

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";

Я запустил эту программу так:

perl BayesianBot.plx
PhiNotPi
источник
5

DynamicBot

Динамический бот почти всегда меняется. Это действительно ненавидит повторяться

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))])

Язык: Python 3.4.1

Команда: python dynamicbot.py <history>или в python3 dynamicbot.py <history>зависимости от вашей системы

Tymric
источник
Да, думал об этом.
Seequ
5

SmartBot - Java

Моя первая запись о чем-либо на этом сайте!

Хотя не очень креативное имя ...

SmartBot находит последовательности ходов, в которых ходы противника и / или самого себя аналогичны последним сделанным ходам, и планирует соответственно.

name = SmartBot

Я думаю, чтобы запустить его, поправьте меня, если я ошибаюсь.

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;
    }
}

Он присваивает оценку каждому возможному следующему ходу по количеству повторений похожих паттернов.

Это немного одобряет ящерицу.

Стрейч маньяк
источник
Я полагаю, что именно так ты и будешь управлять, если сначала встряхнешь. Если вы сначала просто скомпилируете его, то java ABotдолжны сработать (не забудьте назвать файл так же, как открытый класс)
Джастин
Спасибо! Как относительно новый программист, я не знал об этом.
Стрейч-маньяк
5

SpockOrRock - PHP

SpockOrRock

Когда играют в реальном мире, большинство людей инстинктивно выбирают ножницы. Этот бот выбирает Спока или Рока, чтобы побить среднего игрока. Это не беспокоит предыдущие раунды.

бежать с php spockorrock.php

<?php

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


?>
ArcticanAudio
источник
4

SlowLizard, Ruby

Начав с Ящера, он всегда выбирает случайный ход, который бьет предыдущий ход противника.

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

Беги как

ruby slowlizard.rb
Мартин Эндер
источник
4

LexicographicBot

Этот бот любит заказывать свои письма, поэтому он выберет ответ, который на 1 больше, чем его оппонент в предыдущем раунде - если только оппонент не выбрал Вулкана, он случайным образом выбирает ответ.

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])

Это предполагает, что рука оппонента будет сдана второй:

                           me
                            v
python LexicographicBot.py SR RV
                              ^
                            opponent
Кайл Канос
источник
@ MartinBüttner: команда добавлена! Я был довольно занят на работе, пытаясь опубликовать что-то, отсюда и исчезновение.
Кайл Канос
перерывы при первом запуске без аргументов. Traceback (последний вызов был последним): файл "LexicographicBot \ LexicographicBot.py", строка 10, в <module> соперник = sys.argv [2] IndexError: список индексов вне диапазона
Eoin Campbell
@EoinCampbell: я забыл предложение о выходе при первом запуске, оно было добавлено и теперь должно работать нормально.
Кайл Канос
4

Веревулкан - Рубин

Беги как 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

Днем оборотень выглядит нормально, но когда восходит луна, уши становятся заостренными, а движения становятся более логичными.

histocrat
источник
4

Аналог - Рубин

Беги с ruby analogizer.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

  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

Предполагается, что бот-противник всегда реагирует на мой предыдущий ход и выбирает что-то, что побьет его, что-то, что может быть ему проиграно, или тот же ход, возможно, из ограниченного набора возможных ходов. Затем он выбирает лучший ход, учитывая это предположение.

За исключением того, что первые десять ходов жестко запрограммированы: сначала я притворяюсь, что знаю только ящерицу, затем я предполагаю, что мой оппонент всегда бросает что-то, чтобы побить последнее, что я бросил, пока у меня не будет достаточно данных для надлежащего анализа.

histocrat
источник
4

Java - SelfLoathingBot

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

Бот начинает случайным образом, затем ~ 33%, чтобы выбрать случайный, или ~ 33%, чтобы сыграть выигрышную тактику против любой из предшествующих игр, с 50% выбором выигрышной тактики.

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
источник
4

Аналитик

Аналитик анализирует некоторые вещи и делает некоторые вещи, чтобы попытаться победить вас.

скомпилировать javac Analyst.javaи запустить какjava 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
источник
4

Игрок - Питон 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)

Вопреки названию, в этой программе используется случайность только в первом раунде, когда нет информации. Вместо этого, он назван в честь заблуждения игрока, убеждения в том, что если случайное событие случалось реже в прошлом, оно более вероятно произойдет в будущем. Например, если вы подбрасываете честную монету 20 раз, а первые 15 - это головы, ошибка игрока указывает на то, что шансы оставшихся бросков, являющихся хвостами, увеличиваются. Конечно, это неправда; независимо от предыдущих бросков, шансы на выпадение хвоста у честной монеты всегда равны 50%.

Эта программа анализирует историю противника, находит 2 хода, которые она использовала меньше всего, и предполагает, что ход противника на этот раз будет одним из этих двух. Присвоив 2 победе, 1 ничьей и 0 проигрышу, он находит ход с максимальным счетом против этих двух предсказанных ходов и бросает его.

Брат игрока - Питон 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)

Переключив MODEпеременную на 0, эта программа будет работать на основе связанной ошибки, которая также иногда называется ошибкой игрока. В нем говорится, что если случайное событие происходило чаще в прошлом, оно более вероятно произойдет в будущем. Например, если вы подбрасываете монету 20 раз, а первые 15 - это головы, это заблуждение говорит о том, что оставшиеся броски с большей вероятностью будут головами, поскольку в настоящее время существует полоса. В режиме 0 эта программа работает аналогичным образом, за исключением того, что предполагается, что противник бросит один из двух ходов, которые он кидал чаще всего.

Так что да, эти две программы отличаются друг от друга. :)

undergroundmonorail
источник
При каких условиях TheGambler меняет режим?
Доктор Р Диззл
@DrRDizzle Это не так, похоже, что это представление двух ботов в одном.
Пауло Эберманн
2
Разве эта программа не будет более эффективной, если переключится режим, если вы проигрываете более определенного количества раз подряд?
Доктор Р. Диззл
4

Dienstag (Python 2)

Моя первая запись « Пони», кажется, вполне справляется со всеми ее вторыми догадками (тройным угадыванием, ...) и мета-рассуждениями. Но это даже необходимо?

Итак, вот Динстаг, маленький друг Пони, у которого есть только одна из 55 стратегий: предсказать следующий ход противника и одолеть его.

В долгосрочной перспективе Dienstag выигрывает или связывается с каждым ботом в первой десятке текущего списка лидеров. За исключением Пони.

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]

Беги как:

python Dienstag.py

Я признаю, что код немного запутан. Если кто-то захочет узнать больше об этом, я мог бы добавить объяснения.

Изменить: Вот краткое примерное руководство, чтобы объяснить идею:

  • Программа получает свою историю и ходы противника:

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

  • История объединяется в список пар, а ходы переводятся в числа (R = 0, ...):

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

  • Количество сыгранных раундов определяется:

    N = 7

  • Основная идея теперь состоит в том, чтобы искать самую длинную непрерывную цепочку точно из последних ходов в более ранней истории. Программа отслеживает, где такая цепочка заканчивается в списке cand(для «кандидатов»). В начале, без проверки, каждая позиция в истории, кроме последней, считается:

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

  • Теперь длина возможных цепочек увеличивается шаг за шагом. Для длины цепи l = 1он ищет предыдущие вхождения последней пары ходов [4, 1]. Это может быть найдено в истории позиции 1и 3. Только они хранятся в candсписке:

    cand = [1, 3]

  • Далее, для l = 2него проверяется, кому из возможных кандидатов предшествовала пара со второго до последнего хода [3, 2]. Это только случай для позиции 3:

    cand = [3]

  • Для l = 3и более не существует предыдущих цепочек такой длины и candбудет пустым. В этом случае candсохраняется последний элемент :

    cand = [3]

  • Теперь бот предполагает, что история повторится. В последний раз, когда [3, 2], [4, 1]произошел каин , за ним последовало [4, 2]. Итак, противник сыграл 2(ножницами), которых можно побить (2+1)%5 = 3(Споком) или (2+3)%5 = 0(камнем). Бот отвечает, с первой или второй альтернативой, в зависимости от того, Nявляется ли странным или даже просто ввести некоторую дисперсию.

  • Здесь 3выбирается ход, который затем переводится обратно:

    print 'V'

Примечание: Dienstag имеет временную сложность O ( N 2 ) для возврата следующего хода после N раундов. Пони имеет временную сложность O ( N 3 ). Так что в этом аспекте они, вероятно, намного хуже, чем большинство других записей.

Эмиль
источник
пожалуйста, сделай. Это потрясающий опыт обучения для меня. Я обычно живу на земле C # / Java, поэтому все безумие lua, ruby, python, haskell очень интересно для меня.
Эойн Кэмпбелл
Я также испытываю желание добавить дополнительный экземпляр Пони в игры. Это будет похоже на то, как нужно сражаться со своим зеркалом на 3-м и последнем уровнях Mortal Combat ;-)
Eoin Campbell
@EoinCampbell :-) По крайней мере прямой матч Пони против Пони был бы идеальной ничьей. Там нет элемента случайности в обоих моих ботов.
Эмиль
3

Баш скалы

Cygwin слишком много, чтобы спросить как время выполнения?

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 ]}

и запустить его так:

sh bashrocks.sh
mccannf
источник
5
Прочитав заголовок, я немного разочарован тем, что вы делаете что-либо кроме R. ;)
Мартин Эндер
@mccannf. возникли некоторые проблемы с этим ... Я установил cygwin и изменил ваши сценарии с полными путями к C: \ Cygwin \ bin для od.exe, xargs.exe & echo.exe. по-прежнему получаю следующую ошибку. C: / Cygwin / bin / xargs: echo: нет такого файла или каталога% 5 ") синтаксическая ошибка: ожидается операнд (ошибочный токен"
Eoin Campbell
@EoinCampbell - когда вы создаете файл в windows, можете ли вы запустить dos2unixфайл в cygwin перед его выполнением?
mccannf
конечно. Я попробую.
Эойн Кэмпбелл
Я думаю , что проблема может быть с / DEV / urandom заявления
Йон Кэмпбелл
3

Алгоритм

Алгоритм ради того, чтобы иметь один.

Потому что всегда безопаснее делать что-то, чем сложнее, тем лучше.

Еще не сделали какой-то серьезной математики, поэтому этот алгоритм может быть не таким эффективным.

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")

Программа Python 2: python algorithm.py

Векторизованное
источник
1
Краткое описание этого алгоритма: посмотрите, что в последний раз играл противник, а затем случайным образом разыграйте один из двух ходов, который проиграл бы против последнего хода противника, если бы он сыграл его снова. Так что лучше против ботов, которые не играют один и тот же ход дважды подряд.
Рори О'Кейн
Ха - ха. Я действительно не знаю, сделал ли я это так. Если я не ошибаюсь, это на самом деле просто запутанный способ случайного выбора любого из 5 ходов. ;)
Векторизовано
3

FairBot, Ruby

Давайте начнем с простого.

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

Беги как

ruby fairbot.rb
Мартин Эндер
источник
маленькая опечатка в последнем 'V' парам. исправил это на myside, если хочешь обновить для полноты
Eoin Campbell
@EoinCampbell спасибо, исправлено!
Мартин Эндер
1
Интересно то, что шансы на выигрыш против ВСЕХ стратегий равны.
Cruncher
3

ViolentBot

Этот бот выбирает наиболее жестокий вариант, основываясь на предыдущем выборе оппонентов:

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])

Беги как

python ViolentBot.py (me) (opp)
Кайл Канос
источник
ломается без параметров. Traceback (последний вызов был последним): файл "ViolentBot \ ViolentBot.py", строка 9, в <module> соперник = sys.argv [2] IndexError: список индексов вне диапазона
Эоин Кэмпбелл
разрывается с парам. Traceback (последний вызов был последним): файл "ViolentBot \ ViolentBot.py", строка 12, в <module> print (choice_dict [оппонент_last]) KeyError: 'S'
Эойн Кэмпбелл
@EoinCampbell: я добавил условие выхода для первого запуска, теперь вы сможете его запустить.
Кайл Канос
3

Haskell - MonadBot

Я не знаю, считается ли ghc «в пределах разумного», но давайте просто предположим, что это так. Стратегия этого бота заключается в противодействии наиболее популярному ходу противника.

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

Код:

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
источник