Euchre bots (jeu de cartes)

10

L'idée de ce défi est simple: créer un bot pour jouer au jeu de cartes Euchre.

Pour ceux d'entre vous qui ne les connaissent pas déjà, j'ai écrit les règles à Euchre ici en ce qui concerne ce défi.

Je recommande d'utiliser python ou quelque chose de similaire, mais la seule vraie restriction est qu'il doit être compatible avec le code du contrôleur

Contribution:

Votre bot euchre obtiendra différents types d'entrée en fonction de la phase actuelle du jeu ou du tour. De manière générale, vous obtiendrez la phase de jeu sur la première ligne suivie d'une virgule et du nombre de points de votre équipe, puis des données pertinentes sur les lignes suivantes.

Chronologiquement, votre bot recevra une entrée dans l'ordre suivant:

Ordering Trump:
    js,ah,qc,ts,jc  // the cards in your hand
    2               // number of points your team has
    0               // number of tricks your team has taken
    ordering        // the phase of the game
    th              // the turned up card
    p,p             // each previous player’s decision

Naming Trump:
    js,ah,qc,ts,jc  // the cards in your hand
    2               // number of points your team has
    0               // number of tricks your team has taken
    naming          // the phase of the game
    p               // each previous player’s decision

Dealer Discarding:
    js,ah,qc,ts,jc  // the cards in your hand
    2               // number of points your team has
    0               // number of tricks your team has taken
    discard         // the phase of the game
    th              // the card you will pick up

Going alone:
    js,ah,qc,ts,jc  // the cards in your hand
    2               // number of points your team has
    0               // number of tricks your team has taken
    alone           // the phase of the game
    h               // the trump suit
    n,n             // each previous player’s decision

Your turn:
    js,ah,qc,ts,jc  // the cards in your hand
    2               // number of points your team has
    0               // number of tricks your team has taken
    turn            // the phase of the game
    h               // the trump suit
    td,8h,p         // each previous player’s card

Trick data:
                    // the cards in your hand (none, since this happens at the end of a trick)
    2               // number of points your team has
    1               // number of tricks your team has taken
    trick           // the phase of the game
    0               // the index of the following list that is your card
    js,tc,4d,js     // the cards played during the trick in the order they were played

Production:

Votre bot euchre aura différentes sorties selon la phase actuelle du jeu ou du tour.

Ordering Trump:
    p   //for pass
    OR
    o   //for order up

Naming Trump:
    p           //for pass
    OR ANY OF
    c,s,h,d     //the suit you want to name

Going alone:
    n   // no
    OR
    y   // yes

Your turn:
    js  //the card you want to play

Notation:

Le score de votre bot est le nombre total de jeux qu'il gagne.

Votre bot jouera contre tous les autres bots, et il sera toujours associé à une copie de lui-même.

Remarques:

Voici un modèle simple en python2.7:

#!/usr/bin/python2.7
import sys

data = sys.stdin.readlines()

hand = data[0].strip().split(',')   # Hand as a list of strings
points = int(data[1])       # Number of points
tricks = int(data[2])       # Number of tricks

out = ''

if data[3] == 'ordering':
    card = data[4]              # The upturn card
    prev = data[5].strip().split(',')   # The previous player's decisions as a list
    # Ordering logic
    out =       # 'o' or 'p'
elif data[3] == 'naming':
    prev = data[4].strip().split(',')   # The previous player's decisions as a list
    # Naming logic
    out =       # 'p', 'h', 's', 'c', or 'd'
elif data[3] == 'discard':
    card = data[4]              # The card you'll take
    # Discarding logic
    out =       # The card you want to discard
elif data[3] == 'alone':
    trump = data[4]             # The trump suit
    prev = data[5].strip().split(',')   # The previous player's decisions as a list
    # Alone logic
    out =       # 'y' for yes, 'n' for no
elif data[3] == 'turn':
    trump = data[4]             # The trump suit
    prev = data[5].strip().split(',')
    # Turn logic
    out =       # The card you want to play
elif data[3] == 'trick':
    trump = data[5]
    cards = data[6].strip().split(',')
    my_card = cards[int(data[4])]
    # Data logic

print(out)
  1. Il y aura toujours 4 réponses au total. Si quelqu'un part seul, la réponse de son partenaire sera "p" à son tour.

  2. J'ai essayé de réduire la quantité d'entrée redondante, donc pour être plus clair:

    2a. Votre position par rapport au croupier / leader et la carte que votre partenaire a joué peuvent être déterminées par le nombre de sorties précédentes. Il y a 1 joueur entre vous et votre partenaire. Là Par exemple, si vous obtenez "td, 8h, p" comme dernière ligne de votre tour, vous pouvez voir que votre partenaire a joué 8h, et l'autre équipe a un joueur qui va seul.

  3. Si vous êtes curieux, la transaction se fait de manière traditionnelle (en deux tours alternant des paquets de 2 et 3 cartes) mais ce n'est pas vraiment pertinent pour votre bot, alors ...

  4. Si le deuxième joueur décide de passer commande dans la phase d'atout, cette phase continuera, mais leurs sorties seront à peu près ignorées. En d'autres termes, celui qui commande en premier fait partie de l'équipe Namers indépendamment de toute autre sortie.

  5. Voici les valeurs par défaut pour les différentes phases de jeu. Si vous ne fournissez pas de réponse valide pour ce tour, votre réponse est modifiée comme suit.

    Commander Trump: p

    Nommer Trump: p

    Défausse: (la première carte de votre main)

    Aller seul: n

    Votre tour: (la première carte légale dans votre main)

  6. Voici le code du contrôleur à des fins de test.

    6a. Remarquez que vous pouvez transmettre 2 ou 4 noms de bots, si vous lui donnez 4 bots, ils seront associés de manière aléatoire et avec 2, ils seront associés à des copies d'eux-mêmes.

    6b. Vous avez besoin d'un répertoire «bots» dans le même répertoire que le code du contrôleur, et votre code bot doit être dans le répertoire bots.

  7. Pour ceux qui veulent que leur bot se souvienne quelles cartes ont été jouées, vous avez la possibilité pendant la phase de "truc", qui indique à votre bot quelles cartes ont été jouées. Vous pouvez écrire dans un fichier du répertoire des bots tant que ce fichier ne dépasse pas 1 Ko.

Tableau d'affichage:

Old Stager:  2
Marius:      1
Random 8020: 0
Le haricot magique
la source
2
Je recommanderais d'inclure des exemples de robots pour faciliter l'écriture des robots par les utilisateurs.
Nathan Merrill
3
Affichez-le en tant que soumission. Cependant, le problème avec ce bot aléatoire est qu'il ignore la majorité de l'entrée que vous lui donnez. Les gens aiment copier / coller (puis modifier) ​​le code, donc plus vos robots initiaux sont complets, plus vous recevrez de soumissions (et de meilleures soumissions).
Nathan Merrill
1
Ai-je raison de supposer que si le bot n'est pas le dernier joueur du tour, il n'a aucun moyen de savoir ce qui a été joué au dernier tour?
plannapus
1
@Sleafar bien s'il y avait un moyen de savoir ce qui a été joué pendant le tour en cours, le bot pourrait l'écrire dans un fichier, afin de garder une trace.
plannapus
1
@NotthatCharles J'ai mis à jour les règles pour autoriser explicitement l'écriture dans un fichier
The Beanstalk

Réponses:

2

Marius

J'ai écrit ce bot dans R. J'ai fait quelques tests avec votre contrôleur et ils semblent communiquer correctement.

#!/usr/bin/Rscript
options(warn=-1)
infile = file("stdin")
open(infile)
input = readLines(infile,5)
hand = strsplit(input[1],",")[[1]]
phase = input[4]
if(!phase%in%c("discard","naming")) input = c(input,readLines(infile,1))
other_o = c("a","k","q","j","t","9")
alone = "n"
ord = "p"
trumpify = function(color){
    tr_suit = switch(color,
            "c" = c("c","s",rep("c",5)),
            "s" = c("s","c",rep("s",5)),
            "h" = c("h","d",rep("h",5)),
            "d" = c("d","h",rep("d",5)))
    paste(c("j","j","a","k","q","t","9"),tr_suit,sep="")
    }

if(phase%in%c("ordering","alone")){
    flip = input[5]
    if(phase=="ordering") trump = trumpify(substr(flip,2,2))
    if(phase=="alone") trump = trumpify(flip)
    hand_value = sum((7:1)[trump%in%c(hand,flip)])
    if(hand_value>13) ord = "o"
    if(hand_value>18) alone = "y"
    if(phase=="alone") cat(alone)
    if(phase=="ordering") cat(ord)
    }

if(phase=="naming"){
    name = "p"
    colors = unique(substr(hand,2,2))
    col_values = sapply(colors,function(x)sum((7:1)[trumpify(x)%in%hand]))
    if(any(col_values>13)){name = colors[which.max(col_values)]}
    cat(name)
    }

if(phase=="discard"){
    flip = input[5]
    new_hand = c(hand,flip)
    trump = trumpify(substr(flip,2,2))
    discardables = new_hand[!new_hand%in%trump]
    if(length(discardables)){
        val = sapply(substr(discardables,1,1),function(x)(6:1)[other_o==x])
        d = discardables[which.min(val)]
    }else{d = tail(trump[trump%in%new_hand],1)}
    cat(d)
    }

if(phase=="turn"){
    trump = trumpify(input[5])
    fold = strsplit(gsub("[[:punct:]]","",input[6]),",")[[1]]
    if(length(fold)&!any(is.na(fold))){
        fold_c = substr(fold[1],2,2)
        f_suit = if(fold_c!=input[5]){paste(other_o,fold_c,sep="")}else{trump}
        l = length(f_suit)
        current = (l:1)[f_suit%in%fold]
        if(any(hand%in%f_suit)){
            playable = hand[hand%in%f_suit]
            val = sapply(playable,function(x)(l:1)[f_suit==x])
            if(all(max(val)>current)){
                play = playable[which.max(val)]
            }else{play = playable[which.min(val)]}
        }else if(any(hand%in%trump)){
            playable = hand[hand%in%trump]
            val = sapply(playable,function(x)(7:1)[trump==x])
            if(!any(fold%in%trump)){
                play = playable[which.min(val)]
            }else{
                trumped = fold[fold%in%trump]
                val_o = max((7:1)[trump%in%trumped])
                play = ifelse(any(val>val_o), playable[which.min(val[val>val_o])], playable[which.min(val)])
            }
        }else{
            val = sapply(substr(hand,1,1),function(x)(6:1)[other_o==x])
            play = hand[which.min(val)]
            }
    }else{
        col = c("c","s","h","d")
        non_tr = col[col!=input[5]]
        aces = paste("a",non_tr,sep="")
        if(any(hand%in%aces)){
            play = hand[hand%in%aces][1]
        }else if(any(hand%in%trump)){
            playable = hand[hand%in%trump]
            val = sapply(playable,function(x)(7:1)[trump==x])
            play = playable[which.max(val)]
        }else{
            val = sapply(substr(hand,1,1),function(x)(6:1)[other_o==x])
            play = hand[which.max(val)]
        }
    }
    cat(play)   
}

Je vais probablement le modifier plus tard car je n'ai pas implémenté de logique de "tour" pour quand le bot se défend, mais je le poste maintenant pour que les gens aient un autre bot à tester.

Pour l'instant, il ne met en œuvre que des stratégies très basiques telles que mener avec un as, un atout ou toute autre carte haute; suivre avec une carte plus élevée dans la mesure du possible ou jouer la carte la moins chère sinon; ordonner lorsque la main a une valeur élevée et nommer la couleur dans laquelle la main aurait eu la valeur la plus élevée; aller seul lorsque la main a une valeur très élevée. La "valeur" de chaque carte est calculée très simplement: la valeur des atouts commence à 7 pour le premier jack et diminue le long de l'atout.

plannapus
la source
1

Vieux routier

Ce bot suit quelques règles simples qui lui ont bien servi pendant longtemps:

  • Attribuez intuitivement un score à chaque carte
  • Choisissez l'atout si le score de la main est assez bon
  • En cas de très bon jeu de mains seul
  • Choisissez la meilleure carte lorsque vous jouez en premier
  • Choisissez une meilleure carte que les adversaires s'ils gagnent
  • Choisissez la pire carte si le partenaire gagne ou s'il n'est pas possible de gagner

J'ai augmenté le score cible de 10 à 100 pour les tests dans le contrôleur. Les résultats sont encore très aléatoires, mais bien plus stables qu'auparavant.

#!/usr/bin/python2.7
from __future__ import print_function
import sys, re, math

base = 1.2
playThreshold = 27.0
aloneThreshold = 36.0
sameColor = { 'd' : 'h', 'h' : 'd', 's' : 'c', 'c' : 's' , '' : '', 'n' : 'n' }
cardValue = { 'p' : 0, '9' : 1, 't' : 2, 'j' : 3, 'q' : 4, 'k' : 5, 'a' : 6 }

class Card(object):
    def __init__(self, name, trump):
        self.name = name
        self.value = cardValue[name[0:1]]
        self.suit = name[1:2]
        self.trump = False
        self.updateScore(trump)
    def updateScore(self, trump):
        self.score = self.value
        if self.suit == trump:
            self.trump = True
            self.score += 6
        if self.value == 3:
            if self.suit == trump:
                self.score = 14
            if self.suit == sameColor[trump]:
                self.trump = True
                self.score = 13

class Cards(object):
    def __init__(self, cards, trump):
        self.list = []
        self.score = 0.0
        if cards:
            for c in cards.split(','):
                self.append(Card(c, trump))
    def append(self, card):
        self.list.append(card)
        self.score += math.pow(base, card.score)
    def updateScore(self, trump):
        self.score = 0.0
        for card in self.list:
            card.updateScore(trump)
            self.score += math.pow(base, card.score)
    def best(self):
        card = self.list[0]
        for i in self.list[1:]:
            if i.score > card.score:
                card = i
        return card
    def worst(self):
        card = self.list[0]
        for i in self.list[1:]:
            if i.score < card.score:
                card = i
        return card
    def better(self, ref):
        card = None
        for i in self.list:
            if i.score > ref.score and (card is None or i.score < card.score):
                card = i
        return card

def ordering(hand, card, decisions):
    if len(decisions) == 3:
        hand.append(card)
    return 'o' if hand.score > playThreshold else 'p'

def naming(hand):
    result = 'p'
    score = playThreshold
    for trump in ['d', 'h', 's', 'c']:
        hand.updateScore(trump)
        if hand.score > score:
            result = trump
            score = hand.score
    return result

def turn(hand, decisions):
    bestIndex = -1
    for i, d in enumerate(decisions.list):
        if d.suit:
            bestIndex = i
            break
    if bestIndex == -1:
        return hand.best()
    else:
        suit = decisions.list[bestIndex].suit
        for i in range(2, len(decisions.list)):
            if (decisions.list[i].suit == suit or decisions.list[i].trump) and decisions.list[i].score > decisions.list[bestIndex].score:
                bestIndex = i
        matching = Cards('', '')
        for card in hand.list:
            if card.suit == suit:
                matching.append(card)
        if not matching.list:
            if bestIndex == len(decisions.list) - 2:
                return hand.worst()
            for card in hand.list:
                if card.trump:
                    matching.append(card)
            if not matching.list:
                return hand.worst()
        if bestIndex == len(decisions.list) - 2:
            return matching.worst()
        card = matching.better(decisions.list[bestIndex])
        if card:
            return card
        return matching.worst()

output = ''
input = re.split('\n', re.sub(r'[^a-z0-9,\n]+', '', sys.stdin.read()))

if input[3] == 'ordering':
    output = ordering(Cards(input[0], input[4][1:2]), Card(input[4], input[4][1:2]), input[5].split(','))
elif input[3] == 'naming':
    output = naming(Cards(input[0], 'n'))
elif input[3] == 'discard':
    output = Cards(input[0], input[4][1:2]).worst().name
elif input[3] == 'alone':
    output = 'y' if Cards(input[0], input[4]).score > aloneThreshold else 'n'
elif input[3] == 'turn':
    output = turn(Cards(input[0], input[4]), Cards(input[5], input[4])).name

print(output)
Sleafar
la source
0

Aléatoire 8020

Un bot aléatoire simple, qui passera 80% du temps. Décommentez la dernière ligne pour voir l'entrée et la sortie (effacées).

#!/usr/bin/python2.7
from __future__ import print_function
import sys, re, random

output = ''
input = re.split('\n', re.sub(r'[^a-z0-9,\n]+', '', sys.stdin.read()))
hand = input[0].split(',')

if input[3] == 'ordering':
    output = random.choice(['p', 'p', 'p', 'p', 'o'])
elif input[3] == 'naming':
    output = random.choice(['p', 'p', 'p', 'p', random.choice(hand)[1:2]])
elif input[3] == 'discard':
    output = random.choice(hand)
elif input[3] == 'alone':
    output = random.choice(['n', 'n', 'n', 'n', 'y'])
elif input[3] == 'turn':
    output =  random.choice(hand)
    if input[5]:
        suited = filter(lambda x: input[5][1:2] in x, hand)
        if suited:
            output = random.choice(suited)

print(output)
#print(input, " --> ", output, file=sys.stderr)
Sleafar
la source