⬆️ ⬇️

Labyrinth generation by Euler algorithm in 30 lines

image

Well, you should immediately apologize for the late reaction, because the “week of 30 lines” has passed, and I am posting this post just now. All because of the hard work week and only on weekends we managed to allocate some time.

Immediately thank the deadkrolik user for the article Eller’s Algorithm for generating labyrinths and agree that I’m a rogue and a crook and do not smell here in 30 lines of code))) Who doesn’t like to wait for an explanation, please go straight to Fiddle .



When I just wrote these unlucky labyrinths, my code took up about 200 lines with comments, indents and a bunch of unnecessary variables. Of course, it was necessary to reduce it. But something was not an easy task and I could not cut the code in 30 lines. All that happened after my manipulations can be found here:

(function mapGen(elid, w, h, steps, complete) { var canvas = document.querySelector(elid), cell = canvas.getContext("2d"); document.querySelector('#step').innerHTML = Math.floor(steps), document.querySelector('#complete').innerHTML = Math.floor(complete); canvas.width = w * 13 + 3, canvas.height = h * 13 + 3; cell.fillStyle = "black", cell.fillRect(0, 0, w * 13 + 3, h * 13 + 3); var line = new Array(w), cell_floor = new Array(w), cell_wall = new Array(w), many = 1; for (cr_l = 0; cr_l < h; cr_l++) { for (i = 0; i < w; i++) { if (cr_l == 0) line[i] = 0; cell.clearRect(13 * i + 3, 13 * cr_l + 3, 10, 10), cell_wall[i] = 0; if (cell_floor[i] == 1) cell_floor[i] = line[i] = 0; if (line[i] == 0) line[i] = many++;} for (i = 0; i < w; i++) { cell_wall[i] = Math.floor(Math.random() * 2), cell_floor[i] = Math.floor(Math.random() * 2); if (((cell_wall[i] == 0) || (cr_l == h - 1)) && (i != w - 1) && (line[i + 1] != line[i])) { var temp_line = line[i + 1]; for (j = 0; j < w; j++) if (line[j] == temp_line) line[j] = line[i]; cell.clearRect(13 * i + 3, 13 * cr_l + 3, 15, 10);} if ((cr_l != h - 1) && (cell_floor[i] == 0)) cell.clearRect(13 * i + 3, 13 * cr_l + 3, 10, 15);} for (i = 0; i < w; i++) { var count_floor = 0, count_hole = 0; for (j = 0; j < w; j++) if ((line[i] == line[j]) && (cell_floor[j] == 0)) count_hole++; else count_floor++; if (count_hole == 0) { cell_floor[i] = 0; cell.clearRect(13 * i + 3, 13 * cr_l + 3, 10, 15);}}} cell.clearRect(13 * w, 3, 15, 10); var cur_x = 0, cur_y = 0; cell.fillStyle = "red"; character(-1, -1); document.body.onkeydown = function (e) { if ((e.keyCode > 36) && (e.keyCode < 41)) character((e.keyCode - 38) % 2, (e.keyCode - 39) % 2);}; function character(sx, sy) { var stepData = cell.getImageData(13 * cur_x + 7 + 6 * sx, 13 * cur_y + 7 + 6 * sy, 1, 1); if ((stepData.data[0] == 0) && (stepData.data[1] == 0) && (stepData.data[2] == 0) && (stepData.data[3] == 255)) sx = sy = 0; else document.querySelector('#step').innerHTML = Math.floor(document.querySelector('#step').innerHTML) + 1; cell.clearRect(13 * cur_x + 3, 13 * cur_y + 3, 10, 10); cur_x += sx, cur_y += sy; cell.fillRect(3 + 13 * cur_x, 3 + 13 * cur_y, 10, 10); if (cur_x >= w) mapGen("#canvas", w, h, 0, complete + 1);} })("#canvas", 25, 30, 0, 0); 




In the overall standings 42 lines turned out. But even here, attentive users see a scam, because I declared several variables in one line, and also contained both condition and operators in one line. I really wanted to put everything in 30 lines all the same, and I continued the scam! On the Internet I found a very interesting and good code optimizer, which you can find here . He managed to reduce my code to 38 lines. There is no limit to my impudence at all, and with the help of a dashing operator "," and a few keystrokes of the DEL key, I still put everything in 30 lines.

 (function mapGen(b, c, e, a, m) { function character(a, b) { var h = d.getImageData(13 * f + 7 + 6 * a, 13 * g + 7 + 6 * b, 1, 1); 0 == h.data[0] && 0 == h.data[1] && 0 == h.data[2] && 255 == h.data[3] ? a = b = 0 : document.querySelector("#step").innerHTML = Math.floor(document.querySelector("#step").innerHTML) + 1; d.clearRect(13 * f + 3, 13 * g + 3, 10, 10), f += a, g += b, d.fillRect(3 + 13 * f, 3 + 13 * g, 10, 10); f >= c && mapGen("#canvas", c, e, 0, m + 1)} b = document.querySelector(b); var d = b.getContext("2d"); document.querySelector("#step").innerHTML = Math.floor(a), document.querySelector("#complete").innerHTML = Math.floor(m); b.width = 13 * c + 3, b.height = 13 * e + 3, d.fillStyle = "black", d.fillRect(0, 0, 13 * c + 3, 13 * e + 3), a = Array(c), b = Array(c); var k = Array(c), q = 1; for (cr_l = 0; cr_l < e; cr_l++) { for (i = 0; i < c; i++) 0 == cr_l && (a[i] = 0), d.clearRect(13 * i + 3, 13 * cr_l + 3, 10, 10), k[i] = 0, 1 == b[i] && (b[i] = a[i] = 0), 0 == a[i] && (a[i] = q++); for (i = 0; i < c; i++) { k[i] = Math.floor(2 * Math.random()), b[i] = Math.floor(2 * Math.random()); if ((0 == k[i] || cr_l == e - 1) && i != c - 1 && a[i + 1] != a[i]) { var l = a[i + 1]; for (j = 0; j < c; j++) a[j] == l && (a[j] = a[i]); d.clearRect(13 * i + 3, 13 * cr_l + 3, 15, 10) } cr_l != e - 1 && 0 == b[i] && d.clearRect(13 * i + 3, 13 * cr_l + 3, 10, 15) } for (i = 0; i < c; i++) { var p = l = 0; for (j = 0; j < c; j++) a[i] == a[j] && 0 == b[j] ? p++ : l++; 0 == p && (b[i] = 0, d.clearRect(13 * i + 3, 13 * cr_l + 3, 10, 15)) } } d.clearRect(13 * c, 3, 15, 10); var f = 0, g = 0; d.fillStyle = "red", character(-1, -1); document.body.onkeydown = function (a) { 36 < a.keyCode && 41 > a.keyCode && character((a.keyCode - 38) % 2, (a.keyCode - 39) % 2) } })("#canvas", 25, 30, 0, 0); 




The input parameters of this function are the drawing area, the width and length of the maze by the number of cells, the number of steps taken by the character and the number of the mazes passed.

I do not pretend to a good code or at least good reviews, but I am pleased to share my first post. Please do not judge strictly. And all comments and corrections carefully listen in the comments.

')

UPD 1:

To improve the aesthetics and readability of the code:

 (function mapGen(b, c, e, a, m) { //    function character(a, b) { //          ,       var h = d.getImageData(13 * f + 7 + 6 * a, 13 * g + 7 + 6 * b, 1, 1); //    ,     ( dx (a)  dy (b)),     0 == h.data[0] && 0 == h.data[1] && 0 == h.data[2] && 255 == h.data[3] ? a = b = 0 : document.querySelector("#step").innerHTML = Math.floor(document.querySelector("#step").innerHTML) + 1; //   d.clearRect(13 * f + 3, 13 * g + 3, 10, 10); //     f += a; g += b; //    d.fillRect(3 + 13 * f, 3 + 13 * g, 10, 10); //      ,         f >= c && mapGen("#canvas", c, e, 0, m + 1) } //    b = document.querySelector(b); var d = b.getContext("2d"); //        document.querySelector("#step").innerHTML = Math.floor(a); document.querySelector("#complete").innerHTML = Math.floor(m); //       b.width = 13 * c + 3; b.height = 13 * e + 3; //      d.fillStyle = "black"; d.fillRect(0, 0, 13 * c + 3, 13 * e + 3); //        ,          a = Array(c); b = Array(c); var k = Array(c), //   q = 1; //    for (cr_l = 0; cr_l < e; cr_l++) { //       -  for (i = 0; i < c; i++) 0 == cr_l && (a[i] = 0), d.clearRect(13 * i + 3, 13 * cr_l + 3, 10, 10), k[i] = 0, 1 == b[i] && (b[i] = a[i] = 0), 0 == a[i] && (a[i] = q++); //        for (i = 0; i < c; i++) { k[i] = Math.floor(2 * Math.random()), b[i] = Math.floor(2 * Math.random()); if ((0 == k[i] || cr_l == e - 1) && i != c - 1 && a[i + 1] != a[i]) { var l = a[i + 1]; for (j = 0; j < c; j++) a[j] == l && (a[j] = a[i]); d.clearRect(13 * i + 3, 13 * cr_l + 3, 15, 10) } cr_l != e - 1 && 0 == b[i] && d.clearRect(13 * i + 3, 13 * cr_l + 3, 10, 15) } //    . for (i = 0; i < c; i++) { var p = l = 0; for (j = 0; j < c; j++) a[i] == a[j] && 0 == b[j] ? p++ : l++; 0 == p && (b[i] = 0, d.clearRect(13 * i + 3, 13 * cr_l + 3, 10, 15)) } } //     d.clearRect(13 * c, 3, 15, 10); //     var f = 0, g = 0; //    d.fillStyle = "red"; //       character(-1, -1); //    document.body.onkeydown = function (a) { 36 < a.keyCode && 41 > a.keyCode && character((a.keyCode - 38) % 2, (a.keyCode - 39) % 2) } })("#canvas", 25, 30, 0, 0); 

Source: https://habr.com/ru/post/203478/



All Articles