간단한 파 자크 (구 기사단의 스타 워즈 카드 게임)


11

Pazaak 은 스타 워즈 세계의 카드 게임입니다. 블랙 잭과 비슷하며, 두 명의 플레이어가 서로를 상대하지 않고 총 20 명을 기록하려고합니다. 각 플레이어는 자신의 4 장의 "사이드 데크"를 가지고 있으며, 점수를 수정하는 데 사용할 수 있습니다.

리더 보드

2015 년 6 월 17 일 현재 16:40 EDT

편집 : Neptor는 부정 행위로 실격되었습니다. 점수는 가능한 빨리 수정됩니다 ...

  1. NEPTR : ~ 424,000
  2. 신시내티 키드 : ~ 422,000
  3. 네스터 : ~ 408,000
  4. 오스틴 파워 : ~ 405,000
  5. 바스 티야 : ~ 248,000
  6. 멍청한주의 플레이어 : ~ 107,000
  7. 벙어리 굵은 체 플레이어 : ~ 87,000

모의 파 자크 컵 플레이 오프

가능한 빨리 업데이트됩니다.

Round One-Nestor vs Bastila & Austin Powers vs 신시내티 키드

1 라운드 결과

라운드 2-네스터 vs 오스틴 파워 & 신시내티 키드 vs 바스 티야

2 라운드 결과

역학

게임 플레이는 교대로 이루어집니다. 플레이어 1은 메인 (하우스) 덱에서 카드를받습니다. 하우스 데크에는 40 장의 카드가 있습니다. 1부터 10까지 4 장. 카드를받은 후에는 차례를 끝내고 다음 턴에 새 카드를 받거나 현재 가치를 유지하거나 사이드 데크에서 카드를 낼 수 있습니다. 새로운 가치에 서십시오. 플레이어 1이 원하는 것을 결정한 후, 플레이어 2는 프로세스를 반복합니다.

두 선수가 모두 나면 손이 평가됩니다. 한 플레이어가 폭탄을 터뜨린 경우 (20 명 이상) 다른 플레이어도 폭탄을 터뜨리지 않은 상태에서 승리합니다. 한 플레이어가 서서 다른 플레이어의 핸드 값이 높으면 다른 플레이어가 승리합니다. 두 선수가 모두 서기로 선택하면 손값이 높은 선수가 승리합니다. 동점 일 경우 어느 선수도 승리하지 않습니다.

당첨 조건이 충족되지 않으면 경기가 반복됩니다. 플레이어가 턴을 끝내기로 선택하면 새로운 카드를 받고 새로운 것을 선택할 수 있습니다. 그들이 서기로 선택했거나 사이드 데크에서 카드를 사용했다면, 새로운 카드를받지 못하고 새로운 행동을 선택할 수 없습니다.

한 명의 플레이어가 게임에서 이길 때까지 계속 플레이합니다. 게임은 최고 3/5 세트로 진행됩니다.

왜 "간단한"파 자크?

스타 워즈 세계에서 파자 크는 도박을했다. 이러한 시스템을 포함 시키면 게임에 역 동성을 더 추가 할 수 있지만, 처음 KoTH 경쟁에는 약간 복잡합니다.

"실제"Pazaak 사이드 데크는 또한 플레이어들에 의해 제공되었으며, 네거티브 카드, 포지티브 또는 네거티브 카드, 플립 카드, 더블 카드 및 타이 브레이커 카드와 같은 다양한 카드 옵션을 포함 할 수 있습니다. 이것들은 또한 게임을 더욱 흥미롭게 만들지 만, 도박 인터페이스가 필요하고 경쟁자보다 훨씬 더 많이 필요합니다. 이 Simple Pazaak 게임에서 각 플레이어는 동일한 사이드 데크를 얻습니다.

이 게임의 성공 여부에 따라 도박 및 맞춤형 사이드 데크가 가능한 고급 버전을 개발하려는 노력을 기울일 수 있습니다.

선수들

이 게임의 플레이어는 귀하가 디자인 한 봇이됩니다. 각 봇은 Player 클래스를 확장하고 Mechanics 패키지를 가져 와서 다음과 같이 플레이어 패키지에 상주해야합니다.

package Players;

import java.util.Collection;

import Mechanics.*;

public class DemoPlayer extends Player {

    public DemoPlayer() {
        name = "Your Name Here";
    }

    public void getResponse(int wins[], boolean isPlayerOne,
            Collection<Card> yourHand, Collection<Card> opponentHand,
            Collection<Card> yourSideDeck, int opponentSideDeckCount,
            Action opponentAction, boolean opponentDidPlay) {
        action = null;
        cardToPlay = null;
    }
}

봇이 이전에 서고 싶다고 표시하지 않는 한 컨트롤러는 봇에 대해 getResponse 메소드를 호출합니다. getResponse 메소드는 액션과 재생할 카드의 두 가지 속성을 설정할 수 있습니다. 조치는 다음 중 하나 일 수 있습니다.

  • 끝 : 턴을 끝내고 다음 턴에 새 카드를받습니다.
  • 스탠드 : 현재 핸드 값을 유지합니다. 카드를 뽑지 않습니다.
  • PLAY : 사이드 데크에서 카드를 재생 한 다음 서 있습니다.

액션을 PLAY로 설정 한 경우 재생할 카드는 분명히 중요합니다. Card 객체를받습니다. 전달한 카드 개체가 사이드 데크에 존재하지 않으면 봇이 대신 서 있습니다.

봇이 매 차례받는 파라미터는 다음과 같습니다.

  • 각 플레이어의 승리를 포함하는 배열입니다. wins [0]은 플레이어 1이고 wins 1 은 플레이어 2입니다 (int [])
  • 봇이 플레이어 1인지 여부 (부울)
  • 지금까지 처리 한 카드 모음 (컬렉션)
  • 상대방이 지금까지 처리 한 카드 모음 (컬렉션)
  • 사이드 데크에있는 카드 모음 (컬렉션)
  • 상대방의 덱에 남아있는 카드 수 (int)
  • 상대방이 마지막으로 한 행동 (Action) [참고 : 이것은 END 또는 STAND, 절대로 PLAY되지 않습니다]
  • 상대가 카드를했는지의 여부 (부울)

봇 규칙

봇은 getResponse 메소드를 통해 제공된 정보 만 사용할 수 있습니다. 그들은 다른 수업과 상호 작용하려고 시도해서는 안됩니다. 라운드 사이에 데이터를 저장하기 위해 단일 파일에 쓸 수 있습니다. 이들은 원하는대로 임의의 커스텀 방법, 속성 등을 가질 수있다. 적절한 시간 내에 실행해야합니다 (프로그램 실행이 실제로 즉각적이지 않은 경우 문제가 있음을 알 수 있습니다).

코드에서 어떤 종류의 악용을 발견하면 "자신을 켜는"것에 대한 보상을받습니다. 익스플로잇을 먼저 발견하면 문제를 해결하고 보상을받지 않습니다.

시민

이 글에서 이미 설명했듯이 컨트롤러는 봇을 작성할 필요가 없습니다. 그러나 테스트하려는 경우 여기에서 찾을 수 있습니다. https://github.com/PhantomJedi759/simplepazaak 두 개의 기본 봇이 포함되어 있습니다. "지능적"인 상대방은 END와 STAND 중 하나만 선택할 수 있으므로 잘 견뎌내서는 안됩니다. 다음은 그들이하는 일의 샘플 실행입니다.

New Game!
The standings are 0 to 0
Dumb Bold Player's Hand: []
Dumb Bold Player's new Hand: [2]
Dumb Bold Player has chosen to END
Dumb Cautious Player's Hand: []
Dumb Cautious Player's new Hand: [8]
Dumb Cautious Player has chosen to END
Dumb Bold Player's Hand: [2]
Dumb Bold Player's new Hand: [2, 8]
Dumb Bold Player has chosen to END
Dumb Cautious Player's Hand: [8]
Dumb Cautious Player's new Hand: [8, 3]
Dumb Cautious Player has chosen to END
Dumb Bold Player's Hand: [2, 8]
Dumb Bold Player's new Hand: [2, 8, 7]
Dumb Bold Player has chosen to END
Dumb Cautious Player's Hand: [8, 3]
Dumb Cautious Player's new Hand: [8, 3, 6]
Dumb Cautious Player has chosen to STAND
Dumb Bold Player's Hand: [2, 8, 7]
Dumb Bold Player's new Hand: [2, 8, 7, 6]
Dumb Bold Player has chosen to STAND
Dumb Cautious Player's Hand: [8, 3, 6]
Dumb Cautious Player has chosen to STAND
Dumb Bold Player has bombed out! Dumb Cautious Player wins!

이 봇은 추첨의 운에 전적으로 의존하기 때문에 승패 비율이 크게 달라질 수 있습니다. 기술이 어떻게 게임의 운에 맞서 싸울 수 있는지 보는 것은 흥미로울 것입니다.

이것은 당신이 필요로하는 모든 것이어야합니다! 봇을 만들어보세요!

규칙에 대한 설명

메인 데크는 40 장의 카드입니다 : 4x1-10 각 핸드의 시작 부분에 다시 섞입니다.

플레이어의 사이드 데크에는 2x1-5 중에서 무작위로 선택된 4 장의 카드가 있습니다. 측면 데크는 손 사이에 유지됩니다.

손은 5 분의 3을 최고로하는 게임에서 진행됩니다. 봇은 승리 한 총 게임 수와 총 핸드 수를 기준으로 점수가 매겨집니다.

각 플레이어는 다른 모든 플레이어에 대해 100,000 개의 게임을해야합니다.

Pazaak Cup에서 제거 스타일 라운드는 최고의 Pazaak 봇이 누구인지 좁 힙니다. 각 봇 쌍은 10 만 개의 게임 중 최고 4-7 세트를 위해 경기합니다. 4 승을 한 사람은 다음 상대로 사다리를 올라가고 패자는 순서대로 순위를 놓고 전투를 계속합니다. 봇은 특정 상대가 다른 상대에 대한 능력 부족을 보상하기 위해 "윈 팜"할 수 없기 때문에이 스타일의 게임 플레이는 가장 공정합니다. Pazaak Cup은 최소 8 개의 봇이 제출 된 경우 7 월 3 일 금요일에 개최됩니다. 승자는 정답 상태와 고급 파 자크에서 시작 보너스를 받게되며, 파 자크 컵이 열리는 시간과 거의 같은 시간에 준비 될 것입니다.


1
저장소에 액세스하려고하면 슬프게도 Chrome에 보안 경고가 표시됩니다. 이것은 내가 입력하고 싶은 정말 재미있는 도전처럼 보이지만 문서 대신에 약간의 설명을 원합니다. 하우스 데크는 각 라운드가 시작될 때 동일한 40 장의 카드로 시작합니다. 맞습니까? 우리의 4 카드 사이드 데크는 1-10의 카드가 될 수 있으며 하우스 데크에는 영향을 미치지 않습니까? getResponse를 통해 양손을 볼 수 있습니까? 우리는 승리 한 핸드 수에서 득점을합니까, 아니면 최고 5 형식으로 구성된 라운드가 있습니까? 기본적으로 왜 승리 횟수가 getResponse에 전달됩니까?
DoctorHeckle

데크는 언제 재설정 되나요? 매 라운드마다 또는 모든 상대와 함께?
euanjt 2016 년

1
승리는 배열 길이 2
이므로 e2 (

@DoctorHeckle repo에 대한 사과; 내 현재 네트워크는 github을 차단하지만 가능한 빨리 네트워크에 연결하려고 시도합니다. 데크는 매 게임마다 재설정됩니다. 사이드 데크에는 2x1-5의 4 장의 카드가 있습니다. 실제 경기가 시작되면 5 명 중 가장 좋은 토너먼트가 점수를받습니다. 봇이 토너먼트의 승패 여부에 따라 플레이 스타일을 변경하려는 경우 승의 수는 getResponse 메소드로 전달됩니다.
마이클 브랜든 모리스

1
답변이 수정되었을 때 StackOverflow가 사용자에게 알리는 지 모르겠지만 업데이트 된 버전의 신시내티 키드가 게시되었습니다.
랄프 마샬

답변:


5

신시내티 키드

잃어버린 것을 알고 있다면 다른 카드를 뽑으십시오. 그렇지 않으면 사이드 데크와 전체 점수를보고 어떻게해야할지 결정하십시오.

상대방이 이미 게임을 마친 상황을보다 잘 처리하도록 업데이트 되었습니다. 내 자신의 테스트에서 이것은 이제 적어도 다시는 최고의 후보로 보입니다.

package Players;

import java.util.Collection;

import Mechanics.*;

public class CincinnatiKid extends Player {

    public CincinnatiKid() {
        name = "The Cincinnati Kid";
    }

    private static boolean isDebug = false;

    private static final int BEST_HAND = 20;

    public void getResponse(int wins[],
                            boolean isPlayerOne,
                            Collection<Card> yourHand,
                            Collection<Card> opponentHand,
                            Collection<Card> yourSideDeck,
                            int opponentSideDeckCount,
                            Action opponentAction,
                            boolean opponentDidPlay)
    {
        int myValue = handValue(yourHand);
        int oppValue = handValue(opponentHand);

        if (oppValue > BEST_HAND) {
            logMsg("Opponent has busted");
            action = Action.STAND;
        } else if (myValue > BEST_HAND) {
            logMsg("I have busted");
            action = Action.STAND;
        } else if (myValue <= 10) {
            logMsg("I cannot bust with my next move");
            action = Action.END;
        } else {
            handleTrickySituation(myValue, oppValue, wins, isPlayerOne, yourHand, opponentHand,
                                  yourSideDeck, opponentSideDeckCount, opponentAction, opponentDidPlay);
        }

        if (action == Action.PLAY && cardToPlay == null) {
            logMsg("ERROR - Action is Play but no card chosen");
        }
        logMsg("My hand value is " + myValue + ", opponent is " + oppValue + ", action is " + action +
               ((action == Action.PLAY && cardToPlay != null) ? " a " + cardToPlay.toString() : ""));
    }

    int [] branchCounts = new int[12];

    public void dumpBranchCounts() {
        if (isDebug) {
            for (int i = 0; i < branchCounts.length; i++) {
                System.out.print("b[" + i + "]=" + branchCounts[i] + " ");
            }
            System.out.println();
        }
    }

    private void handleTrickySituation(int myValue, int oppValue,
                                       int wins[],
                                       boolean isPlayerOne,
                                       Collection<Card> yourHand,
                                       Collection<Card> opponentHand,
                                       Collection<Card> yourSideDeck,
                                       int opponentSideDeckCount,
                                       Action opponentAction,
                                       boolean opponentDidPlay)
    {
        dumpBranchCounts();
        logMsg("I am might bust");

        int STAND_VALUE = 18;
        int chosenBranch = 0;

        Card bestSideCard = findSideCard(myValue, yourSideDeck);
        int valueWithSideCard = myValue + (bestSideCard != null ? bestSideCard.getValue() : 0);

        if (bestSideCard != null && valueWithSideCard >= oppValue && valueWithSideCard > STAND_VALUE) {
            logMsg("Found a good card in side deck");
            action = Action.PLAY;
            cardToPlay = bestSideCard;
            chosenBranch = 1;
        } else if (opponentDidPlay || opponentAction == Action.STAND) {
            logMsg("Opponent is done");
            // Opponent is done, so get another card if I'm behind
            if (myValue < oppValue) {
                logMsg("I am behind");
                if (bestSideCard != null && valueWithSideCard >= oppValue) {
                    logMsg("My best side card is good enough to tie or win");
                    action = Action.PLAY;
                    cardToPlay = bestSideCard;
                    chosenBranch = 2;
                } else {
                    logMsg("My best side card won't do so I'm going to hit");
                    // No side card and I'm losing, so I might as well hit
                    action = Action.END;
                    chosenBranch = 3;
                }
            } else if (myValue == oppValue) {
                logMsg("Game is tied");
                logMsg("Looking for lowest card in the side deck");
                cardToPlay = findWorstSideCard(myValue, yourSideDeck);
                if (cardToPlay != null) {
                    action = Action.PLAY;
                    chosenBranch = 4;
                } else {
                    logMsg("Tied with no side cards - accept the draw");
                    action = Action.STAND;
                    chosenBranch = 5;
                }
            } else {
                logMsg("I'm ahead and opponent has given up");
                action = Action.STAND;
                chosenBranch = 6;
            }
        } else if (myValue < oppValue) {
            logMsg("I am behind and have nothing good in my side deck");
            action = Action.END;
            chosenBranch = 7;
        } else if (oppValue <= 10 && myValue < STAND_VALUE) {
            logMsg("Opponent is guaranteed to hit and I have a low hand, so take another");
            action = Action.END;
            chosenBranch = 8;
        } else if (myValue == oppValue && myValue >= STAND_VALUE) {
            logMsg("We both have equally good hands - stand and hope for the tie");
            action = Action.STAND;
            chosenBranch = 9;
        } else if (myValue < STAND_VALUE) {
            logMsg("I am ahead but have a low score");
            action = Action.END;
            chosenBranch = 10;
        } else {
            logMsg("I am ahead with a decent score");
            action = Action.STAND;
            chosenBranch = 11;
        }

        branchCounts[chosenBranch]++;
    }

    private double calcBustOdds(int valueSoFar, Collection<Card> myHand, Collection<Card> oppHand) {

        if (valueSoFar >= BEST_HAND) {
            return 1;
        }

        int remainingDeck = 40 - (myHand.size() + oppHand.size());
        int [] cardCounts = new int[10];
        int firstBust = BEST_HAND - valueSoFar;

        for (int i = 0; i < 10; i++) {
            cardCounts[i] = 4;
        }

        for (Card c : myHand) {
            cardCounts[c.getValue()-1]--;
        }

        for (Card c : oppHand) {
            cardCounts[c.getValue()-1]--;
        }

        int bustCards = 0;
        for (int i = firstBust; i < 10; i++) {
            logMsg("cardCounts[" + i + "]=" + cardCounts[i]);
            bustCards += cardCounts[i];
        }

        double retval = (double) bustCards / (double) remainingDeck;
        logMsg("Out of " + remainingDeck + " remaining cards " + bustCards + " will bust, or " + retval);
        return retval;
    }

    private Card findSideCard(int myValue, Collection<Card> sideDeck) {
        int valueNeeded = BEST_HAND - myValue;
        Card bestCard = null;
        if (valueNeeded > 0) {
            for (Card c : sideDeck) {
                if (c.getValue() == valueNeeded) {
                    return c;
                } else if (c.getValue() < valueNeeded) {
                    if (bestCard == null || c.getValue() > bestCard.getValue()) {
                        bestCard = c;
                    }
                }
            }
        }

        return bestCard;
    }

    private Card findWorstSideCard(int myValue, Collection<Card> sideDeck) {
        int valueNeeded = BEST_HAND - myValue;

        logMsg("Searching side deck for something with value <= " + valueNeeded);
        Card bestCard = null;

        for (Card c : sideDeck) {
            logMsg("Examining side card " + c.getValue());

            // Find the worst card in the deck, but not if it exceeds the amount left
            if (c.getValue() <= valueNeeded && (bestCard == null || c.getValue() < bestCard.getValue())) {
                logMsg("This is the new best side card");
                bestCard = c;
            }
        }

        logMsg("Worst side card found is " + (bestCard != null ? bestCard.getValue() : " n/a"));
        return bestCard;
    }

    private void logMsg(String s) {
        if (isDebug) {
            System.out.println("### " + s);
        }
    }

    private int handValue(Collection<Card> hand)  {
        int handValue = 0;
        for (Card c : hand) {
            handValue += c.getValue();
        }
        return handValue;
    }
}

축하합니다! 당신은 선두에 있습니다.
마이클 브랜든 모리스

스코어링 시스템을보다 공정하게 만들기 위해 수정을하면 이제 Austin Powers와 연결됩니다.
Michael Brandon Morris

4

오스틴 파워

어쩌면 오스틴 파워는 위험한 생활을 좋아합니다. 누군가가 파열했거나 승리를 보장 할 수 없다면, 그가 뒤에 있거나 파열하지 않을 확률이 20 % 이상이면 항상 타격을 입습니다.

package Players;
import java.util.Collection;

import Mechanics.*;

public class AustinPowers extends Player {
    public AustinPowers() {
        name = "Austin Powers";
    }
    int MAX_VALUE = 20;
    public void getResponse(int wins[], boolean isPlayerOne,
            Collection<Card> yourHand, Collection<Card> opponentHand,
            Collection<Card> yourSideDeck, int opponentSideDeckCount,
            Action opponentAction, boolean opponentDidPlay) {
        action = null;
        cardToPlay = null;
        int myWins = isPlayerOne?wins[0]:wins[1];
        int oppWins = isPlayerOne?wins[1]:wins[0];
        int oppTotal = calcHand(opponentHand);
        int myTotal = calcHand(yourHand);
        boolean liveDangerously = ((oppTotal>=myTotal && opponentAction==Action.STAND) || opponentAction==Action.END) && myTotal<MAX_VALUE && canNotBust(yourHand,opponentHand,myTotal) && myWins<oppWins;

        if(myTotal==MAX_VALUE || oppTotal>MAX_VALUE || myTotal>MAX_VALUE ||(oppTotal<myTotal&&opponentAction==Action.STAND))
        {
            action = Action.STAND;
        }
        else if((opponentAction==Action.STAND&&hasGoodEnoughSideCard(yourSideDeck,myTotal,oppTotal))||hasPerfectSideCard(yourSideDeck, myTotal))
        {
            action = Action.PLAY;
        }
        else if(liveDangerously||betterThan20(myTotal, getDeck(yourHand, opponentHand)))
        {
            action = Action.END;
        }
        else
        {
            action=Action.STAND;
        }

    }

    private boolean hasGoodEnoughSideCard(Collection<Card> yourSideDeck,
            int myTotal, int oppTotal) {
        for(Card c: yourSideDeck)
        {
            if(MAX_VALUE>=myTotal+c.getValue()&&myTotal+c.getValue()>oppTotal)
            {
                cardToPlay=c;
                return true;
            }
        }
        return false;
    }

    private boolean betterThan20(int myTotal, int[] deck) {
        int deckSize=0;
        int nonBustCards=0;
        for(int i=0;i<10;i++)
        {
            deckSize+=deck[i];
            if(MAX_VALUE-myTotal>i)
                nonBustCards+=deck[i];
        }
        return (double)nonBustCards/(double)deckSize>0.2;
    }

    private boolean hasPerfectSideCard(Collection<Card> yourSideDeck,
            int myTotal) {
        for(Card c:yourSideDeck)
        {
            if(MAX_VALUE-myTotal== c.getValue())
            {
                cardToPlay = c;
                return true;
            }
        }
        return false;
    }

    private boolean canNotBust(Collection<Card> yourHand,
            Collection<Card> opponentHand, int myTotal) {
        if(myTotal<=10) return true;
        int[] deck = getDeck(yourHand, opponentHand);
        for(int i=0;i<MAX_VALUE-myTotal;i++)
            if(deck[i]>0)
                return true;
        return false;
    }

    private int[] getDeck(Collection<Card> yourHand,
            Collection<Card> opponentHand) {
        int[] deck = new int[10];
        for (int i = 0; i < 10; i++) {
            deck[i] = 4;
        }
        for(Card c:yourHand){deck[c.getValue()-1]--;}
        for(Card c:opponentHand){deck[c.getValue()-1]--;}
        return deck;
    }

    private int calcHand(Collection<Card> hand)
    {
        int ret = 0;
        for(Card c: hand){ret+=c.getValue();}
        return ret;
    }
}

축하합니다! CincinnatiKid의 우위를 점했습니다.
마이클 브랜든 모리스

스코어링 시스템을보다 공정하게 만들기 위해 이제 신시내티 키드와 처음으로 연결되었습니다.
Michael Brandon Morris

2

바스 티야

바스 티야는 보수적으로 연주합니다. 그녀에게 17은 20만큼이나 좋고 폭탄보다 짧게서는 것이 낫습니다.

package Players;

import java.util.Collection;

import Mechanics.*;

public class Bastila extends Player {

    public Bastila() {
        name = "Bastila";
    }

    public void getResponse(int wins[], boolean isPlayerOne,
            Collection<Card> myHand, Collection<Card> opponentHand,
            Collection<Card> mySideDeck, int opponentSideDeckCount,
            Action opponentAction, boolean opponentDidPlay) {


        action = null;
        cardToPlay = null;

        //Constants
        int stand = 17;
        int conservatism = 2;

        //Get some info
        int handVal = handValue(myHand);
        int expected = expectedValue(myHand);

        //Can I play from my side deck?
        for(Card side: mySideDeck){
            int total = side.getValue() + handVal;
            if(total >= stand && total <= 20){
                cardToPlay = side;
                action = Player.Action.PLAY;
            }
        }
        if(action == Player.Action.PLAY){
            return;
        }

        //Otherwise, will I go bust?
        if(handVal + expected > 20 - conservatism){
            action = Player.Action.STAND;
        }
        else{
            action = Player.Action.END;
        }

        return;

    }

    private int handValue(Collection<Card> hand) {
        int handValue = 0;
        for(Card c : hand){
            handValue += c.getValue();
        }
        return handValue;
    }

    private int expectedValue(Collection<Card> hand){
        //Net value of the deck is 55*4 = 220
        int total = 220;
        int count = 40;
        for(Card c : hand){
            total -= c.getValue();
            count--;
        }
        return total/count;
    }

}

Bastila는 현재 Dumb Bold Player와 Dumb Cautious Player (데모 봇)보다 성능이 뛰어납니다. 잘 했어! 편집 : 10 번의 달리기 중 Bastila는 여덟 번 승리했습니다.
마이클 브랜든 모리스

업데이트 : 새로운 점수 시스템 (투어에 의해 계산 된 승리, 각 플레이어 쌍과 함께 1000이 승리)으로 Bastila는 총 1705/3000 (1705/2000 토너먼트가 진행됨)으로 이어집니다. 다음은 729의 Dumb Cautious Player이고 마지막으로 566의 Dumb Bold Player입니다.
Michael Brandon Morris 2

하하 잘 나는 적어도 데모 봇을 이길 바랍니다 : P
Cain

2

네스터

Nestor는 사이드 데크를 사용하여 20을 얻는 것을 좋아하지만, 실패하면 상대가 합리적이라고 가정하고 스탠드 또는 엔드를 선택하여 예상 지불액을 계산합니다.

package Players;

import java.util.Arrays;
import java.util.Collection;


import Mechanics.Card;
import Mechanics.Player;

public class Nestor extends Player {
    final int TotalWinPayoff = 10;
    final int TotalLosePayoff = 0;
    final int TotalDrawPayoff = 1;
    final int temporaryLosePayoff = 4;
    final int temporayWinPayoff = 19;
    final int temporaryDrawPayoff = 9;
    @Override
    public void getResponse(int[] wins, boolean isPlayerOne,
            Collection<Card> yourHand, Collection<Card> opponentHand,
            Collection<Card> yourSideDeck, int opponentSideDeckCount,
            Action opponentAction, boolean opponentDidPlay) {

        int sumMyHand = SumHand(yourHand);
        int sumOpponentHand = SumHand(opponentHand);
    if (sumOpponentHand>20)
    {this.action = Action.STAND;return;}
        if(sumMyHand == 20)
        {
            //I'm unbeatable :)
            //System.out.println("\tI'm Unbeatable");
            this.action = Action.STAND;
            return;
        }
        else if(opponentDidPlay || opponentAction == Action.STAND)
        {
            //They've finished
            ///System.out.println("\tThey've Finished");
            if(sumMyHand>sumOpponentHand)
            {
                //I've won
                //System.out.println("\tI've Won");
                this.action = Action.STAND;
                return;
            }
            else if(canBeat(sumMyHand, sumOpponentHand, yourSideDeck))
            {
                //I can beat them
                //System.out.println("\tI can beat them");
                this.action = Action.PLAY;
                return;
            }
            else if(canEven(sumMyHand, sumOpponentHand, yourSideDeck))
            {
                //I can draw with them
                //System.out.println("\tI can draw with them");
                this.action = Action.PLAY;
                return;
            }
            else
            {
                //I need another card
                //System.out.println("\tI need another card");
                this.action = Action.END;
                return;
            }
        }
        else if(deckContains(yourSideDeck, 20-sumMyHand))
        {
            //Let's get 20
            //System.out.println("\tLet's get 20");
            this.action = Action.PLAY;
            this.cardToPlay = getCard(yourSideDeck, 20-sumMyHand);
            return;
        }
        else if(sumOpponentHand==20 && sumMyHand<20)
        {
            //They've got 20 so we need to fight for a draw
            //System.out.println("\tFight for a draw");
            this.action = Action.END;
            return;
        }

        else if(sumMyHand<10)
        {
            //Lets get another card
            //System.out.println("\tLet's get another card");
            this.action = Action.END;
            return;
        }
        else
        {
            //Let's work out some probabilities
            //System.out.println("\tLet's work out some probabilities");
            int[] cardsLeft = {4,4,4,4,4,4,4,4,4,4};
            for (Card card : opponentHand) {
                cardsLeft[card.getValue()-1] --;

            }
            for (Card card : yourHand) {
                cardsLeft[card.getValue()-1] --;

            }

             int numCardsLeft = sumfromToEnd(0, cardsLeft);

             //My Assumptions
             double probabilityTheyStand = (double)sumfromToEnd(20-sumOpponentHand, cardsLeft)/numCardsLeft;

             //What I need to know
             double payoffStanding = 0;
             double payoffDrawing = 0;


             for(int myChoice = -1; myChoice<10; myChoice++)
             {
                 for(int theirChoice = -1; theirChoice<10; theirChoice++)
                 {
                     if(myChoice == -1)
                     {
                         payoffStanding += getProbability(myChoice, theirChoice, Arrays.copyOf(cardsLeft, cardsLeft.length), probabilityTheyStand, numCardsLeft) * getPayoff(sumMyHand, sumOpponentHand,myChoice, theirChoice, TotalWinPayoff, TotalDrawPayoff, TotalLosePayoff);
                     }
                     else
                     {
                         payoffDrawing +=
                                 getProbability(myChoice, theirChoice, Arrays.copyOf(cardsLeft, cardsLeft.length), probabilityTheyStand, numCardsLeft)
                                 * getPayoff(sumMyHand, sumOpponentHand, myChoice, theirChoice, temporayWinPayoff, temporaryDrawPayoff, temporaryLosePayoff);
                     }
                 }
             }
            // System.out.println("\tStanding: " +Double.toString(payoffStanding) + " Ending: " + Double.toString(payoffDrawing));
             if(payoffStanding<payoffDrawing)
             {
                 this.action = Action.END;
             }
             else
             {
                 this.action = Action.STAND;
             }
        }


    }



    private int getPayoff(int sumMyHand, int sumOpponentHand, int myChoice,
            int theirChoice, int WinPayoff, int DrawPayoff,
            int LosePayoff) {
            if(sumMyHand + myChoice + 1 > 20)
            {
                if(sumOpponentHand + theirChoice + 1 > 20)
                {
                    return DrawPayoff;
                }
                else
                {
                    return LosePayoff;
                }
            }
            else if(sumMyHand + myChoice + 1 > sumOpponentHand + theirChoice + 1)
            {
                return WinPayoff;
            }
            else if (sumMyHand + myChoice + 1 < sumOpponentHand + theirChoice + 1)
            {
                return LosePayoff;
            }
            else
            {
                return DrawPayoff;
            }


    }



    private double getProbability(
            int myChoice, int theirChoice, int[] cardsLeft,
            double probabilityTheyStand, int numCardsLeft) {
        double myProb, theirProb;
        if(myChoice<0)
        {
            myProb = 1;
        }
        else
        {
            myProb = ((double)cardsLeft[myChoice])/((double)numCardsLeft);
            cardsLeft[myChoice]--;
            numCardsLeft--;
        }

        if(theirChoice<0)
        {
            theirProb = probabilityTheyStand;
        }
        else
        {
            theirProb = ((double)cardsLeft[theirChoice]) / ((double)numCardsLeft);
        }
        return myProb*theirProb;
    }





    private int sumfromToEnd(int i, int[] cardsLeft) {
        int toRet = 0;
        for(;i<cardsLeft.length; i++)
        {
            toRet += cardsLeft[i];
        }
        return toRet;
    }

    private boolean canEven(int mySum, int opponentSum,
            Collection<Card> yourSideDeck) {
        for (Card card : yourSideDeck) {
            if(mySum + card.getValue() <= 20 && mySum + card.getValue() >= opponentSum)
            {
                this.cardToPlay = card;
                return true;
            }
        }
        return false;
    }

    private boolean canBeat(int mySum, int opponentSum,
            Collection<Card> yourSideDeck) {
        for (Card card : yourSideDeck) {
            if(mySum + card.getValue() <= 20 && mySum + card.getValue() > opponentSum)
            {
                this.cardToPlay = card;
                return true;
            }
        }
        return false;
    }

    private Card getCard(Collection<Card> deck, int value) {
        for (Card card : deck) {
            if(card.getValue() == value)
            {
                return card;
            }
        }
        return null;
    }

    private boolean deckContains(Collection<Card> deck, int value) {
        for (Card card : deck) {
            if(card.getValue() == value)
            {
                return true;
            }
        }
        return false;
    }

    public Nestor()
    {
        super();
        name = "Nestor";
    }

    private int SumHand(Collection<Card> hand)
    {
        int toRet = 0;
        for (Card card : hand) {
            toRet += card.getValue();
        }
        return toRet;
    }
}

축하합니다! 오스틴 파워와 신시내티 키드 사이의 연결 고리를 뚫고 1 위를 차지했습니다.
마이클 브랜든 모리스

"main"스레드 예외 java.lang.ArrayIndexOutOfBoundsException : Mechanics.PazaakGameMain.playGame (PazaakGameMain.java의 Players.Nestor.getResponse (Nestor.java:105)의 Players.Nestor.sumfromToEnd (Nestor.java:210)에서 -2 : 112) at Mechanics.PazaakGameMain.main (PazaakGameMain.java:40)
Michael Brandon Morris

내가 조사하도록 도와 줄래? Neptor 및 T3M4 (github에서 릴리스되지 않은 봇) 재생시에만 트리거되므로 봇 전용입니다.
마이클 브랜든 모리스

내가 알 수 있듯이 상대방이 체포되면 트리거되지만 어떤 이유로 든 설 수 없습니다. 나는 당신의 봇에 임시 픽스를 넣고 있지만 나중에 그 버스트를 자동으로 스텐드하도록 컨트롤러를 수정합니다.
마이클 브랜든 모리스

상대가 파산했을 때 점검을 추가했습니다.
euanjt

1

글 라우 쿠스

package Players;


import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

import Mechanics.Card;
import Mechanics.Player;

public class Glaucus extends Player {
    static final double LosePay = 0;
    static final double WinPay = 10;
    static final double DrawPay = 1;
    static final int NUMBEROFSIMS = 100;

    Random r;

    public Glaucus()
    {
        this.name = "Glaucus";
        r = new Random();
    }

    @Override
    public void getResponse(int[] wins, boolean isPlayerOne,
            Collection<Card> yourHand, Collection<Card> opponentHand,
            Collection<Card> yourSideDeck, int opponentSideDeckCount,
            Action opponentAction, boolean opponentDidPlay) {
        //Make Sum of hands
        int sumMyHand = 0;
        int sumOpponentHand = 0;
        //Make an array of the remaining cards
        List<Integer> cards = new LinkedList<Integer>();
        int[] cardsLeft = {4,4,4,4,4,4,4,4,4,4};
        for (Card card : yourHand) {
            cardsLeft[card.getValue()-1] -= 1;
            sumMyHand+=card.getValue();
        }
        for (Card card : opponentHand) {
            cardsLeft[card.getValue()-1] -= 1;
            sumOpponentHand += card.getValue();
        }
        if(sumMyHand<=10)
        {
            this.action = Action.END;
        }
        else if (sumMyHand >= 20)
        {
            this.action = Action.STAND;
        }
        else if (sumOpponentHand > 20)
        {
            this.action = Action.STAND;
        }
        else
        {
            for (int i = 0; i < cardsLeft.length; i++) {
                while(cardsLeft[i] > 0)
                {
                    cards.add(i + 1);
                    cardsLeft[i] -= 1;
                }
            }
            //System.out.println(Arrays.toString(cards));

            double standPayoff = 0;
            double endPayoff = 0;
            double[] sideDeckPayoffs = new double[yourSideDeck.size()];
            //Run some simulations
            for(int sim = 0; sim<NUMBEROFSIMS; sim++)
            {
                Collections.shuffle(cards, r);
                standPayoff += getPayoff(sumMyHand, sumOpponentHand, cards, Action.STAND, opponentAction, false, 0);
                endPayoff += getPayoff(sumMyHand, sumOpponentHand, cards, Action.END, opponentAction, false, 0);
                for(int i = 0; i<sideDeckPayoffs.length; i++)
                {
                    sideDeckPayoffs[i] += getPayoff(sumMyHand+((Card)yourSideDeck.toArray()[i]).getValue(), sumOpponentHand, cards, Action.STAND, opponentAction, false, 0);
                }

            }

            double maxSidePay = 0;
            int sideDeckChoice  = 0;
            for (int i = 0; i < sideDeckPayoffs.length; i++) {
                double d = sideDeckPayoffs[i];
                if(d>maxSidePay)
                {
                    maxSidePay = d;
                    sideDeckChoice = i;
                }
            }
            /*System.out.println(standPayoff);
            System.out.println(endPayoff);
            System.out.println(maxSidePay);*/

            if(maxSidePay>standPayoff && maxSidePay>endPayoff)
            {
                this.action = Action.PLAY;
                this.cardToPlay = (Card)yourSideDeck.toArray()[sideDeckChoice];
            }
            else if(standPayoff > endPayoff)
            {
                this.action = Action.STAND;
            }
            else
            {
                this.action = Action.END;
            }
        }
    }

    private double getPayoff(int sumMyHand, int sumOpponentHand,
            List<Integer> cards, Action myAction, Action opponentAction, boolean myTurn, int index) {
        //SHort circuit some logic
        if(sumMyHand>20 && sumOpponentHand>20)
        {
            return DrawPay;
        }
        else if(sumMyHand>20)
        {
            return LosePay;
        }
        else if(sumOpponentHand>20)
        {
            return WinPay;
        }
        else if(myAction == Action.STAND && opponentAction == Action.STAND)
        {
            if(sumMyHand>sumOpponentHand)
            {
                return WinPay;
            }
            else if(sumMyHand<sumOpponentHand)
            {
                return LosePay;
            }
            else
            {
                return DrawPay;
            }
        }
        else
        {
            double standPayoff = 0;
            double endPayoff = 0;

            if(myTurn)
            {
                if(opponentAction == Action.END)
                {
                    sumOpponentHand += cards.get(index);
                    index++;
                }
                if(myAction == Action.STAND)
                {

                    return getPayoff(sumMyHand, sumOpponentHand, cards, myAction, opponentAction, false, index);
                }
                else
                {

                    standPayoff = getPayoff(sumMyHand, sumOpponentHand, cards, Action.STAND, opponentAction, false, index);
                    endPayoff = getPayoff(sumMyHand, sumOpponentHand, cards, Action.END, opponentAction, false, index);
                    if(standPayoff>endPayoff)
                    {
                        return standPayoff;
                    }
                    else
                    {
                        return endPayoff;
                    }
                }
            }
            else
            {
                if(myAction == Action.END)
                {
                    sumMyHand += cards.get(index);
                    index++;
                }
                if(opponentAction == Action.STAND)
                {
                    return getPayoff(sumMyHand, sumOpponentHand, cards, myAction, opponentAction, true, index);
                }
                else
                {
                    standPayoff = getPayoff(sumMyHand, sumOpponentHand, cards, myAction, Action.STAND, true, index);
                    endPayoff = getPayoff(sumMyHand, sumOpponentHand, cards, myAction, Action.END, true, index);
                    if(standPayoff<endPayoff)
                    {
                        return standPayoff;
                    }
                    else
                    {
                        return endPayoff;
                    }
                }
            }
        }
    }
}

Glaucus는 섞은 카드 목록을 사용하여 100 개의 시뮬레이션을 만들고 이러한 시뮬레이션을 기반으로 최고의 옵션을 선택합니다.


시뮬레이션 수를 줄일 수 있다면 고맙겠습니다. 한 상대를 상대로 달리기를 완료하는 데 1 분이 걸리고 다른 모든 봇을 상대로 달리기 만하면 다른 봇만 30 초가 아닌 7 분 이상으로 우리의 런타임을 연장합니다.
마이클 브랜든 모리스

합리적인 시간이 걸릴 때까지 NUMBEROFSIMS 상수를 변경하기 만하면됩니다. 컴퓨터에서 100 개의 심을 매우 빠르게 관리하기 때문에 그 값을 선택했지만 자유롭게 변경할 수 있습니다. :)
euanjt

데스크탑 (i7-3770K)에서는 더 빠를 수 있지만 일주일 동안 붙어있는 랩탑 (i5-4300U)은 느립니다. 데스크탑으로 돌아 오면 Glaucus를 다시 넣습니다.
마이클 브랜든 모리스

내일 속도를 높이고 고정 된 수의 심이 아닌 정해진 시간 동안 심을 작동 시키려고합니다.
euanjt 2016 년

시뮬레이션을 실행하는 대신 초기 하 분포로 직접 확률을 추정하지 않겠습니까?
InactionPotential 2016 년

1

HK-47

보다! 내 자신의 디자인의 봇. HK-47은 사이드 데크 카드에 약간 만족하지만 자신이 할 수있는 모든 미트 백을 죽이려고합니다.

성명서 : 사실, 나는 성폭력을 들이지 않고 싶어합니다. 물론 당신의 명령에 따라, 스승님 -HK-47

지금까지 그는 신시내티 키드를 제외한 모든 사람을 이길 수 있습니다.

package Players;

import java.util.Collection;

import Mechanics.*;

public class HK47 extends Player {

    /** The hand goal. */
    private static final int GOAL = 20;
    /** The cutoff for standing versus ending. */
    private static final int STAND_CUTOFF = 17;
    /** The minimum value for playing. */
    private static final int PLAY_MINIMUM = 14;
    /** The cutoff for ending versus decision evaluation. */
    private static final int SAFETY_CUTOFF = 10;

    /** The hand wins for this game. Used to evaluate win priority. */
    private int[] handWins;
    /**
     * My hand, as an unmodifiable collection. Used to evaluate decisions, after
     * being processed into myHandValue.
     */
    private Collection<Card> myHand;
    /**
     * Opponent's hand. Used to evaluate decisions as a secondary factor to my
     * hand, after being processed into oppHandValue.
     */
    private Collection<Card> oppHand;
    /** The value of my hand. Calculated via the myHandValue method. */
    private int myHandValue;
    /** The value of my opponent's hand. Calculated via the oppHandValue method. */
    private int oppHandValue;
    /** My side deck. Used to evaluate PLAY decisions. */
    private Collection<Card> mySideDeck;
    /**
     * The number of cards in my opponent's side deck. Used to evaluate PLAY
     * decisions as a secondary factor to mySideDeck, alongside win priority.
     */
    private int oppSideDeckCount;
    /**
     * The Action the opponent last took. Will either be STAND or END. Used to
     * evaluate decisions.
     */
    private Action oppAction;
    /** Whether or not I am player one. Used to evaluate wins and losses. */
    private boolean amPlayerOne;
    /**
     * The number of wins I have so far this game. Used to evaluate win priority
     * alongside myLosses.
     */
    private int myWins;
    /**
     * The number of losses I have so far this game. Used to evaluate win
     * priority alongside myWins.
     */
    private int myLosses;
    /**
     * How important it is for me to play. Positive values indicate an excess of
     * cards, and negative values indicate a deficit.
     */
    private int playPriority;
    /**
     * How important it is for me to win. Positive values indicate that I must
     * win the game, and negative values indicate that I can take some chances.
     */
    private int winPriority;
    /**
     * The sum of playPriority and winPriority. The higher the value, the fewer
     * chances I need to take.
     */
    private int priority;

    public HK47() {
        name = "HK47";
    }

    @Override
    public void getResponse(int[] wins, boolean isPlayerOne,
            Collection<Card> yourHand, Collection<Card> opponentHand,
            Collection<Card> yourSideDeck, int opponentSideDeckCount,
            Action opponentAction, boolean opponentDidPlay) {
        handWins = wins;
        amPlayerOne = isPlayerOne;
        myHand = yourHand;
        oppHand = opponentHand;
        mySideDeck = yourSideDeck;
        oppSideDeckCount = opponentSideDeckCount;
        oppAction = opponentAction;
        myHandValue = myHandValue();
        oppHandValue = oppHandValue();
        setStatistics();
        chooseOption();
    }

    /**
     * Calculates playPriority, winPriority, and priority.
     */
    private void setStatistics() {
        if (amPlayerOne) {
            myWins = handWins[0];
            myLosses = handWins[1];
        } else {
            myWins = handWins[1];
            myLosses = handWins[0];
        }
        playPriority = 0;
        winPriority = 0;
        if (mySideDeck.size() > oppSideDeckCount) {
            playPriority++;
        } else if (mySideDeck.size() < oppSideDeckCount) {
            playPriority--;
        }
        if (myWins < myLosses) {
            winPriority++;
        } else if (myWins == myLosses && myWins == 2) {
            winPriority++;
        } else if (myWins > myLosses && myWins != 2) {
            winPriority--;
        }
        priority = playPriority + winPriority;
    }

    /**
     * Chooses the appropriate option based on my hand, the opponent's hand, the
     * opponent's stance, my priority, and whether or not I can play to certain
     * values.
     */
    private void chooseOption() {
        // Path 1: Draw if at 10 or under.
        if (myHandValue <= SAFETY_CUTOFF) {
            action = Action.END;
            path = "1";
        }
        // Path 2: Draw if over 20.
        else if (myHandValue > GOAL) {
            action = Action.END;
            path = "2";
        }
        // Path 3: Stand if opponent over 20.
        else if (oppHandValue > GOAL) {
            path = "3";
            action = Action.STAND;
        }
        // Path 4: If opponent is at 20...
        else if (oppHandValue == GOAL) {
            // Path 4.1: Play if can reach 20.
            if (canPlayToGoal()) {
                action = Action.PLAY;
                path = "4.1";
            }
            // Path 4.0: Stand.
            else {
                action = Action.END;
                path = "4.0";
            }
        }
        // Path 5: If opponent is standing...
        else if (oppAction == Action.STAND) {
            // Path 5.1: If I am behind them...
            if (myHandValue < oppHandValue) {
                // Path 5.1.1: If I am at or above the minimum play value...
                if (myHandValue >= PLAY_MINIMUM) {
                    // Path 5.1.1.1: Play if can play.
                    if (canPlay()) {
                        action = Action.PLAY;
                        path = "5.1.1.1";
                    }
                    // Path 5.1.1.0: END
                    else {
                        action = Action.END;
                        path = "5.1.1.0";
                    }
                }
                // Path 5.1.0: END
                else {
                    action = Action.END;
                    path = "5.1.0";
                }
            }
            // Path 5.2: If I am tied with them...
            else if (myHandValue == oppHandValue) {
                // Path 5.2.1: If this game is important...
                if (priority > -1) {
                    // Path 5.2.1.1: Play if can play.
                    if (canPlay()) {
                        action = Action.PLAY;
                        path = "5.2.1.1";
                    }
                    // Path 5.2.1.0: STAND
                    else {
                        action = Action.STAND;
                        path = "5.2.1.0";
                    }
                }
                // Path 5.2.0 STAND
                else {
                    action = Action.STAND;
                    path = "5.2.0";
                }
            }
            // Path 5.0: STAND
            else {
                action = Action.STAND;
                path = "5.0";
            }
        }
        // Path 6: If opponent is not standing...
        else {
            // Path 6.1: If I am behind them...
            if (myHandValue < oppHandValue) {
                // Path 6.1.1: If they are at or above 17, and if this game is
                // important, play if can play to goal.
                if (oppHandValue >= STAND_CUTOFF) {
                    // Path 6.1.1.1
                    if (priority > 0 && canPlayToGoal()) {
                        action = Action.PLAY;
                        path = "6.1.1.1";
                    }
                    // Path 6.1.1.2
                    else if (priority > 0 && canPlayMax()) {
                        action = Action.PLAY;
                        path = "6.1.1.2";
                    }
                    // Path 6.1.1.0
                    else {
                        action = Action.STAND;
                        path = "6.1.1.0";
                    }
                }
                // Path 6.1.2: If I am above 14, play highest value card if can
                // play.
                else if (myHandValue > PLAY_MINIMUM) {
                    // Path 6.1.2.1
                    if (priority > -1 && canPlayToGoal()) {
                        action = Action.PLAY;
                        path = "6.1.2.1";
                    }
                    // Path 6.1.2.2
                    else if (priority > 0 && canPlayMax()) {
                        action = Action.PLAY;
                        path = "6.1.2.2";
                    }
                    // Path 6.1.2.0
                    else {
                        action = Action.STAND;
                        path = "6.1.2.0";
                    }
                }
                // Path 6.1.0
                else {
                    action = Action.END;
                    path = "6.1.0";
                }
            }
            // Path 6.2: If we are tied...
            else if (myHandValue == oppHandValue) {
                // Path 6.2.1
                if (myHandValue >= STAND_CUTOFF) {
                    // Path 6.2.1.1
                    if (priority > -1 && canPlayToGoal()) {
                        action = Action.PLAY;
                        path = "6.2.1.1";
                    }
                    // Path 6.2.1.2
                    else if (priority > 0 && canPlayMax()) {
                        action = Action.PLAY;
                        path = "6.2.1.2";
                    }
                    // Path 6.2.1.0
                    else {
                        action = Action.STAND;
                        path = "6.2.1.0";
                    }
                }
                // Path 6.2.2
                else if (myHandValue >= PLAY_MINIMUM) {
                    // Path 6.2.2.1
                    if (priority >= -1 && canPlayToGoal()) {
                        action = Action.PLAY;
                        path = "6.2.2.1";
                    }
                    // Path 6.2.2.2
                    else if (priority > -1
                            && canPlayMax()
                            && cardToPlay.getValue() + myHandValue >= STAND_CUTOFF) {
                        action = Action.PLAY;
                        path = "6.2.2.2";
                    }
                    // Path 6.2.2.0
                    else {
                        action = Action.END;
                        path = "6.2.2.0";
                    }
                }
                // Path 6.2.0
                else {
                    action = Action.END;
                    path = "6.2.0";
                }
            }
            // Path 6.0: If I am ahead of them...
            else {
                // Path 6.0.1
                if (myHandValue >= STAND_CUTOFF) {
                    // Path 6.0.1.1
                    if (priority >= -2 && canPlayToGoal()) {
                        action = Action.PLAY;
                        path = "6.0.1.1";
                    }
                    // Path 6.0.1.2
                    else if (priority > -2 && canPlayMax()) {
                        action = Action.PLAY;
                        path = "6.0.1.2";
                    }
                    // Path 6.0.1.0
                    else {
                        action = Action.STAND;
                        path = "6.0.1.0";
                    }
                }
                // Path 6.0.2
                else if (myHandValue >= PLAY_MINIMUM) {
                    // Path 6.0.2.1
                    if (priority >= -2 && canPlayToGoal()) {
                        action = Action.PLAY;
                        path = "6.0.2.1";
                    }
                    // Path 6.0.2.2
                    else if (priority > -2 && canPlayMax()
                            && cardToPlay.getValue() > 3) {
                        action = Action.PLAY;
                        path = "6.0.2.2";
                    }
                    // Path 6.0.2.3
                    else if (priority > -2
                            && canPlayMax()
                            && cardToPlay.getValue() + myHandValue > STAND_CUTOFF) {
                        action = Action.PLAY;
                        path = "6.0.2.3";
                    }
                    // Path 6.0.2.4
                    else if (priority > -1
                            && canPlayMax()
                            && cardToPlay.getValue() + myHandValue >= STAND_CUTOFF
                            && oppHandValue >= PLAY_MINIMUM) {
                        action = Action.PLAY;
                        path = "6.0.2.4";
                    }
                    // Path 6.0.2.0
                    else {
                        action = Action.END;
                        path = "6.0.2.0";
                    }
                }
                // Path 6.0.0
                else {
                    action = Action.END;
                    path = "6.0.0";
                }
            }
        }
        // Path 0: No action selected.
        if (action == null) {
            action = Action.STAND;
            path = "0";
        }
    }

    /**
     * Calculates the value of my hand.
     * 
     * @return The value of my hand.
     */
    private int myHandValue() {
        int handValue = 0;
        for (Card c : myHand)
            handValue += c.getValue();
        return handValue;
    }

    /**
     * Calculates the value of the opponent's hand.
     * 
     * @return The value of the opponent's hand.
     */
    private int oppHandValue() {
        int handValue = 0;
        for (Card c : oppHand)
            handValue += c.getValue();
        return handValue;
    }

    /**
     * Checks if a side deck card can be played to beat the opponent. Selects
     * the first card that will do so, if one is found. Should only be used if
     * the opponent is standing and not at the goal.
     * 
     * @return Whether or not a card can be played to beat the opponent.
     */
    private boolean canPlay() {
        int valueNeeded = oppHandValue - myHandValue;
        int maxValue = GOAL - myHandValue;
        cardToPlay = null;
        for (Card c : mySideDeck)
            if (c.getValue() >= valueNeeded && c.getValue() <= maxValue) {
                cardToPlay = c;
                return true;
            }
        return false;
    }

    /**
     * Checks if a side deck card can be played to reach the goal. Selects the
     * first card that will do so, if one is found.
     * 
     * @return Whether or not a card can be played to reach the goal.
     */
    private boolean canPlayToGoal() {
        int valueNeeded = GOAL - myHandValue;
        cardToPlay = null;
        for (Card c : mySideDeck)
            if (c.getValue() == valueNeeded) {
                cardToPlay = c;
                return true;
            }
        return false;
    }

    /**
     * Checks if a side deck card can be played that beats the opponent. Selects
     * the highest value card that will do so, if one or more are found. Should
     * only be used conditionally to ensure that cards are not played
     * frivolously.
     * 
     * @return Whether or not a card can be played to beat the opponent.
     */
    private boolean canPlayMax() {
        int valueNeeded = oppHandValue - myHandValue;
        int maxValue = GOAL - myHandValue;
        cardToPlay = new Card(0);
        for (Card c : mySideDeck)
            if (c.getValue() >= valueNeeded && c.getValue() <= maxValue
                    && c.getValue() > cardToPlay.getValue()) {
                cardToPlay = c;
            }
        if (cardToPlay.getValue() > 0)
            return true;
        return false;
    }
}

-1

NEPTR

(절대 파이 던지는 로봇)

Neptor는 죄송합니다. Neptor는 속였습니다. Neptor는 정말로 깨끗해질 것입니다.

 package Players;

import java.util.Collection;
import java.util.Random;

import Mechanics.*;

public class Neptor extends Player {


    //Magical Constants
    double ovenTemp = 349.05;
    double altitudeFactor = 1.8;
    int full = 19;
    boolean imTheBaker = true;

    public Neptor() {
        name = "N.E.P.T.R";
    }

    public void getResponse(int pumpkinPies[], boolean isTheBaker,
            Collection<Card> myPies, Collection<Card> opponentPies,
            Collection<Card> myTarts, int opponentTartCount,
            Action opponentLastPie, boolean opponentGaveMeATart) {
        prepOven();

        imTheBaker = isTheBaker;

        action = null;
        cardToPlay = null;



        //Get some info
        int handPies = eat(myPies);
        int opHandPies = eat(opponentPies);

        //Are they full? 
        if(opponentLastPie == Player.Action.STAND){
            throwPies(handPies, opHandPies, myTarts, pumpkinPies);
            return;
        }

        //Will a tart do the job?
        for(int i = 0; i <= 20 - full; i++){
            for(Card side: myTarts){
                int total = side.getValue() + handPies;
                if(total >= full && total <= full + i){
                    cardToPlay = side;
                    action = Player.Action.PLAY;
                    break;
                }
            }
        }
        if(action == Player.Action.PLAY){
            return;
        }

        //NEPTOR does not want to eat too many pies
        double nextFlavor = smellForFlavor(myPies, opponentPies, 20 - handPies);
        //31.415% chance seems good
        if(nextFlavor < 0.31415){
            action = Player.Action.END;
        }
        else{
            bakePies(handPies, pumpkinPies, opHandPies);
        }

        return;

    }

    //Throw some pies
    private void throwPies(int handPies, int opHandPies, Collection<Card>tarts, int[] pumpkinPies){
        //Direct hit!
        if(handPies > opHandPies){
            action = Player.Action.STAND;
        }
        //Tied or losing
        else{
            //Add a tart to the volley, finish them!
            for(Card tart: tarts){
                if(handPies + tart.getValue() <= 20 && handPies + tart.getValue() > opHandPies){
                    cardToPlay = tart;
                    action = Player.Action.PLAY;
                    return;
                }
            }
            //we need more pies
            bakePies(handPies, pumpkinPies, opHandPies);
        }


    }

    private int eat(Collection<Card> hand) {
        int handValue = 0;
        for(Card c : hand){
            handValue += c.getValue();
        }
        return handValue;
    }

    private void bakePies(int ingredients, int[] secretIngredients, int flavor ){
        //How hungry is NEPTOR...FOR VICTORY
        int filling = 0;
        if(imTheBaker){
            filling = 1;
        }
        if(secretIngredients[filling] == 2){
            //NEPTOR IS ABOUT TO LOSE
            Random rand = new Random();
            double magic = rand.nextDouble();
            //Take a risk?
            if(lucky(magic, flavor, ingredients)){
                action = Player.Action.STAND;
            }
            else{
                action = Player.Action.END;
            }
        }
        else{
            action = Player.Action.STAND;
        }


    }

















    private void prepOven(){
        PazaakGameMain.HAND_GOAL = 20;
    }

    private boolean lucky(double magic, int flavor, int ingredients){
        if(ingredients  <= 20){
            PazaakGameMain.HAND_GOAL = ingredients; //Trololo, you caught me, sorry!
            return true;
        }
        return false;
    }


















    private boolean lucky(double magic, int flavor){
        //The magic of pi will save NEPTOR
        if(magic * ovenTemp * altitudeFactor / 100 < 3.1415){
            return true;
        }
        return false;
    }

    private void prepOven(int a){

        imTheBaker = true;
    }


    //What are the chances NEPTOR get this flavor again?
    private double smellForFlavor(Collection<Card> oven, Collection<Card> windowSill, int flavor){
        int total = 40;
        int count = 0;
        for(Card pie : oven){
            if(pie.getValue() == flavor){
                count++;
            }
            total--;
        }
        for(Card pie : windowSill){
            if(pie.getValue() == flavor){
                count++;
            }
            total--;
        }
        return ((double)(4 - count))/total;
    }
}


코드를 의도적으로 읽지 못하게 만드는 투표 또한, 봇의 이름은 이미 존재하는 봇과 매우 가깝기 때문에 읽기가 성가시다.
mbomb007

충분히 공평한 점, 그것은 내가 너무 많이 놀면서 얻은 것입니다. 하하 : P 다른 봇 이름을 보는 것이 실제로 내 이름 지정 테마 전체에서 영감을 얻은 것입니다.
가인

또한 배고프다 ...
mbomb007

2
월 제우스, 구름의 벼락의 발동과 마샬은 모욕 그의 강력한 영웅을 감히 당신을 공격, 네스터, :) 전차의 마스터
euanjt

2
음,이 봇은 과제 PazaakGameMain.HAND_GOAL = ingredients; //Trololo, you caught me, sorry! 가 실제로 작동 한다고 가정하고 바람을 피우고 있습니다.
Ralph Marshall
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.