Привет.
Есть некоторая игра, состояние которой описывается структурой GameState
. Искусственные игроки (боты) ходят по-очереди, что-то вычисляют и результатом вычислений является какой-то Move
, поведение ботов описывается простым трейтом Bot
:
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum Move {
Right, Up, Left, Down, Stop,
}
// the bot is mutable agent that makes a decision about the move
trait Bot {
fn reset(&mut self);
fn do_move(&mut self, game_state: &GameState) -> Move;
}
Реализация do_move
может быть достаточно сложной, и в этой реализации множеству различных функций нужен доступ к этому game_state
. Теоретически можно протянуть game_state
как параметр во все функции, но это очень громоздко. Поэтому хочется сохранить game_state
в состоянии бота пока работает функция do_move
. Делаю так:
struct Bot1 {
my_gs: *const GameState,
}
impl Bot for Bot1 {
fn reset(&mut self) {
self.my_gs = null();
println!("reset gs={:?}", self.my_gs);
}
fn do_move(&mut self, gs: &GameState) -> Move {
///////////////////////////////////////
self.my_gs = gs; // setup the reference
///////////////////////////////////////
// some bot logic goes here
let the_move = if self.find_closest_empty(&Point(0, 0)).is_some() {
Move::Left
} else {
Move::Right
};
///////////////////////////////////////
self.my_gs = null(); // clear it back
///////////////////////////////////////
the_move
}
}
Теперь внутри алгоритма выбора хода (в данном случае это find_closest_empty
) доступ к состянию игры можно сделать просто:
fn find_closest_empty(&self, _src: &Point) -> Option<Point> {
// guaranteed to exist since we have initialized
let my_gs = unsafe { &*self.my_gs }; // OMG unsafe
println!("inside find_closest_empty gs={:?}", my_gs);
None
}
Но это решение мне ужасно не нравится из-за unsafe
.
Передавать в do_move
Rc<GameState>
не хотелось бы, поскольку я хочу сохранить свободу у вызывающего кода решать какое именно состояние туда передать - тот же объект, или может какой-то другой (хотя может я что-то не учёл и Rc
тут годится).
Какие у меня есть варианты?
Спасибо.
Этот пример на playground
Расширенный пример с рандомами и GameState как матрицей ячеек