UNPKG

tetris-fumen

Version:
231 lines (230 loc) 9.02 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.encode = void 0; var inner_field_1 = require("./inner_field"); var buffer_1 = require("./buffer"); var defines_1 = require("./defines"); var action_1 = require("./action"); var comments_1 = require("./comments"); var quiz_1 = require("./quiz"); var FieldConstants = { GarbageLine: 1, Width: 10, }; function encode(pages) { var updateField = function (prev, current) { var _a = encodeField(prev, current), changed = _a.changed, values = _a.values; if (changed) { // フィールドを記録して、リピートを終了する buffer.merge(values); lastRepeatIndex = -1; } else if (lastRepeatIndex < 0 || buffer.get(lastRepeatIndex) === buffer_1.Buffer.tableLength - 1) { // フィールドを記録して、リピートを開始する buffer.merge(values); buffer.push(0); lastRepeatIndex = buffer.length - 1; } else if (buffer.get(lastRepeatIndex) < (buffer_1.Buffer.tableLength - 1)) { // フィールドは記録せず、リピートを進める var currentRepeatValue = buffer.get(lastRepeatIndex); buffer.set(lastRepeatIndex, currentRepeatValue + 1); } }; var lastRepeatIndex = -1; var buffer = new buffer_1.Buffer(); var prevField = (0, inner_field_1.createNewInnerField)(); var actionEncoder = (0, action_1.createActionEncoder)(FieldConstants.Width, 23, FieldConstants.GarbageLine); var commentParser = (0, comments_1.createCommentParser)(); var prevComment = ''; var prevQuiz = undefined; var innerEncode = function (index) { var currentPage = pages[index]; currentPage.flags = currentPage.flags ? currentPage.flags : {}; var field = currentPage.field; var currentField = field !== undefined ? (0, inner_field_1.createInnerField)(field) : prevField.copy(); // フィールドの更新 updateField(prevField, currentField); // アクションの更新 var currentComment = currentPage.comment !== undefined ? ((index !== 0 || currentPage.comment !== '') ? currentPage.comment : undefined) : undefined; var piece = currentPage.operation !== undefined ? { type: (0, defines_1.parsePiece)(currentPage.operation.type), rotation: (0, defines_1.parseRotation)(currentPage.operation.rotation), x: currentPage.operation.x, y: currentPage.operation.y, } : { type: defines_1.Piece.Empty, rotation: defines_1.Rotation.Reverse, x: 0, y: 22, }; var nextComment; if (currentComment !== undefined) { if (currentComment.startsWith('#Q=')) { // Quiz on if (prevQuiz !== undefined && prevQuiz.format().toString() === currentComment) { nextComment = undefined; } else { nextComment = currentComment; prevComment = nextComment; prevQuiz = new quiz_1.Quiz(currentComment); } } else { // Quiz off if (prevQuiz !== undefined && prevQuiz.format().toString() === currentComment) { nextComment = undefined; prevComment = currentComment; prevQuiz = undefined; } else { nextComment = prevComment !== currentComment ? currentComment : undefined; prevComment = prevComment !== currentComment ? nextComment : prevComment; prevQuiz = undefined; } } } else { nextComment = undefined; prevQuiz = undefined; } if (prevQuiz !== undefined && prevQuiz.canOperate() && currentPage.flags.lock) { if ((0, defines_1.isMinoPiece)(piece.type)) { try { var nextQuiz = prevQuiz.nextIfEnd(); var operation = nextQuiz.getOperation(piece.type); prevQuiz = nextQuiz.operate(operation); } catch (e) { // console.error(e.message); // Not operate prevQuiz = prevQuiz.format(); } } else { prevQuiz = prevQuiz.format(); } } var currentFlags = __assign({ lock: true, colorize: index === 0 }, currentPage.flags); var action = { piece: piece, rise: !!currentFlags.rise, mirror: !!currentFlags.mirror, colorize: !!currentFlags.colorize, lock: !!currentFlags.lock, comment: nextComment !== undefined, }; var actionNumber = actionEncoder.encode(action); buffer.push(actionNumber, 3); // コメントの更新 if (nextComment !== undefined) { var comment = escape(currentPage.comment); var commentLength = Math.min(comment.length, 4095); buffer.push(commentLength, 2); // コメントを符号化 for (var index_1 = 0; index_1 < commentLength; index_1 += 4) { var value = 0; for (var count = 0; count < 4; count += 1) { var newIndex = index_1 + count; if (commentLength <= newIndex) { break; } var ch = comment.charAt(newIndex); value += commentParser.encode(ch, count); } buffer.push(value, 5); } } else if (currentPage.comment === undefined) { prevComment = undefined; } // 地形の更新 if (action.lock) { if ((0, defines_1.isMinoPiece)(action.piece.type)) { currentField.fill(action.piece); } currentField.clearLine(); if (action.rise) { currentField.riseGarbage(); } if (action.mirror) { currentField.mirror(); } } prevField = currentField; }; for (var index = 0; index < pages.length; index += 1) { innerEncode(index); } // テト譜が短いときはそのまま出力する // 47文字ごとに?が挿入されるが、実際は先頭にv115@が入るため、最初の?は42文字後になる var data = buffer.toString(); if (data.length < 41) { return data; } // ?を挿入する var head = [data.substr(0, 42)]; var tails = data.substring(42); var split = tails.match(/[\S]{1,47}/g) || []; return head.concat(split).join('?'); } exports.encode = encode; // フィールドをエンコードする // 前のフィールドがないときは空のフィールドを指定する // 入力フィールドの高さは23, 幅は10 function encodeField(prev, current) { var FIELD_TOP = 23; var FIELD_MAX_HEIGHT = FIELD_TOP + 1; var FIELD_BLOCKS = FIELD_MAX_HEIGHT * FieldConstants.Width; var buffer = new buffer_1.Buffer(); // 前のフィールドとの差を計算: 0〜16 var getDiff = function (xIndex, yIndex) { var y = FIELD_TOP - yIndex - 1; return current.getNumberAt(xIndex, y) - prev.getNumberAt(xIndex, y) + 8; }; // データの記録 var recordBlockCounts = function (diff, counter) { var value = diff * FIELD_BLOCKS + counter; buffer.push(value, 2); }; // フィールド値から連続したブロック数に変換 var changed = true; var prev_diff = getDiff(0, 0); var counter = -1; for (var yIndex = 0; yIndex < FIELD_MAX_HEIGHT; yIndex += 1) { for (var xIndex = 0; xIndex < FieldConstants.Width; xIndex += 1) { var diff = getDiff(xIndex, yIndex); if (diff !== prev_diff) { recordBlockCounts(prev_diff, counter); counter = 0; prev_diff = diff; } else { counter += 1; } } } // 最後の連続ブロックを処理 recordBlockCounts(prev_diff, counter); if (prev_diff === 8 && counter === FIELD_BLOCKS - 1) { changed = false; } return { changed: changed, values: buffer, }; }