The Rock, Paper, Scissors, Lizard, Spock Tournament of Epicness


98

Plus récents classements @ 2014-08-02 12:00

| Pos # | Author               | Name                    | Language   | Score | Win   | Draw  | Loss  | Avg. Dec. Time |
+-------+----------------------+-------------------------+------------+-------+-------+-------+-------+----------------+
| 1st   | Emil                 | Pony                    | Python2    | 064   | 064   | 000   | 005   | 0026.87 ms     |
| 2nd   | Roy van Rijn         | Gazzr                   | Java       | 062   | 062   | 001   | 006   | 0067.30 ms     |
| 2nd   | Emil                 | Dienstag                | Python2    | 062   | 062   | 001   | 006   | 0022.19 ms     |
| 4th   | ovenror              | TobiasFuenke            | Python2    | 061   | 061   | 001   | 007   | 0026.89 ms     |
| 5th   | PhiNotPi             | BayesianBot             | Perl       | 060   | 060   | 000   | 009   | 0009.27 ms     |
| 6th   | Claudiu              | SuperMarkov             | Python2    | 058   | 058   | 001   | 010   | 0026.77 ms     |
| 7th   | histocrat            | Alternator              | Ruby       | 057   | 057   | 001   | 011   | 0038.53 ms     |
| 8th   | histocrat            | LeonardShelby           | Ruby       | 053   | 053   | 000   | 016   | 0038.55 ms     |
| 9th   | Stretch Maniac       | SmarterBot              | Java       | 051   | 051   | 002   | 016   | 0070.02 ms     |
| 9th   | Martin Büttner       | Markov                  | Ruby       | 051   | 051   | 003   | 015   | 0038.45 ms     |
| 11th  | histocrat            | BartBot                 | Ruby       | 049   | 049   | 001   | 019   | 0038.54 ms     |
| 11th  | kaine                | ExcitingishBot          | Java       | 049   | 049   | 001   | 019   | 0065.87 ms     |
| 13th  | Thaylon              | UniformBot              | Ruby       | 047   | 047   | 001   | 021   | 0038.61 ms     |
| 14th  | Carlos Martinez      | EasyGame                | Java       | 046   | 046   | 002   | 021   | 0066.44 ms     |
| 15th  | Stretch Maniac       | SmartBot                | Java       | 045   | 045   | 001   | 023   | 0068.65 ms     |
| 16th  | Docopoper            | RoboticOboeBotOboeTuner | Python2    | 044   | 044   | 000   | 025   | 0156.55 ms     |
| 17th  | Qwix                 | Analyst                 | Java       | 043   | 043   | 001   | 025   | 0069.06 ms     |
| 18th  | histocrat            | Analogizer              | Ruby       | 042   | 042   | 000   | 027   | 0038.58 ms     |
| 18th  | Thaylon              | Naan                    | Ruby       | 042   | 042   | 004   | 023   | 0038.48 ms     |
| 20th  | Thaylon              | NitPicker               | Ruby       | 041   | 041   | 000   | 028   | 0046.21 ms     |
| 20th  | bitpwner             | AlgorithmBot            | Python2    | 041   | 041   | 001   | 027   | 0025.34 ms     |
| 22nd  | histocrat            | WereVulcan              | Ruby       | 040   | 040   | 003   | 026   | 0038.41 ms     |
| 22nd  | Ourous               | QQ                      | Cobra      | 040   | 040   | 003   | 026   | 0089.33 ms     |
| 24th  | Stranjyr             | RelaxedBot              | Python2    | 039   | 039   | 001   | 029   | 0025.40 ms     |
| 25th  | JoshDM               | SelfLoathingBot         | Java       | 038   | 038   | 001   | 030   | 0068.75 ms     |
| 25th  | Ourous               | Q                       | Cobra      | 038   | 038   | 001   | 030   | 0094.04 ms     |
| 25th  | Ourous               | DejaQ                   | Cobra      | 038   | 038   | 001   | 030   | 0078.31 ms     |
| 28th  | Luis Mars            | Botzinga                | Java       | 037   | 037   | 002   | 030   | 0066.36 ms     |
| 29th  | kaine                | BoringBot               | Java       | 035   | 035   | 000   | 034   | 0066.16 ms     |
| 29th  | Docopoper            | OboeBeater              | Python2    | 035   | 035   | 002   | 032   | 0021.92 ms     |
| 29th  | Thaylon              | NaanViolence            | Ruby       | 035   | 035   | 003   | 031   | 0038.46 ms     |
| 32nd  | Martin Büttner       | SlowLizard              | Ruby       | 034   | 034   | 004   | 031   | 0038.32 ms     |
| 33rd  | Kyle Kanos           | ViolentBot              | Python3    | 033   | 033   | 001   | 035   | 0032.42 ms     |
| 34th  | HuddleWolf           | HuddleWolfTheConqueror  | .NET       | 032   | 032   | 001   | 036   | 0029.86 ms     |
| 34th  | Milo                 | DogeBotv2               | Java       | 032   | 032   | 000   | 037   | 0066.74 ms     |
| 34th  | Timmy                | DynamicBot              | Python3    | 032   | 032   | 001   | 036   | 0036.81 ms     |
| 34th  | mccannf              | YAARBot                 | JS         | 032   | 032   | 002   | 035   | 0100.12 ms     |
| 38th  | Stranjyr             | ToddlerProof            | Java       | 031   | 031   | 010   | 028   | 0066.10 ms     |
| 38th  | NonFunctional User2..| IHaveNoIdeaWhatImDoing  | Lisp       | 031   | 031   | 002   | 036   | 0036.26 ms     |
| 38th  | john smith           | RAMBOBot                | PHP        | 031   | 031   | 002   | 036   | 0014.53 ms     |
| 41st  | EoinC                | SimpleRandomBot         | .NET       | 030   | 030   | 005   | 034   | 0015.68 ms     |
| 41st  | Martin Büttner       | FairBot                 | Ruby       | 030   | 030   | 006   | 033   | 0038.23 ms     |
| 41st  | Docopoper            | OboeOboeBeater          | Python2    | 030   | 030   | 006   | 033   | 0021.93 ms     |
| 44th  | undergroundmonorail  | TheGamblersBrother      | Python2    | 029   | 029   | 000   | 040   | 0025.55 ms     |
| 45th  | DrJPepper            | MonadBot                | Haskel     | 028   | 028   | 002   | 039   | 0008.23 ms     |
| 46th  | Josef E.             | OneBehind               | Java       | 027   | 027   | 007   | 035   | 0065.87 ms     |
| 47th  | Ourous               | GitGudBot               | Cobra      | 025   | 025   | 001   | 043   | 0053.35 ms     |
| 48th  | ProgramFOX           | Echo                    | .NET       | 024   | 024   | 004   | 041   | 0014.81 ms     |
| 48th  | JoshDM               | SelfHatingBot           | Java       | 024   | 024   | 005   | 040   | 0068.88 ms     |
| 48th  | Trimsty              | Herpetologist           | Python3    | 024   | 024   | 002   | 043   | 0036.93 ms     |
| 51st  | Milo                 | DogeBot                 | Java       | 022   | 022   | 001   | 046   | 0067.86 ms     |
| 51st  | William Barbosa      | StarWarsFan             | Ruby       | 022   | 022   | 002   | 045   | 0038.48 ms     |
| 51st  | Martin Büttner       | ConservativeBot         | Ruby       | 022   | 022   | 001   | 046   | 0038.25 ms     |
| 51st  | killmous             | MAWBRBot                | Perl       | 022   | 022   | 000   | 047   | 0016.30 ms     |
| 55th  | Mikey Mouse          | LizardsRule             | .NET       | 020   | 020   | 007   | 042   | 0015.10 ms     |
| 55th  | ja72                 | BlindForesight          | .NET       | 020   | 020   | 001   | 048   | 0024.05 ms     |
| 57th  | robotik              | Evolver                 | Lua        | 019   | 019   | 001   | 049   | 0008.19 ms     |
| 58th  | Kyle Kanos           | LexicographicBot        | Python3    | 018   | 018   | 003   | 048   | 0036.93 ms     |
| 58th  | William Barbosa      | BarneyStinson           | Lua        | 018   | 018   | 005   | 046   | 0005.11 ms     |
| 60th  | Dr R Dizzle          | BartSimpson             | Ruby       | 017   | 017   | 001   | 051   | 0038.22 ms     |
| 60th  | jmite                | IocainePowder           | Ruby       | 017   | 017   | 003   | 049   | 0038.50 ms     |
| 60th  | ArcticanAudio        | SpockOrRock             | PHP        | 017   | 017   | 001   | 051   | 0014.19 ms     |
| 60th  | Dr R Dizzle          | BetterLisaSimpson       | Ruby       | 017   | 017   | 000   | 052   | 0038.23 ms     |
| 64th  | Dr R Dizzle          | LisaSimpson             | Ruby       | 016   | 016   | 002   | 051   | 0038.29 ms     |
| 65th  | Martin Büttner       | Vulcan                  | Ruby       | 015   | 015   | 001   | 053   | 0038.26 ms     |
| 65th  | Dr R Dizzle          | Khaleesi                | Ruby       | 015   | 015   | 005   | 049   | 0038.29 ms     |
| 67th  | Dr R Dizzle          | EdwardScissorHands      | Ruby       | 014   | 014   | 002   | 053   | 0038.21 ms     |
| 67th  | undergroundmonorail  | TheGambler              | Python2    | 014   | 014   | 002   | 053   | 0025.47 ms     |
| 69th  | cipher               | LemmingBot              | Python2    | 011   | 011   | 002   | 056   | 0025.29 ms     |
| 70th  | Docopoper            | ConcessionBot           | Python2    | 007   | 007   | 000   | 062   | 0141.31 ms     |
+-------+----------------------+-------------------------+------------+-------+-------+-------+-------+----------------+
Total Players: 70
Total Matches Completed: 2415
Total Tourney Time: 06:00:51.6877573

Notes du tournoi

Bots exclus

  • BashRocksBot - toujours pas de joie avec .net qui exécute les scripts cygwin bash
  • CounterPreferenceBot - en attente d'un correctif
  • RandomlyWeighted - en attente d'un correctif
  • CasinoShakespeare - exclu car il nécessite une connexion Internet active

Question originale publiée

Vous avez visité la maison de vos amis pour la bataille la plus épique qui ait jamais eu lieu entre Rock, Paper, Scissors, Lizard, Spock. Dans le plus pur style BigBang, aucun des joueurs ne joue lui-même mais a créé des robots de la console pour jouer en son nom. Vous sortez votre clé USB et remettez-la au Sheldor le Conquérant pour l'inclure dans l'abattage. Penny swoons. Ou peut-être Howard swoons. Nous ne jugeons pas ici chez Léonard.

Règles

Les règles standard Rock, Papier, Ciseaux, Lézard, Spock s'appliquent.

  • Ciseaux coupe papier
  • Papier couvre la roche
  • La roche écrase le lézard
  • Lézard poisons Spock
  • Spock brise des ciseaux
  • Ciseaux Décapiter Lézard
  • Lézard mange du papier
  • Le papier réfute Spock
  • Spock vaporise la roche
  • La pierre écrase les ciseaux

Règles RPSLV

Le bot de chaque joueur jouera un match contre un autre bot dans le tournoi.

Chaque match consistera en 100 itérations d'un jeu RPSLV.

Après chaque match, le gagnant est le joueur qui a remporté le plus grand nombre de jeux / mains sur 100.

Si vous gagnez un match, on vous attribue 1 point au classement. À l'issue d'un match nul, aucun joueur ne gagnera de point.

Exigences de Bot

Votre bot doit être exécutable à partir de la ligne de commande.

La boîte * nix de Sheldor est morte, nous la lançons donc sur son ordinateur portable de jeu Windows 8, alors assurez-vous que votre solution fournie peut fonctionner sous Windows. Sheldor a gracieusement offert d'installer toutes les exécutions requises (dans des limites raisonnables) pour pouvoir exécuter votre solution. (.NET, Java, Php, Python, Ruby, Powershell ...)

Contributions

Dans le premier match de chaque match, aucun argument n'est fourni à votre bot. Dans chaque jeu suivant de chaque match: - Arg1 contiendra l'historique de vos mains / décisions de bots dans ce match. - Arg2 contiendra l'historique des mains / décisions de vos adversaires dans ce match.

L’histoire sera représentée par une séquence de majuscules représentant les mains que vous pouvez jouer.

 | R | Rock     |
 | P | Paper    |
 | S | Scissors |
 | L | Lizard   |
 | V | Spock    |

Par exemple

  • Jeu 1: MyBot.exe
  • Jeu 2: MyBot.exe SV
  • Jeu 3: MyBot.exe SS VL
  • Jeu 4: MyBot.exe SSR VLS

Sortie

Votre bot doit écrire une réponse de caractère unique représentant sa "main" pour chaque partie. Le résultat devrait être écrit dans STDOUT et le bot devrait alors quitter. Les lettres majuscules valides sont indiquées ci-dessous.

 | R | Rock     |
 | P | Paper    |
 | S | Scissors |
 | L | Lizard   |
 | V | Spock    |

Si votre bot ne retourne pas une main valide (c’est-à-dire qu’une des cinq majuscules susmentionnées est automatiquement perdue, la correspondance est perdue et la correspondance continue.

Dans le cas où les deux robots ne retournent pas une main valide, le jeu est considéré comme un match nul et le match continue.

Format de correspondance

Chaque bot soumis jouera un match contre l'autre bot dans le tournoi.

Chaque match durera exactement 100 parties.

Les matchs seront joués de manière anonyme, vous n’aurez pas une connaissance approfondie du bot spécifique contre lequel vous jouez, mais vous pouvez utiliser toutes les informations que vous pouvez obtenir de sa prise de décision au cours de l’historique du match en cours pour modifier votre stratégie en fonction de votre stratégie. adversaire. Vous pouvez également suivre l'historique de vos jeux précédents pour créer des modèles / heuristiques, etc. (voir les règles ci-dessous).

Au cours d'une seule partie, le moteur d'orchestration exécutera votre bot et celui de vos adversaires à 100 millisecondes, puis comparera les résultats afin d'éviter toute collision PRNG dans la même langue / durée d'exécution. (c'est ce qui m'est arrivé pendant les tests).

Jugement et contraintes

Dr. Sheldon Cooper sous les traits de Sheldor le Conquérant a aimablement offert de superviser le déroulement du tournoi. Sheldor le Conquérant est un surveillant juste et juste (la plupart du temps). Toutes les décisions de Sheldor sont finales.

Le jeu se déroulera de manière juste et appropriée:

  • Votre script / programme bot sera stocké dans le moteur d'orchestration sous un sous-dossier Players\[YourBotName]\
  • Vous pouvez utiliser ce sous-dossier Players\[YourBotName]\datapour enregistrer toutes les données ou l'historique des parties du tournoi en cours. Les répertoires de données seront purgés au début de chaque tournoi.
  • Vous ne pouvez pas accéder au répertoire des joueurs d'un autre joueur du tournoi.
  • Votre bot ne peut pas avoir de code spécifique qui cible un autre comportement spécifique de bots
  • Chaque joueur peut soumettre plus d’un bot à jouer tant qu’il n’interagit pas ou ne s’assiste pas.

Modifier - Contraintes supplémentaires

  • En ce qui concerne les forfaits, ils ne seront pas pris en charge. Votre bot doit jouer l'une des 5 mains valides. Je vais tester chaque bot en dehors du tournoi avec des données aléatoires pour s'assurer qu'il se comporte bien. Tous les robots qui jetteront des erreurs (c.-à-d. Des erreurs perdues) seront exclus du tournoi jusqu'à ce qu'ils soient corrigés par un bogue.
  • Les robots peuvent être dérivés tant qu'ils ont succinctement différents comportements. Les bots (y compris dans d'autres langages) ayant exactement le même comportement qu'un bot existant seront disqualifiés
  • Il y a déjà des robots anti-spam pour les articles suivants, alors veuillez ne pas les renvoyer.
    • Rock - BartSimpson
    • Papier - LisaSimpson
    • Ciseaux - EdwardScissorhands
    • Spock - Vulcan
    • Lézard - Khaleesi
    • Pseudo Aléatoire - SimpleRandomBot & FairBot
    • Psuedo Random RPS - ConservativeBot
    • Psuedo Random LV - Barney Stinson
  • Les robots ne peuvent pas faire appel à des services tiers ni à des ressources Web (ou à toute autre chose qui ralentit considérablement la vitesse / le temps de prise de décision des matchs). CasinoShakespeareest la seule exception car ce bot a été soumis avant l'ajout de cette contrainte.

Sheldor mettra à jour cette question aussi souvent que possible avec les résultats du tournoi, au fur et à mesure du nombre de robots envoyés.

Programme d'orchestration / contrôle

Le programme d'orchestration, ainsi que le code source de chaque bot, est disponible sur github.

https://github.com/eoincampbell/big-bang-game

Détails de la soumission

Votre soumission devrait inclure

  • Le nom de ton bot
  • Votre code
  • Une commande à
    • exécutez votre bot depuis le shell, par exemple
    • ruby myBot.rb
    • python3 myBot.py
    • OU
    • compilez d’abord vos deux, puis exécutez-le. par exemple
    • csc.exe MyBot.cs
    • MyBot.exe

Exemple de soumission

BotName: SimpleRandomBot
Compile: "C:\Program Files (x86)\MSBuild\12.0\Bin\csc.exe" SimpleRandomBot.cs
Run:     SimpleRandomBot [Arg1] [Arg2]

Code:

using System;
public class SimpleRandomBot
{
    public static void Main(string[] args)
    {
        var s = new[] { "R", "P", "S", "L", "V" };
        if (args.Length == 0)
        {
            Console.WriteLine("V"); //always start with spock
            return;
        }
        char[] myPreviousPlays = args[0].ToCharArray();
        char[] oppPreviousPlays = args[1].ToCharArray();
        Random r = new Random();
        int next = r.Next(0, 5);
        Console.WriteLine(s[next]);
    }
}

Clarification

Toutes les questions, demandez dans les commentaires ci-dessous.


7
À quoi ressemble l'histoire lorsqu'un joueur a perdu sa main?
Histocrat

1
J'allais tout faire avec une approche analytique, mais la plupart des robots ici sont assez stupides pour vaincre l'IA intelligente.
moelleux

1
Juste parce que je ne suis jamais en tête d' un défi KotH dans lequel j'ai participé, j'ai pris une capture d'écran en souvenir.
Kyle Kanos

3
Je ferai un autre tournoi ce soir et publierai les résultats complets du match sur pastebin ... le prochain lot comptera environ 450 parties, mais il devrait être un peu plus rapide à exécuter car j'ai implémenté des éléments de parallélisation dans le programme de contrôle
Eoin Campbell

3
Si je ne me trompe pas, il semble y avoir un sérieux problème dans le script d’orchestration: les historiques des joueurs 1 et 2 sont toujours transmis aux bots en tant que premier et second arguments respectivement, alors que selon les règles, les bots devraient toujours obtenir leur propre histoire d'abord. Maintenant, le joueur 2 tente effectivement de se battre. (Je suis devenu un peu méfiant parce que mon bot a remporté tous les matchs où il était joueur 1 et a perdu la moitié des autres matchs.)
Emil

Réponses:


26

Poney (Python 2)

Ceci est basé sur un robot rock-paper-ciseaux que j'ai écrit il y a quelque temps pour un défi de programmation à la fin d'une classe en ligne Udacity . Je l'ai changé pour inclure Spock et lézard et apporté quelques améliorations.

Le programme a 11 stratégies simples différentes, chacune avec 5 variantes. Il choisit parmi ceux-ci en fonction de leur performance au cours des derniers tours.

J'ai supprimé une stratégie de repli qui consistait à jouer au hasard contre des adversaires plus puissants. Je suppose que c'est plus amusant comme ça.

import sys

# just play Spock for the first two rounds
if len(sys.argv)<2 or len(sys.argv[1])<2: print 'V'; sys.exit()

# initialize and translate moves to numbers for better handling:
my_moves, opp_moves = sys.argv[1], sys.argv[2]
moves = ('R', 'P', 'S', 'V', 'L')   
history = zip([moves.index(i) for i in my_moves],
              [moves.index(i) for i in opp_moves])

# predict possible next moves based on history
def prediction(hist):
    N = len(hist)    

    # find longest match of the preceding moves in the earlier history
    cand_m = cand_o = cand_b = range(N-1)
    for l in xrange(1,min(N, 20)):
        ref = hist[N-l]
        cand_m = ([c for c in cand_m if c>=l and hist[c-l+1][0]==ref[0]]
                  or cand_m[-1:])
        cand_o = ([c for c in cand_o if c>=l and hist[c-l+1][1]==ref[1]]
                  or cand_o[-1:])
        cand_b = ([c for c in cand_b if c>=l and hist[c-l+1]==ref]
                  or cand_b[-1:])

    # analyze which moves were used how often
    freq_m, freq_o = [0]*5, [0]*5
    for m in hist:
        freq_m[m[0]] += 1
        freq_o[m[1]] += 1

    # return predictions
    return ([hist[-i][p] for i in 1,2 for p in 0,1]+   # repeat last moves
            [hist[cand_m[-1]+1][0],     # history matching of my own moves
             hist[cand_o[-1]+1][1],     # history matching of opponent's moves
             hist[cand_b[-1]+1][0],     # history matching of both
             hist[cand_b[-1]+1][1],
             freq_m.index(max(freq_m)), # my most frequent move
             freq_o.index(max(freq_o)), # opponent's most frequent move
             0])                        # good old rock (and friends)


# what would have been predicted in the last rounds?
pred_hist = [prediction(history[:i]) for i in xrange(2,len(history)+1)]

# how would the different predictions have scored?
n_pred = len(pred_hist[0])
scores = [[0]*5 for i in xrange(n_pred)]
for pred, real in zip(pred_hist[:-1], history[2:]):
    for i in xrange(n_pred):
        scores[i][(real[1]-pred[i]+1)%5] += 1
        scores[i][(real[1]-pred[i]+3)%5] += 1
        scores[i][(real[1]-pred[i]+2)%5] -= 1
        scores[i][(real[1]-pred[i]+4)%5] -= 1

# return best counter move
best_scores = [list(max(enumerate(s), key=lambda x: x[1])) for s in scores]
best_scores[-1][1] *= 1.001   # bias towards the simplest strategy    
if best_scores[-1][1]<0.4*len(history): best_scores[-1][1] *= 1.4
strat, (shift, score) = max(enumerate(best_scores), key=lambda x: x[1][1])
print moves[(pred_hist[-1][strat]+shift)%5]

Courir comme:

python Pony.py

Edit : J'ai fait un petit changement en mettant un parti pris pour la stratégie la plus simple (c'est-à-dire que vous jouez toujours le même coup) dans les cas incertains. Cela aide un peu à ne pas essayer de trouver des schémas trop compliqués où il n'y en a pas, par exemple chez des robots comme ConservativeBot.

Remarque : j'ai essayé d'expliquer la stratégie de correspondance d'historique de base utilisée par ce bot dans le message de mon autre bot Dienstag .


3
Un taux de victoire de 96% est remarquable.
AndoDaan

Très agréable. Vous pouvez aimer Iocaine Powder , si vous ne l'avez pas déjà vu.
wchargin le

@WChargin, bien sûr. :) Quand j'ai écrit mon code original, j'avais lu quelques années plus tôt à propos de la poudre de Iocaïne et je me souvenais vaguement de l'idée générale. Donc, Pony s’en inspire, si ce n’est très directement. En fait, ils sont très similaires. Je pense que le mien a un répertoire plus large de stratégies alors que Iocaine Powder possède un niveau intelligent de méta-méta-raisonnement que je n’ai pas inclus.
Emil

20

Markov, Ruby

Regarde les deux derniers mouvements de l'adversaire et détermine les suivis possibles (et les plus probables). Si la combinaison n'a pas été choisie auparavant, il utilise simplement tous les mouvements de l'adversaire (jusqu'à présent). Ensuite, il collecte toutes les réponses possibles à ces questions et en choisit une au hasard.

responses = {
  'R' => ['P', 'V'],
  'P' => ['S', 'L'],
  'S' => ['R', 'V'],
  'L' => ['S', 'R'],
  'V' => ['P', 'L']
}

if ARGV.length == 0 || (history = ARGV[1]).length < 3
    choices = ['R','P','S','L','V']
else
    markov = Hash.new []
    history.chars.each_cons(3) { |chars| markov[chars[0..1].join] += [chars[2]] }

    choices = []
    likely_moves = markov.key?(history[-2,2]) ? markov[history[-2,2]] : history.chars
    likely_moves.each { |move| choices += responses[move] }
end

puts choices.sample

Courir comme

markov.rb

Et ensuite, j'utilise ce programme pour déterminer le mouvement le plus possible que je ferai ensuite, puis ce que vous ferez et enfin trouver le moyen de vaincre ce que vous ferez et de faire une boucle infinie, encore et encore.
Jamie

@Jamie Vous voulez dire comme ce gars? codegolf.stackexchange.com/a/35295/8478
Martin Ender

vous le devinez. (le commentaire n'a pas été assez long pour être publié)
Jamie

19

ConservativeBot, Ruby

Les nouvelles choses sont mauvaises.

puts ['R','P','S'].sample

Courir comme

ruby conservative.rb

La version OG est la meilleure version.
maxywb

13

Fan de Star Wars - Ruby

Voyez-vous, Spock

puts ['R','P','L','S'].sample

Courez comme ça:

ruby starwarsfan.rb

Ajouté au contrôleur
Eoin Campbell

vous pouvez annuler une modification de réponse - je ferai juste un commentaire ici lorsque je les aurai ajoutées.
Eoin Campbell

Pourquoi R et S? : P
cjfaure

@mardavi C'est un fan de Star Wars car il n'utilise pas Spock.
William Barbosa

ah, vous avez raison (bien sûr). Je l'ai lu trop vite, mon erreur (mais heureusement sans conséquences)
mardavi

13

Barney Stinson - Lua

Je n'ai qu'une règle: le nouveau, c'est toujours mieux. Visser la vieille Jo Ken Po ou peu importe comment vous l'appelez.

math.randomseed(os.time())
print(math.random() > 0.5 and "V" or "L")

Courez comme ça:

lua legenwaitforitdary.lua

8

Boring Bot (Java)

Il suppose que tout le monde joue toujours la même chose et planifie en conséquence. Il a l'habitude de prendre des cailloux dans une cravate bien parce que tout le monde a raison?

public class BoringBot
{
    public static void main(String[] args)
    {
        int Rock=0;
        int Paper=0;
        int Scissors=0;
        int Lizard=0;
        int Spock=0;

        if (args.length == 0)
        {
            System.out.print("P");
            return;
        }

        char[] oppPreviousPlays = args[1].toCharArray();

        for (int j=0; j<oppPreviousPlays.length; j++) {
            switch(oppPreviousPlays[j]){
                case 'R': Rock++; break;
                case 'P': Paper++; break;
                case 'S': Scissors++; break;
                case 'L': Lizard++; break;
                case 'V': Spock++;
            }
        }

        int Best = Math.max(Math.max(Lizard+Scissors-Spock-Paper,
                                     Rock+Spock-Lizard-Scissors),
                            Math.max(Math.max(Paper+Lizard-Spock-Rock,
                                              Paper+Spock-Rock-Scissors),
                                     Rock+Scissors-Paper-Lizard));

        if (Best== Lizard+Scissors-Spock-Paper){
            System.out.print("R"); return;
        } else if (Best== Rock+Spock-Lizard-Scissors){
            System.out.print("P"); return;
        } else if (Best== Paper+Lizard-Spock-Rock){
            System.out.print("S"); return;
        } else if(Best== Paper+Spock-Rock-Scissors){
            System.out.print("L"); return;
        } else {
            System.out.print("V"); return;
        }
    }
}

Notez que s'il s'agit d'une stratégie que quelqu'un d'autre utilise déjà, faites-le-moi savoir et je le supprimerai. C'est comme une évidence que je n'avais pas déjà vue.
kaine

est-ce C #. vos propriétés .length sont fausses. et il n'y a pas de méthodemax
Eoin Campbell

@EoinCampbell C'est java, j'ai joué avec les deux et apparemment oublié quelles commandes appartiennent à quelles.
kaine

Ah cool. laisse-le moi et je l'aurai inclus.
Eoin Campbell

encore cassé. en cours d' exécution jre8 - java BoringBot.java - Erreur: Impossible de trouver ou de charger la classe principale D: \ My Software Dev \ big-bang jeu \ BigBang.Orchestrator \ bin \ Debug \ Players \ BoringBot \ BoringBot.java -
Eoin Campbell

8

IocainePowder, Ruby

entrez la description de l'image ici

Basé sur (volé sans vergogne) la stratégie RPS ici . Le bot semble choisir une hypothèse identique à celle du bot Markov, mais suppose ensuite que l'adversaire a deviné ce qu'il va choisir et choisit un coup pour battre celui-ci en conséquence.

Notez que je viens d'adapter l'idée de base de la stratégie liée, mais pas de la suivre en détail.

responses = {
  'R' => ['P', 'V'],
  'P' => ['S', 'L'],
  'S' => ['R', 'V'],
  'L' => ['S', 'R'],
  'V' => ['P', 'L']
}

if ARGV.length == 0 || (history = ARGV[1]).length < 3
    choices = ['R','P','S','L','V']
else
    markov = Hash.new []
    history.chars.each_cons(3) { |chars| markov[chars[0..1].join] += [chars[2]] }

    choices = []
    likely_moves = markov.key?(history[-2,2]) ? markov[history[-2,2]] : history.chars
    likely_moves.each { |move| choices += responses[move] }
end

myChoice = choices.sample 
theirChoice = responses[myChoice].sample
actualChoice = responses[theirChoice].sample
puts actualChoice

Courir comme

iocaine.rb

5
Tu continues à utiliser ce mot. Je ne pense pas que cela signifie ce que vous pensez que cela signifie.
JoshDM

2
Le vrai pouvoir de Iocaine Powder est qu’il permute l’utilisation du markov et du battage-markov. Cela commence comme un markov intelligent, mais une fois qu'il sent (commence à perdre), il passe en mode battant-markov. Devrait être facile à ajouter.
Roy van Rijn

Ahh, intelligent! Je ne vais pas mentir, je n’avais entendu que Iocaine me l’avoir été décrite, sans vraiment la regarder en détail. N'hésitez pas à modifier mon code si vous souhaitez ou soumettre le vôtre et obtenir le crédit!
Jmite

8

HuddleWolfTheConqueror - C #

HuddleWolf est de retour et meilleur que jamais. Il battra Sheldor le Conquérant à son propre jeu stupide. HuddleWolf est suffisamment intelligent pour identifier et contrer les spammerbots. Pour des adversaires plus intelligents, HuddleWolf utilise ses connaissances des statistiques de base de 5e année et utilise un jet de dés pondéré basé sur l'historique de parties jouées par l'opposition.

using System;
using System.Collections.Generic;
using System.Linq;

public class HuddleWolfTheConqueror
{

    public static readonly char[] s = new[] { 'R', 'P', 'S', 'L', 'V' };

    public static void Main(string[] args)
    {
        if (args.Length == 0)
        {
            Console.WriteLine(pickRandom());
            return;
        }

        char[] myPlays = args[0].ToCharArray();
        char[] oppPlays = args[1].ToCharArray();

        char tryPredict = canPredictCounter(oppPlays);
        if (tryPredict != '^')
        {
            Console.WriteLine(tryPredict);
        }
        else
        {
            Console.WriteLine(pickRandom());
        }
        return;
    }


    public static char canPredictCounter(char[] history)
    {
        // don't predict if insufficient data
        if (history.Length < 5)
        {
            return '^';
        }

        // calculate probability of win for each choice
        Dictionary<char, double> dic = getBestProabability(history);

        // get item with highest probability of win
        List<char> maxVals = new List<char>();
        char maxVal = '^';
        double mostFreq = 0;
        foreach (var kvp in dic)
        {
            if (kvp.Value > mostFreq)
            {
                mostFreq = kvp.Value;
            }
        }
        foreach (var kvp in dic)
        {
            if (kvp.Value == mostFreq)
            {
                maxVals.Add(kvp.Key);
            }
        }

        // return error
        if (maxVals.Count == 0)
        {
            return maxVal;
        }

        // if distribution is not uniform, play best play
        if (maxVals.Count <= 3)
        {
            Random r = new Random(Environment.TickCount);
            return maxVals[r.Next(0, maxVals.Count)];
        }

        // if probability is close to uniform, use weighted dice roll
        if (maxVals.Count == 4)
        {
            return weightedRandom(dic);
        }

        // if probability is uniform, use random dice roll
        if (maxVals.Count >= 5)
        {
            return pickRandom();
        }

        // return error
        return '^';
    }

    public static Dictionary<char, double> getBestProabability(char[] history)
    {
        Dictionary<char, double> dic = new Dictionary<char, double>();
        foreach (char c in s)
        {
            dic.Add(c, 0);
        }
        foreach (char c in history)
        {
            if (dic.ContainsKey(c))
            {
                switch(c)
                {
                    case 'R' : 
                        dic['P'] += (1.0/(double)history.Length);
                        dic['V'] += (1.0/(double)history.Length);
                        break;
                    case 'P' : 
                        dic['S'] += (1.0/(double)history.Length);
                        dic['L'] += (1.0/(double)history.Length);
                        break;
                    case 'S' : 
                        dic['V'] += (1.0/(double)history.Length);
                        dic['R'] += (1.0/(double)history.Length);
                        break;
                    case 'L' : 
                        dic['R'] += (1.0/(double)history.Length);
                        dic['S'] += (1.0/(double)history.Length);
                        break;
                    case 'V' : 
                        dic['L'] += (1.0/(double)history.Length);
                        dic['P'] += (1.0/(double)history.Length);
                        break;
                    default : 
                        break;

                }
            }
        }
        return dic;
    }

    public static char weightedRandom(Dictionary<char, double> dic)
    {
        Random r = new Random(Environment.TickCount);
        int next = r.Next(0, 100);
        int curVal = 0;
        foreach (var kvp in dic)
        {
            curVal += (int)(kvp.Value*100);
            if (curVal > next)
            {
                return kvp.Key;
            }
        }
        return '^';
    }

    public static char pickRandom()
    {
        Random r = new Random(Environment.TickCount);
        int next = r.Next(0, 5);
        return s[next];
    }
}

8

Enfant en bas âge

Ce bot assez stupide suppose qu'il joue un enfant qui va "chasser" ses mouvements, essayant toujours de battre ce qui a été jeté en dernier. Si le bot est battu plusieurs fois de suite, il passe à un nouveau point du pattern. C'est basé sur ma stratégie pour toujours battre mon frère beaucoup plus jeune. :)

EDIT :: Changement de la longueur d'une séquence de perte requise pour sauter dans des lancers aléatoires. Également corrigé un bug majeur avec le saut aléatoire.

Enregistrer sous ToddlerProof.java, compiler, puis exécuter avecjava ToddlerProof [me] [them]

import java.util.HashMap;
public class ToddlerProof
{
    char[] moves = new char[]{'R', 'P', 'S', 'L', 'V'};
    public static void main(String[] args)
    {
        if(args.length<1) //first Round
        {
            System.out.print('V');//Spock is best
            return;
        }
        else
        {
            String them = args[1];
            String me = args[0];
            int streak = 0;

            HashMap<Character, Character> nextMove = new HashMap<Character, Character>();
            //Next move beats things that beat my last move
            nextMove.put('L', 'V');
            nextMove.put('V', 'S');
            nextMove.put('S', 'P');
            nextMove.put('P', 'R');
            nextMove.put('R', 'L');
            //Check if last round was a tie or the opponent beat me
            int lastResult = winner(me.charAt(me.length()-1), them.charAt(them.length()-1));
            if(lastResult == 0)
            {
                //tie, so they will chase my last throw
                System.out.print(nextMove.get(me.charAt(me.length()-1)));

                return;
            }
            else if(lastResult == 1)
            {
                //I won, so they will chase my last throw
                System.out.print(nextMove.get(me.charAt(me.length()-1)));


                return;
            }

            else{
                //I lost
                //find streak
                for(int i = 0; i<me.length(); i++)
                {
                    int a = winner(me.charAt(i), them.charAt(i));
                    if(a >= 0) streak = 0;
                    else streak++;
                }
                //check lossStreak
                //If the streak is 2, then a rotation will make it even.
                //if it is >2, something bad has happened and I need to adjust.
                if(streak>2)
                {
                    //if they are on to me, do something random-ish
                    int r = (((them.length()+me.length()-1)*13)/7)%4;
                    System.out.print(move[r]);
                    return;
                }
                //otherwise, go on with the plan
                System.out.print(nextMove.get(me.charAt(me.length()-1)));
                return;
            }
        }
    }
    public static int winner(char me, char them)
    {
        //check for tie
        if(me == them) return 0;
        //check if they won
        if(me=='V' && (them == 'L' || them == 'P')) return -1;
        if(me=='S' && (them == 'V' || them == 'R')) return -1;
        if(me=='P' && (them == 'S' || them == 'L')) return -1;
        if(me=='R' && (them == 'P' || them == 'V')) return -1;
        if(me=='L' && (them == 'R' || them == 'S')) return -1;
        //otherwise, I won
        return 1;
    }
}

1
Devrions-nous utiliser print ou println? ... Je n'en étais pas certain.
kaine

Hmmm. J'imagine que les deux fonctionneraient, mais je pouvais voir println déconner si le programme de contrôle saisissait la nouvelle ligne au lieu du personnage. Merci de me l'avoir signalé, je modifierai mon code au cas où
Stranjyr

@ Stranjyr il y avait quelques bugs dans votre dernière course. Il n’a pas bombardé le programme de contrôle, mais si vous recherchez dans l’historique «ToddlerProof joue n», il semble que votre bot retourne la valeur null pour certaines mains, puis se ferme automatiquement. Exemple de jeu: "Echo & ToddlerProof" où Echo a joué à "LVSPRLV" avant que votre bot ne commence à déconner.
Eoin Campbell

@Eion Campbell Merci de le mentionner. Je l'ai vu plus tôt lorsque vous avez posté les journaux du tournoi raté, et je pense que cela a été corrigé. Il y avait une erreur: s'il perdait plus de 5 fois de suite, au lieu de sauter dans un jeu aléatoire, il jetait simplement une valeur non valide. Et puis, parce que cela l’a fait perdre, cela a jeté une autre valeur invalide. Un cercle vicieux.
Stranjyr

Cool. Faites-le mettre à jour dans le programme de contrôle maintenant.
Eoin Campbell le

8

Bart Simpson

"Bon vieux rock! Rien ne vaut le rock!"

puts 'R'

Courir comme

ruby DoTheBartman.rb

Lisa Simpson

"Bart pauvre et prévisible. Choisit toujours le rock."

puts 'P'

Courir comme

ruby LisaSimpson.rb

Mieux Lisa Simpson

Je me sentais mal de rendre Lisa si stupide, alors je lui ai permis de choisir au hasard entre l’une ou l’autre des mains qui battront le rock. Encore stupide, mais c'est une Simpson après tout. Peut-être qu'un crayon s'est coincé dans son cerveau?

puts ['P','V'].sample

Courir comme

ruby BetterLisaSimpson.rb

2
Clash de nom mineur . +1 quand même.
Martin Ender

@ MartinBüttner Zut, je ne l'avais pas remarqué. Les programmes semblent toujours faire des choses différentes - et au moins Lisa ici peut se sentir mieux en battant deux versions différentes de son frère.
Dr R Dizzle

1
Sheldor accepte ... il y aura un BartBot et un BartSimpson :)
Eoin Campbell

3
Nous avons seulement BortBot.
JoshDM

1
Ceux - ci seront abattus par se markov :)
Cruncher

7

Écho

Écrit en C #. Compiler avec csc Echo.cs. Courir commeEcho.exe ARG1 ARG2 .

La première fois, Echo prend une option au hasard. Après chaque premier passage, Echo répète simplement la dernière action de l'adversaire.

using System;

namespace Echo
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                Random r = new Random();
                string[] options = new string[] { "R", "P", "S", "L", "V" };
                Console.WriteLine(options[r.Next(0, options.Length)]);
            }
            else if (args.Length == 2)
            {
                string opponentHistory = args[1];
                Console.WriteLine(opponentHistory[opponentHistory.Length - 1]);
            }
        }
    }
}

7

Vulcan, Ruby

Mes doigts sont collés ensemble.

puts 'V'

Courir comme

ruby vulcan.rb

(Je pense que c'est la seule stratégie dans le personnage pour votre arrière-plan.)


Il faut revenir sur les épisodes pour voir si quelqu'un est né avec une langue fourchue. LizardMan FTW !!!
Eoin Campbell

3
Mais n’est-ce pas ainsi que tout le monde au big bang joue de toute façon?
Kaine

2
@anotherguest C'est ce que je voulais dire par "c'est la seule stratégie dans le personnage".
Martin Ender

6

Tyrannosaurus, Godzilla, Barney ... La règle des lézards. De temps en temps, ils ont des problèmes et doivent appeler Spock ou lancer des pierres.

using System;
public class LizardsRule
{
    public static void Main(string[] args)
    {
        if (args.Length == 0)
        {
            Console.WriteLine("L");
            return;
        }
        char[] oppPreviousPlays = args[1].ToCharArray();
        var oppLen = oppPreviousPlays.Length;
        if (oppPreviousPlays.Length > 2
            && oppPreviousPlays[oppLen - 1] == 'R'
            && oppPreviousPlays[oppLen - 2] == 'R'
            && oppPreviousPlays[oppLen - 3] == 'R')
        {
            //It's an avalance, someone call Spock
            Console.WriteLine("V");
            return;
        }

        if (oppPreviousPlays.Length > 2
                && oppPreviousPlays[oppLen - 1] == 'S'
                && oppPreviousPlays[oppLen - 2] == 'S'
                && oppPreviousPlays[oppLen - 3] == 'S')
        {
            //Scissors, Drop your tail and pick up a rock
            Console.WriteLine("R");
            return;
        }

        //Unleash the Fury Godzilla
        Console.WriteLine("L");     
    }
}

6

BayesianBot, Perl (maintenant v2!)

Avant tout, il s'agit d'un programme unique. Vous y verrez la fusion brillante de statistiques et d’horribles formes de programmation. En outre, ce bot enfreint probablement de nombreuses règles de statistiques bayésiennes, mais le nom sonne plus froid.

L’essence de ce bot réside dans la création de 250 modèles prédictifs différents. Chaque modèle prend la forme de "Étant donné que j’ai joué au rock le dernier tour et que mon adversaire a joué aux ciseaux il ya deux tours, c’est la distribution de probabilité pour le prochain coup de mon adversaire." Chaque distribution de probabilité prend la forme d'une distribution de Dirichlet multidimensionnelle.

Chaque tour, les prédictions de tous les modèles applicables (généralement 10) sont multipliées ensemble pour former une prédiction globale, qui est ensuite utilisée pour déterminer quels mouvements ont le rendement attendu le plus élevé.

Edit 1: Dans cette version, j'ai changé la distribution précédente et rendu le bot plus aléatoire quand il perd.

Quelques éléments peuvent être améliorés, tels que le nombre de modèles (250 correspond à un nombre à 3 chiffres seulement), le choix de la distribution antérieure (actuellement Dir (3,3,3,3,3)) et la méthode de fusion des prédictions. En outre, je n'ai jamais pris la peine de normaliser les distributions de probabilité, ce qui est bien pour le moment car je les multiplie.

Je n'ai pas de grandes attentes, mais j'espère que ce bot sera capable de bien faire.

my ($phist, $ohist) = @ARGV;

my %text2num = ('R',0,'V',1,'P',2,'L',3,'S',4);  #the RVPLS ordering is superior
my @num2text = ('R','V','P','L','S');

@phist = map($text2num{$_},split(//,$phist));
@ohist = map($text2num{$_},split(//,$ohist));

$lowerlimit = 0;
for($lowerlimit..~~@phist-3){$curloc=$_;
 $result = $ohist[$curloc+2];
 @moveset = ($ohist[$curloc],$ohist[$curloc+1],$phist[$curloc],$phist[$curloc+1]);
 for(0..3){$a=$_;
  for(0..$a){$b=$_;
   $predict[$a][$b][$moveset[$a]][$moveset[$b]][$result]++;
  }
 }
}

@recentmoves = ($ohist[-2],$ohist[-1],$phist[-2],$phist[-1]);

@curpred = (1,1,1,1,1);

for(0..3){$a=$_;
 for(0..$a){$b=$_;
  for(0..4){$move=$_;
   $curpred[$move] *= $predict[$a][$b][$recentmoves[$a]][$recentmoves[$b]][$move]/3+1;
  }
 }
}

@bestmove = (0,0,0,0,0);
for(0..4){
 $bestmove[$_] = $curpred[$_]/2+$curpred[$_-1]+$curpred[$_-2];
}

$max = 0;
for(0..4){
 if($bestmove[$_]>$max){
  $max = $bestmove[$_];
 }
}
@options=();
$offset=0;
if(($ohist[-1] - $phist[-1])%5 < 2 && ($ohist[-2] - $phist[-2])%5 < 2 && ($ohist[-3] - $phist[-3])%5 < 2){  #frequentist alert!
 $offset=int(rand(3));
}
for(0..4){
 if($bestmove[$_] == $max){
  push(@options,$num2text[($_+$offset)%5]);
 }
}
$outputb = $options[int(rand(~~@options))];

print "$outputb";

J'ai couru ce programme comme suit:

perl BayesianBot.plx

5

DynamicBot

Bot dynamique est presque toujours en train de changer. Il déteste vraiment se répéter

import sys, random
choices = ['L','V','S','P','R'] * 20
if len(sys.argv) > 1:
    my_history = sys.argv[1]
    [choices.remove(my_history[-1]) for i in range(15)]
print(choices[random.randrange(len(choices))])

Langue: Python 3.4.1

Commande: python dynamicbot.py <history>ou python3 dynamicbot.py <history>selon votre système


Oui, j'ai pensé à ça.
seequ

5

SmartBot - Java

Ma première entrée pour n'importe quoi sur ce site!

Bien que pas un nom très créatif ...

SmartBot trouve des séquences de mouvements où les mouvements de l'adversaire et / ou lui-même sont similaires aux derniers mouvements effectués et planifie en conséquence.

name = SmartBot

Je pense que pour l'exécuter, corrigez-moi si je me trompe.

java -jar SmartBot.jar

import java.util.ArrayList;
public class SmartBot {
    public static void main(String[] args) {
        if(args.length ==0){
            System.out.print("L");
            return;
        }
        if(args[0].length()<3){
            String[] randLetter = new String[]{"R","P","S","L","V"};
            System.out.print(randLetter[(int) Math.floor(Math.random()*5)]);
            return;
        }
        String myHistory = args[0];
        String otherHistory = args[1];

        double rScore,pScore,sScore,lScore,vScore;//score - highest = highest probability of next opponent move
        rScore = pScore = sScore = lScore = vScore = 0;
        lScore = .001;
        ArrayList<ArrayList<Integer>> moveHits = new ArrayList<ArrayList<Integer>>();
        for(int g = 0;g<2;g++){
            for(int i=1;i<(myHistory.length() / 2) + 1;i++){
                if(g==0){
                    moveHits.add(findAll(myHistory.substring(myHistory.length() - i),myHistory));
                }
                else{
                    moveHits.add(findAll(otherHistory.substring(otherHistory.length() - i),otherHistory));
                }
            }
            for(int i = 0; i < moveHits.size();i++){
                int matchingMoves = i+1;
                ArrayList<Integer> moveIndexes = moveHits.get(i);
                for(Integer index:moveIndexes){
                    if(index+matchingMoves +1<= otherHistory.length()){
                        char nextMove = otherHistory.charAt(index + matchingMoves-1);
                        if(nextMove=='R'){rScore = rScore + matchingMoves;}
                        if(nextMove=='P'){pScore = pScore + matchingMoves;}
                        if(nextMove=='S'){sScore = sScore + matchingMoves;}
                        if(nextMove=='L'){lScore = lScore + matchingMoves;}
                        if(nextMove=='V'){vScore = vScore + matchingMoves;}
                    }
                }
            }
        }
        if(rScore >= pScore && rScore >= sScore && rScore >= lScore && rScore >= vScore){
            System.out.print("V");
            return;
        }
        if(pScore >= rScore && pScore >= sScore && pScore >= lScore && pScore >= vScore){
            System.out.print("L");
            return;
        }
        if(sScore >= pScore && sScore >= rScore && sScore >= lScore && sScore >= vScore){
            System.out.print("R");
            return;
        }
        if(vScore >= pScore && vScore >= sScore && vScore >= lScore && vScore >= rScore){
            System.out.print("L");
            return;
        }
        if(lScore >= pScore && lScore >= sScore && lScore >= rScore && lScore >= vScore){
            System.out.print("S");
        }
        return;
    }
    public static ArrayList<Integer> findAll(String substring,String realString){
        ArrayList<Integer> ocurrences = new ArrayList<Integer>();
        Integer index = realString.indexOf(substring);
        if(index==-1){return ocurrences;}
        ocurrences.add(index+1);
        while(index!=-1){
            index = realString.indexOf(substring,index + 1);
            if(index!=-1){
                ocurrences.add(index+1);
            }
        }
        return ocurrences;
    }
}

Il attribue un score à chaque prochain mouvement possible en fonction du nombre de fois où des tendances similaires se sont produites.

Cela favorise légèrement le lézard.


Je crois que c'est comme ça que vous le dirigez si vous le jar en premier. Si vous le compilez simplement en premier, alors java ABotdevrait fonctionner (n'oubliez pas de nommer le fichier de la même manière que la classe publique)
Justin

Merci! En tant que programmeur relativement nouveau, je n’étais pas au courant.
Stretch Maniac

5

SpockOrRock - PHP

SpockOrRock

Lorsqu'ils sont joués dans le monde réel, la plupart des gens choisissent instinctivement des ciseaux. Ce bot choisit Spock ou Rock pour battre le joueur moyen. Cela ne gêne pas les tours précédents.

courir avec php spockorrock.php

<?php

//Pick either Spock or Rock
if (rand(0,1) == 0)     echo("R\n");
else                    echo("V\n");


?>

4

SlowLizard, Ruby

Après avoir commencé avec Lizard, il choisit toujours un coup aléatoire qui bat le coup précédent de l'adversaire.

responses = {
  'R' => ['P', 'V'],
  'P' => ['S', 'L'],
  'S' => ['R', 'V'],
  'L' => ['S', 'R'],
  'V' => ['P', 'L']
}

if ARGV.length == 0
  puts 'L'
else
  puts responses[ARGV[1][-1]].sample
end

Courir comme

ruby slowlizard.rb

4

LexicographicBot

Ce bot aime commander ses lettres. Il choisira donc une réponse supérieure de 1 à celle donnée par son adversaire lors du tour précédent. À moins que l'adversaire ne choisisse Vulcan, il choisit une réponse au hasard.

import sys
import random

choices = ["L", "P", "R", "S", "V"]

total = len(sys.argv)
if total==1:
    print("L")
    sys.exit()

opponent = sys.argv[2]
opponent_last = opponent[-1]

if opponent_last == choices[-1]:
    print(random.choice(choices))
else:
    next = choices.index(opponent_last)+1
    print(choices[next])

Ceci s'attend à ce que la main de l'adversaire soit traitée en seconde position:

                           me
                            v
python LexicographicBot.py SR RV
                              ^
                            opponent

@ MartinBüttner: commande ajoutée! J'ai été très occupé au travail à essayer de faire publier quelque chose, d'où la disparition.
Kyle Kanos

pauses à la première manche sans argument. Traceback (appel le plus récent en dernier): Fichier "LexicographicBot \ LexicographicBot.py", ligne 10, dans <module> opposant = sys.argv [2] IndexError: index de liste hors plage
Eoin Campbell

@ EoinCampbell: J'ai oublié la clause de sortie lors de la première utilisation, elle a été ajoutée et devrait fonctionner correctement maintenant.
Kyle Kanos

4

Werevulcan - Ruby

Courir comme ruby werevulcan.rb

@rules = {

  'L' => %w[V P],
  'P' => %w[V R],
  'R' => %w[L S],
  'S' => %w[P L],
  'V' => %w[R S]
}

@moves = @rules.keys

def defeats?(move1, move2)
  @rules[move1].include?(move2)
end

def score(move1, move2)
  if move1 == move2
    0
  elsif defeats?(move1, move2)
    1
  else
    -1
  end
end

def move
  player, opponent = ARGV

  # For the first 30 rounds, pick a random move that isn't Spock
  if player.to_s.size < 30
    %w[L P R S].sample
  elsif opponent.chars.to_a.uniq.size < 5
    exploit(opponent)
  else
    # Pick a random move that's biased toward Spock and against lizards
    %w[L P P R R S S V V V].sample
  end

end

def exploit(opponent)
  @moves.shuffle.max_by{ |m| opponent.chars.map{|o| score(m,o) }.reduce(:+) }
end

puts move

Le wasvulcan semble normal le jour, mais lorsque la lune se lève, ses oreilles deviennent pointues et ses mouvements deviennent plus logiques.


4

Analogizer - Ruby

Courez avec ruby analogizer.rb. J'ai apporté une solution logique au code, mais je ne sais pas pourquoi il y a eu des erreurs avec cela.

@rules = {

  'L' => %w[V P],
  'P' => %w[V R],
  'R' => %w[L S],
  'S' => %w[P L],
  'V' => %w[R S]
}

@moves = @rules.keys

def defeats?(move1, move2)
  @rules[move1].include?(move2)
end

def score(move1, move2)
  if move1 == move2
    0
  elsif defeats?(move1, move2)
    1
  else
    -1
  end
end

def move
  player, opponent = ARGV

  case player.to_s.size
  # Throw six lizards in the beginning to confuse opponent
  when 0..5
    'L'
  when 6
    'V'
  when 7
    'S'
  when 8
    'P'
  when 9
    'R'
  else
    analyze_history(player.chars.to_a, opponent.chars.to_a)
  end

end

def analyze_history(player, opponent)
  my_last_move = player.last
  predicted_moves = Hash.new {0}
  opponent_reactions = player.zip(opponent.drop(1))

  # Check whether opponent tended to make a move that would've beaten, lost, or tied my last move
  opponent_reactions.each do |my_move, reaction|
    score = score(reaction, my_move)
    analogous_moves = @moves.select { |move| score == score(move, my_last_move) }
    analogous_moves.each { |move| predicted_moves[move] += 1 }
  end

  # Assume if an opponent has never made a certain move, it never will
  @moves.each { |m| predicted_moves[m] = 0 unless opponent.include?(m) }

  # Pick the move with the best score against opponent's possible moves, weighted by their likelihood, picking randomly for ties
  @moves.shuffle.max_by{ |m| predicted_moves.map { |predicted, freq| score(m, predicted) * freq }.reduce(0,:+) }

end

puts move

Supposons que le bot adverse réagisse toujours à mon coup précédent, et choisit soit quelque chose qui le vaincrait, soit quelque chose qui lui ferait perdre, ou le même coup, éventuellement parmi un ensemble restreint de coups possibles. Il choisit ensuite le meilleur coup compte tenu de cette hypothèse.

Sauf que les dix premiers mouvements sont codés en dur: je fais d'abord semblant de ne connaître que le lézard, puis je suppose que mon adversaire lance toujours quelque chose pour battre la dernière chose que j'ai lancée jusqu'à ce que je dispose de suffisamment de données pour une analyse correcte.


4

Java - SelfLoathingBot

BotName: SelfLoathingBot
Compile: Save as 'SelfLoathingBot.java'; compile.
Run:     java SelfLoathingBot [me] [them]

Le bot commence au hasard, puis environ 33% des joueurs choisissent de jouer au hasard, ou environ 33% des joueurs tentent de jouer une tactique gagnante contre l’un des jeux précédents, avec 50% de choix de la tactique gagnante.

import java.util.Random;

public class SelfLoathingBot {

    static final Random RANDOM = new Random();

    private static char randomPlay() {

        switch (RANDOM.nextInt(5)) {

            case 0 : return 'R';

            case 1 : return 'P';

            case 2 : return 'S';

            case 3 : return 'L';

            default : return 'V';
        }
    }

    private static char antiPlay(String priorPlayString) {

        char[] priorPlays = priorPlayString.toCharArray();

        int choice = RANDOM.nextInt(2);

        switch (priorPlays[priorPlays.length - 1]) {

            case 'R' : return choice == 0 ? 'P' : 'V'; 

            case 'P' : return choice == 0 ? 'S' : 'L';

            case 'S' : return choice == 0 ? 'V' : 'R';

            case 'L' : return choice == 0 ? 'R' : 'S';

            default : return choice == 0 ? 'L' : 'P'; // V        
        }
    }

    public static void main(String[] args) {

        int choice = args.length == 0 ? 0 : RANDOM.nextInt(3);

        char play;

        switch (choice) {

            case 1 :

                // 33.3% chance Play myself
                play = antiPlay(args[0]);
                break;

            case 2 :

                // 33.3% chance Play opponent just in case opponent is screwy like that
                play = antiPlay(args[1]);
                break;

            default :

                // 33.3% chance 100% Random
                play = randomPlay();
        }

        System.out.print(play);
        return;
    }
}

4

L'analyste

L'analyste analyse certaines choses et fait des choses pour essayer de vous battre.

compiler avec javac Analyst.javaet exécuter en tant quejava Analyst

import java.util.Random;

public class Analyst{
    public static void main(String[] args){
        char action = 'S';

        try{
            char[] enemyMoves = null, myMoves = null;

            //first move is random
            if(args.length == 0){
                System.out.print(randomMove());
                System.exit(0);
            //moves 2-3 will beat their last move
            }else if(args[0].length() < 8){
                System.out.print(counterFor(args[1].charAt(args[1].length()-1)));
                System.exit(0);
            //following moves will execute some analyzation stuff
            }else{
                //get previous moves
                myMoves = args[0].toCharArray();
                enemyMoves = args[1].toCharArray();
            }

            //test if they're trying to beat our last move
            if(beats(enemyMoves[enemyMoves.length-1], myMoves[myMoves.length-2])){
                action = counterFor(counterFor(myMoves[myMoves.length-1]));
            }
            //test if they're copying our last move
            else if(enemyMoves[enemyMoves.length-1] == myMoves[myMoves.length-2]){
                action = counterFor(myMoves[myMoves.length-1]);
            }
            //else beat whatever they've done the most of
            else{
                action = counterFor(countMost(enemyMoves));
            }

            //if they've beaten us for the first 40 moves, do the opposite of what ive been doing
            if(theyreSmarter(myMoves, enemyMoves)){
                action = counterFor(action);
            }

        //if you break my program do something random
        }catch (Exception e){
            action = randomMove();
        }

        System.out.print(action);
    }

    private static char randomMove(){
        Random rand = new Random(System.currentTimeMillis());
        int randomMove = rand.nextInt(5);

        switch (randomMove){
            case 0: return 'R';
            case 1: return 'P';
            case 2: return 'S';
            case 3: return 'L';
            default: return 'V';
        }
    }

    private static char counterFor(char move){
        Random rand = new Random(System.currentTimeMillis());
        int moveSet = rand.nextInt(2);

        if(moveSet == 0){
            switch (move){
                case 'R': return 'P'; 
                case 'P': return 'S'; 
                case 'S': return 'R'; 
                case 'L': return 'R'; 
                default: return 'P';
            }
        }else{
            switch (move){
                case 'R': return 'V'; 
                case 'P': return 'L'; 
                case 'S': return 'V'; 
                case 'L': return 'S'; 
                default: return 'L';
            }
        }
    }

    private static boolean beats(char move1, char move2){
        if(move1 == 'R'){
            if((move2 == 'S') || (move2 == 'L')){
                return true;
            }else{
                return false;
            }
        }else if(move1 == 'P'){
            if((move2 == 'R') || (move2 == 'V')){
                return true;
            }else{
                return false;
            }
        }else if(move1 == 'S'){
            if((move2 == 'L') || (move2 == 'P')){
                return true;
            }else{
                return false;
            }
        }else if(move1 == 'L'){
            if((move2 == 'P') || (move2 == 'V')){
                return true;
            }else{
                return false;
            }
        }else{
            if((move2 == 'R') || (move2 == 'S')){
                return true;
            }else{
                return false;
            }
        }
    }

    private static char countMost(char[] moves){
        int[] enemyMoveList = {0,0,0,0,0};

        for(int i=0; i<moves.length; i++){
            if(moves[i] == 'R'){
                enemyMoveList[0]++;
            }else if(moves[i] == 'P'){
                enemyMoveList[1]++;
            }else if(moves[i] == 'S'){
                enemyMoveList[2]++;
            }else if(moves[i] == 'L'){
                enemyMoveList[3]++;
            }else if(moves[i] == 'V'){
                enemyMoveList[4]++;
            }
        }

        int max = 0, maxIndex = 0;
        for(int i=0; i<5; i++){
            if(enemyMoveList[i] > max){
                max = enemyMoveList[i];
                maxIndex = i;
            }
        }

        switch (maxIndex){
            case 0: return 'R';
            case 1: return 'P';
            case 2: return 'S';
            case 3: return 'L';
            default: return 'V';
        }
    }

    private static boolean theyreSmarter(char[] myMoves, char[] enemyMoves){
        int loseCounter = 0;

        if(enemyMoves.length >= 40){
            for(int i=0; i<40; i++){
                if(beats(enemyMoves[i],myMoves[i])){
                    loseCounter++;
                }
            }
        }else{
            return false;
        }

        if(loseCounter > 20){
            return true;
        }else{
            return false;
        }
    }
}

4

Le joueur - Python 2

import sys
import random

MODE = 1

moves = 'RSLPV'

def element_sums(a, b):
    return [a[i] + b[i] for i in xrange(len(a))]

def move_scores(p):
    def calc(to_beat):
        return ['LDW'.find('DLLWW'[moves.find(m)-moves.find(to_beat)]) for m in moves]

    return dict(zip(moves, element_sums(calc(p[0]), calc(p[1]))))

def move_chooser(my_history, opponent_history):
    predict = sorted(moves, key=opponent_history.count, reverse=MODE)[-2:]
    scores = move_scores(predict)
    return max(scores, key=lambda k:scores[k])

if __name__ == '__main__':
    if len(sys.argv) == 3:
        print move_chooser(*sys.argv[1:])
    elif len(sys.argv) == 1:
        print random.choice(moves)

Contrairement au nom, le seul moment où le hasard est utilisé dans ce programme est au premier tour, quand il n'y a pas d'information. Au lieu de cela, il est nommé en raison de l'erreur du joueur, la conviction que si un événement aléatoire s'est produit moins souvent dans le passé, il est plus probable qu'il se produise à l'avenir. Par exemple, si vous jetez une pièce équitable 20 fois et que les 15 premières sont des têtes, l'erreur du joueur indique que la probabilité que les revers restants soient des queues est augmentée. Bien sûr, c'est faux; Quels que soient les lancers précédents, les chances d'une pièce équitable de tirer la queue sont toujours de 50%.

Ce programme analyse l'historique de l'adversaire, trouve les 2 coups qu'il a le moins utilisés jusqu'à présent et suppose que le coup de l'adversaire sera cette fois-ci l'un des deux. Attribuant 2 à une victoire, 1 à un match nul et 0 à une défaite, il trouve le coup avec le score maximum contre ces deux coups prédits et le jette.

Le frère du joueur - Python 2

import sys
import random

MODE = 0

moves = 'RSLPV'

def element_sums(a, b):
    return [a[i] + b[i] for i in xrange(len(a))]

def move_scores(p):
    def calc(to_beat):
        return ['LDW'.find('DLLWW'[moves.find(m)-moves.find(to_beat)]) for m in moves]

    return dict(zip(moves, element_sums(calc(p[0]), calc(p[1]))))

def move_chooser(my_history, opponent_history):
    predict = sorted(moves, key=opponent_history.count, reverse=MODE)[-2:]
    scores = move_scores(predict)
    return max(scores, key=lambda k:scores[k])

if __name__ == '__main__':
    if len(sys.argv) == 3:
        print move_chooser(*sys.argv[1:])
    elif len(sys.argv) == 1:
        print random.choice(moves)

En commutant le MODE variable à 0, ce programme fonctionnera sur la base d'une erreur connexe, parfois également appelée erreur du joueur. Il indique que si un événement aléatoire s'est produit plus souvent dans le passé, il est plus probable qu'il se produise à l'avenir. Par exemple, si vous lancez une pièce 20 fois et que les 15 premières sont des têtes, cette erreur indique que les flips restants sont plus susceptibles d’être des têtes, car il ya actuellement une strie. En mode 0, ce programme fonctionne de la même manière, sauf qu'il suppose que l'adversaire effectuera l'un des deux mouvements le plus souvent jusqu'à présent.

Alors oui, ces deux programmes ne sont qu’un seul caractère à part. :)


A quelle condition TheGambler change-t-il de MODE?
Dr R Dizzle

@DrRDizzle Ce n'est pas le cas, il semblerait que ce soit une soumission de deux bots en un.
Paŭlo Ebermann

2
Ce programme ne serait-il pas plus efficace si MODE est changé si vous perdez plus d'un certain nombre de fois de suite?
Dr R Dizzle

4

Dienstag (Python 2)

Ma première entrée, Pony, semble bien réussir avec toutes ses secondes devinettes (triples devinettes, ...) et méta-raisonnement. Mais est-ce même nécessaire?

Voici donc Dienstag, le petit ami de Pony, qui n’a qu’une des 55 stratégies: prédire le prochain coup de l’adversaire et le battre.

Sur le long terme, Dienstag gagne ou lie chaque Bot parmi les dix premiers du classement actuel. Sauf pour Pony, c'est ça.

import sys
if len(sys.argv)<2 or len(sys.argv[1])<2: print 'L'; sys.exit()
hist = [map('RPSVL'.index, p) for p in zip(sys.argv[1], sys.argv[2])]
N = len(hist)
cand = range(N-1)
for l in xrange(1,N):
    cand = ([c for c in cand if c>=l and hist[c-l+1]==hist[-l]] or cand[-1:])
print 'RPSVL'[(hist[cand[-1]+1][1]+(1,3)[N%2==0])%5]

Courir comme:

python Dienstag.py

J'avoue que le code est un peu obscurci. Si quelqu'un veut en savoir plus à ce sujet, je pourrais ajouter des explications.

Edit: Voici un court exemple procédure pas à pas pour expliquer l'idée:

  • Le programme obtient son histoire et les mouvements de l'adversaire:

    sys.arg[1] = 'LLVLLVL', sys.arg[2] = 'RPSPSSP'

  • L'historique est combiné dans une liste de paires et les déplacements sont traduits en nombres (R = 0, ...):

    hist = [[4, 0], [4, 1], [3, 2], [4, 1], [4, 2], [3, 2], [4, 1]]

  • Le nombre de rounds joués jusqu'à présent est déterminé:

    N = 7

  • L'idée de base est maintenant de rechercher la plus longue chaîne ininterrompue des derniers mouvements de l'histoire précédente. Le programme garde une trace du point où une telle chaîne se termine dans la liste cand(pour les "candidats"). Au début, sans vérification, chaque position de l'historique, à l'exception de la dernière, est considérée:

    cand = [0, 1, 2, 3, 4, 5]

  • Maintenant, la longueur des chaînes possibles augmente progressivement. Pour la longueur de la chaîne, l = 1il recherche les occurrences précédentes de la dernière paire de mouvements [4, 1]. Cela peut être trouvé à la position de l'histoire 1et 3. Seuls ceux-ci sont conservés dans la candliste:

    cand = [1, 3]

  • Ensuite, l = 2il vérifie lequel des candidats possibles a été précédé de l'avant-dernière paire [3, 2]. Ce n'est que le cas pour la position 3:

    cand = [3]

  • Pour l = 3et plus il n'y a aucune chaîne précédente de cette longueur et candserait vide. Dans ce cas, le dernier élément de candest conservé:

    cand = [3]

  • Le bot suppose maintenant que l'histoire se répète. La dernière fois que le caïn [3, 2], [4, 1]s'est produit, il a été suivi de [4, 2]. Ainsi, l’adversaire a joué 2(ciseaux) et peut être battu par (2+1)%5 = 3(Spock) ou (2+3)%5 = 0(rock). Le bot répond, avec la première ou la deuxième alternative, selon qu’il Nest impair ou même simplement pour introduire une certaine variance.

  • Ici 3on choisit le mouvement qui est ensuite traduit:

    print 'V'

Remarque: Dienstag a une complexité temporelle O ( N 2 ) pour retourner le prochain coup après N tours. Pony a une complexité temporelle O ( N 3 ). Donc, sous cet aspect, elles sont probablement bien pires que la plupart des autres entrées.


s'il vous plaît faire. C'est une expérience d'apprentissage incroyable pour moi. Je vis habituellement en C # / Java, donc toute la folie lua, rubis, python, haskell m’intéresse beaucoup.
Eoin Campbell

Je suis également tenté d'ajouter une instance supplémentaire de Pony aux jeux. Ce sera comme si vous deviez vous battre vous-même dans le miroir du 3ème au dernier niveau de combat mortel ;-)
Eoin Campbell

@EoinCampbell :-) Au moins le match direct Pony vs Pony serait un tirage parfait. Il n'y a pas d'élément de hasard dans mes deux robots.
Emil

3

Bash Rocks

Est-ce que cygwin est trop demander en exécution?

bashrocks.sh:

#!/bin/bash
HAND=(R P S L V)
RAND=`od -A n -t d -N 1 /dev/urandom | xargs`
echo ${HAND[ $RAND  % 5 ]}

et lancez-le comme ça:

sh bashrocks.sh

5
Après avoir lu le titre, je suis un peu déçu que vous fassiez autre chose R. ;)
Martin Ender

@ McCannf. ayant quelques problèmes avec celui-ci ... J'ai installé cygwin et modifié vos scripts avec des chemins d'accès complets à C: \ Cygwin \ bin pour od.exe, xargs.exe & echo.exe. toujours obtenir l'erreur suivante. C: / Cygwin / bin / xargs: echo: pas de fichier ou de répertoire% 5 ") Erreur de syntaxe: Opérande attendu (le jeton d'erreur est"
Eoin Campbell

@EoinCampbell - lorsque vous créez le fichier dans Windows, pouvez-vous ensuite l'exécuter dos2unixsur le fichier dans Cygwin avant de l'exécuter?
mccannf

sûr. Je vais essayer.
Eoin Campbell

Je pense que le problème pourrait être avec la déclaration / dev / urandom
Eoin Campbell

3

Algorithme

Un algorithme pour en avoir un.

Parce que c'est toujours plus sûr de faire quelque chose, plus c'est compliqué, mieux c'est.

N'ayant pas encore fait de maths sérieux, cet algorithme n'est peut-être pas aussi efficace.

import random, sys

if __name__ == '__main__':

    # Graph in adjacency matrix here
    graph = {"S":"PL", "P":"VR", "R":"LS", "L":"VP", "V":"SR"}
    try:
        myHistory = sys.argv[1]
        opHistory = sys.argv[2]
        choices = ""

        # Insert some graph stuff here. Newer versions may include advanced Math.
        for v in graph:
            if opHistory[-1] == v:
                for u in graph:
                    if u in graph[v]:
                        choices += graph[u]

        print random.choice(choices + opHistory[-1])

    except:
        print random.choice("RPSLV")

Programme Python 2: python algorithm.py


1
Résumé de cet algorithme: regardez ce que l'adversaire a joué en dernier, puis jouez au hasard l'un des deux mouvements qui perdraient contre le dernier coup de l'adversaire s'il le rejouait. C'est donc mieux contre les bots qui ne jouent pas le même coup deux fois de suite.
Rory O'Kane

Haha. Je ne sais pas vraiment si je l'ai fait ainsi. Si je ne me trompe pas, il s’agit en fait d’une méthode compliquée consistant à sélectionner au hasard l’un des cinq mouvements. ;)
Vectorisé le

3

FairBot, Ruby

Commençons simple.

puts ['R','P','S','L','V'].sample

Courir comme

ruby fairbot.rb

petite faute de frappe sur ce dernier 'V' param. l'a corrigé sur myside si vous voulez effectuer une mise à jour complète
Eoin Campbell

@EoinCampbell merci, réparé!
Martin Ender

1
La chose intéressante est que cela a exactement les mêmes chances de gagner contre toutes les stratégies.
Cruncher

3

ViolentBot

Ce bot choisit l'option la plus violente en fonction du choix précédent de l'adversaire:

import sys

choice_dict = {"L" : "S", "P" : "S", "R" : "V", "S" : "V", "V" : "L"}

total = len(sys.argv)
if total==1:
    print("L")
    sys.exit()

opponent = sys.argv[2]
opponent_last = opponent[-1]

print(choice_dict[opponent_last])

Courir comme

python ViolentBot.py (me) (opp)

pauses sans params. Traceback (appel le plus récent en dernier): Fichier "ViolentBot \ ViolentBot.py", ligne 9, dans <module> opposant = sys.argv [2] IndexError: index de liste hors limites
Eoin Campbell

pauses avec params. Traceback (appel le plus récent en dernier): Fichier "ViolentBot \ ViolentBot.py", ligne 12, dans <module> print (choix_dict [opposant_last]) KeyError: 'S'
Eoin Campbell

@EoinCampbell: J'ai ajouté une clause de sortie pour la première exécution, vous devriez pouvoir l'exécuter maintenant.
Kyle Kanos

3

Haskell - MonadBot

Je ne sais pas si ghc est considéré "dans les limites de la raison", mais supposons que ce soit le cas. La stratégie de ce bot est de contrer l'action la plus populaire de son adversaire.

Compile: ghc monadbot.hs
Run:     ./monadbot [Arg1] [Arg2]

Code:

import System.Environment
import Data.List
import Data.Ord

main :: IO ()
main = do
  args <- getArgs
  let moves = if not (null args) then args !! 1 else ""
      fave = if not (null moves) then head $ maximumBy (comparing length) (group $ sort moves) else 'V'
  putChar $ case fave of 'R' -> 'P'
                         'P' -> 'S'
                         'S' -> 'R'
                         'L' -> 'R'
                         'V' -> 'P'
                         _   -> 'V'
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.