sluchaynayakotya

sweet_loaf

Nov 28th, 2020
824
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /* gen by new.py at 2020-11-28 01:42:48.024758 */
  2. window.onload = async function onload() {
  3.   // if ('seedrandom' in Math) Math.seedrandom('0');
  4.   const height = 400;
  5.   const width = 400;
  6.   const ctx = document.createElement('canvas').getContext('2d');
  7.   ctx.canvas.height = height;
  8.   ctx.canvas.width = width;
  9.   document.body.appendChild(ctx.canvas);
  10.   ctx.imageSmoothingEnabled = false;
  11.  
  12.   const COLORS = Array(10).fill().map(() => `rgb(${Array(3).fill().map(() => Math.random()*256)})`);
  13.  
  14.  
  15.  
  16.   ctx.save();
  17.   ctx.fillStyle = 'black';
  18.   ctx.fillRect(0, 0, width, height);
  19.   ctx.translate(200, 200);
  20.   ctx.scale(6, 6);
  21.  
  22.  
  23.   const grid = new InfinitGrid();
  24.  
  25.   const rect_max_w = 20;
  26.   const rect_max_h = 20;
  27.   const rect_min_w = 4;
  28.   const rect_min_h = 4;
  29.   const rect_min_per = 4; // any face of rect must be equal or greater than rect_min_per
  30.  
  31.   const tries_num = 1000;
  32.   const rects_num = 3;
  33.   const rects = [];
  34.  
  35.   for (let i = 0; i < rects_num; ++i) {
  36.     for (let t = 0; t < tries_num; ++t) {
  37.       const parent = rects[Math.random() * rects.length | 0] || [0, 0, 0, 0];
  38.       const w = rect_min_w + Math.random() * (rect_max_w - rect_min_w) | 0;
  39.       const h = rect_min_h + Math.random() * (rect_max_h - rect_min_h) | 0;
  40.       const angle = Math.random() * Math.PI * 2;
  41.       const r = (Math.min(parent[2], parent[3]) + Math.min(w, h)) / 2;
  42.       const x = parent[0] + parent[2] / 2 + r * Math.cos(angle) - w / 2 | 0;
  43.       const y = parent[1] + parent[3] / 2 + r * Math.sin(angle) - h / 2 | 0;
  44.  
  45.       if (grid.fill_back(x, y, w, h, i) === 0) continue; // area == 0
  46.  
  47.       // TODO: нужно найти все точки, граничащие с void'ом, и посчитать длину стрипа до любого другого индекса (или воида).
  48.       //       если длина стрипа меньше rect_min_per -- не ok.
  49.  
  50.       if (grid.faces(i, null, x, y, x+w, y+h).some((side) => side.some((line) => {
  51.         const w = Math.abs(line[2]-line[0]);
  52.         const h = Math.abs(line[3]-line[1]);
  53.         return w > 0 && w < rect_min_per || h > 0 && h < rect_min_per;
  54.       })))
  55.       { // not ok
  56.         grid.clear_value(i);
  57.       } else { // ok
  58.         rects.push([x, y, w, h]);
  59.         break;
  60.       }
  61.     }
  62.   }
  63.  
  64.  
  65.   for (let y = grid.top; y <= grid.bottom; ++y) {
  66.     if (grid.grid[y] instanceof Array) {
  67.       for (let x = grid.left; x <= grid.right; ++x) {
  68.         if (grid.grid[y][x] != null) {
  69.           ctx.fillStyle = COLORS[grid.grid[y][x]];
  70.           ctx.fillRect(x, y, 0.9, 0.9);
  71.         }
  72.       }
  73.     }
  74.   }
  75.   ctx.restore();
  76. }
  77.  
  78. // negative indices will be used, also no boundary checks
  79. class InfinitGrid {
  80.   constructor() {
  81.     this.grid = [];
  82.     this.top = 0;
  83.     this.left = 0;
  84.     this.right = 0;
  85.     this.bottom = 0;
  86.   }
  87.  
  88.   get(x, y) {
  89.     if (this.grid[y] instanceof Array) {
  90.       return this.grid[y][x];
  91.     }
  92.     return null;
  93.   }
  94.  
  95.   // intersection_area(x, y, w, h) {
  96.   //   let area = 0;
  97.   //   for (let y0 = 0; y0 < h; ++y0) {
  98.   //     if (this.grid[y0+y] instanceof Array) {
  99.   //       for (let x0 = 0; x0 < w; ++x0) {
  100.   //         area += ~~(this.grid[y0+y][x0+x] != null);
  101.   //       }
  102.   //     }
  103.   //   }
  104.   //   return area;
  105.   // }
  106.  
  107.   fill_back(x, y, w, h, value) {
  108.     let area = 0;
  109.     if (x < this.left) this.left = x;
  110.     if (x+w > this.right) this.right = x+w;
  111.     if (y < this.top) this.top = y;
  112.     if (y+h > this.bottom) this.bottom = y+h;
  113.     for (let y0 = 0; y0 < h; ++y0) {
  114.       if (!(this.grid[y0+y] instanceof Array)) {
  115.         this.grid[y0+y] = [];
  116.       }
  117.       for (let x0 = 0; x0 < w; ++x0) {
  118.         if (this.grid[y0+y][x0+x] == null) {
  119.           this.grid[y0+y][x0+x] = value;
  120.           ++area;
  121.         }
  122.       }
  123.     }
  124.     return area;
  125.   }
  126.  
  127.   /*
  128.   clone() {
  129.     const clone = new this.constructor();
  130.     for (let y = this.top; y <= this.bottom; ++y) {
  131.       if (this.grid[y] instanceof Array) {
  132.         clone.grid[y] = [];
  133.         for (let x = this.left; x <= this.right; ++x) {
  134.           if (this.grid[y][x] != null) {
  135.             clone.grid[y][x] = this.grid[y][x];
  136.           }
  137.         }
  138.       }
  139.     }
  140.     clone.top = this.top;
  141.     clone.left = this.left;
  142.     clone.right = this.right;
  143.     clone.bottom = this.bottom;
  144.     return clone;
  145.   }
  146.   */
  147.  
  148.   clear_value(value) {
  149.     for (let y = this.top; y <= this.bottom; ++y) {
  150.       if (this.grid[y] instanceof Array) {
  151.         for (let x = this.left; x <= this.right; ++x) {
  152.           if (this.grid[y][x] === value) {
  153.             this.grid[y][x] = null;
  154.           }
  155.         }
  156.       }
  157.     }
  158.   }
  159.  
  160.  
  161.   // make_outlines from creature/grid.js~205
  162.   faces(for_index, void_value, left, top, right, bottom) {
  163.     top = top || this.top;
  164.     left = left || this.left;
  165.     right = right || this.right;
  166.     bottom = bottom || this.bottom;
  167.     void_value = void_value || null;
  168.     const FCI = for_index != null; // "for certain index" flag (if not then for all non null)
  169.     const FIV = FCI ? for_index : void_value; // "for_index" value
  170.     const faces_L=[], faces_T=[], faces_R=[], faces_B=[];
  171.     for (let y = top; y <= bottom; ++y) {
  172.       if (!(this.grid[y] instanceof Array)) continue;
  173.       for (let x = left; x <= right; ++x) {
  174.         if (this.grid[y][x] == void_value) continue; // skip void cell.
  175.         if (FCI && this.grid[y][x] != FIV) continue; // skip for certain index.
  176.         if (this.grid[y][x-1] == FIV ^ FCI) {
  177.           const line = faces_L.find((line) => x === line[0] && y === line[3]);
  178.           if (line) line[3] = y+1; else faces_L.push([x, y, x, y+1]);
  179.         }
  180.         if (this.grid[y][x+1] == FIV ^ FCI) {
  181.           const line = faces_R.find((line) => x+1 === line[0] && y === line[3]);
  182.           if (line) line[3] = y+1; else faces_R.push([x+1, y, x+1, y+1]);
  183.         }
  184.         if (!(this.grid[y-1] instanceof Array) || (this.grid[y-1][x] == FIV ^ FCI)) {
  185.           const line = faces_T.find((line) => y === line[1] && x === line[2]);
  186.           if (line) line[2] = x+1; else faces_T.push([x, y, x+1, y]);
  187.         }
  188.         if (!(this.grid[y+1] instanceof Array) || (this.grid[y+1][x] == FIV ^ FCI)) {
  189.           const line = faces_B.find((line) => y+1 === line[1] && x === line[2]);
  190.           if (line) line[2] = x+1; else faces_B.push([x, y+1, x+1, y+1]);
  191.         }
  192.       }
  193.     }
  194.     return [faces_L, faces_T, faces_R, faces_B];
  195.   }
  196.  
  197. }
  198.  
RAW Paste Data