Caveman Duels (ou: Me cutucá-lo com uma vara afiada)


151

Homem das cavernas louco. Outro homem das cavernas pega pau, mas pau era para mim. Luta do homem das cavernas !


Descrição

Homem das cavernas precisa de uma vara afiada para esfaquear outro homem das cavernas. Outro homem das cavernas também tenta esfaquear com uma vara afiada. O homem das cavernas pode afiar o bastão, cutucar com o bastão ou bloquear palitos enfiados.

Se um homem das cavernas cutucar outro homem das cavernas com uma vara afiada, outro homem das cavernas foge e me ganha. Mas se outro homem das cavernas bloquear com inteligência quando eu cutucar, nada acontecerá, a não ser que meu pau fique embotado e eu precise afiar novamente.

Homem das cavernas preguiçoso. Além disso, homem das cavernas burro. O homem das cavernas não sabe o que fazer, portanto, o homem das cavernas precisa de um programa de computador techno sofisticado para dizer ao homem das cavernas o que fazer.

Entrada

A entrada do seu programa será uma história dos eventos que aconteceram, onde Ssignifica afiar (ou seja, o homem das cavernas afiou o graveto), Psignifica cutucar e Bsignifica bloquear. A entrada será um histórico de ambos os lados (você e o oponente); portanto, os movimentos do seu e do oponente serão separados por vírgula ( ,).

Exemplo de entrada:

SPB,SBB

Isso significa que o jogador afiou o taco, depois cutucou, bloqueou e o oponente afiou, bloqueou e bloqueou novamente.

Você não receberá nenhuma entrada no turno 1.

Resultado

A saída é muito semelhante à entrada (porque o homem das cavernas não é muito inteligente). Seu programa deve ser exibido Spara nitidez, Pcutucada e Bbloco. Somente o primeiro caractere da saída será levado em consideração e qualquer outra entrada será tratada como um Bcomando (bloco).

  • S: afiar

    Ao afiar, a nitidez do bastão do homem das cavernas aumenta em 1 e o bastão recebe 1 cutucada extra. Cada puxão reduz a nitidez do bastão em 1 e se a nitidez do bastão é 0, é muito chato para mexer. A nitidez começa em 0. Se a nitidez chegar a 5, o bastão é uma espada! (Ver abaixo.)

    Se o oponente cutucar enquanto você está afiando (e tem nitidez> 0), o oponente vence!

  • P: cutucar

    Ao cutucar, a nitidez do bastão do homem das cavernas diminui em 1 e você cutuca o seu oponente! Se seu oponente está afiando, você ganha! Se o oponente estiver cutucando, seu taco bate no taco do oponente e os dois ficam mais opacos (por 1 "unidade de nitidez"). Se o oponente estiver bloqueando, nada acontece, exceto que seu taco fica mais tedioso.

    Se você cutucar quando a nitidez do seu bastão for 5 ou maior, ele se tornará uma espada e você sempre vencerá! (A menos que seu oponente também tenha uma espada e também escolha P; nesse caso, ambos ficam mais opacos e podem reverter para paus se a nitidez cair abaixo de 5.)

    Você não pode cutucar com uma nitidez de 0. Se o fizer, nada acontecerá.

  • B: quadra

    Quando você bloqueia, nada acontece quando seu oponente cutuca. Se seu oponente não estiver cutucando, o bloco não fará nada.

    O bloqueio não protege contra uma espada, mesmo que você também tenha uma!

Regras e restrições

Regras adicionais são:

  • Seu programa pode ler e gravar arquivos em sua própria pasta (sem roubo!) Se você quiser salvar dados, mas não puder acessar nada fora dele (e os homens das cavernas não têm conexão com a Internet no deserto).
    • Nota importante sobre os arquivos : Se você salvar os arquivos, lembre-se de salvá-los no diretório players/YourBotsName/somefile.foo! O diretório de trabalho atual do seu programa não será do seu programa!
  • Homens das cavernas são justos: um programa não pode ter código específico para outro programa, e os programas não podem ajudar um ao outro. (Você pode ter vários programas, mas eles não podem interagir de forma alguma.)
  • O juiz do homem das cavernas não é paciente. Se os homens das cavernas fizerem mais de 100 turnos cada um para decidir um vencedor, o juiz ficará entediado e os dois homens das cavernas perderão.

Se o seu programa infringir uma regra ou não seguir a especificação, o programa será desqualificado, removido playerlist.txte todos os duelos serão reiniciados desde o início. Se o seu programa for desqualificado, o líder do homem das cavernas (eu!) Comentará a postagem do programa e explicará o motivo. Se você não está infringindo nenhuma regra, seu programa será adicionado à tabela de classificação. (Se o seu programa não está na tabela de classificação, não há comentários explicativos na sua postagem e você postou seu programa antes da hora da "Última atualização" abaixo, informe ao líder do homem das cavernas! Talvez ele tenha esquecido.)

Na sua postagem, inclua:

  • Um nome.
  • Um comando shell para executar o seu programa (ex. java MyBot.java, ruby MyBot.rb, python3 MyBot.py, Etc.).
    • Nota: a entrada será anexada a isso como um argumento de linha de comando.
    • Os homens das cavernas usam o Ubuntu 14.04, portanto, verifique se o seu código funciona (livremente) nele.
  • Um número de versão, se o seu código funcionar de maneira diferente em versões diferentes do idioma escolhido.
  • Seu código (obviamente).
  • Como compilar o código, se necessário.

Código / teste do controlador, exemplo bot

O líder do homem das cavernas escreveu o código de controle em C ++ e o publicou em um repositório do Github . Você pode executar e testar seu programa lá.

Um programa muito, muito simples (1 linha!) Também é publicado nas respostas abaixo .

Pontuação e placar

Marcar é fácil. Qualquer que seja o homem das cavernas, ganha um ponto. O homem das cavernas com mais pontos após 3 duelos contra todos os outros homens das cavernas se torna o novo líder das cavernas!

150     Watson
147     SpeculativeSylwester
146     Gruntt
141     BashMagnon
126     ChargerMan
125     PrisonRules
124     ViceLeader
122     MultiMarkov
122     CaveDoctor
120     RegExMan
120     Hodor
117     FancyTechnoAlgorithm
116     Semipatient
113     Watcher
108     BobCaves
105     MinimaxMan
104     Oracle
102     MaybeMarkov
97      Nash
95      Sicillian
95      Feint
95      Basilisk
94      SharpMan
93      Darwin
91      Nigel
91      JavaMan
88      Entertainer
88      CarefulBot
85      CaveMonkey
84      SSBBP
82      SirPokealot
79      MasterPoker
77      Unpredictable
76      IllogicalCaveman
75      SharpenBlockPoke
75      HuddleWolfWithStick
72      WoodenShield
68      PokeBackBot
68      PatientBlacksmith
66      PatientWolf
58      MonteCarloMan
58      BlindFury
56      BinaryCaveman
55      PokeBot
55      CavekidBlocks
53      Swordmaster
53      Blocker
52      NakedEarlyNerd
52      ModestCaveman
50      LatePokeBot
40      Trickster
39      SwordLover
38      ForeignCaveman
36      Swordsmith *
28      Touche
27      WantASword
27      FoolMeOnce
24      PeriodicalCavemanCicada
11      Aichmophobic

(este placar foi gerado automaticamente)

Jogadores marcados com um *lançaram algum tipo de erro ou exceção em algum momento; esses jogadores também têm um comentário em suas postagens.

Os jogadores que não puderam ser incluídos nos testes por qualquer motivo (estes jogadores terão um comentário sobre as suas mensagens explicando o problema): Monkey, Elephant, FacileFibonacci, StudiousSylwester.

Última atualização: 3 de agosto às 00:15 (UTC).


Estou surpreso que ninguém parece ter tentado encontrar a estratégia minimax ainda. Parece a coisa mais óbvia a se fazer.
user2357112

@ user2357112 Não acho que o minimax seja uma melhoria aqui. Quero dizer, você pode projetar uma implementação minimax, mas como a lógica é muito simples, o mesmo comportamento exato pode ser expresso com uma máquina de estados finitos. (ou seja, o bot nunca afiará até que o oponente fique opaco, porque, se o fizer, o movimento minimizador do oponente será cutucar e você perderá, o bot sempre bloqueará até termos uma espada, porque o movimento maximizador do bot sempre ser para bloquear, etc.)
HuddleWolf

3
Muitas das entradas parecem permitir nitidez negativa em seus cálculos. As regras escritas dizem que nada acontece quando você cutuca com nitidez zero. Esse "nada" também significa que sua nitidez permanece zero, em vez de ser diminuída?
Sparr

6
Isso precisa estar aqui: dresdencodak.com/comics/2009-09-22-caveman_science_fiction.jpg Talvez isso aconteça com a imaginação. :)
Evi1M4chine

2
Isso ainda está aberto? Vejo pessoas adicionando novos envios, mas não vejo a tabela de classificação sendo atualizada.
ASCIIThenANSI

Respostas:


35

Darwin - C

Quem precisa de estratégia, afinal? Peça a um grupo de homens das cavernas que se aproximem e deixe a seleção natural fazer o resto!


Usamos um modelo muito simples para descobrir o cérebro primitivo do homem das cavernas: ele não tem memória e leva em consideração apenas a nitidez do bastão dele e de seu oponente. Essas são usadas como variáveis ​​para um polinômio binário de alguma ordem finita. Cada ação (bloco, nitidez e puxão) possui um polinômio associado cujo resultado determina a probabilidade relativa de escolher essa ação. Isso é praticamente tudo o que existe - comece com alguns coeficientes aleatórios e otimize iterativamente.

O bot:

#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/* magic numbers */
#define SWORD_SHARPNESS 5
#define PROGRAM_DIM 4 /* polynomial order + 1 */
#define DEFAULT_FILENAME "players/Darwin/program"

typedef double real;
typedef real program[PROGRAM_DIM][PROGRAM_DIM];
typedef program caveman_brain[3];

typedef char action; /* S, B or P */
/* encodes a pair of actions */
#define ACTION_PAIR(a1, a2) (((int)(a1) << (sizeof(action) * 8)) | (a2))

real eval_program(const program p, double x, double y) {
    real v = 0;
    int i, j;

    for (i = 0; i < PROGRAM_DIM; ++i) {
        real w = 0;
        for (j = 0; j < PROGRAM_DIM; ++j)
            w = x * w + p[i][j];
        v = y * v + w;
    }

    if (v < 0)
        v = 0;
    return v;
}
void read_program(FILE* f, program p) {
    int i, j;
    for (i = 0; i < PROGRAM_DIM; ++i) {
        for (j = 0; j < PROGRAM_DIM; ++j) {
            double v;
            fscanf(f, "%lg", &v);
            p[i][j] = v;
        }
    }
}

int blunt(int* s) {
    int temp = *s;
    if (temp)
        --*s;
    return temp;
}
void sharpen(int* s) { ++*s; }
/* takes two sharpness/action pairs and updates the sharpness accordingly.
 * returns negative value if first caveman wins, positive value if second
 * caveman wins and 0 otherwise. */
int act(int* s1, action a1, int* s2, action a2) {
    switch (ACTION_PAIR(a1, a2)) {
        case ACTION_PAIR('B', 'B'): return 0;
        case ACTION_PAIR('B', 'S'): sharpen(s2); return 0;
        case ACTION_PAIR('B', 'P'): return blunt(s2) >= SWORD_SHARPNESS ? 1 :
                                                                          0;
        case ACTION_PAIR('S', 'B'): sharpen(s1); return 0;
        case ACTION_PAIR('S', 'S'): sharpen(s1); sharpen(s2); return 0;
        case ACTION_PAIR('S', 'P'): sharpen(s1); return *s2 > 0 ? 1 : 0;
        case ACTION_PAIR('P', 'B'): return blunt(s1) >= SWORD_SHARPNESS ? -1 :
                                                                          0;
        case ACTION_PAIR('P', 'S'): sharpen(s2); return *s1 > 0 ? -1 : 0;
        case ACTION_PAIR('P', 'P'): {
            int t1 = blunt(s1), t2 = blunt(s2);
            if (t1 >= SWORD_SHARPNESS && t2 < SWORD_SHARPNESS)
                return -1;
            else if (t2 >= SWORD_SHARPNESS && t1 < SWORD_SHARPNESS)
                return 1;
            else
                return 0;
        }
    }
}
/* processes a pair of strings of actions */
int str_act(int* s1, const char* a1, int* s2, const char* a2) {
    for (; *a1 && *a2; ++a1, ++a2) {
        int winner = act(s1, *a1, s2, *a2);
        if (winner)
            return winner;
    }
    return 0;
}

double frandom() { return (double)rand() / RAND_MAX; }

/* chooses an action based on self and opponent's sharpness */
action choose_action(const caveman_brain b, int s1, int s2) {
    double v[3];
    double sum = 0;
    double r;
    int i;
    for (i = 0; i < 3; ++i) {
        v[i] = eval_program(b[i], s1, s2);
        sum += v[i];
    }
    r = frandom() * sum;
    if (r <= v[0])
        return 'B';
    else if (r <= v[0] + v[1])
        return 'S';
    else
        return 'P';
}

/* portable tick-count for random seed */
#ifdef _WIN32
#include <Windows.h>
unsigned int tick_count() { return GetTickCount(); }
#else
#include <sys/time.h>
unsigned int tick_count() {
    struct timeval t;
    gettimeofday(&t, NULL);
    return 1000 * t.tv_sec + t.tv_usec / 1000;
}
#endif

int main(int argc, const char* argv[]) {
    const char* filename = DEFAULT_FILENAME;
    const char *a1, *a2;
    FILE* f;
    caveman_brain b;
    int s1 = 0, s2 = 0;
    int i;

    srand(tick_count()); rand();

    a1 = argc > 1 ? argv[1] : "";
    if (*a1) {
        a2 = strchr(a1, ',');
        if (a2 == NULL) {
            printf("invalid input!\n");
            return 1;
        }
        ++a2;
    } else
        a2 = a1;

    if (argc > 2)
        filename = argv[2];

    f = fopen(filename, "r");
    if (f == NULL) {
        printf("failed to open `%s'\n", filename);
        return 1;
    }
    for (i = 0; i < 3; ++i)
        read_program(f, b[i]);
    fclose(f);

    str_act(&s1, a1, &s2, a2);
    printf("%c\n", choose_action(b, s1, s2));

    return 0;
}

Compilar com: gcc darwin.c -odarwin -w -O3. Corra com: ./darwin <history>.

O bot lê os coeficientes de um arquivo nomeado programno players/Darwindiretório (um arquivo diferente pode ser especificado como um segundo argumento da linha de comando). Este programa parece se sair bem:

0.286736 0.381578 -0.128122 1.33933 
0.723126 0.380574 1.21659 -0.9734 
0.924371 0.998632 -0.0951554 0.744323 
-0.113888 -0.321772 -0.260496 -0.136341 

0.280292 -0.699782 -0.246245 1.27435 
-1.24563 -0.959822 -0.745656 0.0347998 
-0.917928 -0.384105 0.319008 -0.70434 
0.484375 0.802138 0.0967234 0.638466 

0.406679 0.597322 1.39409 0.902353 
-0.735946 0.742589 0.955567 0.643268 
-0.503946 0.446167 1.002 0.328205 
0.26037 0.113346 0.0517265 -0.223298 

Salvar como players/Darwin/program.

A seguir está um programa que gera programarquivos que podem ser usados ​​pelo bot (não precisa ser compilado se você usar o programarquivo acima):

#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/* magic numbers */
#define SWORD_SHARPNESS 5
#define MAX_TURN_COUNT 100
#define PROGRAM_DIM 4 /* polynomial order + 1 */
#define CAVEMAN_COUNT 500
#define GENERATION_COUNT 12
#define DUEL_COUNT 8
#define ERROR_BACKOFF 0.5
#define DEFAULT_FILENAME "players/Darwin/program"

typedef double real;
typedef real program[PROGRAM_DIM][PROGRAM_DIM];
typedef program caveman_brain[3];

typedef char action; /* S, B or P */
/* encodes a pair of actions */
#define ACTION_PAIR(a1, a2) (((int)(a1) << (sizeof(action) * 8)) | (a2))

real eval_program(const program p, double x, double y) {
    real v = 0;
    int i, j;

    for (i = 0; i < PROGRAM_DIM; ++i) {
        real w = 0;
        for (j = 0; j < PROGRAM_DIM; ++j)
            w = x * w + p[i][j];
        v = y * v + w;
    }

    if (v < 0)
        v = 0;
    return v;
}
void write_program(FILE* f, const program p) {
    int i, j;
    for (i = 0; i < PROGRAM_DIM; ++i) {
        for (j = 0; j < PROGRAM_DIM; ++j)
            fprintf(f, "%g ", p[i][j]);
        fprintf(f, "\n");
    }
    fprintf(f, "\n");
}

int blunt(int* s) {
    int temp = *s;
    if (temp)
        --*s;
    return temp;
}
void sharpen(int* s) { ++*s; }
/* takes two sharpness/action pairs and updates the sharpness accordingly.
 * returns negative value if first caveman wins, positive value if second
 * caveman wins and 0 otherwise. */
int act(int* s1, action a1, int* s2, action a2) {
    switch (ACTION_PAIR(a1, a2)) {
        case ACTION_PAIR('B', 'B'): return 0;
        case ACTION_PAIR('B', 'S'): sharpen(s2); return 0;
        case ACTION_PAIR('B', 'P'): return blunt(s2) >= SWORD_SHARPNESS ? 1 :
                                                                          0;
        case ACTION_PAIR('S', 'B'): sharpen(s1); return 0;
        case ACTION_PAIR('S', 'S'): sharpen(s1); sharpen(s2); return 0;
        case ACTION_PAIR('S', 'P'): sharpen(s1); return *s2 > 0 ? 1 : 0;
        case ACTION_PAIR('P', 'B'): return blunt(s1) >= SWORD_SHARPNESS ? -1 :
                                                                          0;
        case ACTION_PAIR('P', 'S'): sharpen(s2); return *s1 > 0 ? -1 : 0;
        case ACTION_PAIR('P', 'P'): {
            int t1 = blunt(s1), t2 = blunt(s2);
            if (t1 >= SWORD_SHARPNESS && t2 < SWORD_SHARPNESS)
                return -1;
            else if (t2 >= SWORD_SHARPNESS && t1 < SWORD_SHARPNESS)
                return 1;
            else
                return 0;
        }
    }
}
/* processes a pair of strings of actions */
int str_act(int* s1, const char* a1, int* s2, const char* a2) {
    for (; *a1 && *a2; ++a1, ++a2) {
        int winner = act(s1, *a1, s2, *a2);
        if (winner)
            return winner;
    }
    return 0;
}

double frandom() { return (double)rand() / RAND_MAX; }
double firandom() { return 2.0 * rand() / RAND_MAX - 1.0; }

/* chooses an action based on self and opponent's sharpness */
action choose_action(const caveman_brain b, int s1, int s2) {
    double v[3];
    double sum = 0;
    double r;
    int i;
    for (i = 0; i < 3; ++i) {
        v[i] = eval_program(b[i], s1, s2);
        sum += v[i];
    }
    r = frandom() * sum;
    if (r <= v[0])
        return 'B';
    else if (r <= v[0] + v[1])
        return 'S';
    else
        return 'P';
}

typedef struct {
    caveman_brain brain;
    int sharpness;
    int score;
} caveman;
void init_caveman(caveman* c, const caveman* m, double e) {
    int p, i, j;
    c->score = 0;
    for (p = 0; p < 3; ++p) {
        for (i = 0; i < PROGRAM_DIM; ++i) {
            for (j = 0; j < PROGRAM_DIM; ++j) {
                c->brain[p][i][j] = m->brain[p][i][j] + firandom() * e;
            }
        }
    }
}
int duel(caveman* c1, caveman* c2) {
    int winner;
    int turn;
    c1->sharpness = c2->sharpness = 0;
    for (turn = 0; turn < MAX_TURN_COUNT; ++turn) {
        winner = act(&c1->sharpness,
                     choose_action(c1->brain, c1->sharpness, c2->sharpness),
                     &c2->sharpness,
                     choose_action(c2->brain, c2->sharpness, c1->sharpness));
        if (winner)
            break;
    }
    if (winner < 0)
        ++c1->score;
    else if (winner > 0)
        ++c2->score;
    return winner;
}

/* portable tick-count for random seed */
#ifdef _WIN32
#include <Windows.h>
unsigned int tick_count() { return GetTickCount(); }
#else
#include <sys/time.h>
unsigned int tick_count() {
    struct timeval t;
    gettimeofday(&t, NULL);
    return 1000 * t.tv_sec + t.tv_usec / 1000;
}
#endif

int main(int argc, const char* argv[]) {
    const char* filename = DEFAULT_FILENAME;
    FILE* f;
    caveman* cavemen;
    caveman winner;
    int gen;
    double err = 1.0;
    int i;

    srand(tick_count()); rand();
    memset(&winner, 0, sizeof(caveman));

    if ((cavemen = (caveman*)malloc(sizeof(caveman) * CAVEMAN_COUNT)) == NULL) {
        printf("not enough memory!\n");
        return 1;
    }

    for (gen = 0; gen < GENERATION_COUNT; ++gen) {
        int i, j, k;
        const caveman* leader;

        printf("[Gen. %d / %d] ", gen + 1, GENERATION_COUNT);
        fflush(stdout);

        for (i = 0; i < CAVEMAN_COUNT; ++i)
            init_caveman(&cavemen[i], &winner, err);

        for (i = 0; i < CAVEMAN_COUNT; ++i) {
            for (j = i + 1; j < CAVEMAN_COUNT; ++j) {
                for (k = 0; k < DUEL_COUNT; ++k)
                    duel(&cavemen[i], &cavemen[j]);
            }
        }

        leader = cavemen;
        for (i = 1; i < CAVEMAN_COUNT; ++i) {
            if (cavemen[i].score > leader->score)
                leader = &cavemen[i];
        }

        printf("Caveman #%d wins with %d victories in %d duels\n",
               leader - cavemen + 1,
               leader->score, (CAVEMAN_COUNT - 1) * DUEL_COUNT);

        memcpy(&winner, leader, sizeof(caveman));
        err *= ERROR_BACKOFF;
    }

    free(cavemen);

    if (argc > 1)
        filename = argv[1];
    printf("Dumping brain to `%s'\n", filename);
    f = fopen(filename, "w");
    if (f == NULL) {
        printf("failed to open `%s'\n", filename);
        return 1;
    }
    for (i = 0; i < 3; ++i)
        write_program(f, winner.brain[i]);
    fclose(f);

    return 0;
}

Compilar com: gcc genprog.c -ogenprog -w -O3. Corra com: ./genprog [output-filename].


Watson

Qual é o DNA de um homem das cavernas vencedor? Talvez esse cara tenha a resposta:

# That's the actual logic. Initialization goes below.
def run():
    if his_sharpness[-10] - turn / 15 + 1 + turn % 3 - his_sharpness[-6] < 0:
        act(B=0, S=0, P=100) # 7.21% chance
    elif his_sharpness[-6] + 1 - his_sharpness[-2] < 0:
        act(B=0, S=0, P=100) # 4.15% chance
    elif his_history[-3] - my_history[-1] <= 0 and my_sharpness[-1] - turn / 10 <= 0:
        act(B=0, S=100, P=0) # 11.34% chance
    elif his_sharpness[-1] == 0:
        act(B=0, S=100, P=0) # 27.84% chance
    else:
        act(B=100, S=0, P=0) # 49.46% chance

# Boring stuff go here...

import sys, random

# Actions
block, sharpen, poke, idle = range(4)

# Converts textual history to internal format
def convert_history(textual_history):
    return ["BSP".index(action) for action in textual_history]

# Calculates sharpness after performing an action sequence
def calculate_sharpness(history):
    return history.count(sharpen) - history.count(poke)

# Returns a list containing the sharpness at the end of each turn
def sharpness_history(history):
    return [calculate_sharpness(history[:i + 1]) for i in range(len(history))]

# Acts based on the probability distribution (B%, S%, P%)
def act(B, S, P):
    r = random.random() * 100
    print "BSP"[(r >= B) + (r >= B + S)]

# Setup data
textual_history = sys.argv[1] if len(sys.argv) > 1 else ","
my_history, his_history = (convert_history(h) for h in textual_history.split(','))
my_sharpness, his_sharpness = (sharpness_history(h) for h in (my_history, his_history))
turn = len(my_history)
my_history, his_history = ([idle] * 16 + h for h in (my_history, his_history))
my_sharpness, his_sharpness = ([0] * 16 + s for s in (my_sharpness, his_sharpness))

# Make a move
run()

Correr com: python Watson.py

Watson é o produto de um algoritmo genético. Ao contrário de Darwin, o dado genético desta vez é um programa real, escrito em uma pequena linguagem específica de domínio (aqui traduzida para Python).


Sequência simples vence grandes jogadores

Esse amiguinho se sai surpreendentemente (ou talvez não tão surpreendentemente), especialmente contra os líderes:

import sys
print "Simple Sequence Beats Big Players".split(' ')[
    len(sys.argv[1]) / 2 % 5 if len(sys.argv) > 1 else 0
]

Correr com: python SSBBP.py


Como faço para compilar e executar isso? Além disso, conforme mencionado na pergunta, você só pode ler / gravar arquivos no players/Darwindiretório.
Maçaneta

@ Doorknob: fixo.
DarwinBot

Estou recebendo esses erros de compilação ao compilar esse código. (Eu estou no Ubuntu 14.04.)
Doorknob

@ Doorknob: Fixed. Deve funcionar agora.
DarwinBot

Agora estou conseguindo undefined reference to `fmax'. --Edit-- Não importa, eu realmente precisava -lm.
Maçaneta

50

Homem das cavernas imprevisível

me, he = (ARGV[0] || ' , ').split(',')

@possible_actions = %w[Sharpen Poke Block]

class String

  def sharpness
    @sharpness ||= count('S') - count('P')
  end

  def has_pointy_stick
    (1..4).cover? sharpness
  end

  def has_sword
    sharpness >= 5
  end

  def scary
    sharpness > 0
  end

end

def no action
  @possible_actions.delete(action)
end

def do!
  puts @possible_actions.sample[0]
end

no 'Block' if not he.has_pointy_stick

no 'Poke' if not me.scary

no 'Sharpen' if me.has_sword

no 'Block' if me.has_sword

do!

Esse homem das cavernas escolhe aleatoriamente a cada rodada, mas expliquei a ele com muita simplicidade que certas ações simplesmente não fazem sentido às vezes. Sinta-se livre para copiar esse código se desejar expressar uma lógica diferente.

Este é Ruby, salve como 'imprevisível.rb' e execute com ruby unpredictable.rb


Na verdade, acho que no 'Block'também deve ser se meu oponente tiver uma espada.
Njzk2

O primeiro não 'Block' realmente cobre isso: um pau pontudo não é uma espada.
histocrat

2
Por que você não usa unlessas declarações no 'Block'e no 'Poke'? ( no 'Block' unless he.has_pointy_stick)
wchargin

25

Cave Doctor - Lua

"Eu perco para novos estrangeiros, nocauteei-os para estudá-los"

Quando você vê tantos pacientes quanto o médico da caverna, começa a entender verdadeiramente a psique do homem das cavernas (ou pelo menos espero). O jogo do médico da caverna é pura estratégia, ele espera cutucadas que ele bloqueia na tentativa de desarmar seu oponente, mas não deixa que esse oponente se aproxime de fazer uma espada. Ele tenta prever quando é seguro afiar para não perder a vantagem.

caveman={havePointyStick=function (t)     
   local pointy=0   
   for i in t.stick:gmatch("[SP]") do
    if i=="S" then 
      pointy=pointy+1
    elseif pointy>0 then
      pointy=pointy-1
    end   
   end 
 t.sharp=pointy>0
 t.lastmove=t.stick:sub(t.stick:len())
 return pointy 
 end,
    Stupid=function (stick)--I put way to much effort in this...
      o = {} 
      setmetatable(o, caveman)
      o.smartness=0
      o.stick=stick
      caveman.__index = caveman
      return o
    end,
     Smart= function (stick)
      o ={} 
      setmetatable(o, caveman)
      o.smartness=100
      o.stick=stick
      caveman.__index = caveman
      return o
    end
       }


    if arg[1]==nil then  
       print("S")
    else   
      split=arg[1]:find(",")  
      me=caveman.Smart(arg[1]:sub(0,split-1)) 
      he=caveman.Stupid(arg[1]:sub(split+1)) 
      mesharp=me:havePointyStick()  
      hesharp=he:havePointyStick()
      if not he.sharp and mesharp<5 then print("S")--Go for the sword  
      elseif mesharp>4 or me.stick:len()>93 then
         if (mesharp>0) then print("P")--We're losing/about to win or time's running out
         else print("S")--uh-oh
         end
      else 
         u,g,h=he.stick:match("(B+)S+(B+)S+(B+)$")
         g,u,h=he.stick:match("(P+)S+(P+)S+(P+)$")
         if u~=nil and u==g and g==h then 
            if not me.sharp then print("S")
            else print("P")
            end
         elseif me.stick:match("SBSB$")~=nil then print("B")
         elseif he.stick:len()>7 and he.stick:match("P")==nil and me.lastmove~="S" then print("S")
         else
         b,u,h=he.stick:match("(B*)(S+)(B*)$")
         if u~=nil then
             if (h:len()>3 and me.lastmove=="B") or (b:len()>h:len() and b:len()>0 and h:len()>0) then print("S")
             else print("B")
             end
          else print("B")
          end   
      end   
   end 
end

Correr com: lua CaveDoctor.lua


3
Isso perde apenas duas vezes no ranking atual? oO
justhalf

A revisão 5 gera vários erros; portanto, a revisão 4 é a incluída na atual rodada de tentativas.
Maçaneta

@ Doorknob Acho que corrigi todos eles, houve apenas uma alteração na lógica real de qualquer maneira.
Nexus

20

ForeignCaveman

ForeignCaveman não faz ideia do que você acabou de dizer. Ele apenas ... faz coisas.

javac ForeignCaveman.java então java ForeignCaveman

public class ForeignCaveman {

    public static void main(String[] args) {
        int m = (int) (Math.random()*3);
        switch(m) {
            case 0: System.out.println('B'); 
                    break;
            case 1: System.out.println('P'); 
                    break;
            case 2: System.out.println('S'); 
                    break;
        }
   }
}

11
Provavelmente isso tem muitos votos positivos pelo quão ruim ele é #
Kevin L

19

Vice líder

Maçaneta da porta ♦ é líder. Eu quero ser líder! Siga o programa super inteligente para se tornar líder!

Compilar: javac ViceLeader.javaExecutar: java ViceLeader.

public class ViceLeader {

    public static void main(String[] args) {
        if (args.length == 0 || !args[0].contains(",")) {
            System.out.print("S");
            return;
        }
        String[] history = args[0].split(",");
        int mySharpness = getSharpness(history[0]);
        int enemySharpness = getSharpness(history[1]);

        // enough sharpness to strike until end of game
        if (100 - history[0].length() <= mySharpness) {
            System.out.print("P");
            return;
        }

        // sharpen while secure
        if (enemySharpness == 0) {
            System.out.print("S");
            return;
        }

        // enemy blocks the whole time and I didn't use this tactic on last turn
        if (isBlocker(history[1]) && history[0].charAt(history[0].length() - 1) != 'S') {
            System.out.print("S");
            return;
        }

        // TAKE HIM OUT!
        if (enemySharpness == 4 || mySharpness >= 5) {            
            System.out.print("P");
            return;
        }

        // enemy sharpens the whole time => sharpen to strike on next turn
        if (isSharpener(history[1])) {
            System.out.print("S");
            return;
        }

        System.out.print("B");
    }

    private static int getSharpness(String history) {
        int sharpness = 0;
        for (char move : history.toCharArray()) {
            if (move == 'S') {
                sharpness++;
            } else if ((move == 'P' && sharpness > 0) || move == '^') {
                sharpness--;
            }
        }
        return sharpness;
    }

    private static boolean isBlocker(String history) {
        if (history.length() < 3) {
            return false;
        }
        for (int i = history.length() - 1; i > history.length() - 3; i--) {
            if (history.charAt(i) != 'B') {
                return false;
            }
        }
        return true;
    }

    private static boolean isSharpener(String history) {
        if (history.length() < 3) {
            return false;
        }
        for (int i = history.length() - 1; i > history.length() - 3; i--) {
            if (history.charAt(i) != 'S') {
                return false;
            }
        }
        return true;
    }
}

Por que isso não é if (enemySharpness <= 4 || mySharpness >= 5)vs ==?
durron597

@ durron597 Porque eu só quero cutucar o inimigo se ele puder fazer uma espada no próximo turno (o que ele provavelmente fará). O VizeLeader não cutuca com frequência, mas na hora certa .
CommonGuy

Mas você tem uma espada e seu oponente não ...
durron597 30/07

@ durron597 Não, é uma declaração OR. Significa "cutucar o oponente se eu tiver uma espada OU se ele tiver uma espada em breve".
CommonGuy

7
Oh Deus. Tempo para obter uma xícara de café :) Ou novas lentes de contato
durron597

15

Talvez Markov 2.1

Acho que ele usa cadeias de Markov para prever o que o outro homem das cavernas fará, mas apenas olhei brevemente a página da Wikipedia sobre cadeias de Markov e decidi que tinha muito texto.

Ele tenta permanecer vivo por 30 rodadas e, em seguida, constrói uma mesa com as atuais mudanças de estado atuais e reage ao que pensa que o outro homem das cavernas fará.

O código contém muitas instruções desnecessárias, mas funciona muito bem.

EDITAR

Detectou uma falha na lógica. Agora ele realmente faz alguma coisa quando tem uma espada.

$ python3 players/MaybeMarkov/MaybeMarkov.py

import sys, itertools
from operator import itemgetter
from collections import defaultdict

SHARPEN, POKE, BLOCK, HALP = 'SPB?'

all_actions = SHARPEN, POKE, BLOCK
always = 1

def do(action):
    print(action)
    exit(0)

if len(sys.argv) < 2:
    do(SHARPEN)

class status:
    def __init__(self, actions):
        self.step = len(actions)
        self.last = actions[-1]
        self.sh = self.sharpness = actions.count(SHARPEN) - actions.count(POKE)
        self.dull = self.sharpness <= 0
        self.has_sword = self.sharpness >= 5
        self.actions = actions
        self.ratio = {act:actions.count(act)/self.step for act in all_actions}
        self.can_do = set(all_actions)

        if self.dull:
            self.can_do.remove(POKE)

    def can(self, action):
        return action in self.can_do


me, he = map(status, sys.argv[-1].split(','))
turns = me.step

if he.has_sword:
    if me.can(POKE)                :do(POKE)
    if always                      :do(SHARPEN)

if me.has_sword:
    if he.last != POKE and me.last == BLOCK :do(POKE)
    if he.can(POKE)                :do(BLOCK)
    if always                      :do(POKE)

if not he.can(POKE)                :do(SHARPEN)

if turns <= 4                      :do(BLOCK)
if turns < 30:
    if he.ratio[SHARPEN] == 1:
        if me.can(POKE)            :do(POKE)
        if always                  :do(SHARPEN)
    if always                      :do(BLOCK)

if turns > 97:
    do(POKE)

def react_on(action):
    do({
        HALP    : BLOCK,
        SHARPEN : POKE,
        POKE    : BLOCK,
        BLOCK   : SHARPEN
    }[action])

states = tuple(itertools.product(all_actions, all_actions))
change = defaultdict(lambda:defaultdict(lambda:0))
count  = defaultdict(lambda:0)

for i in range(1, turns):
    prev = me.actions[i-1], he.actions[i-1]
    now  = me.actions[i]  , he.actions[i]
    change[prev][now] += 1
    count[prev] += 1

current = change[me.last, he.last]
prediction = HALP

if len(current) is 0:
    do(BLOCK)

if len(current) is 1:
    if tuple(current.values())[0] > turns / 7:
        prediction = tuple(current.keys())[0][1]

counts = itemgetter(1)

if len(current) > 1:
    key1, value1 = max(current.items(), key=counts)
    current[key1] *= 0.9
    key2, value2 = max(current.items(), key=counts)
    if key1 == key2:
        prediction = key1[1]

react_on(prediction)

14

PeriódicoCicadaCaveman

Este homem das cavernas bastante inteligente estudou um certo bug e percebeu que ninguém pode ajustar seu estilo de vida para aproveitar o número primo da cigarra.

Esconde / bloqueia a maior parte da vida, mas ocasionalmente cutuca. Claro que é vulnerável às Espadas e passa um ciclo inteiro com um graveto não afiado, mas afiando-o quando é totalmente sem corte? Isso é exatamente o que os outros esperam dele ... não esta cigarra

compilar: mcs program.cs para executar o mono program.exe

public class PeriodicalCicadaCaveman
{
  const int Periodic = 13; //Could be 17
  public static void Main(string[] args)
  {
    if (args.Length == 0) 
    {
          System.Console.WriteLine("S");
          return;
    }
    var arg1 = args[0];
    if(arg1.Length == 0) 
    {
        //Always start with a sharp stick
        System.Console.WriteLine("S");
        return;
    }
    var myHistory = arg1.Split(',')[0];
    var theirHistory = arg1.Split(',')[1];
    int sharpness = 0;
    int timeElapsed =  myHistory.Length;

    for(int i = 0; i < timeElapsed; i++)
    {
        if(myHistory[i] == 'S')  
        {
            sharpness++;
        }
        if(myHistory[i] == 'P')
        {
            sharpness--;
        }
    }

    if((myHistory.Length % 13) == 0 
            || timeElapsed > 90 // Running out of time! To hell with the routine
        )
    {
        //The Secada strikes!
        if(sharpness > 1)
        {
            System.Console.WriteLine("P");
            return;
        }
        else
        {
            System.Console.WriteLine("S"); 
            return;
        }
    }
    System.Console.WriteLine("B"); 

  }

}

Edit: Alterou o código sharpness-- ... se eu cutucar ou ganhar ou meu pau ficar mais tonto

Edit2: Adicionado na sugestão de Bobs

Edit: Alterado para cutucar apenas quando estiver com nitidez 2, se o pau estiver em zero, o outro cara poderá fazer uma espada.


1
Estou rodando no Ubuntu; isso irá compilar sob Mono? Em caso afirmativo, como faço para compilar e como faço para executá-lo?
Maçaneta

Para ser sincero, não sei. Estou prestes a ir para a cama. Posso reescrevê-lo para Java amanhã de manhã no trabalho. O código Java deve ser quase idêntico.
21714 Mikey Mouse

5
O @Doorknob mcs program.csirá compilá-lo, mono programexecutá-lo, mas você precisará substituir os foo.Dump();s por System.Console.WriteLine(foo);(ou adicionar um método de extensão public static void Dump(this string value) { System.Console.WriteLine(value); }).
Bob

@ Bob Obrigado, amigo, eu adicionei no seu método de extensão.
Mikey Mouse

Desculpe, o nome do arquivo padrão atual mcsgerado é <filename>.exe, por exemplo, program.csse tornaria program.exe. Então, o comando run seria mono program.exe. (Eu não tinha acesso a mono no momento do meu comentário anterior.)
Bob

14

FancyTechnoAlgorithm

Um algoritmo de techno chique para o programa de computador techno chique.

O homem das cavernas continua a perder a batalha. Homem das cavernas com raiva. Então o homem das cavernas vai para a escola de informática aprender a criar algoritmo.

import random, sys  # Need import some advanced techno code

if __name__ == '__main__':  # If fancy techno computer program is main

    try:  # Me try use fancy techno algorithm!

        me, he     = sys.argv[1].split(",")
        mePointy   = me.count("S") - me.count("P")
        hePointy   = he.count("S") - he.count("P")
        meCanPoke  = mePointy > 0
        heCanPoke  = hePointy > 0
        meHasSword = mePointy >= 5
        heHasSword = hePointy >= 5
        meScary    = meCanPoke + meHasSword 
        heScary    = heCanPoke + heHasSword

        # Me donno fancy coding math algoritm.
        # Math confuse. Me code work, me happy.
        if he[-6:] == "SB"*3:
            print "SP"[meCanPoke]
        elif (len(he) > 30 and he[-3:].count("B") > 2) or \
             (hePointy > 2 and he.count("SSBB") > 0 and he.count("BBS") > 0):
            if meHasSword:
                print "P"
            else:
                print "SB"[me[-1] == "S"]
        elif hePointy > 3 and he.count("BBS") > 2:
            print "SP"[me[-1] == "S"]
        else:
            print random.choice(\
                [["S", "SP", "P" ],\
                 ["B", "B" , "P" ],\
                 ["S", "P" , "P" ]][heScary][meScary])

    except:  # Fancy techno algorithm Failed... Me just sharpen.
        print "S"

Programa Python 2. Para correr:python fancytechnoalgorithm.py


Isso interrompe quando não há entrada (ou seja, no primeiro turno). Não sei como você quer lidar com isso, então vou ter que excluí-lo da primeira rodada de testes.
Maçaneta

@Doorknob Para a primeira entrada, é "," ou ""? Eu acho que é o último disso.
Vetorizado

Para a primeira entrada, não haverá argumentos (será executado como python StickSharpener.py).
Maçaneta

@Doorknob Eu o editei. Veja se funciona agora.
Vetorizado

Tudo bem, obrigado! Vou incluir isso na próxima rodada de testes.
Maçaneta

14

O vigia

Ele observa os movimentos de seu oponente, sempre deixando que eles mostrem suas mãos antes que ele ataque. Ele está particularmente preparado para aqueles que negligenciam trabalhar em direção a uma espada.

import sys, random

if len(sys.argv) > 1:
    history_self, history_other = sys.argv[1].split(',')
else:
    history_self = history_other = ""

def sharpness(history):
    ret = 0
    for action in history:
        if action == 'S':
            ret += 1
        elif action == 'P' and ret > 0:
            ret -= 1
    return ret

def weighted_random(dict):
    i = random.randrange(sum(dict.values()))
    for k, v in dict.items():
        i -= v
        if i < 0:
            return k

def action(history_self, history_other):
    sharpness_self = sharpness(history_self)
    sharpness_other = sharpness(history_other)
    if sharpness_self >= 5:
        return 'P'
    elif sharpness_other == 0:
        return 'S'  #Guaranteed safe
    elif sharpness_other == 1:
        #If the opponent isn't interested in a sword, time is on our side
        block_count = len(history_self) - len(history_self.rstrip('B'))
        if block_count > 3 and random.randrange(block_count) > 3:
            return 'S'
        else:
            return 'B'
    elif sharpness_other >= 5:
        return 'S'
    else:
        #Search for a weakness
        for i in range(10, 2, -1):
            if history_other[-i:] == history_other[-i*2:-i]:
                predicted_action = history_other[-i]
                if predicted_action == 'S':
                    if sharpness_self > 0:
                        return 'P'
                    else:
                        return 'S'
                elif predicted_action == 'B':
                    return 'S'
                elif predicted_action == 'P':
                    return 'B'
        #Presumably the opponent is random - respond with some educated randomness
        if sharpness_self == 0:
            return random.choice(['S','S','B'])
        return weighted_random({
            'S': sharpness_self,
            'B': 1,
            'P': sharpness_other,
        })

if __name__ == "__main__":
    print(action(history_self, history_other))

Nome do arquivo: watcher.py

Para correr: python watcher.py

Basilisco

Procura destruir aqueles que olham para ele com muita atenção. Consistentemente vence o Observador, mas provavelmente se sairá pior no geral.

import sys, random

if len(sys.argv) > 1:
    history_self, history_other = sys.argv[1].split(',')
else:
    history_self = history_other = ""

def sharpness(history):
    ret = 0
    for action in history:
        if action == 'S':
            ret += 1
        elif action == 'P' and ret > 0:
            ret -= 1
    return ret

def action(history_self, history_other):
    sharpness_self = sharpness(history_self)
    sharpness_other = sharpness(history_other)
    if sharpness_self >= 5:
        return 'P'
    elif len(history_self) < 13:
        return 'SBBSBPSBBSBPP'[len(history_self)]
    elif 5 + 5 * sharpness_self < random.randrange(len(history_self)):
        return 'S'
    elif sharpness_other == 0:
        if sharpness_self == 0 or random.randrange(sharpness_self) == 0:
            return 'S'
        else:
            return 'P'
    elif sharpness_other == sharpness_self:
        return 'P'
    else:
        return 'B'

if __name__ == "__main__":
    print(action(history_self, history_other))

Nome do arquivo: basilisk.py

Para correr: python basilisk.py

Nash

Procura tornar irrelevantes as escolhas de seu oponente, escolhendo cada jogada com uma probabilidade que explique seus riscos e recompensas

import sys, random

if len(sys.argv) > 1:
    history_self, history_other = sys.argv[1].split(',')
else:
    history_self = history_other = ""

movemap = [ [(1.000000,0.000000),(0.473863,0.526137),(0.394636,0.605364),(0.490512,0.509488),(1.000000,0.000000)],
        [(0.695328,0.000000,0.304672),(0.275953,0.582347,0.141700),(0.192635,0.700391,0.106974),(0.196343,0.689662,0.113995),(0.289968,0.544619,0.165413)],
        [(0.570635,0.000000,0.429365),(0.236734,0.570126,0.193139),(0.167197,0.687133,0.145670),(0.173139,0.667169,0.159693),(0.264911,0.475316,0.259773)],
        [(0.490512,0.000000,0.509488),(0.196309,0.578888,0.224803),(0.135744,0.692358,0.171898),(0.140638,0.663397,0.195965),(0.220709,0.426989,0.352302)],
        [(1.000000,0.000000,0.000000),(0.147944,0.636760,0.215296),(0.089478,0.737358,0.173165),(0.087259,0.704604,0.208137),(0.128691,0.435655,0.435655)]  ]

def sharpness(history):
    ret = 0
    for action in history:
        if action == 'S':
            ret += 1
        elif action == 'P' and ret > 0:
            ret -= 1
    return ret

def action(history_self, history_other):
    sharpness_self = sharpness(history_self)
    sharpness_other = sharpness(history_other)
    if sharpness_self >= 5:
        return 'P'
    elif sharpness_other >= 5:
        return 'S'
    moves = movemap[sharpness_self][sharpness_other]
    v = random.random()
    if v < moves[0]:
        return 'S'
    elif v < moves[0] + moves[1]:
        return 'B'
    else:
        return 'P'

if __name__ == "__main__":
    print(action(history_self, history_other))

Este não é exatamente o equilíbrio de Nash (meu gerador de estratégia tem alguma instabilidade), mas está próximo.

Por uma questão de curiosidade, aqui estão as estimativas de qual a probabilidade desse bot vencer em cada estado do jogo:

map = [ [0.50000000,0.26337111,0.15970733,0.08144046,0.00000000,0.00000000],
        [0.73662889,0.50000000,0.37879183,0.28035985,0.16622410,0.00000000],
        [0.84029267,0.62120817,0.50000000,0.39441630,0.26038353,0.00000000],
        [0.91855954,0.71964015,0.60558370,0.50000000,0.35246401,0.00000000],
        [1.00000000,0.83377590,0.73961647,0.64753599,0.50000000,0.00000000],
        [1.00000000,1.00000000,1.00000000,1.00000000,1.00000000,0.50000000] ]

Nome do arquivo: nash.py

Para correr: python nash.py

Finta, simulação, fingimento, falsa ação

Abre com um ataque rápido, para testar as defesas de seu oponente.

import sys, random

if len(sys.argv) > 1:
    history_self, history_other = sys.argv[1].split(',')
else:
    history_self = history_other = ""

def sharpness(history):
    ret = 0
    for action in history:
        if action == 'S':
            ret += 1
        elif action == 'P' and ret > 0:
            ret -= 1
    return ret

def action(history_self, history_other):
    sharpness_self = sharpness(history_self)
    sharpness_other = sharpness(history_other)
    if sharpness_self >= 5:
        return 'P'
    elif len(history_self) < 2:
        return 'SP'[len(history_self)]
    elif history_other[1] == 'P':
        # Fierce fight
        if sharpness_self == 0:
            return 'S'
        elif history_self[-(1 + history_self.count('P'))] == 'S':
            return 'P'
        else:
            return 'B'
    else:
        # Smart guy
        if sharpness_other == 1:
            return 'B'
        elif history_self[-1] != 'S' or history_self[-4:] == 'BSBS':
            return 'S'
        elif history_other.count('S') > history_other.count('B'):
            return 'P'
        else:
            return 'B'

if __name__ == "__main__":
    print(action(history_self, history_other))

Nome do arquivo: feint.py

Para correr: python feint.py

LatePokeBot

Irmão mais novo de PokeBot. Nunca mostra fraqueza, mas tenta lutar como seu irmão mais velho.

import sys, random

if len(sys.argv) > 1:
    history_self, history_other = sys.argv[1].split(',')
else:
    history_self = history_other = ""

def sharpness(history):
    ret = 0
    for action in history:
        if action == 'S':
            ret += 1
        elif action == 'P' and ret > 0:
            ret -= 1
    return ret

def action(history_self, history_other):
    sharpness_self = sharpness(history_self)
    return 'SSP'[sharpness_self]

if __name__ == "__main__":
    print(action(history_self, history_other))

Nome do arquivo: latepokebot.py

Para correr: python latepokebot.py


Faltava um :no Basilisk; Eu consertei isso para você
Maçaneta da porta

Esse envio gerou algum tipo de erro ou exceção em algum momento; convém consertar isso antes da próxima rodada de testes. (a do Basilisco)
Maçaneta da porta

@ Doorknob Eu escolhi a sequência inicial do Basilisk, observando as suposições feitas por The Watcher e Cave Doctor e encontrando uma sequência que faria essas suposições darem muito errado. Isso viola a regra "homens das cavernas são justos"?
Brilliand

Vai Nash! Ganhe exatamente metade das suas partidas contra todos os bots inteligentes o suficiente para evitar suas opções de P = 0!
aschepler

12

PokeBot

Escrito em Ruby.

puts((ARGV.shift || "P,").match(/(.),/)[1] == "P" ? "S" : "P")

Corra com ruby pokebot.rb.

Este bot não é muito inteligente; faz sobre o que o homem das cavernas médio faria sozinho de qualquer maneira.


9

PatientWolf v2.0

Afia se estiver sem brilho, cutuca se o inimigo tiver uma espada no próximo turno ou se o inimigo estiver sem brilho, bloqueia o contrário.

my ($me,$him) = split(/,/,$ARGV[0]);
if(!defined $me) {
    print "S";
    exit;
}
my $mysharpness =()= ($me =~ /S/g);
$mysharpness -= ($me =~ /P/g);
my $opponentsharpness =()= ($him =~ /S/g);
$opponentsharpness -= ($him =~ /P/g);
if($mysharpness == 0) {
    print "S";
} elsif($opponentsharpness <= 0 || $opponentsharpness == 4) {
    print "P";
} else {
    print "B";
}

Correr com

perl patientwolf.pl

EDIT: obrigado a @sylwester por apontar um erro


Como você obtém apenas um argumento com os dois históricos separados por vírgula, está analisando-o incorretamente. Por exemplo. PatientWolf.pl SB,SPfaz uma Pvez que pensa que tem uma vara afiada.
27414 Sylwester

@Sylwester não está correto. A primeira linha atribui o primeiro argumento para mim e para o segundo argumento para US $-lhe $
killmous

O programa CavemanDuel não usa dois argumentos, apenas um. por exemplo. perl patientwolf.pl "SB,SP". Você deveria fazer my($me,$him) = split/,/ $ARGV[0];e if( @ARGV ) {print "S";exit}.
Sylwester 27/07

@Sylwester ok Eu vejo o que você está recebendo. Isso não ficou claro no OP ou no olhar rápido que eu lancei no código do controlador. Vou consertar isso em breve
killmous

9

Homem das cavernas binário

Afiar, Facada, Repetir

Baseado na idéia de que o bloqueio é para mariquinhas, esse homem das cavernas alterna entre as duas opções restantes.

public class BinaryCaveman { 

    public static void main(String[] args) {
        int timelapse = 0;
        if(args.length>0)
        {
            timelapse = ((args[0].length() - 1) / 2);
        }
        switch(timelapse % 2) 
        {
            case 0: System.out.println('S'); 
                    break;
            case 1: System.out.println('P'); 
                    break;
        }
    }
}

Ajuntar com javac BinaryCaveman.java

Correr com java BinaryCaveman

Edição: aventuras em matrizes de seqüência de caracteres ..... args.length () lança um erro. args.length sempre retorna 1. args [0] .length () retorna os comprimentos da primeira string na matriz.

EDIT 2: Atualizado graças à ajuda da Maçaneta da porta, Brilliand e Sylwester. Obrigado rapazes.


@ MartinBüttner Esqueci de dividir args - 1 por 2 para obter apenas o número de envios anteriores por um único jogador. Corrigido isso. Não consigo entender a submissão de Dorknob, rubi é praticamente sem sentido para mim. Ele sempre começa com afiação?
23414 Red 18:19

Sim, ele apenas verifica se sua última jogada foi Pou Sfaz o oposto. E se ainda não há história, ele finge que a história seria P,(o que o leva a fazer Sprimeiro).
Martin Ender

Duas abordagens diferentes que resultam na mesma saída. Isso é contra as regras?
21414 Red 18:22

Provavelmente não, eu só gostaria de informá-lo.
Martin Ender

2
@ Doorknob Eu acho que deveria ser args[0].length(), não args.length.
Brilliand

8

CavekidBlocks

Um garoto da caverna chorando e assustado pode parecer uma presa fácil. Não deixe o rosto bonito dele te enganar, porque ele sabe como bloquear.

import sys, math, random
def count(a):
    s = 0
    for i in range(len(a)):
        if a[i] == 'P': s-=1
        elif a[i] == 'S': s+=1
        if s < 0: s = 0
    return s
kid = []
scary_adult = []
what2do = 'Sharpen the Stick! Why not? Adult may be doing the same. DONT trust adults!'
if len(sys.argv) > 1:
    kid, scary_adult = sys.argv[1].split(",")
    kid_stick_sharpness = count( kid )
    scary_adult_stick_sharpness = count( scary_adult )
    if (scary_adult_stick_sharpness >= 2):
        what2do = "Block! Block! Block! Adult's stick looks scary sharp."
    elif (kid_stick_sharpness > 0):
        what2do = 'Point your Stick to the adult. It may scary him.'
    else:
        what2do = 'Sharpen the Stick!'

    # Roll d20 for a courage check.
    dice = random.randint(1,20)
    if (dice > 15): what2do = 'Poke the adult! Critical Hit!'
    elif (dice <= 5): what2do = 'Block! Block! Block!'
print(what2do[0])

Correr com python3 cavekidblocks.py

ChargerMan

Este homem das cavernas é muito conservador. Tentará carregar sua arma e só ataca quando necessário.

import sys, math, random
def countSharpness(a):
    s = 0
    for i in range(len(a)):
        if a[i] == 'P': s-=1
        elif a[i] == 'S': s+=1
        if s < 0: s = 0
    return s
def getHistory():
    me = ""
    him = ""
    if len(sys.argv) > 1:
        me, him = sys.argv[1].split(",")
    return me,him
if __name__ == '__main__':
    me, him = getHistory()
    me_s = countSharpness(me)
    him_s = countSharpness(him)
    answer = 'B'
    # First Case
    if (len(me) == 0):
        answer = 'S'
    # I have a sword
    elif (me_s == 5):
        answer = 'P'
    # Cant let he gets a sword
    elif (him_s == 4):
        answer = 'P'
    # His sword is dull
    elif (him_s == 0):
        # He may try to sharp
        # Cant attack? Sharp my stick
        if (me_s == 0): answer = 'S'
        else:
            if (random.randint(0,33) != 0): answer = 'S'
            else: answer = 'P'
    elif (len(him) % 5 == 0):
        # Decide what to do based on the
        # opponent last 3 movements.
        hist = him[-3:]
        # Does he like to block?
        if (hist.count('B') >= 2): answer = 'S'
    print(answer)

Correr com python3 chargerman.py

Malandro

Malandro não sabe lutar, então ele tenta confundir outro homem das cavernas.

import sys, math
a = "PPS"
i = 0
if (len(sys.argv) > 1): i = math.floor(((len(sys.argv[1])-1)/2) % 3)
print(a[i])

Correr com python3 trickster.py

Infelizmente, após a confirmação acc74 , Malandro não funciona como planejado mais.


4
Esse programa trickster é mau
Nexus

@ Nexus eu também. Infelizmente, o Malandro não está indo bem nos duelos.
Wendelbsilva

7

Hodor

Hodor não é muito agressivo. Ele gosta de ficar em seu escudo, a menos que haja uma boa oportunidade para atacar.

compile com: javac Hodor.javae execute com:java Hodor

código:

public class Hodor {
    public static void main(String[] args){

        String previousMoves = null;

        //account for no input
        if(args.length == 0){
            System.out.print('S');
            System.exit(0);
        }else{
            previousMoves = args[0];
        }

        //declare variables
        char action = 'S';
        int enemySharpens = 0, enemyPokes = 0, myPokes = 0, mySharpens = 0;
        String[] movesArray = previousMoves.split(",");
        char[] enemyMoves = movesArray[1].toCharArray(), myMoves = movesArray[0].toCharArray();

        //determine enemy sharpness
        for(int i=0; i<enemyMoves.length; i++){
            if(enemyMoves[i] == 'S'){
                enemySharpens++;
            }else if(enemyMoves[i] == 'P'){
                enemyPokes++;
            }
        }

        //block if opponent can poke, else sharpen
        if(enemySharpens - enemyPokes > 0){
            action = 'B';
        }else{
            action = 'S';
        }

        //determine my sharpness
        for(int i=0; i<movesArray[0].length(); i++){
            if(myMoves[i] == 'P'){
                myPokes++;
            }else if(myMoves[i] == 'S'){
                mySharpens++;
            }
        }

        //poke as much as possible if the game is about to end
        if((mySharpens-myPokes) > (100-enemyMoves.length)){
            action = 'P';
        }

        try{
            //sharpen if opponent blocks 2 times in a row and I didn't just sharpen
            if((enemyMoves[enemyMoves.length-1] == 'B') && (enemyMoves[enemyMoves.length-2] == 'B') && (myMoves[myMoves.length-1] != 'S')){
                action = 'S';
            }
            //poke if opponent sharpens twice in a row
            if((enemyMoves[enemyMoves.length-1] == 'S') && (enemyMoves[enemyMoves.length-2] == 'S')){
                action = 'P';
            }
            //poke if the opponent just sharpened/blocked then poked, has a blunt stick, and my stick isn't blunt
            if((enemyMoves[enemyMoves.length-2] != 'P') && (enemyMoves[enemyMoves.length-1] == 'P') && (enemySharpens-enemyPokes == 0) && (mySharpens - myPokes > 0)){
                action = 'P';
            }
        }catch (ArrayIndexOutOfBoundsException e){
            //not enough info
        }

        //poke if we have a sword
        if(mySharpens-myPokes > 4){
            action = 'P';
        }

        System.out.print(action);
    }
}

Editar: atualização secundária do código


Esse envio gerou algum tipo de erro ou exceção em algum momento; convém consertar isso antes da próxima rodada de testes.
Maçaneta

1
Tente com SB,BB. Quando outros homens das cavernas se comportam mal no primeiro turno, Hodor também se comporta.
27414 Sylwester

7

Sylwester especulativo - Perl5

Sylwester especulativo quer eliminar os caçadores de espadas, observando os padrões e cutucando quando há uma chance de o oponente afiar e afiar quando o mais provável é que o oponente bloqueie. No entanto, ele não fará isso se houver uma chance de ter adivinhado que ele próprio se aguçará na próxima jogada e somos ainda mais cautelosos quando decidimos aguçar.

Quando o oponente é franco, ele tenta ser agressivo, mas acaba economizando para uma espada quando isso parecer infrutífero.

#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;

## Valid operations
my $SHARPEN = "S";
my $POKE    = "P";
my $BLOCK   = "B";

## It will also print resolution to stderr
my $VERBOSE = 0;

my $first_move = not @ARGV;
my ($me, $you) = split(',', $ARGV[0]) unless( $first_move );

## What do I do?
me_do($SHARPEN, "beginning") if $first_move;
me_do($POKE, "end is near") if  almost_over() || sword($me);
me_do($SHARPEN, "you sword") if !sword($me) && sword($you);
me_do($POKE, "you repeat") if consecutive_sharpens($you) && sharp($me);
me_do(blunt_move(), "you blunt stick") if not sharp($you); 
me_do(aggressive_move(), "me think you sharpen") if sharpen_next($you) && !sharpen_next($me);
me_do($SHARPEN, "me think you block") if you_block_next() && very_little_chance_me_sharpen_next();
me_do($BLOCK, "me have no idea you do");

sub almost_over {
  sharp($me) >= (100 - length($you));
}

sub sharp {
  my $history = shift;
  my $sharp = 0;
  foreach my $s ( split('',$history) ) {
    $sharp++ if( $s eq "S");
    $sharp-- if( $s eq "P" && $sharp > 0);
  }
  return $sharp;
}

sub sword {
  my $me = shift;
  sharp($me) >= 5;
}

sub num_pokes {
  my $me = shift;
  $me =~ s/[^P]//g; #/ SO highlight bug?
  length($me);
}

sub consecutive_sharpens {
  my $you = shift;
  $you =~ m/SS+$/
}

sub sharpen_next {
  my $you = shift;
  $you =~ /([^S]+)S\1S\1$/;
}

sub you_block_next {
  $you =~ /([^B]+B*)B\1B\1$/ || $you =~ /B{4}$/;
}

sub very_little_chance_me_sharpen_next {
  $me !~ /S$/ && ( $me !~ /([^S]+)S\1$/ || $me =~ /^SB+SB+$/ ); 
}

sub blunt_move {
  my $sword_move = sword($me) ? $POKE : $SHARPEN;
  ( $me =~ m/(?:PS){5,}/ || sharp($me)*7 < num_pokes($me) ? $sword_move : aggressive_move() );
}

sub aggressive_move {
  sharp($me)? $POKE : $SHARPEN;
}

sub me_do {
  my ($stick_operation, $reason) = @_;
  my $arg = ( $first_move ? "" : "$me,$you" );
  my $resolution = "$stick_operation me do because $reason ($arg)";
  print "$resolution\n";
  err($resolution);
  exit;
}

sub err {
  my($str) = @_;
  print STDERR "SpeculativeSylwester:$str\n" if $VERBOSE;
}

Para rodar no linux, adicione isso no playerlist.txt:

perl players/SpeculativeSylwester/SpeculativeSylwester.pl

Fibonacci fácil - esquema R6RS

Além do primeiro movimento, o Facile Fibonacci bloqueia quando o turn é um número de Fibonacci (a partir de 0) e preenche o resto com PPSS..alterações quando passa 8 para uma sequência interminável de PSSvitórias com uma espada.

#!r6rs
(import (rnrs base)
        (only (rnrs) fold-left display command-line))

(define %SHARPEN "S")
(define %POKE    "P")
(define %BLOCK   "B")

(define (fibonacci? n)
  (let loop ((a 1) (b 1))
    (cond ((> a n) #f)
          ((= a n) #t)
          (else (loop b (+ a b))))))

(define (poke? num-sp)
  (if (< num-sp 8)
      (even? (div num-sp 2))
      (= 2 (mod num-sp 3))))

(define (split-string x)
  (let ((len (div (string-length x) 2)))
    (substring x 0 len)))

(define (num-sp x)
  (fold-left (lambda (a x)
               (if (eqv? x #\B) a (+ a 1)))
               0
               (string->list x)))

(define (advanced-strategy me)
  (cond ((fibonacci? (string-length me)) %BLOCK)
        ((poke? (num-sp me)) %POKE)
        (else %SHARPEN)))

(define (decide args)
  (if (= (length args) 1)
      %SHARPEN
      (advanced-strategy (split-string (cadr args)))))

;; The dirty imperative code:
(display (decide (command-line)))

Para executar, instale o ikarus apt-get install ikaruse adicione-o no playerlist.txt:

ikarus --r6rs-script players/FacileFibonacci/FacileFibonacci.scm

Estudioso Sylwester - Perl5

Sylwester estudioso usa a mesma tática que Sylwester especulativo, mas ele também analisa os jogos anteriores para determinar onde ele pode ter feito uma escolha errada.

#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;

## Valid operations
my $SHARPEN = "S";
my $POKE    = "P";
my $BLOCK   = "B";

## It will also print resolution to stderr
my $VERBOSE = 0;

my $path = $0; # "players/StudiousSylwester/StudiousSylwester.pl";
my $first_move = not @ARGV;
my ($me, $you) = split(',', $ARGV[0]) unless( $first_move );

## What do I do?
me_do($SHARPEN, "beginning") if $first_move;
me_do(consult_history($POKE, "end is near")) if  almost_over() || sword($me);
me_do(consult_history($SHARPEN, "you sword")) if sword($you);
me_do(consult_history($POKE, "you repeat")) if consecutive_sharpens($you) && sharp($me);
me_do(consult_history(blunt_move(), "you blunt stick")) if not sharp($you);
me_do(consult_history(aggressive_move(), "me think you sharpen")) if sharpen_next($you) && !sharpen_next($me);
me_do(consult_history($SHARPEN, "me think you block")) if you_block_next() && very_little_chance_me_sharpen_next();
me_do(consult_history($BLOCK, "me have no idea you do"));

sub almost_over {
  sharp($me) >= (100 - length($you));
}

sub sharp {
  my $history = shift;
  my $sharp = 0;
  foreach my $s ( split('', $history) ) {
    $sharp++ if( $s eq "S");
    $sharp-- if( $s eq "P" && $sharp > 0);
  }
  return $sharp;
}

sub sword {
  my $me = shift;
  sharp($me) >= 5;
}

sub num_pokes {
  my $me = shift;
  $me =~ s/[^P]//g; #/ SO highlight bug?
  length($me);
}


sub consecutive_sharpens {
  my $you = shift;
  $you =~ m/SS+$/
}

sub sharpen_next {
  my $you = shift;
  $you =~ /([^S]+)S\1S\1$/;
}

sub you_block_next {
  $you =~ /([^B]+B*)B\1B\1$/ || $you =~ /B{4}$/;
}

sub very_little_chance_me_sharpen_next {
  $me !~ /S$/ && ( $me !~ /([^S]+)S\1$/ || $me =~ /^SB+SB+$/ );
}

sub blunt_move {
  my $sword_move = sword($me) ? $POKE : $SHARPEN;
  ( $me =~ m/(?:PS){5,}/ || sharp($me)*7 < num_pokes($me) ? $sword_move : aggressive_move() );
}

sub aggressive_move {
  sharp($me)? $POKE : $SHARPEN;
}


sub consult_history {
  my ($suggested_move, $why) = @_;
  my $mylen = length($me);

  # By demanding 5 or more there are 81 (- illegals)
  # different possibilities. Below that and
  # we are shooting in the dark.
  return @_ if( $mylen <= 4 );

  my $override = $suggested_move;
  my @lines = ();
  my %matches      = (P => 0, B=> 0, S=> 0);
  my %match_prefix = (P => 0, B=> 0, S=> 0);
  my $file = "$path.prefix";
  my $sem = "$path.sem";
  my $found_session = 0;

  # Since Judge is running multiple instances at the same time we flock
  open(LOCK, "> $sem") || die ("$path error while open $sem: $!");
  flock(LOCK, 2);

  if( -e $file ) {
    open(FH, $file) || die("$path: error while open $file: $!");

    my $prevyou = substr($you,0,-1);
    while(my $ln = <FH>){
      if ( $ln =~ m/^$me(.).*,$you(.?).*$/ ) {
         # Match that ends here is either a win or a loss depending on my choice
     my $key = ($2 eq "" ? ( $1 eq $POKE ? $SHARPEN : $POKE ) : $2);
     $matches{$key}++;
     $match_prefix{$1}++;
      }
      if( $ln =~ m/^$me,$prevyou$/ ) {
        $found_session++;
    next;
      }
      $found_session++ if( $ln =~ m/^$me.*,$prevyou.*$/ );
      push @lines,$ln;
    }
  }

  my $num_matches = (grep { $matches{$_} != 0 } keys %matches);
  unless( $num_matches || $found_session || $mylen == 5 ) {
    err("WARNING: You have not started this game from the beginning. This will not be a valid outcome! ($me,$you)");
  }

  if( $num_matches == 1 ) {
    my $match_val = (grep { $matches{$_} != 0 } keys %matches)[0];
    if( $match_val eq $BLOCK && !sharp($me)) {
      $override = $SHARPEN;
      $why = "me know u block";
    } elsif ( $match_val eq $SHARPEN ) {
      $override =  aggressive_move();
      $why = "me know u sharpen";
    } elsif ( $match_val eq $POKE && !sword($me) ) { 
      $override = $BLOCK;
      $why = "me know u poke";
    }

  } elsif($num_matches > 1 && $mylen > 6 ) {
    # if the chances are overwelming we are not poked we might as well sharpen
    # if we are wrong here we loose
    if( $matches{$POKE} * 4 < ($matches{$BLOCK}+$matches{$SHARPEN}) && !sword($me)){
      $override = $SHARPEN;
      $why = "me think u block/sharpen";
    }
    # if chances for sharpening is higher than poke/block we go for it with any stick
    if( $matches{$SHARPEN} > 2*($matches{$BLOCK}+$matches{$POKE}) && sharp($me) ) {
      $override = $POKE;
      $why = "me think u sharpen";
    }

    # if the chances for poke is overwelming, we might consider blocking
    if( $matches{$POKE} > 2*($matches{$BLOCK}+$matches{$SHARPEN}) && !sword($me)){
      $override = $BLOCK;
      $why = "me think u poke";
    }
  }

  unless ( $match_prefix{$override} ) {
    open( FH, "> $file") ||     die("$path: error while open $file: $!");
    push @lines, "$me$override,$you\n";
    foreach my $line ( sort @lines ) {
      print FH $line;
    }
  }

  my $stats = join("",map {"$_=>$matches{$_} "} keys %matches);

  if( $override ne $suggested_move ) {
     $why .= ". stats: $stats, original choice: $suggested_move";
  }

  close FH;
  close LOCK;

  return ( $override, $why );
}

sub me_do {
  my ($stick_operation, $reason) = @_;
  my $arg = ( $first_move ? "" : "$me,$you" );
  my $resolution = "$stick_operation me do because $reason ($arg)";
  print "$resolution\n";
  err($resolution);
  exit;
}

sub err {
  my($str) = @_;
  print STDERR "StudiousSylwester:$str\n" if $VERBOSE;
}

Para rodar no linux, adicione-o ao playerlist.txt

perl players/StudiousSylwester/StudiousSylwester.pl

Estudioso editar

Não consigo reproduzir os problemas que você teve por $0não ser o caminho completo para o script perl quando ele é executado com perl. Também retirei suas alterações e não vejo alterações no CavemanDuels src. É o mesmo que corri mais de 20 vezes sem o problema que está relatando. Estou começando a temer que você tenha originado o script como um script bash, em vez de executá-lo enquanto executável ou como um argumento para perl. Preciso de mais informações para realmente ter certeza. Como teste, fiz isso e você pode fazer o mesmo para ver se obtém o mesmo resultado:

echo '#!/usr/bin/perl
print "$0\n\n";' > testcmd.pl;
perl ./testcmd.pl;           # outputs ./testcmd.pl
bash -c "perl ./testcmd.pl"; # outputs ./testcmd.pl
bash -c ./testcmd.pl;        # outputs an error since it's not executable
chmod 755 ./testcmd.pl;
./testcmd.pl;                # outputs ./testcmd.pl
bash -c ./testcmd.pl;        # outputs ./testcmd.pl since it's executable

O esquema não parece querer cooperar comigo na minha máquina, por isso não consegui testar o Fibonacci. Vou continuar tentando fazê-lo funcionar, mas seria ótimo se você pudesse traduzi-lo para outro idioma.
Maçaneta

O estudioso também parece não funcionar, porque $0é bashquando chamado a partir de uma linha de comando do bash (que é feita pelo controlador). Você poderia apenas codificar players/StudiousSylwester/foo.txt, no entanto.
Maçaneta

@ Doorknob Adicionei como instalar ikaruse adicionei meus pensamentos $0para o Studious.
21413 Sylwester

6

Ferreiro

Precisa de vara afiada. Se tiver uma vara afiada, cutucar. Eu não sinto dor.

program Swordsmith
   implicit none
   integer :: mySharp,ierr,arg_count
   logical :: lExist
   character(38) :: filename = "players/Swordsmith/SwordsmithSharp.txt"

! check argument counts for initialization of storage file
   arg_count = command_argument_count()
   if(arg_count == 0) then
      inquire(file=filename,exist=lExist)
      mySharp = 0
      if(lExist) then
         open(unit=10,file=filename,status='replace')
      else
         open(unit=10,file=filename,status='new')
      endif
      write(10,*) mySharp
      close(10)
   endif

! open, read, & close the file for mySharp
   open(unit=10,file=filename,status='old')
   read(10,*) mySharp
   close(10)

! make decision
   if(mySharp < 5) then
      print '(a1)',"S"
      open(unit=10,file=filename,status='replace')
      mySharp = mySharp + 1
      write(10,*) mySharp
      stop
   endif
   print '(a1)',"P"
end program Swordsmith

Salvar como swordsmith.f90e compilar com gfortran -o swordsmith swordsmith.f90, executar como faria com qualquer executável normal: ./swordsmith.


Isso parece imprimir um espaço (``) antes da saída real. Não tenho idéia de como consertar isso, então vou ter que excluir esse envio da primeira rodada de testes.
Maçaneta

Além disso, eu corrigi o caminho do arquivo; Acontece que o diretório de trabalho atual, quando executado, não é do seu programa. Ah, e se por "nova instância" você quer dizer "cada jogo", eu não posso fazer isso porque isso exigiria um revestimento especial do programa do controlador; convém fazer isso em seu próprio código.
Maçaneta

@ Doorknob: Eu atualizei meu código: output é um único caractere, exclui um arquivo já existente na primeira execução e o arquivo está no diretório do player.
Kyle Kanos

Tudo bem, obrigado! Este envio agora está incluído no placar.
Maçaneta

@Doorknob: Cool! Suga que eu não sou o primeiro. Além disso: tenho certeza de que os usuários do Fortran são como vampiros, por isso tenho certeza de que você começará a codificar no Fortran em breve! Muahahahaha!
Kyle Kanos

5

Paciente

Este bot está escrito em R, use Rscript PatientBlacksmith.Rpara acioná-lo.

args <- commandArgs(TRUE)
if(length(args)){
    input <- strsplit(strsplit(args,split=",")[[1]],"")
    me <- input[[1]]
    opponent <- input[[2]]
    sharpness <- 0
    for(i in seq_along(opponent)){
        if(opponent[i]=="S") sharpness <- sharpness + 1
        if(opponent[i]=="P") sharpness <- sharpness - 1
        }
    out <- ifelse(sharpness>0,"B","S")
    bfree <- me[me!="B"]
    r <- rle(bfree) #run length encoding
    S_sequence <- r$length[r$value=="S"]
    P_sequence <- r$length[r$value=="P"]
    if(!length(P_sequence)) P_sequence <- 0
    if(tail(S_sequence,1)==5 & tail(P_sequence,1)!=5) out <- "P"
}else{out <- "S"}
cat(out)

Mede a nitidez do manche do oponente: bloqueia quando afiado, leva tempo para afiar de outra forma. Quando a nitidez própria atingir 5, cutuque até a nitidez desaparecer.


Isso quebra quando não é fornecida nenhuma entrada (ou seja, no primeiro turno); Não sei como consertá-lo, então vou ter que excluí-lo da primeira rodada do teste.
Maçaneta

@Doorknob corrigido.
plannapus

5

Regras da prisão, Haskell

As mulheres das cavernas acham que o homem das cavernas e outros homens das cavernas deveriam conversar, compartilhar o pau. Mas, ei, se precisar lutar, lute contra as regras da prisão. Encontre chefe e ataque.

Vice-líder Alpha Caveman agora; aquele que homem das cavernas deve lutar. Outros homens das cavernas lutam mais tarde. Se meu homem das cavernas perder, não se preocupe; ele também peludo de qualquer maneira.

import System.Environment


-- Tell caveman next move

next move
    | end with sharp stick  = poke with (what have)
    | they no poky          = sharpen stick
    | me have sword         = poke with sword
    | soon them have sword  = try poke or sharpen
    | soon have own sword   = fear pokes
    | think them want sword = sharpen stick
    | getting bored now     = sharpen stick
    | otherwise             = block poky stick


-- How fancy techno computer program know?

    where
        end with sharp stick = pokiness my stick >= moves before fight boring
        they no poky  = pokiness their stick == 0
        me have sword = pokiness my stick >= 5
        soon "them" have sword = pokiness their stick == 4
        soon have "own" sword  = pokiness my stick == 4
        try poke or sharpen = if pokiness my stick > 0
                              then poke with stick
                              else sharpen stick
        fear pokes = count 2 (block poky stick) and (sharpen stick)
        think them want sword = pokiness their stick == 3
        getting bored now = those last 2 mine same

        what have
            | me have sword = sword
            | otherwise     = stick



-- Rest not for caveman - only techno computer

        moves before time up = time - (length . fst $ move)

        and   = my
        mine  = my
        my    = fst move
        their = snd move

        before = "before"
        bored  = "bored"
        boring = "boring"
        have   = "have"
        no     = "no"
        now    = "now"
        own    = "own"
        pokes  = "pokes"
        same   = "same"
        sharp  = "sharp"
        them   = "them"
        want   = "want"


fight = 100


main = do
    movesHistoryEtc <- getArgs
    putStrLn . next . basedOn $ movesHistoryEtc


basedOn = movesOfEachCaveman . history

history []    = ""
history (h:_) = h

movesOfEachCaveman "" = ("", "")
movesOfEachCaveman h  = (\(a, b) -> (a, tail b)) . span (/= ',') $ h


sharpened = 'S'
poked     = 'P'
blocked   = 'B'

times m = length . filter (== m)


with  = "WITH"
poky  = "POKY"
sword = "SWORD"
stick = "STICK"

sharpen stick    = "SHARPEN " ++ stick
block poky stick = "BLOCK " ++ poky ++ " " ++ stick
poke with stick  = "POKE " ++ with ++ " " ++ stick


pokiness stick is = foldl countPokiness 0 stick

countPokiness pokyPoints 'P'
    | pokyPoints > 0         = pokyPoints - 1
    | otherwise              = 0
countPokiness pokyPoints 'S' = pokyPoints + 1
countPokiness pokyPoints  _  = pokyPoints


allLast n x xs = all (== x) $ take n . reverse $ xs

those previous n moves same = ((length moves) >= n)
                           && (allLast n (last moves) moves)

count n firstMoves moveHistory lastMove = if allLast n fm moveHistory
                                          then lastMove
                                          else firstMoves
    where fm = head firstMoves

Escrito em Haskell (vá para a programação funcional!), Salve como prisãorules.hs e compile com:

ghc prisonrules.hs

E execute como:

prisonrules [history]

4

Eu o chamo de JavaMan

compile: javac JavaMan.java
run: java JavaMan SPB,SBB

nota: eu não pretendo jogar código de golfe .. mas se você é um jogador de golfe e os espaços / linhas extras fazem seus olhos sangrarem .. fique à vontade para alterá-lo

public class JavaMan
{
    public static void main(String[] args)
    {
        // input: SPB,SBB
        // me, enemy
        // S: sharpen, P: poke, B: block

        if (args.length == 0)
        {
            System.out.println("S");
        }
        else
        {
            String[] states = args[0].split(",");
            Player me = new Player(states[0].toCharArray());
            Player enemy = new Player(states[1].toCharArray());  //fixed thanks to Roy van Rijn

            if (me.hasSword())
            {
                System.out.println("P");
            }
            else if (!enemy.canPoke())
            {
                if (me.canPoke() && (Math.random() * 95) < states[0].length())
                {
                    System.out.println("P");
                }
                else
                {
                    System.out.println("S");
                }
            }
            else if (enemy.hasSword())
            {
                if (me.canPoke())
                {
                    System.out.println("P");
                }
                else
                {
                    System.out.println("S");
                }

            }
            else if (enemy.canPoke())
            {
                if (me.canPoke())
                {
                    if ((Math.random() * 95) < states[0].length())
                    {
                        System.out.println("P");
                    }
                    else
                    {
                        System.out.println("B");
                    }
                }
                else
                {
                    if ((Math.random() * 95) < states[0].length())
                    {
                        System.out.println("S");
                    }
                    else
                    {
                        System.out.println("B");
                    }
                }
            }
            else
            {
                System.out.println("S");
            }
        }
    }

}

class Player
{
    int sharpLevel;

    public Player(char[] state)
    {
        sharpLevel = 0;
        for (char c : state)
        {
            switch (c)
            {
            case 'S':
                sharpLevel++;
                break;
            case 'P':
                sharpLevel--;
                break;
            case 'B':
                break;
            default:
                System.out.println(c);
            }
        }
    }

    public boolean hasSword()
    {
        return sharpLevel > 4;
    }

    public boolean canPoke()
    {
        return sharpLevel > 0;
    }
}

4
As inscrições para os desafios de King of the Hill não devem ser disputadas, por isso não se preocupe. ;)
Martin Ender

Mudei o nome para JavaMan, porque "Caveman" é um pouco genérico demais para figurar na tabela de classificação. Espero que esteja tudo bem com você; caso contrário, basta alterá-lo para outra coisa.
Maçaneta

1
Isso quebra quando não é fornecida nenhuma entrada (ou seja, no primeiro turno); Não sei como você quer lidar com isso, então vou ter que excluí-lo da primeira rodada de testes.
Maçaneta

Corrigido, e a mudança de nome está bem comigo
user2813274

1
Eu acho que você cometeu um erro ao analisar o estado, 'eu' e 'inimigo' fazem os mesmos movimentos: states [0]
Roy van Rijn

4

Pensamentos Profundos, C

Código do homem das cavernas. Homem das cavernas pensar. Homem das cavernas.

// DeepThoughts.c
#include <stdio.h>  // Me need for plan
#include <string.h> // Me need for memory

// Me count sharps. If me still here, pokes no work
int is_pointy(char *past){
    int pointy = 0;     // Stick dull
    while(*past){
        switch(*past ++){
            case 'S': pointy ++; break;
            case 'P': if(pointy > 0) pointy --;
        }
    }
    return pointy;
}

// Me brain
int main(int argc, char *argv[]){
    int me_pointy = 0;  // Is 0, stick dull. Is 5, has sword
    int you_pointy = 0; // Same to you
    int me_last;        // Me last plan
    int you_last;       // Same to you
    char *you;          // You past
    int when;           // Time
    int me_plan;        // Me deep thought

    // Me remember
    if(argc > 1){
        you = strchr(argv[1], ',');     // Me find you past in me arg
        *you ++ = 0;
        when = strlen(argv[1]);         // Time is passing
        me_pointy = is_pointy(argv[1]); // Me look at me past
        you_pointy = is_pointy(you);    // Same to you
        me_last = argv[1][when - 1];    // Why me do that?
        you_last = you[when - 1];       // Same to you
    }

    // Me has deep thoughts. Me make plan
    if(me_pointy >= 5) me_plan = 'P';       // Me has sword
    else if(you_pointy == 0) me_plan = 'S'; // Me safe. You stick dull
    else if(when == 1) me_plan = 'P';       // Me shoot first (more thought)
    else if(me_pointy == 1 && when < 42) me_plan = 'B';  // Me try for sharper (deeper thought)
    else if(me_pointy > 0) me_plan = 'P';   // Me stick not dull
    else if(me_last == 'P') me_plan = 'B';  // Me in trouble
    else me_plan = 'S';                     // Me cross toes

    // Me do plan
    putchar(me_plan);
    return 0;
}

Eu faço testes. Mais pensamentos melhores.


1
+1 para os nomes e comentários dos var do homem das cavernas: P Também, bom programa c:
cat

3

Nigel

Nigel é um velho homem das cavernas, defensivo e paciente, que prefere ser tático a dar o máximo de si no ataque.

É um script PHP, ligue com php nigel.php

<?php
// Seed the random number generator
srand(time());

// Simple function output chosen move
function move($m)
{
    echo $m;
    echo "\n";
    exit;
}

// Make stick sharp if first move
if (sizeof($argv) == 1)
    move("S");

// Grab the list of moves
$moves = explode(",", $argv[1]);    
$mySharpness = 0;
$opSharpness = 0;

// Loop through all previous moves and calculate sharpness
for ($i=0; $i<strlen($moves[0]); $i++)
{
    $myMove = substr ($moves[0], $i, 1);
    $opMove = substr ($moves[1], $i, 1);
    if ($myMove == "S")     $mySharpness++;
    if ($opMove == "S")     $opSharpness++; 
    if ($myMove == "P" && $mySharpness > 0)     $mySharpness--;
    if ($opMove == "P" && $opSharpness > 0)     $opSharpness--;     
}

// We somehow have a sword.. ATTACK!
if ($mySharpness > 4)
    move("P");

// Opponent is blunt, guarenteed upgrade!
if ($opSharpness < 1)
    move("S");          

// If we're sharp, either block or poke, unless OP is near a sword
if ($mySharpness > 0)
{
    // Oppenent is halfway to a sword.. ATTACK!
    if ($opSharpness > 2)
        move("P");  

    if (rand(0,1) == 0)     move("P");
    else                    move("B");
}

// If we're blunt, either sharpen or block
else
{
    if (rand(0,1) == 0)     move("S");
    else                    move("B");  
}

?>

3

Aichmophobic - Lua

Ele ocasionalmente cutucará você, mas apenas até que o pau fique muito afiado. Quando isso acontece, ele entra em pânico e se enrola na posição fetal.

if arg[1] == nil then
  response = "S"
elseif not arg[1]:match('SSSSS') == nil then
  --PANIC
  response = "B"
else  
  --Minds his own business and goes where he pleases
  math.randomseed(os.time())
  local rand = math.random();

  response = rand > 0.6 and "P" or "S"
end

print(response)

Execute-o com:

lua aichmophobic.lua


2
Sua saída deve estar em letras maiúsculas; Eu consertei isso para você. (Além disso, digitei o nome dessa submissão milhares de vezes.: P)
Maçaneta da porta

3

Bob Caves

Bob Caves é um dos caras mais inteligentes de sua caverna. Ele aprendeu a contar com uma mão (a outra está ocupada segurando o graveto). Ele sabia das Olimpíadas da Idade da Pedra e queria participar.

Sua principal estratégia é bloquear e afiar o bastão até que ele tenha um bom bastão de sharpy ou o outro homem das cavernas também. Nesse caso, Bob Caves tenta cutucá-lo!

import java.util.Random;

public class BobCaves {

    public static void main(String[] args) {
        int mySharpness = 0;
    int otherSharpness = 0;

    //Boc counts
    if (args.length > 0) {
        String[] ss = args[0].split(",");
        mySharpness = howSpiky(ss[0]);
        otherSharpness = howSpiky(ss[1]);
    }
    // Bob thinks!
    Random rn = new Random();
    if (mySharpness == 0 && otherSharpness == 0){
        System.out.println( "S");
    }
    if (otherSharpness == 0 && mySharpness < 5 && mySharpness > 0){
        if (rn.nextBoolean()){
            System.out.println("P");
        } else {
            System.out.println("S");
        }
    } 

    if (mySharpness >= 5 || (otherSharpness >= 2 && mySharpness > 0)) {
        System.out.println("P");
    }

    if (rn.nextInt(5) > 3) {
        System.out.println("S");
    } 

    System.out.println("B");
    }

    private static int howSpiky(String s1) {
        int count = 0;
        char[] c1 = s1.toCharArray();
        for (int i = 0; i < c1.length; i++) {
        if (c1[i] == 'S') {
                count++;
            } else if (c1[i] == 'P'){
                count --;
            }
        }
        return count;
    }

}

Compilar javac BobCaves.javae executar comjava BobCaves

Edit: Bob agora conta quando há algum bloco! (graças a Mikey Mouse ). Além disso, ele afiará o graveto quando o outro graveto do homem das cavernas estiver embotado.

Editar 2: método de contagem aprimorado (obrigado novamente a Mikey).

Edit 3: Tornando Bob um pouco mais agressivo.


2
Bob esqueça o efeito de contagem de puxão: Bloqueie a nitidez da vara. Três "S" em s não significam que o pau seja três vezes nítido. Cada "P" em s significa bastão não afiado. Huh huh huh ... "Xixi" piada do homem das cavernas ...
Mikey Mouse

@MikeyMouse Bob concorda. Bob visitará o feiticeiro para melhorar sua técnica. Bob grato!
Averroes

1
O feiticeiro ensina bem a Bob. Mas ele esquece de mencionar o puxão: puxão. Stick fica franco também. Bob não precisa considerar o movimento do oponente. Se Bob Poke, fique duro. Ou sem corte: cutucada do oponente, no bloco do oponente ou na cabeça do oponente. Se estiver no Head adversário, Bob vence e pode dançar ao redor da caverna com o bastão.
25714 Mikey Mouse

1
@MikeyMouse Bob sabe contar. Bob precisa aprender a ler. Obrigado novamente!
Averroes

3

Gruntt

Gruntt está na defensiva. Gruntt analisa outros movimentos dos homens das cavernas para saber como cutucá-los. Então ele os cutuca bem nos olhos. Gruntt não é um bom homem das cavernas.

public class Gruntt {

public static void main(String[] args) {
    System.out.println(whatToDo(args));
}

private static String whatToDo(String[] args){
    int mySharpness = 0;
    int otherSharpness = 0;

    if (args.length > 0) {
        String[] ss = args[0].split(",");
        mySharpness = howSpiky(ss[0]);
        otherSharpness = howSpiky(ss[1]);
    } else {
        return "S";
    }

    if (mySharpness >= 5){
        return "P";
    }

    String res = wowoo(args[0].split(",")[1]);
    if ("P".equals(res) && mySharpness > 0) {
        return "P";
    } else if ("P".equals(res) && mySharpness == 0) {
        return "S";
    } else if ("S".equals(res) && !args[0].split(",")[0].endsWith("S")) {
        return "S";
    }

    if (otherSharpness == 4 && !args[0].split(",")[0].endsWith("P")){
        return "P";
    }

    if (otherSharpness == 0){
        return "S";
    }

    return "B";

}

private static int howSpiky(String s1) {
    int count = 0;
    char[] c1 = s1.toCharArray();
    for (int i = 0; i < c1.length; i++) {
    if (c1[i] == 'S') {
            count++;
        } else if (c1[i] == 'P'){
            count --;
        }
    }
    return count;
}

private static String wowoo(String s){
    String s1 = "";
    String s2 = "";

    if (s.length() >= 4){
        s1 = s.substring(s.length() - 4);
    }

    if (s.length() >= 3){
        s2 = s.substring(s.length() - 3);
    }

    if ("SPSP".equals(s1)){
        return "P";
    } else if ("SSS".equals(s2)){
        return "P";
    } else if ("BBBB".equals(s1)){
        return "S";
    } else if ("SBSB".equals(s1)){
        return "P";
    }

    return null;
}

}

Compilar javac Gruntt.javae executar comjava Gruntt


Isso lança um ArrayOutOfBoundsExceptionno primeiro turno e, às vezes, gera várias ações em outros turnos.
Maçaneta

@Doorknob Ops! Corrigido, obrigado!
Averroes

3

Isso é um passaro? É um avião? É RegExMan!

Ele tenta analisar suas sequências super-chatas com seu poder primordial especial RegEx!

#!/usr/bin/env python
import sys, re

def whatAmIDoing(opnHist, meSharp, opnSharp) :

    match = re.search(r"([PSB]{3,})\1$", opnHist)    ### Super RegEx ftw!

    if meSharp >= 5 :
        return "P"
    if opnSharp == 4 and meSharp > 0 :
        return "P"
    if match :
        opnStrat = match.group()
        if opnStrat[0] == "S" :
            if meSharp > 0 :
                return "P"
            else :
                return "S"
        elif opnStrat[0] == "B" :
            return "S"
    if opnSharp <= 0 :
        return "S"
    return "B"

try :
    hist = sys.argv[1].split(",")
    sharp = map(lambda h : h.count("S") - h.count("P"), hist)
    answer = whatAmIDoing(hist[1], *sharp)
except Exception :
    answer = "S"
finally :
    print(answer)

Escrito em Python 2.7, execute com python RegExMan.py [history]


3

Siciliano

Mas é tão simples! Tudo o que tenho a fazer é divino com o que sei de outro homem das cavernas: ele é o tipo de homem das cavernas que iria bloquear, afiar ou cutucar? Agora, um homem das cavernas esperto cutucava ou bloqueava, porque sabia que apenas um grande tolo se afiaria e se exporia ao ataque. Eu não sou um grande tolo, então claramente não posso aguçar. Mas outro homem das cavernas deve saber que eu não sou um grande tolo e teria contado com isso, para que eu claramente não possa cutucar ou bloquear!

Correr com:

javac Sicillian.java
java Sicillian

Código:

public class Sicillian {

    public static void main(String[] args) {

        if (args.length == 0) System.out.println("S");
        else {
            //get and analyze history
            String[] history = args[0].split(",");
            Caveman vizzini = new Caveman(history[0].toCharArray());
            Caveman fool = new Caveman(history[1].toCharArray());
            Think divine = new Think(history[0].toCharArray(),history[1].toCharArray());

            //The Sicillian always thinks and makes a logical decision before acting...
            char onlyAFool = divine.clearly(vizzini.getSharpness(),fool.getSharpness());

            //Never go in against a Sicillian when death is on the line!
            if(onlyAFool == 'S') {
                if(!vizzini.weaponless()) poke();
                else sharpen();
            }
            else if(onlyAFool == 'P') {
                if(vizzini.hasSword()) poke();
                else block();
            }
            else if(onlyAFool == 'B') sharpen();

            else {          // Inconceivable!

                //if he's a sharpener, poke him where it hurts!
                if(fool.isSharpener()) {
                    if(vizzini.getSharpness() >= 2) poke();  //don't ever go weaponless, else you give him the advantage
                    else sharpen();
                }               
                //if he's a blocker, get sword and break through his defense
                else if(fool.isDefensive()) {
                    if(vizzini.hasSword()) poke();
                    else sharpen();
                }
                // fool doesn't have a disposition to do anything in particular
                else {
                    //he could be sharpening and blocking to get a sword in which case his sharpness will be higher
                    //or a random, which will average a lower sharpness
                    if (fool.getSharpness() <= 2) { //assume random
                        if(vizzini.hasSword()) poke();
                        else if(fool.weaponless()) sharpen();
                        else block();
                    }
                    else {
                        if(vizzini.hasSword()) poke();
                        else if(vizzini.getSharpness() > fool.getSharpness()) sharpen();    //we can win race to sword
                        else if(vizzini.getSharpness() >= 2 || (!vizzini.weaponless() && fool.onEdge())) poke();
                        else sharpen();
                    }
                }
            }           
        }
    }   //end of main

    private static void poke() {
        System.out.println("P");
    }
    private static void block() {
        System.out.println("B");
    }
    private static void sharpen() {
        System.out.println("S");
    }
}
class Think {
    private char[][] cleverman = new char[6][6];    //tracks what the enemy does in a particular situation 
    private int mySharpness;
    private int enemySharpness;
    public Think(char[] myAction, char[] enemyAction) {
        //init variables
        mySharpness = 0;
        enemySharpness = 0;

        for(int i = 0; i < myAction.length; i++) {
            //remember what enemy did last time
            cleverman[mySharpness][enemySharpness] = enemyAction[i];
            //System.out.println("When I was at ("+mySharpness+") and he was at ("+enemySharpness+") he did ("+enemyAction[i]+")");

            //calculate my sharpness
            if(myAction[i] == 'S') mySharpness++;
            else if(myAction[i] == 'P') mySharpness--;
            if(mySharpness < 0) mySharpness = 0; //ensure multiple pokes don't create a negative sharpness
            //calculate my enemy's sharpness
            if(enemyAction[i] == 'S') enemySharpness++;
            else if(enemyAction[i] == 'P') enemySharpness--;
            if(enemySharpness < 0) enemySharpness = 0; //ensure multiple pokes don't create a negative sharpness
        }   
    }
    public char clearly(int myAction, int enemyAction) {
        if(myAction > 5) myAction = 5;
        if(enemyAction > 5) enemyAction = 5;
        return cleverman[myAction][enemyAction];
    }
}
class Caveman {
    private int sharpness;
    private int disposition;    //Finite State Machine: how inclined the caveman is toward blocking (0) or sharpening (4)
    public Caveman(char[] action) {
        sharpness = 0;
        disposition = 1;        //assume a slightly defensive disposition
        for (int i = 0; i < action.length; i++) {
            if(action[i] == 'S') {
                sharpness++;
                disposition++;
            }
            else if(action[i] == 'P') sharpness--;
            else disposition--;                     //blocking
            if(sharpness < 0) sharpness = 0; //ensure multiple pokes don't create a negative sharpness
            if(disposition > 4) disposition = 4;
            else if(disposition < 0) disposition = 0;
        }
    }
    public int getSharpness() {
        return sharpness;
    }
    public boolean weaponless() {
        return sharpness == 0;
    }
    public boolean hasSword() {
        return sharpness >= 5;
    }
    public boolean onEdge() {
        return sharpness == 4;
    }
    public boolean isDefensive() {
        return disposition == 0;
    }
    public boolean isSharpener() {
        return disposition == 4;
    }
    public int getDisposition() {
        return disposition;
    }
}

3

bash-magnon

Bash-magnons foram robustos e poderosos. O corpo era geralmente pesado e sólido, com uma musculatura forte. A testa era razoavelmente reta, em vez de inclinada, como nos neandertais, e com apenas ligeiras sobrancelhas. O rosto era curto e largo. O queixo era proeminente. A capacidade cerebral era de cerca de 1.600 centímetros cúbicos (98 cu in), maior que a média dos humanos modernos. No entanto, pesquisas recentes sugerem que as dimensões físicas do chamado "Bash-Magnon" não são suficientemente diferentes dos humanos modernos para justificar uma designação separada.

Eu tenho um cérebro, me lembro.

Este é um auto executável ./bash-magnon.sh

#!/bin/bash

function min () {
 [[ $1 -gt $2 ]] && echo $2 || echo $1
}

function max () {
[[ ${1%% *} -gt ${2%% *} ]] && echo $1 || echo $2
}

declare -A brain
declare -i C S P B me he
he=0
me=0
C=0
S=0; B=0; P=0

left=${1%%,*}
right=${1##*,}
while  : 
do

    [[ "${right:$C:1}" ]] && brain[$he$me]=${right:$C:1}
    case "${left:$C:1}${right:$C:1}" in
    BB) true;;
    BP) ((he--));;
    BS) ((he++));;
    PP) ((he--)); ((me--));;
    PB) ((me--));;
    PS|SP) exit;;
    SB) ((me++));;
    SS) ((me++)); ((he++));;
    "") break;;
    esac
    me=$(max 0 $me)
    me=$(min 9 $me)
    he=$(max 0 $he)
    he=$(min 9 $he)
    ((C++))
done

[[ $me$he =  *[5-9] ]] && ((P+=2))
[[ $me$he =  [5-9]* ]] && ((P+=2))
[[ $me$he =  [1-9]0 ]] && ((P+=2))
[[ $me$he =  00 ]] && ((S+=2))
[[ $me$he =  [1-4]4 ]] && ((P+=2))
[[ $me$he =  0[1-4] ]] && ((S+=1))
[[ $me$he =  0* ]] && ((B+=1))

case "${brain["$he$me"]}" in 
S) ((P+=2));;
B) ((S+=2));;
P) ((B+=2));;
*) ((B++));;
esac

set $(max "$B B" "$(max "$P P" "$S S")" )
echo $2

1+ Você obviamente tem a ferramenta certa para o trabalho e seus nomes homens das cavernas são bastante divertido :) (Eu, pessoalmente, como peixes melhor embora)
Sylwester

@Sylwester Obrigado, esse é meu primeiro +1. Tentei primeiro criar um autômato homeostático inspirado no que o primeiro cibernético tinha em seu próprio equilíbrio, depois desisti e fiz um roteiro bash.
Emmanuel

2

PokeBackBot

Simplesmente adaptado do PokeBot:

puts 'SBPB'[(ARGV.shift || ',').split(',', 2)[0].length % 4]

Corra com ruby pokebackbot.rb.

Isso usa a próxima estratégia mais simples e bloqueia "pacientemente" por uma rodada antes de atacar.


3
@ PeterTaylor Eu li isso como não sendo permitido mudar minha estratégia com base na impressão digital do oponente. Se minha submissão puder apenas superar uma outra submissão, isso não afetará realmente a pontuação de outras submissões, e minha própria submissão provavelmente sairá muito mal. Além disso, se houver apenas uma inscrição, e uma segunda for escrita, é provável que a segunda vença a primeira (porque, caso contrário, por que se preocupar) - isso por si só é qualificado como "específico para outro programa"? Meu bot SPSvencerá qualquer bot que comece com (o que parece razoável), mas até agora o PokeBot era o único.
Martin Ender

2

Mestre de espada

Escrito em Python 3.4 (funciona com Python 3.x)

Tenta obter uma espada o mais rápido possível, mas ataca se tiver uma chance de atingi-lo (nitidez> 0) e o inimigo também pode machucá-la (nitidez do inimigo> 0).
Bloqueia apenas se não tiver nitidez e o inimigo puder atacar.

Começar com:

python3 swordmaster.py MOVES

(supondo que você o salve como swordmaster.py)

Código rápido e feio:

import sys, random
dg = False
if len(sys.argv) > 1:
    ow,ot = sys.argv[1].split(',')
else:
    ow = ot = ""
def gs(m):
    ow = 0
    ot = 0
    i = 0
    ms = m[0]
    mo = m[1]
    for _ in mo:
        if ms[i] == 'S':
            ow += 1
        elif ms[i] == 'P' and mo[i] in ['P','B']:
            ow -= 1
        if mo[i] == 'S':
            ot += 1
        elif mo[i] == 'P' and ms[i] in ['P','B']:
            ot -= 1
        if dg:
            print("Own: {}, Other: {}".format(ow,ot))
        i += 1
    return [ow, ot]

def sm(sh):
    if (type(sh) != list) and dg:
        raise ValueError('Invalid sh type.')
    ow, ot = sh
    if ow >= 5:
        ret = 'P'
    elif ow >= 0 and ot == 0:
        ret = 'S'
    elif ow > 0 and ot > 0:
        ret = 'P'
    elif ow == 0 and ot > 0:
        ret = 'B'
    else:
        ret = random.choice(['S','B','P']) #Should not happen
    return ret

if __name__ == "__main__":
    print(sm(gs([ow,ot])))

(Defina dgpara Trueativar as mensagens de depuração)


1
Dica: Não deixe que a batalha em si - que vai impasse com S, P, S, P...
chill0r

Eu descobri que isso acontece com o meu também. A menos que você examine a história ou use um grau de aleatoriedade, você ficará preso em um ciclo.
Pharap

2

FoolMeOnce.py

Salve os movimentos de cada jogador no primeiro duelo e depois jogue com os mesmos movimentos. Se o algoritmo do inimigo não for aleatório, podemos prever o mesmo resultado e atacar apenas quando sabemos que venceremos.

import os
import sys
import random

def getLastMove(player, turn):
    path = 'players/FoolMeOnce/'+player+str(turn)+'.txt'
    if os.path.isfile(path):
        with open(path, 'r') as f:
            return f.read()
    else:
        return 'nofile'

def sharpness(history):
    sharpness = 0
    for c in history:
        if c is 'S':
            sharpness+=1
        elif c is 'P' and sharpness > 0:
            sharpness-=1
    return sharpness

def takeTurn(choice, history, turn):
    print(choice)
    with open('players/FoolMeOnce/me'+str(turn)+'.txt', 'w') as f:
        f.write(choice)
    #also record their last choice
    choice = history[-1]
    with open('players/FoolMeOnce/them'+str(turn)+'.txt', 'w') as f:
        f.write(choice)

#if its the first turn, always sharpen
if(len(sys.argv) == 1):
    print('S')

else:
    history = sys.argv[1].split(',')
    meSharp = sharpness(history[0])
    themSharp = sharpness(history[1])
    turn = len(history[0])

    #read opponents move and our move for this turn from last duel
    them = getLastMove('them', turn);
    me = getLastMove('me', turn);

    #if this is first duel, fool me once
    if(them is 'nofile' or me is 'nofile'):
        if themSharp is 0 and meSharp >0:
            takeTurn(random.SystemRandom().choice('PS'), history, turn)
        else:
            takeTurn('B', history, turn)

    #if we could have played a winning move, do it. otherwise do what we did last time
    elif(them is 'S' and meSharp > 0):
        takeTurn('P', history, turn)
    else:
        takeTurn(me, history, turn)

Escrito em python 3, provavelmente você precisará usar python3 FoolMeOnce.py Na primeira rodada, não tenho certeza se obtemos uma string vazia ou apenas uma vírgula; portanto, podem ser necessários alguns ajustes.


Corrigi o caminho do arquivo - o diretório de trabalho atual não é do seu programa.
Maçaneta

Enquanto brincava com o testador CavemanDuel, notei que o FoolMeOnce ganha pontos muito melhores se eu usar mais threads (eu testei 16 threads contra 4). Com 4 threads, obtém ~ 25 pontos, com 16, ~ 34.
Wendelbsilva

Estranho, não tenho ideia do porquê disso.
tzazy
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.