それはBSです!(トランプゲーム)


29

BSは、ゲームの目的がすべてのカードを失うことであるカードゲームです。

ゲームは4人のプレーヤーと52枚のカードデッキで構成されます。各プレイヤーにはランダムに13枚のカードが配られます。通常、カードには2〜10、エース、ジャック、クイーン、キングのラベルが付けられますが、簡単にするために、カードには0〜12の番号が付けられます。プレーヤーの手にあるカードの数は公開情報ですが、プレーヤーだけが自分の手にある特定のカードを知っています。

ゲームは次のようになります:最初のプレーヤーは、0のラベルが付いたカードを好きなだけ捨て札の山に置きます(通常は、0のラベルが付いたすべてのカードをプレイする必要はありませんが、そうするのが最善です) )。彼は少なくとも1枚のカードをプレイしなければなりません。2番目のプレーヤーは1のラベルを付けたい数のカードをプレイし、3番目のプレーヤーは2をプレイします。12の後、0にリセットされます。

あなたがプレイすることになっているカードのいずれかを持っていない場合はどうなりますか?覚えておいて、あなたは少なくとも1枚のカードをプレイする必要があります-実際には、あなたが望むカードをプレイすることができます!(実際、正しいカードを持っている場合でも、嘘をついて別のカードをプレイできます)。ただし、誰かがあなたに電話して「BS!」と言うことはできます。その誰かが正しく、あなたが嘘をついていたなら、あなたは捨て札の山にあるすべてのカードを取らなければなりません。報酬として、あなたをコールしたプレイヤーは、自分のカードの1つを捨て札の山にランダムに置きます。ただし、告発者が間違っている場合、彼はすべてのカードを破棄パイルに入れなければなりません。あなたがプレイするカードのについて嘘をつくことができないことに注意してください。

より詳細な情報:

  • ゲームの開始時に、4人のランダムなプレイヤーが選ばれます。少なくとも1000のゲームがあるため、各プレイヤーはプレイする機会を得ます。ターン順は、ゲームの開始時にランダムに決定されます
  • あなたは1枚の正しいカードと1枚の間違ったカードを返却した場合、それは嘘と考えられている(あなたが与えることになっていた場合、すなわち2秒を、あなたは1与えた2と1 1を、その後のが嘘をついていることを、)
  • 2人以上のプレイヤーが両方とも同時にBSと言う場合、1人がランダムに選択されます。
  • スコアは、勝ったゲームの割合です。
  • 最大1000ラウンドがあり、1ラウンドはすべてのプレーヤーが1回行くことです。通常、この前に誰かが勝ちます。誰も勝てない場合、プレイされたゲームの総数にカウントされますが、誰も勝ちません。

仕様:

を拡張するクラスを作成する必要がありますPlayer。次のようになります。

package players;

import java.util.ArrayList;
import java.util.List;

import controller.*;

public class Player1 extends Player {

    @Override
    protected List<Card> requestCards(int card, Controller controller) {
        Card[] hand = getHand();
        List<Card> ret =  new ArrayList<Card>();
        for (Card c : hand) {
            if (c.getNumber() == card) {
                ret.add(c);
            }
        }
        if (ret.size() == 0) ret.add(hand[0]);
        return ret;
    }

    @Override
    protected boolean bs(Player player, int card, int numberOfCards, Controller controller) {
        return numberOfCards >= 3;
    }

    protected void update(Controller controller) {
      // This method gets called once at the end of every round
    }

    protected void initialize(Controller controller) {
      // This method gets called once at the beginning once all the cards are dealt
    }

    public String toString() {
        return "Player 1";
    }
}

requestCardsあなたの番になると、メソッドが呼び出されます。引数cardは、提供することになっているカード番号です。廃棄パイルに入れたいカードのリストを返します。上記のプレーヤーは、要求されたカードタイプのカードがあるかどうかを確認します。そうでない場合、彼は単に最初のカードをプレイし、誰もチェックしないことを望みます。

このメソッドbsは、他の誰かがカードをプレイするたびに呼び出されます。最初の引数はプレーヤーであり、2番目はプレーヤーがプレーするはずだったカード、3番目はプレーヤーがプレーしたと主張するそのタイプのカードの番号です。true「BS」を呼び出す場合に戻ります。上記のコードでは、プレーヤーは、他のプレーヤーが要求されたタイプのカードを3枚以上持っていると主張する場合にのみ「BS」を呼び出します。

両方のメソッドの最後の引数controllerは、ゲームを制御する単なるコントローラーです。コントローラーから、より多くの公開情報を取得できます。たとえば、破棄パイル内のカードの数や、プレーヤーのリストとターンの順番などです。

このtoString方法はオプションです。

GitHubのコントローラー:https : //github.com/prakol16/bs

Java以外のソリューションを投稿する場合は、https://github.com/LegionMammal978/bs(LegionMammal978の功績)で提供されているインターフェイスを使用できます。統合を試みます。

これまでのスコアボード:

class players.PlayerConMan: 2660/4446 = 59.82905982905983%
class players.CalculatingLiar: 2525/4426 = 57.049254405784005%
class players.PlayerTruthy: 1653/4497 = 36.75783855903936%
class players.Player4: 1446/4425 = 32.67796610169491%
class players.Player1: 536/4382 = 12.23185759926974%
class players.Player3: 493/4425 = 11.141242937853107%
class players.Player2: 370/4451 = 8.312738710402156%
class players.LiePlayer: 317/4432 = 7.152527075812275%
class players.Hoarder: 0/4516 = 0.0%

PlayerConManが勝ちましたが、CalculatingLiarは1秒以内です。これらのスコアは一貫しているように見えます-それらは毎回ほぼ同じです。


13
あなたは私をからかっている必要があります。この正確な課題を作成することを唯一の目的として、BS用のほぼ完成したコントローラーがあります。まあ、私は今、私の時間を過ごすために他の方法を見つける必要があると思います。
IchBinKeinBaum

3
Controller.toString()すべてのプレイヤーの手とパイルを捨てるので、一般に公開しないことをお勧めします。
-es1024

@IchBinKeinBaum、コントローラーがSTDIN / STDOUTと通信できる場合、すべてのJava以外のユーザーのために、コントローラーでチャレンジを公開することを検討できます。
ロジックナイト

@CarpetPython:あります。また、わずかに異なるルールを使用します。それが重複としてカウントされない場合、私はそうします。
IchBinKeinBaum

多言語コントローラーの作成が完了しました。使用法はProgram.csにあります。ここで見つけることができます。
LegionMammal978

回答:


10

詐欺師

ConManは手札を通過するすべてのカードを監視し、カードの場所が原因でプレイが不可能な場合にBSを呼び出します。

可能な場合は真実を再生しますが、勝利が発生した場合、最後のカードを使用して知的に嘘をつきます。

対戦相手が嘘をついている可能性が高い場合、またはBSを呼び出すのが有益である場合(廃棄パイルから有用なカードを取得するなど)、BSを呼び出すためのテクニックを調整するのに長い時間を費やしましたが、実際には、BSを呼び出すことはまったくありませんでした私が最もポイント。

package players;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import controller.*;
import java.text.DecimalFormat;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;

public class PlayerConMan extends Player {

    private enum Location {

        PLAYER_0,
        PLAYER_1,
        PLAYER_2,
        PLAYER_3,
        DISCARD,
        UNKNOWN
    };

    private class MyCard {

        private final int number;
        private Location location;
        private double confidence;
        protected Card card;

        public MyCard(int x) {
            this.number = x;
            location = Location.UNKNOWN;
            confidence = 1.0;
        }

        @Override
        public String toString() {
            if (confidence > 0.75) {
                return ""+number;
            } else if (confidence > 0.25) {
                return number+"*";
            } else {
                return number+"_";
            }
        }
    }

    private final ArrayList<ArrayList<MyCard>> theDeck = new ArrayList();
    private Location myLocation;
    private ArrayList<Player> players;
    private final ArrayList<MyCard> myHand = new ArrayList();
    private final HashMap<Location, Integer> sizes = new HashMap();
    private ArrayList<Integer> lies = new ArrayList();
    private ArrayList<Integer> truths = new ArrayList();


    // Constructor
    public PlayerConMan() {
        for (int i = 0; i < 13; ++i) {
            ArrayList<MyCard> set = new ArrayList();
            for (int j = 0; j < 4; ++j) {
                set.add(new MyCard(i));
            }
            theDeck.add(set);
        }
        sizes.put(Location.PLAYER_0, 13);
        sizes.put(Location.PLAYER_1, 13);
        sizes.put(Location.PLAYER_2, 13);
        sizes.put(Location.PLAYER_3, 13);
        sizes.put(Location.DISCARD, 13);
        sizes.put(Location.UNKNOWN, 39);
    }

    //Gets the MyCard for this card, updating a MyCard with the lowest confidence if not already created
    private MyCard getCard(Card c) {
        ArrayList<MyCard> set = theDeck.get(c.getNumber());
        MyCard unknown = null;
        double confidence = 1.0;
        for (MyCard m : set) {
            if (m.card == c) {
                return m;
            }
            if (m.card == null) {
                if (m.location == Location.UNKNOWN) {
                    unknown = m;
                    confidence = 0.0;
                } else if (m.confidence < confidence || unknown == null) {
                    unknown = m;
                    confidence = m.confidence;
                }
            }
        }
        unknown.card = c;
        return unknown;
    }

    //Returns the Location of a player
    private Location getLocation(Player p) {
        return Location.values()[players.indexOf(p)];
    }

    @Override
    protected void initialize(Controller controller) {
        super.initialize(controller);
        players = new ArrayList(controller.getPlayers());
        for (Player p : players) {
            if (p == this) {
                myLocation = getLocation(p);
            }
        }
        for (Location loc : Location.values()) {
            sizes.put(loc, 0);
        }
    }

    private ArrayList<Integer>[] getTruthesAndLies(Player player, int card, ArrayList<MyCard> myHand) {
            //Determine our next plays
            int offset = players.indexOf(player);
            int myOffset = players.indexOf(this);
            int nextCard = (card + (myOffset - offset + 4) % 4)%13;
            ArrayList<Integer> truths = new ArrayList();
            ArrayList<Integer> lies = new ArrayList();
            ArrayList<MyCard> cardsLeft = new ArrayList(myHand);
            while (!cardsLeft.isEmpty()) {
                boolean isLie = true;
                Iterator<MyCard> it = cardsLeft.iterator();
                while (it.hasNext()) {
                    MyCard m = it.next();
                    if (m.number == nextCard) {
                        it.remove();
                        isLie = false;
                    }
                }
                if (isLie) {
                    lies.add(nextCard);
                } else {
                    truths.add(nextCard);
                }
                nextCard = (nextCard + 4)%13;
            }

            return new ArrayList[]{truths, lies};
    }

    private void updateDeck(Player player, int card, int numberOfCards, Controller controller) {
        Location loc = getLocation(player);

        //Update from BS
        if (sizes.get(Location.DISCARD) + numberOfCards != controller.getDiscardPileSize()) {

            //Move all cards from DISCARD to the losing player
            //  Losing player defaults to player playing, in the rare case of a tie
            Location losingPlayer = loc;
            Location winningPlayer = null;
            for (Player p : players) {
                Location pLoc = getLocation(p);
                int size = p.handSize();
                if (pLoc == loc) size += numberOfCards;
                if (p.handSize() > sizes.get(pLoc)) {
                    losingPlayer = pLoc;
                } else if (size < sizes.get(pLoc)) {
                    winningPlayer = pLoc;
                }
            }

            if (winningPlayer == null) {
                debug(losingPlayer+" lost a BS");
            } else {
                debug(losingPlayer+" lied and "+winningPlayer+" lost a card");
            }

            //Move the cards from the discard to the player
            ArrayList<MyCard> winnersHand = new ArrayList();
            for (ArrayList<MyCard> set : theDeck) {
                for (MyCard m : set) {
                    if (m.location == Location.DISCARD) {
                        if (losingPlayer == myLocation) {
                            //If we lost, update the discard cards to unknown;
                            //  They'll be updated when we look at our hand
                            m.location = Location.UNKNOWN;
                            m.confidence = 1.0;
                        } else {
                            //Move to the losing player
                            m.location = losingPlayer;
                        }
                    } else if (m.location == myLocation && winningPlayer == myLocation) {
                        //Update our old cards to the discard pile, in case we won
                        m.location = Location.DISCARD;
                        m.confidence = 1.0;
                    } else if (m.location == winningPlayer) {
                        //Add the card to the winner's hand for later processing
                        winnersHand.add(m);
                    }
                }
            }

            //If someone else won, adjust the probabilities on their cards
            if (winningPlayer != myLocation && winningPlayer != null) {
                int winningSize = players.get(winningPlayer.ordinal()).handSize();
                if (winningPlayer == loc) winningSize += numberOfCards;
                for (MyCard m : winnersHand) {
                    m.confidence *= 1-(1/winningSize);
                }
            }

        }
        sizes.put(Location.DISCARD, controller.getDiscardPileSize());
        //Update player handSize
        for (Player p : players) {
            sizes.put(getLocation(p), p.handSize());
        }


        //Detect if my hand size has changed to speed processing
        if (myHand.size() != handSize()) {
            //Update values from my hand
            myHand.clear();
            for (Card c : getHand()) {
                MyCard m = getCard(c);
                m.location = myLocation;
                m.confidence = 1.0;
                myHand.add(m);
            }

            //Determine our next plays
            ArrayList<Integer> tl[] = getTruthesAndLies(player, card, myHand);
            truths = tl[0];
            lies = tl[1];
            debug("Truthes: "+truths);
            debug("Lies: "+lies);
        }
    }


    @Override
    protected List<Card> requestCards(int card, Controller controller) {
        updateDeck(this, card, 0, controller);

        ArrayList<Card> ret = new ArrayList();
        int pick = card;
        boolean all = true;
        if (truths.get(0) != card) {
            pick = truths.get(truths.size()-1);
            all = false;
        }

        for (MyCard m : myHand) {
            if (m.number == pick) {
                m.location = Location.DISCARD;
                ret.add(m.card);
                if (!all) break;
            }
        }

        sizes.put(Location.DISCARD, controller.getDiscardPileSize() + ret.size());
        sizes.put(myLocation, myHand.size() - ret.size());
        printTheDeck();

        return ret;
    }

    @Override
    protected boolean bs(Player player, int card, int numberOfCards, Controller controller) {
        updateDeck(player, card, numberOfCards, controller);
        Location loc = getLocation(player);

        //Get total number of unknown cards and total number of cards the player must have
        int handSize = player.handSize() + numberOfCards;
        ArrayList<MyCard> playerHand = new ArrayList();
        ArrayList<MyCard> discardPile = new ArrayList();
        double totalUnknown = 0;
        double playerUnknown = handSize;
        double cardsHeld = 0;
        double cardsNotHeld = 0;
        for (ArrayList<MyCard> set : theDeck) {
            for (MyCard m : set) {
                if (m.location == Location.UNKNOWN) {
                    totalUnknown++;
                } else if (m.location == loc) {
                    playerHand.add(m);
                    playerUnknown -= m.confidence;
                    totalUnknown += 1.0 - m.confidence;
                    if (m.number == card) {
                        cardsHeld += m.confidence;
                    }
                } else {
                    if (m.location == Location.DISCARD) {
                        discardPile.add(m);
                    }
                    totalUnknown += 1.0 - m.confidence;
                    if (m.number == card) {
                        cardsNotHeld += m.confidence;
                    }
                }
            }
        }

        boolean callBS = false;
        double prob;
        int possible = (int)Math.round(4-cardsNotHeld);
        int needed = (int)Math.round(numberOfCards - cardsHeld);
        if (needed > possible) {
            //Player can't possibly have the cards
            prob = 0.0;
            debug("impossible");
            callBS = true;
        } else if (needed <= 0) {
            //Player guaranteed to have the cards
            prob = 1.0;
            debug("guaranteed");
        } else {
            //The probability that player has needed or more of the possible cards
            double successes = 0;
            for (int i = (int)needed; i <= (int)possible; i++) {
                successes += choose(possible, i) * choose(totalUnknown-possible, playerUnknown-i);
            }
            double outcomes = choose(totalUnknown, playerUnknown);
            prob = successes / outcomes;
            if (Double.isNaN(prob)) {
                prob = 0;
                callBS = true;
            }
            debug("prob = "+new DecimalFormat("0.000").format(prob));
        }

        //Update which cards they may have put down
        //  Assume they put down as many as they could truthfully
        int cardsMoved = 0;
        Iterator<MyCard> it = playerHand.iterator();
        while (it.hasNext()) {
            MyCard m = it.next();
            if (m.number == card) {
                it.remove();
                m.location = Location.DISCARD;
                discardPile.add(m);
                cardsMoved++;
                if (cardsMoved >= numberOfCards) {
                    break;
                }
            }
        }

        //We can't account for all the cards they put down
        //  Adjust existing probabilities and move our lowest confidence cards to the discard
        if (cardsMoved < numberOfCards) {
            //  Reduce the confidence of all remaining cards, in case they lied
            //  Assumes they lie at random
            double cardsLeft = handSize-cardsMoved;
            double cardsNeeded = numberOfCards-cardsMoved;
            double probChosen = 1 * choose(cardsLeft-1, cardsNeeded-1) / choose(cardsLeft, cardsNeeded);
            if (Double.compare(cardsLeft, cardsNeeded) == 0) {
                //They're gonna win, call their bluff
                callBS = true;
                for (MyCard m : playerHand) {
                    m.location = Location.DISCARD;
                }
            } else {
                for (MyCard m : playerHand) {
                    m.confidence *= (1-probChosen) * (1-prob) + prob;
                }
            }

            //  Move any UNKNOWN cards they could have played, assuming they told the truth
            Collections.sort(theDeck.get(card), new Comparator<MyCard>() {
                @Override
                public int compare(MyCard o1, MyCard o2) {
                    double p1 = o1.confidence - (o1.location == Location.UNKNOWN ? 10 : 0);
                    double p2 = o2.confidence - (o2.location == Location.UNKNOWN ? 10 : 0);
                    return (int)Math.signum(p1-p2);
                }
            });
            for (MyCard m : theDeck.get(card)) {
                if (m.location == Location.UNKNOWN || m.confidence < prob) {
                    m.location = Location.DISCARD;
                    m.confidence = prob;
                    cardsMoved++;
                    discardPile.add(m);
                    if (cardsMoved >= numberOfCards) break;
                }
            }
        }

        //Get the confidence of the discardPile
        double discardPileConfidence = 1.0;
        for (MyCard m : discardPile) {
            discardPileConfidence *= m.confidence;
        }
        discardPileConfidence *= Math.pow(0.5, controller.getDiscardPileSize() - discardPile.size());

        //Call BS if the cards in the discard pile consists only of cards we need / will play
        if (discardPileConfidence > 0.5 && discardPile.size() == controller.getDiscardPileSize()) {
            double truthCount = 0;
            double lieCount = 0;
            double unknownCount = 0;
            for (MyCard m : discardPile) {
                if (truths.contains(m.number)) {
                    truthCount += m.confidence;
                    unknownCount += 1-m.confidence;
                } else if (lies.contains(m.number)) {
                    lieCount += m.confidence;
                    unknownCount += 1-m.confidence;
                } else {
                    unknownCount += 1;
                    break;
                }
            }
            if (lieCount > 0 && unknownCount < 1) {
                debug("Strategic BS");
                //callBS = true;
            }
        }

        //What's the worst that could happen?
        //Test the decks' 
        ArrayList<MyCard> worstHand = new ArrayList<MyCard>(myHand);
        worstHand.addAll(discardPile);
        ArrayList<Integer> loseCase[] = getTruthesAndLies(player, card, worstHand);
        int winPlaysLeft = truths.size() + lies.size();
        int losePlaysLeft = loseCase[0].size() + loseCase[1].size();
        double randomPlaysLeft = Math.max(losePlaysLeft,7);
        double expectedPlaysLeft = losePlaysLeft * discardPileConfidence + randomPlaysLeft * (1-discardPileConfidence);
        double threshold = 0.0 - (expectedPlaysLeft - winPlaysLeft)/13.0;
        debug("winPlaysLeft = "+winPlaysLeft);
        debug("expectedPlaysLeft   = "+expectedPlaysLeft);
        debug("Threshold    = "+threshold);

        if(lies.isEmpty()) {
            threshold /= 2;
        }
        //callBS = callBS || prob < threshold;

        printTheDeck();
        return callBS;
    }

    static double logGamma(double x) {
        double tmp = (x - 0.5) * Math.log(x + 4.5) - (x + 4.5);
        double ser = 1.0 + 76.18009173 / (x + 0) - 86.50532033 / (x + 1)
                + 24.01409822 / (x + 2) - 1.231739516 / (x + 3)
                + 0.00120858003 / (x + 4) - 0.00000536382 / (x + 5);
        return tmp + Math.log(ser * Math.sqrt(2 * Math.PI));
    }

    static double gamma(double x) {
        return Math.exp(logGamma(x));
    }

    static double factorial(double x) {
        return x * gamma(x);
    }

    static double choose(double n, double k) {
        if (Double.compare(n, k) == 0 || Double.compare(k, 0) == 0) return 1.0;
        if (k < 0 || k > n) {
            return 0.0;
        }
        return factorial(n) / (factorial(n-k) * factorial(k));
    }

    public String toString() {
        return "ConMan";
    }

    public void printTheDeck() {
        HashMap<Location, ArrayList<MyCard>> map = new HashMap();
        for (Location loc : Location.values()) {
            map.put(loc, new ArrayList());
        }
        for (ArrayList<MyCard> set : theDeck) {
            for (MyCard m : set) {
                map.get(m.location).add(m);
            }
        }
        String ret = "";
        for (Player p : players) {
            ret += p.toString()+": "+map.get(getLocation(p))+"\n";
        }
        ret += "Discard pile: "+map.get(Location.DISCARD)+"\n";
        ret += "Unknown: ("+map.get(Location.UNKNOWN).size()+" cards)\n";
        debug(ret);
    }

    public void debug(Object s) {

    }
}

良くやった。このボットは、これまでのところほとんどのゲームで簡単に勝ちます。
soktinpk

ありがとうございました!コードを見ると、BSが完全に不可能だと言ったときにcallBSを忘れていたことがわかりました。上記のコードを更新しました。
Wasmoo

4

プレイヤー3131961357_10

各ゲームでランダムなプレイヤーを選択し、常にそのプレイヤーでBSを呼び出します。

package players;

import java.util.ArrayList;
import java.util.List;

import controller.*;

public class Player3131961357_10 extends Player{
    private int[] ducks = new int[13];
    private Player target = null;
    private int cake = 0;

    @Override
    protected List<Card> requestCards(int bacon, Controller controller){
        Card[] hand = getHand();
        List<Card> ret = new ArrayList<Card>();
        List<Card> others = new ArrayList<Card>();
        for(Card c:hand){
            if(c.getNumber() == bacon){
                ret.add(c);
            }else{
                others.add(c);
            }
        }
        if(ret.size() == 0){
            ImperfectPlayer.moveRandom(others, ret);
        }
        if(others.size() > 0 && ret.size() < 3 && handSize() > ret.size() + 1){
            ImperfectPlayer.moveRandom(others, ret);
        }
        return ret;
    }

    private final int someoneLied = 0;
    @Override
    protected boolean bs(Player player, int bacon, int howMuchBacon, Controller controller){
        if(target == null){
            // Could not find my cake.
            // Someone must have taken it.
            // They are my target.
            List<Player> players = controller.getPlayers();
            do target = players.get((int)Math.floor(Math.random() * players.size()));
            while(target != this);
        }

        int count = 0;
        Card[] hand = getHand();
        for(Card c:hand){
            if(c.getNumber() == bacon) 
                ++count;
        }
        if(cake >= controller.getDiscardPileSize()){
            ducks = new int[13];
            cake = someoneLied;
        }
        ducks[bacon] += howMuchBacon;
        cake += howMuchBacon;

        if(player.handSize() == 0) return true;
        return player.handSize() == 0 
            || howMuchBacon + count > 4 
            || ducks[bacon] > 5 
            || player == target 
            || Math.random() < 0.025; // why not?
    }

    public String toString(){
        return "Player 3131961357_10";
    }

    public static <T> void moveRandom(List<T> from, List<T> to){
        T a = from.remove((int)Math.floor(Math.random() * from.size()));
        to.add(a);
    }
}

4

真実の

BSを呼び出した結果を伝える方法がわからないため(完全に終わっていません。

現時点では、証明できる場合にのみBSに電話してください。必要がない限り嘘をつかないでください。嘘つきアルゴリズムを改善する必要があります。私は他のプレイヤーとBSをプレイする方法にできるだけ近づけるようにしています(マイナスでランダムに追加のカードを下に置いて、5または6を知らずにプレイします)。

package players;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import controller.*;

public class PlayerTruthy extends Player {

    private List<Card> played;
    private int discardPileSize;
    private HashMap<String,Integer> handSizes;
    private boolean initialized;
    //controller.getDiscardPileSize()

    // Constructor
    public PlayerTruthy() {
        played = new ArrayList<Card>();
        handSizes = new HashMap<String,Integer>();
        discardPileSize = 0;
        initialized = false;
    }

    // Initialize (do once)
    private void init(Controller controller) {
        for (Player p : controller.getPlayers()) {
            handSizes.put(p, 0);
        }
        initialized = true;
    }

    @Override
    protected List<Card> requestCards(int card, Controller controller) {
        if (!initialized) {
            init(controller);
        }
        List<Card> cards = getCards(card);
        if (cards.size() == 0) {
            cards = lieCards(card);
        }
        played.addAll(cards);
        return cards;
    }

    @Override
    protected boolean bs(Player player, int card, int numberOfCards, Controller controller) {
        if (!initialized) {
            init(controller);
        }
        List<Card> hand = Arrays.asList(getHand());
        int count = countCards(hand, card);
        return numberOfCards > 4-count;
    }

    public String toString() {
        return "Truthy";
    }

    private int countCards(List<Card> list, int card) {
        int count = 0;
        for (Card c : list) {
            if (c.getNumber() == card) {
                count++;
            }
        }
        return count;
    }

    private List<Card> getCards(int card) {
        List<Card> cards = new ArrayList<Card>();
        Card[] hand = getHand();
        for (Card c : hand) {
            if (c.getNumber() == card) {
                cards.add(c);
            }
        }
        return cards;
    }

    private List<Card> lieCards(int card) {
        List<Card> hand = Arrays.asList(getHand());
        List<Card> cards = new ArrayList<Card>();
        int limit = 1;
        int count = 0;
        int index = (card+9) % 13;
        while (cards.size() == 0) {
            count = countCards(hand, index);
            if (count <= limit) {
                cards = getCards(index);
            }
            if (limit >= 3) {
                cards.removeRange(1, cards.size());
            }
            if (index == card) {
                limit++;
            }
            index = (index+9) % 13;
        }
        return cards;
    }
}

1
また、プレイしたカードを追跡することもできます。
seequ

あなたが何をしようとしているのか分からないcards = cards.get(0)cardsはリストなので、にCardを割り当てることはできませんList<Card>。最初の要素以外のすべてを削除しようとしていますか?
soktinpk

はい、修正しました。
mbomb007

BSの結果は、各プレーヤーの手のサイズを記憶し、その後、自分の記憶をコントローラーの持っているものと比較することで見つけました。増加とは、プレーヤーが負けたことを意味します。減少は、そのプレーヤーが勝ったことを意味します。(呼び出されnumberOfCardsたときに既に破棄されているため、現在のプレーヤーのハンドサイズはによって相殺される必要がありますbs
-Wasmoo

自分がやりたいことを実装する時間があるかどうかはわかりません。BSを最適にプレイする方法を考えれば考えるほど、プログラミングは難しくなります。ConManの機能をある程度実行したかったのですが、私にとってはその複雑さは少しだけです。
mbomb007

4

計算する

これは真実を演じようとします。彼が嘘をついている場合、彼は近い将来使用しないカードを使用します。また、最後のカードがほとんど収まらないため、他のプレーヤーでBSを呼び出してトラフに勝とうとします。

package players;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import controller.Card;
import controller.Controller;
import controller.Player;

public class CalculatingLiar extends Player {
    private final List<Integer> knownCardsOnDeck = new ArrayList<>();
    private int lastDeckSize = 0;

    @Override
    protected List<Card> requestCards(int card, Controller controller) {
        Card[] hand = getHand();
        List<Card> ret =  new ArrayList<Card>();
        for (Card c : hand) {
            if (c.getNumber() == card) {
                ret.add(c);
            }
        }
        if (ret.size() == 0) {
            ret.add(calculateWorstCard(card));
        }

        update(controller);

        for (Card c : ret) {
            knownCardsOnDeck.add(c.getNumber());
        }
        lastDeckSize = controller.getDiscardPileSize() + ret.size();
        return ret;
    }

    @Override
    protected boolean bs(Player player, int card, int numberOfCards,
            Controller controller) {
        Card[] hand = getHand();
        int myCards = 0;
        for (Card c : hand) {
            if (c.getNumber() == card)
                myCards++;
        }       
        update(controller);
        for (Integer number : knownCardsOnDeck) {
            if (number == card) {
                myCards++;
            }
        }

        return player.handSize() == 0
                || numberOfCards > 4
                || myCards + numberOfCards > 4
                || (player.handSize() < 5 && handSize() == 1);
    }

    @Override
    protected void initialize(Controller controller) {
        knownCardsOnDeck.clear();
        lastDeckSize = 0;
    }

    @Override
    protected void update(Controller controller) {
        if (lastDeckSize > controller.getDiscardPileSize()) {
            knownCardsOnDeck.clear();
            lastDeckSize = controller.getDiscardPileSize();
        } else {
            lastDeckSize = controller.getDiscardPileSize();
        }
    }

    private Card calculateWorstCard(int currentCard) {
        List<Integer> cardOrder = new ArrayList<>();

        int nextCard = currentCard;
        do {
            cardOrder.add(nextCard);
            nextCard = (nextCard + 4) % 13;
        } while (nextCard != currentCard);
        Collections.reverse(cardOrder);

        Card[] hand = getHand();
        for (Integer number : cardOrder) {
            for (Card card : hand) {
                if (card.getNumber() == number) {
                    return card;
                }
            }
        }
        //never happens
        return null;
    }

    @Override
    public String toString() {
        return "(-";
    }
}

2

買いだめ

package players;

import java.util.ArrayList;
import java.util.List;

import controller.*;

public class Hoarder extends Player{
    @Override
    protected List<Card> requestCards(int card, Controller controller) {
        Card[] hand = getHand();
        List<Card> ret =  new ArrayList<Card>();
    if( canWinHonestly(card) ) { //Hoarded enough cards that I won't have to bs ever again, time to win.
      for (Card c : hand) {
            if (c.getNumber() == card) {
                ret.add(c);
            }
        }
    }
    else { // Don't have the cards I'll need in the future. Play my entire hand. Either get more cards or instantly win.
      for (Card c : hand) {
                ret.add(c);
      }
    }
        return ret;
    }

    @Override
    protected boolean bs(Player player, int card, int numberOfCards, Controller controller) {
    //Don't call unless I have to, don't want to lose a random card
        return (player.handSize() <= numberOfCards);
    }

  @Override
    public String toString() {
        return "Hoarder";
    }

  private boolean canWinHonestly(int card) {
    Card[] hand = getHand();
    List<Integer> remainingCards = new ArrayList<Integer>();
    for (Card c : hand) {
      remainingCards.add(c.getNumber());
    }
    while( remainingCards.size() > 0 ) {
      if(remainingCards.contains(card)) {
        remainingCards.remove((Integer) card);
        card = (card + 4) % 13;
      }
      else {
        return false;
      }
    }
    return true;
  }

}

非常に単純な戦略で、正直に連勝して勝つことができるまでカードを収集します。それをテストできませんでした。うまくいけば、私のJavaがさびすぎないことを願っています。


remainingCards.remove(card)にキャストする必要がありIntegerます。そうでない場合、Javaは呼び出し.remove(int)ていると判断し、インデックスによって削除されます。
es1024

2

LiePlayer

真実を広めることを意味する場合でも、少なくとも 2枚のカードを置きます。

package players;

import java.util.ArrayList;
import java.util.List;

import controller.*;

public class LiePlayer extends Player {

    @Override
    protected List<Card> requestCards(int card, Controller controller) {
        Card[] hand = getHand();
        List<Card> ret =  new ArrayList<Card>();
        for (Card c : hand) {
            if (c.getNumber() == card) {
                ret.add(c);
            }
        }
        int i=0;
        while(ret.size()<2 && i<cards.length){
            if(c.getNumber() != card){
               ret.add(hand[i])
            }
            i++;
        }
        return ret;
    }

    @Override
    protected boolean bs(Player player, int card, int numberOfCards, Controller controller) {
        Card[] hand = getHand();
        int myCards = 0;//How meny of that card do I have.
        for (Card c : hand) {
            if (c.getNumber() == card) {
                myCards += 1;
            }
        }
        return numberOfCards+myCards >= 4;
        //for that to work, he would have to have all the other cards of that number.
    }

    public String toString() {
        //Why would we admit to lying?
        return "Truthful Player";
    }
}

1
Card[] hand = getHand();の上部に必要ですbs(..)Player.handプライベートです)。また、手札が2枚未満の場合、これはクラッシュします。
es1024

残念ながら、コードにはいくつかのエラーがあります。カードはで定義されていませんi<cards.length。手はで定義されていませんCard c : hand。また、ループ内で実行しないために、無限ループに入ることもあり++iます。これらを追加しますが、それがどのように正確に必要なのかはわかりません。
soktinpk
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.