Rei da Colina - Dados do Mentiroso

22

Dados do Mentiroso é um jogo de dados bastante simples. Eu já vi algumas variações diferentes das regras, mas aqui está a versão com a qual estou mais familiarizado:

  • Cada jogador começa com 5d6
  • Exceto ao somar os dados no final de uma rodada, cada jogador pode ver seus próprios dados, mas não os de qualquer oponente
  • No início de qualquer rodada, todos os jogadores jogam os dados que possuem atualmente
  • Então, um jogador (normalmente, este é o vencedor da rodada anterior OU o jogador à esquerda do jogador que iniciou a última vez; usaremos o primeiro para este KotH; com um jogador aleatório iniciando a primeira rodada) faz um palpite sobre quantos números estão em cima da mesa (OS SÃO SELVAGENS)
  • Os lances continuam à direita, aumentando cada vez mais (por exemplo; 3 cincos, 3 seis e 4 duplas são todos maiores que 3 quatrocentos, mas 3 três não é; 4 outros também são mais altos, mas a licitação de um provavelmente o coloca em um nível desvantagem); até que um jogador chame o mentiroso que o precede
  • Neste ponto, todos os jogadores revelam seus dados e contam o número do último lance de número na mesa.
  • Se o total for menor do que o lance, o jogador que fez o lance deve dar um dado ao jogador que os chamou de mentiroso; caso contrário, o jogador que chamou o lance de mentiroso deve dar um dado ao licitante (para que o licitante vença se eles tiverem pelo menos o número que ele havia solicitado, não precisa ser o número exato)
  • Quando você fica sem dados, você perde
  • O último jogador em pé vence

Por exemplo:

O jogador um tem 1,1,2,4,6
O jogador dois tem 1,2,2,3,5
O jogador três tem 1,3,3,4,6
Jogador um: três seis.
Jogador dois: quatro pares.
Jogador três: quatro trios.
Jogador um: cinco duplas.
Jogador dois: seis dois.
Jogador três: seis trios.
Jogador um: seis e quatro.
Jogador dois: Mentiroso!
Eles revelam seus dados e contam os (porque são selvagens) e os quatro.
Acontece que existem, de fato, exatamente seis quatros.
Então, o jogador dois dá ao jogador um um dado.
Eles re-rolam e o jogador um começa a próxima rodada.

Você deve escrever um bot para jogar este jogo. Ele deve implementar a seguinte classe java abstrata:

public abstract class Player {
    public Player() {}
    public String toString() {
        return this.getClass().getSimpleName();
    }
    public abstract String bid(int yourId, int[] diceEachPlayerHas, int[] yourDice, String[] bids);
}
  • Você deve implementar o método de lance
    • O primeiro argumento é a posição atual do seu bot na ordem do turno, o segundo é uma matriz que mostra quantos dados cada jogador (incluindo você) possui atualmente, o terceiro é uma matriz que mostra os valores atualmente exibidos em seus próprios dados e a quarta é uma matriz de todos os lances feitos desde o início da rodada atual - terá o comprimento 0 se você estiver fazendo o primeiro lance da rodada
    • A saída deve ser uma sequência do formato "número da face" ou a sequência "Mentiroso!" chamar o licitante anterior de mentiroso.
    • Se sua saída for formatada ilegalmente, você será eliminado.
  • Você pode substituir o método toString, mas não é necessário. No entanto, você não pode editá-lo de qualquer maneira que interfira na legibilidade da saída do controlador.
  • Você tem permissão para chamar qualquer outro método público do controlador, mas não o método principal.
  • Você pode ler e editar apenas arquivos no diretório em execução prefixado com o nome do seu bot
  • Você não tem permissão para receber informações de nenhuma outra fonte
  • Variáveis ​​de instância são redefinidas no início de cada novo jogo, mas variáveis ​​estáticas não são.

Pontuação

  • Um conjunto de 1.000 jogos, com 3-5 jogadores em cada, será simulado cada vez que um bot for adicionado (assim que três ou mais bots forem enviados), pontuados conforme mostrado na fonte do controlador (em qualquer jogo, você receba 1 no início de cada turno, 10 sempre que capturar um dado e 1.000 de bônus se vencer); impor um limite de 5.000 TURNS (não rodadas) a cada jogo.
  • Seu bot será pontuado pela pontuação do último conjunto de jogos; mais dez vezes sua pontuação de voto, se não negativo. (É improvável que este último tenha um efeito significativo na pontuação)

A fonte do controlador pode ser encontrada aqui.

Pontuações a partir de 19/06/2015:

Badnomial: 434,924 + 6x10 = 424,984
Nobody: 282,329 + 6x10 = 282,389
StraightShooter: 265,205 + 5x10 = 265,255
MostlyHonestAbe: 158,958 + 4x10 = 158,998
The Pirate: 157,005 + 1x10 = 157,015
Statistician: 144,012 + 2x10 = 144,032
Fidelio: 49,973 + 2x10 = 49,993
Absurd Bot: 6,831
DrHouse: 2,638 + 3x10 = 2,668
SuperJedi224
fonte
1
Você deve esclarecer que a saída deve ser "2 3" e não "dois três", como mostra o seu exemplo. Além disso, existe uma maneira no controlador de assistir a uma única partida?
Cain
Não na versão oficial, mas vou postar uma versão alternativa que permite fazer isso.
SuperJedi224
@ Geobits: Se você quiser. Isso o colocará em desvantagem se alguém ligar para você.
SuperJedi224
1
Presumo que os índices das matrizes sejam os "ids" dos jogadores, de modo que diceEachPlayerHas[yourId]= seus dados contam e bids[yourId]é sua primeira oferta (ou nulo se for sua primeira vez). Isso está correto?
Não que Charles,
1
Eu já vi jogos em que alguns envios jogam mais do que outros (Ninguém: 414 jogos, Straight Shooter: 409 jogos). Isso não é justo, você pode consertar isso?
CommonGuy

Respostas:

6

Ninguém

Tenta adivinhar os dados de outros jogadores. Chama outros bots mentirosos se não souber o que fazer.

Edit: Corrigido um problema em que ninguém faria lances para sempre, nunca chamando de mentiroso.

public class Nobody extends Player{

    @Override
    public String bid(int myId, int[] diceEachPlayerHas, int[] myDice,
            String[] bids) {
        if (bids.length == 0)
            return "1 2";
        int wilds = 0;
        int players = Controller.numPlayers();
        double myKnowledge = (double)diceEachPlayerHas[myId]/Controller.diceInPlay();
        double previousKnowledge = (double)diceEachPlayerHas[(myId-1+players)%players] / Controller.diceInPlay();
        int[] dice = new int[5];
        for (int i = 0; i < myDice.length; i++) {
            if (myDice[i] == 1) {
                wilds++;
            } else {
                dice[myDice[i]-2]++;
            }
        }
        wilds = (int) (1/myKnowledge+wilds-1)+1;
        for (int i = 2; i <= 6; i++) {
            dice[i-2] += wilds;
        }
        String best = "0 0";
        for (int i = 2; i <= 6; i++) {
            if (Controller.isGreaterThan(dice[i-2] + " " + i, best)) {
                best = dice[i-2] + " " + i;
            }
        }
        if (Controller.isGreaterThan(best, bids[bids.length - 1])) {
            return best;
        }
        if (previousKnowledge > 0.4) {
            int prev = Integer.valueOf(bids[bids.length - 1].split(" ")[0]);
            int prevFace = Integer.valueOf(bids[bids.length - 1].split(" ")[1]);
            if (dice[prevFace - 2] +2 >= prev)
                return (prev+1) + " " + bids[bids.length - 1].split(" ")[1];
        }
        return "Liar!";
    }
}
CommonGuy
fonte
Seu último conjunto de atualizações realmente parece ter ajudado.
SuperJedi224
6

Badnomial, o bot que toma más decisões com base em distribuições binomiais: Edit: Corrigido um erro estúpido nos cálculos de probabilidade, agora é responsável pelo próximo Licitante e também pelo anterior.

    public class Badnomial extends Player{
    public String toString() {return "Badnomial";}

  public String bid(int myId, int[] diceEachPlayerHas, int[] myDice, String[] bids) {
  int[] dieCounts = new int[7];
  for(int i:myDice)
   dieCounts[i]++;
  for(int i=2; i<7; i++)
   dieCounts[i] += dieCounts[1];

  if(bids.length > 0)
  {
   String[] lastBid = bids[bids.length - 1].split(" ");
   int bidCount = Integer.valueOf(lastBid[0]);
   int bidDie = Integer.valueOf(lastBid[1]);
   // Check if I hold a better bid
   boolean betterBid = false;
   int myBidDie;
   int myBidCount;
   int myHighestCount = 0;
   int myHighDie = bidDie +1;

   for(int i = 2; i < 7; i++) {
    if(dieCounts[i] >= myHighestCount) {
     myHighestCount = dieCounts[i];
     myHighDie = i;
    }
   } 
    if((myHighestCount > bidCount) || ((myHighestCount == bidCount) && (myHighDie > bidDie))) {
     betterBid = true;
     myBidDie = myHighDie;
     myBidCount = myHighestCount;
     }

   if(betterBid == false) {
    int unknownDice = Controller.diceInPlay() - myDice.length;
    int myDiceNeeded = bidCount - myHighestCount;
 if(myHighDie <= bidDie)
  myDiceNeeded++;
    int previousBidder = myId - 1;
    if(previousBidder < 0)
     previousBidder = Controller.numPlayers() -1;
    int bidderDiceNeeded = bidCount - dieCounts[bidDie] - (int)(diceEachPlayerHas[previousBidder]/3 +1);
    int bidderUnknown = Controller.diceInPlay() - diceEachPlayerHas[previousBidder] -myDice.length;
 int nextBidder = myId + 1;
 if(nextBidder == Controller.numPlayers())
  nextBidder = 0;
 int nbDiceNeeded = myDiceNeeded - (int)(diceEachPlayerHas[nextBidder]/3 +1);
    int nbUnknown = Controller.diceInPlay() - diceEachPlayerHas[nextBidder];
    //float myChances = (unknownDice/3 - myDiceNeeded)/((float)unknownDice/9);
    //float bidderChances = (bidderUnknown/3 - bidderDiceNeeded)/((float)bidderUnknown/9);
    double myChances = 1 - cumBinomialProbability(unknownDice, myDiceNeeded -1);
    double bidderChances;
    if(bidderDiceNeeded > 0)
     bidderChances = 1- cumBinomialProbability(bidderUnknown, bidderDiceNeeded -1);
    else bidderChances = 1.0;
    double nbChances;
    if(nbDiceNeeded > 0)
      nbChances = 1- cumBinomialProbability(nbUnknown, nbDiceNeeded -1 );
    else nbChances = 1.0;
    if(((myChances < .5) && (nbChances <.5)) || (bidderChances < .2))
     return "Liar!";
   }

   return (bidCount+1) + " " + myHighDie;
  }

  return 2 + " " + 2;
 } 

 private double cumBinomialProbability(int n, int k) {
   double sum = 0;
   for(int i = 0; i <=k; i++)
     sum += binomialProbability(n, i);
   return sum;
 }

 private double binomialProbability(int n, int k) {
   double nfact = 1;
   double dfact = 1;
   int greater;
   int lesser;
   if((n-k) > k) {
     greater = n - k;
     lesser = k;
   }
   else {
     greater = k;
     lesser = n-k;
   }
   for(int i = greater+1; i <= n; i++)
     nfact = nfact * i;
   for(int i = 2; i <= lesser; i++)
     dfact = dfact * i;
   return (nfact/dfact)*(Math.pow((1.0/3), k))*Math.pow(2.0/3, (n-k));
 }

}

Ele tenta determinar se deve blefar ou chamar o mentiroso com base nas distribuições binomiais acumuladas estimadas para si e nas chances dos concorrentes anteriores e seguintes de ter os dados necessários presentes.

Basicamente, ele chama Mentiroso se o Licitante anterior é muito provável que seja um Mentiroso ou se sente que tanto ele quanto o Licitante seguinte provavelmente estão mentindo.

InactionPotential
fonte
Com essas alterações, o Badnomial realmente parece remotamente competente em relação aos outros bots.
usar o seguinte
5

Straight Shooter

Ele joga direto e não blefa. Ele também é ingênuo o suficiente para pensar que outros o fazem, então ele nunca chama mentiroso, a menos que o lance ultrapasse o número total de dados em jogo (menos seus próprios dados que não correspondem ao lance).

Para ser um pouco mais conservador do que o número exato esperado para cada dado, ele não conta sua própria natureza, mas assume que outros têm uma distribuição uniforme. Com os quatro jogadores atuais, ele ou MostlyHonestAbe surgiram primeiro a cada vez, com pontuações bastante próximas.

Estou assumindo que o lance mínimo é 2 2. Se uma licitação de um dado (ou licitações) for permitida, informe-me para que eu possa fazer essa alteração.

public class StraightShooter extends Player{
    public String toString(){return "Straight Shooter";}
    public String bid(int me, int[] numDices, int[] dice, String[] bids){
        int[] counts = new int[7];
        double[] expected = new double[7];
        int unknown = Controller.diceInPlay() - dice.length;
        for(int i:dice)
            counts[i]++;
        for(int i=2;i<7;i++)
            expected[i] = counts[i] + unknown / 3d;
        int bidCount = 2;
        int bidDie = 2;
        if(bids.length > 0){
            String[] lastBid = bids[bids.length-1].split(" ");
            bidCount = Integer.valueOf(lastBid[0]);
            bidDie = Integer.valueOf(lastBid[1])+1;
            int possible = Controller.diceInPlay();
            for(int i=2;i<7;i++)
                if(i != bidDie)
                    possible -= counts[i];
            if(bidCount > possible)
                return "Liar!";

            if(bidDie > 6){
                bidDie = 2;
                bidCount++;
            }
        }
        double best = Double.MAX_VALUE;
        int bestCount = bidCount;
        int bestDie = bidDie;
        for(int count=bidCount;count<=Controller.diceInPlay();count++){
            for(int die=bidDie;die<7;die++){
                double score = Math.abs(expected[die]-bidCount);
                if(score < best){
                    best = score;
                    bestCount = count;
                    bestDie = die;
                }
            }
            bidDie = 2;
        }   
        return bestCount + " " + bestDie;
    }
}
Geobits
fonte
Este e o MostlyHonestAbe são tão hesitantes em mentir ou chamar mentiroso, existem alguns jogos que vão até 2000 voltas quando eu testo haha. : P
Caim
O mesmo no meu. Tudo bem, porém, porque cada turno é um ponto extra para a pontuação final. Se eu últimas voltas de 2000 e não ganhar, isso é melhor do que ganhar depois de 100 no meu livro;)
Geobits
Eu só tinha que olhar as regras de pontuação novamente. Novo jogo XD
Caim
Sim, com essa pontuação, parece que a melhor estratégia pode ser ser o mais conservador possível e apenas acumular pontos. Talvez haja algo melhor, mas não consigo ver.
Geobits
1
Não tenho certeza se isso faria muita diferença. Ser conservador ainda seria uma vantagem, apenas porque você tem uma chance menor de perder um dado. A razão pela qual mais pessoas não jogam dessa maneira na vida real é porque é apenas chato, mas o que é tédio para um bot?
Geobits
4

MostlyHonestAbe

Abe faz suposições conservadoras sobre o resto dos oponentes morrerem, e depois permanece honesto até que ele não pense que haja dados suficientes para vencer a oferta atual. Nesse ponto, ele blefa uma vez e depois chama mentiroso na próxima vez.

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintStream;

public class MostlyHonestAbe extends Player{

    final boolean debug = false;
    boolean bluffedOnce = false;
    PrintStream out;
    @Override
    public String bid(int myId, int[] diceEachPlayerHas, int[] myDice, String[] bids) {
        try {
            File f = new File("abe.log.txt");
            out = new PrintStream(f);
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            //e.printStackTrace();
        }
        if(debug){
            out = System.out;
        }

        //reset bluff counter on the first round
        if(bids.length < diceEachPlayerHas.length){
            bluffedOnce = false;
        }

        //Is it the first bid?
        if(bids.length == 0){
            out.println("I go first");
            return lowestViableBid(1,1, myDice, diceEachPlayerHas, true);
        }

        out.println("Last bid = " + bids[bids.length - 1]);
        out.print("My Dice = ");
        for(int d : myDice){
            out.print(d + ", ");
        }
        out.println();

        //What was the last bid?
        String[] lastBid = bids[bids.length -1].split(" ");
        return lowestViableBid(Integer.parseInt(lastBid[1]), Integer.parseInt(lastBid[0]), myDice, diceEachPlayerHas, false);


    }

    //Lowest honest bid, or liar
    private String lowestViableBid(int highestVal, int highestCount, int[] myDice, int[] otherDice, boolean firstTurn){

        //Make a better array for the dice
        //Include what the other players probably have
        int wilds = numDie(1, myDice);
        int[] diceCount = new int[6];
        diceCount[0] = wilds;
        int otherPlayerExpectedValue = 0;
        for(int d : otherDice){
            otherPlayerExpectedValue += d;
        }
        otherPlayerExpectedValue -= myDice.length;
        out.println("Number of other dice = " + otherPlayerExpectedValue);
        otherPlayerExpectedValue = otherPlayerExpectedValue / 4;
        //Note: Other player expected value is biased low, counting wilds the number should be divided by 3.

        out.println("playerExpectedVal = " + otherPlayerExpectedValue);
        for(int i = 1; i < 6; i++){
            diceCount[i] = numDie(i + 1, myDice) + wilds + otherPlayerExpectedValue;
        }


        //What's my array look like?
        for(int i = 0; i < diceCount.length; i++){
            out.println("diceVal = " + (i + 1) + ", diceCount = " + diceCount[i]);
        }

        //Can I bid the same number, but higher dice val?
        for(int diceVal = highestVal + 1; diceVal <= 6; diceVal++){
            if(diceCount[diceVal - 1] >= highestCount){ 
                out.println("1.Returning " + highestCount + " " + diceVal);
                return highestCount + " " + diceVal; }  
        }

        //What about more dice?
        for(int diceNum = highestCount + 1; diceNum <= myDice.length; diceNum++){
            for(int diceVal = highestVal + 1; diceVal <= 6; diceVal++){
                if(diceCount[diceVal - 1] == diceNum){ 
                    out.println("2.Returning " + (diceNum) + " " + diceVal);
                    return (diceNum) + " " + diceVal; } 
            }
        }

        if(firstTurn){ return "1 2"; }
        //If this is the first time I'm out of my league, bluff a round before calling liar.
        if(!bluffedOnce){
            out.println("bluffing " + (highestCount + 1) + " " + highestVal);
            bluffedOnce = true;
            return (highestCount + 1) + " " + highestVal;
        }
        out.println("Returning Liar!");
        //Well, wouldn't want to lie
        return "Liar!";
    }

    private int numDie(int i, int[] myDice){
        int result = 0;
        for(int j : myDice){
            if(i == j){ result++; }
        }
        return result;
    }
}
Caim
fonte
1
Você está brincando comigo? Eu estava a menos de cinco minutos da publicação do HonestAbe . Agora eu tenho que pensar em um novo nome: P
Geobits
1
Não pode ter um jogo com Liar no nome sem uma referência a Abraham Lincoln em algum lugar.
Caim
4

Dr. House

Todos mentem!

public class DrHouse extends Player
{   
  public String bid(int yourId, int[] diceEachPlayerHas, int[] yourDice, String[] bids)
  {
    return "Liar!";
  }
}
Gus314
fonte
1
Sugiro adicionar lógica especial para quando você tiver o primeiro lance da rodada.
SuperJedi224
4
@ SuperJedi224 I imaginar que o bot em seguida, considera o controlador dizendo-lhe que é a sua vez de ser um mentiroso
Nathan Merrill
Fez o meu dia lol
Rohan Jhunjhunwala
2

Fidelio

Esse bot sabe que apenas seu valor mais recorrente o levará à vitória, então ele permanece com ele. Ele assume que há uma porção dos dados de todos iguais aos dele, se alguém oferecer mais do que essa parte, ele assume que é um mentiroso.

public class Fidelio extends Player
{
    final String LIAR ="Liar!";
    @Override
    public String bid(int yourId, 
            int[] diceEachPlayerHas, 
            int[] yourDice,
            String[] bids) 
    {
        int[] myDices = new int[6];
        int valueToBid=1;
        for(int i : yourDice)
            myDices[i-1]++;
        for(int i=2;i<myDices.length;i++)
            if(myDices[i]>=myDices[valueToBid])
                valueToBid=i;
        if(bids.length==0)
            return 2+" "+valueToBid;
        int sum=0;
        String[] lastBidString=bids[bids.length-1].split(" ");
        int[] lastBid = new int[2];
        lastBid[0] = Integer.parseInt(lastBidString[0]);
        lastBid[1] = Integer.parseInt(lastBidString[1])-1;
        for(int i : diceEachPlayerHas)
            sum+=i;
        sum-=yourDice.length;
        if(lastBid[0]>sum/3+myDices[lastBid[1]]+myDices[0])
            return LIAR;
        if(lastBid[1]>= valueToBid)
        {
            if(lastBid[0]>=myDices[0]+myDices[valueToBid]+sum*2/5)
                return LIAR;
            return (lastBid[0]+1)+" "+myDices[valueToBid];
        }
        return lastBid[0]+" "+valueToBid;
    }
}

Espero que ele faça um bom trabalho :).

Katenkyo
fonte
Estou recebendo uma IndexOutOfBoundsException na linha 13. Lembre-se de que as matrizes são 0-indexadas em java.
SuperJedi224
Agora estou recebendo um do outro lado da linha 19, para um índice de -1. Parece que ele estava tentando ler o último elemento de uma matriz vazia; você deve incluir uma verificação para isso.
SuperJedi224
Fixa, a seleção se (bids.length == 0) foi feito depois que eu usei lances ...
Katenkyo
Ah, acabei de propor outra solução possível, mas provavelmente isso também funcionará.
SuperJedi224
Ah, então essa edição sugerida não é mais necessária?
mbomb007
2

Estatístico

Você tem 1/3 de chance de ter outro número que não seja ases. Um cara me disse uma vez que não checar seus dados e apenas saber as probabilidades pode fazer você ganhar este jogo. EDIT: O lance estava muito alto. Mas isso não melhora muito a pontuação.

public class Statistician extends Player{
    public String toString(){return "Statistician";}
    public String bid(int me, int[] numDices, int[] dice, String[] bids){
        int totalDices = 0;
        int currentBid, max;
        for (int i : numDices)
            totalDices += i;
        max = totalDices/3;
        if(bids.length>0){
            currentBid = Integer.valueOf(bids[bids.length-1].split(" ")[0]);
            if(currentBid>max)
                return "Liar!";
        }
        return max+" 6";
    }
}
Acertar
fonte
1

Bot absurdo

Defende que todos os dados são 6, a menos que não possam. Se o bot não puder fazer isso, significa que esta é uma situação impossível ou quase impossível. Por isso, chama mentiroso. Estou curioso para saber como esse bot será eficaz.

public class AbsurdBot extends Player {
    @Override
    public String bid(int yourId, int[] diceEachPlayerHas,int[] yourDice,String[] bids)
    {
        String[] lastbid;
        int a, b, d;
        d = 0;
        for (int dice : diceEachPlayerHas)
            d += dice;
        if (bids.length != 0)
            {
                lastbid = bids[bids.length-1].split(" ");
                a = Integer.parseInt(lastbid[0]);
                b = Integer.parseInt(lastbid[1]);
                if (a > d || a == d && b == 6)
                    return "Liar!";
            }
        return d + " 6";
    }
}
Frederick
fonte
Quanto à eficácia: Sua principal função parece entregar dados para o jogador que a seguir: P
Geobits
@ Geobits Corrigi o código. Isto é o que acontece quando você tenta pular em uma linguagem de programação que você não tenha programado antes ...
Frederick
@ Geobits Obrigado por toda a ajuda. Eu acho que isso finalmente funciona corretamente agora. Faz? (Java é confuso)
frederick
Sim, ele roda agora. A estratégia é insanamente suicida. Ele marca apenas ~ 2% do próximo jogador mais baixo.
Geobits
@ Geobits Eu nunca tentei correr contra os outros jogadores. Você correu contra os outros?
Frederick
1

O pirata

Fiz alguns bots simples ao testar o controlador, e este é o único que é realmente bom.

Provavelmente será melhorado mais tarde.

import java.util.Arrays;
import java.util.Scanner;

public class Pirate extends Player{
    public Pirate() {
    }
    public String toString(){
        return "The Pirate";
    }
    private String bid(int[] t,int tol){
        int[]z=t.clone();
        Arrays.sort(z);
        int j=0;
        for(int i=0;i<6;i++){
            if(t[i]==z[5]){j=i;break ;}
        }
        return (tol+t[j])+" "+(j+1);
    }
    @Override
    public String bid(int yourId, int[] diceEachPlayerHas, int[] yourDice,
            String[] bids) {
        int[] t=new int[6];
        for(int i=0;i<yourDice.length;i++){
            t[yourDice[i]-1]++;
        }
        for(int i=1;i<t.length;i++)t[i]+=t[0];
        int tol=(Controller.diceInPlay()-yourDice.length)/4;
        if(bids.length==0)return bid(t,1);
        Scanner i=new Scanner(bids[bids.length-1]);
        int x=i.nextInt(),y=i.nextInt();
        i.close();
        if(t[y-1]>x)return (t[y-1]+2)+" "+y;
        int nd=Controller.diceInPlay();
        if(x>nd+t[y-1]-yourDice.length)return "Liar!";
        if(Controller.isGreaterThan(bid(t,tol), bids[bids.length-1])){
            int z=Controller.valueOf(bids[bids.length-1]);
            for(int j=1;j<=tol;j++)if(Controller.valueOf(bid(t,j))>z)return bid(t,j);
        }
        return "Liar!";
    }
}
SuperJedi224
fonte