Algorithm
Puzzle Solver
Block Placement
Optimization
Block Blast

How can I algorithmically determine optimal block placement in a Block Blast-style puzzle solver?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

A Block Blast-style solver is not just checking whether one move fits. It is searching a branching decision tree where each placement changes the board, affects future mobility, and may clear rows or columns.

Model the Game State First

Before talking about optimization, define the game state precisely:

  • the board occupancy grid
  • the current set of available pieces
  • whether rotations are allowed
  • the line-clear rules and scoring rules
  • the lookahead depth you want to search

For many puzzle variants, the best practical solver is an exact search over the next few pieces combined with a heuristic evaluation of the resulting board. Full-game exhaustive search is usually too large, but short-horizon exhaustive search is often realistic because there are only so many legal placements for each piece.

A Search-Based Solver

The code below implements a small depth-first solver for an 8 x 8 board. It tries every legal placement for each upcoming piece, applies row and column clears, and keeps the move sequence with the best score.

python
1from copy import deepcopy
2
3SIZE = 8
4
5pieces = {
6    "square": [(0, 0), (0, 1), (1, 0), (1, 1)],
7    "line3": [(0, 0), (0, 1), (0, 2)],
8    "L": [(0, 0), (1, 0), (2, 0), (2, 1)],
9}
10
11
12def empty_board():
13    return [[0 for _ in range(SIZE)] for _ in range(SIZE)]
14
15
16def fits(board, piece, top, left):
17    for dr, dc in piece:
18        r = top + dr
19        c = left + dc
20        if r < 0 or c < 0 or r >= SIZE or c >= SIZE:
21            return False
22        if board[r][c] == 1:
23            return False
24    return True
25
26
27def place_and_clear(board, piece, top, left):
28    new_board = deepcopy(board)
29    for dr, dc in piece:
30        new_board[top + dr][left + dc] = 1
31
32    full_rows = [r for r in range(SIZE) if all(new_board[r][c] == 1 for c in range(SIZE))]
33    full_cols = [c for c in range(SIZE) if all(new_board[r][c] == 1 for r in range(SIZE))]
34
35    for r in full_rows:
36        for c in range(SIZE):
37            new_board[r][c] = 0
38
39    for c in full_cols:
40        for r in range(SIZE):
41            new_board[r][c] = 0
42
43    cleared = len(full_rows) + len(full_cols)
44    return new_board, cleared
45
46
47def heuristic(board):
48    empty_cells = sum(cell == 0 for row in board for cell in row)
49    near_full_rows = sum(sum(row) == SIZE - 1 for row in board)
50    near_full_cols = sum(sum(board[r][c] for r in range(SIZE)) == SIZE - 1 for c in range(SIZE))
51    return empty_cells + 5 * (near_full_rows + near_full_cols)
52
53
54def search(board, queue):
55    if not queue:
56        return heuristic(board), []
57
58    piece_name = queue[0]
59    piece = pieces[piece_name]
60    best_score = float("-inf")
61    best_moves = []
62    move_found = False
63
64    for r in range(SIZE):
65        for c in range(SIZE):
66            if not fits(board, piece, r, c):
67                continue
68
69            move_found = True
70            next_board, cleared = place_and_clear(board, piece, r, c)
71            future_score, future_moves = search(next_board, queue[1:])
72            total_score = cleared * 100 + future_score
73
74            if total_score > best_score:
75                best_score = total_score
76                best_moves = [(piece_name, r, c)] + future_moves
77
78    if not move_found:
79        return -100000, []
80
81    return best_score, best_moves
82
83
84board = empty_board()
85score, moves = search(board, ["square", "line3", "L"])
86print(score)
87print(moves)

This is already a real solver. It is not fast enough for every production use case, but it captures the correct optimization structure: generate legal moves, simulate them, recurse into the next piece, and score the resulting board.

What Makes a Placement Good

Raw line clears matter, but they are not the whole story. Good solvers also care about board shape because the current move affects future flexibility.

Useful heuristic features include:

  • number of empty cells
  • number of almost-complete rows or columns
  • number of isolated holes that are hard to fill later
  • piece placement flexibility for the remaining queue
  • penalties for creating narrow dead zones

Once the branching factor grows, alpha-beta style pruning is less helpful than in strict adversarial games because this is mostly a single-player search problem. Better performance usually comes from move ordering, beam search, bitboard representations, memoization, or limiting lookahead depth.

Exact Search Versus Heuristics

If you only search the currently visible pieces, you can often solve the subproblem exactly. If you try to optimize the entire future of an endless puzzle game, you need heuristics or learned value estimates because the horizon is too large.

That is why strong solvers often combine both ideas. They do exact search over the next few pieces and use a heuristic to estimate the longer-term quality of the resulting position. This hybrid approach usually gives most of the benefit without the full cost of exhaustive planning.

Common Pitfalls

  • Scoring only immediate line clears and ignoring whether the move ruins future mobility.
  • Forgetting to simulate the actual clear rules before evaluating the new board.
  • Searching placements for one piece greedily when the game presents multiple upcoming pieces.
  • Using a slow board representation after the search depth grows. Bitboards or packed integers can be much faster than nested lists.
  • Assuming there is always one globally optimal move independent of future piece order. In these games, the queue matters.

Summary

  • Block placement is best framed as a search problem over board states and upcoming pieces.
  • A practical solver enumerates legal moves, simulates clears, and scores future board states.
  • Strong heuristics care about flexibility and hole creation, not just immediate points.
  • Exact search works well for short lookahead windows, while long-horizon play needs approximation.
  • Performance improvements usually come from better state representation and smarter pruning, not from a purely greedy policy.

Course illustration
Course illustration

All Rights Reserved.