Using the Game of Life rules, create a heatmap based on the patterns present.
Added basic support for RLE notation (left out the headers): conwaylife.com/wiki/run_length_encoded
Log in to post a comment.
// You can find the Turtle API reference here: https://turtletoy.net/syntax Canvas.setpenopacity(0.2); const turtle = new Turtle(); turtle.penup(); //note: can't exceed 32 due to integer bits. //note: 16 seems the minimum size for the patterns. const BLOCK_COUNT = 16; const BLOCK_SIZE = 200 / BLOCK_COUNT; const BLOCK_HALF_SIZE = BLOCK_SIZE / 2; const MIDDLE_POINT = BLOCK_COUNT / 2; //note: has major impact on the performance. const LINE_SPACING = 0.5; const matrix = new Array(BLOCK_COUNT).fill(0); const buffer = new Array(BLOCK_COUNT).fill(0); // Initialize a random pattern in the middle. if(Math.random() < 0.5) { load_pattern(MIDDLE_POINT - 1, MIDDLE_POINT - 2, "bob$3o$obo$bob!"); } else { load_pattern(MIDDLE_POINT - 2, MIDDLE_POINT - 3, "obobo$o3bo$o3bo$o3bo$obobo!"); } // The walk function will be called until it returns false. function walk(i) { // Render frame. render(); // Calculate next generation. next_generation(); // Should be enough. :) return i < 50; } function render() { for(x = 0; x < BLOCK_COUNT; x++) { for(y = 0; y < BLOCK_COUNT; y++) { if(isset(x, y)) { draw(x, y); } } } } function draw(x, y) { let nx = -100 - BLOCK_HALF_SIZE + (x * BLOCK_SIZE); let ny = -100 + BLOCK_HALF_SIZE + (y * BLOCK_SIZE); for(cy = ny; cy < ny + BLOCK_SIZE; cy += LINE_SPACING) { turtle.goto(nx, cy); turtle.pendown(); turtle.goto(nx + BLOCK_SIZE, cy); turtle.penup(); } } function next_generation() { // Write grid to buffer. for (i = 0; i < BLOCK_COUNT; i++) { buffer[i] = matrix[i]; } // Write new generation to buffer. for (x = 0; x < BLOCK_COUNT; x++) { for (y = 0; y < BLOCK_COUNT; y++) { if (should_toggle_state(x, y)) { buffer[y] ^= (1 << x); } } } // Write buffer to grid. for (i = 0; i < BLOCK_COUNT; i++) { matrix[i] = buffer[i]; } } function should_toggle_state(x, y) { let isAlive = (matrix[y] & (1 << x)) == (1 << x); let numberOfNeighbors = get_number_of_neighbors(x, y, isAlive); if (isAlive && (numberOfNeighbors == 2 || numberOfNeighbors == 3)) { return false; } if (!isAlive && numberOfNeighbors == 3) { return true; } return isAlive; } function get_number_of_neighbors(x, y, isAlive) { let sum = 0; for(cy = y - 1; cy <= y + 1; cy++) { if (cy < 0 || cy >= BLOCK_COUNT) { continue; } let v = matrix[cy] >> (x - 1) & 0x7; v = v - ((v >> 1) & 0x55555555); v = (v & 0x33333333) + ((v >> 2) & 0x33333333); sum += (((v + (v >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; } return isAlive ? sum - 1 : sum; } function set(x, y, value) { if(value) { matrix[y] |= (1 << x); } else { matrix[y] &= ~(1 << x); } } function isset(x, y) { return (matrix[y] & (1 << x)) == (1 << x); } /* Load pattern from RLE format. b = Dead o = Alive $ = Newline */ function load_pattern(startx, starty, rle) { let x = startx, y = starty; let pattern = rle.replace(/(\d+)(\w)/g, function(m,n,c){ return new Array(parseInt(n,10)+1).join(c); } ); for(ci = 0; ci < pattern.length; ci++) { switch(pattern[ci]) { //case "b": // set(x, y, false); // break; case "o": set(x, y, true); break; case "$": x = startx; y++; continue; } x++; } }