diff options
| author | 2025-09-12 04:02:02 +0800 | |
|---|---|---|
| committer | 2025-09-12 04:02:02 +0800 | |
| commit | 0288d0956330d5ac8db48b752240f723e8703929 (patch) | |
| tree | 0297dee9f8166af0a856dd3a1057ad5f25f14c6a /src/python_bindings.rs | |
| parent | 5135876b5e2a6c40232414ea0b7eb875fa225cf0 (diff) | |
| download | OneRoll-0288d0956330d5ac8db48b752240f723e8703929.tar.gz OneRoll-0288d0956330d5ac8db48b752240f723e8703929.zip | |
feat: initial basic roll features
Diffstat (limited to 'src/python_bindings.rs')
| -rw-r--r-- | src/python_bindings.rs | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/src/python_bindings.rs b/src/python_bindings.rs new file mode 100644 index 0000000..4073238 --- /dev/null +++ b/src/python_bindings.rs @@ -0,0 +1,154 @@ +use pyo3::prelude::*; +use pyo3::types::PyDict; + +use crate::calculator::DiceCalculator; +use crate::parser::DiceParser; +use crate::types::{DiceModifier, DiceRoll}; + +#[pyclass] +pub struct OneRoll; + +#[pymethods] +impl OneRoll { + #[new] + fn new() -> Self { + Self + } + + fn roll(&mut self, expression: &str) -> PyResult<PyObject> { + Python::with_gil(|py| { + let mut calculator = DiceCalculator::new(); + let expr = DiceParser::parse_expression(expression) + .map_err(|e| PyErr::new::<pyo3::exceptions::PyValueError, _>(e.to_string()))?; + + let result = calculator.evaluate_expression(&expr) + .map_err(|e| PyErr::new::<pyo3::exceptions::PyValueError, _>(e.to_string()))?; + + let dict = PyDict::new(py); + dict.set_item("expression", &result.expression)?; + dict.set_item("total", result.total)?; + dict.set_item("rolls", result.rolls)?; + dict.set_item("details", &result.details)?; + dict.set_item("comment", result.comment.as_deref().unwrap_or(""))?; + + Ok(dict.into()) + }) + } + + fn roll_simple(&mut self, dice_count: i32, dice_sides: i32) -> PyResult<i32> { + let mut calculator = DiceCalculator::new(); + let dice = DiceRoll { + count: dice_count, + sides: dice_sides, + modifiers: vec![], + }; + + let rolls = calculator.roll_dice(&dice) + .map_err(|e| PyErr::new::<pyo3::exceptions::PyValueError, _>(e.to_string()))?; + + Ok(rolls.iter().flatten().sum()) + } + + fn roll_with_modifiers(&mut self, dice_count: i32, dice_sides: i32, modifiers: Vec<String>) -> PyResult<PyObject> { + Python::with_gil(|py| { + let mut calculator = DiceCalculator::new(); + let mut dice_modifiers = Vec::new(); + + for modifier_str in modifiers { + let modifier = match modifier_str.as_str() { + "!" => DiceModifier::Explode, + s if s.starts_with("r") && !s.starts_with("ro") => { + let num = s[1..].parse::<i32>() + .map_err(|_| PyErr::new::<pyo3::exceptions::PyValueError, _>("无效的重投数值"))?; + DiceModifier::Reroll(num) + } + s if s.starts_with("ro") => { + let num = s[2..].parse::<i32>() + .map_err(|_| PyErr::new::<pyo3::exceptions::PyValueError, _>("无效的条件重投数值"))?; + DiceModifier::RerollOnce(num) + } + s if s.starts_with("kh") => { + let num = s[2..].parse::<i32>() + .map_err(|_| PyErr::new::<pyo3::exceptions::PyValueError, _>("无效的取高数值"))?; + DiceModifier::KeepHigh(num) + } + s if s.starts_with("kl") => { + let num = s[2..].parse::<i32>() + .map_err(|_| PyErr::new::<pyo3::exceptions::PyValueError, _>("无效的取低数值"))?; + DiceModifier::KeepLow(num) + } + s if s.starts_with("dh") => { + let num = s[2..].parse::<i32>() + .map_err(|_| PyErr::new::<pyo3::exceptions::PyValueError, _>("无效的丢弃高数值"))?; + DiceModifier::DropHigh(num) + } + s if s.starts_with("dl") => { + let num = s[2..].parse::<i32>() + .map_err(|_| PyErr::new::<pyo3::exceptions::PyValueError, _>("无效的丢弃低数值"))?; + DiceModifier::DropLow(num) + } + _ => return Err(PyErr::new::<pyo3::exceptions::PyValueError, _>("未知的修饰符")), + }; + dice_modifiers.push(modifier); + } + + let dice = DiceRoll { + count: dice_count, + sides: dice_sides, + modifiers: dice_modifiers, + }; + + let rolls = calculator.roll_dice(&dice) + .map_err(|e| PyErr::new::<pyo3::exceptions::PyValueError, _>(e.to_string()))?; + + let total: i32 = rolls.iter().flatten().sum(); + let details = format!("{}d{}{} = {} (详情: {:?})", + dice_count, dice_sides, + calculator.modifiers_to_string(&dice.modifiers), + total, rolls); + + let dict = PyDict::new(py); + dict.set_item("total", total)?; + dict.set_item("rolls", rolls)?; + dict.set_item("details", &details)?; + + Ok(dict.into()) + }) + } +} + +#[pyfunction] +pub fn roll_dice(expression: &str) -> PyResult<PyObject> { + Python::with_gil(|py| { + let mut calculator = DiceCalculator::new(); + let expr = DiceParser::parse_expression(expression) + .map_err(|e| PyErr::new::<pyo3::exceptions::PyValueError, _>(e.to_string()))?; + + let result = calculator.evaluate_expression(&expr) + .map_err(|e| PyErr::new::<pyo3::exceptions::PyValueError, _>(e.to_string()))?; + + let dict = PyDict::new(py); + dict.set_item("expression", &result.expression)?; + dict.set_item("total", result.total)?; + dict.set_item("rolls", result.rolls)?; + dict.set_item("details", &result.details)?; + dict.set_item("comment", result.comment.as_deref().unwrap_or(""))?; + + Ok(dict.into()) + }) +} + +#[pyfunction] +pub fn roll_simple(dice_count: i32, dice_sides: i32) -> PyResult<i32> { + let mut calculator = DiceCalculator::new(); + let dice = DiceRoll { + count: dice_count, + sides: dice_sides, + modifiers: vec![], + }; + + let rolls = calculator.roll_dice(&dice) + .map_err(|e| PyErr::new::<pyo3::exceptions::PyValueError, _>(e.to_string()))?; + + Ok(rolls.iter().flatten().sum()) +} |
