Faites une partie parfaite de 2048

18

Votre travail consiste à simuler un jeu mathématiquement parfait de 2048. L'idée est de trouver la limite supérieure théorique de jusqu'où un jeu 2048 peut aller, et de trouver comment y arriver.

Pour avoir une idée de ce à quoi cela ressemble, jouez avec ce clone 2x2 et essayez de marquer 68 points. Si vous le faites, vous vous retrouverez avec une tuile 2, 4, 8 et 16. Il est impossible d'avancer au-delà de ce point.

Votre tâche est facilitée car vous pouvez choisir où les tuiles apparaissent et quelles sont leurs valeurs, tout comme ce clone .

Vous devez écrire un programme ou une fonction qui accepte une carte 2048 en entrée et qui sort la carte avec la tuile générée et la carte après la réduction des tuiles. Par exemple:

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

Votre programme sera alimenté à plusieurs reprises sa propre sortie pour simuler un jeu entier de 2048. La première entrée du programme sera un plateau vide. Vous devez faire apparaître une tuile dessus, contrairement aux deux tuiles du jeu original. À la dernière étape du jeu, vous ne pourrez pas vous déplacer, vos deux cartes de sortie peuvent donc être identiques.

Vous devez bien sûr uniquement produire des mouvements légaux. Seul 2 ou 4 peuvent être générés, vous devez déplacer ou réduire au moins une tuile lors d'un mouvement, etc.

J'ai délibérément rendu les exigences d'entrée et de sortie vagues. Vous êtes libre de choisir le format de l'entrée et de la sortie. Vous pouvez utiliser des matrices, des tableaux, des chaînes ou tout ce que vous voulez. Tant que vous pouvez simuler un jeu 2048 avec eux, vos entrées et sorties sont correctes.

Le gagnant sera celui qui termine la partie avec le plus grand nombre de tuiles du plateau, puis le plus petit nombre d'octets dans le code source. Le score du jeu original ne sera pas pris en compte. (Astuce: utilisez 4)

Kendall Frey
la source
@undergroundmonorail C'est différent de cette question. Cette question permet de générer vos propres tuiles, et va aussi loin que possible mathématiquement, pas seulement jusqu'en 2048.
Kendall Frey
1
@TheDoctor 68 est une somme de puissances de 2, et est ce que serait votre score si vous obtenez 2, 4, 8, 16.
user12205
2
Est-ce vraiment un doublon? Que faudrait-il de plus pour le rendre différent?
Kendall Frey
1
@Quincunx Cela générerait vraiment un jeu sous-optimal cependant.
Kendall Frey
4
J'ai trouvé que le cœur de ce défi, "Trouver une solution optimale", était unique, mais il est vrai que ce n'était pas un bon choix de l'enfermer dans un "shell" en double. Celui-ci crie, "Oh regarde, un autre défi du Code Golf 2048". Les votes serrés étant si subjectifs, vous devez vraiment vendre votre défi à la foule. Parfois, cela signifie générer votre propre arnaque terrible de 2048.
Rainbolt

Réponses:

4

Ruby, dans le coin, score: 3340

Voici une stratégie très simple pour lancer cela. J'ai une idée d'un score (presque) parfait, mais j'ai du mal à le formaliser, alors voici quelque chose de simple pour faire avancer les choses.

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

La advancefonction est celle que vous demandez. Il prend une planche en tableau 1d et retourne la planche après que la tuile a été générée et après que le mouvement a été effectué.

Vous pouvez le tester avec cet extrait

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 :+}"

La stratégie est très simple, et c'est celle que j'ai utilisée pour passer au 128 lorsque je jouais 2048 moi-même: il suffit d'alterner entre haut et gauche . Pour que cela fonctionne aussi longtemps que possible, de nouveaux 4s apparaissent dans le coin inférieur droit.

EDIT: J'ai ajouté un commutateur codé en dur pour aller à droite plusieurs fois à des étapes spécifiques juste avant la fin, ce qui me permet en fait d'atteindre 1024. Cela devient cependant quelque peu incontrôlable, donc je vais arrêter avec cela pour l'instant et penser à une approche généralement meilleure demain. (Honnêtement, le fait que je puisse augmenter mon score d'un facteur 4 en ajoutant des hacks ajustés à la main me dit seulement que ma stratégie est de la merde.)

C'est le tableau avec lequel vous vous retrouvez

1024 512 256 128
 512 256 128  16
 256 128  64   8
   8  32   8   4
Martin Ender
la source
Pour faire simple, la génération de 4 ne vous donne pas un score optimal car vous n'obtenez pas les 4 points à chaque fois que l'un est créé au lieu d'être généré par 2 2.
BrunoJ
@BrunoJ Le score de ce défi est simplement calculé comme le total de toutes les tuiles à la fin, pas le score que vous auriez dans le jeu réel. Mais si c'était le cas, vous avez bien sûr raison. ;) ... Bien que je pense qu'avec ma stratégie, cela ne ferait pas de différence, car je n'atteindrais que 128 au lieu de 256.
Martin Ender
Oh, je n'ai pas compris que le score n'est pas le même, mes excuses
BrunoJ