レオのポーカーフェイス


13

ポーカーフェース

前書き

レオはポーカーを楽しんでいますが、Tech Inc.での彼の仕事は、彼が上手にプレーする方法を学ぶことを要求しすぎています。コンピュータ科学者であるレオは落胆していません。彼はポーカーを学ぶために必要な時間よりも多くの時間を費やすことに決め、それを使ってポーカーボットを作成し、より良いプレーを支援します。しかし、今レオには問題があります:少し上手にプレイする方法を理解するために、レオは複数の「人」の複数のゲームを観察する必要がありますが、「人」はゲームの品質と現実を改善するために異なるプレイスタイルを必要とします。

チャレンジ

レオは、実際にプログラミングの課題に特化したウェブサイトがあり、あなたの助けを募集していることを思い出します!あなたの仕事は、修正版の5カードポーカー「Pokerface」をプレイするプログラムを書くことです。プログラムは、希望する形式で5カードの手として入力を受け取り、その後、プログラムは出力します。

  • プレーヤーがカードを交換する場合は、正確に(大文字と小文字を区別する) "true" "1"または "t"、その他の場合は空でない他の出力。
  • trueの場合、プレーヤーが交換したいカードのインデックスおよび/またはカード名のリスト。
  • プレーヤーが必要とする追加のカードの数を指定する0〜3の単一の数値。
  • プレーヤーが使用したい手を印刷します。

(以下のフォーマットを参照)

ポーカーフェイスのルール

  • pokerfaceはテキストベースのアドベンチャーゲームであるため、カードは一貫した方法で提示する必要があります。カードは2つの文字コードで表され、最初の文字はスーツ、2番目の文字はカードの名前です。
    • カード:
      • 2-9 = 2-9
      • 10 = T
      • ジャック= J
      • クイーン= Q
      • キング= K
      • エース= A
    • スーツ:
      • スペード= S
      • クラブ= C
      • ハート= H
      • ダイヤモンド= D

したがって、スペードのエースはSA、ハートの10はHT、ダイヤモンドの4番目はD4などになります。

  • Pokerfaceの1ラウンドは4つのステップで構成されています。
    • デッキがシャッフルされ、各プレイヤーに5枚のカードが配られます。
    • 各プレイヤーには、好きなだけカードを交換する機会が与えられます。
    • 各プレイヤーには、最大3枚のカードを獲得する機会が与えられます。
    • 各プレイヤーはベストハンドを公開する必要があります。
  • 最高のハンドが勝ち、そのプレーヤーにポイントを獲得します。同点の場合、両方のプレイヤーがポイントを獲得します。
  • 単一のゲームでは、10ラウンドがプレイされ、最もポイントの多いプレーヤーが勝ち、単一の「勝ち点」を獲得します。同点の場合、両方のプレイヤーが勝利ポイントを獲得します。
  • レオには実際には多額のお金がないので、ボットはこれが賭けのない完璧な世界であると想定できます。

  • 手の長さは正確に5枚です(初期入力と最終出力)。
  • 手はここで説明さた規則と一致してランクされます

入出力

  • LeoはJavaのみを知っているため、プログラムはProcess API(コマンドライン)を介して実行可能で、入力と出力にそれぞれSTDINとSTDOUTを使用する必要があります。
  • 上記の入力および出力の各ステップでは、入力と出力がそれぞれ1行に存在する必要があります。
  • 最終出力の後に、少なくとも1つの末尾の改行がなければなりません。(これは、入力がSTDINから読み取られる方法によるものです)
  • 後続スペースと先行スペース以外の、外部からの入出力は許可されません。パーサーは単にfinal_hand=...やなどのことを理解しませんdraw 0
  • 描画の場合、出力は単一の整数であり、出力の交換は以下で定義される整数および/またはカードのリストであり、元のハンドが配られる場合、出力は以下で定義されるカードのリストです。
  • すべての入力/出力番号は、基数10の正の整数でなければなりません。
  • カード入力の形式を定義できます(以下の投稿形式を参照)。
  • trueは正確に「true」、「1」または「t」として定義され、falseは他の空でない値です。
  • 交換ステップ中:
    • カードインデックスは、少なくとも1つのスペースを空けて出力する必要があります(例3 4 0
    • カード名は、少なくとも1つのスペースを空けて出力する必要があります(例H4 S8
    • カード名とインデックスが出力に混在する場合があります(例0 H7 3 D3
    • 末尾と先頭のスペースは許可されます。
    • 上記を出力するプレーヤーの結果としての入力は、bot.jlsc要求されたのと同じ順序で、ファイルで指定されたとおりにフォーマットされます
  • プレーヤーが自分の手に追加したいカードの数には、先頭と末尾のスペースがあります。
  • 手は少なくとも1つのスペース(例:)で出力する必要がありますH4 D5 CA。末尾のスペースと先頭のスペースは許可されます。
  • 手は適切な順序で出力する必要はありません(例H4 D4 C4 DA SAH4 DA D4 SA C4両方とも4、4、4、エース、エース、フルハウスを表します)。
  • 対戦相手の手を分析して戦略を構築する場合、<botname>/dataディレクトリにデータを保存できます。
    • 競合するボットが手を表示した後、それらはすべてのボットデータディレクトリのhands.txtに書き込まれ、各ハンドは新しい行(\ nで区切られます)に置かれます。ファイルはUS_ASCIIでエンコードされます。
  • ボットが新しいカードを要求するか、カードを交換すると、bot.jlscファイルで指定した形式に応じてカードが入力されます。

投稿フォーマット

  • すべての投稿には次の2つを含める必要があります。
    • ボットのソースコード、または公開リポジトリへのリンク。
    • 以下を含むzipファイル:
      • ボットのコンパイル済み/実行可能バージョン(ファイルが.exeまたはその他の非コンパイル可能ファイルである場合は、投稿にコンパイルの指示を含めてください)。
      • bot.jlscファイルは、下記(サイドノート:.jlsc拡張子が理由だけで私のサイドプロジェクト、コンフィギュレーション・フォーマットであるマッチ下記のファイル適切な構文を、それほど心配しないでください。)を参照してください。
    • .zipファイルには、ボットと同じ名前を付ける必要があります。
  • Windowsやその他の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>にあることに注意してください。したがって、それに応じてコマンドを調整してください。
  • 「名前」はボットの名前です。
  • 「リンク」は回答へのリンクです。投稿後に編集する必要があります。
    • 「input_hand」は、元の取引をフォーマットする方法です($ {#}はカード0〜4を表します)。
  • 「input_1」は、追加のカードの入力をフォーマットする方法です。
  • 「input_2」は、追加の2枚のカードの入力をフォーマットする方法です。
  • 「input_3」は、追加の3枚のカードの入力をフォーマットする方法です。
  • 「input_4」は、追加の4枚のカードの入力をフォーマットする方法です。

仕様

  • これらの抜け穴は許可されていません(「よくある落とし穴」を参照)
  • ルールセット内で、常に可能な限り最高のハンドを常に出力するボットを作成することはできません。(つまり、長時間実行されるブルートフォースボットはありません。LeoBotほど「良い」ものはありません)
  • ボットは〜100ミリ秒以下で実行する必要があります(この時点での制限は、最大〜1秒です)
  • 選択したハンドの後のボットの出力は無視されます。
  • 標準の抜け穴は許可されていません。
  • はい、Linuxの方が優れていることはわかっていますが、Windows PCを使用しているので、プログラムのコンパイル済み/実行可能バージョンがWindowsコマンドラインから実行できることを確認してください。
    • 既にコンピューターにpythonとjavaがインストールされていますが、新しいバージョンに更新して他の環境をインストールすることもできますので、プログラムに必要な環境のタイプを指定してください。
  • あらゆる場合に別のボットと同じことを行うボットを書くことはできません。スパムボットは許可されますが、推奨されません。
  • ボットは、所有しているカードのみを使用できます。交換によって失われたカード、または最初に対処されなかったカードは、最終ハンドでの無効な出力です。
  • 入出力にはASCII文字のみを含めることができます。

トーナメント

  • 時間があるときにトーナメントが開催されます(私のスケジュールはLeoのスケジュールとほぼ同じなので、これは少し頻繁ではありません。ご不便をおかけして申し訳ありません。)
  • ボットは4人のゲームで互いに対戦し、ボットの可能なサブセットごとに1つのゲーム(つまり、多くのゲーム)があります。
    • このプロセスは5回繰り返されます。
    • トーナメントハンドラーがボットのグループを作成する方法により、最大3つのフィラーボットが追加され、ボットの数を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.はストーリー要素であり、現実の企業や人々との類似点は純粋に意図的なものではありません。(ただし、Leoの「状況」が質問に条件を追加または削除する場合、それらは実際には質問の一部です...)


1
@SocraticPhoenix重み付けすることを強くお勧めします。提出が既にランク付けされた後にスコアを調整することは、プレーヤーにとって本当に不公平です。
ネイサンメリル

2
@DestructibleWatermelonの方が良いですか?ちなみに、これは2〜3日間サンドボックスで行われました...誰もコメントしませんでした。私が意味する、それはかかわらず、すべてのクールだ
ソクラテスのフェニックス

2
また、@ NathanMerrillは、おそらくダムボットの勝利についてはまだ正しいでしょう。cjam somwhatを調査した後、5バイトのプログラムは"f"q+最小要件を満たしています。競争相手が10人の場合、これはおそらくすべての非ダムエントリを破ります(非ダムエントリはおそらく75文字以上、5 * 10(ダムボットのスコア、最後に来る)= 50 <75(非常に小さなスマートボットのスコア) (最初に来る)))。したがって、おそらくこのチャレンジからcodegolfを削除する必要があります
Destructible Lemon

2
Cjamを使用できない場合でも、ダンボットは合理的な戦略になるという点があり、codegolfを削除することで、サイズとパフォーマンスのバランスをとるというすべての困難が解消されます
Destructible Lemon

1
死に殺さコードゴルフ....
ソクラテスのフェニックス

回答:


1

(Python)、Pairbot、競合していません(cmdコマンドなどの作成方法がわかりません)

ペアボットは、誰かがbot.jlscやzipファイルなどを支援するとすぐに競争します。


ペアボットは、あなたが常に良いハンドを得るとは限らないことを知っています。彼は良い手がまれであることを知っています。ペアボットはペアを知っており、他の複製は最高のハンドの一部です。ペアボットはまた、あなたが得ることができる最低ハンドが7ハイであることを知っているので、彼は彼が6ハイを持っているかどうかを知っています、それは実際にストレートです(ペアボットは彼がそれを知っている理由を知りません)。彼はまた、自分の最低カードが10である(ペアがない)かどうか、それがストレートであることも知っています(ペアボットはこの方法でロイヤルフラッシュを獲得できることを知っています)。Pairbotは、主に同じ数の重複をチェックしますが、特別な場合には2種類のストレートもチェックします。

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

入力の形式は、例と同じです:スペースで区切られます


ソクラティックフェニックスがファイルを支援できるなら、それは良いことです


賢い!あなたがたいと思うファイルがあるので、ここでは、私が...実際の.zipファイルのオプションを作るために編集する主なポストに行くんだ
ソクラテスのフェニックス

また、FGITWの+1
ソクラ

FGITLOSG(スローガンの土地で最速のガン)に似ています。
破壊可能なレモン

本当です。入力/出力が適切な形式であるかどうかはわかりません。私がハンドを入力すると、プログラムは「True」をプリントしてから、現在のハンドをプリントします。「True」はカードを交換することを示しているため、「false」を印刷するだけでよいと思います。次に、プログラムは描画時に単一の整数、または交換時にスペースで区切られた整数を出力する必要があります。「0を描画しない」。メインポストを明確にしようとします。
ソクラティックフェニックス

[だから、今は競合しているとみなされますか?]新しいメッセージは表示されませんでした。ボットをすぐに修正します
Destructible Lemon

1

配管工、Python

配管工は、フラッシュに関するすべてです。配管工は、より価値の高いカードも優先します(特に王室の場合は、特にフラッシュが発生する可能性があることを意味します)。Sherlock9による計算が正しい場合、配管工は約20%の時間でフラッシュを取得します。

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

また、他の私の2つのボットのようにスペースで区切られた入力を受け取ります


注:自分のトーナメントプログラムのバグのため、出力ルールをわずかに変更しました。これで、最終出力の後に少なくとも1つの末尾の改行がなければなりません。
ソクラティックフェニックス

1

LadyGaga、Python 3

  • スーツにやや盲目
  • 虫だらけのドレスを着ている
  • 時々Poker Faceをプレイするのが好きです

    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をモデル化-編集:破壊可能なスイカによる広範なバグ修正-編集:新しいルールにより、最終出力後の改行

カードの値に複雑なものの代わりに辞書を使用したい場合があります
Destructible Lemon

配列に詰め込まれたものは、すでに私の知る限りのものです。コードのどのセクションを短縮できますか?
マゼンタ

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)]) to 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のみだけ長くあなたのプログラムよりも、それが読めるだからです
破壊可能なレモン

知っている。悪いcodegolfing習慣。
マゼンタ

0

LuckyBot、Python

ペアボットは相棒のラッキーボットを招待しました。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])
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.