video.mp4
After experimenting with recursion using command blocks in Minecraft, I challenged myself to implement Conway's Game of life.
In the end, I was able to create a smoothly running simulation on a 20x20 grid. A main feature is that the screen can be expanded only with a small constant amount of effort per pixel.
At the top is a video showing the Pentadecathlon configuration.
- unzip
TheGameOfLife.zipand putTheGameOfLifedirectory into your Minecraft Worlds foldersaves. - Join the World with Minecraft version 1.21.1
Glowstone and blackstone are representing cells that are alive and dead. Those blocks are placed in a plane inside the Minecraft world, forming the world grid.
We can check if the cell at position (x, y, z) is alive by using the following command:
execute if block x y z glowstone run say cell is alive.
The say command is only executed if the block at (x, y, z) is glowstone.
For counting dead and alive neighbors, we need some kind of variable.
The easiest way to store numbers are the scoreboards of the game.
execute can also be used for storing the number of living neighbors of a cell at position (x, y, z) into all player scores.
After replacing all [formula] with their specific value, the following commands would be valid:
scoreboard players set @a count 0
execute if block [x-1] [y] [z] minecraft:glowstone run scoreboard players add @a count 1
execute if block [x-1] [y+1] [z] minecraft:glowstone run scoreboard players add @a count 1
execute if block [x] [y+1] [z] minecraft:glowstone run scoreboard players add @a count 1
execute if block [x+1] [y+1] [z] minecraft:glowstone run scoreboard players add @a count 1
execute if block [x-1] [y] [z] minecraft:glowstone run scoreboard players add @a count 1
execute if block [x-1] [y-1] [z] minecraft:glowstone run scoreboard players add @a count 1
execute if block [x] [y-1] [z] minecraft:glowstone run scoreboard players add @a count 1
execute if block [x+1] [y-1] [z] minecraft:glowstone run scoreboard players add @a count 1
@a is a selector for all players, and count is a previously created scoreboard.
The first command initializes the count score for all players to 0.
The following commands are checking all surrounding cells; if the checked cell is alive, the score is increased by one.
In the end, the score is equal to the count of living neighbors of the given cell.
Command blocks can execute those commands. However, for larger screens, it would be insane to hardcode all those coordinates by hand. Relative coordinates save the day.
With ~dx ~dy ~dz we can address blocks relatively from the current player position or command block position.
By placing the neighbor counting commands blocks at specific relative offsets (dx,dy,dz) to the cell, we can use the following commands:
scoreboard players set @a count
execute if block ~[dx+1] ~[dy] ~[dz] minecraft:glowstone run scoreboard players add @a count 1
execute if block ~[dx-1] ~[dy+1] ~[dz] minecraft:glowstone run scoreboard players add @a count 1
execute if block ~[dx] ~[dy+1] ~[dz] minecraft:glowstone run scoreboard players add @a count 1
execute if block ~[dx+1] ~[dy+1] ~[dz] minecraft:glowstone run scoreboard players add @a count 1
execute if block ~[dx-1] ~[dy] ~[dz] minecraft:glowstone run scoreboard players add @a count 1
execute if block ~[dx-1] ~[dy-1] ~[dz] minecraft:glowstone run scoreboard players add @a count 1
execute if block ~[dx] ~[dy-1] ~[dz] minecraft:glowstone run scoreboard players add @a count 1
execute if block ~[dx+1] ~[dy-1] ~[zd] minecraft:glowstone run scoreboard players add @a count 1
This looks more complicated, however, it allows us to just copy those commands into multiple commands at different locations. We can therefore use the same commands for counting neighbors for different cells.
Next we discuss how to change the state of cells.
The classic game of life obeys to the following rules:
- Any live cell with fewer than two live neighbors dies, as if by underpopulation.
- Any live cell with two or three live neighbors lives on to the next generation.
- Any live cell with more than three live neighbors dies, as if by overpopulation.
- Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction
By simplifying the rules, we get:
- Any live cell with more than three neighbors dies.
- Any live cell with less than two neighbors dies.
- Any dead cell with exactly three neighbors rises from the dead.
Conveniently, we can leverage the execute command again.
This time, however, we have to compare to values.
Specifically, the values 2 and 3.
Therefore, I created two entities holding scoreboard values 2 and 3.
@e[name=Two,limit=1] can addresses a bat holding the value 2 in its score.
Now for a cell placed at offset (dx, dy, dz) we can implement the following rules:
execute if block ~[dx] ~[dy] ~[dz] glowstone if score @a count > @e[name=Three,limit=1] count run setblock ~[dx] ~[dy] ~[dz] minecraft:blackstone
execute if block ~[dx] ~[dy] ~[dz] glowstone if score @a count < @e[name=Two,limit=1] count run setblock ~[dx] ~[dy] ~[dz] minecraft:blackstone
execute if block ~[dx] ~[dy] ~[dz] blackstone if score @a count = @e[name=Three,limit=1] count run setblock ~[dx] ~[dy] ~[dz] minecraft:glowstone
Those conditions are mutual exclusive. This allows us to run those commands in sequence without any branching.
- init scoreboard
- count live neighbors
- update cell
Now we can simulate a single cell.
If we want to simulate multiple cells at once, we have to store the neighbor count individually at different places.
Until now, the counts from different cells are all stored in the scores of all players.
The easiest way is to introduce for each cell a new entity, like a ItemFrame.
This entity can't move by default, can be placed like a block and doesn't despawn.
The selector @e[type=minecraft:item_frame,limit=1,sort=nearest] selects the nearest ItemFrame from the position of execution.
Relative to the command block position, we can now also address different values inside the scoreboard.
Now extending the grid by one cell is easy.
- clone the command blocks
- init the cell state
- place the
ItemFrame
For the 20x20 screen, automation seemed worthwhile.
One issue is still not covered. Due to the parallel nature of cell computation, reading and writing from the same grid leads to race conditions. A cell counting it neighbors would also count already updated neighbors. Using two grids can solve this concurrency issue. Therefore, I copied the latest grid state to another location before cells can safely read it.
The final simulation runs fluently on the 20x20 screen. In the future, it would be interesting to explore larger screen sizes.
By sharing the world, you can try it by your self.
Thanks for reading!



