ピエロがお前たちを嘲笑う
先月の月報を書きました.
最近の進捗について.
ルービックキューブソルバを書いてる.
入力形式を少しまともにした. キューブの状態を今までは展開図の形で
YYY
YYY
YYY
GGGOOOBBBRRR
RRRGGGOOOBBB
OOOBBBRRRGGG
WWW
WWW
WWW
とベタ書きしてた. これは9行であって改行を除いて全部で54文字であることにしてた. つまり, 例えば途中で空白を入れたりコメントを書いたりできない. これはパーズを自力で素朴かつ幼稚に行っていたためだ. そういえば最近, ルービックキューブ図示ツールとして作った
のフォーマットをそのまま持ってくることにした. 初期状態は Init
というタグを用いて次のように書く.
Init {
YYY
YYY
YYY
GGG OOO BBB RRR # 間に空白を入れて読みやすく出来る
RRR GGG OOO BBB
OOO BBB RRR GGG # シャープ記号より後ろはコメント
WWW
WWW
WWW
}
初期状態を陽に与える代わりにスクランブルを与えてることもできる. というか本来はこっちのほうが使う場面があるはずだ.
Scramble {
F' U2 F2 R' F2 L2 R' F2 R2 D2 F2 U' L2 F D2 U2 B2 U' R2
}
最終状態は Goal { ... }
で与えるが, 標準色配列で良ければデフォルトがこれになっているので, 省略可能. 特に初期状態をスクランブルで与えるなら, 色の順序には意味がないのでゴールは常に省略してて構わない.
さて cympfh/cube
ソルバーはただただ双方向幅優先探索をするだけでこれといって面白いことはない. 人手で解く場合のルービックキューブの解法は有名なものがいくつもあるが, 速度優先で安定してるものとしては CFOP 法があまりに有名. これは 3x3 のキューブを3つの層からなる構造だと思うことにして, これを下の層から順に組み立ててく方法. 大雑把すぎる説明だけどね. しかしながら最初の2層 (F2L) を作るまでは自由度が高く, 探索空間が大きい. そこを乗り越えたら一気に探索空間が小さくなる. 人間が解く場合でもこの F2L というフェーズが肝になる.
さて, 手法はいくつもあると述べたが, その通りで CFOP 以外にも人気度は落ちるが実践的な手法はいくつかある. その一つに Roux Method (るー・めそっど)がある. ちょっと口頭で説明するのは難しいが, さっきの三段構造をそのまま使うなら, 先に一段目と三段目を揃えてから最後に二段目を揃える, サンドイッチで言うところのパンだけ先に用意して具材部分を最後に調整するという流れ. ルービックキューブというパズルは本質的には, センターとエッジとコーナーという三種類のパズルの組み合わせで出来ている. 組み合わせといっても掛け算ではなくてそれぞれは独立になっている. この中でセンターというのは実は無視してよくて, エッジとコーナーという2つのパズルをそれぞれ解けば良い. Roux Method の中の一つのステップはコーナーだけについて解くようになっていて (CMLL), その点で探索空間を一気に狭める事ができる良さがある. 後半は使う操作が二種類しかない (M と U) ので \(2^N\) に関する探索だけすればよくて, これもかなり高速に完了する. というわけでソルバーを実装するのに Roux Method は良さそうだと思った.
実装しました. さっきの cube
に --roux
というオプションを与えるとやってくれます.
$ cube --version
cube 0.4.1
$ cat input
Scramble {
F' U2 F2 R' F2 L2 R' F2 R2 D2 F2 U' L2 F D2 U2 B2 U' R2
}
$ cube --roux < input
[2022-09-07T15:41:50Z INFO ] Init
{
BWR
GYG
BWG
OOO YRG YGR YOY
RRR YGW BOO BBB
OOW BWW RYB WGG
WYR
YWR
OBG
}
[2022-09-07T15:41:50Z INFO ] Goal
{
YYY
YYY
YYY
RRR GGG OOO BBB
RRR GGG OOO BBB
RRR GGG OOO BBB
WWW
WWW
WWW
}
[2022-09-07T15:41:50Z INFO ] FB/1
[2022-09-07T15:41:50Z INFO ] Solution: DB'DU
[2022-09-07T15:41:50Z INFO ] FB/2
[2022-09-07T15:41:50Z INFO ] Solution: B'U'BBR'B'
[2022-09-07T15:41:50Z INFO ] SB/1
[2022-09-07T15:41:52Z INFO ] Solution: U'r'U'rUM'rU'r'U'R'
[2022-09-07T15:41:52Z INFO ] SB/2
[2022-09-07T15:41:52Z INFO ] Solution: Mr'UrUUr'U'R
[2022-09-07T15:41:52Z INFO ] CMLL
[2022-09-07T15:41:52Z INFO ] Solution: RRU'RFR'URRFU'F'
[2022-09-07T15:41:52Z INFO ] LSE
[2022-09-07T15:41:52Z INFO ] Solution: UUM'UMUM'UMMUMMUU
{"ok":true,"solution":{"algorithm":"DB'DUB'U'BBR'B'U'r'U'rUM'rU'r'U'R'Mr'UrUUr'U'R'U'RFR'URRFU'F'UUM'UMUM'UMMUMMUU","length":55}}
出来上がった手順としては一番最後の algorithm
というのを見てくれれば良くて, 55手順の DB'DUB'U'BBR'B'U'r'U'rUM'rU'r'U'R'Mr'UrUUr'U'R'U'RFR'URRFU'F'UUM'UMUM'UMMUMMUU
がそれ. ただ途中経過で Solution というのが沢山ログ出力されているんだけど, これが各ステップに対応する手順(最終手順はこれらを結合しただけ).
私擬憲法
Stable Diffusion の danbooru でファインチューニングしたもの
Docker 代替
スプラトゥーン3しかやってない. 昨日はガチアサリで S になれた. ガチエリアが苦手であることがわかった.
冷静に面倒くさくなってgithubの二要素認証をやめた.
以下自分用メモ. 詳細は上のリンクを読むこと.
キューブとは8個のコーナーキューブと12個のエッジキューブのこと. キューブは回転操作で移動する. キューブは持ってる色と座標で表現される. 色は六点集合 \([6]\) の部分集合(ただしサイズは 2 または 3 に限る). 座標は \([3]^2\) で表現できる(ただし一部の座標は invalid).
領域とはキューブが存在できる座標の集合のこと ( \([3]^2\) の部分集合). 領域は回転操作で移動シない. キューブ \(c\) が領域 \(Z\) にあることを \(c \in Z\) と書く. これはキューブの持つ座標が集合 \(Z\) に含まれることを言う.
回転操作は座標に関する変換操作のこと. 操作 \(A\) をキューブ \(c\) に適用したものを \(A(c)\) と書く. これは色はそのままで座標だけ \(A\) に従って変換して出来る新しいキューブのこと.
操作 \(A\) に影響を受ける ( \(A\) する前後でキューブが変わる) 領域を \(Ar(A)\) と書く ( \(c \in Ar(A) \iff A(c) \ne c\) ). 2つの重なり \(N = Ar(A) \cap Ar(B)\) . 操作 \(A'\) によって 領域 \(N\) にあったキューブが動いた先の領域を \(NA'\) と書く ( \(c \in NA' \iff A(c) \in N\) ). 同様に \(NB'\) を定める. \(NA'\) を \(A\) すると \(N\) になる.
操作 \([A,B]\) によって影響を受ける領域は3つの和 \(N \cup NA' \cup NB'\) になる. 例えば \(NA' \setminus A \setminus NB'\) は純粋に操作 \(A\) の影響しか受けないので, \([A,B]\) 中の \(A\) で動いて, \(A'\) でもとの場所に戻る.
\(N\) と \(NA'\) と \(NB'\) が独立でいずれも重ならないパターンを考える.
操作 \([A,B]\) をする過程でのキューブ \(c \in NA'\) の行き先を追いかける. \(A\) によって \(A(c) \in N\) . さらに \(B\) を適用して \(AB(c) \in NB\) .
この次にこれに \(A'\) を適用する. \(A'\) で動く領域 \(Ar(A')\) は \(Ar(A)\) と等しい. ここに \(AB(c) \in Ar(A)\) の場合 \(A'\) によって動いてしまうわけだが, どうか. \(NB\) とは \(B\) で動く領域だから \(AB(c) \in Ar(B)\) なのは間違いない. 従って \(AB(c) \in Ar(A)\) であるならば \(AB(c) \in Ar(A) \cap Ar(B) = N\) なのでこれを調べればいい.
\(AB(c)\) とは \(A(c)\) に \(B\) を適用したものだった. もし \(B\) を適用して領域 \(N\) にあるならば, それは \(A(c) \in NB'\) だということに他ならない ( \(NB'\) はそういう定義だった). しかし一方で \(A(c) \in N\) であることもわかってる. これは \(N\) と \(NB'\) が重ならないという始めの前提に反している. というわけで \(AB(c) \not\in N\) ということ.
というわけでキューブ \(AB(c)\) は操作 \(A'\) の影響を受けないので, \(ABA'(c) \in NB\) . 最後に \(B'\) するとこれは素直に \(ABA'B'(c) \in N\) .
他の領域についても同様に追っていけば, \(NA' \to N \to NB' ~ (\to NA')\) という3つの領域に関する交換が行われることが分かる.
特に \(N\) が単集合なら \(NA', NB'\) もそうなので全体として三点交換になる.
というかこれが最強の記事では
死後 碌でもない商売に付き合うのはやめよう
TRIBO で買った. 日曜日に届いて遊んでた.
4x4x4 は最低限度の解く方法が分かって, ソラで解けるようになった. OLLパリティを直す手順をよく間違えて台無しにすることがあってスリリング.
手順メモ:
タイマーは完全に雰囲気づくりでしかない. ちゃんとしたスクランブルをするときは finger timer を表示するのでそこにタイマー機能があるから専用のタイマーは要らない. cstimer.net と連携させたら便利なんだろう. いつか試す.
GAN356 i3. 2022年買ってよかったものベスト3に入る. Bluetooth でインターネット端末とアプリ連携させられる. 普段の解法で各ステップにどのくらい時間を掛けてるか調べる事ができる. オンライン対戦でレーティングバトルが出来る. ずっと遊んでられる.
中身には6つ軸が入っていて, それぞれが90度回ったことを送信してるらしい. このためのセンサー機構がやはり重たく, 回しやすいとは言えない. 単純に全体質量も重たいので, 疲れやすくもある. アプリ連携の為にこれを使うが, それがないならこれを回したいとは思わない. 普通に部屋で練習するときは GAN 12Mを, 外で回すときは静音を期待して Tornado v2 を持って回してる. しかしでも, 部屋で練習するときはついつい i3 を持ってアプリを起動してしまう中毒性がある.
人をルービックキューブ沼に引きずり落とすには, 私なら Tornado v2 を買い与え, 一通り LBL 法で揃えられるようになった頃に i3 を買い与える.
探したけどこれ以上見つからなかった. というわけで暫定ベスト1位です.
生きてる最中にしか死ぬことはできない
ルービックキューブの(というか CFOP Method の)本質は F2L. ここまでを如何に手早くするかでしかタイムは縮まらない. OLL と PLL はデータベースから引き出して実行するだけなので.
でもこのくらいかな. 2022年前半は節制出来てた. 夏中盤くらいから無駄遣いが目に余るようになってきたので気をつけましょう.
これは web API というか web ページなんだけど, 適当なブラウザだと web API から Bluetooth が使えてスマートキューブと連携が出来る. 私の手元の GAN i3 とももちろん連携できる. 公式アプリの Cube Station でも一回のソルブの CFOP の各ステップに掛けた時間が見えたりもするけど, こっちは手を動かさずに見てた時間 (Recoginition) と, 手を動かしてた時間 (Execution) の内訳まで見れる. これは本当良い.
cubeast, スマートキューブだけでなくて GAN タイマーにも Bluetooth 連携して使うことが出来る. 公式ルールと同じ計測が出来る. 細かく「タイマーから手を離してからキューブを回し始めるまでのラグ」「キューブが完成してからタイマーに手をつくまでのラグ」まで出してくれる. もちろん完成したと思ったら即座にキューブは放り投げて両手をタイマーの上に置くのが正しいのだが, 最後のAUFすら今の私には手間取るので, ここのラグが無視できない.
これでオンライン対戦要素とかランキングバトル要素があれば, 公式アプリの Cube Station が要らなくなる
"我们每天为客户和用户节省了 434 年的 handshake time。"
貧乏性なので沢山の回数食べられる8枚切り食パンしか買えない. 食パンN枚切り, N の小ささは豊かさの証.
描けない絵を描いてるときってまだ所詮、既に世にある概念のコピーを作ってるに過ぎなくて全然創作じゃない
今の実力だとこれで十分良くて, どこを縮めるべきか困る.
少し前の夢日記。何かツボに入って笑い転げた。笑おうと思い込んで笑ってるようでもあった。
それより前の夢日記。皮膚科の先生に診察を受けていたらちょうどそのタイミングで蕁麻疹が出てきたのでチャンスだと思ってその左腕を先生に見せた。先生はピンセットでなにやらほじくり返し、ちょうどシラスのような虫が一匹出てきた。
ルービックキューブソルバーを書いてる. CFOP の手順通りに解くソルバーの高速化を図っている. その中でも最後の P
であるところの "PLL" が大変に重たい.
いくつかの種類は \(M\) と \(U\) という2つの基本操作だけで解ける(正確には逆元である \(M'\) と \(U'\) も入れるので4つなんだが, そこはあんまし本質じゃない). 愚直な全探索は, 使える操作の種類 \(n\) と, 長さ \(m\) に関して
\[n^m\]という指数時間が掛かる. \(m\) を減らしたいのはやまやまだが \(n\) を減らすことも大いに意味がある. 今述べたものは \(n=2\) なのでめちゃくちゃ小さい. なのでこれで解ける手順は 5 ミリ秒もあれば長さ 13 の手順を発見できる. これは良い.
MU系以外はかなり複雑だ. それでも目を凝らすと, 頻出するパターンがあることに気が附く. 私でも気が附くくらいなので, とっくに皆に知られており, その証拠に名前がついている. Sexy Move と SledgeHammer だ.
これらはどちらとも基本操作を4つ組み合わせただけだ. これを探索の手順に加えてみた. \(n\) を 2 増やす代わりに \(m\) が減ることを期待する.
やってみると上手く動いた. かなり多くの, というか MU 系の手順以外は全てこの2つをかなり使ってくれた. しかもどうやら U と Sexy Move と SledgeHammer の3つだけで解けてるらしい. 試しに MU 系や他の探索を全て消して本当にこの3つだけで探索させてみた. 結果は上手く行った.
全てのPLLについての解法が以下の通り.
PLL_solution_by_sexymove_and_sledgehammer · GitHub
ここで (Sx)
は RUR'U'
という Sexy Move を表し, (Sx)'
はその逆手順で URU'R'
. (SH)
は Sledgehammer で R'FRF'
. (SH)'
は逆手順 FR'F'R
.
これらを一手とカウントしてるから 13 くらいでなんとか収まってるが, 展開するとアホみたいに長くなるので実際に手で回したくはならないけどね.
PLL 解法, 結局重たいのは手順をハードコーディングしてしまった. 一番手っ取り早く高速化できるんだもん.
というわけで CFOP 解法を追加した.