狮子座的扑克脸


13

扑克脸

介绍

Leo喜欢玩扑克,但是他在Tech Inc.的工作要求他学习如何打法。不反对作为计算机科学家的Leo。他决定花更多的时间来学习扑克,并用它编写一个扑克机器人来帮助他玩得更好。但是现在,狮子座遇到了一个问题:为了了解如何更好地玩游戏,狮子座需要观察由多个“人物”组成的多个游戏,但是“人物”需要不同的游戏风格来提高游戏的质量和真实性。

挑战

Leo回忆说,实际上有一个致力于编程挑战的网站,正在寻求您的帮助!您的工作是编写一个程序,玩“ Pokerface”(五张扑克)的修改版。该程序将以您希望的任何格式将其输入为5张牌,然后程序将输出:

  • 如果玩家希望交换纸牌,则完全(区分大小写)为“ true”,“ 1”或“ t”,否则为任何其他非空输出。
  • 如果为true,则显示玩家希望交换的卡片索引列表和/或卡片名称。
  • 0到3之间的一个数字,指定玩家需要多少张额外的纸牌。
  • 打印出玩家希望使用的手。

(请参见下面的格式)

扑克规则

  • 由于pokerface是基于文本的冒险游戏,因此必须以一致的方式提供卡片。卡用两个字符代码表示,第一个字符是西服,第二个字符是卡的名称。
    • 牌:
      • 2-9 = 2-9
      • 10 = T
      • 杰克= J
      • 皇后= Q
      • 国王= K
      • ace = A
    • 西装:
      • 黑桃= S
      • 球杆= C
      • 心= H
      • 钻石= D

所以黑桃的王牌是SA,红心的10是HT,钻石的第4是D4,依此类推。

  • 一轮Pokerface包含四个步骤:
    • 重新洗牌,向每位玩家发五张牌。
    • 每个玩家都有机会交换任意数量的卡。
    • 每个玩家都有机会再获得最多三张牌。
    • 每个玩家都必须展现自己的最佳手牌。
  • 最佳牌手获胜,并获得该玩家的积分。如果出现平局,两位选手都将获得积分。
  • 在一个游戏中,进行了十轮比赛,得分最高的玩家获胜并获得一个“胜利点”。如果出现平局,则两个玩家都将赢得一个胜利点。
  • Leo确实没有很多钱,因此您的机器人可以认为这是一个没有下注的完美世界。

  • 手的长度正好是5张牌(初始输入和最终输出)。
  • 双手的排名与此处所述规则一致。

输入输出

  • Leo只懂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 SAH4 DA D4 SA C4两个都代表4、4、4,Ace,Ace,这是满屋子)。
  • 如果您希望通过分析对手的手来制定策略,则可以将数据存储在<botname>/data目录中。
    • 竞争的机器人显示了其手之后,它们将被写入hands.txt中的每个bots数据目录,并且每只手都换行(由\ n分隔)。该文件将以US_ASCII编码。
  • 机器人请求新卡或交换卡后,将根据您在bot.jlsc文件中指定的格式输入卡。

帖子格式

  • 每个帖子必须包括两件事情:
    • 机器人的源代码,或指向公共存储库的链接。
    • 包含以下内容的zip文件:
      • 您的漫游器的已编译/可执行版本(如果文件是.exe或其他不可反编译的文件,请仅在帖子中包含编译说明)。
      • 一个bot.jlsc文件,请参阅下面的内容(附带说明:.jlsc扩展名仅是由于我的附带项目(一种配置格式)。下面的文件与正确的语法匹配,因此不必担心)。
    • .zip文件的名称必须与您的漫游器相同。
  • 如果您无权访问Windows或其他压缩实用程序,或者由于某种原因而无法创建.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”是您希望格式化另外两个卡的输入的方式。
  • “ input_3”是您希望格式化三张附加卡的输入的方式。
  • “ input_4”是您希望格式化四个附加卡的输入的方式。

细节

  • 这些漏洞是不允许的(请参阅“常见陷阱”)
  • 您可能没有写过机器人,它总是会在规则集中每次都输出最佳手牌。(即没有长期运行的暴力机器人,没有什么比LeoBot的“好”了)
  • 您的漫游器应在〜100毫秒或更短的时间内运行(此时的延迟时间,最长为〜1秒)
  • 机器人在其选择的手之后的任何输出都将被忽略。
  • 不允许出现标准漏洞。
  • 是的,我知道linux更好,但是我有Windows PC,因此请确保可以从Windows命令行运行程序的编译/可执行版本。
    • 我已经在计算机上安装了python和java,但是我愿意更新到新版本并安装其他环境,因此请指定程序所需的环境类型。
  • 您可能不会编写一个在任何情况下都与另一个机器人做相同事情的机器人。允许使用垃圾邮件漫游器,但不鼓励使用。
  • 您的机器人只能使用其拥有的卡。通过交换丢失的卡或未开始处理的卡在最后一手无效输出。
  • 输入和输出只能包含ASCII字符。

比赛

  • 我会在有时间的时候进行比赛(我的日程安排几乎和Leo一样,所以我很少见。对于给您带来的不便,我们深表歉意。)
  • 机器人将在4人游戏中互相对峙,每个可能的机器人子集(即很多游戏)都会有一个游戏。
    • 此过程将重复五次。
    • 由于锦标赛处理程序将机器人进行分组的方式,最多将添加三个加注机器人,以使机器人的数量被4整除。这些机器人将简单地返回最初处理的手。
  • 每轮比赛结束后,将根据机器人赢得的比赛次数来计算机器人的得分。
    • 多个机器人可以共享一个职位(按先发先赢的平局)。
  • 比赛结束后,分数将附加到该帖子的底部。

计分

正常的KoTH规则。赢得最多游戏的机器人赢得了挑战。

狮子座

Leo的机器人非常聪明。它不交换任何卡,这太难了,但是它确实要求最大数量的附加卡,并且它决定了它可以做出的最佳手牌,并使用该手牌。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(非常小的智能机器人分数) (先到))。因此,您可能应该从此挑战中删除代码高尔夫
Destructible Lemon

2
即使不能使用Cjam,也可以说哑巴机器人将是一个合理的策略,而删除代码高尔夫球将消除平衡大小与性能之间的所有困难
Destructible Lemon

1
杀死了代码高尔夫球,将其杀死
。...–苏格拉底凤凰城

Answers:


1

(Python),Pairbot,竞争并不激烈(我不知道如何制作cmd命令和内容)

只要有人协助bot.jlsc和zip文件等,Pairbot就会竞争。


Pairbot知道您并不总是能得到帮助。他知道好手很少。Pairbot知道配对和其他重复项是最好的选择。Pairbot还知道您可以得到的最低手牌是7高,因此他知道他是否有6高,这实际上是直牌(pairbot不知道为什么他知道这一点)。他还知道自己的最低卡数是否为10(无对),这也是顺子(pairbot知道他可以用这种方式获得皇家同花顺)。Pairbot主要检查相同号码的重复,但在特殊情况下也检查两种类型的直线。

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

另外,为FGITW +1
苏格拉底凤凰城

更像是FGITLOSG(慢速枪领域中的最快枪)。
破坏的柠檬

真正。我不确定输入/输出的格式是否正确。当我输入一只手时,程序将打印“ True”,然后显示其当前手。我相信您只想打印“ false”,因为“ True”表示您要交换卡。其次,程序在绘制时需要打印单个整数,而在交换时则需要打印以空格分隔的整数。不是“画0”。我将尝试澄清主要帖子。
苏格拉底凤凰城

[所以现在算是竞争吗?]没有看到新消息。我会纠正机器人马上
可破坏柠檬

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

还像其他两个机器人一样,将输入分隔成空格


注意:由于我自己的锦标赛程序中的错误,我已经稍微改变了输出规则。在最终输出之后,现在至少必须有一条尾随新行。
苏格拉底凤凰城

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为模型-编辑:由于可破坏的西瓜而产生了广泛的错误修正-编辑:由于新规则,最终输出后出现尾随换行符

您可能需要使用字典来代替所有复杂的卡片值
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)])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也只是刚刚超过你的程序,那是因为它是可读
可破坏柠檬

我知道。不良的打高尔夫习惯。
洋红色

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])
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.