KOTH - Geladene RPS


12

Wettbewerb permanent geöffnet - Aktualisiert am 10. August 2017

Obwohl ich am 5. Juni 2017 einen Gewinner gekürt habe (der als beste Antwort gilt), werde ich neue Bots starten und die Ergebnisse aktualisieren.

5. Juni Ergebnisse

Glückwunsch user1502040

Da es keine Gleichheit gibt, zeige ich nur den Prozentsatz der gewonnenen Matches.

Statistician2- 95,7%
Fitter- 89,1%
Nash- 83,9%
Weigher- 79,9%
ExpectedBayes- 76,4%
AntiRepeater- 72,1%
Yggdrasil- 65,0%
AntiGreedy- 64,1%
Reactor- 59,9%
NotHungry- 57,3%
NashBot- 55,1%
Blodsocer- 48,6%
BestOfBothWorlds- 48,4%
GoodWinning- 43,9%
Rockstar- 40,5%
ArtsyChild- 40,4%
Assassin- 38,1 %
WeightedRandom- 37,7%
Ensemble- 37,4%
UseOpponents- 36,4%
GreedyPsychologist- 36,3%
TheMessenger- 33,9%
Copycat- 31,4%
Greedy- 28,3%
SomewhatHungry- 27,6%
AntiAntiGreedy- 21,0%
Cycler- 20,3%
Swap- 19,8%
RandomBot- 16,2%

Ich habe ein Google Sheet mit dem Ergebnisraster für jede Verknüpfung erstellt: https://docs.google.com/spreadsheets/d/1KrMvcvWMkK-h1Ee50w0gWLh_L6rCFOgLhTN_QlEXHyk/edit?usp=sharing


Dank des Petri-Dilemmas konnte ich mit diesem König des Hügels fertig werden.

Das Spiel

Das Spiel ist eine einfache "Stein-Papier-Schere" mit einem Twist: Punkte, die mit jedem Sieg während des Spiels gewonnen werden (Ihre R, P oder S werden geladen).

  • Papier gewinnt Rock
  • Schere gewinnt Papier
  • Rock gewinnt die Schere

Der Gewinner erhält so viele Punkte wie er spielt.

Der Verlierer erhöht die Belastung seines Spiels um 1.

Bei einem Gleichstand erhöht jeder Spieler die Belastung seines Spiels um 0,5.

Nach 100 Spielen gewinnt derjenige mit mehr Punkten.

Beispiel: P1 hat Lasten [10,11,12] (Stein, Papier, Schere) und P2 [7,8,9]. P1 spielt R, P2 spielt P. P2 gewinnt und bekommt 8 Punkte. P1-Lasten werden [11,11,12], P2-Lasten bleiben gleich.

Herausforderungsspezifikationen

Ihr Programm muss in Python geschrieben sein (Entschuldigung, ich weiß nicht, wie ich damit umgehen soll). Sie müssen eine Funktion erstellen, die bei jeder Ausführung jede dieser Variablen als Argument verwendet:

my_points, opp_points, my_loaded, opp_loaded, my_history, opp_history

points - Aktuelle Punkte (Ihre und Ihre Gegner)

loaded- Array mit Lasten (in der Reihenfolge RPS) (Ihr und Ihr Gegner)

history- Saite mit allen Spielen, letzter Charakter ist das letzte Spiel (dein und dein Gegner)

Sie müssen zurückkehren "R", "P"oder "S". Wenn Sie etwas anderes zurückgeben würden, wäre dies automatisch ein Verlust des Spiels.

Regeln

Sie können die integrierten Funktionen nicht ändern.

Testen

Ich halte einen Git mit dem Code und allen Bots auf dem Laufenden: https://github.com/Masclins/LoadedRPS

Beurteilen

Der Gewinner wird durch Auswahl der Person mit den meisten Siegen nach 1000 vollen Round-Robin-Spielen ermittelt. Die Krawatten werden durch Gleichstand unterbrochen. Es werden mehr als 1000 Spiele gespielt, weil ich viel Zufälligkeit erwarte, und auf diese Weise wäre die Zufälligkeit weniger relevant.

Sie können bis zu 5 Bots einreichen.

Der Wettbewerb endet am Juli 4. Juni (das wird der letzte Tag sein , die ich keine Antwort akzeptieren werde), und am Juli 5. Juni werde ich die letzten stadings Post (vielleicht versuchen , eine advancemnt vor schreiben).


Da dies meine erste KOTH ist, bin ich zu 100% offen für Verbesserungen, wie zum Beispiel die Anzahl der Matches, die gegen jeden Bot gespielt werden.

Auf 1000 Streichhölzer bearbeitet, da ich sehe, dass es wirklich um Zufälligkeiten geht.


Mit einigen zufälligen Bots möchten Sie tatsächlich mehrere Spiele mit mehreren Runden machen
Destructible Lemon

@DestructibleLemon Ich habe darüber nachgedacht, jeden Bot dreimal anstatt einmal gegeneinander spielen zu lassen. Wenn ich sehe, dass Sie ähnlich denken, tue ich das auch.
Masclins

1
(Wirklich, Sie brauchen eine ziemlich große Anzahl, da sich einige Wahrscheinlichkeiten tatsächlich über mehrere Spiele erstrecken. Sehen Sie meinen Bot, wo er abgehackt werden könnte, aber wahrscheinlich nicht mit einer angemessenen Anzahl von Treffern)
Destructible Lemon

1
Ich bin froh, dass Ihnen meine Frage dabei geholfen hat, @AlbertMasclans!
Gryphon

2
@ AlbertMasclans Können Sie das vollständige Testskript (einschließlich runcode und bots) veröffentlichen?
CalculatorFeline

Antworten:


8

Statistiker (spielt nicht mehr)

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)]

Wechselt zwischen einigen einfachen Strategien, basierend auf der erwarteten Leistung in der Vergangenheit

Statistiker 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]

Berechnet ein ungefähres Nash-Gleichgewicht durch Gradientenabstieg.


1
Ich mag diesen Ansatz wirklich und kann verstehen, warum Sie in der Lage sein möchten, den Zustand zwischen den Runden beizubehalten. Obwohl ich es für ein großes Problem halte, es angesichts der Anzahl der Einsendungen zu ändern. Ich werde das für weitere Herausforderungen berücksichtigen (was ich erwarten werde, wenn dies abgeschlossen ist).
Masclins

5

Wieger

Ich habe den Überblick verloren, als ich mit dem Code experimentiert habe, aber die Grundidee ist, die Zugwahrscheinlichkeit des Gegners durch die letzten drei Züge unter Verwendung einiger Gewichte zu schätzen und sie mit einem anderen Gewicht zu multiplizieren, das von der Last abhängt. Ich dachte, dass ich es irgendwie auch benutzen kann my_loaded, aber ich konnte mich nicht entscheiden, also ließ ich es weg.

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))]

Satan

Wahrscheinlich wird es disqualifiziert, weil es eine Art Schummeln ist und einige Annahmen über die Testfunktion macht (es muss die Funktion des Gegners in einer Variablen auf seinem Stack-Frame haben), aber es bricht technisch keine aktuellen Regeln - es tut es nicht etwas neu definieren oder umschreiben. Es benutzt einfach schwarze Magie, um die gegnerische Funktion auszuführen und zu sehen, was sie getan haben / tun werden. Es kann nicht mit Zufälligkeiten umgehen, aber deterministische Bots haben keine Chance, Satan zu besiegen.

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

Ohne Zweifel die beste in Bezug auf Simplicity-Ergebnisse
Masclins

Übrigens können Sie zur Verwendung my_loadedein Gewicht hinzufügen, das den Zug bewertet, der gegen Ihre letzten Züge verloren würde. Das ist so, als würde man annehmen, dass Ihr Gegner etwas Ähnliches tut wie Sie und ihn deshalb dafür bestrafen, dass er annimmt, dass Sie das Gleiche weiterspielen. So etwas wie:for i, m in enumerate(reversed(my_history[-3:])): sc[(idx[m]+1)%3] += (K / (1 + i))
Masclins

@ AlbertMasclans fügte eine andere Lösung hinzu
Anzeigename

1
Ich mag den Satan wirklich. Aber wie Sie sagten, ich glaube, es sollte sich nicht qualifizieren: Auch wenn es keine explizite Regel verletzt, ist es eindeutig gegen den Geist des Spiels. Herzlichen Glückwunsch zu Ihrer Idee!
Masclins

4

Monteur

Dieser Bot verbessert Pattern und verschmilzt ihn mit Economist (Pattern und Economist nehmen nicht mehr teil)

Die Verbesserung von Pattern ist, dass der Bot nun nach zwei Arten von Patterns sucht: Gegner, der auf sein letztes Spiel reagiert, und Gegner, der auf mein letztes Spiel reagiert. Anschließend werden beide Vorhersagen ausgewertet, um diejenige zu verwenden, die am besten passt.

Aus diesem Muster hat der Bot nun die Wahrscheinlichkeit für R, P und S. Unter Berücksichtigung des erwarteten Werts jedes Spiels (wie Economist es tat) spielt der Bot denjenigen, der den größten Wert ergibt.

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]

Hier sind die beiden alten Codes

Pattern (spielt nicht mehr)

Das Pattern versucht, Muster auf seinem Gegner zu finden. Es sieht so aus, als hätte der Gegner nach dem letzten Spiel, das er gespielt hat, mehr Gewicht gegeben. Dadurch wird erraten, was der Gegner spielen wird, und das Gegenstück dazu gespielt.

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]

Ökonom (spielt nicht mehr)

Der Economist tut Folgendes: Ermittelt die Wahrscheinlichkeit jedes Spiels des Gegners, indem er beobachtet, was er in den letzten 9 Runden gespielt hat. Berechnet daraus den erwarteten Nutzen eines jeden Spiels und geht zu dem Spiel über, das den besten erwarteten Wert hat.

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

Dies wird "Yggdrasil" genannt, weil es im Spielbaum nach vorne schaut. Dieser Bot nimmt keine Vorhersage des Gegners vor, sondern versucht lediglich, einen statistischen Vorteil beizubehalten, wenn er einen hat (durch Abwägen aktueller und zukünftiger Gewinne). Es berechnet eine ungefähr ideale gemischte Strategie und gibt einen Zug zurück, der zufällig mit diesen Gewichten ausgewählt wurde. Wenn dieser Bot perfekt wäre (was nicht der Fall ist, weil die Funktion zur Bewertung des Zustands ziemlich schlecht ist und nicht sehr weit vorausschaut), wäre es unmöglich, diesen Bot in mehr als 50% der Fälle zu schlagen. Ich weiß nicht, wie gut dieser Bot in der Praxis abschneiden wird.

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

Bitte entfernen Sie Kommentare, die den Code nicht verständlicher machen
Anzeigename

@ SargeBorsch fertig
PhiNotPi

1
@PhiNotPi Mir ist bewusst, dass ich keine Zeitbeschränkung gepostet habe, aber Yggdrasil braucht mehr als eine Minute gegen jeden Gegner. Wäre es möglich, es ein wenig zu optimieren?
Masclins

Ja, es ist unerträglich langsam
Anzeigename

@ AlbertMasclans pro Minute pro Gegner meinst du insgesamt 1 Minute für alle Spiele gegen einen Gegner? Ich kann auch versuchen, es zu beschleunigen, aber ich weiß nicht wirklich, wie es geht.
PhiNotPi

4

Anti-Repeater

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"

Nimmt Papier in der ersten Runde und gibt dann das zurück, was der Gegner am meisten getan hat. Bei einem Unentschieden wählt er Papier aus.

Nachahmer

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]

Kopiert einfach den letzten Zug des Gegners.

Anti-Anti-Gierig

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"])

Wählt, was auch immer an der am schwersten gewichteten Wahl des Gegners verliert.

Etwas hungrig

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

Der Messenger

def themessengerfunc (ich brauche diese Argumente nicht): return "P"

Rockstar

def rockstarfunc (ich brauche diese Argumente nicht): return "R"

Attentäter

def assassinfunc (ich brauche diese Argumente nicht): return "S"

Erläuterung

Nun, Sie könnten denken, dass diese Bots völlig dumm sind.

Dies ist nicht ganz richtig, sondern basiert auf der Idee, einen riesigen Bonus zu sammeln und den Feind in die Irre zu führen und sich damit herumschlagen zu lassen.

Diese Bots spielen sich sehr ähnlich wie Gierige, sind jedoch einfacher und werden nicht zufällig ausgewählt, bis sie eine Waffe beladen haben. Sie bleiben bei der Waffe ihrer Wahl.

Noch etwas zu beachten: Diese schlagen jeweils etwa die Hälfte der Zeit gierig, ziehen ein Drittel der Zeit und verlieren ein Sechstel der Zeit. Wenn sie gewinnen, werden sie tendenziell viel gewinnen. warum ist das?

Gierig, bis er eine Runde verliert, wird zufällig eine Waffe auswählen. Dies bedeutet, dass er, wenn er keine Runde gewinnt, zufällig wieder eine Waffe auswählt, die möglicherweise wieder gewinnt. Wenn gierig zieht oder verliert, bleibt er bei dieser Waffe. Wenn gierig mindestens eine Runde gewinnt, wählt sie die gleiche Waffe wie der Bot. Gierig gewinnt. Wenn gierig irgendwann die verlorene Waffe auswählt, gewinnt unser Bot, weil die Ladung unserer Waffe höher gewesen wäre als die Punktzahl, die gierig ist.

Vorausgesetzt, dass Gierige nicht immer nur die Siegerwaffe durch einen großen Zufall auswählen, bedeutet dies, dass folgende Chancen bestehen:

1/3: {1/2 Gewinn (insgesamt 1/6). 1/2 verlieren (1/6 insgesamt). }

1/3 Unentschieden

1/3 Gewinn

Also: 1/3-Chance zu ziehen, 1/6-Chance auf Niederlage, 1/2-Chance zu gewinnen.

Dies zeigt wahrscheinlich, dass Sie mehrere Spiele in mehreren Runden durchführen müssen

Diese dienen hauptsächlich dazu, die Herausforderung ins Rollen zu bringen


3

Reaktor

Macht das Spiel, das die vorherige Runde gewonnen hätte.

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
Sie können ersetzen opp_history[len(opp_history)-1]mit opp_history[-1].
CalculatorFeline

3

Künstlerisches Kind

Dieser Bot verhält sich wie ein Kind, das Kunsthandwerk spielt, mit Papier anfängt und entweder Papier oder Schere zufällig verwendet, aber keine Schere nach Stein oder Schere verwendet, weil sie die Schere auf Papier verwenden muss. Wirft einen Stein zurück auf jemanden, der einen Stein auf sie wirft.

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

Hier die drei Bots, die ich zum Testen gebaut habe:


RandomBot

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

Gierig

Wählt einfach seine am meisten geladene Option.

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

Angenommen, der Gegner spielt gierig und spielt die gewinnende Alternative.

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

Nicht hungrig

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"])

Dies ist buchstäblich das Gegenteil von Gierig, es wählt die niedrigsten verfügbaren Punkte.


1

Verwenden Sie den Favoriten des Gegners

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"])

Wählt in der ersten Runde einen zufälligen Gegenstand aus. Verwendet für jede zweite Runde die häufigste Wahl des Gegners. Wenn es ein Unentschieden gibt, wird standardmäßig die früheste häufigste Wahl getroffen.

// Ich habe Code von hier


Gewinnen ist gut

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"])

Gibt die Wahl des Gewinners der vorherigen Runde zurück. Wenn die vorherige Runde unentschieden war, wird die vorherige Runde rekursiv überprüft. Wenn es nur Unentschieden waren oder es sich um die erste Runde handelt, wird eine zufällige Auswahl zurückgegeben.


1

Beste aus beiden Welten

Dieser Bot kombiniert grundsätzlich Anti-Greedy und Greedy (daher der Name).

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

Dies ist das Antigreedy, das bereits als Beispiel veröffentlicht wurde.
Masclins

@ AlbertMasclans Änderte es auf einen anderen Bot.
Clismique

findist für Streicher. my_loadedund opp_loadedsind beide Listen. indexsollte gut für das sein, was du willst.
Masclins

@ AlbertMasclans Whoops, jetzt behoben. Danke für den Fang! Ich hoffe, das ist kein weiterer Trottel ... Ich möchte diesen Beitrag nicht noch einmal löschen.
Clismique

Dies ist in
Ordnung

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"

Wählt nach dem Zufallsprinzip eine der drei Optionen aus, sodass der Gegner statistisch gesehen keine Präferenz zwischen Zügen hat, was die Punktzahl betrifft. Mit anderen Worten, sowohl Gierig als auch Nicht hungrig sollten die gleiche durchschnittliche erwartete Punktzahl haben.


1

Erwartete Bayes

Bearbeiten: Rangliste aktualisiert

Dies ist die neue Top-Platzierung nach Einbeziehung von Expectedbayes:

  • statistician2func 91.89%
  • fitterfunc 85,65%
  • nashfunc 80.40%
  • Gewicht 76.39%
  • erwartetbayesfunc 73.33%
  • Antirepeaterfunktion 68.52%
  • ...

Erklärungen

(Hinweis: Einreichung nach dem 05.06.2017)

Dieser Bot versucht den erwarteten Wert seines nächsten Zuges zu maximieren, indem er:

  • Berechnung der Wahrscheinlichkeit für jeden nächsten möglichen Zug des Gegners
  • Verwenden Sie diese Zahl und die Lasten, um den erwarteten Wert für R, P und S zu berechnen
  • Auswahl der Bewegung mit dem höchsten erwarteten Wert
  • Zufällige Auswahl eines Wertes, wenn die Vorhersage fehlgeschlagen ist

Die Wahrscheinlichkeiten werden alle zehn Züge aktualisiert. Die Anzahl der letzten Züge, die zur Berechnung der Wahrscheinlichkeiten verwendet wurden, wurde für jeden Bot auf 10 festgelegt (also insgesamt 20 Features). Dies ist wahrscheinlich eine Überanpassung der Daten, aber ich habe nicht weiter versucht, dies zu überprüfen.

Es stützt sich auf die Scikit-Bibliothek, um die Zugwahrscheinlichkeiten des Gegners zu berechnen (ich sage es, falls ich die Regeln falsch verstanden habe und es tatsächlich nicht erlaubt war).

Es gewinnt leicht gegen Bots, die immer die gleiche Wahl treffen. Überraschenderweise ist es gegen den Zufallsbot mit einer Gewinnrate von 93% recht effektiv (ich glaube, dies liegt an der Tatsache, dass es die Anzahl der Punkte begrenzt, die sein Gegner erhalten kann, während er seine eigene Anzahl möglicher Punkte für jede Runde maximiert).

Ich habe einen schnellen Versuch mit 100 Runden und nur einer begrenzten Anzahl von Bots gemacht, und das habe ich von result_standing erhalten:

  • Randombotfunc, 35
  • nashbotfunc, 333
  • gierig, 172
  • Antigreedyfunc, 491
  • themessengerfunc, 298
  • Rockstarfunc, 200
  • statistician2func, 748
  • Schlosser, 656
  • expectedbayesfunc, 601

Welches ist nicht so schlimm!

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

Willkommen bei PPCG und schönen ersten Beitrag!
Zacharý

Danke vielmals! Ich wollte schon lange an PPCG teilnehmen. Jetzt ist es behoben!
Lesibius

0

Cycler

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

0


0

Ensemble

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)

Mehrere konkurrierende Algorithmen stimmen über die beste Lösung ab.

Tauschen

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)

Führt einen zufälligen Zug aus, ohne jedoch den letzten zu wiederholen.


0

Blodsocer

Gesellschaft

Ich habe es behoben, also sollte es jetzt wahrscheinlich funktionieren, hoffe ich

Ich habe wieder etwas durcheinander gebracht, also habe ich gelöscht und wieder hergestellt. Ich mache eine Menge Durcheinander.

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"Was für eine Gesellschaft ist das?
Robert Fraser

@ DestructibleLemon Dies wird durch 0 geteilt: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 Ich habe das behoben.
Destructible Lemon

@RobertFraser Was genau ist an diesem Code-Snippet herausragend?
Destructible Lemon

@DestructibleLemon Ich bin mir nicht ganz sicher, was Sie hier machen wollten: "RPS"[my_loaded.index(max(my_loaded))+len(my_history)%2]aber es sieht nicht in Reichweite aus (und die weiteren Zeilen auch).
Masclins

0

Gewichteter Zufall

Wie RandomBot, aber bei jedem Aufruf werden nur 2 geworfen. Schlägt manchmal Rockstar oder Assassin, erhöht aber die Punktzahl des anderen (wenn es beispielsweise Rockstar schlägt, gibt es Assassin einen Punkt-Boost).

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

Gieriger Psychologe

Genannt, weil es standardmäßig gierig ist, aber wenn es sich nicht entscheiden kann, kontert es, was der Gegner tun würde, wenn er die gierige Strategie verwendet. Wenn es sich immer noch nicht entscheiden kann, geht es nach dem Zufallsprinzip.

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))]
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.