From efb02413d45b2c2f20ab306638e9fcd3829c5a96 Mon Sep 17 00:00:00 2001 From: Lennard Sprong Date: Mon, 1 Apr 2024 13:53:49 +0200 Subject: [PATCH] Add Subomino --- src-ui/changes.html | 2 +- src-ui/img/subomino.png | Bin 0 -> 140 bytes src-ui/js/ui/KeyPopup.js | 3 +- src-ui/js/ui/Misc.js | 1 + src-ui/list.html | 1 + src/pzpr/variety.js | 1 + src/res/failcode.en.json | 1 + src/variety/nawabari.js | 148 ++++++++++++++++++++++++++++++++++++--- test/script/subomino.js | 31 ++++++++ 9 files changed, 177 insertions(+), 11 deletions(-) create mode 100644 src-ui/img/subomino.png create mode 100644 test/script/subomino.js diff --git a/src-ui/changes.html b/src-ui/changes.html index cfe9f16c8..83b26f592 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/subomino.png b/src-ui/img/subomino.png new file mode 100644 index 0000000000000000000000000000000000000000..8793f956cdf75c368aaca26d82612c78ea8c3494 GIT binary patch literal 140 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~wg8_H*R*Lj zZXPZ3zW@F+P{hR3#W6%;YH|V#BO4o=n??ddp#y`PurkASAG-t>HjQP6ZwM?mJQNub jvfy_s<2puPO+Q8kjZ6l&UKhq)K>ZA!u6{1-oD!M<+|VSX literal 0 HcmV?d00001 diff --git a/src-ui/js/ui/KeyPopup.js b/src-ui/js/ui/KeyPopup.js index c77aa65d2..79cd26859 100644 --- a/src-ui/js/ui/KeyPopup.js +++ b/src-ui/js/ui/KeyPopup.js @@ -194,7 +194,8 @@ ui.keypopup = { mannequin: [10, 0], tetrominous: [128, 128], lineofsight: [10, 0], - mrtile: [10, 0] + mrtile: [10, 0], + subomino: [10, 0] }, //--------------------------------------------------------------------------- diff --git a/src-ui/js/ui/Misc.js b/src-ui/js/ui/Misc.js index 019b4dece..27edd9e67 100755 --- a/src-ui/js/ui/Misc.js +++ b/src-ui/js/ui/Misc.js @@ -185,6 +185,7 @@ function toBGimage(pid) { "squarejam", "starbattle", "statuepark", + "subomino", "wafusuma", "symmarea", "tachibk", diff --git a/src-ui/list.html b/src-ui/list.html index 82b53057b..ee31a9077 100644 --- a/src-ui/list.html +++ b/src-ui/list.html @@ -252,6 +252,7 @@

パズルの種類のリスト
  • +
  • diff --git a/src/pzpr/variety.js b/src/pzpr/variety.js index b70f5e05a..447d91c45 100755 --- a/src/pzpr/variety.js +++ b/src/pzpr/variety.js @@ -375,6 +375,7 @@ statuepark: [0, 0, "Statue Park", "Statue Park"], "statuepark-aux": [0, 0, "図形の編集", "Edit shape"], stostone: [0, 0, "ストストーン", "Stostone", "shimaguni"], + subomino: [0, 0, "Subomino", "Subomino", "nawabari"], sudoku: [0, 1, "数独", "Sudoku"], sukoro: [1, 0, "数コロ", "Sukoro", "sukoro"], sukororoom: [0, 0, "数コロ部屋", "Sukoro-room", "sukoro"], diff --git a/src/res/failcode.en.json b/src/res/failcode.en.json index d392ea300..72ba29dd6 100644 --- a/src/res/failcode.en.json +++ b/src/res/failcode.en.json @@ -206,6 +206,7 @@ "bkObjGe2.kinkonkan": "A room has more than one mirror.", "bkObjNotSym.bonsan": "Position of circles in the room is not point symmetric.", "bkOddSize.kazunori": "The size of the room is not even.", + "bkOverlap.subomino": "A block fits entirely in an adjacent block.", "bkOverNum": "A block contains too many numbers.", "bkPassTwice.country": "A line passes a country twice or more.", "bkPassTwice.moonsun": "A line passes a room twice or more.", diff --git a/src/variety/nawabari.js b/src/variety/nawabari.js index 325b53caf..9495cfec2 100644 --- a/src/variety/nawabari.js +++ b/src/variety/nawabari.js @@ -7,7 +7,7 @@ } else { pzpr.classmgr.makeCustom(pidlist, classbase); } -})(["nawabari", "fourcells", "fivecells", "heteromino"], { +})(["nawabari", "fourcells", "fivecells", "heteromino", "subomino"], { //--------------------------------------------------------- // マウス入力系 MouseEvent: { @@ -29,10 +29,13 @@ this.inputempty(); } }, - "MouseEvent@fourcells,fivecells,heteromino": { + "MouseEvent@fourcells,fivecells,subomino": { inputModes: { edit: ["empty", "number", "clear"], play: ["border", "subline"] + }, + mouseinput_clear: function() { + this.inputFixedNumber(-1); } }, @@ -42,7 +45,7 @@ enablemake: true }, - "KeyEvent@fourcells,fivecells,heteromino": { + "KeyEvent@fourcells,fivecells,subomino,heteromino": { keyinput: function(ca) { if (ca === "w") { this.key_inputvalid(ca); @@ -87,6 +90,19 @@ maxnum: 3, minnum: 0 }, + "Cell@subomino": { + maxnum: function() { + return this.board.cols * this.board.rows; + }, + minnum: 2, + posthook: { + qnum: function(num) { + if (this.room) { + this.board.roommgr.setExtraData(this.room); + } + } + } + }, "CellList@heteromino": { triminoShape: function() { if (this.length !== 3) { @@ -106,6 +122,15 @@ return id; } }, + "CellList@subomino": { + seterr: function(err) { + this.each(function(cell) { + if (err > cell.error) { + cell.error = err; + } + }); + } + }, Border: { isGrid: function() { @@ -154,6 +179,14 @@ AreaRoomGraph: { enabled: true }, + "AreaRoomGraph@subomino": { + setExtraData: function(component) { + component.clist = new this.klass.CellList(component.getnodeobjs()); + component.valid = !component.clist.some(function(cell) { + return cell.qnum > 0 && cell.qnum !== component.clist.length; + }); + } + }, //--------------------------------------------------------- // 画像表示系 @@ -169,13 +202,14 @@ this.drawQansBorders(); this.drawQuesBorders(); - this.drawQuesNumbers(); - this.drawBorderQsubs(); - - if (this.pid === "heteromino") { + if (this.pid === "heteromino" || this.pid === "subomino") { + this.drawCircles(); this.drawChassis(); } + this.drawQuesNumbers(); + this.drawBorderQsubs(); + this.drawTarget(); }, @@ -210,12 +244,24 @@ } }, - "Graphic@heteromino": { + "Graphic@heteromino,subomino": { + errbcolor2: "rgb(255, 216, 216)", + circlestrokecolor_func: "null", + circleratio: [0.35, 0.35], getBGCellColor: function(cell) { if (!cell.isValid()) { return "black"; } - return this.getBGCellColor_error1(cell); + var info = cell.error || cell.qinfo; + if (info === 1 || info === 3) { + return this.errbcolor1; + } else if (info === 2) { + return this.errbcolor2; + } + return null; + }, + getCircleFillColor: function(cell) { + return cell.error === 3 ? this.errbcolor2 : null; } }, @@ -295,6 +341,16 @@ this.outbstr += cm; } }, + "Encode@subomino": { + decodePzpr: function(type) { + this.decodeNumber16(); + this.decodeEmpty(); + }, + encodePzpr: function(type) { + this.encodeNumber16(); + this.encodeEmpty(); + } + }, //--------------------------------------------------------- FileIO: { decodeData: function() { @@ -440,5 +496,79 @@ l2.seterr(1); } } + }, + "AnsCheck@subomino": { + checklist: ["checkAreaOverlap", "checkNumberValid", "checkBorderDeadend+"], + + checkAreaOverlap: function() { + var sides = this.board.roommgr.getSideAreaInfo(); + for (var i = 0; i < sides.length; i++) { + var small = sides[i][0], + large = sides[i][1]; + + if (!small.valid || !large.valid) { + continue; + } + if (small.clist.length > large.clist.length) { + large = sides[i][0]; + small = sides[i][1]; + } + + var ss = small.clist.getRectSize(); + var ls = large.clist.getRectSize(); + var clist = new this.klass.CellList(); + var found = false; + + for (var ox = 0; !found && ox <= ls.cols - ss.cols; ox++) { + for (var oy = 0; !found && oy <= ls.rows - ss.rows; oy++) { + var c; + for (c = 0; c < small.clist.length; c++) { + var oldcell = small.clist[c]; + var newcell = this.board.getc( + ox * 2 + ls.x1 + oldcell.bx - ss.x1, + oy * 2 + ls.y1 + oldcell.by - ss.y1 + ); + if (newcell.isnull || newcell.room !== large) { + break; + } + clist.add(newcell); + } + + if (c === small.clist.length) { + found = true; + } else { + clist = new this.klass.CellList(); + } + } + } + if (!found) { + continue; + } + + this.failcode.add("bkOverlap"); + if (this.checkOnly) { + break; + } + clist.seterr(3); + small.clist.seterr(2); + large.clist.seterr(1); + } + }, + + checkNumberValid: function() { + var bd = this.board; + for (var r = 0; r < bd.roommgr.components.length; r++) { + var area = bd.roommgr.components[r]; + if (area.valid) { + continue; + } + + this.failcode.add("bkSizeNe"); + if (this.checkOnly) { + break; + } + area.clist.seterr(1); + } + } } }); diff --git a/test/script/subomino.js b/test/script/subomino.js new file mode 100644 index 000000000..f9b06d074 --- /dev/null +++ b/test/script/subomino.js @@ -0,0 +1,31 @@ +/* subomino.js */ + +ui.debug.addDebugData("subomino", { + url: "5/5/3j6j3i4o410000", + failcheck: [ + [ + "bkSizeNe", + "pzprv3/subomino/5/5/3 . . . * /6 . . . . /3 . . . 4 /. . . . . /. . . . 4 /0 0 0 1 0 0 /0 0 1 0 1 0 /0 1 0 1 1 0 /0 1 1 1 1 0 /0 1 0 0 1 0 /0 0 0 0 0 /1 1 1 0 0 /1 0 1 0 0 /0 1 0 1 0 /0 0 1 0 0 /0 0 0 0 0 /" + ], + [ + "bkOverlap", + "pzprv3/subomino/5/5/3 . . . * /6 . . . . /3 . . . 4 /. . . . . /. . . . 4 /0 0 0 1 0 0 /0 0 0 0 1 0 /0 1 1 1 0 0 /0 1 0 0 1 0 /0 1 0 0 0 0 /0 0 0 0 0 /1 1 1 0 0 /1 1 0 1 0 /0 0 1 1 0 /0 1 1 1 1 /0 0 0 0 0 /" + ], + [ + null, + "pzprv3/subomino/5/5/3 . . . * /6 . . . . /3 . . . 4 /. . . . . /. . . . 4 /0 0 0 1 0 0 /0 0 1 0 1 0 /0 1 0 1 1 0 /0 1 1 0 1 0 /0 1 0 0 1 0 /0 0 0 0 0 /1 1 1 0 0 /1 0 1 0 0 /0 1 0 1 0 /0 0 1 1 0 /0 0 0 0 0 /" + ] + ], + inputs: [ + { + input: ["newboard,3,3", "editmode", "cursor,3,3", "mouse,right,3,3"], + result: + "pzprv3/subomino/3/3/. . . /. 9 . /. . . /0 0 0 0 /0 0 0 0 /0 0 0 0 /0 0 0 /0 0 0 /0 0 0 /0 0 0 /" + }, + { + input: ["editmode,clear", "mouse,left,3,3"], + result: + "pzprv3/subomino/3/3/. . . /. . . /. . . /0 0 0 0 /0 0 0 0 /0 0 0 0 /0 0 0 /0 0 0 /0 0 0 /0 0 0 /" + } + ] +});