Leo's Pokerface


13

Морда кирпичом

Вступление

Лео нравится играть в покер, но его работа в Tech Inc. слишком сложна, чтобы научиться хорошо играть. Лев, будучи специалистом по информатике, не унывает. Он решает потратить больше времени, чем просто учиться покеру, и использовать его, чтобы написать покерного бота, чтобы помочь ему играть лучше. Но теперь у Лео есть проблема: чтобы понять, как играть немного лучше, Лео нужно наблюдать за несколькими играми нескольких «людей», но «людям» нужны разные стили игры, чтобы улучшить качество и реальность игры.

Соревнование

Лео вспоминает, что на самом деле есть сайт, посвященный программированию, и заручается вашей помощью! Ваша задача - написать программу, которая играет в «Pokerface» модифицированную версию 5-карточного покера. Программа примет ввод в виде 5-карточной раздачи в любом формате, который вы пожелаете, после чего программа выведет:

  • Точно (с учетом регистра) "true", "1" или "t", если игрок хочет обменять карты, любой другой непустой вывод в противном случае.
  • Если это правда, список индексов карт и / или названий карт, которые игрок хочет обменять.
  • Одно число от 0 до 3, которое указывает, сколько дополнительных карт хочет игрок.
  • Распечатайте руку, которую игрок хочет использовать.

(См. Форматирование ниже)

Правила покера

  • Поскольку pokerface - это текстовая приключенческая игра, карты должны быть представлены в согласованном порядке. Карты представлены двумя кодами символов, первый символ - масть, а второй - название карты.
    • Карты:
      • 2-9 = 2-9
      • 10 = Т
      • Джек = J
      • Королева = Q
      • Кинг = К
      • Ace = A
    • Костюмы:
      • Пики = S
      • Клубы = C
      • Hearts = H
      • Алмаз = D

Таким образом, пиковым тузом будет SA, 10 червей - HT, 4-й бриллиант - D4 и т. Д.

  • Один раунд Pokerface состоит из четырех этапов:
    • Колода перетасовывается, и каждому игроку раздается пятикарточная комбинация.
    • Каждому игроку предоставляется возможность обменять столько карт, сколько они захотят.
    • Каждому игроку предоставляется возможность получить еще три карты.
    • Каждый игрок должен показать свою лучшую руку.
  • Лучшая рука выигрывает и получает этому игроку очко. В случае ничьей оба игрока получают очко.
  • В одной игре разыгрывается десять раундов, и игрок, набравший наибольшее количество очков, выигрывает и получает одно «очко победы». В случае ничьей оба игрока получают выигрышное очко.
  • У Лео на самом деле нет большой суммы денег, поэтому ваш бот может предположить, что это идеальный мир без ставок.

Руки

  • Руки составляют ровно 5 карт (начальный ввод и окончательный вывод).
  • Руки ранжируются в соответствии с правилами, описанными здесь .

Ввод, вывод

  • Лев знает только Java, поэтому ваша программа должна быть исполняемой через Process API (командную строку) и использовать STDIN и STDOUT для ввода и вывода соответственно.
  • Для каждого шага ввода и вывода, описанного выше, вход и выход должны находиться в одной строке.
  • После окончательного вывода должна быть хотя бы одна завершающая новая строка. (Это связано со способом чтения ввода из STDIN)
  • Никакой посторонний ввод / вывод не допускается, кроме конечных и начальных пробелов. Парсер просто не понимает таких вещей, как final_hand=...или draw 0.
  • При рисовании выводом является одно целое число, когда обмен выводом представляет собой список целых чисел и / или карт, определенных ниже, а при раздаче исходной руки, вывод представляет собой список карт, определенных ниже.
  • Все числа ввода / вывода должны быть положительными целыми числами в базе 10.
  • Вы можете определить формат для ввода карты (см. Формат сообщения ниже).
  • True определяется как «true», «1» или «t», а false - это любое другое непустое значение.
  • На этапе обмена:
    • Индексы карт должны быть выведены с хотя бы одним пробелом между ними (например 3 4 0)
    • Имена карт должны быть выведены с хотя бы одним пробелом между ними (например H4 S8)
    • Имена карт и индексы могут быть смешаны в выводе (например 0 H7 3 D3)
    • Трейлинг и ведущие пробелы разрешены.
    • Ввод данных в результате вывода проигрывателем вышеупомянутого будет отформатирован, как указано в bot.jlscфайле, в том же порядке, что и запрошенный
  • Количество карт, которые игрок хочет добавить в свою руку, может иметь пробелы в начале и в конце.
  • Руки должны быть выведены, по крайней мере, с одним пробелом между ними (например H4 D5 CA), допускаются завершающие пробелы и начальные пробелы.
  • Руки не должны быть выведены в правильном порядке (например, H4 D4 C4 DA SAи H4 DA D4 SA C4обе представляют 4, 4, 4, туз, туз, который является фулл-хаусом).
  • Если вы хотите построить стратегию, анализируя руки оппонентов, вы можете хранить данные в <botname>/dataкаталоге.
    • После того, как конкурирующие боты отобразят свои руки, они будут записаны в каждый каталог данных ботов, в hands.txt, с каждой рукой в ​​новой строке (разделенной \ n). Файл будет закодирован в US_ASCII.
  • После того, как ваш бот запросит новые карты или обменные карты, карты будут введены в зависимости от того, какой формат вы указали в bot.jlscфайле.

Формат сообщения

  • Каждый пост должен включать две вещи:
    • Исходный код вашего бота или ссылка на общедоступный репозиторий.
    • ZIP-файл, содержащий:
      • Скомпилированная / исполняемая версия вашего бота (если это файл .exe или другой некомпилируемый файл, пожалуйста, просто включите инструкции по компиляции в ваш пост).
      • bot.jlscФайл, смотрите ниже (сторона примечание: .jlsc расширение только из сайд - проекта шахты, формат конфигурации Файл ниже спичек правильный синтаксис, так что не беспокойтесь.).
    • Файл .zip должен называться так же, как ваш бот.
  • Если у вас нет доступа к окнам или какой-либо другой утилите архивации, или вы по какой-либо причине не можете создать .zip, просто включите в свой пост текст файла bot.jlsc.

файл bot.jlsc:

name= "Botty"
link= "example.com"
cmd= "java -jar Botty.jar"
input_hand= "${0} ${1} ${2} ${3} ${4}"
input_1= "${0}"
input_2= "${0} ${1}"
input_3= "${0} ${1} ${2}"
input_4= "${0} ${1} ${2} ${3}"

Где:

  • «cmd» - это команда командной строки Windows для запуска вашего бота. Обратите внимание, что ваш бот будет в каталоге <botname>, поэтому настройте команду соответствующим образом.
  • «name» - это имя вашего бота.
  • "ссылка" - это ссылка на ваш ответ, вам нужно будет отредактировать ее после публикации.
    • «input_hand» - это то, как вы хотите, чтобы оригинальная раздача была отформатирована (с $ {#}, представляющим карточки 0-4).
  • «input_1» - это то, как вы хотите отформатировать ввод одной дополнительной карты.
  • «input_2» - это способ форматирования ввода двух дополнительных карточек.
  • «input_3» - это способ форматирования ввода трех дополнительных карточек.
  • «input_4» - это способ форматирования ввода четырех дополнительных карточек.

конкретика

  • Эти лазейки запрещены (см. «Общие ловушки»)
  • Вы не можете написать бота, который всегда будет выдавать лучшую возможную руку, каждый раз, в пределах набора правил. (т.е. никаких длительных ботов-ботов, ничто не должно быть столь же «хорошим», как LeoBot)
  • Ваш бот должен работать в течение ~ 100 мс или меньше (в этот момент не более 1 секунды)
  • Любой вывод бота после выбранной руки будет игнорироваться.
  • Стандартные лазейки запрещены.
  • Да, я знаю, что Linux лучше, но у меня Windows-ПК, поэтому убедитесь, что скомпилированную / исполняемую версию вашей программы можно запустить из командной строки Windows.
    • На моем компьютере уже установлены python и java, но я хочу обновиться до новых версий и установить другие среды, поэтому, пожалуйста, укажите, какой тип среды требует ваша программа.
  • Вы не можете написать бота, который делает то же самое, что и другой бот в каждом случае. Спам-боты разрешены, но не приветствуются.
  • Ваш бот может использовать только те карты, которые у него есть. Карты, утерянные в результате обмена или не сданные для начала, являются недействительными на выходе в последней раздаче.
  • Вход и выход могут содержать только символы ASCII.

Турниры

  • Турниры будут проводиться, когда у меня будет время (мое расписание почти такое же плотное, как у Лео, так что это может быть немного нечастым. Приносим извинения за неудобства.).
  • Боты будут противостоять друг другу в играх на 4 человека, и будет по одной игре на каждое возможное подмножество ботов (то есть множество игр).
    • Этот процесс будет повторяться пять раз.
    • Из-за способа, которым обработчик турнира формирует группы ботов, будет добавлено до трех ботов-наполнителей, чтобы количество ботов делилось на 4. Эти боты просто вернут руку, с которой они были изначально разыграны.
  • После каждого раунда и запуска игры очки ботов будут рассчитываться на основе количества выигранных игр.
    • Множество ботов могут разделять позиции (связи для первого победителя с первым опубликованным).
  • После окончания турнира результаты будут добавлены в конец этого поста.

счет

Нормальные правила KoTH. Бот (ы), которые выигрывают в большинстве игр, выигрывают вызов.

LeoBot

Бот Лео довольно умен. Он не обменивает карты, это слишком сложно, но он запрашивает максимальное количество дополнительных карт, определяет наилучшую возможную руку и разыгрывает эту руку. Основная логика леобота ниже.

package com.gmail.socraticphoenix.pokerface.leobot;

import com.gmail.socraticphoenix.pokerface.lib.card.Card;
import com.gmail.socraticphoenix.pokerface.lib.card.Deck;
import com.gmail.socraticphoenix.pokerface.lib.rule.HandRegistry;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class LeoBot {

    public static void main(String[] args) {
        List<Card> hand = new ArrayList<>();

        Scanner scanner = new Scanner(System.in);
        hand.addAll(Card.parseHand(scanner.nextLine()));
        System.out.println(false);

        System.out.println(3);
        hand.addAll(Card.parseHand(scanner.nextLine()));

        List<List<Card>> possibleHands = LeoBot.getSubsets(hand, 5);
        System.out.println(Deck.toString(possibleHands.stream().sorted((a, b) -> HandRegistry.determineWinner(b, a).comparable()).findFirst().get()));
    }

    private static <T> void getSubsets(List<T> superSet, int k, int idx, List<T> current, List<List<T>> solution) {
        if (current.size() == k) {
            solution.add(new ArrayList<>(current));
            return;
        }
        if (idx == superSet.size()) return;
        T x = superSet.get(idx);
        if (!current.contains(x)) {
            current.add(x);
        }
        getSubsets(superSet, k, idx + 1, current, solution);
        current.remove(x);
        getSubsets(superSet, k, idx + 1, current, solution);
    }

    public static <T> List<List<T>> getSubsets(List<T> superSet, int k) {
        List<List<T>> res = new ArrayList<>();
        getSubsets(superSet, k, 0, new ArrayList<T>(), res);
        return res;
    }

}

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

Важные ссылки

отказ

Leo и Tech Inc. являются элементами истории, и любое сходство с реальными компаниями или людьми является чисто непреднамеренным. (Однако, когда «ситуация» Лео добавляет или вычитает условия из вопроса, они фактически являются частью вопроса ...)


1
@SocraticPhoenix Я бы настоятельно рекомендовал взвешивать это сейчас или никогда. Игрокам было бы несправедливо корректировать счет после того, как представление уже занято.
Натан Меррилл

2
@DestructibleWatermelon лучше? Просто к вашему сведению, это было в песочнице 2-3 дня ... Никто не прокомментировал. Я имею в виду, это все круто, хотя
Сократик Феникс

2
Кроме того, @NathanMerrill, вероятно, все еще прав насчет победы тупого бота. После изучения cjam, 5-байтовая программа "f"q+удовлетворяет минимальным требованиям. Если в соревновании участвуют 10 человек, это, вероятно, превосходит все нематериальные записи (в нематурной записи, вероятно,> 75 символов, 5 * 10 (оценка немого бота, идущего последним) = 50 <75 (оценка очень маленького умного бота). (впереди))). Таким образом, вы, вероятно, должны удалить Codegolf из этого испытания
Разрушаемый Лимон

2
даже если Cjam не может быть использован, точка зрения гласит, что гантели будут разумной стратегией, а удаление Codegolf устраняет все трудности с балансировкой производительности по сравнению с размером
Destructible Lemon

1
Убит код-гольф до смерти ....
Сократов Феникс

Ответы:


1

(Python), Pairbot, не совсем конкурирующий (я не знаю, как создавать команды cmd и прочее)

Pairbot будет соревноваться, как только кто-то поможет с bot.jlsc, zip-файлами и т. Д.


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

card_values={"2":2, "3":3, "4":4, "5":5, "6":6, "7":7, "8":8,
             "9":9, "T":10, "J":11, "Q":12, "K":13, "A":14,}
straight=False
def card_valuing(item):
    return card_values[item[1]]

input_list=input().split()
pairs_to_keep=[]
for item in input_list:
    if sum(item[1]==card[1] for card in input_list)>1:
        pairs_to_keep+=[item]
cards_to_remove=input_list
for item in pairs_to_keep:cards_to_remove.remove(item)#we want to remove all non pairs
hand=pairs_to_keep
if pairs_to_keep==[]:
    input_list.sort(key=card_valuing, reverse=True)
    if card_values[input_list[0][1]]==6:
        straight=True
        hand=input_list
    elif card_values[input_list[-1][1]]==10:
        straight=True
        hand=input_list
    else:
        print("true\n"+" ".join(input_list[1:]))
        hand+=input_list[0]+input().split()
elif input_list!=[]:
    print("true\n"+" ".join(input_list))
    hand+=input().split()
else:print(0, end=', ')
if straight:print("0\n0\n"+" ".join(hand))
else:
    print("3")
    hand+=input().split()
    same_number_dict={} #holds the amount of each type (A, 2, 3, etc.)

    def dict_value(item):
        return int(same_number_dict[item[1]])*100+card_values[item[1]]

    for card in hand:
        same_number_dict[card[1]]=sum(card[1] == item[1] for item in hand)

    hand=list(sorted(hand, key=dict_value, reverse=True))
    final_hand =[]
    last_number=hand[0][1]
    hand_taken=0
    while hand_taken < 5:
        if last_number==hand[0][1]:
            final_hand+=[hand[0]]
            hand=hand[1:]
            hand_taken+=1
        else:
            for card in hand:
                if same_number_dict[card[1]]>5-hand_taken:
                    same_number_dict[card[1]]=5-hand_taken
            hand=list(sorted(hand, key=dict_value, reverse=True))
            last_number=hand[0][1]
    print(" ".join(final_hand))

Формат ввода такой же, как в примере: разделены пробелами


Если бы Socratic Phoenix мог помочь с файлами, это было бы хорошо


Умная! Итак, файл, который вам нужен, находится здесь , я собираюсь отредактировать основной пост, чтобы сделать фактический .zip необязательным ...
Socratic Phoenix

Кроме того, +1 за FGITW
Сократов Феникс

Больше похоже на FGITLOSG (самая быстрая пушка в стране медленных пушек).
Разрушаемый лимон

Правда. Я не уверен, что ввод / вывод в правильной форме. Когда я ввожу руку, программа печатает «True», а затем свою текущую руку. Я полагаю, что вы хотите просто напечатать «false», так как «True» означает, что вы хотите обменять карты. Во-вторых, программе необходимо печатать одно целое число при рисовании или целые числа, разделенные пробелами при обмене. Не "рисуй 0." Я постараюсь уточнить основной пост.
Сократов Феникс

[Так значит ли это, что он конкурирует сейчас?] Не видел новых сообщений. Я исправлю бот прямо сейчас
Разрушаемый Лимон

1

Сантехник, Питон

Сантехник это все о приливах. Сантехник также отдает приоритет картам с более высокой стоимостью (это означает, что он может иногда получать стрит-флеши, особенно королевские (если они случаются)). Сантехник в значительной степени испорчен, если он не получает флеш, за исключением того, что ему может повезти на стрите. Сантехник получит приливы примерно в 20% случаев, если расчеты Шерлока9 верны

hand=input().split()
suit_in_hand={"S":0,"C":0,"D":0,"H":0}
card_values={"2":2, "3":3, "4":4, "5":5, "6":6, "7":7, "8":8,
             "9":9, "T":10, "J":11, "Q":12, "K":13, "A":14,}
def value_sort(x):
    return card_values[x[1]]
def suit_sort(x):
    return suit_in_hand[x[0]]

for card in hand:
    suit_in_hand[card[0]]+=1

hand.sort(key=suit_sort, reverse=True)

print(" ".join(hand[suit_in_hand[hand[0][0]]:]))
hand=hand[:suit_in_hand[hand[0][0]]]

for new_card in input().split():
    hand+=[new_card]
    suit_in_hand[new_card[0]]+=1

print(3)

for new_card in input().split():
    hand+=[new_card]
    suit_in_hand[new_card[0]]+=1
hand.sort(key=value_sort, reverse=True)
hand.sort(key=suit_sort, reverse=True)
print(" ".join(hand[:5]))

Также принимает ввод, разделенный пробелами, как другие мои два бота


Примечание: я немного изменил правила вывода из-за ошибки в моей собственной турнирной программе. Теперь должна быть хотя бы одна завершающая новая строка после вашего окончательного результата.
Сократов Феникс

1

LadyGaga, Python 3

  • Несколько слеп к костюму
  • Имеет платье, полное ошибок
  • И любит играть в Покер Лицо время от времени

    from math import ceil as f
    M=lambda A:max(set(A),key=A.count)
    K=lambda A:A.count(M(A))
    O=lambda A:range(len(A))
    J=lambda A:A[0]+str(U(A[1]))
    X={"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9,"T":10,"J":11,"Q":12,"K":13,"A":14}
    def V(A):return([A[0]]+[int(X[A[1]])])
    def U(c):
     if c==10:c='T'
     if c==11:c='J'
     if c==12:c='Q'
     if c==13:c='K'
     if c==14:c='A'
     return(c)
    def P(A):
     S=[];C=[];t=len(A)
     for x in A:S.append(x[0]);C.append(x[1])
     B=[0]*9;q=len(set(C));p=K(C);D=list(set(C));D.sort()
     B[2]=1/f(13**(4-p));B[6]=1/f(13**(3-p));B[8]=1/f(13**(2-p))
     if (p,q)==(2,4):B[3]=1/1100;B[7]=5/34
     if (p,q)==(3,3):B[3]=1/169;B[7]=1/169
     if (p,q)==(4,2):B[3]=1/13;B[7]=1
     if (p,q)==(2,3):B[3]=5/169;B[7]=1
     if (p,q)==(3,2):B[3]=1;B[7]=1
     for x in O(D):D[x]-=x
     j=M(D);h=K(D)-5;B[5]=13**h
     for x in O(D):
      if j+h<D[x]<j-h and D[x]!=j:B[5]*=13
     W=K(S);B[4]=(4**(W-t))*(13-W)/52
     return(B,M(S))
    def E(B,h,u):
     x=0;D=[];C=[]
     while 1:
      k=list(C)
      C=[]
      while 1:
       p=list(B);del p[x]
       if len(D)==3:break
       if P(p)[0][h]>=P(B)[0][h]:C.append(B[x])
       x+=1
       if x>len(p):break
      if len(C)==0:break
      for x in O(C):
       if k==C or not((u in C[x])and(len(C)-1)):D.append(C[x]);del B[B.index(C[x])]
     return(D)
    s=input()
    A=s.split(' ')
    b=list(map(V,A));G,u=P(b);F=[649739,72192,4164,693,508,254,46.3,20,1.4];H=[]
    for x in O(F):F[x]=1-((1-(1/F[x]))**4)
    for x in O(F):H.append(G[x]-F[x])
    Y=H.index(max(H));p=[]
    e=E(list(b),Y,u);g=list(e)
    for x in O(e):e[x]=J(e[x])
    print(' '.join(e)if len(e)else'')
    for x in g:
     if x in b:del b[b.index(x)]
    s=input()
    if len(s):
     A=s.split(' ')
     b+=list(map(V,A))
    print(3)
    s=input()
    A=s.split(' ')
    b+=list(map(V,A));G,u=P(b);H=[]
    for x in O(F):H.append(G[x]-F[x])
    Y=H.index(max(H))
    e=E(list(b),Y,u)
    for x in e:
     if x in b:del b[b.index(x)]
    for x in O(b):b[x]=J(b[x])
    print(' '.join(b[:5]))
    print()
    
    • (I / O), смоделированный после PlumberBot -Edit: обширные исправления ошибок благодаря Destructible Watermelon -Edit: из-за новых правил, завершающий символ новой строки после окончательного вывода

Вы могли бы хотеть использовать словарь вместо всего этого сложного материала для значений карты
Разрушаемый Лимон

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

def V(A): b=[A[0]];c=A[1] if c=='T':c=10 if c=='J':c=11 if c=='Q':c=12 if c=='K':c=13 if c=='A':c=14 return (b + [int(c)]) в x={"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9,"T":10,"J":11,"Q":12,"K":13,"A":14,} def V(A):return(A[0] + x[A[1]])
Разрушаемый Лимон

Pairbot только дольше, чем ваша программа, и это потому, что он доступен для чтения
Destructible Lemon

Я знаю. Плохие привычки в кодогольфинге.
Пурпурный

0

LuckyBot, Python

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


lucky_number=24 #IMPORTANT

from random import randint as roll


def lucky_shuffle(i):
    return sorted(i, key=lucky_dice)


def lucky_dice(seed):
    return sum(roll(1,6)for i in range(roll(1,6)))


hand=lucky_shuffle(input().split())

throw=lucky_dice(lucky_number)%5
print("true\n"+" ".join(hand[throw:]))

hand=hand[:throw]+lucky_shuffle(input().split())

hand=lucky_shuffle(hand)
hand=lucky_shuffle(hand)
#One more for good luck
hand=lucky_shuffle(hand)
#maybe one more
hand=lucky_shuffle(hand)
#I got a good feeling about this one
hand=lucky_shuffle(hand)

hand=lucky_shuffle(hand)
#I think I'm done
hand=lucky_shuffle(hand)
#for real this time


hand=lucky_shuffle(hand)

print("3")
hand=hand+lucky_shuffle(input().split())
#All right, I got a real good feeling about this,
#let me shuffle some more luck into them cards!


def extra_super_lucky_shuffle(item):
 return lucky_shuffle(lucky_shuffle(lucky_shuffle(\
    lucky_shuffle(lucky_shuffle(lucky_shuffle(\
        lucky_shuffle(lucky_shuffle(lucky_shuffle(item)))))))))


def super_duper_extra_ultra_uber_luckyshuffle(item):
    return extra_super_lucky_shuffle(extra_super_lucky_shuffle(\
        extra_super_lucky_shuffle(extra_super_lucky_shuffle(item))))


hand=super_duper_extra_ultra_uber_luckyshuffle(super_duper_extra_ultra_uber_luckyshuffle(hand))
#cmoooooooooooooooon
print(hand[:5])
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.