1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
//! Implementation of agent. //! //! Loop based single policy agent. //! //! `Agent` is structure for playing game with given policy. //! As we pass the policy, agent play the game with given based on loop. //! Method `play` return the `PlayResult` which consisted of winner and playing history (called path). //! //! # Examples //! For black-white seperable policy, reference [MultiPolicy](../policy/struct.MultiPolicy.html). //! ```ignore //! # #[macro_use] extern crate connect6; //! # use connect6::{agent::Agent, policy::{RandomPolicy, MultiPolicy}}; //! io_policy_stdio!(io_policy); //! let mut rand_policy = RandomPolicy::new(); //! //! let mut multi_policy = MultiPolicy::new(&mut rand_policy, &mut io_policy); //! let result = Agent::debug(&mut multi_policy).play(); //! # assert!(result.is_ok()); //! ``` use game::{Game, Player}; use policy::Policy; use Board; use std::error::Error; use std::io; use std::time::Instant; #[cfg(test)] mod tests; /// Unit of playing history, turn, board and selected position. #[derive(Debug, PartialEq)] pub struct Path { pub turn: Player, pub board: Board, pub pos: (usize, usize), } /// Result of playing game, consists of winner and path (history of game). pub struct PlayResult { pub winner: Player, pub path: Vec<Path>, } /// Loop based single policy agent. /// /// Agent is structure for playing game with given policy. /// As we pass the policy, agent play the game with given based on loop. /// Method `play` return the `SetResult` and it can be converted as `PyObject`. /// /// # Examples /// For black-white seperable policy, reference [MultiPolicy](../policy/struct.MultiPolicy.html). /// ```ignore /// # #[macro_use] extern crate connect6; /// # use connect6::{agent::Agent, policy::{RandomPolicy, MultiPolicy}}; /// io_policy_stdio!(io_policy); /// let mut rand_policy = RandomPolicy::new(); /// /// let mut multi_policy = MultiPolicy::new(&mut rand_policy, &mut io_policy); /// let result = Agent::debug(&mut multi_policy).play(); /// # assert!(result.is_ok()); /// ``` pub struct Agent<'a> { game: Game, debug: bool, policy: &'a mut Policy, } impl<'a> Agent<'a> { /// Construct a new `Agent` with given policy. /// /// # Examples /// ```rust /// # extern crate connect6; /// # use connect6::{agent::Agent, policy::RandomPolicy}; /// let mut policy = RandomPolicy::new(); /// let mut agent = Agent::new(&mut policy); /// ``` pub fn new(policy: &'a mut Policy) -> Agent<'a> { Agent { game: Game::new(), debug: false, policy, } } /// Construct a debug mode `Agent` with given policy, it will display the dbg info. /// /// # Examples /// ```rust /// # extern crate connect6; /// # use connect6::{agent::Agent, policy::RandomPolicy}; /// let mut policy = RandomPolicy::new(); /// let mut agent = Agent::debug(&mut policy); /// ``` pub fn debug(policy: &'a mut Policy) -> Agent<'a> { Agent { game: Game::new(), debug: true, policy, } } /// Self-play the game with given policy. /// /// # Examples /// ```rust /// # extern crate connect6; /// # use connect6::{agent::Agent, policy::RandomPolicy}; /// let mut policy = RandomPolicy::new(); /// let mut agent = Agent::new(&mut policy); /// /// let result = agent.play(); /// assert!(result.is_ok()); /// println!("winner: {:?}", result.unwrap().winner); /// ``` /// /// # Errors /// if selected position raise Err at [Game::play](../game/struct.Game.html#method.play). pub fn play(&mut self) -> Result<PlayResult, Box<Error + Send>> { let mut winner = Player::None; let mut path = Vec::new(); let game = &mut self.game; loop { if self.debug { game.print(&mut io::stdout()).unwrap(); } let before = Instant::now(); let pos = self.policy.next(&game); let duration = before.elapsed(); // if policy could't generate next selection if pos.is_none() { break; } let pos = pos.unwrap(); path.push(Path { turn: game.get_turn(), board: *game.get_board(), pos, }); match game.set(pos) { Ok(result) => { if self.debug { // log the selection info let (row, col) = result.position; let row = (row as u8 + 0x61) as char; let col = (col as u8 + 0x41) as char; println!( "{:?} ({}, {}), remain {}, {}.{} elapsed", result.player, row, col, result.num_remain, duration.as_secs(), duration.subsec_millis() ); } } Err(err) => return Err(err), }; // if game end, method return the winner, or None. let is_end = game.is_game_end(); if is_end != Player::None { winner = is_end; break; } } if self.debug { game.print(&mut io::stdout()).unwrap(); } Ok(PlayResult { winner, path }) } }