KOTH - Yüklü RPS


12

Yarışma kalıcı olarak açıldı - 10 Ağustos 2017'de güncellendi

5 Haziran 2017'de (en iyi cevap olarak tutulacak) bir kazanan ilan etsem de yeni botları rnning edeceğim ve sonuçları güncelleyeceğim.

5 Haziran Sonuçları

Tebrikler user1502040

Beraberlik olmadığı için sadece kazanılan maçların yüzdesini gösteriyorum.

Statistician2-% 95,7 -%
Fitter89,1 -%
Nash83,9 -%
Weigher79,9 -%
ExpectedBayes76,4 -%
AntiRepeater72,1 -%
Yggdrasil65,0 -%
AntiGreedy64,1 -%
Reactor59,9 -%
NotHungry57,3 -%
NashBot55,1 -%
Blodsocer48,6 -%
BestOfBothWorlds48,4
GoodWinning-% 43,9 -% 43,9 -%
Rockstar40,5 -%
ArtsyChild40,4
Assassin- 38,1 %
WeightedRandom- % 37,7 -%
Ensemble37,4 -%
UseOpponents36,4 -%
GreedyPsychologist36,3 -%
TheMessenger33,9 -%
Copycat31,4 -%
Greedy28,3 -%
SomewhatHungry27,6 -%
AntiAntiGreedy21,0 -%
Cycler20,3 -%
Swap19,8 -%
RandomBot16,2

Her eşleştirmenin sonuç tablosunu içeren bir Google E-Tablosu oluşturdum: https://docs.google.com/spreadsheets/d/1KrMvcvWMkK-h1Ee50w0gWLh_L6rCFOgLhTN_QlEXHyk/edit?usp=sharing


Petri İkilemi sayesinde kendimi bu Tepenin Kralı ile başa çıkabildim.

Oyun

Oyun bir bükülme ile basit bir "Taş-Kağıt-Makas": Maç sırasında her zafer artışı ile kazanılan puan (R, P veya S yüklenir).

  • Kağıt Rock kazandı
  • Makas kazanır Kağıt
  • Rock Makas kazandı

Kazanan, oyunundaki yükü kadar puan alır.

Kaybeden oyundaki yükü 1 arttırır.

Beraberlik durumunda, her oyuncu oyunundaki yükü 0,5 arttırır.

100 oyundan sonra, daha fazla puana sahip olan kazanır.

örneğin: P1 yükleri [10,11,12] (Taş, Kağıt, Makas) ve P2 [7,8,9] 'a sahiptir. P1 oynar R, P2 oynar P. P2 kazanır ve 8 puan alır. P1 yükleri [11,11,12] olur, P2 yükleri aynı kalır.

Zorluk özellikleri

Programınız Python ile yazılmış olmalıdır (üzgünüm, başka türlü nasıl kullanacağımı bilmiyorum). Bu değişkenlerin her birini her yürütmede bağımsız değişken olarak alan bir işlev oluşturmalısınız:

my_points, opp_points, my_loaded, opp_loaded, my_history, opp_history

points - Güncel noktalar (senin ve oppin)

loaded- Yüklü dizi (RPS sırayla) (sizinki ve rakibiniz)

history- Tüm oyunlarla dize, son karakter son oyun (senin ve oppin)

Geri dönmelisin "R", "P"ya da "S". Farklı bir şey döndürürseniz, maçın otomatik olarak kaybedilmesi olurdu.

kurallar

Yerleşik işlevleri değiştiremezsiniz.

Test yapmak

Bir Git kodunu ve tüm botları birleştirerek güncel tutacağım: https://github.com/Masclins/LoadedRPS

YARGILAMAK

Kazanan, 1000 tam turdan sonra en çok kazanma maçına sahip olan kişiyi seçerek karar verilir. Berabere kalan maçlar berabere bitecek. Birinden çok 1000 maç oynanıyor çünkü çok fazla rastgelelik bekliyorum ve bu şekilde rastgelelik daha az alakalı olacak.

En fazla 5 bot gönderebilirsiniz.

Yarışma 4 Temmuz'da (herhangi bir cevabı kabul edeceğim son gün olacak) sona erecek ve 5 Temmuz'da son stadları göndereceğim (daha önce bir avans gönderebilir).


Bu benim ilk KOTH olduğum için, her bot için oynanan maç sayısı gibi iyileştirme için herhangi bir şeyi değiştirmeye% 100 açıldım.

1000 maçta düzenlendi, çünkü gerçekten karışıklık olduğunu görüyorum.


bazı randomize botlarla, aslında birden fazla turdan birden fazla oyun yapmak istersiniz
Yıkılabilir Limon

@DestructibleLemon Her botu bir kereden ziyade birbirlerine karşı üç kez oynatmayı düşündüm. Benzer şekilde düşündüğünü görünce, ben de yaparım.
Masclins

1
(bazı olasılıklar gerçekten birden fazla eşleşmeye yayıldığından, gerçekten çok sayıda ihtiyacınız var. botumu görün, nerede yırtılabileceğini, ancak muhtemelen adil miktarda maçla olmaz)
Yıkılabilir Limon

1
Sorumun bunu çalıştırmana yardım ettiğine sevindim, @ AlbertMasclans!
Gryphon

2
@AlbertMasclans Test komut dosyasının tamamını ( runcodeve dahil bots) gönderebilir misiniz ?
CalculatorFeline

Yanıtlar:


8

İstatistikçi (artık oynamıyor)

import random
import collections

R, P, S = moves = range(3)
move_idx = {"R": R, "P": P, "S": S}
name = "RPS"
beat = (P, S, R)
beaten = (S, R, P)

def react(_0, _1, _2, _3, _4, opp_history):
    if not opp_history:
        return random.randrange(0, 3)
    return beat[opp_history[-1]]

def anti_react(_0, _1, _2, _3, _4, opp_history):
    if not opp_history:
        return random.randrange(0, 3)
    return beaten[opp_history[-1]]

def random_max(scores):
    scores = [s + random.normalvariate(0, 1) for s in scores]
    return scores.index(max(scores))

def greedy_margin(my_points, opp_points, my_loaded, opp_loaded, my_history, opp_history):
    scores = [my_loaded[move] - opp_loaded[beat[move]] for move in moves]
    return random_max(scores)

def anti_greedy(my_points, opp_pints, my_loaded, opp_loaded, my_history, opp_history):
    scores = [-my_loaded[move] for move in moves]
    return random_max(scores)

def recent_stats(my_points, opp_points, my_loaded, opp_loaded, my_history, opp_history):
    opp_history = opp_history[-10:-1]
    counts = collections.Counter(opp_history)
    scores = [(counts[beaten[move]] + 1) * my_loaded[move] - 
              (counts[beat[move]] + 1) * opp_loaded[move] for move in moves]
    return random_max(scores)

def statistician(_0, _1, _2, _3, my_history, opp_history):
    m1 = []
    o1 = []
    my_loaded = [0] * 3
    opp_loaded = [0] * 3
    my_points = 0
    opp_points = 0
    strategies = [react, anti_react, greedy_margin, anti_greedy, recent_stats]
    strategy_scores = [0 for _ in strategies]
    for i, (mx, ox) in enumerate(zip(my_history, opp_history)):
        mx = move_idx[mx]
        ox = move_idx[ox]
        for j, strategy in enumerate(strategies):
            strategy_scores[j] *= 0.98
            move = strategy(my_points, opp_points, my_loaded, opp_loaded, m1, o1)
            if move == beat[ox]:
                strategy_scores[j] += my_loaded[move]
            elif move == beaten[ox]:
                strategy_scores[j] -= opp_loaded[ox]
        m1.append(mx)
        o1.append(ox)
        if mx == beat[ox]:
            opp_loaded[ox] += 1
            my_points += my_loaded[mx]
        elif mx == beaten[ox]:
            my_loaded[mx] += 1
            opp_points += opp_loaded[ox]
        else:
            my_loaded[mx] += 0.5
            opp_loaded[ox] += 0.5
    strategy = strategies[random_max(strategy_scores)]
    return name[strategy(my_points, opp_points, my_loaded, opp_loaded, m1, o1)]

Beklenen geçmiş performansa dayalı birkaç basit strateji arasında geçiş yapar

İstatistik 2

import random
import collections
import numpy as np

R, P, S = moves = range(3)
move_idx = {"R": R, "P": P, "S": S}
names = "RPS"
beat = (P, S, R)
beaten = (S, R, P)

def react(my_loaded, opp_loaded, my_history, opp_history):
    if not opp_history:
        return random.randrange(0, 3)
    counts = [0, 0, 0]
    counts[beat[opp_history[-1]]] += 1
    return counts

def random_max(scores):
    scores = [s + random.normalvariate(0, 1) for s in scores]
    return scores.index(max(scores))

def argmax(scores):
    m = max(scores)
    return [s == m for s in scores]

def greedy_margin(my_loaded, opp_loaded, my_history, opp_history):
    scores = [my_loaded[move] - opp_loaded[beat[move]] for move in moves]
    return argmax(scores)

recent_counts = None

def best_move(counts, my_loaded, opp_loaded):
    scores = [(counts[beaten[move]] + 0.5) * my_loaded[move] - 
              (counts[beat[move]] + 0.5) * opp_loaded[move] for move in moves]
    return argmax(scores)

def recent_stats(my_loaded, opp_loaded, my_history, opp_history):
    if len(opp_history) >= 10:
        recent_counts[opp_history[-10]] -= 1
    recent_counts[opp_history[-1]] += 1
    return best_move(recent_counts, my_loaded, opp_loaded)

order2_counts = None

def order2(my_loaded, opp_loaded, my_history, opp_history):
    if len(my_history) >= 2:
        base0 = 9 * my_history[-2] + 3 * opp_history[-2]
        order2_counts[base0 + opp_history[-1]] += 1
    base1 = 9 * my_history[-1] + 3 * opp_history[-1]
    counts = [order2_counts[base1 + move] for move in moves]
    return best_move(counts, my_loaded, opp_loaded)

def nash(my_loaded, opp_loaded, my_history, opp_history):
    third = 1.0 / 3
    p = np.full(3, third)
    q = np.full(3, third)
    u = np.array(my_loaded)
    v = np.array(opp_loaded)
    m0 = np.zeros(3)
    m1 = np.zeros(3)
    lr = 0.2
    for _ in range(10):
        de0 = u * np.roll(q, 1) - np.roll(v * q, 2)
        de1 = v * np.roll(p, 1) - np.roll(u * p, 2)
        m0 = 0.9 * m0 + 0.1 * de0
        m1 = 0.9 * m1 + 0.1 * de1
        p += lr * m0
        q += lr * m1
        p[p < 0] = 0
        q[q < 0] = 0
        tp, tq = np.sum(p), np.sum(q)
        if tp == 0 or tq == 0:
            return np.full(3, third)
        p /= tp
        q /= tq
        lr *= 0.9
    return p

strategies = [react, greedy_margin, recent_stats, order2, nash]

predictions = strategy_scores = mh = oh = None

def statistician2func(my_points, opp_points, my_loaded, opp_loaded, my_history, opp_history):
    global strategy_scores, history, recent_counts, mh, oh, predictions, order2_counts
    if not opp_history:
        strategy_scores = [0 for _ in strategies]
        recent_counts = collections.Counter()
        order2_counts = collections.Counter()
        mh, oh = [], []
        predictions = None
        return random.choice(names)
    my_move = move_idx[my_history[-1]]
    opp_move = move_idx[opp_history[-1]]
    if predictions is not None:
        for j, p in enumerate(predictions):
            good = beat[opp_move]
            bad = beaten[opp_move]
            strategy_scores[j] += (my_loaded[good] * p[good] - opp_loaded[opp_move] * p[bad]) / sum(p)
    mh.append(my_move)
    oh.append(opp_move)
    predictions = [strategy(my_loaded, opp_loaded, mh, oh) for strategy in strategies]
    strategy = random_max(strategy_scores)
    p = predictions[strategy]
    r = random.random()
    for i, pi in enumerate(p):
        r -= pi
        if r <= 0:
            break
    return names[i]

Nash

import numpy as np
import random

def nashfunc(my_points, opp_points, my_loaded, opp_loaded, my_history, opp_history):
    third = 1.0 / 3
    p = np.full(3, third)
    q = np.full(3, third)
    u = np.array(my_loaded)
    v = np.array(opp_loaded)
    m0 = np.zeros(3)
    m1 = np.zeros(3)
    lr = 0.2
    for _ in range(10):
        de0 = u * np.roll(q, 1) - np.roll(v * q, 2)
        de1 = v * np.roll(p, 1) - np.roll(u * p, 2)
        m0 = 0.9 * m0 + 0.1 * de0
        m1 = 0.9 * m1 + 0.1 * de1
        p += lr * m0
        q += lr * m1
        p[p < 0] = 0
        q[q < 0] = 0
        tp, tq = np.sum(p), np.sum(q)
        if tp == 0 or tq == 0:
            return random.choice("RPS")
        p /= tp
        q /= tq
        lr *= 0.9
    r = random.random()
    for i, pi in enumerate(p):
        r -= pi
        if r <= 0:
            break
    return "RPS"[i]

Degrade iniş ile yaklaşık Nash dengesini hesaplar.


1
Bu yaklaşımı gerçekten çok seviyorum ve durumu neden mermiler arasında tutmak isteyebileceğinizi anlayabiliyorum. Gönderme sayısı göz önüne alındığında bunu değiştirmek büyük bir sorun olsa da Bunu (bu bittiğinde yapmayı umduğum) diğer zorluklar için dikkate alacağım.
Masclins

5

tartı

Kod ile deneme yaparken akıl yürütme yolunu kaybettim, ancak temel fikir, rakibin hareket olasılığını son 3 hamle ile bazı ağırlıkları kullanarak tahmin etmek ve yüklere bağlı başka bir ağırlıkla çarpmaktır. Bir şekilde de kullanabileceğimi düşündüm my_loaded, ama nasıl karar veremedim, bu yüzden dışarıda bıraktım.

def weigher(my_points, opp_points, my_loaded, opp_loaded, my_history, opp_history):
    idx = {"R": 0, "P": 1, "S": 2}
    sc = [0, 0, 0]
    for i, m in enumerate(reversed(opp_history[-3:])):
        sc[idx[m]] += (1 / (1 + i))

    for i in range(3):
        sc[i] *= (opp_loaded[i] ** 2)

    return "PSR"[sc.index(max(sc))]

şeytan

Muhtemelen diskalifiye edilecektir, çünkü bu bir tür hile ve test işlevi hakkında bazı varsayımlar yapar (yığın çerçevesindeki bir değişkente rakibin işlevine sahip olması gerekir), ancak teknik olarak mevcut kuralları ihlal etmez - herhangi bir şeyi yeniden tanımlayın veya yeniden yazın. Ne dönüş yaptığını / yapacaklarını görmek için rakibin işlevini yürütmek için sadece kara büyü kullanır. Rasgelelik ile başa çıkamaz, ancak deterministik botların Şeytan'ı yenme şansı yoktur.

def satan(my_points, opp_points, my_loaded, opp_loaded, my_history, opp_history):
    import inspect, types
    f = inspect.currentframe()
    s = f.f_code.co_name
    try:
        for v in f.f_back.f_locals.values():
            if isinstance(v, types.FunctionType) and v.__name__ != s:
                try:
                    return "PSR"[{"R": 0, "P": 1, "S": 2}[
                        v(opp_points, my_points, opp_loaded, my_loaded, opp_history, my_history)]]
                except:
                    continue
    finally:
        del f

Kuşkusuz Sadelik-Sonuçlar açısından en iyisi
Masclins

Bu arada, kullanmak my_loadediçin son hamlelerinize karşı kaybedeceğiniz hamleye değer veren bir ağırlık ekleyebilirsiniz. Bu, rakibinizin yaptıklarınıza benzer bir şey yapacağını varsaymak gibidir ve bu nedenle aynı oyunu oynamaya devam edeceğinizi varsaydığı için onu cezalandırır. Gibi bir şey:for i, m in enumerate(reversed(my_history[-3:])): sc[(idx[m]+1)%3] += (K / (1 + i))
Masclins

@AlbertMasclans başka bir çözüm ekledi
Görünen Ad

1
Şeytan'ı çok seviyorum. Ama dediğin gibi, bunun hak kazanmaması gerektiğine inanıyorum: Açık bir kuralı çiğnemese bile, açıkça oyunun ruhuna aykırı. Yine de, fikriniz için tebrikler!
Masclins

4

Tesisatçı

Bu Bot Deseni geliştirir ve Ekonomist ile kaynaştırır (Pattern ve Economist artık katılmayacak)

Paternin iyileştirilmesi, Bot'un şimdi iki tür patern aramasıdır: Rakibin son oyununa tepki veren ve rakip son oyunuma tepki veren. Ardından, en uygun olanı kullanmak için her iki tahmini de değerlendirir.

Bu modelden Bot şimdi R, P ve S olasılıklarına sahip. Bunu hesaba katarak her bir oyunun beklenen değerini (Ekonomist'in yaptığı gibi) dikkate alarak Bot en fazla değeri veren oyunu oynar.

import random
import numpy as np
def fitterfunc(my_points, opp_points, my_loaded, opp_loaded, my_history, opp_history):
        t = len(opp_history)
        RPS = ["R","P","S"]
        if t <= 2:
                return RPS[t]
        elif t == 3:
                return random.choice(RPS)

        def n(c): return RPS.index(c)

        total_me = np.zeros(shape=(3,3))
        total_opp= np.zeros(shape=(3,3))
        p_me = np.array([[1/3]*3]*3)
        p_opp = np.array([[1/3]*3]*3)

        for i in range(1, t):
                total_me[n(my_history[i-1]), n(opp_history[i])] += 1
                total_opp[n(opp_history[i-1]), n(opp_history[i])] += 1
        for i in range(3):
                if np.sum(total_me[i,:]) != 0:
                        p_me[i,:] = total_me[i,:] / np.sum(total_me[i,:])
                if np.sum(total_opp[i,:]) != 0:
                        p_opp[i,:] = total_opp[i,:] / np.sum(total_opp[i,:])

        error_me = 0
        error_opp = 0

        for i in range(1, t):
                diff = 1 - p_me[n(my_history[i-1]), n(opp_history[i])]
                error_me += diff * diff
                diff = 1 - p_opp[n(opp_history[i-1]), n(opp_history[i])]
                error_opp += diff * diff

        if error_me < error_opp:
                p = p_me[n(my_history[-1]),:]
        else:
                p = p_opp[n(opp_history[-1]),:]


# From here, right now I weight values, though not 100% is the best idea, I leave the alternative in case I'd feel like changing it
        value = [(p[2]*my_loaded[0] - p[1]*opp_loaded[1], "R"), (p[0]*my_loaded[1] - p[2]*opp_loaded[2], "P"), (p[1]*my_loaded[2] - p[0]*opp_loaded[0], "S")]
        value.sort()

        if value[-1][0] > value[-2][0]:
                return value[-1][1]
        elif value[-1][0] > value[-3][0]:
                return random.choice([value[-1][1], value[-2][1]])
        else:
                return random.choice(RPS)

#       idx = p.tolist().index(max(p))
#       return ["P", "S", "R"][idx]

İşte iki eski kod

Desen (artık oynatılmıyor)

Patern rakibinde patern bulmaya çalışır. Son maçtan sonra rakibin oynadığı gibi görünüyor (ikinci oyunlara daha fazla ağırlık vererek). Bu sayede rakibin ne oynayacağını tahmin eder ve buna karşı oynar.

import random
import numpy as np
def patternfunc(my_points, opp_points, my_loaded, opp_loaded, my_history, opp_history):
        if len(opp_history) == 0:
                return random.choice(["R","P","S"])
        elif len(opp_history) == 1:
                if opp_history == "R":
                        return "P"
                elif opp_history == "P":
                        return "S"
                elif opp_history == "S":
                        return "R"

        p = np.array([1/3]*3)
        c = opp_history[-1]
        for i in range(1, len(opp_history)):
                c0 = opp_history[i-1]
                c1 = opp_history[i]
                if c0 == c:
                        p *= .9
                        if c1 == "R":
                                p[0] += .1
                        elif c1 == "P":
                                p[1] += .1
                        elif c1 == "S":
                                p[2] += .1

        idx = p.tolist().index(max(p))
        return ["P", "S", "R"][idx]

Ekonomist (artık oynamıyor)

Ekonomist şunları yapar: Son 9 turda ne oynadığını izleyerek rakibin her oyunun olasılığını tahmin eder. Bundan, her oyunun beklenen faydasını hesaplar ve beklenen en iyi değere sahip olanla oynar.

import random
def economistfunc(my_points, opp_points, my_loaded, opp_loaded, my_history, opp_history):
        if len(opp_history) == 0:
                return random.choice(["R","P","S"])
        if len(opp_history) > 9:
                opp_history = opp_history[-10:-1]
        p = [opp_history.count("R"), opp_history.count("P"), opp_history.count("S")]

        value = [(p[2]*my_loaded[0] - p[1]*opp_loaded[1], "R"), (p[0]*my_loaded[1] - p[2]*opp_loaded[2], "P"), (p[1]*my_loaded[2] - p[0]*opp_loaded[0], "S")]
        value.sort()

        if value[-1][0] > value[-2][0]:
                return value[-1][1]
        elif value[-1][0] > value[-3][0]:
                return random.choice([value[-1][1], value[-2][1]])
        else:
                return random.choice(["R","P","S"])

4

Yggdrasil

Buna "Yggdrasil" adı verilir çünkü oyun ağacında ileriye bakar. Bu bot rakibin herhangi bir tahminini yapmaz, sadece bir tane verilirse istatistiksel bir avantaj sağlamaya çalışır (mevcut ve gelecekteki karları dengeleyerek). Yaklaşık olarak ideal bir karma strateji hesaplar ve bu ağırlıklarla rastgele seçilen bir hamle döndürür. Eğer bu bot mükemmel olsaydı (durum değerlendirme fonksiyonu oldukça kötü olduğu ve çok ileriye bakmadığı için), bu botu% 50'den fazla yenmek imkansız olurdu. Bu botun pratikte ne kadar iyi olacağını bilmiyorum.

def yggdrasil(my_points, opp_points, my_loaded, opp_loaded, my_history, opp_history):
    cache = {}
    def get(turn, ml, ol):
        key = str(turn) + str(ml) + str(ol)
        if not key in cache:
            cache[key] = State(turn, ml, ol)
        return cache[key]

    def wrand(opts):
        total = sum(abs(w) for c,w in opts.items())
        while True:
            r = random.uniform(0, total)
            for c, w in opts.items():
                r -= abs(w)
                if r < 0:
                    return c
            print("error",total,r)

    class State():
        turn = 0
        ml = [1,1,1]
        ol = [1,1,1]
        val = 0
        strat = [1/3, 1/3, 1/3]
        depth = -1
        R = 0
        P = 1
        S = 2
        eps = 0.0001
        maxturn = 1000

        def __init__(self, turn, ml, ol):
            self.turn = turn
            self.ml = ml
            self.ol = ol
        def calcval(self, depth):
            if depth <= self.depth:
                return self.val
            if turn >= 1000:
                return 0
            a = 0
            b = -self.ol[P]
            c = self.ml[R]
            d = self.ml[P]
            e = 0
            f = -self.ol[S]
            g = -self.ol[R]
            h = self.ml[S]
            i = 0
            if depth > 0:
                a += get(self.turn+1,[self.ml[R]+1,self.ml[P],self.ml[S]],[self.ol[R]+1,self.ol[P],self.ol[S]]).calcval(depth-1)
                b += get(self.turn+1,[self.ml[R]+2,self.ml[P],self.ml[S]],[self.ol[R],self.ol[P],self.ol[S]]).calcval(depth-1)
                c += get(self.turn+1,[self.ml[R],self.ml[P],self.ml[S]],[self.ol[R],self.ol[P],self.ol[S]+2]).calcval(depth-1)
                d += get(self.turn+1,[self.ml[R],self.ml[P],self.ml[S]],[self.ol[R]+2,self.ol[P],self.ol[S]]).calcval(depth-1)
                e += get(self.turn+1,[self.ml[R],self.ml[P]+1,self.ml[S]],[self.ol[R],self.ol[P]+1,self.ol[S]]).calcval(depth-1)
                f += get(self.turn+1,[self.ml[R],self.ml[P]+2,self.ml[S]],[self.ol[R],self.ol[P],self.ol[S]]).calcval(depth-1)
                g += get(self.turn+1,[self.ml[R],self.ml[P],self.ml[S]+2],[self.ol[R],self.ol[P],self.ol[S]]).calcval(depth-1)
                h += get(self.turn+1,[self.ml[R],self.ml[P],self.ml[S]],[self.ol[R],self.ol[P]+2,self.ol[S]]).calcval(depth-1)
                i += get(self.turn+1,[self.ml[R],self.ml[P],self.ml[S]+1],[self.ol[R],self.ol[P],self.ol[S]+1]).calcval(depth-1)
            self.val = -9223372036854775808
            for pr in range(0,7):
                for pp in range(0,7-pr):
                    ps = 6-pr-pp
                    thisval = min([pr*a+pp*d+ps*g,pr*b+pp*e+ps*h,pr*c+pp*f+ps*i])
                    if thisval > self.val:
                        self.strat = [pr,pp,ps]
                        self.val = thisval
            self.val /= 6


            if depth == 0:
                self.val *= min(self.val, self.maxturn - self.turn)
            return self.val

    turn = len(my_history)
    teststate = get(turn, [x * 2 for x in my_loaded], [x * 2 for x in opp_loaded])
    teststate.calcval(1)
    return wrand({"R":teststate.strat[R],"P":teststate.strat[P],"S":teststate.strat[S]})

lütfen kodu daha anlaşılır hale getirmeyen yorumları kaldırın
Görünen Ad

@SargeBorsch bitti
PhiNotPi

1
@PhiNotPi Zaman sınırlaması yayınlamadığımı biliyorum, ancak Yggdrasil her rakibe karşı bir dakikadan fazla sürüyor. Biraz optimize etmek mümkün olabilir mi?
Masclins

evet dayanılmaz yavaş
Görünen Ad

@AlbertMasclans rakip başına dakika başına Toplam bir dakikaya karşılık rakibin karşısında mı? Ayrıca hızlandırmayı deneyebilirim ama nasıl yapılacağını gerçekten bilmiyorum, sadece 1 adım ileride görünüyor.
PhiNotPi

4

Anti-Tekrarlayıcı

from random import choice
def Antirepeaterfunc(my_points, opp_points, my_loaded, opp_loaded, my_history, opp_history):
    s = opp_history.count("S")
    r = opp_history.count("R")
    p = opp_history.count("P")

    if s>p and s>r:
        return "R"
    elif p>s and p>r:
        return "S"
    else:
        return "P"

İlk turda kağıt alır, daha sonra rakibin en çok ne yaptığını yenerse, berabere olursa kağıt alır.

taklitçi

import random
def copycatfunc(I,dont,care,about,these,enmoves):
    if not enmoves:
        return random.choice(["R","P","S"])
    else:
        return enmoves[len(enmoves)-1]

Sadece rakiplerin son hamlesini kopyalar.

Anti-Anti-Açgözlü

from random import choice
def antiantigreedy(my_points, opp_points, my_loaded, opp_loaded, my_history, opp_history):
    if opp_loaded[0] > opp_loaded[1] and opp_loaded[0] > opp_loaded[2]:
        return "S"
    if opp_loaded[1] > opp_loaded[0] and opp_loaded[1] > opp_loaded[2]:
        return "R"
    if opp_loaded[2] > opp_loaded[0] and opp_loaded[2] > opp_loaded[1]:
        return "P"
    else:
        return choice(["R","P","S"])

Rakibin en ağır seçimine kaybettiği her şeyi seçer.

Biraz Aç

from random import choice
def somewhathungryfunc(blah, blah2, load, blah3, blah4, blah5):
    if load[0] > load[1] and load[0] < load[2] or load[0] < load[1] and load[0] > load[2]:
        return "R"
    if load[1] > load[0] and load[1] < load[2] or load[1] < load[0] and load[1] > load[2]:
        return "P"
    if load[2] > load[1] and load[2] < load[0] or load[2] < load[1] and load[2] > load[0]:
        return "S"
    else:
        return choice(["R","P","S"])

3

Haberci

def themessengerfunc (Bu argümanlara ihtiyacım yok, gerek yok): dönüş "P"

Rock yıldızı

def rockstarfunc (Bu argümanlara ihtiyacım yok, gerek yok): dönüş "R"

katil

def assassinfunc (Bu argümanlara ihtiyacım yok, gerek yok): dönüş "S"

açıklama

Şimdi, bu botların tamamen aptal olduğunu düşünebilirsiniz.

tamamen doğru değil, bunlar aslında büyük bir bonus biriktirme ve düşmanın bir yanlış adım atması ve onunla dolaşması fikrine dayanıyor.

şimdi, bu botlar açgözlü ile çok benzer şekilde oynuyorlar, ancak daha basitler ve bir silah üzerinde bir yük alana kadar rastgele seçmiyorlar, seçim silahlarına bağlı kalıyorlar.

Dikkat edilmesi gereken başka bir şey: bunların her biri yarıya yakın açgözlü, üçte birini çizecek ve zamanın altıda birini kaybedecek. kazandıklarında çok fazla kazanma eğilimi gösterirler. bu neden?

Açgözlü, bir turu kaybedene kadar rastgele bir silah seçer. Bu, bir raundu kazanmadığında, rastgele bir silah seçeceği anlamına gelir, bu da yine kazanan bir silah olabilir. eğer açgözlülük çekerse veya kaybederse, o silahla yapışır. açgözlü en az bir tur kazanırsa, botla aynı silahı alır, açgözlü kazanır. eğer açgözlü kaybedilen silahı bir noktada alırsa, botumuz kazanır, çünkü silahımızdaki yük açgözlü puandan daha yüksek olurdu.

Açgözlülüğün her zaman kazanan silahı büyük bir şansla seçmediğini varsayarsak, bu şansın:

1/3: {1/2 galibiyet (toplam 1/6). 1/2 kaybet (toplam 1/6). }

1/3 beraberlik

1/3 galibiyet

yani: 1/3 beraberlik şansı, 1/6 kaybetme şansı, 1/2 kazanma şansı.

bu muhtemelen birden fazla turdan oluşan birden fazla oyun yapmanız gerektiğini gösterir

bunlar asıl zorluğun üstesinden gelmek için


3

Reaktör

Bir önceki turu kazanacak olan oyunu yapar.

import random
def reactfunc(I, dont, need, all, these, opp_history):
    if not opp_history:
        return random.choice(["R","P","S"])
    else:
        prev=opp_history[len(opp_history)-1]
        if prev == "R":
            return "P"
        if prev == "P":
            return "S"
        else:
            return "R"

1
Sen yerini alabilir opp_history[len(opp_history)-1]ile opp_history[-1].
CalculatorFeline

3

İddialı Çocuk

Bu bot, sanat ve zanaat oynayan bir çocuk gibi davranır, kağıtla başlayacak ve rastgele kağıt veya makas kullanacak, ancak kaya veya makastan sonra makas kullanmayacak, çünkü kağıt üzerinde makas kullanması gerekiyor. Ona bir taş atan herkese bir kaya fırlatacak.

import random
def artsychildfunc(my_points, opp_points, my_loaded, opp_loaded, my_history, opp_history):
    if len(opp_history) == 0:
            return "P"
    elif opp_history[-1] == "R":
            return "R"
    elif my_history[-1] != "P":
            return "P"
    else:
            return random.choice(["P", "S"])

2

İşte test için inşa ettiğim üç Bot:


RandomBot

import random
def randombotfunc(my_points, opp_points, my_loaded, opp_loaded, my_history, opp_history):
        return random.choice(["R","P","S"])

Açgözlü

En yüklü seçeneğini seçer.

import random
def greedyfunc(my_points, opp_points, my_loaded, opp_loaded, my_history, opp_history):
        if my_loaded[0] > my_loaded[1]:
                if my_loaded[0] > my_loaded[2]:
                        return "R"
                elif my_loaded[0] < my_loaded[2]:
                        return "S"
                else:
                        return random.choice(["R","S"])
        elif my_loaded[0] < my_loaded[1]:
                if my_loaded[1] > my_loaded[2]:
                        return "P"
                elif my_loaded[1] < my_loaded[2]:
                        return "S"
                else:
                        return random.choice(["P","S"])
        else:
                if my_loaded[0] > my_loaded[2]:
                        return random.choice(["R","P"])
                elif my_loaded[0] < my_loaded[2]:
                        return "S"
                else:
                        return random.choice(["R","P","S"])

Antigreedy

Rakibin açgözlü oynayacağını ve kazanan alternatifi oynayacağını varsayar.

import random
def antigreedyfunc(my_points, opp_points, my_loaded, opp_loaded, my_history, opp_history):
        if opp_loaded[0] > opp_loaded[1]:
                if opp_loaded[0] > opp_loaded[2]:
                        return "P"
                elif opp_loaded[0] < opp_loaded[2]:
                        return "R"
                else:
                        return "R"
        elif opp_loaded[0] < opp_loaded[1]:
                if opp_loaded[1] > opp_loaded[2]:
                        return "S"
                elif opp_loaded[1] < opp_loaded[2]:
                        return "R"
                else:
                        return "S"
        else:
                if opp_loaded[0] > opp_loaded[2]:
                        return "P"
                elif opp_loaded[0] < opp_loaded[2]:
                        return "R"
                else:
                        return random.choice(["R","P","S"])

1

Aç değil

def nothungryfunc(my_points, opp_points, my_loaded, opp_loaded, my_history, opp_history):
    if my_loaded[0] < my_loaded[1]:
            if my_loaded[0] < my_loaded[2]:
                    return "R"
            elif my_loaded[0] > my_loaded[2]:
                    return "S"
            else:
                    return random.choice(["R","S"])
    elif my_loaded[0] > my_loaded[1]:
            if my_loaded[1] < my_loaded[2]:
                    return "P"
            elif my_loaded[1] > my_loaded[2]:
                    return "S"
            else:
                    return random.choice(["P","S"])
    else:
            if my_loaded[0] < my_loaded[2]:
                    return random.choice(["R","P"])
            elif my_loaded[0] > my_loaded[2]:
                    return "S"
            else:
                    return random.choice(["R","P","S"])

Bu tam anlamıyla Açgözlü ters, mevcut en düşük puan seçeneğini seçer.


1

Rakibin Favorisini Kullan

from collections import Counter
import random
def useopponents(hi, my, name, is, stephen, opp_history):
  if opp_history:
    data = Counter(opp_history)
    return data.most_common(1)[0][0]
  else:
    return random.choice(["R","P","S"])

İlk dönüş için rastgele bir öğe seçer. Diğer her turda rakibin en yaygın tercihini kullanır. Bir kravat varsa, varsayılan olarak en erken seçimdir.

// Buradan kod çaldım


Kazanmak İyi

import random
def goodwinning(no, yes, maybe, so, my_history, opp_history):
  if opp_history:
    me = my_history[len(my_history)-1]
    you = opp_history[len(opp_history)-1]
    if you == me:
      return goodwinning(no, yes, maybe, so, my_history[:-1], opp_history[:-1])
    else:
      if me == "R":
        if you == "P":
          return "P"
        else:
          return "R"
      elif me == "P":
        if you == "S":
          return "S"
        else:
          return "R"
      else:
        if you == "R":
          return "R"
        else:
          return "P"
  else:
    return random.choice(["R","P","S"])

Önceki turun galibi seçimini döndürür. Önceki tur bir beraberlikse, önceki turu tekrar tekrar kontrol eder. Sadece bağlarsa ya da ilk tursa, rastgele bir seçim döndürür.


1

Her iki dünyanın en iyisi

Bu bot temel olarak Açgözlü ve Açgözlü (dolayısıyla adı) birleştirir.

def bobwfunc(a, b, my_loaded, opp_loaded, c, d):
    opp_max = max(opp_loaded)
    opp_play = "PSR"[opp_loaded.index(opp_max)]

    my_max = max(my_loaded)
    my_play = "RPS"[my_loaded.index(my_max)]

    if opp_play == my_play:
        return opp_play
    else:
        return my_play if opp_max < my_max else opp_play

Bu Antigreedy, zaten örnek olarak gönderildi.
Masclins

@AlbertMasclans Başka bir botla değiştirdi.
clismique

finddizeler içindir. my_loadedve opp_loadedher ikisi de listedir. indexne istersen iyi olmalı.
Masclins

@AlbertMasclans Whoops, şimdi düzeltildi. Yakaladığınız için teşekkürler! Umarım bu başka bir dup değildir ... Bu yazıyı tekrar silmek istemiyorum.
clismique

Bu sorun değil, oynadığınız için teşekkürler
Masclins

1

NashBot

import random
def nashbotfunc(my_points, opp_points, my_loaded, opp_loaded, my_history, opp_history):
    r = opp_loaded[0] * opp_loaded[2]
    p = opp_loaded[0] * opp_loaded[1]
    s = opp_loaded[1] * opp_loaded[2]
    q = random.uniform(0, r + p + s) - r
    return "R" if q < 0 else "P" if q < p else "S"

Üç seçenek arasından, rakibin ne kadar puan aldığı konusunda hamleler arasında istatistiksel olarak hiçbir tercih olmayacak şekilde rastgele seçim yapar; başka bir deyişle, hem Açgözlü hem de Aç Değil, buna karşı beklenen ortalama puanı almalıdır.


1

Expectedbayes

Düzenleme: Güncellenmiş Sıralama

Bu, Beklenen baysların dahil edilmesinden sonraki yeni sıralamadır:

  • istatistikçi2func 91.89%
  • tesisatçı% 85.65
  • nashfunc 80.40%
  • kantarcı% 76.39
  • beklenen% 73.33
  • antirepeaterfunc 68.52%
  • ...

açıklamalar

(Not: 05/06/2017 sonrası)

Bu bot, bir sonraki hamlesinin beklenen değerini şu şekilde en üst düzeye çıkarmaya çalışır:

  • Rakibin bir sonraki olası hamlesi için olasılığı hesaplamak
  • Bu rakamı ve R, P ve S'nin her biri için beklenen değeri hesaplamak için yükleri kullanma
  • Beklenen en yüksek değere sahip hamleyi seçme
  • Tahmin başarısız olursa rastgele bir değer seçme

Olasılıklar her on hamlede bir güncellenir. Olasılıkları hesaplamak için kullanılan geçmiş hamle sayısı her bot için 10 olarak ayarlanmıştır (bu nedenle toplam 20 özellik). Bu muhtemelen verileri abartıyor, ancak daha fazla kontrol etmeye çalışmadım.

Rakibin hareket olasılıklarını hesaplamak için scikit kütüphanesine dayanır (kuralları yanlış okuduğumda ve aslında izin verilmediğinde söylüyorum).

Her zaman aynı seçimi yapan botlara karşı kolayca kazanır. Şaşırtıcı bir şekilde,% 93'lük bir kazanma oranı ile rastgele botlara karşı oldukça etkilidir (bunun, her tur için kendi olası puan sayısını en üst düzeye çıkarırken rakibinin alabileceği puan sayısını sınırlaması nedeniyle olduğuna inanıyorum).

100 dönüş ve sadece sınırlı sayıda bot ile hızlı bir denemede bulundum ve sonuçtan elde ettiğim şey bu:

  • randombotfunc, 35
  • nashbotfunc, 333
  • greedyfunc, 172
  • antigreedyfunc, 491
  • themessengerfunc, 298
  • rockstarfunc, 200
  • statistician2func, 748
  • fitterfunc, 656
  • expectedbayesfunc, 601

Bu o kadar da kötü değil!

from sklearn.naive_bayes import MultinomialNB
import random

#Number of past moves used to compute the probability of next move
#I did not really try to make such thing as a cross-validation, so this number is purely random
n_data = 10

#Some useful data structures
choices = ['R','P','S']
choices_dic = {'R':0,'P':1,'S':2}
point_dic = {(0,0):0,(1,1):0,(2,2):0, #Same choices
             (0,1):-1,(0,2):1, #me = rock
             (1,0):1,(1,2):-1, #me = paper
             (2,0):-1,(2,1):1} #me = scissor

def compute_points(my_choice,opp_choice,my_load,opp_load):
    """
    Compute points
    @param my_choice My move as an integer
    @param opp_choice Opponent choice as an integer
    @param my_load my_load array
    @param opp_load opp_load array
    @return A signed integer (+ = points earned, - = points losed)
    """
    points = point_dic[(my_choice,opp_choice)] #Get -1, 0 or 1
    if points > 0:
        return points*my_load[my_choice] 
    else:
        return points*opp_load[opp_choice]

#This use to be a decision tree, before I changed it to something else. Nevertheless, I kept the name
class Decision_tree:
    def __init__(self):
        self.dataX = []
        self.dataY = []
        self.clf = MultinomialNB()

    def decide(self,my_load,opp_load,my_history,opp_history):
        """
        Returns the decision as an integer

        Done through a try (if a prediction could be made) except (if not possible)
        """
        try:
            #Let's try to predict the next move
            my_h = list(map(lambda x: choices_dic[x],my_history[-n_data:-1]))
            opp_h = list(map(lambda x: choices_dic[x],opp_history[-n_data:-1]))
            pred = self.clf.predict_proba([my_h+opp_h])
            #We create a points array where keys are the available choices
            pts = []
            for i in range(3):
                #We compute the expected gain/loss for each choice
                tmp = 0
                for j in range(3):
                    tmp += compute_points(i,j,my_load,opp_load)*pred[0][j]
                pts.append(tmp)
            return pts.index(max(pts)) #We return key for the highest expected value
        except:
            return random.choice(range(3))

    def append_data(self,my_history,opp_history):
        if my_history == "":
            self.clf = MultinomialNB()
        elif len(my_history) < n_data:
            pass
        else:
            my_h = list(map(lambda x: choices_dic[x],my_history[-n_data:-1]))
            opp_h = list(map(lambda x: choices_dic[x],opp_history[-n_data:-1]))
            self.dataX = self.dataX + [my_h+opp_h]
            self.dataY = self.dataY + [choices_dic[opp_history[-1:]]]

            if len(self.dataX) >= 10:
                self.clf.partial_fit(self.dataX,self.dataY,classes=[0,1,2])

                self.dataX = []
                self.dataY = []


#Once again, this is not actually a decision tree
dt = Decision_tree()

#There we go:
def expectedbayesfunc(my_points, opp_points, my_loaded, opp_loaded, my_history, opp_history):
    dt.append_data(my_history,opp_history)
    choice = choices[dt.decide(my_loaded,opp_loaded,my_history,opp_history)]
    return choice

PPCG'ye hoş geldiniz, ve ilk güzel yazı!
Zacharý

Çok teşekkürler! PPCG'ye uzun süre katılmak istedim. Şimdi düzeltildi!
lesibius

0

Cycler

def cycler(my_points, opp_points, my_loaded, opp_loaded, my_history, opp_history):
    return "RPS"[len(myhistory)%3]

0


0

topluluk

from random import *
def f(I):
    if I==0:return "R"
    if I==1:return "P"
    return "S"
def b(I):
    if I=="R":return 0
    if I=="P":return 1
    return 2
def Ensemble(mp,op,ml,ol,mh,oh):
    A=[0]*3
    B=[0]*3
    if(len(oh)):
        k=b(oh[-1])
        A[k-2]+=0.84
        A[k]+=0.29
        for x in range(len(oh)):
            g=b(oh[x])
            B[g-2]+=0.82
            B[g]+=0.22
        s=sum(B)
        for x in range(len(B)):
            A[x]+=(B[x]*1.04/s)
        r=max(A)
    else:
        r=randint(0,3)
    return f(r)

Çeşitli rakip algoritmalar en iyi çözümü seçer.

takas

from random import *
def f(I):
    if I==0:return "R"
    if I==1:return "P"
    return "S"
def b(I):
    if I=="R":return 0
    if I=="P":return 1
    return 2
def Swap(mp,op,ml,ol,mh,oh):
    A=[0]*3
    B=[0]*3
    if(len(mh)):
        r=(b(mh[-1])+randint(1,2))%3
    else:
        r=randint(0,3)
    return f(r)

Rastgele bir hareket yapar, ancak son hamleyi tekrar etmeden yaptı.


0

blodsocer

socery

Bir düzeltme verdim, bu yüzden muhtemelen şimdi çalışmalı umarım

Bir şeyleri tekrar karıştırdım, bu yüzden sildim ve silindim. Çok fazla karışıklık yapıyorum.

def blodsocerfunc(my_points, opp_points, my_loaded, opp_loaded, my_history, opp_history):
    import random
    # tuned up an ready to go hopeful
    # s o c e r y
    if len(my_history) > 40 and len(set(opp_history[-30:])) == 1:
        if opp_history[-1] == "S":
            return "R"
        elif opp_history[-1] == "R":
            return "P"
        else:
            return "S"
        # against confused bots that only do one thing most of the time.
    elif len(my_history)>30 and min(opp_history.count(i) for i in "RPS")/max(opp_history.count(i) for i in "RPS") >0.8:
        return "RPS"[my_loaded.index(max(my_loaded))] # This is so if the other bot is acting errratic
                                                      # the max bonus is used for advantage
    elif len(my_history) < 10:
        if len(my_history) > 2 and all(i == "S" for i in opp_history[1:]):
            if len(my_history) > 5: return "S"
            return "P"
        return "S" # Be careful, because scissors are SHARP
    elif len(set(opp_history[1:10])) == 1 and len(my_history) < 20:
        if opp_history[1] == "S":
            return "R"
        elif opp_history[1] == "R":
            return "R"
        else:
            return "P"
    elif len(opp_history) -  max(opp_history.count(i) for i in "RPS") < 4 and len(my_history) < 30:
        if opp_history.count("R") > max(opp_history.count(i) for i in "PS"):
            return "P"
        if opp_history.count("P") > max(opp_history.count(i) for i in "RS"):
            return "S"
        if opp_history.count("S") > max(opp_history.count(i) for i in "RP"):
            return "R"
    elif len(my_history) < 15:
        if max(opp_loaded)<max(my_loaded):
            return "RPS"[len(my_history)%3]
        else:
            return "RPS"[(my_loaded.index(max(my_loaded))+len(my_history)%2)%3]
    elif len(my_history) == 15:
        if max(opp_loaded)<max(my_loaded):
            return "RPS"[(len(my_history)+1)%3]
        else:
            return "RPS"[(my_loaded.index(max(my_loaded))+ (len(my_history)%2)^1)%3]
    else:
        if max(opp_loaded)<max(my_loaded):
            return random.choice("RPS")
        else:
            return "RPS"[(my_loaded.index(max(my_loaded))+ (random.randint(0,1)))%3]

1
if opp_history[1] == "S": return "R" elif opp_history[1] == "R": return "R" else: return "P"bu ne tür bir toplum?
Robert Fraser

@DestructibleLemon Bu, 0'a bölünür:elif min(opp_history.count(i) for i in "RPS")/max(opp_history.count(i) for i in "RPS") >0.8 and len(my_history)>30:
Masclins

@ AlbertMasclans Bunu düzelttim.
Yıkılabilir Limon

@RobertFraser bu kod snippet'inin tam olarak göze çarpan özelliği nedir?
Yıkılabilir Limon

@DestructibleLemon Burada ne yapmak istediğinizden tam olarak emin değilim: "RPS"[my_loaded.index(max(my_loaded))+len(my_history)%2]ancak aralık dışında görünüyor (ve diğer satırlar da öyle).
Masclins

0

Ağırlıklı Rastgele

RandomBot gibi, ancak her çağrıldığında atmak için sadece 2 tane seçer. Bazen Rockstar veya Assassin'i yenecek, ancak diğerinin puanlarını artıracak (örneğin, Rockstar'ı yenerse, Assassin'e bir puan artışı verir).

import random

selection_set = ["R", "P", "S"]
selection_set.pop(random.randint(0,2))
def weightedrandombotfunc(my_points, opp_points, my_loaded, opp_loaded, my_history, opp_history):
    return random.choice(selection_set)

0

Açgözlü psikolog

Bunun adı varsayılan olarak açgözlüdür, ancak karar veremezse, açgözlü stratejiyi kullanırsa rakibin yapacağı her şeye karşı koyar. Hala karar veremezse, rastgele gider.

from random import choice

def greedypsychologistfunc(my_points, opp_points, my_loaded, opp_loaded, my_history, opp_history):
    greedy = get_my_move(my_loaded)
    combined = list(set(greedy) & set(get_opp_counter(opp_loaded)))

    if len(combined) == 0:
        return choice(greedy)
    return choice(combined)

def get_indexes(lst, value):
    return [i for i,x in enumerate(lst) if x == value]

def get_my_move(my_loaded):
    return ["RPS"[i] for i in get_indexes(my_loaded, max(my_loaded))]

def get_opp_counter(opp_loaded):
    return ["PSR"[i] for i in get_indexes(opp_loaded, max(opp_loaded))]
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.