BS입니다! (카드 게임)


29

BS 는 게임의 목적이 모든 카드를 잃는 카드 게임입니다.

게임은 4 명의 플레이어와 52 장의 카드 덱으로 구성됩니다. 각 플레이어는 무작위로 13 장의 카드를받습니다. 일반적으로 카드에는 2-10, Ace, Jack, Queen, King이라는 레이블이 붙어 있지만 단순성을 위해 0-12의 숫자로 레이블이 지정됩니다. 플레이어의 손에있는 카드의 수는 공개 정보이지만 플레이어는 자신의 손에있는 특정 카드가 무엇인지 알고 있습니다.

게임은 다음과 같이 진행됩니다 : 첫 번째 플레이어 는 버리기 더미에 원하는만큼 0 이라는 카드를 많이 넣습니다 (보통 0 이라는 카드를 모두 사용할 필요는 없지만 , 일반적으로 그렇게하는 것이 가장 좋습니다) ). 그는 하나 이상의 카드를 사용해야합니다. 두 번째 플레이어는 1 이라는 레이블을 원하는만큼의 카드를 재생하고 세 번째 플레이어는 2 등을 재생 합니다. 12 이후에는 0으로 재설정됩니다.

카드를 가지고 있지 않으면 어떻게 되나요? 하나 이상의 카드를 사용해야합니다. 실제로 원하는 카드를 모두 사용할 수 있습니다! (실제로, 올바른 카드를 가지고 있더라도 다른 카드를 가지고 누워서 사용할 수 있습니다). 그러나 누군가가 당신을 불러 "BS!"라고 말할 수 있습니다. 누군가가 맞고 거짓말을했다면, 버리는 카드 더미에있는 모든 카드를 가져 가야합니다. 보상으로, 당신을 불렀던 플레이어는 무작위로 자신의 카드 중 하나를 버림 더미에 놓습니다. 그러나 고소인이 틀렸다면 버리는 카드 더미에있는 모든 카드를 가져 가야합니다. 참고 당신은 거짓말을 할 수없는 수의 연주 것을 카드.

더 자세한 정보 :

  • 게임이 시작되면 4 명의 무작위 플레이어가 선택됩니다. 최소 1000 개의 게임이 있기 때문에 각 플레이어는 게임을 즐길 수 있습니다. 턴 순서는 게임 시작시 무작위로 결정됩니다
  • 하나 개 올바른 카드와 하나 개의 잘못된 카드를 반환한다면, 그것은 거짓말로 간주됩니다 (당신이 제공하기로했다 경우, 즉 이 개 들, 당신은 하나 준 하나 (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"에 전화하려면 반환 하십시오. 위의 코드에서 플레이어는 다른 플레이어가 요청 된 유형의 카드를 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가 곧 끝납니다. 이 점수는 일관된 것처럼 보이며 매번 상당히 동일합니다.


13
너 지금 농담하는 거지. 나는이 정확한 도전을 만들기위한 목적으로 BS에 거의 완성 된 컨트롤러를 가지고 있습니다. 글쎄, 나는 지금 내 시간을 보낼 다른 방법을 찾아야 할 것 같다.
IchBinKeinBaum 1

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를 호출하는 것을 잊었다는 것을 깨달았습니다. 위의 코드를 업데이트했습니다.
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

Truthy

BS에 전화 한 결과를 말하는 방법을 모르기 때문에 (완료되지 않았거나 넥타이의 경우 다른 사람이 있었거나)

현재 증명할 수 있으면 BS에게만 전화하십시오. 내가하지 않으면 거짓말을하지 마십시오. 거짓말 알고리즘을 개선해야합니다. 나는 다른 플레이어들과 BS를 플레이하는 방법에 최대한 가깝게하려고 노력하고 있습니다.

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당신이를 할당 할 수 있도록 목록 CardA를가 List<Card>. 첫 번째 요소를 제외한 모든 것을 제거하려고합니까?
soktinpk

응, 고쳤다
mbomb007

각 플레이어의 손 크기를 기억 한 다음 컨트롤러의 메모리와 메모리를 비교하여 BS의 결과를 찾았습니다. 증가는 플레이어가 패했다는 것을 의미합니다. 감소는 플레이어가 이겼 음을 의미합니다. (현재 플레이어의 핸드 사이즈 는 호출 numberOfCards될 때 이미 버려지기 때문에에 의해 오프셋되어야합니다 bs)
Wasmoo

내가 원하는 것을 구현할 시간이 있는지 모르겠습니다. BS를 최적으로 연주하는 방법에 대해 더 많이 생각할수록 프로그래밍이 어려워집니다. ConMan의 기능을 어느 정도 수행하고 싶었지만 복잡성이 다소 나빴습니다.
mbomb007 2016

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에서 하지 않기 때문에 무한 루프로 들어갑니다 . 나는 이것을 추가 할 것이지만 그것이 당신이 정확하게 원하는 방법인지 확실하지 않습니다.
속 팅크
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.