Asta di banconote da un dollaro


32

Questa è una sfida KOTH per il gioco di aste di banconote da un dollaro nella teoria dei giochi. In esso, un dollaro viene venduto al miglior offerente. Le offerte aumentano con incrementi di 5 ¢ e anche il perdente paga la propria offerta. L'idea è che entrambi i giocatori intensifichino la guerra delle offerte ben oltre il valore di un dollaro per ridurre le loro perdite.

Speriamo che i tuoi robot siano più intelligenti di così.

Creerai un bot per giocare estendendo la net.ramenchef.dollarauction.DollarBidderclasse. È necessario implementare il nextBidmetodo che restituisce la prossima offerta del proprio bot data l'offerta precedente dell'altro bot. Se necessario, puoi anche usare il newAuctionmetodo per resettare per ogni asta con la classe del bot dell'avversario.

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

L'offerta è valida fino a quando si verifica una delle seguenti condizioni:

  • nextBidgenera un'eccezione. In questo caso, il bot che ha generato l'eccezione paga la sua offerta precedente e l'altro bot ottiene il dollaro gratis.
  • Entrambi i bot non pagano abbastanza per completare l'offerta precedente. Se ciò accade, entrambi i robot pagano le loro offerte (il perdente paga la loro offerta precedente) e il vincitore riceve un dollaro.
  • Entrambi i robot offrono oltre $ 100. Se ciò accade, entrambi i robot pagano $ 100 e nessuno dei due bot ottiene il dollaro.

Si svolgono 2 aste per ogni combinazione di robot. I bot vengono assegnati in base al profitto totale realizzato in tali aste. Vince il punteggio più alto.

Esempi

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

Non usarlo come modello per i robot con mentalità analitica; usa ImprovedAnalystBotinvece.

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

Regole aggiuntive

  • Sono vietate le scappatoie standard .
  • È consentito sabotare altri robot, ma tentare di alterare la visibilità del campo / metodo si tradurrà in misteriosi messaggi di posta SecurityExceptionelettronica. Un'eccezione sta facendo sì che un altro bot rompa il limite di 500ms.
  • I robot non possono accedere al pacchetto runner se non per estendere la DollarBidderclasse.
  • Tutti i metodi dovrebbero tornare in 500ms o meno.
  • I robot non devono essere deterministici.
  • La tua offerta non deve essere un multiplo di 5 ¢.
  • $ 1 = 100 ¢
  • I risultati saranno pubblicati il ​​24 aprile 2018.

Runner su GitHub

risultati

Visualizza i singoli round qui.

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

Congratulazioni a MTargetedBotcon un profitto di $ 14,30!


11
Questa sfida è fondamentalmente vulnerabile a One-Upping. Dal momento che conosco la classe del mio avversario, è facile scegliere la migliore strategia contro di essa. (Poi qualcuno arriva e può aprire il mio robot , ecc.)
Nathan Merrill

2
" Le offerte aumentano con incrementi di 5 ¢ ". Non hai nulla nel tuo codice per convalidare questo, però ... LuckyDiceBotper esempio offerte in incrementi di 2-12casualmente ..
Kevin Cruijssen,

4
Inoltre: cosa succede se il mio bot fa sì che altri robot superino la limitazione di 500ms?
Nathan Merrill,

4
@RamenChef Stiamo parlando di codice dannoso qui. Cosa succede se rilevo quando un altro bot mi sta chiamando e chiamo Thread.sleep (1000)?
Nathan Merrill,

3
Sono VTC questo in quanto non è chiaro cosa sia consentito il sabotaggio e cosa no. L'OP ha vietato l'invio che "attacca il corridore" (che è vago) e non esiste una linea chiara tra il codice dannoso consentito e il codice dannoso che non lo è (Come si determina quale bot ha causato un bot troppo lungo ?)
Nathan Merrill,

Risposte:


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);
    }
}
  • Basato su MBot aggiornato
  • Utilizza un metodo simile come CounterBot, ma con alcuni metodi perfezionati per colpire più duramente alcuni avversari, dovrebbe anche essere più leggibile
  • Su un avversario sconosciuto il default è MBot strat

1
Questo non è giusto.
Giosuè,

@Joshua Secondo te cosa non è giusto in merito a questa soluzione?
mleko,

Conoscere i nomi dei tuoi avversari.
Giosuè,

@Joshua metà delle soluzioni utilizza tali informazioni. Abbiamo anche scritto all'autore che questo dovrebbe essere cambiato o si verificherà One-Upping, ha rifiutato di cambiare la sfida - quindi eccolo qui
mleko

1
Già fatto ...
Giosuè il

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

Mucca sacra. Mi aspettavo che fosse semplice da scrivere, poi ho trascorso 3 ore su di esso.

In sostanza, MimicBotmantiene un elenco aggiornato dei robot disponibili. Quando va a una nuova asta, scorre l'elenco alla ricerca di quella più efficace contro l'avversario attuale. Quindi utilizza quel bot come "riferimento" nell'asta.

A scopo di test, sarebbe meglio utilizzare un sottoinsieme randomizzato degli invii o l'intero set. Inizia con GreedyBot, MimicBote un altro bot che offre solo 5 ¢.


11

InsiderTradingBot

Nello spirito della risposta di @ StephenLeppik, InsiderTradingBot conosce tutti i suoi avversari e comprende le loro strategie. La tua mossa, 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
No, l'insider trading sarebbe se il RichJerkbot avesse fatto un'eccezione specifica per il tuo bot e avesse offerto $ 0 per questo.
Nissa,

È troppo presto per ottimizzare contro altre risposte. Inoltre, non lo AnalystBotè Analyst.
RamenChef,

8
Probabilmente ci deve essere una regola "i nomi delle classi saranno randomizzati".
user202729,

1
@ user202729 Che ne dici di "nessun riferimento diretto alle classi"?
RamenChef,

1
Mi piacerebbe vederlo gestire MimicBot.
Nissa,

8

MirrorBot

Fa giocare il nemico contro se stesso.

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
Hai nuotato in modo Analystspettacolare.
Silvio Mayolo,

@SilvioMayolo Come?
dkudriavtsev,

Mirror tenta di emulare l'analista giocando contro se stesso, causando uno stack overflow.
Silvio Mayolo,

8

Modifica : le modifiche mirate nella classe DollarBidder hanno rotto questo bot.

ScoreOverflowBot

import net.ramenchef.dollarauction.DollarBidder;

public class ScoreOverflowBot extends DollarBidder {
  boolean betBig = true;

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

Dopo 1 asta, il suo punteggio sarà -2147483645 ma la prossima volta perderà 5 ¢ o 105 ¢ rendendo il punteggio positivo e molto grande. Tutte le altre perdite sarebbero quindi trascurabili.

Nella prima asta, farebbe anche una scommessa su GreedyBot -2147483646 che non è divisibile per 5.


scoreè protetto da pacchetti. I tuoi robot non possono accedervi.
RamenChef,

@RamenChef Oops, rimosso CheatingBot
Inverno

Non esiste una regola contro "attaccare il corridore", solo "accedervi", cosa che non succede. Consiglio di correggere l'errore, che risolve il problema :)
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;
        }
    }
}

Al momento non è possibile verificarlo, quindi per favore fatemi sapere se è rotto.

Fondamentalmente, scegli un valore per il dollaro e supera l'avversario fino a quando non superiamo quel valore.


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

Molto semplice, cerca di determinare se un avversario contesterebbe un'offerta minima e, in caso contrario, la piazza.

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

Una nuova versione più intelligente di MarginalBot che controlla se è in grado di fare qualsiasi mossa senza soldi, senza sperare di vincere con il minimo.

Dato che appartiene alla stessa famiglia del mio bot precedente, ma elude le strategie che cercano di batterlo, ho pensato che una nuova voce nello stesso post fosse il modo più ragionevole di presentarlo.

Modifica 1: apportata una piccola modifica al nuovo metodo di Aspirazione per ottimizzare rispetto ad altri robot di tipo analizzatore.

Modifica 2: apportato una modifica a MarginalerBot per ridurre al minimo le perdite contro strategie subdole o non deterministiche.


Benvenuti in PPCG!
Martin Ender,

1
È semplice, ma batte tutti gli altri robot con un margine abbastanza grande!
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);
  }
}

Si arrende se non riesce a pareggiare.


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

Doveva essere fatto.


" Le offerte aumentano con incrementi di 5 ¢ ". Il tuo bot al momento non lo sta facendo.
Kevin Cruijssen,

1
@KevinCruijssen Abbastanza giusto. Ho anche modificato il limite superiore in modo che potesse offrire l'intero $ 1, per ogni evenienza,
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;
    }
}

Tenta di persuadere tutti i robot con una mentalità analitica che l'unica mossa vincente è quella di non giocare.


1
Ho notato che il mio commento un po 'enigmatico "Giosuè? Sei tu?" è stato cancellato. Quindi, solo per chiarire, è stato un riferimento a una famosa citazione del film WarGames: "l'unica mossa vincente è non giocare" . (Joshua è il soprannome del WOPR .)
Arnauld

5

LuckyDiceBot

LuckyDiceBot si fida solo dei suoi dadi. Lancia due dadi, aggiunge la somma al valore attuale dell'offerente e offre così tanto. Se non è abbastanza per vincere l'offerta dell'avversario, taglia le sue perdite e procede per la sua strada.

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
In che modo questo riduce le perdite o ferma le perdite? Se aggiunge sempre il suo tiro di dado all'offerta degli avversari, allora farai sempre di più. La casualità potrebbe confondere un bot sufficientemente analitico, mi piace il concetto.
Freiheit,

Se il tiro è 4 o meno (statisticamente improbabile, ma alla fine accadrà), l'offerta non è sufficiente per battere l'avversario e l'asta termina.
Silvio Mayolo,

Due cose: 1. @Freiheit ha ragione e questo bot continuerà a fare offerte fino a quando non avrà vinto, non importa quanto in alto. opponentsBidnel nextBid(int opponentsBid)detiene il totale delle offerte presentate il tuo avversario ha fatto un'offerta finora, non la sua prossima offerta. Un termine migliore per il metodo sarebbe raise(come il termine Poker) imho. 2. Il tuo bot non morde con incrementi di 5, quindi sta convalidando una delle regole. Se questi problemi vengono risolti, mi piace comunque il concetto, perché i bot analitici non saranno in grado di contrastare e quindi molto probabilmente vincerai abbastanza spesso.
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 fa una fortuna con il suo gioco d'azzardo illegale con LuckyDiceBot. Quindi, naturalmente, quando arriva la polizia (DeterrentBot), deve smaltire rapidamente i suoi guadagni in qualche modo, come ad esempio un'offerta all'asta successiva.


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

Al momento non è possibile verificarlo, quindi per favore fatemi sapere se è rotto.

Ad ogni round, il valore del dollaro aumenta.


Questo sarebbe eccellente contro MirrorBot, MarginalerBot e probabilmente anche MimicBot.
Nissa,

@StephenLeppik Questo è quello che stavo pensando quando l'ho realizzato. Ancora molte debolezze, comunque.

+1, mi piace l'idea. Hmm, è previsto che il tuo bot offra 0 e si rompa anche se inizia un round (quando opponentsBidè ancora 0)?
Kevin Cruijssen,

@KevinCruijssen Sì. Questo può accadere solo contro il primo avversario. Tutti i robot che lo copiano inizieranno da 0, quindi questo non sprecherà più di 5c su di essi.

4

Non concorrente: 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;
        }
    }
}

Questo non è inteso come una vera presentazione, ma piuttosto come una piastra di caldaia che altri possono usare per scoraggiare i robot per tenere animali domestici come MirrorBote MimicBot.

Poiché è il costruttore predefinito, non è necessario chiamarlo nella sottoclasse. Implementa un isPeekingmetodo per determinare se un altro bot sta ficcando il naso.


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

scenari

  • Se l'avversario può iniziare e le offerte <= 0perdono.
  • Se l'avversario può iniziare e fare offerte [5,95]: fai un'offerta da solo. O il tuo avversario si ferma ora, o farà un'offerta superiore a 100 in totale, nel qual caso smetti di fare offerte per fargli vincere e rompere anche te stesso.
  • Se l'avversario può iniziare e fare offerte >= 100: offri 0 te stesso per perdere ma pareggiare.
  • Se puoi iniziare: offri subito 100. O il tuo avversario si ferma ora, o farà un'offerta superiore a 100, nel qual caso smetti di fare offerte per fargli vincere e rompere anche te stesso.

Wow, questo è un bug. Diceva che stavo commentando la domanda, ma è finita qui. Devo trovare un modo per riprodurlo
Stan Strum,

@RamenChef Typo .. Ma ho modificato l'intero bot. Aveva comunque alcuni bug ..
Kevin Cruijssen,

4
Questo può assolutamente perdere denaro. Se offri 100, il tuo avversario offre 105,

@Mnemonic Ah ovviamente .. Non avevo pensato a quella parte .. Hmm .. questo rende le cose più interessanti ma anche più difficili. Modifica la descrizione per ora, ma lascia il bot così com'è.
Kevin Cruijssen,

1
Penso che intendi "perdere", non "perdere". Perdere è l'opposto della vittoria. Loose è l'opposto di 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;
    }

}

Genera un errore invece di un'eccezione per confondere gli analisti.


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

Cerca di valutare l'avversario che deve affrontare e assicurarsi di non mordere più di quanto possa masticare.


1
Benvenuti in 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;
        }
    }
}

messi insieme da parti di altri robot. questo si gioca cercando di essere AnalystBot e, se non ha successo, diventa BorkBorkBot.

Non penso che questo lo farà bene.


Attenzione per il AnalystKiller.
RamenChef,

@RamenChef AFAIK l'analista killer lancia un'eccezione se si vede analizzato. Posso prenderlo
dkudriavtsev il

1
Probabilmente dovresti prenderlo.
RamenChef,

@RamenChef Non ho idea se funzionerà, non posso 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;
  }
}

contatori:

  • DarthVadercontrasta se stesso causando un SecurityExceptionprima dell'inizio dell'offerta, ma ne farò 5 per ogni evenienza.
  • AnalystBot e AnalystOptimizer guarderò entrambi la mia risposta quando pronuncio 95, nel qual caso mostrerò che ho offerto 100, quindi offrirà 95 stesso. Offrirò 5 comunque se inizio (o 100 se hanno iniziato), quindi perdono 95 centesimi e vinco il conto da 1 USD offrendo solo 5 centesimi o andando in pareggio.
  • MirrorBotoffrirò ciò che vorrei offrire contro di esso. Quindi offro solo 5 e chi inizia vince 95 centesimi e l'altro perde 5 centesimi.
  • MarginalBot offrirò 5 se offro meno di 10 (o quello che inizia), altrimenti offrirà 0. Quindi se offro solo 5 quando inizio, o 10 quando inizia, vinco 95 o 90 centesimi, e loro perdono 5 centesimi.
  • GreedyBot fa sempre 5 offerte in più di me, quindi offri solo 0 per pareggiare e lasciare che abbiano la vittoria
  • OnlyWinningMoveed AnalystKillerentrambi offrono sempre 0, quindi basta offrire 5 per vincere
  • TargetValueBot farà un'offerta nell'intervallo [100,200] , quindi fai altre 5 offerte ogni volta fino a quando non saranno a 190, nel qual caso aumenteremo a 200 per pareggiare vincendo il dollaro (e lasciamo perdere 190 o 195 a seconda di chi ha iniziato)
  • BorkBorkBotfarà un'offerta nell'intervallo [5,95], quindi fai anche altre 5 offerte ogni volta. Non appena fanno un'offerta 85 o 90 (a seconda di chi ha iniziato), fai un'offerta 95 tu stesso. Perderanno 85 o 90 centesimi e vincerai la banconota da 1 USD per un profitto di 5 centesimi.
  • DeterrentBot offriranno 5 se iniziano o 100 se iniziamo, quindi basta offrire 105 in modo che contrastino con 100, causando loro di perdere 100 e noi perdiamo solo 5 centesimi vincendo la fattura da 1 USD.
  • BreakEvenAsapoffrirà subito 100. Quindi, se hanno iniziato con la loro offerta di 100, contatta con 105 per vincere 95 centesimi e lascia che perdano 100. Se potessimo iniziare solo l'offerta di 100, entrambi andremo in pareggio.
  • RichJerk offrirà subito 1.001, quindi basta offrire 0 per pareggiare e farli perdere 9.901.
  • DeterredBot non mi conosce e quindi offrirà 0, quindi offri solo 5 per vincere.
  • LuckyDiceBotcontinua a fare offerte finché non vince. Quindi, se abbiamo iniziato, offri 5 nella speranza che puntino il più alto possibile per vincere il dollaro. Se hanno iniziato, offri solo 0 per far loro vincere e rompere anche te stesso.
  • RandBotfarà un'offerta casuale nell'intervallo [5,100], quindi fai solo altre 5 fino a quando non si ferma, nel qual caso hai vinto 95 centesimi e hanno perso 0-100.
  • UpTo200(come dice il nome) farà un'offerta fino a 200. Quindi fai solo 5 in più fino a quando non si fermano. Vinceremo la banconota da 1 USD e subiremo una perdita totale di 105 centesimi, ma perdono comunque 200 centesimi.
  • InsiderTradingBot non mi conosce, quindi offri solo 5 centesimi per vincere
  • MimicBotè stato il più difficile. Basta fare un'offerta 10 per iniziare con o contrastare la loro prima offerta di 5. Se provano ad accedere a me lancerò una RuntimeException (che cattureranno nel qual caso si comporterebbe come se avessi invece offerto 100 - anche se interromperà il interno mentre anello). In base ai nemici che ha nel suo HashSet succede una cosa diversa. Dovrò rivisitare e guardare più da vicino per vedere se c'è un contatore reale.
  • RiskRewardBot non mi conosce, quindi farò solo 5, nel qual caso farò 5 per vincere.
  • MarginalerBotsarà morso fino a 100 a seconda di ciò che vorrei offrire. Se potessi iniziare, offrirò 90, poi offrirà 95, quindi offrirò 100 in modo che offrirà 0 e perderò 95 centesimi, mentre vinco il conto da 1 USD e raggiungo il pareggio. Se invece dovesse iniziare, vedrebbe che avrei offerto 90 contro di esso, quindi offre 90 se stesso, quindi offrirò 95 in modo da fare 0 e perdere 90 centesimi, mentre io vinco la banconota da 1 USD con un profitto di 5 cent.
  • BuzzardBotanalizzerò tutti i miei contatori nell'intervallo [0,100). Se faccio 100subito un'offerta , usaoppFlag = 0 e l'array completo di 100 dimensioni conterrà 100x il valore 100. Nell'interruttore case 0, il loop sarà di [0,100)nuovo nell'intervallo e dato i + 5che al massimo sarà 104, l'if bids[i] < i + 5non sarà mai vero , quindi l'offerta che fa rimane 0.
  • ImprovedAnalystBotavrà sempre this.enemy = nullperché il suo avversario è CounterBot, non se stesso. Quindi offrirà sempre 0, che ho appena contrastato con un'offerta di 5.
  • InflationBot offrirà 0 per andare in pareggio anche quando inizia, altrimenti continuerà a fare offerte 5. Quindi offri 0 noi stessi per andare in pareggio subito e lasciare che abbiano la vittoria.
  • ScoreOverflowBotfaranno un'offerta vicino Integer.MAX_VALUEse possono iniziare, altrimenti faranno un'offerta 105. Quindi, se hanno offerto 105, devi solo offrire 110 noi stessi (perderanno 105, perderemo 10), altrimenti fai solo 0 per consentire loro di vincere.
  • MBotè lo stesso MarginalerBot, ma con una protezione aggiuntiva contro gli avversari "sbirciati". Dal momento che non 'sbirciare', è praticamente lo stesso di MarginalerBot.
  • SecretBot avrà il suo isPeeking() metodo restituirà false, quindi se può iniziare o se offro 5, offrirà 5 o 10 rispettivamente. Altrimenti farà un'offerta 0. Quindi, sia che io inizi o meno, opponentsBid + 5mi farebbe vincere in entrambi i modi, con la mia offerta di 10 centesimi o 15 centesimi, facendoli perdere 5 o 10 centesimi.
  • BluffBotguarderò cosa farei quando la sua offerta è 95, e se questa è maggiore o uguale a 100, offrirà 0 per pareggiare, altrimenti farà un'offerta opponentsBid + 5. Quindi farò solo un'offertaopponentsBid + 5 . Si romperà a prescindere da chi inizia, e io vinco 100 o 95 centesimi a seconda che io abbia iniziato o meno.
  • StackTraceObfuscaterBot agirà come MarginalerBot .
  • EvilBot farà sempre un'offerta 5, quindi fai solo un'offerta opponentsBid + 5 . Ad ogni modo, perderanno quei 5 centesimi e vinceremo l'offerta di 1 USD (o con un'offerta di 5 centesimi se abbiamo iniziato, o un'offerta di 10 centesimi se hanno iniziato).
  • MSlowBotè uguale MBote quindi anche MarginalerBot.

Fammi sapere se vedi errori di battitura o difetti nei miei contatori.


1
MirrorBotchiama newAuction con la tua classe, quindi questo è un problema. Inoltre, felice di sapere che le 3 ore trascorse su MimicBot non sono state vane.
Nissa,

@StephenLeppik Rimosso il codice in newAuctionperché avrebbe fallito il più delle volte .. Non posso contrastare MirrorBotné mi può contrastare. Chi inizia dei due vince 95 centesimi e l'altro perde 5 centesimi.
Kevin Cruijssen,

3
Santo concatenamento ternario, Batman!
Skyler,

1
Inoltre, quando giochi BorkBorkBot, non dovresti rilanciare a 95 quando hanno colpito 85? Altrimenti offrite entrambi 95 se iniziano.
Skyler,

1
@Freiheit Lo so. Ho appena usato un caso aggiuntivo per restituire 0 nel caso volessi cambiare l'impostazione predefinita per qualsiasi motivo. Ma ora li ho messi in default (commentandoli). E so che posso golf tutto un po ', ma non si tratta di creare il codice più breve. Ho appena reso un ternario per renderlo un po 'più compatto, ma questo è tutto. Per ora lo lascerò così.
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;
        }
    }
}

Al momento non è possibile verificarlo, quindi per favore fatemi sapere se è rotto.

L'obiettivo è ottenere il punteggio totale più alto, quindi non preoccuparti di battere nessuno. Prendi semplicemente le vittorie facili e non sprecare soldi per possibili perdite.


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


}

Una spia che conosci è più preziosa di nessuna spia ...

Se qualcun altro prova a chiamare il metodo getBid, BluffBot risponde con $ 100 per indurli a smettere o scommettere molto in alto.

Altrimenti, vedi se è possibile vincere per meno di $ 1 e non fare offerte se non lo è.


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

}

Questo bot fa tentativi minimi di vincere offrendo 5 o 10. Controlla anche la traccia dello stack per vedere se è stato chiamato da un altro Bot e poi mente a loro su quali offerte farà.


Ti dispiace se porto isPeekingdentro AbstractAnalystCounterBot?
Nissa,

1
@StephenLeppik, beh, l'ho rubato da MBot ...
Winston Ewert,

1
Beh, probabilmente MBot me l'ha rubato ...
Nissa,

2

Un extra

import net.ramenchef.dollarauction.DollarBidder;

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

Offerte 6 in più rispetto all'ultima offerta, solo perché lui può.


Non può fare offerte 6 poiché tutte le offerte devono essere multipli di 5 ...
Neil

@Neil è probabilmente un errore di battitura ...
Stan Strum

@Neil le regole specificano esplicitamente: "La tua offerta non deve necessariamente essere un multiplo di 5 ¢"
MegaTom

@MegaTom Huh, bene che è stato aggiunto dall'ultima volta che ho letto le regole ...
Neil

@Neil Faceva parte delle regole originali, ma l'ho aggiunto lì perché non era molto ovvio.
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;
    }
}

Questo robot ride dei tentativi di rilevare la riflessione attraverso la traccia dello stack. La cosa più vicina a una a DollarBidderè una classe lambda che ha creato. Chiaramente non un altro robot che cerca di rifletterli. Non sanno che quella classe lambda sta effettivamente lavorando per a DollarBidder. Oltre a ciò, si comporta come MarginalerBot.


Da allora ho aggiornato il controllo dello stack stack per gestirlo.
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;
}
}

Questo cerca di forzare il bot dell'avversario a pagare in eccesso impostando la cache intera sul valore oltre il limite di $ 100.


2
Il responsabile della sicurezza lo fermerebbe.
Nissa,

2
E questo non funzionerebbe comunque dal momento che in nessun punto del runner si inscatolano i suoi numeri interi.
Nissa,

Anche se questo non si sarebbe fermato, questa è una mossa a scatti, anche se valida. "È consentito sabotare altri robot, ma tentare di alterare la visibilità del campo / metodo comporterà misteriose eccezioni di sicurezza."
NoOneIsHere

1
@StephenLeppik Il punto è rompere cose del genere return opponentsBid <= 195 ? opponentsBid + 5 : 0e farcela return opponentsBid <= 100001 ? opponentsBid + 100001 : 100001.
NoOneIsHere

1
Impossibile compilare a causa di eccezioni non selezionate.
Nissa,

1

ImprovedAnalystBot (Fuori concorso)

Molte persone sembrano utilizzare il AnalystBotcodice come modello, anche se è deliberatamente un codice errato. Quindi sto creando un modello migliore.

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

Perché non modificare semplicemente la tua sfida?
Nathan Merrill,

@NathanMerrill Come lo modificherei?
RamenChef,

Facendo clic sul pulsante Modifica e sostituendo AnalystBot con questo codice?
Nathan Merrill,

@NathanMerrill AnalystBotè un codice volutamente cattivo in modo che possa dimostrare di AnalystKilleraverlo sabotato.
RamenChef,

1
AnalystKiller funziona ancora con quello migliorato :) Il problema nel renderlo un post è che la sfida è molto più visibile di una risposta.
Nathan Merrill,

1

Mbot

import net.ramenchef.dollarauction.DollarBidder;

import java.util.Arrays;

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


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

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

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

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

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

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

MarginalerBot leggermente raffinato

  • sii gentile con coloro che non vogliono controllarti
  • consentire di pagare 100 per ottenere 100 e rompere il caso, solo per negare agli altri soldi facili

Non puoi dichiarare nextBiddi lanciare ClassCastException.
RamenChef,

@RamenChef ok, l'ho scambiato con RuntimeException che non richiede una dichiarazione :)
mleko

Il tuo codice per il controllo della traccia dello stack sembra sospettosamente simile al mio.
Nissa,

@StephenLeppik probabilmente ne è una copia
mleko il

@mleko perché però? La classe da cui è copiata è una superclasse astratta che è gratuita da usare.
Nissa,

1

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

Stessa logica di MBot, basta usare il timeout invece dell'eccezione quando si combatte contro il nemico. Finora nessuno sta difendendo il timeout, quindi dovrebbe essere efficace


Le regole dichiarate vietano deliberatamente il timeout di un altro bot.
Winston Ewert,

@WinstonEwert puoi citare? Non riesco a trovare una regola che non lo
autorizzi

"Il sabotaggio di altri robot è consentito, ma il tentativo di modificare la visibilità del campo / metodo comporterà misteriose eccezioni di sicurezza. Un'eccezione sta facendo sì che un altro bot superi il limite di 500 ms." Inoltre, mi sto difendendo dal timeout.
RamenChef,

@RamenChef ma questo non altera la visibilità di altri elementi. Non sono sicuro di averti capito correttamente. È consentito il timeout provocatorio?
mleko,

"Un'eccezione sta facendo sì che un altro bot rompa il limite di 500ms." In particolare, questa è un'eccezione alla regola del sabotaggio.
RamenChef,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.