From fd2550493773698d7a4bf14de2a6f03e5e59e722 Mon Sep 17 00:00:00 2001 From: Lennard Sprong Date: Wed, 8 Apr 2026 15:16:08 +0200 Subject: [PATCH] Add Nurikabe Loop --- src-ui/js/ui/KeyPopup.js | 1 + src-ui/list.html | 1 + src/pzpr/variety.js | 1 + src/variety/nuriloop.js | 160 +++++++++++++++++++++++++++++++++++++++ test/script/nuriloop.js | 48 ++++++++++++ 5 files changed, 211 insertions(+) create mode 100644 src/variety/nuriloop.js create mode 100644 test/script/nuriloop.js diff --git a/src-ui/js/ui/KeyPopup.js b/src-ui/js/ui/KeyPopup.js index 44a3eab11..46a8d458b 100644 --- a/src-ui/js/ui/KeyPopup.js +++ b/src-ui/js/ui/KeyPopup.js @@ -251,6 +251,7 @@ ui.keypopup = { heavydots: [10, 0], suguru: [10, 10], marutaring: [10, 0], + nuriloop: [10, 0], tetroctb: [10, 0], hasunomura: [10, 0], bramble: [10, 0], diff --git a/src-ui/list.html b/src-ui/list.html index c07abe2fd..4af89749c 100644 --- a/src-ui/list.html +++ b/src-ui/list.html @@ -171,6 +171,7 @@

パズルの種類のリスト
  • +
  • diff --git a/src/pzpr/variety.js b/src/pzpr/variety.js index 9aa09e87f..799b6fbd2 100755 --- a/src/pzpr/variety.js +++ b/src/pzpr/variety.js @@ -329,6 +329,7 @@ numrope: [0, 0, "ナンバーロープ", "Number Rope", "kakuru"], nuribou: [1, 0, "ぬりぼう", "Nuribou", "nurikabe"], nurikabe: [0, 1, "ぬりかべ", "Nurikabe", "nurikabe"], + nuriloop: [0, 0, "面積リンク", "Nurikabe Loop"], nurimaze: [0, 0, "ぬりめいず", "Nuri-Maze", "nurimaze"], nurimisaki: [0, 0, "ぬりみさき", "Nurimisaki", "kurodoko"], nuritwin: [0, 0, "ぬりツイン", "Nuritwin", "shimaguni"], diff --git a/src/variety/nuriloop.js b/src/variety/nuriloop.js new file mode 100644 index 000000000..c56d3a57d --- /dev/null +++ b/src/variety/nuriloop.js @@ -0,0 +1,160 @@ +(function(pidlist, classbase) { + if (typeof module === "object" && module.exports) { + module.exports = [pidlist, classbase]; + } else { + pzpr.classmgr.makeCustom(pidlist, classbase); + } +})(["nuriloop"], { + MouseEvent: { + use: true, + inputModes: { + edit: ["number", "clear", "info-line"], + play: ["line", "peke", "subcircle", "subcross", "info-line"] + }, + autoedit_func: "qnum", + autoplay_func: "lineMB" + }, + + KeyEvent: { + enablemake: true + }, + + Board: { + hasborder: 1 + }, + Border: { + enableLineNG: true + }, + Cell: { + maxnum: function() { + return this.board.cols * this.board.rows; + }, + noLP: function() { + return this.isNum(); + }, + isUnshade: function() { + return this.lcnt === 0; + } + }, + LineGraph: { + enabled: true + }, + AreaUnshadeGraph: { + enabled: true, + relation: { "border.line": "block" }, + modifyOtherInfo: function(border, relation) { + this.setEdgeByNodeObj(border.sidecell[0]); + this.setEdgeByNodeObj(border.sidecell[1]); + } + }, + + Graphic: { + irowake: true, + gridcolor_type: "LIGHT", + numbercolor_func: "qnum", + qanscolor: "black", + + paint: function() { + this.drawBGCells(); + this.drawGrid(); + + this.drawQuesNumbers(); + + this.drawMBs(); + this.drawLines(); + this.drawPekes(); + + this.drawChassis(); + + this.drawTarget(); + } + }, + + Encode: { + decodePzpr: function(type) { + this.decodeNumber16(); + }, + encodePzpr: function(type) { + this.encodeNumber16(); + } + }, + FileIO: { + decodeData: function() { + this.decodeCellQnum(); + this.decodeCellQsub(); + this.decodeBorderLine(); + }, + encodeData: function() { + this.encodeCellQnum(); + this.encodeCellQsub(); + this.encodeBorderLine(); + } + }, + + AnsCheck: { + checklist: [ + "checkLineExist+", + "checkBranchLine", + "checkCrossLine", + "checkLineOverlap", + + "checkNoNumberInUnshade", + "checkDoubleNumberInUnshade", + "checkNumberAndUnshadeSize", + + "checkDeadendLine+", + "checkOneLoop" + ], + + checkLineOverlap: function() { + this.checkAllCell(function(cell) { + return cell.lcnt > 0 && cell.qnum !== -1; + }, "lnOverlap"); + }, + + checkDoubleNumberInUnshade: function() { + this.checkAllBlock( + this.board.ublkmgr, + function(cell) { + return cell.isNum(); + }, + function(w, h, a, n) { + return a < 2; + }, + "bkNumGe2" + ); + }, + checkNumberAndUnshadeSize: function() { + this.checkAllCell(function(cell) { + if (!cell.isValidNum()) { + return false; + } + if (!cell.ublk) { + return true; + } + + if (cell.ublk.clist.length !== cell.getNum()) { + cell.ublk.clist.seterr(1); + return true; + } + return false; + }, "bkSizeNe"); + }, + + checkNoNumberInUnshade: function() { + this.checkAllBlock( + this.board.ublkmgr, + function(cell) { + return cell.isNum(); + }, + function(w, h, a, n) { + return a !== 0; + }, + "bkNoNum" + ); + } + }, + FailCode: { + lnOverlap: "lnOverlap.tontti" + } +}); diff --git a/test/script/nuriloop.js b/test/script/nuriloop.js new file mode 100644 index 000000000..03c39fca2 --- /dev/null +++ b/test/script/nuriloop.js @@ -0,0 +1,48 @@ +/* nuriloop.js */ + +ui.debug.addDebugData("nuriloop", { + url: "5/5/4m2m1n", + failcheck: [ + [ + "brNoLine", + "pzprv3/nuriloop/5/5/4 . . . . /. . . 2 . /. . . . . /. 1 . . . /. . . . . /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 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/nuriloop/5/5/4 . . . . /. . . 2 . /. . . . . /. 1 . . . /. . . . . /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 1 1 0 /0 0 0 0 /0 0 0 0 /0 0 0 0 0 /0 0 1 0 0 /0 0 0 0 0 /0 0 0 0 0 /" + ], + [ + "lnCross", + "pzprv3/nuriloop/5/5/4 . . . . /. . . 2 . /. . . . . /. 1 . . . /. . . . . /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 1 1 /0 0 0 0 /0 0 0 0 0 /0 0 0 0 0 /0 0 0 1 0 /0 0 0 1 0 /" + ], + [ + "lnPlLoop", + "pzprv3/nuriloop/5/5/3 . . . . /. . . 1 . /. . . . . /. 1 . . . /. . . . . /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 1 1 /0 1 0 0 /1 0 1 1 /0 0 0 1 /1 1 0 1 /0 0 1 0 1 /0 1 0 0 1 /1 0 1 0 0 /1 0 1 1 1 /" + ], + [ + "lnOverlap", + "pzprv3/nuriloop/5/5/4 . . . . /. . . 2 . /. . . . . /. 1 . . . /. . . . . /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 1 1 /0 0 0 0 /1 1 0 0 /0 1 1 1 /1 0 0 0 /0 0 1 0 1 /0 0 1 0 1 /1 0 0 0 1 /1 1 0 0 0 /" + ], + [ + "bkNoNum", + "pzprv3/nuriloop/5/5/4 . . . . /. . . 2 . /. . . . . /. 1 . . . /. . . . . /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 1 1 /0 0 0 0 /1 1 0 0 /0 0 1 1 /1 1 0 0 /0 0 1 0 1 /0 0 1 0 1 /1 0 0 0 1 /1 0 1 0 0 /" + ], + [ + "bkNumGe2", + "pzprv3/nuriloop/5/5/4 . . . . /. . . 2 . /. . . . . /. 1 . . . /. . . . . /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 1 1 /0 0 0 0 /1 1 0 0 /0 0 0 0 /1 1 1 1 /0 0 1 0 1 /0 0 1 0 1 /1 0 0 0 1 /1 0 0 0 1 /" + ], + [ + "bkSizeNe", + "pzprv3/nuriloop/5/5/4 . . . . /. . . 2 . /. . . . . /. 1 . . . /. . . . . /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 1 1 1 /0 1 0 0 /1 1 0 0 /0 0 1 0 /1 1 0 1 /0 1 0 0 1 /0 0 1 0 1 /1 0 0 0 1 /1 0 1 1 1 /" + ], + [ + "lnDeadEnd", + "pzprv3/nuriloop/5/5/4 . . . . /. . . 2 . /. . . . . /. 1 . . . /. . . . . /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 1 1 /0 0 0 0 /1 1 0 0 /0 0 1 0 /1 0 1 1 /0 0 1 0 1 /0 0 1 0 1 /1 0 0 0 1 /1 0 1 0 1 /" + ], + [ + null, + "pzprv3/nuriloop/5/5/4 . . . . /. . . 2 . /. . . . . /. 1 . . . /. . . . . /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 1 1 /0 0 0 0 /1 1 0 0 /0 0 1 0 /1 1 0 1 /0 0 1 0 1 /0 0 1 0 1 /1 0 0 0 1 /1 0 1 1 1 /" + ] + ], + inputs: [] +});