Teilweise beobachtbare Verbindung-4

8

Das Spiel

Sie spielen ein (fast) Standardspiel von Connect-4 . Leider ist es ein Korrespondenzspiel und jemand hat jede zweite Reihe von unten schwarz mit Klebeband versehen, so dass Sie keine Bewegungen Ihres Gegners in diesen Reihen sehen können.

Alle Züge in bereits vollen Spalten gelten als bestanden, und wenn ein Spiel länger als die 6 * 7Runden läuft , wird es als Unentschieden gewertet.

Herausforderungsspezifikation

Ihr Programm sollte als Python 3-Funktion implementiert sein. Das erste Argument ist eine "Ansicht" des Bretts, die den bekannten Brettstatus als 2D-Liste von Zeilen von unten nach oben darstellt, wobei 1es sich um einen Zug des ersten Spielers, 2einen Zug des zweiten Spielers und 0eine leere Position oder eine versteckte handelt bewege dich an deinem Gegner vorbei.

Das zweite Argument ist eine Zugnummer, aus der indiziert wird 0, und ihre Parität gibt an, welcher Spieler Sie sind.

Das letzte Argument ist ein beliebiger Status, Noneder zu Beginn jedes Spiels initialisiert wurde und mit dem Sie den Status zwischen den Runden beibehalten können.

Sie sollten ein 2-Tupel des Spaltenindex zurückgeben, den Sie spielen möchten, und den neuen Status, der Ihnen in der nächsten Runde zurückgegeben werden soll.

Wertung

Ein Gewinn zählt als +1, ein Unentschieden als 0und ein Verlust als -1. Ihr Ziel ist es, die höchste durchschnittliche Punktzahl in einem Round-Robin-Turnier zu erzielen. Ich werde versuchen, so viele Spiele wie nötig durchzuführen, um einen eindeutigen Gewinner zu ermitteln.

Regeln

Jeder Konkurrent sollte höchstens einen konkurrierenden Bot gleichzeitig haben, aber es ist in Ordnung, Ihren Eintrag zu aktualisieren, wenn Sie Verbesserungen vornehmen. Bitte versuchen Sie, Ihren Bot auf ~ 1 Sekunde Denkzeit pro Runde zu beschränken.

Testen

Hier ist der Quellcode für den Controller zusammen mit einigen nicht konkurrierenden Beispiel-Bots als Referenz:

import itertools
import random

def get_strides(board, i, j):
    yield ((i, k) for k in range(j + 1, 7))
    yield ((i, k) for k in range(j - 1, -1, -1))
    yield ((k, j) for k in range(i + 1, 6))
    yield ((k, j) for k in range(i - 1, -1, -1))
    directions = [(1, 1), (-1, -1), (1, -1), (-1, 1)]
    def diag(di, dj):
        i1 = i
        j1 = j
        while True:
            i1 += di
            if i1 < 0 or i1 >= 6:
                break
            j1 += dj
            if j1 < 0 or j1 >= 7:
                break
            yield (i1, j1)
    for d in directions:
        yield diag(*d)

DRAWN = 0
LOST = 1
WON = 2
UNDECIDED = 3

def get_outcome(board, i, j):
    if all(board[-1]):
        return DRAWN
    player = board[i][j]
    strides = get_strides(board, i, j)
    for _ in range(4):
        s0 = next(strides)
        s1 = next(strides)
        n = 1
        for s in (s0, s1):
            for i1, j1 in s:
                if board[i1][j1] == player:
                    n += 1
                    if n >= 4:
                        return WON
                else:
                    break
    return UNDECIDED

def apply_move(board, player, move):
    for i, row in enumerate(board):
        if board[i][move] == 0:
            board[i][move] = player
            outcome = get_outcome(board, i, move)
            return outcome
    if all(board[-1]):
        return DRAWN
    return UNDECIDED

def get_view(board, player):
    view = [list(row) for row in board]
    for i, row in enumerate(view):
        if i % 2:
            continue
        for j, x in enumerate(row):
            if x == 3 - player:
                row[j] = 0
    return view

def run_game(player1, player2):
    players = {1 : player1, 2 : player2}
    board = [[0] * 7 for _ in range(6)]
    states = {1 : None, 2 : None}
    for turn in range(6 * 7):
        p = (turn % 2) + 1
        player = players[p]
        view = get_view(board, p)
        move, state = player(view, turn, states[p])
        outcome = apply_move(board, p, move)
        if outcome == DRAWN:
            return DRAWN
        elif outcome == WON:
            return p
        else:
            states[p] = state
    return DRAWN

def get_score(counts):
    return (counts[WON] - counts[LOST]) / float(sum(counts))

def run_tournament(players, rounds=10000):
    counts = [[0] * 3 for _ in players]
    for r in range(rounds):
        for i, player1 in enumerate(players):
            for j, player2 in enumerate(players):
                if i == j:
                    continue
                outcome = run_game(player1, player2)
                if outcome == DRAWN:
                    for k in i, j:
                        counts[k][DRAWN] += 1
                else:
                    if outcome == 1:
                        w, l = i, j
                    else:
                        w, l = j, i
                    counts[w][WON] += 1
                    counts[l][LOST] += 1
        ranks = sorted(range(len(players)), key = lambda i: get_score(counts[i]), reverse=True)
        print("Round %d of %d\n" % (r + 1, rounds))
        rows = [("Name", "Draws", "Losses", "Wins", "Score")]
        for i in ranks:
            name = players[i].__name__
            score = get_score(counts[i])
            rows.append([name + ":"] + [str(n) for n in counts[i]] + ["%6.3f" % score])
        lengths = [max(len(s) for s in col) + 1 for col in zip(*rows)]
        for i, row in enumerate(rows):
            padding = ((n - len(s)) * ' ' for s, n in zip(row, lengths))
            print(''.join(s + p for s, p in zip(row, padding)))
            if i == 0:
                print()
        print()

def random_player(view, turn, state):
    return random.randrange(0, 7), state

def constant_player(view, turn, state):
    return 0, state

def better_random_player(view, turn, state):
    while True:
        j = random.randrange(0, 7)
        if view[-1][j] == 0:
            return j, state

def better_constant_player(view, turn, state):
    for j in range(7):
        if view[-1][j] == 0:
            return j, state

players = [random_player, constant_player, better_random_player, better_constant_player]

run_tournament(players)

Fröhliches KoTHing!

Vorläufige Ergebnisse

Name                    Draws Losses Wins  Score  

zsani_bot:              40    5377   94583  0.892 
better_constant_player: 0     28665  71335  0.427 
constant_player:        3     53961  46036 -0.079 
normalBot:              38    64903  35059 -0.298 
better_random_player:   192   71447  28361 -0.431 
random_player:          199   75411  24390 -0.510 
user1502040
quelle
Können Sie erklären, warum Sie die Ansicht [-1] [j] == 0 aktivieren? Ich bin mir nicht ganz sicher, ob ich sehe, wo Sie sie gefüllt haben, und mein Python-Wissen scheint etwas verrostet zu sein.
Barbarian72
@ Barbarian772 Ich überprüfe, ob in dieser Spalte noch Platz ist. Beachten Sie, dass es 6 Zeilen gibt, sodass die oberste Zeile vollständig eingehalten wird.
user1502040
1
Sie sollten das Platzieren in bereits vollen Spalten nicht als Pass zählen. Viele Connect 4-Spiele enden mit nur einer nicht gefüllten Spalte. Wenn ein Spieler durch das Spielen in dieser Spalte verliert, wird das Spiel unentschieden, wenn es ansonsten ein erzwungener Gewinn für einen Spieler ist.
Saktinpk
@soktinpk Fügt das nicht einfach eine weitere Strategieebene hinzu? Connect-4 ist schließlich ein gelöstes Spiel, daher könnte der Faktor für das Überspringen von Runden als Regeländerung ausreichen, bei der Mitwirkende nicht nur die Standardalgorithmen verwenden können.
Mypetlion
1
Null-Indizierung von unten, sind die überklebten Zeilen (0,2,4,6) oder (1,3,5)? Einige ASCII-Grafiken wären hilfreich.
SIGSTACKFAULT

Antworten:

6

Dieser Bot nimmt alle sicheren Siege und fällt zurück, um die Rivalen zu blockieren, sie vertikal und horizontal zu erraten oder zufällige Züge zu machen.

Druck, Mathematik, Sammlungen, Kopie importieren
def zsani_bot_2 (anzeigen, drehen, angeben):
    if state == None: #erster Zug - immer für die Mitte
        state = (1, 2) if turn == 0 else (2, 1) # (my_symbol, dein Symbol)
        #print (pprint.pformat (Ansicht) + 'Turn:' + str (turn) + 'Player:' + str (state [0]))
        Rückgabe 3, Zustand

    #suchen Sie offensichtliche Punkte
    für i im Bereich (1, 6): # Erste Zeile überspringen
        für j in range (len (view [i])): #TODO: Mit zip optimieren. Gehen Sie jetzt für Klarheit
            wenn view [i] [j]! = 0 und view [i-1] [j] == 0:
                Ansicht [i-1] [j] = Zustand [1]
    feindliche_punkte = math.floor (Runde / 2)
    ++ feindliche_Punkte wenn Zustand [0] == 2 sonst feindliche_Punkte
    bekannte_Punkte = Summe ([i.count (Zustand [1]) für i in Ansicht])
    fehlende_Punkte = feindliche_Punkte - bekannte_Punkte

    #get sicher gewinnt in jede Richtung
    für j im Bereich (0, 7): #jede Spalte
        für i im Bereich (4, -1, -1):
            if view [i] [j]! = 0:
                break #find höchster bekannter gefüllter Punkt
        if (nicht fehlende_Punkte oder i + 1 in {1, 3, 5}):
            view1 = copy.deepcopy (Ansicht)
            try = apply_move (view1, state [0], j)
            if try == WON:
               # print (pprint.pformat (Ansicht) + 'Turn:' + str (Turn) + 'Player:' + str (Status [0]) + 'Winner Move')
                return j, state

    # Block sicher, dass der Feind in jede Richtung gewinnt
    für j im Bereich (0, 7):
        für i im Bereich (4, -1, -1):
            if view [i] [j]! = 0:
                break #find höchster bekannter gefüllter Punkt
        if (nicht fehlende_Punkte oder (i + 1 in {1, 3, 5})):
            view1 = copy.deepcopy (Ansicht)
            try = apply_move (view1, state [1], j)
            if try == WON:
              # print (pprint.pformat (Ansicht) + 'Turn:' + str (Turn) + 'Player:' + str (Status [0]) + 'Save Move')
                return j, state

    # Wände blockieren
    für i im Bereich (0, 3): # Es ist unmöglich, 4 in einer Reihe zu erhalten, wenn die Spalte voll ist
        für j im Bereich (0, 6):
            wenn Ansicht [i] [j]! = 0 und Ansicht [i] [j] == Ansicht [i + 1] [j] und Ansicht [i + 2] [j] == Ansicht [i + 3] [j ] == 0:
             # print (pprint.pformat (Ansicht) + 'Turn:' + str (turn) + 'Player:' + str (state [0]) + 'column move')
                return j, state

    # Plattform blockieren, wenn perfekte Informationen in der Zeile darunter und am Ablagepunkt vorhanden sind
    für i im Bereich (0, 5):
        für j im Bereich (0, 3):
            stats = collection.Counter ([Ansicht [i] [j], Ansicht [i] [j + 1], Ansicht [i] [j + 2], Ansicht [i] [j + 3]])
            wenn stats [0] == 2 und (stats [state [0]] == 2 oder stats [state [0]] == 2):
                für k im Bereich (0, 3):
                    if view [i] [j + k] == 0:
                        brechen
                if (i == 0 oder view [i-1] [j + k]! = 0) und (nicht fehlende_Punkte oder i in {1, 3, 5}):
                    #print (pprint.pformat (Ansicht) + 'Turn:' + str (turn) + 'Player:' + str (state [0]) + 'platform move')
                    return j + k, state
                sonst:
                    für l im Bereich (k, 3):
                        if view [i] [j + l] == 0:
                            brechen
                        if (i == 0 oder view [i-1] [j + l]! = 0) und (nicht fehlende_Punkte oder i in {1, 3, 5}):
                     # print (pprint.pformat (Ansicht) + 'Turn:' + str (turn) + 'Player:' + str (state [0]) + 'platform move')
                            return j + l, state

    #fallback -> zufällig
    während wahr:
        j = random.randrange (0, 7)
        if view [-1] [j] == 0:
            #print (pprint.pformat (Ansicht) + 'Turn:' + str (turn) + 'Player:' + str (state [0]) + 'random move')
            return j, state

Danke, dass du run_game repariert hast!

Änderungsprotokoll:

  • v2 fügt horizontales Blockieren hinzu - wenn in einer Reihe von 4 zwei leere Stellen und zwei Stellen vom selben Spieler besetzt sind, wird versucht, eine davon zu füllen, um drei in einer Reihe zu haben / die gegnerische Reihe zu blockieren, was hoffentlich der Fall sein wird in den folgenden Runden aktiviert werden.
Syfer Polski
quelle
3
Willkommen auf der Website. Ich habe dafür gestimmt, die Bearbeitung abzulehnen, um sie in Code umzuwandeln. Am besten lassen Sie sie als Kommentar, damit das OP entscheiden kann, was mit dem Code geschehen soll.
Ad-hoc-Garf-Jäger
Ich habe nicht genug Ruf, um den Hauptbeitrag zu kommentieren. Wie ziehe ich eine Bearbeitung zurück?
Syfer Polski
Sie müssen die Bearbeitung nicht zurückziehen (ich glaube nicht, dass Sie das können). In Zukunft wird es ausreichen, Kommentare abzugeben, aber da Sie dies in Ihrer Antwort gesagt haben, ist es wahrscheinlich, dass das OP dies sieht. Außerdem denke ich , dass das OP sehen wird, dass Sie vorgeschlagen und bearbeitet haben, auch wenn es abgelehnt wurde.
Ad-hoc-Garf-Jäger
Der Grund, warum ich die Bearbeitung zurückziehen möchte, ist, dass ich eine Zeile in den Änderungen verpasst habe, ohne die der bearbeitete Code nicht vollständig ausgeführt werden kann. Ich habe es in den Bearbeitungsvorschlag in meinem Beitrag aufgenommen. Danke für Ihre Hilfe!
Syfer Polski
2

normalBot geht davon aus, dass Flecken in der Mitte wertvoller sind als Flecken an den Enden. Daher wird eine in der Mitte zentrierte Normalverteilung verwendet, um die Auswahl zu bestimmen.

def normalBot(view, turn, state):
    randomNumber = round(np.random.normal(3, 1.25))
    fullColumns = []
    for i in range(7):
        if view[-1][i] != 0:
            fullColumns.append(i)
    while (randomNumber > 6) or (randomNumber < 0) or (randomNumber in fullColumns):
        randomNumber = round(np.random.normal(3, 1.25))
    return randomNumber, state
Bob Cratchit
quelle
-1

Dies ist offensichtlich nicht konkurrierend, aber dennoch sehr nützlich zum Debuggen ... und überraschend lustig, wenn Sie Ihren Bot gut genug kennen, um zu schummeln: D Ich poste also in der Hoffnung, weitere Einsendungen zu inspirieren:

import math, pprint
def manual_bot(view, turn, state):
    if state == None:
        state = (1, 2) if turn == 0 else (2, 1) #(my_symbol, your symbol)

#locate obvious points
    for row in range (1, 6):
        for j in range(len(view[row])):
            if view[row][j] != 0 and view[row-1][j] == 0:
                view[row-1][j] = state[1]

#if you're second, the opponent has one more point than half the turns
    enemy_points = math.ceil(turn/2)
    known_points = sum([row.count(state[1]) for row in view])
    missing_points = enemy_points - known_points

    print(pprint.pformat(view) + ' Turn: ' + str(turn) + ' Player: ' + str(state[0]) + ' Missing points: ' + str(missing_points))
    while True:
        try:
            move = int(input("What is your move?(0-6) "))
        except ValueError:
            continue
        if move in {0, 1, 2, 3, 4, 5, 6}:
            return move, state

Das Gitter steht auf dem Kopf (die unterste Reihe ist am höchsten). Um die Gewinnerankündigungen zu erhalten, müssen Sie den Gamecontroller patchen und eine Druckanweisung hinzufügen, bevor Sie den Gewinn zurückgeben:

elif outcome == WON:
    print(pprint.pformat(board) + ' Turn: ' + str(turn) +' Winner: '+ str(p))
    return p

[[0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0]] Zug: 0 Spieler: 1 Fehlende Punkte: 0
Was ist dein Zug? (0-6) 3
[[0, 0, 0, 1, 0, 0, 0],
 [0, 0, 0, 2, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0]] Zug: 2 Spieler: 1 Fehlende Punkte: 0
Was ist dein Zug? (0-6) 2
[[0, 0, 1, 1, 0, 0, 0],
 [0, 0, 0, 2, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0]] Zug: 4 Spieler: 1 Fehlende Punkte: 1
Was ist dein Zug? (0-6) 4
[[0, 0, 1, 1, 1, 0, 0],
 [0, 0, 0, 2, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0]] Zug: 6 Spieler: 1 Fehlende Punkte: 2
Was ist dein Zug? (0-6) 1
[[2, 1, 1, 1, 1, 2, 0],
 [0, 0, 0, 2, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0]] Runde: 6 Gewinner: 1
[[0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0]] Zug: 1 Spieler: 2 Fehlende Punkte: 1
Was ist dein Zug? (0-6) 2
[[0, 0, 2, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0]] Zug: 3 Spieler: 2 Fehlende Punkte: 2
Was ist dein Zug? (0-6) 3
[[0, 0, 2, 1, 0, 0, 0],
 [0, 0, 1, 2, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0]] Zug: 5 Spieler: 2 Fehlende Punkte: 1
Was ist dein Zug? (0-6) 4
[[0, 0, 2, 1, 2, 0, 0],
 [0, 0, 1, 2, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0]] Zug: 7 Spieler: 2 Fehlende Punkte: 2
Was ist dein Zug? (0-6) 1
[[0, 2, 2, 1, 2, 0, 0],
 [0, 0, 1, 2, 0, 0, 0],
 [0, 0, 1, 0, 0, 0, 0],
 [0, 0, 1, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0]] Zug: 9 Spieler: 2 Fehlende Punkte: 1
Was ist dein Zug? (0-6) 2
[[0, 2, 2, 1, 2, 0, 0],
 [0, 0, 1, 2, 0, 0, 0],
 [0, 0, 1, 0, 0, 0, 0],
 [0, 0, 1, 0, 0, 0, 0],
 [0, 0, 2, 0, 0, 0, 0],
 [0, 0, 1, 0, 0, 0, 0]] Zug: 11 Spieler: 2 Fehlende Punkte: 1
Was ist dein Zug? (0-6) 4
[[0, 2, 2, 1, 2, 0, 0],
 [0, 0, 1, 2, 2, 0, 0],
 [0, 0, 1, 0, 0, 0, 0],
 [0, 0, 1, 0, 0, 0, 0],
 [0, 0, 2, 0, 0, 0, 0],
 [0, 0, 1, 0, 0, 0, 0]] Zug: 13 Spieler: 2 Fehlende Punkte: 2
Was ist dein Zug? (0-6) 4
[[0, 2, 2, 1, 2, 0, 0],
 [0, 1, 1, 2, 2, 0, 0],
 [0, 0, 1, 0, 1, 0, 0],
 [0, 0, 1, 0, 2, 0, 0],
 [0, 0, 2, 0, 0, 0, 0],
 [0, 0, 1, 0, 0, 0, 0]] Zug: 15 Spieler: 2 Fehlende Punkte: 1
Was ist dein Zug? (0-6) 3
[[0, 2, 2, 1, 2, 0, 0],
 [0, 1, 1, 2, 2, 0, 0],
 [0, 0, 1, 2, 1, 0, 0],
 [0, 0, 1, 0, 2, 0, 0],
 [0, 0, 2, 0, 0, 0, 0],
 [0, 0, 1, 0, 0, 0, 0]] Zug: 17 Spieler: 2 Fehlende Punkte: 2
Was ist dein Zug? (0-6) 5
[[0, 2, 2, 1, 2, 1, 1],
 [0, 1, 1, 2, 2, 2, 1],
 [0, 0, 1, 2, 1, 0, 0],
 [0, 0, 1, 0, 2, 0, 0],
 [0, 0, 2, 0, 0, 0, 0],
 [0, 0, 1, 0, 0, 0, 0]] Zug: 19 Spieler: 2 Fehlende Punkte: 0
Was ist dein Zug? (0-6) 
Was ist dein Zug? (0-6) 6
[[0, 2, 2, 1, 2, 1, 1],
 [0, 1, 1, 2, 2, 2, 1],
 [0, 0, 1, 2, 1, 0, 2],
 [0, 0, 1, 0, 2, 0, 0],
 [0, 0, 2, 0, 0, 0, 0],
 [0, 0, 1, 0, 0, 0, 0]] Zug: 21 Spieler: 2 Fehlende Punkte: 1
Was ist dein Zug? (0-6) 1
[[0, 2, 2, 1, 2, 1, 1],
 [0, 1, 1, 2, 2, 2, 1],
 [0, 2, 1, 2, 1, 0, 2],
 [0, 1, 1, 0, 2, 0, 0],
 [0, 0, 2, 0, 0, 0, 0],
 [0, 0, 1, 0, 0, 0, 0]] Zug: 23 Spieler: 2 Fehlende Punkte: 1
Was ist dein Zug? (0-6) 3
[[0, 2, 2, 1, 2, 1, 1],
 [0, 1, 1, 2, 2, 2, 1],
 [0, 2, 1, 2, 1, 0, 2],
 [0, 1, 1, 2, 2, 0, 0],
 [0, 0, 2, 0, 0, 0, 0],
 [0, 0, 1, 0, 0, 0, 0]] Zug: 25 Spieler: 2 Fehlende Punkte: 2
Was ist dein Zug? (0-6) 6
[[0, 2, 2, 1, 2, 1, 1],
 [0, 1, 1, 2, 2, 2, 1],
 [0, 2, 1, 2, 1, 0, 2],
 [0, 1, 1, 2, 2, 0, 2],
 [0, 0, 2, 1, 0, 0, 0],
 [0, 0, 1, 1, 0, 0, 0]] Zug: 27 Spieler: 2 Fehlende Punkte: 1
Was ist dein Zug? (0-6) 5
[[1, 2, 2, 1, 2, 1, 1],
 [1, 1, 1, 2, 2, 2, 1],
 [0, 2, 1, 2, 1, 2, 2],
 [0, 1, 1, 2, 2, 0, 2],
 [0, 0, 2, 1, 0, 0, 0],
 [0, 0, 1, 1, 0, 0, 0]] Zug: 29 Spieler: 2 Fehlende Punkte: 0
Was ist dein Zug? (0-6) 5
[[1, 2, 2, 1, 2, 1, 1],
 [1, 1, 1, 2, 2, 2, 1],
 [0, 2, 1, 2, 1, 2, 2],
 [0, 1, 1, 2, 2, 2, 2],
 [0, 0, 2, 1, 0, 0, 0],
 [0, 0, 1, 1, 0, 0, 0]] Runde: 29 Gewinner: 2
Runde 1 von 1

Name Draws Losses Wins Score
manual_bot: 0 0 2 1.000 zsani_bot_2: 0 2 0 -1.000

Syfer Polski
quelle