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 })
    }
}