+
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: []
+});