2016年10月5日水曜日

開発環境

アルゴリズムパズル(Anany Levitin (著)、Maria Levitin (著)、黒川 洋 (翻訳)、松崎 公紀 (翻訳)、オライリージャパン)の中級パズル、64.(八角形の作成 (Creating Octagons))をJavaScriptで。

64.(八角形の作成 (Creating Octagons))

コード(Emacs)

HTML5

<div id="graph0"></div>
<label for="n0">点の個数: n = </label>
<input id="n0" type="number" min="8" step="8" value="40">
<button id="polygons">八角形を生成して描画</button>

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.6/d3.min.js" integrity="sha256-5idA201uSwHAROtCops7codXJ0vja+6wbBrZdQ6ETQc=" crossorigin="anonymous"></script>
<script src="sample64.js"></script>

JavaScript

{
    'use strict';
    Array.range = function (start, end, step) {
        var nums = [],
            i;

        if (step === 0) {
            throw {
                name: 'ValueError',
                message: 'range() arg 3 must not be zero',
            };
        }
        if (step === undefined) {
            step = 1;
        }
        if (end === undefined) {
            end = start;
            start = 0;
        }
        if (step > 0) {
            for (i = start; i < end; i += step) {
                nums.push(i);
            }
        } else {
            for (i = start; i > end; i += step) {
                nums.push(i);
            }
        }
        return nums;
    };
    let points,
        svg,
        width = 600,
        height = 600,
        padding = 50,
        div_graph = document.querySelector('#graph0'),
        input_n = document.querySelector('#n0'),
        input_polygons = document.querySelector('#polygons');

    let getPoints = (n) => {
        let points = Array.range(n).map(
            () => [Math.random() * (width - 1) + 1,
                   Math.random() * (height - 1) + 1]
        );
        points.sort((p1, p2) => {
            let x1 = p1[0],
                x2 = p2[0];

            if (x1 === x2) {
                return p1[1] - p2[1];
            }
            return x1 - x2;
        });
        return points;
    };

    let drawPoints = () => {
        let n = parseInt(input_n.value, 10);        
        
        points = getPoints(n),
        div_graph.innerHTML = '';
        svg = d3.select('#graph0')
            .append('svg')
            .attr('width', width)
            .attr('height', height);

        svg.selectAll('circle')
            .data(points)
            .enter()
            .append('circle')
            .attr('cx', (d) => d[0])
            .attr('cy', (d) => d[1])
            .attr('r', 2)
            .attr('fill', 'green');
    };

    let getLineFunc = (p1, p2) => {
        let x1 = p1[0],
            x2 = p2[0];

        if (x1 === x2) {
            throw {
                name: '',
                message: '',
            };
        }
        let a = (p2[1] - p1[1]) / (x2 - x1);
        return (x) => a * x - a * x1 + p1[1];
    };
    let drawPolygons = () => {
        let polygons = [],
            color = 'blue';

        let polygon = [];
        console.log(points);
        points.forEach((p, i) => {
            if (i % 8 === 7) {
                let p0 = polygon.shift(),
                    func = getLineFunc(p0, p);
                let ps1 = polygon.filter((p) => func(p[0])< p[1]),
                    ps2 = polygon.filter((p) => func(p[0])> p[1]);
                ps1.sort((p1, p2) => p1[0] - p2[0]);
                ps2.sort((p1, p2) => p2[0] - p1[0]);
                polygons.push([p0].concat(ps1).concat([p]).concat(ps2));
                polygon = [];
            } else {
                polygon.push(p);
            }
        });
        console.log(polygons);
        points = polygons.reduce((p1, p2) => p1.concat(p2), []);
        svg.selectAll('line')
            .data(points)
            .enter()
            .append('line')
            .attr('x1', (d) => d[0])
            .attr('y1', (d) => d[1])
            .attr('x2', (d, i) => points[i + (i % 8 === 7 ? -7 : 1)][0])        
            .attr('y2', (d, i) => points[i + (i % 8 === 7 ? -7 : 1)][1])
            .attr('stroke', (d, i) => {
                if (i % 8 === 0) {
                    color =
                        color === 'red' ? 'green' :
                        color === 'green' ? 'blue' : 'red';
                }
                return color;
            });    
    };
    input_n.onchange = drawPoints;
    polygons.onclick = drawPolygons;
    drawPoints();
    drawPolygons();
}

0 コメント:

コメントを投稿