Jogue um jogo perfeito de 2048

18

Seu trabalho é simular um jogo matematicamente perfeito de 2048. A idéia é encontrar o limite superior teórico de quão longe um jogo de 2048 pode ir e descobrir como chegar lá.

Para ter uma idéia de como isso é, brinque com esse clone 2x2 e tente marcar 68 pontos. Se fizer isso, você terminará com um bloco de 2, 4, 8 e 16. É impossível avançar além desse ponto.

Sua tarefa é facilitada porque você pode escolher onde os blocos aparecerão e quais serão seus valores, assim como este clone .

Você deve escrever um programa ou função que aceite uma placa 2048 como entrada e produza a placa com o bloco gerado e o painel após o recolhimento dos blocos. Por exemplo:

Input:
-------
0 0 0 0
0 0 0 0
0 0 0 0
0 0 8 8

Output:
-------
0 0 0 0
0 0 0 0
0 0 0 0
0 4 8 8

0 0 0 0
0 0 0 0
0 0 0 0
0 0 4 16

Seu programa receberá repetidamente sua própria saída para simular um jogo inteiro de 2048. A primeira entrada do programa será um tabuleiro vazio. Você deve gerar uma peça sobre ela, diferente das duas peças do jogo original. Na última etapa do jogo, você não poderá se mover, portanto suas duas placas de saída podem ser idênticas.

Obviamente, você deve produzir apenas movimentos legais. Apenas um 2 ou 4 pode ser gerado, você deve mover ou recolher pelo menos um bloco em um movimento, etc.

Eu propositadamente tornei os requisitos de entrada e saída vagos. Você é livre para escolher o formato da entrada e saída. Você pode usar matrizes, matrizes, strings ou o que quiser. Contanto que você possa simular um jogo de 2048 com eles, suas entradas e saídas são boas.

O vencedor será aquele que terminar o jogo com a maior soma de peças no tabuleiro e, em seguida, com o menor número de bytes no código-fonte. A pontuação do jogo original não será levada em consideração. (Dica: use 4)

Kendall Frey
fonte
@undergroundmonorail Isso é diferente dessa pergunta. Esta questão permite desova suas próprias telhas, e é sobre ir tão longe quanto possível matematicamente, não apenas para 2048.
Kendall Frey
11
@TheDoctor 68 é uma soma de potências de 2 e é sua pontuação se você obtiver 2, 4, 8, 16. #
user12205 13/14
2
Isso é realmente uma duplicata? O que mais seria necessário para torná-lo diferente?
Kendall Frey
11
@ Quincunx Isso realmente geraria um jogo abaixo do ideal.
Kendall Frey
4
Eu achei o coração desse desafio, "Encontre uma solução ideal", único, mas reconhecidamente foi uma má escolha incluí-lo em um "shell" duplicado. Este grita: "Oh, olhe, outro desafio do Código Golf de 2048". Como os votos próximos são tão subjetivos, você realmente precisa vender seu desafio à multidão. Às vezes isso significa gerar sua própria imitação terrível de 2048.
Rainbolt

Respostas:

4

Ruby, Para o Canto, Pontuação: 3340

Aqui está uma estratégia muito simples para iniciar isso. Eu tenho uma idéia para uma pontuação (quase) perfeita, mas estou tendo problemas para formalizá-la, então aqui está algo simples para fazer as coisas acontecerem.

def slide board, dir
    case dir
    when 'U'
        i0 = 0
        i_stride = 1
        i_dist = 4
    when 'D'
        i0 = 15
        i_stride = -1
        i_dist = -4
    when 'L'
        i0 = 0
        i_stride = 4
        i_dist = 1
    when 'R'
        i0 = 15
        i_stride = -4
        i_dist = -1
    end

    4.times do |x|
        column = []
        top_merged = false
        4.times do |y|
            tile = board[i0 + x*i_stride + y*i_dist]
            next if tile == 0
            if top_merged || tile != column.last
                column.push tile
                top_merged = false
            else
                column[-1] *= 2
                top_merged = true
            end
        end

        4.times do |y|
            board[i0 + x*i_stride + y*i_dist] = column[y] || 0
        end
    end

    board
end

def advance board
    if board.reduce(:*) > 0
        return board, board
    end

    16.times do |i|
        if board[15-i] == 0
            board[15-i] = 4
            break
        end
    end

    spawned = board.clone

    # Attention, dirty dirty hand-tweaked edge cases to avoid
    # the inevitable for a bit longer. NSFS!
    if board[11] == 8 && (board[12..15] == [32, 16, 4, 4] ||
                          board[12..15] == [16, 16, 4, 4] && board[8..10] == [256,64,32]) || 
       board[11] == 16 && (board[12..15] == [32, 8, 4, 4] || 
                           board[12..15] == [4, 32, 8, 8] || 
                           board[12..15] == [4, 32, 0, 4])

        dir = 'R'
    elsif board[11] == 16 && board[12..15] == [4, 4, 32, 4] ||
          board[11] == 8 && board[12..15] == [0, 4, 32, 8]
        dir = 'U'
    else
        dir = (board.reduce(:+)/4).even? ? 'U' : 'L'
    end

    board = slide(board, dir)

    if board == spawned
        dir = dir == 'U' ? 'L' : 'U'
        board = slide(board, dir)
    end
    return spawned, board
end

A advancefunção é a que você está solicitando. Ele pega um tabuleiro como matriz 1d e o devolve depois que o ladrilho foi gerado e depois que a jogada foi feita.

Você pode testá-lo com este trecho

board = [0]*16
loop do
    spawned, board = advance(board)
    board.each_slice(4) {|row| puts row*' '}
    puts
    break if board[15] > 0
end

puts "Score: #{board.reduce :+}"

A estratégia é muito simples, e é a que eu realmente costumava pular para o 128 quando estava jogando 2048: apenas alterne entre cima e esquerda . Para fazer isso funcionar o máximo de tempo possível, novos 4s são gerados no canto inferior direito.

EDIT: Eu adicionei um comutador codificado para ir para a direita algumas vezes em etapas específicas antes do final, o que na verdade me permite chegar a 1024. Isso está ficando um pouco fora de controle, por isso vou parar com isso por enquanto e pense em uma abordagem geralmente melhor amanhã. (Honestamente, o fato de eu poder aumentar minha pontuação em um fator 4, adicionando hacks ajustados à mão, apenas me diz que minha estratégia é péssima.)

Este é o quadro com o qual você acaba

1024 512 256 128
 512 256 128  16
 256 128  64   8
   8  32   8   4
Martin Ender
fonte
Apenas para nitpick, gerar 4 não dá uma pontuação ideal, porque você não está ganhando os 4 pontos cada vez que um é criado, em vez de ser gerado por 2 2.
brunoJ
@BrunoJ A pontuação deste desafio é simplesmente calculada como o total de todas as peças no final, não a pontuação que você teria no jogo real. Mas se for esse o caso, você está certo, é claro. ;) ... Embora eu ache que com a minha estratégia não faria diferença, porque eu só chegaria a 128 em vez de 256 então.
Martin Ender
Oh, não entendi que a pontuação não é o mesmo, as minhas desculpas
brunoJ