-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtower_of_hanoi.min.js
98 lines (98 loc) · 19.4 KB
/
tower_of_hanoi.min.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
"use strict";function _typeof(a){return _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a},_typeof(a)}/**
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/var runtime=function(a){"use strict";function b(a,b,c,e){// If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator.
var f=b&&b.prototype instanceof d?b:d,g=Object.create(f.prototype),h=new m(e||[]);return g._invoke=i(a,c,h),g}// Try/catch helper to minimize deoptimizations. Returns a completion
// record like context.tryEntries[i].completion. This interface could
// have been (and was previously) designed to take a closure to be
// invoked without arguments, but in all the cases we care about we
// already have an existing method we want to call, so there's no need
// to create a new function object. We can even get away with assuming
// the method takes exactly one argument, since that happens to be true
// in every case, so we don't have to touch the arguments object. The
// only additional allocation required is the completion record, which
// has a stable shape and so hopefully should be cheap to allocate.
function c(a,b,c){try{return{type:"normal",arg:a.call(b,c)}}catch(a){return{type:"throw",arg:a}}}// Dummy constructor functions that we use as the .constructor and
// .constructor.prototype properties for functions that return Generator
// objects. For full spec compliance, you may wish to configure your
// minifier not to mangle the names of these two functions.
function d(){}function e(){}function f(){}// This is a polyfill for %IteratorPrototype% for environments that
// don't natively support it.
// Helper for defining the .next, .throw, and .return methods of the
// Iterator interface in terms of a single ._invoke method.
function g(a){["next","throw","return"].forEach(function(b){a[b]=function(a){return this._invoke(b,a)}})}function h(a){function b(d,e,f,g){var h=c(a[d],a,e);if("throw"===h.type)g(h.arg);else{var i=h.arg,j=i.value;return j&&"object"===_typeof(j)&&q.call(j,"__await")?Promise.resolve(j.__await).then(function(a){b("next",a,f,g)},function(a){b("throw",a,f,g)}):Promise.resolve(j).then(function(a){i.value=a,f(i)},function(a){// If a rejected Promise was yielded, throw the rejection back
// into the async generator function so it can be handled there.
return b("throw",a,f,g)})}}function d(a,c){function d(){return new Promise(function(d,e){b(a,c,d,e)})}return e=// If enqueue has been called before, then we want to wait until
// all previous Promises have been resolved before calling invoke,
// so that results are always delivered in the correct order. If
// enqueue has not been called before, then it is important to
// call invoke immediately, without waiting on a callback to fire,
// so that the async generator function has the opportunity to do
// any necessary setup in a predictable way. This predictability
// is why the Promise constructor synchronously invokes its
// executor callback, and why async functions synchronously
// execute code before the first await. Since we implement simple
// async functions in terms of async generators, it is especially
// important to get this right, even though it requires care.
e?e.then(d,// Avoid propagating failures to Promises returned by later
// invocations of the iterator.
d):d()}// Define the unified helper method that is used to implement .next,
// .throw, and .return (see defineIteratorMethods).
var e;this._invoke=d}function i(a,b,d){var e="suspendedStart";return function(f,g){if("executing"===e)throw new Error("Generator is already running");if("completed"===e){if("throw"===f)throw g;// Be forgiving, per 25.3.3.3.3 of the spec:
// https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume
return o()}for(d.method=f,d.arg=g;;){var h=d.delegate;if(h){var i=j(h,d);if(i){if(i===v)continue;return i}}if("next"===d.method)d.sent=d._sent=d.arg;else if("throw"===d.method){if("suspendedStart"===e)throw e="completed",d.arg;d.dispatchException(d.arg)}else"return"===d.method&&d.abrupt("return",d.arg);e="executing";var k=c(a,b,d);if("normal"===k.type){if(e=d.done?"completed":"suspendedYield",k.arg===v)continue;return{value:k.arg,done:d.done}}"throw"===k.type&&(// Dispatch the exception by looping back around to the
// context.dispatchException(context.arg) call above.
e="completed",d.method="throw",d.arg=k.arg)}}}// Call delegate.iterator[context.method](context.arg) and handle the
// result, either by returning a { value, done } result from the
// delegate iterator, or by modifying context.method and context.arg,
// setting context.delegate to null, and returning the ContinueSentinel.
function j(a,b){var d=a.iterator[b.method];if(void 0===d){if(b.delegate=null,"throw"===b.method){// Note: ["return"] must be used for ES3 parsing compatibility.
if(a.iterator["return"]&&(b.method="return",b.arg=void 0,j(a,b),"throw"===b.method))// If maybeInvokeDelegate(context) changed context.method from
// "return" to "throw", let that override the TypeError below.
return v;b.method="throw",b.arg=new TypeError("The iterator does not provide a 'throw' method")}return v}var e=c(d,a.iterator,b.arg);if("throw"===e.type)return b.method="throw",b.arg=e.arg,b.delegate=null,v;var f=e.arg;if(!f)return b.method="throw",b.arg=new TypeError("iterator result is not an object"),b.delegate=null,v;if(f.done)b[a.resultName]=f.value,b.next=a.nextLoc,"return"!==b.method&&(b.method="next",b.arg=void 0);else// Re-yield the result returned by the delegate method.
return f;// The delegate iterator is finished, so forget it and continue with
// the outer generator.
return b.delegate=null,v}// Define Generator.prototype.{next,throw,return} in terms of the
// unified ._invoke helper method.
function k(a){var b={tryLoc:a[0]};1 in a&&(b.catchLoc=a[1]),2 in a&&(b.finallyLoc=a[2],b.afterLoc=a[3]),this.tryEntries.push(b)}function l(a){var b=a.completion||{};b.type="normal",delete b.arg,a.completion=b}function m(a){this.tryEntries=[{tryLoc:"root"}],a.forEach(k,this),this.reset(!0)}function n(a){if(a){var b=a[s];if(b)return b.call(a);if("function"==typeof a.next)return a;if(!isNaN(a.length)){var c=-1,d=function b(){for(;++c<a.length;)if(q.call(a,c))return b.value=a[c],b.done=!1,b;return b.value=void 0,b.done=!0,b};return d.next=d}}// Return an iterator with no values.
return{next:o}}function o(){return{value:void 0,done:!0}}var p=Object.prototype,q=p.hasOwnProperty,r="function"==typeof Symbol?Symbol:{},s=r.iterator||"@@iterator",t=r.asyncIterator||"@@asyncIterator",u=r.toStringTag||"@@toStringTag";a.wrap=b;var v={},w={};w[s]=function(){return this};var x=Object.getPrototypeOf,y=x&&x(x(n([])));y&&y!==p&&q.call(y,s)&&(w=y);var z=f.prototype=d.prototype=Object.create(w);// Regardless of whether this script is executing as a CommonJS module
// or not, return the runtime object so that we can declare the variable
// regeneratorRuntime in the outer scope, which allows this module to be
// injected easily by `bin/regenerator --include-runtime script.js`.
return e.prototype=z.constructor=f,f.constructor=e,f[u]=e.displayName="GeneratorFunction",a.isGeneratorFunction=function(a){var b="function"==typeof a&&a.constructor;return!!b&&(b===e||// For the native GeneratorFunction constructor, the best we can
// do is to check its .name property.
"GeneratorFunction"===(b.displayName||b.name))},a.mark=function(a){return Object.setPrototypeOf?Object.setPrototypeOf(a,f):(a.__proto__=f,!(u in a)&&(a[u]="GeneratorFunction")),a.prototype=Object.create(z),a},a.awrap=function(a){return{__await:a}},g(h.prototype),h.prototype[t]=function(){return this},a.AsyncIterator=h,a.async=function(c,d,e,f){var g=new h(b(c,d,e,f));return a.isGeneratorFunction(d)?g// If outerFn is a generator, return the full iterator.
:g.next().then(function(a){return a.done?a.value:g.next()})},g(z),z[u]="Generator",z[s]=function(){return this},z.toString=function(){return"[object Generator]"},a.keys=function(a){var b=[];for(var c in a)b.push(c);// Rather than returning an object with a next method, we keep
// things simple and return the next function itself.
return b.reverse(),function c(){for(;b.length;){var d=b.pop();if(d in a)return c.value=d,c.done=!1,c}// To avoid creating an additional object, we just hang the .value
// and .done properties off the next function object itself. This
// also ensures that the minifier will not anonymize the function.
return c.done=!0,c}},a.values=n,m.prototype={constructor:m,reset:function reset(a){if(this.prev=0,this.next=0,this.sent=this._sent=void 0,this.done=!1,this.delegate=null,this.method="next",this.arg=void 0,this.tryEntries.forEach(l),!a)for(var b in this)// Not sure about the optimal order of these conditions:
"t"===b.charAt(0)&&q.call(this,b)&&!isNaN(+b.slice(1))&&(this[b]=void 0)},stop:function stop(){this.done=!0;var a=this.tryEntries[0],b=a.completion;if("throw"===b.type)throw b.arg;return this.rval},dispatchException:function dispatchException(a){function b(b,d){return f.type="throw",f.arg=a,c.next=b,d&&(c.method="next",c.arg=void 0),!!d}if(this.done)throw a;for(var c=this,d=this.tryEntries.length-1;0<=d;--d){var e=this.tryEntries[d],f=e.completion;if("root"===e.tryLoc)// Exception thrown outside of any try block that could handle
// it, so set the completion value of the entire function to
// throw the exception.
return b("end");if(e.tryLoc<=this.prev){var g=q.call(e,"catchLoc"),h=q.call(e,"finallyLoc");if(g&&h){if(this.prev<e.catchLoc)return b(e.catchLoc,!0);if(this.prev<e.finallyLoc)return b(e.finallyLoc)}else if(g){if(this.prev<e.catchLoc)return b(e.catchLoc,!0);}else if(!h)throw new Error("try statement without catch or finally");else if(this.prev<e.finallyLoc)return b(e.finallyLoc)}}},abrupt:function abrupt(a,b){for(var c,d=this.tryEntries.length-1;0<=d;--d)if(c=this.tryEntries[d],c.tryLoc<=this.prev&&q.call(c,"finallyLoc")&&this.prev<c.finallyLoc){var e=c;break}e&&("break"===a||"continue"===a)&&e.tryLoc<=b&&b<=e.finallyLoc&&(e=null);var f=e?e.completion:{};return f.type=a,f.arg=b,e?(this.method="next",this.next=e.finallyLoc,v):this.complete(f)},complete:function complete(a,b){if("throw"===a.type)throw a.arg;return"break"===a.type||"continue"===a.type?this.next=a.arg:"return"===a.type?(this.rval=this.arg=a.arg,this.method="return",this.next="end"):"normal"===a.type&&b&&(this.next=b),v},finish:function finish(a){for(var b,c=this.tryEntries.length-1;0<=c;--c)if(b=this.tryEntries[c],b.finallyLoc===a)return this.complete(b.completion,b.afterLoc),l(b),v},catch:function _catch(a){for(var b,c=this.tryEntries.length-1;0<=c;--c)if(b=this.tryEntries[c],b.tryLoc===a){var d=b.completion;if("throw"===d.type){var e=d.arg;l(b)}return e}// The context.catch method must only be called with a location
// argument that corresponds to a known catch block.
throw new Error("illegal catch attempt")},delegateYield:function delegateYield(a,b,c){return this.delegate={iterator:n(a),resultName:b,nextLoc:c},"next"===this.method&&(this.arg=void 0),v}},a}(// If this script is executing as a CommonJS module, use module.exports
// as the regeneratorRuntime namespace. Otherwise create a new empty
// object. Either way, the resulting object will be used to initialize
// the regeneratorRuntime variable at the top of this file.
"object"===("undefined"==typeof module?"undefined":_typeof(module))?module.exports:{});try{regeneratorRuntime=runtime}catch(a){// This module should not be running in strict mode, so the above
// assignment should always work unless something is misconfigured. Just
// in case runtime.js accidentally runs in strict mode, we can escape
// strict mode using a global Function call. This could conceivably fail
// if a Content Security Policy forbids using Function, but in that case
// the proper solution is to fix the accidental strict mode problem. If
// you've misconfigured your bundler to force strict mode and applied a
// CSP to forbid Function, and you're not willing to fix either of those
// problems, please detail your unique predicament in a GitHub issue.
Function("r","regeneratorRuntime = r")(runtime)}/*
tower_of_hanoi.js
Created by Douile (https://github.com/Douile/)
For licensing see LICENSE (MIT)
*/function map(a,b,c,d,e){return(a-b)/(c-b)*(e-d)+d}function Stack(a){var b=new Uint8Array(a);return Object.defineProperties(b,{position:{value:0,writable:!0},add:{value:function value(a){if(this.position>=this.byteLength)throw new Error("Stack already full");return this[this.position]=a,this.position+=1}},remove:{value:function(){if(1>this.position)throw new Error("Stack empty");this.position-=1;var a=this[this.position];return a}},peek:{value:function value(){return 0<this.position?this[this.position-1]:null}}}),b}function Modal(a,b){var c=document.querySelector("#".concat(a));if(null===c)throw new Error("Could not find modal ".concat(a));b||(b={});var d=c.innerHTML,e=/\$[^\$\n]+\$/g,f=d.match(e);if(null!==f){var g=!0,h=!1,i=void 0;try{for(var j,k=f[Symbol.iterator]();!(g=(j=k.next()).done);g=!0){var l=j.value,m=l.substr(1,l.length-2);d=d.replace(l,m in b?b[m]:"")}}catch(a){h=!0,i=a}finally{try{g||null==k.return||k.return()}finally{if(h)throw i}}}var n=document.createElement("template");n.innerHTML=d;var o=document.importNode(n.content,!0);return document.querySelector(".container-modal").appendChild(o),o}function App(){var a=Math.floor,b={};return Object.defineProperties(b,{_canvas:{enumerable:!1,writable:!0},canvas:{enumerable:!1,get:function get(){return this._canvas?this._canvas:this._canvas=document.getElementById("game-canvas")}},_context:{enumerable:!1,writable:!0},context:{enumerable:!1,get:function get(){return this._context?this._context:this._context=this.canvas.getContext("2d")}},width:{get:function get(){return this.canvas.width},set:function set(a){return this.canvas.width=a}},height:{get:function get(){return this.canvas.height},set:function set(a){return this.canvas.height=a}},_selected:{enumerable:!1,writable:!0,value:0},selected:{get:function get(){return this._selected},set:function set(a){if(null!==this.floating)this._selected=0>a?this.nTowers-1:a>=this.nTowers?0:a;else if(a<this._selected){for(var b=a;0<=b;b-=1)if(0<this.towers[b].position)return this._selected=b;for(var c=this.nTowers-1;c>a;c-=1)if(0<this.towers[c].position)return this._selected=c}else if(a>this._selected){for(var d=a;d<this.nTowers;d++)if(0<this.towers[d].position)return this._selected=d;for(var e=0;e<a;e++)if(0<this.towers[e].position)return this._selected=e}}},_nTowers:{enumerable:!1,writable:!0},nTowers:{get:function get(){return this._nTowers},set:function set(a){1<a&&(this._nTowers=a,this.buildTowers())}},_nRings:{enumerable:!1,writable:!0},nRings:{get:function get(){return this._nRings},set:function set(a){1<a&&(this._nRings=a,this.buildTowers())}},_acceptInput:{value:!0,writable:!0,enumerable:!1},buildTowers:{value:function value(){var a=Math.pow;if(!isNaN(this.nRings)&&!isNaN(this.nTowers)){this.floating=null,this.minMoves=3===this.nTowers?a(2,this.nRings)-1:null,this.moves=0,this.playKey=0,delete this.towers,this.towers=Array(this.nTowers);for(var b,c=0;c<this.nTowers;c++){if(b=Stack(this.nRings),0==c)for(var d=1;d<=this.nRings;d++)b.add(this.nRings-d);this.towers[c]=b}this.selected=0}}},initialize:{value:function value(a,b){console.log("App starting"),this.width=a,this.height=b,this.floating=null,this.nTowers=3,this.nRings=3,console.log(this.sizes(this.nTowers,this.nRings));var c=this;return window.addEventListener("keydown",function(a){c.onKey(a)}),this.context.font="10px consolas",this.draw(),document.querySelector(".container-loading").style.opacity=0,this}},onKey:{value:function value(a){if(this._acceptInput)switch(a.keyCode){case 39:case 68:this.selected+=1;break;case 37:case 65:this.selected-=1;break;case 13:case 32:case 38:case 40:case 87:case 83:if(null!==this.floating){var b=this.towers[this.selected];(0===b.position||0<b.position&&b[b.position-1]>this.floating)&&(b.add(this.floating),this.floating=null,this.moves+=1)}else this.floating=this.towers[this.selected].remove();// console.log(`Completed ${this.towers[this.nTowers-1].position}/${this.nRings}`);
if(this.towers[this.nTowers-1].position===this.nRings){// alert('Well done!');
// this.nRings += 1;
var c=document.querySelector(".container-game");c.removeAttribute("completed"),requestAnimationFrame(function(){c.setAttribute("completed","")})}break;case 82:this.buildTowers();}}},sizes:{value:function value(b,c){var d=Math.max,e=Math.ceil;if(isNaN(b))throw new Error("nTowers must be a number");if(isNaN(c))throw new Error("nRings must be a number");for(var f=this.width,g=this.height,h=1-2*.2,j=f*h,k=g*h,l=j/b,m=l*.1,n=(l-m)/2,o=k*.9,p=Array(b),q=0;q<b;q++){var r=l*q+n+(f-j)/2;p[q]={x:r,y:(k-o)/2+(g-k)/2}}for(var s=Array(c),t=o/d(20,e(1.4*this.nRings)),u=0;u<c;u++){var v=a(map(u,0,c,.3*l,.9*l));s[u]={width:v,height:t,offsetX:n-(l-v)/2}}return{tower:{width:m,height:o,positions:p},rings:s}}},draw:{value:function value(){if(this)var c=this;window.requestAnimationFrame(function(){c.draw()});this.context.clearRect(0,0,this.width,this.height);for(var d,e=b.sizes(this.nTowers,this.nRings),f=0;f<this.nTowers;f++){d=e.tower.positions[f],this.context.fillStyle="#ffffff",this.context.fillRect(d.x,d.y,e.tower.width,e.tower.height);for(var g=0;g<this.towers[f].position;g++){var h=this.towers[f][g],k=d.x-e.rings[h].offsetX,l=d.y+e.tower.height-1.4*e.rings[h].height*(g+1);this.context.fillStyle="#".concat(a(map(h,0,this.nRings-1,0,255)).toString(16).padStart(2,"0"),"ff00"),this.context.fillRect(k,l,e.rings[h].width,e.rings[h].height),this.selected===f&&null===this.floating&&g==this.towers[f].position-1&&(this.context.strokeStyle="#ff0000",this.context.lineWidth="4",this.context.strokeRect(k,l,e.rings[h].width,e.rings[h].height))}if(this.selected===f&&null!==this.floating){var m=e.rings[this.floating],n=d.x-m.offsetX,o=d.y-1.4*m.height;this.context.fillStyle="#00ff00",this.context.fillRect(n,o,m.width,m.height)}}this.context.fillStyle="#ffffff",this.context.textAlign="right",this.context.font="80pt consolas",this.context.fillText("".concat(this.moves,"/").concat(this.minMoves),this.width,100)}},play:{value:function value(){function a(b,d,e,f){return regeneratorRuntime.wrap(function(c){for(;;)switch(c.prev=c.next){case 0:if(!(0<b)){c.next=5;break}return c.delegateYield(a(b-1,d,f,e),"t0",2);case 2:return c.next=4,[d,e];case 4:return c.delegateYield(a(b-1,f,e,d),"t1",5);case 5:case"end":return c.stop();}},c)}function b(){var a=d.next();e.playKey!==f||a.done||!1!==e._acceptInput?(e._acceptInput=!0,document.querySelector(".overlay-auto").setAttribute("paused","")):(e.towers[a.value[1]].add(e.towers[a.value[0]].remove()),e._selected=a.value[1],e.moves+=1,setTimeout(b,100))}var c=/*#__PURE__*/regeneratorRuntime.mark(a);this._acceptInput=!1,this.buildTowers();var d=a(this.nRings,0,2,1),e=this,f=new Date().getTime();e.playKey=f,b()}},stop:{value:function value(){this._acceptInput=!0}}}),b}var _app=App().initialize(4e3,4e3);window.addEventListener("click",function(a){var b=0;a.target.classList.forEach(function(c){switch(c){case"overlay-settings":console.log("Toggling settings overlay");break;case"overlay-auto":var d=a.target.hasAttribute("paused");d?(_app.play(),a.target.removeAttribute("paused")):(_app.stop(),a.target.setAttribute("paused",""));break;case"overlay-plus":_app.nRings+=1;break;case"overlay-minus":3<_app.nRings&&(_app.nRings-=1);break;case"modal-background":document.querySelector(".container-modal").innerHTML="";break;case"overlay-github":break;default:b+=1;}}),b===a.target.classList.length&&a.preventDefault()});