From 28baf600b9a2cd24fe4dafa8a4d1547ea9316673 Mon Sep 17 00:00:00 2001 From: Lennard Sprong Date: Mon, 1 Dec 2025 09:06:51 +0100 Subject: [PATCH 1/2] Add Oasis --- src-ui/js/ui/KeyPopup.js | 3 +- src-ui/list.html | 1 + src/pzpr/variety.js | 1 + src/res/failcode.en.json | 2 + src/variety/oasis.js | 339 +++++++++++++++++++++++++++++++++++++++ test/script/oasis.js | 68 ++++++++ 6 files changed, 413 insertions(+), 1 deletion(-) create mode 100644 src/variety/oasis.js create mode 100644 test/script/oasis.js diff --git a/src-ui/js/ui/KeyPopup.js b/src-ui/js/ui/KeyPopup.js index 08c832a39..df5c13244 100644 --- a/src-ui/js/ui/KeyPopup.js +++ b/src-ui/js/ui/KeyPopup.js @@ -240,7 +240,8 @@ ui.keypopup = { diamond: [4, 0], morningwalk: [10, 0], energywalk: [10, 0], - keywest: [4, 4] + keywest: [4, 4], + oasis: [10, 0] }, //--------------------------------------------------------------------------- diff --git a/src-ui/list.html b/src-ui/list.html index acf42fbe4..3ea5bf49b 100644 --- a/src-ui/list.html +++ b/src-ui/list.html @@ -122,6 +122,7 @@

パズルの種類のリスト
  • +
  • diff --git a/src/pzpr/variety.js b/src/pzpr/variety.js index 51093f627..e4ad3d818 100755 --- a/src/pzpr/variety.js +++ b/src/pzpr/variety.js @@ -324,6 +324,7 @@ nurimisaki: [0, 0, "ぬりみさき", "Nurimisaki", "kurodoko"], nuritwin: [0, 0, "ぬりツイン", "Nuritwin", "shimaguni"], nuriuzu: [0, 0, "ぬりうず", "Nuri-uzu", "tentaisho"], + oasis: [0, 0, "Oasis", "Oasis"], ovotovata: [0, 0, "Ovotovata", "Ovotovata", "country"], oneroom: [0, 0, "ワンルームワンドア", "One Room One Door", "heyawake"], onsen: [0, 0, "温泉めぐり", "Onsen-meguri", "country"], diff --git a/src/res/failcode.en.json b/src/res/failcode.en.json index 9d22c0a96..4fcd1ff91 100644 --- a/src/res/failcode.en.json +++ b/src/res/failcode.en.json @@ -808,6 +808,8 @@ "nmNumberNe.sukoro": "The number of numbers placed in four adjacent cells is not equal to the number.", "nmNumberNe.sukororoom": "The number of numbers placed in four adjacent cells is not equal to the number.", "nmNumberNe.view": "The number of numbers placed in four adjacent cells is not equal to the number.", + "nmOasisGt": "A number is larger than the amount of circles that can be reached.", + "nmOasisLt": "A number is smaller than the amount of circles that can be reached.", "nmOrbitNe.orbital": "A number does not indicate the amount of white circles used by the loop.", "nmOrder.numcity": "The size of a district is larger or equal to the size of the previous district.", "nmOutOfBk.oyakodori": "A bird is outside a nest.", diff --git a/src/variety/oasis.js b/src/variety/oasis.js new file mode 100644 index 000000000..b994b8d03 --- /dev/null +++ b/src/variety/oasis.js @@ -0,0 +1,339 @@ +/* global Set:false */ +(function(pidlist, classbase) { + if (typeof module === "object" && module.exports) { + module.exports = [pidlist, classbase]; + } else { + pzpr.classmgr.makeCustom(pidlist, classbase); + } +})(["oasis"], { + //--------------------------------------------------------- + // マウス入力系 + MouseEvent: { + RBShadeCell: true, + use: true, + inputModes: { + edit: ["number", "clear"], + play: ["shade", "unshade", "peke", "completion"] + }, + mouseinput_auto: function() { + if (this.puzzle.playmode) { + if (this.mousestart) { + this.isDraggingPeke = this.puzzle.key.isALT; + } + if (this.isDraggingPeke) { + this.inputpeke(); + } else if (this.btn === "left" && this.mousestart) { + if (!this.inputdark()) { + this.inputcell(); + } + } else if (this.inputData === null || this.inputData < 20) { + this.inputcell(); + } + } else if (this.puzzle.editmode) { + if (this.mousestart) { + this.inputqnum(); + } + } + }, + inputdark: function() { + var cell = this.getcell(); + if (cell.isnull) { + return false; + } + + var distance = 0.6, + dx = this.inputPoint.bx - cell.bx /* ここはtargetcellではなくcell */, + dy = this.inputPoint.by - cell.by; + if (cell.isNum() && dx * dx + dy * dy < distance * distance) { + this.inputData = cell.qcmp !== 1 ? 21 : 20; + cell.setQcmp(this.inputData === 21 ? 1 : 0); + cell.draw(); + return true; + } + return false; + }, + inputqcmp: function() { + var cell = this.getcell(); + if (cell.isnull) { + return; + } + + cell.setQcmp(+!cell.qcmp); + cell.draw(); + + this.mousereset(); + } + }, + + //--------------------------------------------------------- + // キーボード入力系 + KeyEvent: { + enablemake: true + }, + + //--------------------------------------------------------- + // 盤面管理系 + Cell: { + numberRemainsUnshaded: true, + + maxnum: function() { + return this.board.cols * this.board.rows - 1; + }, + + isCmp: function() { + if (!this.isNum()) { + return false; + } + if (this.qcmp === 1) { + return true; + } + if (!this.isValidNum() || !this.puzzle.execConfig("autocmp")) { + return false; + } + return this.countResult(true) === 0; + }, + + countResult: function(explicit) { + if (!this.isValidNum()) { + return 0; + } + var targets = new Set(); + for (var dir in this.adjacent) { + var c = this.adjacent[dir]; + if (c.isNum()) { + targets.add(c); + } + var group = explicit ? c.autooasis : c.oasis; + if (group) { + group.adjclist.each(function(obj) { + targets.add(obj); + }); + } + } + targets.delete(this); + return targets.size - this.qnum; + }, + redrawConnected: function() { + if (this.autooasis) { + this.autooasis.adjclist.each(function(c) { + c.draw(); + }); + } else { + for (var dir in this.adjacent) { + var c = this.adjacent[dir]; + if (c && c.autooasis) { + c.redrawConnected(); + } else if (c && c.isNum()) { + c.draw(); + } + } + } + }, + + posthook: { + qnum: function() { + var bd = this.board; + var oasis = new Set(); + var autooasis = new Set(); + + for (var dir in this.adjacent) { + var c = this.adjacent[dir]; + if (c && c.oasis) { + oasis.add(c.oasis); + } + if (c && c.autooasis) { + autooasis.add(c.autooasis); + } + } + + oasis.forEach(function(cmp) { + bd.oasisgraph.setExtraData(cmp); + }); + autooasis.forEach(function(cmp) { + bd.autooasisgraph.setExtraData(cmp); + }); + this.redrawConnected(); + }, + qsub: function() { + this.redrawConnected(); + } + } + }, + Board: { + hasborder: 1, + cols: 8, + rows: 8, + + addExtraInfo: function() { + this.oasisgraph = this.addInfoList(this.klass.ImplicitOasisGraph); + this.autooasisgraph = this.addInfoList(this.klass.ExplicitOasisGraph); + } + }, + + AreaUnshadeGraph: { + enabled: true + }, + "ImplicitOasisGraph:AreaGraphBase": { + enabled: true, + relation: { "cell.qans": "node", "cell.qnum": "node", "cell.qsub": "node" }, + setExtraData: function(component) { + this.common.setExtraData.call(this, component); + + var set = new Set(); + + component.clist.each(function(cell) { + for (var dir in cell.adjacent) { + var adj = cell.adjacent[dir]; + if (adj.isNum()) { + set.add(adj); + } + } + }); + component.adjclist = new this.klass.CellList(Array.from(set)); + }, + + isnodevalid: function(cell) { + return cell.isUnshade() && !cell.isNum(); + }, + + getComponentRefs: function(obj) { + return obj.oasis; + }, + setComponentRefs: function(obj, component) { + obj.oasis = component; + }, + getObjNodeList: function(nodeobj) { + return nodeobj.oasisnodes; + }, + resetObjNodeList: function(nodeobj) { + nodeobj.oasisnodes = []; + } + }, + "ExplicitOasisGraph:ImplicitOasisGraph": { + isnodevalid: function(cell) { + return cell.isUnshade() && !cell.isNum() && cell.qsub; + }, + getComponentRefs: function(obj) { + return obj.autooasis; + }, + setComponentRefs: function(obj, component) { + obj.autooasis = component; + }, + getObjNodeList: function(nodeobj) { + return nodeobj.autooasisnodes; + }, + resetObjNodeList: function(nodeobj) { + nodeobj.autooasisnodes = []; + } + }, + + //--------------------------------------------------------- + // 画像表示系 + Graphic: { + qanscolor: "black", + bgcellcolor_func: "qsub1", + gridcolor_type: "LIGHT", + + autocmp: "number", + hideHatena: true, + enablebcolor: true, + + paint: function() { + this.drawBGCells(); + this.drawGrid(); + this.drawShadedCells(); + + this.drawCircledNumbers(); + + this.drawChassis(); + + this.drawPekes(); + + this.drawTarget(); + }, + + getCircleFillColor: function(cell) { + if (!cell.isNum()) { + return null; + } + return cell.isCmp() ? this.qcmpcolor : this.bgcolor; + } + }, + + //--------------------------------------------------------- + // URLエンコード/デコード処理 + Encode: { + decodePzpr: function(type) { + this.decodeNumber16(); + }, + encodePzpr: function(type) { + this.encodeNumber16(); + } + }, + //--------------------------------------------------------- + FileIO: { + decodeData: function() { + this.decodeCellQnum(); + this.decodeCellQanssubcmp(); + this.decodeBorderLine(); + }, + encodeData: function() { + this.encodeCellQnum(); + this.encodeCellQanssubcmp(); + this.encodeBorderLineIfPresent(); + }, + + decodeCellQanssubcmp: function() { + this.decodeCell(function(cell, ca) { + if (ca === "+") { + cell.qsub = 1; + } else if (ca === "c") { + cell.qsub = 1; + cell.qcmp = 1; + } else if (ca === "-") { + cell.qcmp = 1; + } else if (ca === "1") { + cell.qans = 1; + } + }); + }, + encodeCellQanssubcmp: function() { + this.encodeCell(function(cell) { + if (cell.qans === 1) { + return "1 "; + } else if (cell.qsub === 1) { + return cell.qcmp ? "c " : "+ "; + } else if (cell.qcmp === 1) { + return "- "; + } else { + return ". "; + } + }); + } + }, + + //--------------------------------------------------------- + // 正解判定処理実行部 + AnsCheck: { + checklist: [ + "checkShadeCellExist", + "checkAdjacentShadeCell", + "checkConnectUnshadeRB", + "checkCellNumberLarge", + "check2x2UnshadeCell++", + "checkCellNumberSmall", + "doneShadingDecided" + ], + + checkCellNumberLarge: function() { + this.checkAllCell(function(cell) { + return cell.countResult(false) < 0; + }, "nmOasisGt"); + }, + checkCellNumberSmall: function() { + this.checkAllCell(function(cell) { + return cell.countResult(false) > 0; + }, "nmOasisLt"); + } + } +}); diff --git a/test/script/oasis.js b/test/script/oasis.js new file mode 100644 index 000000000..77ff6f93b --- /dev/null +++ b/test/script/oasis.js @@ -0,0 +1,68 @@ +/* oasis.js */ + +ui.debug.addDebugData("oasis", { + url: "6/6/2.m.l3h2l.m.1", + failcheck: [ + [ + "brNoShade", + "pzprv3/oasis/6/6/2 - . . . . /. . . - . . /. . . . 3 . /. 2 . . . . /. . - . . . /. . . . - 1 /. . . . . . /. . . . . . /. . . . . . /. . . . . . /. . . . . . /. . . . . . /" + ], + [ + "csAdjacent", + "pzprv3/oasis/6/6/2 - . . . . /. . . - . . /. . . . 3 . /. 2 . . . . /. . - . . . /. . . . - 1 /. . . . . . /. . . . . . /. . 1 . . . /. . 1 . . . /. . . . . . /. . . . . . /" + ], + [ + "cuDivideRB", + "pzprv3/oasis/6/6/2 - . . . . /. . . - . . /. . . . 3 . /. 2 . . . . /. . - . . . /. . . . - 1 /. . 1 . . . /. 1 . . 1 . /. . 1 . . 1 /1 . . 1 . . /. 1 . . . 1 /. . 1 . . . /" + ], + [ + "nmOasisGt", + "pzprv3/oasis/6/6/2 - . . . . /. . . - . . /. . . . 3 . /. 2 . . . . /. . - . . . /. . . . - 1 /. . . 1 . 1 /1 . 1 . . . /. . . 1 . 1 /1 . 1 . . . /. . . 1 . 1 /. 1 . . . . /" + ], + [ + "nmOasisLt", + "pzprv3/oasis/6/6/2 - . . . . /. . . - . . /. . . . 3 . /. 2 . . . . /. . - . . . /. . . . - 1 /. . 1 . . . /. 1 . . 1 . /. . . 1 . . /1 . 1 . . 1 /. . . . 1 . /1 . 1 . . . /" + ], + [ + "cu2x2", + "pzprv3/oasis/6/6/2 - . . . . /. . . - . . /. . . . 3 . /. 2 . . . . /. . - . . . /. . . . - 1 /. . . 1 . 1 /. 1 . . . . /. . 1 . . 1 /1 . . 1 . . /. . . . . 1 /. 1 . 1 . . /" + ], + [ + null, + "pzprv3/oasis/6/6/2 - . . . . /. . . - . . /. . . . 3 . /. 2 . . . . /. . - . . . /. . . . - 1 /+ + 1 + + + /+ 1 + + 1 + /+ + 1 + + 1 /1 + + 1 + + /+ 1 + + + 1 /+ + + 1 + + /" + ] + ], + inputs: [ + { + input: [ + "newboard,3,3", + "editmode", + "cursor,3,1", + "key,1", + "playmode", + "mouse,left,3,3", + "mouse,right,5,3" + ], + result: "pzprv3/oasis/3/3/. 1 . /. . . /. . . /. . . /. 1 + /. . . /" + }, + { + input: [ + "editmode", + "cursor,5,5", + "key,2", + "playmode", + "mouse,left,3,1", + "mouse,left,4.1,4.1" + ], + result: "pzprv3/oasis/3/3/. 1 . /. . . /. . 2 /. - . /. 1 + /. . . /" + }, + { + input: ["setconfig,use,2", "mouse,left,4.1,4.1"], + result: "pzprv3/oasis/3/3/. 1 . /. . . /. . 2 /. - . /. 1 + /. . + /" + }, + { + input: ["mouse,left,5,5", "playmode,completion", "mouse,left,3,1"], + result: "pzprv3/oasis/3/3/. 1 . /. . . /. . 2 /. . . /. 1 + /. . c /" + } + ] +}); From b6266f5cec81e84a496eca0ca07cb47b9ba101e4 Mon Sep 17 00:00:00 2001 From: Lennard Sprong Date: Mon, 15 Dec 2025 09:34:22 +0100 Subject: [PATCH 2/2] Remove bcolor --- src-ui/changes.html | 2 +- src/variety/oasis.js | 33 +++++++-------------------------- test/script/oasis.js | 15 ++------------- 3 files changed, 10 insertions(+), 40 deletions(-) diff --git a/src-ui/changes.html b/src-ui/changes.html index 6b3eb76cc..e437dd4e1 100644 --- a/src-ui/changes.html +++ b/src-ui/changes.html @@ -33,13 +33,13 @@
    Latest types (all types)
    diff --git a/src/variety/oasis.js b/src/variety/oasis.js index b994b8d03..93bae064a 100644 --- a/src/variety/oasis.js +++ b/src/variety/oasis.js @@ -23,7 +23,7 @@ if (this.isDraggingPeke) { this.inputpeke(); } else if (this.btn === "left" && this.mousestart) { - if (!this.inputdark()) { + if (!this.inputqcmp()) { this.inputcell(); } } else if (this.inputData === null || this.inputData < 20) { @@ -35,33 +35,18 @@ } } }, - inputdark: function() { - var cell = this.getcell(); - if (cell.isnull) { - return false; - } - - var distance = 0.6, - dx = this.inputPoint.bx - cell.bx /* ここはtargetcellではなくcell */, - dy = this.inputPoint.by - cell.by; - if (cell.isNum() && dx * dx + dy * dy < distance * distance) { - this.inputData = cell.qcmp !== 1 ? 21 : 20; - cell.setQcmp(this.inputData === 21 ? 1 : 0); - cell.draw(); - return true; - } - return false; - }, inputqcmp: function() { var cell = this.getcell(); - if (cell.isnull) { - return; + if (cell.isnull || !cell.isNum()) { + return false; } + this.inputData = 20; cell.setQcmp(+!cell.qcmp); cell.draw(); this.mousereset(); + return true; } }, @@ -231,15 +216,14 @@ // 画像表示系 Graphic: { qanscolor: "black", - bgcellcolor_func: "qsub1", gridcolor_type: "LIGHT", autocmp: "number", hideHatena: true, - enablebcolor: true, paint: function() { this.drawBGCells(); + this.drawDotCells(); this.drawGrid(); this.drawShadedCells(); @@ -287,9 +271,6 @@ this.decodeCell(function(cell, ca) { if (ca === "+") { cell.qsub = 1; - } else if (ca === "c") { - cell.qsub = 1; - cell.qcmp = 1; } else if (ca === "-") { cell.qcmp = 1; } else if (ca === "1") { @@ -302,7 +283,7 @@ if (cell.qans === 1) { return "1 "; } else if (cell.qsub === 1) { - return cell.qcmp ? "c " : "+ "; + return "+ "; } else if (cell.qcmp === 1) { return "- "; } else { diff --git a/test/script/oasis.js b/test/script/oasis.js index 77ff6f93b..076b536a9 100644 --- a/test/script/oasis.js +++ b/test/script/oasis.js @@ -46,23 +46,12 @@ ui.debug.addDebugData("oasis", { result: "pzprv3/oasis/3/3/. 1 . /. . . /. . . /. . . /. 1 + /. . . /" }, { - input: [ - "editmode", - "cursor,5,5", - "key,2", - "playmode", - "mouse,left,3,1", - "mouse,left,4.1,4.1" - ], + input: ["editmode", "cursor,5,5", "key,2", "playmode", "mouse,left,3,1"], result: "pzprv3/oasis/3/3/. 1 . /. . . /. . 2 /. - . /. 1 + /. . . /" }, - { - input: ["setconfig,use,2", "mouse,left,4.1,4.1"], - result: "pzprv3/oasis/3/3/. 1 . /. . . /. . 2 /. - . /. 1 + /. . + /" - }, { input: ["mouse,left,5,5", "playmode,completion", "mouse,left,3,1"], - result: "pzprv3/oasis/3/3/. 1 . /. . . /. . 2 /. . . /. 1 + /. . c /" + result: "pzprv3/oasis/3/3/. 1 . /. . . /. . 2 /. . . /. 1 + /. . - /" } ] });