Random Connected Area - Frenzied real

https://xcoder.in/2018/04/02/random-connected-area/#生成「胖胖的」区域

by XadillaX

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/fbbk-json/1.1.1/fjson.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>
<input id="length" placeholder="宽高" />
<input id="need-area" placeholder="填充面积" />
<button id="gen">生成</button>
<br />
<canvas id="cvs"></canvas><br /><br />

<img style="display: none;" id="tile" src="http://xcoder-7niu.nbut.ac.cn/basictiles.png" />

CSS

body {
    background: #20262E;
    padding: 20px;
    font-family: Helvetica;
}

#banner-message {
    background: #fff;
    border-radius: 4px;
    padding: 20px;
    font-size: 25px;
    text-align: center;
    transition: all 0.2s;
    margin: 0 auto;
    width: 300px;
}

button {
    background: #0084ff;
    border: none;
    border-radius: 5px;
    padding: 8px 14px;
    font-size: 15px;
    color: #fff;
}

#banner-message.alt {
    background: #0084ff;
    color: #fff;
    margin-top: 40px;
    width: 200px;
}

#banner-message.alt button {
    background: #fff;
    color: #000;
}

JavaScript

'use strict';

const BFS_HOLE = Symbol('bfsHole');
const DELETE_FRONTIER = Symbol('deleteFrontier');
const GET_CONTIGUOUS = Symbol('getContiguous');
const IS_INSIDE_MAT = Symbol('isInsideMat');
const IS_FRONTIER = Symbol('isFrontier');
const IS_BREAKING_SIMPLY_CONNECTED = Symbol('isBreakingSymplyConnected');
const PUT_FRONTIER = Symbol('putFrontier');
const RANDOM_COOR = Symbol('randomCoor');
const RANDOM_FRONTIER = Symbol('randomFrontier');
const FILL_FAT = Symbol('fillFat');
const FILL_DFS = Symbol('fillDFS');
const UPDATE_FRONTIERS = Symbol('updateFrontier');
const FRONTIER_EXIST = Symbol('frontierExist');

function random(max) {
    return Math.round(Math.random() * max);
}

class Filler4 {
    constructor(length, needArea) {
        this.length = length;
        this.needArea = needArea;
    }

    [BFS_HOLE](start1, start2) {
        const mat = _.cloneDeep(this.mat);

        let which;
        let q1 = [ start1 ];
        let q2 = [ start2 ];
        const fill1 = [];
        const fill2 = [];

        if(!this[IS_INSIDE_MAT](start1)) {
            which = 2;
            q1 = [];
        }

        if(!this[IS_INSIDE_MAT](start2)) {
            which = 1;
            q2 = [];
        }

        // 双队列 BFS,哪个先结束就哪个
        while(true) {
            // 执行队列 1
            if(q1.length) {
                const coor = q1.shift();
                if(this[IS_INSIDE_MAT](coor) && mat[coor.x][coor.y] === '.') {
                    const x = coor.x, y = coor.y;
                    if(coor.x === 0 || coor.x === this.length - 1 || coor.y === 0 || coor.y === this.length - 1) {
                        // q1 在单连通区域之外,不需要继续搜索
                        q1 = [];
                        which = 2;
                    } else {
                        mat[coor.x][coor.y] = 'x';
                        fill1.push(coor);
                        q1.push({ x: x - 1, y });
                        q1.push({ x: x + 1, y });
                        q1.push({ x, y: y - 1 });
           ...