Bir zar oyunu, ancak 6 numaradan kaçının [kapalı]


58

Turnuva bitti!

Turnuva şimdi bitti! Son simülasyon gece boyunca toplam oyun çalıştırıldı. Kazanan Christian Sievers , botu OptFor2X ile birlikte . Christian Sievers, ikinci sırayı da Rebel ile korumayı başardı . Tebrikler! Aşağıda turnuva için resmi yüksek skor listesini görebilirsiniz.3108

Hala oyunu oynamak istiyorsan, aşağıda belirtilen kontrol cihazını kullanıp kendi oyununu oluşturmak için içindeki kodu kullanmandan memnuniyet duyarsın.

Zar

Hiç duymadığım bir zar oyununa davet edildim. Kurallar basitti, ancak KotH mücadelesi için mükemmel olacağını düşünüyorum.

Kurallar

Oyunun başlangıcı

Kalıp masanın etrafına gider ve her zaman sizin sıranız olduğunda, kalıbı istediğiniz kadar atarsınız. Ancak, en az bir kere atmanız gerekir. Turunuz için tüm atışların toplamını takip edersiniz. Durdurmayı seçerseniz, raundun puanı toplam puanınıza eklenir.

Öyleyse neden ölmeyi atmayı bıraktın? Çünkü 6 alırsanız, tüm raund için puanınız sıfır olur ve kalıp geçer. Böylece, ilk hedef, puanınızı olabildiğince çabuk artırmaktır.

Kazanan kim?

Masanın etrafındaki ilk oyuncu 40 veya daha fazla puana ulaştığında, son tur başlar. Son tur başladıktan sonra, son turu başlatan kişi dışındaki herkes bir tur daha alır.

Son raundun kuralları, diğer raundlarla aynıdır. Atmaya devam etmeyi veya durmayı seçtin. Ancak, son rauntta önünüzden daha yüksek bir puan alamazsanız, kazanma şansınızın olmadığını biliyorsunuzdur. Ama fazla ileri gidersen 6 alabilirsin.

Ancak, dikkate alınması gereken bir kural daha var. Eğer mevcut toplam puanınız (önceki puanınız + turdaki mevcut puanınız) 40 veya daha fazla ise ve 6'ya bastığınızda toplam puanınız 0 olarak ayarlanır. Bu, her şeye baştan başlamanız gerektiği anlamına gelir. Mevcut toplam puanınız 40 veya daha fazla olduğunda 6'ya vursanız, oyun şu anda en son sırada olmanız dışında normal şekilde devam eder. Toplam puanınız sıfırlandığında son tur tetiklenmez. Hala raundu kazanabilirsin, ama daha zor hale geldi.

Son tur bittiğinde kazanan, en yüksek puana sahip oyuncu. İki veya daha fazla oyuncu aynı puanı paylaşırsa, hepsi galip sayılır.

Ek bir kural, oyunun maksimum 200 tur boyunca devam etmesidir. Bu, çoklu botların temelde mevcut puanlarında kalmak için 6'ya vurarak atmaya devam ettiği durumları önlemektir. 199. tur geçtikten last_roundsonra true olarak ayarlanır ve bir tur daha oynanır. Oyun 200 raund'a giderse, en yüksek puanı alan botlar (veya botlar) 40 puan veya daha fazla olmasa bile kazanır.

tekrarlamak

  • Her turda durmayı seçinceye kadar ya da 6
  • Bir kez kalıbı atmanız gerekir (ilk atışınız 6 ise, turunuz hemen biter)
  • 6 alırsanız, mevcut puanınız 0'a ayarlanır (toplam puanınız değil)
  • Her bir turdan sonra geçerli puanınızı toplam puanınıza eklersiniz.
  • Bir bot sırasını tamamladığında en az 40 puan kazanırsa, diğerleri son sırayı alır
  • Mevcut toplam puanınız ve 6 alırsanız, toplam puanınız 0 olarak ayarlanır ve .40
  • Yukarıdakiler gerçekleştiğinde son tur tetiklenmez
  • Son turdan sonra en yüksek toplam puan alan kişi kazanır.
  • Birden fazla kazanan olması durumunda, hepsi kazanan olarak sayılacaktır.
  • Oyun maksimum 200 tur sürer

Skorların netleştirilmesi

  • Toplam puan: önceki turlardan kaydettiğiniz puan
  • Şu anki skor: güncel raund için puan
  • Mevcut toplam puan: Yukarıdaki iki puanın toplamı

Nasıl katılırsın

Bu KotH yarışmasına katılmak için miras alan bir Python sınıfı yazmalısınız Bot. : İşlevini uygulamanız gerekir make_throw(self, scores, last_round). Bu fonksiyon sizin sıranız geldiğinde çağrılacak ve ilk atışınız 6 değildi. Atmaya devam etmek için yapmalısınız yield True. Atmayı durdurmak için yapmalısın yield False. Her atıştan sonra ana işlev update_stateçağrılır. Böylece, geçerli raunttaki atışlarınızı değişkeni kullanarak erişebilirsiniz self.current_throws. Ayrıca, kullanarak kendi dizininize de erişebilirsiniz self.index. Böylece kendi toplam puanınızı görmek için kullanırsınız scores[self.index]. Ayrıca end_scoreoyuna kullanarak oyuna da erişebilirsiniz self.end_score, ancak bu meydan okuma için 40 olacağını güvenli bir şekilde kabul edebilirsiniz.

Sınıfınızda yardımcı fonksiyonlar yaratmanıza izin verilir. Ayrıca Bot, daha fazla sınıf özelliği eklemek istiyorsanız , ana sınıfta varolan işlevleri geçersiz kılabilirsiniz . Oyunun durumunu, verim Trueveya oyun dışında hiçbir şekilde değiştiremezsin False.

Bu gönderiden ilham almakta özgürsünüz ve buraya dahil ettiğim iki bottan herhangi birini kopyalıyorsunuz. Ancak, özellikle etkili olmadıklarından korkuyorum ...

Diğer dillere izin vermek üzerine

Hem sanal alanda hem de On Dokuzuncu Bayt'ta, diğer dillerde gönderimlere izin vermeyle ilgili tartışmalar yaptık. Bu tür uygulamaları okuduktan ve her iki taraftan argümanları dinledikten sonra, bu zorluğu sadece Python ile sınırlamaya karar verdim. Bunun nedeni iki faktörden kaynaklanıyor: Birden fazla dili desteklemek için gereken zaman ve bu zorluğun rastlantısallığı, kararlılığa ulaşmak için çok sayıda yinelemeyi gerektiriyor. İnşallah yine de katılacaksınız ve bu zorluk için bir Python öğrenmek istiyorsanız, sohbette mümkün olduğunca sık olmaya çalışacağım.

Aklınıza gelebilecek tüm sorularınız için, sohbet odasında bu zorluk için yazabilirsiniz . Orada görüşürüz!

kurallar

  • Sabotaj izin verilir ve teşvik edilir. Yani, diğer oyunculara karşı sabotaj
  • Denetleyiciyle, çalışma zamanıyla veya diğer gönderilerle bağlantı kurma girişimleri diskalifiye edilecektir. Tüm başvurular sadece verdikleri girdi ve depolama ile çalışmalıdır.
  • Kararını vermek için 500 MB’dan fazla hafıza kullanan botlar diskalifiye edilir (bu kadar hafızaya ihtiyacınız varsa tercihlerinizi yeniden düşünmelisiniz)
  • Bir bot, bilerek veya kazayla, mevcut olanla aynı stratejiyi uygulamamalıdır.
  • Meydan okuma sırasında botunuzu güncellemenize izin verilir. Bununla birlikte, yaklaşımınız farklıysa başka bir bot da gönderebilirsiniz.

Örnek

class GoToTenBot(Bot):
    def make_throw(self, scores, last_round):
        while sum(self.current_throws) < 10:
            yield True
        yield False

Bu bot tur için en az 10 olana kadar devam eder, ya da 6 atar. Atma için herhangi bir mantığa ihtiyacınız olmadığına dikkat edin. 6 Ayrıca, ilk atışı 6 ise make_throw, Asla aranmadı, çünkü turunuz hemen sona eriyor.

Python'da yeni olan (ve yieldkonsepti yeni olan ) ancak buna bir adım atmak isteyenler için, yieldanahtar kelime bazı şekillerde bir dönüşe benzer, ancak başka şekillerde farklıdır. Sen kavramı hakkında okuyabilirsiniz burada . Temelde, bir kez yield, işleviniz durur ve yieldgirdiğiniz değer denetleyiciye geri gönderilir. Burada, denetleyici, botunuzun başka bir karar vermesi için gereken zamana kadar mantığını ele alır. Ardından kontrolör size zar atışı gönderir ve make_throwfonksiyonunuz daha önce durduğunda, temel olarak bir önceki yieldifadeden sonraki hatta çalışmaya devam eder .

Bu sayede, oyun kumandası her zar atışı için ayrı bir bot işlev çağrısı gerektirmeden durumu güncelleyebilir.

Şartname

İçinde bulunan herhangi bir Python kütüphanesini kullanabilirsiniz pip. İyi bir ortalama alabileceğimi garantilemek için, tur başına 100 milisaniye zaman sınırına sahipsiniz. Senaryonuz bundan daha hızlı olsaydı daha mutlu olurdum, böylece daha fazla raund koştum.

Değerlendirme

Kazanan bulmak için, tüm botları alıp 8 kişilik rasgele gruplar halinde koşacağım. Gönderilen 8'den az ders varsa, her turda her zaman tüm botların bulunmamasını önlemek için 4 kişilik rasgele gruplar halinde koşacağım. Simülasyonları yaklaşık 8 saat çalıştıracağım ve kazanan en yüksek kazanma oranına sahip bot olacak. 2019 başında final simülasyonlarına başlayacağım ve botlarınızı kodlamanız için tüm Noel'leri size vereceğim! İlk final tarihi 4 Ocak, ancak çok küçük bir zaman ise daha sonraki bir tarihe değiştirebilirim.

O zamana kadar 30-60 dakika CPU zamanı kullanarak ve puan tablosunu güncelleyerek günlük bir simülasyon yapmaya çalışacağım. Bu resmi puan olmayacak, ancak hangi botların en iyi performansı gösterdiğini görmek için bir rehber olacak. Ancak, Noel yaklaşırken, umarım her zaman müsait olmayacağımı anlarsınız. Simülasyon yapmak ve zorluklarla ilgili soruları yanıtlamak için elimden geleni yapacağım.

Kendin test et

Kendi simülasyonlarınızı çalıştırmak istiyorsanız, iki örnek bot dahil olmak üzere simülasyonu çalıştıran kontrol cihazının tam kodu.

kontrolör

İşte bu zorluk için güncellenmiş kontrolör. ANSI çıktılarını destekler, çoklu iş parçacığı ve AKroell sayesinde ek istatistikler toplar ! Denetleyicide değişiklikler yaptığımda, belgeler tamamlandıktan sonra gönderiyi güncelleyeceğim.

Sayesinde BMO , kontrolör şimdi kullanarak bu görevinden tüm botlara indirmek mümkün olan -dbayrak. Bu sürümde diğer işlevler değişmemiştir. Bu, tüm son değişikliklerin mümkün olan en kısa sürede simüle edilmesini sağlamalıdır!

#!/usr/bin/env python3
import re
import json
import math
import random
import requests
import sys
import time
from numpy import cumsum

from collections import defaultdict
from html import unescape
from lxml import html
from multiprocessing import Pool
from os import path, rename, remove
from sys import stderr
from time import strftime

# If you want to see what each bot decides, set this to true
# Should only be used with one thread and one game
DEBUG = False
# If your terminal supports ANSI, try setting this to true
ANSI = False
# File to keep base class and own bots
OWN_FILE = 'forty_game_bots.py'
# File where to store the downloaded bots
AUTO_FILE = 'auto_bots.py'
# If you want to use up all your quota & re-download all bots
DOWNLOAD = False
# If you want to ignore a specific user's bots (eg. your own bots): add to list
IGNORE = []
# The API-request to get all the bots
URL = "https://api.stackexchange.com/2.2/questions/177765/answers?page=%s&pagesize=100&order=desc&sort=creation&site=codegolf&filter=!bLf7Wx_BfZlJ7X"


def print_str(x, y, string):
    print("\033["+str(y)+";"+str(x)+"H"+string, end = "", flush = True)

class bcolors:
    WHITE = '\033[0m'
    GREEN = '\033[92m'
    BLUE = '\033[94m'
    YELLOW = '\033[93m'
    RED = '\033[91m'
    ENDC = '\033[0m'

# Class for handling the game logic and relaying information to the bots
class Controller:

    def __init__(self, bots_per_game, games, bots, thread_id):
        """Initiates all fields relevant to the simulation

        Keyword arguments:
        bots_per_game -- the number of bots that should be included in a game
        games -- the number of games that should be simulated
        bots -- a list of all available bot classes
        """
        self.bots_per_game = bots_per_game
        self.games = games
        self.bots = bots
        self.number_of_bots = len(self.bots)
        self.wins = defaultdict(int)
        self.played_games = defaultdict(int)
        self.bot_timings = defaultdict(float)
        # self.wins = {bot.__name__: 0 for bot in self.bots}
        # self.played_games = {bot.__name__: 0 for bot in self.bots}
        self.end_score = 40
        self.thread_id = thread_id
        self.max_rounds = 200
        self.timed_out_games = 0
        self.tied_games = 0
        self.total_rounds = 0
        self.highest_round = 0
        #max, avg, avg_win, throws, success, rounds
        self.highscore = defaultdict(lambda:[0, 0, 0, 0, 0, 0])
        self.winning_scores = defaultdict(int)
        # self.highscore = {bot.__name__: [0, 0, 0] for bot in self.bots}

    # Returns a fair dice throw
    def throw_die(self):
        return random.randint(1,6)
    # Print the current game number without newline
    def print_progress(self, progress):
        length = 50
        filled = int(progress*length)
        fill = "="*filled
        space = " "*(length-filled)
        perc = int(100*progress)
        if ANSI:
            col = [
                bcolors.RED, 
                bcolors.YELLOW, 
                bcolors.WHITE, 
                bcolors.BLUE, 
                bcolors.GREEN
            ][int(progress*4)]

            end = bcolors.ENDC
            print_str(5, 8 + self.thread_id, 
                "\t%s[%s%s] %3d%%%s" % (col, fill, space, perc, end)
            )
        else:
            print(
                "\r\t[%s%s] %3d%%" % (fill, space, perc),
                flush = True, 
                end = ""
            )

    # Handles selecting bots for each game, and counting how many times
    # each bot has participated in a game
    def simulate_games(self):
        for game in range(self.games):
            if self.games > 100:
                if game % (self.games // 100) == 0 and not DEBUG:
                    if self.thread_id == 0 or ANSI:
                        progress = (game+1) / self.games
                        self.print_progress(progress)
            game_bot_indices = random.sample(
                range(self.number_of_bots), 
                self.bots_per_game
            )

            game_bots = [None for _ in range(self.bots_per_game)]
            for i, bot_index in enumerate(game_bot_indices):
                self.played_games[self.bots[bot_index].__name__] += 1
                game_bots[i] = self.bots[bot_index](i, self.end_score)

            self.play(game_bots)
        if not DEBUG and (ANSI or self.thread_id == 0):
            self.print_progress(1)

        self.collect_results()

    def play(self, game_bots):
        """Simulates a single game between the bots present in game_bots

        Keyword arguments:
        game_bots -- A list of instantiated bot objects for the game
        """
        last_round = False
        last_round_initiator = -1
        round_number = 0
        game_scores = [0 for _ in range(self.bots_per_game)]


        # continue until one bot has reached end_score points
        while not last_round:
            for index, bot in enumerate(game_bots):
                t0 = time.clock()
                self.single_bot(index, bot, game_scores, last_round)
                t1 = time.clock()
                self.bot_timings[bot.__class__.__name__] += t1-t0

                if game_scores[index] >= self.end_score and not last_round:
                    last_round = True
                    last_round_initiator = index
            round_number += 1

            # maximum of 200 rounds per game
            if round_number > self.max_rounds - 1:
                last_round = True
                self.timed_out_games += 1
                # this ensures that everyone gets their last turn
                last_round_initiator = self.bots_per_game

        # make sure that all bots get their last round
        for index, bot in enumerate(game_bots[:last_round_initiator]):
            t0 = time.clock()
            self.single_bot(index, bot, game_scores, last_round)
            t1 = time.clock()
            self.bot_timings[bot.__class__.__name__] += t1-t0

        # calculate which bots have the highest score
        max_score = max(game_scores)
        nr_of_winners = 0
        for i in range(self.bots_per_game):
            bot_name = game_bots[i].__class__.__name__
            # average score per bot
            self.highscore[bot_name][1] += game_scores[i]
            if self.highscore[bot_name][0] < game_scores[i]:
                # maximum score per bot
                self.highscore[bot_name][0] = game_scores[i]
            if game_scores[i] == max_score:
                # average winning score per bot
                self.highscore[bot_name][2] += game_scores[i]
                nr_of_winners += 1
                self.wins[bot_name] += 1
        if nr_of_winners > 1:
            self.tied_games += 1
        self.total_rounds += round_number
        self.highest_round = max(self.highest_round, round_number)
        self.winning_scores[max_score] += 1

    def single_bot(self, index, bot, game_scores, last_round):
        """Simulates a single round for one bot

        Keyword arguments:
        index -- The player index of the bot (e.g. 0 if the bot goes first)
        bot -- The bot object about to be simulated
        game_scores -- A list of ints containing the scores of all players
        last_round -- Boolean describing whether it is currently the last round
        """

        current_throws = [self.throw_die()]
        if current_throws[-1] != 6:

            bot.update_state(current_throws[:])
            for throw in bot.make_throw(game_scores[:], last_round):
                # send the last die cast to the bot
                if not throw:
                    break
                current_throws.append(self.throw_die())
                if current_throws[-1] == 6:
                    break
                bot.update_state(current_throws[:])

        if current_throws[-1] == 6:
            # reset total score if running total is above end_score
            if game_scores[index] + sum(current_throws) - 6 >= self.end_score:
                game_scores[index] = 0
        else:
            # add to total score if no 6 is cast
            game_scores[index] += sum(current_throws)

        if DEBUG:
            desc = "%d: Bot %24s plays %40s with " + \
            "scores %30s and last round == %5s"
            print(desc % (index, bot.__class__.__name__, 
                current_throws, game_scores, last_round))

        bot_name = bot.__class__.__name__
        # average throws per round
        self.highscore[bot_name][3] += len(current_throws)
        # average success rate per round
        self.highscore[bot_name][4] += int(current_throws[-1] != 6)
        # total number of rounds
        self.highscore[bot_name][5] += 1


    # Collects all stats for the thread, so they can be summed up later
    def collect_results(self):
        self.bot_stats = {
            bot.__name__: [
                self.wins[bot.__name__],
                self.played_games[bot.__name__],
                self.highscore[bot.__name__]
            ]
        for bot in self.bots}


# 
def print_results(total_bot_stats, total_game_stats, elapsed_time):
    """Print the high score after the simulation

    Keyword arguments:
    total_bot_stats -- A list containing the winning stats for each thread
    total_game_stats -- A list containing controller stats for each thread
    elapsed_time -- The number of seconds that it took to run the simulation
    """

    # Find the name of each bot, the number of wins, the number
    # of played games, and the win percentage
    wins = defaultdict(int)
    played_games = defaultdict(int)
    highscores = defaultdict(lambda: [0, 0, 0, 0, 0, 0])
    bots = set()
    timed_out_games = sum(s[0] for s in total_game_stats)
    tied_games = sum(s[1] for s in total_game_stats)
    total_games = sum(s[2] for s in total_game_stats)
    total_rounds = sum(s[4] for s in total_game_stats)
    highest_round = max(s[5] for s in total_game_stats)
    average_rounds = total_rounds / total_games
    winning_scores = defaultdict(int)
    bot_timings = defaultdict(float)

    for stats in total_game_stats:
        for score, count in stats[6].items():
            winning_scores[score] += count
    percentiles = calculate_percentiles(winning_scores, total_games)


    for thread in total_bot_stats:
        for bot, stats in thread.items():
            wins[bot] += stats[0]
            played_games[bot] += stats[1]

            highscores[bot][0] = max(highscores[bot][0], stats[2][0])       
            for i in range(1, 6):
                highscores[bot][i] += stats[2][i]
            bots.add(bot)

    for bot in bots:
        bot_timings[bot] += sum(s[3][bot] for s in total_game_stats)

    bot_stats = [[bot, wins[bot], played_games[bot], 0] for bot in bots]

    for i, bot in enumerate(bot_stats):
        bot[3] = 100 * bot[1] / bot[2] if bot[2] > 0 else 0
        bot_stats[i] = tuple(bot)

    # Sort the bots by their winning percentage
    sorted_scores = sorted(bot_stats, key=lambda x: x[3], reverse=True)
    # Find the longest class name for any bot
    max_len = max([len(b[0]) for b in bot_stats])

    # Print the highscore list
    if ANSI:
        print_str(0, 9 + threads, "")
    else:
        print("\n")


    sim_msg = "\tSimulation or %d games between %d bots " + \
        "completed in %.1f seconds"
    print(sim_msg % (total_games, len(bots), elapsed_time))
    print("\tEach game lasted for an average of %.2f rounds" % average_rounds)
    print("\t%d games were tied between two or more bots" % tied_games)
    print("\t%d games ran until the round limit, highest round was %d\n"
        % (timed_out_games, highest_round))

    print_bot_stats(sorted_scores, max_len, highscores)
    print_score_percentiles(percentiles)
    print_time_stats(bot_timings, max_len)

def calculate_percentiles(winning_scores, total_games):
    percentile_bins = 10000
    percentiles = [0 for _ in range(percentile_bins)]
    sorted_keys = list(sorted(winning_scores.keys()))
    sorted_values = [winning_scores[key] for key in sorted_keys]
    cumsum_values = list(cumsum(sorted_values))
    i = 0

    for perc in range(percentile_bins):
        while cumsum_values[i] < total_games * (perc+1) / percentile_bins:
            i += 1
        percentiles[perc] = sorted_keys[i] 
    return percentiles

def print_score_percentiles(percentiles):
    n = len(percentiles)
    show = [.5, .75, .9, .95, .99, .999, .9999]
    print("\t+----------+-----+")
    print("\t|Percentile|Score|")
    print("\t+----------+-----+")
    for p in show:
        print("\t|%10.2f|%5d|" % (100*p, percentiles[int(p*n)]))
    print("\t+----------+-----+")
    print()


def print_bot_stats(sorted_scores, max_len, highscores):
    """Print the stats for the bots

    Keyword arguments:
    sorted_scores -- A list containing the bots in sorted order
    max_len -- The maximum name length for all bots
    highscores -- A dict with additional stats for each bot
    """
    delimiter_format = "\t+%s%s+%s+%s+%s+%s+%s+%s+%s+%s+"
    delimiter_args = ("-"*(max_len), "", "-"*4, "-"*8, 
        "-"*8, "-"*6, "-"*6, "-"*7, "-"*6, "-"*8)
    delimiter_str = delimiter_format % delimiter_args
    print(delimiter_str)
    print("\t|%s%s|%4s|%8s|%8s|%6s|%6s|%7s|%6s|%8s|" 
        % ("Bot", " "*(max_len-3), "Win%", "Wins", 
            "Played", "Max", "Avg", "Avg win", "Throws", "Success%"))
    print(delimiter_str)

    for bot, wins, played, score in sorted_scores:
        highscore = highscores[bot]
        bot_max_score = highscore[0]
        bot_avg_score = highscore[1] / played
        bot_avg_win_score = highscore[2] / max(1, wins)
        bot_avg_throws = highscore[3] / highscore[5]
        bot_success_rate = 100 * highscore[4] / highscore[5]

        space_fill = " "*(max_len-len(bot))
        format_str = "\t|%s%s|%4.1f|%8d|%8d|%6d|%6.2f|%7.2f|%6.2f|%8.2f|"
        format_arguments = (bot, space_fill, score, wins, 
            played, bot_max_score, bot_avg_score,
            bot_avg_win_score, bot_avg_throws, bot_success_rate)
        print(format_str % format_arguments)

    print(delimiter_str)
    print()

def print_time_stats(bot_timings, max_len):
    """Print the execution time for all bots

    Keyword arguments:
    bot_timings -- A dict containing information about timings for each bot
    max_len -- The maximum name length for all bots
    """
    total_time = sum(bot_timings.values())
    sorted_times = sorted(bot_timings.items(), 
        key=lambda x: x[1], reverse = True)

    delimiter_format = "\t+%s+%s+%s+"
    delimiter_args = ("-"*(max_len), "-"*7, "-"*5)
    delimiter_str = delimiter_format % delimiter_args
    print(delimiter_str)

    print("\t|%s%s|%7s|%5s|" % ("Bot", " "*(max_len-3), "Time", "Time%"))
    print(delimiter_str)
    for bot, bot_time in sorted_times:
        space_fill = " "*(max_len-len(bot))
        perc = 100 * bot_time / total_time
        print("\t|%s%s|%7.2f|%5.1f|" % (bot, space_fill, bot_time, perc))
    print(delimiter_str)
    print() 


def run_simulation(thread_id, bots_per_game, games_per_thread, bots):
    """Used by multithreading to run the simulation in parallel

    Keyword arguments:
    thread_id -- A unique identifier for each thread, starting at 0
    bots_per_game -- How many bots should participate in each game
    games_per_thread -- The number of games to be simulated
    bots -- A list of all bot classes available
    """
    try:
        controller = Controller(bots_per_game, 
            games_per_thread, bots, thread_id)
        controller.simulate_games()
        controller_stats = (
            controller.timed_out_games,
            controller.tied_games,
            controller.games,
            controller.bot_timings,
            controller.total_rounds,
            controller.highest_round,
            controller.winning_scores
        )
        return (controller.bot_stats, controller_stats)
    except KeyboardInterrupt:
        return {}


# Prints the help for the script
def print_help():
    print("\nThis is the controller for the PPCG KotH challenge " + \
        "'A game of dice, but avoid number 6'")
    print("For any question, send a message to maxb\n")
    print("Usage: python %s [OPTIONS]" % sys.argv[0])
    print("\n  -n\t\tthe number of games to simluate")
    print("  -b\t\tthe number of bots per round")
    print("  -t\t\tthe number of threads")
    print("  -d\t--download\tdownload all bots from codegolf.SE")
    print("  -A\t--ansi\trun in ANSI mode, with prettier printing")
    print("  -D\t--debug\trun in debug mode. Sets to 1 thread, 1 game")
    print("  -h\t--help\tshow this help\n")

# Make a stack-API request for the n-th page
def req(n):
    req = requests.get(URL % n)
    req.raise_for_status()
    return req.json()

# Pull all the answers via the stack-API
def get_answers():
    n = 1
    api_ans = req(n)
    answers = api_ans['items']
    while api_ans['has_more']:
        n += 1
        if api_ans['quota_remaining']:
            api_ans = req(n)
            answers += api_ans['items']
        else:
            break

    m, r = api_ans['quota_max'], api_ans['quota_remaining']
    if 0.1 * m > r:
        print(" > [WARN]: only %s/%s API-requests remaining!" % (r,m), file=stderr)

    return answers


def download_players():
    players = {}

    for ans in get_answers():
        name = unescape(ans['owner']['display_name'])
        bots = []

        root = html.fromstring('<body>%s</body>' % ans['body'])
        for el in root.findall('.//code'):
            code = el.text
            if re.search(r'^class \w+\(\w*Bot\):.*$', code, flags=re.MULTILINE):
                bots.append(code)

        if not bots:
            print(" > [WARN] user '%s': couldn't locate any bots" % name, file=stderr)
        elif name in players:
            players[name] += bots
        else:
            players[name] = bots

    return players


# Download all bots from codegolf.stackexchange.com
def download_bots():
    print('pulling bots from the interwebs..', file=stderr)
    try:
        players = download_players()
    except Exception as ex:
        print('FAILED: (%s)' % ex, file=stderr)
        exit(1)

    if path.isfile(AUTO_FILE):
        print(' > move: %s -> %s.old' % (AUTO_FILE,AUTO_FILE), file=stderr)
        if path.exists('%s.old' % AUTO_FILE):
            remove('%s.old' % AUTO_FILE)
        rename(AUTO_FILE, '%s.old' % AUTO_FILE)

    print(' > writing players to %s' % AUTO_FILE, file=stderr)
    f = open(AUTO_FILE, 'w+', encoding='utf8')
    f.write('# -*- coding: utf-8 -*- \n')
    f.write('# Bots downloaded from https://codegolf.stackexchange.com/questions/177765 @ %s\n\n' % strftime('%F %H:%M:%S'))
    with open(OWN_FILE, 'r') as bfile:
        f.write(bfile.read()+'\n\n\n# Auto-pulled bots:\n\n')
    for usr in players:
        if usr not in IGNORE:
            for bot in players[usr]:
                f.write('# User: %s\n' % usr)
                f.write(bot+'\n\n')
    f.close()

    print('OK: pulled %s bots' % sum(len(bs) for bs in players.values()))


if __name__ == "__main__":

    games = 10000
    bots_per_game = 8
    threads = 4

    for i, arg in enumerate(sys.argv):
        if arg == "-n" and len(sys.argv) > i+1 and sys.argv[i+1].isdigit():
            games = int(sys.argv[i+1])
        if arg == "-b" and len(sys.argv) > i+1 and sys.argv[i+1].isdigit():
            bots_per_game = int(sys.argv[i+1])
        if arg == "-t" and len(sys.argv) > i+1 and sys.argv[i+1].isdigit():
            threads = int(sys.argv[i+1])
        if arg == "-d" or arg == "--download":
            DOWNLOAD = True
        if arg == "-A" or arg == "--ansi":
            ANSI = True
        if arg == "-D" or arg == "--debug":
            DEBUG = True
        if arg == "-h" or arg == "--help":
            print_help()
            quit()
    if ANSI:
        print(chr(27) + "[2J", flush =  True)
        print_str(1,3,"")
    else:
        print()

    if DOWNLOAD:
        download_bots()
        exit() # Before running other's code, you might want to inspect it..

    if path.isfile(AUTO_FILE):
        exec('from %s import *' % AUTO_FILE[:-3])
    else:
        exec('from %s import *' % OWN_FILE[:-3])

    bots = get_all_bots()

    if bots_per_game > len(bots):
        bots_per_game = len(bots)
    if bots_per_game < 2:
        print("\tAt least 2 bots per game is needed")
        bots_per_game = 2
    if games <= 0:
        print("\tAt least 1 game is needed")
        games = 1
    if threads <= 0:
        print("\tAt least 1 thread is needed")
        threads = 1
    if DEBUG:
        print("\tRunning in debug mode, with 1 thread and 1 game")
        threads = 1
        games = 1

    games_per_thread = math.ceil(games / threads)

    print("\tStarting simulation with %d bots" % len(bots))
    sim_str = "\tSimulating %d games with %d bots per game"
    print(sim_str % (games, bots_per_game))
    print("\tRunning simulation on %d threads" % threads)
    if len(sys.argv) == 1:
        print("\tFor help running the script, use the -h flag")
    print()

    with Pool(threads) as pool:
        t0 = time.time()
        results = pool.starmap(
            run_simulation, 
            [(i, bots_per_game, games_per_thread, bots) for i in range(threads)]
        )
        t1 = time.time()
        if not DEBUG:
            total_bot_stats = [r[0] for r in results]
            total_game_stats = [r[1] for r in results]
            print_results(total_bot_stats, total_game_stats, t1-t0)

Bu meydan okuma için orijinal denetleyiciye erişmek istiyorsanız, düzenleme geçmişinde kullanılabilir. Yeni kumanda oyunu çalıştırmak için aynı mantığa sahip, tek fark performans, stat toplama ve daha güzel baskı.

botlar

Makinemde, botlar dosyada tutuluyor forty_game_bots.py. Dosya için başka bir ad kullanıyorsanız import, denetleyicinin üstündeki ifadeyi güncellemelisiniz .

import sys, inspect
import random
import numpy as np

# Returns a list of all bot classes which inherit from the Bot class
def get_all_bots():
    return Bot.__subclasses__()

# The parent class for all bots
class Bot:

    def __init__(self, index, end_score):
        self.index = index
        self.end_score = end_score

    def update_state(self, current_throws):
        self.current_throws = current_throws

    def make_throw(self, scores, last_round):
        yield False


class ThrowTwiceBot(Bot):

    def make_throw(self, scores, last_round):
        yield True
        yield False

class GoToTenBot(Bot):

    def make_throw(self, scores, last_round):
        while sum(self.current_throws) < 10:
            yield True
        yield False

Simülasyonu çalıştırma

Simülasyon çalıştırmak için, yukarıda belirtilen her iki kod parçasını da iki ayrı dosyaya kaydedin. Onları forty_game_controller.pyve olarak kurtardım forty_game_bots.py. Daha sonra Python yapılandırmanıza bağlı olarak python forty_game_controller.pyveya kullanırsınız python3 forty_game_controller.py. Simülasyonunuzu daha fazla yapılandırmak istiyorsanız oradaki talimatları izleyin ya da isterseniz kodu eklemeyi deneyin.

Oyun istatistikleri

Başka botlar göz önünde bulundurulmaksızın belirli bir skoru hedefleyen bir bot yapıyorsanız, bunlar kazanan skor yüzdeleridir:

+----------+-----+
|Percentile|Score|
+----------+-----+
|     50.00|   44|
|     75.00|   48|
|     90.00|   51|
|     95.00|   54|
|     99.00|   58|
|     99.90|   67|
|     99.99|  126|
+----------+-----+

Yüksek puanlar

Daha fazla cevap gönderildiği için bu listeyi güncel tutmaya çalışacağım. Listenin içeriği her zaman en son simülasyondan olacaktır. Botlar ThrowTwiceBotve GoToTenBotyukarıdaki koddaki botlardır ve referans olarak kullanılırlar. Yaklaşık 1 saat süren 10 ^ 8 oyunla bir simülasyon yaptım. Daha sonra 10 ^ 7 oyun ile oyunumun koşularla karşılaştırıldığında dengeye ulaştığını gördüm. Bununla birlikte, insanlar hala bot gönderirken, cevap sıklığı azalıncaya kadar daha fazla simülasyon yapmayacağım.

Tüm yeni botları eklemeye ve mevcut botlara yaptığınız değişiklikleri eklemeye çalışıyorum. Botunuzu veya yaptığınız herhangi bir değişikliği kaçırmışım gibi görünüyorsa, sohbete yazın ve bir sonraki simülasyonda en son sürümünüzü aldığınızdan emin olacağım.

AKroell sayesinde artık her bot için daha fazla istatistik var ! Üç yeni sütun tüm oyunlar için maksimum puanı, oyun başına ortalama puanı ve her bot için kazanma sırasındaki ortalama puanı içerir.

Yorumlarda da belirtildiği gibi, oyun mantığında, oyun içinde daha yüksek indeksli botların bazı durumlarda fazladan bir tur atmasına neden olan bir sorun vardı. Bu şimdi düzeltildi ve aşağıdaki puanlar bunu yansıtıyor.

Simulation or 300000000 games between 49 bots completed in 35628.7 seconds
Each game lasted for an average of 3.73 rounds
29127662 games were tied between two or more bots
0 games ran until the round limit, highest round was 22

+-----------------------+----+--------+--------+------+------+-------+------+--------+
|Bot                    |Win%|    Wins|  Played|   Max|   Avg|Avg win|Throws|Success%|
+-----------------------+----+--------+--------+------+------+-------+------+--------+
|OptFor2X               |21.6|10583693|48967616|    99| 20.49|  44.37|  4.02|   33.09|
|Rebel                  |20.7|10151261|48977862|   104| 21.36|  44.25|  3.90|   35.05|
|Hesitate               |20.3| 9940220|48970815|   105| 21.42|  44.23|  3.89|   35.11|
|EnsureLead             |20.3| 9929074|48992362|   101| 20.43|  44.16|  4.50|   25.05|
|StepBot                |20.2| 9901186|48978938|    96| 20.42|  43.47|  4.56|   24.06|
|BinaryBot              |20.1| 9840684|48981088|   115| 21.01|  44.48|  3.85|   35.92|
|Roll6Timesv2           |20.1| 9831713|48982301|   101| 20.83|  43.53|  4.37|   27.15|
|AggressiveStalker      |19.9| 9767637|48979790|   110| 20.46|  44.86|  3.90|   35.04|
|FooBot                 |19.9| 9740900|48980477|   100| 22.03|  43.79|  3.91|   34.79|
|QuotaBot               |19.9| 9726944|48980023|   101| 19.96|  44.95|  4.50|   25.03|
|BePrepared             |19.8| 9715461|48978569|   112| 18.68|  47.58|  4.30|   28.31|
|AdaptiveRoller         |19.7| 9659023|48982819|   107| 20.70|  43.27|  4.51|   24.81|
|GoTo20Bot              |19.6| 9597515|48973425|   108| 21.15|  43.24|  4.44|   25.98|
|Gladiolen              |19.5| 9550368|48970506|   107| 20.16|  45.31|  3.91|   34.81|
|LastRound              |19.4| 9509645|48988860|   100| 20.45|  43.50|  4.20|   29.98|
|BrainBot               |19.4| 9500957|48985984|   105| 19.26|  45.56|  4.46|   25.71|
|GoTo20orBestBot        |19.4| 9487725|48975944|   104| 20.98|  44.09|  4.46|   25.73|
|Stalker                |19.4| 9485631|48969437|   103| 20.20|  45.34|  3.80|   36.62|
|ClunkyChicken          |19.1| 9354294|48972986|   112| 21.14|  45.44|  3.57|   40.48|
|FortyTeen              |18.8| 9185135|48980498|   107| 20.90|  46.77|  3.88|   35.32|
|Crush                  |18.6| 9115418|48985778|    96| 14.82|  43.08|  5.15|   14.15|
|Chaser                 |18.6| 9109636|48986188|   107| 19.52|  45.62|  4.06|   32.39|
|MatchLeaderBot         |16.6| 8122985|48979024|   104| 18.61|  45.00|  3.20|   46.70|
|Ro                     |16.5| 8063156|48972140|   108| 13.74|  48.24|  5.07|   15.44|
|TakeFive               |16.1| 7906552|48994992|   100| 19.38|  44.68|  3.36|   43.96|
|RollForLuckBot         |16.1| 7901601|48983545|   109| 17.30|  50.54|  4.72|   21.30|
|Alpha                  |15.5| 7584770|48985795|   104| 17.45|  46.64|  4.04|   32.67|
|GoHomeBot              |15.1| 7418649|48974928|    44| 13.23|  41.41|  5.49|    8.52|
|LeadBy5Bot             |15.0| 7354458|48987017|   110| 17.15|  46.95|  4.13|   31.16|
|NotTooFarBehindBot     |15.0| 7338828|48965720|   115| 17.75|  45.03|  2.99|   50.23|
|GoToSeventeenRollTenBot|14.1| 6900832|48976440|   104| 10.26|  49.25|  5.68|    5.42|
|LizduadacBot           |14.0| 6833125|48978161|    96|  9.67|  51.35|  5.72|    4.68|
|TleilaxuBot            |13.5| 6603853|48985292|   137| 15.25|  45.05|  4.27|   28.80|
|BringMyOwn_dice        |12.0| 5870328|48974969|    44| 21.27|  41.47|  4.24|   29.30|
|SafetyNet              |11.4| 5600688|48987015|    98| 15.81|  45.03|  2.41|   59.84|
|WhereFourArtThouChicken|10.5| 5157324|48976428|    64| 22.38|  47.39|  3.59|   40.19|
|ExpectationsBot        | 9.0| 4416154|48976485|    44| 24.40|  41.55|  3.58|   40.41|
|OneStepAheadBot        | 8.4| 4132031|48975605|    50| 18.24|  46.02|  3.20|   46.59|
|GoBigEarly             | 6.6| 3218181|48991348|    49| 20.77|  42.95|  3.90|   35.05|
|OneInFiveBot           | 5.8| 2826326|48974364|   155| 17.26|  49.72|  3.00|   50.00|
|ThrowThriceBot         | 4.1| 1994569|48984367|    54| 21.70|  44.55|  2.53|   57.88|
|FutureBot              | 4.0| 1978660|48985814|    50| 17.93|  45.17|  2.36|   60.70|
|GamblersFallacy        | 1.3|  621945|48986528|    44| 22.52|  41.46|  2.82|   53.07|
|FlipCoinRollDice       | 0.7|  345385|48972339|    87| 15.29|  44.55|  1.61|   73.17|
|BlessRNG               | 0.2|   73506|48974185|    49| 14.54|  42.72|  1.42|   76.39|
|StopBot                | 0.0|    1353|48984828|    44| 10.92|  41.57|  1.00|   83.33|
|CooperativeSwarmBot    | 0.0|     991|48970284|    44| 10.13|  41.51|  1.36|   77.30|
|PointsAreForNerdsBot   | 0.0|       0|48986508|     0|  0.00|   0.00|  6.00|    0.00|
|SlowStart              | 0.0|       0|48973613|    35|  5.22|   0.00|  3.16|   47.39|
+-----------------------+----+--------+--------+------+------+-------+------+--------+

RebelKuralları değiştirmek için aşağıdaki botlar (hariç ) yapılır ve yaratıcılar resmi turnuvaya katılmamayı kabul etmişlerdir. Bununla birlikte, fikirlerinin yaratıcı olduğunu düşünüyorum ve onurlu bir sözü hakediyorlar. İsyancı da bu listede çünkü sabotajı önlemek için akıllı bir strateji kullanıyor ve oyunda sabote edici botla daha iyi performans gösteriyor.

Botlar NeoBotve KwisatzHaderachkurallara uyuyor, ancak rasgele üreteci tahmin ederek bir boşluk kullanıyor. Bu botlar taklit etmek için çok kaynak kullandığından, daha az oyun içeren bir simülasyondan istatistiklerini ekledim. Bot HarkonnenBot, kurallara kesinlikle aykırı olan diğer tüm botları devre dışı bırakarak zafer kazanıyor.

    Simulation or 300000 games between 52 bots completed in 66.2 seconds
    Each game lasted for an average of 4.82 rounds
    20709 games were tied between two or more bots
    0 games ran until the round limit, highest round was 31

    +-----------------------+----+--------+--------+------+------+-------+------+--------+
    |Bot                    |Win%|    Wins|  Played|   Max|   Avg|Avg win|Throws|Success%|
    +-----------------------+----+--------+--------+------+------+-------+------+--------+
    |KwisatzHaderach        |80.4|   36986|   46015|   214| 58.19|  64.89| 11.90|   42.09|
    |HarkonnenBot           |76.0|   35152|   46264|    44| 34.04|  41.34|  1.00|   83.20|
    |NeoBot                 |39.0|   17980|   46143|   214| 37.82|  59.55|  5.44|   50.21|
    |Rebel                  |26.8|   12410|   46306|    92| 20.82|  43.39|  3.80|   35.84|
    +-----------------------+----+--------+--------+------+------+-------+------+--------+

    +----------+-----+
    |Percentile|Score|
    +----------+-----+
    |     50.00|   45|
    |     75.00|   50|
    |     90.00|   59|
    |     95.00|   70|
    |     99.00|   97|
    |     99.90|  138|
    |     99.99|  214|
    +----------+-----+

2
Bu nedenle, "bir oyuncu sırasını en az 40 puanla bitirdiğinde, herkes son bir sırayı alırsa" dediğinde, belki kurallar biraz daha netleşir. Bu gerçekten son turda tetikler 40 ulaşmadan değil işaret edilerek belirgin çatışmayı önler, en az 40 ile durduran
aschepler

1
Bunun iyi bir formülasyon var @aschepler benim bilgisayar üzerinde olduğum zaman, ben yayını düzenleyebilir edeceğiz
maxb

2
@maxb benim geliştirme sürecine alakalı olduğunu daha fazla istatistik eklemek için denetleyici uzattığımızı: en yüksek puan ulaştığı ortalama puan ulaştı ve ortalama kazanan skor gist.github.com/AwK/91446718a46f3e001c19533298b5756c
AKroell

2
Bu Farkled adında çok eğlenceli bir zar oyununa çok benziyor en.wikipedia.org/wiki/Farkle
Caleb Jay

5
Zaten de-facto çünkü yeni cevapları ( "! Turnuvası, 3 * 108 oyun toplam artık bitti nihai simülasyon gece boyunca çalıştırıldı ise") kapalı Bu soruyu kapatmak için oy vereceğim
pppery

Yanıtlar:


6

OptFor2X

Bu bot, bu oyuncunun iki oyunculu versiyonu için en uygun stratejiye yaklaşımı izler, sadece puanını ve en iyi rakibinin puanını kullanır. Son turda, güncellenmiş sürüm tüm puanları dikkate alır.

class OptFor2X(Bot):

    _r = []
    _p = []

    def _u(self,l):
        res = []
        for x in l:
            if isinstance(x,int):
                if x>0:
                    a=b=x
                else:
                    a,b=-2,-x
            else:
                if len(x)==1:
                    a = x[0]
                    if a<0:
                        a,b=-3,-a
                    else:
                        b=a+2
                else:
                    a,b=x
            if a<0:
                res.extend((b for _ in range(-a)))
            else:
                res.extend(range(a,b+1))
        res.extend((res[-1] for _ in range(40-len(res))))
        return res


    def __init__(self,*args):
        super().__init__(*args)
        if self._r:
            return
        self._r.append(self._u([[-8, 14], -15, [-6, 17], [18, 21], [21],
                                 -23, -24, 25, [-3, 21], [22, 29]]))
        self._r.extend((None for _ in range(13)))
        self._r.extend((self._u(x) for x in
                   ([[-19, 13], [-4, 12], -13, [-14], [-5, 15], [-4, 16],
                     -17, 18],
                    [[-6, 12], [-11, 13], [-4, 12], -11, -12, [-13], [-14],
                     [-5, 15], -16, 17],
                    [11, 11, [-10, 12], -13, [-24], 13, 12, [-6, 11], -12,
                     [-13], [-6, 14], -15, 16],
                    [[-8, 11], -12, 13, [-9, 23], 11, [-10], [-11], [-12],
                     [-5, 13], -14, [14]],
                    [[-4, 10], [-11], 12, [-14, 22], 10, 9, -10, [-4, 11],
                     [-5, 12], -13, -14, 15],
                    [[-4, 10], 11, [-18, 21], [-9], [-10], [-5, 11], [-12],
                     -13, 14],
                    [[-24, 20], [-5, 9], [-4, 10], [-4, 11], -12, 13],
                    [[-25, 19], [-8], [-4, 9], [-4, 10], -11, 12],
                    [[-26, 18], [-5, 8], [-5, 9], 10, [10]],
                    [[-27, 17], [-4, 7], [-5, 8], 9, [9]],
                    [[-28, 16], -6, [-5, 7], -8, -9, 10],
                    [[-29, 15], [-5, 6], [-7], -8, 9],
                    [[-29, 14], [-4, 5], [-4, 6], [7]],
                    [[-30, 13], -4, [-4, 5], 6, [6]], 
                    [[-31, 12], [-5, 4], 5, [5]],
                    [[-31, 11], [-4, 3], [3], 5, 6],
                    [[-31, 10], 11, [-2], 3, [3]],
                    [[-31, 9], 10, 2, -1, 2, [2]],
                    [[-31, 8], 9, [-4, 1], [1]],
                    [[-30, 7], [7], [-5, 1], 2],
                    [[-30, 6], [6], 1],
                    [[-31, 5], [6], 1],
                    [[-31, 4], [5, 8], 1],
                    [[-31, 3], [4, 7], 1],
                    [[-31, 2], [3, 6], 1],
                    [[-31, 1], [2, 10]] ) ))
        l=[0.0,0.0,0.0,0.0,1.0]
        for i in range(300):
            l.append(sum([a/6 for a in l[i:]]))
        m=[i/6 for i in range(1,5)]
        self._p.extend((1-sum([a*b for a,b in zip(m,l[i:])])
                                           for i in range(300)))

    def update_state(self,*args):
        super().update_state(*args)
        self.current_sum = sum(self.current_throws)

    def expect(self,mts,ops):
        p = 1.0
        for s in ops:
            p *= self._p[mts-s]
        return p

    def throw_again(self,mts,ops):
        ps = self.expect(mts,ops)
        pr = sum((self.expect(mts+d,ops) for d in range(1,6)))/6
        return pr>ps

    def make_throw(self,scores,last_round):
        myscore=scores[self.index]
        if last_round:
            target=max(scores)-myscore
            if max(scores)<40:
                opscores = scores[self.index+1:]
            else:
                opscores = []
                i = (self.index + 1) % len(scores)
                while scores[i] < 40:
                    opscores.append(scores[i])
                    i = (i+1) % len(scores)
        else:
            opscores = [s for i,s in enumerate(scores) if i!=self.index]
            bestop = max(opscores)
            target = min(self._r[myscore][bestop],40-myscore)
            # (could change the table instead of using min)
        while self.current_sum < target:
            yield True
        lr = last_round or myscore+self.current_sum >= 40
        while lr and self.throw_again(myscore+self.current_sum,opscores):
            yield True
        yield False

En kısa sürede uygulamaya başlayacağım. Noel kutlamaları ile, 25
maxb

Botunuz önde! Ayrıca, daha hızlı çalışmasına gerek yoktur, karar verirken diğer tüm botlar kadar hızlıdır.
maxb

Daha hızlı yapmak istemedim. Yapmak istediğim şeyi yaptım - sadece bir kere başlattım - ama özellikle sınıf dışında işlevleri tanımlamaksızın daha güzel bir yol arıyordum. Bence şimdi daha iyi.
Christian Sievers,

Şimdi çok daha iyi görünüyor, iyi iş!
maxb

Birinci ve ikinci sırayı aldığınız için tebrik ederiz!
maxb

20

NeoBot

Bunun yerine, sadece gerçeği anlamaya çalışın - kaşık yok

NeoBot matrise göz atar (aka rastgele) ve bir sonraki rulonun 6 olup olmayacağını tahmin eder - başlangıç ​​için 6 verilmesiyle ilgili hiçbir şey yapamaz ancak bir çizgi sonlandırıcıdan kaçmaktan çok mutludur.

NeoBot denetleyiciyi veya çalışma zamanını değiştirmiyor, kütüphaneden daha fazla bilgi almak istiyor.

class NeoBot(Bot):
    def __init__(self, index, end_score):
        self.random = None
        self.last_scores = None
        self.last_state = None
        super().__init__(index,end_score)

    def make_throw(self, scores, last_round):
        while True:
            if self.random is None:
                self.random = inspect.stack()[1][0].f_globals['random']
            tscores = scores[:self.index] + scores[self.index+1:]
            if self.last_scores != tscores:
                self.last_state = None
                self.last_scores = tscores
            future = self.predictnext_randint(self.random)
            if future == 6:
                yield False
            else:
                yield True

    def genrand_int32(self,base):
        base ^= (base >> 11)
        base ^= (base << 7) & 0x9d2c5680
        base ^= (base << 15) & 0xefc60000
        return base ^ (base >> 18)

    def predictnext_randint(self,cls):
        if self.last_state is None:
            self.last_state = list(cls.getstate()[1])
        ind = self.last_state[-1]
        width = 6
        res = width + 1
        while res >= width:
            y = self.last_state[ind]
            r = self.genrand_int32(y)
            res = r >> 29
            ind += 1
            self.last_state[-1] = (self.last_state[-1] + 1) % (len(self.last_state))
        return 1 + res

1
PPCG'ye Hoşgeldiniz! Bu gerçekten etkileyici bir cevap. İlk çalıştırdığımda, diğer tüm botlarla aynı miktarda çalışma zamanı kullandığı için rahatsız oldum. Sonra galibiyet yüzdesine baktım. Gerçekten zekice bir yol kuralları kuralları. Botunuzun turnuvaya katılmasına izin vereceğim, ancak umarım diğerleri oyunun ruhunu ihlal ettiği için aynı taktiği kullanmaktan kaçınırlar.
azami

2
Bu bot ile ikinci yer arasında çok büyük bir boşluk olduğu için, botunuzun çok fazla bilgi işlem gerektirdiği gerçeğiyle birleştiğinde, kazanma oranınızı bulmak için daha az yinelemeli bir simülasyon çalıştırdığımı kabul eder misiniz ve daha sonra resmi botunuz olmadan simülasyon?
azami

3
Bana göre, bunun muhtemelen diskalifiye edilebileceğini ve kesinlikle oyunun ruhu içinde olmadığını anladım. Olduğu söyleniyor, çalışmak için bir patlama ve python kaynak kodunda dolaşmak için eğlenceli bir bahane oldu.
Çoğunlukla Zararsız

2
Teşekkürler! Başka bir botun puanına yaklaşacağını sanmıyorum. Ve bu stratejiyi uygulamayı düşünen başka biri için yapma. Bundan böyle bu strateji kurallara aykırı ve turnuvanın adil olmasını sağlamak için kullanmasına izin verilen tek kişi NeoBot.
azami

1
Eh, myBot her birini yeniyor, ama bu çok daha iyi - sanki eğer botu böyle yazarsam, -100 alırdım ve en iyi puanı alamazdım.
Jan Ivan

15

Kooperatif sürüsü

strateji

Bu kuralın önemini henüz başka kimsenin farketmediğini sanmıyorum:

Oyun 200 raund'a giderse, en yüksek puanı olan botlar (veya botlar) 40 puan veya daha fazla olmasa bile kazanır.

Her bot patlayana kadar her zaman toplanırsa, herkes 200inci turun sonunda sıfır puan alır ve herkes kazanır! Dolayısıyla, Kooperatif Sürüsü'nün stratejisi, tüm oyuncular sıfır puan aldıkları sürece işbirliği yapmak, ancak herhangi bir puan alırsa normal olarak oynamaktır.

Bu yazıda, iki bot gönderiyorum: ilki CooperativeSwarmBot, ikincisi CooperativeThrowTwice. CooperativeSwarmBot, resmi olarak kooperatif kümesinin bir parçası olan tüm botlar için bir temel sınıf olarak hizmet eder ve işbirliği başarısız olduğunda ilk başarılı rolünü kabul etme konusunda yer tutucu davranışına sahiptir. CooperativeSwarmBot, ebeveyni olarak CooperativeSwarmBot'a sahiptir ve kooperatif olmayan davranışının bir yerine iki rulo yapmak dışında her şekilde aynıdır. Önümüzdeki birkaç gün içinde, kooperatif olmayan botlara karşı daha akıllı davranışı kullanan yeni botlar eklemek için bu yazıyı revize edeceğim.

kod

class CooperativeSwarmBot(Bot):
    def defection_strategy(self, scores, last_round):
        yield False

    def make_throw(self, scores, last_round):
        cooperate = max(scores) == 0
        if (cooperate):
            while True:
                yield True
        else:
            yield from self.defection_strategy(scores, last_round)

class CooperativeThrowTwice(CooperativeSwarmBot):
    def defection_strategy(self, scores, last_round):
        yield True
        yield False

analiz

yaşayabilirlik

Bu oyunda işbirliği yapmak çok zor çünkü bunun için sekiz oyuncunun da desteğine ihtiyacımız var. Her bot sınıfı oyun başına bir örnekle sınırlı olduğundan, elde edilmesi zor bir hedeftir. Örneğin, 100 kooperatif botu ve 30 kooperatif olmayan bot havuzundan sekiz kooperatif botu seçme şansı:

100130991299812897127961269512594124931230.115

icn

c!÷(ci)!(c+n)!÷(c+ni)!

i=8n=38

Vaka Analizi

Bir takım nedenlerden dolayı (dipnot 1 ve 2'ye bakınız), resmi bir oyunda uygun bir kooperatif sürüsü asla rekabet etmeyecektir. Dolayısıyla, bu bölümdeki kendi simülasyonlarımdan birinin sonuçlarını özetleyeceğim.

Bu simülasyon, en son kontrol ettiğimde burada yayınlanan diğer 38 botu ve ebeveyn sınıfı olarak CooperativeSwarmBot olan 2900 botu kullanarak 10000 oyun yaptı. Kontrolör, 10000 oyunun 9051'inin (% 90,51) 200 turda sona erdiğini, bunun da oyunların% 90'ının kooperatif olacağı tahminine oldukça yakın olduğunu bildirdi. Bu botların uygulanması önemsizdi; CooperativeSwarmBot dışında hepsi bu formu aldı:

class CooperativeSwarm_1234(CooperativeSwarmBot):
    pass

Botların% 3'ünden daha az kazanma yüzdesi % 80'in altındaydı ve botların% 11'inden fazlası oynadıkları her oyunda kazandı. Sürüdeki 2900 botun ortanca kazanma yüzdesi yaklaşık% 86'dır, bu çirkin bir şekilde iyidir. Karşılaştırma için, mevcut resmi liderlik tablosundaki en iyi oyuncular oyunlarının% 22'sinden azını kazanıyor. Kooperatif sürüsünün tam listesine bir cevap için izin verilen maksimum süre dahilinde sığamıyorum, bu nedenle bunun yerine buraya gitmek zorunda kalacağınızı görmek istiyorsanız: https://pastebin.com/3Zc8m1Ex

Her bot ortalama 27 oyunda oynadığından, bireysel botların sonuçlarına baktığınızda şans nispeten büyük bir rulo oynuyor. Kooperatif olmayan oyunlar için henüz gelişmiş bir strateji uygulamadığım için, diğer pek çok bot kooperatif sürüsüne karşı oynamaktan, kooperatif sürüsünün medyan kazanma oranını bile% 86 oranında gerçekleştirmekten büyük ölçüde faydalandı.

Sürüde bulunmayan botların tam sonuçları aşağıda listelenmiştir; Sonuçları belli bir ilgiyi hakettiğini düşündüğüm iki bot var. İlk olarak, StopBot hiç oyun kazanamadı. Bu özellikle trajiktir çünkü kooperatif sürüsü aslında StopBot ile aynı stratejiyi kullanıyordu; StopBot'un oyunlarından sekizi şans eseri kazanmasını beklerdiniz ve biraz daha fazlası çünkü kooperatif sürüsü rakiplerine ilk hamleyi vermek zorunda kaldı. Bununla birlikte, ikinci ilginç sonuç, PointsAreForNerdsBot'un zor çalışmasının nihayetinde karşılığını vermesiydi: sürüyle işbirliği yaptı ve oynadığı her oyunu kazanmayı başardı!

+---------------------+----+--------+--------+------+------+-------+------+--------+
|Bot                  |Win%|    Wins|  Played|   Max|   Avg|Avg win|Throws|Success%|
+---------------------+----+--------+--------+------+------+-------+------+--------+
|AggressiveStalker    |100.0|      21|      21|    42| 40.71|  40.71|  3.48|   46.32|
|PointsAreForNerdsBot |100.0|      31|      31|     0|  0.00|   0.00|  6.02|    0.00|
|TakeFive             |100.0|      18|      18|    44| 41.94|  41.94|  2.61|   50.93|
|Hesitate             |100.0|      26|      26|    44| 41.27|  41.27|  3.32|   41.89|
|Crush                |100.0|      34|      34|    44| 41.15|  41.15|  5.38|    6.73|
|StepBot              |97.0|      32|      33|    46| 41.15|  42.44|  4.51|   24.54|
|LastRound            |96.8|      30|      31|    44| 40.32|  41.17|  3.54|   45.05|
|Chaser               |96.8|      30|      31|    47| 42.90|  44.33|  3.04|   52.16|
|GoHomeBot            |96.8|      30|      31|    44| 40.32|  41.67|  5.60|    9.71|
|Stalker              |96.4|      27|      28|    44| 41.18|  41.44|  2.88|   57.53|
|ClunkyChicken        |96.2|      25|      26|    44| 40.96|  41.88|  2.32|   61.23|
|AdaptiveRoller       |96.0|      24|      25|    44| 39.32|  40.96|  4.49|   27.43|
|GoTo20Bot            |95.5|      21|      22|    44| 40.36|  41.33|  4.60|   30.50|
|FortyTeen            |95.0|      19|      20|    48| 44.15|  45.68|  3.71|   43.97|
|BinaryBot            |94.3|      33|      35|    44| 41.29|  41.42|  2.87|   53.07|
|EnsureLead           |93.8|      15|      16|    55| 42.56|  42.60|  4.04|   26.61|
|Roll6Timesv2         |92.9|      26|      28|    45| 40.71|  42.27|  4.07|   29.63|
|BringMyOwn_dice      |92.1|      35|      38|    44| 40.32|  41.17|  4.09|   28.40|
|LizduadacBot         |92.0|      23|      25|    54| 47.32|  51.43|  5.70|    5.18|
|FooBot               |91.7|      22|      24|    44| 39.67|  41.45|  3.68|   51.80|
|Alpha                |91.7|      33|      36|    48| 38.89|  42.42|  2.16|   65.34|
|QuotaBot             |90.5|      19|      21|    53| 38.38|  42.42|  3.88|   24.65|
|GoBigEarly           |88.5|      23|      26|    47| 41.35|  42.87|  3.33|   46.38|
|ExpectationsBot      |88.0|      22|      25|    44| 39.08|  41.55|  3.57|   45.34|
|LeadBy5Bot           |87.5|      21|      24|    50| 37.46|  42.81|  2.20|   63.88|
|GamblersFallacy      |86.4|      19|      22|    44| 41.32|  41.58|  2.05|   63.11|
|BePrepared           |86.4|      19|      22|    59| 39.59|  44.79|  3.81|   35.96|
|RollForLuckBot       |85.7|      18|      21|    54| 41.95|  47.67|  4.68|   25.29|
|OneStepAheadBot      |84.6|      22|      26|    50| 41.35|  46.00|  3.34|   42.97|
|FlipCoinRollDice     |78.3|      18|      23|    51| 37.61|  44.72|  1.67|   75.42|
|BlessRNG             |77.8|      28|      36|    47| 40.69|  41.89|  1.43|   83.66|
|FutureBot            |77.4|      24|      31|    49| 40.16|  44.38|  2.41|   63.99|
|SlowStart            |68.4|      26|      38|    57| 38.53|  45.31|  1.99|   66.15|
|NotTooFarBehindBot   |66.7|      20|      30|    50| 37.27|  42.00|  1.29|   77.61|
|ThrowThriceBot       |63.0|      17|      27|    51| 39.63|  44.76|  2.50|   55.67|
|OneInFiveBot         |58.3|      14|      24|    54| 33.54|  44.86|  2.91|   50.19|
|MatchLeaderBot       |48.1|      13|      27|    49| 40.15|  44.15|  1.22|   82.26|
|StopBot              | 0.0|       0|      27|    43| 30.26|   0.00|  1.00|   82.77|
+---------------------+----+--------+--------+------+------+-------+------+--------+

Kusurlar

Bu işbirlikçi yaklaşımın birkaç dezavantajı var. Birincisi, kooperatif olmayan botlara karşı oynarken kooperatif botları asla ilk sırayı alamazlar, çünkü ilk oynadıklarında, rakiplerinin işbirliği yapmaya istekli olup olmadıklarını henüz bilemezler, ve böylece bir seçim yapmaktan başka çareleri olmaz. sıfır puan Benzer şekilde, bu kooperatif stratejisi kötü niyetli botların sömürmesine karşı son derece savunmasız; örneğin, kooperatif oyun sırasında, son turda en son oynayan bot, diğer herkesin kaybetmesini sağlamak için derhal yuvarlanmayı bırakmayı seçebilir (elbette ilk atışlarının altı olmadığı varsayılarak).

İşbirliği yaparak, tüm botlar% 100 kazanma oranının optimal çözümünü elde edebilir. Dolayısıyla, kazanma oranı önemli olan tek şey olsaydı, işbirliği istikrarlı bir denge olurdu ve endişelenecek bir şey olmazdı. Bununla birlikte, bazı botlar, lider panosuna ulaşmak gibi diğer hedeflere öncelik verebilir. Bu, son dönüşünüzden sonra başka bir botun kusurlu olma riski taşıdığı anlamına gelir, bu da ilk önce kusurlu olmanız için bir teşvik oluşturur. Bu yarışmanın düzenlenmesi, rakiplerimizin önceki oyunlarında ne yaptığını görmemize izin vermediğinden, kusurlu kişileri cezalandıramayız. Bu nedenle, işbirliği sonuçta başarısızlığa mahkum dengesiz bir dengedir.

Dipnotlar

[1]: Sadece iki yerine binlerce bot göndermek istemememin temel nedenleri, simülasyonu 1000'in üzerinde bir faktöre göre yavaşlatmasıdır [2] ve bunu yapmanın ciddi bir kargaşaya neden olacağıdır. Diğer botlar neredeyse yalnızca birbirlerinden ziyade sürüye karşı oynayacakları için yüzdeleri kazan. Ancak, daha önemlisi, istemiş olsam bile, bir çok botun makul bir zaman dilimi içinde kuralım ruhunu kırmadan, “Bir bot aynı stratejiyi uygulamamalı. kasıtlı olarak veya kazayla bir tane var olan ".

[2]: Kooperatif sürüsü çalıştırırken simülasyonun yavaşlamasının iki ana nedeni olduğunu düşünüyorum. İlk olarak, daha fazla bot, her bir botun aynı sayıda oyunda oynamasını istiyorsanız daha fazla oyun anlamına gelir (örnek olay incelemesinde, oyun sayısı yaklaşık 77 faktöre göre değişir). İkincisi, kooperatif oyunları sadece 200 tur boyunca sürdüğü için daha uzun sürüyor ve yuvarlak bir oyuncu içinde süresiz olarak kaymaya devam etmek zorundalar. Kurulumum için, oyunların simülasyonu yaklaşık 40 kat daha uzun sürdü: vaka çalışması 10000 oyunu çalıştırmak için üç dakikadan biraz fazla sürdü, ancak kooperatif sürüsünü çıkardıktan sonra sadece 4.5 saniyede 10000 oyunu bitirecekti. Bu iki nedenin arasında, olmadığında rekabet eden bir küme olduğunda botların performansını doğru bir şekilde ölçmenin yaklaşık 3100 kat daha uzun olacağını tahmin ediyorum.


4
Vay. Ve PPCG'ye hoş geldiniz. Bu oldukça ilk cevap. Gerçekten böyle bir durumu planlamıyordum. Kurallarda kesinlikle bir kaçamak buldun. Cevabınız tek bir bottan ziyade botlardan oluşan bir koleksiyon olduğundan, bunu nasıl değerlendirmem gerektiğinden emin değilim. Ancak, şu anda söyleyeceğim tek şey, bir katılımcının tüm botların% 98,7'sini kontrol edeceği haksızlık hissi veriyor.
maxb

2
Aslında çift botların resmi yarışmada olmasını istemiyorum; Bu yüzden binlerce neredeyse aynı robotu göndermek yerine simülasyonu kendim koştum. Bunu daha net yapmak için gönderimde değişiklik yapacağım.
Einhaender

1
Böyle bir cevabı beklemiş olsaydım, 200 raund'a kadar çıkan oyunları oyunculara skor vermemeleri için değiştirirdim. Ancak, not ettiğiniz gibi, bu stratejiyi kurallara aykırı hale getirecek özdeş botlar oluşturma hakkında bir kural vardır. Kuralları değiştirmeyeceğim, çünkü bot yapan herkes için haksızlık olur. Bununla birlikte, işbirliği kavramı çok ilginçtir. Umarım, işbirliği stratejisini kendi benzersiz stratejisiyle birlikte uygulayan başka botlar da gönderilir.
maxb

1
Sanırım gönderiniz daha ayrıntılı olarak okunduktan sonra açık.
maxb

Birçoğunun lider yerleşiminde net bir kazanç görebilmesi için kaç tane robotun kodlarını bu işbirliği çerçevesine koyması gerekecek? Saf tahminim% 50.
Sparr,

10

GoTo20Bot

class GoTo20Bot(Bot):

    def make_throw(self, scores, last_round):
        target = min(20, 40 - scores[self.index])
        if last_round:
            target = max(scores) - scores[self.index] + 1
        while sum(self.current_throws) < target:
            yield True
        yield False

Sadece hepsini denemelisin GoToNBot, Ve 20, 22, 24 en iyi oyun. Neden bilmiyorum.


Güncelleme: puan 40 veya daha fazla olsun her zaman atmayı durdurun.


Ben de bu tür botlarla denedim. Tur başına en yüksek ortalama puan, bot 16'ya gittiğinde bulunur, ancak "son oyun" un 20 botu daha sık kazandığını düşünüyorum.
maksimum

@ maxb Öyle değil, 20 hala benim test "son oyun" olmadan en iyisi olmak. Belki de kontrol cihazının eski versiyonunda test ettin.
18'de

Bu mücadeleyi tasarlamadan önce ayrı bir test yaptım; buradaki yazımdaki iki taktik için tur başına ortalama puanı hesapladım ("x kez at" ve "x puana kadar at") ve bulduğum maksimum 15-16 idi. . Örneklem büyüklüğüm çok küçük olsa da kararsızlık olduğunu fark ettim.
maksimum

2
Bununla bazı testler yaptım ve sonucum 20'nin 40/2 olduğundan iyi sonuç vermesi. Yine de tam olarak emin değilim. end_score4000 olarak belirlediğimde (ve targethesaplamada bunu kullanmak için botunuzu değiştirdim ) 15-16 botlar çok daha iyiydi. Ancak oyun sadece puanınızı arttırmakla ilgiliyse önemsiz olacaktır.
maxb

1
@ maxb end_score4000 ise, 200 turdan önce 4000 almak neredeyse imkansızdır. Ve oyun sadece 200 turda en yüksek puana sahip olan oyundur. Ve 15 yaşında durmak işe yarayacak, bu sefer bir sırayla en yüksek skor stratejisi 200 sıradaki en yüksek skorla aynı olacak.
tsh

10

Adaptif rulo

Daha agresif başlar ve turun sonuna doğru sakinleşir.
Kazandığına inanıyorsa, güvenlik için fazladan bir zaman ayırın.

class AdaptiveRoller(Bot):

    def make_throw(self, scores, last_round):
        lim = min(self.end_score - scores[self.index], 22)
        while sum(self.current_throws) < lim:
            yield True
        if max(scores) == scores[self.index] and max(scores) >= self.end_score:
            yield True
        while last_round and scores[self.index] + sum(self.current_throws) <= max(scores):
            yield True
        yield False

Harika ilk başvuru! Testler için yazdığım botlarıma karşı koyacağım, fakat daha fazla bot gönderildiğinde yüksek skoru güncelleyeceğim.
maksimum

Botunuzda küçük değişiklikler yaparak bazı testler yaptım. lim = max(min(self.end_score - scores[self.index], 24), 6)Maksimum değeri 24'e yükseltmek ve en az 6 eklemek hem kazanma yüzdesini kendi başına hem de daha fazla bir araya getirerek arttırır.
AKroell

@ AKroell: Harika! Sonunda birkaç kez yuvarlandığından emin olmak için benzer bir şey yapmayı planlamıştım, ancak kendim için henüz zamanım olmadı. Garip bir şekilde, 100k koşu yaptığım zaman bu değerlerle daha kötü performans gösteriyor gibi görünüyor. Sadece 18 botla test ettim. Belki de tüm botlarla bazı testler yapmalıyım.
Emigna

5

Alfa

class Alpha(Bot):
    def make_throw(self, scores, last_round):
        # Throw until we're the best.
        while scores[self.index] + sum(self.current_throws) <= max(scores):
            yield True

        # Throw once more to assert dominance.
        yield True
        yield False

Alpha, hiç kimseye ikinci olmayı reddediyor. Daha yüksek skorlu bir bot olduğu sürece, yuvarlanmaya devam edecek.


Nasıl yieldçalıştığından dolayı, yuvarlanmaya başlarsa asla durmayacak. Döngüde güncellemek istersiniz my_score.
Spitemaster

@Spitemaster Sabit, teşekkürler.
Anma

5

NotTooFarBehindBot

class NotTooFarBehindBot(Bot):
    def make_throw(self, scores, last_round):
        while True:
            current_score = scores[self.index] + sum(self.current_throws)
            number_of_bots_ahead = sum(1 for x in scores if x > current_score)
            if number_of_bots_ahead > 1:
                yield True
                continue
            if number_of_bots_ahead != 0 and last_round:
                yield True
                continue
            break
        yield False

Buradaki fikir, diğer botların puan kaybedebileceği, yani 2. olmak fena değil - ama eğer çok geride kaldıysanız, kırılmaya da gidebilirsiniz.


1
PPCG'ye Hoşgeldiniz! Gönderiminize bakıyorum ve görünen o ki, oyunda ne kadar fazla oyuncu olursa, kazanma oranı o kadar düşük olur. Neden hemen söyleyemem. Botlar 1vs1 ile eşleştirildiğinde,% 10'luk bir kazanma oranı elde edersiniz. Fikir umut verici görünüyor ve kod doğru görünüyor, bu yüzden neden winrate'in daha yüksek olmadığını söyleyemem.
maxb

6
Davranış içine baktım ve bu çizgide kafam karıştı 6: Bot NotTooFarBehindBot plays [4, 2, 4, 2, 3, 3, 5, 5, 1, 4, 1, 4, 2, 4, 3, 6] with scores [0, 9, 0, 20, 0, 0, 0] and last round == False. Botunuz 7 atıştan sonra öne geçse de 6'ya kadar devam eder. Bunu yazarken konuyu çözdüm! scoresSadece toplam skorları değil, mevcut tur için kalıp vakaları içerir. Olması için değiştirmelisin current_score = scores[self.index] + sum(self.current_throws).
maxb

Teşekkürler - bu değişikliği yapacak!
Stuart Moore

5

GoHomeBot

class GoHomeBot(Bot):
    def make_throw(self, scores, last_round):
        while scores[self.index] + sum(self.current_throws) < 40:
            yield True
        yield False

Büyük ya da eve gitmek istiyoruz, değil mi? GoHomeBot çoğunlukla sadece eve gider. (Ama şaşırtıcı derecede iyi yapıyor!)


Bu bot her zaman 40 puan kazandığından, hiçbir zaman scoreslistede hiç puan kalmayacak . Daha önce böyle bir bot vardı (GoToEnd botu), ama David cevaplarını sildi. O botu senin yerine değiştireceğim.
maxb

1
PointsAreForNerds ve StopBot dışında, işbu bot en düşük ortalama noktaları vardır ve henüz bu hoş bir kazanım oranına sahip: O expaned istatistikleri bu botlar görerek, oldukça komik
Belhenix

5

EnsureLead

class EnsureLead(Bot):

    def make_throw(self, scores, last_round):
        otherScores = scores[self.index+1:] + scores[:self.index]
        maxOtherScore = max(otherScores)
        maxOthersToCome = 0
        for i in otherScores:
            if (i >= 40): break
            else: maxOthersToCome = max(maxOthersToCome, i)
        while True:
            currentScore = sum(self.current_throws)
            totalScore = scores[self.index] + currentScore
            if not last_round:
                if totalScore >= 40:
                    if totalScore < maxOtherScore + 10:
                        yield True
                    else:
                        yield False
                elif currentScore < 20:
                    yield True
                else:
                    yield False
            else:
                if totalScore < maxOtherScore + 1:
                    yield True
                elif totalScore < maxOthersToCome + 10:
                    yield True
                else:
                    yield False

EnsureLead, GoTo20Bot'tan fikir ödünç alıyor. Her zaman (last_round içindeyken veya 40'a ulaştığında) en az bir ruloya sahip olacak başkalarının olduğunu düşündüğü kavramını ekler. Böylece, bot onları yakalamak için biraz öne geçmeye çalışır.


4

Roll6TimesV2

Şu anki en iyiyi geçmiyor, ama bence oyunda daha fazla botla daha iyi olacak.

class Roll6Timesv2(Bot):
    def make_throw(self, scores, last_round):

        if not last_round:
            i = 0
            maximum=6
            while ((i<maximum) and sum(self.current_throws)+scores[self.index]<=40 ):
                yield True
                i=i+1

        if last_round:
            while scores[self.index] + sum(self.current_throws) < max(scores):
                yield True
        yield False

Bu arada gerçekten harika bir oyun.


PPCG'ye Hoşgeldiniz! Sadece ilk KotH mücadelen için değil, ilk cevabın için çok etkileyici. Oyunu sevdiğine sevindim! Oynadığım akşamdan sonra oyun için en iyi taktik hakkında çok tartışma yaptım, bu yüzden bir meydan okuma için mükemmel görünüyordu. Sen 18. dışına üçüncü sırada yer Gittiğiniz
maxb

4

StopBot

class StopBot(Bot):
    def make_throw(self, scores, last_round):
        yield False

Kelimenin tam anlamıyla sadece bir atış.

Bu, temel Botsınıfa eşdeğerdir .


1
Üzülme Tüm kuralları izliyorsunuz, ancak botunuzun tur başına ortalama 2,5 puanla çok etkili olmadığından korkuyorum.
maxb

1
Biliyorum, birileri o botu göndermek zorunda kaldı. Kayıp için dejenere botlar.
Zacharı

5
Son benzetimde tam olarak bir galibiyet aldığınızı ve bunun tamamen işe yaramaz olmadığını kanıtladığınızı kanıtladığımı söyleyebilirim.
maxb

2
BİR OYUN KAZANDI ?! Bu şaşırtıcı.
Zacharı

3

BringMyOwn_dice (BMO_d)

Bu bot zarları sever, 2'sini getirir (en iyisini yapıyor gibi görünüyor). Bir rauntta zar atmadan önce, kendi 2 zarını atar ve toplamını hesaplar, bu, gerçekleştireceği atma sayısıdır, sadece 40 puan atarsa ​​atır.

class BringMyOwn_dice(Bot):

    def __init__(self, *args):
        import random as rnd
        self.die = lambda: rnd.randint(1,6)
        super().__init__(*args)

    def make_throw(self, scores, last_round):

        nfaces = self.die() + self.die()

        s = scores[self.index]
        max_scores = max(scores)

        for _ in range(nfaces):
            if s + sum(self.current_throws) > 39:
                break
            yield True

        yield False

2
Bir madeni para çevirme kullanarak rastgele bir bot düşünüyordum, ama bu meydan okuma ile daha ruhu! İki zarın en iyi performansı verdiğini düşünüyorum, çünkü kalıbı 5-6 kez atarken tur başına en fazla puanı alıyorsunuz, iki zar attığınızda ortalama puana yakın.
maxb

3

FooBot

class FooBot(Bot):
    def make_throw(self, scores, last_round):
        max_score = max(scores)

        while True:
            round_score = sum(self.current_throws)
            my_score = scores[self.index] + round_score

            if last_round:
                if my_score >= max_score:
                    break
            else:
                if my_score >= self.end_score or round_score >= 16:
                    break

            yield True

        yield False

# Must throw at least oncegereksizdir - botunuzu çağırmadan önce bir kez atar. Botunuz daima en az iki kere atar.
Spitemaster

Teşekkürler. Yöntemin adıyla yanıldım.
Peter Taylor

@PeterTaylor Gönderiniz için teşekkürler! make_throwOyuncunun sırasını atlayabilmeyi istediğimde, yöntemi daha önce adlandırdım . Sanırım daha uygun bir isim olurdu keep_throwing. Sanal alandaki geri bildirimleriniz için teşekkür ederiz, bu gerçekten uygun bir zorluk haline geldi!
maxb

3

Büyük Erken Git

class GoBigEarly(Bot):
    def make_throw(self, scores, last_round):
        yield True  # always do a 2nd roll
        while scores[self.index] + sum(self.current_throws) < 25:
            yield True
        yield False

Konsept: Erken bir ruloda büyük kazanmaya çalışın (25'e kadar) Sonra bir kerede 2 rulo yukarı doğru sürün.


3

BinaryBot

Son puana yaklaşmaya çalışır, böylece bir başkası son tura başlar başlamaz galibiyet için kendi skorunu yenebilir. Hedef, mevcut puan ve bitiş puanı arasında daima yarı yoldadır.

class BinaryBot(Bot):

    def make_throw(self, scores, last_round):
        target = (self.end_score + scores[self.index]) / 2
        if last_round:
            target = max(scores)

        while scores[self.index] + sum(self.current_throws) < target:
            yield True

        yield False

İlginç, Hesitateayrıca ilk önce çizgiyi geçmeyi reddediyor. İşlevinizi classmalzeme ile kuşatmanız gerekir.
Christian Sievers

3

PointsAreForNerdsBot

class PointsAreForNerdsBot(Bot):
    def make_throw(self, scores, last_round):
        while True:
            yield True

Bunun bir açıklaması gerekmiyor.

OneInFiveBot

class OneInFiveBot(Bot):
    def make_throw(self, scores, last_round):
        while random.randint(1,5) < 5:
            yield True
        yield False

Kendi 5 taraflı kalıbında beşe dolana kadar yuvarlanmaya devam eder. Beş altıdan az, bu yüzden kazanmak zorunda!


2
PPCG'ye Hoşgeldiniz! Eminim farkındasınız, ancak ilk botunuz tam anlamıyla bu yarışmanın en kötü botu! OneInFiveBotDüzgün bir fikirdir, ama daha gelişmiş botların bazılarına göre son oyunda uğrar düşünüyorum. Yine de harika bir sunum!
maxb

2
Bu OneInFiveBot, sürekli olarak en yüksek toplam puana ulaşması bakımından oldukça ilginçtir.
AKroell

1
StopBotKum torbasını verdiğin için teşekkürler : P. OneInFiveBot aslında oldukça temiz, güzel bir iş!
Zacharý

@ maxb Yep, adımı orası aldım. Dürüst olmak gerekirse test etmedim OneInFiveBotve beklediğimden çok daha iyi yapıyor
The_Bob


3

LizduadacBot

1 adımda kazanmaya çalışır. Son koşul, biraz keyfi.

Bu da benim ilk yazım (ve Python'da yeniyim), bu yüzden "PointsAreForNerdsBot" u geçersem mutlu olurum!

class LizduadacBot(Bot):

    def make_throw(self, scores, last_round):
        while scores[self.index] + sum(self.current_throws) < 50 or scores[self.index] + sum(self.current_throws) < max(scores):
            yield True
        yield False

PPCG'ye Hoş Geldiniz (ve Python'a Hoş Geldiniz)! Kaybetmekte zorlanacaksınız PointsAreForNerdsBotama botunuz aslında oldukça iyi. Puanı bu gece veya yarın saatinde güncelleyeceğim, ancak kazancınız yaklaşık% 15'tir, bu da ortalama% 12,5'ten yüksektir.
maxb

"Zor zamanlar" derken, bunun imkansız olduğu anlamına geliyor (çok fazla yanlış
anlamadığım

@ maxb Aslında kazanma oranının o kadar yüksek olacağını düşünmedim! (Yerel olarak test etmedim). Acaba 50'yi biraz daha yüksek / düşük olarak değiştirmenin kazanma oranını arttırıp arttırmayacağını merak ediyorum.
lizduadac

3

Yavaş başla

Bu bot, TCP Yavaş Başlatma algoritmasını uygular. Bu silindirler (sayısını ayarlar de önceki da bir 6 rulo yoktu, kalma oranını arttırmaktadır:) önceki dönüş göre de , bu dönüş için; oysa azalır ya da azalır .

class SlowStart(Bot):
    def __init__(self, *args):
        super().__init__(*args)
        self.completeLastRound = False
        self.nor = 1
        self.threshold = 8

    def updateValues(self):
        if self.completeLastRound:
            if self.nor < self.threshold:
                self.nor *= 2
            else:
                self.nor += 1
        else:
            self.threshold = self.nor // 2
            self.nor = 1


    def make_throw(self, scores, last_round):

        self.updateValues()
        self.completeLastRound = False

        i = 1
        while i < self.nor:
            yield True

        self.completeLastRound = True        
        yield False

PPCG'ye Hoşgeldiniz! İlginç bir yaklaşım, rastgele dalgalanmalara karşı ne kadar hassas olduğunu bilmiyorum. Bu çalışmayı yapmak için gereken iki şey: def updateValues():olmalıdır def updateValues(self):(ya def update_values(self):da PEP8'i takip etmek istiyorsanız). İkincisi, arama updateValues()yerine self.updateValues()(veya self.update_vales()) olmalıdır.
maxb

2
Ayrıca, iwhile döngüsünde değişkeninizi güncellemeniz gerektiğini düşünüyorum . Şu anda botunuz süre döngüsünü tamamen geçiyor veya 6'ya ulaşana kadar süre döngüsüne takılıyor.
maxb

Mevcut yüksek puanlarda, bu değişiklikleri uygulama özgürlüğünü aldım. Bence bunun başlangıç ​​değerini deneyebilir self.norve bunun botunuzun performansını nasıl etkilediğini görebilirsiniz.
maksimum

3

KwisatzHaderach

import itertools
class KwisatzHaderach(Bot):
    """
    The Kwisatz Haderach foresees the time until the coming
    of Shai-Hulud, and yields True until it is immanent.
    """
    def __init__(self, *args):
        super().__init__(*args)
        self.roller = random.Random()
        self.roll = lambda: self.roller.randint(1, 6)
        self.ShaiHulud = 6

    def wormsign(self):
        self.roller.setstate(random.getstate())
        for i in itertools.count(0):
            if self.roll() == self.ShaiHulud:
                return i

    def make_throw(self, scores, last_round):
        target = max(scores) if last_round else self.end_score
        while True:
            for _ in range(self.wormsign()):
                yield True
            if sum(self.current_throws) > target + random.randint(1, 6):
                yield False                                               

Bilinç genellikle kazanır - fakat kaderden kaçınılmaz.
Büyük ve gizemli, Shai-Hulud'un yolları!


Bu zorluğun ilk günlerinde (yani daha önce NeoBotyayınlanmıştı), neredeyse önemsiz bir Oraclebot yazdım :

    class Oracle(Bot):
        def make_throw(self, scores, last_round):
        randơm = random.Random()
        randơm.setstate(random.getstate())
        while True:
            yield randơm.randint(1, 6) != 6

ama yeterince ilginç olmadığını düşündüğüm için göndermedim;) Ama bir kez NeoBotöncülüğe girdiğinde, geleceği tahmin etme konusundaki mükemmel yeteneğini nasıl yeneceğini düşünmeye başladım. İşte bir Dune teklifi; Paul Atreides, Kwisatz Haderach, farklı geleceklerin sonsuzluğunun ortaya çıkabileceği bir bağın içinde dururken:

Farkında olduğu bilinç, bir zamanlar doğruluk ve anlamlı bir hata kaynağı olan ortaya çıkardıklarının sınırlarını içeren bir aydınlanmaydı. Bir çeşit Heisenberg belirsizlik müdahalesine müdahale etti: gördüklerini ortaya çıkaran, gördüğü şeyi değiştiren enerjinin harcanması…… en küçük hareket - bir göz kırpması, dikkatsiz bir kelime, yanlış yerleştirilmiş bir kum tanesi - devasa bir kolu hareket ettirdi bilinen evren. Sonucu o kadar çok değişkene maruz bırakarak şiddet gördü ki en küçük hareketi desenlerde büyük değişiklikler yarattı.

Vizyon onu hareketsizliğe dondurmak istemesine neden oldu, ama bu da sonuçları ile harekete geçti.

İşte cevap buydu: Geleceği öngörmek, onu değiştirmek; ve eğer çok dikkatli olursanız, seçici eylem veya hareketsizlikle, en azından çoğu zaman, bunu avantajlı bir şekilde değiştirebilirsiniz. KwisatzHaderach% 100 kazanma oranı bile alamıyor!


Bu botun, 6 yuvarlanmasından kaçınılmasını veya en azından onu öngörmesini sağlamak için rasgele sayı üretecinin durumunu değiştirdiği anlaşılıyor. Aynı HarkonnenBot için de geçerli. Ancak, bu botların kazanma oranlarının NeoBot'tan daha yüksek olduğuna dikkat ediyorum. 6'yı yuvarlamasını önlemek için rasgele sayı üretecini aktif olarak mı kullanıyorsunuz?
maxb

Oh, ilk okumamda bunun sadece daha iyi NeoBotdeğil aynı zamanda daha iyi olduğunu farketmedim ! Ayrıca, burada rastgele kullanım (özellikle de denetleyici) kullanarak her şeyin ne yapması gerektiğine dair bir örnek vermeyi seviyorum: kendi random.Randomörneğinizi kullanın . Gibi NeoBot, bu kontrolörün belirtilmemiş uygulama detaylarındaki değişikliklere biraz hassas görünüyor.
Christian Sievers

@ maxb: RNG'ye dokunmuyor HarkonnenBot; rastgele sayıları hiç umursamıyor. Sadece diğer tüm botları zehirler, sonra bitiş çizgisine kadar yavaşça yürür. Birçok mutfak lezzetinde olduğu gibi, intikam, uzun ve narin hazırlıklardan sonra yavaşça en çok sevilen bir yemektir.
Dani O

@HristiyanSievers: (ve ) aksine , uygulamanın sadece bir detayına dayanır; özellikle random.random () 'un nasıl uygulandığını bilmek zorunda değildir, sadece kontrol cihazının kullandığını; DNeoBotHarkonnenBotKwisatzHaderach
Dani O

1
Tüm botlarına baktım. Ben davranmaya karar verdik KwisatzHaderachve HarkonnenBotaynı şekilde olarak NeoBot. Puanlarını daha az oyun içeren bir simülasyondan alacaklar ve resmi simülasyonda bulunmayacaklar. Ancak, onlar gibi yüksek puanlar listesinde sona erecek NeoBot. Resmi simülasyonda bulunmamalarının ana nedeni, diğer bot stratejilerini karıştırmalarıdır. Ancak. WisdomOfCrowdskatılım için uygun olmalı ve bunun için yaptığınız yeni değişiklikleri merak ediyorum!
maxb

2
class ThrowThriceBot(Bot):

    def make_throw(self, scores, last_round):
        yield True
        yield True
        yield False 

Peki, bu açıktır


Bu bot sınıfıyla bazı deneyler yaptım (ilk kez oyunu oynadığımda kullandığım taktikti). 4 atışla gittim, ancak 5-6 tur başına ortalama daha yüksek bir puana sahip.
maxb

Ayrıca, ilk KotH cevabınız için tebrikler!
maxb

2
class LastRound(Bot):
    def make_throw(self, scores, last_round):
        while sum(self.current_throws) < 15 and not last_round and scores[self.index] + sum(self.current_throws) < 40:
            yield True
        while max(scores) > scores[self.index] + sum(self.current_throws):
            yield True
        yield False

LastRound her zaman son raund gibi davranır ve son bottur: liderliğe kadar devam eder. Aynı zamanda son raunt olmadıkça veya 40 puana ulaşmadıkça 15 puandan daha azına razı olmak istemiyor.


İlginç yaklaşım Sanırım geride kalmaya başlarsa botunuz acı çeker. Tek bir turda> 30 puan alma şansı düşük olduğundan botunuzun şu anki skorunda kalması daha olasıdır.
maksimum

1
Bunun yaptığım hatadan muzdarip olduğundan şüpheleniyorum (bakınız NotTooFarBehindBot yorumlarına bakın) - son raundda olduğu gibi, kazanmazsanız 6 elde edene kadar atmaya devam edersiniz (puanlar [self.index] asla güncellenmez) Aslında - Bu eşitsizliğin yanlış yolu var mı? max (puanlar) her zaman> = puan olacak [self.index]
Stuart Moore

@StuartMoore Haha, evet, haklı olduğunu düşünüyorum. Teşekkürler!
Spitemaster

İstediğiniz şeyi yaparken 2. sırada "ve last_round" istediğinizi zannediyorum - aksi takdirde 2. süre last_round'un doğru olup olmadığına bakılacak
Stuart Moore

3
Bu kasıtlı. Sırasını sonlandırırken daima liderlikte olmaya çalışır.
Spitemaster

2

QuotaBot

Tamamen oldukça yüksek puan almış gibi görünen, saf bir "kota" sistemi.

class QuotaBot(Bot):
    def __init__(self, *args):
        super().__init__(*args)
        self.quota = 20
        self.minquota = 15
        self.maxquota = 35

    def make_throw(self, scores, last_round):
        # Reduce quota if ahead, increase if behind
        mean = sum(scores) / len(scores)
        own_score = scores[self.index]

        if own_score < mean - 5:
            self.quota += 1.5
        if own_score > mean + 5:
            self.quota -= 1.5

        self.quota = max(min(self.quota, self.maxquota), self.minquota)

        if last_round:
            self.quota = max(scores) - own_score + 1

        while sum(self.current_throws) < self.quota:
            yield True

        yield False


if own_score mean + 5:benim için hata veriyor. Ayrıcawhile sum(self.current_throws)
Spitemaster

@Spitemaster, yığın değiş tokuşuna yapıştırarak yapılan bir hataydı, şimdi çalışmalı.
FlipTack

@Spitemaster çünkü kullandığım etiketlere müdahale eden semboller <ve >semboller vardı<pre>
FlipTack

2

ExpectationsBot

Sadece düz oynar, atma için beklenen değeri hesaplar ve sadece pozitifse yapar.

class ExpectationsBot(Bot):

    def make_throw(self, scores, last_round):
        #Positive average gain is 2.5, is the chance of loss greater than that?
        costOf6 = sum(self.current_throws) if scores[self.index] + sum(self.current_throws) < 40  else scores[self.index] + sum(self.current_throws)
        while 2.5 > (costOf6 / 6.0):
            yield True
            costOf6 = sum(self.current_throws) if scores[self.index] + sum(self.current_throws) < 40  else scores[self.index] + sum(self.current_throws)
        yield False

Denetleyiciyi çalıştırırken sorun yaşıyordum, çok iş parçacığında bir "NameError: name 'bots_per_game' tanımlanmadı", bunun nasıl bir performans olduğu hakkında hiçbir fikrim yoktu.


1
Sanırım bu bir "16'ya Git" botuna eşdeğerdir, fakat henüz bunlardan birine sahip değiliz
Stuart Moore

1
@StuartMoore Bu ... çok doğru bir nokta, evet
Cain

Sorunları Windows makinemde çalıştırdığımda denetleyiciyle karşılaştım. Her nasılsa Linux makinemde iyi çalıştı. Kontrol cihazını güncelliyorum ve yayın yapıldıktan sonra gönderimi güncelleyeceğim.
maxb

@ maxb Teşekkürler, muhtemelen farklı süreçte hangi değişkenlerin mevcut olduğu hakkında bir şeyler. FYI ayrıca bu hatayı güncelledi:
Cain

2

BlessRNG

class BlessRNG(Bot):
    def make_throw(self, scores, last_round):
        if random.randint(1,2) == 1 :
            yield True
        yield False

BlessRNG FrankerZ GabeN Instagram Hesabındaki Resim ve Videoları BlessRNG


2

FortyTeen

class FortyTeen(Bot):
    def make_throw(self, scores, last_round):
        if last_round:
            max_projected_score = max([score+14 if score<self.end_score else score for score in scores])
            target = max_projected_score - scores[self.index]
        else:
            target = 14

        while sum(self.current_throws) < target:
            yield True
        yield False

Son tura kadar 14 puan kazanmaya çalışın, sonra herkesin 14 puan deneyeceğini ve bu puanı bağlamaya çalışacağını varsayalım.


Bende TypeError: unsupported operand type(s) for -: 'list' and 'int'senin bot ile.
tsh

Ben senin varsayarak yaşıyorum max_projected_score, listenin tamamı yerine listenin en fazla olmalıdır DÜZELTEBİLİRİM ben? Aksi takdirde aynı sorunu tsh ile alıyorum.
maxb

Hata! Düzeltmek için düzenlendi.
histocrat

2

tereddüt

İki mütevazı adım yapar, sonra başka birinin çizgiyi geçmesini bekler. Güncellenen sürüm artık yüksek puanı geçmeyi denemez, yalnızca ulaşmak ister - kaynak kodun iki baytını silerek performansı artırır!

class Hesitate(Bot):
    def make_throw(self, scores, last_round):
        myscore = scores[self.index]
        if last_round:
            target = max(scores)
        elif myscore==0:
            target = 17
        else:
            target = 35
        while myscore+sum(self.current_throws) < target:
            yield True
        yield False

2

asi

Bu bot, Hesitate son stratejisinin basit stratejisini birleştiriyor, BotFor2Xkim olduğunu hatırlamaya çalışıyor ve bir yanılsama içerisinde yaşadığı zaman çıldırıyor.

class Rebel(Bot):

    p = []

    def __init__(self,*args):
        super().__init__(*args)
        self.hide_from_harkonnen=self.make_throw
        if self.p:
            return
        l = [0]*5+[1]
        for i in range(300):
            l.append(sum(l[i:])/6)
        m=[i/6 for i in range(1,5)]
        self.p.extend((1-sum([a*b for a,b in zip(m,l[i:])])
                                          for i in range(300) ))

    def update_state(self,*args):
        super().update_state(*args)
        self.current_sum = sum(self.current_throws)
        # remember who we are:
        self.make_throw=self.hide_from_harkonnen

    def expect(self,mts,ops):
        p = 1
        for s in ops:
            p *= self.p[mts-s]
        return p

    def throw_again(self,mts,ops):
        ps = self.expect(mts,ops)
        pr = sum((self.expect(mts+d,ops) for d in range(1,6)))/6
        return pr>ps

    def make_throw(self, scores, last_round):
        myscore = scores[self.index]
        if len(self.current_throws)>1:
            # hello Tleilaxu!
            target = 666
        elif last_round:
            target = max(scores)
        elif myscore==0:
            target = 17
        else:
            target = 35
        while myscore+self.current_sum < target:
            yield True
        if myscore+self.current_sum < 40:
            yield False
        opscores = scores[self.index+1:] + scores[:self.index]
        for i in range(len(opscores)):
            if opscores[i]>=40:
                opscores = opscores[:i]
                break
        while True:
            yield self.throw_again(myscore+self.current_sum,opscores)

Peki bu oldukça zarif :) Ayrıca, ana yarışmada hem birinci hem de ikinci sırada yer aldığınız için tebrikler!
Dani O

Doğal olarak ben küçük değişiklikler yaptık HarkonnenBotki Rebelartık kendisi unpoison can;) ve ben de küçük değişiklikler yaptık TleilaxuBotki Rebelartık bunları algılamaz!
Dani O

1

Beş al

class TakeFive(Bot):
    def make_throw(self, scores, last_round):
        # Throw until we hit a 5.
        while self.current_throws[-1] != 5:
            # Don't get greedy.
            if scores[self.index] + sum(self.current_throws) >= self.end_score:
                break
            yield True

        # Go for the win on the last round.
        if last_round:
            while scores[self.index] + sum(self.current_throws) <= max(scores):
                yield True

        yield False

Zamanın yarısı, 6'dan önce bir 5 atacağız.


Bunun yerine 1'de durursak, daha yavaş ilerler, ancak tek bir sınırda 40'a ulaşması daha olasıdır.
Anma

Testlerimde TakeOne, TakeFive'in tur başına 24.262 puanına kıyasla tur başına 20.868 puan aldı (ve ayrıca 0.291'den 0.259'a kadar winrate getirdi). Bu yüzden buna değer olduğunu sanmıyorum.
Spitemaster

1

kovalayan

class Chaser(Bot):
    def make_throw(self, scores, last_round):
        while max(scores) > (scores[self.index] + sum(self.current_throws)):
            yield True
        while last_round and (scores[self.index] + sum(self.current_throws)) < 44:
            yield True
        while self.not_thrown_firce() and sum(self.current_throws, scores[self.index]) < 44:
            yield True
        yield False

    def not_thrown_firce(self):
        return len(self.current_throws) < 4

Chaser birinciyi yakalamaya çalışıyor Son tursa çaresizce en az 50 puana ulaşmaya çalışır. Sadece iyi bir önlem almak için ne olursa olsun en az dört kez atar.

[düzenleme 1: son rauntta altın için bir strateji eklendi]

[değiştir 2: güncellenmiş mantık çünkü bir botun yanlışlıkla sadece en yüksek bot puanlama yerine 40 puan alacağını düşündüm]

[düzenleme 3: oyun sonunda kovalayıcıyı biraz daha savunmacı hale getirdi]


PPCG'ye Hoşgeldiniz! Düzgün bir fikir sadece yakalamaya çalışmakla kalmaz, aynı zamanda ilk sırada yer alır. Şu an bir simülasyon yapıyorum ve sana iyi şanslar diliyorum!
maxb

Teşekkürler! Başlangıçta, önceki lideri sabit bir miktarla aşmaya çalıştım (6 ile 20 arasında değerler denedim) ancak iki kat daha fazla fuar daha iyi attı.
AKroell


1

FutureBot

class FutureBot(Bot):
    def make_throw(self, scores, last_round):
        while (random.randint(1,6) != 6) and (random.randint(1,6) != 6):
            current_score = scores[self.index] + sum(self.current_throws)
            if current_score > (self.end_score+5):
                break
            yield True
        yield False

OneStepAheadBot

class OneStepAheadBot(Bot):
    def make_throw(self, scores, last_round):
        while random.randint(1,6) != 6:
            current_score = scores[self.index] + sum(self.current_throws)
            if current_score > (self.end_score+5):
                break
            yield True
        yield False

Bir çift bot kendi zar setlerini getiriyorlar ve geleceği tahmin etmek için döndürüyorlar. Biri 6 ise durursa, FutureBot hangisinin 2 zarının bir sonraki rulo için olduğunu hatırlayamaz, böylece vazgeçer.

Hangisinin daha iyi olacağını merak ediyorum.

OneStepAhead, zevkime göre OneInFive'a biraz fazla benziyor, ancak aynı zamanda FutureBot ve OneInFive ile nasıl karşılaştırıldığını görmek istiyorum.

Düzenleme: Şimdi vurduktan sonra dururlar 45


PPCG'ye Hoşgeldiniz! Botunuz kesinlikle oyunun ruhu ile oynuyor! Bu akşam daha sonra bir simülasyon yapacağım.
maxb

Teşekkürler! Ne kadar iyi olacağını merak ediyorum ama düşük tarafta olacağını tahmin ediyorum.
william porter,
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.