Files
hakorune/src/boxes/random_box.rs
Moe Charm 0bed0c0271 🎉 initial commit: Nyash Programming Language完成版
🚀 主要機能:
• Everything is Box哲学による革新的アーキテクチャ
• WebAssemblyブラウザー対応プレイグラウンド
• アーティスト協同制作デモ - 複数Boxインスタンス実証
• 視覚的デバッグシステム - DebugBox完全統合
• static box Mainパターン - メモリ安全設計

 言語機能:
• NOT/AND/OR/除算演算子完全実装
• ジェネリクス/テンプレートシステム
• 非同期処理(nowait/await)
• try/catchエラーハンドリング
• Canvas統合グラフィックス

🎨 ブラウザー体験:
• 9種類のインタラクティブデモ
• リアルタイムコード実行
• WebCanvas/WebConsole/WebDisplay
• モバイル対応完了

🤖 Built with Claude Code collaboration
Ready for public release!
2025-08-09 15:14:44 +09:00

225 lines
7.8 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*!
* Nyash Random Box - Random number generation
*
* 乱数生成を提供するBox型
* Everything is Box哲学に基づく乱数ライブラリ
*/
use crate::box_trait::{NyashBox, StringBox, IntegerBox, BoolBox, ArrayBox};
use crate::boxes::math_box::FloatBox;
use std::fmt::{Debug, Display};
use std::any::Any;
use std::sync::{Arc, Mutex};
/// 乱数生成を提供するBox
#[derive(Debug, Clone)]
pub struct RandomBox {
// 簡易線形合同法による疑似乱数生成器
seed: Arc<Mutex<u64>>,
id: u64,
}
impl RandomBox {
pub fn new() -> Self {
static mut COUNTER: u64 = 0;
let id = unsafe {
COUNTER += 1;
COUNTER
};
// 現在時刻を種として使用
let seed = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos() as u64;
Self {
seed: Arc::new(Mutex::new(seed)),
id,
}
}
/// 種を設定
pub fn seed(&self, new_seed: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
if let Some(int_box) = new_seed.as_any().downcast_ref::<IntegerBox>() {
*self.seed.lock().unwrap() = int_box.value as u64;
Box::new(StringBox::new("Seed set"))
} else {
Box::new(StringBox::new("Error: seed() requires integer input"))
}
}
/// 次の乱数を生成(線形合同法)
fn next_random(&self) -> u64 {
let mut seed = self.seed.lock().unwrap();
// 線形合同法の定数Numerical Recipes より)
*seed = seed.wrapping_mul(1664525).wrapping_add(1013904223);
*seed
}
/// 0.0-1.0の浮動小数点乱数
pub fn random(&self) -> Box<dyn NyashBox> {
let r = self.next_random();
let normalized = (r as f64) / (u64::MAX as f64);
Box::new(FloatBox::new(normalized))
}
/// 指定範囲の整数乱数
pub fn randInt(&self, min: Box<dyn NyashBox>, max: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
if let (Some(min_int), Some(max_int)) = (
min.as_any().downcast_ref::<IntegerBox>(),
max.as_any().downcast_ref::<IntegerBox>()
) {
if min_int.value > max_int.value {
return Box::new(StringBox::new("Error: min must be <= max"));
}
let range = (max_int.value - min_int.value + 1) as u64;
let r = self.next_random() % range;
Box::new(IntegerBox::new(min_int.value + r as i64))
} else {
Box::new(StringBox::new("Error: randInt() requires two integer inputs"))
}
}
/// true/falseのランダム選択
pub fn randBool(&self) -> Box<dyn NyashBox> {
let r = self.next_random();
Box::new(BoolBox::new(r % 2 == 0))
}
/// 配列からランダム選択
pub fn choice(&self, array: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
if let Some(array_box) = array.as_any().downcast_ref::<ArrayBox>() {
let length = array_box.length().to_string_box().value.parse::<i64>().unwrap_or(0);
if length == 0 {
return Box::new(StringBox::new("Error: cannot choose from empty array"));
}
let index = self.next_random() % (length as u64);
match array_box.get(index as usize) {
Some(element) => element,
None => Box::new(StringBox::new("Error: index out of bounds")),
}
} else {
Box::new(StringBox::new("Error: choice() requires array input"))
}
}
/// 配列をシャッフル
pub fn shuffle(&self, array: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
if let Some(array_box) = array.as_any().downcast_ref::<ArrayBox>() {
let length = array_box.length().to_string_box().value.parse::<i64>().unwrap_or(0);
if length <= 1 {
return array;
}
// 新しい配列を作成
let shuffled = ArrayBox::new();
// 元の配列の要素を全て新しい配列にコピー
for i in 0..length {
if let Some(element) = array_box.get(i as usize) {
shuffled.push(element);
}
}
// 簡易シャッフル実装完全なFisher-Yatesは複雑なので
// 代わりに、元の配列からランダムに選んで新しい配列を作る
let result = ArrayBox::new();
let mut remaining_indices: Vec<usize> = (0..length as usize).collect();
while !remaining_indices.is_empty() {
let random_idx = (self.next_random() % remaining_indices.len() as u64) as usize;
let actual_idx = remaining_indices.remove(random_idx);
if let Some(element) = array_box.get(actual_idx) {
result.push(element);
}
}
Box::new(result)
} else {
Box::new(StringBox::new("Error: shuffle() requires array input"))
}
}
/// ランダムな文字列生成
pub fn randString(&self, length: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
if let Some(len_int) = length.as_any().downcast_ref::<IntegerBox>() {
if len_int.value < 0 {
return Box::new(StringBox::new("Error: length must be positive"));
}
let chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
let char_vec: Vec<char> = chars.chars().collect();
let mut result = String::new();
for _ in 0..len_int.value {
let index = self.next_random() % (char_vec.len() as u64);
result.push(char_vec[index as usize]);
}
Box::new(StringBox::new(&result))
} else {
Box::new(StringBox::new("Error: randString() requires integer length"))
}
}
/// 指定確率でtrue
pub fn probability(&self, prob: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
if let Some(float_box) = prob.as_any().downcast_ref::<FloatBox>() {
if float_box.value < 0.0 || float_box.value > 1.0 {
return Box::new(StringBox::new("Error: probability must be 0.0-1.0"));
}
let r = self.next_random() as f64 / u64::MAX as f64;
Box::new(BoolBox::new(r < float_box.value))
} else if let Some(int_box) = prob.as_any().downcast_ref::<IntegerBox>() {
let prob_val = int_box.value as f64;
if prob_val < 0.0 || prob_val > 1.0 {
return Box::new(StringBox::new("Error: probability must be 0.0-1.0"));
}
let r = self.next_random() as f64 / u64::MAX as f64;
Box::new(BoolBox::new(r < prob_val))
} else {
Box::new(StringBox::new("Error: probability() requires numeric input"))
}
}
}
impl NyashBox for RandomBox {
fn type_name(&self) -> &'static str {
"RandomBox"
}
fn to_string_box(&self) -> StringBox {
StringBox::new("RandomBox()")
}
fn clone_box(&self) -> Box<dyn NyashBox> {
Box::new(self.clone())
}
fn equals(&self, other: &dyn NyashBox) -> BoolBox {
if let Some(other_random) = other.as_any().downcast_ref::<RandomBox>() {
BoolBox::new(self.id == other_random.id)
} else {
BoolBox::new(false)
}
}
fn as_any(&self) -> &dyn Any {
self
}
fn box_id(&self) -> u64 {
self.id
}
}
impl Display for RandomBox {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "RandomBox()")
}
}