2016年10月2日日曜日

開発環境

アルゴリズムパズル(Anany Levitin (著)、Maria Levitin (著)、黒川 洋 (翻訳)、松崎 公紀 (翻訳)、オライリージャパン)の中級パズル、61.(対角線上のチェッカー(Checkers on a Diagonal))をJavaScriptで。

n = 4k、n = 4k + 1 (k = 1, 2, …)の時に可能。

コード(Emacs)

HTML5

<div id="board0"></div>
<label for="n0">チェッカー盤 n = </label>
<input id="n0" type="number" min="4" step="1" value="4">
<label for="speed0">
  速度:
</label>
<input id="speed0" type="range" min="1" max="10000" value="1">
<span id="count0"></span>
<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="array.js"></script>
<script src="sample61.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 lines,
        pieces,
        count,
        svg,
        width = 600,
        height = 600,
        padding = 50,
        xscale,
        yscale,
        n,
        min,
        max,
        w,
        h,
        r,
        interval,
        ts = [],
        div_board = document.querySelector('#board0'),
        input_n = document.querySelector('#n0'),
        input_speed = document.querySelector('#speed0'),
        span_count = document.querySelector('#count0');

    let drawLines = () => {
        div_board.innerHTML = '';
        svg = d3.select('#board0')
            .append('svg')
            .attr('width', width)
            .attr('height', height);
        svg.selectAll('line')
            .data(lines)
            .enter()
            .append('line')
            .attr('x1', (d) => xscale(d[0][0]))
            .attr('y1', (d) => yscale(d[0][1]))
            .attr('x2', (d) => xscale(d[1][0]))
            .attr('y2', (d) => yscale(d[1][1]))
            .attr('stroke', 'black');
    };
    let downPieces = () => {
        count += 1;
        span_count.innerText = `${count}手`;

        let c = 0;
        for (let i = 0; i < n; i += 1) {
            if (pieces[i][1] > r) {
                pieces[i][1] -= h;
                c += 1;
                if (c === 2) {
                    break;
                }
            }
        }
        if (c === 2) {
            drawLines();
            drawPieces();
        }
    };
    let drawPieces = () => {
        svg.selectAll('circle')
            .data(pieces)
            .enter()
            .append('circle')
            .attr('cx', (d) => xscale(d[0]))
            .attr('cy', (d) => yscale(d[1]))
            .attr('r', xscale(r) - xscale(0))
            .attr('fill', 'green')
            .attr('stroke', 'yellow');
        
        if (pieces.filter((p) => p[1] > r).length >= 2) {
            interval = 1000 / parseFloat(input_speed.value);
            ts.push(setTimeout(downPieces, interval));
        }
    };
    let output = () => {
        for (let i = 0, len = ts.length; i < len; i += 1) {
            clearTimeout(ts[i]);
        }
        n = parseInt(input_n.value, 10);
        min = 0;
        max = n;
        w = max / n;
        h = w;
        r = w / 2,
        count = 0;

        xscale = d3.scaleLinear()
            .domain([min, max])
            .range([padding, width - padding]);
        yscale = d3.scaleLinear()
            .domain([min, max])
            .range([height - padding, padding]);

        lines = Array.range(0, max + h, h)
            .map((y) => [[min, y],
                         [max, y]])
            .concat(Array.range(0, max + w, w)
                    .map((x) => [[x, min],
                                 [x, max]]));
        
        pieces = Array.range(0, n)
            .map((i) => [w * i + r, max - h * i - r]);    
        drawLines();
        drawPieces();
    };
    input_n.onchange = output;

    output();

}

0 コメント:

コメントを投稿