Vamos jogar máfia!


42

Mafia (também conhecido como Lobisomem) é um jogo de festa que é mais ou menos assim:

  • O jogo começa no dia 0. Depois de cada dia nchega uma noite n. Depois de toda noite nchega o dia n+1. ie D0, N0, D1, N1, D2, N2...
  • No início do dia 0, um anfitrião escolhe secretamente os jogadores para desempenhar certas funções:  
    • Algum número de jogadores se torna a máfia. Toda noite, todo mafioso escolhe um jogador. Ao amanhecer do dia seguinte, o jogador escolhido pelos mais mafiosos é morto. Eles são permanentemente removidos do jogo e seu papel é revelado publicamente. Alinhado à máfia.  
    • Algum número de jogadores se torna policial. Toda noite, cada policial escolhe um jogador. No amanhecer do dia seguinte, o policial toma conhecimento do alinhamento dos jogadores. Alinhado pela vila.  
    • Algum número de jogadores se torna médico. Toda noite, cada médico escolhe um jogador. Se este jogador for o mesmo que a máfia escolheu matar, as ações da máfia naquela noite serão canceladas. Alinhado pela vila.  
    • Todos os jogadores que não são escolhidos para outro papel são aldeões. Os moradores não têm habilidades que não são compartilhadas por toda a cidade. Alinhado pela vila.
  • Todos os dias, exceto o dia 0, a cidade inteira (ou seja, todos os jogadores vivos) vota em um jogador. No final do dia, esse jogador é removido do jogo e seu papel é revelado. (No dia 0, todos relaxam até o anoitecer.)
  • Se, a qualquer momento, não houver mafiosos restantes, o jogo termina com todos os jogadores alinhados à aldeia vitoriosos (incluindo os mortos).
  • Se, a qualquer momento, os jogadores alinhados à aldeia não superarem os jogadores alinhados à máfia, o jogo terminará com todos os jogadores alinhados à máfia vitoriosos (incluindo os mortos).

Para esse desafio, seu objetivo é escrever um bot para vencer outros bots na Mafia!

Como fazer um bot funcionando

Tudo o que você precisa fornecer para mim é um arquivo chamado run. Dentro da estrutura de diretórios em que esse desafio ocorrerá, seu bot viverá aqui:

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/

O runarquivo, quando executado, fará com que seu bot faça seu trabalho. É importante observar que esse arquivo não deve exigir argumentos de linha de comando ou algo assim. Será executado exatamente como ./run. Se você precisar ser executado de uma maneira diferente, precisará contorná-lo fazendo algo assim:

real_bot.py

#!/bin/python2

# code goes here

run

#!/bin/bash

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

Uma coisa importante a ser observada é que todas as entradas recebidas pelo bot serão encontradas no arquivo from_servere o programa de controle procurará a saída do bot to_server. Eu escolhi fazer dessa maneira para que qualquer idioma que possa fazer a E / S de arquivo possa participar. Se seu idioma facilitar o trabalho com stdin e stdout do que com E / S de arquivos, você pode escrever um runarquivo parecido com este:

#!/bin/bash

./real_bot.py < from_server > to_server

Isso fará com que stdin venha do from_serverarquivo e stdout vá diretamente para to_server.

Seu bot não ficará em execução durante o jogo. Em vez disso, ele será executado quando precisar tomar uma decisão. Da mesma forma, ele não será informado quando estiver morto, apenas não será mais executado. Planeje isso salvando tudo o que deseja lembrar em um arquivo e lendo-o mais tarde. Você pode criar, gravar ou ler qualquer arquivo na pasta do seu bot, mas não pode escrever ou ler em qualquer lugar fora dessa pasta, incluindo acesso à rede ou qualquer outra coisa . Se o seu bot souber algo que não foi informado de dentro da pasta, ou se tocar em algo que não está nessa pasta, seu bot será desqualificado.

Como fazer um bot funcional

Dia

No início do jogo, o arquivo playersserá preenchido com uma lista delimitada por nova linha de todos os jogadores no jogo. Não será atualizado quando os jogadores saírem do jogo.

No início do dia 0, todos os jogadores encontrarão esta mensagem em seu from_serverarquivo:

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

Se você é o policial, a linha You are the copé anexada ao final. O médico vê You are the doctor. A máfia vê You are a member of the mafia.\nYour allies are:e uma lista delimitada por nova linha de membros da máfia, excluindo o jogador que está lendo a mensagem.

No início de todos os outros dias, esta mensagem aparecerá:

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é substituído pelo número do dia. victimé substituído pelo nome da vítima da noite passada e victim_roleé um dos seguintes:

  • a villager
  • a mafioso
  • the cop
  • the doctor

cop_targeté o nome do jogador que o policial investigou na noite passada e target_alignmenté villageou mafia. Finalmente, remaining_playersé uma lista de jogadores que ainda estão vivos neste formato:player1, player2, player3

A segunda linha é omitida se não houve morte ontem à noite, e a terceira linha é mostrada apenas para o policial.

Por exemplo,

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

Uma vez que esta mensagem está fora do caminho, o dia começa! Cada bot pode realizar 50 ações ao longo do dia, onde uma "ação" está votando em um jogador ou dizendo algo em voz alta.

Para votar em um jogador, escreva vote player_nameno seu to_serverarquivo e termine. Para votar para não matar ninguém, escreva vote no one. Quando você votar, todos os jogadores (incluindo você) verão your_bot votes to kill your_selection. Os votos são ignorados no dia 0.

Um número de mensagens predefinidas pode ser enviado a todos os jogadores. O ID de cada mensagem possível está listado aqui:

 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?

Todas essas mensagens, exceto as cinco primeiras, estão se referindo a um jogador específico. Para dizer uma dessas mensagens, escreva say message_id player_name. Para uma das cinco primeiras mensagens, basta escrever say message_id. Você pode adicionar um terceiro argumento opcional a ambos, especificando o nome do jogador com quem está falando (todos os jogadores ainda podem lê-lo, mas saberão quem é o destinatário pretendido).

Quando o seu bot diz uma mensagem, todos os jogadores leem your_bot says "message", onde messageestá a mensagem associada ao ID que você escreveu. Se a mensagem incluir um assunto, um caractere de espaço e o assunto serão inseridos diretamente após o final da mensagem. Se incluir um destinatário, seu nome, dois pontos e um caractere de espaço serão inseridos imediatamente antes da mensagem.

No final do dia, todos os jogadores vivos são disputados uma última vez para ver o resultado da votação. Se um jogador foi eliminado, está escrito:

The town has killed player_name!
They were a villager

... ou a mafioso, ou the cop, ou the doctor.

Se nenhum jogador foi votado, isto está escrito:

The town opted to lynch no one today.

Quando o controlador envia essas mensagens, ele ignora qualquer resposta dos jogadores. O dia acabou.

Noite

À noite, todos, menos os moradores, usam seu poder.

Máfia:

Você vai ler It is night. Vote for a victim.. Quando isso acontecer, digite o nome do jogador que você gostaria de matar.

Policial:

Você vai ler It is night. Who would you like to investigate?. Quando isso acontece, imprima o nome do player que você deseja verificar.

Médico:

Você vai ler It is night. Who would you like to save?. Quando isso acontecer, digite o nome do jogador que você deseja proteger.

Depois disso, o dia seguinte começa normalmente.

Você pode se salvar apenas uma vez por jogo.

Informação geral

  • O jogo não será executado sem 6 ou mais jogadores.
  • Um terço dos jogadores, arredondados, será da máfia. Um jogador será médico e um jogador será policial. Todos os outros jogadores são aldeões.
  • Os laços no voto da aldeia ou o voto da máfia da noite para o dia são resolvidos aleatoriamente.
  • Os nomes dos bot devem ser alfanuméricos + traços e sublinhados.
  • É proibido usar o conhecimento do código do oponente diretamente. Em teoria, eu deveria ser capaz de colocar seu bot contra bots que você nunca viu antes e ter um desempenho comparável.
  • Lamentavelmente, se eu não conseguir executar seu programa usando software exclusivamente gratuito (como em cerveja), terei que desqualificá-lo.
  • Reservo-me o direito de desqualificar qualquer envio, se achar que é malicioso. Isso inclui, mas não se limita ao uso excessivo de tempo, memória ou espaço para execução. Intencionalmente deixei o limite baixo, mas lembre-se: estou executando isso no meu computador doméstico, não em um supercomputador, e não quero que os resultados levem um ano. Não espero ter que usar isso, pois meus padrões são bem baixos. Isso é basicamente "se eu acho que você está sendo um idiota de propósito", e se você pode me convencer do contrário, vou reverter minha decisão.

Pontuação

A cada rodada, 100 jogos serão executados (isso pode aumentar à medida que mais bots se juntam para manter o tamanho da amostra grande o suficiente, mas na teoria isso não afeta nada). Vou gravar quantas vezes cada bot vence como aldeão em comparação com quantas vezes ele joga como aldeão, e o mesmo para a máfia. Um bot villager_ratioé number of games won as villager / number of games played as villager, e mafia_ratioé o mesmo, mas s/villager/mafia/g. A pontuação de um bot é (villager_ratio - mean villager_ratio) + (mafia_ratio - mean mafia_ratio).

Exemplo de bot

Randy, o robô, não é um bom jogador da máfia. Randy ignora praticamente tudo, escolhendo aleatoriamente o que dizer, em quem votar e em quem mirar com poderes noturnos.

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

Controlador

O @undergroundmonorail escreveu um programa de controle para esse desafio, disponível aqui .

Você tem um mês para codificar e entregar as respostas. Eu darei ao bot vencedor (o desempate com maior taxa de vitória é o voto) pelo menos uma recompensa de 50 reputação (dependendo de quanto rep eu posso ganhar em um mês)


Aqui está um script de wrapper, criado por @Blacksilver, para usar com idiomas compilados:

#!/bin/bash

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

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

Coloque isso run.


Este post foi escrito por @undergroundmonorail (fiz algumas edições).

Ele o entregou aqui para quem quisesse terminar e publicá-lo.


Comentários não são para discussão prolongada; esta conversa foi movida para o bate-papo .
Martin Ender

Respostas:


3

zulu

run

#!/usr/bin/env php
<?php
error_reporting(E_ERROR|E_WARNING|E_PARSE);

$self = basename(__DIR__);

$msgids = array(
    "No",
    "Yes",
    "I am the cop",
    "I am the doctor",
    "I am a normal villager",
    "I trust this player:",
    "I think this player is suspicious:",
    "I think this player is the cop:",
    "I think this player is the doctor:",
    "I think this player is a normal villager:",
    "I think this player is mafia:",
    "Do you think this player is mafia?",
    "I tried to save this player:",
    "I successfully saved this player:",
    "I investigated this player and found that they were mafia-aligned:",
    "I investigated this player and found that they were village-aligned:",
    "Will you please use your power on this player tonight?"
);
$msgids = array_flip($msgids);

if(!file_exists('./from_server')){
    die;
}
$in = file('from_server');
if(count($in) && strpos($in[0],'day 0.') !== false){
    $game = array(
        'day'               =>0,
        'players'           =>array(),
        'alive'             =>array(),
        'dead'              =>array(),
        'mafia'             =>array(),
        'village'           =>array(),
        'cop'               =>'',
        'doctor'            =>'',
        'votes'             =>array(),
        'messages'          =>array(),
        'currentvotes'      =>array(),
        'currentmessages'   =>array()
    );
    $playersfile = file('players');
    foreach($playersfile as $name){
        $game['players'][trim($name)] = 1;
        $game['alive'][trim($name)] = 1;
        $game['votes'][trim($name)] = array();
        $game['messages'] = array();
    }
    $allies = false;
    foreach($in as $line){
        if($allies){
            if(array_key_exists(trim($line),$game['players'])){
                $game['mafia'][trim($line)] = 1;
            }
        }
        else if(strpos($line,"You are the cop") !== false){
            $game['cop'] = $self;
            $game['village'][$self] = 1;
        }
        else if(strpos($line,"You are the doctor") !== false){
            $game['doctor'] = $self;
            $game['village'][$self] = 1;
        }
        else if(strpos($line,"member of the mafia") !== false){
            $game['mafia'][$self] = 1;
        }
        else if(strpos($line,"allies are:") !== false && $game['mafia'][$self]){
            $allies = true;
        }
    }
    if(!$game['mafia'][$self]){
        $game['village'][$self] = 1;
    }
    else{
        foreach($game['players'] as $name=>$g){
            if(!$game['mafia'][$name]){
                $game['village'][$name] = 1;
            }
        }
    }
    $out = json_encode($game);
    write('myinfo',$out);
}
else{
    $myinfo = file_get_contents('myinfo');
    $game = json_decode($myinfo,true);
    if(count($in) && strpos($in[0],"town has killed") !== false){
        $e = explode(" ",trim($in[0]));
        $dead = trim($e[4],'!');
        unset($game['alive'][$dead]);
        $game['dead'][$dead] = 1;
        $e = explode(" ",trim($in[1]));
        $allegiance = trim($e[3],".");
        $game[$allegiance][$dead] = 1;
    }
    else if(count($in) && strpos($in[0],"town opted to") !== false){
        //
    }
    else if(count($in) && strpos($in[0],"night") !== false){
        if(strpos($in[0],"victim") !== false){
            $voted = false;
            if($game['day'] > 0){
                $possible = array();
                foreach($game['alive'] as $name=>$g){
                    if(!$game['mafia'][$name]){
                        foreach($game['votes'][$name] as $for){
                            if($voted && $game['mafia'][$for]){
                                $possible[] = $name;
                            }
                        }
                    }
                }
                if(count($possible)){
                    shuffle($possible);
                    write('to_server',$possible[0]);
                    $voted = 1;
                }               
            }
            if(!$voted){
                while($rand = array_rand($game['alive'])){
                    if(!$game['mafia'][$rand]){
                        write('to_server',$rand);
                        $voted = 1;
                        break;
                    }
                }
            }
        }
        else if(strpos($in[0],"investigate") !== false){
            $possible = array();
            foreach($game['alive'] as $name=>$g){
                if(!$game['village'][$name] && !$game['mafia'][$name] && $game['doctor'] != $name){
                    $possible[] = $name;
                }
            }
            if(count($possible)){
                shuffle($possible);
                write('to_server',$possible[0]);
            }
        }
        else if(strpos($in[0],"save") !== false){
            if($game['day'] == 0){
                write('to_server',$self);
            }
            else{
                if($game['cop'] != '' && $game['alive'][$game['cop']]){
                    write('to_server',$game['cop']);
                }
                else{
                    $voted = false;
                    foreach($game['alive'] as $name=>$g){
                        if($game['village'][$name] && $name != $self){
                            write('to_server',$name);
                            $voted = true;
                            break;
                        }
                    }
                    if(!$voted){
                        while($rand = array_rand($game['alive'])){
                            if($rand != $self){
                                write('to_server',$rand);
                                break;
                            }
                        }
                    }
                }
            }
        }
    }
    else if(count($in) && strpos($in[0],"Dawn of day") !== false){
        $e = explode(" ",trim($in[0]));
        $game['day'] = trim($e[3],".");
        foreach($in as $line){
            if(strpos($line,"was killed") !== false){
                $e = explode(" ",trim($line));
                $dead = $e[2];
                if(strpos($line,"the cop") !== false){
                    $game['cop'] = $dead;
                    $game['village'][$dead] = 1;
                }
                else if(strpos($line,"the doctor") !== false){
                    $game['doctor'] = $dead;
                    $game['village'][$dead] = 1;
                }
                else if(strpos($line,"a villager") !== false){
                    $game['village'][$dead] = 1;
                }
                else if(strpos($line,"a mafioso") !== false){
                    $game['mafia'][$dead] = 1;
                }
                unset($game['alive'][$dead]);
                $game['dead'][$dead] = 1;
            }
            else if(strpos($line,"Investigations showed") !== false){
                $e = explode(" ",trim($line));
                $name = $e[3];
                $align = trim($e[5]);
                $e = explode("-",$align);
                $game[$e[0]][$name] = 1;
            }
        }
        $game['currentvotes'] = array();
        $game['currentmessages'] = array();
        foreach($game['alive'] as $name=>$g){
            $game['currentvotes'][$name] = '';
        }
    }
    else{
        foreach($in as $line){
            if(strpos($line," has voted to lynch no one") !== false){
                $e = explode(" ",trim($line));
                $game['votes'][$e[0]][] = false;
                $game['currentvotes'][$e[0]] = false;
            }
            else if(strpos($line," has voted to ") !== false){
                $e = explode(" ",trim($line));
                $game['votes'][$e[0]][] = trim($e[5]," .");
                $game['currentvotes'][$e[0]] = trim($e[5]," .");
            }
            else if(strpos($line," says ") !== false){
                foreach($msgids as $msg=>$id){
                    $chk = preg_match('/([^\s]+) says "(([^\s]+)[:,] )?'.preg_quote($msg).'( ([^\s]+))?"/',$line,$matches);
                    if($chk){
                        //                                  said by     said to     said  said about
                        $game['messages'][]         = array($matches[1],$matches[3],$msg, $matches[5]);
                        $game['currentmessages'][]  = array($matches[1],$matches[3],$msg, $matches[5]);
                    }
                }
            }
        }
        $written = false;
        $convo = array();
        foreach($game['currentmessages'] as $msg){
            if($msg[1] == $self){
                $convo[$msg[0]] = $msg;
            }
            else if($msg[0] == $self && $msg[1] != ''){
                unset($convo[$msg[1]]);
            }
        }
        if(count($convo)){
            foreach($convo as $c){
                if($msgids[$c[2]] == 11){
                    if($game['mafia'][$msg[3]]){
                        write('to_server',"say 1 ".$msg[0]);
                        $written = true;
                        break;
                    }
                    else if($game['village'][$msg[3]]){
                        write('to_server',"say 0 ".$msg[0]);
                        $written = true;
                        break;
                    }
                    else{
                        write('to_server',"say 11 ".$msg[0]);
                        $written = true;
                        break;
                    }
                }
                else if($msgids[$c[2]] == 16){
                    write('to_server',"say 0 ".$msg[0]);
                    $written = true;
                }
                else{
                    write('to_server',"say 4 ".$msg[0]);
                    $written = true;
                }
            }
        }
        if(!$written){
            $currentvote = false;
            if(array_key_exists($self,$game['currentvotes'])){
                $currentvote = $game['currentvotes'][$self];
            }
            if($game['mafia'][$self]){
                $votes = @array_count_values($game['currentvotes']);
                if($votes && count($votes)){
                    arsort($votes);
                    foreach($votes as $name=>$number){
                        if($game['village'][$name]){
                            if($currentvote != $name){
                                write('to_server','vote '.$name);
                                $written = true;
                                break;
                            }
                        }
                    }
                }
            }
            else{
                if(count($game['mafia'])){
                    foreach($game['mafia'] as $name=>$g){
                        if($game['alive'][$name]){
                            $written = true;
                            if($currentvote != $name){
                                write('to_server','vote '.$name);
                            }
                            break;
                        }
                    }
                    if(!$written){
                        foreach($game['mafia'] as $name=>$g){
                            $non = $game['alive'];
                            unset($non[$self]);
                            if(array_key_exists($name,$game['votes'])){
                                foreach($game['votes'][$name] as $vote){
                                    if(array_key_exists($vote,$non)){
                                        unset($non[$vote]);
                                    }
                                }
                            }
                            if(count($non)){
                                $rand = array_rand($non);
                                write('to_server','vote '.$rand);
                                $written = true;
                                break;
                            }
                        }
                    }
                }
                if(!$written && $game['cop']){
                    $possible = array();
                    foreach($game['votes'][$game['cop']] as $name){
                        if($game['alive'][$name] && $name != $self){
                            $possible[] = $name;
                        }
                    }
                    if(count($possible)){
                        shuffle($possible);
                        write('to_server','vote '.$possible[0]);
                        $written = true;
                    }
                }
                if(!$written && count($game['dead'])){
                    foreach($game['dead'] as $name=>$g){
                        if($game['village'][$name]){
                            $v = array();
                            foreach($game['votes'] as $voted=>$arr){
                                if($game['alive'][$voted] && in_array($name,$arr)){
                                    $v[$voted] = 1;
                                }
                            }
                            unset($v[$self]);
                            if(count($v)){
                                $rand = array_rand($v);
                                write('to_server','vote '.$rand);
                                $written = true;
                                break;
                            }
                        }
                    }
                }
                if(!$written){
                    $votes = @array_count_values($game['currentvotes']);
                    if($votes && count($votes) && array_key_exists($self,$votes)){
                        arsort($votes);
                        foreach($votes as $name=>$number){
                            if(!$game['village'][$name]){
                                if($name != $self){
                                    write('to_server','vote '.$name);
                                    $written = true;
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    $myinfo = json_encode($game);
    write('myinfo',$myinfo);
}

function write($filename,$data){
    $fh = fopen($filename,"wb+");
    if($fh){
        $bytes = fwrite($fh,$data);
        fclose($fh);
    }
}

Nem tudo o que eu esperava que fosse. Eu posso acabar mexendo de vez em quando.

Como funciona v1.0

Controla o número do dia, quem está vivo, quem está morto, quem é máfia, quem está alinhado com a aldeia, papéis, votos / mensagens do dia atual e votos / mensagens gerais.

  1. Noite

    uma. Máfia - vote em qualquer morador que tenha votado contra a máfia (aleatoriamente), se possível, caso contrário, um morador aleatório.

    b. Policial - Investigue quem é de alinhamento desconhecido.

    c. Médico - salve a si próprio primeiro turno, depois salve o policial se souber (acho que nunca saberá disso a partir de agora), salve o aldeão se souber (provavelmente também não sabe disso), caso contrário salve uma pessoa aleatória.

  2. Dia

    uma. Se alguém falou uma mensagem diretamente para si mesmo, responda a eles (respostas limitadas são possíveis).

    b. Máfia - vote no aldeão com mais votos.

    c. Aldeão com qualquer conhecido vivo alinhado à Máfia - vote em mafioso.

    d. Aldeão conhecido apenas como morto pela máfia - vote em um bot aleatório que nunca votou no mafioso.

    e Aldeão com policial conhecido - vote no bot aleatório em que o policial votou.

    f. Aldeão com mortos conhecidos alinhados com a aldeia - vote em um bot aleatório que votou nos mortos.

    g. Aldeão com votos contra o voto próprio para o bot mais alto atualmente não alinhado com a aldeia.


1
Espere, o que isso faz?
SIGSTACKFAULT

1
Ora, ele interpreta máfia, é claro! :)
Jo.

Eu quero dizer a estratégia.
SIGSTACKFAULT 25/01

6

O código de exemplo não funcionou para mim, eu uso o Python 3, então alterei o main.pyarquivo para fazê-lo funcionar.

Então, aqui está a minha versão fixa para o Python 3, eu nunca programei em Python antes, talvez seja um código horrível, mas funcione :)

run.sh:

#!/bin/bash

./randy.py < from_server > to_server

randy.py:

#!/usr/bin/env python3

import random

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

with open('from_server') as f:
    fs = f.read().split()

msg = ""
day = True
try:
    line = fs[0]
    if line.endswith(('?', 'victim.')):
        day = False
    if not day:
        msg = (random.choice(p))
    else:
        if random.random() > 0.5:
            if random.random() > 0.5:
                msg = ('vote {}'.format(random.choice(p)))
            else:
                id = random.randint(0, 17)
                msg = ('say {}{}'.format(id, (' ' + random.choice(p)) if id > 4 else ''))

    with open('to_server', 'w') as f:
        f.write(msg)
    print(msg)
except: pass

Algumas coisas que aprendi enquanto fazia esse trabalho (e não estava claro para mim na descrição)

  • printnão faz nada com o jogo é como um console.logem js
  • input() bloqueia o programa em execução, pode ser bom para depuração passo a passo
  • from_servere to_serveré limpo a cada rodada.
  • É impossível parar o script com uma Ctrl+Ccombinação, o que é irritante.

Bem-vindo ao PPCG! Ótimo primeiro post! Espero que você fique por aqui! Editei sua postagem para destacar a sintaxe em funcionamento e, por uma questão de consistência, acrescentei a run.sh.
Rɪᴋᴇʀ

1
Obrigado! Não tenho certeza se < from_server > to_serveré necessário porque codifiquei os nomes de arquivos no código. o mecanismo de jogo simplesmente liga ./runsem canos. então input()e print()não funcionou com o jogo. mayn.pylinha 57:os.system('./run')
Peter

2
Como você conseguiu que o controlador funcionasse? Eu não consigo entender. Você pode fornecer uma chamada de amostra?
Rɪᴋᴇʀ

Nota: O original randy.pyfoi escrito em Python 2 , o que causou os problemas.
SIGSTACKFAULT

para o controlador que você precisa ./startda pasta original ou você precisa de uma versão python 3 do arquivomain.py
Peter

5

The 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 = "<vote against>"
                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 = ("<vote against>", "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 == "<vote against>":
                    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)

Fantasia, longo monte de código python que eu não vou explicar (embora não seja um jogo de golfe), além de manter listas de "amigos" e "inimigos" que são originalmente preenchidos com base em chances e / ou investigação policial . Aviso: não fique na presença do lógico.


é o seu run.shpadrão (fazer alguns testes)
Stan Strum

Não, meu run.sh poderia simplesmente ser "run.py" sem a tubulação de entrada e saída usual, mas o padrão funcionaria.
pppery

1
Isso parece muito com o que eu teria escrito, se tivesse tempo e inclinação.
Draco18s

Por alguma razão eu acho que o lógico não vai fazer tão bem em todo o outros bots ... nenhum dos outros bots relatório da investigação policial
JavaScriptCoder

1
... e percebo, meses depois, que minha resposta assume incorretamente que só pode haver um policial / médico.
pppery 17/04

4

Sobrevivente (v 1.0)

Sinopse

O Survivalist simplesmente sobrevive brutalmente ao jogo, repreendendo qualquer um que se atreve a acusá-lo, independentemente de ser ou não máfia.

Lógica

Se você sobreviver até o final do jogo, você ganha, não importa o quê. Portanto, você sobrevive a todo custo.

História de fundo

As tropas marcharam pela floresta úmida e escura.

"Tenente, onde estamos marchando?" O jovem recruta aparentemente não se endureceu com atrocidades, pensou o comandante. Ah bem. Ele respondeu com um brusco "para destruir o inimigo".

Na vila, o comandante inimigo estava bebendo e rindo junto com os outros oficiais do clube quando um batedor apareceu com as notícias. "Há uma coluna, com várias centenas de metros de comprimento, marchando pela floresta Yulin para nós! Reúna as tropas!"

O comandante inimigo, obviamente embriagado, disse inesperadamente: "Não recebi relatos de outros batedores". O batedor (mais tarde sobrevivente) pensou, então terei que reunir as tropas eu mesmo . Depois de contar a história aos companheiros, eles voltaram juntos, todos dizendo que haviam visto tropas inimigas. O comandante ainda não acreditou, dizendo: "Estou ordenando que você interrompa o escotismo. Não tropas inimigas".

Os batedores decidiram pegar suas armas para salvar a comunidade. Eles conseguiram chegar a suas posições assim que o inimigo chegou à vila em vigor. "CARREGAR!" gritou o comandante da emboscada. "QUEIME AS CASAS! QUEIME AS CASAS! MATE TODOS, INCLUINDO AS MULHERES E AS CRIANÇAS! "

Os batedores salvaram todo o exército. Eles esperavam promoção, prêmios e medalhas. Em vez disso, receberam uma corte marcial fraudulenta por motim, condenação, 10 anos de prisão, dispensa desonrosa dos militares e exílio.


Há um ancião idoso no conselho da cidade de Salem, Massachusetts. Diz a lenda que ele fundou a cidade. Quando você o encontrar em sua cabana isolada na floresta, não deixe o brilho nos olhos dele fazer você pensar que ele é pacífico. Se você o acusar, ele o arruinará em frente à cidade.

O veterano riu na escuridão. Com medo do escuro, de jeito nenhum. Com medo de monstros debaixo da cama? O homem com a mão no gatilho de uma arma riu nervosamente. Ele não tinha medo de nada, dissera a si mesmo. Claro, ele era um herói do tempo da guerra no passado, mas estava tão acostumado a emboscadas e situações de risco de vida que tornava o homem simplesmente neurótico. Seu dedo no gatilho se contraiu com sombras simples; seu batimento cardíaco acelerou com cada pequeno som. Sim, ele estava com tanto medo da morte. Como ele não pôde, vendo tantas pessoas morrerem de maneiras horríveis? Tudo o que sabia ao ser seqüestrado e escapar milagrosamente de seus inimigos era que não havia piedade.

Veterano


Código (eu sou um novato em python, não tenho certeza se o código é bom)

#!/bin/python2

import random

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


day = True
target = "survivalist"
role = "villager"
try:
    line = raw_input()
    if "You are the cop" in line:
        role = "cop"
    else if "You are the doctor" in line:
        role = "doctor"
    else if "You are a member of the mafia" in line:
        role = "mafia"

    if line.endswith(('?', 'victim.')):
        day = False
    if not day:
        if target == "survivalist":
            print random.choice(p)
        else if role == mafia || role == sheriff:
            print target
        else if role == doctor:
            print random.choice(p)
    else:
        if "survivalist" in line && ("I think this player is suspicious:" in line || 
        "I think this player is mafia:" in line ||
        "I investigated this player and found that they were mafia-aligned:")):
            print 'say 0'
            if role == "villager" || role == "mafia":
                print 'say 4'
            else if role == "cop":
                print 'say 2'
            else if role == "doctor"
                print 'say 3'
            target = line.split(" ")[0]
            print 'vote ' + target

        else if target != "survivalist":
            print 'say 6 ' + target
            print 'vote ' + target
    else:
        pass

except: pass

Você quis dizer em orvez de ||? Você testou? Além disso, você provavelmente deve apontar que é Python 2.
Solomon Ucko

3

Avatar

O avatar "aleatoriamente" escolhe um jogador no início e o concentra incansavelmente pelo resto da rodada.

Esta não é uma referência a um programa de TV animado com o mesmo nome.

É uma referência online da EVE.

Baixe o tar de todos os arquivos necessários

Changelog

  • Aniversário v1
  • v2 Não registra nada stdout, apenas para stderr.
    Para suprimir stderrtambém, adicione 2>/dev/nullno final do runarquivo.
/*  Casting his sight on his realm, the Lord witnessed
    The cascade of evil, the torrents of war.
    Burning with wrath, He stepped 
    down from the Heavens
    To judge the unworthy,
    To redeem the pure.

    -The Scriptures, Revelation Verses 2:12
*/

#include <stdlib.h>
#include <stdio.h>
#include "mafia.h"

int getRandomNumber(){
    return 4; // Chosen by a fair dice roll.
              // Garunteed to be random.
}


void day0(){
    char * target = get_player(getRandomNumber()-1)->name;
    fprintf(stderr, "Target: `%s'\n", target);
    FILE * f = fopen("target", "w");
    if(!f){exit(1);}
    fprintf(f, "%s", target);
    fclose(f);
}


int main(){
    get_players();
    int cycle = get_cycle(day0);
    FILE * out = fopen("to_server", "w");
    if(!out){exit(1);}
    FILE * targetF = fopen("target", "r");
    if(!targetF){exit(1);}

    char target[64];

    fscanf(targetF, "%s", target);

    fprintf(stderr, "Target: %s\n", target);

    if(cycle == 0){
        // night
        fprintf(out,"%s\n", target);
        fprintf(stderr, "> Voting to kill %s\n", target);
        exit(0);
    } else if (cycle > 0) {
        // day
        fprintf(out, "vote %s\n", target);
        fprintf(stderr, "> Voting to lynch %s\n", target);
        exit(0);
    } else if (cycle == -1) {
        fprintf(stderr, "> saying 6, 10 at %s\n", target);
        fprintf(out, "say 6 %s\n", target);
        fprintf(out, "say 10 %s\n", target);
    }
}

Requer mafia.ce mafia.h, bibliotecas que escrevi, no mesmo diretório.

Eles estão incluídos no download, junto com um Makefile e um script de execução.

FAÇAM

  • Pare de votar no alvo quando eles forem mortos ou linchados.

Enquanto estiver aqui, enviarei o não bot, Steve:


FYI, eu chamo dibs em avatar, erebus, leviathan, eragnarok
SIGSTACKFAULT

"Esta não é uma referência a um programa de TV animado com o mesmo nome". é uma referência ao filme?
precisa

@ StanStrum não, não é.
SIGSTACKFAULT

O from_serverarquivo do meu bot não está sendo gravado. Você precisou definir permissões específicas ou algo assim?
Rɪᴋᴇʀ

1
Nota para os curiosos: as Escrituras mencionadas aqui são as do Amarr de EVE Online. Não é um Apocalipse 02:12 na Bíblia, mas ele lê em vez de forma diferente.
DLosc

2

Leviatã

O Leviathan repete todos os jogadores no playersarquivo e os direciona um a um.

Baixar

/*  Citizens of the State, rejoice!

    Today, a great milestone has been achieved by our glorious leaders.
    A stepping stone in the grand story of our empire has been traversed.
    Our individual fears may be quietened;
    the safety of our great nation has been secured.

    Today, unyielding, we have walked the way of the warrior.
    In our hands have our fates been molded.
    On the Leviathan's back will our civilization be carried home
    and the taint of the Enemy purged from our souls.

    Rejoice, citizens! Victory is at hand.

    -Caldari State Information Bureau Pamphlet, YC 12
*/

#include <stdio.h>
#include <stdlib.h>
#include "mafia.h"

void day0(){
    FILE * index = fopen("idx", "w");

    fprintf(index,"0");

    fclose(index);
}

int main(){
    get_players();
    int i, cycle = get_cycle(day0);

    FILE * out = fopen("to_server", "w");
    FILE * idx = fopen("idx", "r");

    fscanf(idx, "%d", &i);
    fclose(idx);

    char * target;
    target = get_player(i)->name;

    fprintf(stderr, "Idx: %d\n", i);
    fprintf(stderr, "Target: %s\n", target);

    if(cycle > 0){
        idx = fopen("idx", "w");
        i++;
        i = i%NPLAYERS;
        fprintf(idx, "%d", i);
        fprintf(out, "vote %s\n", target);
    } else if (cycle == -1) {
        printf("> saying 6, 10 at %s\n", target);
        fprintf(out, "say 6 %s\n", target);
        fprintf(out, "say 10 %s\n", target);
    }

    fclose(out);
}

Como no Avatar, ele requer mafia.ce mafia.hno mesmo diretório.

Eles estão incluídos no download, junto com um Makefile e um script de execução.


:) adição de sobrevivência, uma vez im feito com ele
JavaScriptCoder
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.