{"size": 4598, "ext": "js", "max_stars_repo_path": "demo/canvas-026.js", "max_stars_repo_name": "w0lramD/Scrawl-canvas", "max_stars_repo_stars_event_min_datetime": null, "max_stars_repo_stars_event_max_datetime": null, "max_issues_repo_path": "demo/canvas-026.js", "max_issues_repo_name": "w0lramD/Scrawl-canvas", "max_issues_repo_issues_event_min_datetime": null, "max_issues_repo_issues_event_max_datetime": null, "max_forks_repo_path": "demo/canvas-026.js", "max_forks_repo_name": "w0lramD/Scrawl-canvas", "max_forks_repo_forks_event_min_datetime": null, "max_forks_repo_forks_event_max_datetime": null}
{"max_stars_count": null, "max_issues_count": null, "max_forks_count": null, "avg_line_length": 20.5267857143, "max_line_length": 89, "alphanum_fraction": 0.5717703349}
// # Demo Canvas 026 
// Tower of Hanoi

// [Run code](../../demo/canvas-026.html)
import * as scrawl from '../source/scrawl.js'

import { reportSpeed } from './utilities.js';

// Get Scrawl-canvas to recognise and act on device pixel ratios greater than 1
scrawl.setIgnorePixelRatio(false);


// #### Scene setup
let canvas = scrawl.library.canvas.mycanvas;


canvas.set({
    backgroundColor: 'honeydew',
}).setAsCurrentCanvas();

scrawl.makeBlock({

    name: 'peg-1',

    width: '30%',
    height: '90%',

    startX: '17%',
    startY: 'center',

    handleX: 'center',
    handleY: 'center',

    fillStyle: 'rgb(220, 220, 220)',
    strokeStyle: 'red',
    lineWidth: 5,

    method: 'drawThenFill',

}).clone({

    name: 'peg-2',
    startX: '50%',
    strokeStyle: 'blue',

}).clone({

    name: 'peg-3',
    startX: '83%',
    strokeStyle: 'orange',
});

scrawl.makeWheel({

    name: 'disc-1',

    order: 1,

    radius: '12%',

    handleX: 'center',
    handleY: 'center',

    pivot: 'peg-1',
    lockTo: 'pivot',

    fillStyle: 'pink',
    strokeStyle: 'red',
    lineWidth: 6,

    method: 'drawAndFill',

    shadowColor: 'black',

}).clone({

    name: 'disc-2',
    order: 2,
    radius: '10%',
    fillStyle: 'lightblue',
    strokeStyle: 'blue',

}).clone({

    name: 'disc-3',
    order: 3,
    radius: '8%',
    fillStyle: 'yellow',
    strokeStyle: 'orange',
});

let discGroup = scrawl.makeGroup({

    name: 'discs',
});

let dragActions = scrawl.makeDragZone({

    zone: canvas,
    collisionGroup: 'discs',
    endOn: ['up', 'leave'],
    exposeCurrentArtefact: true,

    resetCoordsToZeroOnTouchEnd: false,

    updateOnStart: {
        shadowBlur: 10,
        shadowOffsetX: 3,
        shadowOffsetY: 3,
    },

    updateOnEnd: {
        shadowBlur: 0,
        shadowOffsetX: 0,
        shadowOffsetY: 0,
    },
});

let checkPeg = function () {

    let peg, disc;

    let pegGroup = scrawl.makeGroup({

        name: 'pegs',

    }).addArtefacts('peg-1', 'peg-2', 'peg-3');

    // Setup the game's initial state
    let pegState = {

        'peg-1': ['disc-1', 'disc-2', 'disc-3'],
        'peg-2': [],
        'peg-3': [],
    };

    // Function to update the game's state
    // - mydisc will always be the last member of an array, 
    // - so we can pop it when found, then push it onto mypeg
    let updateState = function (mypeg, mydisc) {

        for (let [pName, pState] of Object.entries(pegState)) {

            if (pState.includes(mydisc.name)) pState.pop();
        }
        pegState[mypeg.name].push(mydisc.name);
    }

    // Function to update the disc group's membership
    // - a disc can only be moved if it is a member of this group
    let updateDiscGroup = function () {

        discGroup.clearArtefacts();

        for (let [pName, pState] of Object.entries(pegState)) {

            if (pState.length) discGroup.addArtefacts(pState[pState.length - 1]);
        }

        // Because this Group is outside the Display cycle
        // - (we haven't assigned it to a Cell object)
        // - we need to manually invoke its sort routine
        discGroup.sortArtefacts();
    }
    updateDiscGroup();

    // Enforce the game rules
    // - a disc can only move to a peg if no smaller discs are already on that peg
    let entity = scrawl.library.entity;

    let checkForLegalMove = function (mypeg, mydisc) {

        if (!pegState[mypeg.name].length) return true;

        return pegState[mypeg.name].every(d => entity[d].order < mydisc.order);
    }

    return function () {

        let hit = pegGroup.getArtefactAt(canvas.here);

        if (typeof hit !== 'boolean' && hit) peg = hit.artefact;
        else peg = false;

        let checkDrag = dragActions();

        if (typeof checkDrag !== 'boolean' && checkDrag) disc = checkDrag.artefact;

        else if (disc) {

            if (peg) {

                if (checkForLegalMove(peg, disc)) {

                    updateState(peg, disc);
                    updateDiscGroup();

                    disc.set({ 
                        pivot: peg, 
                    });
                }
            }
            disc = false;
        }
    }
}();

// #### Scene animation
// Function to display frames-per-second data, and other information relevant to the demo
const report = reportSpeed('#reportmessage');


// Create the Animation loop which will run the Display cycle
scrawl.makeRender({
    name: `${canvas.name}-render`,
    target: canvas,
    commence: checkPeg,
    afterShow: report,
});


// #### Development and testing
console.log(scrawl.library);
