aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/python_bindings.rs
diff options
context:
space:
mode:
author简律纯 <i@jyunko.cn>2025-09-12 04:02:02 +0800
committer简律纯 <i@jyunko.cn>2025-09-12 04:02:02 +0800
commit0288d0956330d5ac8db48b752240f723e8703929 (patch)
tree0297dee9f8166af0a856dd3a1057ad5f25f14c6a /src/python_bindings.rs
parent5135876b5e2a6c40232414ea0b7eb875fa225cf0 (diff)
downloadOneRoll-0288d0956330d5ac8db48b752240f723e8703929.tar.gz
OneRoll-0288d0956330d5ac8db48b752240f723e8703929.zip
feat: initial basic roll features
Diffstat (limited to 'src/python_bindings.rs')
-rw-r--r--src/python_bindings.rs154
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())
+}