Show code
<think>
Okay, let's see. The user wants me to create a self-contained HTML file that simulates diffusion-limited aggregation on a 200x150 cell grid using a canvas. Hmm. DLA is that branching structure where particles stick to a cluster when they hit it. The requirements are pretty specific: strict cell-based movement, no floating points, use requestAnimationFrame for smooth animation, and it should restart automatically when done. Also, need to show the number of frozen cells and the cluster radius, all within 120 lines. Alright, let's break this down step by step.
First, I'll set up the basic HTML structure with a canvas element. The canvas size needs to be 200x150 cells, but the actual dimensions in pixels can be scaled. Maybe 20x15 pixels per cell? Wait, 200 cells wide, 150 tall. To make it visible but not too big, maybe 400x300 pixels (so each cell is 2x2 pixels)? That might be better for visibility. Let me check: 200x2 is 400, 150x2 is 300. Yeah, that works. So the canvas will be 400x300, each cell is 2x2 pixels.
Next, the JavaScript part. I'll need variables for the grid. Since it's 200x150, a 2D array might be too big. Alternatively, a flat array where each row is stored consecutively. Let's see, rows are 150, each with 200 cells. So the array length would be 200 * 150. But maybe using a Uint8Array for efficiency? Not sure, but for simplicity, a regular array might work. Wait, but for performance, maybe a 1D array is better.
The seed cell is in the middle. The middle of a 200x150 grid would be at (100, 75). Wait, since arrays are zero-based, maybe (99,74) if starting from 0? So the center is (Math.floor(gridWidth/2), Math.floor(gridHeight/2)). Let me confirm: gridWidth is 200, so 200//2 is 100, but indexes go from 0 to 199, so the center is (100,75) if 150 rows? Wait, rows would be 150, so y from 0 to 149, so center y is 74.5, so floor is 74. Hmm.
The walkers start from random positions on the perimeter. So each walker is initialized at a random edge of the grid. The edges: top, bottom, left, or right. For each walk, they move randomly in one of the four directions each step until they hit the cluster or are frozen.
Each step for the walker: randomly choose direction (up, down, left, right), but need to stay within the grid. Once they move, check if any adjacent cell is part of the cluster. If yes, freeze and add to the cluster, then spawn a new walker.
The cluster grows over time. The number of frozen cells is tracked, and the radius is the maximum distance from the seed. The radius can be calculated as the maximum of distance between each frozen cell and the seed's coordinates. Maybe store all frozen cells in an array and compute the radius each time a new cell is added?
For the animation, use requestAnimationFrame. The main loop will handle updating the walkers and drawing. Need to make sure it runs smoothly.
Now, the code structure:
- Setup the canvas and context.
- Initialize grid, with the seed in the center.
- Track the current number of frozen cells (starts at 1 initially).
- The radius starts at 0, but after the first step, it will grow.
- Walkers: need to have a list of active walkers. Each walker has x and y coordinates. But maybe process one walker at a time until it sticks? Or process multiple walkers per frame?
Wait, the problem says "random walkers step one cell at a time in the four grid directions and freeze permanently when they touch the cluster". So each frame, one walker takes a step. Or perhaps have multiple walkers active at once? Hmm, maybe the standard DLA approach is one walker at a time until it sticks, then spawn a new one. That might be more efficient.
Wait, the way DLA usually works is that you have particles starting randomly on a perimeter, moving until they stick to the cluster, then another is released. So here, the simulation is per particle, each moving until it sticks or maybe until it goes beyond a certain distance? Or maybe they keep moving until they hit the cluster.
So the steps for each frame: if there are no active walkers (or one), then spawn a new walker on the perimeter. But how to handle multiple walkers? Maybe process one walker per frame. Because if we process too many at once, it might be faster but not accurate. Alternatively, have a bunch of walkers moving each step. But given the grid size, maybe just one walker at a time.
Hmm. Let's think: each frame, check if a current walker exists. If not, spawn a new one. Then, move the walker in a random direction. Check if any of the adjacent cells are part of the cluster. If yes, freeze and add to the cluster, then spawn a new walker. Otherwise, proceed.
Alternatively, have a pool of walkers. But for simplicity, maybe just one walker at a time. That would be easier to code, and maybe faster since each frame only processes one step.
So variables:
- grid: a 1D array representing the grid. Each cell is 0 (empty) or 1 (occupied).
- clusterCells: array of [x,y] positions, to track all frozen cells for radius calculation.
- currentWalker: object with x,y coordinates, and maybe some other state.
- frozenCount: number of frozen cells (starts at 1 for the seed).
- radius: current maximum distance from the seed.
- seedX, seedY: the center coordinates.
- walking: boolean indicating if a walker is active.
The steps in the animation loop would be:
1. If no walker is active, spawn a new one on the perimeter.
2. Move the current walker in a random direction (up, down, left, right).
3. Check if any adjacent cell is part of the cluster. If yes, freeze the walker, add it to the grid and clusterCells, increment frozenCount, compute new radius.
4. Else, continue.
5. After each step, draw the grid on the canvas.
But how to spawn the walker on the perimeter? To choose a random edge and a position on that edge.
For example:
- Randomly select one of the four edges (top, bottom, left, right).
- For top edge: y=0, x random between 0 and 199.
- For bottom edge: y=149, x random between 0 and 199.
- Left edge: x=0, y random between 0 and 149.
- Right edge: x=199, y random between 0 and 149.
So, first, pick a direction (0-3), then compute x,y accordingly.
Once the walker is moving, each step:
- pick a direction (random delta for x and y: like dx and dy can be -