Um jogo de proporções atômicas

21

Sua tarefa cria um bot que joga Atomas , com a maior pontuação.

Como o jogo funciona:

O tabuleiro começa com um anel de 6 "átomos", com números que variam de 1a 3. Você pode "reproduzir" um átomo entre dois átomos ou em outro átomo, dependendo do próprio átomo.

Você pode ter um átomo normal ou um átomo especial.

O átomo normal:

Você pode jogar um átomo normal entre dois átomos disponíveis no tabuleiro.

Você começa com átomos no intervalo 1 to 3, mas o intervalo aumenta em 1 uma vez a cada 40 movimentos (portanto, após 40 movimentos, o intervalo se torna 2 to 4).

Se houver átomos no tabuleiro abaixo do intervalo, ele 1 / no. of atoms of that number on the boardpoderá gerar.

Digamos que você tem 2que jogar, e o quadro fica assim:

   1 1 2 1

Vamos colocar o 2lado direito do 1.

O conselho passa a ser:

   1 1 2 1 2

Nota: o tabuleiro gira ao redor, de modo que o 1lado esquerdo fica realmente próximo ao lado 2direito. Isso será importante mais tarde.

Existem 4 tipos de átomos "especiais" e são:

O +átomo:

Este átomo é jogado entre dois átomos. Tem uma chance de 1 em 5 de desova.

Se os átomos dos dois lados do +átomo são iguais, ocorre a fusão. Veja como funciona:

The two atoms fuse together to create an atom one higher.
(So, two 3 atoms fuse together to form one 4 atom.)
While the atoms on both sides of the fused atom are equal:
    If the atoms on the side >= the fused atom:
        The new fused atom = the old fused atom's value + 2.
    If the atoms on the side < the fused atom:
        The new fused atom = the old fused atom's value + 1.

Exemplo:

   1 1 3 2 2 3  (the 1 on the left-hand side "wraps back" 
                 to the 3 on the right-hand side)

Let's use the + on the two 2's in the middle.

-> 1 1 3 3 3    (the two 2's fused together to make a 3)
-> 1 1 5        (the two 3's fused with the 3, and because 3 >= 3,
                 the new fused atom = 3 + 2 = 5)
-> 6            (the two 1's fused with the 5, since the board wraps,
                 and because 1 < 5, the new fused atom = 5 + 1 = 6)

Because the atoms on the sides of the 6 don't exist, fusion stops,
and the board is now [6].

Se os átomos de ambos os lados do +átomo forem diferentes, as +partículas permanecerão no quadro.

Exemplo:

   1 3 2 3 1 1

Let's use the + on the 2 and 3 in the middle.

-> 1 3 2 + 3 1 1 (2 != 3, so the + stays on the board)

O -átomo:

Este átomo é jogado em outro átomo. Tem 1 em 10 chances de gerar.

O -átomo remove um átomo da placa e oferece uma opção para:

  • jogar o átomo removido na próxima rodada ou
  • transformá-lo em um átomo + para jogar na próxima rodada.

Exemplo:

   1 3 2 3 1 1

Let's use the - on the left-hand 2.

-> 1 3 3 1 1    (the 2 is now removed from the board)

Let's turn it into a +, and place it in between the 3's.

-> 1 4 1 1      (the two 3's fused together to make a 4)
-> 5 1          (the two 1's fused with the 4, and because 1 < 4,
                 the new fused atom = 4 + 1 = 5)

O +átomo preto ( B):

Este átomo é jogado entre 2 átomos. Tem uma chance de 1 em 80 de desova, e só aparece uma vez que sua pontuação for> 750.

Esse átomo é basicamente o mesmo que o +átomo, exceto que ele une dois átomos, até +os. A partir de então, segue a +regra (apenas funde átomos se os átomos de ambos os lados do átomo fundido forem iguais).

O átomo fundido como resultado do preto +é igual a:

  • o átomo de maior número na fusão + 3
  • 4Se os dois átomos fundidos são +'s

Exemplo:

   1 3 2 1 3 1

Let's use the black + on the 2 and 1 in the middle.

-> 1 3 5 3 1    (the 2 and 1 fused together to make a 2 + 3 = 5)
-> 1 6 1        (+ rule)
-> 7            (+ rule)

Outro exemplo:

   2 + + 2

Let's use the black + on the two +'s.

-> 2 4 2        (the two +'s fused together to make a 4)
-> 5            (+ rule)

O átomo do clone ( C):

Este átomo é jogado em outro átomo. Tem 1 em 60 chances de gerar, e só aparece quando sua pontuação for> 1500.

O átomo de clone permite que você escolha um átomo e o jogue na próxima rodada.

Exemplo:

   1 1 2 1

Let's use the clone on the 2, and place it to the right of the 1.

-> 1 1 2 1 2

Aqui está minha versão do jogo, em Python 2:

import random
import subprocess

logs='atoms.log'
atom_range = [1, 3]
board = []
score = 0
move_number = 0
carry_over = " "
previous_moves = []

specials = ["+", "-", "B", "C"]


def plus_process(user_input):
    global board, score, previous_moves, matches
    previous_moves = []
    matches = 0

    def score_calc(atom):
        global score, matches
        if matches == 0:
            score += int(round((1.5 * atom) + 1.25, 0))
        else:
            if atom < final_atom:
                outer = final_atom - 1
            else:
                outer = atom
            score += ((-final_atom + outer + 3) * matches) - final_atom + (3 * outer) + 3
        matches += 1

    if len(board) < 1 or user_input == "":
        board.append("+")
        return None
    board_start = board[:int(user_input) + 1]
    board_end = board[int(user_input) + 1:]
    final_atom = 0
    while len(board_start) > 0 and len(board_end) > 0:
        if board_start[-1] == board_end[0] and board_end[0] != "+":
            if final_atom == 0:
                final_atom = board_end[0] + 1
            elif board_end[0] >= final_atom:
                final_atom += 2
            else:
                final_atom += 1
            score_calc(board_end[0])
            board_start = board_start[:-1]
            board_end = board_end[1:]
        else:
            break
    if len(board_start) == 0:
        while len(board_end) > 1:
            if board_end[0] == board_end[-1] and board_end[0] != "+":
                if final_atom == 0:
                    final_atom = board_end[0]
                elif board_end[0] >= final_atom:
                    final_atom += 2
                else:
                    final_atom += 1
                score_calc(board_end[0])
                board_end = board_end[1:-1]
            else:
                break
    if len(board_end) == 0:
        while len(board_start) > 1:
            if board_start[0] == board_start[-1] and board_start[0] != "+":
                if board_start[0] >= final_atom:
                    final_atom += 2
                else:
                    final_atom += 1
                score_calc(board_start[0])
                board_start = board_start[1:-1]
            else:
                break
    if matches == 0:
        board = board_start + ["+"] + board_end
    else:
        board = board_start + [final_atom] + board_end
        for a in range(len(board) - 1):
            if board[a] == "+":
                if board[(a + 1) % len(board)] == board[a - 1]:
                    board = board[:a - 1] + board[a:]
                    plus_process(a)
                    break


def minus_process(user_input, minus_check):
    global carry_over, board
    carry_atom = board[int(user_input)]
    if user_input == len(board) - 1:
        board = board[:-1]
    else:
        board = board[:int(user_input)] + board[int(user_input) + 1:]
    if minus_check == "y":
        carry_over = "+"
    elif minus_check == "n":
        carry_over = str(carry_atom)


def black_plus_process(user_input):
    global board
    if board[int(user_input)] == "+":
        if board[int(user_input) + 1] == "+":
            inter_atom = 4
        else:
            inter_atom = board[int(user_input) + 1] + 2
    else:
        if board[int(user_input)] + 1 == "+":
            inter_atom = board[int(user_input)] + 2
        else:
            inter_list = [board[int(user_input)], board[int(user_input) + 1]]
            inter_atom = (inter_list.sort())[1] + 2
    board = board[int(user_input) - 1:] + [inter_atom] * 2 + board[int(user_input) + 1:]
    plus_process(int(user_input) - 1)


def clone_process(user_input):
    global carry_over
    carry_over = str(board[int(user_input)])


def regular_process(atom,user_input):
    global board
    if user_input == "":
        board.append(random.randint(atom_range[0], atom_range[1]))
    else:
        board = board[:int(user_input) + 1] + [int(atom)] + board[int(user_input) + 1:]

def gen_specials():
    special = random.randint(1, 240)
    if special <= 48:
        return "+"
    elif special <= 60 and len(board) > 0:
        return "-"
    elif special <= 64 and len(board) > 0 and score >= 750:
        return "B"
    elif special <= 67 and len(board) > 0 and score >= 1500:
        return "C"
    else:
        small_atoms = []
        for atom in board:
            if atom not in specials and atom < atom_range[0]:
                small_atoms.append(atom)
        small_atom_check = random.randint(1, len(board))
        if small_atom_check <= len(small_atoms):
            return str(small_atoms[small_atom_check - 1])
        else:
            return str(random.randint(atom_range[0], atom_range[1]))


def specials_call(atom, user_input):
    specials_dict = {
        "+": plus_process,
        "-": minus_process,
        "B": black_plus_process,
        "C": clone_process
    }
    if atom in specials_dict.keys():
        if atom == "-":
            minus_process(user_input[0], user_input[1])
        else:
            specials_dict[atom](user_input[0])
    else:
        regular_process(atom,user_input[0])


def init():
    global board, score, move_number, carry_over, previous_moves
    board = []
    score = 0

    for _ in range(6):
        board.append(random.randint(1, 3))

    while len(board) <= 18:
        move_number += 1
        if move_number % 40 == 0:
            atom_range[0] += 1
            atom_range[1] += 1
        if carry_over != " ":
            special_atom = carry_over
            carry_over = " "
        elif len(previous_moves) >= 5:
            special_atom = "+"
        else:
            special_atom = gen_specials()
        previous_moves.append(special_atom)
        bot_command = "python yourBot.py"
        bot = subprocess.Popen(bot_command.split(),
                               stdout = subprocess.PIPE,
                               stdin = subprocess.PIPE)
        to_send="/".join([
            # str(score),
            # str(move_number),
            str(special_atom),
            " ".join([str(x) for x in board])
        ])
        bot.stdin.write(to_send)
        with open(logs, 'a') as f:f.write(to_send+'\n')
        bot.stdin.close()
        all_user_input = bot.stdout.readline().strip("\n").split(" ")
        specials_call(special_atom, all_user_input)

    print("Game over! Your score is " + str(score))

if __name__ == "__main__":
    for a in range(20):
        with open(logs, 'a') as f:f.write('round '+str(a)+'-'*50+'\n')
        init()

Como a coisa bot funciona:

Entrada

  • Seu bot terá duas entradas: o átomo que está atualmente em jogo e o estado do tabuleiro.
  • O átomo será assim:
    • +para um +átomo
    • -para um -átomo
    • Bpara um +átomo preto
    • C para um átomo de clone
    • {atom} para um átomo normal
  • O estado do quadro será assim:
    • atom 0 atom 1 atom 2... atom n, com os átomos separados por espaços ( atom nvolta para atom 1, para simular uma placa de jogo em "anel")
  • Esses dois serão separados por a /.

Exemplo de entradas:

1/1 2 2 3   (the atom in play is 1, and the board is [1 2 2 3])
+/1         (the atom in play is +, and the board is [1] on its own)

Saída

  • Você produzirá uma string, dependendo do átomo em jogo.

    • Se o átomo deve ser jogado entre dois átomos:

      • Crie o intervalo em que você deseja reproduzir o átomo. Os intervalos são iguais entre cada átomo, da seguinte forma:

        atom 0, GAP 0, atom 1, GAP 1, atom 2, GAP 2... atom n, GAP N
        

        ( gap nindica que você deseja colocar o átomo entre atom 1e átomo n) Portanto, imprima 2se quiser reproduzir o átomo gap 2.

    • Se o átomo deve ser jogado em um átomo:
      • Emita o átomo em que você deseja reproduzi-lo; portanto, 2se você quiser reproduzir o átomo atom 2.
    • Se o átomo é um -:
      • Emita o átomo em que você deseja reproduzi-lo, seguido por um espaço, seguido de uma y/nopção de transformá-lo em um +posterior, portanto, 2, "y"se você deseja atom 2ativá-lo e deseja transformá-lo em a +. Nota: isso requer 2 entradas, em vez de 1.

Exemplo de saídas:

(Atom in play is a +)
2   (you want to play the + in gap 2 - between atom 2 and 3)
(Atom in play is a -)
3 y  (you want to play the - on atom 3, and you want to change it to a +)
2 n  (you want to play the - on atom 2, and you don't want to change it)
  • Para fazer o bot funcionar, você precisa ir ao Popenbit (no final do código) e substituí-lo pelo que faz com que seu programa seja executado como uma lista Pythonic (então, se o seu programa for derp.java, substitua ["python", "bot.py"]por ["java", "derp.java"]).

Especificações específicas da resposta:

  • Coloque o código inteiro do seu bot na resposta. Se não couber, não conta.
  • Cada usuário pode ter mais de 1 bot; no entanto, todos devem estar em postagens de resposta separadas.
  • Além disso, dê um nome ao seu bot.

Pontuação:

  • O bot com a maior pontuação vence.
    • Seu bot será testado em 20 jogos e a pontuação final é a média dos 20 jogos.
  • O desempate será o horário do upload da resposta.
  • Portanto, sua resposta será formatada assim:

    {language}, {bot name}
    Score: {score}
    

Boa sorte!

clismique
fonte
Como o gerado +para um -átomo funciona? Se você escolher, yterá a garantia de obter um +na próxima jogada?
Ton Hospel
4
Sugiro alterar seu driver de bot para que ele possa lidar com qualquer programa autônomo que aceite entradas no STDIN e dê um resultado no STDOUT. Isso deve dar independência ao idioma e a maioria dos idiomas usados ​​neste site pode fazer isso facilmente. Claro que isso significa definir um formato estrito de E / S, por exemplo, input_atom\natom0 atom1 .... atomn\npara STDIN
Ton Hospel 11/16/16
11
O código parece capaz de colocar +na lista de elementos, mas isso não é encontrado em nenhum lugar na descrição textual
Ton Hospel
11
Ah, vejo que você tornou o programa capaz de ligar para bots externos. No entanto, você também precisa passar o número do movimento atual e marcar em STDIN caso contrário o bot não pode prever as chances de cada átomo que acontecem no futuro
Ton Hospel
11
Idk se as pessoas gastam tempo criando uma solução se o controlador não for aprimorado. Eu gosto da pergunta, mas não da implementação.
Mbomb007

Respostas:

1

Python, draftBot, Pontuação = 889

import random
def h(b):
    s=0
    for x in b:
        try:
            s+=int(x)
        except: 
            s+=0
    return s
def d(i):g=i.split("/");a=g[0];b=g[1].split(" ");return(a,b)
def p(a,_,j):
    v=[]
    for x in _:
        try:
            v.append(int(x))
        except: 
            v.append(0)
    try:
        v=v[:j+1]+[int(a)]+v[j+1:]
    except: 
        v=v[:j+1]+[a]+v[j+1:]
    r1=[[]];b=[x for x in v];m=range(len(b)+1)
    for k in m:
        for i in m:
            for j in range(i):
                c = b[j:i + 1]
                if len(c)%2==0 and c==c[::-1] and 0 not in c:r1.append(c)
        b.insert(0, b.pop())
    q1=max(r1,key=len)
    r2=[[]];b=[x for x in v];m=range(len(b)+1)
    for k in m:
        for i in m:
            for j in range(i):
                c = b[j:i + 1]
                if len(c)>2 and len(c)%2==1 and c==c[::-1] and "+" in c and 0 not in c:r2.append(c)
        b.insert(0, b.pop())
    q2=max(r2,key=h)
    with open('f.log', 'a') as f:f.write('pal '+str(_)+' : '+str(q1)+' : '+str(q2)+'\n')
    if q2!=[]:return 100+h(q2)
    else:return len(q1)
i=raw_input()
(a,b)=d(i)
if a in ['C','B']:print('0')
elif a=='-':print("0 y" if random.randint(0, 1) == 1 else "0 n")
else:q,j=max((p(a,b,j),j)for j in range(len(b)));print(str(j))

Eu descobri que o controlador:

  • trava quando a pontuação excede 1500;
  • não mescla átomos adequadamente nos mesmos casos.
mdahmoune
fonte
0

Python, RandomBot, Pontuação = 7,95

Nada muito chique, apenas um bot aleatório.

import random

game_input = raw_input().split("/")
current_atom = game_input[0]
board = game_input[1].split(" ")

if current_atom != "-":
    print(random.randint(0, len(board) - 1))
else:
    random_choice = " y" if random.randint(0, 1) == 1 else " n"
    print(str(random.randint(0, len(board) - 1)) + random_choice)
clismique
fonte
0

Python, BadPlayer, Pontuação = 21.45

import random

try:
    raw_input
except:
    raw_input = input

game_input = raw_input().split("/")
current_atom = game_input[0]
board = game_input[1].split(" ")

def get_chain(board, base):
    chain = []
    board = board[:]
    try:
        while board[base] == board[base + 1]:
            chain = [board[base]] + chain + [board[base + 1]]
            del board[base]
            del board[base]
            base -= 1
    except IndexError:
        pass
    return chain

def biggest_chain(board):
    chains = []
    base = 0
    i = 0
    while i < len(board) - 1:
        chains.append([i, get_chain(board, i)])
        i += 1
    return sorted(chains, key=lambda x: len(x[1]) / 2)[-1]

def not_in_chain():
    a, b = biggest_chain(board)
    if len(b) == 0:
        print(random.randint(0, len(board) - 1))
    elif random.randint(0, 1) == 0:
        print(random.randint(a + len(b)/2, len(board) - 1))
    else:
        try:
            print(random.randint(0, a - len(b)/2 - 1))
        except:
            print(random.randint(a + len(b)/2, len(board) - 1))

if current_atom in "+B":
    a, b = biggest_chain(board)
    if len(b) == 0:
        print(0)
    else:
        print(a)
elif current_atom == "C":
    not_in_chain()
elif current_atom == "-":
    a, b = biggest_chain(board)
    if len(b) == 0:
        print(str(random.randint(0, len(board) - 1)) + " n")
    elif random.randint(0, 1) == 0:
        print(str(random.randint(a + len(b)/2, len(board) - 1)) + " n")
    else:
        try:
            print(str(random.randint(0, a - len(b)/2 - 1)) + " n")
        except:
            print(str(random.randint(0, len(board) - 1)) + " n")
else:
    not_in_chain()

Apenas um bot muito ruim que muitas vezes faz o controlador travar

TuxCrafting
fonte
Como isso faz o controlador travar? E se isso acontecer, há um problema com o controlador ou seu bot?
mbomb007
@ mbomb007 não me lembro por que ele falhar, mas as falhas foram no controlador
TuxCrafting
Este bot deve funcionar sem erros, basta alterar um pouco o código para acomodar a coisa "stdin" atualizada.
Clismique