From 3931cbcec2f306f02194d7884ed2bb996b4fb386 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Thu, 12 Nov 2015 22:16:28 -0800 Subject: [PATCH] move JS to separate file --- .gitignore | 3 + index.html | 806 +---------------------------------------------------- js/main.js | 804 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 809 insertions(+), 804 deletions(-) create mode 100644 .gitignore create mode 100644 js/main.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9b5a796 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# vim files +*.swp +*.sqo diff --git a/index.html b/index.html index ab55af5..7e22693 100644 --- a/index.html +++ b/index.html @@ -90,809 +90,7 @@ .speed { font-size:0.9em; color:#60BF5F } - @@ -1376,4 +574,4 @@

Contact

- \ No newline at end of file + diff --git a/js/main.js b/js/main.js new file mode 100644 index 0000000..98f4472 --- /dev/null +++ b/js/main.js @@ -0,0 +1,804 @@ + +var IMG_INIT ='img/mona_lisa_crop.jpg'; // mona_lisa_crop.jpg mondrian.jpg +var DEPTH = 4; + +var INIT_TYPE = 'color'; // random color +var INIT_R = 0; +var INIT_G = 0; +var INIT_B = 0; +var INIT_A = 0.001; + +var mutateDNA = mutate_medium; // mutate_soft mutate_medium mutate_hard + +var CANVAS_INPUT = 0; +var CANVAS_OUTPUT = 0; +var CANVAS_BEST = 0; + +var CONTEXT_INPUT = 0; +var CONTEXT_TEST = 0; +var CONTEXT_BEST = 0; + +var IMAGE = new Image(); +var IWIDTH = 0; +var IHEIGHT = 0; +var SUBPIXELS = 0; + +var EV_TIMEOUT = 0; +var EV_ID = 0; + +var COUNTER_TOTAL = 0; +var COUNTER_BENEFIT = 0; + +var LAST_COUNTER = 0; +var LAST_START = 0.0; +var ELAPSED_TIME = 0.0; + +var EL_STEP_TOTAL = 0; +var EL_STEP_BENEFIT = 0; +var EL_FITNESS = 0; +var EL_ELAPSED_TIME = 0; +var EL_MUTSEC = 0; + +var MAX_SHAPES = 50; // max capacity +var MAX_POINTS = 6; + +var ACTUAL_SHAPES = MAX_SHAPES; // current size +var ACTUAL_POINTS = MAX_POINTS; + +var DNA_BEST = new Array(MAX_SHAPES); +var DNA_TEST = new Array(MAX_SHAPES); + +var CHANGED_SHAPE_INDEX = 0; + +var FITNESS_MAX = 999923400656; +var FITNESS_TEST = FITNESS_MAX; +var FITNESS_BEST = FITNESS_MAX; + +var FITNESS_BEST_NORMALIZED = 0; // pixel match: 0% worst - 100% best +var NORM_COEF = IWIDTH*IHEIGHT*3*255; // maximum distance between black and white images + +var DATA_INPUT = 0; +var DATA_TEST = 0; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function hide(id) { + var el = document.getElementById(id); + if(el) + el.style.display = 'none'; +} + +function show(id) { + var el = document.getElementById(id); + if(el) + el.style.display = 'block'; +} + +function setElement(id, value) { + var el = document.getElementById(id); + if(el) + el.innerHTML = value; +} + +function setButtonHighlight(highlighted, others) { + for(var i in others) { + var el = document.getElementById(others[i]); + if(el) { + el.style.color = 'white'; + el.style.background = 'black'; + } + } + var elHighighted = document.getElementById(highlighted); + if(elHighighted) { + elHighighted.style.color = 'white'; + elHighighted.style.background = 'orange'; + } +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function rand_int(maxval) { + return Math.round(maxval*Math.random()); +} + +function rand_float(maxval) { + return maxval*Math.random(); +} + +function clamp(val, minval, maxval) { + if(valmaxval) return maxval; + return val; +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function stop() { + clearTimeout(EV_ID); + + ELAPSED_TIME += get_timestamp() - LAST_START; + + hide('stop'); + show('start'); +} + +function start() { + EV_ID = setInterval(evolve, EV_TIMEOUT); + + LAST_START = get_timestamp(); + LAST_COUNTER = COUNTER_TOTAL; + + hide('start'); + show('stop'); +} + +function get_timestamp() { + return 0.001*(new Date).getTime(); +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function addPolygon() { + ACTUAL_SHAPES = clamp(ACTUAL_SHAPES+1, 1, 1000); + if(ACTUAL_SHAPES>MAX_SHAPES) { + extend_dna_polygons(DNA_TEST); + extend_dna_polygons(DNA_BEST); + MAX_SHAPES++; + pass_gene_mutation(DNA_BEST, DNA_TEST, DNA_BEST.length-1); + } + setElement('polygons', ACTUAL_SHAPES); + + redrawDNA(); + refreshStats(); +} + +function removePolygon() { + ACTUAL_SHAPES = clamp(ACTUAL_SHAPES-1, 1, 1000); + setElement('polygons', ACTUAL_SHAPES); + + redrawDNA(); + refreshStats(); +} + +function addVertex() { + ACTUAL_POINTS = clamp(ACTUAL_POINTS+1, 3, 1000); + if(ACTUAL_POINTS>MAX_POINTS) { + extend_dna_vertices(DNA_TEST); + extend_dna_vertices(DNA_BEST); + MAX_POINTS++; + copyDNA(DNA_BEST, DNA_TEST); + } + setElement('vertices', ACTUAL_POINTS); + + redrawDNA(); + refreshStats(); +} + +function removeVertex() { + ACTUAL_POINTS = clamp(ACTUAL_POINTS-1, 3, 1000); + setElement('vertices', ACTUAL_POINTS); + + redrawDNA(); + refreshStats(); +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function setMutation(m) { + var trans = { 'gauss':[mutate_gauss,'b_mut_gauss'], 'soft':[mutate_soft,'b_mut_soft'], 'medium':[mutate_medium,'b_mut_med'], 'hard':[mutate_hard,'b_mut_hard'] }; + mutateDNA = trans[m][0]; + setButtonHighlight(trans[m][1], ['b_mut_gauss', 'b_mut_soft', 'b_mut_med', 'b_mut_hard']); +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function setDnaRandom() { + if(confirm('WARNING! This will reset all your progress so far. Do you really want to reset DNA?')) { + INIT_TYPE = 'random'; + resetDna(); + refreshStats(); + setButtonHighlight('b_dna_random', ['b_dna_random', 'b_dna_white', 'b_dna_black']); + } +} + +function setDnaColor(r,g,b) { + if(confirm('WARNING! This will reset all your progress so far. Do you really want to reset DNA?')) { + INIT_TYPE = 'color'; + INIT_R = r; + INIT_G = g; + INIT_B = b; + resetDna(); + refreshStats(); + if(r==0&&g==0&&b==0) + setButtonHighlight('b_dna_black', ['b_dna_random', 'b_dna_white', 'b_dna_black']); + else + setButtonHighlight('b_dna_white', ['b_dna_random', 'b_dna_white', 'b_dna_black']); + } +} + +function resetDna() { + init_dna(DNA_TEST); + init_dna(DNA_BEST); + copyDNA(DNA_BEST, DNA_TEST); + + FITNESS_TEST = FITNESS_MAX; + FITNESS_BEST = FITNESS_MAX; + + COUNTER_BENEFIT = 0; + COUNTER_TOTAL = 0; + + redrawDNA(); +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function refreshStats() { + FITNESS_TEST = compute_fitness(DNA_TEST); + FITNESS_BEST = FITNESS_TEST; + FITNESS_BEST_NORMALIZED = 100*(1-FITNESS_BEST/NORM_COEF); + EL_FITNESS.innerHTML = FITNESS_BEST_NORMALIZED.toFixed(2)+'%'; + + EL_STEP_BENEFIT.innerHTML = COUNTER_BENEFIT; + EL_STEP_TOTAL.innerHTML = COUNTER_TOTAL; +} + +function redrawDNA() { + drawDNA(CONTEXT_TEST, DNA_TEST); + drawDNA(CONTEXT_BEST, DNA_BEST); +} + +function render_nice_time(s) { + if(s<60) { + return Math.floor(s).toFixed(0)+'s'; + } + else if(s<3600) { + var m = Math.floor(s/60); + return m+'m'+' '+render_nice_time(s-m*60); + } + else if(s<86400) { + var h = Math.floor(s/3600); + return h+'h'+' '+render_nice_time(s-h*3600); + } + else { + var d = Math.floor(s/86400); + return d+'d'+' '+render_nice_time(s-d*86400); + } +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function drawShape(ctx, shape, color) { + ctx.fillStyle = 'rgba('+color.r+','+color.g+','+color.b+','+color.a+')'; + ctx.beginPath(); + ctx.moveTo(shape[0].x, shape[0].y); + for(var i=1;i= step) { + if (x != 0) dist[index++] = x; + accumulator -= step; + } + } + bell_offsets[range] = off; + return bell_distributions[range] = dist; +} + +function test_bell(count, range, center) { + var bell_tests = new Array(0); + for (var i = 0; i < count; i++) { + var r = rand_bell(range, center); + if (bell_tests[r]) bell_tests[r]=bell_tests[r]+1; + else bell_tests[r] = 1; + } + draw_dist(CONTEXT_TEST, bell_tests); +} + +function draw_dist(ctx, dist) { + var current = dist[0]; + var count = 0; + ctx.fillStyle = 'rgb(255,255,255)'; + ctx.fillRect(0, 0, IWIDTH, IHEIGHT); + ctx.fillStyle = 'rgb(0,0,255)'; + + var max = 0; + for (var i in dist) { if (dist[i] > max) max = dist[i]; } + for (var i in dist) { + current = Math.round((dist[i] / max) * IHEIGHT); + i = parseInt(i); + ctx.beginPath(); + ctx.moveTo(i, IHEIGHT+1); + ctx.lineTo(i, IHEIGHT-current); + ctx.lineTo(i+1, IHEIGHT-current); + ctx.lineTo(i+1, IHEIGHT+1); + ctx.closePath(); + ctx.fill(); + } +} + +function mutate_gauss(dna_out) { + CHANGED_SHAPE_INDEX = rand_int(ACTUAL_SHAPES-1); + + var roulette = rand_float(2.0); + + // mutate color + if(roulette<1) { + // red + if(roulette<0.25) { + dna_out[CHANGED_SHAPE_INDEX].color.r = rand_bell(255, dna_out[CHANGED_SHAPE_INDEX].color.r); + } + // green + else if(roulette<0.5) { + dna_out[CHANGED_SHAPE_INDEX].color.g = rand_bell(255, dna_out[CHANGED_SHAPE_INDEX].color.g); + } + // blue + else if(roulette<0.75) { + dna_out[CHANGED_SHAPE_INDEX].color.b = rand_bell(255, dna_out[CHANGED_SHAPE_INDEX].color.b); + } + // alpha + else if(roulette<1.0) { + dna_out[CHANGED_SHAPE_INDEX].color.a = 0.00390625 * rand_bell(255, Math.floor(dna_out[CHANGED_SHAPE_INDEX].color.a*255)); + } + } + + // mutate shape + else { + var CHANGED_POINT_INDEX = rand_int(ACTUAL_POINTS-1); + + // x-coordinate + if(roulette<1.5) { + dna_out[CHANGED_SHAPE_INDEX].shape[CHANGED_POINT_INDEX].x = rand_bell(IWIDTH, dna_out[CHANGED_SHAPE_INDEX].shape[CHANGED_POINT_INDEX].x); + } + + // y-coordinate + else { + dna_out[CHANGED_SHAPE_INDEX].shape[CHANGED_POINT_INDEX].y = rand_bell(IHEIGHT, dna_out[CHANGED_SHAPE_INDEX].shape[CHANGED_POINT_INDEX].y); + } + } +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function mutate_medium(dna_out) { + CHANGED_SHAPE_INDEX = rand_int(ACTUAL_SHAPES-1); + + var roulette = rand_float(2.0); + + // mutate color + if(roulette<1) { + // red + if(roulette<0.25) { + dna_out[CHANGED_SHAPE_INDEX].color.r = rand_int(255); + } + // green + else if(roulette<0.5) { + dna_out[CHANGED_SHAPE_INDEX].color.g = rand_int(255); + } + // blue + else if(roulette<0.75) { + dna_out[CHANGED_SHAPE_INDEX].color.b = rand_int(255); + } + // alpha + else if(roulette<1.0) { + dna_out[CHANGED_SHAPE_INDEX].color.a = rand_float(1.0); + } + } + + // mutate shape + else { + var CHANGED_POINT_INDEX = rand_int(ACTUAL_POINTS-1); + + // x-coordinate + if(roulette<1.5) { + dna_out[CHANGED_SHAPE_INDEX].shape[CHANGED_POINT_INDEX].x = rand_int(IWIDTH); + } + + // y-coordinate + else { + dna_out[CHANGED_SHAPE_INDEX].shape[CHANGED_POINT_INDEX].y = rand_int(IHEIGHT); + } + } +} + +function mutate_hard(dna_out) { + CHANGED_SHAPE_INDEX = rand_int(ACTUAL_SHAPES-1); + + dna_out[CHANGED_SHAPE_INDEX].color.r = rand_int(255); + dna_out[CHANGED_SHAPE_INDEX].color.g = rand_int(255); + dna_out[CHANGED_SHAPE_INDEX].color.b = rand_int(255); + dna_out[CHANGED_SHAPE_INDEX].color.a = rand_float(1.0); + var CHANGED_POINT_INDEX = rand_int(ACTUAL_POINTS-1); + + dna_out[CHANGED_SHAPE_INDEX].shape[CHANGED_POINT_INDEX].x = rand_int(IWIDTH); + dna_out[CHANGED_SHAPE_INDEX].shape[CHANGED_POINT_INDEX].y = rand_int(IHEIGHT); +} + +function mutate_soft(dna_out) { + CHANGED_SHAPE_INDEX = rand_int(ACTUAL_SHAPES-1); + + var roulette = rand_float(2.0); + + var delta = -1+rand_int(3); + + // mutate color + if(roulette<1) { + // red + if(roulette<0.25) { + dna_out[CHANGED_SHAPE_INDEX].color.r = clamp(dna_out[CHANGED_SHAPE_INDEX].color.r+delta, 0, 255); + } + // green + else if(roulette<0.5) { + dna_out[CHANGED_SHAPE_INDEX].color.g = clamp(dna_out[CHANGED_SHAPE_INDEX].color.g+delta, 0, 255); + } + // blue + else if(roulette<0.75) { + dna_out[CHANGED_SHAPE_INDEX].color.b = clamp(dna_out[CHANGED_SHAPE_INDEX].color.b+delta, 0, 255); + } + // alpha + else if(roulette<1.0) { + dna_out[CHANGED_SHAPE_INDEX].color.a = clamp(dna_out[CHANGED_SHAPE_INDEX].color.a+0.1*delta, 0.0, 1.0); + } + } + + // mutate shape + else { + var CHANGED_POINT_INDEX = rand_int(ACTUAL_POINTS-1); + + // x-coordinate + if(roulette<1.5) { + dna_out[CHANGED_SHAPE_INDEX].shape[CHANGED_POINT_INDEX].x = clamp(dna_out[CHANGED_SHAPE_INDEX].shape[CHANGED_POINT_INDEX].x+delta, 0, IWIDTH); + } + + // y-coordinate + else { + dna_out[CHANGED_SHAPE_INDEX].shape[CHANGED_POINT_INDEX].y = clamp(dna_out[CHANGED_SHAPE_INDEX].shape[CHANGED_POINT_INDEX].y+delta, 0, IHEIGHT); + } + } +} + +function compute_fitness(dna) { + var fitness = 0; + + DATA_TEST = CONTEXT_TEST.getImageData(0, 0, IWIDTH, IHEIGHT).data; + + for(var i=0;i\n'; + dna_string += '\n'; + dna_string += '\n'; + + // shapes + for(var i=0;i\n'; + } + dna_string += '<\/svg>\n'; + return dna_string; +} + +function deserializeDNA(dna, text) { + var data = text.split(' '); + + MAX_POINTS = parseInt(data[0]); + MAX_SHAPES = parseInt(data[1]); + + ACTUAL_SHAPES = MAX_SHAPES; + ACTUAL_POINTS = MAX_POINTS; + + alert('Importing '+MAX_SHAPES+' polygons ['+MAX_POINTS+'-vertex] ['+data.length+' numbers]...'); + + init_dna(dna); + + var shape_size = 4+2*MAX_POINTS; + + for(var i=0;i