달러 지폐 경매


33

이것은 게임 이론에서 달러 지폐 경매 게임에 대한 KOTH 도전입니다 . 그것에서, 달러는 최고 입찰자에게 판매되고 있습니다. 입찰가는 5 ¢ 단위로 올라가고 패자는 입찰을합니다. 아이디어는 두 선수 모두 손실을 줄이기 위해 1 달러 이상의 가치로 입찰 전쟁을 확대하는 것입니다.

봇이 그보다 똑똑해지기를 바랍니다.

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예외가 발생합니다. 이 경우 예외를 발생시킨 봇은 이전 입찰을 지불하고 다른 봇은 무료로 달러를받습니다.
  • 봇은 이전 입찰가보다 높은 금액을 지불하지 않습니다. 이 경우 두 봇 모두 입찰에 참여하고 (패자가 이전 입찰에 지불) 승자는 1 달러를받습니다.
  • 두 봇 모두 $ 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;
    }
}

추가 규칙

  • 표준 허점 은 금지되어 있습니다.
  • 다른 봇을 방해하는 것은 허용되지만 필드 / 방법 가시성을 변경하려고 시도하면 신비로운 결과를 초래할 수 있습니다 SecurityException. 예외로 인해 다른 봇이 500ms 제한을 위반합니다.
  • 봇은 DollarBidder클래스 를 확장하지 않으면 러너 패키지에 액세스 할 수 없습니다 .
  • 모든 방법은 500ms 이하로 반환해야합니다.
  • 봇은 결정론적일 필요는 없습니다.
  • 입찰가는 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
이 과제는 근본적으로 One-Upping에 취약합니다. 상대방의 직업을 알고 있기 때문에 이에 대한 최고의 전략을 쉽게 선택할 수 있습니다. (그런 다음 누군가가 와서 내 봇 등을 올릴 수 있습니다 )
Nathan Merrill

2
" 입찰가는 5 ¢ 씩 증가 합니다." LuckyDiceBot예를 들어 2-12무작위로 증분하여 입찰하는 등 코드를 검증 할 수있는 코드가 없습니다 .
Kevin Cruijssen

4
또한 : 내 봇으로 인해 다른 봇이 500ms 제한을 초과하면 어떻게됩니까?
Nathan Merrill

4
@RamenChef 여기서 악성 코드에 대해 이야기하고 있습니다. 다른 봇이 언제 전화를 걸고 Thread.sleep (1000)을 호출하면 어떻게됩니까?
Nathan Merrill

3
어떤 방해 행위가 허용되고 무엇이 허용되지 않는지 명확하지 않기 때문에 VTC입니다. OP는 "주자를 공격하는"(모호한) 제출을 허용하지 않았으며 허용되는 악성 코드와 허용되지 않는 악성 코드 사이에 명확한 선이 없습니다 (봇이 너무 오래 걸리는 봇을 어떻게 결정합니까? ?)
Nathan Merrill

답변:


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 strat

1
이건 불공평 해
Joshua

@Joshua 귀하의 의견으로는이 솔루션에 대해 특히 불공평 한 것은 무엇입니까?
mleko

상대방의 이름을 아는 것.
Joshua

솔루션의 @Joshua 절반이 해당 정보를 사용합니다. 그래서 여기있다 - 우리는 심지어이 변경해야하거나 한 흐름이 완만이 발생할 것이라고 저자에게 쓴 그는 도전을 변경하는 것을 거부
mleko

1
이미 ..
Joshua

15

모방 봇

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,로 시작하고 MimicBot5 ¢ 만 입찰하는 봇이 하나 더 있습니다.


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를 입찰 한 경우입니다.
Nissa

다른 답변에 대해 최적화하기에는 너무 이릅니다. 또한 AnalystBot그렇지 않습니다 Analyst.
RamenChef

8
아마도 "클래스 이름은 무작위 화 될 것"이라는 규칙이 필요할 것입니다.
user202729

1
@ user202729 "클래스에 대한 직접적인 참조는 없습니까?"
RamenChef

1
이 핸들이 MimicBot을 처리하고 싶습니다.
Nissa

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

아주 간단하지만 상대방이 최소 입찰에 이의를 제기할지 여부를 결정하려고 시도합니다.

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

MarginalBot의 새롭고 더 스마트 한 버전으로, 최소한의 승리를 기대하기보다는 경쟁없이 돈을 벌 수 있는지 확인합니다.

이전 봇과 같은 가족에 있었지만 그것을 극복하려는 회피 전략이 있었기 때문에 같은 게시물에 새로운 항목이 그것을 제시하는 가장 합리적인 방법이라고 생각했습니다.

편집 1 : 다른 분석기 유형 봇에 대해 최적화하기 위해 newAuction 방법을 약간 변경했습니다.

편집 2 : 몰래 또는 비 결정적 전략에 대한 손실을 최소화하기 위해 MarginalerBot를 변경했습니다.


PPCG에 오신 것을 환영합니다!
Martin Ender

1
간단하지만 다른 모든 봇보다 상당히 큰 차이가 있습니다!
RamenChef

8

미러 봇

적을 스스로 상대하게 만듭니다.

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

@SilvioMayolo 어떻게?
dkudriavtsev

미러는 Analyst가 자신에 대해 재생하는 것을 모방하려고 시도하여 스택 오버플로를 일으 킵니다.
Silvio Mayolo

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

한 번의 경매 후에는 점수가 -2147483645가되지만 다음에 5 ¢ 또는 105 ¢를 잃으면 점수가 긍정적이고 매우 커집니다. 다른 모든 손실은 무시할 수 있습니다.

첫 번째 경매에서는 GreedyBot을 -2147483646으로 내기하여 5로 나눌 수 없습니다.


score패키지로 보호됩니다. 봇이 액세스 할 수 없습니다.
RamenChef

@RamenChef Oops, CheatingBot
Winter를

"주자 공격"에 대한 규칙은 없으며, "접근"만 할 수 있습니다. 문제를 해결하는 버그를 수정하는 것이 좋습니다.)
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

BorkBorkBot

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 ¢ 씩 증가 합니다." 봇은 현재 그렇게하지 않습니다.
Kevin Cruijssen

1
@KevinCruijssen 박람회 충분합니다. 또한 만일을 대비하여 상한을 1 달러 전체로 입찰 할 수 있도록 상한을 변경했습니다.
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;
    }
}

분석적으로 생각하는 봇을 설득하려고한다면 유일한 승리는 움직이지 않는 것입니다.


1
나는 다소 비밀스러운 의견 "여호수아? 그게 너야 ?" 삭제되었습니다. 따라서 명확히하기 위해 영화 WarGames의 유명한 인용문 인 "유일한 승리의 움직임은하지 않는 것"에 대한 언급 이었습니다. (Joshua는 WOPR 의 닉네임입니다 .)
Arnauld

5

LuckyDiceBot

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

두 가지 : 1. @Freiheit가 옳으며이 봇은 아무리 높아도 이길 때까지 계속 입찰합니다. opponentsBid에서 nextBid(int opponentsBid)다음 입찰이 아니라 상대방이 지금까지 입찰 한 총 입찰가 를 보유합니다. 이 방법에 대한 더 좋은 용어는 raise(포커 용어로) imho입니다. 2. 봇은 5 씩 증가하지 않으므로 규칙 중 하나를 확인합니다. 이러한 문제가 해결되면 분석 봇이 대응할 수 없기 때문에 여전히 개념을 좋아합니다.
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는 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에 비해 우수합니다.
Nissa

@StephenLeppik 그것이 제가 생각했을 때의 생각입니다. 그래도 여전히 많은 약점.
니모닉

+1, 나는 그 아이디어를 좋아한다. 흠, 봇은 0을 입찰하고 라운드가 시작 되더라도 중단됩니다 ( opponentsBid아직 0 일 때 )?
Kevin Cruijssen

@KevinCruijssen 예. 그것은 첫 번째 상대에 대해서만 발생할 수 있습니다. 그것을 복사하는 모든 봇은 0에서 시작하므로 5c 이상을 낭비하지 않습니다.
니모닉

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 : 0을 잃고조차 부수십시오.
  • 시작하는 경우 : 즉시 100을 입찰하십시오. 상대방이 지금 멈췄거나 100 이상으로 입찰 할 것입니다.이 경우 입찰을 중단하여 승리를 거두고 자신을 깰 수도 있습니다.

와우, 그건 버그 야 그것은 내가 그 질문에 대해 언급하고 있다고 말했지만 결국 끝났습니다. 그것을 재현하는 방법을 찾아야합니다
Stan Strum

@RamenChef Typo ..하지만 전체 봇을 수정했습니다. 어쨌든 약간의 버그가 있었다 ..
Kevin Cruijssen

4
이것은 절대적으로 돈을 잃을 수 있습니다. 100을 입찰하면 상대가 105를 입찰하면 결국 100을 잃고 5 만 잃습니다.
Mnemonic

@Mnemonic Ah 물론 .. 그 부분에 대해 생각하지 않았습니다. 지금은 설명을 편집하지만 봇은 그대로 둡니다.
Kevin Cruijssen

1
"느슨한"이 아니라 "느슨한"을 의미한다고 생각합니다. 패배는 승리의 반대입니다. 루스는 타이트의 반대입니다.
Kat

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

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

상대편을 평가하고 씹을 수있는 것 이상으로 물지 않도록하십시오.


1
PPCG에 오신 것을 환영합니다!
Alion

3

애널리스트

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

카운터 :

  • DarthVaderSecurityException입찰이 시작되기 전에을 발생시켜 자체적으로 이의 를 제기하지만 경우에 따라 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을 입찰하여 짝수를 나누고 승리하도록하십시오.
  • OnlyWinningMove그리고 AnalystKiller모두는 항상 그래서 그냥 승리 (5) 입찰, 0 입찰
  • TargetValueBot 범위 내에서 입찰합니다 [100,200] 에서 입찰 할 것이므로 190에 도달 할 때까지 5 번 더 입찰하십시오.이 경우 달러로이기더라도 중단하려면 200으로 올립니다 (시작한 사람에 따라 190 또는 195를 잃게됩니다)
  • BorkBorkBot범위 내 [5,95]에서 입찰하므로 매번 5 번 더 입찰하십시오. 그들이 시작한 사람에 따라 85 또는 90을 입찰하자마자 95를 입찰하십시오. 그들은 85 또는 90 센트를 잃을 것이고, 당신은 5 센트 이익을 위해 1 달러 법안을 이깁니다.
  • DeterrentBot 그들이 시작하면 5, 우리가 시작하면 100을 입찰하므로 105를 입찰하면 100과 카운터하여 100을 잃고 1 달러짜리 지폐를 얻음으로써 5 센트를 잃게됩니다.
  • BreakEvenAsap100을 즉시 입찰합니다. 만약 그들이 100의 입찰로 시작했다면, 105와 맞서 95 센트를 이기고 100을 잃게하십시오. 만약 우리가 단지 100을 입찰하기 시작하면 우리는 둘 다 깨집니다.
  • RichJerk 즉시 10,001의 입찰가가 책정되므로 0을 입찰하여 짝수를 나누고 9,901을 잃게하십시오.
  • DeterredBot 저를 모르고 따라서 0을 입찰 할 것이므로 5를이기십시오.
  • LuckyDiceBot이길 때까지 계속 입찰합니다. 우리가 시작했다면, 그들이 5 달러를 벌기 위해 가능한 한 높게 입찰하기를 희망하면서 5를 입찰하십시오. 그들이 시작했다면 그냥 0을 입찰하여 그들이 승리하고 자신을 깨뜨릴 수있게하십시오.
  • RandBot범위 내에서 무작위로 입찰 [5,100]하므로 중단 될 때까지 5 번 더 입찰하면이 경우 95 센트를 얻었고 잃었습니다 0-100.
  • UpTo200이름에서 알 수 있듯이 최대 200 개까지 입찰합니다. 따라서 중지 될 때까지 5 개 더 높게 입찰하십시오. 우리는 1 달러짜리 지폐를 이기고 총 105 센트의 손실을 입지 만 200 센트를 잃습니다.
  • InsiderTradingBot 나도 몰라, 그냥이기려면 5 센트를 입찰
  • MimicBot가장 힘들었다. 첫 입찰 5로 시작하거나 카운터하기 위해 10을 입찰하면됩니다. 그들이 내게 접근하려고하면 RuntimeException을 던질 것입니다. 내부 while 루프). HashSet에있는 적을 기반으로 다른 일이 발생합니다. 실제 카운터가 있는지 다시 살펴보고 더 자세히 살펴 봐야합니다.
  • RiskRewardBot 나도 몰라 5 만 입찰 할 것이고이 경우 5를 이길 것입니다.
  • MarginalerBot내가 입찰 할 대상에 따라 최대 100을 비트합니다. 시작하면 90을 입찰하고 95를 입찰 한 다음 100을 입찰하여 0을 입찰하고 95 센트를 잃게됩니다. 대신 시작하면 90으로 입찰하고 90 자체를 입찰 한 다음 95로 입찰하여 0으로 입찰하고 90 센트를 잃는 반면 5 달러 수익으로 1 달러 지폐를 얻습니다.
  • BuzzardBot범위 내 모든 카운터를 분석합니다 [0,100). 내가 100즉시 입찰 하면 사용 oppFlag = 0하고 100 크기의 완전한 배열은 100의 100 값을 포함합니다. 스위치 case 0에서 루프는 [0,100)다시 범위에 i + 5있으며 최대 104이므로 if bids[i] < i + 5는 사실이 아닙니다. 입찰가는 0으로 유지됩니다.
  • ImprovedAnalystBotthis.enemy = null그의 상대는 CounterBot그 자체 가 아니기 때문에 항상 가질 것입니다. 따라서 항상 입찰가가 0이며, 입찰가는 5입니다.
  • InflationBot 시작될 때도 깨지려면 0을 입찰하고, 그렇지 않으면 입찰 5를 유지합니다. 따라서 0도 스스로 입찰하여 바로 깨고 승리를 거두십시오.
  • ScoreOverflowBotInteger.MAX_VALUE시작될 경우 근처에 입찰하거나 그렇지 않으면 입찰 105합니다. 만약 그들이 105를 입찰했다면 110을 직접 입찰하십시오 (105를 잃으면 10을 잃을 것입니다), 그렇지 않으면 0을 입찰하여 그들이 승리하도록하십시오.
  • MBot와 동일 MarginalerBot하지만 '피킹'상대에 대한 보호 기능이 추가되었습니다. 나는 '탐색'하지 않기 때문에 기본적으로와 동일합니다 MarginalerBot.
  • SecretBot그의 것 isPeeking()그것이 시작하거나 내가 5를 입찰하는 경우는 각각 5 또는 10을 입찰 할 경우, 그래서 방법 반환 거짓을. 그렇지 않으면 0이 입찰 될 것입니다. 따라서 시작 여부에 관계없이 opponentsBid + 510 센트 또는 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 센트를 잃습니다.
Kevin Cruijssen

3
배터 맨!
Skyler

1
또한을 플레이 BorkBorkBot할 때 85에 도달했을 때 95까지 올리면 안됩니까? 그렇지 않으면 시작하면 둘 다 입찰합니다.
Skyler

1
@Freiheit 알고 있습니다. 어떤 이유로 든 기본값을 변경하려는 경우 추가 사례를 사용하여 0을 반환했습니다. 그러나 나는 그것들을 주석으로 처리하여 현재 기본값으로 두었습니다. 그리고 나는 모든 것을 조금씩 골프를 칠 수 있다는 것을 알고 있지만 이것은 가장 짧은 코드를 만드는 것이 아닙니다. 좀 더 컴팩트하게 만들기 위해 3 진으로 만들었지 만 그게 전부입니다. 지금은 그대로 두겠습니다.
Kevin Cruijssen

3

위험 보상 봇

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

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

}

이 봇은 5 또는 10을 입찰하여 승리를 최소한으로 시도합니다. 또한 스택 추적을 확인하여 다른 봇이 호출했는지 확인한 다음 입찰에 대해 거짓말을합니다.


I 포트의 경우 마음 isPeekingAbstractAnalystCounterBot?
니사

1
@StephenLeppik은, 글쎄, 난 ... MBot에서 훔친
윈스턴 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을 더 많이 입찰합니다.


모든 입찰은 5의 배수 여야하므로 6을 입찰 할 수 없습니다.
Neil

@Neil 아마 오타 일 것입니다.
Stan Strum

@ 규칙에 구체적으로 명시하십시오 : "입찰가가 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그것이 만든 람다 클래스입니다. 분명히 다른 봇이 그들을 반영하려고하지 않습니다. 람다 클래스가 실제로 일하고 있다는 것을 거의 알지 못합니다 DollarBidder. 그 외에도 그는 다음과 같이 행동 MarginalerBot합니다.


그 이후로 이것을 처리하기 위해 스택 추적 검사를 업데이트했습니다.
니사

1

다스 베이더

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이 발생합니다."
NoOneIsHere 여기

1
@StephenLeppik 이것의 요점은 좋아하는 것을 깨뜨리고 return opponentsBid <= 195 ? opponentsBid + 5 : 0만드는 것 return opponentsBid <= 100001 ? opponentsBid + 100001 : 100001입니다.
NoOneIsHere 여기

1
확인되지 않은 예외로 인해 컴파일에 실패합니다.
Nissa

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

왜 도전을 편집하지 않습니까?
Nathan Merrill

@NathanMerrill 어떻게 편집합니까?
RamenChef

편집 버튼을 클릭하고 AnalystBot를이 코드로 대체 하시겠습니까?
Nathan Merrill

@NathanMerrill AnalystBot은 의도적으로 나쁜 코드이므로 AnalystKiller방해 행위를 보여줄 수 있습니다 .
RamenChef

1
AnalystKiller는 여전히 개선 된 기능을 사용합니다. 게시물을 게시 할 때의 문제는 답변보다 도전이 훨씬 더 눈에 띄는 것입니다.
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

  • 당신을 확인하고 싶지 않은 사람들에게 불친절하다
  • 100을 지불하면 100을 받고 사건을 중단 할 수 있습니다. 다른 사람들에게 쉬운 돈을 거부하기 위해

nextBid던지기를 선언 할 수 없습니다 ClassCastException.
RamenChef

@RamenChef ok, 선언이 필요없는 RuntimeException으로 교체했습니다. :)
mleko

스택 추적 검사 코드는 의심 할 여지없이 비슷합니다.
Nissa

@StephenLeppik 아마 그것의 사본
mleko

@mleko 왜 그래? 이 클래스에서 복사 한 클래스는 무료로 사용할 수있는 추상 슈퍼 클래스입니다.
Nissa

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과 같은 논리로 적과 싸울 때 예외 대신 시간 초과를 사용하십시오. 지금까지 아무도 다시 타임 아웃을 방어하지 않으므로 효과적이어야합니다.


명시된 규칙은 의도적으로 다른 봇이 시간 초과되는 것을 금지합니다.
Winston Ewert

@WinstonEwert 인용 할 수 있습니까? 나는 이것을 금지하는 규칙을 찾을 수 없다
mleko

"다른 봇을 방해하는 것은 허용되지만 필드 / 방법 가시성을 변경하려고 시도하면 신비한 SecurityException이 발생합니다. 예외로 인해 다른 봇이 500ms 제한을 초과하게됩니다." 또한 시간 초과를 방지하고 있습니다.
RamenChef

@RamenChef 그러나 이것은 다른 요소의 가시성을 변경하지 않습니다. 내가 당신을 올바르게 이해하는지 잘 모르겠습니다. 자극 시간 초과가 허용됩니까?
mleko

"예외로 인해 다른 봇이 500ms 제한을 위반했습니다." 특히 이것은 방해 행위에 대한 규칙의 예외입니다.
RamenChef
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.