From f4f80831d335d6164d929a2b6b89e1b9f9cf204c Mon Sep 17 00:00:00 2001 From: minorin EEL Date: Fri, 18 Apr 2025 00:03:58 +0900 Subject: [PATCH] Add 'EndSum' --- src-ui/js/ui/KeyPopup.js | 1 + src-ui/js/ui/UI.js | 1 + src-ui/list.html | 1 + src-ui/res/rules.en.yaml | 1 + src-ui/res/rules.ja.yaml | 1 + src/pzpr/variety.js | 1 + src/res/failcode.en.json | 2 + src/res/failcode.ja.json | 2 + src/variety/endsum.js | 574 +++++++++++++++++++++++++++++++++++++++ test/script/endsum.js | 89 ++++++ 10 files changed, 673 insertions(+) create mode 100644 src/variety/endsum.js create mode 100644 test/script/endsum.js diff --git a/src-ui/js/ui/KeyPopup.js b/src-ui/js/ui/KeyPopup.js index ac7beff5d..c28979d5c 100644 --- a/src-ui/js/ui/KeyPopup.js +++ b/src-ui/js/ui/KeyPopup.js @@ -104,6 +104,7 @@ ui.keypopup = { aqre: [10, 0], doppelblock: [10, 115], japanesesums: [10, 115], + endsum: [10, 10], interbd: [116, 0], toichika2: [10, 10], crossstitch: [10, 0], diff --git a/src-ui/js/ui/UI.js b/src-ui/js/ui/UI.js index 3c1375c5c..6f28aa9fb 100644 --- a/src-ui/js/ui/UI.js +++ b/src-ui/js/ui/UI.js @@ -176,6 +176,7 @@ window.ui = { case "skyscrapers": case "easyasabc": case "japanesesums": + case "endsum": case "box": padding = 0.05; break; diff --git a/src-ui/list.html b/src-ui/list.html index 6919f4130..4ecbdf148 100644 --- a/src-ui/list.html +++ b/src-ui/list.html @@ -322,6 +322,7 @@

パズルの種類のリスト
  • +
  • diff --git a/src-ui/res/rules.en.yaml b/src-ui/res/rules.en.yaml index f6d9e4f2f..428c4141b 100644 --- a/src-ui/res/rules.en.yaml +++ b/src-ui/res/rules.en.yaml @@ -337,3 +337,4 @@ dotchi2: "Draw lines through orthogonally adjacent cells to form a loop.\n1. The arrowflow: "Place an arrow in every empty cell.\n1. Identical arrows cannot be adjacent.\n2. Following the arrows must lead to one of the numbers.\n3. Each number indicates how many arrows lead to that goal." japanesesums: "Place some numbers from the given range into the grid, and shade the rest of the cells.\n1. Numbers cannot repeat in a row or column.\n2. Clues outside the grid indicate the sums of the numbers in groups of consecutive numbered cells in the corresponding row or column, in order from left to right or top to bottom. Sums must be separated by at least one shaded cell.\n3. A question mark represents an unknown sum.\n4. Rows or columns without clues can have any amount of sums." retsurin: "Shade some cells on the board, and draw a single loop that goes through all remaining cells.\n1. The loop cannot branch off or cross itself.\n2. Shaded cells cannot be orthogonally adjacent.\n3. Cells with numbers or question marks cannot be shaded, and are not part of the loop.\n4. A number indicates the amount of shaded cells in the same row as the clue or in the same column, but it must not indicate both." +endsum: "1. Fill some of the empty cells with numbers from the given set so that each number appears exactly once in every row and column.\n2. Clues outside the grid indicate the sum of numbers in the first connected (not separated by an empty cell) group in that direction." diff --git a/src-ui/res/rules.ja.yaml b/src-ui/res/rules.ja.yaml index 3d02f8513..28267d570 100644 --- a/src-ui/res/rules.ja.yaml +++ b/src-ui/res/rules.ja.yaml @@ -283,3 +283,4 @@ yajirushi: "1. すべての白マスに「←→↑↓」のいずれかの矢 dotchi2: "1. 盤面のいくつかのマスに線を引き、1つの輪っかを作りましょう。\n2. 線はマスの中央を通るようにタテヨコに引きます。線を交差させたり枝分かれさせてはいけません。\n3. それぞれの部屋において、線は黒丸か白丸のいずれか一方の丸をすべて通り、もう一方の丸はどれも通らないようにします。一種類の丸しかない部屋では線はすべての丸を通ります。\n4. 線は黒丸を通るときそのマスで曲がり、白丸を通るときそのマスで直進するようにします。" arrowflow: "1. 同じ向きの矢印が隣接しないように全ての空きマスに上下左右いずれかの矢印を配置する。\n2. 矢印をその方向にたどると必ずどこかの数字マスに行きつくようにする。\n3. 数字は、そのマスにたどり着く矢印の個数を表す。" japanesesums: "1. いくつかのマスに、指定された数のどれかを書き込みます。数が入らないマスは黒マスになります。\n2. 1つのマスに2つ以上の数は入りません。タテヨコの各列で同じ数が2回以上現れることはありません。\n3. 盤面の外の数は、その列で黒マスをはさまずに連続して入る数の和を上/左から順に表します。?は、1以上の数を表します。" +endsum: "1. いくつかの空いているマスに数字を1つずつ書き込み、タテヨコ全ての列で指定された数字が1つずつ現れるようにします。\n2. 盤面の外の数字は、その場所から盤面内を見た時に、一番手前にある数字のカタマリ(間に空きマスを挟まない、連続して数字の入るマス)の合計を表します。" diff --git a/src/pzpr/variety.js b/src/pzpr/variety.js index ee198cd35..eec6a32f1 100755 --- a/src/pzpr/variety.js +++ b/src/pzpr/variety.js @@ -149,6 +149,7 @@ dotchi2: [0, 0, "ドッチドッチループ", "Dotchi Dotchi Loop", "country"], doubleback: [0, 0, "Double Back", "Double Back", "country"], easyasabc: [0, 0, "ABCプレース", "Easy as ABC"], + endsum: [0, 0, "エンドサム", "Easy as Japanese Sums"], evolmino: [0, 0, "シンカミノ", "Evolmino"], factors: [0, 0, "因子の部屋", "Rooms of Factors"], fakearrow: [0, 0, "フェイクアロー", "Fake Arrow", "nagare"], diff --git a/src/res/failcode.en.json b/src/res/failcode.en.json index 218d06d35..43f15e389 100644 --- a/src/res/failcode.en.json +++ b/src/res/failcode.en.json @@ -739,6 +739,7 @@ "nmMissing.lohkous": "There is no segment of the given length in the room.", "nmMissRow.alter": "A row or column has less than two symbols.", "nmMissRow.easyasabc": "There are missing letters in a row or column.", + "nmMissRow.endsum": "There are missing numbers in a row or column.", "nmMixed.aquapelago": "A group contains different numbers.", "nmMoveNe.tren": "A block cannot move in the correct number of spaces.", "nmNoLine.amibo": "No bar connects to a white circle.", @@ -797,6 +798,7 @@ "nmSightNe.easyasabc": "The letter is not the closest.", "nmSightNe.roundtrip": "The length of the closest line segment is wrong.", "nmSightNe.skyscrapers": "The number of visible buildings is wrong.", + "nmSightSumNe.endsum": "The total of the foremost group of numbers is incorrect.", "nmSizeGt.pencils": "A number is larger than the length of the pencil.", "nmSizeLt.pencils": "A number is smaller than the length of the pencil.", "nmSizeNe.tontonbeya": "The clusters inside a room are of different sizes.", diff --git a/src/res/failcode.ja.json b/src/res/failcode.ja.json index e691c9582..d7c34ccea 100644 --- a/src/res/failcode.ja.json +++ b/src/res/failcode.ja.json @@ -527,6 +527,7 @@ "nmMinesNe.mines": "タテヨコナナメに接する爆弾の数が数字と異なります。", "nmMissing.lohkous": "領域内に数字と同じ長さのセグメントがありません。", "nmMissRow.easyasabc": "列に入っていないアルファベットがあります。", + "nmMissRow.endsum": "列に入っていない数字があります。", "nmMoveNe.tren": "数字がクルマの動けるマス数と異なります。", "nmNoLine.amibo": "白丸に線がつながっていません。", "nmNoLine.firefly": "ホタルから線が出ていません。", @@ -562,6 +563,7 @@ "nmShootShadeNe1.kurochute": "数字の数だけ離れたマスのうち、1マスだけ黒マスになっていません。", "nmSightNe.easyasabc": "アルファベットが最も手前にありません。", "nmSightNe.skyscrapers": "見えるビルの数が正しくありません。", + "nmSightSumNe.endsum": "最も手前にある数字のカタマリの合計が正しくありません。", "nmSizeGt.pencils": "中の数字よりも短い軸があります。", "nmSizeLt.pencils": "中の数字よりも長い軸があります。", "nmSmallGap.ripple": "数字よりもその間隔が短いところがあります。", diff --git a/src/variety/endsum.js b/src/variety/endsum.js new file mode 100644 index 000000000..cf6f3e934 --- /dev/null +++ b/src/variety/endsum.js @@ -0,0 +1,574 @@ +// +// パズル固有スクリプト部 エンドサム版 endsum.js +// +(function(pidlist, classbase) { + if (typeof module === "object" && module.exports) { + module.exports = [pidlist, classbase]; + } else { + pzpr.classmgr.makeCustom(pidlist, classbase); + } +})(["endsum"], { + //--------------------------------------------------------- + // マウス入力系 + MouseEvent: { + inputModes: { + edit: ["number"], + play: ["number", "numexist", "numblank", "clear"] + }, + + mouseinput_number: function() { + if (this.mousestart) { + if (!this.puzzle.editmode || !this.inputqnum_excell()) { + this.inputqnum(); + } + } + }, + mouseinput_auto: function() { + if (this.puzzle.playmode) { + if (this.mousestart) { + var piece = this.getcell_excell(); + if (!piece.isnull && piece.group === "cell") { + this.inputqnum(); + } + } + } else if (this.puzzle.editmode) { + this.mouseinput_number(); + } + }, + + inputqnum_excell: function() { + var excell = this.getpos(0).getex(); + if (excell.isnull) { + return; + } + + if (excell !== this.cursor.getex()) { + this.setcursor(this.getpos(0)); + } else { + if (excell.group === "excell") { + this.inputqnum_main(excell); + } else { + var indicator = this.board.indicator; + var val = this.getNewNumber(indicator, indicator.count); + if (val === null) { + return; + } else if (val <= 0) { + val = + this.btn === "left" + ? indicator.getminnum() + : indicator.getmaxnum(); + } + indicator.set(val); + } + } + } + }, + + //--------------------------------------------------------- + // キーボード入力系 + KeyEvent: { + enablemake: true, + enableplay: true, + keyinput: function(ca) { + if (this.puzzle.playmode) { + var isSnum = this.cursor.targetdir !== 0; + if (isSnum) { + } else if (ca === "q") { + ca = "s1"; + } else if (ca === "w") { + ca = "s2"; + } else if (ca === "e") { + ca = "BS"; + } + this.key_inputqnum(ca); + if (!isSnum && ca === " ") { + this.cursor.getc().clrSnum(); + } + } else { + if (this.cursor.by <= this.board.maxby) { + var excell = this.cursor.getex(); + if (!excell.isnull) { + this.key_inputqnum_main(excell, ca); + } else { + this.key_inputqnum(ca); + } + } else { + this.key_inputqnum_indicator(ca); + } + } + }, + key_inputqnum_indicator: function(ca) { + var bd = this.puzzle.board; + var val = this.getNewNumber(bd.indicator, ca, bd.indicator.count); + if (val === null) { + return; + } + bd.indicator.set(val); + this.prev = bd.indicator; + } + }, + + TargetCursor: { + initCursor: function() { + this.init(-1, -1); + this.adjust_init(); + }, + setminmax_customize: function() { + if (this.puzzle.editmode) { + // インジケーター分、カーソルの可動範囲を下に伸ばす + this.maxy += 2; + return; + } + + // 解答モードはグリッド内のみ選択できれば良い + this.minx = 1; + this.miny = 1; + } + }, + + //--------------------------------------------------------- + // 盤面管理系 + Cell: { + disInputHatena: true, + enableSubNumberArray: true, + numberWithMB: true, + + maxnum: function() { + return this.board.indicator.count; + } + }, + + //--------------------------------------------------------- + // 盤面外管理系 + ExCell: { + disInputHatena: true, + + maxnum: function() { + var bx = this.bx, + by = this.by; + if (bx < 0 && by < 0) { + return 0; + } + + // 1~nまでの数字からm(m<=n)個の数字を足した場合の最大値 + // 同じ数字は選べないものとする + var n = this.board.indicator.count; + var m = 0; + if (by < 0 || by > this.board.rows * 2) { + m = Math.min(this.board.rows, n); + } else { + m = Math.min(this.board.cols, n); + } + return (n * (n + 1) - (n - m) * (n - m + 1)) / 2; + } + }, + + Board: { + cols: 5, + rows: 5, + hasexcell: 2, + + indicator: null, + + createExtraObject: function() { + this.indicator = new this.klass.Indicator(); + }, + initExtraObject: function(col, row) { + this.indicator.init(); + this.count = this.constructor.prototype.count; + }, + getex: function(bx, by) { + if (by <= this.maxby) { + return this.common.getex.call(this, bx, by); + } + return this.indicator; + }, + + searchSight: function(startexcell, seterror) { + var pos = startexcell.getaddr(), + dir = 0; + if (pos.by === this.minby + 1) { + dir = 2; + } else if (pos.by === this.maxby - 1) { + dir = 1; + } else if (pos.bx === this.minbx + 1) { + dir = 4; + } else if (pos.bx === this.maxbx - 1) { + dir = 3; + } + + var cells = []; + while (dir !== 0) { + pos.movedir(dir, 2); + var cell = pos.getc(); + if (cell.isnull) { + break; + } + + if (!cell.isNumberObj()) { + if (cells.length === 0) { + continue; + } else { + break; + } + } + cells.push(cell); + } + + if (!!seterror) { + startexcell.error = 1; + for (var i = 0; i < cells.length; i++) { + cells[i].error = 1; + } + } + + return { dest: cells }; + } + }, + + //--------------------------------------------------------- + // 使用可能数字管理系 + Indicator: { + count: 4, + rect: null, + qnum: -1, + + initialize: function(val) { + if (!!val) { + this.count = val; + } + this.rect = { bx1: -1, by1: -1, bx2: -1, by2: -1 }; + }, + init: function() { + this.count = this.constructor.prototype.count; + var bd = this.puzzle.board; + // インジケーターを囲む位の大きさ + this.rect = { + bx1: bd.maxbx - 3.5, + by1: bd.maxby + 0.2, + bx2: bd.maxbx + 0.1, + by2: bd.maxby + 1.9 + }; + }, + set: function(val) { + if (val <= 0) { + val = 1; + } + if (this.count !== val) { + this.addOpe(this.count, val); + this.count = val; + this.draw(); + } + }, + getmaxnum: function() { + return 9; + }, + getminnum: function() { + return 1; + }, + addOpe: function(old, num) { + this.puzzle.opemgr.add(new this.klass.IndicatorOperation(old, num)); + }, + draw: function() { + this.puzzle.painter.paintRange( + this.puzzle.board.maxbx - 3.5, + this.puzzle.board.maxby + 0.2, + this.puzzle.board.maxbx + 0.1, + this.puzzle.board.maxby + 1.9 + ); + } + }, + "IndicatorOperation:Operation": { + type: "indicator", + setData: function(old, num) { + this.old = old; + this.num = num; + }, + decode: function(strs) { + if (strs[0] !== "AS") { + return false; + } + this.old = +strs[1]; + this.num = +strs[2]; + return true; + }, + toString: function() { + return ["AS", this.old, this.num].join(","); + }, + undo: function() { + this.exec(this.old); + }, + redo: function() { + this.exec(this.num); + }, + exec: function(num) { + this.board.indicator.set(num); + } + }, + OperationManager: { + addExtraOperation: function() { + this.operationlist.push(this.klass.IndicatorOperation); + } + }, + + Graphic: { + gridcolor_type: "LIGHT", + + paint: function() { + this.drawBGCells(); + this.drawBGExCells(); + this.drawTargetSubNumber(); + + this.drawGrid(); + this.drawBorders(); + + this.drawMBs(); + this.drawSubNumbers(); + this.drawAnsNumbers(); + this.drawQuesNumbers(); + this.drawNumbersExCell(); + + this.drawChassis(); + + this.drawIndicator(); + this.drawCursor_endsum(); + }, + + /* 下に入力可能数字の表示領域を追加 */ + drawIndicator: function() { + var g = this.vinc("indicator", "auto", true), + bd = this.board; + + if (g.use.canvas) { + g.context.clearRect( + 0, + bd.maxby * this.bh + 5, + g.child.width, + bd.maxby * this.bh + 10 + ); + } + + g.fillStyle = this.quescolor; + + g.vid = "bd_indicator"; + g.font = ((this.ch * 0.66) | 0) + "px " + this.fontfamily; + g.textAlign = "right"; + g.textBaseline = "middle"; + g.fillText( + "[1-" + bd.indicator.count + "]", + bd.maxbx * this.bw, + (bd.rows * 2 + 3) * this.bh + ); + }, + drawCursor_endsum: function() { + var isOnBoard = this.puzzle.board.maxby >= this.puzzle.cursor.by; + var isOnIndicator = !isOnBoard; + this.drawCursor(true, isOnBoard); + this.drawCursorOnIndicator(isOnIndicator); + }, + drawCursorOnIndicator: function(isdraw) { + var g = this.vinc("target_cursor_indicator", "crispEdges", true), + bd = this.board; + + var isdraw = + isdraw && + this.puzzle.editmode && + this.puzzle.getConfig("cursor") && + !this.outputImage; + g.vid = "ti"; + if (isdraw) { + var rect = bd.indicator.rect; + g.strokeStyle = this.targetColorEdit; + g.lineWidth = Math.max(this.cw / 16, 2) | 0; + g.strokeRect( + rect.bx1 * this.bw, + rect.by1 * this.bh, + (rect.bx2 - rect.bx1) * this.bw, + (rect.by2 - rect.by1) * this.bh + ); + } else { + g.vhide(); + } + }, + + getBoardRows: function() { + return this.board.maxby / 2 + 2; + } + }, + + //--------------------------------------------------------- + // URLエンコード/デコード処理 + Encode: { + decodePzpr: function(type) { + this.decodeIndicator(); + this.decodeNumber16ExCell(); + this.decodeNumber16(); + }, + encodePzpr: function(type) { + this.encodeIndicator(); + this.encodeNumber16ExCell(); + if ( + this.board.cell.some(function(b) { + return b.qnum !== -1; + }) + ) { + this.encodeNumber16(); + } + }, + + decodeIndicator: function() { + var barray = this.outbstr.split("/"), + bd = this.board; + bd.indicator.count = +barray[0]; + this.outbstr = !!barray[1] ? barray[1] : ""; + }, + encodeIndicator: function() { + this.outbstr = this.board.indicator.count + "/"; + } + }, + + FileIO: { + decodeData: function() { + this.decodeIndicator(); + this.decodeCellExCellQnumAnumsub(); + }, + encodeData: function() { + this.encodeIndicator(); + this.encodeCellExCellQnumAnumsub(); + }, + + decodeIndicator: function() { + this.board.indicator.count = +this.readLine(); + }, + encodeIndicator: function() { + this.writeLine(this.board.indicator.count); + }, + + decodeCellExCellQnumAnumsub: function() { + this.decodeCellExCell(function(obj, ca) { + if (ca === ".") { + return; + } else if (obj.group === "excell") { + obj.qnum = +ca; + } else if (obj.group === "cell") { + if (ca[0] === "q") { + obj.qnum = +ca.substr(1); + return; + } + if (ca.indexOf("[") >= 0) { + ca = this.setCellSnum(obj, ca); + } + if (ca === "+") { + obj.qsub = 1; + } else if (ca === "-") { + obj.qsub = 2; + } else if (ca !== ".") { + obj.anum = +ca; + } + } + }); + }, + encodeCellExCellQnumAnumsub: function() { + this.encodeCellExCell(function(obj) { + if (obj.group === "excell") { + if (obj.qnum !== -1) { + return "" + obj.qnum + " "; + } + } else if (obj.group === "cell") { + if (obj.qnum !== -1) { + return "q" + obj.qnum + " "; + } + var ca = "."; + if (obj.anum !== -1) { + ca = "" + obj.anum; + } else if (obj.qsub === 1) { + ca = "+"; + } else if (obj.qsub === 2) { + ca = "-"; + } + if (obj.anum === -1) { + ca += this.getCellSnum(obj); + } + return ca + " "; + } + return ". "; + }); + } + }, + + AnsCheck: { + checklist: [ + "checkDifferentNumberInLine", + "checkSightSum+", + "checkNumberSaturatedInLine" + ], + + checkSightSum: function() { + var bd = this.board, + result = true; + for (var ec = 0; ec < bd.excell.length; ec++) { + var excell = bd.excell[ec]; + if (excell.qnum === -1) { + continue; + } + + var cells = bd.searchSight(excell, false).dest; + var sum = 0; + for (var i = 0; i < cells.length; i++) { + if (cells[i].isnull) { + continue; + } + sum += cells[i].getNum(); + } + if (excell.qnum === sum) { + continue; + } + + result = false; + if (this.checkOnly) { + break; + } + + excell.seterr(1); + bd.searchSight(excell, true); + } + if (!result) { + this.failcode.add("nmSightSumNe"); + } + }, + + checkNumberSaturatedInLine: function() { + this.checkRowsCols(this.isNumberSaturatedInClist, "nmMissRow"); + }, + + isNumberSaturatedInClist: function(clist) { + if (clist.length <= 0) { + return true; + } + var result = true, + d = []; + var max = this.board.indicator.count, + bottom = 1; + for (var n = bottom; n <= max; n++) { + d[n] = 0; + } + for (var i = 0; i < clist.length; i++) { + var num = clist[i].getNum(); + if (num >= bottom) { + d[num]++; + } + } + for (var n = bottom; n <= max; n++) { + if (d[n] === 0) { + result = false; + break; + } + } + + if (!result) { + clist.seterr(1); + } + return result; + } + } +}); diff --git a/test/script/endsum.js b/test/script/endsum.js new file mode 100644 index 000000000..ad406510d --- /dev/null +++ b/test/script/endsum.js @@ -0,0 +1,89 @@ +ui.debug.addDebugData("endsum", { + url: "5/5/3/g1k1g6g3g6i2g4", + failcheck: [ + [ + "nmDupRow", + "pzprv3/endsum/5/5/3/. . 1 . . . . /. . . . . . . /3 . . . . . . /. . . 1 . . 2 /6 . . . . . . /. . . 1 . . 4 /. . . 1 . 6 . /" + ], + [ + "nmSightSumNe", + "pzprv3/endsum/5/5/3/. . 1 . . . . /. 2 1 3 . . . /3 3 . 2 1 . . /. 1 3 . . 2 2 /6 . . 1 2 3 . /. . 2 . 3 1 4 /. . . 1 . 5 . /" + ], + [ + "nmSightSumNe", + "pzprv3/endsum/5/5/3/. . 1 . . . . /. 2 1 3 . . . /3 3 . 2 1 . . /. 1 3 . . 2 2 /7 . . 1 2 3 . /. . 2 . 3 1 4 /. . . 1 . 6 . /" + ], + [ + "nmMissRow", + "pzprv3/endsum/5/5/3/. . 1 . . . . /. 2 1 3 . . . /3 3 . 2 1 . . /. 1 3 . . 2 2 /6 . . 1 2 3 . /. . . . 3 1 4 /. . . 1 . 6 . /" + ], + [ + null, + "pzprv3/endsum/5/5/3/. . 1 . . . . /. 2 1 3 . . . /3 3 . 2 1 . . /. 1 3 . . 2 2 /6 . . 1 2 3 . /. . 2 . 3 1 4 /. . . 1 . 6 . /" + ] + ], + inputs: [ + { + input: [ + "newboard,4,4", + "editmode", + "cursor,3,-1", + "key,2", + "cursor,3,3", + "mouse,left,3,3" + ], + result: + "pzprv3/endsum/4/4/4/. . 2 . . . /. . . . . . /. . q1 . . . /. . . . . . /. . . . . . /. . . . . . /" + }, + { + input: ["playmode", "cursor,1,3", "key,1,right,2,right,2"], + result: + "pzprv3/endsum/4/4/4/. . 2 . . . /. . . . . . /. 1 q1 2 . . /. . . . . . /. . . . . . /. . . . . . /" + }, + { + input: [ + "playmode,numexist", + "mouse,left,1,3,7,3", + "playmode,numblank", + "mouse,left,7,7" + ], + result: + "pzprv3/endsum/4/4/4/. . 2 . . . /. . . . . . /. + q1 + + . /. . . . . . /. . . . - . /. . . . . . /" + }, + { + input: [ + "playmode,auto", + "cursor,1,3", + "mouse,left,1,3", + "cursor,5,3", + "mouse,leftx2,5,3", + "cursor,3,1", + "mouse,right,3,1", + "cursor,3,5", + "mouse,rightx3,3,5" + ], + result: + "pzprv3/endsum/4/4/4/. . 2 . . . /. . - . . . /. - q1 . + . /. . 4 . . . /. . . . - . /. . . . . . /" + }, + { + input: ["playmode,auto", "cursor,1,1", "key,5"], + result: + "pzprv3/endsum/4/4/4/. . 2 . . . /. . - . . . /. - q1 . + . /. . 4 . . . /. . . . - . /. . . . . . /" + }, + { + input: ["editmode", "cursor,9,11", "mouse,left,9,11"], + result: + "pzprv3/endsum/4/4/5/. . 2 . . . /. . - . . . /. - q1 . + . /. . 4 . . . /. . . . - . /. . . . . . /" + }, + { + input: ["playmode,auto", "cursor,1,1", "key,5"], + result: + "pzprv3/endsum/4/4/5/. . 2 . . . /. 5 - . . . /. - q1 . + . /. . 4 . . . /. . . . - . /. . . . . . /" + }, + { + input: ["editmode", "cursor,7,-1", "mouse,right,7,-1"], + result: + "pzprv3/endsum/4/4/5/. . 2 . 14 . /. 5 - . . . /. - q1 . + . /. . 4 . . . /. . . . - . /. . . . . . /" + } + ] +});