Euchre bots (juego de cartas)

10

La idea de este desafío es simple: crear un bot para jugar el juego de cartas Euchre.

Para aquellos de ustedes que aún no los conocen, he escrito las reglas a Euchre aquí en lo que respecta a este desafío.

Recomiendo usar Python o algo similar, pero la única restricción real es que tiene que ser compatible con el código del controlador

Entrada:

Su euchre bot recibirá diferentes tipos de entrada dependiendo de la fase actual del juego o ronda. En términos generales, obtendrá la fase del juego en la primera línea seguida de una coma y la cantidad de puntos que tiene su equipo, y luego los datos relevantes en las siguientes líneas.

Cronológicamente, su bot recibirá información en el siguiente orden:

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

Salida:

Su euchre bot tendrá diferentes salidas dependiendo de la fase actual del juego o ronda.

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

Puntuación:

La puntuación de tu bot es el número total de juegos que gana.

Tu bot jugará contra cualquier otro bot, y siempre estará asociado con una copia de sí mismo.

Notas:

Aquí hay una plantilla 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. Siempre habrá 4 respuestas totales. Si alguien va solo, entonces la respuesta de su compañero será "p" en su turno.

  2. Traté de reducir la cantidad de entradas redundantes, para ser más claro:

    2a. Tanto su posición con respecto al crupier / líder como la carta que jugó su compañero pueden determinarse por el número de salidas anteriores. Hay 1 jugador entre usted y su compañero. Por ejemplo, si obtienes "td, 8h, p" como la última línea de tu turno, puedes ver que tu compañero jugó 8h, y el otro equipo tiene un jugador que va solo.

  3. Si tienes curiosidad, el trato se hace de la manera tradicional (en dos rondas alternando paquetes de 2 y 3 cartas) pero eso no es realmente relevante para tu bot, así que ...

  4. Si el segundo jugador decide ordenar en la fase de triunfo, esa fase continuará, pero sus resultados serán ignorados. En otras palabras, quien ordene primero está en el equipo de Namers, independientemente de cualquier otro resultado.

  5. Los siguientes son los valores predeterminados para las diversas fases del juego. Si no emite una respuesta válida para esa ronda, su respuesta cambiará a la siguiente.

    Ordenar Trump: p

    Nombramiento de Trump: p

    Descarte: (la primera carta en tu mano)

    Yendo solo: n

    Tu turno: (la primera carta legal en tu mano)

  6. Aquí está el código del controlador para sus propósitos de prueba.

    6a. Tenga en cuenta que puede pasar 2 o 4 nombres de bot, si le da 4 bots, se asocian al azar, y con 2 se asocian con copias de sí mismos.

    6b. Necesita un directorio 'bots' en el mismo directorio que el código del controlador, y su código bot debe estar en el directorio bots.

  7. Para aquellos que quieren que su bot recuerde qué cartas se jugaron, se les da la oportunidad durante la fase de "truco", que le dice a su bot qué cartas se jugaron. Puede escribir en un archivo en el directorio de bots siempre que ese archivo no exceda 1kb.

Marcador:

Old Stager:  2
Marius:      1
Random 8020: 0
La judía
fuente
2
Recomiendo incluir bots de muestra para que sea más fácil para las personas escribir sus bots.
Nathan Merrill
3
Publícalo como un envío. Sin embargo, el problema con ese bot aleatorio es que ignora la mayoría de la entrada que le está dando. A la gente le encanta copiar / pegar (luego modificar) el código, por lo que cuanto más completos sean sus bots iniciales, más presentaciones (y mejores presentaciones) recibirá.
Nathan Merrill
1
¿Tengo razón al suponer que a menos que el bot sea el último jugador del turno, no tiene forma de saber qué se jugó en el último turno?
plannapus
1
@Sleafar bien, si hubiera una manera de saber qué se jugó durante el turno actual, el bot podría escribirlo en un archivo, para poder seguirlo.
plannapus
1
@NotthatCharles He actualizado las reglas para permitir explícitamente la escritura en un archivo
The Beanstalk

Respuestas:

2

Mario

Escribí ese bot en R. Hice algunas pruebas con su controlador y parecen comunicarse correctamente.

#!/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)   
}

Probablemente lo modifique más tarde, ya que no implementé una lógica de "giro" para cuando el bot se defiende, pero lo estoy publicando ahora para que la gente tenga otro bot para probar.

Por ahora, solo implementa estrategias muy básicas como liderar con un as, un triunfo o cualquier otra carta alta; seguir con una carta más alta cuando sea posible o jugar la carta de menor valor si no; ordenar cuando la mano tiene un valor alto y nombrar el color en el que la mano habría tenido el valor más alto; ir solo cuando la mano tiene un valor muy alto. El "valor" de cada carta se calcula de manera muy simple: el valor de los triunfos comienza desde 7 para el primer jack y disminuye a lo largo del palo de triunfo.

plannapus
fuente
1

Old Stager

Este bot sigue algunas reglas simples que le sirvieron durante mucho tiempo:

  • Asigne intuitivamente un puntaje a cada tarjeta
  • Elige el triunfo si la puntuación de la mano es lo suficientemente buena
  • En caso de un juego de manos realmente bueno solo
  • Elige la mejor carta cuando juegues primero
  • Elige una mejor carta que los oponentes si están ganando
  • Elija la peor carta si el compañero está ganando o si ganar no es posible

Aumenté el puntaje objetivo de 10 a 100 para probar en el controlador. Los resultados siguen siendo muy aleatorios, pero mucho más estables que antes.

#!/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
fuente
0

Aleatorio 8020

Un bot aleatorio simple, que pasará el 80% del tiempo. Elimine el comentario de la última línea para ver la entrada (salida) borrada.

#!/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
fuente