এটাই বিএস! (কার্ড খেলা)


29

বিএস হ'ল একটি কার্ড গেম যেখানে গেমের অবজেক্টটি আপনার সমস্ত কার্ড হারাতে পারে।

একটি গেমটিতে চার খেলোয়াড় এবং একটি 52-কার্ড ডেক থাকে। প্রতিটি খেলোয়াড় এলোমেলোভাবে 13 কার্ড ডিল করা হয়। সাধারণত, কার্ডগুলিতে 2 - 10, এস, জ্যাক, কুইন, কিং লেবেলযুক্ত থাকে তবে সরলতার জন্য কার্ডগুলি 0 - 12 সহ অন্তর্ভুক্ত সহ একটি সংখ্যার লেবেলযুক্ত হবে। যদিও কোনও খেলোয়াড়ের হাতে কার্ডের সংখ্যা জনসাধারণের তথ্য, তবে কেবল খেলোয়াড়ই জানেন যে তার হাতে নির্দিষ্ট কার্ডগুলি রয়েছে।

খেলাটি নিম্নরূপ: প্রথম প্লেয়ারটি 0 টি লেবেলযুক্ত যতগুলি কার্ড ফেলে দিতে চান সেটিকে 0 টি লেবেলযুক্ত করে রাখুন (নোট করুন যে তার 0 টি লেবেলযুক্ত সমস্ত কার্ড খেলতে হবে না , যদিও এটি করা তার পক্ষে সবচেয়ে বেশি আগ্রহী )। তাকে অবশ্যই কমপক্ষে একটি কার্ড খেলতে হবে। দ্বিতীয় খেলোয়াড় 1 টি লেবেল করতে যতটা কার্ড খেলেন , তৃতীয় খেলোয়াড় 2 টি খেলেন , এবং আরও অনেক কিছু। 12 এর পরে, এটি 0 এ পুনরায় সেট করা।

আপনি যে কার্ডটি খেলবেন বলে মনে করেন তা যদি না থাকে তবে কী হবে? মনে রাখবেন, আপনার অবশ্যই কমপক্ষে একটি কার্ড খেলতে হবে - বাস্তবে আপনি যে কোনও কার্ড খেলতে পারবেন! (প্রকৃতপক্ষে, আপনার কাছে সঠিক কার্ড থাকলেও আপনি মিথ্যা বলতে এবং একটি আলাদা কার্ড খেলতে পারেন)। তবে, কেউ আপনাকে ডেকে বলতে পারেন, "বিএস!" যদি কেউ সঠিক থাকে এবং আপনি মিথ্যা বলেছিলেন, তবে আপনাকে অবশ্যই বাতিল কার্ডের সমস্ত কার্ড অবশ্যই নিতে হবে; পুরষ্কার হিসাবে, প্লেয়ার যিনি আপনাকে এলোমেলোভাবে ডাকলেন তাদের কার্ডগুলির মধ্যে একটি কার্ড ফেলে দেওয়া গাদাতে রাখেন। যদি অভিযোগকারী ভুল হয় তবে তাকে অবশ্যই ফেলে দেওয়া স্তূপের সমস্ত কার্ড নিতে হবে। নোট আপনার সম্পর্কে থাকা দিতে পারে না যে সংখ্যা কার্ডগুলি আপনি খেলা হয়।

আরও বিস্তারিত তথ্য:

  • গেমের শুরুতে চারটি এলোমেলো খেলোয়াড় খেলতে বেছে নেওয়া হয়। যেহেতু কমপক্ষে 1000 গেমস থাকবে তাই প্রতিটি খেলোয়াড় খেলার সুযোগ পাবে। খেলার শুরুতে এলোমেলোভাবে টার্ন অর্ডার সিদ্ধান্ত নেওয়া হয় is
  • যদি আপনি একটি সঠিক কার্ড এবং একটি ভুল কার্ড ফেরত দেন তবে এটি মিথ্যা বলে বিবেচিত হয় (যেমন যদি আপনি 2 টি দেওয়ার কথা বলেছিলেন এবং আপনি একটি 2 এবং একটি 1 দিয়েছেন , তবে এটি মিথ্যা)
  • যদি দু'জন বা তার বেশি প্লেয়ার উভয়ই একই সময়ে BS বলে, তবে যেকোন একটি এলোমেলোভাবে বেছে নেওয়া হয়েছে।
  • আপনার স্কোর আপনি যে গেম জিতেছেন তার শতাংশ।
  • এখানে সর্বাধিক 1000 রাউন্ড রয়েছে, যেখানে প্রতি প্লেয়ার একবারে এক রাউন্ডে চলে। সাধারণত, এর আগে কেউ জিততে পারে। যদি কেউ জিততে না পারে তবে এটি খেলে যাওয়া মোট খেলাগুলির সংখ্যার মধ্যে ধরা হয়, তবে কেউ জিতেনি।

ফটকা খেলা:

আপনি প্রসারিত একটি ক্লাস লিখতে হবে 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যখনই অন্য কেউ কার্ড খেলেন তখন পদ্ধতিটি বলা হয়। প্রথম যুক্তি হ'ল খেলোয়াড়, দ্বিতীয় - তিনি যে কার্ডটি খেলবেন বলে মনে করা হয়েছিল , এবং তৃতীয় - এই ধরণের কার্ডের সংখ্যা যেটি তিনি দাবি করেছেন যে তিনি খেলেছেন। trueআপনি যদি "BS" কল করতে চান তবে ফিরে আসুন । উপরের কোডে, খেলোয়াড় কেবল তখনই "BS" কল করে যখন অন্য খেলোয়াড় অনুরোধ করা ধরণের 3 বা ততোধিক কার্ড রাখার দাবি করে।

উভয় পদ্ধতির জন্য সর্বশেষ যুক্তি হ'ল controller, যা কেবলমাত্র নিয়ন্ত্রক যা গেমটি নিয়ন্ত্রণ করে। কন্ট্রোলার থেকে আপনি আরও জনসাধারণের তথ্য পেতে পারেন, যেমন ফেলে দেওয়া পাইলের তালিকার সংখ্যা বা প্লেয়ারদের তালিকা এবং টার্ন অর্ডার।

toStringপদ্ধতি ঐচ্ছিক।

গিটহাবের কনরোলার: https://github.com/prakol16/bs

যদি আপনি একটি জাভা-বিহীন সমাধান পোস্ট করতে চান তবে আপনি https://github.com/LegionMammal978/bs (লেজিওনম্যামাল 978 এর ক্রেডিট) এ দেওয়া ইন্টারফেসটি ব্যবহার করতে পারেন এবং আমি এটি সংহত করার চেষ্টা করব।

এখন পর্যন্ত স্কোরবোর্ড:

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%

প্লেয়ারকনম্যান জিতছে, তবে ক্যালকুলেটিংলিয়রটি খুব কাছের সেকেন্ডে। এই স্কোরগুলি সামঞ্জস্যপূর্ণ বলে মনে হচ্ছে - প্রতিবার এগুলি মোটামুটি একই।


13
তুমি আমার সাথে মজা নিচ্ছ. আমার এই বিস্মৃত চ্যালেঞ্জটি তৈরি করার একমাত্র উদ্দেশ্যে বিএসের কাছে প্রায় সমাপ্ত কন্ট্রোলার রয়েছে। ঠিক আছে, আমার ধারণা এখন আমার সময় কাটাতে আমাকে অন্য কোনও উপায় খুঁজে বের করতে হবে।
ইচবিনকিনবাম

3
এটি Controller.toString()জনসাধারণের সামনে প্রকাশ না করার পরামর্শ দেওয়া হতে পারে , কারণ এটি সমস্ত খেলোয়াড়দের হাতছাড়া করে এবং ফেলে দেওয়া গাদা।
es1024

@ ইচবিনকিনবাউম, যদি আপনার নিয়ামকটি STDIN / STDOUT এর সাথে যোগাযোগ করতে পারে তবে আপনি জাভা-বিহীন সমস্ত লোকের জন্য আপনার নিয়ামকের সাহায্যে চ্যালেঞ্জটি প্রকাশের বিষয়টি বিবেচনা করতে পারেন।
লজিক নাইট

@ কার্পেট পাইথন: এটি করে। এটি সামান্য ডিফারেন্স নিয়মও ব্যবহার করে। যদি এটি সদৃশ হিসাবে গণনা না করে তবে আমি করব।
ইচবিনকিনবাম

আমি সবেমাত্র একটি বহু-ভাষা নিয়ামক তৈরি করা শেষ করেছি। ব্যবহার প্রোগ্রাম.cs এ রয়েছে। আপনি এটি এখানে খুঁজে পেতে পারেন ।
LegionMammal978

উত্তর:


10

ConMan

কনমান তার হাতে থাকা প্রতিটি কার্ড দেখে, কার্ডগুলি যেখানে থাকায় কোনও নাটক সম্ভব না হলে বিএস কল করে।

সক্ষম হওয়ার পরে সত্য খেলেন, তবে কোনও বিজয় ঘটলে বুদ্ধিমানভাবে শেষ কার্ডটি ব্যবহার করে।

আমি যখন বিএসিকে কল করার সম্ভাবনা বেশি ছিল বা যখন বিএস কল করা সুবিধাজনক ছিল (যেমন, ফেলে দেওয়া পাইল থেকে দরকারী কার্ড পাওয়া) তখন বিএসকে কল করার কৌশলটি টিউন করার জন্য আমি দীর্ঘ সময় অতিবাহিত করেছি, তবে বাস্তবে, বিএসকে মোটামুটি কল না করে আমি সবচেয়ে পয়েন্ট।

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

ধন্যবাদ! কোডটি দেখে, আমি বুঝতে পেরেছিলাম যে কার্ডগুলি যখন একেবারেই অসম্ভব বলেছিল তখন আমি কল করতে ভুলে গিয়েছিলাম। আমি উপরের কোড আপডেট করেছি।
ওয়াসমু

4

খেলোয়াড় 3131961357_10

প্রতিটি গেম একটি এলোমেলো খেলোয়াড় চয়ন করে এবং সর্বদা সেই প্লেয়ারকে বিএস কল করে।

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

Truthy

পুরোপুরি সমাপ্ত হয়নি, যেহেতু আমি বিএস কল করার ফলাফলটি কীভাবে জানাতে জানি না (যদি তারা গাদাটি বেছে নিয়েছিল, বা টাইয়ের ক্ষেত্রে অন্য কেউ, অথবা আমি করেছি)।

এই মুহুর্তে, আমি যদি এটি প্রমাণ করতে পারি তবে কেবল বিএস কল করুন। আমার না থাকলে মিথ্যা বলবেন না। আমার মিথ্যা অ্যালগরিদমটি উন্নত করতে হবে। আমি অন্যান্য খেলোয়াড়দের বিরুদ্ধে কীভাবে বিএস খেলি তা যতটা সম্ভব সম্ভব করার চেষ্টা করছি (এগুলি না জেনে 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

আমি প্রতিটি প্লেয়ারের হাতের মাপ মুখস্থ করে বিএস এর ফলাফলগুলি পেয়েছি এবং তারপরে নিয়ামকটির সাথে আমার স্মৃতি তুলনা করে। বৃদ্ধি মানে প্লেয়ার হেরে গেছে; হ্রাস মানে প্লেয়ার জিতেছে। (বর্তমান প্লেয়ারের হাতের আকার অবশ্যই অফসেট করা উচিত numberOfCardsকারণ তারা যখন bsডেকে ডেকে
ফেলেছে

আমি যা চাইছিলাম তা বাস্তবায়নের জন্য আমার কাছে সময় ছিল কিনা তা আমি জানি না। আমি কীভাবে সর্বোত্তমভাবে বিএস খেলব সে সম্পর্কে যত বেশি চিন্তা করেছি, প্রোগ্রামিংটি তত বেশি শক্ত হবে। কনমানের যা কিছুটা রয়েছে তা আমি করতে চেয়েছিলাম, তবে জটিলতা আমার কাছে একটু বেশি।
mbomb007

4

CalculatingLiar

এই সত্য চেষ্টা করার চেষ্টা করে। যদি তিনি মিথ্যা বলে থাকেন তবে তিনি এমন একটি কার্ড ব্যবহার করেন যা তিনি অদূর ভবিষ্যতে ব্যবহার করবেন না। এটি অন্যান্য খেলোয়াড়দের উপর বিএস কল করে ট্রট জয়ের চেষ্টা করে, যেহেতু শেষ কার্ডটি প্রায় কখনও ফিট হয় না।

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;
  }

}

খুব সহজ কৌশল, কার্ডগুলি সংগ্রহ করে যতক্ষণ না এটি কোনও সততার ধারা অবধি জেতে পারে। এটি পরীক্ষা করতে সক্ষম ছিল না, আশা করি আমার জাভা খুব মরিচা নয়।


remainingCards.remove(card)এতে একটি কাস্ট করা উচিত Integer, অন্যথায় জাভা মনে করে যে আপনি কল করছেন .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.