Aukcja dolara


32

To wyzwanie KOTH dla gry aukcyjnej za dolary w teorii gier. W nim dolar jest sprzedawany oferentowi, który zaoferował najwyższą cenę. Oferty rosną w krokach co 5 centów, a przegrany płaci również swoją ofertę. Chodzi o to, że obaj gracze eskalują wojnę przetargową znacznie przekraczającą wartość dolara, aby zmniejszyć straty.

Miejmy nadzieję, że twoje boty są mądrzejsze.

Będziesz tworzyć bota, aby zagrać w tę grę, rozszerzając net.ramenchef.dollarauction.DollarBidderklasę. Musisz wdrożyć nextBidmetodę, która zwraca następną ofertę twojego bota, biorąc pod uwagę poprzednią ofertę innego bota. W razie potrzeby możesz także użyć newAuctionmetody resetowania dla każdej aukcji z klasą bota przeciwnika.

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

Licytacja trwa do momentu spełnienia jednego z poniższych warunków:

  • nextBidzgłasza wyjątek. Jeśli tak się stanie, bot, który zgłosił wyjątek, płaci swoją poprzednią ofertę, a drugi bot dostaje dolara za darmo.
  • Żaden bot nie płaci wystarczająco dużo, aby przewyższyć poprzednią ofertę. Jeśli tak się stanie, oba boty płacą swoje oferty (przegrany płaci poprzednią ofertę), a zwycięzca dostaje dolara.
  • Oba boty licytują ponad 100 $. Jeśli tak się stanie, oba boty płacą 100 USD, a żaden bot nie dostaje dolara.

Dla każdej kombinacji botów odbywają się 2 aukcje. Boty są oceniane na podstawie całkowitego zysku, jaki osiągnęły na tych aukcjach. Najwyższy wynik wygrywa.

Przykłady

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

Nie używaj tego jako szablonu dla analitycznie nastawionych botów; użyj ImprovedAnalystBotzamiast tego.

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

Dodatkowe zasady

  • Standardowe luki są zabronione.
  • Sabotowanie innych botów jest dozwolone, ale próba zmiany widoczności pola / metody spowoduje tajemnicze SecurityExceptions. Wyjątek powoduje, że inny bot przekroczy limit 500ms.
  • Boty nie mogą uzyskać dostępu do pakietu runnera, z wyjątkiem rozszerzenia DollarBidderklasy.
  • Wszystkie metody powinny zostać zwrócone w ciągu 500 ms lub mniej.
  • Boty nie muszą być deterministyczne.
  • Twoja oferta nie musi być wielokrotnością 5 ¢.
  • 1 USD = 100 ¢
  • Wyniki zostaną opublikowane 24 kwietnia 2018 r.

Runner na GitHub

Wyniki

Zobacz poszczególne rundy tutaj.

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

Gratulacje MTargetedBotz zyskiem 14,30 $!


11
To wyzwanie jest zasadniczo podatne na One-Upping. Ponieważ znam klasę mojego przeciwnika, łatwo jest wybrać najlepszą strategię przeciwko niej. (Wtedy ktoś przychodzi i może podnieść mojego bota itp.)
Nathan Merrill

2
Oferty rosną o 5 ¢ ”. Nie masz nic w kodzie, by to sprawdzić, ale ... LuckyDiceBotna przykład oferty w przyrostach 2-12losowych ..
Kevin Cruijssen

4
Ponadto: co jeśli mój bot spowoduje, że inne boty przekroczą ograniczenie 500ms?
Nathan Merrill,

4
@RamenChef Mówimy tutaj o złośliwym kodzie. Co się stanie, jeśli wykryję, kiedy dzwoni do mnie inny bot i wywołam Thread.sleep (1000)?
Nathan Merrill,

3
Jestem VTC, ponieważ nie jest jasne, jaki sabotaż jest dozwolony, a co nie. OP nie zezwalał na przekazywanie informacji „atakujących runnera” (co jest niejasne) i nie ma wyraźnej granicy między dozwolonym złośliwym kodem a złośliwym kodem, który nie jest (Jak ustalić, który bot spowodował, że bot trwał zbyt długo ?)
Nathan Merrill,

Odpowiedzi:


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);
    }
}
  • Na podstawie zaktualizowanego MBota
  • Używa podobnej metody, jak CounterBot, ale z niektórymi ulepszonymi metodami, aby mocniej trafiać niektórych przeciwników, również powinna być bardziej czytelna
  • W przypadku nieznanego przeciwnika domyślnie ustawiona jest MBot

1
To niesprawiedliwe.
Joshua,

@Joshua Co Twoim zdaniem szczególnie niesprawiedliwe w tym rozwiązaniu?
mleko

Znając nazwiska swoich przeciwników.
Joshua

@Joshua połowa rozwiązań wykorzystuje te informacje. Napisaliśmy nawet do autora, że ​​należy to zmienić, bo inaczej nastąpi One-Upping, odmówił zmiany wyzwania - więc oto
mleko

1
Już zrobiłem ....
Jozuego

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

Święta krowa. Spodziewałem się, że będzie to łatwe do napisania, a następnie spędziłem nad nim 3 godziny.

Zasadniczo MimicBotutrzymuje bieżącą listę dostępnych botów. Gdy idzie na nową aukcję, przegląda listę w poszukiwaniu najbardziej efektywnej z aktualnym przeciwnikiem. Następnie używa tego bota jako „odniesienia” na aukcji.

Do celów testowych najlepiej byłoby użyć losowego podzestawu zgłoszeń lub pełnego zestawu. Zaczyna się od GreedyBot, MimicBoti jeszcze jednego bota, który licytuje tylko 5 centów.


11

InsiderTradingBot

W duchu odpowiedzi @ StephenLeppik InsiderTradingBot zna wszystkich swoich przeciwników i rozumie ich strategie. Twój ruch, 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
Nie, handel poufnymi informacjami byłby, gdyby RichJerkbot zrobił wyjątek dla twojego bota i zaoferował za niego 0 $.
Nissa,

Jest za wcześnie, aby optymalizować w stosunku do innych odpowiedzi. Poza tym AnalystBotnie Analyst.
RamenChef

8
Prawdopodobnie musi istnieć reguła „nazwy klas będą losowe”.
user202729,

1
@ user202729 Co powiesz na „brak bezpośrednich odniesień do klas”?
RamenChef

1
Chciałbym zobaczyć, jak obsługuje MimicBot.
Nissa,

8

MirrorBot

Sprawia, że ​​wróg gra przeciwko sobie.

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
Nukowałeś Analystspektakularnie.
Silvio Mayolo,

@SilvioMayolo Jak?
dkudriavtsev

Mirror próbuje naśladować grę Analityka przeciwko sobie, co powoduje przepełnienie stosu.
Silvio Mayolo,

8

Edycja : Ukierunkowane zmiany w klasie DollarBidder spowodowały uszkodzenie tego bota.

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

Po 1 aukcji jego wynik wyniesie -2147483645, ale następnym razem straci 5 ¢ lub 105 ¢, co daje wynik pozytywny i bardzo duży. Wszystkie pozostałe straty byłyby wówczas nieistotne.

Na pierwszej aukcji GreedyBot postawiłby również na -2147483646, co nie jest podzielne przez 5.


scorejest chroniony paczką. Twoje boty nie mają do niego dostępu.
RamenChef,

@RamenChef Ups, usunięto CheatingBot
Zima

Nie ma żadnej reguły przeciwko „atakowaniu biegacza”, tylko „dostęp” do niego, czego nie robi. Polecam naprawienie błędu, który rozwiązuje problem :)
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;
        }
    }
}

W tej chwili nie można tego przetestować, więc daj mi znać, jeśli jest uszkodzony.

Zasadniczo wybierz wartość dolara i przebijaj przeciwnika, aż przekroczymy tę wartość.


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

Bardzo proste, próbuje ustalić, czy przeciwnik podważy minimalną ofertę, a jeśli nie, stawia ją.

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

Nowa, inteligentniejsza wersja MarginalBot, która sprawdza, czy może wykonać jakiś zarabianie pieniędzy bez rywalizacji, a nie tylko ma nadzieję wygrać z minimum.

Ponieważ jest w tej samej rodzinie co mój poprzedni bot, ale strategie, które próbują go pokonać, pomyślałem, że nowy wpis w tym samym poście był najbardziej rozsądnym sposobem przedstawienia go.

Edycja 1: Wprowadzono niewielką zmianę w metodzie newAuction w celu optymalizacji w stosunku do innych botów typu analizatora.

Edycja 2: Dokonano zmiany w MarginalerBot, aby zminimalizować straty w stosunku do podstępnych lub niedeterministycznych strategii.


Witamy w PPCG!
Martin Ender

1
To proste, ale pokonuje wszystkie inne boty o dość duży margines!
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);
  }
}

Poddaje się, jeśli nie da rady.


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

To musiało być zrobione.


Oferty rosną o 5 ¢ ”. Twój bot obecnie tego nie robi.
Kevin Cruijssen

1
@KevinCruijssen Wystarczająco fair. I również zmienić górną granicę więc może licytować cała $ 1, na wszelki wypadek
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;
    }
}

Próbuje przekonać analitycznie nastawionych botów, że jedynym zwycięskim ruchem nie jest gra.


1
Zauważyłem, że mój nieco tajemniczy komentarz „Joshua? Czy to ty?” zostało usunięte. Żeby wyjaśnić, było to odniesienie do słynnego cytatu z filmu WarGames: „jedynym zwycięskim ruchem jest nie grać” . (Joshua jest przezwiskiem WOPR .)
Arnauld

5

LuckyDiceBot

LuckyDiceBot ufa tylko jego kościom. Rzuca dwiema kostkami, dodaje sumę do wartości aktualnego licytanta i tyle licytuje. Jeśli nie wystarczy pokonać ofertę przeciwnika, zmniejsza straty i idzie dalej.

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
W jaki sposób ogranicza to straty lub zatrzymuje straty? Jeśli zawsze dodaje rzut kostką do stawki przeciwnika, zawsze licytujesz więcej. Przypadkowość może mylić wystarczająco analitycznego bota, podoba mi się koncepcja.
Freiheit,

Jeśli rzut wynosi 4 lub mniej (statystycznie mało prawdopodobne, ale w końcu się stanie), oferta jest niewystarczająca, aby pokonać przeciwnika i aukcja się kończy.
Silvio Mayolo,

Dwie rzeczy: 1. @ Freiheit ma rację i ten bot będzie licytował, dopóki nie wygra, bez względu na to, jak wysoko. opponentsBidw nextBid(int opponentsBid)trzyma całkowitą ofertę, którą twój przeciwnik złożył do tej pory, a nie kolejną. Lepszym terminem dla tej metody byłoby raise(jako termin pokera) imho. 2. Twój bot nie gryzie w krokach co 5, dlatego sprawdza jedną z reguł. Jeśli te problemy zostaną rozwiązane, nadal podoba mi się ta koncepcja, ponieważ boty analityczne nie będą w stanie przeciwdziałać, więc najprawdopodobniej wygrasz dość często.
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 robi fortunę z nielegalnego hazardu w LuckyDiceBot. Oczywiście, kiedy przybywa policja (DeterrentBot), musi on szybko w jakiś sposób pozbyć się swoich zarobków, takich jak licytacja na następnej aukcji.


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

W tej chwili nie można tego przetestować, więc daj mi znać, jeśli jest uszkodzony.

W każdej rundzie wartość dolara rośnie.


Byłoby to doskonałe przeciwko MirrorBot, MarginalerBot i prawdopodobnie także MimicBot.
Nissa,

@StephenLeppik Właśnie o tym myślałem, kiedy to zrobiłem. Jednak wciąż wiele słabości.

+1, podoba mi się ten pomysł. Hmm, czy to ma oznaczać, że twój bot licytuje 0 i pęka, nawet jeśli zaczyna rundę (kiedy opponentsBidwciąż jest 0)?
Kevin Cruijssen

@KevinCruijssen Tak. Może się to zdarzyć tylko przeciwko pierwszemu przeciwnikowi. Każdy bot, który go skopiuje, zacznie od 0, więc nie zmarnuje na nich więcej niż 5c.

4

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

Nie jest to zamierzone jako prawdziwe podporządkowanie, ale raczej jako pewna płyta dla innych, aby powstrzymać boty trzymające zwierzęta domowe, takie jak MirrorBotiMimicBot .

Ponieważ jest to domyślny konstruktor, nie ma potrzeby wywoływania go w podklasie. Implementuje isPeekingmetodę określania, czy inny bot szpieguje.


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

Scenariusze

  • Jeśli przeciwnik może zacząć i licytuje <= 0 , przegrywa.
  • Jeśli przeciwnik może zacząć i licytuje [5,95] : sam licytuj 100. Albo twój przeciwnik się zatrzyma, albo licytuje łącznie powyżej 100, w takim przypadku przestajesz licytować, aby pozwolić mu wygrać i wyrównać.
  • Jeśli przeciwnik może zacząć i licytuje >= 100: postaw 0 za siebie, by przegrać, ale wyrównaj.
  • Jeśli możesz zacząć: od razu licytuj 100. Albo twój przeciwnik się zatrzyma, albo licytuje powyżej 100, w takim przypadku przestajesz licytować, aby pozwolić mu wygrać i wyrównać.

Wow, to jest błąd. Powiedział, że komentuję to pytanie, ale skończyło się tutaj. Muszę znaleźć sposób na jego odtworzenie
Stan Strum,

@RamenChef Typo .. Ale zmodyfikowałem cały bot. I tak miał trochę błędów ..
Kevin Cruijssen

4
To może całkowicie stracić pieniądze. Jeśli licytujesz 100, to twój przeciwnik licytuje 105, w efekcie przegrywasz 100, a on przegrywa tylko 5.

@Mememoniczny Ah oczywiście .. Nie myślałem o tej części .. Hmm .. to czyni sprawy bardziej interesującymi, ale i trudniejszymi. Na razie edytuje opis, ale zostaw bota bez zmian.
Kevin Cruijssen

1
Myślę, że masz na myśli „stracić”, a nie „stracić”. Przegrana to przeciwieństwo wygranej. Luźne to przeciwieństwo ciasnego.
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;
    }

}

Zgłasza błąd zamiast wyjątku, aby zmylić analityków.


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

Próbuje ocenić przeciwnika, z którym się mierzy, i upewnij się, że nie odgryzasz więcej, niż może przeżuć.


1
Witamy w 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;
        }
    }
}

brukowane razem z części innych botów. ten gra próbując być AnalystBot, a jeśli się nie powiedzie, staje się BorkBorkBot.

Nie sądzę, żeby to zrobiło tak dobrze.


Uważaj na AnalystKiller.
RamenChef

@RamenChef AFAIK, zabójca analityka po prostu zgłasza wyjątek, jeśli widzi, że jest analizowany. Mogę to złapać
dkudriavtsev

1
Prawdopodobnie powinieneś to złapać.
RamenChef

@RamenChef Nie mam pojęcia, czy to zadziała, nie mogę 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;
  }
}

Liczniki:

  • DarthVaderprzeciwdziała samemu powodując a SecurityExceptionprzed rozpoczęciem licytacji, ale na wszelki wypadek licytuję 5.
  • AnalystBoti AnalystOptimizeroboje spojrzą na moją odpowiedź, kiedy licytuję 95, w takim przypadku pokażę, że licytuję 100, więc sama licytuje 95. Będę jednak licytować 5, jeśli zacznę (lub 100, jeśli rozpoczęły), więc tracą 95 centów i albo wygrywam rachunek 1 USD, licytując tylko 5 centów, lub osiągając próg rentowności.
  • MirrorBotlicytuje to, co ja licytowałbym przeciwko niemu. Więc licytuję 5, a ktokolwiek zacznie wygrywać 95 centów, a drugi traci 5 centów.
  • MarginalBot licytuje 5, jeśli licytujebym mniej niż 10 (lub to, co zaczyna), w przeciwnym razie licytuje 0. Więc jeśli po prostu licytuję 5, gdy zaczynam lub 10, gdy zaczyna, wygrywam 95 lub 90 centów, a oni przegrywają 5 centów.
  • GreedyBot zawsze licytuje o 5 więcej ode mnie, więc po prostu licytuj 0, aby osiągnąć próg rentowności i pozwolić im wygrać
  • OnlyWinningMove i AnalystKiller oba zawsze licytują 0, więc po prostu licytuj 5, aby wygrać
  • TargetValueBot będzie licytować w zakresie [100,200] , więc licytuj o 5 więcej za każdym razem, dopóki nie osiągną 190, w takim przypadku podbijamy do 200, aby wyrównać, wygrywając dolara (i pozwalamy im stracić 190 lub 195 w zależności od tego, kto zaczął)
  • BorkBorkBotbędzie licytować w tym zakresie [5,95], więc za każdym razem licytuj również o 5 więcej. Gdy tylko licytują 85 lub 90 (w zależności od tego, kto zaczął), licytuj 95 samodzielnie. Stracą 85 lub 90 centów, a ty wygrasz rachunek 1 USD za zysk 5 centów.
  • DeterrentBot licytuje 5, jeśli zaczynają, lub 100, jeśli zaczynamy, więc po prostu licytuj 105, więc liczą 100, powodując, że tracą 100, a my tracimy tylko 5 centów, wygrywając rachunek 1 USD.
  • BreakEvenAsapod razu licytuje 100. Więc jeśli rozpoczęli licytację 100, skontruj 105, aby wygrać 95 centów i pozwolić im stracić 100. Jeśli możemy zacząć, licytuj tylko 100, więc oboje osiągniemy próg rentowności.
  • RichJerk licytuje od razu 10,001, więc po prostu licytuj 0, aby wyrównać i pozwolić im stracić 9,901.
  • DeterredBot mnie nie zna i dlatego licytuje 0, więc po prostu licytuj 5, aby wygrać.
  • LuckyDiceBotlicytuje, aż wygra. Więc jeśli zaczniemy, licytuj 5 w nadziei, że licytują jak najwyższą kwotę, aby wygrać dolara. Jeśli zaczęli, po prostu licytuj 0, aby pozwolić im wygrać i wyrównać.
  • RandBotbędzie licytować losowo w zakresie [5,100], więc po prostu licytuj o 5 więcej, aż się zatrzyma, w którym to przypadku wygrałeś 95 centów i przegrali 0-100.
  • UpTo200będzie (jak sama nazwa wskazuje) licytować do 200. Więc po prostu licytuj o 5 wyżej, aż się zatrzymają. Wygramy rachunek za 1 USD i poniesiemy całkowitą stratę 105 centów, ale oni stracą 200 centów.
  • InsiderTradingBot nie zna mnie, więc po prostu licytuj 5 centów, aby wygrać
  • MimicBotbyło najtrudniejsze. Po prostu licytuj 10, aby zacząć od lub licytować ich pierwszą ofertę 5. Jeśli spróbują uzyskać do mnie dostęp, rzucę wyjątek RuntimeException (który złapią, w którym to przypadku działałoby to tak, jakbym miał licytować 100 - chociaż spowoduje to przerwanie wewnętrzna pętla while). W zależności od wrogów, których ma w HashSet, dzieje się coś innego. Będę musiał ponownie odwiedzić i przyjrzeć się bliżej, aby sprawdzić, czy istnieje prawdziwy licznik.
  • RiskRewardBot nie zna mnie, więc po prostu licytuje 5, w takim przypadku licytuję 5, aby wygrać.
  • MarginalerBotugryzę do 100 w zależności od tego, co chciałbym licytować Jeśli mogę zacząć, licytuję 90, następnie licytuję 95, następnie licytuję 100, więc licytuję 0 i tracę 95 centów, podczas gdy wygrywam rachunek 1 USD i osiągam rentowność. Jeśli zacznie się zamiast tego, zobaczy, że postawiłbym przeciwko niemu 90, więc licytuje sam 90, wtedy licytuję 95, więc licytuje 0 i tracę 90 centów, a ja wygrywam rachunek 1 USD z zyskiem 5 centów.
  • BuzzardBotprzeanalizuje wszystkie moje liczniki w zakresie [0,100). Jeśli 100od razu licytuję, użyj, oppFlag = 0a pełna tablica 100 będzie zawierać 100x wartość 100. W przełączniku case 0pętla znów znajdzie się w zakresie [0,100), a ponieważ i + 5co najwyżej 104,bids[i] < i + 5 nigdy nie będzie prawdą , więc stawka, którą robi, wynosi 0.
  • ImprovedAnalystBotzawsze tak będzie, this.enemy = nullponieważ jego przeciwnikiem jestCounterBot nie jest sobą. Więc zawsze będzie licytować 0, co ja po prostu liczę z ofertą 5.
  • InflationBot licytuje 0, aby przełamać, nawet gdy się zacznie, w przeciwnym razie będzie licytować 5. Więc po prostu licytuj 0, aby od razu wyrównać i pozwolić im wygrać.
  • ScoreOverflowBotalbo licytuje w pobliżu, Integer.MAX_VALUEjeśli mogą zacząć, w przeciwnym razie będą licytować105 . Więc jeśli licytują 105, po prostu sami licytują 110 (przegrają 105, my stracimy 10), w przeciwnym razie po prostu licytuj 0, aby pozwolić im wygrać.
  • MBotjest taki sam jak MarginalerBot, ale z dodatkową ochroną przed „zerkającymi” przeciwnikami. Ponieważ nie „podglądam”, jest to w zasadzie to samo coMarginalerBot .
  • SecretBotspowoduje, że jego isPeeking()metoda zwróci false, więc jeśli może się rozpocząć lub jeśli licytuję 5, odpowiednio licytuje 5 lub 10. W przeciwnym razie będzie licytować 0. Więc czy zacznę, czy nie,opponentsBid + 5 spowodowałbym wygraną w obu kierunkach, zarówno z moimi 10 centami, jak i 15 centów, powodując, że przegrali 5 lub 10 centów.
  • BluffBotspojrzy na to, co licytuję, gdy jego oferta wynosi 95, a jeśli jest ona większa lub równa 100, zaoferuje 0, aby się przebić, w przeciwnym razie będzie licytować opponentsBid + 5. Więc po prostu licytuję opponentsBid + 5. Wybije nawet niezależnie od tego, kto zacznie, i wygrywam 100 lub 95 centów w zależności od tego, czy zacząłem, czy nie.
  • StackTraceObfuscaterBotbędzie działać tak samo jak MarginalerBot.
  • EvilBotzawsze licytuje 5, więc po prostu licytuj opponentsBid + 5. Tak czy inaczej stracą te 5 centów, a my wygramy licytację 1 USD (albo 5 centów, jeśli zaczniemy, albo 10 centów, jeśli zaczną).
  • MSlowBotjest taki sam jak MBoti dlatego też MarginalerBot.

Daj mi znać, jeśli zobaczysz jakieś literówki lub wady w moich licznikach.


1
MirrorBotnazywa newAuction z własną klasą, więc to jest problem. Cieszę się również, że 3 godziny spędzone na MimicBot nie poszły na marne.
Nissa,

@StephenLeppik Usunąłem kod, newAuctionponieważ często by się nie udawał . Nie mogę przeciwdziałać MirrorBotani nie może mi się przeciwstawić. Ktokolwiek zaczyna z tych dwóch, wygrywa 95 centów, a drugi traci 5 centów.
Kevin Cruijssen

3
Święty łańcuch trójskładnikowy, Batman!
Skyler

1
Czy podczas gry BorkBorkBotnie powinieneś przebijać do 95, gdy osiągną 85? W przeciwnym razie oboje licytujesz 95, jeśli zaczną.
Skyler

1
@Freiheit wiem. Właśnie użyłem dodatkowego przypadku, aby zwrócić 0, na wypadek, gdybym chciał zmienić ustawienie domyślne z jakiegokolwiek powodu. Ale ustawiłem je teraz jako domyślne (komentując je). Wiem, że potrafię trochę grać w golfa, ale nie chodzi o to, by stworzyć najkrótszy kod. Właśnie uczyniłem go trójskładnikiem, aby uczynić go nieco bardziej kompaktowym, ale o to chodzi. Na razie zostawię to w ten sposób.
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;
        }
    }
}

W tej chwili nie można tego przetestować, więc daj mi znać, jeśli jest uszkodzony.

Celem jest uzyskanie jak najwyższego wyniku, więc nie przejmuj się nikim. Po prostu weź łatwe wygrane i nie marnuj pieniędzy na ewentualne straty.


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


}

Znany szpieg jest cenniejszy niż żaden szpieg ...

Jeśli ktoś inny spróbuje wywołać metodę getBid, BluffBot odpowiada kwotą 100 $, aby nakłonić ich do rezygnacji lub obstawienia naprawdę wysokich.

W przeciwnym razie sprawdź, czy można wygrać za mniej niż 1 $, i po prostu nie licytuj, jeśli nie jest.


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

}

Ten bot podejmuje minimalne próby wygrania przez licytację 5 lub 10. Sprawdza również ślad stosu, aby sprawdzić, czy został powołany przez innego Bota, a następnie okłamuje ich, jakie stawki złoży.


Przeszkadza jeśli portu I isPeekingdo AbstractAnalystCounterBot?
Nissa,

1
@StephenLeppik, cóż, ukradłem go MBotowi ...
Winston Ewert,

1
Cóż, MBot prawdopodobnie ukradł mi go…
Nissa,

2

Jeden dodatkowy

import net.ramenchef.dollarauction.DollarBidder;

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

Licytuje o 6 więcej niż ostatnia oferta, tylko dlatego, że może.


Nie może licytować 6, ponieważ wszystkie oferty muszą być wielokrotnościami 5 ...
Neil,

@Neil to prawdopodobnie literówka ...
Stan Strum

@ Zasady nie określają wyraźnie: „Twoja oferta nie musi być wielokrotnością 5 ¢”
MegaTom,

@MegaTom Huh, cóż, to zostało dodane, odkąd ostatnio czytałem zasady ...
Neil,

@Neil Było to częścią oryginalnych zasad, ale dodałem je tam, ponieważ nie było to bardzo oczywiste.
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;
    }
}

Ten bot śmieje się z prób wykrycia odbicia za pomocą śladu stosu. Najbliższą rzeczą, jaką widzą, DollarBidderjest stworzona przez nią klasa lambda. Najwyraźniej żaden inny bot nie próbuje ich odzwierciedlić. Niewiele wiedzą, że ta klasa lambda faktycznie pracuje dla DollarBidder. Poza tym zachowuje się jak MarginalerBot.


Zauważ, że od tego czasu zaktualizowałem sprawdzanie śledzenia stosu, aby to obsłużyć.
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;
}
}

Ten próbuje zmusić bota przeciwnika do przepłacenia, ustawiając całkowitą pamięć podręczną na wartość przekraczającą limit 100 $.


2
Kierownik ochrony zatrzymałby to.
Nissa

2
I tak by to nie zadziałało, ponieważ nigdzie w biegaczu nie ma pola liczb całkowitych.
Nissa

Nawet jeśli nie można tego zatrzymać, jest to ruch palantem, choć ważny. „Sabotowanie innych botów jest dozwolone, ale próba zmiany widoczności pola / metody spowoduje tajemnicze wyjątki bezpieczeństwa”.
NoOneIsHere

1
@StephenLeppik Chodzi o to, aby coś zepsuć return opponentsBid <= 195 ? opponentsBid + 5 : 0i zrobić return opponentsBid <= 100001 ? opponentsBid + 100001 : 100001.
NoOneIsHere

1
Nie można skompilować z powodu niesprawdzonych wyjątków.
Nissa,

1

ImprovedAnalystBot (niekonkurujący)

Wydaje się, że wiele osób używa AnalystBotkodu jako szablonu, nawet jeśli jest to celowo zły kod. Więc tworzę lepszy szablon.

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

Dlaczego nie po prostu edytować swojego wyzwania?
Nathan Merrill,

@NathanMerrill Jak mógłbym to edytować?
RamenChef

Klikając przycisk edycji i zastępując AnalystBot tym kodem?
Nathan Merrill,

@NathanMerrill AnalystBotjest celowo złym kodem, dzięki czemu może zademonstrować AnalystKillersabotaż.
RamenChef

1
AnalystKiller nadal działa z ulepszoną wersją :) Problemem z opublikowaniem posta jest to, że wyzwanie jest znacznie bardziej widoczne niż odpowiedź.
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;
    }
}

Lekko dopracowany MarginalerBot

  • bądź niemiły dla tych, którzy nie chcą cię sprawdzić
  • pozwalają płacić 100, aby dostać 100, i nawet wyrównać, po prostu, aby odmówić innym łatwych pieniędzy

Nie możesz zadeklarować nextBidrzucenia ClassCastException.
RamenChef,

@RamenChef ok, zamieniłem go na RuntimeException, które nie wymagają deklaracji :)
mleko

Twój kod do sprawdzania śledzenia stosu wygląda podejrzanie podobnie do mojego.
Nissa,

@StephenLeppik prawdopodobnie jest to jego kopia
mleko

@mleko dlaczego jednak? Klasa, z której została skopiowana, jest abstrakcyjną superklasą, z której można korzystać bezpłatnie.
Nissa,

1

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

Ta sama logika co MBot, po prostu użyj limitu czasu zamiast wyjątku podczas walki z wrogiem. Jak dotąd nikt nie broni limitu czasu, więc powinno być skuteczne


Podane zasady celowo zabraniają celowego przekroczenia limitu czasu przez innego bota.
Winston Ewert,

@WinstonEwert czy możesz cytować? Nie mogę znaleźć reguły uniemożliwiającej to
mleko

„Sabotowanie innych botów jest dozwolone, ale próba zmiany widoczności pola / metody spowoduje tajemnicze wyjątki bezpieczeństwa. Wyjątek powoduje, że inny bot przekroczy limit 500 ms”. Ponadto bronię przed przekroczeniem limitu czasu.
RamenChef,

@RamenChef, ale to nie zmienia widoczności innych elementów. Nie jestem pewien, czy dobrze cię rozumiem. Czy dozwolone jest przekroczenie limitu czasu prowokacji?
mleko

„Wyjątek powoduje, że inny bot przekroczy limit 500 ms”. W szczególności jest to wyjątek od reguły dotyczącej sabotażu.
RamenChef,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.