519 lines
22 KiB
JavaScript
519 lines
22 KiB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
});
|
|
};
|
|
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
function step(op) {
|
|
if (f) throw new TypeError("Generator is already executing.");
|
|
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
switch (op[0]) {
|
|
case 0: case 1: t = op; break;
|
|
case 4: _.label++; return { value: op[1], done: false };
|
|
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
default:
|
|
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
if (t[2]) _.ops.pop();
|
|
_.trys.pop(); continue;
|
|
}
|
|
op = body.call(thisArg, _);
|
|
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
}
|
|
};
|
|
var CANVAS_ID = "myCanvas";
|
|
var BG_RECT = { x: 0, y: 0, w: 1050, h: 1050 };
|
|
var FPS = 30;
|
|
var FRAME_INTERVAL = 1000 / FPS;
|
|
var WAIT_TIME = 300;
|
|
var PROCESSING = false;
|
|
var GLOBAL_PROCESSING = false;
|
|
var LEARNING = false;
|
|
var canvas = document.getElementById(CANVAS_ID);
|
|
var ctx = canvas.getContext("2d");
|
|
canvas.width = BG_RECT.w;
|
|
canvas.height = BG_RECT.h;
|
|
var staticCanvas = document.createElement('canvas');
|
|
var staticCtx = staticCanvas.getContext("2d");
|
|
staticCanvas.width = BG_RECT.w;
|
|
staticCanvas.height = BG_RECT.h;
|
|
var animationFrameId;
|
|
var lastFrameTime = 0;
|
|
var callbacks = [];
|
|
var Pile = /** @class */ (function () {
|
|
function Pile() {
|
|
this.length = 0;
|
|
this.mem = [];
|
|
}
|
|
Pile.prototype.push = function (e) {
|
|
this.length++;
|
|
this.mem.push(e);
|
|
};
|
|
Pile.prototype.pop = function () {
|
|
this.length = this.length > 0 ? this.length - 1 : 0;
|
|
return this.mem.pop();
|
|
};
|
|
Pile.prototype.empty = function () {
|
|
this.mem = [];
|
|
this.length = 0;
|
|
};
|
|
Pile.prototype.draw = function (x, y) {
|
|
var w = 150;
|
|
var h = 200;
|
|
var e = 10;
|
|
var eh = 10;
|
|
// container
|
|
staticCtx.fillStyle = "#000000";
|
|
staticCtx.fillRect(x - w / 2, y - h, w, h);
|
|
staticCtx.fillStyle = "#ffffff";
|
|
staticCtx.fillRect(x - w / 2 + e, y - h, w - 2 * e, h - e);
|
|
// element
|
|
var ye = y - e - eh / 2;
|
|
for (var i = 0; i < this.length; i++) {
|
|
var ew = this.mem[i].value / 10 * (w - 2 * e);
|
|
staticCtx.fillStyle = this.mem[i].color;
|
|
staticCtx.fillRect(x - ew / 2, ye - i * eh - eh / 2, ew, eh);
|
|
}
|
|
};
|
|
return Pile;
|
|
}());
|
|
var File_t = /** @class */ (function () {
|
|
function File_t() {
|
|
this.head = new Pile();
|
|
this.b_head = new Pile();
|
|
this.tail = new Pile();
|
|
this.c_tail = new Pile();
|
|
this.b_1 = new Pile();
|
|
this.b_2 = new Pile();
|
|
this.stepLevel = 0;
|
|
this.count = 0;
|
|
}
|
|
File_t.prototype.emptyAll = function () {
|
|
this.b_head.empty();
|
|
this.b_1.empty();
|
|
this.b_2.empty();
|
|
this.c_tail.empty();
|
|
while (this.tail.length > 0) {
|
|
this.b_1.push(this.tail.pop());
|
|
}
|
|
while (this.b_1.length > 0) {
|
|
var e = this.b_1.pop();
|
|
this.tail.push(e);
|
|
this.c_tail.push(e);
|
|
}
|
|
};
|
|
File_t.prototype.push = function (e) {
|
|
return __awaiter(this, void 0, void 0, function () {
|
|
return __generator(this, function (_a) {
|
|
switch (_a.label) {
|
|
case 0:
|
|
console.log("Current step:", this.stepLevel, "\n");
|
|
if (!(this.head.length === 0 && this.tail.length === 0)) return [3 /*break*/, 1];
|
|
this.tail.push(e);
|
|
this.c_tail.push(e);
|
|
return [3 /*break*/, 5];
|
|
case 1:
|
|
if (!(this.stepLevel > 0)) return [3 /*break*/, 3];
|
|
this.head.push(e);
|
|
GLOBAL_PROCESSING = true;
|
|
return [4 /*yield*/, this.step()];
|
|
case 2:
|
|
_a.sent();
|
|
return [3 /*break*/, 5];
|
|
case 3:
|
|
this.head.push(e);
|
|
if (!(this.head.length === this.tail.length)) return [3 /*break*/, 5];
|
|
console.log("Begin Transfert\n");
|
|
this.stepLevel = 1;
|
|
GLOBAL_PROCESSING = true;
|
|
return [4 /*yield*/, this.step()];
|
|
case 4:
|
|
_a.sent();
|
|
_a.label = 5;
|
|
case 5: return [2 /*return*/];
|
|
}
|
|
});
|
|
});
|
|
};
|
|
File_t.prototype.pop = function () {
|
|
return __awaiter(this, void 0, void 0, function () {
|
|
return __generator(this, function (_a) {
|
|
switch (_a.label) {
|
|
case 0:
|
|
if (!(this.stepLevel > 2)) return [3 /*break*/, 2];
|
|
this.count++;
|
|
this.tail.pop();
|
|
GLOBAL_PROCESSING = true;
|
|
return [4 /*yield*/, this.step()];
|
|
case 1:
|
|
_a.sent();
|
|
return [3 /*break*/, 4];
|
|
case 2:
|
|
this.c_tail.pop();
|
|
this.tail.pop();
|
|
if (!(this.stepLevel > 0)) return [3 /*break*/, 4];
|
|
GLOBAL_PROCESSING = true;
|
|
return [4 /*yield*/, this.step()];
|
|
case 3:
|
|
_a.sent();
|
|
_a.label = 4;
|
|
case 4:
|
|
if (!(this.head.length === this.tail.length)) return [3 /*break*/, 6];
|
|
console.log("Begin Transfert\n");
|
|
this.stepLevel = 1;
|
|
return [4 /*yield*/, this.step()];
|
|
case 5:
|
|
_a.sent();
|
|
_a.label = 6;
|
|
case 6: return [2 /*return*/];
|
|
}
|
|
});
|
|
});
|
|
};
|
|
File_t.prototype.step = function () {
|
|
return __awaiter(this, arguments, void 0, function (n) {
|
|
var e, e, e;
|
|
var _a, _b, _c, _d, _e, _f;
|
|
if (n === void 0) { n = 5; }
|
|
return __generator(this, function (_g) {
|
|
switch (_g.label) {
|
|
case 0:
|
|
if (n <= 0) { // finit le nombre d'étape pour le moment
|
|
GLOBAL_PROCESSING = false;
|
|
return [2 /*return*/];
|
|
}
|
|
if (!!LEARNING) return [3 /*break*/, 2];
|
|
return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, WAIT_TIME); })];
|
|
case 1:
|
|
_g.sent();
|
|
_g.label = 2;
|
|
case 2:
|
|
this.draw();
|
|
console.log("Transfer step:", this.stepLevel, "\n");
|
|
if (!(this.stepLevel === 1)) return [3 /*break*/, 5];
|
|
_a = [this.b_head, this.head], this.head = _a[0], this.b_head = _a[1];
|
|
this.stepLevel++;
|
|
if (!!LEARNING) return [3 /*break*/, 4];
|
|
return [4 /*yield*/, this.step(n)];
|
|
case 3:
|
|
_g.sent();
|
|
_g.label = 4;
|
|
case 4: return [3 /*break*/, 34];
|
|
case 5:
|
|
if (!(this.stepLevel === 2)) return [3 /*break*/, 13];
|
|
e = this.b_head.pop();
|
|
if (!(e === undefined)) return [3 /*break*/, 8];
|
|
this.stepLevel++;
|
|
if (!!LEARNING) return [3 /*break*/, 7];
|
|
return [4 /*yield*/, this.step(n)];
|
|
case 6:
|
|
_g.sent();
|
|
_g.label = 7;
|
|
case 7: return [3 /*break*/, 12];
|
|
case 8:
|
|
this.b_1.push(e);
|
|
this.b_2.push(e);
|
|
if (!!LEARNING) return [3 /*break*/, 10];
|
|
return [4 /*yield*/, this.step(n - 2)];
|
|
case 9:
|
|
_g.sent();
|
|
return [3 /*break*/, 12];
|
|
case 10: return [4 /*yield*/, this.step(n)];
|
|
case 11:
|
|
_g.sent();
|
|
_g.label = 12;
|
|
case 12: return [3 /*break*/, 34];
|
|
case 13:
|
|
if (!(this.stepLevel === 3)) return [3 /*break*/, 16];
|
|
_b = [this.b_2, this.b_head], this.b_head = _b[0], this.b_2 = _b[1];
|
|
this.stepLevel++;
|
|
if (!!LEARNING) return [3 /*break*/, 15];
|
|
return [4 /*yield*/, this.step(n)];
|
|
case 14:
|
|
_g.sent();
|
|
_g.label = 15;
|
|
case 15: return [3 /*break*/, 34];
|
|
case 16:
|
|
if (!(this.stepLevel === 4)) return [3 /*break*/, 24];
|
|
e = this.c_tail.pop();
|
|
if (!(e === undefined)) return [3 /*break*/, 19];
|
|
this.stepLevel++;
|
|
if (!!LEARNING) return [3 /*break*/, 18];
|
|
return [4 /*yield*/, this.step(n)];
|
|
case 17:
|
|
_g.sent();
|
|
_g.label = 18;
|
|
case 18: return [3 /*break*/, 23];
|
|
case 19:
|
|
this.b_2.push(e);
|
|
if (!!LEARNING) return [3 /*break*/, 21];
|
|
return [4 /*yield*/, this.step(n - 1)];
|
|
case 20:
|
|
_g.sent();
|
|
return [3 /*break*/, 23];
|
|
case 21: return [4 /*yield*/, this.step(n)];
|
|
case 22:
|
|
_g.sent();
|
|
_g.label = 23;
|
|
case 23: return [3 /*break*/, 34];
|
|
case 24:
|
|
if (!(this.stepLevel === 5)) return [3 /*break*/, 33];
|
|
if (this.b_2.length === this.count) { // ne pas compter les éléments déjà retirés
|
|
_c = [this.c_tail, this.b_1], this.b_1 = _c[0], this.c_tail = _c[1];
|
|
_d = [this.tail, this.b_head], this.b_head = _d[0], this.tail = _d[1];
|
|
this.stepLevel = 0;
|
|
this.emptyAll();
|
|
GLOBAL_PROCESSING = false;
|
|
this.count = 0;
|
|
return [2 /*return*/];
|
|
}
|
|
e = this.b_2.pop();
|
|
if (!(e === undefined)) return [3 /*break*/, 25];
|
|
this.stepLevel++;
|
|
if (!LEARNING) {
|
|
this.step(n);
|
|
}
|
|
return [3 /*break*/, 32];
|
|
case 25:
|
|
this.b_head.push(e);
|
|
this.b_1.push(e);
|
|
if (!(this.b_2.length === 0)) return [3 /*break*/, 28];
|
|
this.stepLevel++;
|
|
if (!!LEARNING) return [3 /*break*/, 27];
|
|
return [4 /*yield*/, this.step(n)];
|
|
case 26:
|
|
_g.sent();
|
|
_g.label = 27;
|
|
case 27: return [3 /*break*/, 32];
|
|
case 28:
|
|
if (!!LEARNING) return [3 /*break*/, 30];
|
|
return [4 /*yield*/, this.step(n - 2)];
|
|
case 29:
|
|
_g.sent();
|
|
return [3 /*break*/, 32];
|
|
case 30: return [4 /*yield*/, this.step(n)];
|
|
case 31:
|
|
_g.sent();
|
|
_g.label = 32;
|
|
case 32: return [3 /*break*/, 34];
|
|
case 33:
|
|
if (this.stepLevel === 6) { // dernier échange
|
|
_e = [this.c_tail, this.b_1], this.b_1 = _e[0], this.c_tail = _e[1];
|
|
_f = [this.tail, this.b_head], this.b_head = _f[0], this.tail = _f[1];
|
|
this.stepLevel = 0;
|
|
this.emptyAll();
|
|
GLOBAL_PROCESSING = false;
|
|
this.count = 0;
|
|
return [2 /*return*/];
|
|
}
|
|
_g.label = 34;
|
|
case 34: return [2 /*return*/];
|
|
}
|
|
});
|
|
});
|
|
};
|
|
File_t.prototype.draw = function () {
|
|
var ofs = 200;
|
|
var c = 525;
|
|
staticCtx.clearRect(0, 0, BG_RECT.w, BG_RECT.h);
|
|
// processing
|
|
if (PROCESSING) {
|
|
staticCtx.fillStyle = "#000000";
|
|
staticCtx.font = "40px garamond";
|
|
staticCtx.fillText("Échanges en cours", 390, 50);
|
|
}
|
|
// piles
|
|
this.head.draw(c - ofs, 300);
|
|
this.tail.draw(c + ofs, 300);
|
|
this.b_head.draw(c - ofs, 600);
|
|
this.c_tail.draw(c + ofs, 600);
|
|
this.b_1.draw(c - ofs, 900);
|
|
this.b_2.draw(c + ofs, 900);
|
|
// flèches entrée/sortie
|
|
var R = 80;
|
|
var ox = c - ofs - 150 / 2 - 5;
|
|
var oy = 100;
|
|
staticCtx.strokeStyle = "#000000";
|
|
staticCtx.beginPath();
|
|
staticCtx.moveTo(ox - R, oy);
|
|
staticCtx.quadraticCurveTo(ox, oy - R, ox + R, oy);
|
|
staticCtx.lineTo(ox + R, oy - 10);
|
|
staticCtx.moveTo(ox + R, oy);
|
|
staticCtx.lineTo(ox + R - 10, oy);
|
|
staticCtx.stroke();
|
|
ox = c + ofs + 150 / 2 + 5;
|
|
staticCtx.beginPath();
|
|
staticCtx.moveTo(ox - R, oy);
|
|
staticCtx.quadraticCurveTo(ox, oy - R, ox + R, oy);
|
|
staticCtx.lineTo(ox + R, oy - 10);
|
|
staticCtx.moveTo(ox + R, oy);
|
|
staticCtx.lineTo(ox + R - 10, oy);
|
|
staticCtx.stroke();
|
|
// explication touches
|
|
staticCtx.fillStyle = "#000000";
|
|
staticCtx.font = "40px garamond";
|
|
if (!LEARNING) {
|
|
if (!PROCESSING) {
|
|
staticCtx.fillText("'+' : empiler", c - ofs - 300, 150);
|
|
staticCtx.fillText("'-' : dépiler", c - ofs - 300, 242);
|
|
staticCtx.fillText("'a' : mode apprentissage (off)", c - ofs - 300, 335);
|
|
}
|
|
}
|
|
else {
|
|
if (!GLOBAL_PROCESSING) {
|
|
staticCtx.fillText("'+' : empiler", c - ofs - 300, 150);
|
|
staticCtx.fillText("'-' : dépiler", c - ofs - 300, 242);
|
|
staticCtx.fillText("'a' : mode apprentissage (on)", c - ofs - 300, 335);
|
|
}
|
|
else {
|
|
staticCtx.fillText("'Entrée' :", c - ofs - 300, 150);
|
|
staticCtx.fillText(" suivant", c - ofs - 300, 200);
|
|
staticCtx.fillText("'a' : mode apprentissage (on)", c - ofs - 300, 335);
|
|
}
|
|
}
|
|
// séparation
|
|
staticCtx.strokeStyle = "#ff0000";
|
|
staticCtx.beginPath();
|
|
staticCtx.moveTo(c - ofs - 200, 350);
|
|
staticCtx.lineTo(c + ofs + 200, 350);
|
|
staticCtx.stroke();
|
|
// flèches
|
|
console.log("step:", this.stepLevel, "\n");
|
|
staticCtx.strokeStyle = "#000000";
|
|
if (this.stepLevel === 2 || this.stepLevel === 3) {
|
|
this.drawArrow(c - ofs, 610, c - ofs, 700);
|
|
this.drawArrow(c - ofs, 610, c + ofs, 700);
|
|
}
|
|
else if (this.stepLevel == 5) {
|
|
this.drawArrow(c + ofs, 610, c + ofs, 700);
|
|
}
|
|
else if (this.stepLevel === 6) {
|
|
this.drawArrow(c + 100, 800, c - 100, 800);
|
|
this.drawArrow(c + 100, 800, c - ofs, 610);
|
|
}
|
|
ctx.clearRect(0, 0, BG_RECT.w, BG_RECT.h);
|
|
ctx.drawImage(staticCanvas, 0, 0);
|
|
};
|
|
File_t.prototype.drawArrow = function (x0, y0, x1, y1) {
|
|
staticCtx.beginPath();
|
|
staticCtx.moveTo(x0, y0);
|
|
staticCtx.lineTo(x1, y1);
|
|
var vx = x1 - x0;
|
|
var vy = y1 - y0;
|
|
var n = Math.sqrt(Math.pow(vx, 2) + Math.pow(vy, 2));
|
|
if (n !== 0) {
|
|
var s2 = Math.sqrt(2) / 2;
|
|
vx /= -n;
|
|
vy /= -n;
|
|
var vx1 = s2 * vx + s2 * vy;
|
|
var vy1 = -s2 * vx + s2 * vy;
|
|
staticCtx.lineTo(x1 + vx1 * 10, y1 + vy1 * 10);
|
|
staticCtx.moveTo(x1, y1);
|
|
var vx2 = s2 * vx - s2 * vy;
|
|
var vy2 = s2 * vx + s2 * vy;
|
|
staticCtx.lineTo(x1 + vx2 * 10, y1 + vy2 * 10);
|
|
}
|
|
staticCtx.stroke();
|
|
};
|
|
return File_t;
|
|
}());
|
|
//animation de la file
|
|
var FILE = new File_t();
|
|
function drawFrame() {
|
|
FILE.draw();
|
|
}
|
|
function animationLoop(currentTime) {
|
|
animationFrameId = requestAnimationFrame(animationLoop);
|
|
var delaTime = currentTime - lastFrameTime;
|
|
if (delaTime < FRAME_INTERVAL)
|
|
return;
|
|
lastFrameTime = currentTime - (delaTime % FRAME_INTERVAL);
|
|
drawFrame();
|
|
}
|
|
function initEventListener() {
|
|
var _this = this;
|
|
var handlers = {
|
|
handleKeyDown: function (e) { return __awaiter(_this, void 0, void 0, function () {
|
|
return __generator(this, function (_a) {
|
|
switch (_a.label) {
|
|
case 0:
|
|
if (!(e.key === '+')) return [3 /*break*/, 3];
|
|
if (!(!PROCESSING && !GLOBAL_PROCESSING)) return [3 /*break*/, 2];
|
|
PROCESSING = true;
|
|
return [4 /*yield*/, FILE.push({
|
|
value: Math.floor(Math.random() * 10) + 1,
|
|
color: getRandomColor()
|
|
})];
|
|
case 1:
|
|
_a.sent();
|
|
PROCESSING = false;
|
|
_a.label = 2;
|
|
case 2: return [3 /*break*/, 10];
|
|
case 3:
|
|
if (!(e.key === "-")) return [3 /*break*/, 6];
|
|
if (!(!PROCESSING && !GLOBAL_PROCESSING)) return [3 /*break*/, 5];
|
|
PROCESSING = true;
|
|
return [4 /*yield*/, FILE.pop()];
|
|
case 4:
|
|
_a.sent();
|
|
PROCESSING = false;
|
|
_a.label = 5;
|
|
case 5: return [3 /*break*/, 10];
|
|
case 6:
|
|
if (!(e.key === "Enter")) return [3 /*break*/, 9];
|
|
if (!(LEARNING && !PROCESSING)) return [3 /*break*/, 8];
|
|
PROCESSING = true;
|
|
return [4 /*yield*/, FILE.step()];
|
|
case 7:
|
|
_a.sent();
|
|
PROCESSING = false;
|
|
_a.label = 8;
|
|
case 8: return [3 /*break*/, 10];
|
|
case 9:
|
|
if (e.key === "a") {
|
|
LEARNING = !LEARNING;
|
|
FILE.emptyAll();
|
|
FILE.stepLevel = 0;
|
|
FILE.count = 0;
|
|
PROCESSING = false;
|
|
GLOBAL_PROCESSING = false;
|
|
}
|
|
_a.label = 10;
|
|
case 10: return [2 /*return*/];
|
|
}
|
|
});
|
|
}); }
|
|
};
|
|
document.addEventListener('keydown', handlers.handleKeyDown);
|
|
callbacks.push(function () {
|
|
document.removeEventListener('keydown', handlers.handleKeyDown);
|
|
});
|
|
}
|
|
function getRandomColor() {
|
|
return '#' + Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0');
|
|
}
|
|
function initDisplay() {
|
|
initEventListener();
|
|
requestAnimationFrame(animationLoop);
|
|
window.cleanup = cleanup;
|
|
}
|
|
function cleanup() {
|
|
cancelAnimationFrame(animationFrameId);
|
|
callbacks.forEach(function (fn) { return fn(); });
|
|
}
|
|
if (typeof window !== 'undefined') {
|
|
initDisplay();
|
|
}
|