유커 봇 (카드 게임)


10

이 도전의 아이디어는 간단합니다. 카드 게임 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

산출:

유커 봇은 게임의 현재 단계 또는 라운드에 따라 다른 출력을 갖습니다.

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 개의 응답이 있습니다. 누군가 혼자 가면 파트너의 차례가 "p"가됩니다.

  2. 여분의 입력량을 줄이려고 노력했습니다.

    2a. 딜러 / 리더와의 상대 위치 및 파트너가 사용한 카드는 이전 출력 수에 따라 결정될 수 있습니다. 당신과 당신의 파트너 사이에 1 명의 플레이어가 있습니다. 예를 들어, 턴에서 마지막 줄에 "td, 8h, p"가 표시되면 파트너가 8 시간을 뛰었고 다른 팀에 혼자가는 선수가 있다는 것을 알 수 있습니다.

  3. 호기심이 많으면 거래는 전통적인 방식으로 이루어지며 (2와 3 카드로 이루어진 두 번의 라운드로) 봇과는 관련이 없습니다.

  4. 두 번째 플레이어가 트럼프 단계에서 주문하기로 결정하면 해당 단계는 계속되지만 출력은 거의 무시됩니다. 다시 말해, 먼저 주문한 사람은 다른 출력과 상관없이 Namers 팀에 있습니다.

  5. 다음은 다양한 게임 단계의 기본값입니다. 해당 라운드에 유효한 응답을 출력하지 않으면 응답이 아래의 내용으로 변경됩니다.

    주문 트럼프 : p

    명명 트럼프 : p

    폐기 : (손에 든 첫 번째 카드)

    혼자가 : n

    당신의 차례 : (당신의 손에있는 첫 번째 법정 카드)

  6. 테스트 목적의 컨트롤러 코드는 다음과 같습니다 .

    6a. 2 개 또는 4 개의 봇 이름을 전달할 수 있습니다. 4 개의 봇을 제공하면 무작위로 파트너가되고 2 개는 자신의 사본과 파트너가됩니다.

    6b. 컨트롤러 코드와 동일한 디렉토리에 'bots'디렉토리가 필요하며 봇 코드는 bots 디렉토리에 있어야합니다.

  7. 봇이 어떤 카드를 사용했는지 기억하고 싶은 사람들을 위해, "트릭"단계에서 봇에게 어떤 카드를 사용했는지 알려주는 기회가 주어집니다. 파일이 1kb를 초과하지 않는 한 bots 디렉토리의 파일에 쓸 수 있습니다.

스코어 보드 :

Old Stager:  2
Marius:      1
Random 8020: 0

2
사람들이 봇을 더 쉽게 작성할 수 있도록 샘플 봇을 포함하는 것이 좋습니다.
Nathan Merrill

3
제출물로 게시하십시오. 그러나 임의 봇의 문제점은 사용자가 제공하는 입력의 대부분을 무시한다는 것입니다. 사람들은 코드를 복사 / 붙여 넣기 (그런 다음 수정)하는 것을 좋아하므로 초기 봇이 더 포괄적 일수록 더 많은 제출 (및 더 나은 제출)을 받게됩니다.
Nathan Merrill

1
봇이 턴의 마지막 플레이어가 아니라면, 마지막 턴에서 어떤 게임을했는지 알 수있는 방법이 없다고 생각할 수 있습니까?
plannapus

1
@Sleafar 현재 턴 중에 무엇을했는지 알 수있는 방법이 있다면 봇은 파일을 기록하여 추적 할 수 있습니다.
plannapus

1
@NotthatCharles 나는 파일에 명시 적으로 쓰기를 허용하는 규칙을 업데이트했습니다
The Beanstalk

답변:


2

마리우스

나는 R에서 그 봇을 썼다. 나는 당신의 컨트롤러로 테스트를했는데 제대로 통신하는 것 같습니다.

#!/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)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.