A clone of JezzBall.
The goal is to fill at least 75% of the room. Click on any corner button or use mouse wheel to change the orientation of the wall builder. For more detailed instructions, see JezzBall Walkthrough/FAQ page on IGN.
Enjoy ! :)
| /.project | |
| /.settings |
A clone of JezzBall.
The goal is to fill at least 75% of the room. Click on any corner button or use mouse wheel to change the orientation of the wall builder. For more detailed instructions, see JezzBall Walkthrough/FAQ page on IGN.
Enjoy ! :)
| <!DOCTYPE html> | |
| <meta charset="utf-8"> | |
| <title>D3 JezzBall</title> | |
| <link rel="icon" href="/favicon.png"> | |
| <style> | |
| @import url("http://bl.ocks.org/style.css?20120730"); | |
| </style> | |
| <header> | |
| <a href="/ericcitaire">ericcitaire</a>’s block <a href="https://gist.github.com/ericcitaire/5408146">#5408146</a> | |
| </header> | |
| <h1>D3 JezzBall</h1> | |
| <p><aside style="margin-top:-43px;">April 29, 2013</aside> | |
| <iframe src="index.html" marginwidth="0" marginheight="0" scrolling="no"></iframe> | |
| <p><aside><a style="position:relative;top:6px;" href="index.html" target="_blank">Open in a new window.</a></aside> | |
| <footer> | |
| <aside>April 29, 2013</aside> | |
| <a href="/ericcitaire">ericcitaire</a>’s block <a href="https://gist.github.com/ericcitaire/5408146">#5408146</a> | |
| </footer> | |
| <!DOCTYPE html> | |
| <meta charset="utf-8"> | |
| <title>D3 JezzBall</title> | |
| <style> | |
| body { | |
| padding: 0px; | |
| margin: 0px; | |
| } | |
| rect { | |
| fill: none; | |
| pointer-events: all; | |
| } | |
| .smallTextStroke { | |
| font-family: sans-serif; | |
| font-size: 12px; | |
| fill: none; | |
| stroke: black; | |
| stroke-width: 1px; | |
| } | |
| .smallText { | |
| font-family: sans-serif; | |
| font-size: 12px; | |
| fill: white; | |
| } | |
| .bigTextStroke { | |
| font-family: sans-serif; | |
| font-size: 24px; | |
| font-weight: bold; | |
| fill: none; | |
| stroke: black; | |
| stroke-width: 4px; | |
| } | |
| .bigText { | |
| font-family: sans-serif; | |
| font-size: 24px; | |
| font-weight: bold; | |
| fill: white; | |
| } | |
| .cell { | |
| } | |
| .cell.wall { | |
| fill: #000; | |
| stroke: #000; | |
| } | |
| .cell.air { | |
| fill: #ddd; | |
| stroke: #999; | |
| } | |
| .cell.blue { | |
| stroke: blue; | |
| stroke-opacity: .8; | |
| } | |
| .cell.red { | |
| stroke: red; | |
| stroke-opacity: .8; | |
| } | |
| .ball { | |
| fill: #f00; | |
| fill-opacity: 1; | |
| stroke: #333; | |
| stroke-opacity: .5; | |
| } | |
| .builder.head { | |
| stroke: #333; | |
| stroke-opacity: .5; | |
| } | |
| .builder.blue { | |
| fill: blue; | |
| } | |
| .builder.red { | |
| fill: red; | |
| } | |
| .builder.tail { | |
| fill-opacity: .4; | |
| } | |
| .switch { | |
| position: absolute; | |
| top: 0px; | |
| left: 0px; | |
| padding: 0px; | |
| width: 20px; | |
| height: 20px; | |
| } | |
| #nextLevelButton, #playAgainButton { | |
| position: absolute; | |
| width: 100px; | |
| visibility: hidden; | |
| } | |
| </style> | |
| <body> | |
| <script src="http://d3js.org/d3.v3.min.js"></script> | |
| <form> | |
| <input id="switchOrientationButton1" class="switch" type="button" value="V" /> | |
| <input id="switchOrientationButton2" class="switch" type="button" value="V" /> | |
| <input id="switchOrientationButton3" class="switch" type="button" value="V" /> | |
| <input id="switchOrientationButton4" class="switch" type="button" value="V" /> | |
| <input id="nextLevelButton" type="button" value="Next level" /> | |
| <input id="playAgainButton" type="button" value="Play again" /> | |
| </form> | |
| <script type="text/javascript" src="jezzball.js"></script> |
| d3.selection.prototype.size = function() { | |
| var n = 0; | |
| this.each(function() { ++n; }); | |
| return n; | |
| }; | |
| var level = 1; | |
| window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) { | |
| if (key == "level") { | |
| level = +value; | |
| } | |
| }); | |
| var w = 960, | |
| h = 500, | |
| sz = 20, | |
| r = sz / 2, | |
| sr = r * r, | |
| ssz = sz * sz, | |
| v = 3, | |
| n = level + 1, | |
| t = 5000; | |
| var rows = Math.ceil(h / sz); | |
| var cols = Math.ceil(w / sz); | |
| var s = false; | |
| d3.selectAll(".switch") | |
| .on("click", function(e) { s = !s; d3.selectAll(".switch").attr("value", s ? "H" : "V"); }); | |
| d3.select("#switchOrientationButton2") | |
| .style("left", (w - 20) + "px"); | |
| d3.select("#switchOrientationButton3") | |
| .style("top", (h - 20) + "px"); | |
| d3.select("#switchOrientationButton4") | |
| .style("top", (h - 20) + "px") | |
| .style("left", (w - 20) + "px"); | |
| d3.select("#nextLevelButton") | |
| .style("top", Math.round(h / 2 + 20) + "px") | |
| .style("left", Math.round(w / 2 - 50) + "px") | |
| .on("click", function(e) { window.location.href = "?level=" + (level + 1); }); | |
| d3.select("#playAgainButton") | |
| .style("top", Math.round(h / 2 + 20) + "px") | |
| .style("left", Math.round(w / 2 - 50) + "px") | |
| .on("click", function(e) { window.location.href = "?level=1"; }); | |
| var cells = d3.range(0, rows * cols).map(function (d) { | |
| var col = d % cols; | |
| var row = (d - col) / cols; | |
| return { | |
| r: row, | |
| c: col, | |
| x: col * sz + r, | |
| y: row * sz + r | |
| }; | |
| }); | |
| var balls = d3.range(0, n).map(function (d) { | |
| var bx = (w - sz * 4) * Math.random() + sz * 2; | |
| var by = (h - sz * 4) * Math.random() + sz * 2; | |
| var ball = { | |
| x: bx, | |
| y: by, | |
| px: bx + v * (Math.random() > .5 ? 1 : -1), | |
| py: by + v * (Math.random() > .5 ? 1 : -1), | |
| id: d, | |
| isMoving: true | |
| }; | |
| return ball; | |
| }); | |
| var svg = d3.select("body").append("svg") | |
| .attr("width", w) | |
| .attr("height", h); | |
| var mousewheel = function(e) { | |
| s = !s; | |
| d3.selectAll(".switch").attr("value", s ? "H" : "V"); | |
| var p = d3.mouse(this); | |
| var c1 = ballCell({x: p[0], y: p[1]}); | |
| previewLocation(c1, p); | |
| d3.event.preventDefault(); | |
| }; | |
| svg.on("mousewheel.zoom", mousewheel) | |
| .on("DOMMouseScroll.zoom", mousewheel); | |
| var rectx = function(d) { return d.x - r; }; | |
| var recty = function(d) { return d.y - r; }; | |
| var tailx = function(d) { return d.dx > 0 ? d.sx - r : rectx(d) - d.dx * sz; }; | |
| var taily = function(d) { return d.dy > 0 ? d.sy - r : recty(d) - d.dy * sz; }; | |
| var tailw = function(d) { return d.dx == 0 ? sz : d.sz = (d.x - d.sx) * d.dx; }; | |
| var tailh = function(d) { return d.dy == 0 ? sz : d.sz = (d.y - d.sy) * d.dy; }; | |
| var ballCell = function(b) { | |
| var row = (b.y - b.y % sz) / sz; | |
| var col = (b.x - b.x % sz) / sz; | |
| return cells[row * cols + col]; | |
| }; | |
| var topCell = function(c) { return cells[Math.max(0, c.r - 1) * cols + c.c]; }; | |
| var leftCell = function(c) { return cells[c.r * cols + Math.max(0, c.c - 1)]; }; | |
| var bottomCell = function(c) { return cells[Math.min(rows - 1, c.r + 1) * cols + c.c]; }; | |
| var rightCell = function(c) { return cells[c.r * cols + Math.min(cols - 1, c.c + 1)]; }; | |
| var topLeftCell = function(c) { return cells[Math.max(0, c.r - 1) * cols + Math.max(0, c.c - 1)]; }; | |
| var bottomLeftCell = function(c) { return cells[Math.min(rows - 1, c.r + 1) * cols + Math.max(0, c.c - 1)]; }; | |
| var bottomRightCell = function(c) { return cells[Math.min(rows - 1, c.r + 1) * cols + Math.min(cols - 1, c.c + 1)]; }; | |
| var topRightCell = function(c) { return cells[Math.max(0, c.r - 1) * cols + Math.min(cols - 1, c.c + 1)]; }; | |
| var cell = svg.selectAll(".cell") | |
| .data(cells) | |
| .enter().append("rect") | |
| .attr("class", function(d) { return "cell " + ((d.isWall = d.c == 0 || d.c == cols - 1 || d.r == 0 || d.r == rows - 1) ? "wall" : "air"); }) | |
| .attr("x", rectx) | |
| .attr("y", recty) | |
| .attr("width", sz) | |
| .attr("height", sz) | |
| .each(function(d) { | |
| d.elnt = d3.select(this); | |
| }); | |
| function previewLocation(c1, p) { | |
| if (blue) blue.classed("blue", false); | |
| if (red) red.classed("red", false); | |
| var c2, d; | |
| if (s) { | |
| d = p[0] - c1.x; | |
| c2 = d > 0 ? rightCell(c1) : leftCell(c1); | |
| } else { | |
| d = p[1] - c1.y; | |
| c2 = d > 0 ? bottomCell(c1) : topCell(c1); | |
| } | |
| if (c1.isWall || c2.isWall) { | |
| blue = null; | |
| red = null; | |
| } else if (d > 0) { | |
| blue = c1.elnt; | |
| red = c2.elnt; | |
| } else { | |
| blue = c2.elnt; | |
| red = c1.elnt; | |
| } | |
| if (blue) blue.classed("blue", function(d) { return !d.isWall; }); | |
| if (red) red.classed("red", function(d) { return !d.isWall; }); | |
| } | |
| var blue, red; | |
| svg.selectAll(".air") | |
| .on("mouseover", function(c1) { | |
| var p = d3.mouse(this); | |
| previewLocation(c1, p); | |
| }).on("mouseout", function() { | |
| if (blue) blue.classed("blue", false); | |
| if (red) red.classed("red", false); | |
| }).on("click", function() { | |
| if (percentageCleared < 75 && lives >= 0 && timeLeft > 0) { | |
| var dx = s ? 1 : 0; | |
| var dy = s ? 0 : 1; | |
| if (blue) blue.each(function(d) { startWall(d, "blue", -dx, -dy); }); | |
| if (red) red.each(function(d) { startWall(d, "red", dx, dy); }); | |
| } | |
| }); | |
| var areaCleared = 0; | |
| var totalArea = svg.selectAll(".air").size(); | |
| var percentageCleared = 0; | |
| svg.append("text") | |
| .attr("x", w / 2 - 50) | |
| .attr("y", h - 5) | |
| .attr("class", "smallText") | |
| .attr("id", "areaFilledText") | |
| .text("Area cleared: 0%"); | |
| var lives = n; | |
| svg.append("text") | |
| .attr("x", 50) | |
| .attr("y", 15) | |
| .attr("class", "smallText") | |
| .attr("id", "livesText") | |
| .text("Lives: " + lives); | |
| var gameStartedAt = new Date().getTime(); | |
| var timeLeft = t; | |
| svg.append("text") | |
| .attr("x", w - 130) | |
| .attr("y", 15) | |
| .attr("class", "smallText") | |
| .attr("id", "timeLeftText") | |
| .text("Time left: " + timeLeft); | |
| var force = d3.layout.force() | |
| .gravity(0) | |
| .charge(0) | |
| .friction(1) | |
| .size([w, h]); | |
| balls.forEach(function (b) { | |
| svg.append("svg:circle") | |
| .data([b]) | |
| .attr("class", "ball") | |
| .attr("cx", function (d) { | |
| return d.x; | |
| }) | |
| .attr("cy", function (d) { | |
| return d.y; | |
| }) | |
| .attr("r", r); | |
| force.nodes().push(b); | |
| }); | |
| force.on("tick", function () { | |
| var ball = svg.selectAll(".ball"); | |
| ball.attr("cx", function (d) { return d.x; }) | |
| .attr("cy", function (d) { return d.y; }) | |
| .each(function(b) { | |
| detectCollisions(b); | |
| var cc = ballCell(b); | |
| var tc = topCell(cc); | |
| var lc = leftCell(cc); | |
| var bc = bottomCell(cc); | |
| var rc = rightCell(cc); | |
| if (cc.isWall || (tc.isWall && bc.isWall) || (lc.isWall && rc.isWall)) { | |
| cc.elnt | |
| .classed("air", true) | |
| .classed("wall", false); | |
| b.px = b.x = cc.x; | |
| b.py = b.y = cc.y; | |
| cc.isWall = b.isMoving = false; | |
| } | |
| }); | |
| var head = svg.selectAll(".head"); | |
| head.attr("x", function(d) { d.x += d.dx * (v * .4); return rectx(d); }) | |
| .attr("y", function(d) { d.y += d.dy * (v * .4); return recty(d); }) | |
| .each(function(d) { | |
| svg.select("." + d.cl + ".tail") | |
| .attr("x", tailx) | |
| .attr("y", taily) | |
| .attr("width", tailw) | |
| .attr("height", tailh); | |
| }); | |
| var air = svg.selectAll(".air"); | |
| var tail = svg.selectAll(".tail"); | |
| var wallWasBuilt = false; | |
| head.filter(function(h) { | |
| var hc = ballCell(h); | |
| if (h.dy < 0) { | |
| var tc = topCell(hc); | |
| return tc.isWall && h.y - tc.y < sz; | |
| } | |
| if (h.dx < 0) { | |
| var lc = leftCell(hc); | |
| return lc.isWall && h.x - lc.x < sz; | |
| } | |
| if (h.dy > 0) { | |
| var bc = bottomCell(hc); | |
| return bc.isWall && bc.y - h.y < sz; | |
| } | |
| if (h.dx > 0) { | |
| var rc = rightCell(hc); | |
| return rc.isWall && rc.x - h.x < sz; | |
| } | |
| }).each(function(h) { | |
| air.filter(function(a) { | |
| return h.dx == 0 ? h.x == a.x && Math.min(h.sy, h.y) <= a.y && a.y <= Math.max(h.sy, h.y) : h.y == a.y && Math.min(h.sx, h.x) <= a.x && a.x <= Math.max(h.sx, h.x); | |
| }) | |
| .classed("newWall", true) | |
| .classed("air", false) | |
| .each(function(d) { if (!d.isWall) { ++areaCleared; d.isWall = true; } }); | |
| tail.filter("." + h.cl) | |
| .remove(); | |
| wallWasBuilt = true; | |
| }).remove(); | |
| if (wallWasBuilt) { | |
| fillEmptyRooms(); | |
| } | |
| var timePlayed = Math.floor(((new Date().getTime()) - gameStartedAt) / 100); | |
| timeLeft = timePlayed > t ? 0 : t - timePlayed; | |
| svg.select("#timeLeftText") | |
| .text("Time left: " + timeLeft); | |
| if (percentageCleared < 75 && lives >= 0 && timeLeft > 0) { | |
| force.resume(); | |
| } else { | |
| force.stop(); | |
| var text, textWidth; | |
| if (percentageCleared >= 75 && lives >= 0 && timeLeft > 0) { | |
| text = "Level complete !"; | |
| textWidth = 188; | |
| d3.select("#nextLevelButton") | |
| .style("visibility", "visible"); | |
| } else { | |
| text = "Game over !"; | |
| textWidth = 138; | |
| d3.select("#playAgainButton") | |
| .style("visibility", "visible"); | |
| } | |
| svg.append("text") | |
| .attr("x", w / 2 - textWidth / 2) | |
| .attr("y", h / 2) | |
| .attr("class", "bigTextStroke") | |
| .text(text); | |
| svg.append("text") | |
| .attr("x", w / 2 - textWidth / 2) | |
| .attr("y", h / 2) | |
| .attr("class", "bigText") | |
| .text(text); | |
| } | |
| }); | |
| force.start(); | |
| function detectCollisions(b) { | |
| var dx = b.x - b.px > 0 ? 1 : -1; | |
| var dy = b.y - b.py > 0 ? 1 : -1; | |
| var d, sd; | |
| // tail collision | |
| svg.selectAll(".tail").filter(function(t) { | |
| var w = tailw(t); | |
| var h = tailh(t); | |
| var x0 = tailx(t); | |
| var x1 = x0 + w; | |
| var y0 = taily(t); | |
| var y1 = y0 + h; | |
| return x0 - r < b.x && b.x < x1 - r && y0 - r < b.y && b.y < y1 + r; | |
| }) | |
| .each(function(t) { | |
| --lives; | |
| svg.select("#livesText") | |
| .text("Lives: " + (lives < 0 ? 0 : lives)); | |
| svg.selectAll(".head." + t.cl).remove(); | |
| }) | |
| .remove(); | |
| // wall borders collision | |
| var cc = ballCell(b); | |
| var tc = topCell(cc); | |
| if (tc.isWall && dy < 0 && (d = b.y - tc.y) <= sz) { | |
| bounceY(b, sz, d, dy); | |
| } | |
| var lc = leftCell(cc); | |
| if (lc.isWall && dx < 0 && (d = b.x - lc.x) <= sz) { | |
| bounceX(b, sz, d, dx); | |
| } | |
| var bc = bottomCell(cc); | |
| if (bc.isWall && dy > 0 && (d = bc.y - b.y) <= sz) { | |
| bounceY(b, sz, d, dy); | |
| } | |
| var rc = rightCell(cc); | |
| if (rc.isWall && dx > 0 && (d = rc.x - b.x) <= sz) { | |
| bounceX(b, sz, d, dx); | |
| } | |
| svg.selectAll(".head").each(function(h) { | |
| if (h.y - r <= b.y && b.y <= h.y + r) { | |
| if (dx < 0 && (d = b.x - h.x) <= sz && d > 0) { | |
| bounceX(b, sz, d, dx); | |
| } | |
| if (dx > 0 && (d = h.x - b.x) <= sz && d > 0) { | |
| bounceX(b, sz, d, dx); | |
| } | |
| } | |
| if (h.x - r <= b.x && b.x <= h.x + r) { | |
| if (dy < 0 && (d = b.y - h.y) <= sz && d > 0) { | |
| bounceY(b, sz, d, dy); | |
| } | |
| if (dy > 0 && (d = h.y - b.y) <= sz && d > 0) { | |
| bounceY(b, sz, d, dy); | |
| } | |
| } | |
| }); | |
| // wall corners collision | |
| var tlc = topLeftCell(cc); | |
| if (!tc.isWall && !lc.isWall && tlc.isWall && (sd = cornerSquareDistance(b.x, b.y, tlc.x + r, tlc.y + r)) <= sr) { | |
| d = Math.sqrt(sd); | |
| if (dx < 0) { | |
| bounceX(b, r, d, dx); | |
| } | |
| if (dy < 0) { | |
| bounceY(b, r, d, dy); | |
| } | |
| } | |
| var blc = bottomLeftCell(cc); | |
| if (!bc.isWall && !lc.isWall && blc.isWall && (sd = cornerSquareDistance(b.x, b.y, blc.x + r, blc.y - r)) <= sr) { | |
| d = Math.sqrt(sd); | |
| if (dx < 0) { | |
| bounceX(b, r, d, dx); | |
| } | |
| if (dy > 0) { | |
| bounceY(b, r, d, dy); | |
| } | |
| } | |
| var brc = bottomRightCell(cc); | |
| if (!bc.isWall && !rc.isWall && brc.isWall && (sd = cornerSquareDistance(b.x, b.y, brc.x - r, brc.y - r)) <= sr) { | |
| d = Math.sqrt(sd); | |
| if (dx > 0) { | |
| bounceX(b, r, d, dx); | |
| } | |
| if (dy > 0) { | |
| bounceY(b, r, d, dy); | |
| } | |
| } | |
| var trc = topRightCell(cc); | |
| if (!tc.isWall && !rc.isWall && trc.isWall && (sd = cornerSquareDistance(b.x, b.y, trc.x - r, trc.y + r)) <= sr) { | |
| d = Math.sqrt(sd); | |
| if (dx > 0) { | |
| bounceX(b, r, d, dx); | |
| } | |
| if (dy < 0) { | |
| bounceY(b, r, d, dy); | |
| } | |
| } | |
| svg.selectAll(".head").each(function(h) { | |
| if ((sd = cornerSquareDistance(b.x, b.y, h.x + r, h.y + r)) <= sr && sd > 0) { | |
| d = Math.sqrt(sd); | |
| if (dx < 0) { | |
| bounceX(b, r, d, dx); | |
| } | |
| if (dy < 0) { | |
| bounceY(b, r, d, dy); | |
| } | |
| } | |
| if ((sd = cornerSquareDistance(b.x, b.y, h.x + r, h.y - r)) <= sr && sd > 0) { | |
| d = Math.sqrt(sd); | |
| if (dx < 0) { | |
| bounceX(b, r, d, dx); | |
| } | |
| if (dy > 0) { | |
| bounceY(b, r, d, dy); | |
| } | |
| } | |
| if ((sd = cornerSquareDistance(b.x, b.y, h.x - r, h.y - r)) <= sr && sd > 0) { | |
| d = Math.sqrt(sd); | |
| if (dx > 0) { | |
| bounceX(b, r, d, dx); | |
| } | |
| if (dy > 0) { | |
| bounceY(b, r, d, dy); | |
| } | |
| } | |
| if ((sd = cornerSquareDistance(b.x, b.y, h.x - r, h.y + r)) <= sr && sd > 0) { | |
| d = Math.sqrt(sd); | |
| if (dx > 0) { | |
| bounceX(b, r, d, dx); | |
| } | |
| if (dy < 0) { | |
| bounceY(b, r, d, dy); | |
| } | |
| } | |
| }); | |
| // ball collision | |
| svg.selectAll(".ball").each(function(b2) { | |
| if (b.id == b2.id) { | |
| return; | |
| } | |
| var sd = cornerSquareDistance(b.x, b.y, b2.x, b2.y); | |
| if (sd <= ssz) { | |
| var dx2 = b2.x - b2.px > 0 ? 1 : -1; | |
| var dy2 = b2.y - b2.py > 0 ? 1 : -1; | |
| var d = Math.sqrt(sd); | |
| if (b.isMoving && (b2.x - b.x) * dx > r / 2) { | |
| bounceX(b, sz, d, dx); | |
| } | |
| if (b2.isMoving && (b.x - b2.x) * dx2 > r / 2) { | |
| bounceX(b2, sz, d, dx2); | |
| } | |
| if (b.isMoving && (b2.y - b.y) * dy > r / 2) { | |
| bounceY(b, sz, d, dy); | |
| } | |
| if (b2.isMoving && (b.y - b2.y) * dy2 > r / 2) { | |
| bounceY(b2, sz, d, dy2); | |
| } | |
| } | |
| }); | |
| } | |
| function bounceX(b, m, d, dx) { | |
| if (b.isMoving) { | |
| b.x -= (m - d) * dx; | |
| b.px = b.x + dx * v; | |
| } | |
| } | |
| function bounceY(b, m, d, dy) { | |
| if (b.isMoving) { | |
| b.y -= (m - d) * dy; | |
| b.py = b.y + dy * v; | |
| } | |
| } | |
| function cornerSquareDistance(x0, y0, x1, y1) { | |
| var w = x1 - x0; | |
| var h = y1 - y0; | |
| return (w * w + h * h); | |
| } | |
| function fillEmptyRooms() { | |
| var air = d3.selectAll(".air"); | |
| air | |
| .each(function (d) { | |
| d.visited = false; | |
| }); | |
| svg.selectAll(".ball") | |
| .each(function (b) { | |
| var cc = ballCell(b); | |
| cc.visited = true; | |
| visit(cc); | |
| }); | |
| air | |
| .classed("newWall", function(d) { return !d.visited; }) | |
| .classed("air", function(d) { return d.visited; }) | |
| .each(function(d) { if (!d.visited && !d.isWall) { ++areaCleared; d.isWall = true; } }); | |
| percentageCleared = Math.floor((areaCleared * 100) / totalArea); | |
| svg.select("#areaFilledText") | |
| .text("Area cleared: " + percentageCleared + "%"); | |
| svg.selectAll(".newWall") | |
| .on("mouseover", null) | |
| .on("mouseout", null) | |
| .on("click", null) | |
| .classed("wall", true) | |
| .classed("blue", false) | |
| .classed("red", false); | |
| } | |
| function visit(c) { | |
| var tc = topCell(c); | |
| if (!tc.isWall && !tc.visited) { | |
| tc.visited = true; | |
| visit(tc); | |
| } | |
| var lc = leftCell(c); | |
| if (!lc.isWall && !lc.visited) { | |
| lc.visited = true; | |
| visit(lc); | |
| } | |
| var bc = bottomCell(c); | |
| if (!bc.isWall && !bc.visited) { | |
| bc.visited = true; | |
| visit(bc); | |
| } | |
| var rc = rightCell(c); | |
| if (!rc.isWall && !rc.visited) { | |
| rc.visited = true; | |
| visit(rc); | |
| } | |
| } | |
| function startWall(cell, cl, dx, dy) { | |
| var wallHead = { | |
| sx: cell.x, | |
| sy: cell.y, | |
| x: cell.x, | |
| y: cell.y, | |
| dx: dx, | |
| dy: dy, | |
| cl: cl | |
| }; | |
| if (svg.selectAll("." + cl + ".head").empty()) { | |
| svg.selectAll("." + cl + ".head") | |
| .data([wallHead]).enter().append("rect") | |
| .classed("builder", true) | |
| .classed(cl, true) | |
| .classed("head", true) | |
| .attr("x", rectx) | |
| .attr("y", recty) | |
| .attr("width", sz) | |
| .attr("height", sz); | |
| var tail = svg.selectAll("." + cl + ".tail") | |
| .data([wallHead]); | |
| tail.enter().append("rect") | |
| .classed("builder", true) | |
| .classed(cl, true) | |
| .classed("tail", true) | |
| .attr("x", tailx) | |
| .attr("y", taily) | |
| .attr("width", tailw) | |
| .attr("height", tailh); | |
| tail.exit().remove(); | |
| } | |
| } |