0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

なわばり — 数字は部屋の大きさを言わない。「どの席に座っているか」を言う。ヒント数がダイヤルでないパズルを実装した

0
Posted at

なわばり(Nawabari / Territory)を、5 段のソルバー内蔵でブラウザに実装した。ルールは「盤を長方形の部屋に分ける。各部屋は数字をちょうど 1 つ持ち、数字はそのマス自身の 4 辺のうち何辺が部屋の壁かを表す(外枠も壁)」。つまり数字は部屋について何も語らない。そのマスが部屋のどの席に座っているかだけを語る。結果、このジャンルにはヒント数というダイヤルが存在しない — 数字の個数は答えの部屋数と同一で、選べるのは「各部屋のどのマスに数字を置くか」だけだ。出荷 72 盤・633 部屋で測ると、同じ答えを印刷する方法のうち一意になるのは 6×6 で 19.5%、8×8 で 3.3%。数字を部屋の中で 1 マス動かすと 50.1% が壊れ、印刷される数字が変わらない移動 1,360 通りに限っても 679 通り(49.9%)しか生き残らない。数字を 1 つ消す操作は「弱いヒント」ではなく盤の破壊で、633 回の消去のうち意図した答えが合法のまま残るのは 0 回、盤そのものが死ぬのが 59.4%。外枠を壁に数えないと解が全部消え、「各部屋に数字は 1 つ以下」を落としても中央値は 1 のままだが、「1 つ以上」を落とすと 8×8 の中央値が 218 億に飛ぶ。ソルバー内蔵パズル第 63 弾。

デモ: https://sen.ltd/portfolio/nawabari/
リポジトリ: https://github.com/sen-ltd/nawabari

Nawabari

ルール

  • 盤を長方形の部屋に分ける
  • 各部屋は数字をちょうど 1 つ持つ
  • 数字は「そのマス自身の 4 辺のうち何辺が部屋の壁か」。外枠も壁に数える

ニコリの比較的マイナーなジャンルで、puzz.link のエンジン(pzprjs)の判定は「部屋が長方形」「数字のない部屋は不可」「数字が 2 つある部屋は不可」「数字のマスの 4 辺の壁数が数字と一致」の 4 つ。実装前にこの 4 節を一次資料で確認してから書き始めた。

数字が語るのは「席」であって「広さ」ではない

自分がこれまで実装してきた「盤を切り分ける」系 — シカク、アラフ、フィルオミノ、ヘヤワケ — は、どれも領域を領域についての数で採点する。面積、マス数、合計。なわばりの数字は領域について何も言わない。それはその数字が印刷されたマスの性質で、言い換えると「そのマスが部屋のどの席に座っているか」だ。

6×6 盤で、全マス × そのマスが属しうる全長方形を数え上げるとアルファベットの全体が出る。

数字 席 許す長方形 許す部屋の広さの種類 最小 最大
4 自分だけの部屋 36 1 1 1
3 幅 1 の帯の端 360 5 2 6
2 太い部屋の角、または帯の中ほど 1,140 16 3 36
1 辺沿い(角ではない) 1,200 13 6 36
0 完全に内部 400 10 9 36

4 だけが部屋の広さを確定する。しかもそれは「部屋そのものだから」であって、広さを語っているわけではない。2 は 3 マスの部屋から 36 マスの部屋まで許す。

そして席は 6 種類、文字は 5 種類。2 だけが 2 つの席を持つ — 太い部屋の角と、幅 1 の帯の中ほどは、紙の上で区別がつかない。これがこのジャンルの曖昧さの全予算だ。

出荷盤では、1 つの数字が残す長方形は中央値で 6 個(6×6)/ 8 個(8×8)、部屋の広さの種類は中央値 4 / 5、最大 20。1 つの数字だけで決まるものは何もない。

ヒント数はダイヤルではない

ここが実装していて一番戸惑った点だ。このシリーズの他のパズルでは、生成器は必ずヒント数という予算を持っている。多く配れば易しく、少なく配れば難しく、「最小何個で一意になるか」は答えのある問いだ。

なわばりにその問いは無い。1 部屋 1 数字なので、数字の個数は答えの部屋数そのもの。ここで出荷している 72 盤が 633 個の数字を持つのは、答えが 633 部屋だからで、それ以外の選択肢は最初から存在しない。1 つ減らした盤は「難しい盤」ではなく不正な盤だ。

残る自由度は「各部屋のどのマスに数字を置くか」で、これが設計空間の全部になる。出荷答えを取り、印刷された盤を忘れて、各部屋のランダムなマスに数字を置き直す。値は席から自動的に決まるので、盤は常に合法で、常にその答えを持つ。問題は他の答えも持つかどうかだ。

盤 答え 1 答えあたりの置き方(中央値) 最大 抽出数 一意
6×6 36 6,696 103,680 600 4,221 (19.5%)
8×8 36 3,414,528 91,445,760 400 470 (3.3%)

6×6 で最も寛容な答えは置き方の 84.3% が一意、最も意地悪な答えは 2.3%、中央値 15.0%。8×8 の中央値は 2.0%。生成器の仕事は「何を言うか」ではなく「どこに立つか」を選ぶことだ。

同じ数字を、同じ部屋の別のマスへ

この分離をいちばん鋭く測れるのが 1 マス移動だ。出荷盤の数字を 1 つ選び、自分の部屋の中の別のマスへ動かし、新しい席に合わせて値を書き直す。答えは一切変わらず、合法のままだ。盤全体で 2,967 通りの移動があり、一意のまま残るのは 1,485 通り、50.1%。

そのうち 1,360 通りは印刷される数字が変わらない(新しい席の壁数が元と同じ)。盤は「同じ情報を少し違う場所に持っている」ようにしか見えない。そのうち一意のまま残るのは 679 通り、49.9%。

盤が言っている内容は 1 文字も変わっていないのに、別のパズルになっている。 ヒントの位置は値を届ける入れ物ではなく、値の半分そのものだ、というのがこのジャンルで一番はっきり見える事実だと思う。

数字が着地した席 移動数 一意のまま
帯の端 337 174 (51.6%)
帯の中ほど 353 190 (53.8%)
太い部屋の角 900 409 (45.4%)
辺沿い 1,202 603 (50.2%)
完全に内部 175 109 (62.3%)

期待と逆だった行が 1 つある。アルファベットで一番弱い文字 0(完全に内部)が、着地先として一番強い(62.3%)。一番強い文字が乗る角は一番弱い(45.4%)。情報量の多い文字を分かりやすい場所に置くことは、盤を締めることではないらしい。

数字を 1 つ消すと、難しくなるのではなく盤が死ぬ

このシリーズの他のパズルでは毎回「どのヒントも 1 つ消すと第 2 の答えが現れる(=局所最小)」を検証してきた。なわばりではこのテストがそもそも実行できない。数字を消すと、その数字が属していた答えのほうが不正になる — 数字を持たない部屋ができてしまうからだ。

盤 数字 消すと盤が死ぬ 答えは残る しかも一意
6×6 239 140 (58.6%) 99 52
8×8 394 236 (59.9%) 158 92

633 回の消去のうち、意図した答えが合法のまま残るのは 0 回。盤が丸ごと死ぬのが 59.4%、残り 40.6% は答えを持ち、そのうち **144 個は「別の答えを持つ、まっとうな一意パズル」**になる。

このジャンルでヒントは「答えについての証拠」ではない。「答えとは何であるかの仕様の一部」だ。

数字を消して点だけ残す

逆の実験。位置は全部残し、値だけ消す。盤は「各部屋に数字が 1 つある、その場所はここだ」としか言わなくなる(これは実在のジャンル — 面積を消したシカク — でもある)。転送行列で上限なしの厳密計算ができる。

盤 盤数 一意 答え数(中央値) 最小 最大
6×6 36 0 564 24 30,844
8×8 36 0 369,090 5,872 109,011,159

72 盤中 0 盤。各部屋のマスを 1 つずつ全部知っていることは、答えを知っていることではない。

16 通りのうち 8 通り

「1 部屋 1 数字」以外のすべての条項は、1 つの格子点についての条件だ。内部の格子点には壁の芽が 4 本集まり、その 16 通りのうち 8 通りが合法 — 何も無い、直線の交差、4 通りの T、十字。禁止されるのは「芽が 1 本だけ」(何も隔てない壁)と「直交する 2 本」(凹角になるので周りの部屋が長方形でなくなる)。

これがこのジャンルの幾何の全部で、npm test は 3×3 の 2^12 通り、2×5 の 2^13 通り、3×4 の 2^17 通りの壁パターン全数について「全格子点で合法」と「全部屋が長方形かつ全ての壁が何かを隔てている」が一致することを確認している(不一致 0 件、生き残り数は既知の長方形分割数と一致)。

出荷答えの格子点 2,664 個の内訳:

格子点で出会うもの 回数 割合
何も無い 1,109 41.6%
直線の交差 1,016 38.1%
T 字 528 19.8%
十字 11 0.4%
凹角(違法) 0 0.0%
独りの芽(違法) 0 0.0%

局所的であることが、数えられることに直結する。 頂点模型なので転送行列が列ごとに歩ける。列境界の状態は「行がどう部屋に切られているか」+「各部屋の数字がまだ何を要求しているか」の 4 状態(未配置 / 充足済 / この列に置いたので部屋はここで終われない / この列に置いたので部屋はここで終わらねばならない)で足りる。

梯子

2 段は辺の上に、2 段は長方形の上に住んでいて、受け渡しの場所に全部の強さがある。

  • count — 数字のマスの周りの壁数が数字と一致する。外枠は壁。4 ビットの算数
  • vertex — 格子点の 8 通りを伝播する
  • room — 答えとは「数字 1 つにつき長方形 1 つを選び、それらが盤を敷き詰めること」= exact cover。各数字の候補長方形を既知の壁で篩い、全生存候補が同意する辺を書き戻し、ある数字しか届かないマスをその数字に渡す
  • probe — 長方形を 1 つ仮定し、下 3 段を回して矛盾したら捨てる
  • search — 生存候補の少ない数字から分岐
段 6×6 壁が決まる 6×6 完走 8×8 壁が決まる 8×8 完走
count 8.5% 0/36 7.6% 0/36
vertex 14.5% 0/36 12.1% 0/36
room 98.3% 35/36 89.4% 28/36
probe 100% 36/36 100% 36/36

言うのは簡単なので値段をつける。完全探索に「分岐の合間で使ってよい段」を制限して、分岐点の数を数えた。

使ってよい段 6×6 中央値 6×6 最悪 8×8 中央値 8×8 最悪
count まで 269 9,382 101,701 20 万で打ち切り(15 盤)
vertex まで 260 8,318 98,164 20 万で打ち切り(13 盤)
room まで 0 4 0 3

辺の 2 段だけだと 8×8 の中央値は 98,164 分岐。長方形の段を足すと 0。ソルバー全体がこの視点変更 1 つでできている — 「どの辺が壁か」を訊くのをやめて「各数字はどの長方形に属するか」を訊く。

読み違えは対称に壊れない

ルールは 4 節(長方形 / 1 部屋 1 数字 / 自分のマスの壁を数える / 外枠も壁)。どれも単独で間違えられる。

読み違え 盤 意図した答えが合法 答え数(中央値) 一意のまま
外枠を壁に数えない 6×6 / 8×8 0/72 0 0/72
数字を部屋の面積と読む 6×6 / 8×8 0/72 0 0/72
1 部屋に数字が複数あってよい 6×6 36/36 1 24/36
1 部屋に数字が複数あってよい 8×8 36/36 1 21/36
数字の無い部屋があってよい 6×6 36/36 122,637 0/36
数字の無い部屋があってよい 8×8 36/36 21,823,026,293 0/36

締める向きの誤読は大声で失敗する。外枠を忘れる、あるいはシカク系の癖で「数字=面積」と読むと、意図した答えが 72 盤すべてで不正になり、盤は真っ白になる。気づかずに出荷することはできない。

緩める向きが危ない。そして「ちょうど 1 つ」の 2 つの半分は等価ではない。 「1 つ以下」を落とすと 72 盤中 27 盤が一意性を失う(中央値は 1 のまま、痛いが致命的ではない)。「1 つ以上」を落とす — つまり隣接ジャンルが普通に許している「数字の無い部屋」を許す — と、8×8 の中央値が 1 から 218 億、最悪 336 兆に飛ぶ。1 つの節の片側だけで、ジャンル全体を支えている。

でたらめに数字を撒いた盤はほぼ必ず死ぬ

盤 数字 値の引き方 抽出 解無し ちょうど 1 つ 複数
6×6 7 一様 400 398 (99.5%) 0 2
6×6 7 出荷盤の分布 400 393 (98.3%) 3 4
8×8 11 一様 400 400 (100.0%) 0 0
8×8 11 出荷盤の分布 400 396 (99.0%) 0 4

出荷盤が実際に使っている値の分布(3 と 2 が多い)から引いても 8×8 で 99.0% が解無し。一意性は既知の答えから外向きに作るしかない。

外部の台帳

数字を全部消すと、なわばりの盤は素の長方形分割になる。これは文献で数えられている数列なので、転送行列はそれを再現する義務がある。A333476 の三角形 28 項すべて一致、対角線 A182275 は探索が絶対に届かない先まで:

盤 長方形分割の数 既知の値と 転送行列
6×6 535,236,230,270 一致 6 ms
7×7 18,100,579,400,986,674 一致 33 ms
8×8 3,250,879,178,100,782,348,462 一致 199 ms
9×9 3,097,923,464,622,249,063,718,465,240 一致 1,170 ms

行方向も別々に公開されている(2×n が A034999、3×n が A208215、4×n が A220297、5×n が A220298、1×n は 2^(n-1))。転送行列を知らない 2 つの探索 — 長方形を左上から敷く bruteByRooms と、内部の辺を 1 本ずつ決めて最後にだけ盤の姿を訊く bruteByEdges — が、届く範囲で同じ数を返す。

そして誰も公開していない数: 印刷できない答え

分割は答えだ。それがパズルかどうかは「各部屋に数字を 1 つずつ書く方法のどれかで一意になるか」で決まる。これは盤ではなく分割についての問いだ。小さい盤で全分割 × 全配置を歩く。

盤 分割 合法な盤 うち一意 印刷できない答え
1×7 64 377 331 0
2×6 2,864 64,520 42,505 0
3×3 322 3,232 2,224 0
3×4 3,164 71,624 43,436 0

1×n の「合法な盤」の列は 1, 3, 8, 21, 55, 144, 377 = F(2n)(A001906)。帯の上の合法な盤が「n の分割(composition)を各部分の積で重みづけたもの」になるからで、これは外部で確認できる。隣の「一意」の列 1, 3, 8, 21, 53, 133, 331 は、2026 年 9 月時点で OEIS に無い。2×n の 17, 122, 879, 6169, 42505 も、3×3 の 2,224 も 3×4 の 43,436 も無い。

最後の列は、もっと早く非ゼロになると思っていたし、実際そうならなかった。一意な配置が 1 つ見つかれば打ち切れるので、大きい盤まで届く。

盤 調べた答え 印刷できない 最悪の探索
4×4 70,878(全分割) 12 288
3×6 314,662(全分割) 0 322
4×5 1,613,060(全分割) 267 1,152
6×6 60(生成器の分布) 0 3,241

印刷できない答えは 4×4 で初めて現れる(70,878 分割中 12、5,907 個に 1 個)。一方 3×6 は分割が 4.5 倍あるのに 1 つも無い。効いているのは大きさではなく形だ: 4×4 の 12 個は全部ちょうど 6 部屋で、全部が幅 1 の帯だけでできていて、全部が「2×2 を埋める平行なドミノ 2 枚」を含む。4×5 でもほぼ同じ(267 個中 247 個が帯だけ、260 個がドミノ対を含む)。

ドミノ対はこのジャンル最小の曖昧さだ。並んだドミノ 2 枚は 2×2 を埋め、ドミノではどのマスも端なので、縦割りでも横割りでも 4 マスすべてが 3 を印刷する。数字は 2 つの割り方を区別できない。区別できるのはどのマスが数字を持つかだけ(1 部屋 1 数字なので、一方の割り方では行ごとに 1 つ、他方では列ごとに 1 つになる)。単独なら解消できる — だから 3×6 は 1 つも死なない。盤が帯だけでできていて、1 つの曖昧さから逃げると次の曖昧さに入ってしまうときに、答えは立つ場所を失う。

実装

  • src/nawabari.ts — ルール、5 段の梯子、exact cover の探索
  • src/brute.ts — 独立な 2 つの列挙器(長方形から / 辺から)
  • src/count.ts — 転送行列(BigInt、上限なし)とその逆写像による一様サンプリング
  • src/generate.ts — 答えを先に引き、置き方を探す生成器
  • tools/{generate,ledger,stats,notes}.mts — 盤・台帳・測定・ページ生成

ページと README の数値は全部 src/stats.json / src/ledger.json から生成していて、手書き転記はゼロ。テストは 23 本で、出荷盤の一意性・格付け・「どの段も答えと矛盾することを証明しない」ことをファイルから再導出している。

TypeScript、ランタイム依存なし、MIT。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?