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 nightn
. After every nightn
comes a dayn+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).
For this challenge, your goal is to write a bot to beat other bots at Mafia!
How to make a working bot
All you have to supply for me is a file called run
. Inside the directory structure where this challenge will take place, your bot will live here:
start
controller/
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/
The run
file, when executed, will make your bot do its thing. It's important to note that this file must not require any command line arguments or anything. It will be run exactly as ./run
. If you need to be executed in a different way, you'll have to work around it by doing something like this:
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
This will make it so that stdin comes from the from_server
file and stdout goes directly to to_server
.
Your bot will not stay running for the duration of the game. Instead, it will be run when it needs to make a decision. Likewise, it will not be informed when it's dead, it just won't be run anymore. Plan for this by saving anything you want to remember to a file and reading it later. You may create, write to or read from any file in your bot's folder, but you may not write or read anywhere outside of that folder, including network access or anything. If your bot knows anything that it wasn't told from inside the folder, or if it touches anything that isn't inside that folder, your bot is disqualified.
How to make a functional bot
Day
At the beginning of the game, the file players
will be filled with a newline-delimited list of all players in the game. It will not be updated as players leave the game.
At the dawn of day 0, all players will find this message in their from_server
file:
Rise and shine! Today is day 0.
No voting will occur today.
Be warned: Tonight the mafia will strike.
If you are the cop, the line You are the cop
is appended to the end. The doctor sees You are the doctor
. The mafia sees You are a member of the mafia.\nYour allies are:
and a newline-delimited list of mafia members, excluding the player reading the message.
At the dawn of all other days, this message will appear:
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 villager
a mafioso
the cop
the doctor
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
The second line is omitted if there was no kill last night, and the third line is shown only to the cop.
For example,
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
Once this message is out of the way, the day begins! Each bot can make 50 actions throughout the day, where an "action" is voting for a player or saying something out loud.
To vote for a player, write vote player_name
to your to_server
file and terminate. To vote to not kill anyone, write vote no one
. When you vote, all players (including you) will see your_bot votes to kill your_selection
. Votes are ignored on day 0.
A number of pre-defined messages can be sent to all players. The id of each possible message is listed here:
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?
All of these messages except the first five are referring to a specific player. To say one of those messages, write say message_id player_name
. For one of the first five messages, just write say message_id
. You may add an optional third argument to both of these, specifying the name of a player you're talking to (all players can still read it, but they'll know who the intended recipient is).
When your bot says a message, all players read your_bot says "message"
, where message
is the message associated with the id you wrote. If the message includes a subject, one space character and the subject are inserted directly after the end of the message. If it includes a recipient, their name, one colon and one space character are inserted immediately before the message.
At the end of the day, all living players are run one last time to see the result of the vote. If a player was voted out, this is written:
The town has killed player_name!
They were a villager
... or a mafioso
, or the cop
, or the doctor
.
If no player was voted out, this is written instead:
The town opted to lynch no one today.
When the controller sends these messages, it ignores any response from players. The day is over.
Night
At night, everyone but the villagers get to use their power.
Mafia:
You will read It is night. Vote for a victim.
. When this happens, output the name of the player you'd like to kill.
Cop:
You will read It is night. Who would you like to investigate?
. When this happens, output the name of the player you'd like to check.
Doctor:
You will read It is night. Who would you like to save?
. When this happens, output the name of the player you'd like to protect.
After this, the next day begins as normal.
You may save yourself only once per game.
General Information
- The game will not run without 6 or more players.
- One third of the players, rounded down, will be mafia. One player will be a doctor, and one player will be a cop. All other players are villagers.
- Ties in the village vote or the mafia's overnight vote are settled randomly.
- Bot names must be alphanumeric + dashes and underscores.
- It is forbidden to use knowledge of opponent's code directly. In theory, I should be able to put your bot up against bots you've never seen before and have it perform comparably.
- Regrettably, if I can't get your program running using exclusively free (as in beer) software, I'll have to disqualify it.
- I reserve the right to disqualify any submission if I believe it to be malicious. This includes, but is not limited to using excessive abouts of time, memory or space to run. I've intentionally left the limit soft, but remember: I'm running this on my home computer, not a supercomputer, and I don't want getting results to take a year. I don't expect to have to use this, since my standards are pretty low. This is basically "if I think you're being a dick on purpose", and if you can convince me otherwise I'll reverse my decision.
Scoring
Each round, 100 games will be run (this may increase as more bots join to keep the sample size large enough, but in theory that won't affect anything). I will record how many times each bot wins as a villager compared to how many times it plays as a villager, and the same for mafia. A bot's villager_ratio
is number of games won as villager / number of games played as villager
, and mafia_ratio
is the same but s/villager/mafia/g
. A bot's score is (villager_ratio - mean villager_ratio) + (mafia_ratio - mean mafia_ratio)
.
Example bot
Randy the Robot is not a good mafia player. Randy ignores pretty much everything, randomly choosing what to say, who to vote for, and who to target with night powers.
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
Controller
@undergroundmonorail wrote a control program for this challenge, available here.
You have one month to code and turn in answers, I will give the winning bot (highest win rate tie breaker is votes) at least a 50 reputation bounty (depending on how much rep I can earn in a month)
Here is a wrapper script, made by @Blacksilver, to use with compiled languages:
#!/bin/bash
run="./a.out"
compile="gcc bot.c"
if [ -e $run ]; then
$run
else
$compile
$run
fi
Put this in run
.
This post was written by @undergroundmonorail (I made a few edits).
He gave it up here to anyone who wanted to finish and post it.