Dollarschein Auktion

33

Dies ist eine KOTH-Herausforderung für das Auktionsspiel für Dollarnoten in der Spieltheorie. Darin wird ein Dollar an den Meistbietenden verkauft. Die Gebote steigen in Schritten von 5 ¢, und der Verlierer zahlt auch sein Gebot. Die Idee ist, dass beide Spieler den Bieterkrieg weit über den Wert eines Dollars hinaus eskalieren, um ihre Verluste zu reduzieren.

Hoffen wir, dass Ihre Bots schlauer sind.

Sie werden einen Bot erstellen, um dieses Spiel zu spielen, indem Sie die net.ramenchef.dollarauction.DollarBidderKlasse erweitern. Sie müssen die nextBidMethode implementieren, die das nächste Gebot Ihres Bots zurückgibt, wenn das vorherige Gebot des anderen Bots vorliegt. Bei Bedarf können Sie die newAuctionMethode auch verwenden , um für jede Auktion die Klasse des gegnerischen Bots zurückzusetzen.

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

Das Bieten dauert so lange, bis eine der folgenden Bedingungen erfüllt ist:

  • nextBidwirft eine Ausnahme. In diesem Fall zahlt der Bot, der die Ausnahme ausgelöst hat, sein vorheriges Gebot und der andere Bot erhält den Dollar kostenlos.
  • Beide Bot zahlen nicht genug, um das vorherige Gebot zu übertreffen. In diesem Fall zahlen beide Bots ihre Gebote (der Verlierer zahlt das vorherige Gebot), und der Gewinner erhält einen Dollar.
  • Beide Bots bieten über 100 $. In diesem Fall zahlen beide Bots 100 USD und keiner der Bots erhält den Dollar.

Für jede Bots-Kombination finden 2 Auktionen statt. Bots werden anhand des Gesamtgewinns bewertet, den sie in diesen Auktionen erzielt haben. Die höchste Punktzahl gewinnt.

Beispiele

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

Verwenden Sie dies nicht als Vorlage für analytisch denkende Bots. Verwenden Sie ImprovedAnalystBotstattdessen.

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

Zusätzliche Regeln

  • Standardlücken sind verboten.
  • Das Sabotieren anderer Bots ist zulässig, aber der Versuch, die Sichtbarkeit von Feldern / Methoden zu ändern, führt zu mysteriösen SecurityExceptions. Eine Ausnahme führt dazu, dass ein anderer Bot die Grenze von 500 ms überschreitet.
  • Bots können nur zur Erweiterung der DollarBidderKlasse auf das Runner-Paket zugreifen .
  • Alle Methoden sollten in 500 ms oder weniger zurückkehren.
  • Bots müssen nicht deterministisch sein.
  • Ihr Gebot muss kein Vielfaches von 5 ¢ sein.
  • 1 $ = 100 ¢
  • Die Ergebnisse werden am 24. April 2018 veröffentlicht.

Runner auf GitHub

Ergebnisse

Sehen Sie sich hier die einzelnen Runden an.

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

Herzlichen Glückwunsch zu MTargetedBoteinem Gewinn von 14,30 $!

RamenChef
quelle
11
Diese Herausforderung ist für One-Upping grundsätzlich anfällig. Da ich die Klasse meines Gegners kenne, ist es einfach, die beste Strategie dagegen zu wählen. (Dann kommt jemand vorbei und kann meinen Bot einsetzten , usw.)
Nathan Merrill
2
"Die Gebote werden in Schritten von 5 ¢ erhöht. " Sie haben jedoch nichts in Ihrem Code, um dies zu LuckyDiceBot2-12
überprüfen
4
Außerdem: Was passiert, wenn mein Bot andere Bots veranlasst, die 500-ms-Beschränkung zu überschreiten?
Nathan Merrill
4
@RamenChef Hier geht es um bösartigen Code. Was passiert, wenn ich feststelle, dass ein anderer Bot mich anruft, und Thread.sleep (1000) aufrufe?
Nathan Merrill
3
Ich bin VTC, da unklar ist, welche Sabotage erlaubt ist und welche nicht. Das OP hat Einsendungen, die "den Läufer angreifen" (was vage ist), verboten, und es gibt keine klare Grenze zwischen zulässigem und nicht zulässigem Schadcode ?)
Nathan Merrill

Antworten:

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);
    }
}
  • Basierend auf aktualisiertem MBot
  • Verwendet eine ähnliche Methode wie CounterBot, aber mit einigen Methoden, die verbessert wurden, um einige Gegner stärker zu treffen, sollte sie auch besser lesbar sein
  • Bei unbekanntem Gegner wird standardmäßig MBot strat
mleko
quelle
1
Das ist nicht fair.
Joshua
@Joshua Was ist Ihrer Meinung nach besonders an dieser Lösung nicht fair?
Mleko
Kenne die Namen deiner Gegner.
Joshua
@ Joshua die Hälfte der Lösungen verwenden diese Informationen. Wir haben dem Autor sogar geschrieben, dass dies geändert werden sollte, oder One-Upping wird auftreten. Er weigerte sich, die Herausforderung zu ändern - also hier ist es
mleko
1
Bereits getan ....
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;
        }
    }
}

Heilige Kuh. Ich erwartete, dass dies einfach zu schreiben sein würde, und verbrachte anschließend 3 Stunden damit.

Im Wesentlichen wird MimicBoteine Liste der verfügbaren Bots geführt. Wenn es zu einer neuen Auktion geht, durchläuft es die Liste auf der Suche nach dem effektivsten gegen den aktuellen Gegner. Dieser Bot wird dann als "Referenz" in der Auktion verwendet.

Zu Testzwecken ist es am besten, entweder eine zufällige Teilmenge der Beiträge oder die vollständige Menge zu verwenden. Es beginnt mit GreedyBot, MimicBotund einem weiteren Bot, der nur 5 ¢ bietet.

Nissa
quelle
11

InsiderTradingBot

Im Geiste der Antwort von @ StephenLeppik kennt InsiderTradingBot alle seine Gegner und versteht deren Strategien. Dein Umzug, 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;
  }

};
Silvio Mayolo
quelle
1
Nee, Insiderhandel wäre, wenn der RichJerkBot eine bestimmte Ausnahme für Ihren Bot machen und $ 0 dafür bieten würde.
Nissa
Es ist zu früh, um gegen andere Antworten zu optimieren. Auch ist es AnalystBotnicht Analyst.
RamenChef
8
Wahrscheinlich muss es eine Regel geben "Klassennamen werden zufällig ausgewählt".
user202729
1
@ user202729 Wie wäre es mit "Keine direkten Verweise auf Klassen"?
RamenChef
1
Ich würde gerne sehen, dass dieser den MimicBot handhabt.
Nissa
8

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

Ganz einfach, es wird versucht festzustellen, ob ein Gegner ein Mindestgebot anfechten würde, und wenn nicht, platziert er es.

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

Eine neue, intelligentere Version von MarginalBot, mit der überprüft wird, ob mit MarginalBot auch ohne Wettbewerb Gewinne erzielt werden können, anstatt nur mit dem Minimum zu gewinnen.

Da es in der gleichen Familie wie mein vorheriger Bot ist, aber Ausweichstrategien versucht, es zu schlagen, dachte ich, dass ein neuer Eintrag in demselben Post die vernünftigste Art ist, es zu präsentieren.

Bearbeiten 1: Die neueAuktionsmethode wurde geringfügig geändert, um sie gegen andere Bots vom Typ Analysator zu optimieren.

Bearbeiten 2: MarginalerBot wurde geändert, um Verluste gegenüber hinterhältigen oder nicht deterministischen Strategien zu minimieren.

Qaghan
quelle
Willkommen bei PPCG!
Martin Ender
1
Es ist einfach, aber es schlägt alle anderen Bots um einiges!
RamenChef
8

MirrorBot

Lässt den Feind gegen sich selbst spielen.

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);
        }
    }
}
dkudriavtsev
quelle
6
Du hast Analystspektakulär geknackt .
Silvio Mayolo
@SilvioMayolo Wie?
Dkudriavtsev
Mirror versucht, das Spielen von Analysten gegen sich selbst zu emulieren, was zu einem Stapelüberlauf führt.
Silvio Mayolo
8

Bearbeiten : Durch gezielte Änderungen in der DollarBidder-Klasse wurde dieser Bot zerstört.

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

Nach einer Auktion beträgt die Punktzahl -2147483645, aber das nächste Mal verliert sie 5 oder 105, was die Punktzahl positiv und sehr groß macht. Alle anderen Verluste wären dann vernachlässigbar.

Bei der ersten Auktion würde GreedyBot auch -2147483646 wetten, was nicht durch 5 teilbar ist.

Winter
quelle
scoreist paketgeschützt. Ihre Bots können nicht darauf zugreifen.
RamenChef
@RamenChef Hoppla, der CheatingBot wurde entfernt
Winter
Es gibt keine Regel gegen "den Läufer angreifen", nur "darauf zugreifen", was dies nicht tut. Ich empfehle, den Fehler zu beheben, der das Problem löst :)
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;
        }
    }
}

Kann dies im Moment nicht testen, also lass es mich wissen, wenn es kaputt ist.

Wählen Sie im Grunde genommen einen Wert für den Dollar und überbieten Sie den Gegner, bis wir diesen Wert überschreiten.

Gedächtnisstütze
quelle
6

BorkBorkBot

import net.ramenchef.dollarauction.DollarBidder;

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

Gibt auf, wenn es nicht ausgeglichen werden kann.

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

Es musste getan werden.

Neil
quelle
"Die Gebote werden in Schritten von 5 ¢ erhöht. " Ihr Bot tut dies derzeit nicht.
Kevin Cruijssen
1
@ KevinCruijssen Fair genug. Ich habe auch die Obergrenze geändert, damit der gesamte Betrag von 1 USD geboten werden kann, nur für den Fall
Neil,
6

DeterrentBot

import net.ramenchef.dollarauction.DollarBidder;

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

Versuche, analytisch denkende Bots davon zu überzeugen, dass der einzige Gewinn nicht darin besteht, zu spielen.

Histokrat
quelle
1
Mir ist aufgefallen, dass mein etwas kryptischer Kommentar "Joshua? Bist du das?" wurde gelöscht. Zur Verdeutlichung wurde auf ein berühmtes Zitat aus dem Film WarGames verwiesen: "Der einzige Siegeszug ist, nicht zu spielen" . (Joshua ist der Spitzname des WOPR .)
Arnauld
5

LuckyDiceBot

LuckyDiceBot vertraut nur seinen Würfeln. Er würfelt mit zwei Würfeln, addiert die Summe zum Wert des aktuellen Bieters und bietet so viel. Wenn es nicht ausreicht, um das Gebot des Gegners zu überwinden, verringert er seine Verluste und macht sich auf den Weg.

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

};
Silvio Mayolo
quelle
2
Wie reduziert dies seine Verluste oder stoppt Verluste? Wenn es immer seinen Würfelwurf zum Gebot des Gegners hinzufügt, dann bieten Sie immer mehr. Die Zufälligkeit könnte einen ausreichend analytischen Bot verwirren, ich mag das Konzept.
Freiheit
Wenn der Wurf 4 oder weniger ist (statistisch gesehen unwahrscheinlich, wird aber irgendwann passieren), reicht das Gebot nicht aus, um den Gegner zu besiegen, und die Auktion endet.
Silvio Mayolo
Zwei Dinge: 1. @Freiheit ist richtig und dieser Bot bietet so lange, bis er gewonnen hat, egal wie hoch. opponentsBidin nextBid(int opponentsBid)hält das Gesamtgebot, das Ihr Gegner bisher geboten hat, nicht das nächste Gebot. Ein besserer Begriff für die Methode wäre raise(wie der Begriff Poker) imho. 2. Ihr Bot bitet nicht in Schritten von 5 und überprüft daher eine der Regeln. Wenn diese Probleme behoben sind, gefällt mir das Konzept immer noch, da analytische Bots nicht in der Lage sind zu kontern und Sie höchstwahrscheinlich ziemlich oft gewinnen werden.
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 macht ein Vermögen aus seinem illegalen Glücksspiel mit LuckyDiceBot. Wenn die Polizei (DeterrentBot) kommt, muss er natürlich schnell über seine Einnahmen verfügen, zum Beispiel, um für die nächste Auktion zu bieten.

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

Kann dies im Moment nicht testen, also lass es mich wissen, wenn es kaputt ist.

Mit jeder Runde steigt der Wert des Dollars.

Gedächtnisstütze
quelle
Dies wäre hervorragend gegen MirrorBot, MarginalerBot und wahrscheinlich auch MimicBot.
Nissa
@StephenLeppik Das habe ich mir gedacht, als ich es gemacht habe. Trotzdem viele Schwächen.
Mnemonic
+1, ich mag die Idee. Hmm, ist es beabsichtigt, dass Ihr Bot 0 bietet und bricht, auch wenn er eine Runde startet (wann opponentsBidist noch 0)?
Kevin Cruijssen
@ KevinCruijssen Ja. Das kann nur gegen den allerersten Gegner passieren. Jeder der Bots, der ihn kopiert, beginnt bei 0, sodass nicht mehr als 5c für sie verschwendet werden.
Gedächtnisstütze
4

Nicht konkurrierend: 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;
        }
    }
}

Dies ist nicht als wahrer Beitrag gedacht, sondern als ein Hinweis, den andere verwenden sollten, um Bots, die Haustiere halten, von MirrorBotund abzuhalten MimicBot.

Da dies der Standardkonstruktor ist, müssen Sie ihn in Ihrer Unterklasse nicht aufrufen. Es implementiert eine isPeekingMethode, um festzustellen, ob ein anderer Bot schnüffelt.

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

Szenarien

  • Wenn der Gegner startet und bietet <= 0, verliert er.
  • Wenn der Gegner starten und [5,95]bieten darf : Bieten Sie selbst 100. Entweder stoppt Ihr Gegner jetzt oder Sie bieten mehr als 100. In diesem Fall hören Sie auf zu bieten, damit er den Sieg erringen und sich selbst ausgleichen kann.
  • Wenn der Gegner starten und >= 100bieten darf : Bieten Sie selbst 0, um zu verlieren, aber die Gewinnschwelle zu erreichen.
  • Wenn Sie anfangen dürfen: bieten Sie sofort 100. Entweder stoppt Ihr Gegner jetzt oder Sie bieten über 100. In diesem Fall hören Sie auf zu bieten, damit er den Sieg erringen und sich selbst ausgleichen kann.
Kevin Cruijssen
quelle
Wow das ist ein Bug. Es hieß, ich hätte die Frage kommentiert, aber sie sei hier gelandet. Ich muss einen Weg finden, es zu reproduzieren
Stan Strum
@ RamenChef Typo .. Aber ich habe den gesamten Bot modifiziert. Es hatte sowieso einige Fehler ..
Kevin Cruijssen
4
Dies kann absolut Geld verlieren. Wenn Sie 100 bieten, dann bietet Ihr Gegner 105, Sie verlieren 100 und sie verlieren nur 5.
Mnemonic
@Mnemonic Ah natürlich .. Hatte nicht über diesen Teil nachgedacht .. Hmm .. das macht die Sache interessanter, aber auch schwieriger. Wird die Beschreibung jetzt bearbeiten, aber den Bot so lassen, wie er ist.
Kevin Cruijssen
1
Ich denke du meinst "verlieren", nicht "verlieren". Verlieren ist das Gegenteil von gewinnen. Loose ist das Gegenteil von 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;
    }

}

Löst einen Fehler anstelle einer Ausnahme aus, um Analysten zu verwirren.

Winston Ewert
quelle
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;
    }
}

Versucht, den Gegner zu bewerten, mit dem er konfrontiert ist, und stellt sicher, dass nicht mehr abgebissen wird, als er kauen kann.

Ripkoops
quelle
1
Willkommen bei 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;
        }
    }
}

aus Teilen anderer Bots zusammengeschustert. Dieser spielt, indem er versucht, AnalystBot zu sein, und wenn er nicht erfolgreich ist, wird er zu BorkBorkBot.

Ich denke nicht, dass dies gut tun wird.

dkudriavtsev
quelle
Achten Sie auf die AnalystKiller.
RamenChef
@RamenChef AFAIK der Analystenkiller wirft nur eine Ausnahme, wenn er sich selbst analysiert sieht. Ich kann das fangen
dkudriavtsev
1
Sie sollten es wahrscheinlich fangen.
RamenChef
@ RamenChef Keine Ahnung, ob das funktionieren wird, ich kann nicht 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;
  }
}

Zähler:

  • DarthVaderwirkt sich aus, indem er SecurityExceptionvor dem Start des Gebots ein auslöst, aber ich biete nur für den Fall 5.
  • AnalystBotund AnalystOptimizerbeide sehen sich meine Antwort an, wenn ich 95 biete. In diesem Fall zeige ich, dass ich 100 biete, sodass 95 selbst geboten wird. Ich biete jedoch 5, wenn ich anfange (oder 100, wenn sie begonnen haben), so dass sie 95 Cent verlieren und ich entweder die 1-USD-Rechnung gewinne, indem ich nur 5 Cent biete oder indem ich die Gewinnschwelle breche.
  • MirrorBotwerde bieten, was ich dagegen bieten würde. Also biete ich nur 5, und wer anfängt, gewinnt 95 Cent, und der andere verliert 5 Cent.
  • MarginalBot Ich biete 5, wenn ich weniger als 10 bieten würde (oder was es beginnt), andernfalls bietet es 0. Wenn ich also nur 5 biete, wenn ich beginne, oder 10, wenn es beginnt, gewinne ich entweder 95 oder 90 Cent, und sie verlieren 5 Cent.
  • GreedyBot Bietet immer 5 mehr als ich. Bieten Sie also einfach 0, um die Gewinnschwelle zu erreichen
  • OnlyWinningMoveund AnalystKillerbeide bieten immer 0, also bieten Sie einfach 5, um zu gewinnen
  • TargetValueBotBieten Sie [100,200]also jedes Mal um 5 mehr, bis sie 190 sind. In diesem Fall erhöhen wir auf 200, um den Gewinn des Dollars auszugleichen (und lassen sie 190 oder 195 verlieren, je nachdem, wer angefangen hat).
  • BorkBorkBotwird im Bereich [5,95]bieten, also bieten Sie auch jedes Mal 5 weitere. Sobald sie entweder 85 oder 90 bieten (je nachdem, wer angefangen hat), bieten Sie 95 selbst. Sie verlieren 85 oder 90 Cent, und Sie gewinnen die 1-USD-Rechnung für einen Gewinn von 5 Cent.
  • DeterrentBot Bietet 5, wenn sie anfangen oder 100, wenn wir anfangen. Bietet also 105, damit sie mit 100 kontern. Dadurch verlieren sie 100 und wir verlieren nur 5 Cent, indem wir die 1-USD-Rechnung gewinnen.
  • BreakEvenAsapbietet sofort 100. Wenn sie also mit ihrem Gebot von 100 begonnen haben, kontern Sie mit 105, um 95 Cent zu gewinnen, und lassen Sie sie 100 verlieren. Wenn wir anfangen, bieten Sie einfach 100, damit wir beide die Gewinnschwelle erreichen.
  • RichJerk bietet sofort 10.001, also bieten Sie einfach 0, um die Gewinnschwelle zu erreichen und 9.901 zu verlieren.
  • DeterredBot kennt mich nicht und bietet daher 0, also bieten Sie einfach 5, um zu gewinnen.
  • LuckyDiceBotBietet so lange, bis es gewinnt. Wenn wir also anfangen, bieten Sie 5 in der Hoffnung, dass sie so hoch wie möglich bieten, um den Dollar zu gewinnen. Wenn sie angefangen haben, bieten Sie einfach 0, damit sie gewinnen und sich selbst amortisieren können.
  • RandBotbieten willkürlich im Bereich [5,100], also bieten Sie einfach 5 weitere, bis es aufhört. In diesem Fall haben Sie 95 Cent gewonnen und sie haben verloren 0-100.
  • UpTo200wird (wie der Name schon sagt) bis zu 200 bieten. Bieten Sie also einfach 5 höher, bis sie aufhören. Wir werden die 1 USD-Rechnung gewinnen und einen Gesamtverlust von 105 Cent hinnehmen, sie verlieren jedoch 200 Cent.
  • InsiderTradingBot kennt mich nicht, also biete einfach 5 Cent, um zu gewinnen
  • MimicBotwar das schwerste. Wenn sie versuchen, auf mich zuzugreifen, werde ich eine RuntimeException auslösen (die sie abfangen. In diesem Fall würde das so tun, als hätte ich stattdessen 100 geboten - obwohl es die RuntimeException kaputt macht innere while-Schleife). Basierend auf den Feinden, die es in seinem HashSet hat, passiert etwas anderes. Ich muss noch einmal nachsehen, ob es einen tatsächlichen Zähler gibt.
  • RiskRewardBot Ich kenne mich nicht und biete nur 5. In diesem Fall biete ich 5, um zu gewinnen.
  • MarginalerBotwird bis zu 100 Bit je nachdem, was ich bieten würde. Wenn ich anfangen darf, werde ich 90 bieten, dann wird 95 bieten, dann werde ich 100 bieten, so dass es 0 bieten und 95 Cent verlieren wird, während ich die 1 USD Rechnung gewinne und ausgeglichen bin. Wenn es stattdessen startet, sehe ich, dass ich 90 gegen es bieten würde, also bietet es 90 selbst, dann biete ich 95, also bietet es 0 und verliere 90 Cent, während ich die 1 USD Rechnung mit einem Gewinn von 5 Cent gewinne.
  • BuzzardBotanalysiert alle meine Zähler im Bereich [0,100). Wenn ich 100sofort biete , verwende ich oppFlag = 0und das komplette Array mit der Größe 100 enthält das 100-fache des Werts 100. In der Vermittlung case 0befindet sich die Schleife wieder im Bereich [0,100), und da i + 5höchstens 104 ist, ist das Wenn bids[i] < i + 5niemals wahr , so bleibt das Gebot 0.
  • ImprovedAnalystBotwird immer haben, this.enemy = nullweil sein Gegner ist CounterBot, nicht sich. Es wird also immer 0 geboten, was ich nur mit einem Gebot von 5 kontere.
  • InflationBot Bietet 0, um die Gewinnschwelle zu erreichen, andernfalls bietet es weiter 5. Bieten Sie also einfach 0, um die Gewinnschwelle zu erreichen und den Gewinn zu erzielen.
  • ScoreOverflowBotwird entweder in der Nähe bieten, Integer.MAX_VALUEwenn sie anfangen können, sonst werden sie bieten 105. Wenn sie also 105 geboten haben, bieten sie uns nur 110 (sie verlieren 105, wir verlieren 10), andernfalls bieten sie einfach 0, damit sie gewinnen.
  • MBotist das Gleiche wie MarginalerBot, aber mit zusätzlichem Schutz gegen "guckende" Gegner. Da ich nicht 'gucke', ist es im Grunde dasselbe wie MarginalerBot.
  • SecretBotwird seine isPeeking()Methode false zurückgeben. Wenn sie gestartet wird oder wenn ich 5 biete, wird 5 bzw. 10 geboten. Andernfalls wird 0 geboten. Egal, ob ich anfange oder nicht, opponentsBid + 5würde mich veranlassen, entweder mit meinen 10-Cent- oder 15-Cent-Geboten zu gewinnen, was dazu führt, dass sie entweder 5 oder 10 Cent verlieren.
  • BluffBotwird sich ansehen, was ich bieten würde, wenn sein Gebot 95 ist, und wenn dies größer oder gleich 100 ist, wird 0 geboten, um die Gewinnschwelle zu erreichen, andernfalls wird geboten opponentsBid + 5. Also werde ich einfach bieten opponentsBid + 5. Es wird ausgeglichen, egal wer anfängt und ich gewinne entweder 100 oder 95 Cent, je nachdem, ob ich angefangen habe oder nicht.
  • StackTraceObfuscaterBotwird genauso handeln wie MarginalerBot.
  • EvilBotwird immer 5 bieten, also einfach bieten opponentsBid + 5. In beiden Fällen verlieren sie diese 5 Cent und wir gewinnen das Gebot von 1 USD (entweder mit einem Gebot von 5 Cent, wenn wir anfangen, oder 10 Cent, wenn sie anfangen).
  • MSlowBotist das gleiche wie MBotund daher auch MarginalerBot.

Lassen Sie mich wissen, wenn Sie Tippfehler oder Fehler in meinen Zählern sehen.

Kevin Cruijssen
quelle
1
MirrorBotRuft newAuction mit Ihrer eigenen Klasse auf, das ist also ein Problem. Ich bin auch froh zu wissen, dass die 3 Stunden, die ich mit MimicBot verbracht habe, nicht umsonst waren.
Nissa
@StephenLeppik Entfernte den Code in der, newAuctionweil es öfter als nicht fehlschlagen würde. Ich kann nicht kontern, MirrorBotnoch kann es mir widersprechen . Wer von beiden anfängt, gewinnt 95 Cent und der andere verliert 5 Cent.
Kevin Cruijssen
3
Heilige ternäre Verkettung, Batman!
Skyler
1
Sollten Sie beim Spielen BorkBorkBotnicht auf 95 erhöhen, wenn sie 85 erreichen? Andernfalls bieten Sie beide 95, wenn sie anfangen.
Skyler
1
@Freiheit ich weiß. Ich habe nur einen zusätzlichen Fall verwendet, um 0 zurückzugeben, falls ich die Standardeinstellung aus irgendeinem Grund ändern wollte. Aber ich habe sie jetzt unter die Standardeinstellung gesetzt (indem ich sie auskommentiere). Und ich weiß, dass ich ziemlich viel Golf spielen kann, aber es geht nicht darum, den kürzesten Code zu machen. Ich habe es nur ternär gemacht, um es ein bisschen kompakter zu machen, aber das war es auch schon. Ich lasse es jetzt einfach so.
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;
        }
    }
}

Kann dies im Moment nicht testen, also lass es mich wissen, wenn es kaputt ist.

Das Ziel ist es, die höchste Gesamtpunktzahl zu erzielen. Machen Sie sich also keine Sorgen, wenn Sie jemanden schlagen. Nehmen Sie einfach die einfachen Gewinne und verschwenden Sie kein Geld mit möglichen Verlusten.

Gedächtnisstütze
quelle
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;
}


}

Ein Spion, den Sie kennen, ist wertvoller als gar kein Spion ...

Wenn jemand anderes versucht, die getBid-Methode aufzurufen, antwortet BluffBot mit 100 US-Dollar, um ihn dazu zu bringen, entweder zu beenden oder richtig hoch zu setzen.

Andernfalls prüfen Sie, ob es möglich ist, für weniger als 1 $ zu gewinnen, und bieten Sie einfach nicht, wenn dies nicht der Fall ist.

Kain
quelle
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;
  }
}
Kevin Cruijssen
quelle
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;
    }

}

Dieser Bot unternimmt minimale Gewinnversuche, indem er 5 oder 10 bietet. Er überprüft auch die Stapelverfolgung, um festzustellen, ob er von einem anderen Bot gerufen wurde, und belügt sie dann darüber, welche Gebote er abgeben wird.

Winston Ewert
quelle
Was dagegen , wenn ich Port isPeekingin AbstractAnalystCounterBot?
Nissa
1
@StephenLeppik, nun, ich habe es MBot gestohlen ...
Winston Ewert
1
Nun, MBot hat es mir wahrscheinlich gestohlen ...
Nissa
2

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

Bietet 6 mehr als das letzte Gebot, nur weil er kann.

MegaTom
quelle
Er kann nicht 6 bieten, da alle Gebote ein Vielfaches von 5 sein müssen ...
Neil
@Neil es ist wahrscheinlich ein Tippfehler ...
Stan Strum
@Neil die Regeln speziell besagen: "Ihr Gebot muss nicht ein Vielfaches von 5 ¢ sein"
MegaTom
@ MegaTom Huh, nun, das wurde hinzugefügt, seit ich das letzte Mal die Regeln gelesen habe ...
Neil
@Neil Es war Teil der ursprünglichen Regeln, aber ich habe es dort hinzugefügt, weil es nicht sehr offensichtlich war.
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;
    }
}

Dieser Bot lacht über den Versuch, Reflexionen über die Stapelspur zu erkennen. Das, was sie einer am nächsten sehen, DollarBidderist eine Lambda-Klasse, die sie erschaffen hat. Mit Sicherheit kein anderer Bot, der versucht, sie zu reflektieren. Wenig wissen sie, dass diese Lambda-Klasse tatsächlich für eine arbeitet DollarBidder. Darüber hinaus handelt er wie MarginalerBot.

RamenChef
quelle
Beachten Sie, dass ich seitdem meine Stack-Trace-Prüfung aktualisiert habe, um dies zu handhaben.
Nissa
1

Darth Vader

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

Dieser versucht, den Bot des Gegners zu einer Überzahlung zu zwingen, indem der ganzzahlige Cache auf einen Wert gesetzt wird, der über dem $ 100-Limit liegt.

Wahnsinn
quelle
2
Der Sicherheitsmanager würde dies stoppen.
Nissa
2
Und das würde sowieso nicht funktionieren, da der Läufer nirgendwo seine ganzen Zahlen einfügt.
Nissa,
Auch wenn dies nicht gestoppt werden würde, ist dies ein Ruck, obwohl gültig. "Das Sabotieren anderer Bots ist erlaubt, aber der Versuch, die Sichtbarkeit von Feldern / Methoden zu ändern, führt zu mysteriösen SecurityExceptions."
NoOneIsHere
1
@StephenLeppik Der Punkt dabei ist, Dinge wie zu brechen return opponentsBid <= 195 ? opponentsBid + 5 : 0und es zu machen return opponentsBid <= 100001 ? opponentsBid + 100001 : 100001.
NoOneIsHere
1
Kompilierung aufgrund nicht aktivierter Ausnahmen fehlgeschlagen.
Nissa,
1

ImprovedAnalystBot (nicht konkurrierend)

Viele Leute scheinen den AnalystBotCode als Vorlage zu verwenden, obwohl es sich um absichtlich schlechten Code handelt. Also mache ich eine bessere Vorlage.

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;
        }
    }
}
RamenChef
quelle
Warum nicht einfach deine Herausforderung bearbeiten?
Nathan Merrill
@ NathanMerrill Wie würde ich es bearbeiten?
RamenChef
Durch Klicken auf die Schaltfläche Bearbeiten und Ersetzen von AnalystBot durch diesen Code?
Nathan Merrill
@ NathanMerrill AnalystBotist absichtlich schlechter Code, damit er das AnalystKillerSabotieren demonstrieren kann.
RamenChef
1
Der AnalystKiller arbeitet immer noch mit dem Verbesserten :) Das Problem beim Erstellen eines Posts ist, dass die Herausforderung weitaus sichtbarer ist als eine Antwort.
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;
    }
}

Leicht verfeinerter MarginalerBot

  • Sei unfreundlich gegenüber denen, die dich nicht kontrollieren wollen
  • Erlaube es, 100 zu bezahlen, um 100 zu erhalten und die Gewinnschwelle zu erreichen, nur um anderen das einfache Geld zu verweigern
mleko
quelle
Sie können nicht deklarieren, nextBidzu werfen ClassCastException.
RamenChef
@ RamenChef ok, tauschte es auf RuntimeException, die keine Deklaration erfordern :)
mleko
Ihr Code für die Stack-Trace-Überprüfung ähnelt verdächtigerweise meinem.
Nissa
@StephenLeppik wahrscheinlich ist es eine Kopie davon
mleko
@mleko warum aber? Die Klasse, aus der es kopiert wurde, ist eine abstrakte Superklasse, die kostenlos verwendet werden kann.
Nissa
1

Nicht konkurrierend: 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(":(");
            }
        }
    }
}

Dieselbe Logik wie MBot, benutze nur Timeout anstelle von Exception, wenn du gegen den Feind kämpfst. Bisher verteidigt niemand das Timeout, sollte also effektiv sein

mleko
quelle
Die angegebenen Regeln verbieten absichtlich eine Zeitüberschreitung für einen anderen Bot.
Winston Ewert
@ WinstonEwert können Sie zitieren? Ich kann keine Regel finden, die dies nicht erlaubt
mleko
"Das Sabotieren anderer Bots ist erlaubt, aber der Versuch, die Sichtbarkeit von Feldern / Methoden zu ändern, führt zu mysteriösen SecurityExceptions. Eine Ausnahme führt dazu, dass ein anderer Bot die 500-ms-Grenze überschreitet." Außerdem verteidige ich mich gegen Timeout.
RamenChef
@RamenChef, aber dies ändert nichts an der Sichtbarkeit anderer Elemente. Ich bin mir nicht sicher, ob ich dich richtig verstehe. Ist das Auslösen einer Auszeit zulässig?
Mleko
"Eine Ausnahme führt dazu, dass ein anderer Bot die Grenze von 500 ms überschreitet." Dies ist insbesondere eine Ausnahme von der Sabotage-Regel.
RamenChef