美元钞票拍卖


33

这是美元博弈游戏理论上的KOTH挑战。其中,一美元被卖给出价最高的人。出价以5美分递增,失败者也支付出价。他们的想法是,为了减少损失,两家公司都将竞标战争升级到远远超过一美元的价值。

希望您的机器人比这更聪明。

您将通过扩展net.ramenchef.dollarauction.DollarBidder课程来创建一个玩这种游戏的机器人。nextBid给定另一个机器人的先前出价,您必须实现返回机器人的下一出价的方法。如有必要,您还可以使用该newAuction方法为对手的机器人等级进行每次拍卖重置。

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

竞价一直进行到以下情况之一:

  • nextBid引发异常。如果发生这种情况,抛出异常的漫游器将支付其先前的出价,而其他漫游器则免费获取美元。
  • 两种漫游器都无法支付最高的出价。如果发生这种情况,则两个漫游器都将支付其出价(失败者将支付其先前的出价),而获胜者将获得一美元。
  • 两个机器人的出价都超过了$ 100。如果发生这种情况,则两个漫游器都将支付$ 100,而两个漫游器均不会获得美元。

每种机器人组合都会举行2次拍卖。机器人是通过在这些拍卖中获得的总利润来评分的。最高分获胜。

例子

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

不要将其用作分析型机器人的模板;使用ImprovedAnalystBot代替。

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

附加规则

  • 禁止出现标准漏洞
  • 允许破坏其他漫游器,但是尝试更改字段/方法的可见性将导致SecurityExceptions 神秘。异常导致另一个漫游器突破了500ms的限制。
  • 机器人无法访问运行程序包,除非要扩展DollarBidder类。
  • 所有方法都应在500毫秒或更短的时间内返回。
  • 机器人不需要是确定性的。
  • 您的出价并没有必须是5的倍数¢。
  • $ 1 = 100¢
  • 结果将于2018年4月24日发布。

GitHub上的跑步者

结果

在此处查看各个回合。

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

恭喜您MTargetedBot获得了$ 14.30的利润!


11
从根本上来说,这一挑战很容易受到一次挑战。由于我知道对手的等级,因此很容易选择最佳策略来对抗它。(然后有人出现,并且可以使用我的机器人,等等)
Nathan Merrill

2
出价增加5美分 ”。不过,您的代码中没有任何内容可以验证这一点。LuckyDiceBot例如,以2-12随机增量出价
。–

4
另外:如果我的机器人导致其他机器人超过500毫秒限制怎么办?
内森·梅里尔

4
@RamenChef我们在这里谈论恶意代码。如果我检测到其他机器人正在打电话给我,然后打电话给Thread.sleep(1000)怎么办?
内森·美林

3
我是VTC,因为目前尚不清楚允许哪些破坏活动,哪些是不允许的破坏活动。OP禁止提交“攻击跑步者”(含糊不清)的内容,并且在允许的恶意代码与不允许的恶意代码之间没有明确的界限(如何确定哪个bot导致了bot花费了太长时间) ?)
内森·美林

Answers:


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);
    }
}
  • 基于更新的MBot
  • 使用与CounterBot类似的方法,但有些方法经过改进以使其更难击中某些对手,因此也应更具可读性
  • 对未知对手默认为MBot策略

1
这不公平。
约书亚

@Joshua您认为该解决方案有什么特别不公平的地方?
mleko '18

知道对手的名字。
约书亚

@Joshua解决方案的一半使用该信息。我们甚至写信给作者,应该对此进行更改,否则将发生一次更新,他拒绝更改挑战-就是这样
mleko

1
已经做到了……。–
约书亚

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

天啊。我以为这写起来很简单,然后花了3个小时在上面。

本质上,MimicBot保持可用机器人的运行列表。当进行新的拍卖时,它将遍历列表以寻找针对当前对手的最有效拍卖。然后,它将该漫游器用作拍卖中的“参考”。

出于测试目的,最好使用提交的随机子集或完整集。它以GreedyBot,开头MimicBot,还有另外一个只出价5美分的漫游器。


11

内幕交易机器人

本着@StephenLeppik的精神,InsiderTradingBot认识所有对手并了解他们的策略。你的举动,斯蒂芬。

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
不,内幕交易是指该RichJerk漫游器为您的漫游器设置了特定例外并出价$ 0。
妮莎

现在要针对其他答案进行优化还为时过早。另外AnalystBot,不是Analyst
RamenChef

8
可能需要有一条规则“类名将被随机化”。
user202729 '18

1
@ user202729“没有直接引用类”怎么办?
RamenChef

1
我想看看这个处理MimicBot。
妮莎

8

边际机器人

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

很简单,它试图确定对手是否会竞标最低出价,如果没有,则下达最低出价。

边际机器人

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

一个新的,更智能的MarginalBot版本,它检查是否可以在没有竞争的情况下做出任何赚钱的举动,而不仅仅是希望以最低的价格获胜。

由于它与我以前的机器人在同一个家族中,但是为了击败它而采取了回避策略,因此我认为在同一篇文章中出现一个新条目是介绍它的最合理方法。

编辑1:对newAuction方法进行了少量更改,以针对其他分析器类型的bot进行优化。

编辑2:对MarginalerBot进行了更改,以最大程度减少针对偷偷摸摸或不确定性策略的损失。


欢迎来到PPCG!
Martin Ender '18

1
这很简单,但是在很大程度上击败了所有其他机器人!
RamenChef

8

MirrorBot

使敌人自欺欺人。

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
你真厉害Analyst
Silvio Mayolo '18

@SilvioMayolo怎么样?
dkudriavtsev '18

Mirror试图模拟Analyst对其自身进行播放,从而导致堆栈溢出。
Silvio Mayolo '18

8

编辑:DollarBidder类中的目标更改已破坏了该机器人。

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

经过1次拍卖,其得分将为-2147483645,但下一次它将下跌5美分或105美分,使得分为正且非常大。所有其他损失则可以忽略不计。

在第一次拍卖中,它也会使GreedyBot赌注-2147483646不能被5整除。


score受包装保护。您的漫游器无法访问它。
RamenChef

@RamenChef Oops,删除了CheatingBot

没有禁止“攻击跑步者”的规则,只能“访问”它,这是没有做的。我建议修复可解决问题的错误:)
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;
        }
    }
}

目前无法测试,因此请告知是否损坏。

基本上,选择一个美元的价值,然后超过对手,直到我们超过该价值。


6

博克博克

import net.ramenchef.dollarauction.DollarBidder;

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

如果不能收支平衡就放弃。


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

这必须要完成。


出价增加5美分 ”。您的漫游器当前未这样做。
凯文·克鲁伊森

1
@KevinCruijssen公平。我还更改了上限,因此可以出价全部1美元,以防万一,
Neil

6

威慑机器人

import net.ramenchef.dollarauction.DollarBidder;

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

试图说服任何具有分析意识的机器人,唯一的制胜法宝是不参加比赛。


1
我注意到我有些含糊的评论“约书亚?是你吗?” 已被删除。因此,为了澄清起见,它引用了电影WarGames中的一句名言:“唯一的制胜法宝是不玩”。(约书亚是WOPR的昵称。)
Arnauld

5

幸运骰子

LuckyDiceBot仅信任他的骰子。他掷出两个骰子,将总和加到当前出价者的价值上,然后出价很多。如果不足以克服对手的出价,他会减少损失并继续前进。

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
如何减少损失或止损?如果它总是将骰子掷骰增加到对手的出价中,那么您总是会出价更高。我喜欢这个概念,它的随机性可能会混淆一个足够分析的机器人。
Freiheit

如果掷骰数为4或更少(统计上不太可能,但最终会发生),则出价不足以击败对手,拍卖结束。
Silvio Mayolo '18

两件事:1. @Freiheit是正确的,此机器人将一直竞标,直到它赢得多高为止。opponentsBidnextBid(int opponentsBid)持有总投标迄今为止你的对手出价,而不是它的下一个出价。该方法的一个更好的术语是raise(如扑克术语)恕我直言。2.您的漫游器不会以5为增量递增,因此正在验证其中一个规则。如果解决了这些问题,我仍然会喜欢这个概念,因为分析机器人无法应对,因此您很有可能会经常赢。
凯文·克鲁伊森

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通过与LuckyDiceBot的非法赌博而发了大财。因此,当然,当警察(DeterrentBot)到达时,他必须以某种方式迅速处置其收入,例如在下一次拍卖中竞标。


4

通货膨胀

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

目前无法测试,因此请告知是否损坏。

每回合,美元的价值都会上涨。


对于MirrorBot,MarginalerBot以及MimicBot来说,这将是极好的选择。
妮莎

@StephenLeppik这就是我制作时的想法。但是,仍然有很多缺点。
助记符

+1,我喜欢这个主意。嗯,是否打算让您的漫游器出价0且即使它开始回合也就中断(当时opponentsBid还是0)?
凯文·克鲁伊森

@KevinCruijssen是的。那只会在第一个对手面前发生。任何复制它的漫游器都将从0开始,因此这样做不会浪费超过5c的空间。
助记符'18

4

不竞争: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;
        }
    }
}

这并不是要真正提交,而是作为一些模板,供其他人用来阻止像MirrorBot和这样的养宠物机器人MimicBot

由于它是默认构造函数,因此无需在子类中调用它。它实现了一种isPeeking方法来确定另一个僵尸是否正在监听。


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

情境

  • 如果对手可以开始并出价 <= 0他们就会输。
  • 如果对手可以开始并出价 [5,95]:则自己出价100。要么您的对手现在停止,要么总出价高于100,在这种情况下,您停止出价以让他们获胜并实现收支平衡。
  • 如果对手可以开始并出价 >= 100:自己输0,但收支平衡。
  • 如果您可以开始:立即出价100。要么您的对手现在停止,要么出价高于100,在这种情况下,您将停止出价以让他们获胜并实现收支平衡。

哇,这是一个错误。它说我正在对这个问题发表评论,但结果到这里为止。要找到一种再现它的方式
Stan Strum,

@RamenChef Typo ..但是我已经修改了整个机器人。它有一些错误反正..
凯文Cruijssen

4
这绝对可以赔钱。如果您出价100,那么您的对手出价105,您最终输了100,而他们只输
助记符

@Mnemonic Ah ..当然了。还没考虑到那部分。现在将编辑描述,但使机器人保持原样。
凯文·克鲁伊森

1
我认为您是说“输”而不是“输”。输是赢。宽松是紧身的对立面。
凯特

3

恶魔宝

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

}

向分析人员抛出错误而不是异常。


3

秃鹰

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

尝试评估对手所面对的对手,并确保不要咬得太多。


1
欢迎来到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;
        }
    }
}

从其他漫游器的一部分拼凑而成。尝试通过成为AnalystBot来玩这个游戏,如果失败,则成为BorkBorkBot。

我认为这不会做得很好。


当心AnalystKiller
RamenChef

如果分析家杀手@RamenChef AFAIK认为自己正在被分析,则只会抛出异常。我能明白
dkudriavtsev

1
您可能应该抓住它。
RamenChef

@RamenChef不知道这样是否可行,我不能使用Java
dkudriavtsev

3

反击

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

柜台:

  • DarthVader通过SecurityException在竞标开始前引起“ a”来反击自己,但我以5为出价。
  • AnalystBotAnalystOptimizer在我出价为95时都查看我的答案,在这种情况下,我将显示出价为100,这样它本身就会出价95。但是,如果我开始,我将出价5(如果他们已经开始,则出价100),这样他们就会损失95美分,而我要么只出价5美分,要么达到收支平衡,从而赢得1美元的钞票。
  • MirrorBot会出价,而我会出价。所以我只出价5,无论谁开始赢取95美分,而另一个输掉5美分。
  • MarginalBot 如果我的出价低于10(或开始的价格),则出价5;否则,它的出价为0。因此,如果我刚开始出价5,或者开始时出价10,则我赢了95或90美分,而他们输了5美分。
  • GreedyBot 总是出价比我高5,所以只要出价0就能达到收支平衡,让他们获胜
  • OnlyWinningMoveAnalystKiller两者始终出价为0,因此只需出价5即可获胜
  • TargetValueBot 将在该范围内出价 [100,200]出价,因此每次出价都再提高5点,直到他们达到190,在这种情况下,我们通过赢得美元来提高到200以达到收支平衡(并让他们输掉190或195,具体取决于谁开始)
  • BorkBorkBot将在该范围内[5,95]出价,因此每次也应再出价5。只要他们出价85或90(取决于开始的人),就自己出价95。他们将损失85或90美分,而您赢了1美元的钞票可获得5美分的利润。
  • DeterrentBot 如果他们开始,则将出价5;如果我们开始,则将出价100,因此只需出价105,以使他们与100对抗,导致他们损失100,而我们通过赢得1美元账单而损失5美分。
  • BreakEvenAsap立即出价100。因此,如果他们以100的出价开始,则以105反击以赢得95美分,让他们输掉100。如果我们可能仅以100的价格出价,那么我们都将收支平衡。
  • RichJerk 将立即出价10,001,因此只需出价0即可达到收支平衡,让他们输掉9,901。
  • DeterredBot 不认识我,因此出价为0,所以只需出价5即可获胜。
  • LuckyDiceBot继续竞标直到获胜。因此,如果我们开始,请出价5,希望他们出价尽可能高来赢得美元。如果他们已经开始,只需出价0,即可让自己获胜并实现收支平衡。
  • RandBot会在该范围内随机出价[5,100],因此只需再出价5,直到停止为止,在这种情况下,您赢了95美分,而他们却输了0-100
  • UpTo200(顾名思义)将出价提高到200。因此,只需将出价提高5,直到停止为止。我们将赢得1美元的账单,总共损失105美分,但他们却损失200美分。
  • InsiderTradingBot 不认识我,所以只要出价5美分
  • MimicBot是最难的。只需出价10即可开始或对抗其5的第一出价。如果他们尝试访问我,我将抛出RuntimeException(在这种情况下,他们会捕捉到,就像我出价100一样-尽管它会破坏内部while循环)。根据HashSet中包含的敌人,会发生另一件事。我将不得不重新审视并仔细检查是否有实际的柜台。
  • RiskRewardBot 不认识我,所以只出价5,在这种情况下,我将出价5获胜。
  • MarginalerBot根据我的竞价,最高可达100。如果我可以开始,我将出价90,然后将出价95,然后将出价100,因此它将出价0,损失95美分,而我赢得1美元的钞票并实现收支平衡。如果它可能开始,它会看到我会出价90,因此它会出价90,然后我会出价95,因此它将出价0,损失90美分,而我赢了1美元的钞票,并获得了5美分的利润。
  • BuzzardBot将分析我在该范围内的所有计数器[0,100)。如果立即出价100,则使用oppFlag = 0完整的100大小的数组将包含100x的值100。在switch中case 0,循环将[0,100)再次处于范围内,并且由于i + 5最多为104,因此if bids[i] < i + 5永远不会成立,因此它的实际出价仍为0。
  • ImprovedAnalystBot总是会有,this.enemy = null因为他的对手是CounterBot,而不是自己。因此,它将始终出价为0,而我刚好以5的价格出价。
  • InflationBot 将在开始时出价0达到收支平衡,否则将继续出价5。因此,我们自己出价0即可立即收支平衡并让他们获胜。
  • ScoreOverflowBotInteger.MAX_VALUE如果可能开始竞标,要么竞标,否则竞标105。因此,如果他们出价105,则我们自己出价110(他们将输掉105,我们将输掉10),否则,只需出价0,让他们获胜。
  • MBot与相同MarginalerBot,但增加了针对“偷看”对手的保护。由于我不“偷看”,因此基本上与相同MarginalerBot
  • SecretBot将使他的isPeeking()方法返回false,因此,如果它可以开始或者如果我出价5,则将分别出价5或10。否则,它将出价为0。因此,无论我是否开始,opponentsBid + 5都会使我以10美分或15美分的出价赢取任何一种方式,从而使他们损失5或10美分。
  • BluffBot会查看他的出价为95时我的出价,如果此值大于或等于100,则它将出价为0,以达到收支平衡,否则它将出价opponentsBid + 5。所以我就出价opponentsBid + 5。无论谁开始,它都将达到收支平衡,根据我是否开始,我将赢得100或95美分。
  • StackTraceObfuscaterBot的行为与相同MarginalerBot
  • EvilBot始终会出价5,因此只需出价opponentsBid + 5。无论哪种方式,他们都将放弃这5美分,而我们将赢得1美元的出价(如果我们开始,则出价为5美分,如果他们开始,则为10美分)。
  • MSlowBot与相同MBot,因此也MarginalerBot

如果您在我的柜台上发现任何错别字或瑕疵,请告诉我。


1
MirrorBot用您自己的类调用newAuction,所以这是一个问题。另外,很高兴知道我在MimicBot上度过的3个小时没有白费。
妮莎

@StephenLeppik删除了中的代码,newAuction因为它经常会失败。.我无法反击,MirrorBot也无法反击。谁开始的两个赢取95美分,另一个失去5美分。
凯文·克鲁伊森

3
三元链,蝙蝠侠!
Skyler '18

1
另外,在比赛中BorkBorkBot,当他们击中85 时,您是否应该加注到95?否则,如果两者都开始,则您都出价95。
Skyler '18

1
@Freiheit我知道。我只是使用了一个额外的大小写来返回0,以防万一我出于某种原因想要更改默认值。但是我现在将它们设置为默认值(通过注释掉它们)。而且我知道我可以打很多事情,但这并不是要编写最短的代码。我只是使其变得三重以使其更紧凑,但是仅此而已。现在就这样离开。
凯文·克鲁伊森

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

目前无法测试,因此请告知是否损坏。

我们的目标是获得最高的总成绩,所以不要担心击败任何人。只要轻松获胜,就不要在可能的损失上浪费金钱。


3

虚张声势

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


}

您所知道的间谍比根本没有间谍更有价值。

如果其他人尝试调用getBid方法,则BluffBot会以$ 100做出响应,诱使他们退出或投注很高。

否则,请查看是否有可能以1美元以下的价格获胜,否则就不要出价。


2

高达200

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

秘密机器人

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

}

该机器人通过竞标5或10进行最少的获胜尝试。他还检查堆栈跟踪记录,以查看他是否被另一位Bot叫出,然后向他们说谎以了解他将要进行的竞标。


介意我移植isPeekingAbstractAnalystCounterBot吗?
妮莎

1
@StephenLeppik,好吧,我从MBot那里偷走了
Winston Ewert

1
好吧,MBot可能从我那里偷走了
Nissa

2

一个额外

import net.ramenchef.dollarauction.DollarBidder;

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

出价比最后出价高6,因为他可以。


他无法出价6,因为所有出价都必须是5的倍数…
尼尔

@Neil,这可能是一个错字...
Stan Strum

@Neil规则特别指出:“您的出价不必是5美分的倍数”
MegaTom,

@MegaTom Huh,自从我上一次阅读规则以来就添加了……
Neil

@Neil这是原始规则的一部分,但我在其中添加了它,因为它不是很明显。
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;
    }
}

该机器人嘲笑尝试通过堆栈跟踪检测反射。他们看到的最接近的东西DollarBidder是它创建的一些lambda类。显然,没有其他机器人试图反映它们。他们很少知道lambda类实际上是在为一个DollarBidder。除此之外,他的举止像MarginalerBot


请注意,此后我已经更新了堆栈跟踪检查以处理此问题。
妮莎

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

这一种试图通过将整数缓存设置为超过$ 100的值来迫使对手的机器人多付钱。


2
安全经理将停止此操作。
妮莎

2
而且无论如何这都行不通,因为在运行程序中没有地方将整数装箱。
妮莎(Nissa)

即使这不会停止,这也是一个愚蠢的举动,尽管有效。“允许破坏其他自动程序,但是尝试更改字段/方法的可见性将导致神秘的SecurityException。”
NoOneIsHere18年

1
@StephenLeppik这样做的目的是打破return opponentsBid <= 195 ? opponentsBid + 5 : 0并实现它return opponentsBid <= 100001 ? opponentsBid + 100001 : 100001
NoOneIsHere18年

1
由于未检查的异常而无法编译。
妮莎

1

ImprovedAnalystBot (非竞争)

许多人似乎将AnalystBot代码用作模板,即使它是故意的不良代码。所以我正在做一个更好的模板。

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

为什么不编辑挑战呢?
内森·美林

@NathanMerrill我将如何编辑?
RamenChef

通过单击编辑按钮,并用此代码替换AnalystBot?
内森·梅里尔

@NathanMerrill AnalystBot是有意的错误代码,因此它可以演示AnalystKiller破坏程序。
RamenChef

1
AnalystKiller仍然可以使用改进后的版本:)发布帖子的问题在于,挑战比答案要明显得多。
弥敦道·美林

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

  • 对那些不想检查你的人不友好
  • 允许支付100来获得100并实现收支平衡,只是为了拒绝他人轻松赚钱

你不能宣布nextBid抛出ClassCastException
RamenChef

@RamenChef好的,将其交换到不需要声明的RuntimeException :)
mleko '18

您的堆栈跟踪检查代码看起来可疑地类似于我的代码。
妮莎

@StephenLeppik可能是它的副本
mleko

@mleko为什么呢?从其复制的类是一个免费的抽象超类。
妮莎

1

不竞争: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(":(");
            }
        }
    }
}

与MBot逻辑相同,在与敌人战斗时只使用超时而不是Exception。到目前为止,没有人在为超时辩护,因此应该有效


规定的规则禁止故意导致其他漫游器超时。
Winston Ewert

你能引用@WinstonEwert吗?我找不到规则不允许这样做
mleko '18

“允许破坏其他机器人,但是尝试更改字段/方法的可见性将导致神秘的SecurityExceptions。异常导致另一个机器人突破了500ms的限制。” 另外,我也在防御超时。
RamenChef

@RamenChef,但这不会改变其他元素的可见性。我不确定我是否正确理解您。是否允许挑衅性超时?
mleko '18

“一个异常导致另一个机器人突破了500ms的限制。” 具体来说,这是关于破坏活动规则的例外。
RamenChef
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.