Боти Euchre (карткова гра)


10

Ідея цього виклику проста: створити бота, щоб грати в карточну гру Euchre.

Для тих із вас, хто їх ще не знає, я написав тут Еухре правила, коли вони стосуються цього завдання.

Я рекомендую використовувати python або щось подібне, але єдиним реальним обмеженням є те, що він повинен бути сумісний з кодом контролера

Вхід:

Ваш бот euchre отримає різні види введення залежно від поточної фази гри або раунду. Взагалі кажучи, ви отримаєте фазу гри на першому рядку з комою та кількістю очок, яку має ваша команда, а потім відповідні дані у наступних рядках.

Хронологічно ваш бот отримає дані в такому порядку:

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

Вихід:

Ваш бот euchre матиме різні виходи залежно від поточної фази гри або раунду.

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

Оцінка:

Оцінка вашого бота - це загальна кількість виграних ігор.

Ваш бот буде грати проти кожного іншого бота, і він завжди буде співпрацювати з його копією.

Примітки:

Ось простий шаблон у 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. Завжди буде 4 загальні відповіді. Якщо хтось піде наодинці, то відповідь їх партнера буде "р" на свою чергу.

  2. Я намагався зменшити кількість зайвого введення, щоб бути надзвичайно зрозумілим:

    2а. Як ваша позиція щодо дилера / лідера, так і карта, яку грав ваш партнер, можна визначити за кількістю попередніх результатів. Між вами та вашим партнером є 1 гравець. Наприклад, якщо ви отримуєте "td, 8h, p" в якості останнього рядка на черзі, ви можете бачити, що ваш партнер грав 8h, а в іншій команді є гравець, який збирається один.

  3. Якщо вам цікаво, угода робиться традиційним способом (у два раунди чергування пакетів по 2 та 3 карти), але це не дуже важливо для вашого бота, тому ...

  4. Якщо другий гравець вирішить замовити у козирній фазі, ця фаза продовжиться, але їхні результати будуть майже ігноровані. Іншими словами, хто замовлює першим, той є в команді Намер, незалежно від будь-якого іншого результату.

  5. Нижче наведено параметри за замовчуванням для різних фаз гри. Якщо ви не отримаєте дійсну відповідь на цей раунд, то ваша відповідь буде змінена на те, що нижче.

    Замовлення Трампа: с

    Ім'я Трампа: с

    Відмова: (перша картка в руці)

    Ідучи наодинці: н

    Ваша черга: (перша юридична картка у вашій руці)

  6. Ось код контролера для ваших тестових цілей.

    6а. Зауважте, що ви можете передати 2 або 4 бот-імена, якщо ви даєте йому 4 боти, то вони потрапляють у довільне співпрацю, а з 2 вони є партнерами з копіями самих себе.

    6б. Вам потрібен каталог "ботів" у тому ж каталозі, що і код контролера, і ваш код бота повинен бути в каталозі ботів.

  7. Тим, хто хоче, щоб їх бот запам'ятав, в які карти грали, вам надається можливість під час фази "фокус", яка повідомляє вашому боту, в які карти грав. Ви можете записати файл у каталог ботів до тих пір, поки цей файл не перевищує 1 кб.

Табло:

Old Stager:  2
Marius:      1
Random 8020: 0

2
Я рекомендую включити зразки ботів, щоб людям було простіше писати своїх ботів.
Натан Меррілл

3
Опублікуйте це як подання. Однак проблема цього випадкового бота полягає в тому, що він ігнорує більшість вкладених вами даних. Люди люблять копіювати / вставляти (а потім змінювати) код, тому чим вичерпніші ваші початкові боти, тим більше отриманих матеріалів (і кращих матеріалів) ви отримаєте.
Натан Меррілл

1
Чи правильно я вважаю, що якщо бот не є останнім гравцем черги, він не може знати, що було зіграно в останню чергу?
планнапус

1
@Sleafar Добре, якщо був би спосіб дізнатися, що грали під час поточної черги, бот міг записати його у файл, щоб відстежувати.
планнапус

1
@NotthatCharles Я оновив правила, щоб явно дозволяти писати у файл
Beanstalk

Відповіді:


2

Маріус

Я написав цього бота в Р. Я робив кілька тестів з вашим контролером, і вони, здається, правильно спілкуються.

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

Я, мабуть, модифікую його пізніше, оскільки я не застосував логіку "повороту", коли бот захищає, але я розміщую його зараз, щоб у людей був ще один бот для перевірки.

Поки що він реалізує лише дуже основні стратегії, такі як лідерство з тузом, козиром або будь-якою іншою високою картою; наступне з вищою картою, коли це можливо, або граючи на карту з найнижчою ціною, якщо ні; замовлення, коли рука має високу цінність та називає колір, у якому рука мала б найвище значення; ходити поодинці, коли рука має дуже високу цінність. "Значення" кожної картки обчислюється дуже просто: значення козирів починається від 7 для першого джека і зменшується уздовж козирного костюма.


1

Старий егер

Цей бот дотримується деяких простих правил, які йому добре слугували довгий час:

  • Інтуїтивно призначайте бал кожній картці
  • Виберіть козир, якщо оцінка рук достатня
  • У випадку дійсно хорошої руки грайте поодинці
  • Виберіть найкращу карту, коли граєте спочатку
  • Виберіть кращу карту, ніж суперники, якщо вони виграють
  • Виберіть найгіршу карту, якщо партнер виграє або якщо перемогти неможливо

Я збільшив цільовий бал з 10 до 100 для тестування в контролері. Результати все ще дуже випадкові, але набагато стабільніші, ніж раніше.

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

Випадкові 8020

Простий випадковий бот, який пройде 80% часу. Відмініть останній рядок, щоб побачити (очищений) вхід і вихід.

#!/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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.