นักเดินทางเวลา Tossing เหรียญ


19

ในอนาคตเมื่อการเดินทางข้ามเวลา (ตัวย่อเป็น TT) เป็นเรื่องธรรมดาการโยนเหรียญจะกลายเป็นกีฬาที่จริงจัง เพื่อเตรียมความพร้อมสำหรับอนาคตเราได้สร้างการแข่งขันสำหรับรายการที่การเดินทางข้ามเวลาจะเกิดขึ้นจริงจากมุมมองของรายการ

การแข่งขันเป็น King of the Hill แบบกลมซึ่งประกอบด้วยการโยนเหรียญการแข่งขันระหว่างคลาส Java

กฎของการโยนเหรียญที่ตรงกัน

  • มีผู้เล่นสองคนและ 100 รอบ
  • ในทุก ๆ รอบเหรียญจะถูกโยนและตามผลการแข่งขันหนึ่งคะแนนของผู้เล่น 1 คะแนน ผู้เล่นแต่ละคนมีโอกาส 50% ที่จะทำคะแนนจุด
  • หลังจากการโยนผู้เล่นทั้งสองมีโอกาสควบคุมเวลาด้วยการดึงคันโยก
  • หากคุณดึงคันโยกสีน้ำเงิน (เปลี่ยนกลับเป็นตัวหยุด) จะไม่สามารถใช้งาน TT กับรอบได้นั่นคือใช้คันโยกหรือรอบก่อนหน้านี้อีกต่อไป TT ความพยายามที่จะไปรอบนี้จะไม่มีผลใด ๆ
  • หากคุณดึงคันโยกสีแดง (ตัวแปลงกลับ)คุณพยายามที่จะย้อนเวลากลับไปสู่รอบก่อน หากประสบความสำเร็จหน่วยความจำของฝ่ายตรงข้ามจะถูกเปลี่ยนกลับไปเป็นหน่วยความจำก่อนรอบที่เลือกและผลการโยนเหรียญที่เริ่มต้นจากรอบที่เลือกจะถูกลบด้วย เครื่องหมายเดียวที่เป็นไปได้สำหรับฝ่ายตรงข้ามของคุณเกี่ยวกับ TT คือจำนวนคันโยกที่ไม่ได้ใช้ซึ่งจะไม่เปลี่ยนกลับ
  • ผู้เล่นแต่ละคนจะมีคันโยกที่ไม่ได้ใช้สีน้ำเงินและน้ำเงิน 5 อันในช่วงเริ่มต้นการแข่งขัน คันโยกเหล่านี้ไม่ได้รับผลกระทบจาก TT
  • หากไม่มี TT เกิดขึ้นในตอนท้ายของรอบที่ 100 เกมจะสิ้นสุดลงและผู้เล่นที่มีคะแนนสูงกว่าจะเป็นผู้ชนะ

รายละเอียด

  • รอบมีการจัดทำดัชนีแบบ 1 (แบบฟอร์ม 1 ถึง 100)
  • ก่อนออกรอบxคุณจะได้รับจำนวนคันโยกสีน้ำเงินและสีแดงที่มีอยู่เหรียญจะโยนผลลัพธ์จนกว่าจะมีการเปิดx(รวม) และหน่วยความจำของคุณ (ครั้งสุดท้าย)x-1รอบที่คุณ
  • การดึงคันโยกสีน้ำเงินในรอบนั้นxจะเป็นการหยุด TT ใด ๆ ที่มีปลายทางในรอบxหรือก่อนหน้า (จะบล็อก TT ถ้ามันเกิดขึ้นในรอบเดียวกันนั้นเหมือนกัน)
  • ย้อนกลับไปในรอบหมายความว่ารอบต่อไปจะเป็นรอบxx
  • หากผู้เล่นทั้งสองคนเลือกที่จะย้อนกลับเมื่อสิ้นสุดรอบเวลาจะถูกเปลี่ยนกลับไปยังปลายทางก่อนหน้าซึ่งไม่ถูกบล็อก ผู้เล่นที่พยายามย้อนกลับมาในเวลานี้จะเก็บความทรงจำไว้

รายละเอียดทางเทคนิค

  • คุณควรเขียนคลาส Java ที่ใช้อินเตอร์เฟส Bot ที่จัดเตรียมไว้
  • เพิ่มบอทของคุณไปยังโครงการ
  • เพิ่มตัวอย่างของ ธ ปทของคุณไปในแฟ้มBotController.java
  • ชั้นของคุณควรจะได้เก็บข้อมูลระหว่างการโทร (ในกรณีส่วนใหญ่ที่มีเพียงfinalตัวแปรนอกฟังก์ชั่นตรงตามข้อกำหนดนี้)
  • คุณสามารถให้ข้อมูลกับตัวควบคุมในmemoryฟิลด์ของActionวัตถุที่ส่งคืน สิ่งนี้จะได้รับกลับมาให้คุณในเทิร์นถัดไปหากไม่มี TT เกิดขึ้น หาก TT เกิดขึ้นคุณจะได้รับหน่วยความจำก่อนหน้าของคุณ
  • คุณสามารถใช้totalScore()วิธีการGameเรียนเพื่อรับคะแนนของสตริงประวัติศาสตร์

มาตรการ

  • ทุกtakeTurn(...)วิธีการของคุณถูกเรียกว่ามี 5 อาร์กิวเมนต์:

    • จำนวนคันโยกสีน้ำเงินที่ไม่ได้ใช้
    • จำนวนของคันโยกสีแดงที่ไม่ได้ใช้
    • เหรียญที่โยนประวัติความเป็นมาสตริงที่ประกอบด้วย 1 และ 0 ของการทำเครื่องหมายชนะและการสูญเสียของคุณในรอบก่อนหน้า อักขระตัวแรกสอดคล้องกับการโยนเหรียญครั้งแรก (ในรอบแรกความยาวของสตริงจะเป็น1 )
    • สตริงหน่วยความจำที่เก็บไว้ของคุณจากรอบก่อนหน้า
    • ดัชนีที่ใช้ 1 ของรอบนี้
  • ทุกครั้งที่เมธอดของคุณส่งคืนActionวัตถุที่มี

    • จำนวนเต็มในmoveฟิลด์ที่อธิบายถึงการกระทำของคุณ:

      • 0 ไม่มีการดำเนินการ
      • -1 เพื่อดึงคันโยกสีน้ำเงินและปิดกั้น TT ที่กำลังผ่านรอบนี้
      • จำนวนเต็มบวกxซึ่งไม่ใหญ่กว่ารอบปัจจุบันเพื่อดึงคันโยกสีแดงแล้วลองเปลี่ยนกลับเป็นแบบกลมx
      • 0จำนวนเต็มไม่ถูกต้องจะถือว่าเป็น
    • สตริงที่มีหน่วยความจำของคุณจากรอบนี้ซึ่งคุณต้องการรักษา โปรดทราบว่าการจัดเก็บหน่วยความจำที่ไม่ได้เป็นส่วนสำคัญของความท้าทาย คุณสามารถสร้างรายการที่ดีได้โดยไม่ต้องเก็บข้อมูลที่เป็นประโยชน์ไว้ในสตริง ในรอบแรกสตริงจะเป็นสตริงว่าง

  • วิธีการของคุณควรใช้เวลาไม่เกิน 10 ms ต่อรอบโดยเฉลี่ยในการแข่งขัน

  • การล้มเหลวของผลการ จำกัด เวลาอย่างสม่ำเสมอเป็นผลให้ถูกตัดสิทธิ์

เกณฑ์การให้คะแนน

  • ชนะการแข่งขันจะได้รับ 2 คะแนนและการจับสลากจะได้รับ 1 คะแนนสำหรับผู้เล่นทั้งสอง การสูญเสียไม่ได้รับคะแนน
  • คะแนนบ็อตจะเป็นคะแนนรวมทั้งหมดที่รวบรวมไว้
  • จำนวนการแข่งขันที่เล่นระหว่างผู้เข้าแข่งขันแต่ละคู่จะขึ้นอยู่กับจำนวนรายการและความเร็ว

บอทตัวอย่างง่าย ๆ สองโพสต์เป็นคำตอบ

ควบคุมและบอทคู่แรกที่มีอยู่ที่นี่

ผลการทดสอบที่ส่งบอทจนถึงวันที่ 3 พฤศจิกายน

คะแนนรวม:

Oldschool: 3163
Random: 5871
RegretBot: 5269
Nostalgia: 8601
Little Ten: 8772
Analyzer: 17746
NoRegretsBot: 5833
Oracle: 15539
Deja Vu: 5491
Bad Loser: 13715

(ตัวควบคุมขึ้นอยู่กับตัวควบคุมความท้าทายของCat catcherขอขอบคุณสำหรับ @flawr ที่ให้เป็นพื้นฐานสำหรับสิ่งนี้)

โบนัส: ภาพยนตร์ 6 นาทีที่ดีตามแนวคิดที่คล้ายกัน


1
ฉันไม่เข้าใจความหมายของกฎนี้ If you pull a blue lever (revert stopper) no TT is possible through that round anymore. TT's attempting to go through the round will have no effect."การผ่านรอบ" คืออะไร
feersum

@feersum หากฉันเข้าใจถูกต้องให้ดึงคันโยกสีน้ำเงินอย่างถาวร "ล็อค" รอบปัจจุบัน (และรอบก่อนหน้านี้ทั้งหมด) เพื่อไม่ให้สามารถแก้ไขผลการเดินทางข้ามเวลาได้ หากใครพยายาม TT ก่อนเวลาเมื่อคุณดึงคันโยกสีน้ำเงินพวกเขาจะไม่สามารถทำได้
PhiNotPi

@feersum @PhiNotPi ถูกต้องรุ่นนี้ชัดเจนกว่านี้ไหม If you pull a blue lever (revert stopper) no TT is possible to the round the lever was used or any earlier round anymore. TT's attempting to go to these rounds will have no effect.
randomra

เมื่อคุณดึงคันโยกสีแดงคุณสามารถเลือกรอบเดียวกันกับที่คุณกำลังทำอยู่เพื่อทำการโยนเหรียญใหม่สำหรับรอบนั้นได้หรือไม่?
TheNumberOne

@TheNumberOne ใช่นั่นคือสิ่งที่บอทตัวอย่างสุ่มทำ
randomra

คำตอบ:


12

วิเคราะห์

สิ่งนี้จะวิเคราะห์อดีตเพื่อคาดการณ์ที่ดีที่สุดสำหรับอนาคต

แก้ไข:หลีกเลี่ยงเวลาคานสีฟ้า ใช้คันโยกสีน้ำเงินอย่างมีประสิทธิภาพ ใช้คันโยกสีแดงอย่างมีประสิทธิภาพ เพิ่มความขาดแคลนสำหรับเทศกาลวันฮาโลวีน

แก้ไข:แก้ไขข้อผิดพลาด 1 ครั้ง

แก้ไข:ปรับปรุงcomputeWinningProbabilityฟังก์ชั่น ตอนนี้ใช้คันโยกสีแดงและคันโยกสีน้ำเงินมากขึ้นอย่างจริงจัง

//Boo!
package bots;

import main.Action;
import main.Game;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Created 10/24/15
 *
 * @author TheNumberOne
 */
public class Analyzer implements Bot{

    @Override
    public String getName(){
        return "Analyzer";
    }

    @Override
    public Action takeTurn(int blue_levers, int red_levers, String history,
                           String memory, int roundNumber) {
        /*System.out.println(Game.totalScore(history) + " : " + history);
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
        }*/
        int roundsLeft = 100 - roundNumber;
        int myScore = (Game.totalScore(history) + roundNumber) / 2; //My number of wins.
        int enemyScore = roundNumber - myScore;                     //Enemy's number of wins.
        Map<Integer, Double> bestRounds = new HashMap<>();
        int timeLimit = 0;

        Scanner scanner = new Scanner(memory);
        if (scanner.hasNext()){     //No memory, first turn.
            boolean triedTimeTravel = scanner.nextBoolean();
            if (triedTimeTravel){
                int time = scanner.nextInt();
                if (roundNumber > time) {     //Failed.
                    timeLimit = time;
                }
            }
            timeLimit = Math.max(timeLimit, scanner.nextInt());
            int size = scanner.nextInt();
            for (int i = 0; i < size; i++) {
                bestRounds.put(scanner.nextInt(), scanner.nextDouble());
            }
        } else {
            bestRounds.put(1, 0.5);
        }

        clean(bestRounds, roundNumber, timeLimit);
        double winningProb = computeWinningProbability(myScore, enemyScore, roundsLeft);
        String newMemory = computeMemory(bestRounds, roundNumber, winningProb);

        if (winningProb >= new double[]{1.5, .75, .7, .65, .6, .55}[blue_levers]){ //Ensure success ... slowly.
            return getAction(-1, newMemory, timeLimit, roundNumber);
        }

        int bestRound = bestRound(bestRounds);
        double bestRoundProb = bestRounds.get(bestRound);

        if ((winningProb <= bestRoundProb - .05 || winningProb < .5 && bestRoundProb > winningProb) && red_levers > 0){
            return getAction(bestRound, newMemory, timeLimit, roundNumber);  //Let's find the best past.
        } else {
            return getAction(0, newMemory, timeLimit, roundNumber); //Let's wait it out :)
        }
    }

    //Should be combined with computeMemory.
    private static Action getAction(int actionNum, String newMemory, int timeLimit, int roundNumber){
        if (actionNum == -1){
            timeLimit = Math.max(timeLimit, roundNumber);
            newMemory = "false " + timeLimit + " " + newMemory;
            return new Action(actionNum, newMemory);
        }
        if (actionNum == 0){
            return new Action(actionNum, "false " + timeLimit + " " + newMemory);
        }
        if (actionNum > 0){
            return new Action(actionNum, "true " + actionNum + " " + timeLimit + " " + newMemory);
        }
        return null;
    }

    private static int bestRound(Map<Integer, Double> bestRounds) {
        int best = 0;           //If no previous rounds ... just go forward a round.
        double bestScore = -1;
        for (Map.Entry<Integer, Double> entry : bestRounds.entrySet()){
            if (entry.getValue() > bestScore){
                best = entry.getKey();
                bestScore = entry.getValue();
            }
        }
        return best;
    }

    private static String computeMemory(Map<Integer, Double> map, int roundNumber, double winningProb) {
        StringBuilder builder = new StringBuilder();
        builder.append(map.size() + 1).append(" ");
        for (Map.Entry<Integer, Double> entry : map.entrySet()){
            builder.append(entry.getKey()).append(" ").append(entry.getValue()).append(" ");
        }
        builder.append(roundNumber + 1).append(" ").append(winningProb);
        return builder.toString();
    }

    private static void clean(Map<Integer, Double> data, int round, int timeLimit) {
        data
                .entrySet()
                .stream()
                .filter(entry -> entry.getKey() > round || entry.getKey() <= timeLimit)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList()).forEach(data::remove);
    }

    private static double computeWinningProbability(int myScore, int enemyScore, int roundsLeft){ //Too complex for IntelliJ
        int height = myScore - enemyScore;
        double total = 0.0;
        for (int i = Math.max(height - roundsLeft, 2); i <= height + roundsLeft; i += 2){
            total += prob(roundsLeft, height, i);
        }
        total += prob(roundsLeft, height, 0) / 2;
        return total;
    }

    private static double prob(int roundsLeft, int height, int i){
        double prob = 1;
        int up = i - height + (roundsLeft - Math.abs(i - height))/2;
        int down = roundsLeft - up;
        int r = roundsLeft;
        int p = roundsLeft;
        while (up > 1 || down > 1 || r > 1 || p > 0){  //Weird algorithm to avoid loss of precision.
            //Computes roundsLeft!/(2**roundsLeft*up!*down!)

            if ((prob >= 1.0 || r <= 1) && (up > 1 || down > 1 || p > 1)){
                if (p > 0){
                    p--;
                    prob /= 2;
                    continue;
                } else if (up > 1){
                    prob /= up--;
                    continue;
                } else if (down > 1){
                    prob /= down--;
                    continue;
                } else {
                    break;
                }
            }
            if (r > 1) {
                prob *= r--;
                continue;
            }
            break;
        }
        return prob;
    }

}

คะแนน (ตั้งแต่ 2 พฤศจิกายน):

Total Scores:
Oldschool: 3096
Random: 5756
RegretBot: 5362
Nostalgia: 8843
Little Ten: 8929
Analyzer: 17764
NoRegretsBot: 5621
Oracle: 15528
Deja Vu: 5281
Bad Loser: 13820

1
ที่น่าประทับใจ! บอทของคุณบล็อกอย่างมีประสิทธิภาพและย้อนกลับในเวลาที่เหมาะสม มันจะเป็นเรื่องยากมากที่จะสร้างบอทที่สามารถอยู่เหนือสิ่งนี้
ทีเอ็นที

ฉันไม่แน่ใจว่าบ็อตนี้จะหยุดทำงานโดยไม่ใช้รายการที่ออกแบบมาเป็นพิเศษเพื่อยุ่งกับบ็อตนี้และเพิ่มบ็อตอื่น
Mego

4

ความคิดถึง

package bots;

import main.Action;
import main.Game;

public class Nostalgia implements Bot {

    @Override
    public String getName() {
        return "Nostalgia";
    }

    @Override
    public Action takeTurn(int blue_levers, int red_levers, String history,
            String memory, int roundNumber) {

        int current_score = Game.totalScore(history);

        // wait until the end to use blue levers
        if (current_score > 0 && blue_levers >= (100 - roundNumber)) {
            return new Action(-1, memory);
        }

        // become increasingly likely to go back as the gap between the good old days
        // and the horrible present increases
        if (current_score < 0 && red_levers > 0) {
            //identify the best time to travel back to
            int best_score = -100;
            int good_old_days = 1;
            int past_score = 0;

            int unreachable_past = 0;
            if(memory != "") {
              unreachable_past = Integer.parseInt(memory, 10);
            }

            for(int i = unreachable_past; i<roundNumber ; i++) {
              if(history.charAt(i) == '1') {
                past_score += 1;
                if(past_score > best_score) {
                  best_score = past_score;
                  good_old_days = i + 1;
                }
              }
              else {
                past_score -= 1;
              }
            }
            if(roundNumber >= 95 || Math.random() < (best_score - current_score) / 100.0) {
              return new Action(good_old_days, Integer.toString(good_old_days));
            }
        }

        // if neither action was needed do nothing
        return new Action(0, memory);
    }
}

ไม่ได้ทดสอบเพียงแค่แทงอย่างรวดเร็วที่พยายามสร้างบอทที่ยากต่อการบล็อก (เพราะมันจะทำการตัดสินใจว่าเมื่อใดที่จะต้องดึงคันโยกสีแดงส่วนใหญ่แบบสุ่ม) แต่นั่นเป็นการตัดสินใจที่ดี

แก้ไข: ฉันพลาดกฎนี้:

หากคุณดึงคันโยกสีน้ำเงิน (เปลี่ยนกลับเป็นตัวหยุด) จะไม่สามารถ TT ได้ในรอบนั้นอีกต่อไป

นั่นเป็นเหตุผลที่ดีในการใช้หน่วยความจำ - ถ้าคุณจำได้ว่าพยายามที่จะ TT ในรอบที่กำหนดคุณอาจล้มเหลวดังนั้นคุณจึงไม่ควรลอง TT ในรอบนั้นอีก แก้ไขบอทของฉันเพื่อพยายามหลีกเลี่ยงปัญหานี้


4

คำพยากรณ์

ฉันคัดลอกโค้ดบางส่วนจาก Analyzer (เพื่อวิเคราะห์หน่วยความจำ) การส่งนี้พยายามดึงคันโยกสีน้ำเงินก่อนและค่อย ๆ สร้างตะกั่วขึ้นมา ฉันคิดว่าประสิทธิภาพของ bot นี้ทำขึ้นสำหรับรหัสที่น่าเกลียด :)

package bots;

import java.util.*;
import java.util.Map.Entry;
import main.*;

public class Oracle implements Bot {

    @Override
    public String getName() {
        return "Oracle";
    }

    @Override
    public Action takeTurn(int blue_levers, int red_levers, String history, String memory, int roundNumber) {
        int roundsLeft = 100 - roundNumber;
        Map<Integer, Integer> rounds = new HashMap<>();
        int myScore = (Game.totalScore(history) + roundNumber) / 2;
        int difference = myScore*2 - roundNumber;
        int highestBlockedRound = -1;
        int bestScore = 0;
        boolean hasUsedBlueLever = false;

        Scanner scanner = new Scanner(memory);
        if (scanner.hasNext()) {
            //timeTravel toRound highestBlockedRound hasUsedBlueLever bestScore rounds round1 percent1 round2 percent2 round3 percent3...
            boolean triedTravel = scanner.nextBoolean();
            int time = scanner.nextInt();
            if (triedTravel){
                if (roundNumber > time) {
                    highestBlockedRound = time;
                }
            }
            highestBlockedRound = Math.max(highestBlockedRound, scanner.nextInt());

            hasUsedBlueLever = scanner.nextBoolean();
            bestScore = scanner.nextInt();

            int size = scanner.nextInt();
            for (int i = 0; i < size && i < roundNumber; i++) {
                int number = scanner.nextInt();
                int diff = scanner.nextInt();
                if (number < roundNumber) {
                    rounds.put(number, diff);
                }
            }
        }
        rounds.put(roundNumber, difference);
        final int blockedRound = highestBlockedRound;

        int roundToRevert = 0;
        if (rounds.size() > 2) {
            Optional<Entry<Integer, Integer>> bestRound = rounds.entrySet()
                    .stream()
                    .filter(x -> x.getKey() >= blockedRound && x.getKey() <= roundNumber)
                    .sorted(Comparator
                        .comparingInt((Entry<Integer, Integer> x) -> x.getValue()*-1)
                        .thenComparingInt(x -> x.getKey()))
                    .findFirst();
            if (bestRound.isPresent()) {
                roundToRevert = bestRound.get().getKey();
            }
        }

        if (roundsLeft + Game.totalScore(history) <= 0 && red_levers > 0) {
            roundToRevert = highestBlockedRound+1;
        } else if (blue_levers > 0 && roundToRevert == roundNumber && ((hasUsedBlueLever && difference >= bestScore*1.5) || (!hasUsedBlueLever && difference > 1))) {
            roundToRevert = -1;
            hasUsedBlueLever = true;
            bestScore = difference;
            highestBlockedRound = roundNumber;
        } else if (red_levers > 0 && roundToRevert > 0 && rounds.get(roundToRevert) > difference+2) {
            roundToRevert += 1;
        } else {
            roundToRevert = 0;
        }

        StringBuilder sb = new StringBuilder();
        sb.append(roundToRevert > 0).append(' ');
        sb.append(roundToRevert).append(' ');
        sb.append(highestBlockedRound).append(' ');
        sb.append(hasUsedBlueLever).append(' ');
        sb.append(bestScore).append(' ');
        sb.append(rounds.size()).append(' ');
        rounds.entrySet().stream().forEach((entry) -> {
            sb.append(entry.getKey()).append(' ').append(entry.getValue()).append(' ');
        });
        String mem = sb.toString().trim();
        scanner.close();
        return new Action(roundToRevert, mem);
    }
}

เยี่ยมมาก! ฉันรู้ว่าฉันไม่ได้ก้าวร้าวมากพอกับคันโยกสีแดงของฉัน ตอนนี้เพื่อปรับปรุงตัววิเคราะห์ ;)
TheNumberOne

3

RegretBot

ในตอนท้ายของ ชีวิตการแข่งขันเราเสียใจในความล้มเหลวในอดีตของเราและพยายามที่จะกลับไปแก้ไข

package bots;

import main.Action;
import main.Game;

public final class RegretBot implements Bot {

    @Override
    public String getName() {
        return "RegretBot";
    }

    @Override
    public Action takeTurn(int blue_levers, int red_levers, String history, String memory, int roundNumber) {
        int actionNum = 0;
        if(roundNumber == 100) {
            // if it's the end of the game and we're losing, go back
            //  in time to the first loss, in hopes of doing better
            if(Game.totalScore(history)<=0 && red_levers > 0) {
                actionNum = history.indexOf("0")+1;
            }
            // if we're winning at the end, pull a blue lever if we can,
            //  to prevent our opponent from undoing our victory
            else if(blue_levers > 0) {
                actionNum = -1;
            }
        }
        // we don't need no stinkin' memory!
        return new Action(actionNum, null);
    }

}

2

สิบน้อย

Little Ten ทำการคูณและหารจำนวน 10 จำนวนมากโดยใช้ตัวเลขที่เป็นทวีคูณของ 10 และกลับไปสู่รอบที่มีทวีคูณเป็น 10

package bots;

import main.Action;
import main.Game;

public class LittleTen implements Bot {

    @Override
    public String getName() {
        return "Little Ten";
    }

    @Override
    public Action takeTurn(int blue_levers, int red_levers, String history, String memory, int roundNumber) {
        int score = Game.totalScore(history);
        char c = history.charAt(history.length() - 1);
        if (memory.isEmpty())
            memory = "1";

        if (roundNumber == 100) {
            if (score >= 0)
                // We're tied or ahead by the end of the match. Prevent time
                // travel if we can; otherwise whatever happens happens.
                return new Action(blue_levers > 0 ? -1 : 0, memory);
            else {
                // Travel to earlier rounds the farther behind we are if we can
                // (of course using 10 as a reference)
                if (red_levers > 0) {
                    int i = Integer.parseInt(memory);
                    int round = score <= -10 ? i : 100 - ((100 - i) / (11 + (score <= -10 ? -10 : score)));
                    return new Action(round, memory);
                }
            }
        }
        else if (score >= 7 + roundNumber / 20 && blue_levers > 0) {
            // We're ahead; we don't want to lose our lead, especially if the
            // match is close to ending. But we don't want to use up our blue
            // levers too quickly.
            int choice = (int) (Math.random() * 100),
                bound = (roundNumber / 10 + 1) * 5 - ((6 - blue_levers) * 5 - 2);
            if (choice < bound) {
                memory = String.valueOf(roundNumber);
                return new Action(-1, memory);
            }
        }
        else if (score <= -3) {
            // Possibly use a red lever if we're falling too far behind
            if (red_levers > 0) {
                int choice = (int) (Math.random() * 100),
                    bound = score <= -11 ? 90 : 10 * (-3 - score + 1);
                if (choice < bound) {
                    // Check the first round that is the lower multiple of ten
                    // and decide if we've been successful up to that point; if
                    // so, travel back to that round, otherwise go back 10 more
                    int round = roundNumber / 10 * 10;
                    if (round < 10)
                        return new Action(1, memory);
                    String seq = history.substring(0, round-1);
                    int minRound = Integer.parseInt(memory);
                    while (Game.totalScore(seq) <= 0 && round > 10 && round > minRound) {
                        round -= 10;
                        seq = history.substring(0, round-1);
                    }
                    if (round == 0)
                        round = 1;
                    return new Action(round, memory);
                }
            }
        }
        return new Action(0, memory);
    }
}

แก้ไข: เปลี่ยนกลไกเล็กน้อยตอนนี้คำอธิบายว่าจะเกิดอะไรขึ้นเมื่อดึงคันโยกสีน้ำเงินที่ชัดเจนขึ้น ยังได้ปรับสมดุลอีกเล็กน้อย


1

สุ่ม

กลยุทธ์ของ Random มีดังต่อไปนี้:

  • บล็อกมีโอกาส 10% ถ้าเป็นผู้นำและมีคันโยกสีน้ำเงินเหลืออยู่
  • เดินทางย้อนกลับหนึ่งรอบ (เล่นรอบที่ผ่านมาอีกครั้ง) พร้อมโอกาส 10% หากอยู่ในอันดับหลังและมีคันโยกสีแดงเหลืออยู่
package bots;

import main.Action;
import main.Game;

public class RandomBot implements Bot {

    @Override
    public String getName() {
        return "Random";
    }

    @Override
    public Action takeTurn(int blue_levers, int red_levers, String history,
            String memory, int roundNumber) {

        // if in the lead and has blocks left, blocks with a 10% chance
        if (Game.totalScore(history) > 0 && blue_levers > 0
                && Math.random() > 0.9) {
            return new Action(-1, null);
        }

        // if behind and has travels left, travel back the current step to
        // replay it with a 10% chance
        if (Game.totalScore(history) < 0 && red_levers > 0
                && Math.random() > 0.9) {
            return new Action(roundNumber, null);
        }

        // if neither action were needed do nothing
        return new Action(0, null);
    }
}

1

NoRegretsBot

package bots;

import main.Action;
import main.Game;

public final class NoRegretsBot implements Bot {

    @Override
    public String getName() {
        return "NoRegretsBot";
    }

    @Override
    public Action takeTurn(int blue_levers, int red_levers, String history, String memory, int roundNumber) {
        // every 20 turns, pull a blue lever to lock in the past
        // hopefully this will thwart some of those pesky time-travelers
        return new Action(roundNumber%20==0?-1:0, null);
    }

}

1

Bad Loser

บอทนี้ใช้หน่วยความจำไม่และดีอย่างน่าประหลาดใจ (แต่มันไม่ชนะ Analyzer หรือ Oracle)

package main;

import bots.Bot;

/**
 * Created 11/2/15
 *
 * @author TheNumberOne
 */
public class BadLoser implements Bot{
    @Override
    public String getName() {
        return "Bad Loser";
    }

    @Override
    public Action takeTurn(int blue_levers, int red_levers, String history, String memory, int roundNumber) {
        if (history.contains("00") && red_levers > 0){       //Subtract a zero for better performance against
            return new Action(history.indexOf("00") + 1, "");// Analyzer and Nostalgia, and worse performance 
                                                             // against everything else.
        }
        int wins = 0;
        for (char c : history.toCharArray()){
            wins += c - '0';
        }
        if (wins >= new int[]{101, 51, 40, 30, 20, 10}[blue_levers]){
            return new Action(-1, "");
        }
        return new Action(0, "");
    }
}

0

โรงเรียนเก่า

บอทนี้จะไม่ดำเนินการใด ๆ เนื่องจาก Oldschool ไม่เชื่อในการเดินทางข้ามเวลา

package bots;

import main.Action;

public class OldschoolBot implements Bot {

    @Override
    public String getName() {
        return "Oldschool";
    }

    @Override
    public Action takeTurn(int blue_levers, int red_levers, String history,
            String memory, int roundNumber) {       
        // never tries to block or travel at all
        return new Action(0, null);
    }
}

0

Bot Deja Vu

บอทนี้พยายามติดตามเมื่อมันดึงสีน้ำเงินเพื่อหลีกเลี่ยงการดึงสีแดงในพื้นที่นั้น จะดึงคันโยกสีแดงเมื่ออยู่ข้างหลังคะแนนอย่างมากเท่านั้น

package bots;

import main.*;

public class Dejavu implements Bot
{
    @Override
    public String getName()
    {
        return "Deja Vu";
    }

@Override
public Action takeTurn(int blue_levers, int red_levers, String history,
                       String memory, int roundNumber) {

    if(roundNumber == 1)
    {
        memory = "-1";
    }
    int[] blevers = getBlueLevers(memory);
    char[] hist = history.toCharArray();
    int ms = 0;
    int ts = 0;
    int rl = -1;
    boolean bl = false;
    boolean url = false;

    for(int i = 0; i < hist.length; i++)
    {
        switch(hist[i])
        {
            case '1':
            ms++;
            break;
            case '0':
            ts++;
            break;
        }
    }

    if(ts - ms >= 10)
    {   
        for(rl = hist.length - 1; ts - ms <= 5 && rl >= 0; rl--)
        {
            switch(hist[rl])
            {
                case '1':
                ms--;
                break;
                case '0':
                ts--;
                break;
            }
        }
        url = true;
    }

    if(ms - ts >= 7)
    {
        bl = true;
        url = false;
        memory += "," + roundNumber;
    }

    for(int i = 0; i < blevers.length; i++)
    {
        if(rl <= blevers[i])
        {
            rl = blevers[i] + 1;
        }
    }

    if(url)
    {
        return new Action(rl, memory);
    }
    else if(bl)
    {
        return new Action(-1, memory);
    }
    else
    {
        return new Action(0, memory);
    }              
}

private int[] getBlueLevers(String s)
{
    String[] b = s.split(",");

    int[] bl = new int[b.length];
    for(int i = 0; i < b.length; i++)
    {
        bl[i] = Integer.parseInt(b[i]);
    }

    return bl;
}

}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.