Skip to content

Commit 30797e3

Browse files
authored
Add Land Measurement
1 parent 73e0f0f commit 30797e3

7 files changed

Lines changed: 416 additions & 7 deletions

File tree

src-ui/js/ui/KeyPopup.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,8 @@ ui.keypopup = {
259259
bramble: [10, 0],
260260
golemgrad: [10, 0],
261261
topo: [10, 10],
262-
soulmates: [10, 10]
262+
soulmates: [10, 10],
263+
landmeasure: [10, 0]
263264
},
264265

265266
//---------------------------------------------------------------------------
@@ -508,6 +509,8 @@ ui.keypopup = {
508509
pid === "mrtile"
509510
) {
510511
cap = "■";
512+
} else if (pid === "landmeasure") {
513+
cap = "∞";
511514
} else if (pid === "patchwork") {
512515
cap = {
513516
text: "■",

src-ui/list.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ <h2 id="title"><span lang="ja">パズルの種類のリスト</span><span lang="
7373
<li data-pid="sansaroad"></li>
7474
<li data-pid="cornerch"></li>
7575
<li data-pid="hasunomura"></li>
76+
<li data-pid="landmeasure"></li>
7677
</ul>
7778
</div>
7879
<div class="lists blocks">

src/pzpr/variety.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@
264264
kusabi: [0, 0, "クサビリンク", "Kusabi"],
265265
ladders: [0, 0, "はしごをかけろ", "Ladders"],
266266
lapaz: [0, 0, "La Paz", "La Paz"],
267+
landmeasure: [0, 0, "Land Measurement", "Land Measurement"],
267268
lightshadow: [0, 0, "Light and Shadow", "Light and Shadow"],
268269
lightup: [
269270
0,

src/res/failcode.en.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,9 @@
433433
"crAdjacent.tajmahal": "A square does not touch the correct amount of other squares.",
434434
"crConnSlNe.gokigen": "A number is not equal to count of lines that is connected to it.",
435435
"crNoSegment.tajmahal": "A clue is not inside a square.",
436+
"crShade0": "A number 0 is overlapping a shaded cell.",
437+
"crShadeDistNe.landmeasure": "A number isn't equal to the length of the path covering all adjacent cells.",
438+
"crShadeInfinite.landmeasure": "An infinity clue doesn't overlap 2 disconnected shaded cells.",
436439
"crShadeGt.creek": "The number of shaded cells overlapping a number is too high.",
437440
"crShadeLt.creek": "The number of shaded cells overlapping a number is too low.",
438441
"cs1x1.cityspace": "There is an isolated shaded cell.",

src/variety-common/Graphic.js

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -927,13 +927,13 @@ pzpr.classmgr.makeCommon({
927927
for (var i = 0; i < clist.length; i++) {
928928
var cross = clist[i],
929929
px = cross.bx * this.bw,
930-
py = cross.by * this.bh;
930+
py = cross.by * this.bh,
931+
iserr = cross.error === 1 || cross.qinfo === 1;
931932

932933
// ○の描画
933934
g.vid = "x_cp_" + cross.id;
934935
if (cross.qnum !== -1) {
935-
g.fillStyle =
936-
cross.error === 1 || cross.qinfo === 1 ? this.errcolor1 : "white";
936+
g.fillStyle = iserr ? this.errcolor1 : "white";
937937
g.strokeStyle = "black";
938938
g.shapeCircle(px, py, csize);
939939
} else {
@@ -942,14 +942,18 @@ pzpr.classmgr.makeCommon({
942942

943943
// 数字の描画
944944
g.vid = "cross_text_" + cross.id;
945-
if (cross.qnum >= 0) {
946-
g.fillStyle = this.quescolor;
947-
this.disptext("" + cross.qnum, px, py, option);
945+
var txt = this.getCrossNumberText(cross, cross.qnum);
946+
if (txt) {
947+
g.fillStyle = iserr ? "white" : this.quescolor;
948+
this.disptext(txt, px, py, option);
948949
} else {
949950
g.vhide();
950951
}
951952
}
952953
},
954+
getCrossNumberText: function(cross, num) {
955+
return num >= 0 ? "" + num : null;
956+
},
953957
drawCrossMarks: function() {
954958
var g = this.vinc("cross_mark", "auto", true);
955959

src/variety/landmeasure.js

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
(function(pidlist, classbase) {
2+
if (typeof module === "object" && module.exports) {
3+
module.exports = [pidlist, classbase];
4+
} else {
5+
pzpr.classmgr.makeCustom(pidlist, classbase);
6+
}
7+
})(["landmeasure"], {
8+
//---------------------------------------------------------
9+
// マウス入力系
10+
MouseEvent: {
11+
use: true,
12+
inputModes: {
13+
edit: ["number", "clear", "info-blk"],
14+
play: ["shade", "unshade", "info-blk"]
15+
},
16+
mouseinput_clear: function() {
17+
this.inputclean_cross();
18+
},
19+
mouseinput_number: function() {
20+
if (this.mousestart) {
21+
this.inputqnum_cross();
22+
}
23+
},
24+
mouseinput_auto: function() {
25+
if (this.puzzle.playmode) {
26+
if (this.mousestart || this.mousemove) {
27+
this.inputcell();
28+
}
29+
} else if (this.puzzle.editmode) {
30+
if (this.mousestart) {
31+
this.inputqnum_cross();
32+
}
33+
}
34+
},
35+
36+
getNewNumber: function(cross, num) {
37+
var max = cross.getmaxnum();
38+
if (this.btn === "left") {
39+
num += 1;
40+
if (num > 3) {
41+
num |= 1;
42+
}
43+
if (num === 5) {
44+
num = 7;
45+
}
46+
if (num > max) {
47+
return max < 3 ? -1 : -2;
48+
}
49+
return num;
50+
} else {
51+
num -= 1;
52+
if (num < -2) {
53+
num = max;
54+
} else if (max < 3 && num < -1) {
55+
num = max;
56+
} else if (num > 7 && !(num & 1)) {
57+
num -= 1;
58+
}
59+
if (num > 3 && num < 7) {
60+
return 3;
61+
}
62+
63+
return num;
64+
}
65+
}
66+
},
67+
68+
//---------------------------------------------------------
69+
// キーボード入力系
70+
KeyEvent: {
71+
enablemake: true,
72+
moveTarget: function(ca) {
73+
return this.moveTCross(ca);
74+
},
75+
76+
keyinput: function(ca) {
77+
this.key_inputcross(ca);
78+
}
79+
},
80+
81+
TargetCursor: {
82+
crosstype: true
83+
},
84+
85+
//---------------------------------------------------------
86+
// 盤面管理系
87+
Cross: {
88+
minnum: 0,
89+
maxnum: function() {
90+
var bd = this.board;
91+
var edge1 = this.bx === bd.minbx || this.bx === bd.maxbx;
92+
var edge2 = this.by === bd.minby || this.by === bd.maxby;
93+
if (edge1 || edge2) {
94+
return edge1 && edge2 ? 1 : 2;
95+
}
96+
97+
return ((bd.cols * bd.rows) | 1) - 2;
98+
}
99+
},
100+
101+
Board: {
102+
hasborder: 1
103+
},
104+
AreaShadeGraph: {
105+
enabled: true,
106+
coloring: true
107+
},
108+
109+
Cell: {
110+
distanceTo: function(end) {
111+
/* Calculate Manhattan distance using Dijkstra's algorithm */
112+
113+
var visited = new Set();
114+
var distances = {};
115+
distances[this.id] = 0;
116+
117+
while (true) {
118+
var current = null;
119+
var minimum = -1;
120+
for (var idx in distances) {
121+
if (visited.has(+idx)) {
122+
continue;
123+
}
124+
125+
var dist = distances[idx];
126+
if (minimum === -1 || dist < minimum) {
127+
current = this.board.cell[+idx];
128+
minimum = dist;
129+
}
130+
}
131+
132+
if (!current || current === end) {
133+
break;
134+
}
135+
136+
for (var dir in current.adjacent) {
137+
var next = current.adjacent[dir];
138+
if (!next.isShade() || visited.has(+next.id)) {
139+
continue;
140+
}
141+
var olddist = distances[next.id];
142+
var newdist = minimum + 1;
143+
if (olddist === undefined || newdist < olddist) {
144+
distances[next.id] = newdist;
145+
}
146+
}
147+
148+
visited.add(current.id);
149+
}
150+
151+
return distances[end.id];
152+
}
153+
},
154+
155+
//---------------------------------------------------------
156+
// 画像表示系
157+
Graphic: {
158+
margin: 0.5,
159+
irowakeblk: true,
160+
161+
qanscolor: "black",
162+
shadecolor: "rgb(96, 96, 96)",
163+
164+
crosssize: 0.35,
165+
166+
paint: function() {
167+
this.drawBGCells();
168+
this.drawShadedCells();
169+
this.drawDotCells();
170+
this.drawGrid();
171+
172+
this.drawChassis();
173+
174+
this.drawCrosses();
175+
this.drawTarget();
176+
},
177+
getCrossNumberText: function(cross, num) {
178+
return num === -2 ? "∞" : num >= 0 ? "" + num : null;
179+
}
180+
},
181+
182+
//---------------------------------------------------------
183+
// URLエンコード/デコード処理
184+
Encode: {
185+
decodePzpr: function(type) {
186+
var bd = this.board;
187+
this.genericDecodeNumber16(bd.cross.length, function(c, val) {
188+
bd.cross[c].qnum = val;
189+
});
190+
},
191+
encodePzpr: function(type) {
192+
var bd = this.board;
193+
this.genericEncodeNumber16(bd.cross.length, function(c) {
194+
return bd.cross[c].qnum;
195+
});
196+
}
197+
},
198+
//---------------------------------------------------------
199+
FileIO: {
200+
decodeData: function() {
201+
this.decodeCrossNum();
202+
this.decodeCellAns();
203+
},
204+
encodeData: function() {
205+
this.encodeCrossNum();
206+
this.encodeCellAns();
207+
}
208+
},
209+
210+
//---------------------------------------------------------
211+
// 正解判定処理実行部
212+
AnsCheck: {
213+
checklist: [
214+
"checkShadeCellExist",
215+
"check2x2ShadeCell",
216+
"checkShadeLoop",
217+
"checkZeroes",
218+
"checkAllNumbers",
219+
"checkInfinites",
220+
"doneShadingDecided"
221+
],
222+
223+
checkQnumCross: function(func, code) {
224+
var bd = this.board;
225+
for (var c = 0; c < bd.cross.length; c++) {
226+
var cross = bd.cross[c],
227+
num = cross.qnum;
228+
if (num === -1) {
229+
continue;
230+
}
231+
232+
var bx = cross.bx,
233+
by = cross.by;
234+
var clist = bd.cellinside(bx - 1, by - 1, bx + 1, by + 1);
235+
var shaded = clist.filter(function(cell) {
236+
return cell.isShade();
237+
});
238+
239+
if (func(num, shaded)) {
240+
this.failcode.add(code);
241+
if (this.checkOnly) {
242+
break;
243+
}
244+
cross.seterr(1);
245+
}
246+
}
247+
},
248+
249+
checkZeroes: function() {
250+
this.checkQnumCross(function(num, shaded) {
251+
return num === 0 && shaded.length !== 0;
252+
}, "crShade0");
253+
},
254+
255+
checkInfinites: function() {
256+
this.checkQnumCross(function(num, shaded) {
257+
if (num !== -2) {
258+
return false;
259+
}
260+
261+
return shaded.length !== 2 || shaded[0].sblk === shaded[1].sblk;
262+
}, "crShadeInfinite");
263+
},
264+
265+
checkAllNumbers: function() {
266+
this.checkQnumCross(function(num, shaded) {
267+
if (num < 2) {
268+
return false;
269+
}
270+
if (num === 1 || num === 3) {
271+
return shaded.length !== num;
272+
}
273+
if (shaded.length !== 2 || shaded[0].sblk !== shaded[1].sblk) {
274+
return true;
275+
}
276+
277+
return shaded[0].distanceTo(shaded[1]) !== num - 1;
278+
}, "crShadeDistNe");
279+
},
280+
281+
checkShadeLoop: function() {
282+
var bd = this.board,
283+
blks = bd.sblkmgr.components;
284+
for (var r = 0; r < blks.length; r++) {
285+
if (blks[r].circuits === 0) {
286+
continue;
287+
}
288+
289+
this.failcode.add("csLoop");
290+
if (this.checkOnly) {
291+
return;
292+
}
293+
this.searchloop(blks[r], bd.sblkmgr).seterr(1);
294+
}
295+
}
296+
}
297+
});

0 commit comments

Comments
 (0)