Random Connected Area - Mix

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

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

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

    _getContiguous(frontier) {
        return Filler3.DIRS.map(dir => ({
            x: frontier.x + dir[0],
            y: frontier.y + dir[1]
        }));
    }
    
    _processFrontier(coor) {
        // 获取接壤坐标
        const contiguousOfNewCoor = this._getContiguous(coor).filter(coor => {
            if (coor.x < 0 || coor.y < 0 || coor.x >= this.length || coor.y >= this.length) return false;
            return true;
        });

        // 若有一个接壤点为空,就认为当前坐标是边界,若是边界则把当前坐标加入对象
        if (contiguousOfNewCoor.reduce((ret, coor) => {
            if (this.map[coor.x][coor.y] === "x") return ret;
            return true;
        }, false)) {
            this.frontiers[`${coor.x}:${coor.y}`] = true;
            this.frontierCount++;
        }

        // 再检查接壤的坐标是否继续为边界
        for (let i = 0; i < contiguousOfNewCoor.length; i++) {
            const cur = contiguousOfNewCoor[i];

            const isFrontier = this._getContiguous(cur).filter(coor => {
                if (coor.x < 0 || coor.y < 0 || coor.x >= this.length || coor.y >= this.length) return false;
                return true;
            }).reduce((ret, coor) => {
                if (this.map[coor.x][coor.y] === "x") return ret;
                return true;
            }, false);

            // 若不是边界的话,只管删除
            if (!isFrontier && this.frontiers[`${cur.x}:${cur.y}`]) {
                delete this.frontiers[`${cur.x}:${cur.y}`];
                this.frontierCount--;
            }
        }
    }
    
    _getUsableContiguous(coor) {
        // _getContiguous 算出接壤坐标,filter 去除无用坐标
        return this._getContiguous({
            x: coor.x,
            y: coor.y
        }).filter(coor => {
            if (coor.x < 0 || coor.y < 0 || coor.x >= this.length || coor.y >= this.length) return false;
            if...