I'm trying to figure out how to handle simulating many "games" (in the game theory sense of the word) with various strategies. The end goal is to be able to know that for a given game, this choice of 10 strategies will work the best. I'm getting stuck at how to handle getting the different strategies to play the game.
That probably doesn't make a lot of sense, so here's the code I'm currently working with:
trait Strategy {
fn play_game(self: Self, current_game: Game, last_results: Option<GameResult>) -> bool;
}
struct Game {
a: i32,
b: i32,
c: i32,
d: i32,
strategy_a: Box<dyn Strategy>,
strategy_b: Box<dyn Strategy>,
}
struct GameResult {
game: Game,
a_choice: bool,
b_choice: bool,
a_score: i32,
b_score: i32,
}
impl GameResult {
fn opponent_chose(self: Self, player: &dyn Strategy) -> bool {
todo!()
}
}
struct StrategyAlwaysA {}
impl Strategy for StrategyAlwaysA {
fn play_game(self: Self, _current_game: Game, _last_results: Option<GameResult>) -> bool { false }
}
struct StrategyAlwaysB {}
impl Strategy for StrategyAlwaysB {
fn play_game(self: Self, _current_game: Game, _last_results: Option<GameResult>) -> bool { true }
}
struct StrategyTitForTat {}
impl Strategy for StrategyTitForTat {
fn play_game(self: Self, current_game: Game, last_results: Option<GameResult>) -> bool {
last_results.map(|r| r.opponent_chose(&self)).unwrap_or(false)
}
}
A major component of this is being able to generate thousands of games, and then doing statistics on the games where (for example) strategyAlwaysA played, and figuring out what values for the Game said strategy does well with over other strategies. Does that mean I shouldn't use just a struct/trait object for the strategy choice in each game? Does the fact that I'm generating games with all sorts of strategies mean generics are a bad fit? How far off am I from idiomatic Rust code so far?