Metadata-Version: 2.4
Name: pure-gacha
Version: 0.1.0
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Rust
Classifier: Topic :: Software Development :: Libraries :: Python Modules
License-File: LICENSE-APACHE
License-File: LICENSE-MIT
Summary: 純粋な偶然を与えるガチャアルゴリズム — Rust + PyO3 実装
Keywords: gacha,random,probability,rust,pyo3
Author: Gachal29
License: MIT OR Apache-2.0
Requires-Python: >=3.9
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Homepage, https://github.com/Gachal29/pure-gacha
Project-URL: Issues, https://github.com/Gachal29/pure-gacha/issues
Project-URL: Repository, https://github.com/Gachal29/pure-gacha

# pure-gacha

> **純粋な偶然を与える**

Rust 製の高速なガチャアルゴリズムを Python から使えるライブラリです。

```python
from pure_gacha import Gacha

gacha = Gacha()
gacha.pull(destiny=42)  # → 0.0〜1.0 の float
```

---

## 設計哲学

> 偶然性は **結果が良くて嬉しいのではなく、偶然性によって得られた結果だから嬉しい**。

- **実装者が確率を操作する手段はアーキテクチャ上存在しない**
- **数式構造そのものがプルごとにランダムに組み変わる**
- **品質のばらつきは設計上の意図**（バグではなく仕様）

ゆえに本ライブラリには「レアリティを上げる」「排出率を指定する」といった API は存在しません。実装者に与えられるのは **`destiny`（運命）という整数を 1 つ渡す** ことだけです。

---

## インストール

```bash
pip install pure-gacha
```

- Python 3.9 以降をサポート
- Linux / macOS / Windows の wheel を配布

---

## 使い方

### 基本

```python
from pure_gacha import Gacha

gacha = Gacha()
value: float = gacha.pull(destiny=42)
```

- コンストラクタ `Gacha()` は引数を取らない
- `pull(destiny: int) -> float` に **整数 1 つ** を渡す
- 返り値は `0.0 <= x <= 1.0` の `float`
- 同じ `destiny` でも毎回異なる値が返る（OS エントロピーが混ぜられているため）

### 値の性質

| 性質 | 内容 |
|---|---|
| 範囲 | `0.0 <= x <= 1.0` |
| 分布 | ほぼ一様（1000 回プルで各 0.1 幅のバケットが 70〜130 個に収まる基準） |
| 再現性 | **なし** — 同じ `destiny` でも毎回異なる |
| 並列安全性 | スレッドセーフ（`OsRng` 由来） |

### なぜ `destiny` は整数 1 つなの？

`destiny`（運命）はプルの種になる概念的な整数です。ユーザー ID、タイムスタンプ、イベント ID など、**そのプルを一意に意味づける値**を好きに入れてください。

ただし、`destiny` の値で結果を操作することは**できません**。Stage 1 で OS エントロピー 8 バイトと混ぜてハッシュ化されるため、`destiny` は単にハッシュの種の一部として機能します。

---

## アルゴリズム概要

```
destiny: int（実装者が渡す整数 1 つ）
    │
    ▼
【Stage 1】SHA256(destiny_str + os_entropy_8bytes) → [u8; 32]
    │
    ▼
【Stage 2】h[31] が残り 29 バイトの読み方を決める自己参照的バイト分配
    │
    ▼
【Stage 3】二分木による数式構築・実行
    - 深さ 2〜4 の二分木をハッシュから組み立てる
    - 二項演算子 25 種 + 単項演算子 25 種 = 計 50 種からランダム選択
    │
    ▼
【Stage 4】SHA256(raw + h[0..8]) → u32 / u32::MAX → float (0.0〜1.0)
```

詳細仕様は [AGENTS.md](AGENTS.md) を参照。

---

## ライセンス

未定（OSS として公開予定）。

---
---

# コントリビューター向け

以下はこのリポジトリで開発する方向けの情報です。ライブラリを利用するだけの方は読む必要はありません。

## プロジェクト構成

```
pure-gacha/
├── AGENTS.md              # 実装ガイド（= CLAUDE.md のシンボリックリンク元）
├── README.md              # このファイル
├── LICENSE-MIT / LICENSE-APACHE
├── pyproject.toml         # maturin プロジェクト定義（PyPI パッケージ）
├── Cargo.toml             # Rust workspace 定義
├── Docker/
│   └── Dockerfile         # Rust + Python + maturin の開発イメージ
├── docker-compose.yml     # dev サービス定義（キャッシュボリューム込み）
├── prototype/
│   └── prototype_v1.py    # Python リファレンス実装
├── gacha-core/            # Rust クレート本体
└── gacha-py/              # PyO3 バインディング crate（cdylib）
```

## 開発環境セットアップ

前提: **Docker** / **Docker Compose** が使えること。

### 1. イメージのビルド

```bash
docker compose build
```

### 2. 開発コンテナに入る

```bash
docker compose run --rm dev
```

コンテナ内では次がそのまま使えます。

| ツール | バージョン |
|---|---|
| rustc / cargo | 1.82 |
| Python | 3.11 |
| maturin | 1.13 |
| pytest | 9.x |
| rustfmt / clippy | ✅ |

ホストの `./` が `/workspace` にマウントされ、cargo レジストリと `target/` は名前付きボリュームに分離されているためリビルドは高速です。

### 3. Python プロトタイプの実行

```bash
docker compose run --rm dev python3 prototype/prototype_v1.py
```

### 4. Rust 実装のビルド・テスト

```bash
docker compose run --rm dev cargo test
docker compose run --rm dev bash -lc 'maturin develop && pytest'
```

## 実装上の制約（厳守）

1. **`os.urandom(8)` 相当を必ず使う**（Rust では `OsRng`）。同じ `destiny` でも毎回違う結果が出得る性質を壊さないこと。
2. **非有限値（NaN / Inf）は必ず `default_val` にフォールバック**する。
3. **演算子の順序・インデックスを変えない**。`(byte >> 1) % 25` の対応は固定。
4. **destiny と `struct_bytes[0..4]` を結合して SHA256 に掛けるロジックを変えない**。独自性の核心部分。
5. **演算子をユーザーに選ばせない**。50 種は内部に固定。
6. **公開 API は `Gacha()` / `pull(destiny)` のみ**。むやみに拡張しない。

詳細は [AGENTS.md](AGENTS.md) を参照してください。

## ステータス

- [x] Python プロトタイプ (`prototype/prototype_v1.py`)
- [x] Docker 開発環境
- [x] `gacha-core` Rust クレート
- [x] `gacha-py` PyO3 バインディング
- [x] 分布テスト・Invariant テスト
- [ ] PyPI 公開

