Euchre bots (gioco di carte)


10

L'idea di questa sfida è semplice: crea un bot per giocare al gioco di carte Euchre.

Per quelli di voi che non li conoscono già, ho scritto le regole a Euchre qui per quanto riguarda questa sfida.

Consiglio di usare Python o qualcosa di simile, ma l'unica vera limitazione è che deve essere compatibile con il codice del controller

Ingresso:

Il tuo bot euchre riceverà diversi tipi di input a seconda della fase corrente del gioco o del round. In generale, otterrai la fase di gioco sulla prima riga seguita da una virgola e dal numero di punti che la tua squadra ha, e quindi i dati rilevanti sulle seguenti righe.

Cronologicamente, il tuo bot riceverà input nel seguente ordine:

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

Produzione:

Il tuo bot euchre avrà output diversi a seconda della fase corrente del gioco o del round.

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

punteggio:

Il punteggio del tuo bot è il numero totale di partite che vince.

Il tuo bot giocherà contro ogni altro bot e sarà sempre associato a una copia di se stesso.

Appunti:

Ecco un semplice modello in 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. Ci saranno sempre 4 risposte totali. Se qualcuno va da solo, la risposta del suo partner sarà "p" al suo turno.

  2. Ho provato a radere la quantità di input ridondante, quindi per essere più chiaro:

    2a. Sia la tua posizione relativa al mazziere / leader sia la carta giocata dal tuo partner possono essere determinate dal numero di risultati precedenti. C'è 1 giocatore tra te e il tuo partner. Ad esempio, se ottieni "td, 8h, p" come ultima riga del tuo turno, puoi vedere che il tuo partner ha giocato un 8h e l'altra squadra ha un giocatore che sta andando da solo.

  3. Se sei curioso, l'affare è fatto in modo tradizionale (in due turni alternando pacchetti di 2 e 3 carte) ma non è rilevante per il tuo bot, quindi ...

  4. Se il secondo giocatore decide di ordinare nella fase di briscola, quella fase continuerà, ma le loro uscite saranno praticamente ignorate. In altre parole, chi ordina per primo fa parte del team Namers indipendentemente da qualsiasi altro risultato.

  5. Di seguito sono riportate le impostazioni predefinite per le varie fasi del gioco. Se non ottieni una risposta valida per quel round, la tua risposta viene modificata in quello che segue.

    Ordinare Trump: p

    Trump dei nomi: p

    Scarto: (la prima carta nella tua mano)

    Andare da soli: n

    Il tuo turno: (la prima carta legale in mano)

  6. Ecco il codice del controller per i tuoi scopi di test.

    6a. Nota che puoi passare in 2 o 4 nomi di bot, se gli dai 4 robot, questi vengono associati in modo casuale e con 2 vengono associati con copie di se stessi.

    6b. È necessaria una directory "bot" nella stessa directory del codice controller e il codice bot deve trovarsi nella directory bot.

  7. Per coloro che vogliono che il loro bot ricordi quali carte sono state giocate, durante la fase di "presa" ti viene data l'opportunità che dice al tuo bot quali carte sono state giocate. Puoi scrivere su un file nella directory dei bot purché quel file non superi 1kb.

Pagelle:

Old Stager:  2
Marius:      1
Random 8020: 0

2
Consiglierei di includere i robot di esempio per rendere più semplice per le persone scrivere i loro robot.
Nathan Merrill,

3
Pubblicalo come invio. Tuttavia, il problema con quel bot casuale è che ignora la maggior parte dell'input che gli stai dando. Alla gente piace copiare / incollare (quindi modificare) il codice, quindi più completi sono i tuoi bot iniziali, più invii (e migliori invii) riceverai.
Nathan Merrill,

1
Ho ragione a supporre che, a meno che il bot non sia l'ultimo giocatore del turno, non abbia modo di sapere cosa è stato giocato nell'ultimo turno?
plannapus,

1
@Sleafar bene se c'era un modo per sapere cosa veniva giocato durante il turno in corso, il bot poteva scriverlo su un file, al fine di tenere traccia.
plannapus,

1
@NotthatCharles Ho aggiornato le regole per consentire esplicitamente la scrittura in un file
The Beanstalk

Risposte:


2

marius

Ho scritto quel bot in R. Ho fatto alcuni test con il tuo controller e sembrano comunicare correttamente.

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

Probabilmente lo modificherò più tardi poiché non ho implementato una logica di "turn" per quando il bot si sta difendendo, ma lo sto pubblicando ora in modo che le persone abbiano un altro bot da testare.

Per ora, implementa solo strategie di base come condurre con un asso, una briscola o qualsiasi altra carta alta; seguire con una carta più alta quando possibile o giocare la carta con il valore più basso in caso contrario; ordinare quando la mano ha un valore elevato e denominare il colore in cui la mano avrebbe avuto il valore più alto; andare da solo quando la mano ha un valore molto alto. Il "valore" di ogni carta viene calcolato in modo molto semplice: il valore di briscole inizia da 7 per il primo jack e diminuisce lungo il seme di briscola.


1

Vecchio Stager

Questo bot segue alcune semplici regole che lo hanno servito bene per molto tempo:

  • Assegna intuitivamente un punteggio a ogni carta
  • Scegli la briscola se il punteggio della mano è abbastanza buono
  • In caso di mano davvero buona, gioca da solo
  • Scegli la carta migliore quando giochi per prima
  • Scegli una carta migliore rispetto agli avversari se stanno vincendo
  • Scegli la carta peggiore se il partner sta vincendo o se non è possibile vincere

Ho aumentato il punteggio target da 10 a 100 per i test nel controller. I risultati sono ancora molto casuali, ma molto più stabili di prima.

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

0

Casuale 8020

Un semplice robot casuale, che passerà l'80% delle volte. Rimuovi il commento dall'ultima riga per vedere l'input e l'output (cancellati).

#!/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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.