マフィアをやりましょう!

Mafia (also known as Werewolf) is a party game
that plays roughly like this:

  • The game begins on day 0. After every day n comes
    a night n. After every night n comes a
    day n+1. i.e. D0, N0, D1, N1, D2,
    N2
  • At the dawn of day 0, a host secretly chooses players to fill
    certain roles:  

    • Some number of players become the mafia. Every night, every
      mafioso chooses a player. At the dawn of the next day, the player
      chosen by the most mafiosos is killed. They are permanently removed
      from the game and their role is publicly revealed. Mafia-aligned.
       
    • Some number of players become cops. Every night, each cop
      chooses a player. At the dawn of the next day, the cop becomes
      aware of that players alignment. Village-aligned.  
    • Some number of players become doctors. Every night, each doctor
      chooses a player. If this player is the same player that the mafia
      chose to kill, the mafia’s actions for that night are canceled.
      Village-aligned.  
    • All players who aren’t chosen for another role are villagers.
      Villagers have no abilities that aren’t shared by the whole town.
      Village-aligned.
  • Every day except day 0, the entire town (that is, all living
    players) votes for a player. At the end of the day, that player is
    removed from the game and their role is revealed. (On day 0,
    everyone just chills until nightfall.)
  • If, at any point, there are no remaining mafiosos, the game
    ends with all village-aligned players victorious (including the
    dead).
  • If, at any point, the village-aligned players do not outnumber
    the mafia-aligned players, the game ends with all mafia-aligned
    players victorious (including the dead).

この挑戦のために、あなたの目標は、マフィアで他のボットを打つためのボットを書くことです!

ボットを作る方法

私のために提供するすべての持っているは、 run
というファイルです。このチャレンジが行われるディレクトリ構造の中で、あなたのボットはここに住んでいます:

start
コントローラ/
tmp/
players/               # You are here!
    some_bot/          # Let's pretend you're some_bot.
        to_server
        from_server
        players
        run            # This is what you give me
    mafia-game-bot/
    skynet/

run
ファイルが実行されると、あなたのボットはそのことを行います。このファイルには、コマンドライン引数などが必要でないことに注意することが重要です。これは
./ run
と同じように実行されます。別の方法で実行する必要がある場合は、次のようなことをして回避する必要があります。

real_bot.py

#!/bin/python2

# code goes here

run

#!/bin/bash

./real_bot.py --flags --or --whatever

An important thing to note is that all input your bot receives
will be found in the file from_server and the control
program will look for your bot’s output in to_server.
I chose to do it this way so that any language that can do file I/O
is able to participate. If your language makes it easier to work
with stdin and stdout than file I/O, you may want to write a
run file that looks like this:

#!/bin/bash

./real_bot.py < from_server > to_server

これによりstdinは from_server ファイルから取得され、stdoutは
to_server から直接取得されます。

あなたのボットは試合の間中走り続けることはありません。代わりに、決定を下す必要があるときに実行されます。同様に、死んだら通知されることはありません。それ以上は実行されません。覚えておきたいことをファイルに保存し、後で読むことでこれを計画します。あなたは、ボットのフォルダ内のファイルを作成、書き込み、または読み取ることができますが、ネットワークアクセスやその他のものを含め、そのフォルダの外にどこでも書き込むことも読めることもできません。あなたのボットがフォルダ内から言われなかったことを何か知っている場合、またはそのフォルダ内にないもの何かに接触した場合、ボットは失格となります。

機能的なボットを作る方法

ゲームの開始時に、 players
ファイルは、ゲーム内のすべてのプレイヤーの改行で区切られたリストで埋められます。プレイヤーがゲームを終了すると更新されません。

0日目の夜明けに、すべてのプレイヤーは from_server
ファイルでこのメッセージを見つけます:

Rise and shine! Today is day 0.
No voting will occur today.
Be warned: Tonight the mafia will strike.

あなたが警官であれば、あなたは警官ですという行が最後に追加されます。医者はあなたは医師ですと見なします。マフィアは、あなたがマフィアのメンバーであることを知っています。
nあなたの同盟者は:と改行で区切られたマフィアメンバーのリストです。

他のすべての日の夜明けに、このメッセージが表示されます:

Dawn of day `day_number`.
Last night, `victim` was killed. They were `victim_role`.
Investigations showed that `cop_target` is `target_alignment`-aligned.
These players are still alive: `remaining_players`

dayNumber is replaced with the number of the day.
victim is replaced with the name of last night’s
victim, and victim_role is one of:

  • 村人
  • a mafioso
  • 警官
  • 医師

cop_target is the name of the player the cop
investigated last night, and target_alignment is
either village or mafia. Finally,
remaining_players is a list of players that are still
alive in this format: player1, player2, player3

昨夜の殺害がなければ2行目は省略され、3行目は警官にのみ表示されます。

例えば、

Dawn of day 42.
Last night, Xyzzy was killed. They were a villager.
Investigations showed that Randy is mafia-aligned.
These players are still alive: Randy, CopBot, JohnDoe, Steve

このメッセージが途切れると、その日が始まります!各ボットは、1日中50回のアクションを行うことができます。ここでは、「アクション」がプレーヤーに投票しているか、何か大きなものを言っています。

プレーヤーに投票するには、 to_server ファイルに vote
player_name
を書いて終了します。誰かを殺さないために投票するには、 vote no
one
を書いてください。あなたが投票すると、(あなたを含む)すべての選手が
your_selectionを殺すためにあなたの投票を見るでしょう。投票は0日目に無視されます。

あらかじめ定義されたいくつかのメッセージをすべてのプレーヤーに送ることができます。考えられる各メッセージのIDは次のとおりです。

 0: No
 1: Yes
 2: I am the cop
 3: I am the doctor
 4: I am a normal villager
 5: I trust this player: 
 6: I think this player is suspicious: 
 7: I think this player is the cop: 
 8: I think this player is the doctor: 
 9: I think this player is a normal villager: 
10: I think this player is mafia: 
11: Do you think this player is mafia? 
12: I tried to save this player: 
13: I successfully saved this player: 
14: I investigated this player and found that they were mafia-aligned: 
15: I investigated this player and found that they were village-aligned: 
16: Will you please use your power on this player tonight?

最初の5つを除くすべてのメッセージは、特定のプレーヤーを参照しています。これらのメッセージの1つを言うには、 say
message_id player_name
と書いてください。最初の5つのメッセージのうち、 say
message_id

と書いてください。あなたは話しているプレイヤーの名前を指定して、これらの両方にオプションの3番目の引数を追加することができます(すべてのプレイヤーがそれを読むことができますが、意図した受信者が誰かを知ることができます)。

あなたのボットがメッセージを言うと、すべてのプレイヤーは your_botに "message"
と答えます。ここで message
はあなたが書いたIDに関連付けられたメッセージです。メッセージに件名が含まれている場合は、メッセージの末尾の直後に1つのスペース文字と件名が挿入されます。受信者が含まれている場合は、その名前の前にコロンとスペース文字がメッセージの直前に挿入されます。

終わりには、投票の結果を見るためにすべての生きているプレイヤーが最後に実行されます。プレーヤーが投票された場合、これは以下のように書かれます:

The town has killed player_name!
They were a villager

…または a mafiosothe cop 、または
the doctor

投票されたプレイヤーがいない場合は、代わりに以下のように記述されます。

The town opted to lynch no one today.

コントローラーがこれらのメッセージを送信すると、プレイヤーからの応答は無視されます。その日は終わった。

ナイト

夜は、村人以外の誰もが自分の力を使うようになる。

マフィア:

それは夜です。被害者に投票してください。。この場合、殺すプレイヤーの名前を出力します。

Cop:

それは夜です。誰が調査したいですか?。この場合、確認したいプレーヤーの名前を出力します。

医師:

それは夜です。誰を保存しますか?。このような場合は、保護したいプレーヤーの名前を出力してください。

その後、次の日は通常通りに始まります。

1回の試合につき1回だけ自分を救うことができます。

一般情報

  • 6人以上のプレーヤーがいなくてもゲームは実行されません。
  • 3分の1のプレーヤーが、マフィアになります。
    1人のプレーヤーが医者になり、1人のプレーヤーが警官になります。他のすべてのプレイヤーは村人です。
  • 村落の票の結びつきやマフィアの一票がランダムに決済されます。
  • ボット名は英数字+ダッシュとアンダースコアでなければなりません。
  • 相手のコードの知識を直接使用することは禁じられています。理論的には、これまでに見たことがないボットとボットを比較し、同等の性能を発揮できるはずです。
  • 残念ながら、(ビールのように)ソフトウェアを無料で使用してプログラムを稼働させることができない場合は、失格とする必要があります。
  • 私は悪意のあると判断した場合、提出物を失格とする権利を留保します。これには、過度の時間、メモリ、または実行するスペースを使用することが含まれますが、これに限定されません。私は意図的に限界を柔らかいままにしましたが、覚えています:私はスーパーコンピュータではなく、私の家のコンピュータでこれを実行しています。結果が1年かかることは望ましくありません。私の基準がかなり低いので、これを使う必要はないと思う。これは基本的に「私があなたが故意に性交していると思うならば」、そうでなければ私に納得させることができるなら、私は私の決定を逆にするでしょう。

得点

各ラウンドでは、100試合が実行されます(これはサンプルサイズを十分に大きくするためにボットが増えるにつれて増加するかもしれませんが、理論上は何にも影響しません)。各ボットが村人として何度反撃されたのか、村人として何回再生されたのか、マフィアと同じように村人として勝つのかを記録します。ボットの
villager_ratio
は、村人として遊んだゲーム数/村人として遊んだゲーム数であり、
mafia_ratio 村人/マフィア/ g ボットの得点は(villager_ratio -
平均villager_ratio)+(mafia_ratio - 平均mafia_ratio)
です。

ボットの例

ランディロボットは良いマフィアプレーヤーではありません。ランディは、何を言いたいのか、誰に投票するのか、夜の力で誰を目標にするのか、無作為にすべてを無視します。

run.sh:

#!/bin/bash

./randy.py < from_server > to_server

randy.py:

#!/usr/bin/env python

import random

with open('players') as f:
    p = f.read().split() + ['no one']


day = True
try:
    line = raw_input()
    if line.endswith(('?', 'victim.')):
        day = False
    if not day:
        print random.choice(p)
    else:
        if random.random() > 0.5:
            if random.random() > 0.5:
                print 'vote {}'.format(random.choice(p))
            else:
                id = random.randint(0, 17)
                print 'say {}{}'.format(id, (' ' + random.choice(p)) if id > 4 else '')
except: pass

コントローラ

@undergroundmonorailは、このチャレンジのための制御プログラムを作成しました。ここで利用できます。

あなたは1ヶ月間コードを書いて答えを出すことができます。私は勝利ボット(最高勝利率タイブレーカーは投票です)を少なくとも50の評判賞金(1ヶ月でどれくらいの収益を得ることができるかによる)


コンパイルされた言語で使うために、@Blacksilverによって作られたラッパースクリプトがあります:

#!/bin/bash

run="./a.out"
compile="gcc bot.c"

if [ -e $run ]; then
        $run
else
        $compile
        $run
fi

Put this in run .


この投稿は@undergroundmonorail(私はいくつかの編集を行いました)によって書かれました。

彼は仕上げと投稿をしたいと思った人にここをあげました。

ベストアンサー

Logician

#!/usr/bin/env python3
import sys
import os
import re
import random
from types import SimpleNamespace
def chooseSet(set):
    return random.choice(list(set))
sys.stdin = open("from_server")
sys.stdout = open("to_server","w")
def saveData(data):
    with open("gameData.txt", "w") as datafile:
        datafile.write(repr(data.__dict__))
MY_NAME = os.path.basename(os.getcwd())
opener = input()
DATABASES = ("targets","herd","mafiosos","guilty","innocent","unlikely", "requests",
            "selfvotes","players","used_roles")
ALLOW_SELF = ("players", "mafiosos")
LIESPERROLE = {"cop": ("I am the cop",
                "I investigated this player and found that they were mafia-aligned",
                "I investigated this player and found that they were village-aligned"),
              "doctor": ("I am the doctor",
                   "I tried to save this player",
                   "I successfully saved this player"
                   )
        }
#1: At the beginning of the game, parse beginning of day 0
if opener == "Rise and shine! Today is day 0.":
    #Next two lines are completely predetermined and hold no data
    assert input() == "No voting will occur today."
    assert input() == "Be warned: Tonight the mafia will strike."
    data = SimpleNamespace(cop=False, doctor=False, queued=[],askers={})
    for datum in DATABASES:
        setattr(data, datum, set())
    try:
        nextline = input()
        if nextline == "You are a member of the mafia.":
            data.mafiosos.add(MY_NAME)
            assert input() == "Your allies are:"
            while True:
                data.mafiosos.add(input())
        elif nextline == "You are the doctor":
            data.doctor = True
            data.used_roles.add("doctor")
        elif nextline == "You are the cop":
            data.cop = True
            data.used_roles.add("cop")
    except EOFError:
        #villager, or ran out of mafiosos to add
        pass
    with open("players") as playersfile:
        data.players = set(playersfile.read().strip().splitlines())
    saveData(data)
    exit()
with open("gameData.txt") as datafile:
    data = SimpleNamespace(**eval(datafile.read().strip()))
#2: Beginning of day nonzero
if opener.startswith("Dawn of day"):
    data.requests.clear()
    data.selfvotes.clear()
    data.askers.clear()
    data.voted = False
    try:
        while True:
            nextline = input()
            victim = re.match("Last night, (.*) was killed. They were (?:a|the) (.*).", nextline)
            if victim:
                victim, role = victim.groups()
                #remove dead people from lists
                for datum in DATABASES:
                    getattr(data, datum).discard(victim)
                if role == "cop" or role == "doctor":
                    data.used_roles.add(role)
                continue
            investigated = re.match("Investigations showed that (.*) is (.*)-aligned.", nextline)
            if investigated:
                assert data.cop
                who = investigated.group(1)
                if investigated.group(2) == "mafia":
                    data.guilty.add(who)
                    data.unlikely.discard(who)
                else:
                    data.targets.discard(who)
                    data.herd.discard(who)
                    data.innocent.add(who)
                    data.unlikely.add(who)
                continue
    except EOFError:
        pass
#3: We're being told some messages/news
elif " says " in opener or " voted " in opener:
    message = opener
    acted = question = False
    try:
        while True:
            if " voted " in message:
                message = ""
                speaker, subject = re.match("(.*) has voted to lynch (.*)", message).groups()
                target = None
            else:
                speaker, target, message, subject = 
                    re.match("(.*) says "(?:(.*), )?([^:?]+)(?:[:?]s*(.*))?"",
                             message).groups()
            if speaker == MY_NAME:
                continue
            BAD_MESSAGES = ("", "I think this player is mafia",
                            "I investigated this player and found that they were mafia-aligned",
                            "I think this player is suspicious")
            GOOD_MESSAGES = ("I think this player is the cop",
                             "I think this player is the doctor",
                             "I think this player is a normal villager",
                             "I trust this player",
                             "I investigated this player and found that they were village-aligned")
            OUTS = "I am the cop", "I am the doctor"
            LIES = ()
            for role in data.used_roles:
                LIES += LIESPERROLE[role]
            if message == "Yes" or message == "No":
                if question and not target:
                    target = chooseSet(data.askers)
                if target in data.askers:
                    BAD_MESSAGES += "Yes",
                    GOOD_MESSAGES += "No",
                    subject = data.askers[target]
            if message in LIES and speaker not in data.mafiosos and speaker not in data.innocent:
                # What you just said is false, and I know it!
                data.unlikely.discard(speaker)
                data.targets.add(speaker)
                if subject and subject not in (data.unlikely.union(data.mafiosos)):
                    data.targets.add(subject)
            elif message in BAD_MESSAGES:
                if speaker in data.guilty:
                    #mafiosos rarely turn on eachother
                    data.unlikely.add(subject)
                    data.targets.discard(subject)
                elif speaker in data.unlikely:
                    #believe the herd, especially people who we trust
                    data.herd.add(subject)
                elif subject in data.unlikely:
                    #how dare you speak against players likely to be village-aligned!
                    data.targets.add(speaker)
                elif subject == MY_NAME or subject in data.mafiosos:
                    #DON'T ATTACK ME (or my fellow mafiosos)
                    data.targets.add(speaker)
                else:
                    #believe the herd
                    data.herd.add(subject)
                if not acted and message == "":
                    if subject == MY_NAME:
                        data.selfvotes.add(speaker)
                        if len(data.selfvotes) >= (len(data.players)-len(data.mafiosos))/3:
                            if data.cop:
                                print("say 2")
                                #give a data point to prove it
                                if random.random() > .5 and data.guilty:
                                    data.queued.append("say 14 %s" % chooseSet(data.guilty))
                                elif data.innocent:
                                    data.queued.append("say 15 %s" % chooseSet(data.innocent))
                            else:
                                print("say 4") #Don't out myself if I'm the doctor
                                # and just lie if I'm a mafioso
                            acted = True
                    else:
                        data.selfvotes.discard(speaker)
            elif message in OUTS and data.mafiosos and speaker not in data.unlikely:
                data.targets.add(speaker) #Kill the fools who boast!
            elif message in GOOD_MESSAGES:
                chance = random.random() < .1 - (speaker in data.targets)/20
                if speaker in data.guilty: #Mafia liars
                    if subject not in data.unlikely:
                        data.targets.add(subject)
                elif subject == MY_NAME and chance:
                    if speaker in data.targets:data.targets.remove(speaker)
                    data.unlikely.add(speaker)
                elif speaker in data.unlikely or chance:
                    data.unlikely.add(subject)
            elif message == "Do you think this player is mafia":
                if subject == MY_NAME:
                    data.targets.append(speaker)
                if target == MY_NAME or not target:
                    if speaker in data.guilty:
                        data.queued.append("say 14 %s %s" % (subject, speaker))
                    elif speaker in data.innocent:
                        data.queued.append("say 15 %s %s" % (subject, speaker))
                    elif subject in data.targets or subject in data.herd:
                        data.queued.append("say 1 %s" % (speaker))
                    elif subject in data.unlikely:
                        data.queued.append("say 0 %s" % (speaker))
                    if data.cop:
                        data.requests.add(subject)
                data.askers[speaker] = subject
                question = True
            elif target == MY_NAME and message == "Will you please use your power on this player tonight":
                data.requests.add(subject)
            message = input()
    except EOFError:
        pass
    for datum in DATABASES:
        if datum in ALLOW_SELF: continue
        getattr(data, datum).discard(MY_NAME)
    chance = random.random()
    if data.queued:
        print(data.queued.pop())
    elif chance < .1:
        target = chooseSet(data.targets or data.players)
        if target != MY_NAME:
            print("say 10 %s" % target)
            data.askers[MY_NAME] = target
    elif chance < .3 and data.targets:
        print("say 6 %s" % chooseSet(data.guilty or data.targets))
    elif chance < .5 and data.unlikely:
        print("say 5 %s" % chooseSet(data.innocent or data.unlikely))
    elif chance < .6 and not data.voted:
        target = chooseSet(data.guilty or data.targets or data.herd or data.players)
        if target not in data.mafiosos and target != MY_NAME:
            print("vote %s" % target)
        data.voted = True
    elif chance < .8:
        #do nothing
        pass
    elif chance < .9:
        #Confuse everybody
        print("say 1")
        data.queued.append("say 0")
######################
#4: End of day
elif "has killed" in opener:
    victim = re.match("The town has killed (.*)!", opener)
    if not victim:
        exit()
    victim = victim.group(1)
    #remove dead people from lists
    for datum in DATABASES:
        getattr(data, datum).discard(victim)
    role = input()
    role = re.match("They were (?:a|the) (.*)", role).group(1)
    if role == "cop" or role == "doctor":
        data.used_roles.add(role)
    #Misc: purge people from lists if too large
    for list in data.unlikely, data.targets, data.herd:
        while len(list) > len(data.players)/3:
            list.pop()
    for player in data.innocent:
        data.unlikely.add(player)
elif opener == "The town opted to lynch no one today.":
    #Do nothing
    pass
#5: Night
elif "night" in opener:
    if not data.mafiosos and data.requests and random.random() > .5:
        print(chooseSet(data.requests))
    if data.doctor:
        print(chooseSet(data.unlikely or data.players))
    else:
        while True:
            try:
              target = (data.targets or data.herd).pop()
            except KeyError:
              target = chooseSet(data.players)
            if target in data.mafiosos or target == MY_NAME:
                continue
            print(target)
            break
else:
    raise ValueError("Unknown message")
saveData(data)

Fancy, long bunch of python code that I’m
not going to explain (although it isn’t golfed), other than that it
keeps lists of “friends” and “enemies” that are originally
populated based on chance and/or cop investigation. Warning: do not
lie in Logician’s presence.

返信を残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です