Cave Rangers - Explorer les ténèbres

9

Votre ami géologue a failli frapper la porte de votre bureau alors qu'il entrait, les yeux écarquillés d'excitation, et vous a demandé de venir avec lui sur un site qu'il venait de découvrir. En chemin, il explique qu'il pense qu'il vient littéralement de frapper l'or. Le seul problème est qu'il est enterré profondément sous terre dans une caverne avec un toit très instable. Il est trop dangereux de faire de la spéléologie, il veut donc que vous programmiez l'un de ses robots d'exploration des grottes pour collecter autant d'or que possible avant de le remonter. Il mentionne également qu'il a sondé la caverne et trouvé de la faune qui pourrait être nocive pour les robots, et aussi qu'il avait laissé tomber du matériel là-bas qui pourrait encore être utilisable. Chaque robot est équipé de deux bras et d'une gamme de capteurs. Lorsque vous arrivez sur les lieux, il vous dit qu'il prévoit de recruter plus de codeurs,

Maintenant, descendons au fond. Les capteurs transmettent des informations à votre programme sous forme de caractères ASCII. Voici une liste de ce que signifie chaque personnage et des descriptions de tout ce que le bot pourrait rencontrer dans la grotte:

Code    Name/Description

Y       Your bot
        You do things

@       Other bots
        They do other things

-       Ground
        This doesn't do things

C       Centipede
        These will bite you and leave a poison effect
        The bite will cost 1 health
        The poison effect will last for 3 turns, costing 2 health each turn

B       Bats
        If bats end up in the same space you are, your bot runs in a random direction during its turn rather than what you told it to do

L       Lion (because reasons)
        Lions deal heavy damage, 10 health, each time they attack

F       Food
        Eating this will give you 5 health
        Can only be used once

W       Water
        Drinking this will cure poison effects early
        Can only be used once

R       Revealer
        This will increase the range of your visibility to an 11x11 grid
        The extra range will only be 75% correct, but the original range won't be effected

K       Knife
        You do twice as much damage to other bots if you have a knife

G       Gold
        The whole reason you're doing this in the first place

N       Nurse Nina
        She mend you good
        Restores your health by 10 while you occupy the same space as her

}       Boulder
        You can't walk over boulders, and neither can anything else

P       Pit
        If you fall in a pit, you will be stuck for 3 turns

La taille de la caverne augmente en fonction du nombre de robots qui y participent. Il commence comme 30x30, et il obtient un 10x10 supplémentaire pour chaque bot. Donc 2 robots exploreront une caverne 50x50.

Les bots commencent avec 20 points de vie, mais ils n'ont pas de limite maximale de santé.

Contribution:

Vous recevrez une entrée via STDIN dans le format suivant:

20,5,10,1,0,True,False    <-health, number gold pieces, number of turns your bot has lasted, number of until the poison wears off, number of turns until you are no longer stuck in a pit, if you have a revealer, if you have a knife
-----
-G}--
--Y-L
-C---
---B-

La première ligne contient des informations sur votre bot, et le reste est la grille que votre bot peut voir. Si votre bot est contre l'un des 4 murs de la caverne, vous obtiendrez une grille qui ressemble plus à ceci (dans le cas d'être tout le chemin vers l'ouest):

---
}--
Y--
---
---

La caverne ne s'enroule pas et votre vision non plus. Les murs de la caverne ne sont pas marqués, la seule indication que votre bot reçoit qu'il s'approche d'un mur est sa vue diminuée. Avec le révélateur, vous pourriez obtenir quelque chose comme ceci:

--------C--
LW--------B
---K-N-----
--------BR-
-F---------
--B--Y---@N
-W@---F----
------K-F--
----@-}----
R@---G}--}-
--------G-R

Production:

Vous obtenez deux coups par tour, que vous produisez au format suivant:

MNNANW    <- Moves are groups of 3 characters representing the action and the direction

Les actions possibles sont les suivantes:

M    Move - Move your bot in the specified direction
A    Attack - Attack the square in the specified direction
H    Hold - Do nothing

Les directions possibles sont les suivantes:

NN - North (up)
NE - Northeast (up-right)
EE - East (right)
SE - Southeast (down-right)
SS - South
SW - Southwest
WW - West
NW - Northwest

Les mouvements sont appliqués de gauche à droite.

Se tourne:

Transforme les progrès de la manière suivante:

  1. Les effets de poison sont appliqués à tout joueur qui a été empoisonné

  2. Les non-bots se déplacent et attaquent

    2a. Les lions, les mille-pattes et les chauves-souris se déplacent au hasard

    2b. Les Lions et les mille-pattes attaqueront tout ce qui lui est directement adjacent (y compris en diagonale)

    2c. L'effet de chauve-souris ne sera appliqué à un bot que s'il se trouve sur le même espace que la chauve-souris

    2d. L'infirmière Nina restera dans un endroit pendant 3 tours, puis sautera à un endroit aléatoire.

  3. Les bots se déplacent

    3a. Si votre bot donne une sortie invalide, il ne bougera pas

    3b. Votre bot essaiera de se rapprocher le plus possible de l'espace désigné par la sortie (voir la note en bas pour plus de détails)

    3c. Une attaque contre un mille-pattes, un lion ou une chauve-souris le tuera

    3d. Attaquer un autre bot sans couteau fera 5 dégâts et 10 avec un couteau

Règles:

  1. Tenez-vous en aux langues courantes qui peuvent être exécutées sur OS X ou Linux.

  2. Vous pouvez éventuellement écrire jusqu'à 1 Ko de données au maximum dans un fichier

Notation:

Les robots ne seront dans la caverne que jusqu'à ce qu'il n'en reste qu'un, ou jusqu'à ce que 50 tours se soient écoulés, selon la première éventualité. Votre bot sera jugé sur la somme du nombre de pièces d'or qu'il a collectées et du nombre de tours qu'il a duré.

Le code du contrôleur peut être téléchargé pour les tests ici (créez un dossier appelé "bots" dans le même répertoire que celui où vous le téléchargez et placez votre bot dans "bots"). Vous aurez besoin de NumPy pour l'exécuter. N'hésitez pas à creuser, mais vous devrez excuser le désordre ...

Voici un code pour un bot aléatoire:

#!/usr/bin/python
import random as r

a = ['M','A','H']
d = ['NN','NE','EE','SE','SS','SW','WW','NW']

print(a[r.randint(0,2)]+d[r.randint(0,7)]+a[r.randint(0,2)]+d[r.randint(0,7)])

**** Votre bot se déplacera toujours dans la direction générale spécifiée par votre sortie, mais s'il est obstrué par un rocher ou un mur, la direction exacte dépend des circonstances. Par exemple, si votre robot est contre un mur comme ceci:

---
}--
Y--
---
---

et votre sortie est

MNWMSW

votre bot se déplacera d'un espace vers le bas. Il ne pouvait pas se déplacer vers le nord ou l'ouest, donc ce mouvement n'a eu aucun effet. Il pouvait se déplacer vers le sud (et l'a fait) mais ne pouvait pas se déplacer vers l'ouest. Cependant, si votre bot essayait de se déplacer vers le nord-est, il irait directement à cet espace (le mouvement diagonal est diagonal, pas procédural)

Classement

Ce sont les scores moyens de 4 matchs.

The bot of Survival:    54.75
Coward:                 52.25
Pufferfish:             50.00
Randombot:              50.00
Indiana Jones:          47.50
TheoremBot:             46.50
Le haricot magique
la source
Quelle est la santé de chaque bot? Et à quoi ressemble le bord de la caverne?
Conor O'Brien
Ils commencent avec 20 et peuvent collecter autant qu'ils le souhaitent. Ajout de cette information ci
The Beanstalk
Les bords de la caverne ne sont pas marqués, votre programme n'obtiendra que les morceaux sur lesquels vous pourriez potentiellement marcher.
The Beanstalk
Connaissez-vous vraiment pas votre santé?
pppery
Pourriez-vous entrer la longueur et la largeur de la vision du bot?
LegionMammal978 du

Réponses:

4

Indiana Jones, Python 2

Ce bot n'a peur de rien. Il essaiera d'obtenir l'or; et s'il n'en trouve pas, il essaiera de poignarder les adversaires avec des couteaux.

#!/usr/bin/env python
import sys
import random
data = sys.stdin.readlines()
health, gold, turns, poison_remaining, pit_remaining, revealer, knife = eval(data[0])
lines = data[1:]

myloc = [-1, -1]

width, height = len(lines[0]), len(lines)

for y, line in enumerate(lines):
    if line.find('Y')>-1:
        myloc = [line.index('Y'), y]
if myloc[0]<width/2:
    padding = int(width/2-myloc[0])
    lines = ['-'*padding+line for line in lines]
    myloc[0]+=padding
elif myloc[0]>width/2+1:
    padding = int(myloc[0]-width/2-1)
    lines = [line+'-'*padding for line in lines]

if myloc[1]<height/2:
    padding = int(height/2-myloc[1])
    lines = ['-'*width]*padding + lines
    myloc[1]+=padding
elif myloc[1]>height/2+1:
    padding = int(myloc[1]-height/2-1)
    lines = lines + ['-'*width]*padding

uddirections = {1:'N',0:'',-1:'S'}
lrdirections = {1:'E',0:'',-1:'W'}

golds = {}
for y, line in enumerate(lines):
    if 'G' in line:
        x = line.index('G')
        direction = ((uddirections[max(min(myloc[1]-y,1),-1)]+lrdirections[max(min(x-myloc[0],1),-1)])*2)[:2]
        distance = max(abs(myloc[0]-x), abs(myloc[1]-y))
        golds[distance] = direction

bots = {}
for y, line in enumerate(lines):
    if '@' in line:
        x = line.index('@')
        direction = ((uddirections[max(min(myloc[1]-y,1),-1)]+lrdirections[max(min(x-myloc[0],1),-1)])*2)[:2]
        distance = max(abs(myloc[0]-x), abs(myloc[1]-y))
        bots[distance] = direction

foods = {}
for y, line in enumerate(lines):
    if 'F' in line:
        x = line.index('F')
        direction = ((uddirections[max(min(myloc[1]-y,1),-1)]+lrdirections[max(min(x-myloc[0],1),-1)])*2)[:2]
        distance = max(abs(myloc[0]-x), abs(myloc[1]-y))
        foods[distance] = direction

knives = {}
for y, line in enumerate(lines):
    if 'K' in line:
        x = line.index('K')
        direction = ((uddirections[max(min(myloc[1]-y,1),-1)]+lrdirections[max(min(x-myloc[0],1),-1)])*2)[:2]
        distance = max(abs(myloc[0]-x), abs(myloc[1]-y))
        knives[distance] = direction

if golds:
    direction = golds[min(golds.keys())]
elif not knife and knives:
    direction = knives[min(knives.keys())]
elif health<20 and foods:
    direction = foods[min(foods.keys())]
elif bots and knife:
    direction = bots[min(bots.keys())]
    if min(bots.keys())==1:
        print ('A'+direction)*2
        sys.exit(0)
    elif min(bots.keys())==2:
        print 'M'+direction+'A'+direction
        sys.exit(0)
else:
    print ('M'+random.choice('NS')+random.choice('NEWS'))*2
    sys.exit(0)
print ('M'+direction)*2
taixzo
la source
Il suffit de changer une chose pour que cela fonctionne - line.index('Y')générera une erreur si "Y" n'est pas dans la ligne, mais line.find('Y')renverra -1 si "Y" n'est pas dans la ligne. Sinon, c'est super!
The Beanstalk
Vous pouvez parfois sortir une canne MSNMSN, ce qui n'est pas valide.
pppery
3

Lâche, python3

Un lâche court toujours des menaces potentielles.

Cependant, s'il se sent super fort, il se mettra soudainement en colère et poignardera tout près de lui.

Le problème avec l'implémentation actuelle est que les commandes de déplacement sont émises sans savoir s'il s'agit du premier ou du deuxième déplacement.

#!/usr/bin/env python3.4

import sys, random


class Coward():
  """
  A coward always runs from potential threats.

  However, if he feels super strong, he will suddenly run amok 
  and stab everything near him.  
  """
  def __init__(self, hp, gold, turn, poison, pit, revealer, knife):
    self.hp=int(hp)
    self.gold=int(gold)
    if knife=="True": self.knife=True
    else: self.knife=False    
    self.pit=int(pit)
    self.poison=int(poison)

  def readGrid(self, grid):
    self.grid=grid.split("\n")
  @property
  def _confidence(self):
    return self.hp+5*self.knife-2*self.poison
  @property
  def _lineOfY(self):
    for i, line in enumerate(self.grid):
      if "Y" in line:
        return i
  @property
  def _colOfY(self):
    return self.grid[self._lineOfY].index("Y")
  @property
  def _maxX(self):
    return len(self.grid)-1
  @property
  def _maxY(self):
    return len(self.grid[0])-1
  def move(self, step):
    d = {'NN':(0,-1),'NE':(1,-1),'EE':(1,0),'SE':(1,1),'SS':(0,1),'SW':(-1,1),'WW':(-1,0),'NW':(-1,-1)}
    c2d={(0,-1):'NN',(1,-1):'NE',(1,0):"EE",(1,1):"SE",(0,1):"SS",(-1,1):"SW",(-1,0):"WW",(-1,-1):"NW"}
    #Don't move into wall/ boulder/ pit
    #print(d, file=sys.stderr)
    for k,v in list(d.items()):
      x=self._lineOfY+v[0]
      y=self._colOfY+v[1]
      #print (k, v ,x , y, file=sys.stderr)
      if x<0 or y<0 or x>self._maxX or y>self._maxY:
        #print ("Out of bounds: ", k, file=sys.stderr)
        del d[k]
      elif self.grid[x][y]=="}" or self.grid[x][y]=="P":
        del d[k]
    #Always avoid bats, and enemys
    for dx in range(-2,3):
      for dy in range(-2,3):
        x=self._lineOfY+dx
        y=self._colOfY+dy
        if x<0 or y<0 or x>self._maxX or y>self._maxY:
          continue;
        if self.grid[x][y] in ["B", "L", "C", "@"]:
          for k in self._toDirection(dx, dy):
            if k in d: del d[k] #Too many threats from all sides can paralyze the Coward: nowhere to go...
    #print(d, file=sys.stderr)
    tomove=[]
    #Neighboring fields
    for dx in [-1,1]:
      for dy in [-1,1]:
        x=self._lineOfY+dx
        y=self._colOfY+dy
        if x<0 or y<0 or x>self._maxX or y>self._maxY:
          continue
        if self.poison>0 and self.grid[x][y]=="W":
          for k,v in d.items():
            if v==(dx,dy):
              tomove.append(k)
        if self.grid[x][y]=="N": #Always go to nurse, even if dangerous
          tomove.append(c2d[(x,y)])
        if self.grid[x][y] in ["F","K","G"]: #Go to Food, Knife or Gold, if save
          for k,v in d.items():
            if v==(dx,dy):
              tomove.append(k)
    #Further away: Go towards food, knife and gold and Nina if save.
    for target in ["N", "F", "G", "K"]:
      for dx in [-2,2]:
        for dy in [-2,2]:
          x=self._lineOfY+dx
          y=self._colOfY+dy
          if x<0 or y<0 or x>self._maxX or y>self._maxY:
            continue
          if self.grid[x][y]==target:
            l=[ k for k in self._toDirection(dx,dy) if k in d]
            if l: tomove.append(random.choice(l))
    s=list(d.keys())
    random.shuffle(s)
    tomove+=s
    try:
      return "M"+tomove[step-1]
    except IndexError:
      return ""
  def attack(self, step):    
    c2d={(0,-1):'NN',(1,-1):'NE',(1,0):"EE",(1,1):"SE",(0,1):"SS",(-1,1):"SW",(-1,0):"WW",(-1,-1):"NW"}
    #If Bot next to you: always attack
    for k,v in c2d.items():
      x=self._lineOfY+k[0]
      y=self._colOfY+k[1]
      if x<0 or y<0 or x>self._maxX or y>self._maxY:
        continue
      if self.grid[x][y]=="@":
        return "A"+v
    #If Bot or monster could come closer: attack potential new position
    attDir={(-2,-2):["NW"], (-2,-1):["NW","WW"], (-2,0):["WW","NW","SW"], (-2,1):["WW","SW"], (-2,2):["SW"],(-1,-2):["NW","NN"], (-1,2):["SW","SS"], (0,2):["SW","SS","SE"],(0,-2):["NW","NN","NE"],(1,-2):["NN","NE"],(1,2):["SS","SE"],(2,-2):["NE"],(2,-1):["NE","EE"], (2,0):["NE","EE","SE"], (2,1):["EE","SE"], (2,2):["SE"]}
    for k,v in attDir.items():
      x=self._lineOfY+k[0]
      y=self._colOfY+k[1]
      if x<0 or y<0 or x>self._maxX or y>self._maxY:
        continue
      if self.grid[x][y] in ["@","L","C","B"]:
        return "A"+random.choice(v)
    return ""
  def _toDirection(self,dx,dy):
    if dx<0:
      if dy<0:
        return ["WW","NW","NN"]
      elif dy==0:
        return ["WW","NW","SW"]
      elif dy>0:
        return ["WW","SW","SS"]
    elif dx>0:
      if dy<0:
        return ["EE","NE","NN"]
      elif dy==0:
        return ["EE","NE","SE"]
      elif dy>0:
        return ["EE","SE","SS"]
    elif dx==0:
      if dy<0:
        return ["NN","NE","NW"]
      elif dy==0:
        return []
      elif dy>0:
        return ["SS","SE","SW"]
  def _nearBat(self):
    for dx in range(-2,3):
      for dy in range(-2,3):
        x=self._lineOfY+dx
        y=self._colOfY+dy
        if x<0 or y<0:
          continue;
        if self.grid[x][y]=="B":
          return True
    return False
  def makeTurn(self):
    try:
      command=""
      #If stuck, just attack
      if self.pit:
        command+=self.attack(1)+self.attack(2)
      #Always run from bats
      if self._nearBat:
        command+=self.move(1)+self.move(2)
      #If high-confidence: attack
      if self._confidence>30:
        command+=self.attack(1)+self.attack(2)
      #Else: Move somewhere
      command+=self.move(1)+self.move(2)
      #Just in case, two random attacks
      d = ['NN','NE','EE','SE','SS','SW','WW','NW']
      a=random.choice(d)
      b=random.choice([ x for x in d if x!=a])
      command+="A"+a+"A"+b
      return command[:6]
    except Exception as e:
      #print (e, file=sys.stderr)
      #Attacking is better than nothing
      d = ['NN','NE','EE','SE','SS','SW','WW','NW']
      a=random.choice(d)
      b=random.choice([ x for x in d if x!=a])
      return "A"+a+"A"+b


info=sys.stdin.readline()
grid=sys.stdin.read()
info=info.split(",")
bot=Coward(*info)
bot.readGrid(grid)
t=bot.makeTurn()
#print(t, file=sys.stderr)
print(t)
TheEspinosa
la source
3

Le bot de la survie - Python 2

from __future__ import print_function
health,gold,survived,poison,pit,revealer,knife = input()
if pit:
    exit()
#Yes, this is python 2, despite the use of input()
lines = []
try:
    while True:
        lines.append(raw_input())
except EOFError:
    pass
CMOVES={"NW":(-1,-1),"NN":(-1,+0),"NE":(-1,+1),
        "WW":(+0,-1),             "EE":(-0,+1),
    "SW":(+1,-1),"SS":(+1,+0),"SE":(+1,+1),
}
MOVES={v:k for k,v in CMOVES.iteritems()}
import sys
def get_your_pos():
    for row,line in enumerate(lines):
        for col,square in enumerate(line):
            if square == "Y":
                return row,col
    raise ValueError("Your bot is not present.")
def isnearby(thing,p=None):
    your_pos = p or get_your_pos()
    for move in MOVES:
        yp = your_pos[0]+move[0],your_pos[1]+move[1]
        try:
            if yp[0] >= 0 and yp[1] >= 0 and lines[yp[0]][yp[1]] == thing:
                return move
        except IndexError:
            #Edge of cavern
            pass
for turn in range(2):
    import random
    nprio = .5
    if health > 25:
        nprio -= .2
    elif health < 10:
        nprio += .3
    if poison:
        nprio += .18
    #heal
    motive = how = None
    if random.random() < nprio:
        nurse = isnearby("N")
        if nurse:
            motive = "M"
            how = MOVES[nurse]
        elif random.random() < nprio:
            food = isnearby("F")
            if food:
                motive = "M"
                how = MOVES[food]
    #cure poison
    if poison and not motive:
        water = isnearby("W")
        if water:
            motive = "M"
            how = MOVES[water]
    if not motive:
        #Kill lions, bats, and centipedes
        for animal in ("L","B","C"):
            animal = isnearby(animal)
            if animal:
                motive = "A"
                how = MOVES[animal]
                y = get_your_pos()
                y = y[0]+animal[0],y[1]+animal[1]
                lines = map(list,lines)
                lines[y[0]][y[1]] = "-"
                break
        else:
            #Pick up knives
            if not knife:
                knife = isnearby("K")
                if knife:
                    motive = "M"
                    how = MOVES[knife]
            #Attack other bots
            else:
                prey = isnearby("@")
                if prey:
                    motive = "A"
                    how = MOVES[prey]
    #Get gold
    gold = isnearby("G")
    if gold and not motive:
        motive = "M"
        how = MOVES[gold]
    def isvalidmove(c):
        c = CMOVES[c]
        y = get_your_pos()
        y=(y[0]+c[0],y[1]+c[1])
        if y[0] >= 0 and y[1] >= 0:
            try:
                lines[y[0]][y[1]]
            except LookupError:
                pass
            else:
                return True
    if turn and not motive:
        motive = "M"
        while not (how and how not in (isnearby("}"),isnearby("P"),isnearby("@"))\
              and isvalidmove(how)):
            how = random.choice(CMOVES.keys())
    if not motive:break
    if not turn and motive == "M":
        lines = map(list,lines)
        yp = get_your_pos()
        lines[yp[0]][yp[1]] = "-"
        yp=[yp[0]+CMOVES[how][0],yp[1]+CMOVES[how][1]]
        lines[yp[0]][yp[1]] = "Y"
    print(motive+how,end="")
else:
    exit()
#Nothing found on first move
def isvaguelynearby(thing):
    your_pos = get_your_pos()
    for move in MOVES:
        yp = your_pos[0]+move[0],your_pos[1]+move[1]
        try:
            if yp[0] >= 0 and yp[1] >= 0 and board[yp[0]][yp[1]] != "P":
                dest = isnearby(thing,yp)
                if dest:
                    return move,dest
        except IndexError:
            #Edge of cavern
            pass
if random.random() < nprio:
    dests = isvaguelynearby("N")
    if not dests and random.random() < nprio:
        dests = isvaguelynearby("F")
    if dests:
        m1,m2 = MOVES[dests[0]],MOVES[dests[1]]
        print("M" + m1 + "M" + m2)
        exit()
dests = (poison and isvaguelynearby("W")) or (not knife and isvaguelynearby("K"))\
    or isvaguelynearby("G")
prey = isvaguelynearby("L") or isvaguelynearby("B") or isvaguelynearby("C") or \
       (knife and isvaguelynearby("@"))
if dests:
    m1,m2 = MOVES[dests[0]],MOVES[dests[1]]
    print("M" + m1 + "M" + m2)
elif prey:
    m1,m2 = MOVES[prey[0]],MOVES[prey[1]]
    print("M" + m1 + "A" + m2)
else:
    how = None
    while not (how and how not in     (isnearby("}"),isnearby("P"),isnearby("@"))\
          and isvalidmove(how)):
        how = random.choice(CMOVES.keys())
    print("M"+how,end="")
    lines = map(list,lines)
    yp = get_your_pos()
    lines[yp[0]][yp[1]] = "-"
    yp=[yp[0]+CMOVES[how][0],yp[1]+CMOVES[how][1]]
    lines[yp[0]][yp[1]] = "Y"
    while not (how and how not in (isnearby("}"),isnearby("P"),isnearby("@"))\
          and isvalidmove(how)):
            how = random.choice(CMOVES.keys())
    print("M"+how)

Edit: ajout d'un meilleur évitement des stands.

pppery
la source
2

Poisson-globe, Python 3+

Je suis juste cette personne.

#!/usr/bin/env python3.4
import random
def select():
 return "A"+["NN","NE","EE","SE","SS","SW","WW","NW"][random.randint(0,7)]
print(select()+select())
Conor O'Brien
la source
Ce bot a pour but l'autosuffisance. Je pourrais ajouter la recherche de golf plus tard si j'ai le temps.
Conor O'Brien du
Cela rendra votre code un peu plus long, mais Pufferfish est capable d'attaquer deux fois dans le même tour s'il voulait être plus mortel
The Beanstalk
@TheBeanstalk Ohhh doux!
Conor O'Brien
Vous vous rendez compte que ce bot n'obtiendra jamais d'or, et tous les autres bots ne se
promèneront
@ppperry Je m'en rends compte; c'était principalement pour faire rouler la balle; il ne vise pas à gagner, mais à rendre la vie un peu plus difficile. Comme dans, Black Hat Man
Conor O'Brien