Enum open_ttt_lib::ai::Difficulty[][src]

pub enum Difficulty {
    None,
    Easy,
    Medium,
    Hard,
    Unbeatable,
    Custom(fn(depth: i32) -> bool),
}
Expand description

Selects the difficulty used by the Opponent.

The exact behavior of Easy, Medium, and Hard difficulties are set via play testing and are subject to adjustment in future library versions.

Variants

None

The Opponent picks random positions and does not actually evaluate the game.

Easy

Intended for players who are new to tic-tac-toe to learn the rules of the game. The Opponent mostly picks random squares, but occasionally goes for the win or blocks the player from winning.

Medium

Medium difficulty is for players who have some experience with tic-tac-toe. The AI provides a challenge to the player but games are still winnable, especially if the player plans several moves ahead.

Hard

At hard difficulty the computer plays almost perfect games. The player must capitalize on rare mistakes made by the computer to win. This is the recommended difficulty for experienced tic-tac-toe players.

Unbeatable

The Opponent plays perfect games and cannot be defeated. The best outcome for the player is a cat’s game.

Custom(fn(depth: i32) -> bool)

Provides full control over the Opponent’s difficulty via the provided function.

The AI algorithm selects a free position then traverses the tree of all possible moves looking for one of the end game conditions: win, loss, or cat’s game. The provided function is invoked before processing each node in the outcome tree. Return true to evaluate the node. Return false to stop processing the node, and all child nodes thus preventing the algorithm from considering the outcomes from that branch of the tree.

The depth of the node being considered is provided as the function’s parameter so the custom difficulty can take into account how many moves ahead the Opponent is looking. E.g. the Opponent could be more likely to make mistakes the farther ahead it looks. The depth starts at zero.

Notes

  • The number of nodes to evaluate for a game can be large resulting in the provided function being invoked many times when evaluating a game.
  • The AI algorithms contain speed optimizations that might skip evaluating part or all of the outcome tree. In these cases the provided function is not called.

Examples

Implement custom difficulties with the same behavior as the None and Unbeatable variants:

use open_ttt_lib::ai;
let same_as_none = ai::Difficulty::Custom(|_| false);
let same_as_unbeatable = ai::Difficulty::Custom(|_| true);

Create a custom difficulty that is perfect when looking at the current move and has a fixed probability of failing to consider deeper parts of the tree.

use rand::Rng;
use open_ttt_lib::ai;

fn should_evaluate_node(depth: i32) -> bool {
    if depth == 0 {
        true
    } else {
        let evaluate_node_probability = 0.8;
        rand::thread_rng().gen_bool(evaluate_node_probability)
    }
}

let custom_difficulty = ai::Difficulty::Custom(should_evaluate_node);

Trait Implementations

impl Clone for Difficulty[src]

fn clone(&self) -> Difficulty[src]

Returns a copy of the value. Read more

fn clone_from(&mut self, source: &Self)1.0.0[src]

Performs copy-assignment from source. Read more

impl Debug for Difficulty[src]

fn fmt(&self, f: &mut Formatter<'_>) -> Result[src]

Formats the value using the given formatter. Read more

impl Hash for Difficulty[src]

fn hash<__H: Hasher>(&self, state: &mut __H)[src]

Feeds this value into the given Hasher. Read more

fn hash_slice<H>(data: &[Self], state: &mut H) where
    H: Hasher
1.3.0[src]

Feeds a slice of this type into the given Hasher. Read more

impl PartialEq<Difficulty> for Difficulty[src]

fn eq(&self, other: &Difficulty) -> bool[src]

This method tests for self and other values to be equal, and is used by ==. Read more

fn ne(&self, other: &Difficulty) -> bool[src]

This method tests for !=.

impl Copy for Difficulty[src]

impl StructuralPartialEq for Difficulty[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

pub fn type_id(&self) -> TypeId[src]

Gets the TypeId of self. Read more

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

pub fn borrow(&self) -> &T[src]

Immutably borrows from an owned value. Read more

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

pub fn borrow_mut(&mut self) -> &mut T[src]

Mutably borrows from an owned value. Read more

impl<T> From<T> for T[src]

pub fn from(t: T) -> T[src]

Performs the conversion.

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

pub fn into(self) -> U[src]

Performs the conversion.

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

pub fn to_owned(&self) -> T[src]

Creates owned data from borrowed data, usually by cloning. Read more

pub fn clone_into(&self, target: &mut T)[src]

🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

Uses borrowed data to replace owned data, usually by cloning. Read more

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>[src]

Performs the conversion.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>[src]

Performs the conversion.

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

pub fn vzip(self) -> V