Mercurial > touhou
changeset 784:1f152ca95658
Replace pytouhou.utils.random.Random with a Rust version
libtouhou.Prng now supports having its seed generated randomly using the
getrandom crate, and is now exposed to Python.
| author | Link Mauve <linkmauve@linkmauve.fr> |
|---|---|
| date | Sun, 23 Nov 2025 12:48:03 +0100 |
| parents | ec1e06402a97 |
| children | f73e8524c045 |
| files | python/Cargo.toml python/src/lib.rs pytouhou/game/game.pxd pytouhou/game/game.pyx pytouhou/utils/random.pxd pytouhou/utils/random.pyx scripts/pytouhou utils/Cargo.toml utils/src/prng.rs |
| diffstat | 9 files changed, 39 insertions(+), 88 deletions(-) [+] |
line wrap: on
line diff
--- a/python/Cargo.toml +++ b/python/Cargo.toml @@ -14,6 +14,7 @@ [dependencies] touhou-formats = "*" +touhou-utils = { version = "*", path = "../utils" } pyo3 = "0.27" image = { version = "0.25", default-features = false, features = ["png"], optional = true } glob = "0.3.3"
--- a/python/src/lib.rs +++ b/python/src/lib.rs @@ -216,12 +216,43 @@ } } +/// A loader for Touhou files. +#[pyclass(module = "libtouhou")] +struct Prng { + inner: touhou_utils::prng::Prng, +} + +#[pymethods] +impl Prng { + #[pyo3(signature = (seed=None))] + #[new] + fn new(seed: Option<u16>) -> Prng { + let inner = touhou_utils::prng::Prng::new(seed); + Prng { inner } + } + + fn rand_uint16(&mut self) -> u16 { + self.inner.get_u16() + } + + fn rand_uint32(&mut self) -> u32 { + self.inner.get_u32() + } + + fn rand_double(&mut self) -> f64 { + self.inner.get_f64() + } +} + #[pymodule] mod libtouhou { #[pymodule_export] use super::Loader; #[pymodule_export] + use super::Prng; + + #[pymodule_export] use crate::audio::Audio; #[cfg(feature = "glide")]
--- a/pytouhou/game/game.pxd +++ b/pytouhou/game/game.pxd @@ -1,7 +1,6 @@ from pytouhou.game.effect cimport Effect from pytouhou.game.player cimport Player from pytouhou.game.text cimport Text, NativeText -from pytouhou.utils.random cimport Random cdef class Game: cdef public long width, height, nb_bullets_max, stage, rank, difficulty, difficulty_min, difficulty_max, frame @@ -9,7 +8,7 @@ cdef public object interface, boss, msg_runner cdef public dict texts cdef public object sfx_player, music - cdef public Random prng + cdef public object prng cdef public double continues cdef public Effect spellcard_effect cdef public tuple spellcard
--- a/pytouhou/game/game.pyx +++ b/pytouhou/game/game.pyx @@ -26,7 +26,7 @@ cdef class Game: def __init__(self, players, long stage, long rank, long difficulty, bullet_types, laser_types, item_types, long nb_bullets_max=0, long width=384, - long height=448, Random prng=None, interface=None, hints=None, + long height=448, prng=None, interface=None, hints=None, bint friendly_fire=True): self.width, self.height = width, height
deleted file mode 100644 --- a/pytouhou/utils/random.pxd +++ /dev/null @@ -1,10 +0,0 @@ -cdef class Random: - cdef unsigned short seed - cdef unsigned long counter - - cdef void set_seed(self, unsigned short seed) nogil - cdef unsigned short rewind(self) nogil - - cpdef unsigned short rand_uint16(self) - cpdef unsigned int rand_uint32(self) - cpdef double rand_double(self)
deleted file mode 100644 --- a/pytouhou/utils/random.pyx +++ /dev/null @@ -1,73 +0,0 @@ -# -*- encoding: utf-8 -*- -## -## Copyright (C) 2011 Thibaut Girka <thib@sitedethib.com> -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published -## by the Free Software Foundation; version 3 only. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## - - -""" -This file provides a pseudo-random number generator identical to the one used in -Touhou 6: The Embodiment of Scarlet Devil. -It is the only truly reverse-engineered piece of code of this project, -as it is needed in order to retain compatibility with replay files produced by -the offical game code. - -It has been reverse engineered from 102h.exe.""" - - -#TODO: maybe some post-processing is missing - -cimport cython -from time import time - - -@cython.final -cdef class Random: - def __init__(self, long seed=-1): - if seed < 0: - seed = time() - self.set_seed(<unsigned short>(seed & 65535)) - - - cdef void set_seed(self, unsigned short seed) nogil: - self.seed = seed - self.counter = 0 - - - cdef unsigned short rewind(self) nogil: - """Rewind the PRNG by 1 step. This is the reverse of rand_uint16. - Might be useful for debugging purposes. - """ - x = self.seed - x = (x >> 2) | ((x & 3) << 14) - self.seed = ((x + 0x6553) & 0xffff) ^ 0x9630 - self.counter -= 1 - return self.seed - - - cpdef unsigned short rand_uint16(self): - # 102h.exe@0x41e780 - x = ((self.seed ^ 0x9630) - 0x6553) & 0xffff - self.seed = (((x & 0xc000) >> 14) | (x << 2)) & 0xffff - self.counter += 1 - return self.seed - - - cpdef unsigned int rand_uint32(self): - # 102h.exe@0x41e7f0 - a = self.rand_uint16() << 16 - a |= self.rand_uint16() - return a - - - cpdef double rand_double(self): - # 102h.exe@0x41e820 - return self.rand_uint32() / <double>0x100000000
--- a/scripts/pytouhou +++ b/scripts/pytouhou @@ -72,7 +72,7 @@ from pytouhou.ui.gamerunner import GameRunner from pytouhou.game import NextStage, GameOver from pytouhou.formats.t6rp import T6RP, Level -from pytouhou.utils.random import Random +from libtouhou import Prng as Random from pytouhou.formats.hint import Hint from pytouhou.network import Network
--- a/utils/Cargo.toml +++ b/utils/Cargo.toml @@ -10,3 +10,4 @@ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +getrandom = "0.3.4"
--- a/utils/src/prng.rs +++ b/utils/src/prng.rs @@ -8,7 +8,9 @@ impl Prng { /// Create a new pseudo-random number generator from this seed. - pub fn new(seed: u16) -> Prng { + pub fn new(seed: Option<u16>) -> Prng { + // TODO: Maybe add a getrandom::u16() to getrandom instead? + let seed = seed.unwrap_or_else(|| getrandom::u32().unwrap() as u16); Prng { seed, }
