Boty Euchre (gra karciana)

10

Idea tego wyzwania jest prosta: stwórz bota, aby zagrać w grę karcianą Euchre.

Dla tych z was, którzy jeszcze ich nie znają, napisałem zasady Euchre , które dotyczą tego wyzwania.

Polecam używanie Pythona lub czegoś podobnego, ale jedynym prawdziwym ograniczeniem jest to, że musi on być zgodny z kodem kontrolera

Wejście:

Twój bot euchre otrzyma różne dane wejściowe w zależności od aktualnej fazy gry lub rundy. Ogólnie rzecz biorąc, fazę gry otrzymujesz w pierwszym wierszu, po której następuje przecinek i liczba punktów, które ma Twoja drużyna, a następnie odpowiednie dane w kolejnych wierszach.

Chronologicznie twój bot otrzyma dane wejściowe w następującej kolejności:

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

Wynik:

Twój bot euchre będzie miał różne wyjścia w zależności od aktualnej fazy gry lub rundy.

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

Punktacja:

Wynik twojego bota to łączna liczba wygranych gier.

Twój bot będzie grał przeciwko każdemu innemu botowi i zawsze będzie współpracował z jego kopią.

Uwagi:

Oto prosty szablon w 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. Zawsze będą 4 odpowiedzi ogółem. Jeśli ktoś pójdzie sam, wówczas odpowiedź jego partnera będzie oznaczać „p” w swojej turze.

  2. Próbowałem zmniejszyć ilość zbędnych danych wejściowych, aby być bardziej wyraźnym:

    2a. Zarówno twoją pozycję w stosunku do rozdającego / lidera, jak i kartę, którą zagrał twój partner, można określić na podstawie liczby poprzednich wyników. Jest jeden gracz między tobą a twoim partnerem. Tam Na przykład, jeśli dostaniesz „td, 8h, p” jako ostatnią linię w swojej turze, możesz zobaczyć, że twój partner grał 8h, a druga drużyna ma gracza, który idzie sam.

  3. Jeśli jesteś ciekawy, transakcja odbywa się w tradycyjny sposób (w dwóch rundach na przemian pakiety 2 i 3 kart), ale to nie jest tak naprawdę odpowiednie dla twojego bota, więc ...

  4. Jeśli drugi gracz zdecyduje się zamówić w fazie atutowej, faza ta będzie kontynuowana, ale ich wyniki zostaną w zasadzie zignorowane. Innymi słowy, ktokolwiek zamawia jako pierwszy, należy do zespołu Namers, niezależnie od innych wyników.

  5. Poniżej przedstawiono ustawienia domyślne dla różnych faz gry. Jeśli nie podasz prawidłowej odpowiedzi dla tej rundy, twoja odpowiedź zostanie zmieniona na poniżej.

    Zamawianie Trump: p

    Naming Trump: s

    Odrzucanie: (pierwsza karta w ręce)

    Going Alone: ​​n

    Twoja kolej: (pierwsza legalna karta w twojej ręce)

  6. Oto kod kontrolera do celów testowych.

    6a. Zauważ, że możesz podać 2 lub 4 nazwy botów, jeśli dasz mu 4 boty, zostaną one losowo powiązane, a przy 2 są powiązane z kopiami samych siebie.

    6b. Potrzebujesz katalogu „botów” w tym samym katalogu, co kod kontrolera, a kod bota musi znajdować się w katalogu botów.

  7. Dla tych, którzy chcą, aby ich bot pamiętał, które karty zostały zagrane, masz możliwość podczas fazy „lewy”, która informuje bota, które karty zostały zagrane. Możesz pisać do pliku w katalogu botów, o ile plik ten nie przekracza 1kb.

Tablica wyników:

Old Stager:  2
Marius:      1
Random 8020: 0
The Beanstalk
źródło
2
Zalecam włączenie przykładowych botów, aby ułatwić pisanie botów.
Nathan Merrill,
3
Opublikuj jako zgłoszenie. Problem z tym losowym botem polega jednak na tym, że ignoruje on większość wprowadzanych danych. Ludzie uwielbiają kopiować / wklejać (a następnie modyfikować) kod, więc im bardziej obszerne są twoje początkowe boty, tym więcej zgłoszeń (i lepszych zgłoszeń) otrzymasz.
Nathan Merrill,
1
Czy mam rację, zakładając, że jeśli bot nie jest ostatnim graczem w turze, nie ma możliwości dowiedzenia się, co było grane w ostatniej turze?
plannapus
1
@Sleafar dobrze, jeśli istniał sposób, aby wiedzieć, co było odtwarzane podczas bieżącej tury, bot mógłby zapisać go do pliku, aby śledzić.
plannapus
1
@NotthatCharles Zaktualizowałem zasady, aby wyraźnie zezwolić na zapis do pliku
The Beanstalk

Odpowiedzi:

2

Marius

Napisałem tego bota w R. Zrobiłem kilka testów z twoim kontrolerem i wydają się one poprawnie komunikować.

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

Prawdopodobnie zmodyfikuję go później, ponieważ nie wdrożyłem logiki „zakrętu”, gdy bot się broni, ale publikuję go teraz, aby ludzie mieli innego bota do przetestowania.

Na razie implementuje tylko bardzo podstawowe strategie, takie jak prowadzenie z asem, atutem lub inną wysoką kartą; podążanie za wyższą kartą, jeśli to możliwe, lub zagrywanie karty o najniższej wartości, jeśli nie; porządkowanie, gdy ręka ma wysoką wartość, i nazywanie koloru, w którym ręka miałaby najwyższą wartość; idąc samotnie, gdy ręka ma bardzo wysoką wartość. „Wartość” każdej karty jest obliczana bardzo prosto: wartość atutów zaczyna się od 7 dla pierwszego waleta i maleje wraz z kolorem atutu.

plannapus
źródło
1

Wyjadacz

Ten bot przestrzega kilku prostych zasad, które dobrze mu służyły przez długi czas:

  • Intuicyjnie przypisz wynik do każdej karty
  • Wybierz atut, jeśli wynik rozdania jest wystarczająco dobry
  • W przypadku naprawdę dobrej gry w pojedynkę
  • Najpierw wybierz najlepszą kartę
  • Wybierz lepszą kartę niż przeciwnicy, jeśli wygrają
  • Wybierz najgorszą kartę, jeśli partner wygrywa lub jeśli zwycięstwo nie jest możliwe

Podniosłem wynik docelowy z 10 do 100 za testowanie w kontrolerze. Wyniki są nadal bardzo losowe, ale o wiele bardziej stabilne niż wcześniej.

#!/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
źródło
0

Losowo 8020

Prosty losowy bot, który zajmie 80% czasu. Usuń komentarz z ostatniego wiersza, aby zobaczyć (wyczyszczone) wejście i wyjście.

#!/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
źródło