pub fn ai(
    board: &mut [[Option<Card>; 5]; 4],
    deck1: &mut Vec<Card>,
    deck2: &mut Vec<Card>,
    player: u8,
    bombs: &mut [[u8; 5]; 4],
) -> (usize, usize, usize, [Option<(usize, usize)>; 4]) {
    // init best move, best score and available moves
    let mut best_move: usize = 0;
    let mut best_score: i8;
    let moves: Vec<(usize, usize, usize, [Option<(usize, usize)>; 4])>;
    if player == 1 {
        best_score = -125;
        moves = available_moves(board, bombs, deck1, 1);
    } else {
        best_score = 125;
        moves = available_moves(board, bombs, deck2, 2);
    }

    // determines maximum depth of minimax algorithm & minimum depth at which the pruning can occur
    let max_depth: (u8, u8) = {
        match deck1.len() + deck2.len() {
            1..=6 => (6, 0),
            7 => (7, 4),
            8 => (8, 6),
            9..=10 => (5, 3),
            11 => (4, 2),
            12 => (4, 3),
            _ => (3, 2),
        }
    };

    // init channels for communication between threads
    let (tx, rx) = channel();

    // iterate through the moves
    for m in 0..moves.len() {
        // determine move
        let mut mov = moves[m];

        // make a copy of the board
        let mut t_board: [[Option<Card>; 5]; 4] = copy_board(&board);

        // make a clone of the bombs
        let mut t_bombs = bombs.clone();

        // make a copy of the decks
        let mut t_deck1: Vec<Card> = Default::default();
        let mut t_deck2: Vec<Card> = Default::default();
        for i in 0..deck2.len() {
            t_deck2.push(Card::copy(&deck2[i]));
            if i < deck1.len() {
                t_deck1.push(Card::copy(&deck1[i]));
            }
        }

        // spawn a thread to do the calculations
        let sender = tx.clone();
        thread::spawn(move || {
            // place the card down
            Card::place_card(
                &mut t_board,
                &mut t_deck1,
                &mut t_deck2,
                mov.0,
                (mov.1, mov.2),
                player,
                &mut t_bombs,
                &mut mov.3,
            );

            // calculate opponent's best score for this move
            let score = minimax(
                &mut t_board,
                &mut t_deck1,
                &mut t_deck2,
                &mut t_bombs,
                (player % 2) + 1,
                -125,
                125,
                max_depth,
            );

            // send score to main thread
            sender
                .send((m, score))
                .expect("Thread could not send info !");
        });
    }

    // close the sending channel as it is no longer needed
    drop(tx);

    print!("Progress: ");
    flush!();

    // loop through data of the recieving channel
    for data in rx {
        // break down sent data
        let (mov, score) = data;

        // flag to see if there was a better score
        let better_score: bool = {
            // maximizing player
            if player == 1 {
                score > best_score
            }
            // minimizing player
            else {
                score < best_score
            }
        };

        // if we have a better score, update best move
        if better_score {
            best_score = score;
            best_move = mov;
            print!("({})", best_score);
        } else {
            print!("|");
        }
        flush!();
    }

    println!();

    if (player == 1 && best_score > 100) || (player == 2 && best_score < -100) {
        println!("\n  Omae wa mou shindeiru\n");
    }

    return moves[best_move];
}
// plays the best move on the board for current player
plays the best move on the board for current player
plays the best move on the board for current player
pub fn ai(
    board: &mut [[Option<Card>; 5]; 4],
    deck1: &mut Vec<Card>,
    deck2: &mut Vec<Card>,
    player: u8,
    bombs: &mut [[u8; 5]; 4],
) -> (usize, usize, usize, [Option<(usize, usize)>; 4]) {
    // init best move, best score and available moves
    let mut best_move: usize = 0;
    let mut best_score: i8;
    let moves: Vec<(usize, usize, usize, [Option<(usize, usize)>; 4])>;
    if player == 1 {
        best_score = -125;
        moves = available_moves(board, bombs, deck1, 1);
    } else {
        best_score = 125;
        moves = available_moves(board, bombs, deck2, 2);
    }
    // determines maximum depth of minimax algorithm & minimum depth at which the pruning can occur
    let max_depth: (u8, u8) = {
        match deck1.len() + deck2.len() {
            1..=6 => (6, 0),
            7 => (7, 4),
            8 => (8, 6),
            9..=10 => (5, 3),
            11 => (4, 2),
            12 => (4, 3),
            _ => (3, 2),
        }
    };
    // init channels for communication between threads
    let (tx, rx) = channel();
    // iterate through the moves
    for m in 0..moves.len() {
        // determine move
        let mut mov = moves[m];
        // make a copy of the board
        let mut t_board: [[Option<Card>; 5]; 4] = copy_board(&board);
        // make a clone of the bombs
        let mut t_bombs = bombs.clone();
        // make a copy of the decks
        let mut t_deck1: Vec<Card> = Default::default();
        let mut t_deck2: Vec<Card> = Default::default();
        for i in 0..deck2.len() {
            t_deck2.push(Card::copy(&deck2[i]));
            if i < deck1.len() {
                t_deck1.push(Card::copy(&deck1[i]));
            }
        }
        // spawn a thread to do the calculations
        let sender = tx.clone();
        thread::spawn(move || {
            // place the card down
            Card::place_card(
                &mut t_board,
                &mut t_deck1,
                &mut t_deck2,
                mov.0,
                (mov.1, mov.2),
                player,
                &mut t_bombs,
                &mut mov.3,
            );
            // calculate opponent's best score for this move
            let score = minimax(
                &mut t_board,
                &mut t_deck1,
                &mut t_deck2,
                &mut t_bombs,
                (player % 2) + 1,
                -125,
                125,
                max_depth,
            );
            // send score to main thread
            sender
                .send((m, score))
                .expect("Thread could not send info !");
        });
    }
    // close the sending channel as it is no longer needed
    drop(tx);
    print!("Progress: ");
    flush!();
    // loop through data of the recieving channel
    for data in rx {
        // break down sent data
        let (mov, score) = data;
        // flag to see if there was a better score
        let better_score: bool = {
            // maximizing player
            if player == 1 {
                score > best_score
            }
            // minimizing player
            else {
                score < best_score
            }
        };
        // if we have a better score, update best move
        if better_score {
            best_score = score;
            best_move = mov;
            print!("({})", best_score);
        } else {
            print!("|");
        }
        flush!();
    }
    println!();
    if (player == 1 && best_score > 100) || (player == 2 && best_score < -100) {
        println!("\n  Omae wa mou shindeiru\n");
    }
    return moves[best_move];
}
pub fn ai ( board : & mut [ [ Option < Card > ; 5 ] ; 4 ] , deck1 : & mut Vec < Card > , deck2 : & mut Vec < Card > , player : u8 , bombs : & mut [ [ u8 ; 5 ] ; 4 ] , ) -> ( usize , usize , usize , [ Option < ( usize , usize ) > ; 4 ] ) { // init best move, best score and available moves let mut best_move : usize = 0 ; let mut best_score : i8 ; let moves : Vec < ( usize , usize , usize , [ Option < ( usize , usize ) > ; 4 ] ) > ; if player == 1 { best_score = - 125 ; moves = available_moves ( board , bombs , deck1 , 1 ) ; } else { best_score = 125 ; moves = available_moves ( board , bombs , deck2 , 2 ) ; } // determines maximum depth of minimax algorithm & minimum depth at which the pruning can occur let max_depth : ( u8 , u8 ) = { match deck1 . len ( ) + deck2 . len ( ) { 1 ..= 6 => ( 6 , 0 ) , 7 => ( 7 , 4 ) , 8 => ( 8 , 6 ) , 9 ..= 10 => ( 5 , 3 ) , 11 => ( 4 , 2 ) , 12 => ( 4 , 3 ) , _ => ( 3 , 2 ) , } } ; // init channels for communication between threads let ( tx , rx ) = channel ( ) ; // iterate through the moves for m in 0 .. moves . len ( ) { // determine move let mut mov = moves [ m ] ; // make a copy of the board let mut t_board : [ [ Option < Card > ; 5 ] ; 4 ] = copy_board ( & board ) ; // make a clone of the bombs let mut t_bombs = bombs . clone ( ) ; // make a copy of the decks let mut t_deck1 : Vec < Card > = Default :: default ( ) ; let mut t_deck2 : Vec < Card > = Default :: default ( ) ; for i in 0 .. deck2 . len ( ) { t_deck2 . push ( Card :: copy ( & deck2 [ i ] ) ) ; if i < deck1 . len ( ) { t_deck1 . push ( Card :: copy ( & deck1 [ i ] ) ) ; } } // spawn a thread to do the calculations let sender = tx . clone ( ) ; thread :: spawn ( move | | { // place the card down Card :: place_card ( & mut t_board , & mut t_deck1 , & mut t_deck2 , mov . 0 , ( mov . 1 , mov . 2 ) , player , & mut t_bombs , & mut mov . 3 , ) ; // calculate opponent's best score for this move let score = minimax ( & mut t_board , & mut t_deck1 , & mut t_deck2 , & mut t_bombs , ( player % 2 ) + 1 , - 125 , 125 , max_depth , ) ; // send score to main thread sender . send ( ( m , score ) ) . expect ( " " ) ; } ) ; } // close the sending channel as it is no longer needed drop ( tx ) ; print ! ( " " ) ; flush ! ( ) ; // loop through data of the recieving channel for data in rx { // break down sent data let ( mov , score ) = data ; // flag to see if there was a better score let better_score : bool = { // maximizing player if player == 1 { score > best_score } // minimizing player else { score < best_score } } ; // if we have a better score, update best move if better_score { best_score = score ; best_move = mov ; print ! ( " " best_score ) ; } else { print ! ( " " ) ; } flush ! ( ) ; } println ! ( ) ; if ( player == 1 && best_score > 100 ) || ( player == 2 && best_score < - 100 ) { println ! ( " \n \n " ) ; } return moves [ best_move ] ; }
plays the best move on the board for current player
plays the best move on the board for current player
board
&mut [[Option<Card>; 5]; 4]
deck1
&mut Vec<Card>
deck2
&mut Vec<Card>
player
u8
bombs
&mut [[u8; 5]; 4]