▍AI Dev Lab
HexCast

HexCast ができるまで — 易経 六十四卦 を三枚銭法で引く

易経のオンライン占いの開発ログ。 三枚銭法を再現して 6 爻を順に出し、 上卦と下卦から六十四卦を特定、 変爻があれば之卦まで計算する流れと、 八卦盤の描き方を記録しています。

HexCast は、中国古典『易経』(周易) の六十四卦を、古典の三枚銭法を再現して引くブラウザ占いです。質問と名前から決定的に爻を立て、本卦・変爻・之卦まで出します。引く処理はすべて端末の中で、入力はサーバーに送りません。

#🎯 「ランダムに 64 個から選ぶ」 では易にならない

最初に決めたのは、64 卦から 1 つを直接ランダムに選ばないということでした。

易は「6 本の爻(こう)を下から順に立て、その積み重ねが卦になる」という構造をしています。結果だけ見れば 64 通りですが、途中に

  • どの爻が陽で、どの爻が陰か
  • どの爻が「変わる爻」(変爻) か

という情報があり、そこから 之卦(しか) ── 変化したあとの卦 ── が決まります。64 個から 1 つ引く実装だと、この変爻と之卦が原理的に作れません。易の読み方の半分が消えます。

なので、爻を 6 回立てる過程そのものを実装しました。

#🪙 三枚銭法をそのまま数値にする

古典的な立て方のひとつが、コインを 3 枚投げるのを 6 回繰り返す方法です。

  • 表 = 3、裏 = 2 として 3 枚の合計を取る
  • 合計は 6・7・8・9 のいずれかになる

この 4 つの数がそのまま爻の種類です。

数名前陰陽変爻か
6老陰陰変わる (→ 陽)
7少陽陽変わらない
8少陰陰変わらない
9老陽陽変わる (→ 陰)

コードにするとそのままです。

ts
for (let i = 0; i < 6; i++) {
  // 3 枚のコイン: 表=3 / 裏=2 を 3 回足す → 6〜9

  let v = 0
  for (let c = 0; c < 3; c++) {
    s = lcgNext(s)
    const heads = s & 1
    v += heads ? 3 : 2
  }
  const yang = v === 7 || v === 9
  const changing = v === 6 || v === 9
  lines.push({ pos: i + 1, value: v, yang, changing })
}

「老いた陰陽は変わる」という考え方が、v === 6 || v === 9 の一行に落ちます。伝統の側にすでにルールがあるので、実装は決めごとを写すだけでした。

なお三枚銭法は、6 と 9 (変爻) の出る確率が 8 と 7 に比べて低くなります。等確率ではないのが元々の性質なので、そこも均さずそのままにしています。

#🎲 同じ問いには同じ答えを返す

乱数を Math.random() にすると、リロードのたびに違う卦が出ます。占いとしては「引き直せてしまう」ので軽くなります。

そこで 質問文と名前から決定的にシードを作りました。

ts
const baseSeed = fnvHash(`${question}@@${salt}`) || 1
let s = baseSeed
// 以降は線形合同法 (LCG) で 1 ビットずつ取り出す

FNV-1a で文字列を 32bit 整数にし、それを線形合同法の初期値にします。これで

  • 同じ問いを同じ人が立てれば、何度開いても同じ卦
  • 問いを一文字変えれば、まったく別の卦

になります。「一度立てた卦を引き直さない」という易の作法が、実装として自然に守られます。サーバーもデータベースも要りません。

#🏗️ 上卦と下卦から 64 卦を引き当てる

6 本の爻が立ったら、下 3 本が下卦(内卦)、上 3 本が上卦(外卦) です。それぞれが八卦のどれかになります。

ts
const lowerLines = [lines[0].yang?1:0, lines[1].yang?1:0, lines[2].yang?1:0]
const upperLines = [lines[3].yang?1:0, lines[4].yang?1:0, lines[5].yang?1:0]
const primary = hexByUpperLower(upper.id, lower.id)

八卦は 3 本 × 陰陽 = 2³ = 8 通りで、これが上下 2 つ組み合わさって 8 × 8 = 64。六十四卦が 64 個ある理由がここにあります。データも「上卦 id と下卦 id」で持たせて、そこから引くようにしました。

八卦は ☰乾(天) ☱兌(沢) ☲離(火) ☳震(雷) ☴巽(風) ☵坎(水) ☶艮(山) ☷坤(地) の 8 つで、それぞれに「健・説・麗・動・入・陥・止・順」という性質が対応します。この属性を表示に出すと、卦名だけ見るより意味が繋がります。

#🔀 変爻から之卦を作る

変爻があれば、その爻だけ陰陽を反転させて、もう一度卦を引き直します。

ts
for (let i = 0; i < 6; i++) {
  if (lines[i].changing) {
    const flip = lines[i].yang ? 0 : 1
    if (i < 3) changedLowerLines[i] = flip
    else changedUpperLines[i - 3] = flip
  }
}

これが 之卦 = 変化したあとの状況です。本卦が「いまの状況」、之卦が「向かう先」という読み方になります。変爻がなければ之卦は作らず、本卦だけで読みます。

#😓 苦労したところ

八卦の記号が環境によって出ない。 ☰☱☲☳☴☵☶☷ は Unicode にありますが、フォントによっては豆腐(□)になります。実機で確認したうえで、記号と一緒に必ず漢字(乾・兌・離…)と読みを併記する構成にしました。記号が出なくても意味が伝わります。

卦辞をどこまで現代語にするか。 原文のままだと読めず、噛み砕きすぎると別物になります。「元亨利貞」のような原文の要約を残しつつ、その下に現代の助言を別行で置く二段構えにしました。原典を消さずに、読める形にするための折衷です。

当たる占いにしない。 易は本来「決断の補助」で、当てものではありません。断定的な吉凶を強めると、読んだ人の判断を歪めます。助言は「〜せよ」ではなく「〜すると良い / 〜は避ける」の温度に揃えました。

#🔭 今後の拡張

  • 筮竹(ぜいちく)による本式の立て方(十八変筮法)の選択
  • 変爻の数による読み分け(1 本 / 2 本 / 3 本以上で読む爻が変わる伝統的な規則)
  • 384 爻すべての爻辞(現在は位と陰陽から 12 通りに簡略化)
  • 立てた卦を端末内に保存して、後から振り返る

#💡 このサービスから言えること

古典を題材にするときは、結果ではなく手続きを実装するほうが良いものになります。 64 卦からランダムに選ぶ実装は 10 行で書けますが、それだと変爻も之卦も作れず、易として読めるものになりません。三枚銭法という手続きを写したから、変爻が自然に出てきました。

もうひとつは、決定的な乱数は「引き直せない」という体験そのものを作れるということ。技術的にはハッシュを 1 つ挟むだけですが、占いとしての手応えがまったく変わりました。

[ ./next_action ]

読んだら、 HexCast を実際に動かす。

この開発ログは HexCast をどう作ったかの記録です。 読み終わったらそのままサービス本体へ戻って、 実物で価値を確かめてください。

[ ./related_logs ]

関連する開発ログ

all logs →
ShadowTwin

立体パズルの別解を作る:同じ影と最少の積み木

ShadowTwinの開発記録。3方向の図から別々の最少配置を2つ探す仕組み、5問の独立全探索、スマホの横並び比較、保存・再編集と入力検査を解説します。実照明の計算や能力診断ではありません。

read log →
SlitCard

スリットアニメーションを作る:4コマの合成と透明原稿の設計

SlitCardの開発記録。4コマの帯を交互に合成し、すき間と黒帯で別のコマを見せる仕組みを解説。同縮尺の台紙・透明シートSVG、50mm確認線、手動プレビュー・初期非表示、再編集と実出力検査を整理します。

read log →
WindowLight

日当たりシミュレーションを作る:窓の光を床へ投影する幾何モデル

WindowLightの開発記録。太陽位置近似から窓の4隅を床へ投影し、凸多角形を部屋で切り取る設計を解説。国立天文台の16時刻との限定照合、大気差・低高度・実際の採光との違い、SVGと設定の再編集を整理します。

read log →
GridLights

電源構成の比較を作る:割合と実量を100個の電球で読み解く

電源構成比較GridLightsの開発記録。12か国の年次発電データを最大剰余法で100個の電球に変換し、割合とTWhを比較する設計を解説。欠損を0補完しない7分類、予想と実値、出典付きSVGと実データ検証を整理します。

read log →
SoundLoom

音のお絵かきを作る:実WAVから絵を測り直す設計

音のお絵かきの開発記録。描画を正弦波のPCMとWAVへ変換し、保存音声の周波数をGoertzel法で測って比較する仕組みを解説。音量・測定窓・量子化の限界と、編集・離脱時の古い結果を抑止する検証を整理します。

read log →
MazeLoom

宝探し迷路を作る:寄り道まで含めた最短ルートの探索

宝探し迷路の開発記録。通路を木として生成し、現在地と3つの宝の取得状態を組み合わせて最短ルートを探す仕組みを解説。問題コードの版固定、画面と解答付きPDFの一致、手数と印刷の検証を整理します。

read log →