Skip to content

Instantly share code, notes, and snippets.

@shuuki
Last active November 13, 2016 06:25
Show Gist options
  • Save shuuki/6b9411f3906a2097b60303d50e48cfac to your computer and use it in GitHub Desktop.
Save shuuki/6b9411f3906a2097b60303d50e48cfac to your computer and use it in GitHub Desktop.
CAVE MAKER PROCJAM
#output
canvas(id="map" width="500" height="500")
#controls
fieldset
legend New
button#render(onclick="render(parse_config(ui))") Render
fieldset
legend Export
button#save_img Save Image
button#save_txt Save Text
button#save_config Save Settings
fieldset
legend Canvas
label(for="block_size") Block Size
input#block_size(type="number" min="1" value="10")
hr
label(for="map_size") Map Size
input#map_size(type="number" min="1" value="50")
fieldset
legend Starting Location
label(for="root_y") X
input#root_x(type="range" min="0" max="1" step="0.01" value="0.5")
input#random_root_x(type="checkbox")
label(for="random_root_x") Random
hr
label(for="root_y") Y
input#root_y(type="range" min="0" max="1" step="0.01" value="0.5")
input#random_root_y(type="checkbox")
label(for="random_root_y") Random
fieldset
legend Draw Area
input#draw_area(type="range" min="0" max="1" step="0.01" value="0.125")
input#random_draw_area(type="checkbox")
label(for="random_draw_area") Random
fieldset
legend Regularity
input#regularity(type="range" min="1" max="100" step="1" value="4")
input#random_regularity(type="checkbox")
label(for="random_regularity") Random
fieldset
legend Walking Directions
input#walk_cardinal(type="radio" name="walking")
label(for="walk_cardinal") Cardinal
input#walk_diagonal(type="radio" name="walking" checked)
label(for="walk_diagonal") Diagonal
hr
input#walk_orthogonal(type="checkbox" name="walking")
label(for="walk_orthogonal") Orthogonal
fieldset
legend Colors
input#color_bg(type="color" value="#ff00ff")
label(for="color_bg") Canvas
input#color_bg_trans(type="checkbox" name="colors" checked)
label(for="color_bg_trans") Transparent
hr
input#color_fg(type="color" value="#000000")
label(for="color_fg") Cave
input#color_fg_trans(type="checkbox" name="colors")
label(for="color_fg_trans") Transparent
fieldset
legend Defaults
button#reset Reset
button#load_config Load Settings
fieldset
legend About
span SF2016
/*
DRUNK TURTLE'S RANDOM DIFFUSION LIMITED AGGREGATION WALK
*/
"use strict";
function random(count) {
return Math.floor(Math.random() * count);
}
function render(config) {
/*
CONFIGURATION
*/
var config = config || {};
console.log(config)
// size of the map
var edge = config.map_size || 50;
var area = edge * edge;
// size in pixels of final rendered blocks
var block = config.block_size || 10;
// base block where growth begins
var rootX = config.random_root_x ? edge * Math.random() : edge * config.root_x || edge * 0.5;
var rootY = config.random_root_y ? edge * Math.random() : edge * config.root_y || edge * 0.5;
// maximum number of allocated blocks
var limit = config.random_draw_area ? area * Math.random() : area * config.draw_area || area * 0.125;
//
// maximum corridor length
// low = dense, blobby, organic
// high = elongated, angular
// minimum = 1, maximum = ?
var regularity = config.random_regularity ? random(100) : config.regularity || 4;
// allow orthogonal movement?
// false = blockier, easier to navigate, no orphans
// true = finer, harder to navigate, some orphans
var orthogonal = config.walk_orthogonal || false;
// choose a random direction to walk
// change available directions:
// 0-3 = NSEW only, 4-7 = all directions
var where = 0;
if (config.walk_cardinal === true) { where = 3 }
else if (config.walk_diagonal === true) { where = 7 }
else { where = 7 }
var stagger = function() {
return Math.floor(Math.random() * where);
}
/*
FUNCTIONAL VARIABLES
*/
// set up null values
var y, x, cy, cx;
var walking = false;
var direction = 0;
var stepped = 0;
var allocated = 0;
// build a blank map
var map = base();
/*
UTILITIES
*/
function base() {
// set up empty map array
var grid = new Array(edge);
// add dimension to map array
for (var i = 0; i < area; ++i) {
grid[i] = new Array(edge);
}
// fill the map with zeros
for (var x = 0; x < edge; ++x) {
for (var y = 0; y < edge; ++y) {
grid[x][y] = 0;
}
}
// return completed base map
return grid;
}
/*
AGGREGATION LOOP
*/
while (allocated < limit) {
if (walking === false) {
spawnTurtle();
} else {
moveTurtle();
// ensure that the turtle is touching an existing spot
if (cx < edge && cy < edge && cx > 1 && cy > 1 && stepped <= regularity) {
turtleBuild();
} else {
walking = false;
}
}
}
function spawnTurtle() {
// spawn turtle at random position
cx = random(edge);
cy = random(edge);
// check if turtle spawned on root
if (Math.abs(rootX - cx) === 0 && Math.abs(rootY - cy) === 0) {
// turtle spawned too close to root, respawn somewhere else
if (map[cx][cy] != 1) {
map[cx][cy] = 1;
allocated++;
}
}
// drunken turtle takes a shot
else {
stepped = 0;
walking = true;
direction = stagger();
}
}
function moveTurtle() {
// drunk turtle takes a step
stepped++;
// which way does drunk turtle go?
// N
if (direction === 0 && cy > 0) {
cy--;
}
// NE
else if (direction === 4 && cx < edge && cy > 0) {
cy--;
cx++;
}
// E
else if (direction === 1 && cx < edge) {
cx++;
}
// SE
else if (direction === 5 && cx < edge && cy < edge) {
cy++;
cx++;
}
// S
else if (direction === 2 && cy < edge) {
cy++;
}
// SW
else if (direction === 6 && cx > 0 && cy < edge) {
cy++;
cx--;
}
// W
else if (direction === 3 && cx > 0) {
cx++;
}
// NW
else if (direction === 7 && cx > 0 && cy > 0) {
cy--;
cx--;
}
}
function turtleBuild() {
// N
if (map[cx][cy - 1] === 1) {
if (map[cx][cy] != 1) {
map[cx][cy] = 1;
allocated++;
}
}
// NE
else if (map[cx + 1][cy - 1] === 1) {
if (map[cx][cy] != 1) {
map[cx][cy] = 1;
allocated++;
if (!orthogonal) {
map[cx + 1][cy] = 1;
allocated++;
}
}
}
// E
else if (map[cx + 1][cy] === 1) {
if (map[cx][cy] != 1) {
map[cx][cy] = 1;
allocated++;
}
}
// SE
else if (map[cx + 1][cy + 1] === 1) {
if (map[cx][cy] != 1) {
map[cx][cy] = 1;
allocated++;
if (!orthogonal) {
map[cx + 1][cy] = 1;
allocated++;
}
}
}
// S
else if (map[cx][cy + 1] === 1) {
if (map[cx][cy] != 1) {
map[cx][cy] = 1;
allocated++;
}
}
// SW
else if (map[cx - 1][cy + 1] === 1) {
if (map[cx][cy] != 1) {
map[cx][cy] = 1;
allocated++;
if (!orthogonal) {
map[cx - 1][cy] = 1;
allocated++;
}
}
}
// W
else if (map[cx - 1][cy] === 1) {
if (map[cx][cy] != 1) {
map[cx][cy] = 1;
allocated++;
}
}
// NW
else if (map[cx - 1][cy - 1] === 1) {
if (map[cx][cy] != 1) {
map[cx][cy] = 1;
allocated++;
if (!orthogonal) {
map[cx - 1][cy] = 1;
allocated++;
}
}
}
}
/*
RENDERER
*/
// Draw the map
var canvas = document.getElementById("map");
var context = canvas.getContext("2d");
for (var x = 0; x < edge; ++x) {
for (var y = 0; y < edge; ++y) {
if (map[x][y] === 0) {
context.fillStyle = config.color_bg_trans ? "rgba(0,0,0,0)" : config.color_bg || "#d8d8d8";
context.fillRect(x * block, y * block, block, block);
} else if (map[x][y] === 1) {
context.fillStyle = config.color_fg_trans ? "rgba(0,0,0,0)" : config.color_fg || "#121212";
context.fillRect(x * block, y * block, block, block);
}
}
}
}
var ui = [
'render',
'save_img',
'save_txt',
'save_config',
'block_size',
'map_size',
'root_x',
'random_root_x',
'root_y',
'random_root_y',
'draw_area',
'random_draw_area',
'regularity',
'random_regularity',
'walk_cardinal',
'walk_diagonal',
'walk_orthogonal',
'color_bg',
'color_bg_trans',
'color_fg',
'color_fg_trans',
'reset',
'load_config'
];
function parse_config(config) {
var settings = {}
function parse(a) {
var x = document.getElementById(a)
if (x.type === 'number' || x.type === 'range' || x.type === 'color') {
settings[a] = x.value
}
if (x.type === 'checkbox' || x.type === 'radio') {
settings[a] = x.checked
}
//settings[a] = x
}
if (document && config) {
config.forEach(parse)
}
return settings;
}
var settings = parse_config(ui);
render(settings);
//console.log(settings)
* {
box-sizing: border-box;
}
body {
background: #212121;
color: #f8f8f8;
margin: 0;
}
#output {
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAAAAACo4kLRAAAAF0lEQVR4AWN4DQcP4WBoCyKYCOkhLQgA355ncNg2H2MAAAAASUVORK5CYII=');
background-color: #f8f8f8;
height: 60%;
overflow: auto;
position: absolute;
text-align: center;
top: 0;
width: 100%;
}
#controls {
//align-items: top;
background: #212121;
bottom: 0;
color: #f8f8f8;
//display: flex;
//flex-flow: row wrap;
font-family: monospace;
height: 40%;
//justify-content: flex-start;
overflow: scroll;
padding: 1em;
position: absolute;
width: 100%;
}
fieldset {
background: #898989;
border: 2px solid #989898;
border-radius: 0.25em;
box-shadow: 0.25em 0.25em 0.25em rgba(0,0,0,0.2);
display: inline-block;
margin: 0.25em;
vertical-align: top;
}
legend {
background: #212121;
border: none;
border-bottom: 2px solid #989898;
border-radius: 0.25em;
color: #989898;
padding: 0.25em 0.5em;
}
hr {
border: none;
border-top: 2px solid #989898;
}
button,
input[type=checkbox],
input[type=radio],
input[type=range],
input[type=color] {
.reset-inheritance;
}
input[type=number],
input[type=text] {
.reset-inheritance;
width: 8em;
padding: 0.25em;
&:focus {
outline: 3px solid rgba(0,255,255,0.6);
}
}
.reset-inheritance {
font-family: inherit;
font-size: inherit;
font-weight: inherit;
line-height: inherit;
vertical-align: baseline;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment