セーブポイント

特にジャンルの決まってない雑記です。

WSL containersを使ってWindowsで簡単にllama.cppを実行する方法【WSL 3.0/脱Docker】

9月末に「WSL 3.0」がリリースされ「コンテナー」機能の一般提供が開始されたことで、Dockerを利用せずにWindowsでコンテナを利用できるようになりました。(しかもコマンドはDockerに近い)

今回はこのWSLコンテナーを使って、llama.cppを実行してみます。CUDA対応のGPUを持っている人向けの解説です。

llama.app

前準備

WSLを最新バージョンへアップデートします。Powershell等で以下を実行するだけです。

wsl --update

自分の環境では、アップデート後以下のようになりました。WSL バージョンが3.0.1.0になっていれば問題ないと思います。

> wsl --version
WSL バージョン: 3.0.1.0
カーネル バージョン: 6.18.40.1-1
WSLg バージョン: 1.0.79
MSRDC バージョン: 1.2.7214
Direct3D バージョン: 1.611.1-81528511
DXCore バージョン: 10.0.26100.1-240331-1435.ge-release
Windows バージョン: 10.0.26200.9457

続けて、wslcが利用できることを確認します。

wslc version

コマンドの実行結果として、wslc 3.0.1.0のような出力が得られたらokです。

より実際の挙動を試したいなら、hello-worldを実行するとよいです。

wslc run --rm hello-world

GPUが利用できることを確認する

まずWindows側でnvidia-smiが正常に実行できることを確認しておきます。

そのあと、以下を実行することでWSL containersからGPUを利用できるか確認できます。

wslc run --rm --gpus all nvidia/cuda:12.8.1-base-ubuntu24.04 nvidia-smi

wslcでpullしたimageなどの保存先を変更する

標準の状態ではCドライブの%LOCALAPPDATA%\wslc\sessions\wslc-cli-{ユーザー名}\storage.vhdxという場所にデータが保存されていくので、Cドライブの容量を圧迫したくない場合などはサイズの大きなimageをpullする前にストレージの配置場所を変えた方がよいです。

%LOCALAPPDATA%\wslc\settings.yamlを作成して、以下のようにsession.storagePathという項目の値を変更できます。

session:
  storagePath: D:\wsl

設定を変更した後は、wsl --shutdownを実行したあと、さらにRestart-Service -Name WSLServiceでサービスを再起動する必要があります(管理者権限が必要です)。shutdownだけだと設定の変更が反映されません。

llama.cpp公式イメージを実行する

以降、gguf形式のモデルをC:\llm\modelsというディレクトリに置いていると仮定します。自分がモデルを保存しているディレクトリに読み替えてください。

llama.cpp公式では現在、ghcr.io/ggml-org/llama.cpp:server-cudaというCUDA 12対応イメージが配布されています。今回はこれを使用します。

他にも、

server
server-cuda
server-cuda13
full
full-cuda
light
light-cuda

などが配布されています。自分はRTX 3070を使用していますが、より新しいGPUを使っている場合、server-cuda13が必要なケースがあるかもしれません。

あとは以下のコマンドを実行するだけで、推論用のサーバーが立ち上がります。このコマンド例はPowershell用です。

wslc run `
  --name llama `
  --gpus all `
  -p 8080:8080 `
  -v "C:\llm\models:/models" `
  ghcr.io/ggml-org/llama.cpp:server-cuda `
  -m /models/gemma-4-E2B-it-Q4_K_M.gguf `
  --host 0.0.0.0 `
  --port 8080 `
  -ngl 99 `
  -c 16384

コンテナーに公開するGPUを変えたり、コンテキスト長を変えたりしたい場合は引数を編集してください。

llama.cppのサーバーはWeb UIを内蔵しており、http://localhost:8080からアクセスできます。Webのチャット画面を利用するためだけに他のツールを持ってこなくていいので便利です。

llama.cppのWeb UI

自分の環境では、Gemma 4 E2B (Q4_K_M)の回答の生成スピードが87.25 t/sでした。

Gemma 4 E2B (Q4_K_M)の回答例

ローカルならやはり試したいのは無検閲モデルです。今回はGemma-4-E4B-Uncensored-HauhauCS-AggressiveのQ4_K_M版を試してみました。このモデルでも回答の生成スピードは49 t/s程度出ていて、日本語の自然さも十分かなあと感じました。

Gemma 4 E4B改造版の回答例(悪用厳禁)

API経由でモデルを利用する

llama.cppのサーバーはOpenAI互換APIを提供しており、対応しているアプリで以下のURLを指定することでローカルのモデルを外部から利用できます。

http://localhost:8080/v1

コンテナ管理のコマンドチートシート

コンテナの停止:

wslc container stop llama

コンテナの一覧:

wslc container list

コンテナの一覧(停止済みも含む):

wslc container list --all

ログ:

wslc container logs llama

イメージの一覧:

wslc image list

不要な停止済みコンテナを削除:

wslc container prune

不要なイメージを削除:

wslc image prune

本当にオススメできるコーディングエージェント向けskills

筆者はCodexユーザーです。

前提

新しくモデルがリリースされたときなどは、導入しているskillsが本当に必要なのか見直した方がよい。

昔のモデルではわざわざスキルとして詳細に教えないとできなかったことが、最新モデルではプロンプトでちょっと指示するだけでできるようになってるとかは全然ありえる。

セキュリティ的な面でも、人が作ったskillsをどんどん入れていくんじゃなくて本当に標準機能だけでできないのか考えたほうがいいかも。

推薦

grilling

www.skills.sh

実装に入る前に、「自分は本当は何を作りたいのか?」を詰めてくれる。思考の整理に使える。

Codexのプランモードとかよりもさらに前段階で使うskill。grillingで作るものの仕様を確定させたら、プランへ。

frontend-design

www.skills.sh

GPT-5.6 Sol使ってて、最新のモデルでもUIデザインはまだ下手なのかとずっと思ってたけど、これを使ってちょっと考えが変わった。

カラフルすぎとか、フォント細かく変えすぎとか、そういう最近のモデル特有の過剰装飾をいい感じに取り除いてくれる。

これだけで良いとは言わないけど、かなりマシな美的センスを与えてくれると思う。

日本語を書く

前までjapanese-tech-writingを導入していたが、やめた。効果があるのか正直よく分からなかったので。別にこのskillを使って生成されたドキュメントを読んでも全く自然とは感じなかった。

今だったらskillとかでなんとかするより、Gemini 3.8 FlashとかGemmaにライティングをやらせた方が良いと思う。適材適所。

どんなSNSの動画でも簡単に保存する方法【X・Instagram対応】

最近cobaltという便利なサイトを知ったので紹介します。

cobalt.tools

cobaltのトップ画面

使い方は簡単で、paste the link hereと書かれている入力欄にXのポストのURLなどを入れるだけです。

Xのリンクの例

あとは「>>」ボタンを押すとメディアをダウンロードできます。

サイト内のsupported servicesを見ると、XやInstagramの他にもブルスカ、Facebook、reddit、Soundcloudなどにも対応しているようです。

余談ですが、こういうウェブサイトを利用せずにローカルのツールで動画を保存したい人は、gallery-dlやyt-dlpを使うとよいです。

イラストから正方形のサムネイルを自動生成

イラスト調の画像から、(リッチなAIなどは使わずに)自動で切り抜き範囲を推定してサムネイルっぽいものを生成する方法の解説です。

これは以前にブログでも紹介したイラスト管理アプリに最近実装した機能です。以前は新規の投稿を登録したときに先頭の画像をそのままサムネイルとして一覧ページで表示していましたが、解像度の高い画像が多いのに表示するサイズは小さいため画像の読み込みで毎回無駄なリソースを使っている気がしたので、200x200サイズの画像を事前に生成してそれをサムネイルとして使うように仕様変更しました。

new-file.hatenablog.com

現行の仕様

プレビュー用の小さい画像を生成しておくというのは、画像をたくさん表示するギャラリーのようなWebサイトでよくとられる手法ですね。pixivとか。

表示するサイズは小さいのに毎回原寸大のデータを取りに行ってたら通信量もすごいことになるので、Webサイト運営をやるならほぼ対応必須の項目です。ただ、こういうケースではわざわざ自分で実装するよりCloudflare Imagesなどを利用した方が長期的にサービスを運営していく上で楽できるように思います。

自分の場合はデスクトップアプリだったので、自作で簡易的なサムネイル生成システムを実装してみました。この記事で紹介するサンプルコードは以下のリポジトリに置いてあります。

github.com

1. 顔認識でサムネ生成

どうやって機械的にサムネイル画像となる領域を決定するかですが、まず最初に思いつくのが顔認識です。キャラクターの顔が含まれる領域を選択すれば、それっぽいものができそうな感じがします。

顔認識をするとなると結構難しそうに聞こえるかもしれませんが、意外と簡単にできます。今回使うのは、OpenCVの物体検出の機能です。

これはCascade Classifierという機械学習ベースの手法ではあるのですが、非常に軽量で高速に動作します。分類器は以下の方が公開してくれているlbpcascade_animeface.xmlというやつを使います。GitHubのリポジトリからダウンロードしておいてください。

ultraist.hatenablog.com

github.com

自分の実装したシステムでは、thumbnail_generator.pyのget_center_point内で使用されています。イラスト内に顔が複数含まれる場合、最も領域の大きいものの中心をサムネイルの中心座標として採用します。

def get_center_point(image_path: str, use_smartcrop=True):
  # 1. 顔検出
  np_array = np.fromfile(image_path, np.uint8)
  image_cv = cv2.imdecode(np_array, cv2.IMREAD_COLOR)
  gray = cv2.cvtColor(image_cv, cv2.COLOR_BGR2GRAY)

  cascade = cv2.CascadeClassifier(CASCADE_MODEL_PATH)
  faces = cascade.detectMultiScale(
    gray, scaleFactor=1.1, minNeighbors=5, minSize=(24, 24)
  )

  print(f"{len(faces)} face(s) detected")
  if len(faces) > 0:
    # 最も大きい顔を選択
    # 顔の座標: (x, y, w, h)
    x, y, w, h = max(faces, key=lambda f: f[2] * f[3])
    return (x + w // 2, y + h // 2)

この手法で例としていくつかサムネイルを自動生成してみました。左が元画像、右が生成されたサムネイルです。サムネが黒い画像となっているものは、顔が検出できなかった例です。

https://hateblo.mgcup.net/images/2026/03/result_summary_cascade.png

結果を見てもらえば分かる通り、以外とこの手法うまくいきません。元々正面顔でないとあまりうまくいかないらしいのですが、顔が正面を向いていてもちょっと周りに障害物があると検出できなかったり、そもそも横を向いていたりするとだめです。

モデルが結構古いため、最近のイラストだとうまくいってない気がします。明確に顔が描かれているイラストには有効ですが、もっと別のアプローチを考えたほうが良さそうです。

追記:顔検出をもっと頑張りたい場合

以下のyolov8_animefaceを使うとより高精度に顔認識ができそうです。10000件のイラストでトレーニングされたYOLOv8モデルが公開されています。

github.com

2. 画像の特徴を使う

顔を使ったサムネ生成をやってみましたが、顔を目印にするとキャラクターが後ろを向いているイラストやそもそもキャラクターが描かれていない風景画などに対応できません。

「もっと画像の色の情報などを活用できないだろうか?」と思っていたところ、以下のsmartcrop.pyというライブラリを見つけました。

github.com

もともとsmartcrop.jsというライブラリがあり、それをPython環境に移植したものです。

どのようなアルゴリズムで領域を決定しているのだろうと気になりましたが、READMEによると以下のような手続きになっているようです。古典的な手法のみで画像の切り抜きが実現されています。

  1. ラプラシアンフィルタによるエッジ検出
  2. 人の肌のような色を持つ領域を検出
  3. 色の彩度の高い領域を検出
  4. オプションで指定された領域の重みを強くする(顔検出など)
  5. 指定されたアスペクト比で、切り抜く領域の候補を大量に生成
  6. 評価関数で候補をランク付けする(中央付近にあるかどうか、画像の端付近を避ける)
  7. 最もスコアの良かった候補を出力

この手法の良いところは、どのような画像を入力しても必ず候補となる領域が得られるところです。顔が検出できなかった場合のような例外処理をしなくてよくなります。

今回自分が実装したものではOpenCVが顔を検出できなかった場合のフォールバックとしてsmartcropを使っていますが、このライブラリだけ使う実装にしても実用に耐えるかと思います。

ただ、古典的な手法だけ使っているとはいえ、入力画像が高解像度になると先程の手法よりもちょっとだけ重いです。

1.の手法のテストで使用した画像と同じものでテストしてみました。

https://hateblo.mgcup.net/images/2026/03/result_summary_sc.png

先ほどはうまくサムネイル画像が生成できなかった例でも、それらしい領域が切り抜けています。

extra. 人の手で調整する

smartcropでかなり高い品質でサムネイル画像が自動生成できましたが、しばしば「ちょっと切り抜く範囲を調整したい」と思うときもあります。

こういう場合でも対応できるように、GUIで切り抜き範囲を確認・修正できるようにしました。

thumbnail_generator.pyを実行して顔認識→smartcropによる領域の推定が終わると、以下のようなGUIが立ち上がります。

切り抜き位置の調整画面

最初に表示されているのはOpenCVかsmartcropが提案した切り抜き位置であり、位置を変えたければ黄色の枠をドラッグして移動することで切り抜かれる範囲を手動で修正できます。

修正する必要が無いと思った場合は「キャンセル」を押すことで表示されている範囲でそのまま切り抜きが行われます。

GUIはPySide6で作りました。作りましたというか、Geminiに書いてもらいました。

本当に数分くらいで作ったものなので、よしなに調理していただければと思います。

イラストのデータだけから出典・イラストレーターを探す方法

少し前にpixivの削除されたブックマーク作品を復元する方法の記事を書きました。

new-file.hatenablog.com

今回はこれとは逆で、イラストのデータだけ持っているときにその出典を逆引きする方法について解説します。

こういうケースはあまり多くはないと思うんですが、昔保存した画像とかでたまーにあるので。

イラスト向けの画像検索サービス

「Google画像検索で探したら見つかった」というのであればそれでいいんですが、Google画像検索は結構広くヒットしてしまうので、ここではイラストに特化した画像検索サービスを紹介します。

1つ目はsaucenao.comです。pixivをはじめ有名どころのWebサイトを横断して検索できるサービスで、画像のソースのリンクとアーティストのリンクも提供されています。

トップページで画像のURLを入力するか手元の画像をアップロードして、検索するだけで使えます。

SauceNAOで検索した結果

ほとんどのケースがこのサイトだけで完結する気がします。DBのリストを見る限り漫画とかにも対応してそうです。

似たような機能を持つ他のサイトとして、二次元画像詳細検索があります。

検索のモードとして「色合検索」と「特徴検索」があるようです。詳細は説明ページへ。デフォルトは色合検索のようですが、特徴検索だとトリミングされた画像から元の画像を検索できるようです。

この2つのサイトで思ったような結果が得られなかったら最後の手段としてGoogle画像検索を使ってみる、といった流れで良い感じがします。

RTL-SDR Blog V4で航空管制(ATIS)を受信しよう

大学の講義でソフトウェア無線(SDR)を勉強する機会があり、面白かったので記事にします。

今回使ったのは、RTL-SDR Blog V4というPCにUSB接続して使うドングルです。

RTL-SDR Blog V4

実際に使うときは金色の部分にさらにアンテナを接続して使います。

ちなみに、アンテナセットで購入すると日本円で1万円弱くらいするみたいです。

「そもそもSDRって何?」というところですが、ハードウェアには電波を受信する最低限の機能だけ載せて、ソフトウェア側で信号処理することで色んな周波数のデータを受信できる、というものみたいです。ソフトを書き換えれば1つのハードを色んな役割に使い回せるわけですね。

GNU Radioのセットアップ

今回ATISの受信システムの実装にはGNU Radioを使います。Windows環境でGNU Radioを利用したい場合、radiocondaが便利です。

github.com

radioconda-installerのREADMEを少し下にスクロールすると以下の画像のようなところがあるので、自分の環境に応じたインストーラーをダウンロードしてください。

メジャーな環境向けのインストーラーが用意されている

また、Windowsでradiocondaを使う場合、別途ZadigでWinUSBドライバをインストールしておいてください。詳細は → こちら。

航空交通管制(航空管制)について

さっそく実装、といきたいところですが、今回扱っている対象である航空交通管制について簡単に概要を説明しておきます。

ja.wikipedia.org

いや、まあWikipediaでいいんですけど。大事なのは、以下の点です。

航空交通管制に使用される無線電話における電波の変調方式は、全世界で振幅変調が用いられている。

つまり、周波数が分かればAMラジオと同じ感覚で音声を聴くことができる、というわけです。ただし、傍受は合法ですが傍受した通信の内容を一般に公開することは法律で禁止されています。

その航空管制の業務の中に、ATIS(飛行場情報放送業務)と呼ばれるサービスがあります。

ja.wikipedia.org

空港に離着陸する航空機に対して、地上から音声による通信で離着陸に必要な気象情報、飛行場の状態などを提供するものです。

ATISは断続的に音声が流れるという点と、特に規模の大きい空港では24時間放送が実施されていて受信のテストがしやすいという2つの利点があり、今回はATISの音声を受信するシステムを実装してみることにしました。

ATIS受信システムを実装する

GNU Radio Companionを使ってシステムを実装します。

どの空港を対象にするかの話をしてませんでしたが、今回は羽田空港のATIS(128.8MHz)を受信できるようにシステムを作っていきます。ATISの受信は空港からの物理的な距離の制約をかなり受けるので、それぞれ住んでいるところから一番近い、かつATISを実施している空港を対象にすると良いと思います。周波数の設定の部分だけ読み替えれば同じように実装できるはずです。

日本のATIS実施空港等

今回組んだシステムは、以下のような感じです。

RJTT ATIS Receiver

AMラジオを受信するシステムを実装したことがある人が見たら、「見たことあるな」と感じると思います。

以下で簡単に解説をしていきます。

まず、Soapy RTLSDR Sourceでデータストリームを受信します。このとき、Center Freqは128.8MHzではなく128MHzに設定して、このあとのフィルタで周波数をシフトさせています。これは「Center Freqを直接合わせるとDCスパイクが信号に被ってしまう」みたいな話をGeminiから聞いたのでこうしたのですが……ソースの中心周波数を128.8MHzにしてその後ローパスフィルタに通すシンプルな構成と聴き比べたとき、正直そんなに違いが分からなかったです。差はあるのかもしれないですが、今回の実験ではSNRが結構悪く、違いがそんなに分からなかったということなのかもしれません。

後で実験するときにRF Gainをその場で調節できるように、GUIで操作できる変数(rf_gain)を設定しています。

次に、周波数を128.8MHzに合わせるためにFrequency Xlating FIR Filterを使います。このノードで周波数シフトとデータの間引き(デシメーション)をまとめてやってしまいます。Center Freqを800kに設定して、Tapsにはfirdes.low_pass(1, 2.4M, 10k, 5k)を設定しています。ローパスフィルタのパラメータのうち、第3引数(cutoff_freq)と第4引数(transition_width)は調整の余地がありそうです。

low_passのリファレンス

そのあとはRational Resamplerでもう一回データを間引いて周波数を48kHzに合わせて、Complex to Magで信号を復調します。

最後に後処理としてDC Blockerで直流成分を除去して、システムとしては完成です。ただし、等倍だと再生される音声の音量がかなり小さかったので、Multiply Constで雑に音量を上げています。

実験するときの注意点

ATIS受信システムを実装できたので実際に動かしていきたいところですが、先程も少し触れた通り実験する環境にかなり制約があります。

まず、このシステムを家の中で動かしてみてもホワイトノイズしか出力されないと思います。空港からめちゃくちゃ家が近い方だといけるのかな?自分の場合は羽田空港からそこそこ距離があるので、まったく意味のあるデータを受信できませんでした。あまりにノイズしか出てこないので、最初は「実装を間違えてるのでは?」と思ったくらいです。

自分のケースでは家の窓際にアンテナを設置してそこで実験してみたところ、かなりノイズが乗っているもののギリギリ聞き取れるくらいの品質でATISの音声が受信できました。あまりに窓際すぎて外が映るので写真を撮っていないし、受信した結果の音声も共有できないので伝わりにくいと思いますが……。

RF Gainを動かしたりシステム内のパラメータをちょっと変えてみたりして音質の改善を狙うこともできるとは思いますが、物理的な空港との距離・方角とか、アンテナの設置の仕方とかそういう部分を改善するほうが優先度高いな、と感じました。

普段はソフトウェア開発ばかりでレイヤー高めのことばかりしているので、こういったハードウェアで遊ぶのが結構楽しかったです。RTL-SDR Blog V4ですが、他にもADS-Bの信号を受信できたりします。結構面白くてハマる人もいるよなあと思いました。ちょっと受信用のキットがお高めではありますが、趣味としてやってみるのもいいんじゃないでしょうか?

【Minecraft】Cubiomes Viewerで変なseed値を探してみよう

久しぶりにMinecraftの記事を書きます。

マイクラをやったことのある人、Chunk BaseというサイトのSeed Mapというアプリ使ったことありますよね?ワールドのseed値を入れると村の位置とかスライムチャンクの位置とかを出してくれるやつです。

www.chunkbase.com

MineAtlas使ってたっていうあなたは、Minecraft老人です。おめでとうございます。

今回はSeed Mapのような機能を持ちつつ、しかも欲しいワールドの検索機能がついたCubiomes Viewerというツールを紹介します。

ダウンロード

github.com

GitHub上で公開されています。

GitHubリポジトリのトップ

右側に「Releases」という項目があるかと思うので、そこの「cubiomes-viewer x.y.z」というのをクリックしてください。2026年1月時点では4.1.2が最新版のようです。(しばらく更新されてないみたいですが、そもそもマイクラ側が1.21の期間長すぎね)

cubiomes-viewer 4.1.2のリリース

色々ダウンロードできるものがありますが、Windowsを使っている人は末尾に「-static-w64.exe」とついているやつをダウンロードしてください。

Cubiomes Viewerの初期設定

ダウンロードしたexeファイルをダブルクリックすればそのまま起動できます。インストール等は不要です。

起動すると以下のような画面になると思います。

Cubiomes Viewerを起動した画面

最初はライトテーマになっているかと思いますが、自分の画面ではダークテーマに変えています。

ダークテーマに変えたい場合、画面左上メニューの「Edit」>「Edit preferences…」から設定を開いて「GUI Style」という項目を「Dark」に変更してください。


最初起動したままの状態だと画面右のマップにはバイオームの分布しか表示されていないかと思いますが、画面の右端に並んでいるアイコンをクリックすると構造物の位置を表示できます。

スポーン地点と村を表示した状態

また最初の状態では地形の高低差が分からないので、画面左上メニューから「Layer」>「Display Options…」を開いて「Approx. surface height」という項目を「Shaded biome map」に変更すると、上の画像のような状態になります。

Layer Display Options

Cubiomes Viewerを使ってみる

ツールを使って特定の条件を満たすseed値を探してみます。まず、スポーン地点に村があるワールドを探してみます。

Cubiomes Viewerの画面左側にConditionsと書かれたスペースがあるかと思いますが、ここにseed値の検索条件を登録していきます。

Addを押すと条件の設定画面が出てくるので、Condition TypeからOtherを選び、その隣の欄で「Spawn」を設定します。下のLocationの部分は変更せずにOKを押してください。

Spawnの条件を設定する例

これで、初期スポーン地点に(0,0)が含まれるという条件を設定できました。

次にもう一回Addを押して、Condition TypeをStructures、隣の欄でVillageを選びます。これも下のLocationの部分は変更せずにOKを押してください。

以下の画像のように、検索条件が2個設定されていることを確認してください。

初期スポーン地点と村の条件を設定した状態

検索条件が設定できたら、左下にある「Start search」ボタンを押すことで検索が始まります!
今説明したのと同じ条件で検索している場合、おそらく一瞬で以下のような結果が出ると思います。検索結果の行をクリックするとそのseedのマップが画面右側で開きます。

検索結果

どうやら3455というseedではワールドの(0,0)地点に村があるようです。実際にゲーム上で確認してみましょう!

seed=3455 (1.21.11で生成)

村発見

ということで、簡単にseed値の検索ができました。

似たような例で、初期スポーン地点が特定のバイオームであるようなseed値も検索できます。例えば、桜バイオームにスポーンするようなワールドを探してみます。

検索条件から村の条件を選択してから「Remove」を押すことで削除することができます。代わりに、「Add」を押して別の条件を追加します。

バイオーム条件の追加の例

上の画像のように、Condition typeを「Biomes」にし、その隣の欄には「Overworld at scale」を設定します。下に「Biomes」という項目があるので、この中から「Cherry Grove」を選択します。バイオームを選択するのを忘れないように。

この条件で検索すると、447というseedが見つかりました。これもゲーム上で確認してみます。

seed=447 (1.21.11で生成)

ちゃんと条件に合ったワールドになっています。

Sister seedsについて

先ほどスポーン地点に村がある例として3455というseed値を見つけましたが、実はこの情報から281474976714111も同じ条件を満たす可能性があることがすぐに分かります。

seed=281474976714111

Minecraftではseed値は符号付き64bit整数です。なので、生成されるワールドのパターンは 2^{64}=18446744073709551616 (約1840京)通り存在します。

これは正しいのですが、実は構造物の生成に関わるのはこのseed値のうち下位48bitだけです*1。すなわち、seed値の上位16bitがどのような値であろうと、下位48bitが同じならば同じ位置に構造物が生成されます。

このように下位48bitが同じseed値のことをSister seed(あるいはShadow seed)と呼ぶらしいです。3455は16進数に直すと0000 0000 0000 0d7fで、281474976714111は0001 0000 0000 0d7fなのでこの関係にあります。

ちなみに、構造物の生成時にseedの下位48bitだけが使われるのはjava.util.Randomの仕様のせいのようです。Javaの標準ライブラリであるRandomは64bitのseedを受け取りますが、実際に使用されるのは下位の48bitだけで、上位16bitは捨てられてしまうという仕様になっています。

構造物はseedの下位48bitだけ参照されるのに地形とバイオームはそうじゃないのはなぜ?という別の疑問が湧きますが、地形とバイオームの生成に関しては1.18 (Caves & Cliffs: Part II)以降はjava.util.Randomに依存しないアルゴリズムに変更されているとか*2。それより古いバージョンでは、構造物の生成と同じように地形生成でも下位48bitが同じだと似ているみたいな問題があったようです。

さらに余談ですが、最近のMinecraftではJava版でもBedrock版でもseed値が同じならエディションを跨いで同じ地形とバイオームが生成されるみたいです。そこまで同じになってるんですねー。

特に、32bitの範囲に収まる範囲のseed値であれば構造物の位置も含めてかなり似ているワールドになるとか?

珍しいseed値を探してみる

とりあえずCubiomes Viewerを使ってseed値の検索ができるようになったので、ちょっと複雑な例もやってみましょう。

村の近くに森の洋館がある、みたいなワールドを探してみます。

村の検索設定

1つ目の条件として村の検索の設定をします。Locationの部分を上の画像のように設定すると、「ワールドの原点を中心とした128x128の範囲に村がある」という条件になります。

森の洋館の検索設定

続けて森の洋館の条件を追加します。村の近くという条件にしたいので、1つ目の条件で見つけた村を基準に範囲を相対指定します。「Location is relative to」をワールド原点ではなく村に設定して、適当な範囲を設定します。

この条件で検索をかけると、以下のようになりました。検索ボタンの上にある「Stop on results」のチェックを外して検索をすると、複数件探すことができます。

村と森の洋館が近くにあるseedの検索結果

結果をいくつか見てこれが良さそうかなと思ったのでゲーム上で確認してみます。

seed=65100738

この設定だとちょっと洋館が遠い?気がしますね。

森の洋館の探索範囲を「村を中心に192x192」にちょっとだけ狭めてみます。条件を厳しくすると、当然それだけ検索に時間がかかるようになります。

seed=244822728

ちょっと近くなりました。村からすぐ行けて便利ですね。


あと最後に、孤島にある村とか探してみます。直接的に「島にある」みたいな条件は用意されていないのですが、村の東西南北が海系のバイオームであるという条件で検索します。

まず村の条件を追加したあとに、以下の画像のようにバイオーム条件を設定します。

「X=150が海系バイオームである」の設定

LocationのCustomに座標を指定して、下のBiomesの欄でOcean系のバイオームにチェックを入れます。ここで、いずれかのバイオームであればいいので「Match any」にチェックを入れておいてください。

あとはこれを真似して「X=150が海」「X=-150が海」「Z=150が海」「Z=-150が海」という4つの条件を設定してください。正しく設定できていれば、以下の画像のようになっていると思います。

「孤島に村がある」の設定例

あとは検索するだけなのですが、今回は画面左下の「Search」という項目を「48-bit family blocks」に設定して検索してみます。これは、先程説明した構造物の位置は下位48bitだけで決まるという仕様を利用して、逆に上位16bitを変えることでバイオームだけ変えて検索を効率化するという手法です。

「孤島に村がある」の検索結果

以下は見つけたseedです。

seed=5232056867097674387

砂漠の村、周りに木が全然なくてすごい↓

seed=-3730106391369611584

なんかまだ面白いことできそうなので、ある程度まとまったらパート2書きます。

参考にした動画

www.youtube.com

*1:統合版では下位32bit

*2:おそらくxoroshiro128++?