factcircuit
FactCircuit는 불변 출처와 단계별 검증, 제한된 검색, 재현 가능한 평가를 제공하는 감사 가능한 주장·증거 검증 루프입니다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
NLHE(テキサスホールデム)の ハンド vs レンジ / レンジ vs レンジ(ヘッズアップ)のオールインエクイティを計算する単一ページのツール。 依存パッケージなし・ビルド成果物は index.html 1枚で、ダブルクリックすればそのまま動く。README 전문 보기 ↗
NLHE(テキサスホールデム)の ハンド vs レンジ / レンジ vs レンジ(ヘッズアップ)のオールインエクイティを計算する単一ページのツール。
保存したレンジとスポットは、公開したサイトでは端末間で自動同期される(Vercel Function + Upstash for Redis、api/sync.js。保存データはアプリ全体で1つ)。
PC の広い画面では、3人のレンジを並べて入力する 3人モード(モンテカルロ)も使える。
依存パッケージなし・ビルド成果物は index.html 1枚で、ダブルクリックすればそのまま動く。
open index.html # これだけ
:0.5 のようにウェイトを付けると部分レンジになる(グリッドで塗るのは常に100%)AA,KK,AKs,AQo:0.5 形式のテキストで入出力できるハンド評価器(src/evaluator.js)はルックアップテーブルを持たない。4つのスート別ランクビットマスクを作り、
その積で「2枚以上」「3枚以上」「4枚」のランク集合を一度に出す:
const p2 = (s0&s1)|(s0&s2)|(s0&s3)|(s1&s2)|(s1&s3)|(s2&s3); // ペア以上
const p3 = (s0&s1&s2)|(s0&s1&s3)|(s0&s2&s3)|(s1&s2&s3); // トリップス以上
const p4 = s0&s1&s2&s3; // クアッズ
ストレート判定と上位5枚の抽出は 8192 エントリの小さなテーブルで引く。7枚の評価は
1コールあたり約 25ns(Apple Silicon / Node 20 で毎秒 3,900万回、npm run bench で計測)。
エクイティ計算(src/rvr.js の computeRangeEquity)はレンジ vs レンジが基本形で、ハンド vs レンジは
ヒーロー側を1コンボのレンジとして同じ関数で解く。どのボード枚数でも誤差のない値を返す:
| ボード | 方式 | フルレンジ同士の所要時間 |
|---|---|---|
| 0枚(プリフロップ) | 事前計算表を引く(全ボード列挙済み) | 約9ms(初回のみ表の展開 約40ms) |
| 3枚(フロップ) | 残り C(49,2) = 1,176 ランナウトを全列挙 | 約0.4秒 |
| 4枚(ターン) | 残り 48 ランナウトを全列挙 | 約16ms |
| 5枚(リバー) | 1回のスイープ | 1ms未満 |
| 0枚 + デッドカード | ボードをサンプリング(モンテカルロ、95%信頼区間つき) | 2,000ボードで約1秒 |
エクイティはチョップを 1/2 として数え、ウェイトつきレンジでは
Σ wA·wB·[結果] / Σ wA·wB(カードが重ならないペアについての和)を返す。ボード・デッドカード・相手のコンボと
ぶつかる組み合わせは数えないので、ブロッカー効果は自動的に効く。計算は Web Worker で走り、UI は止まらない。
フロップ以降は、ペアを総当たりせずにランナウトごとのスイープで数える。
各ランナウトで両レンジの有効コンボを1回ずつ評価して強度順に並べ、相手側の累積ウェイトを
「全体」と「カード52枚ごと」に持ちながら走査する。自コンボ (x,y) が勝てる相手ウェイトは
L − L[x] − L[y]、引き分け以上は E − E[x] − E[y] + E[xy](同一コンボは必ず同じ強度なので、
補正が要るのは「以下」側だけ)。1ランナウトあたり O(n log n) で、フルレンジ同士でもフロップ約0.4秒・
ターン約16ms・リバー1ms未満。あるペア (a,b) と両立するランナウトの数は常に C(D−4,k) で一定なので、
ランナウトごとの率を平均するのではなく分子・分母を合計すれば厳密な同時分布の期待値になる。
ランナウトはシャッフルした順に回すので、計算途中の暫定値も偏りのない推定になる。
プリフロップは表引き。ヘッズアップのプリフロップ対戦 1326×1225 通りは、
スートの入れ替えで同じになるものをまとめると 47,008 クラスしかない。各クラスについて C(48,5) = 1,712,304 ボードを
全列挙した勝ち数・引き分け数を uint32 で持つ src/preflop-table.bin(376KB)を npm run preflop(8コアで約8分)で生成し、
ビルドが base64 で埋め込む。クラスの番号付け(src/preflop.js の pfInit)は生成スクリプトと実行時で同じコードなので、
並び順がずれる余地がない。実行時は初回に 1326×1326 の対応表を展開し(約40ms)、以後はフルレンジ同士でも約9ms。
整数カウントなので完全列挙と丸め誤差の範囲で一致する。デッドカードがあると表の前提が崩れるため、その場合だけ
ボードを丸ごとサンプリングし(1ボードごとに全ペアをスイープ)、比推定量の標準誤差を返す。
「上位n%」の順序(src/rank-order.json)は、169ハンドそれぞれのランダムハンドに対する
オールインエクイティを 1ハンドあたり200万回で実測した順(AA 85.23% 〜 32o 32.27%)。
プレイアビリティ補正は入れていないので、スモールペアは一般的なオープンレンジ表より高く出る。
npm run rank で再現できる(シード固定、同じ結果が出る)。
npm test
STRAIGHT / PACK5 / POPC の 8192 エントリ全件を独立実装と照合。
eval7 が今は引かないエントリ(5ビット未満の PACK5 など)も含めて守るcomputeEquity と 1e-12 で一致、両側の対称性、ウェイトの相対性computeEquity の固定値との一致、
AA vs KK 81.95%・AKs vs QQ 46.05%・AKo vs 22 47.35%・AA vs ランダム 85.20%。
デッドカードありのモンテカルロは全列挙の値が 4σ 以内に入ることsrc/worker.js を同じバイト列で動かし、進捗→結果の順に返すこと、
新しい問い合わせが来たら古い計算が結果を返さずに止まることtest/reference-equity.js)で AKs vs QQ 46.05%、AKo vs QQ 43.24%、AA vs KK 81.95%、88 vs AKo 55.16%、
AA vs ランダム 85.20% ほか、完全列挙の結果を小数第3位まで固定onProgress が 0..1 で単調に進むこと、isStale が実際に打ち切って
{stale:true} を返すこと、モンテカルロが全コンボに同数のボードを配る(層化)こと、
perCombo から総合エクイティを再構成できること、ボード枚数ごとの残り通り数index.html と dist/artifact.html が現在の src/ のバイト列を含むことを検査する。
npm run build を忘れた状態でコミットするとテストが落ちるsrc/
evaluator.js 7枚ハンド評価器、カード/レンジのユーティリティ
preflop.js プリフロップ対戦のスート同型クラスと表の展開(pfInit)
rvr.js computeRangeEquity(rangeA, rangeB, board, dead, opts)
worker.js Worker 内で動いたときのメッセージ処理
preflop-table.bin 47,008 クラスの勝ち数・引き分け数(tools/build-preflop.js が生成)
app.js UI(グリッド、カード選択、ヒートマップ、配色)
app.css スタイル(ライト・ダークテーマ)
app.head.html <title> とフォント
app.body.html マークアップ
rank-order.json 169ハンドのエクイティ順(tools/build-rank.js が生成)
tools/
build.js src/ を index.html と dist/artifact.html に組み立てる
build-rank.js rank-order.json を再計算する
load-engine.js Node から src/ をブラウザと同じスコープで読み込む
build-preflop.js preflop-table.bin を全列挙で生成する(worker_threads)
bench.js 評価器とレンジ vs レンジの速度計測
test/
evaluator.test.js
evaluator-exhaustive.test.js
rvr.test.js
preflop.test.js
worker.test.js
equity.test.js 参照実装 computeEquity のテスト
reference-equity.js 旧ハンド vs レンジエンジン(出荷しない、交差検証用)
build.test.js
index.html スタンドアロン版(生成物)
dist/artifact.html Claude Artifact 用のフラグメント(生成物、doctype/head/body なし)
| コマンド | 内容 |
|---|---|
npm run build | src/ から index.html と dist/artifact.html を生成 |
npm test | 全テスト 55 件(約10秒) |
npm run check | ビルドしてからテスト |
npm run rank | src/rank-order.json を再計算(約40秒) |
npm run bench | 評価器とレンジ vs レンジの速度を計測 |
npm run preflop | src/preflop-table.bin を再生成(約8分) |
src/ のスクリプトはモジュール構文を持たないプレーンなスクリプトで、ブラウザではエンジン部分が
<script id="engine">、UI が後続の <script> に連結され、Node では tools/load-engine.js が同じ順序で同じスコープに読み込む。
テストが叩くバイト列と出荷されるバイト列が常に同一になる。Worker は別ファイルを持たず、app.js が
#engine の中身から Blob URL で起動する(CSP で blob: の Worker が禁じられた環境では、同じコードをメインスレッドで動かす)。
computeMultiEquity(ranges, board, dead, opts)(src/rvr.js)。3人分の互いに素なコンボの組とランナウトを
全部足し上げるのは現実的でないので、モンテカルロで解く。各レンジからウェイトに比例してコンボを1つずつ引き、
カードが重なったら3つとも引き直す(=重ならない組だけに条件付けたウェイトの積。ヘッズアップ版が全列挙で
足しているのと同じ同時分布)。残りのボードを配って、最強のハンドがポットを等分する。既定 100万回で、
各プレイヤーの標準誤差は約0.05%。2人で呼ぶと厳密なヘッズアップ版と一致することをテストで確かめている。
A5s+ / JJ+ / KQs-K9s 形式のレンジ記法パース