Un juego de proporciones atómicas.

21

Tu tarea es hacer un bot que juegue Atomas , con la puntuación más alta.

Cómo funciona el juego:

El tablero de juego comienza con un anillo de 6 "átomos", con números que van desde 1hasta3 . Puede "jugar" un átomo entre dos átomos, o en otro átomo, dependiendo del átomo mismo.

Puede tener un átomo normal o un átomo especial.

El átomo normal:

Puedes jugar un átomo normal entre dos átomos disponibles en el tablero.

Comienzas con átomos en el rango 1 to 3, pero el rango aumenta en 1 una vez cada 40 movimientos (así que después de 40 movimientos, el rango se convierte 2 to 4).

Si hay átomos en el tablero que son más bajos que el rango, tiene una 1 / no. of atoms of that number on the boardposibilidad de desovar.

Digamos que tienes 2que jugar, y el tablero se ve así:

   1 1 2 1

Coloquemos el 2a la derecha del 1.

El tablero ahora se convierte en:

   1 1 2 1 2

Nota: el tablero se enrolla, por lo que 1el extremo izquierdo está realmente al lado del2 del extremo derecho. Esto será importante más adelante.

Hay 4 tipos de átomos "especiales", y son:

El +átomo:

Este átomo se juega entre dos átomos. Tiene una probabilidad de 1 en 5 de desovar.

Si los átomos en ambos lados del +átomo son iguales, se produce la fusión. Así es 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.

Ejemplo:

   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].

Si los átomos en ambos lados del +átomo son diferentes, entonces el +permanece en el tablero.

Ejemplo:

   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)

El -átomo:

Este átomo se juega en otro átomo. Tiene una probabilidad de 1 en 10 de desovar.

El -átomo elimina un átomo del tablero y le da la opción de:

  • jugar el átomo eliminado la próxima ronda, o
  • conviértelo en un átomo + para jugar la próxima ronda.

Ejemplo:

   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)

El +átomo negro (B ):

Este átomo se juega entre 2 átomos. Tiene una probabilidad de 1 en 80 de generar, y solo genera una vez que su puntaje> 750.

Este átomo es básicamente el mismo que el +átomo, excepto que fusiona dos átomos cualquiera, incluso +el de uno. A partir de entonces, sigue la +regla (solo fusiona átomos juntos si los átomos en ambos lados del átomo fusionado son iguales).

El átomo fusionado como resultado del negro +es igual a:

  • el mayor número de átomos en la fusión + 3
  • 4si los dos átomos fusionados son +de

Ejemplo:

   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)

Otro ejemplo:

   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)

El átomo clon (C ):

Este átomo se juega en otro átomo. Tiene una probabilidad de 1 en 60 de generar, y solo genera una vez que su puntaje> 1500.

El átomo de clonación te permite elegir un átomo y jugarlo la próxima ronda.

Ejemplo:

   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

Aquí está mi versión del juego, en 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()

Cómo funciona el bot:

Entrada

  • Tu bot obtendrá 2 entradas: el átomo que está actualmente en juego y el estado del tablero.
  • El átomo será así:
    • +para un +átomo
    • -para un -átomo
    • Bpara un +átomo negro
    • C para un átomo clon
    • {atom} para un átomo normal
  • El estado del tablero será así:
    • atom 0 atom 1 atom 2... atom n, con los átomos separados por espacios ( atom nvuelve a atom 1, para simular un tablero de juego "en anillo")
  • Estos dos estarán separados por a /.

Entradas de ejemplo:

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)

Salida

  • Producirá una cadena, dependiendo de cuál sea el átomo en juego.

    • Si el átomo está destinado a ser jugado entre dos átomos:

      • Emite el espacio en el que quieres jugar el átomo. Los espacios son como entre cada átomo, así:

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

        ( gap nindica que desea colocar el átomo entre atom 1y el átomo n) Entonces, dé salida 2si desea reproducir el átomo gap 2.

    • Si el átomo está destinado a ser jugado en un átomo:
      • Emite el átomo con el que quieres jugar, así que 2si quieres jugar con el átomo atom 2.
    • Si el átomo es un -:
      • Emite el átomo en el que quieres jugar, seguido de un espacio, seguido de la y/nopción de convertir el átomo en un +más tarde, así que 2, "y"si quieres jugar el átomo atom 2y quieres convertirlo en a +. Nota: esto requiere 2 entradas, en lugar de 1.

Salidas de ejemplo:

(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 que el bot funcione, debe ir al Popenbit (al final del código) y reemplazarlo con lo que haga que su programa se ejecute como una lista Pythonic (por lo tanto, si su programa lo es derp.java, reemplace ["python", "bot.py"]con ["java", "derp.java"]).

Especificaciones específicas de respuesta:

  • Coloque el código completo de su bot en la respuesta. Si no encaja, no cuenta.
  • Cada usuario tiene permitido tener más de 1 bot, sin embargo, todos deben estar en publicaciones de respuestas separadas.
  • Además, dale un nombre a tu bot.

Tanteo:

  • El bot con la puntuación más alta gana.
    • Su bot será probado durante 20 juegos, y la puntuación final es el promedio de los 20 juegos.
  • El desempate será el momento de la carga de la respuesta.
  • Entonces su respuesta tendrá el siguiente formato:

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

¡Buena suerte!

clismique
fuente
¿Cómo funciona el generado +para un -átomo? Si elige y, ¿se le garantizará obtener un +próximo movimiento?
Ton Hospel
44
Sugiero cambiar su controlador de bot para que pueda manejar cualquier programa independiente que reciba información en STDIN y dé un resultado en STDOUT. Eso debería dar independencia lingüística y la mayoría de los idiomas utilizados en este sitio pueden hacerlo fácilmente. Por supuesto, esto significa definir un formato de E / S estricto, por ejemplo, input_atom\natom0 atom1 .... atomn\npara STDIN
Ton Hospel
1
El código parece ser capaz de poner +en la lista de elementos, pero esto no se encuentra en ninguna parte de la descripción textual
Ton Hospel el
1
Ah, veo que hiciste que el programa pudiera llamar a bots externos. Sin embargo, también debe pasar el número de movimiento actual y anotar en STDIN, de lo contrario, el bot no puede predecir las posibilidades de que cada átomo ocurra en el futuro
Ton Hospel
1
No sé si la gente pasará tiempo creando una solución si el controlador no mejora. Me gusta la pregunta, pero no la implementación.
mbomb007

Respuestas:

1

Python, draftBot, Puntuación = 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))

Encontré que el controlador:

  • se bloquea cuando la puntuación supera los 1500;
  • no fusiona adecuadamente los átomos en los mismos casos.
mdahmoune
fuente
0

Python, RandomBot, Puntuación = 7.95

Nada demasiado elegante, solo un bot aleatorio.

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
fuente
0

Python, BadPlayer, Puntuación = 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()

Solo un bot muy malo que a menudo hace que el controlador se bloquee

TuxCrafting
fuente
¿Cómo se bloquea el controlador? Y si lo hace, ¿es un problema con el controlador o su bot?
mbomb007
@ mbomb007 No recuerdo por qué se bloqueó, pero los bloqueos estaban en el controlador
TuxCrafting
Este bot debería funcionar sin ningún error, solo modifique un poco el código para acomodar la cosa actualizada "stdin".
clismique