coursework · ZHAW

2048 AI - Best Heuristics

The game 2048 was developed by Gabriele Cirulli. It’s based on 1024 by Veewo Studio and conceptually similar to Threes by Asher Vollmer. Read his story of the making & rip-offs in game development here: http://asherv.com/threes/threemails/

2048 AI in Action

For the “Artificial Intelligence 1” lab, we built two AI agents — one simple, one sophisticated — to play 2048 in the browser. Our best agent scored 146,348.00.

Heuristic AI

We started with a rule-based agent that could already beat a random player. Here’s what we noticed helps achieve a higher score:

  • When many tiles are on the board, the chance that you can’t move any more is greatly increased; thus, one goal is to have the board as empty as possible.
  • If tiles of big value are at the corner of the board, they don’t block the merging of the “smaller” tiles.
  • A move bringing two tiles with the same value next to each other is preferable over a move that won’t give you this advantage.

We baked all of these observations into our board-scoring heuristics (higher is better):

  1. Snake Shape: Enforce layout by multiplying weights to tiles
def heuristic_tile_layout(board):
    rewardBoard = numpy.array([
        [2**15, 2**14, 2**13, 2**12],
        [2**8, 2**9, 2**10, 2**11],
        [2**7, 2**6, 2**5, 2**4],
        [2**0, 2**1, 2**2, 2**3]
    ])

    return numpy.multiply(rewardBoard,board).sum()
  1. Remove Tiles: Reward for removing tiles
  2. Same Move Penalty: Penalty for not changing board
Type Configuration Score
Heuristic Snake Shape + Same Move Penalty + Remove Tiles 10,136.00
Heuristic Snake Shape + Same Move Penalty + Remove Tiles 6,588.00
Heuristic Snake Shape + Same Move Penalty + Remove Tiles 4,684.00
Heuristic Snake Shape + Same Move Penalty + Remove Tiles 4,316.00
Heuristic Snake Shape + Same Move Penalty + Remove Tiles 3,696.00
Heuristic Snake Shape + Same Move Penalty + Remove Tiles 3,340.00
Heuristic Snake Shape + Same Move Penalty + Remove Tiles 3,060.00
Heuristic Snake Shape + Same Move Penalty + Remove Tiles 1,684.00
Heuristic Snake Shape + Same Move Penalty + Remove Tiles 1,100.00
Heuristic Snake Shape + Same Move Penalty + Remove Tiles 832.00
  • MAX: 10,136.00
  • AVG: 3,943.60

With these heuristics, we were able to achieve an average of 3’943 points and a high score of 10’136 points.

Search AI

Expectimax

Using the expectimax algorithm with our snake shape heuristic, we reached the 2048 tile 100% of the time.

def score_toplevel_move(move, board, depth):
    """
    Entry Point to score the first move.
    """
    global UP, DOWN, LEFT, RIGHT
    global move_args

    countZeros = 0
    nodeScore = 0
    childrenResults = []
    newboard = execute_move(move, board)

    # Stop recursion
    if board_equals(board, newboard):
        return 0
    if depth == 0:
        return ha.evaluate_board(board, newboard)

    newboards = get_all_possible_boards(newboard)

    for boardWithNewTile in newboards:
        result = [score_toplevel_move(i, board, maxDepth) for i in range(len(move_args))]
        bestmove = result.index(max(result))
        childrenResults.append(best)

    countChildren = len(childrenResults) - countZeros
    if countChildren == 0:
        return 0

    for node in childrenResults:
            nodeScore += node / countChildren

    return nodeScore

Other things we did:

  • Calculates score + probability for possible boards per move
  • Only placing 2s as opponent to speed up computation
  • MAX_DEPTH: if countFreeTiles <= 4 then 3, else 2
  • Tried Threading, but no performance gain
Type Configuration Score
Search Snake Shape 146,348.00
Search Snake Shape 128,984.00
Search Snake Shape 124,112.00
Search Snake Shape 79,812.00
Search Snake Shape 76,732.00
Search Snake Shape 72,036.00
Search Snake Shape 67,124.00
Search Snake Shape 58,720.00
Search Snake Shape 52,272.00
Search Snake Shape 50,572.00
  • MAX: 146,348.00
  • AVG: 85,671.20

By looking ahead at future possibilities and scoring them, the search agent dramatically outperformed the heuristic-only approach.

This was one of the most fun labs we worked on. The hardest part? Finding a good method to score a given board.