Creating the Game World
Learn how to create a 4×4 board and initial tiles in the game 2048.
This lesson builds on the existing code skeleton by initializing the board’s starting state. You’ll use the assistant to generate the initial implementation, then test and validate that generated code.
Step 0: Start with the code skeleton
We begin with the code file from the previous lesson, but with main() now doing something real.
# =========================# Function stubs# =========================def render_board(board: list[list[int]]) -> str:"""We'll implement this in Lesson 3."""return str(board) # temporary fallback (shows raw Python list)def compress_row(row: list[int]) -> list[int]:raise NotImplementedErrordef merge_row(row: list[int]) -> tuple[list[int], int]:raise NotImplementedErrordef move_board(board: list[list[int]], direction: str) -> tuple[list[list[int]], int, bool]:raise NotImplementedErrordef check_game_state(board: list[list[int]], target: int = 2048) -> str:raise NotImplementedError# =========================# Functions we have to implement today# =========================def add_random_tile(board: list[list[int]]) -> None:"""Add a tile (2 or 4) to a random empty cell on the 4x4 board.Mutates board in place."""# TODO: implement this in this lessonraise NotImplementedErrordef create_initial_board() -> list[list[int]]:"""Create a fresh 4x4 board with exactly two random tiles placed."""# TODO: implement this in this lessonraise NotImplementedError("create_initial_board not implemented")# =========================# main() now grows for the first time# =========================def main():print("=== 2048: Creating the Game World ===")board = create_initial_board()print("\nYour initial board:\n")print(render_board(board)) # Uses placeholder rendering for nowif __name__ == "__main__":main()
Run this and see errors, like NotImplementedError. Perfect, now we know exactly what to implement.
Step 1: Implement a 4×4 empty board
When the game starts, a tile with value 2 or 4 is placed at a random position on the board. Before introducing randomness, recall how the board is represented in code.
The board is represented as a list of four lists, where each inner list corresponds to a single row. As 0 represents an empty tile, initialize the board with zeros, then place one or more tiles with value 2 or 4 at random positions.
[[0,0,0,0], [0,0,0,0], [0,0,0,0], [0,0,0,0]]
We have to create this inside create_initial_board(). Scroll down to the function definition create_initial_board() and see lines 41–42. We’ve initialized the variable board with all zeros.
import random # a library for initializing random numbers# =========================# Function stubs# =========================def render_board(board: list[list[int]]) -> str:"""We'll implement this in Lesson 3."""return str(board) # temporary fallback (shows raw Python list)def compress_row(row: list[int]) -> list[int]:raise NotImplementedErrordef merge_row(row: list[int]) -> tuple[list[int], int]:raise NotImplementedErrordef move_board(board: list[list[int]], direction: str) -> tuple[list[list[int]], int, bool]:raise NotImplementedErrordef check_game_state(board: list[list[int]], target: int = 2048) -> str:raise NotImplementedError# =========================# Functions we have to implement today# =========================def add_random_tile(board: list[list[int]]) -> None:"""Add a tile (2 or 4) to a random empty cell on the 4x4 board.Mutates board in place."""# TODO: implement this in this lessonraise NotImplementedErrordef create_initial_board() -> list[list[int]]:"""Create a fresh 4x4 board with all zeros. Return that board."""board = [[0,0,0,0], [0,0,0,0], [0,0,0,0], [0,0,0,0]]return board# =========================# main() now grows for the first time# =========================def main():print("=== 2048: Creating the Game World ===")board = create_initial_board()print("\nYour initial board:\n")print(render_board(board)) # Uses placeholder rendering for nowif __name__ == "__main__":main()
When you run the code, line 52 calls the function, and line 55 prints the raw board for now. In the next lesson, we will see how to render the board for the end user more properly.
Step 2: Implement add_random_tile()
The board is initialized, but we still need to place two random tiles; each tile should be a 2 (90% chance) or a 4 (10% chance). Use the assistant to generate the first draft of add_random_tile(). Paste the prompt below along with your current code (from the editor) so it has full context.
AI prompt:
I’ve written the code for initializing a 4x4 board with all zeros. I want you to write add_random_tile() function for me, which will take this initial board and randomly add a 2 or a 4 on one location each time the function is called. Here are the specs for that: Board is always 4×4. Only place tiles in empty cells (value 0). Tile is 2 (with 90% probability) or 4 (with only 10% probability). Function must mutate the board in place and return None. My codebase is as follows:
Copy the above prompt and paste it in the AI widget below. Then append the prompt with the entire code copied from the code widget from Step 1.
Take the code for the add_random_tile function, which was generated by AI, and paste it in the code widget below, at line 28. If anything goes wrong when you run the code, you can copy the solution from the “Solution” tab as well.
import random# =========================# Function stubs# =========================def render_board(board: list[list[int]]) -> str:"""We'll implement this in Lesson 3."""return str(board) # temporary fallback (shows raw Python list)def compress_row(row: list[int]) -> list[int]:raise NotImplementedErrordef merge_row(row: list[int]) -> tuple[list[int], int]:raise NotImplementedErrordef move_board(board: list[list[int]], direction: str) -> tuple[list[list[int]], int, bool]:raise NotImplementedErrordef check_game_state(board: list[list[int]], target: int = 2048) -> str:raise NotImplementedError# =========================# Functions we have to implement today# =========================def add_random_tile(board: list[list[int]]) -> None:def create_initial_board() -> list[list[int]]:"""Create a fresh 4x4 board with all zeros. Return that board."""board = [[0,0,0,0], [0,0,0,0], [0,0,0,0], [0,0,0,0]]return board# =========================# main() now grows for the first time# =========================def main():print("=== 2048: Creating the Game World ===")board = create_initial_board()print("\nYour initial board:\n")print(render_board(board)) # Uses placeholder rendering for nowif __name__ == "__main__":main()
When you run the program, the output is unchanged; you still see an all-zero board. That’s because add_random_tile() is defined but never called yet.
Step 3: Complete create_initial_board()
You have the function that creates an empty board, initialized by all zeros. You have also got the functionality for changing a tile randomly from 0 to a 2 or a 4, but you have to use that add_random_tile inside the create_initial_board now to complete the requirement of this lesson. For that, we have to make two calls to the function right after we have created the board inside the function create_initial_board, and before the function returns the board.
Lines 48–49 are ready for your contribution. In case of any confusion, you can also look up the solution.
import random# =========================# Function stubs# =========================def render_board(board: list[list[int]]) -> str:"""We'll implement this in Lesson 3."""return str(board) # temporary fallback (shows raw Python list)def compress_row(row: list[int]) -> list[int]:raise NotImplementedErrordef merge_row(row: list[int]) -> tuple[list[int], int]:raise NotImplementedErrordef move_board(board: list[list[int]], direction: str) -> tuple[list[list[int]], int, bool]:raise NotImplementedErrordef check_game_state(board: list[list[int]], target: int = 2048) -> str:raise NotImplementedError# =========================# Functions we have to implement today# =========================def add_random_tile(board: list[list[int]]) -> None:"""Add a tile (2 or 4) to a random empty cell on the 4x4 board.Mutates board in place."""empty_cells = [(i, j) for i in range(4) for j in range(4) if board[i][j] == 0]if not empty_cells:return # No empty cells, can't add a tilei, j = random.choice(empty_cells)# 90% chance to add a 2, 10% chance to add a 4board[i][j] = 2 if random.random() < 0.9 else 4def create_initial_board() -> list[list[int]]:"""Create a fresh 4x4 board with all zeros.Add two random tiles to the board. Return that board."""board = [[0,0,0,0], [0,0,0,0], [0,0,0,0], [0,0,0,0]]return board# =========================# main() now grows for the first time# =========================def main():print("=== 2048: Creating the Game World ===")board = create_initial_board()print("\nYour initial board:\n")print(render_board(board)) # Uses placeholder rendering for nowif __name__ == "__main__":main()
If you have completed the implementation as per the requirements of the game, each time you press the Run button, you will see a new initial board in the output, with two non-zero tiles placed at random locations.
It’s a start
We have a start to the game.
You can now:
Create and reason about a fixed 4×4 grid.
Use AI to generate the implementation of the function by giving it complete specifications.
Implement
add_random_tile()safely.Build
create_initial_board()correctly.Test early functions in isolation.
Extend
main()with real functionality.
This sets the stage for the next lesson, where the board becomes beautifully rendered and the “game” starts feeling alive.