Show code
<think>
Alright, let's tackle this problem. The user wants an HTML file that simulates falling sand using a cellular automaton on a 150x100 grid. The key points are:
- It needs to be self-contained, so all code has to be in one HTML file.
- The grid is 150 cells wide and 100 tall.
- Sand pours from the top, and each step, each sand cell tries to move down, then down-left or down-right if down is blocked, otherwise rests.
- Show resting cells count and step count.
- Use requestAnimationFrame for smooth animation.
- No user input, starts immediately, restarts when finished with a new random instance.
- No external libraries, no comments needed. Strictly under 120 lines.
First, I need to structure the HTML file. It should include a canvas element and a script. The canvas will be used to draw the grid, and the script will handle the cellular automaton logic.
Let me think about the grid. Since it's 150x100, I can represent it as a 2D array. Each cell can have a state: 0 (empty), 1 (moving sand), 2 (resting sand). Wait, but the problem says "each step, every sand cell tries to move one cell down, otherwise down-left or down-right, otherwise rests". So maybe each sand particle is processed each step, checking movement options.
But the user specifies "work strictly cell by cell on the grid". So perhaps each cell can hold a state indicating if it's sand and if it's moving. Maybe an array of arrays where each cell is 0 (empty), 1 (moving sand), 2 (resting sand). The algorithm will process each cell in each step, trying to move down first.
The steps per frame: since it's a cellular automaton, each frame (animation frame) might represent a step. But for smoother animation, perhaps multiple steps per frame? Or each animation frame corresponds to one step. Hmm, the problem says "smooth requestAnimationFrame animation", so probably each frame is a step. But maybe steps are processed each frame, but need to ensure it's fast enough.
The simulation steps:
1. For each cell in the grid, check if it's sand (moving or resting). Wait, moving sand needs to move first. Maybe first, in each step, we process all the moving sand cells to see where they can go.
Alternatively, perhaps we process each cell from top to bottom, left to right. For each cell, if it's sand (assuming moving), check the cell below. If that's empty, move it down and mark as resting? Or maybe:
The algorithm per step:
Loop through each cell in the grid. For each cell that is sand (moving), check if it can move down. If yes, move down and mark as moving again (since maybe next step it can go further). Wait, maybe better to process in a way that movement is determined, then updated in a new grid to prevent race conditions.
Wait, handling cellular automata often requires a buffer to avoid overwriting cells that are being processed. Because if you process a cell and move it, then the next cell below might be processed before the movement is complete. So perhaps we need a temporary buffer to store the next state of each cell.
So here's a possible approach:
- Create a 2D array grid, and a temporary buffer array (same size) to store the next state.
- Each step:
- Initialize buffer to all zeros (or copy the grid?)
- For each cell (r, c) in grid:
- If cell is sand (either moving or resting?), Wait, perhaps moving sand is in a separate state. Maybe:
- 0: empty
- 1: moving sand (needs to move this step)
- 2: resting (can't move)
But how does a sand particle transition between states? Let's think:
When sand is poured initially, it starts as moving (state 1). Then, in each step, check if it can move down. If yes, mark the cell below as moving, and current as empty? Or use the buffer approach.
Wait, perhaps the process is:
For each step:
1. Create a buffer array to hold the next state.
2. For each row from bottom to top, and each column, process the cell:
If the current cell is sand (state 1):
Check the cell below (row+1). If it's empty (0), then in the buffer, set the cell below to 1 (moving), and the current to 0.
If the cell below is blocked (2 or 1), then check diagonals (down-left: row+1, col-1 and down-right: row+1, col+1). If either of those is empty (0), choose one randomly? Or alternately, check left first then right. Wait the problem says "otherwise one cell down-left or down-right". It says "otherwise" meaning if down is blocked, then try down-left or down-right. So maybe first check down, then if blocked, try down-left or down-right (both options?), and if either is available, choose one? But the problem says "otherwise one cell down-left or down-right, otherwise it rests". So if down is blocked, then check left and right directions. If either is available, it can move there; if both are blocked, then it rests (becomes 2).
Wait the exact wording:
"each step, every sand cell tries to move one cell down, otherwise one cell down-left or down-right, otherwise it rests."
So the priority is:
1. Move down if possible (to row+1, same column).
2. If not, try down-left (row+1, column-1) and down-right (row+1, column+1). Wait, the problem says "otherwise one cell down-left or down-right". Maybe it can choose either of the two if possible? Or does it check both and pick one?
Hmm, the problem says "otherwise one cell down-left or down-right", perhaps the sand can move to either if possible. But how to choose between them? Maybe check left first, then right. So first check down-left, if possible, else down-right.
Alternatively, pick a random direction between the two if both are blocked? Wait, no: the problem says "otherwise it rests". So if neither down-left nor down-right are possible, then it can't move and becomes resting.
So the algorithm for a sand cell (state 1) at position (r,c):
- Check if r+1 < rows (within grid). If grid[r+1][c] is 0, then move down to r+1, c, becomes moving again.
Wait, no. Because moving sand is trying to move each step. Once it can't move down, it tries the diagonals.
Wait, the process is: Each sand cell in this step first tries to move down. If it can, then it does so (so in the next step, it will again try to move down again). If it can't, then it tries to move down-left or down-right. If neither is possible, then it stops and becomes resting (state 2).
But how do we track this in the grid?
Perhaps:
- The buffer is used to store the next state of each cell.
- For each cell (r,c) in the grid, if it's moving sand (1):
Check if the cell below (r+1,c) is empty (0):
- If yes, then in the buffer, set (r