From 2701762f03fca6256ac8c38e500351f0155e76e0 Mon Sep 17 00:00:00 2001 From: Lennard Sprong Date: Mon, 14 Sep 2026 09:23:56 +0200 Subject: [PATCH 01/10] WIP --- src-ui/list.html | 1 + src/pzpr/variety.js | 1 + src/res/failcode.en.json | 2 + src/variety/balancelink.js | 166 +++++++++++++++++++++++++++++++++++++ 4 files changed, 170 insertions(+) create mode 100644 src/variety/balancelink.js diff --git a/src-ui/list.html b/src-ui/list.html index fcb985bc1..f90543212 100644 --- a/src-ui/list.html +++ b/src-ui/list.html @@ -244,6 +244,7 @@

パズルの種類のリスト
  • +
  • diff --git a/src/pzpr/variety.js b/src/pzpr/variety.js index c25e66dc6..93b40356a 100755 --- a/src/pzpr/variety.js +++ b/src/pzpr/variety.js @@ -101,6 +101,7 @@ arukone: [0, 0, "アルコネ", "Arukone", "numlin"], ayeheya: [0, 1, "∀人∃HEYA", "Ayeheya", "heyawake"], balance: [0, 0, "Balance Loop", "Balance Loop"], + balancelink: [0, 0, "Balance Link", "Balance Link"], balloon: [0, 0, "風船箱", "Balloon Box"], barns: [1, 0, "バーンズ", "Barns"], batten: [0, 0, "Battenberg Painting", "Battenberg Painting"], diff --git a/src/res/failcode.en.json b/src/res/failcode.en.json index ae11df39f..6a6c5f9ea 100644 --- a/src/res/failcode.en.json +++ b/src/res/failcode.en.json @@ -707,6 +707,7 @@ "lnNoTip.pencils": "A line is not connected to a pencil tip.", "lnNotRect.nagenawa": "There is a non-rectangle loop.", "lnNotSq.tajmahal": "A segment doesn't form a square.", + "lnNotSymm.balancelink": "A line is not symmetrical.", "lcNotUTurns.uturns": "A line does not turn twice in the same direction between circles.", "lcNotUTurns.vertigo": "A line turns in the wrong direction.", "lnOnCenter.midloop": "A circle is not the center point of a line.", @@ -791,6 +792,7 @@ "nmCircleNe.slovak": "The amount of circles is not equal to the amount of numbers in the surrounding cells.", "nmConnBarWrong": "The number of lines connected to a shaded cell is wrong.", "nmConnDiff.arukone": "Different alphabets are connected.", + "nmConnDiff.balancelink": "Different symbols are connected.", "nmConnDiff.kouchoku": "Different letters are connected directly.", "nmConnDiff.numlin": "Different numbers are connected.", "nmConnected.bonsan": "There are connected circles.", diff --git a/src/variety/balancelink.js b/src/variety/balancelink.js new file mode 100644 index 000000000..7d3d05930 --- /dev/null +++ b/src/variety/balancelink.js @@ -0,0 +1,166 @@ +(function(pidlist, classbase) { + if (typeof module === "object" && module.exports) { + module.exports = [pidlist, classbase]; + } else { + pzpr.classmgr.makeCustom(pidlist, classbase); + } +})(["balancelink"], { + //--------------------------------------------------------- + // マウス入力系 + MouseEvent: { + inputModes: { + edit: ["number", "clear", "empty", "info-line"], + play: ["line", "peke", "info-line"] + }, + autoedit_func: "qnum", + autoplay_func: "line" + }, + + //--------------------------------------------------------- + // キーボード入力系 + KeyEvent: { + enablemake: true + }, + + //--------------------------------------------------------- + // 盤面管理系 + Cell: { + maxnum: 8 + }, + Board: { + hasborder: 1 + }, + + LineGraph: { + enabled: true, + makeClist: true + }, + + //--------------------------------------------------------- + // 画像表示系 + Graphic: { + gridcolor_type: "LIGHT", + + numbercolor_func: "qnum", + + irowake: true, + + paint: function() { + this.drawBGCells(); + this.drawGrid(); + + this.drawPekes(); + this.drawLines(); + + this.drawQuesNumbers(); + + this.drawChassis(); + + this.drawTarget(); + }, + getBGCellColor: function(cell) { + return cell.ques === 7 ? "black" : this.getBGCellColor_error1(cell); + } + }, + + //--------------------------------------------------------- + // URLエンコード/デコード処理 + Encode: { + decodePzpr: function(type) { + // TODO decode obstacle + this.decodeNumber16(); + }, + encodePzpr: function(type) { + // TODO encode obstacle + this.encodeNumber16(); + } + }, + //--------------------------------------------------------- + FileIO: { + decodeData: function() { + // TODO decode obstacle + this.decodeCellQnum(); + this.decodeBorderLine(); + }, + encodeData: function() { + // TODO encode obstacle + this.encodeCellQnum(); + this.encodeBorderLine(); + } + }, + + //--------------------------------------------------------- + // 正解判定処理実行部 + AnsCheck: { + checklist: [ + "checkLineExist+", + "checkBranchLine", + "checkCrossLine", + "checkTripleObject", + "checkLinkSymmetry", + "checkLineOverLetter", + "checkLinkSameNumber", + "checkDeadendConnectLine+", + "checkDisconnectLine", + "checkNoLineObject+" + ], + + checkLinkSymmetry: function() { + var self = this; + this.checkLineShape(function(path) { + var cell1 = path.cells[0], + cell2 = path.cells[1]; + + if (!cell1.isNum() || cell1.qnum !== cell2.qnum) { + return false; + } + + var map = self.getSymmetryMap(path.dir1, path.dir2); + if (!map) { + return true; + } + + // TODO iterate over objs array, since it's in order + + return false; + }, "lnNotSymm"); + }, + + getSymmetryMap: function(dir1, dir2) { + switch (Math.max(dir1, dir2) + "," + Math.min(dir1, dir2)) { + case "1,1": // up, up + case "2,2": // dn, dn + return {}; // TODO + + case "3,3": // lt, lt + case "4,4": // rt, rt + return {}; // TODO + + case "1,2": // up, dn + case "3,4": // lt, rt + return {}; // TODO + + case "1,3": // up, lt + case "2,4": // dn, rt + return {}; // TODO + + case "1,4": // up, rt + case "2,3": // dn, lt + return {}; // TODO + + default: + return null; + } + }, + + checkLinkSameNumber: function() { + this.checkSameObjectInRoom( + this.board.linegraph, + function(cell) { + return cell.qnum; + }, + "nmConnDiff" + ); + } + } +}); From bd91e941b86c9fe5b35715a74c22432787a283f7 Mon Sep 17 00:00:00 2001 From: Lennard Sprong Date: Thu, 17 Sep 2026 09:13:02 +0200 Subject: [PATCH 02/10] WIP --- src/variety/balancelink.js | 47 ++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/src/variety/balancelink.js b/src/variety/balancelink.js index 7d3d05930..0ff6d0d68 100644 --- a/src/variety/balancelink.js +++ b/src/variety/balancelink.js @@ -97,6 +97,7 @@ "checkBranchLine", "checkCrossLine", "checkTripleObject", + // TODO over invalid cells "checkLinkSymmetry", "checkLineOverLetter", "checkLinkSameNumber", @@ -115,38 +116,66 @@ return false; } + if (path.objs <= 2) { + return false; + } + var map = self.getSymmetryMap(path.dir1, path.dir2); if (!map) { return true; } - // TODO iterate over objs array, since it's in order + var prev1 = cell1, + prev2 = cell2; + for (var i = 0; i <= path.objs.length / 2; i++) { + var j = path.objs.length - (i + 1); + + var link1 = path.objs[i], + link2 = path.objs[j]; + + var next1 = + link1.sidecell[0] === prev1 + ? link1.sidecell[1] + : link1.sidecell[0], + next2 = + link2.sidecell[0] === prev2 + ? link2.sidecell[1] + : link2.sidecell[0]; + + var dir1 = prev1.getdir(next1, 2), + dir2 = prev2.getdir(next2, 2); + + if (map[dir1] !== dir2) { + return true; + } + + prev1 = next1; + prev2 = next2; + } return false; }, "lnNotSymm"); }, getSymmetryMap: function(dir1, dir2) { - switch (Math.max(dir1, dir2) + "," + Math.min(dir1, dir2)) { + switch (Math.min(dir1, dir2) + "," + Math.max(dir1, dir2)) { case "1,1": // up, up case "2,2": // dn, dn - return {}; // TODO + case "3,4": // lt, rt + return { 1: 1, 2: 2, 3: 4, 4: 3 }; case "3,3": // lt, lt case "4,4": // rt, rt - return {}; // TODO - case "1,2": // up, dn - case "3,4": // lt, rt - return {}; // TODO + return { 1: 2, 2: 1, 3: 3, 4: 4 }; case "1,3": // up, lt case "2,4": // dn, rt - return {}; // TODO + return { 1: 3, 2: 4, 3: 3, 4: 2 }; case "1,4": // up, rt case "2,3": // dn, lt - return {}; // TODO + return { 1: 4, 2: 3, 3: 2, 4: 1 }; default: return null; From bda8e29d0946dcf28d4e3e4ce9ddbe2b4dc282db Mon Sep 17 00:00:00 2001 From: Lennard Sprong Date: Thu, 17 Sep 2026 17:29:22 +0200 Subject: [PATCH 03/10] encoding and inputs --- src/variety/balancelink.js | 85 ++++++++++++++++++++++++++++++++------ 1 file changed, 73 insertions(+), 12 deletions(-) diff --git a/src/variety/balancelink.js b/src/variety/balancelink.js index 0ff6d0d68..e82abb7f6 100644 --- a/src/variety/balancelink.js +++ b/src/variety/balancelink.js @@ -19,13 +19,39 @@ //--------------------------------------------------------- // キーボード入力系 KeyEvent: { - enablemake: true + enablemake: true, + keyinput: function(ca) { + if (ca === "q") { + var cell = this.cursor.getc(); + cell.setQues(cell.ques !== 7 ? 7 : 0); + this.prev = cell; + cell.draw(); + } else { + this.key_inputqnum(ca); + } + }, + getNewNumber: function(cell, ca, cur) { + if (ca === "BS" || ca === " ") { + return -1; + } else if (ca === "-") { + return -2; + } else if (ca >= "1" && ca <= "6") { + return cur === +ca ? cur + 6 : +ca; + } + return null; + } }, //--------------------------------------------------------- // 盤面管理系 Cell: { - maxnum: 8 + maxnum: 12, + noLP: function() { + return this.isEmpty(); + } + }, + Border: { + enableLineNG: true }, Board: { hasborder: 1 @@ -66,26 +92,55 @@ //--------------------------------------------------------- // URLエンコード/デコード処理 Encode: { - decodePzpr: function(type) { - // TODO decode obstacle - this.decodeNumber16(); + decodePzpr: function() { + var bd = this.board; + this.genericDecodeNumber16(bd.cell.length, function(c, val) { + var cell = bd.cell[c]; + if (val === 0) { + cell.ques = 7; + } else { + cell.qnum = val; + } + }); }, - encodePzpr: function(type) { - // TODO encode obstacle - this.encodeNumber16(); + encodePzpr: function() { + var bd = this.board; + this.genericEncodeNumber16(bd.cell.length, function(c) { + var cell = bd.cell[c]; + return cell.ques === 7 ? 0 : cell.qnum; + }); } }, //--------------------------------------------------------- FileIO: { decodeData: function() { - // TODO decode obstacle this.decodeCellQnum(); this.decodeBorderLine(); }, encodeData: function() { - // TODO encode obstacle this.encodeCellQnum(); this.encodeBorderLine(); + }, + + decodeCellQnum: function() { + this.decodeCell(function(cell, ca) { + if (ca === "#") { + cell.ques = 7; + } else if (ca !== ".") { + cell.qnum = +ca; + } + }); + }, + encodeCellQnum: function() { + this.encodeCell(function(cell) { + if (cell.ques === 7) { + return "# "; + } else if (cell.qnum !== -1) { + return cell.qnum + " "; + } else { + return ". "; + } + }); } }, @@ -97,7 +152,7 @@ "checkBranchLine", "checkCrossLine", "checkTripleObject", - // TODO over invalid cells + "checkLineOnShaded", "checkLinkSymmetry", "checkLineOverLetter", "checkLinkSameNumber", @@ -106,6 +161,12 @@ "checkNoLineObject+" ], + checkLineOnShaded: function() { + this.checkAllCell(function(cell) { + return cell.noLP() && cell.lcnt > 0; + }, "lnOnShade"); + }, + checkLinkSymmetry: function() { var self = this; this.checkLineShape(function(path) { @@ -186,7 +247,7 @@ this.checkSameObjectInRoom( this.board.linegraph, function(cell) { - return cell.qnum; + return Math.max(cell.qnum, -1); }, "nmConnDiff" ); From 504774cb3910da770d55a7c375b97ce8f9e29f46 Mon Sep 17 00:00:00 2001 From: Lennard Sprong Date: Fri, 18 Sep 2026 12:57:57 +0200 Subject: [PATCH 04/10] Example --- src/variety/balancelink.js | 4 ++-- test/script/balancelink.js | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 test/script/balancelink.js diff --git a/src/variety/balancelink.js b/src/variety/balancelink.js index e82abb7f6..9e5dcf7b6 100644 --- a/src/variety/balancelink.js +++ b/src/variety/balancelink.js @@ -232,14 +232,14 @@ case "1,3": // up, lt case "2,4": // dn, rt - return { 1: 3, 2: 4, 3: 3, 4: 2 }; + return { 1: 3, 2: 4, 3: 1, 4: 2 }; case "1,4": // up, rt case "2,3": // dn, lt return { 1: 4, 2: 3, 3: 2, 4: 1 }; default: - return null; + throw Error("Unknown symmetry for " + dir1 + "," + dir2); } }, diff --git a/test/script/balancelink.js b/test/script/balancelink.js new file mode 100644 index 000000000..c73396684 --- /dev/null +++ b/test/script/balancelink.js @@ -0,0 +1,12 @@ +/* balancelink.js */ + +ui.debug.addDebugData("balancelink", { + url: "5/5/0k1g2m201g2i2", + failcheck: [ + [ + null, + "pzprv3/balancelink/5/5/# . . . . /. 1 . 2 . /. . . . . /. 2 # 1 . /2 . . . 2 /0 1 1 1 /0 0 1 0 /0 1 0 0 /0 0 0 1 /1 1 1 1 /0 1 0 0 1 /0 0 1 0 1 /0 1 0 0 1 /0 0 0 0 0 /" + ] + ], + inputs: [] +}); From 7f1eb05f024e4446c9de49a629698ceb1cb24a91 Mon Sep 17 00:00:00 2001 From: Lennard Sprong Date: Fri, 18 Sep 2026 13:09:54 +0200 Subject: [PATCH 05/10] Graphics --- src/variety-common/Graphic.js | 5 +- src/variety/balancelink.js | 93 ++++++++++++++++++++++++++++++++++- 2 files changed, 95 insertions(+), 3 deletions(-) diff --git a/src/variety-common/Graphic.js b/src/variety-common/Graphic.js index 7335796df..2eac745e3 100644 --- a/src/variety-common/Graphic.js +++ b/src/variety-common/Graphic.js @@ -2300,7 +2300,7 @@ pzpr.classmgr.makeCommon({ } }, - fillStar: function(g, px, py, sizeX, sizeY) { + pathStar: function(g, px, py, sizeX, sizeY) { // 星を描画するときの頂点の位置 var starXOffset = [ 0, @@ -2333,6 +2333,9 @@ pzpr.classmgr.makeCommon({ g.lineTo(px + sizeX * starXOffset[p], py + sizeY * starYOffset[p]); } g.closePath(); + }, + fillStar: function(g, px, py, sizeX, sizeY) { + this.pathStar(g, px, py, sizeX, sizeY); g.fill(); }, diff --git a/src/variety/balancelink.js b/src/variety/balancelink.js index 9e5dcf7b6..d174cda48 100644 --- a/src/variety/balancelink.js +++ b/src/variety/balancelink.js @@ -76,14 +76,103 @@ this.drawGrid(); this.drawPekes(); + this.drawQuesMarks(); this.drawLines(); - this.drawQuesNumbers(); - this.drawChassis(); this.drawTarget(); }, + + drawQuesMarks: function() { + var g = this.vinc("cell_mark", "auto"); + + g.lineWidth = Math.max(this.cw / 18, 2); + var rsize = this.cw * 0.4; + + var triy = 0.867 * rsize, + trix = rsize; + var clist = this.range.cells; + for (var i = 0; i < clist.length; i++) { + var cell = clist[i]; + + g.vid = "c_mk_" + cell.id; + g.strokeStyle = this.getQuesNumberColor(cell); + g.fillStyle = g.strokeStyle; + var px = cell.bx * this.bw, + py = cell.by * this.bh; + var value = cell.qnum > 6 ? cell.qnum - 6 : cell.qnum; + switch (value) { + case 1: + g.strokeCircle(px, py, rsize); + if (cell.qnum > 6) { + g.fillCircle(px, py, rsize); + } + continue; + case 2: + g.beginPath(); + g.setOffsetLinePath( + px, + py, + 0, + -rsize, + rsize, + 0, + 0, + rsize, + -rsize, + 0, + true + ); + break; + case 3: + g.beginPath(); + g.setOffsetLinePath( + px, + py, + 0, + -triy, + -trix, + triy, + trix, + triy, + true + ); + break; + case 4: + if (cell.qnum > 6) { + g.fillRectCenter(px, py, triy, triy); + } else { + g.strokeRectCenter(px, py, triy, triy); + } + continue; + case 5: + this.pathStar(g, px, py, rsize, rsize); + break; + case 6: + g.beginPath(); + g.setOffsetLinePath( + px, + py, + 0, + triy, + -trix, + -triy, + trix, + -triy, + true + ); + break; + default: + g.vhide(); + continue; + } + g.stroke(); + if (cell.qnum > 6) { + g.fill(); + } + } + }, getBGCellColor: function(cell) { return cell.ques === 7 ? "black" : this.getBGCellColor_error1(cell); } From 96cc7889446e666a55805aa955b0629ee1aca8da Mon Sep 17 00:00:00 2001 From: Lennard Sprong Date: Fri, 18 Sep 2026 15:17:37 +0200 Subject: [PATCH 06/10] failchecks --- src/res/failcode.en.json | 4 +++ src/variety/balancelink.js | 15 ++++++++--- test/script/balancelink.js | 53 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 67 insertions(+), 5 deletions(-) diff --git a/src/res/failcode.en.json b/src/res/failcode.en.json index 6a6c5f9ea..ceb075243 100644 --- a/src/res/failcode.en.json +++ b/src/res/failcode.en.json @@ -624,6 +624,7 @@ "lcInvDirW.firefly": "Fireflies are connected without a line starting from point.", "lcInvWhite.wblink": "Two white circles are connected.", "lcIsolate.arukone": "A line doesn't connect any alphabet.", + "lcIsolate.balancelink": "A line doesn't connect to any symbol.", "lcIsolate.balloon": "A string doesn't connect to any number.", "lcIsolate.kusabi": "A line isn't connected to any circle.", "lcIsolate.uturns": "A line doesn't connect two gray circles.", @@ -632,12 +633,14 @@ "lcLenInvNe.kusabi": "The legs of a U have different lengths.", "lcNotKusabi.kusabi": "A line is not U-shaped.", "lcOnNum.anglers": "A line goes through a symbol.", + "lcOnNum.balancelink": "A line goes through a symbol.", "lcOnNum.arukone": "A line goes through an alphabet.", "lcOnNum.kusabi": "A line goes through a circle.", "lcOnNum.uturns": "A line goes through a gray circle.", "lcOnNum": "A line goes through a number.", "lcSameNum.ichimaga": "Same numbers are connected each other.", "lcTripleNum.arukone": "Three or more alphabets are connected.", + "lcTripleNum.balancelink": "Three or more symbols are connected.", "lcTripleNum.kusabi": "Three or more objects are connected.", "lcTripleNum.wblink": "Three or more objects are connected.", "lcTripleNum": "Three or more numbers are connected.", @@ -860,6 +863,7 @@ "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.", + "nmNoLine.balancelink": "A symbol doesn't have a line.", "nmNoLine.coffeemilk": "A white or black circle doesn't have a line.", "nmNoLine.elasticlink": "A number or circle doesn't have a line.", "nmNoLine.firefly": "There is a lonely firefly.", diff --git a/src/variety/balancelink.js b/src/variety/balancelink.js index d174cda48..94c9116c8 100644 --- a/src/variety/balancelink.js +++ b/src/variety/balancelink.js @@ -251,9 +251,18 @@ ], checkLineOnShaded: function() { - this.checkAllCell(function(cell) { - return cell.noLP() && cell.lcnt > 0; - }, "lnOnShade"); + for (var c = 0; c < this.board.cell.length; c++) { + var cell = this.board.cell[c]; + if (cell.ques !== 7 || cell.lcnt === 0) { + continue; + } + + this.failcode.add("lnOnShade"); + if (this.checkOnly) { + break; + } + cell.seterr(1); + } }, checkLinkSymmetry: function() { diff --git a/test/script/balancelink.js b/test/script/balancelink.js index c73396684..53a8e47d6 100644 --- a/test/script/balancelink.js +++ b/test/script/balancelink.js @@ -1,11 +1,60 @@ /* balancelink.js */ ui.debug.addDebugData("balancelink", { - url: "5/5/0k1g2m201g2i2", + url: "5/5/0k1gbmb01gbib", failcheck: [ + [ + "brNoLine", + "pzprv3/balancelink/5/5/# . . . . /. 1 . 11 . /. . . . . /. 11 # 1 . /11 . . . 11 /0 0 0 0 /0 0 0 0 /0 0 0 0 /0 0 0 0 /0 0 0 0 /0 0 0 0 0 /0 0 0 0 0 /0 0 0 0 0 /0 0 0 0 0 /" + ], + [ + "lnBranch", + "pzprv3/balancelink/5/5/# . . . . /. 1 . 11 . /. . . . . /. 11 # 1 . /11 . . . 11 /0 0 0 0 /0 0 0 0 /1 1 1 1 /0 0 0 0 /0 0 0 0 /0 0 0 0 0 /0 0 0 1 0 /1 0 0 0 1 /1 0 0 0 1 /" + ], + [ + "lnCross", + "pzprv3/balancelink/5/5/# . . . . /. 1 . 11 . /. . . . . /. 11 # 1 . /11 . . . 11 /0 0 0 0 /0 0 0 0 /1 1 1 0 /0 0 0 0 /0 0 0 0 /0 0 0 0 0 /0 1 0 0 0 /1 1 0 1 0 /1 0 0 0 0 /" + ], + [ + "lcTripleNum", + "pzprv3/balancelink/5/5/# . . . . /. 1 . 11 . /. . . . . /. 11 # 1 . /11 . . . 11 /0 0 0 0 /0 0 0 1 /0 0 0 0 /0 0 0 0 /1 1 1 1 /0 0 0 0 0 /0 0 0 0 1 /0 0 0 0 1 /0 0 0 0 1 /" + ], + [ + "lnOnShade", + "pzprv3/balancelink/5/5/# . . . . /. 1 . 11 . /. . . . . /. 11 # 1 . /11 . . . 11 /0 0 0 0 /0 1 0 0 /0 0 0 0 /0 0 1 0 /0 0 0 0 /0 0 0 0 0 /0 0 1 0 0 /0 0 1 0 0 /0 0 0 0 0 /", + { skiprules: true } + ], + [ + "lnNotSymm", + "pzprv3/balancelink/5/5/# . . . . /. 1 . 11 . /. . . . . /. 11 # 1 . /11 . . . 11 /0 0 0 0 /0 0 0 1 /0 0 0 0 /0 0 0 0 /0 0 0 0 /0 0 0 0 0 /0 0 0 0 1 /0 0 0 0 1 /0 0 0 0 1 /" + ], + [ + "lnNotSymm", + "pzprv3/balancelink/5/5/# . . . . /. 1 . 11 . /. . . . . /. 11 # 1 . /11 . . . 11 /0 0 0 0 /0 0 0 0 /0 1 1 0 /0 0 0 0 /0 0 0 0 /0 0 0 0 0 /0 1 0 0 0 /0 0 0 1 0 /0 0 0 0 0 /" + ], + [ + "lcOnNum", + "pzprv3/balancelink/5/5/# . . . . /. 1 . 11 . /. . . . . /. 11 # 1 . /11 . . . 11 /0 0 0 0 /0 0 1 1 /0 1 0 0 /0 0 0 0 /0 0 0 0 /0 0 0 0 0 /0 0 1 0 0 /0 1 0 0 0 /0 1 0 0 0 /" + ], + [ + "nmConnDiff", + "pzprv3/balancelink/5/5/# . . . . /. 1 . 11 . /. . . . . /. 11 # 1 . /11 . . . 11 /0 0 0 0 /1 0 0 0 /0 0 0 0 /1 0 0 0 /0 0 0 0 /0 0 0 0 0 /1 0 0 0 0 /1 0 0 0 0 /0 0 0 0 0 /" + ], + [ + "lnDeadEnd", + "pzprv3/balancelink/5/5/# . . . . /. 1 . 11 . /. . . . . /. 11 # 1 . /11 . . . 11 /0 0 0 0 /1 0 1 0 /0 1 0 1 /0 0 0 0 /1 1 1 1 /0 0 0 0 0 /1 0 1 0 0 /0 1 0 1 0 /0 0 0 0 0 /" + ], + [ + "lcIsolate", + "pzprv3/balancelink/5/5/# . . . . /. 1 . . . /. . . . . /. . # 1 . /11 . . . 11 /0 1 1 1 /0 0 1 0 /0 0 1 0 /0 0 0 1 /1 1 1 1 /0 1 0 0 1 /0 0 1 1 1 /0 0 0 0 1 /0 0 0 0 0 /" + ], + [ + "nmNoLine", + "pzprv3/balancelink/5/5/# . . . . /. 1 . 11 . /. . . . . /. 11 # 1 . /11 . . . 11 /0 0 0 0 /0 1 0 0 /0 0 1 0 /0 0 0 0 /1 1 1 1 /0 0 0 0 0 /0 0 1 0 0 /0 0 0 1 0 /0 0 0 0 0 /" + ], [ null, - "pzprv3/balancelink/5/5/# . . . . /. 1 . 2 . /. . . . . /. 2 # 1 . /2 . . . 2 /0 1 1 1 /0 0 1 0 /0 1 0 0 /0 0 0 1 /1 1 1 1 /0 1 0 0 1 /0 0 1 0 1 /0 1 0 0 1 /0 0 0 0 0 /" + "pzprv3/balancelink/5/5/# . . . . /. 1 . 11 . /. . . . . /. 11 # 1 . /11 . . . 11 /0 1 1 1 /0 0 1 0 /0 1 0 0 /0 0 0 1 /1 1 1 1 /0 1 0 0 1 /0 0 1 0 1 /0 1 0 0 1 /0 0 0 0 0 /" ] ], inputs: [] From 3d89889c4347ff2f839987cdeaeb3b469a87bff9 Mon Sep 17 00:00:00 2001 From: Lennard Sprong Date: Fri, 18 Sep 2026 16:45:16 +0200 Subject: [PATCH 07/10] Keypopup --- src-ui/js/ui/KeyPopup.js | 20 +++++++++++++++++++- src/variety/balancelink.js | 6 ++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src-ui/js/ui/KeyPopup.js b/src-ui/js/ui/KeyPopup.js index bcf4f5cd0..eff2f8f82 100644 --- a/src-ui/js/ui/KeyPopup.js +++ b/src-ui/js/ui/KeyPopup.js @@ -268,7 +268,8 @@ ui.keypopup = { slovak: [136, 10], gravel: [120, 0], seiza: [4, 0], - heyajirimisaki: [10, 0] + heyajirimisaki: [10, 0], + balancelink: [139, 0] }, //--------------------------------------------------------------------------- @@ -445,6 +446,8 @@ ui.keypopup = { this.generate_mrokmrno(mode); } else if (type === 138) { this.generate_jatahoku(); + } else if (type === 139) { + this.generate_balancelink(); } else if (type === 5339) { this.generate_swslither(); } @@ -855,6 +858,21 @@ ui.keypopup = { 4 ); }, + generate_balancelink: function() { + this.generate_main( + [ + ["1", { text: "●" }], + ["2", { text: "◆" }], + ["3", { text: "▲" }], + ["4", { text: "■" }], + ["5", { text: "★" }], + ["6", { text: "▼" }], + ["-", { text: "?" }], + " " + ], + 3 + ); + }, generate_bdwalk: function() { this.generate_main( [ diff --git a/src/variety/balancelink.js b/src/variety/balancelink.js index 94c9116c8..45f4213e8 100644 --- a/src/variety/balancelink.js +++ b/src/variety/balancelink.js @@ -104,9 +104,10 @@ var value = cell.qnum > 6 ? cell.qnum - 6 : cell.qnum; switch (value) { case 1: - g.strokeCircle(px, py, rsize); if (cell.qnum > 6) { g.fillCircle(px, py, rsize); + } else { + g.strokeCircle(px, py, rsize); } continue; case 2: @@ -167,9 +168,10 @@ g.vhide(); continue; } - g.stroke(); if (cell.qnum > 6) { g.fill(); + } else { + g.stroke(); } } }, From 7e35c9f7ee3b5810efa236134d4475c71df47832 Mon Sep 17 00:00:00 2001 From: Lennard Sprong Date: Fri, 18 Sep 2026 23:04:52 +0200 Subject: [PATCH 08/10] Rest --- src-ui/changes.html | 2 +- src-ui/img/balancelink.png | Bin 0 -> 117 bytes src-ui/js/ui/Misc.js | 1 + src/pzpr/variety.js | 2 +- 4 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 src-ui/img/balancelink.png diff --git a/src-ui/changes.html b/src-ui/changes.html index 55b4c7620..b0c564794 100644 --- a/src-ui/changes.html +++ b/src-ui/changes.html @@ -33,13 +33,13 @@
    Latest types (all types)
    diff --git a/src-ui/img/balancelink.png b/src-ui/img/balancelink.png new file mode 100644 index 0000000000000000000000000000000000000000..172d452ac8779bfd7429412b8868f8044f338218 GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~wg8_H*L(Nw zty;Hfk7PhGP(;?##W6%;YH~t~1M?D210y3Nq4iS14T5(Y7_ad&2uxs5d~n@#8BigE Mr>mdKI;Vst0N@uM7XSbN literal 0 HcmV?d00001 diff --git a/src-ui/js/ui/Misc.js b/src-ui/js/ui/Misc.js index 58db7f5dd..cc379217c 100755 --- a/src-ui/js/ui/Misc.js +++ b/src-ui/js/ui/Misc.js @@ -113,6 +113,7 @@ function toBGimage(pid) { "araf", "archipelago", "balance", + "balancelink", "balloon", "batten", "battleship", diff --git a/src/pzpr/variety.js b/src/pzpr/variety.js index 93b40356a..a8bdf2dc3 100755 --- a/src/pzpr/variety.js +++ b/src/pzpr/variety.js @@ -101,7 +101,7 @@ arukone: [0, 0, "アルコネ", "Arukone", "numlin"], ayeheya: [0, 1, "∀人∃HEYA", "Ayeheya", "heyawake"], balance: [0, 0, "Balance Loop", "Balance Loop"], - balancelink: [0, 0, "Balance Link", "Balance Link"], + balancelink: [0, 0, "バランスリンク", "Balance Link"], balloon: [0, 0, "風船箱", "Balloon Box"], barns: [1, 0, "バーンズ", "Barns"], batten: [0, 0, "Battenberg Painting", "Battenberg Painting"], From ad9192c780a31247bd8aef7027f13d9e946e1d3d Mon Sep 17 00:00:00 2001 From: Lennard Sprong Date: Sat, 19 Sep 2026 10:52:50 +0200 Subject: [PATCH 09/10] Smaller squares --- src/variety/balancelink.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/variety/balancelink.js b/src/variety/balancelink.js index 45f4213e8..9c5947d80 100644 --- a/src/variety/balancelink.js +++ b/src/variety/balancelink.js @@ -88,10 +88,11 @@ var g = this.vinc("cell_mark", "auto"); g.lineWidth = Math.max(this.cw / 18, 2); - var rsize = this.cw * 0.4; + var rsize = this.cw * 0.35; var triy = 0.867 * rsize, - trix = rsize; + trix = rsize, + sqsize = rsize * 0.75; var clist = this.range.cells; for (var i = 0; i < clist.length; i++) { var cell = clist[i]; @@ -142,9 +143,9 @@ break; case 4: if (cell.qnum > 6) { - g.fillRectCenter(px, py, triy, triy); + g.fillRectCenter(px, py, sqsize, sqsize); } else { - g.strokeRectCenter(px, py, triy, triy); + g.strokeRectCenter(px, py, sqsize, sqsize); } continue; case 5: From 0bdea6a446f07cffdb2f4407656f8dee2ddb1123 Mon Sep 17 00:00:00 2001 From: Lennard Sprong Date: Sat, 19 Sep 2026 12:00:44 +0200 Subject: [PATCH 10/10] Restyle stars --- src/variety-common/Graphic.js | 38 +++++++++-------------------------- src/variety/balancelink.js | 2 +- 2 files changed, 10 insertions(+), 30 deletions(-) diff --git a/src/variety-common/Graphic.js b/src/variety-common/Graphic.js index 2eac745e3..b6583505a 100644 --- a/src/variety-common/Graphic.js +++ b/src/variety-common/Graphic.js @@ -2300,42 +2300,22 @@ pzpr.classmgr.makeCommon({ } }, - pathStar: function(g, px, py, sizeX, sizeY) { - // 星を描画するときの頂点の位置 - var starXOffset = [ - 0, - 0.235, - 0.95, - 0.38, - 0.588, - 0, - -0.588, - -0.38, - -0.95, - -0.235 - ]; - var starYOffset = [ - -1, - -0.309, - -0.309, - 0.124, - 0.809, - 0.4, - 0.809, - 0.124, - -0.309, - -0.309 - ]; + pathStar: function(g, px, py, sizeX, sizeY, factor) { + if (!factor) { + factor = 0.38; + } g.beginPath(); g.moveTo(px, py - sizeY); for (var p = 1; p < 10; p++) { - g.lineTo(px + sizeX * starXOffset[p], py + sizeY * starYOffset[p]); + var starY = Math.cos(p * Math.PI * 0.2) * (p & 1 ? factor : 1), + starX = Math.sin(p * Math.PI * 0.2) * (p & 1 ? factor : 1); + g.lineTo(px + sizeX * starX, py + sizeY * -starY); } g.closePath(); }, - fillStar: function(g, px, py, sizeX, sizeY) { - this.pathStar(g, px, py, sizeX, sizeY); + fillStar: function(g, px, py, sizeX, sizeY, factor) { + this.pathStar(g, px, py, sizeX, sizeY, factor); g.fill(); }, diff --git a/src/variety/balancelink.js b/src/variety/balancelink.js index 9c5947d80..eb5a20821 100644 --- a/src/variety/balancelink.js +++ b/src/variety/balancelink.js @@ -149,7 +149,7 @@ } continue; case 5: - this.pathStar(g, px, py, rsize, rsize); + this.pathStar(g, px, py, rsize, rsize, 0.6); break; case 6: g.beginPath();