Giochiamo a Mafia!


42

Mafia (noto anche come Werewolf) è un gioco di società che gioca all'incirca in questo modo:

  • Il gioco inizia il giorno 0. Dopo ogni giorno narriva una notte n. Dopo ogni notte narriva un giorno n+1. cioè D0, N0, D1, N1, D2, N2...
  • All'alba del giorno 0, un host sceglie segretamente i giocatori per ricoprire determinati ruoli:  
    • Un certo numero di giocatori diventa la mafia. Ogni notte, ogni mafioso sceglie un giocatore. All'alba del giorno successivo, il giocatore scelto dal maggior numero di mafiosi viene ucciso. Vengono definitivamente rimossi dal gioco e il loro ruolo viene rivelato pubblicamente. Mafia-allineati.  
    • Alcuni giocatori diventano poliziotti. Ogni notte, ogni poliziotto sceglie un giocatore. All'alba del giorno successivo, il poliziotto viene a conoscenza dell'allineamento di quel giocatore. Village-allineati.  
    • Un certo numero di giocatori diventa medico. Ogni notte, ogni medico sceglie un giocatore. Se questo giocatore è lo stesso giocatore che la mafia ha scelto di uccidere, le azioni della mafia per quella notte vengono annullate. Village-allineati.  
    • Tutti i giocatori che non sono scelti per un altro ruolo sono abitanti del villaggio. I villici non hanno abilità che non sono condivise da tutta la città. Village-allineati.
  • Ogni giorno tranne il giorno 0, l'intera città (cioè tutti i giocatori viventi) vota per un giocatore. Alla fine della giornata, quel giocatore viene rimosso dal gioco e il loro ruolo viene rivelato. (Il giorno 0, tutti si rilassano fino al calar della notte.)
  • Se, in qualsiasi momento, non ci sono mafiosi rimanenti, il gioco termina con tutti i giocatori allineati al villaggio vittoriosi (inclusi i morti).
  • Se, in qualsiasi momento, i giocatori allineati al villaggio non superano in numero i giocatori allineati alla mafia, il gioco termina con tutti i giocatori allineati alla mafia vittoriosi (inclusi i morti).

Per questa sfida, il tuo obiettivo è quello di scrivere un robot per battere altri robot in Mafia!

Come creare un robot funzionante

Tutto quello che dovete fornire per me è un file chiamato run. All'interno della struttura di directory in cui si svolgerà questa sfida, il tuo bot vivrà qui:

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/

Il runfile, una volta eseguito, farà sì che il tuo bot faccia la sua parte. È importante notare che questo file non deve richiedere argomenti della riga di comando o altro. Verrà eseguito esattamente come ./run. Se devi essere eseguito in un modo diverso, dovrai aggirare il problema facendo qualcosa del genere:

real_bot.py

#!/bin/python2

# code goes here

run

#!/bin/bash

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

Una cosa importante da notare è che tutti gli input ricevuti dal tuo bot saranno trovati nel file from_servere il programma di controllo cercherà l'output del tuo bot to_server. Ho scelto di farlo in questo modo in modo che qualsiasi lingua in grado di eseguire l'I / O dei file sia in grado di partecipare. Se la tua lingua semplifica il lavoro con stdin e stdout rispetto agli I / O dei file, potresti voler scrivere un runfile simile al seguente:

#!/bin/bash

./real_bot.py < from_server > to_server

Questo lo farà in modo che stdin provenga dal from_serverfile e stdout vada direttamente a to_server.

Il tuo bot non rimarrà in esecuzione per la durata del gioco. Invece, verrà eseguito quando deve prendere una decisione. Allo stesso modo, non verrà informato quando è morto, semplicemente non verrà più eseguito. Pianifica questo salvando tutto ciò che vuoi ricordare in un file e leggendolo in seguito. È possibile creare, scrivere o leggere da qualsiasi file nella cartella del proprio bot, ma non è possibile scrivere o leggere ovunque al di fuori di quella cartella, incluso l'accesso alla rete o altro . Se il tuo bot sa qualcosa che non è stato detto all'interno della cartella o se tocca qualcosa che non è all'interno di quella cartella, il tuo bot viene squalificato.

Come creare un bot funzionale

Giorno

All'inizio del gioco, il file playersverrà riempito con un elenco delimitato da una nuova riga di tutti i giocatori nel gioco. Non verrà aggiornato man mano che i giocatori lasciano il gioco.

All'alba del giorno 0, tutti i giocatori troveranno questo messaggio nel loro from_serverfile:

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

Se sei il poliziotto, la linea You are the copviene aggiunta alla fine. Il dottore vede You are the doctor. La mafia vede You are a member of the mafia.\nYour allies are:e un elenco delimitato da newline di membri della mafia, escluso il giocatore che legge il messaggio.

All'alba di tutti gli altri giorni, apparirà questo messaggio:

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`

dayNumberviene sostituito con il numero del giorno. victimviene sostituito con il nome della vittima della scorsa notte ed victim_roleè uno dei seguenti:

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

cop_targetè il nome del giocatore su cui il poliziotto ha indagato ieri sera ed target_alignmentè villageo mafia. Infine, remaining_playersè un elenco di giocatori che sono ancora vivi in ​​questo formato:player1, player2, player3

La seconda riga viene omessa se non è stata uccisa la notte scorsa e la terza riga viene mostrata solo al poliziotto.

Per esempio,

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

Una volta che questo messaggio è finito, la giornata inizia! Ogni bot può compiere 50 azioni durante il giorno, in cui una "azione" sta votando un giocatore o dicendo qualcosa ad alta voce.

Per votare un giocatore, scrivi vote player_namesul tuo to_serverfile e termina. Per votare per non uccidere nessuno, scrivi vote no one. Quando voti, vedranno tutti i giocatori (incluso te) your_bot votes to kill your_selection. I voti vengono ignorati il ​​giorno 0.

Un numero di messaggi predefiniti può essere inviato a tutti i giocatori. L'ID di ogni possibile messaggio è elencato qui:

 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?

Tutti questi messaggi, tranne i primi cinque, si riferiscono a un giocatore specifico. Per dire uno di quei messaggi, scrivi say message_id player_name. Per uno dei primi cinque messaggi, basta scrivere say message_id. Puoi aggiungere un terzo argomento opzionale a entrambi, specificando il nome di un giocatore con cui stai parlando (tutti i giocatori possono ancora leggerlo, ma sapranno chi è il destinatario previsto).

Quando il tuo bot dice un messaggio, tutti i giocatori leggono your_bot says "message", dov'è messageil messaggio associato con l'id che hai scritto. Se il messaggio include un oggetto, uno spazio e l'oggetto vengono inseriti direttamente dopo la fine del messaggio. Se include un destinatario, il loro nome, i due punti e uno spazio sono inseriti immediatamente prima del messaggio.

Alla fine della giornata, tutti i giocatori viventi vengono lanciati un'ultima volta per vedere il risultato del voto. Se un giocatore è stato eliminato, questo è scritto:

The town has killed player_name!
They were a villager

... o a mafioso, o the cop, o the doctor.

Se nessun giocatore è stato eliminato, viene invece scritto:

The town opted to lynch no one today.

Quando il controller invia questi messaggi, ignora qualsiasi risposta dei giocatori. La giornata è finita

Notte

Di notte, tutti tranne gli abitanti del villaggio usano il loro potere.

Mafia:

Leggerai It is night. Vote for a victim.. Quando ciò accade, genera il nome del giocatore che desideri uccidere.

Poliziotto:

Leggerai It is night. Who would you like to investigate?. Quando ciò accade, emetti il ​​nome del giocatore che desideri controllare.

Medico:

Leggerai It is night. Who would you like to save?. Quando ciò accade, genera il nome del giocatore che desideri proteggere.

Dopo questo, il giorno successivo inizia normalmente.

Puoi salvarti solo una volta per partita.

Informazione generale

  • Il gioco non funzionerà senza 6 o più giocatori.
  • Un terzo dei giocatori, arrotondato per difetto, sarà mafioso. Un giocatore sarà un medico e un giocatore sarà un poliziotto. Tutti gli altri giocatori sono abitanti del villaggio.
  • I legami nel voto del villaggio o nel voto durante la notte della mafia vengono risolti casualmente.
  • I nomi dei bot devono essere alfanumerici + trattini e trattini bassi.
  • È vietato utilizzare direttamente la conoscenza del codice dell'avversario. In teoria, dovrei essere in grado di mettere il tuo bot contro i robot che non hai mai visto prima e farlo comparare.
  • Purtroppo, se non riesco a far funzionare il tuo programma utilizzando esclusivamente software gratuito (come nella birra), dovrò squalificarlo.
  • Mi riservo il diritto di squalificare qualsiasi invio se ritengo che sia dannoso. Ciò include, ma non si limita all'utilizzo eccessivo di tempo, memoria o spazio per l'esecuzione. Ho lasciato intenzionalmente il limite, ma ricorda: sto eseguendo questo sul mio computer di casa, non un supercomputer, e non voglio ottenere risultati che impiegheranno un anno. Non mi aspetto di doverlo usare, poiché i miei standard sono piuttosto bassi. Questo è fondamentalmente "se penso che tu sia un coglione apposta", e se puoi convincermi altrimenti invertirò la mia decisione.

punteggio

Ad ogni round, verranno lanciati 100 giochi (questo può aumentare quando più bot si uniscono per mantenere la dimensione del campione abbastanza grande, ma in teoria ciò non influirà su nulla). Annuncerò quante volte ogni bot vince come villico rispetto a quante volte gioca come villico e lo stesso per la mafia. Un bot villager_ratioè number of games won as villager / number of games played as villagered mafia_ratioè lo stesso ma s/villager/mafia/g. Il punteggio di un bot è (villager_ratio - mean villager_ratio) + (mafia_ratio - mean mafia_ratio).

Esempio di bot

Randy the Robot non è un buon giocatore di mafia. Randy ignora praticamente tutto, scegliendo a caso cosa dire, chi votare e chi prendere di mira con poteri notturni.

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

controllore

@undergroundmonorail ha scritto un programma di controllo per questa sfida, disponibile qui .

Hai un mese per programmare e consegnare le risposte, darò al bot vincente (il più alto tasso di vincita è il voto) almeno un premio di 50 reputazione (a seconda di quanto rappresentante posso guadagnare in un mese)


Ecco uno script wrapper, creato da @Blacksilver, da usare con i linguaggi compilati:

#!/bin/bash

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

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

Metti questo run.


Questo post è stato scritto da @undergroundmonorail (ho apportato alcune modifiche).

Lo ha lasciato qui a chiunque volesse finire e pubblicarlo.


I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat .
Martin Ender,

Risposte:


3

zulù

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);
    }
}

Non tutto quello che speravo fosse. Potrei finire per modificarlo di tanto in tanto.

Come funziona v1.0

Tiene traccia del numero del giorno, chi è vivo, chi è morto, chi è mafia, che è allineato al villaggio, ruoli, voti / messaggi del giorno corrente e voti / messaggi complessivi.

  1. Notte

    un. Mafia: vota per ogni abitante del villaggio che ha votato contro la mafia (in modo casuale) se possibile, altrimenti un villico a caso.

    b. Poliziotto - Indaga su chiunque abbia un allineamento sconosciuto.

    c. Dottore: salva il primo turno, poi salva il poliziotto se noto (non credo che possa mai saperlo da ora in poi), salva il villico se noto (probabilmente neanche questo lo sa), altrimenti salva una persona a caso.

  2. Giorno

    un. Se qualcuno ha pronunciato un messaggio direttamente a se stesso, rispondigli (sono possibili risposte limitate).

    b. Mafia - Vota per il villico che ha più voti.

    c. Conquistatore con qualsiasi noto allineato mafioso noto - vota per mafioso.

    d. Un abitante del villaggio con un solo allineamento di mafia morto noto - vota per un robot casuale che non ha mai votato per il mafioso.

    e. Conoscitore di poliziotto noto - vota per bot casuale per cui il poliziotto ha votato.

    f. Contadino con morto allineato al villaggio noto: vota per un robot casuale che ha votato per i morti.

    g. Gli abitanti dei villaggi con voti contrari all'auto-voto per il bot non allineato ai villaggi attualmente più votato.


1
Aspetta, cosa fa questo?
SIGSTACKFAULT

1
Ma gioca alla mafia, ovviamente! :)
Jo.

Intendo la strategia.
SIGSTACKFAULT

6

Il codice di esempio non ha funzionato per me, io uso Python 3, quindi ho cambiato il main.pyfile per farlo funzionare.

Quindi ecco la mia versione fissa per Python 3, non avevo mai programmato in Python prima, quindi forse è un codice orribile ma funziona :)

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

Alcune cose che ho imparato mentre facevo questo lavoro (e non era chiaro per me nella descrizione)

  • printnon fa nulla con il gioco è come un console.logjs
  • input() blocca il programma in esecuzione può essere utile per il debug passo dopo passo
  • from_servered to_serverè eliminato ad ogni round.
  • È impossibile interrompere la sceneggiatura con una Ctrl+Ccombinazione, il che è fastidioso.

Benvenuti in PPCG! Ottimo primo post! Spero che rimani in giro! Ho modificato il tuo post per evidenziare la sintassi funzionante e per motivi di coerenza ho aggiunto a run.sh.
Rɪᴋᴇʀ

1
Grazie! Non sono sicuro che < from_server > to_serversia necessario perché ho codificato i nomi dei file nel codice. il motore di gioco chiama semplicemente ./runsenza pipe. così input()e print()non ha funzionato con il gioco. mayn.pylinea 57:os.system('./run')
Peter,

2
Come hai fatto a far funzionare il controller? Non riesco a capirlo. Potete fornire una chiamata di esempio?
Rɪᴋᴇʀ

Nota: l'originale è randy.pystato scritto in Python 2 , che ha causato i problemi.
SIGSTACKFAULT

per il controller è necessario ./startdalla cartella originale o è necessaria una versione di Python 3 dimain.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)

Fantasioso, lungo mazzo di codice Python che non ho intenzione di spiegare (anche se non è golfato), a parte quello che mantiene elenchi di "amici" e "nemici" che sono originariamente popolati in base al caso e / o all'indagine del poliziotto . Attenzione: non mentire alla presenza del logico.


è il tuo run.shstandard (facendo alcuni test)
Stan Strum il

No, il mio run.sh potrebbe essere semplicemente "run.py" senza le solite tubazioni di input e output, ma lo standard funzionerebbe.
pepery il

1
Sembra molto simile a quello che avrei scritto, se avessi avuto il tempo e l'inclinazione.
Draco18s

Per qualche ragione penso che il logico non si comporterà così bene con gli altri robot ... nessuno degli altri robot riferisce le indagini del poliziotto
JavaScriptCoder

1
... e mi rendo conto, mesi dopo, che la mia risposta presuppone erroneamente che ci possa essere solo un poliziotto / dottore.
pppery

4

Survivalist (v 1.0)

Sinossi

Il sopravvissuto sopravvive semplicemente brutalmente al gioco rimproverando chiunque osi accusarlo, indipendentemente dal fatto che sia mafioso o no.

Logica

Se sopravvivi fino alla fine del gioco, vinci qualunque cosa accada. Pertanto, sopravvivi a tutti i costi.

backstory

Le truppe marciarono attraverso l'oscura e umida foresta.

"Tenente, dove stiamo marciando?" Apparentemente la giovane recluta non si era indurita alle atrocità, pensò il comandante. Oh bene. Ha risposto con una brusca "per distruggere il nemico".

Al villaggio, il comandante nemico stava bevendo e ridendo insieme agli altri ufficiali del club quando uno scout si precipitò dentro con la notizia. "C'è una colonna, lunga diverse centinaia di metri, che marcia per noi attraverso la foresta di Yulin! Raduna le truppe!"

Il comandante nemico, ovviamente ubriaco, disse inaspettatamente: "Non ho avuto notizie da altri scout". Lo scout (poi Survivalist) pensò, poi dovrò radunare le truppe da solo . Dopo aver raccontato la storia ai compagni scout, sono tornati insieme, dicendo tutti di aver visto truppe nemiche. Il comandante ancora non credeva, dicendo: "Io sto ordinando di sospendere scouting. Non ci sono alcun truppe nemiche".

Gli scout hanno deciso di procurarsi le armi per salvare la comunità. Sono riusciti a raggiungere le loro posizioni proprio quando il nemico è arrivato nel villaggio in vigore. "CARICA!" urlò il comandante dell'imboscata. "BRUCIA LE CASE! BRUCIA LE CASE! Uccidi TUTTI, COMPRESI LE DONNE EI BAMBINI! "

Gli esploratori hanno salvato il loro intero esercito. Si aspettavano promozioni, premi e medaglie. Invece, ottennero una corte marziale truccata per ammutinamento, condanna, 10 anni di prigione, dimissioni disonorevoli dall'esercito e dall'esilio.


C'è un anziano anziano nel consiglio comunale di Salem, nel Massachusetts. La leggenda narra che abbia fondato la città. Quando lo incontri nella sua casetta isolata nella foresta, non lasciare che il luccichio nei suoi occhi ti faccia pensare che sia tranquillo. Se lo accusi, ti rovinerà di fronte alla città.

Il veterano rise nell'oscurità. Paura del buio, assolutamente no. Paura dei mostri sotto il letto? L'uomo con la mano sul grilletto di una pistola rise nervosamente. Non aveva paura di niente, si era detto. Certo, era un eroe del tempo di guerra passato, ma era così abituato alle imboscate e alle situazioni potenzialmente letali che rendeva l'uomo semplicemente nevrotico. Il dito del grilletto si contrasse a semplici ombre; il battito del suo cuore accelerò ad ogni piccolo suono. Sì, era così spaventato dalla morte. Come ha potuto non vedere così tante persone morire in modi orribili? Tutto ciò che sapeva di essere stato rapito e sfuggire miracolosamente ai suoi nemici era che non c'era pietà.

Veterano


Codice (sono un novellino in Python, non sono sicuro che il codice sia buono)

#!/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

Intendevi orinvece di ||? L'hai provato? Inoltre, dovresti probabilmente sottolineare che è Python 2.
Solomon Ucko

3

Avatar

Avatar "casualmente" sceglie un giocatore all'inizio e li concentra incessantemente per il resto del round.

Questo non è un riferimento a uno spettacolo televisivo animato con lo stesso nome.

È un riferimento online EVE.

Scarica tar di tutti i file richiesti

changelog

  • Compleanno v1
  • v2 Non registra nulla su stdout, solo su stderr.
    Per sopprimere stderranche, aggiungere 2>/dev/nullalla fine del runfile.
/*  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);
    }
}

Richiede mafia.ce mafia.h, librerie che ho scritto, nella stessa directory.

Questi sono inclusi nel download, insieme a un Makefile e uno script di esecuzione.

FARE

  • Smetti di votare contro il bersaglio quando vengono uccisi o linciati.

Mentre sono qui, invierò il non-bot, Steve:


Cordiali saluti, io chiamo dibs su avatar, erebus, leviathan, eragnarok
SIGSTACKFAULT

"Questo non è un riferimento a uno spettacolo televisivo animato con lo stesso nome." è un riferimento al film?
Stan Strum il

@StanStrum no, non lo è.
SIGSTACKFAULT,

Il from_serverfile del mio bot non viene scritto. Hai dovuto impostare autorizzazioni specifiche o altro?
Rɪᴋᴇʀ

1
Nota per i curiosi: le Scritture citate qui sono quelle degli Amarr di EVE Online. V'è una Rivelazione 2:12 nella Bibbia, ma si legge piuttosto diverso.
DLosc,

2

Leviatano

Leviathan esegue un'iterazione su tutti i giocatori nel playersfile e li bersaglia uno per uno.

Scaricare

/*  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);
}

Come con Avatar, richiede mafia.ce mafia.hnella stessa directory.

Questi sono inclusi nel download, insieme a un Makefile e uno script di esecuzione.


:) aggiungendo sopravvivenza una volta im finito con esso
JavaScriptCoder
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.