Le dilemme du prisonnier v.3 - Petri Dilemma


17

Un savant fou vient de créer une nouvelle espèce de bactérie! Il a décidé de le nommer appeler Noblus Gentlemanus, après avoir observé son comportement. Cependant, ses bactéries ont manqué de nourriture et ont déclaré la guerre, car elles sont capables de récolter les cadavres d'autres bactéries pour suffisamment de nourriture pour créer des copies d'eux-mêmes. Il existe un certain nombre de sous-espèces différentes de cette bactérie, qui ont des stratégies différentes pour jouer à Prisoner's Dilemma, leur jeu préféré. Il existe cinq bactéries de chaque sous-espèce différente. Dans le dilemme du prisonnier, chacun des deux joueurs choisit simultanément soit un défaut soit une coopération. Si un joueur choisit de coopérer et l'autre choisit par défaut, le défaillant obtient 2 points et le coopérateur perd 3 points. Si les deux joueurs choisissent de coopérer, les deux joueurs obtiennent un 1 point. Si les deux joueurs choisissent par défaut, les deux joueurs perdent 1 point.

Étant des gentilshommes nobles, les bactéries ont décidé de mener cette guerre en jouant 200 parties longues de Dilemme du prisonnier itéré. Le perdant de chaque duel se suicidera, permettant au vainqueur de se cloner. En cas d'égalité, les deux bactéries resteront vivantes, mais aucune ne pourra se cloner. De plus, toutes les bactéries d'un match reportent plus de 10% de leurs points au match suivant. Un clone transporte les points de la bactérie par laquelle il a été cloné. De plus, il y a une chance sur dix à chaque tour qu'une bactérie mute en une autre sous-espèce, avec 0 points bonus (si je reçois des plaintes concernant le caractère aléatoire de cela, je peux le supprimer). Après que les bactéries ont joué un nombre de ces duels égal au nombre de sous-espèces de bactéries multiplié par dix, le savant fou laisse tomber accidentellement la boîte de Pétri dans laquelle les bactéries résident, et toutes les bactéries acquièrent de nouvelles sources de nourriture, mettant fin à leurs duels. Ceci est différent du concours de dilemme d'un prisonnier itéré ordinaire, car il implique des duels 1v1 avec des points de report, plutôt que de simplement essayer d'obtenir le plus de points dans l'ensemble. Cela fait une grande différence dans l'efficacité d'une stratégie donnée.

Chaque bactérie recevra une entrée au début de son tour au format: (numéro de tour, points actuels, points ennemis, vos coups précédents [dans une chaîne, en utilisant le caractère "c" pour coopérer et le caractère "d" pour défaut) ], les mouvements antérieurs des ennemis [dans le même format]).

Voici quatre exemples de stratégies qui seront saisis. En fait, je pense que Defector pourrait gagner, même si c'est extrêmement simple.

Mésange pour Tat

def titfortatfunc(counter, mypoints, enpoints, mylist, enlist):
    if counter==0 or enlist[counter-1] == "c":
        return "c"
    else:
        return "d"

RandomPick

from random import choice
def randompickfunc(counter, mypoints, enpoints, mylist, enlist):
    if counter == 199:
        return "d"
    else:
        return choice(["d", "c"])

Coopératrice

def cooperatorfunc(counter, mypoints, enpoints, mylist, enlist):
    return "c"

Transfuge

def defectorfunc(counter, mypoints, enpoints, mylist, enlist):
    return "d"

Toutes les soumissions doivent être sous la forme d'une fonction Python 2.7, le nom étant le nom de la soumission sans espaces, avec funcà la fin. Si quelqu'un souhaite soumettre une réponse dans une autre langue, veuillez l'entrer en pseudo-code, pour que je me convertisse en Python dans une édition de votre réponse une fois que j'en ai le temps, ou donnez-moi des instructions pour interfacer votre langue avec mon contrôleur qui se trouve ci-dessous, configuré pour toutes les soumissions au 4 juin.

from titfortat import titfortatfunc
from randompick import randompickfunc
from cooperator import cooperatorfunc
from defector import defectorfunc
from luckytitfortat import luckytitfortatfunc
from randomtitfortat import randomtitfortatfunc
from remorsefulaggressor import remorsefulaggressorfunc
from everyother import everyotherfunc
from niceguy import niceguyfunc
from titfortatbackstab import titfortatbackstabfunc
from gentleDefector import gentleDefectorfunc
from anticapitalist import anticapitalistfunc
from grimtrigger import grimtriggerfunc
from bizzaro import bizzarofunc
from neoanticapitalist import neoanticapitalistfunc
from bittertat import bittertatfunc
from teamer import teamerfunc
from copyfirst import copyfirstfunc
from exploitivetat import exploitativetatfunc
from defectorv2 import defectorv2func
from crazytat import crazytatfunc
from randomchoicev2 import randomchoicev2func
from twotitsforatat import twotitsforatatfunc
from threetitsforatat import threetitsforatatfunc
from fourtitsforatat import fourtitsforatatfunc
from fivetitsforatat import fivetitsforatatfunc
from sixtitsforatat import sixtitsforatatfunc
from tentitsforatat import tentitsforatatfunc
from theelephant import theelephantfunc
from xbittertat import xbittertatfunc
from fifteentitsforatat import fifteentitsfortatfunc
from twentytitsforatat import twentytitsforatatfunc
from fox import foxfunc
from onehundredfortysixtitsforatat import onehundredfourtysixtitsforatatfunc
from gameofthrones import gameofthronesfunc
from boy import boyfunc
from grimace import grimacefunc
from fiftytitsforatat import fiftytitsfortatfunc
from soreloser import soreloserfunc
from everyotherd import everyotherdfunc
from fiftythreetitsfortat import fiftythreetitsfortatfunc
from twentyfivetitsfortat import twentyfivetitsfortatfunc
from handshake import handshakefunc
from anty import antyfunc
from fiftyfourtitsforatat import fiftyfourtitsfortatfunc
from kindatitsfortat import kindatitsfortatfunc

import random

players = 38

rounds = players*10

def runcode(num, points1, points2, history1, history2, cell):
    ans = ""
    if cell == 0:
        ans = titfortatfunc(num, points1, points2, history1, history2)
    elif cell == 1:
        ans = randompickfunc(num, points1, points2, history1, history2)
    elif cell == 2:
        ans = cooperatorfunc(num, points1, points2, history1, history2)
    elif cell == 3:
        ans = defectorfunc(num, points1, points2, history1, history2)
    elif cell == 4:
        ans = luckytitfortatfunc(num, points1, points2, history1, history2)
    elif cell == 5:
        ans = randomtitfortatfunc(num, points1, points2, history1, history2)
    elif cell == 6:
        ans = remorsefulaggressorfunc(num, points1, points2, history1, history2)
    elif cell == 7:
        ans = everyotherfunc(num, points1, points2, history1, history2)
    elif cell == 8:
        ans = niceguyfunc(num, points1, points2, history1, history2)
    elif cell == 9:
        ans = titfortatbackstabfunc(num, points1, points2, history1, history2)
    elif cell == 10:
        ans = gentleDefectorfunc(num, points1, points2, history1, history2)
    elif cell == 11:
        ans = anticapitalistfunc(num, points1, points2, history1, history2)
    elif cell == 12:
        ans = grimtriggerfunc(num, points1, points2, history1, history2)
    elif cell == 13:
        ans = bizzarofunc(num, points1, points2, history1, history2)
    elif cell == 14:
        ans = neoanticapitalistfunc(num, points1, points2, history1, history2)
    elif cell == 15:
        ans = tentitsforatatfunc(num, points1, points2, history1, history2)
    elif cell == 16:
        ans = bittertatfunc(num, points1, points2, history1, history2)
    elif cell == 17:
        ans = copyfirstfunc(num, points1, points2, history1, history2)
    elif cell == 18:
        ans = exploitativetatfunc(num, points1, points2, history1, history2)
    elif cell == 19:
        ans = sixtitsforatatfunc(num, points1, points2, history1, history2)
    elif cell == 20:
        ans = fifteentitsfortatfunc(num, points1, points2, history1, history2)
    elif cell == 21:
        ans = fivetitsforatatfunc(num, points1, points2, history1, history2)
    elif cell == 22:
        ans = twentytitsforatatfunc(num, points1, points2, history1, history2)
    elif cell == 23:
        ans = threetitsforatatfunc(num, points1, points2, history1, history2)
    elif cell == 24:
        ans = fiftyfourtitsfortatfunc(num, points1, points2, history1, history2)
    elif cell == 25:
        ans = theelephantfunc(num, points1, points2, history1, history2)
    elif cell == 26:
        ans = xbittertatfunc(num, points1, points2, history1, history2)
    elif cell == 27:
        ans = foxfunc(num, points1, points2, history1, history2)
    elif cell == 28:
        ans = gameofthronesfunc(num, points1, points2, history1, history2)
    elif cell == 29:
        ans = boyfunc(num, points1, points2, history1, history2)
    elif cell == 30:
        ans = grimacefunc(num, points1, points2, history1, history2)
    elif cell == 31:
        ans = soreloserfunc(num, points1, points2, history1, history2)
    elif cell == 32:
        ans = everyotherdfunc(num, points1, points2, history1, history2)
    elif cell == 33:
        ans = twentyfivetitsfortatfunc(num, points1, points2, history1, history2)
    elif cell == 34:
        ans = fiftythreetitsfortatfunc(num, points1, points2, history1, history2)
    elif cell == 35:
        ans = handshakefunc(num, points1, points2, history1, history2)
    elif cell == 36:
        ans = antyfunc(num, points1, points2, history1, history2)
    elif cell == 37:
        ans = kindatitsfortatfunc(num, points1, points2, history1, history2)


    return ans

def fight(l1,l2):
    num1,num2=l1[0],l2[0]
    points1,points2=l1[1],l2[1]
    history1 = ""
    history2 = ""

    for num in range(200):
        p1 = runcode(num, points1, points2, history1, history2, num1)
        p2 = runcode(num, points2, points1, history2, history1, num2)

        history1+=p1
        history2+=p2

        if p1 == "c" and p2 == "c":
            points1 += 1
            points2 += 1
        elif p1 == "c" and p2 == "d":
            points1 -= 3
            points2 += 2
        elif p1 == "d" and p2 == "c":
            points1 += 2
            points2 -= 3
        elif p1 == "d" and p2 == "d":
            points1 -= 1
            points2 -= 1

    if points1 > points2:
        return [l1[0], points1/10], [l1[0], points1/10]
    elif points1 < points2:
        return [l2[0], points2/10], [l2[0], points2/10]
    else:
        return [l1[0], points1/10], [l2[0], points2/10]

def rounddoer(bots):
    bots2=[]
    for x in range(len(bots)):
        if x%2==0:
            out1, out2 = fight(bots[x], bots[x-1])
            bots2.append(out1)
            bots2.append(out2)

    return bots2

def gamedoer():

    bots=[[0,0],[1,0],[2,0],[3,0],[4,0],[5,0],[6,0],[7,0],[8,0],[9,0],[10,0],[11,0],[12,0],[13,0],[14,0],[15,0],[16,0],[17,0],[18,0],[19,0],[20,0],[21,0],[22,0],[23,0],[24,0],[25,0],[26,0],[27,0],[28,0],[29,0],[30,0],[31,0],[32,0],[33,0],[34,0],[35,0],[36,0],[37,0],[0,0],[1,0],[2,0],[3,0],[4,0],[5,0],[6,0],[7,0],[8,0],[9,0],[10,0],[11,0],[12,0],[13,0],[14,0],[15,0],[16,0],[17,0],[18,0],[19,0],[20,0],[21,0],[22,0],[23,0],[24,0],[25,0],[26,0],[27,0],[28,0],[29,0],[30,0],[31,0],[32,0],[33,0],[34,0],[35,0],[36,0],[37,0],[0,0],[1,0],[2,0],[3,0],[4,0],[5,0],[6,0],[7,0],[8,0],[9,0],[10,0],[11,0],[12,0],[13,0],[14,0],[15,0],[16,0],[17,0],[18,0],[19,0],[20,0],[21,0],[22,0],[23,0],[24,0],[25,0],[26,0],[27,0],[28,0],[29,0],[30,0],[31,0],[32,0],[33,0],[34,0],[35,0],[36,0],[37,0],[0,0],[1,0],[2,0],[3,0],[4,0],[5,0],[6,0],[7,0],[8,0],[9,0],[10,0],[11,0],[12,0],[13,0],[14,0],[15,0],[16,0],[17,0],[18,0],[19,0],[20,0],[21,0],[22,0],[23,0],[24,0],[25,0],[26,0],[27,0],[28,0],[29,0],[30,0],[31,0],[32,0],[33,0],[34,0],[35,0],[36,0],[37,0],[0,0],[1,0],[2,0],[3,0],[4,0],[5,0],[6,0],[7,0],[8,0],[9,0],[10,0],[11,0],[12,0],[13,0],[14,0],[15,0],[16,0],[17,0],[18,0],[19,0],[20,0],[21,0],[22,0],[23,0],[24,0],[25,0],[26,0],[27,0],[28,0],[29,0],[30,0],[31,0],[32,0],[33,0],[34,0],[35,0],[36,0],[37,0]]
    random.shuffle(bots)
    counter=0

    while counter < rounds:

        counter += 1
        bots = rounddoer(bots)

        if random.randint(0,10) == 9:
            bots[random.randint(0, players*5)-1] = [random.randint(0, players-1), 0]

        random.shuffle(bots)

##        for item in bots:
##            print str(item[0]) + " with " + str(item[1]) + " bonus points."

    return bots

a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31,a32,a33,a34,a35,a36,a37,mycounter=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

while mycounter < 1000:
    mycounter += 1
    bots = gamedoer()

    print "Game: " + str(mycounter)

    for item in bots:
        if item[0]==0:
            a0 += 1
        if item[0]==1:
            a1 += 1
        if item[0]==2:
            a2 += 1
        if item[0]==3:
            a3 += 1
        if item[0]==4:
            a4 += 1
        if item[0]==5:
            a5 += 1
        if item[0]==6:
            a6 += 1
        if item[0]==7:
            a7 += 1
        if item[0]==8:
            a8 += 1
        if item[0]==9:
            a9 += 1
        if item[0]==10:
            a10 += 1
        if item[0]==11:
            a11 += 1
        if item[0]==12:
            a12 += 1
        if item[0]==13:
            a13 += 1
        if item[0]==14:
            a14+=1
        if item[0]==15:
            a15+=1
        if item[0]==16:
            a16+=1
        if item[0]==17:
            a17+=1
        if item[0]==18:
            a18 += 1
        if item[0]==19:
            a19+=1
        if item[0]==20:
            a20+=1
        if item[0]==21:
            a21+=1
        if item[0]==22:
            a22+=1
        if item[0]==23:
            a23+=1
        if item[0]==24:
            a24+=1
        if item[0]==25:
            a25+=1
        if item[0]==26:
            a26+=1
        if item[0]==27:
            a27+=1
        if item[0]==28:
            a28+=1
        if item[0]==29:
            a29+=1
        if item[0]==30:
            a30+=1
        if item[0]==31:
            a31+=1
        if item[0]==32:
            a32+=1
        if item[0]==33:
            a33+=1
        if item[0]==34:

Ce concours est maintenant terminé

Si vous souhaitez ajouter une réponse, je vais voir si je peux contourner l'ajout d'un tableau de bord post-défi sous celui des candidats originaux. J'ajouterai celui-ci dès que le programme de test se terminera (probablement 2-3 jours de plus).

SCORES FINAUX !!!!!

Tit for Tat: 18
Random Pick: 28
Cooperator: 19
Defector: 24
Lucky Tit for Tat: 23
Random Tit for Tat: 23
Remorseful Aggressor: 22
Every Other C: 23
Nice Guy: 18
Tit for Tat Backstab: 15
Gentle Defector: 22
Anticapitalist: 27
Grim Trigger: 19
Bizzaro: 21
NeoAnticapitalist: 24
Ten Tits for a Tat: 240
Bitter Tat: 12
Copy First: 30
Exploitative Tat: 19
Six Tits for a Tat: 16
Thirty Tits for Tat: 4129
Five Tits for a Tat: 22
Forty Tits for a Tat: 1972
Three Tits for a Tat: 22
Fifty Four Tits for a Tat: 25805
The Elephant: 31
Extra Bitter Tat: 28
Fox: 35
Game of Thrones: 11297
The Boy: 31
Grimace: 26
Sore Loser: 39
Every Other D: 18
Twenty Five Tits for a Tat: 2399
Fifty Three Tits for a Tat: 5487
Handshake: 28
Anty: 26
Kinda Tits for Tat: 20
Prudent Defector: 154539
Bizzarro Trigger: 25
Young Mathematician: 21
Older Mathematician: 16
Perfect Gentleman: 1953341

Il semble donc que Perfect Gentleman soit le gagnant. Félicitations à Draco18, qui mérite définitivement sa coche verte.


Les commentaires ne sont pas pour une discussion approfondie; cette conversation a été déplacée vers le chat .
Dennis

1
REMARQUE: SI VOUS MODIFIEZ VOTRE PROGRAMME, S'IL VOUS PLAÎT, DONNEZ-MOI UN COMMENTAIRE POUR QUE JE AVIS, OU IL NE PEUT PAS ÊTRE MIS AU TABLEAU DE BORD PENDANT TOUT !!!!!!!!!!!!!!!!!!!!! !!!
Gryphon - Rétablir Monica le

Oui! Je viens de réaliser le nombre d'importations.
Gryphon - Rétablir Monica le

1
Hé Gryphon, tu travailles sur ces classements finaux? ;)
Draco18s ne fait plus confiance au SE

Désolé, j'ai oublié ça. Donnez-moi un peu pour l'exécuter.
Gryphon - Réintègre Monica le

Réponses:


8

Le parfait gentleman

Je n'ai pas une bonne description de ce bot. Je suis tombé sur quelques optimisations potentielles, les ai testées, affinées et je me suis retrouvé avec une bactérie qui détruit complètement la concurrence. Au lieu de cela, j'ai commenté le code lui-même pour expliquer ce qu'il fait.

import random
def perfectgentlemanfunc(num, i, d, c, en):
    if num>0 and i < 0 and d > 0 and -i%3 == 0 and d%2 == 0 and en[0] == "d":
        #probably very first iteration, probably facing a defector: feed it free points
        #    defector cannot be beaten by *any* bot unless that bot
        #    entered with a point lead. defector does some of our work for us
        if num >= 140:
            #140 threshold restricts how much we feed
            return "d"
        return "c"
    turn_to_betray = 130
    if num > turn_to_betray and en[turn_to_betray -2] == "c" and
     en[turn_to_betray -1] == "c" and en[turn_to_betray] == "d":
        #if self, then sacrifice the lower point bot to raise the points of the higher
        #(better net outcome than "c/c" cooperation)
        #    Handshake independently arrived at this same optimization
        if i == d:
            #max 50% probability of choosing different possible. May as well take it
            #    "ccd" has a 55% chance of choosing the same
            #    better outcomes for splitting early
            return "cd"[random.randint(0,1)]
        if i > d:
            return "d"
        return "c"
    #betray after betray point, or if behind by >200
    #performs 6 percentage points better than not having the condition
    if num >= turn_to_betray or i + 200 < d
        return "d"
    else:
        #be nice the first turn
        if num == 0:
            return "c";
        #finally, be tit-for-tat
        return en[-1]

Plusieurs valeurs ont été choisies arbitrairement avec des alternatives testées et les valeurs ici sont presque optimales à ce stade. Contre la propagation actuelle des factions opposées, The Perfect Gentleman atteint une domination complète (100% de la population bactérienne) environ 90% du temps (plus ou moins 3 points de pourcentage).

Je n'ai pas encore ajouté les mathématiciens à mes tests, mais ces deux ne devraient servir qu'à alimenter les stratégies existantes et à ne pas modifier considérablement le résultat.

Il gère une bonne partie de son contrôle en soutenant Defector, mais cela était autorisé par les règles (les exemples de stratégies étaient un jeu équitable pour le ciblage). Cela a pour effet secondaire de soutenir également Game of Thrones, mais ce n'était pas intentionnel car les deux ne se distinguent pas en fonction des critères que j'ai choisis. Ces "types de transfuges" ont alors un avantage de point au tour 2 et éliminent en conséquence plusieurs voisins gênants (les types N-T4T) et lorsqu'ils refaçonnent The Perfect Gentleman, ils ont dépensé leur avantage de point et sont rapidement consommés.

Il y a environ 5% de chances que tous les Perfect Gentlemen se retrouvent jumelés avec des types de Defector au premier tour et finissent par se suicider en masse. Dans ce cas, l'un des types n-T4t atteint une domination totale (196 cellules sur 196). Très rarement l'un des autres types (Game of Thrones, Boy, Grimace, Sore Loser ...) parvient à ne pas s'éteindre complètement et à marquer un point ou deux.

Simulation actuelle (toujours en cours vers 200 jeux au total). Toutes les entrées marquant 0 ont été supprimées. On dirait que Game of Thrones et 54-T4T ont divisé un tour (195 points entre eux) après l'élimination de PG.

Game: 90

Cooperator: 1
Remorseful Aggressor: 1
Copy First: 1
Six Tits for a Tat: 1
Thirty Tits for Tat: 393
Five Tits for a Tat: 1
Fifty Four Tits for a Tat: 538
Game of Thrones: 248
Perfect Gentleman: 16456 (93.2)%

##Simulation Terminated: Adding new bots

Mésange poignardée pour Tat (avec pardon)

Il s'agit essentiellement de Lucky Tit for Tat (alias Tit for Tat with Forgiveness) qui est la solution optimale "résolue" (pour une valeur de "lucky"), avec une touche. Comme nous savons exactement combien de tours durera le jeu, cette bactérie backstab au dernier tour garantissant ainsi un résultat net bénéfique contre toute autre bactérie Tit for Tat et Cooperator (contre elle-même, elle se termine par un zéro net, comme si elle avait coopéré). En raison du report de 10%, cela se traduit par un avantage à long terme.

from random import randint
def titfortatbackstabfunc(num, i, d, c, enlist):
    if num == 199:
        return "d";
    lucky = randint(0, 200)
    if lucky == 0:
        return "c"
    if num == 0 or enlist[-1] == "c":
        return "c"
    else:
        return "d"

Bitter Tat

Bitter Tat profite de toutes les tentatives de coopération données par l'ennemi lorsque l'ennemi est en avance en points. La plupart des bactéries offrent un rameau d'olivier au moins une fois au cours des 200 rounds, et comme Bitter Tat est en retard dans l'ensemble, il va traire ces 5 points dans une tentative désespérée de récupération.

Sinon, il tit-for-tats selon la stratégie dominante habituelle. En outre, il est un peu plus saccadé que son cousin et poignardé un tour plus tôt et n'offre aucun pardon.

def bittertatfunc(num, i, d, c, enlist):
    if i < d:
        return "d";
    if num >= 198:
        return "d";
    if num == 0 or enlist[-1] == "c":
        return "c"
    else:
        return "d"

Bitter Tat a été conçu en examinant les comportements d'autres robots contre Tit for Tat et les modèles exprimés dans ces résultats, mais n'est pas conçu pour contrer explicitement ces stratégies: il s'agit toujours d'une formule à usage général.

Extra Bitter Tat

def xbittertatfunc(num, i, d, c, enlist):
    if i < d:
        return "d";
    if num >= 188:
        return "d";
    if num == 0 or enlist[-1] == "c":
        return "c"
    else:
        return "d"

Extra amer en faisant défection très tôt.


1
Veuillez changer le nom de votre fonction, car celle-ci est déjà prise.
Gryphon - Rétablir Monica

@Gryphon Oups, désolé, je ne savais pas que j'avais fait ça. Je ne code pas réellement en Python, je viens de casser deux bits de code ensemble.
Draco18 ne font plus confiance au SE

1
I suspect it will outperform NeoAnticapitalist by a small margin. Plus comme par plus de 30 000 points.
Gryphon - Réintègre Monica


2
J'apprécie que vous ayez fait un bot pour faire de ce koth plus une blague
Destructible Lemon

8

Anticapitaliste

Un autre simple. Pour les matchs pairs (commençant au même score) se comporte à peu près comme TitForTat, mais l'idée principale est d'essayer de survivre au match.

def anticapitalistfunc(counter, mypoints, enpoints, mylist, enlist):
    if mypoints >= enpoints:
        return "c"
    else:
        return "d"

Gentle Defector

Mon idée ici est de faire défaut sauf si mon ennemi coopère généralement. Cependant, il commence à coopérer.

def gentleDefectorfunc(counter, mypoints, enpoints, mylist, enlist):
    if enlist.count("d") * 4 > len(enlist):
        return "d"
    else:
        return "c"

NeoAnticapitalist

Une amélioration de l'anticapitaliste (ou du moins je pense). Je ne vois aucune raison de collaborer au dernier tour. Je ne vois pas non plus de raison de collaborer quand je suis sûr que mon adversaire ne le fera pas.

def neoanticapitalistfunc(counter, mypoints, enpoints, mylist, enlist):
    if mypoints >= enpoints:
        if counter > 1:
            if counter == 199 or (enlist[-1] != "c" and enlist[-2] != "c"):
                return "d"
        return "c"
    else:
        return "d"

Je suis en fait surpris de ne pas avoir pensé à ça, mais c'est génial. Je ne sais pas si ça va gagner, mais je pense que ça devrait très bien marcher.
Gryphon - Réintègre Monica

@Gryphon a ajouté un nouveau bot (et a fusionné mes deux autres)
Masclins

@Gryphon merci pour les deux éditions
Masclins

Pas de problème, @AlbertMasclans
Gryphon -

D'après les simulations que j'ai exécutées, NeoAnticapitalist semble avoir pris la tête de Backstabbing Tit for Tat.
Gryphon - Réintègre Monica

6

Agresseur remords

from random import randint
def remorsefulaggressorfunc(counter, mypoints, enpoints, mylist, enlist):
    if counter == 0:
        return "d"
    if (counter > 195 and mylist[-1] == "d"):
        return "d"
    if ((counter == 1 or counter > 2) and enlist[-1] == "d"):
        return "d"
    if (counter == 2 and enlist[-1] == "d" and enlist[-2] == "d"):
        return "d"
    if (counter >= 195 and randint(0, 200 - counter) == 0):
        return "d"
    else:
        return "c"

Ceci est conçu pour "suivre" Defector, en faisant à chaque fois défaut contre lui, et aussi pour battre les stratégies basées sur le tit-for-tat.

L'idée de base est que nous commençons par faire défection, mais si l'adversaire a coopéré au tour 1, nous coopérons ensuite deux fois pour éviter un cycle de récrimination mutuelle, évitant ainsi une pénalité de point trop importante. (Si, cependant, l'adversaire fait défaut plus tard, nous ne rompons pas le cycle nous-mêmes; nous le ferons le faire et perdrons probablement le jeu en conséquence.) Ensuite, à la fin du jeu, nous choisissons un moment aléatoire dans les 5 derniers tours pour poignarder l'ennemi, nous donnant une défection de plus qu'eux et signifiant ainsi que tant que nous n'étions pas trop en retard sur les points de report, nous finissons par gagner, sans sacrifier beaucoup en termes de report dans le processus . (La randomisation de la période signifie que nous sommes très susceptibles d'entrer en premier avec le backstab, également que cette stratégie ne peut pas être "ajustée contre" en visant à le backstab un tour plus tôt.)


Félicitations pour votre place numéro 3! +1
Gryphon - Réintègre Monica

6

Déclenchement sinistre

Bot simpliste, pour essayer de compléter le concours

Il coopérera, à moins que l'ennemi ne fasse défaut, auquel cas il fait défaut sans pardon

def grimtriggerfunc(I, Do, Not, Care, enlist): return "d" if "d" in enlist else "c"

Eh bien, il semble que cela ne fonctionne pas en raison de la méta ntitsfortat de défection précoce


Félicitations pour votre place numéro 5, +1.
Gryphon - Réintègre Monica

@Sleafar Je me demandais qui serait si méchant; _; ok
Destructible Lemon

5

Jeu des trônes

def gameofthronesfunc(counter, mypoints, enpoints, mylist, enlist):
    turn_to_betray = 140
    if counter >= turn_to_betray or mypoints > enpoints or "d" in enlist:
        return "d"
    else:
        return "c"

L'idée ici est que vous ne pouvez jamais perdre en trahissant, donc la seule raison de coopérer est si vous êtes derrière. Il a également le cadre général des autres réponses T4T (sans aucun pardon, car je ne suis pas sûr qu'il y ait beaucoup d'intérêt avec les autres prétendants ici).

Le tour de trahir devra peut-être être changé pour gagner, car dans une course régulière, le T4Ter qui trahit en premier gagnera, mais contre un bot très coopératif, vous manquerez des points à vie. Je ne suis pas sûr du bon sommet pour cette colline, donc je vais juste pour 140. Je ne serais pas surpris si c'était beaucoup plus tôt, cependant.

Si cela se termine dans une boîte de Pétri avec un T4Ter qui trahit plus tôt ou un transfuge (c.-à-d. 146 T4T), alors cela dépend entièrement si le GoT est déjà en avance (il restera en tête) ou s'il est pair / GoT est derrière , auquel cas le premier traître gagnera.


Félicitations pour votre troisième place! +1
Gryphon - Réintègre Monica

Et maintenant jusqu'à la seconde!
Gryphon - Rétablir Monica le

Game of Thrones met tout en œuvre pour lutter contre le bot que je teste actuellement. La stratégie simple fonctionne bien pour cela.
Draco18 ne font plus confiance au SE

4

Lucky Tit For Tat

import os
def luckytitfortatfunc(num, i, d, c, enlist):
    lucky = ord(os.urandom(1))
    lucky = int(round(200 * float(lucky - 0) / 255.0))
    if lucky == 0:
        return "c"
    if num == 0 or enlist[-1] == "c":
        return "c"
    else:
        return "d"

Je suis presque sûr d'avoir lu quelque part que tit for tat était la meilleure stratégie. J'ai décidé de permettre aux autres programmes de se racheter juste pour ajouter de la variété. Maintenant avec un bon générateur de nombres aléatoires (ça me donne un avantage non?).


Fondamentalement, c'est la stratégie gagnante, haut la main, tout le temps comme indiqué sur wikipedia . La seule variation réside dans la probabilité de rupture d'un cycle de défauts tit-for-tat (qui dépend de la correspondance de toutes les autres entrées).
Draco18 ne font plus confiance au SE

1
@ Draco18s C'est la stratégie gagnante pour un système de score différent, le système de score total des points. Le tit-for-tat de base ne peut jamais gagner un tour, s'il ne porte pas quelques points dans le tour, donc il ne ferait pas bien.
isaacg

@isaacg a raison, c'est la raison pour laquelle cette stratégie est maintenant en 14e position sur 18 (bien que je n'ai pas le droit de blâmer AH L pour cela car le 18e programme est l'un des miens.)
Gryphon - Rétablir Monica

4

L'éléphant

L'éléphant n'oublie jamais!

import re
def theelephantfunc(counter, mypoints, enpoints, mylist, enlist):
    interwoven = "".join(i for j in zip(mylist, enlist) for i in j)
    backwoven = interwoven[::-1]
    predict = re.match("^((?:..)*).*?(.).\\1(?:..)*$",backwoven)
    if(predict is None):
        return "c"
    predict = predict.groups()[1]
    if(predict == "d"):
        return "d"
    if(mypoints - enpoints >= 6):
        return "c"
    return "d"

L'éléphant examine l'histoire du combat et essaie de comprendre ce que l'ennemi a prévu. Il regarde à la fois ses mouvements et ses ennemis!

Il essaie de trouver le groupe simultané le plus long qui correspond à ce qui vient de se passer et prend ce que l'ennemi a fait juste après.

S'il ne peut pas le résoudre, l'éléphant coopérera simplement, car l'amitié est toujours la réponse.

S'il pense que son adversaire fera défaut, lui aussi fera défaut, ne voulant pas perdre ses points durement gagnés.

S'il pense que son adversaire coopérera, mais qu'il a moins ou exactement 6 points d'avance, alors il fera défaut pour prendre pied.

Et enfin, s'il pense que son adversaire coopérera et qu'il a une solide avance, il coopérera.


J'attendais quelque chose comme ça qui fonctionnait mieux que Nice Guy. Cependant, je ne serai pas en mesure de le tester pendant environ 8 heures, donc je devrais pouvoir le mettre à jour vers 12-13.
Gryphon - Réintègre Monica

4

54 seins pour un tat

def cinquantefourtitsfortatfunc (num, more, fun, me, en):
    seins = 54
    si "d" dans en [-tits:] ou num> = (200-seins):
        retourner "d"
    retourner "c"

Je me demande si cela va encore gagner?
Gryphon - Réintègre Monica

Cela semble gagner maintenant!
Gryphon - Réintègre Monica

Félicitations, vous avez battu de peu mes deux meilleurs robots!
Gryphon - Réintègre Monica

@Gryphon Je ferais 5 seins pour un tatouage si je n'étais pas si attaché à mes autres robots :)
Alex

Je pense que cela irait de l'autre côté de la courbe. Je pourrais en tester un moi-même!
Gryphon - Réintègre Monica

3

Nice Guy

def niceguyfunc(counter, mypoints, enpoints, mylist, enlist):
  if counter < 2:
    return "c"

  mylast = mylist[-1]
  enlast = enlist[-1]
  last_found_index = -1

  for i, item in enumerate(mylist):
    if i == counter - 1:
      break
    if mylist[i] == mylast and enlist[i] == enlast:
      last_found_index = i

  if last_found_index == -1:
    return "c"
  else:
    if enlist[last_found_index + 1] == "c":
      return "c"
    else:
      return "d"

Tente de prédire la sortie des adversaires en regardant l'historique. Par exemple, si les derniers mouvements ont été (c , ennemis d), il essaie de trouver la dernière occurrence des mêmes mouvements exacts.


3

Hackman [disqualifié comme prévu]

Ok, celui-ci sera probablement exclu du concours, mais j'ai vraiment envie de l'essayer:

def hackmanfunc(counter, mypoints, enpoints, mylist, enlist):
        if enlist.count("#") > 0:
                return "c"
        elif counter >= 2 and enpoints > mypoints:
                return "d"
        elif counter == 198:
                return "d"
        elif counter == 199:
                return "#"
        elif counter == 0 or enlist[-1] == "c":
                return "c"
        elif counter >= 2 and enlist[-2] != "c":
                return "#"
        else:
                return "d"

Ici, je prends comme base le BackstabbingTitForTat qui s'est avéré être le meilleur dans mes simulations. En outre, il est fortement basé sur l'utilisation d'un symbole non utilisé "#"(c'est pourquoi je dis qu'il sera probablement exclu).

Maintenant, laissez-moi vous expliquer les conditions ici:

1er: Assurez-vous que deux Hackman coopèrent en cas de problème.

2e: Si je vais perdre contre un autre bot, faites-lui au moins perdre autant de points que possible, donc ce n'est pas un énorme ennemi par la suite.

3ème: trahir un tour avant, gagne donc contre le poignardage

utiliser "#" au lieu de "d" me fait gagner 0 points au lieu de -1 et aussi communiquer avec d'autres Hackman qui ont moins de points, donc il arrête de faire défaut.


2
Désolé, mais disqualifié. Cela compte comme jouer avec le processus de jugement. Vous DEVEZ retourner "c" ou "d" à chaque tour.
Gryphon - Réintègre Monica

2
Cependant, c'est assez inventif, donc je suis désolé de devoir le disqualifier.
Gryphon - Réintègre Monica

3

Bizzaro

Fait exactement l'opposé de tit pour tat. Quand quelqu'un est gentil avec lui, il montre son amour en étant méchant, et quand quelqu'un est méchant, il fait preuve de vengeance en étant bon. Fortement basé sur tit for tat.

def bizzarofunc(counter, mypoints, enpoints, mylist, enlist):
    if counter==0 or enlist[counter-1] == "c":
        return "d"
    else:
        return "c"

Intéressant. Cela va être tué par Defector, cependant.
Gryphon - Rétablir Monica

@Gryphon Lmao, ne s'en rendait pas compte. Mais bon, Bizzaro ne connaît pas la différence entre le bien et le mal, gagner et perdre.
TitusLucretius

Oui, ce sera transfuge vers coopérateur et coopérateur vers transfuge, ce qui pourrait offrir des possibilités intéressantes. Il ne peut pas vraiment coexister avec autre chose, y compris lui-même.
Gryphon - Réintègre Monica

@Gryphon, oui, il devrait obtenir 0, quand il se joue. Je me demande ce qui va se passer avec Gentle Defector.
TitusLucretius

Je me demande ce qui se passe quand il fait face à la mésange pour le tatouage, ce qui était gagnant avant cette soumission.
Gryphon - Réintègre Monica

3

6 seins pour un tat

def sixtitsforatatfunc (num, more, fun, me, en):
    si "d" dans en [-6:] ou num> = 194:
        retourner "d"
    retourner "c"

La course aux armements de Tit for Tat a lieu :)


Je pense que nous allons aller trop loin et Defector va voler la première place.
Gryphon - Réintègre Monica

3

Dix seins pour un tat

def tentitsforatatfunc(num, more, fun, me, en):
    if "d" in en[-10:] or num >= 190:
        return "d"
    return "c"

Défauts antérieurs, et également défauts si son adversaire a fait défection au cours des dix derniers tours.

CopyFirst

def copyfirstfunc(num, mypoints, enpoints, myhistory, enhistory):        
    if num == 0 or num >= 197:
        return "d"
    else:
        return enhistory[0]

Cela fait défaut au premier tour, puis fait ce que l'adversaire a fait au premier tour, jusqu'au 197e tour, quand il poignarde dans le dos.

Quarante seins pour un Tat

def fourtytitsforatatfunc(num, mypoints, enpoints, myhistory, enhistory):
    if "d" in en[-40:] or num >= 150:
        return "d"
    return "c"

Si l'adversaire a fait défection dans les 40 derniers tours, défaut, sinon coopérez. Poignard dans les 50 derniers tours.

Trois seins pour un tat

Si l'adversaire a fait défection dans les 3 derniers tours, défaut, sinon coopérez. Poignard dans les 5 derniers tours. Ce programme a volé l'avance de Tit pour Two Tats par une marge étroite.

def threetitsforatatfunc(num, mypoints, enpoints, myhistory, enhistory):
    if num == 0 or num==1 and enhistory[-1]=="c" or num==2 and enhistory[-1]=="c" and enhistory[-2]=="c":
        return "c"
    if enhistory[-1] == "d" or enhistory[-2] == "d" or enhistory[-3] == "d" or num >= 195:
        return "d"
    else:
        return "c"

Cinq seins pour un tat

def fivetitsforatatfunc(num, more, fun, me, en):
    if "d" in en[-5:] or num >= 194:
        return "d"
    return "c"

Si vous ne pouvez pas comprendre ce que fait celui-ci, vous êtes un idiot. Poignard également un tour plus tôt.


OMI, n'hésitez pas à soumettre votre propre entrée.
Draco18 ne font plus confiance au SE

Je ne savais tout simplement pas si c'était généralement considéré comme juste.
Gryphon - Réintègre Monica

Ce qui est généralement courant, cependant, c'est que la meilleure réponse est le bot gagnant.
Masclins

Ce sera, je ne choisirai pas seulement ma propre réponse. Ce ne serait certainement pas juste.
Gryphon - Réintègre Monica

Je m'excuse, je n'avais pas réalisé que j'avais accidentellement accepté ma réponse. Elle n'est plus acceptée et j'accepterai la meilleure réponse à compter du 1er juillet.
Gryphon - Reinstate Monica

3

Grimace

def grimacefunc(I, Do, Not, Care, enlist):
    if round < 123: return "d" if "d" in enlist else "c"
    return "d"

On dirait que la solution "optimale" pour cette colline est de faire quelque chose comme ça (T4nT avec n> 5 est fondamentalement ceci), et juste d'optimiser le tour quand il trahit. Tout ce qui est plus créatif sera détruit.
Robert Fraser

3

Tous les autres D

def everyotherdfunc(counter, mypoints, enpoints, mylist, enlist):
    if counter % 2 == 0:
        return "d"
    else:
        return "c"

Tous les autres C

def everyotherdfunc(counter, mypoints, enpoints, mylist, enlist):
    if counter % 2 == 0:
        return "c"
    else:
        return "d"

Vous devriez peut-être soumettre une autre entrée en commençant par coopérer.
Gryphon - Rétablir Monica le

Je pensais juste que ça pourrait être intéressant.
Gryphon - Rétablir Monica le

3

Mathématiciens prévisibles:

Jeune mathématicien

Nouveau dans la dureté du monde

import math
def ymathfunc(num, mpoints, enpoints, mlist, enlist):
  if(math.sin(num) + 0.8 > 0):
    return 'c'
  else:
    return 'd'

Mathématicien plus âgé

Plus expérimenté dans ces domaines

import math
def omathfunc(num, mpoints, enpoints, mlist, enlist):
  if(math.cos(num) + 0.8 > 0):
    return 'd'
  else:
    return 'c'

Je doute que l'un ou l'autre de ces éléments réussisse, mais au moins ils ajouteront des moyens aux autres d'obtenir des points!


Ni l'un ni l'autre ne va bien faire, hein. Tout ce qu'ils font, c'est pour la plupart nourrir les transfuges.
Draco18s ne fait plus confiance au SE

2

Mésange aléatoire pour Tat

import os
def randomtitfortatfunc(forgot, ten, var, iables, enlist):
    luck = enlist.count("d") + 1
    choice = ord(os.urandom(1))
    choice = int(round(luck * float(choice - 0) / 255.0))
    if choice == 0:
        return "c"
    return "d"

Tit For Tat, mais randomisé. Cela ne va pas gagner de prix (sauf si j'ai vraiment de la chance). Maintenant avec des nombres aléatoires générés à partir d'une source appropriée.


2

Exploitative Tat

Exploitative Tat essaie de jouer les stratégies suivantes:

  • Défaut en arrière. C'est le seul moyen de se rattraper.

  • Coopérez contre le tit-for-tat et les stratégies similaires. C'est le seul moyen d'obtenir un bon score à long terme.

  • Défaut contre toujours-coopérateurs et autres chumps.

  • Défaut 5 tours plus tôt.

Voici le code:

def exploitativetatfunc(num, mypoints, enpoints, mylist, enlist):
    if mypoints < enpoints:
        return "d"
    if num >= 195:
        return "d"
    if num == 0:
        return "c"
    # Test defect, and keep defecting as long as they'll allow
    if (num == 5 or num >= 8) and all(choice == "c" for choice in enlist):
        return "d"
    # Recover if that goes wrong, and they were nice.
    if (num == 6 or num == 7) and all(choice == "c" for choice in enlist[:4]):
        return "c"
    # Otherwise, tit for tat.
    return enlist[-1]

Je suis surpris que cela n'ait pas fait mieux que la cravate pour la 8e place, mais je pense que ce n'était pas le bon moment pour cela, et c'était malheureusement entré en même temps que Two Tits for a Tat.
Gryphon - Réintègre Monica

2

30 seins pour un tat

def trentetitsfortatfunc (num, more, fun, me, en):
    seins = 30
    si "d" dans en [-tits:] ou num> = (200-seins):
        retourner "d"
    retourner "c"

2

mais si ... la prochaine réponse n'était pas un sombre déclencheur ou quelque chose

Je présente

Anty

def antyfunc(counter, mypoints, enpoints, mylist, enlist):
    if counter > 150: return "d"
    if not "c" in enlist[-2:]:
        return "d"
    if enpoints >= mypoints:
        return "d"
    else:
        return "c"

Intersting, testera quand je rentrerai.
Gryphon - Rétablir Monica le

2

Renard

def foxfunc(counter, mypoints, enpoints, mylist, enlist):
    if counter > enpoints:
        return "d"
    return "c"

Défauts si le nombre rond est supérieur aux points ennemis, coopère autrement.

Le garçon

def boyfunc(counter, mypoints, enpoints, mylist, enlist):
    if counter!=0 and enlist[-1]=="c" and counter <= 194 or enpoints+10<mypoints:
        return "c"
    return "d"

Coopère au premier tour, puis agit pour tit pour tat mais backstabs sur les cinq derniers tours, et les défauts si ce n'est pas dix points d'avance.

53 seins pour un tat

def fiftythreetitsfortatfunc(num, more, fun, me, en):
    tits = 53
    if "d" in en[-tits:] or num >= (200-tits):
        return "d"
    return "c"

Vous savez tous ce que c'est :)


2

Twentyfivetitsforatat

def twentyfivetitsfortatfunc(num, more, fun, me, en):
    tits = 25
    if "d" in en[-tits:] or num >= (200-tits):
        return "d"
    return "c"

Kinda titsforatat

def kindatitsfortatfunc(num, more, fun, me, en):
    tits = 54  
    if "c" in en[-tits:] or num >= (200-tits):
        return "c"
    return "d"

La prochaine fois que vous modifierez pour ajouter un programme, veuillez également ajouter un commentaire afin que je sois alerté. Merci!
Gryphon - Rétablir Monica le

@Gryphon oh désolé
Christopher

2

Traître prudent

def PrudentBetrayer(counter, mypoints, enpoints, mylist, enlist):
    # Am I ahead, even if he betrays first?
    if mypoints > enpoints + 5:
        if counter == 0:
            return "c"
        else:
            return enlist[-1]
    # Can I catch up if I betray first?
    elif mypoints + 5 > enpoints:
        if counter == 0:
            return "c"
        elif counter > 130:
            return "d"
        else:
            return "d" if "d" in enlist else "c"
    # can't win -> kill his score
    else:
        return "d"

Suppose qu'il combat un n-tits-for-a-tatbot. S'il a le score à trahir et qu'il gagne toujours, il laissera l'autre bot le frapper en premier (jouant en tit pour tat.) S'il ne peut gagner que lorsqu'il trahit en premier, il trahira au tour 130, bien avant tout courant bot. S'il a plusieurs points de retard sur son adversaire, il ne jouera que le transfuge pour tenter de faire baisser le score des bots sans méfiance.


Poignée de main

import random
def handshakefunc(num, me, him, m, en):
    handshake = "cdccd"
    # For the first few rounds, give the handshake.
    if num < len(handshake):
        if m == en:
            return handshake[num]
        return "d"
    if en[:len(handshake)] == handshake:
        if me > him:
            return "d"
        if me == him:
            return "ccd"[random.randint(0,2)]
        return "c"
    return "d"

Utilise le motif cdccd des cinq premiers tours pour savoir s'il est avec lui-même. Si c'est le cas, il essaiera de maximiser ses points en ayant toujours le bot avec plus de points en défaut, tandis que l'autre coopère toujours. S'il trouve qu'il combat un ennemi, il jouera le transfuge.

Dans mes tests, je trouve que la dose est bonne si elle constitue une partie importante de la population. Quand il n'a pas la chance de se battre, il sera essentiellement réduit à un transfuge.

EDIT: Clairement, d'après les scores, ils sont trop nombreux pour que cela fonctionne bien. Il gagnera quand même en combattant seulement les meilleurs ...


Déclencheur Bizzaro

def bizzaroTriggerfunc(round,ms,ts,mm,tm):
  if round==1:return 'c'
  if 'c' in tm:return'd'
  return 'c'

Coopérez toujours, à moins que votre adversaire ne coopère jamais avec vous, auquel cas vous faites défection. Toujours.


@Gryphon the sore loser was removed, and a new bot added!
MegaTom

Dans le test que je fais maintenant sur un bot que je n'ai pas encore publié, Handshake est en 2e place après 390 matchs (5338 bots survivants) surpassant 54-T4T vers 1200. Mon nouveau bot est beaucoup plus fort que cela, cependant . Les tests initiaux l'ont fait marquer 196 sur 196, bien qu'à long terme, il marque en moyenne ~ 124 / match. Chose intéressante, la base de Handshake était ce que j'allais essayer ensuite, il s'avère que vous m'avez battu sans que je m'en rende compte.
Draco18s ne fait plus confiance au SE

0

FakeShake

profite de la poignée de main - fait une poignée de main, puis juste des défauts pendant que la poignée de main lui fait confiance. Quand il se rencontre, cependant, il fait la «vraie» poignée de main. S'il rencontre un autre bot, il joue tit pour tat, avec une trahison à la fin. Cela semble un peu méchant ...

import random
def fakeshakefunc(num, i, d, m, enlist):
      secret_handshake="cdccdd"
      handshake= "cdccd"
      #checks if it is meeting itself
      if enlist[:len(secret_handshake)] == secret_handshake:
          if me > him:
            return "d"
          if me == him:
             return "ccd"[random.randint(0,2)]
          return "c"
      #does handshake's handshake,if the bot is not handshake or fakeshake it plays T4T
      if num < len(handshake):
            if m == enlist:
                return handshake[num]
            if i < d or num>= 198:
                return "d";
            if num == 0 or enlist[-1] == "c":
                return "c"
            else:
                return "d"
            if enlist[:len(handshake)] == handshake:
                return "d"
            if i < d or num>= 198:
                return "d";
            if num == 0 or enlist[-1] == "c":
                return "c"
            else:
                return "d"

One problem with this is that if it meets handshake and it has more points, it thinks its playing itself. I'm a newbie to python and this site (in fact this is my first answer) so make sure to tell me if I've made any stupid mistakes!


Welcome to PPCG!
Laikoni

@Laikoni Thanks!
Arkine
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.