Simple Pazaak (карточная игра «Звездные войны» от рыцарей старой республики)

11

Pazaak - карточная игра из вселенной Звездных войн. Это похоже на Блэкджек, когда два игрока сражаются друг против друга, пытаясь достичь двадцати, не переходя. У каждого игрока есть «боковая колода» из четырех собственных карт, которые они могут использовать для изменения своего счета.

Leaderboard

По состоянию на 17.06.2015, 16:40 EDT

Изменить: Нептор был дисквалифицирован за мошенничество. Результаты будут исправлены как можно скорее ...

  1. НЕПТР: ~ 424 000
  2. Цинциннати Кид: ~ 422 000
  3. Нестор: ~ 408 000
  4. Остин Пауэрс: ~ 405 000
  5. Бастила: ~ 248 000
  6. Тупой осторожный игрок: ~ 107 000
  7. Тупой смелый игрок: ~ 87 000

Плей-офф Кубка Пакака

Будет обновлено как можно скорее.

Первый раунд - Нестор против Бастилы и Остина Пауэрса против Цинциннати Кид

Результаты 1 тура

Второй раунд - Нестор против Остина Пауэрса и Цинциннати Кид против Бастилы

Результаты 2 тура

механика

Геймплей делается по очереди. Игроку 1 сдается карта из основной (домашней) колоды. Колода дома содержит сорок карт: четыре копии от одной до 10. После раздачи карты они могут закончить свой ход и получить новую карту в следующем ходу, стоять на своем текущем уровне или сыграть карту из своей боковой колоды и стоять на новом значении. После того, как игрок один решает, что он хочет сделать, игрок второй повторяет процесс.

Как только оба игрока ушли, руки оцениваются. Если игрок бомбил (прошло более двадцати), другой игрок выиграет, при условии, что он также не бомбил. Если игрок решил встать, а у другого игрока более высокая ценность руки, другой игрок выиграет. Если оба игрока решили встать, победит игрок с более высоким достоинством руки. В случае ничьей ни один из игроков не получает победы.

Если условие выигрыша не выполнено, игра повторится. Если игрок решил закончить свой ход, он получит новую карту и сможет сделать новый выбор. Если они решат встать или если они разыграли карту из своей боковой колоды, им не будет выдана новая карта, и они не смогут выбрать новое действие.

Игра продолжается, пока один из игроков не выиграет. Игры разыгрываются в лучших сетах из пяти.

Почему «простой» пазаак?

Во вселенной «Звездных войн» Пазаак занимался азартными играми. Хотя включение такой системы добавило бы в игру больше динамики, она немного сложна для первого соревнования KoTH.

«Настоящие» боковые колоды Pazaak также были предоставлены самими игроками и могли включать в себя множество различных вариантов карт, таких как негативные карты, позитивные или негативные карты, флип-карты, двойные карты и карты разрешения конфликтов. Это также сделало бы игру более интересной, но потребовало бы игрового интерфейса на месте и потребовало бы гораздо большего от конкурентов. В этой простой игре Pazaak каждый игрок получает одну и ту же боковую колоду: две копии от одного до пяти, из которых четыре выбираются случайным образом.

В зависимости от успеха этой игры, я могу приложить усилия для разработки продвинутой версии, в которой возможны игровые и специальные боковые колоды.

Игроки

Игроками этой игры будут разработанные вами боты. Каждый бот должен расширять класс Player, импортировать пакет Mechanics и находиться в пакете Players следующим образом:

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 может установить два свойства: действие и карту для игры. Действие может быть одним из следующих:

  • КОНЕЦ: Заканчивает ход и в следующем ходу берет новую карту.
  • STAND: остается на текущем значении руки. Не будет рисовать карту.
  • PLAY: проигрывает карту из боковой колоды и затем встает.

Разыгрываемая карта, очевидно, важна только в том случае, если вы установили действие на ИГРА. Требуется объект карты. Если объект карты, который вы передаете ему, не существует в вашей боковой колоде, ваш бот вместо этого будет стоять.

Параметры, которые ваш бот получает каждый ход:

  • Массив, содержащий выигрыши каждого игрока. выигрывает [0] игрока 1, выигрывает 1 игрока 2 (int [])
  • Является ли ваш бот первым игроком (булево)
  • Коллекция карт, которые вы уже раздали (Коллекция)
  • Коллекция карт вашего оппонента была разыграна до сих пор (Коллекция)
  • Коллекция карт в вашей боковой колоде (Коллекция)
  • Количество карт, оставшихся в боковой колоде противника (int)
  • Действие вашего противника в последний раз (Действие) [Примечание: это будет либо КОНЕЦ, либо СТЕНД, никогда не ИГРАТЬ]
  • Играл ли ваш оппонент в карту (булево)

Правила бота

Ваши боты могут использовать только ту информацию, которая им предоставлена ​​через метод 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!

Поскольку эти боты полагаются исключительно на удачу в ничьей, их соотношение выигрышей и проигрышей может сильно различаться. Будет интересно посмотреть, как умение может побороть удачу в игре.

Это должно быть все, что вам нужно! Иди построй несколько ботов!

Разъяснение к правилам

Основная колода состоит из сорока карт: 4x1-10. Перетасовывается в начале каждой руки.

В боковой колоде игрока есть четыре карты, выбранные случайным образом из 2x1-5. Боковая дека сохраняется между руками.

Руки разыгрываются в играх на тройку из пяти. Боты оцениваются по общему количеству выигранных игр, а затем по общему количеству рук.

Соответствие обрабатывается так, что каждый игрок должен будет сыграть 100 000 игр против любого другого игрока.

В Pazaak Cup раунды в стиле исключения сузят, кто же на самом деле лучший бот Pazaak. Каждая пара ботов будет играть за лучшие четыре из семи наборов из 100 000 игр. Кто бы ни выиграл четыре, он поднимется вверх по лестнице к следующему противнику, а проигравшие останутся в битве за последовательные рейтинги. Этот стиль геймплея является наиболее справедливым, поскольку боты не могут «выиграть-фармить» определенных противников, чтобы компенсировать недостаток способностей против других. Кубок Pazaak будет проведен в пятницу, 3 июля, при условии, что будет представлено по меньшей мере восемь ботов. Победитель получит статус «Правильный ответ» и стартовый бонус в Advanced Pazaak, который, как мы надеемся, будет готов к тому же времени, что и Кубок Pazaak.

Майкл Брэндон Моррис
источник
1
К сожалению, попытка получить доступ к репо дает мне предупреждения о безопасности в Chrome. Кажется, это действительно забавный вызов, в который я бы хотел попасть, но мне хотелось бы получить некоторые разъяснения вместо документации. Домашняя колода начинается с тех же 40 карт в начале каждого раунда, верно? Наша колода из 4 карт может быть любой картой 1-10 и не влияет на колоду дома? Обе руки видны через getResponse? Будем ли мы забивать по количеству выигранных рук, или есть раунды, состоящие из пяти лучших форматов? В основном, почему количество побед передается в getResponse?
DoctorHeckle
Когда колода сбрасывается? После каждого раунда или только с каждым противником?
euanjt
1
Это должны быть выигрыши [1] для побед игрока 2, а не выигрыши [2], поскольку выигрыши - это всего лишь длина массива 2
euanjt
@DoctorHeckle Извинения за репо; моя текущая сеть блокирует github, но я постараюсь как можно быстрее ее установить. Колода сбрасывается в каждой игре. В боковой колоде находятся четыре карты 2х1-5. Как только начинается настоящее соревнование, вы будете оцениваться турнирами, которые являются лучшими из пяти. Количество выигрышей передается методу getResponse в случае, если ваш бот хочет изменить свой стиль игры в зависимости от того, выиграл он или проиграл турнир.
Майкл Брэндон Моррис
1
Я не знаю, уведомляет ли вас StackOverflow о том, что ответ был отредактирован, но сейчас у меня есть обновленная версия The Cincinnati Kid.
Ральф Маршалл

Ответы:

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;
    }
}
Ральф Маршалл
источник
Поздравляем! Вы в лидерах.
Майкл Брэндон Моррис
С изменениями, которые сделают систему начисления очков более справедливой, вы в первую очередь связаны с Остином Пауэрсом.
Майкл Брэндон Моррис
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;
    }
}
Fongoid
источник
Поздравляем! Вы взяли на себя инициативу от ЦинциннатиКид.
Майкл Брэндон Моррис
С изменениями, которые сделают систему начисления очков более справедливой, вы в первую очередь связаны с The Cincinnati Kid.
Майкл Брэндон Моррис
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;
    }

}
Каин
источник
Бастила в настоящее время выигрывает у Dumb Bold Player и Dumb Causive Player (демо-боты). Отличная работа! Изменить: Из десяти пробежек Бастила выиграла восемь, проиграв Dumb Осторожный игрок один раз, и один раз связав с Dumb Осторожный игрок.
Майкл Брэндон Моррис
Обновление: с новой системой подсчета очков (выигрыши подсчитываются турнирами, из которых 1000 сыграно с каждой парой игроков), Бастила лидирует с общим количеством 1705/3000 (сыграно 1705/2000 турниров). Следующим является Dumb Осторожный игрок с 729, и, наконец, Dumb Bold Player с 566.
Майкл Брэндон Моррис
Хаха хорошо, я надеюсь, что это по крайней мере бьет демо-ботов: P
Каин
2

Нестор

Нестор любит получать 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;
    }
}
euanjt
источник
Поздравляем! Вы прорвались через ничью между Остином Пауэрсом и Цинциннати Кид, чтобы занять первое место.
Майкл Брэндон Моррис
Исключение в потоке "основной" : 112) в Mechanics.PazaakGameMain.main (PazaakGameMain.java:40)
Майкл Брэндон Моррис
Не могли бы вы помочь мне разобраться в этом? Похоже, что он специфичен для ботов, так как он запускается только при игре с Neptor и T3M4 (невыпущенный бот на github)
Майкл Брэндон Моррис
Из того, что я могу сказать, это срабатывает, если ваш оппонент обанкротился, но по какой-то причине он не выдержал. Я помещаю временное исправление в вашего бота, но позже исправлю контроллер, чтобы автоматически ОСТАНОВИТЬ ботов.
Майкл Брэндон Моррис
Я добавил проверку того, когда оппонент
разорился
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;
                    }
                }
            }
        }
    }
}

Главк делает 100 симуляций с перемешанным списком карт и выбирает свой лучший вариант на основе этих симуляций.

euanjt
источник
Я был бы признателен, если бы вы могли сократить количество симуляций. Чтобы закончить заезд с одним противником, требуется более минуты, а против всех остальных ботов время выполнения у нас составляет более 7 минут, в отличие от 30 секунд с другими ботами.
Майкл Брэндон Моррис
Просто меняйте константу NUMBEROFSIMS до тех пор, пока она не займет разумное количество времени, на моем компьютере она довольно быстро управляет 100 симами, поэтому я выбрал это значение, но не стесняйтесь менять его :)
euanjt
Это может быть быстрее на моем рабочем столе (i7-3770K), но мой ноутбук (i5-4300U) (который я застрял на неделю) медленнее. Я верну Глакуса обратно, когда вернусь к своему рабочему столу.
Майкл Брэндон Моррис
Завтра я попытаюсь ускорить его, и пусть он будет запускать симов в течение определенного времени, а не фиксированного количества симов - сколько времени допустимо на ход?
euanjt
Вместо того, чтобы проводить симуляции, почему бы не оценить вероятности непосредственно с помощью гипергеометрического распределения?
БездействиеПотенциал
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

(Никогда не заканчивающийся робот, бросающий пирог)

Нептор извини, Нептора обманули. Нептор действительно собирался прийти чистым, он просто хотел сначала повеселиться :(

 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
Честно говоря, это то, что я получаю за то, что играю слишком много, ха-ха.
Каин
Это также делает меня голодным ...
mbomb007
2
Пусть Зевс, обладатель молнии и предводитель облаков, ударит вас за то, что осмелился оскорбить своего могучего героя Нестора, повелителя колесницы :)
euanjt
2
Хм, этот бот обманывает, предполагая, что задание PazaakGameMain.HAND_GOAL = ingredients; //Trololo, you caught me, sorry! действительно работает.
Ральф Маршалл