Rey de la colina - Dados de mentiroso

22

Liar's Dice es un juego de dados bastante simple. He visto algunas variaciones diferentes de las reglas, pero aquí está la versión con la que estoy más familiarizado:

  • Cada jugador comienza con 5d6
  • Excepto al contar los dados al final de una ronda, cada jugador puede ver sus propios dados, pero no los de ningún oponente.
  • Al comienzo de cualquier ronda, todos los jugadores tiran cualquier dado que tengan actualmente
  • Luego, un jugador (generalmente, este es el ganador de la ronda anterior O el jugador a la izquierda del jugador que comenzó la última vez; usaremos el primero para este KotH; con un jugador aleatorio que comienza la primera ronda) adivina cuántos de un número en particular hay en la mesa (UNOS SON SALVAJES)
  • Las pujas continúan hacia la derecha, subiendo cada vez (por ejemplo; 3 cinco, 3 seises y 4 dos son más altos que 3 cuatros, pero 3 no lo es; 4 también es más alto, pero pujar por uno probablemente lo pondrá en un desventaja); hasta que cualquier jugador llame mentiroso al jugador que le precede
  • En este punto, todos los jugadores revelan sus dados y cuentan el número del último número ofertado en la mesa por completo
  • Si el total es menor que la oferta, el jugador que hizo la oferta debe dar un dado al jugador que los llamó mentiroso; de lo contrario, el jugador que llamó al postor mentiroso debe darle un dado al postor (para que el postor gane si hay al menos tantos de ese número como había ofertado, no tiene que haber el número exacto)
  • Cuando te quedas sin dados, pierdes
  • El último jugador en pie gana

Por ejemplo:

El jugador uno tiene 1,1,2,4,6
El jugador dos tiene 1,2,2,3,5
El jugador tres tiene 1,3,3,4,6
Jugador uno: tres seises.
Jugador dos: cuatro dos.
Jugador tres: cuatro tres.
Jugador uno: cinco dos.
Jugador dos: seis dos.
Jugador tres: seis tres.
Jugador uno: seis cuatro.
Jugador dos: ¡Mentiroso!
Revelan sus dados y cuentan los que están (porque son salvajes) y los cuatro.
Resulta que hay, de hecho, exactamente seis cuatros.
Entonces el jugador dos le da al jugador uno un dado.
Se vuelven a tirar y el jugador uno comienza la siguiente ronda.

Debes escribir un bot para jugar este juego. Debe implementar la siguiente clase abstracta de Java:

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);
}
  • Debe implementar el método de oferta
    • El primer argumento es la posición actual de su bot en el orden de turno, el segundo es una matriz que muestra cuántos dados tiene actualmente cada jugador (incluido usted), el tercero es una matriz que muestra los valores que se muestran actualmente en sus propios dados, y el cuarto es un conjunto de todas las ofertas realizadas desde el inicio de la ronda actual: tendrá una longitud de 0 si realiza la primera oferta de la ronda
    • El resultado debe ser una cadena de la forma "cara de número" o la cadena "¡Mentiroso!" llamar mentiroso al postor anterior.
    • Si su salida está formateada ilegalmente, será eliminado.
  • Puede anular el método toString, pero no es obligatorio. Sin embargo, no puede editarlo de ninguna manera que interfiera con la legibilidad de la salida del controlador.
  • Se le permite llamar a cualquier otro método público del controlador, pero no a su método principal.
  • Puede leer y editar solo archivos en el directorio en ejecución con el prefijo del nombre de su bot
  • No tiene permiso para recibir información de ninguna otra fuente
  • Las variables de instancia se restablecen al comienzo de cada nuevo juego, pero no las variables estáticas.

Tanteo

  • Se simulará un conjunto de 1,000 juegos, con 3-5 jugadores en cada uno, cada vez que se agregue un bot (tan pronto como se hayan enviado tres o más bots), puntuado como se muestra en la fuente del controlador (en cualquier juego dado, usted obtenga 1 al comienzo de cada uno de sus turnos, 10 cada vez que capture un dado y 1,000 de bonificación si gana); aplicando un límite de 5,000 VUELTAS (no rondas) cada juego.
  • Su bot será calificado por su puntaje del último conjunto de juegos; más diez veces su puntaje de voto, si no es negativo. (Es poco probable que este último tenga un efecto significativo en la puntuación)

La fuente del controlador se puede encontrar aquí.

Puntajes a partir del 2015-06-19:

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
fuente
1
Debe aclarar que la salida debe ser "2 3" y no "dos tres" como muestra su ejemplo. Además, ¿hay alguna forma en el controlador para ver un solo partido?
Caín
No en la versión oficial, pero publicaré una versión alternativa que te permite hacer eso.
SuperJedi224
@Geobits: si quieres. Sin embargo, te pondrá en desventaja si alguien te llama.
SuperJedi224
1
Supongo que los índices de las matrices son los "identificadores" de los jugadores, por lo que diceEachPlayerHas[yourId]= su cuenta de dados, y bids[yourId]es su primera apuesta (o nula si es su primer turno). ¿Es eso correcto?
No es que Charles
1
He visto juegos en los que algunos envíos juegan más juegos que otros (Nadie: 414 juegos, Straight Shooter: 409 juegos). Esto no es justo, ¿puedes arreglar esto?
CommonGuy

Respuestas:

6

Nadie

Intenta adivinar los dados de otros jugadores. Llama a otros mentirosos de bots si no sabe qué hacer.

Editar: se corrigió un problema en el que Nadie pujaba para siempre, nunca llamaba a 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
fuente
Su última serie de actualizaciones realmente parecen haber ayudado.
SuperJedi224
6

Badnomial, el bot que toma malas decisiones en función de las distribuciones binomiales: Editar: Se corrigió un error estúpido en los cálculos de probabilidad, ahora representa el siguiente postor, así como el 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));
 }

}

Intenta determinar si debe farolear o llamar a Mentiroso basándose en las distribuciones binomiales acumuladas estimadas para sí mismo y las posibilidades de los postores anteriores y siguientes de tener presentes sus dados necesarios.

Básicamente, llama a Mentiroso si el Postor anterior es muy probable que sea un Mentiroso o si siente que tanto él como el próximo Postor mienten más que no.

Potencial de inacción
fuente
Con estos cambios, Badnomial en realidad parece remotamente competente frente a los otros bots.
Inactivo
5

Tirador recto

Lo juega derecho y no farolea. También es lo suficientemente ingenuo como para pensar que los demás también lo hacen, por lo que nunca llama mentiroso a menos que la apuesta supere el número total de dados en juego (menos sus propios dados que no coinciden con la oferta).

Para ser un poco más conservador que el número exacto esperado para cada dado, no cuenta sus propios comodines, pero supone que otros tienen una distribución uniforme. Con los cuatro jugadores actuales, él o el MostHonestAbe aparecieron primero cada vez, con puntajes bastante cercanos.

Supongo que la oferta mínima es 2 2 . Si se permite una oferta de un dado (u ofertas), avíseme para que pueda hacer ese cambio.

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
fuente
Esto y MostHonestAbe son tan reacios a mentir o llamar mentiroso, hay algunos juegos que van a 2000 turnos cuando pruebo jaja. : P
Caín
Lo mismo en el mío. Sin embargo, está bien, porque cada turno es un punto extra hacia la puntuación final. Si tengo 2000 turnos y no gano, eso es mejor que ganar después de 100 en mi libro;)
Geobits
Solo tenía que volver a mirar las reglas de puntuación. Juego completamente nuevo XD
Cain
Sí, con este puntaje parece que la estrategia óptima podría ser ser lo más conservador posible y acumular puntos. Quizás haya algo mejor, pero no puedo verlo.
Geobits
1
No estoy seguro de que haga mucha diferencia. Ser conservador aún sería una ventaja, solo porque tiene una menor probabilidad de perder un dado. La razón por la que más personas no juegan de esa manera en la vida real es porque es aburrido, pero ¿qué es el aburrimiento para un bot?
Geobits
4

Mayormente honesto

Abe hace suposiciones conservadoras sobre la muerte del resto de los oponentes, y luego se mantiene honesto hasta que no cree que haya suficientes dados para vencer la oferta actual. En este punto, farolea una vez y luego llama mentiroso la 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;
    }
}
Caín
fuente
1
¿Me estás tomando el pelo? Estaba a menos de cinco minutos de publicar HonestAbe . Ahora tengo que pensar un nuevo nombre: P
Geobits
1
No se puede tener un juego con Liar en el nombre sin una referencia de Abraham Lincoln en alguna parte.
Caín
4

Dr. House

¡Todos mienten!

public class DrHouse extends Player
{   
  public String bid(int yourId, int[] diceEachPlayerHas, int[] yourDice, String[] bids)
  {
    return "Liar!";
  }
}
Gus314
fuente
1
Sugiero agregar una lógica especial para cuando tenga la primera oferta de la ronda.
SuperJedi224
44
@ SuperJedi224 Me imagino que el bot considera al controlador diciéndole que es su turno de mentiroso
Nathan Merrill
Made my day lol
Rohan Jhunjhunwala
2

Fidelio

Este bot sabe que solo su valor más recurrente lo llevará a la victoria, por lo que se queda con él. Asume que hay una porción de los dados de todos que es igual a la suya, si alguien oferta más que esa porción, asume que es un 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 haga un buen trabajo :).

Katenkyo
fuente
Recibo una IndexOutOfBoundsException en la línea 13. Recuerde que las matrices están indexadas en 0 en Java.
SuperJedi224
Ahora estoy obteniendo uno en el otro extremo en la línea 19, para un índice de -1. Parece que estaba intentando leer el último elemento de una matriz vacía, debe incluir una verificación para eso.
SuperJedi224
Se corrigió, la comprobación si (bids.length == 0) se realizó después de usar las ofertas ...
Katenkyo
Oh, acababa de proponer otra posible solución, pero probablemente esto también funcione.
SuperJedi224
Ah, ¿entonces esta edición sugerida ya no es necesaria?
mbomb007
2

Estadístico

Tienes 1/3 de probabilidad de tener cualquier número que no sea ases. Un tipo me dijo una vez que no revisar tus dados y solo saber las probabilidades puede hacerte ganar este juego. EDITAR: estaba haciendo una oferta demasiado alta. Pero no mejora mucho la puntuación.

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";
    }
}
Golpear
fuente
1

Bot absurdo

Afirma que todos los dados son 6's a menos que no pueda. Si el bot no puede hacer eso, significa que esta es una situación imposible o casi imposible. Debido a esto, llama mentiroso. Tengo curiosidad por saber cuán efectivo será este bot.

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
fuente
En cuanto a qué tan efectivo: su función principal parece ser entregar dados a cualquier jugador que lo siga: P
Geobits
@Geobits arreglé el código. Esto es lo que sucede cuando intenta saltar en un lenguaje de programación no ha programado antes ...
Frederick
@Geobits Gracias por toda la ayuda. Creo que esto finalmente funciona correctamente ahora. ¿Lo hace? (Java es confuso)
frederick
Sí, corre ahora. Sin embargo, la estrategia es increíblemente suicida. Obtiene solo ~ 2% del siguiente jugador más bajo.
Geobits
@Geobits Nunca intenté correrlo contra los otros jugadores. ¿Lo corriste contra los demás?
Frederick
1

El pirata

Hice algunos bots simples mientras probaba el controlador, y este es el único que realmente es bueno.

Probablemente se mejorará más adelante.

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
fuente