井字游戏 - Minimax

Tic Tac Toe - Minimax

我正在尝试使用带有 Rust 的极小极大算法构建一个井字游戏。我卡住了。我试图根据维基百科页面上的伪代码编写一个 Rust 代码。 https://en.wikipedia.org/wiki/Minimax。但是,它没有用。 Ai 总是先下手为强。如果你能帮助我,我会很高兴。

在main.rs

fn main() {
    let mut g = Game::new();

    while g.game_state() == Game_State::Continuous {
        g.print();
        println!("{}", minimax(&g));

        if g.turn == Player::Cross {
            g.take_input();
        }
        else {
            g = best_move(&g);
        }
    }

    g.print();

    if let Game_State::Win(Player::None) = g.game_state() {
        println!("Draw");
    }
    else {
        g.print_winner();
    }
}

在ai.rs

pub fn child_nodes(game: &Game) -> Vec<Game> {
    let mut children: Vec<Game> = Vec::new();
    
    for r in 0..3 {
        for c in 0..3 {
            if game.grid[r][c] == Player::None {
                let mut child = game.clone();
                child.grid[r][c] = game.turn;
                child.turn = reverse_player(child.turn);
                children.push(child);
            }
        }
    }

    return children;
}

pub fn minimax(game: &Game) -> isize {
    match game.game_state() {
        Game_State::Win(winner) => to_scor(winner),
        Game_State::Continuous => {
            use std::cmp::{min, max};

            let children_vec = child_nodes(&game);
            let mut score: isize;

            if game.turn == Player::Cross {
                score = -2;

                for i in &children_vec {
                    score = max(score, minimax(i));
                }
                    
            }
            else {
                score = 2;
            
                for i in &children_vec {
                    score = min(score, minimax(i));
                }
            }

            return score;
        }
    }
}

pub fn best_move(game: &Game) -> Game {
    let children = child_nodes(game);
    let mut values: Vec<isize> = Vec::new();

    for i in 0..children.len() {
        values.push(minimax(&children[i]));
    }

    let mut index: usize = 0;
    let iter = values.iter().enumerate();

    if game.turn == Player::Cross {
        if let Option::Some(t) = iter.max() {
            index = t.0;
        }
    }
    else if game.turn == Player::Circle {
        if let Option::Some(t) = iter.min() {
            index = t.0;
        }
    }

    let best_pos = children[index];
    best_pos
}

pub fn to_scor(x: Player) -> isize {
    match x {
        Player::Cross => 1,
        Player::Circle => -1,
        Player::None => 0
    }
} 

.enumerate() returns 元组迭代器,.max().min() 元组迭代器将比较元组 - 即 (1, x)对于 xy 的任何值,始终被认为小于 (2, y)。这可以用这个片段来证明:

fn main() {
    let v = vec![3, 1, 2, 5, 3, 6, 7, 2];
    println!("{:?}", v.iter().enumerate().min());
    println!("{:?}", v.iter().enumerate().max());
}

打印:

Some((0, 3))
Some((7, 2))

它们只是列表的第一个和最后一个元素(而不是最小或最大元素)。

但是,如图,您可以max_by使用您自己的函数来比较元组。