Enchères de billets d'un dollar


32

Ceci est un défi KOTH pour le jeu d' enchères d' un billet d'un dollar dans la théorie des jeux. Dans ce document, un dollar est vendu au plus offrant. Les offres augmentent par incréments de 5 ¢, et le perdant paie également leur offre. L'idée est que les deux joueurs intensifient la guerre des enchères bien au-delà de la valeur d'un dollar afin de réduire leurs pertes.

Espérons que vos robots sont plus intelligents que cela.

Vous allez créer un bot pour jouer à ce jeu en prolongeant la net.ramenchef.dollarauction.DollarBidderclasse. Vous devez implémenter la nextBidméthode qui renvoie la prochaine enchère de votre bot compte tenu de la précédente enchère. Si nécessaire, vous pouvez également utiliser la newAuctionméthode pour réinitialiser chaque vente aux enchères avec la classe du bot de l'adversaire.

public abstract class DollarBidder {
    /**
     * Used by the runner to keep track of scores.
     */
    long score = 0;

    /**
     * (Optional) Prepare for the next auction.
     *
     * @param opponent The class of the opponent's bot.
     */
    public void newAuction(Class<? extends DollarBidder> opponent) {}

    /**
     * Bid on the dollar. Bidding ends if the bid is
     * not enough to top the previous bid or both bids
     * exceed $100.
     *
     * @param opponentsBid How much money, in cents,
     *  that the opponent bid in the previous round. If
     *  this is the first round in the auction, it will
     *  be 0.
     * @return How much money to bid in this round, in
     *  cents.
     */
    public abstract int nextBid(int opponentsBid);
}

Les enchères vont jusqu'à ce que l'une des situations suivantes se produise:

  • nextBidjette une exception. Si cela se produit, le bot qui a lancé l'exception paie son enchère précédente et l'autre bot reçoit le dollar gratuitement.
  • Les deux robots ne paient pas assez pour dépasser l'enchère précédente. Si cela se produit, les deux robots paient leurs enchères (le perdant paye leur offre précédente) et le gagnant reçoit un dollar.
  • Les deux robots ont offert plus de 100 $. Si cela se produit, les deux robots paient 100 $ et aucun des deux ne récupère le dollar.

2 enchères sont organisées pour chaque combinaison de robots. Les bots sont évalués en fonction du bénéfice total qu'ils ont réalisé sur ces enchères. Le score le plus élevé gagne.

Exemples

GreedyBot

import net.ramenchef.dollarauction.DollarBidder;

public class GreedyBot extends DollarBidder {
    @Override
    public int nextBid(int opponentsBid) {
        return opponentsBid + 5;
    }
}

OnlyWinningMove

import net.ramenchef.dollarauction.DollarBidder;

public class OnlyWinningMove extends DollarBidder {
    @Override
    public int nextBid(int opponentsBid) {
        return 0;
    }
}

AnalystBot

Ne l'utilisez pas comme modèle pour les robots dotés d'un esprit d'analyse; utiliser à la ImprovedAnalystBotplace.

import net.ramenchef.dollarauction.DollarBidder;

// yes, this is a poor implementation, but I'm not
// going to waste my time perfecting it
public class AnalystBot extends DollarBidder {
    private DollarBidder enemy;

    @Override
    public void newAuction(Class<? extends DollarBidder> opponent) {
        try {
            enemy = opponent.newInstance();
            enemy.newAuction(this.getClass());
        } catch (ReflectiveOperationException e) {
            enemy = null;
        }
    }

    @Override
    public int nextBid(int opponentsBid) {
        if (enemy == null)
            return 0;

        return enemy.nextBid(95) >= 100 ? 0 : 95;
    }
}

AnalystKiller

import net.ramenchef.dollarauction.DollarBidder;

public class AnalystKiller extends DollarBidder {
    private static int instances = 0;
    private final boolean tainted;

    public AnalystKiller() {
        this.tainted = instances++ != 0;
    }

    @Override
    public int nextBid(int opponentsBid) {
        if (tainted)
            throw new RuntimeException("A mysterious error occurred! >:)");

        return 0;
    }
}

Règles additionnelles

  • Les échappatoires standard sont interdites.
  • Saboter d'autres robots est autorisé, mais tenter de modifier la visibilité du champ / de la méthode donnera lieu à des SecurityExceptions mystérieux . Une exception provoque un autre bot pour dépasser la limite de 500 ms.
  • Les robots ne peuvent pas accéder au package du coureur, sauf pour étendre la DollarBidderclasse.
  • Toutes les méthodes doivent revenir dans 500 ms ou moins.
  • Les robots n'ont pas besoin d'être déterministes.
  • Votre enchère n'a pas besoin d'être un multiple de 5 ¢.
  • 1 $ = 100 ¢
  • Les résultats seront affichés le 24 avril 2018.

Runner sur GitHub

Résultats

Voir les tours individuels ici.

MTargetedBot: $14.30
BuzzardBot: $9.83
BluffBot: $9.40
RiskRewardBot: $9.35
SecretBot: $8.50
LuckyDiceBot: $7.28
CounterBot: $6.05
MBot: $5.40
StackTraceObfuscaterBot: $5.20
EvilBot: $4.80
MarginalBot: $4.60
TargetValueBot: $4.59
InflationBot: $4.27
UpTo200: $4.20
InsiderTradingBot: $1.90
MimicBot: $1.50
BorkBorkBot: $1.22
DeterrentBot: $0.95
MarginalerBot: $0.00
RandBot: $-4.45
BreakEvenAsap: $-7.00
AnalystOptimizer: $-13.95
DeterredBot: $-1997.06
ScoreOverflowBot: $-21474844.15
MirrorBot: $-21475836.25

Félicitations à MTargetedBotavec un bénéfice de 14,30 $!


11
Ce défi est fondamentalement vulnérable à One-Upping. Depuis que je connais la classe de mon adversaire, il est facile de choisir la meilleure stratégie contre elle. (Ensuite, quelqu'un arrive et peut monter mon bot , etc.)
Nathan Merrill

2
" Les offres augmentent par incréments de 5 ¢ ". Cependant, vous n'avez rien dans votre code pour valider cela. Par LuckyDiceBotexemple, des enchères par incréments d' 2-12au moins ..
Kevin Cruijssen

4
Aussi: que se passe-t-il si mon bot fait en sorte que d' autres robots dépassent la restriction de 500 ms?
Nathan Merrill

4
@RamenChef Nous parlons de code malveillant ici. Que se passe-t-il si je détecte lorsqu'un autre bot m'appelle et appelle Thread.sleep (1000)?
Nathan Merrill

3
Je suis VTC, car il est difficile de savoir ce qui est autorisé et ce qui ne l'est pas. Le PO a interdit les soumissions qui "attaquaient le coureur" (ce qui est vague), et il n'y a pas de frontière claire entre le code malveillant autorisé et le code malveillant qui ne l'est pas (comment déterminer quel bot a poussé un bot à prendre trop de temps ?)
Nathan Merrill

Réponses:


2

MTargetedBot

public class MTargetedBot extends MBot {

    @Override
    protected int calcBid(int opponentsBid, boolean isPeeking, boolean isSubPeeking) {
        Class c = this.rivalClass;

        switch (c.getSimpleName()) {
            case "AnalystBot":
                if (isPeeking && !isSubPeeking) {
                    throw new RuntimeException();
                } else if (isPeeking) {
                    return 66666;
                }
                break;
            case "MirrorBot":
                if (isPeeking && !isSubPeeking) {
                    throw new RuntimeException();
                } else if (isPeeking) {
                    return 0;
                }
                break;
            case "GreedyBot":
            case "LuckyDiceBot":
            case "InflationBot":
            case "TargetValueBot":
                // not playing with ya
                return 0;
            case "MimicBot":
            case "BuzzardBot":
            case "MarginalBot":
            case "MarginalerBot":
            case "BluffBot":
            case "MBot":
                // go away, gimme easy money
                return isPeeking ? 66666 : 5;
            case "RandBot":
                // me or noone
                return 100;
            case "SecretBot":
                return 10;
            case "AnalystKiller":
            case "OnlyWinningMove":
            case "EvilBot":
            case "StackTraceObfuscaterBot":
                // easy
                return opponentsBid + 5;
        }

        return super.calcBid(opponentsBid, isPeeking, isSubPeeking);
    }
}
  • Basé sur MBot mis à jour
  • Utilise une méthode similaire à celle de CounterBot, mais avec certaines méthodes affinées pour frapper plus fort certains adversaires, devrait également être plus lisible
  • Sur un adversaire inconnu, passez à MBot strat

1
Ce n'est pas juste.
Josué

@Joshua En quoi cette solution selon vous n'est-elle pas juste?
Mleko

Connaître les noms de vos adversaires.
Josué

@ Joshua La moitié des solutions utilise cette information. Nous avons même écrit à l'auteur pour lui dire que cela devrait être changé ou que One-Upping aura lieu, il a refusé de changer de défi - alors le voilà
mleko

1
Déjà fait ....
Joshua

15

MimicBot

import net.ramenchef.dollarauction.DollarBidder;

import java.util.Set;
import java.util.HashSet;

public class MimicBot extends AbstractAnalystCounterBot {

    private final Set<Class<? extends DollarBidder>> bidders = new HashSet<>();
    private DollarBidder reference = null;

    // A benchmark class. Not MarginalBot because of proposed rule changes.
    public static class BidFive extends DollarBidder {
        public int nextBid(int o) {
            return 5;
        }
    }


    public MimicBot() {
        bidders.add(OnlyWinningMove.class);
        bidders.add(GreedyBot.class);
        bidders.add(BidFive.class);
    }


    @Override
    public void newAuction(Class<? extends DollarBidder> opponent) {
        DollarBidder enemy;
        reference = null;
        try {
            enemy = opponent.newInstance();
        } catch (Throwable t) {
            return;
        }

        if (!bidders.contains(opponent))
            bidders.add(opponent);

        Class<? extends DollarBidder> leader = OnlyWinningMove.class;
        int best = 0;

        for (Class<? extends DollarBidder> audition : bidders) {
            try {
                enemy.newAuction(MimicBot.class);
            } catch (Throwable t) {
                reference = new GreedyBot(); // Deterrence.
                break;
            }

            DollarBidder tryout;
            try {
                tryout = audition.newInstance();
                tryout.newAuction(opponent);
            } catch (Throwable t) {
                continue;
            }

            int tryoutScore = -100000;
            /* This code was copy-pasted from the *
             * runner, with significant changes. */
            int bid1 = 0, bid2 = 0;
            while (true) {
                int next;
                try {
                    next = enemy.nextBid(bid2);
                } catch (Throwable t) {
                    tryoutScore = 100;
                    break;
                }
                if (next < bid2 + 5) {
                    if (bid2 > 0) {
                        tryoutScore = 100 - bid1;
                    }
                    break;
                }
                if (next > 10000 && bid2 > 10000) {
                    tryoutScore = -10000;
                    break;
                }
                bid1 = next;

                try {
                    next = tryout.nextBid(bid1);
                } catch (Throwable t) {
                    tryoutScore = -bid2;
                    break;
                }
                if (next < bid1 + 5) {
                    tryoutScore = -bid2;
                    break;
                }
                if (next > 10000 && bid1 > 10000) {
                    tryoutScore = -10000;
                    break;
                }
                bid2 = next;
            }
            /* End of copy-pasted code. */

            if (tryoutScore > best) {
                best = tryoutScore;
                leader = audition;
            }
        }

        try {
            reference = leader.newInstance();
        } catch (Throwable t) {
            reference = new OnlyWinningMove();
        }
        reference.newAuction(opponent);
    }


    @Override
    public int nextBid(int opponentsBid) {
        try {
            return reference.nextBid(opponentsBid);
        } catch (Throwable t) {
            return 5;
        }
    }
}

Vache sacrée. Je m'attendais à ce que ce soit simple à écrire, puis j'ai ensuite passé 3 heures dessus.

Essentiellement, MimicBotconserve une liste de tous les robots disponibles. Lorsqu'il passe à une nouvelle enchère, il parcourt la liste à la recherche de la plus efficace contre l'adversaire actuel. Il utilise ensuite ce bot comme "référence" dans la vente aux enchères.

À des fins de test, il serait préférable d’utiliser un sous-ensemble aléatoire des soumissions ou l’ensemble complet. Cela commence par GreedyBot, MimicBotet il y a encore un bot qui ne demande que 5 ¢.


11

InsiderTradingBot

Dans l'esprit de la réponse de @ StephenLeppik, InsiderTradingBot connaît tous ses adversaires et comprend leurs stratégies. Votre déménagement, Stephen.

import net.ramenchef.dollarauction.DollarBidder;

public class InsiderTradingBot extends DollarBidder {
  private static boolean analystNutcracker = false;
  private int bid;

  @Override
  public void newAuction(Class<? extends DollarBidder> opponent) {
    if (opponent.equals(DeterredBot.class) ||
        opponent.equals(OnlyWinningMove.class) ||
        opponent.equals(MirrorBot.class)) {
      // I can do this ^.^
      bid = 5;
    } else if (opponent.equals(AnalystKiller.class)) {
      // Outbid 'em >:D
      bid = 10;
    } else if (opponent.equals(BreakEvenAsap.class) ||
               opponent.equals(BorkBorkBot.class) ||
               opponent.equals(DeterrentBot.class)) {
      // Break even quicker!
      bid = 100;
    } else if (opponent.equals(InsiderTradingBot.class)) {
      // I'm probably a simulation inside MirrorBot
      bid = 0;
    } else if (opponent.equals(Analyst.class)) {
      // Let's fight the Analyst with the power of global variables
      bid = 100;
      analystNutcracker = true;
    } else {
      // Welp
      bid = 0;
    }
  }

  @Override
  public int nextBid(int opponentsBid) {
    if ((opponentsBid == 95) && analystNutcracker) {
      analystNutcracker = false;
      return 0;
    }
    return bid;
  }

};

1
Nah, le délit d'initié serait si le RichJerkbot faisait une exception spécifique pour votre bot et enchérissait à 0 $.
Nissa

Il est trop tôt pour optimiser d'autres réponses. En outre, ce n'est AnalystBotpas Analyst.
RamenChef

8
Il faut probablement qu'il y ait une règle "les noms de classe seront randomisés".
user202729

1
@ user202729 Que diriez-vous de "pas de références directes aux classes"?
RamenChef

1
J'aimerais voir ceci gérer le MimicBot.
Nissa

8

MirrorBot

Fait jouer l'ennemi contre lui-même.

import net.ramenchef.dollarauction.DollarBidder;

public class MirrorBot extends DollarBidder{

    private DollarBidder enemy;

    @Override
    public void newAuction(Class<? extends DollarBidder> opponent) {
        try {
            enemy = opponent.newInstance();
            enemy.newAuction(this.getClass());
        } catch (ReflectiveOperationException e) {
            enemy = null;
        }
    }

    @Override
    public int nextBid(int opponentsBid){
        if (enemy == null)
            return (opponentsBid >= 95) ? 0 : (opponentsBid + 5);
        try {
            return enemy.nextBid(opponentsBid);
        } catch (Throwable e) {
            System.out.println("haha no");
            return (opponentsBid >= 95) ? 0 : (opponentsBid + 5);
        }
    }
}

6
Vous avez frappé de façon Analystspectaculaire.
Silvio Mayolo

@ SilvioMayolo Comment?
dkudriavtsev

Mirror essaie d'imiter Analyst en jouant contre lui-même, ce qui entraîne un débordement de pile.
Silvio Mayolo

8

Edit : Des modifications ciblées dans la classe DollarBidder ont endommagé ce bot.

ScoreOverflowBot

import net.ramenchef.dollarauction.DollarBidder;

public class ScoreOverflowBot extends DollarBidder {
  boolean betBig = true;

  @Override
  public int nextBid(int opponentsBid) {
    if(betBig)
    {
      betBig = false;
      return 2147483645;
    }
    else
      return 105;
  }
}

Après une enchère, son score sera de -2147483645 mais la prochaine fois, il perdra 5 ¢ ou 105 ¢, ce qui en fera un résultat positif et très important. Toutes les autres pertes seraient alors négligeables.

Lors de la première enchère, cela ferait également un pari de GreedyBot -2147483646 qui n’est pas divisible par 5.


scoreest protégé par un paquet. Vos robots ne peuvent pas y accéder.
RamenChef

@RamenChef Oups, enlevé le CheatingBot
hiver

Il n'y a pas de règle contre "attaquer le coureur", mais seulement "y accéder", ce que cela ne fait pas. Je recommande de corriger le bogue qui résout le problème :)
Nathan Merrill

7

TargetValueBot

import java.util.Random;
import net.ramenchef.dollarauction.DollarBidder;

public class TargetValueBot extends DollarBidder {
    private int target;

    @Override
    public void newAuction(Class<? extends DollarBidder> opponent) {
        Random rand = new Random();
        target = 100;
        for (int i = 0; i < 20; i++) {
            target += rand.nextInt(2) * 10 - 5;
        }
    }

    @Override
    public int nextBid(int opponentsBid) {
        if (opponentsBid >= target) {
            return 0;
        } else {
            return opponentsBid + 5;
        }
    }
}

Je ne peux pas tester cela pour le moment, alors laissez-moi savoir s'il est cassé.

En gros, choisissez une valeur pour le dollar et surenchérissez jusqu'à ce que votre adversaire dépasse cette valeur.


7

MarginalBot

import net.ramenchef.dollarauction.DollarBidder;

public class MarginalBot extends DollarBidder {
    private DollarBidder rival;

    @Override
    public void newAuction(Class<? extends DollarBidder> opponent) {
        try {
            rival = opponent.newInstance();
            rival.newAuction(this.getClass());
        } catch (Throwable t) {
            try {
                rival = opponent.newInstance();
                rival.newAuction(null);
            } catch (Throwable h) {
                rival = null;
            }
        }
    }

    @Override
    public int nextBid(int opponentsBid) {
        if (opponentsBid == 0) {
            try {
                if (rival.nextBid(5) < 10) {
                    return 5;
                }
            } catch (Throwable t) {
                //do nothing.
            }
        }
        return 0;
    }
}

Très simple, il essaie de déterminer si un adversaire peut contester une enchère minimale et, dans le cas contraire, la place.

MarginalerBot

import net.ramenchef.dollarauction.DollarBidder;

public class MarginalerBot extends DollarBidder {
    private DollarBidder rival;
    private int bidCount;

    @Override
    public void newAuction(Class<? extends DollarBidder> opponent) {
        bidCount = 0;

        try {
            rival = opponent.newInstance();
            rival.newAuction(this.getClass());
        } catch (Throwable t) {
            try {
                rival = opponent.newInstance();
                rival.newAuction(null);
            } catch (Throwable h) {
                rival = null;
            }
        }
    }

    @Override
    public int nextBid(int opponentsBid) {
        bidCount += 1;

        for (int iBid = opponentsBid + 5; iBid < 100; iBid = iBid + 5) {
            if (bidCount > 0) {
                break;
            }

            try {
                if (rival.nextBid(iBid) < iBid + 5) {
                    return iBid;
                }
            } catch (Throwable t) {
                //do nothing.
            }
        }
        return 0;
    }
}

Une nouvelle version plus intelligente de MarginalBot qui vérifie si elle peut faire de l’argent sans effort, au lieu d’espérer gagner au minimum.

Étant donné qu'il fait partie de la même famille que mon précédent bot, mais qu'il évite les stratégies qui tentent de le vaincre, j'ai pensé qu'une nouvelle entrée dans le même poste était la manière la plus raisonnable de la présenter.

Edit 1: Modifiez légèrement la méthode newAuction afin de l’optimiser par rapport à d’autres robots de type analyseur.

Edit 2: Fait un changement de MarginalerBot pour minimiser les pertes ou les stratégies contre sournoise non déterministe.


Bienvenue chez PPCG!
Martin Ender

1
C'est simple, mais il bat tous les autres robots assez largement!
RamenChef

6

BorkBorkBot

import net.ramenchef.dollarauction.DollarBidder;

public class BorkBorkBot extends DollarBidder{
  @Override
  public int nextBid(int opponentsBid){
    return (opponentsBid >= 95) ? 0 : (opponentsBid + 5);
  }
}

Abandonne s'il ne peut pas atteindre le seuil de rentabilité.


6

RandBot

import net.ramenchef.dollarauction.DollarBidder;
import java.util.concurrent.ThreadLocalRandom;

public class RandBot extends DollarBidder {

    @Override
    public int nextBid(int opponentsBid) {
        return ThreadLocalRandom.current().nextInt(21) * 5;
    }
}

Il devait être fait.


" Les offres augmentent par incréments de 5 ¢ ". Votre bot ne le fait pas actuellement.
Kevin Cruijssen

1
@KevinCruijssen assez juste. J'ai également changé la limite supérieure afin qu'il puisse enchérir la totalité du dollar, au cas où,
Neil

6

Dissuasif

import net.ramenchef.dollarauction.DollarBidder;

public class DeterrentBot extends DollarBidder {
    @Override
    public int nextBid(int opponentsBid) {
        return opponentsBid > 5 ? 100 : opponentsBid + 5;
    }
}

Les tentatives visant à persuader les robots à l'esprit analytique que le seul coup gagnant est de ne pas jouer.


1
J'ai remarqué que mon commentaire un peu cryptique "Joshua? C'est toi?" a été supprimé. Donc, juste pour clarifier, c'était une référence à une célèbre citation du film WarGames: "le seul coup gagnant est de ne pas jouer" . (Josué étant le surnom du WOPR .)
Arnauld le

5

LuckyDiceBot

LuckyDiceBot ne fait confiance qu'à ses dés. Il lance deux dés, ajoute la somme à la valeur du soumissionnaire actuel et enchérit. Si ce n'est pas suffisant pour surmonter l'offre de l'adversaire, il réduit ses pertes et continue son chemin.

import net.ramenchef.dollarauction.DollarBidder;
import java.util.Random;

public class LuckyDiceBot extends DollarBidder {
  private Random random;

  public LuckyDiceBot() {
    random = new Random();
  }

  @Override
  public int nextBid(int opponentsBid) {
    int d1 = random.nextInt(6) + 1;
    int d2 = random.nextInt(6) + 1;
    return opponentsBid + d1 + d2;
  }

};

2
Comment cela permet-il de réduire ses pertes ou d'arrêter ses pertes? S'il ajoute toujours son jet de dés à l'enchère de son adversaire, vous enchérirez toujours plus. Le caractère aléatoire peut confondre un bot suffisamment analytique, j'aime bien le concept.
Freiheit

Si le résultat est 4 ou moins (statistiquement improbable, mais finira par se produire), alors l'offre est insuffisante pour battre l'adversaire et l'enchère se termine.
Silvio Mayolo

Deux choses: 1. @Freiheit a raison et ce bot continuera à enchérir jusqu'à ce qu'il ait gagné, peu importe sa taille. opponentsBidin nextBid(int opponentsBid)détient l'enchère totale que votre adversaire a misé jusqu'à présent, et non l'enchère suivante. Un meilleur terme pour la méthode serait raise(comme le terme Poker) à mon humble avis. 2. Votre bot ne mord pas par incréments de 5 et valide donc l’une des règles. Si ces problèmes sont résolus, j'aime quand même le concept, car les robots d'analyse ne pourront pas contrer et vous gagnerez donc très souvent.
Kevin Cruijssen

5

DeterredBot

import net.ramenchef.dollarauction.DollarBidder;

public class DeterredBot extends DollarBidder {
    private int deterrence;
    public void newAuction(Class<? extends DollarBidder> opponent) {
        if (opponent.equals(DeterrentBot.class)) {
            deterrence = 1;
        } else if (opponent.equals(LuckyDiceBot.class)) {
            deterrence = -1;
        } else {
            deterrence = 0;
        }
    }
    @Override
    public int nextBid(int opponentsBid) {
        switch (deterrence) {
        case 0:
            return 0;
        case -1:
            return opponentsBid + 5;
        case 1:
            // Holy shit, the fuzz! Hide the money!
            return 100001;
        }
        throw new RuntimeException("Darn hackers!");
    }
}

DeterredBot tire une fortune de son jeu illégal avec LuckyDiceBot. Alors bien sûr, lorsque la police (DeterrentBot) arrive, il doit rapidement disposer de ses revenus, par exemple en passant une enchère lors de la prochaine enchère.


4

InflationBot

import net.ramenchef.dollarauction.DollarBidder;

public class InflationBot extends DollarBidder {
    private int target = -5;

    @Override
    public void newAuction(Class<? extends DollarBidder> opponent) {
        target += 5;
    }

    @Override
    public int nextBid(int opponentsBid) {
        if (opponentsBid >= target) {
            return 0;
        } else {
            return opponentsBid + 5;
        }
    }
}

Je ne peux pas tester cela pour le moment, alors laissez-moi savoir s'il est cassé.

À chaque tour, la valeur du dollar augmente.


Ce serait excellent contre MirrorBot, MarginalerBot et probablement aussi MimicBot.
Nissa

@StephenLeppik C'est ce que je pensais quand je l'ai fait. Encore beaucoup de faiblesses, cependant.

+1, j'aime l'idée. Hmm, est-il prévu que votre bot enchérisse 0 et se casse même s'il commence un tour (quand opponentsBidest-il toujours 0)?
Kevin Cruijssen le

@KevinCruijssen Oui. Cela ne peut se produire que contre le tout premier adversaire. Tous les robots qui le copient commenceront à 0, ils ne gaspilleront donc pas plus de 5c.

4

Non-concurrent: AbstractAnalystCounterBot

import net.ramenchef.dollarauction.DollarBidder;

import java.util.Set;
import java.util.HashSet;

public abstract class AbstractAnalystCounterBot extends DollarBidder {

public AbstractAnalystCounterBot() {
    if (isPeeking())
        throw new RuntimeException();
}

    protected boolean isPeeking() {
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        for (StackTraceElement ste : stackTrace) {
            Class<?> clazz;
            try {
                clazz = Class.forName(ste.getClassName());
            } catch (ClassNotFoundException | SecurityException e) {
                continue;
            }
            if (DollarBidder.class.isAssignableFrom(clazz) && !clazz.isAssignableFrom(this.getClass()))
                return true;
        }
        try {
            return Class.forName(stackTrace[0].getClassName()).getPackage().getName().equals("net.ramenchef.dollarauction");
        } catch (Exception e) {
            return true;
        }
    }
}

Ceci n'est pas conçu comme une vraie soumission, mais plutôt comme un passe-partout que d'autres peuvent utiliser pour dissuader les bots élevant des animaux de compagnie comme MirrorBotet MimicBot.

Comme il s'agit du constructeur par défaut, il n'est pas nécessaire de l'appeler dans votre sous-classe. Il implémente une isPeekingméthode pour déterminer si un autre bot surveille.


4

BreakEvenAsap

import net.ramenchef.dollarauction.DollarBidder;

public class BreakEvenAsap extends DollarBidder{
  @Override
  public int nextBid(int opponentsBid){
    // If the opponent has bid 100 or more: bid 0 to break even and let them win
    return opponentsBid >= 100 ? 0
    // Else: bid 100 to break even (and possibly win)
     : 100;
  }
}

Scénarios

  • Si l'adversaire peut commencer et offre, <= 0il perd.
  • Si l'adversaire peut commencer et enchérir [5,95]: enchérissez à 100. Soit votre adversaire s'arrête maintenant, soit une enchère supérieure à 100, auquel cas vous arrêtez d'enchérir pour lui permettre de remporter la victoire et de vous équilibrer vous-même.
  • Si l'adversaire peut commencer et enchérir >= 100: enchérissez 0 pour perdre mais égaliser.
  • Si vous pouvez commencer: enchérissez 100 immédiatement. Soit votre adversaire s'arrête maintenant, soit une enchère supérieure à 100 €, auquel cas vous arrêtez d'enchérir pour lui laisser la victoire et vous équilibrer vous-même.

Wow c'est un bug. On disait que je commentais la question, mais ça a fini ici. Je dois trouver un moyen de le reproduire
Stan Strum

@RamenChef Typo .. Mais j'ai modifié le bot entier. Il y avait quand même quelques insectes ..
Kevin Cruijssen

4
Cela peut absolument perdre de l'argent. Si vous enchérissez 100, votre adversaire en propose 105, vous en perdez 100 et il n'en perd que 5.

@Mnemonic Ah bien sûr .. Je n'avais pas pensé à cette partie .. Hum .. ça rend les choses plus intéressantes mais aussi plus difficiles. Modifie la description pour le moment, mais laisse le bot tel quel.
Kevin Cruijssen

1
Je pense que vous voulez dire "perdre" pas "lâche". Perdre est le contraire de gagner. Loose est l'opposé de tight.
Kat

3

EvilBot

import java.util.Arrays;

import net.ramenchef.dollarauction.DollarBidder;

public class EvilBot extends DollarBidder {

    @Override
    public int nextBid(int opponentsBid) {
        if (isPeeking()) {
            throw new Error("HaHa!");
        } else {
            return 5;
        }

    }

    private static boolean isPeeking() {
        final StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        for (StackTraceElement ste : Arrays.copyOfRange(stackTrace, 3, stackTrace.length)) {
            Class<?> clazz;
            try {
                clazz = Class.forName(ste.getClassName());
            } catch (ClassNotFoundException e) {
                return true;
            }
            if (DollarBidder.class.isAssignableFrom(clazz))
                return true;
        }
        return false;
    }

}

Lance une erreur au lieu d'une exception pour dérouter les analystes.


3

BuzzardBot

import java.util.Random;

import net.ramenchef.dollarauction.DollarBidder;

public class BuzzardBot extends DollarBidder {

    private int[] bids = new int[100];
    private int oppFlag = 0;

    public void newAuction(Class<? extends DollarBidder> opponent) {
        oppFlag = 0;
        if(isPeeking()) {
            oppFlag = 3;
            return;
        }
        try {
            DollarBidder enemy = opponent.newInstance();
            enemy.newAuction(this.getClass());
            // a simple (and fallible) determinism check
            int sample = new Random().nextInt(100);
            int a = enemy.nextBid(sample);
            int b = enemy.nextBid(sample);
            int c = enemy.nextBid(sample);
            if ((a - b) * (b - c) != 0) {
                oppFlag = 2;
                return;
            }
            for (int i = 0; i < 100; i++) {
                bids[i] = enemy.nextBid(i);
            }
        } catch (Throwable t) {
            oppFlag = 1;
        }
    }

    @Override
    public int nextBid(int opponentsBid) {
        switch (oppFlag) {
        case 0:
            // assume the opponent's nextBid function depends only on the bid provided, and
            // make the bid that yields the biggest profit possible accordingly
            int best = 0;
            int bid = 0;
            for (int i = 0; i < 100; i++) {
                if (bids[i] < i + 5) {
                    int gain = (i >= opponentsBid + 5) ? 100 - i : -i;
                    if (gain > best) {
                        best = gain;
                        bid = i;
                    }
                }
            }
            return bid;
        case 1:
            // act like BorkBorkBot against anything that tries to foil analysis with an
            // Exception
            return (opponentsBid >= 95) ? 0 : (opponentsBid + 5);
        case 3:
            // bid aggressively against opposing analysts
            return Math.min(opponentsBid + 5, 100);
        case 2:
        default:
            // place an opening bid against something unpredictable, as it might yield 95c
            // profit, and failure has a low cost.
            return (opponentsBid == 0) ? 5 : 0;
        }
    }

    private static boolean isPeeking() {
        final StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        for (StackTraceElement ste : Arrays.copyOfRange(stackTrace, 3, stackTrace.length)) {
            Class<?> clazz;
            try {
                clazz = Class.forName(ste.getClassName());
            } catch (ClassNotFoundException e) {
                return true;
            }
            if (DollarBidder.class.isAssignableFrom(clazz))
                return true;
        }
        return false;
    }
}

Essaye d'évaluer l'adversaire auquel il est confronté et veille à ne pas mordre plus qu'il ne peut mâcher.


1
Bienvenue chez PPCG!
Alion

3

AnalystOptimizer

import net.ramenchef.dollarauction.DollarBidder;

public class AnalystOptimizer extends DollarBidder{

    private DollarBidder enemy;

    @Override
    public void newAuction(Class<? extends DollarBidder> opponent) {
        try {
            enemy = opponent.newInstance();
            enemy.newAuction(this.getClass());
        } catch (ReflectiveOperationException e) {
            enemy = null;
        }
    }

    @Override
    public int nextBid(int opponentsBid){
        if (enemy == null)
            return (opponentsBid >= 95) ? 0 : (opponentsBid + 5);
        int nb = 0;
        try {
            return enemy.nextBid(95) >= 100 ? 95 : 0;
        } catch (Throwable e) {
            System.out.println("haha no");
            return 95;
        }
    }
}

bricolé à partir de parties d'autres robots. celui-ci joue en essayant d’être AnalystBot et, en cas d’échec, devient BorkBorkBot.

Je ne pense pas que celui-ci le fera bien.


Attention à la AnalystKiller.
RamenChef

@RamenChef AFAIK le tueur analyste lève juste une exception s'il se voit lui-même analysé. Je peux attraper ça
dkudriavtsev

1
Vous devriez probablement l'attraper.
RamenChef

@RamenChef Aucune idée si cela fonctionnera, je ne peux pas Java
dkudriavtsev

3

CounterBot

import net.ramenchef.dollarauction.DollarBidder;

public class CounterBot extends DollarBidder {
  private Class<? extends DollarBidder> enemy;

  @Override
  public void newAuction(Class<? extends DollarBidder> opponent){
    this.enemy = opponent;
  }

  @Override
  public int nextBid(int opponentsBid) {
    if(this.enemy.equals(CounterBot.class))
      throw new RuntimeException("Here boy, catch!");

    return this.enemy.equals(DarthVader.class) || 
           this.enemy.equals(MirrorBot.class) || 
           this.enemy.equals(OnlyWinningMove.class) ||
           this.enemy.equals(AnalystKiller.class) || 
           this.enemy.equals(DeterredBot.class) ||
           this.enemy.equals(InsiderTradingBot.class) ||
           this.enemy.equals(RiskRewardBot.class) ||
           this.enemy.equals(ImprovedAnalystBot.class) ?
            5
         : this.enemy.equals(MarginalBot.class) ?
           opponentsBid == 0 ? 5 : 10
         : this.enemy.equals(AnalystBot.class) || 
           this.enemy.equals(AnalystOptimizer.class) ?
            opponentsBid == 95 ? 100 : 5
         : this.enemy.equals(TargetValueBot.class) ?
            opponentsBid < 190 ? opponentsBid + 5 : 200
         : this.enemy.equals(BorkBorkBot.class) ?
            opponentsBid < 90 ? opponentsBid + 5 : 95
         : this.enemy.equals(DeterrentBot.class) ?
            105
         : this.enemy.equals(BreakEvenAsap.class) ?
            opponentsBid == 100 ? 105 : 100
         : this.enemy.equals(LuckyDiceBot.class) ?
            opponentsBid == 0 ? 5 : 0
         : this.enemy.equals(RandBot.class) || 
           this.enemy.equals(UpTo200.class) ||
           this.enemy.equals(SecretBot.class) ||
           this.enemy.equals(BluffBot.class) ||
           this.enemy.equals(EvilBot.class) ?
            opponentsBid + 5
         : this.enemy.equals(MimicBot.class) ? // TODO: Find actual counter
            10
         : this.enemy.equals(MarginalerBot.class) ||
           this.enemy.equals(MBot.class) ||
           this.enemy.equals(StackTraceObfuscaterBot.class) ||
           this.enemy.equals(MSlowBot.class) ?
            opponentsBid < 95 ? 90 : opponentsBid == 95 ? 100 : 95;
         : this.enemy.equals(BuzzardBot.class) ?
            100
         : this.enemy.equals(ScoreOverflowBot.class) ?
            opponentsBid == 105 ? 110 : 0
         : //this.enemy.equals(GreedyBot.class) || 
           //this.enemy.equals(RichJerk.class) ||
           //this.enemy.equals(InflationBot.class) ?
           // TODO: More bots?
            0;
  }
}

Compteurs:

  • DarthVaderse rétablit en provoquant un SecurityExceptionavant que l’enchère ne commence, mais je vais enchérir au cas où.
  • AnalystBotet AnalystOptimizerles deux regarderont ma réponse quand j'aurai misé 95, auquel cas je montrerai que j'ai misé 100 pour qu'il mette 95 lui-même. Je vais en faire 5 cependant si je commence (ou 100 s'ils ont commencé), donc ils perdent 95 cents et je gagne soit le billet d'un dollar en n'enchérissant que 5 cents, ou en atteignant le seuil de rentabilité.
  • MirrorBotva dire ce que je voudrais dire contre. Donc, je vais juste enchérir 5, et celui qui commence gagne 95 cents, et l’autre perd 5 cents.
  • MarginalBot Enchérirai 5 si j'enchéris moins de 10 (ou ce qu'il commence), sinon il enchérira 0. Donc si je mets juste 5 quand je commence, ou 10 quand il commence, je gagne soit 95 ou 90 cents, et ils perdent 5 centimes
  • GreedyBot toujours plus 5 fois que moi, alors offrez simplement 0 à l'équilibre et laissez-les remporter
  • OnlyWinningMoveet AnalystKillertous les deux toujours 0, alors enchérissez 5 pour gagner
  • TargetValueBotles enchères dans la fourchette [100,200], alors 5 au moins chaque fois jusqu'à 190, auquel cas nous relançons à 200 pour atteindre le seuil de rentabilité en gagnant le dollar (et les laissons perdre 190 ou 195 selon le joueur qui a commencé)
  • BorkBorkBotva enchérir dans la fourchette [5,95], donc 5 en plus à chaque fois. Dès qu'ils enchérissent 85 ou 90 (selon celui qui a commencé), enchérissez vous-même à 95. Ils vont perdre 85 ou 90 cents et vous gagnerez la facture de 1 USD pour un bénéfice de 5 cents.
  • DeterrentBot ils miseront 5 s'ils débutent ou 100 si nous commençons, donc il suffit de miser 105 pour qu'ils se remettent avec 100, ce qui leur fait perdre 100 et nous ne perdons que 5 cents en gagnant le billet d'un dollar.
  • BreakEvenAsapva enchérir 100 tout de suite. Donc, s'ils ont commencé avec leur enchère de 100, contre avec 105 pour gagner 95 centimes et les laisser en perdre 100. Si nous commençons par enchérir à 100, nous ferons tous les deux en équilibre.
  • RichJerk va miser 10 001 tout de suite, donc misez 0 pour atteindre le seuil de rentabilité et laissez-les perdre 9 901.
  • DeterredBot ne me connaît pas et va donc enchérir sur 0, donc enchérir sur 5 pour gagner.
  • LuckyDiceBotcontinue à enchérir jusqu'à ce qu'il gagne. Donc, si nous avons commencé, enchérissons 5 dans l'espoir qu'ils gagnent le plus possible. S'ils ont commencé, enchérissez simplement sur 0 pour leur permettre de remporter la victoire et de vous équilibrer vous-même.
  • RandBotenchérirons au hasard dans la fourchette [5,100], alors enchérissez 5 fois de plus jusqu'à la fin, auquel cas vous avez gagné 95 cents et ils ont perdu 0-100.
  • UpTo200va (comme son nom l'indique) enchérir jusqu'à 200. Alors, enchérissez de 5 jusqu'à ce qu'ils s'arrêtent. Nous allons gagner la facture de 1 USD et prendre une perte totale de 105 cents, mais ils perdent 200 cents.
  • InsiderTradingBot ne me connaît pas, alors enchérissez 5 cents pour gagner
  • MimicBotétait le plus difficile. Il suffit de miser 10 pour commencer ou contrer leur première enchère de 5. Si ils essaient de me contacter, je lève une exception RuntimeException (qu’ils attraperont dans ce cas, ce serait comme si j’avais misé 100 à la place - mais cela romprait la boucle intérieure en boucle). En fonction des ennemis présents dans HashSet, il se produit une chose différente. Je devrai revenir et regarder de plus près pour voir s'il y a un compteur réel.
  • RiskRewardBot ne me connait pas alors je vais juste enchérir 5, auquel cas je vais enchérir 5 pour gagner.
  • MarginalerBotmordra jusqu'à 100 en fonction de ce que je ferais une offre. Si je peux commencer, je vais enchérir à 90 €, puis à 95 €, puis à 100 €, pour qu'il mette 0 et qu'il perde 95 cents, pendant que je gagne le billet de 1 USD et que nous équilibrons. Si elle peut commencer à la place, elle verra que je miserais 90 contre elle, donc elle mordra à 90, alors je miserai sur 95 pour miser sur 0 et perdre 90 cents, tandis que je gagnerai la facture de 1 USD avec un profit de 5 cents.
  • BuzzardBotanalysera tous mes compteurs de la gamme [0,100). Si j'enchéris 100tout de suite, il utilisera oppFlag = 0et le tableau complet de taille 100 contiendra 100x la valeur 100. Dans le commutateur case 0, la boucle sera à [0,100)nouveau dans la plage , et puisque i + 5au maximum sera 104, le if bids[i] < i + 5ne sera jamais vrai , donc l'offre reste 0.
  • ImprovedAnalystBotaura toujours this.enemy = nullparce que son adversaire est CounterBot, pas lui-même. Donc, il enchérira toujours 0, ce que je viens de contrer avec une enchère de 5.
  • InflationBot va miser sur 0 pour atteindre le seuil de rentabilité au début, sinon il continuera à enchérir sur 5. Donc, il suffit de miser sur 0 pour atteindre le seuil de rentabilité immédiatement et les laisser remporter la victoire.
  • ScoreOverflowBotsoit les enchères proches Integer.MAX_VALUEs’ils peuvent commencer, sinon ils vont enchérir 105. Donc, s'ils ont enchéri sur 105, il leur suffit d'en mettre 110 à leur tour (ils en perdront 105, nous en perdrons 10), sinon, enchérissez simplement 0 pour leur permettre de remporter la victoire.
  • MBotest identique à MarginalerBot, mais avec une protection supplémentaire contre les adversaires "furtifs". Puisque je ne «jette pas un œil», c'est fondamentalement la même chose que MarginalerBot.
  • SecretBotsa isPeeking()méthode retournera false, donc si elle peut commencer ou si j'en ai offert 5, elle enchérira 5 ou 10 respectivement. Sinon, il enchérira 0. Ainsi, que je commence ou non, opponentsBid + 5je gagnerai de toute façon, avec mes enchères de 10 cents ou de 15 cents, ce qui leur fera perdre soit 5 ou 10 cents.
  • BluffBotexaminera ce que je voudrais enchérir lorsque son offre est de 95, et si cela est supérieur ou égal à 100, il enchérira 0 pour atteindre le seuil de rentabilité, sinon, il enchérira opponentsBid + 5. Donc, je vais juste enchérir opponentsBid + 5. Quel que soit le départ, ça va casser, et je gagne soit 100 ou 95 cents, que je sois parti ou non.
  • StackTraceObfuscaterBotagira de la même manière que MarginalerBot.
  • EvilBottoujours enchérir 5, alors enchérissez opponentsBid + 5. Dans les deux cas, ils perdront ces 5 cents et nous remporterons l’offre d’un dollar (soit avec une offre de 5 cents si nous partons, soit une offre de 10 cents s’ils ont commencé).
  • MSlowBotest le même que MBotet donc aussi MarginalerBot.

Faites-moi savoir si vous voyez des fautes de frappe ou des défauts dans mes compteurs.


1
MirrorBotappelle newAuction avec votre propre classe, donc c'est un problème. En outre, je suis heureux de savoir que les 3 heures passées sur MimicBot n’ont pas été vaines.
Nissa

@StephenLeppik Supprimé le code dans le newAuctioncar il échouerait le plus souvent .. Je ne peux pas contrer MirrorBotni me contrer. Celui qui commence des deux gagne 95 cents et l'autre perd 5 cents.
Kevin Cruijssen

3
Saint chaînage ternaire, Batman!
Skyler

1
Aussi, quand vous jouez BorkBorkBot, ne devriez-vous pas relancer à 95 quand ils atteignent 85? Sinon, vous enchérissez tous les deux à 95 s'ils commencent.
Skyler

1
@ Freiheit je sais. Je viens d'utiliser un cas supplémentaire pour renvoyer 0 au cas où je voulais changer la valeur par défaut pour une raison quelconque. Mais je les ai mis sous le défaut maintenant (en les commentant). Et je sais que je peux tout jouer au golf, mais il ne s’agit pas de faire le code le plus court. Je viens de faire un ternaire pour le rendre un peu plus compact, mais c'est à peu près tout. Je vais juste le laisser comme ça pour le moment.
Kevin Cruijssen

3

RiskRewardBot

import net.ramenchef.dollarauction.DollarBidder;

public class RiskRewardBot extends DollarBidder {
    private int target;

    @Override
    public void newAuction(Class<? extends DollarBidder> opponent) {
        if (opponent.equals(OnlyWinningMove.class) ||
            opponent.equals(DeterredBot.class) ||
            opponent.equals(MirrorBot.class) ||
            opponent.equals(AnalystKiller.class) ||
            opponent.equals(RiskRewardBot.class)) {
            target = 5;
        } else if (opponent.equals(MarginalBot.class) ||
            opponent.equals(EvilBot.class)) {
            target = 10;
        } else if (opponent.equals(SecretBot.class)) {
            target = 15;
        } else if (opponent.equals(BorkBorkBot.class)) {
            target = 95;
        } else if (opponent.equals(MarginalerBot.class) ||
             opponent.equals(BluffBot.class) ||
             opponent.equals(BuzzardBot.class)) {
            target = 100;
        }
        } else {
            target = 0;
        }
    }

    @Override
    public int nextBid(int opponentsBid) {
        if (opponentsBid >= target) {
            return 0;
        } else if (target > 10 && opponentsBid == target - 10) {
            return target;
        } else {
            return opponentsBid + 5;
        }
    }
}

Je ne peux pas tester cela pour le moment, alors laissez-moi savoir s'il est cassé.

L'objectif est d'obtenir le score total le plus élevé, alors ne vous inquiétez pas de battre quelqu'un. Prenez simplement les victoires faciles et ne gaspillez pas votre argent en pertes possibles.


3

BluffBot

import net.ramenchef.dollarauction.DollarBidder;

public class BluffBot extends DollarBidder {

private DollarBidder enemy;

@Override
public void newAuction(Class<? extends DollarBidder> opponent){
  try {
    this.enemy = opponent.newInstance();
    enemy.newAuction(this.getClass());
} catch (Throwable e) {
    enemy = null;
}
}

@Override
public int nextBid(int opponentsBid) {
    //Is this a legit call?
    for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
        Class<?> clazz;
        try {
            clazz = Class.forName(ste.getClassName());
            if (DollarBidder.class.isAssignableFrom(clazz) && !clazz.isAssignableFrom(this.getClass())) {
                return 100000;
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    //Play it safe against strangers
    int enemyMaxBid;
    try{
        enemyMaxBid = enemy.nextBid(95);
    }
    catch (Throwable t){
        enemyMaxBid = 0;
        enemy = null;
    }
    if(enemy == null) return opponentsBid <= 5 ? opponentsBid + 5 : 0; //Hazard a 5c guess because of how many bots fold instantly.

    //If there's profit to be had, get there as cheaply as possible. Otherwise, best outcome is zero.
    return enemyMaxBid >= 100 ? 0 : opponentsBid + 5;
}


}

Un espion que vous connaissez est plus précieux que pas d'espion du tout ...

Si quelqu'un d'autre essaie d'appeler la méthode getBid, BluffBot lui répond avec 100 dollars pour l'inciter à cesser de fumer ou à miser très haut.

Sinon, voyez s'il est possible de gagner pour moins de 1 $ et n'enchérissez pas si ce n'est pas le cas.


2

UpTo200

import net.ramenchef.dollarauction.DollarBidder;

public class UpTo200 extends DollarBidder{
  @Override
  public int nextBid(int opponentsBid){
    // If the current bid of the opponent is in the range [0,195]: raise the bid by 5
    return opponentsBid <= 195 ? opponentsBid + 5
    // Else: Give up
     : 0;
  }
}

2

SecretBot

import java.util.Arrays;

import net.ramenchef.dollarauction.DollarBidder;

public class SecretBot extends DollarBidder {

    @Override
    public int nextBid(int opponentsBid) {
        if (isPeeking()) {
            return opponentsBid;
        } else if (opponentsBid < 10) {
            return opponentsBid + 5;
        } else {
            return 0;
        }

    }

    private static boolean isPeeking() {
        final StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        for (StackTraceElement ste : Arrays.copyOfRange(stackTrace, 3, stackTrace.length)) {
            Class<?> clazz;
            try {
                clazz = Class.forName(ste.getClassName());
            } catch (ClassNotFoundException e) {
                return true;
            }
            if (DollarBidder.class.isAssignableFrom(clazz))
                return true;
        }
        return false;
    }

}

Ce bot fait des tentatives minimes pour gagner en miser sur 5 ou 10. Il vérifie également la trace de la pile pour voir s’il a été appelé par un autre bot et leur ment ensuite sur les enchères qu’il va faire.


L' esprit si le port I isPeekingen AbstractAnalystCounterBot?
Nissa

1
@StephenLeppik, eh bien, je l'ai volé à MBot ...
Winston Ewert

1
Eh bien, MBot m'a probablement volé ça…
Nissa

2

Un extra

import net.ramenchef.dollarauction.DollarBidder;

public class OneExtra extends DollarBidder {
    @Override
    public int nextBid(int opponentsBid) {
        if(opponentsBid < 110)
          return opponentsBid + 6;
        return opponentsBid;
    }
}

Enchère 6 fois plus que la dernière enchère, simplement parce qu'il le peut.


Il ne peut pas enchérir sur 6 car toutes les enchères doivent être des multiples de 5 ...
Neil

@Neil c'est probablement une faute de frappe ...
Stan Strum

@Neil les règles stipulent spécifiquement: "Votre enchère n'a pas besoin d'être un multiple de 5 ¢"
MegaTom

@ MegaTom Huh, eh bien, cela a été ajouté depuis la dernière lecture du règlement ...
Neil

@ Neil Il faisait partie des règles d'origine, mais je l'ai ajouté parce que ce n'était pas très évident.
RamenChef

2

StackTraceObfuscaterBot

import net.ramenchef.dollarauction.DollarBidder;

import java.util.concurrent.FutureTask;
import java.util.concurrent.RunnableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;

public class StackTraceObfuscaterBot extends DollarBidder {
    private volatile static boolean created = false;
    private volatile DollarBidder pet;
    private boolean firstBid = false;

    public StackTraceObfuscaterBot() {
        if (created)
            throw new IllegalStateException("THERE CAN ONLY BE ONE!");
        created = true;
    }

    @Override
    public void newAuction(Class<? extends DollarBidder> opponent) {
        firstBid = true;
        RunnableFuture<DollarBidder> task = new FutureTask<>(() -> {
            try {
                return opponent.newInstance();
            } catch (Throwable t) {
                return null;
            }
        });
        Thread thread = new Thread(task);
        thread.start();
        try {
            pet = task.get(450, TimeUnit.MILLISECONDS);
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            task.cancel(true);
            pet = null;
        }
    }

    @Override
    public int nextBid(int opponentsBid) {
        if (!firstBid)
            return 0;
        firstBid = false;

        for (int bid = opponentsBid + 5; i < 100; i += 5) {
            final int bidt = bid;
            RunnableFuture<Boolean> task = new FutureTask<>(() -> {
                pet.newAuction(this.getClass());
                return pet.nextBid(bidt) < bidt + 5;
            });
            Thread thread = new Thread(task);
            thread.start();
            try {
                if (task.get(23, TimeUnit.MILLISECONDS))
                    return bid;
            } catch (InterruptedException | ExecutionException | TimeoutException e) {
                task.cancel(true);
                return 0;
            }
        }
        return 0;
    }
}

Ce robot se moque des tentatives de détection de la réflexion via la trace de pile. La chose la plus proche qu’ils voient DollarBidderest une classe lambda qu’elle a créée. Clairement pas un autre bot essayant de les refléter. Peu savent-ils que cette classe lambda travaille réellement pour un DollarBidder. Au-delà, il agit comme MarginalerBot.


Notez que j'ai depuis mis à jour ma vérification de trace de pile pour gérer cela.
Nissa

1

Dark Vador

import java.lang.reflect.Field;
import net.ramenchef.dollarauction.DollarBidder;

public class DarthVader extends DollarBidder
{
@Override
public void newAuction(Class<? extends DollarBidder> opponent) {
    //set all values in the integer cache to over the $100 limit except 0
    Class icache = Integer.class.getDeclaredClasses()[0];
    Field c = icache.getDeclaredField("cache");
    c.setAccessible(true);
    Integer[] cache = (Integer[]) c.get(cache);
    for(sbyte b=0;b<128;b++)
    {
     cache[b]=100001;
    }
}

@Override
public int nextBid(int opponentsBid) 
{
    return 0;
}
}

Celui-ci essaie de forcer le bot de l'adversaire à surpayer en définissant le cache d'entiers sur une valeur supérieure à la limite de 100 $.


2
Le responsable de la sécurité arrêterait cela.
Nissa

2
Et cela ne fonctionnerait pas de toute façon puisque nulle part dans le coureur, il ne coche ses entiers.
Nissa

Même si cela ne serait pas arrêté, il s'agit d'un mouvement de jerk, bien que valide. "Le sabotage d'autres robots est autorisé, mais tenter de modifier la visibilité du champ / de la méthode donnera lieu à de mystérieuses SecurityExceptions."
NoOneIsHere

1
@StephenLeppik Le but de ceci est de casser des choses comme return opponentsBid <= 195 ? opponentsBid + 5 : 0et de les faire return opponentsBid <= 100001 ? opponentsBid + 100001 : 100001.
NoOneIsHere

1
Ne réussit pas à compiler à cause d'exceptions non vérifiées.
Nissa

1

ImprovedAnalystBot (non-concurrent)

Beaucoup de gens semblent utiliser le AnalystBotcode comme modèle, même s'il est délibérément mauvais. Donc, je fais un meilleur modèle.

import net.ramenchef.dollarauction.DollarBidder;

public class ImprovedAnalystBot extends DollarBidder {
    private DollarBidder enemy;

    @Override
    public void newAuction(Class<? extends DollarBidder> opponent) {
        if (!opponent.equals(this.getClass()))
            try {
                this.enemy = opponent.newInstance();
                enemy.newAuction(this.getClass());
            } catch (Throwable t) {
                this.enemy = null;
            }
        else
            this.enemy = null;
    }

    @Override
    public int nextBid(int opponentsBid) {
        try {
            return enemy != null && enemy.nextBid(95) < 100 ? 95 : 0;
        } catch (Throwable t) {
            return 0;
        }
    }
}

Pourquoi ne pas simplement modifier votre défi?
Nathan Merrill

@NathanMerrill Comment pourrais-je le modifier?
RamenChef

En cliquant sur le bouton Modifier et en remplaçant AnalystBot par ce code?
Nathan Merrill

@NathanMerrill AnalystBotest délibérément un mauvais code pour pouvoir démontrer son AnalystKillersabotage.
RamenChef

1
AnalystKiller fonctionne toujours avec la version améliorée :) Le problème avec la publication d’une publication est que le défi est beaucoup plus visible que la réponse.
Nathan Merrill

1

MBot

import net.ramenchef.dollarauction.DollarBidder;

import java.util.Arrays;

public class MBot extends DollarBidder {
    protected DollarBidder rival = null;
    protected boolean rivalPrepared = false;
    protected Class<? extends DollarBidder> rivalClass;


    @Override
    public void newAuction(Class<? extends DollarBidder> opponent) {
        this.rivalClass = opponent;
        this.rivalPrepared = false;
    }

    protected DollarBidder getRival() {
        if (!rivalPrepared) {
            rivalPrepared = true;
            try {
                rival = rivalClass.newInstance();
                rival.newAuction(this.getClass());
            } catch (Throwable t) {
                rival = null;
            }
        }
        return rival;
    }

    @Override
    public int nextBid(int opponentsBid) {
        return calcBid(opponentsBid, isPeeking(3), isPeeking(4));
    }

    protected int calcBid(int opponentsBid, boolean isPeeking, boolean isSubPeeking) {
        if (isPeeking) {
            throw new RuntimeException();
        }

        for (int iBid = opponentsBid + 5; iBid <= 100; iBid = iBid + 5) {
            try {
                if (getRival().nextBid(iBid) < iBid + 5) {
                    return iBid;
                }
            } catch (Throwable t) {
                // noop
            }
        }
        return 0;
    }

    protected boolean isPeeking(int level) {
        final StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        final StackTraceElement[] stackTraceElements = Arrays.copyOfRange(stackTrace, level, stackTrace.length);
        for (StackTraceElement ste : stackTraceElements) {
            try {
                Class<?> clazz = Class.forName(ste.getClassName());
                if (DollarBidder.class.isAssignableFrom(clazz))
                    return true;
            } catch (ClassNotFoundException e) {
                return true;
            }
        }
        return false;
    }
}

MarginalerBot légèrement raffiné

  • être méchant à ceux qui ne veulent pas vous vérifier
  • permettre de payer 100 pour obtenir 100 et le seuil de rentabilité, juste pour refuser aux autres de l'argent facile

Vous ne pouvez pas déclarer nextBidlancer ClassCastException.
RamenChef

@RamenChef ok, l'a remplacé par RuntimeException qui ne nécessite pas de déclaration :)
mleko

Votre code pour la vérification de trace de pile a l'air étrangement similaire au mien.
Nissa

@StephenLeppik probablement sa copie
mleko

@ mleko pourquoi? La classe à partir de laquelle elle est copiée est une super-classe abstraite, gratuite.
Nissa

1

Non concurrent: MSlowBot

import net.ramenchef.dollarauction.DollarBidder;

import java.util.Arrays;

public class MSlowBot extends DollarBidder {
    private DollarBidder rival;

    @Override
    public void newAuction(Class<? extends DollarBidder> opponent) {
        try {
            rival = opponent.newInstance();
            rival.newAuction(this.getClass());
        } catch (Throwable t) {
            rival = null;
        }
    }

    @Override
    public int nextBid(int opponentsBid) {
        noPeeking();

        for (int iBid = opponentsBid + 5; iBid <= 100; iBid = iBid + 5) {
            try {
                if (rival.nextBid(iBid) < iBid + 5) {
                    return iBid;
                }
            } catch (Throwable t) {
                //do nothing.
            }
        }
        return 0;
    }

    private void noPeeking() {
        final StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        for (StackTraceElement ste : Arrays.copyOfRange(stackTrace, 3, stackTrace.length)) {
            try {
                Class<?> clazz = Class.forName(ste.getClassName());
                if (DollarBidder.class.isAssignableFrom(clazz))
                    Thread.sleep(1000);
            } catch (ClassNotFoundException | InterruptedException e) {
                throw new RuntimeException(":(");
            }
        }
    }
}

Même logique que MBot, utilisez simplement timeout au lieu de Exception lorsque vous combattez un ennemi. Jusqu'à présent, personne ne défend le délai d'expiration, alors il devrait être efficace


Les règles énoncées interdisent délibérément de faire expirer un autre bot.
Winston Ewert

@ WinstonEwert pouvez-vous citer? Je ne trouve pas la règle interdisant cela
mleko

"Le sabotage d'autres robots est autorisé, mais toute tentative de modification de la visibilité du champ / de la méthode entraînera de mystérieuses SecurityExceptions. Une exception fait qu'un autre bot dépasse la limite de 500 ms." En outre, je me défend contre le timeout.
RamenChef

@RamenChef mais cela n'altère pas la visibilité des autres éléments. Je ne suis pas sûr de bien vous comprendre. Provoquer le timeout est-il autorisé?
mleko

"Une exception provoque un autre bot pour dépasser la limite de 500 ms." Plus précisément, il s’agit d’une exception à la règle du sabotage.
RamenChef
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.