diff --git a/package-lock.json b/package-lock.json index 92bafdffe..18478db80 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8938,4 +8938,4 @@ "dev": true } } -} +} \ No newline at end of file diff --git a/src-ui/changes.html b/src-ui/changes.html index 353df386b..057d62c18 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/turnaround.png b/src-ui/img/turnaround.png new file mode 100644 index 000000000..aec1d387b Binary files /dev/null and b/src-ui/img/turnaround.png differ diff --git a/src-ui/js/ui/KeyPopup.js b/src-ui/js/ui/KeyPopup.js index 0aa14601a..a6a223cf3 100644 --- a/src-ui/js/ui/KeyPopup.js +++ b/src-ui/js/ui/KeyPopup.js @@ -200,6 +200,7 @@ ui.keypopup = { teri: [10, 0], portal: [10, 0], kuromenbun: [10, 0], + turnaround: [3, 0], bosnianroad: [80, 0], sananko: [10, 113], zabajaba: [80, 0], @@ -349,6 +350,8 @@ ui.keypopup = { this.generate_retroships(mode); } else if (type === 130) { this.generate_lix(mode); + } else if (type === 131) { + this.generate_infinity(mode); } }, gentable4: function(mode) { diff --git a/src-ui/js/ui/Misc.js b/src-ui/js/ui/Misc.js index 50c644a52..009633c3f 100755 --- a/src-ui/js/ui/Misc.js +++ b/src-ui/js/ui/Misc.js @@ -210,6 +210,7 @@ function toBGimage(pid) { "tontonbeya", "trainstations", "tslither", + "turnaround", "voxas", "vslither", "walllogic", diff --git a/src-ui/list.html b/src-ui/list.html index cd6b80b5e..4a58a08ae 100644 --- a/src-ui/list.html +++ b/src-ui/list.html @@ -160,6 +160,7 @@

パズルの種類のリスト
  • +
  • diff --git a/src-ui/res/history.en.yaml b/src-ui/res/history.en.yaml index 65798761f..819da23fe 100644 --- a/src-ui/res/history.en.yaml +++ b/src-ui/res/history.en.yaml @@ -226,3 +226,4 @@ curving: This genre was invented by Inaba Naoki. firewalk: This genre was invented by Martin Ender a.k.a. Menderbug and Lennard Sprong a.k.a. X_Sheep. zabajaba: This genre was invented by Eric Fox. fakearrow: This genre first appeared in Puzzle Communication Nikoli vol. 185. +turnaround: This genre was invented by Ivan Adrian Koswara a.k.a. chaotic_iak. diff --git a/src-ui/res/history.ja.yaml b/src-ui/res/history.ja.yaml index 170778333..60f722e3b 100644 --- a/src-ui/res/history.ja.yaml +++ b/src-ui/res/history.ja.yaml @@ -186,3 +186,4 @@ sananko: 齋藤スバル氏発案 curving: 稲葉直貴氏発案 zabajaba: Eric Fox氏発案 fakearrow: パズル通信ニコリ vol.185より +turnaround: Ivan Adrian Koswara (chaotic_iak)氏発案 diff --git a/src-ui/res/rules.en.yaml b/src-ui/res/rules.en.yaml index 052632b59..ab6c8f227 100644 --- a/src-ui/res/rules.en.yaml +++ b/src-ui/res/rules.en.yaml @@ -306,6 +306,7 @@ teri: "Shade some cells on the board.\n1. Shaded cells cannot be horizontally or lixloop: "Shade some cells on the board, and draw a single loop that goes through all remaining cells.\n1. The loop cannot branch off or cross itself.\n2. Shaded cells cannot be orthogonally adjacent.\n3. Cells with letters or question marks cannot be shaded, and are not part of the loop.\n4. The letters represent cells that contain a turning line (L), straight line (I), or shaded cell (X). The clued cells indicate whichever type is most frequent in that direction. If multiple types are tied for most frequent, all letters will be listed in the clue." sananko: "Place a number between 1 and 3 in some of the empty cells.\n1. Numbers must appear in groups of 3 orthogonally connected cells with the same number.\n2. Different groups cannot be orthogonally adjacent.\n3. Clues on shaded cells indicate the sum of numbers in the (up to four) orthogonally adjacent cells." bosnianroad: "Shade some cells to form a loop.\n1. The loop cannot visit a cell that's orthogonally or diagonally adjacent to a cell it has visited before.\n2. Gray cells cannot be shaded.\n3. A number indicates the amount of shaded cells in the orthogonally and diagonally adjacent cells." +turnaround: "Draw a loop traveling orthogonally on cells. \n1. The loop must visit all numbers. \n2. Each number indicates how many turns the loop makes among the three cells: the number itself, and the cells immediately before and after it in the loop." snakeegg: "Shade some cells into the grid to form a snake.\n1. The snake cannot loop back on itself and visit a cell that's orthogonally adjacent to a cell it has visited before.\n2. Circles must lie on one end of the path.\n3. Exactly one orthogonally connected area of unshaded cells must exist of each size given outside the grid. There cannot be other areas of unshaded cells.\n4. Cells with numbers cannot be shaded, and represent the size of the area they’re in." curving: "Shade some cells on the board.\n1. Shaded cells cannot be horizontally or vertically adjacent.\n2. All unshaded cells on the board form an orthogonally connected area.\n3. Cells with circles cannot be shaded.\n4. Every possible orthogonal path through unshaded cells between two circles must turn at least twice." firewalk: "Draw a loop that goes through every numbered cell.\n1. The loop cannot branch off or cross itself.\n2. Orange cells represent fire, while regular cells represent ground. The loop must turn on every orange cell it visits.\n3. The loop is allowed to visit an orange cell twice if the center of the cell is inside the loop.\n4. A number indicates how many cells make up the continuous grounded section of the loop that the number is on." diff --git a/src/puzzle/Config.js b/src/puzzle/Config.js index 19b0691ad..6bcdd5f2a 100644 --- a/src/puzzle/Config.js +++ b/src/puzzle/Config.js @@ -53,7 +53,6 @@ "patchwork_leftaux", true ); /* patchwork: Alternative mouse input */ - this.add("squarecell", true); /* セルは正方形にする */ /* 入力方法設定 */ diff --git a/src/pzpr/variety.js b/src/pzpr/variety.js index 2ee315cf6..d7d6107fc 100755 --- a/src/pzpr/variety.js +++ b/src/pzpr/variety.js @@ -98,12 +98,6 @@ arukone: [0, 0, "アルコネ", "Arukone", "numlin"], ayeheya: [0, 1, "∀人∃HEYA", "Ayeheya", "heyawake"], balance: [0, 0, "Balance Loop", "Balance Loop"], - cave: [1, 0, "バッグ", "Cave", "kurodoko", { alias: "bag" }], - cbanana: [0, 0, "チョコバナナ", "Choco Banana"], - circlesquare: [0, 0, "Circles and Squares", "Circles and Squares"], - context: [0, 0, "Context", "Context"], - crossstitch: [0, 0, "Crossstitch", "Crossstitch"], - cts: [0, 0, "Cross the Streams", "Cross the Streams", "nonogram"], barns: [1, 0, "バーンズ", "Barns"], batten: [0, 0, "Battenberg Painting", "Battenberg Painting"], battleship: [0, 0, "Battleship", "Battleship", "statuepark"], @@ -114,6 +108,12 @@ bosnianroad: [0, 0, "Bosnian Road", "Bosnian Road"], box: [0, 0, "ボックス", "Box"], brownies: [0, 0, "ブラウニー", "Brownies", "yosenabe"], + cave: [1, 0, "バッグ", "Cave", "kurodoko", { alias: "bag" }], + cbanana: [0, 0, "チョコバナナ", "Choco Banana"], + circlesquare: [0, 0, "Circles and Squares", "Circles and Squares"], + context: [0, 0, "Context", "Context"], + crossstitch: [0, 0, "Crossstitch", "Crossstitch"], + cts: [0, 0, "Cross the Streams", "Cross the Streams", "nonogram"], skyscrapers: [ 0, 0, @@ -420,6 +420,7 @@ tren: [0, 0, "パーキング", "Tren"], triplace: [0, 0, "トリプレイス", "Tri-place"], tslither: [0, 0, "Touch Slitherlink", "Touch Slitherlink", "vslither"], + turnaround: [0, 0, "ターンアラウンド", "Turnaround"], usotatami: [0, 0, "ウソタタミ", "Uso-tatami", "fillmat"], usoone: [0, 0, "ウソワン", "Uso-one"], view: [1, 0, "ヴィウ", "View", "sukoro"], diff --git a/src/res/failcode.en.json b/src/res/failcode.en.json index 087f56f26..56d923ff1 100644 --- a/src/res/failcode.en.json +++ b/src/res/failcode.en.json @@ -13,6 +13,7 @@ "anShadeNe.yajisoko": "The number of boxes is not correct.", "anShadeNe": "The number of shaded cells is not correct.", "anTatamiNe.yajitatami": "The number of tatamis are not correct.", + "anTurn.turnaround": "The number of turns is not correct", "anUnitNe.kuroclone": "The size of the pointed unit is not correct.", "arAdjPair.toichika": "There are paired arrows in adjacent countries.", "arAdjPair.toichika2": "There are paired numbers in adjacent countries.", @@ -783,6 +784,7 @@ "nqAroundDup.kakuru": "There are same numbers around the pre-numbered cell.", "nqAroundSumNe.kakuru": "A sum of numbers around the pre-numbered cell is incorrect.", "numNoLine.geradeweg": "A number has no line.", + "numNoLine.turnaround": "A number has no line.", "objShaded.nurimaze": "An object is shaded.", "pairedLetterNe.kinkonkan": "Beam from a light doesn't reach its pair.", "pairedNumberNe.kinkonkan": "The number of reflections is wrong.", @@ -794,6 +796,7 @@ "rmDeadend.scrin": "There is a dead-end rectangle.", "rmIsolated.scrin": "There is an isolated rectangle.", "rmRectUnshade.scrin": "A rectangle is not part of the solution.", + "routeLenLoop": "The route does not contain a loop.", "routeIgnoreCP.nurimaze": "There is a circle out of the shortest route from S to G.", "routePassDeadEnd.nurimaze": "There is a triangle on the shortest route from S to G.", "segBlackEq.balance": "Segments through a black circle are equal.", diff --git a/src/variety/turnaround.js b/src/variety/turnaround.js new file mode 100644 index 000000000..b08905214 --- /dev/null +++ b/src/variety/turnaround.js @@ -0,0 +1,175 @@ +(function(pidlist, classbase) { + if (typeof module === "object" && module.exports) { + module.exports = [pidlist, classbase]; + } else { + pzpr.classmgr.makeCustom(pidlist, classbase); + } +})(["turnaround"], { + MouseEvent: { + inputModes: { + edit: ["number", "clear", "info-line"], + play: ["line", "peke", "clear", "info-line"] + }, + autoedit_func: "qnum", + autoplay_func: "line" + }, + KeyEvent: { + enablemake: true + }, + + Cell: { + minnum: 0, + maxnum: 3, + + isCmp: function() { + if (!this.puzzle.execConfig("autocmp")) { + return false; + } + return this.qnum === this.countTurn(); + }, + + countTurn: function() { + if (!this.isNum() || this.lcnt !== 2) { + return -1; + } + + var clist = this.getAdjCells(); + if ( + clist.some(function(cell) { + return cell.lcnt !== 2; + }) + ) { + return -1; + } + + clist.add(this); + var turncount = 0; + clist.each(function(cell) { + turncount += cell.isLineCurve() ? 1 : 0; + }); + + return turncount; + }, + + getAdjCells: function() { + var clist = new this.klass.PieceList(); + for (var dir in this.adjborder) { + if (this.adjborder[dir].isLine()) { + clist.add(this.adjacent[dir]); + } + } + return clist; + }, + + posthook: { + qnum: function(num) { + if (num >= 0) { + this.checkAutoCmp(); + } + } + } + }, + Board: { + hasborder: 1 + }, + LineGraph: { + enabled: true + }, + + Graphic: { + irowake: true, + qcmpcolor: "rgb(127,127,127)", + autocmp: "number", + + getQuesNumberColor: function(cell) { + var qnum_color = this.getQuesNumberColor_mixed(cell); + if ((cell.error || cell.qinfo) === 1) { + return qnum_color; + } + return cell.isCmp() ? this.qcmpcolor : qnum_color; + }, + + setRange: function(x1, y1, x2, y2) { + var puzzle = this.puzzle, + bd = puzzle.board; + if (puzzle.execConfig("autocmp")) { + x1 = bd.minbx - 2; + y1 = bd.minby - 2; + x2 = bd.maxbx + 2; + y2 = bd.maxby + 2; + } + this.common.setRange.call(this, x1, y1, x2, y2); + }, + + paint: function() { + this.drawBGCells(); + this.drawShadedCells(); + this.drawDashedGrid(); + this.drawLines(); + this.drawQuesNumbers(); + this.drawPekes(); + + this.drawChassis(); + + this.drawTarget(); + } + }, + + Encode: { + decodePzpr: function(type) { + this.decodeNumber16(); + }, + encodePzpr: function(type) { + this.encodeNumber16(); + } + }, + FileIO: { + decodeData: function() { + this.decodeCellQnum(); + this.decodeBorderLine(); + }, + encodeData: function() { + this.encodeCellQnum(); + this.encodeBorderLine(); + } + }, + + AnsCheck: { + checklist: [ + "checkBranchLine", + "checkCrossLine", + + "checkTurnCount", + "checkNoLineNumber", + + "checkDeadendLine+", + "checkOneLoop" + ], + + checkTurnCount: function() { + this.checkAllCell(function(cell) { + if (!cell.isValidNum()) { + return false; + } + + var turncount = cell.countTurn(); + if (turncount === -1) { + return false; + } + if (turncount !== cell.qnum) { + cell.seterr(1); + cell.getAdjCells().seterr(1); + return true; + } + + return false; + }, "anTurn"); + }, + + checkNoLineNumber: function() { + this.checkAllCell(function(cell) { + return cell.isNum() && cell.lcnt === 0; + }, "numNoLine"); + } + } +}); diff --git a/test/script/turnaround.js b/test/script/turnaround.js new file mode 100644 index 000000000..5977befb5 --- /dev/null +++ b/test/script/turnaround.js @@ -0,0 +1,37 @@ +ui.debug.addDebugData("turnaround", { + url: "5/5/h0g1l1g2l2g3h", + failcheck: [ + [ + "numNoLine", + "pzprv3/turnaround/5/5/. . 0 . 1 /. . . . . /. 1 . 2 . /. . . . . /2 . 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 0 /0 0 0 0 0 /0 0 0 0 0 /0 0 0 0 0 /" + ], + [ + "numNoLine", + "pzprv3/turnaround/5/5/. . 0 . 1 /. . . . . /. 1 . 2 . /. . . . . /2 . 3 . . /0 0 0 0 /1 1 1 1 /1 1 1 0 /0 0 0 1 /0 0 0 0 /0 0 0 0 0 /1 0 0 0 1 /0 0 0 1 1 /0 0 0 0 0 /" + ], + [ + "anTurn", + "pzprv3/turnaround/5/5/. . 0 . 1 /. . . . . /. 1 . 2 . /. . . . . /2 . 3 . . /0 1 1 1 /0 0 0 0 /0 0 0 1 /0 0 0 1 /1 1 0 0 /0 1 0 0 0 /0 0 0 0 1 /1 0 0 1 0 /1 0 0 0 1 /" + ], + [ + "lnBranch", + "pzprv3/turnaround/5/5/. . 0 . 1 /. . . . . /. 1 . 2 . /. . . . . /2 . 3 . . /0 0 0 0 /0 1 1 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 0 0 0 /0 0 0 0 0 /" + ], + [ + "lnCross", + "pzprv3/turnaround/5/5/. . 0 . 1 /. . . . . /. 1 . 2 . /. . . . . /2 . 3 . . /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 1 0 0 /0 0 0 0 0 /0 0 0 0 0 /" + ], + [ + "lnDeadEnd", + "pzprv3/turnaround/5/5/. . 0 . 1 /. . . . . /. . . . . /. . . . . /2 . 3 . . /1 1 1 1 /0 0 0 0 /1 0 0 0 /0 1 0 0 /1 0 1 0 /0 0 0 0 1 /0 0 0 0 1 /1 0 0 0 0 /1 1 1 1 0 /" + ], + [ + "lnPlLoop", + "pzprv3/turnaround/5/5/. . 0 . 1 /. . . . . /. . . . . /. . . . . /2 . 3 . . /1 1 1 1 /1 0 1 0 /1 0 1 0 /0 1 0 1 /1 0 1 0 /1 0 0 0 1 /0 1 1 1 1 /1 0 0 0 1 /1 1 1 1 0 /" + ], + [ + null, + "pzprv3/turnaround/5/5/. . 0 . 1 /. . . . . /. 1 . 2 . /. . . . . /2 . 3 . . /1 1 1 1 /1 1 1 0 /1 1 1 0 /0 1 0 1 /1 0 1 0 /1 0 0 0 1 /0 0 0 1 1 /1 0 0 0 1 /1 1 1 1 0 /" + ] + ] +});