2020-12-25 18:42:42 -05:00
//! <b>Outer-Open Gomoku</b> is a board game which is a enhanced version of connect5 (Gomoku).\
//! The game is a two-player game which played on a 15x15 Go board.\
//! Two players take turns placing a move on an empty intersection in this board.\
//! The winner is the first player to form an unbroken chain of five moves horizontally, vertically, or diagonally.\
//! Unlike Gomoku, the first move is required to be placed at the two outer rows or columns of this board.\
//! This program provides an AI playing with Minimax search with alpha-beta pruning which uses
//! patterns on evaluation.\
//! The avx512 intrinsic can do 32 pattern matching at one time.\
//! This avx512 is tested with non-avx512 code to verify its correctness.\
//!
//! On Intel i7-7800x using single thread with fixed AVX-512 clock at 4.0GHz, the avx512 is speed up about 9x.\
//! The average time for each move in the avx512 is around 14.00s <span>±</span> 1.31s and in the non-avx512
//! is 129.02s <span>±</span> 4.96s.\
2021-01-03 19:35:51 -05:00
//! On Intel Tiger Lake i7-1165G7, the avx512 is around 11.11s <span>±</span> 1.31s.
2020-12-25 18:42:42 -05:00
//!
//! <b>Pattern Matching</b>\
//! Use 512-bit to present the board state. The location 0 is top left.\
//! 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <b>15</b>\
//! 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <b>31</b>\
//! ...\
//! Pattern "OOOOO" is matching through "0 1 2 3 4", "1 2 3 4 5", ...\
//! Using avx512, "0 1 2 3 4", "16 17 18 19 20", ... can be matched simultaneously.\
//!
//! //! You can test out this program via:
//!
//! cargo +nightly run --release --bin connect5
//!
//! You should see a game self-playing. In the end of the game, it shows the average time for
//! each move.
#![ feature(stdsimd, avx512_target_feature) ]
#![ feature(stmt_expr_attributes) ]
use rand ::seq ::SliceRandom ;
use rand ::thread_rng ;
use std ::cmp ;
use std ::time ::Instant ;
#[ cfg(target_arch = " x86 " ) ]
use { core_arch ::arch ::x86 ::* , std_detect ::is_x86_feature_detected } ;
#[ cfg(target_arch = " x86_64 " ) ]
use { core_arch ::arch ::x86_64 ::* , std_detect ::is_x86_feature_detected } ;
// types
#[ derive(Clone, Copy, PartialEq, Eq) ]
pub enum Color {
Black = 0 ,
White = 1 ,
Empty = 2 ,
Border = 3 ,
}
type Square = i32 ;
type Move = i32 ;
type Side = Color ;
// constants
const FILE_SIZE : i32 = 15 ;
const RANK_SIZE : i32 = 15 ;
const SQUARE_SIZE : i32 = ( FILE_SIZE + 1 ) * ( FILE_SIZE + 4 ) + 16 + 4 ;
const EVAL_INF : i32 = FILE_SIZE * RANK_SIZE * 100 ;
const MOVE_NONE : Move = - 1 ;
const SCORE_NONE : i32 = - EVAL_INF - 1 ;
/// DIRECTION 0: left to right\
/// DIRECTION 1: top to bottom\
/// DIRECTION 2: top left to bottom right\
/// DIRECTION 3: top right to bottom left
#[ rustfmt::skip ]
const DIRECTION : [ [ i32 ; 5 ] ; 4 ] = [ [ 1 , 2 , 3 , 4 , 5 ] ,
[ 1 * ( FILE_SIZE + 1 ) , 2 * ( FILE_SIZE + 1 ) , 3 * ( FILE_SIZE + 1 ) , 4 * ( FILE_SIZE + 1 ) , 5 * ( FILE_SIZE + 1 ) ] ,
[ 1 * ( FILE_SIZE + 2 ) , 2 * ( FILE_SIZE + 2 ) , 3 * ( FILE_SIZE + 2 ) , 4 * ( FILE_SIZE + 2 ) , 5 * ( FILE_SIZE + 2 ) ] ,
[ 1 * ( FILE_SIZE + 0 ) , 2 * ( FILE_SIZE + 0 ) , 3 * ( FILE_SIZE + 0 ) , 4 * ( FILE_SIZE + 0 ) , 5 * ( FILE_SIZE + 0 ) ] ] ;
/// A table to encode each location to a value in bit 31-0 in the bitboard for 4 direction
#[ rustfmt::skip ]
const MAPMOVEVALUE : [ [ i32 ; 239 ] ; 4 ] = [ [ // Direction 0
1 < < 31 , 1 < < 30 , 1 < < 29 , 1 < < 28 , 1 < < 27 , 1 < < 26 , 1 < < 25 , 1 < < 24 , 1 < < 23 , 1 < < 22 , 1 < < 21 , 1 < < 20 , 1 < < 19 , 1 < < 18 , 1 < < 17 , 0 ,
1 < < 31 , 1 < < 30 , 1 < < 29 , 1 < < 28 , 1 < < 27 , 1 < < 26 , 1 < < 25 , 1 < < 24 , 1 < < 23 , 1 < < 22 , 1 < < 21 , 1 < < 20 , 1 < < 19 , 1 < < 18 , 1 < < 17 , 0 ,
1 < < 31 , 1 < < 30 , 1 < < 29 , 1 < < 28 , 1 < < 27 , 1 < < 26 , 1 < < 25 , 1 < < 24 , 1 < < 23 , 1 < < 22 , 1 < < 21 , 1 < < 20 , 1 < < 19 , 1 < < 18 , 1 < < 17 , 0 ,
1 < < 31 , 1 < < 30 , 1 < < 29 , 1 < < 28 , 1 < < 27 , 1 < < 26 , 1 < < 25 , 1 < < 24 , 1 < < 23 , 1 < < 22 , 1 < < 21 , 1 < < 20 , 1 < < 19 , 1 < < 18 , 1 < < 17 , 0 ,
1 < < 31 , 1 < < 30 , 1 < < 29 , 1 < < 28 , 1 < < 27 , 1 < < 26 , 1 < < 25 , 1 < < 24 , 1 < < 23 , 1 < < 22 , 1 < < 21 , 1 < < 20 , 1 < < 19 , 1 < < 18 , 1 < < 17 , 0 ,
1 < < 31 , 1 < < 30 , 1 < < 29 , 1 < < 28 , 1 < < 27 , 1 < < 26 , 1 < < 25 , 1 < < 24 , 1 < < 23 , 1 < < 22 , 1 < < 21 , 1 < < 20 , 1 < < 19 , 1 < < 18 , 1 < < 17 , 0 ,
1 < < 31 , 1 < < 30 , 1 < < 29 , 1 < < 28 , 1 < < 27 , 1 < < 26 , 1 < < 25 , 1 < < 24 , 1 < < 23 , 1 < < 22 , 1 < < 21 , 1 < < 20 , 1 < < 19 , 1 < < 18 , 1 < < 17 , 0 ,
1 < < 31 , 1 < < 30 , 1 < < 29 , 1 < < 28 , 1 < < 27 , 1 < < 26 , 1 < < 25 , 1 < < 24 , 1 < < 23 , 1 < < 22 , 1 < < 21 , 1 < < 20 , 1 < < 19 , 1 < < 18 , 1 < < 17 , 0 ,
1 < < 31 , 1 < < 30 , 1 < < 29 , 1 < < 28 , 1 < < 27 , 1 < < 26 , 1 < < 25 , 1 < < 24 , 1 < < 23 , 1 < < 22 , 1 < < 21 , 1 < < 20 , 1 < < 19 , 1 < < 18 , 1 < < 17 , 0 ,
1 < < 31 , 1 < < 30 , 1 < < 29 , 1 < < 28 , 1 < < 27 , 1 < < 26 , 1 < < 25 , 1 < < 24 , 1 < < 23 , 1 < < 22 , 1 < < 21 , 1 < < 20 , 1 < < 19 , 1 < < 18 , 1 < < 17 , 0 ,
1 < < 31 , 1 < < 30 , 1 < < 29 , 1 < < 28 , 1 < < 27 , 1 < < 26 , 1 < < 25 , 1 < < 24 , 1 < < 23 , 1 < < 22 , 1 < < 21 , 1 < < 20 , 1 < < 19 , 1 < < 18 , 1 < < 17 , 0 ,
1 < < 31 , 1 < < 30 , 1 < < 29 , 1 < < 28 , 1 < < 27 , 1 < < 26 , 1 < < 25 , 1 < < 24 , 1 < < 23 , 1 < < 22 , 1 < < 21 , 1 < < 20 , 1 < < 19 , 1 < < 18 , 1 < < 17 , 0 ,
1 < < 31 , 1 < < 30 , 1 < < 29 , 1 < < 28 , 1 < < 27 , 1 < < 26 , 1 < < 25 , 1 < < 24 , 1 < < 23 , 1 < < 22 , 1 < < 21 , 1 < < 20 , 1 < < 19 , 1 < < 18 , 1 < < 17 , 0 ,
1 < < 31 , 1 < < 30 , 1 < < 29 , 1 < < 28 , 1 < < 27 , 1 < < 26 , 1 < < 25 , 1 < < 24 , 1 < < 23 , 1 < < 22 , 1 < < 21 , 1 < < 20 , 1 < < 19 , 1 < < 18 , 1 < < 17 , 0 ,
1 < < 31 , 1 < < 30 , 1 < < 29 , 1 < < 28 , 1 < < 27 , 1 < < 26 , 1 < < 25 , 1 < < 24 , 1 < < 23 , 1 < < 22 , 1 < < 21 , 1 < < 20 , 1 < < 19 , 1 < < 18 , 1 < < 17 ] ,
[ // Direction 1
1 < < 31 , 1 < < 31 , 1 < < 31 , 1 < < 31 , 1 < < 31 , 1 < < 31 , 1 < < 31 , 1 < < 31 , 1 < < 31 , 1 < < 31 , 1 < < 31 , 1 < < 31 , 1 < < 31 , 1 < < 31 , 1 < < 31 , 0 ,
1 < < 30 , 1 < < 30 , 1 < < 30 , 1 < < 30 , 1 < < 30 , 1 < < 30 , 1 < < 30 , 1 < < 30 , 1 < < 30 , 1 < < 30 , 1 < < 30 , 1 < < 30 , 1 < < 30 , 1 < < 30 , 1 < < 30 , 0 ,
1 < < 29 , 1 < < 29 , 1 < < 29 , 1 < < 29 , 1 < < 29 , 1 < < 29 , 1 < < 29 , 1 < < 29 , 1 < < 29 , 1 < < 29 , 1 < < 29 , 1 < < 29 , 1 < < 29 , 1 < < 29 , 1 < < 29 , 0 ,
1 < < 28 , 1 < < 28 , 1 < < 28 , 1 < < 28 , 1 < < 28 , 1 < < 28 , 1 < < 28 , 1 < < 28 , 1 < < 28 , 1 < < 28 , 1 < < 28 , 1 < < 28 , 1 < < 28 , 1 < < 28 , 1 < < 28 , 0 ,
1 < < 27 , 1 < < 27 , 1 < < 27 , 1 < < 27 , 1 < < 27 , 1 < < 27 , 1 < < 27 , 1 < < 27 , 1 < < 27 , 1 < < 27 , 1 < < 27 , 1 < < 27 , 1 < < 27 , 1 < < 27 , 1 < < 27 , 0 ,
1 < < 26 , 1 < < 26 , 1 < < 26 , 1 < < 26 , 1 < < 26 , 1 < < 26 , 1 < < 26 , 1 < < 26 , 1 < < 26 , 1 < < 26 , 1 < < 26 , 1 < < 26 , 1 < < 26 , 1 < < 26 , 1 < < 26 , 0 ,
1 < < 25 , 1 < < 25 , 1 < < 25 , 1 < < 25 , 1 < < 25 , 1 < < 25 , 1 < < 25 , 1 < < 25 , 1 < < 25 , 1 < < 25 , 1 < < 25 , 1 < < 25 , 1 < < 25 , 1 < < 25 , 1 < < 25 , 0 ,
1 < < 24 , 1 < < 24 , 1 < < 24 , 1 < < 24 , 1 < < 24 , 1 < < 24 , 1 < < 24 , 1 < < 24 , 1 < < 24 , 1 < < 24 , 1 < < 24 , 1 < < 24 , 1 < < 24 , 1 < < 24 , 1 < < 24 , 0 ,
1 < < 23 , 1 < < 23 , 1 < < 23 , 1 < < 23 , 1 < < 23 , 1 < < 23 , 1 < < 23 , 1 < < 23 , 1 < < 23 , 1 < < 23 , 1 < < 23 , 1 < < 23 , 1 < < 23 , 1 < < 23 , 1 < < 23 , 0 ,
1 < < 22 , 1 < < 22 , 1 < < 22 , 1 < < 22 , 1 < < 22 , 1 < < 22 , 1 < < 22 , 1 < < 22 , 1 < < 22 , 1 < < 22 , 1 < < 22 , 1 < < 22 , 1 < < 22 , 1 < < 22 , 1 < < 22 , 0 ,
1 < < 21 , 1 < < 21 , 1 < < 21 , 1 < < 21 , 1 < < 21 , 1 < < 21 , 1 < < 21 , 1 < < 21 , 1 < < 21 , 1 < < 21 , 1 < < 21 , 1 < < 21 , 1 < < 21 , 1 < < 21 , 1 < < 21 , 0 ,
1 < < 20 , 1 < < 20 , 1 < < 20 , 1 < < 20 , 1 < < 20 , 1 < < 20 , 1 < < 20 , 1 < < 20 , 1 < < 20 , 1 < < 20 , 1 < < 20 , 1 < < 20 , 1 < < 20 , 1 < < 20 , 1 < < 20 , 0 ,
1 < < 19 , 1 < < 19 , 1 < < 19 , 1 < < 19 , 1 < < 19 , 1 < < 19 , 1 < < 19 , 1 < < 19 , 1 < < 19 , 1 < < 19 , 1 < < 19 , 1 < < 19 , 1 < < 19 , 1 < < 19 , 1 < < 19 , 0 ,
1 < < 18 , 1 < < 18 , 1 < < 18 , 1 < < 18 , 1 < < 18 , 1 < < 18 , 1 < < 18 , 1 < < 18 , 1 < < 18 , 1 < < 18 , 1 < < 18 , 1 < < 18 , 1 < < 18 , 1 < < 18 , 1 < < 18 , 0 ,
1 < < 17 , 1 < < 17 , 1 < < 17 , 1 < < 17 , 1 < < 17 , 1 < < 17 , 1 < < 17 , 1 < < 17 , 1 < < 17 , 1 < < 17 , 1 < < 17 , 1 < < 17 , 1 < < 17 , 1 < < 17 , 1 < < 17 ] ,
[ // Direction 2
1 < < 15 , 1 < < 15 , 1 < < 15 , 1 < < 15 , 1 < < 15 , 1 < < 15 , 1 < < 15 , 1 < < 15 , 1 < < 15 , 1 < < 15 , 1 < < 15 , 0 , 0 , 0 , 0 , 0 ,
1 < < 15 , 1 < < 14 , 1 < < 14 , 1 < < 14 , 1 < < 14 , 1 < < 14 , 1 < < 14 , 1 < < 14 , 1 < < 14 , 1 < < 14 , 1 < < 14 , 1 < < 14 , 0 , 0 , 0 , 0 ,
1 < < 15 , 1 < < 14 , 1 < < 13 , 1 < < 13 , 1 < < 13 , 1 < < 13 , 1 < < 13 , 1 < < 13 , 1 < < 13 , 1 < < 13 , 1 < < 13 , 1 < < 13 , 1 < < 13 , 0 , 0 , 0 ,
1 < < 15 , 1 < < 14 , 1 < < 13 , 1 < < 12 , 1 < < 12 , 1 < < 12 , 1 < < 12 , 1 < < 12 , 1 < < 12 , 1 < < 12 , 1 < < 12 , 1 < < 12 , 1 < < 12 , 1 < < 12 , 0 , 0 ,
1 < < 15 , 1 < < 14 , 1 < < 13 , 1 < < 12 , 1 < < 11 , 1 < < 11 , 1 < < 11 , 1 < < 11 , 1 < < 11 , 1 < < 11 , 1 < < 11 , 1 < < 11 , 1 < < 11 , 1 < < 11 , 1 < < 11 , 0 ,
1 < < 15 , 1 < < 14 , 1 < < 13 , 1 < < 12 , 1 < < 11 , 1 < < 10 , 1 < < 10 , 1 < < 10 , 1 < < 10 , 1 < < 10 , 1 < < 10 , 1 < < 10 , 1 < < 10 , 1 < < 10 , 1 < < 10 , 0 ,
1 < < 9 , 1 < < 14 , 1 < < 13 , 1 < < 12 , 1 < < 11 , 1 < < 10 , 1 < < 9 , 1 < < 9 , 1 < < 9 , 1 < < 9 , 1 < < 9 , 1 < < 9 , 1 < < 9 , 1 < < 9 , 1 < < 9 , 0 ,
1 < < 8 , 1 < < 8 , 1 < < 13 , 1 < < 12 , 1 < < 11 , 1 < < 10 , 1 < < 9 , 1 < < 8 , 1 < < 8 , 1 < < 8 , 1 < < 8 , 1 < < 8 , 1 < < 8 , 1 < < 8 , 1 < < 8 , 0 ,
1 < < 7 , 1 < < 7 , 1 < < 7 , 1 < < 12 , 1 < < 11 , 1 < < 10 , 1 < < 9 , 1 < < 8 , 1 < < 7 , 1 < < 7 , 1 < < 7 , 1 < < 7 , 1 < < 7 , 1 < < 7 , 1 < < 7 , 0 ,
1 < < 6 , 1 < < 6 , 1 < < 6 , 1 < < 6 , 1 < < 11 , 1 < < 10 , 1 < < 9 , 1 < < 8 , 1 < < 7 , 1 < < 6 , 1 < < 6 , 1 < < 6 , 1 < < 6 , 1 < < 6 , 1 < < 6 , 0 ,
1 < < 5 , 1 < < 5 , 1 < < 5 , 1 < < 5 , 1 < < 5 , 1 < < 10 , 1 < < 9 , 1 < < 8 , 1 < < 7 , 1 < < 6 , 1 < < 5 , 1 < < 5 , 1 < < 5 , 1 < < 5 , 1 < < 5 , 0 ,
0 , 1 < < 4 , 1 < < 4 , 1 < < 4 , 1 < < 4 , 1 < < 4 , 1 < < 9 , 1 < < 8 , 1 < < 7 , 1 < < 6 , 1 < < 5 , 1 < < 4 , 1 < < 4 , 1 < < 4 , 1 < < 4 , 0 ,
0 , 0 , 1 < < 3 , 1 < < 3 , 1 < < 3 , 1 < < 3 , 1 < < 3 , 1 < < 8 , 1 < < 7 , 1 < < 6 , 1 < < 5 , 1 < < 4 , 1 < < 3 , 1 < < 3 , 1 < < 3 , 0 ,
0 , 0 , 0 , 1 < < 2 , 1 < < 2 , 1 < < 2 , 1 < < 2 , 1 < < 2 , 1 < < 7 , 1 < < 6 , 1 < < 5 , 1 < < 4 , 1 < < 3 , 1 < < 2 , 1 < < 2 , 0 ,
0 , 0 , 0 , 0 , 1 < < 1 , 1 < < 1 , 1 < < 1 , 1 < < 1 , 1 < < 1 , 1 < < 6 , 1 < < 5 , 1 < < 4 , 1 < < 3 , 1 < < 2 , 1 < < 1 ] ,
[ // Direction 3
0 , 0 , 0 , 0 , 1 < < 15 , 1 < < 15 , 1 < < 15 , 1 < < 15 , 1 < < 15 , 1 < < 15 , 1 < < 15 , 1 < < 15 , 1 < < 15 , 1 < < 15 , 1 < < 15 , 0 ,
0 , 0 , 0 , 1 < < 14 , 1 < < 14 , 1 < < 14 , 1 < < 14 , 1 < < 14 , 1 < < 14 , 1 < < 14 , 1 < < 14 , 1 < < 14 , 1 < < 14 , 1 < < 14 , 1 < < 15 , 0 ,
0 , 0 , 1 < < 13 , 1 < < 13 , 1 < < 13 , 1 < < 13 , 1 < < 13 , 1 < < 13 , 1 < < 13 , 1 < < 13 , 1 < < 13 , 1 < < 13 , 1 < < 13 , 1 < < 14 , 1 < < 15 , 0 ,
0 , 1 < < 12 , 1 < < 12 , 1 < < 12 , 1 < < 12 , 1 < < 12 , 1 < < 12 , 1 < < 12 , 1 < < 12 , 1 < < 12 , 1 < < 12 , 1 < < 12 , 1 < < 13 , 1 < < 14 , 1 < < 15 , 0 ,
1 < < 11 , 1 < < 11 , 1 < < 11 , 1 < < 11 , 1 < < 11 , 1 < < 11 , 1 < < 11 , 1 < < 11 , 1 < < 11 , 1 < < 11 , 1 < < 11 , 1 < < 12 , 1 < < 13 , 1 < < 14 , 1 < < 15 , 0 ,
1 < < 10 , 1 < < 10 , 1 < < 10 , 1 < < 10 , 1 < < 10 , 1 < < 10 , 1 < < 10 , 1 < < 10 , 1 < < 10 , 1 < < 10 , 1 < < 11 , 1 < < 12 , 1 < < 13 , 1 < < 14 , 1 < < 15 , 0 ,
1 < < 9 , 1 < < 9 , 1 < < 9 , 1 < < 9 , 1 < < 9 , 1 < < 9 , 1 < < 9 , 1 < < 9 , 1 < < 9 , 1 < < 10 , 1 < < 11 , 1 < < 12 , 1 < < 13 , 1 < < 14 , 1 < < 9 , 0 ,
1 < < 8 , 1 < < 8 , 1 < < 8 , 1 < < 8 , 1 < < 8 , 1 < < 8 , 1 < < 8 , 1 < < 8 , 1 < < 9 , 1 < < 10 , 1 < < 11 , 1 < < 12 , 1 < < 13 , 1 < < 8 , 1 < < 8 , 0 ,
1 < < 7 , 1 < < 7 , 1 < < 7 , 1 < < 7 , 1 < < 7 , 1 < < 7 , 1 < < 7 , 1 < < 8 , 1 < < 9 , 1 < < 10 , 1 < < 11 , 1 < < 12 , 1 < < 7 , 1 < < 7 , 1 < < 7 , 0 ,
1 < < 6 , 1 < < 6 , 1 < < 6 , 1 < < 6 , 1 < < 6 , 1 < < 6 , 1 < < 7 , 1 < < 8 , 1 < < 9 , 1 < < 10 , 1 < < 11 , 1 < < 6 , 1 < < 6 , 1 < < 6 , 1 < < 6 , 0 ,
1 < < 5 , 1 < < 5 , 1 < < 5 , 1 < < 5 , 1 < < 5 , 1 < < 6 , 1 < < 7 , 1 < < 8 , 1 < < 9 , 1 < < 10 , 1 < < 5 , 1 < < 5 , 1 < < 5 , 1 < < 5 , 1 < < 5 , 0 ,
1 < < 4 , 1 < < 4 , 1 < < 4 , 1 < < 4 , 1 < < 5 , 1 < < 6 , 1 < < 7 , 1 < < 8 , 1 < < 9 , 1 < < 4 , 1 < < 4 , 1 < < 4 , 1 < < 4 , 1 < < 4 , 0 , 0 ,
1 < < 3 , 1 < < 3 , 1 < < 3 , 1 < < 4 , 1 < < 5 , 1 < < 6 , 1 < < 7 , 1 < < 8 , 1 < < 3 , 1 < < 3 , 1 < < 3 , 1 < < 3 , 1 < < 3 , 0 , 0 , 0 ,
1 < < 2 , 1 < < 2 , 1 < < 3 , 1 < < 4 , 1 < < 5 , 1 < < 6 , 1 < < 7 , 1 < < 2 , 1 < < 2 , 1 < < 2 , 1 < < 2 , 1 < < 2 , 0 , 0 , 0 , 0 ,
1 < < 1 , 1 < < 2 , 1 < < 3 , 1 < < 4 , 1 < < 5 , 1 < < 6 , 1 < < 1 , 1 < < 1 , 1 < < 1 , 1 < < 1 , 1 < < 1 , 0 , 0 , 0 , 0 ]
] ;
/// A table to encode each location to an index in the bitboard for 4 direction
#[ rustfmt::skip ]
const MAPMOVEIDX : [ [ i32 ; 239 ] ; 4 ] = [ [ // Direction 0
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 ,
2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 0 ,
3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 0 ,
4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 0 ,
5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 0 ,
6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 0 ,
7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 0 ,
8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 0 ,
9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 0 ,
10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 0 ,
11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 0 ,
12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 0 ,
13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 0 ,
14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 ] ,
[ // Direction 1
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 0 ,
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 0 ,
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 0 ,
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 0 ,
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 0 ,
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 0 ,
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 0 ,
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 0 ,
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 0 ,
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 0 ,
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 0 ,
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 0 ,
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 0 ,
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 0 ,
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 ] ,
[ // Direction 2
10 , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 , 0 , 0 , 0 , 0 , 0 , 0 ,
11 , 10 , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 , 0 , 0 , 0 , 0 , 0 ,
12 , 11 , 10 , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 , 0 , 0 , 0 , 0 ,
13 , 12 , 11 , 10 , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 , 0 , 0 , 0 ,
14 , 13 , 12 , 11 , 10 , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 , 0 , 0 ,
15 , 14 , 13 , 12 , 11 , 10 , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 , 0 ,
1 , 15 , 14 , 13 , 12 , 11 , 10 , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 0 ,
2 , 1 , 15 , 14 , 13 , 12 , 11 , 10 , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 0 ,
3 , 2 , 1 , 15 , 14 , 13 , 12 , 11 , 10 , 9 , 8 , 7 , 6 , 5 , 4 , 0 ,
4 , 3 , 2 , 1 , 15 , 14 , 13 , 12 , 11 , 10 , 9 , 8 , 7 , 6 , 5 , 0 ,
5 , 4 , 3 , 2 , 1 , 15 , 14 , 13 , 12 , 11 , 10 , 9 , 8 , 7 , 6 , 0 ,
0 , 5 , 4 , 3 , 2 , 1 , 15 , 14 , 13 , 12 , 11 , 10 , 9 , 8 , 7 , 0 ,
0 , 0 , 5 , 4 , 3 , 2 , 1 , 15 , 14 , 13 , 12 , 11 , 10 , 9 , 8 , 0 ,
0 , 0 , 0 , 5 , 4 , 3 , 2 , 1 , 15 , 14 , 13 , 12 , 11 , 10 , 9 , 0 ,
0 , 0 , 0 , 0 , 5 , 4 , 3 , 2 , 1 , 15 , 14 , 13 , 12 , 11 , 10 ] ,
[ // Direction 3
0 , 0 , 0 , 0 , 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 0 ,
0 , 0 , 0 , 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 0 ,
0 , 0 , 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 0 ,
0 , 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 0 ,
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 0 ,
1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 0 ,
2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 1 , 0 ,
3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 1 , 2 , 0 ,
4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 1 , 2 , 3 , 0 ,
5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 1 , 2 , 3 , 4 , 0 ,
6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 1 , 2 , 3 , 4 , 5 , 0 ,
7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 1 , 2 , 3 , 4 , 5 , 0 , 0 ,
8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 1 , 2 , 3 , 4 , 5 , 0 , 0 , 0 ,
9 , 10 , 11 , 12 , 13 , 14 , 15 , 1 , 2 , 3 , 4 , 5 , 0 , 0 , 0 , 0 ,
10 , 11 , 12 , 13 , 14 , 15 , 1 , 2 , 3 , 4 , 5 , 0 , 0 , 0 , 0 ]
] ;
// structures
/// Use one-dimensional array to store the board state. The location 0 is top left.\
/// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <b>15</b>\
/// 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <b>31</b>\
/// ... \
/// position 15, 31, ... are Borders.\
/// position 0 is file 0, rank 0.\
/// position 17 is file 1, rank 1.\
///
/// Use a three-dimensional array to store the bitboard.\
/// The first dimension is color: Black, White and Empty.\
/// The second and third one are 2 x 512-bit. Direction 0 and 2 use the first 512-bit. Direction 1 and
/// 3 use the second 512-bit.\
/// Each 512-bit is a 32-bit x 16 array. Direction 0 and 1 store at bit 31-16 and Direction 2 and 3 store at bit 15-0.
pub struct Pos {
// position
state : [ Color ; SQUARE_SIZE as usize ] ,
p_turn : Side ,
bitboard : [ [ [ i32 ; 16 ] ; 2 ] ; 3 ] ,
}
impl Pos {
pub fn init ( & mut self ) {
// starting position
// Set up the Border
for i in 0 .. SQUARE_SIZE as usize {
self . state [ i ] = Color ::Border ;
}
// In the beginning, all is Empty
for rk in 0 .. RANK_SIZE {
for fl in 0 .. FILE_SIZE {
let sq : Square = square_make ( fl , rk ) ;
self . state [ sq as usize ] = Color ::Empty ;
}
}
// first move is Black
self . p_turn = Color ::Black ;
let black = Color ::Black as usize ;
let white = Color ::White as usize ;
let empty = Color ::Empty as usize ;
// set up the corresponding bitboard
for i in 0 .. 2 {
for j in 0 .. 16 {
self . bitboard [ black ] [ i ] [ j ] = 0 ;
self . bitboard [ white ] [ i ] [ j ] = 0 ;
self . bitboard [ empty ] [ i ] [ j ] = 0 ;
}
}
for i in 0 .. 2 {
// use bit 31-16 to store direction 0 and 1
#[ rustfmt::skip ]
for j in 0 .. FILE_SIZE as usize {
self . bitboard [ empty ] [ i ] [ j ] = ( 1 < < 31 ) | ( 1 < < 30 ) | ( 1 < < 29 ) | ( 1 < < 28 ) | ( 1 < < 27 ) | ( 1 < < 26 ) | ( 1 < < 25 ) | ( 1 < < 24 ) | ( 1 < < 23 ) | ( 1 < < 22 ) | ( 1 < < 21 ) | ( 1 < < 20 ) | ( 1 < < 19 ) | ( 1 < < 18 ) | ( 1 < < 17 ) ;
}
}
// use bit 15-0 to store direction 2 and 3. There are 21 for each one. We combine row1 and row16, row2 and row17, row3 and row18, row4 and row19, and row 5 and row20
#[ rustfmt::skip ]
for i in 0 .. 2 {
self . bitboard [ empty ] [ i ] [ 0 ] | = ( 1 < < 15 ) | ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 12 ) | ( 1 < < 11 ) ; //row 0
self . bitboard [ empty ] [ i ] [ 1 ] | = ( 1 < < 15 ) | ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 12 ) | ( 1 < < 11 ) | ( 1 < < 10 ) /* row1 */ | ( 1 < < 9 ) | ( 1 < < 8 ) | ( 1 < < 7 ) | ( 1 < < 6 ) | ( 1 < < 5 ) | ( 1 < < 4 ) | ( 1 < < 3 ) | ( 1 < < 2 ) | ( 1 < < 1 ) ; //row16
self . bitboard [ empty ] [ i ] [ 2 ] | = ( 1 < < 15 ) | ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 12 ) | ( 1 < < 11 ) | ( 1 < < 10 ) | ( 1 < < 9 ) /* row2 */ | ( 1 < < 8 ) | ( 1 < < 7 ) | ( 1 < < 6 ) | ( 1 < < 5 ) | ( 1 < < 4 ) | ( 1 < < 3 ) | ( 1 < < 2 ) | ( 1 < < 1 ) ; //row17
self . bitboard [ empty ] [ i ] [ 3 ] | = ( 1 < < 15 ) | ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 12 ) | ( 1 < < 11 ) | ( 1 < < 10 ) | ( 1 < < 9 ) | ( 1 < < 8 ) /* row3 */ | ( 1 < < 7 ) | ( 1 < < 6 ) | ( 1 < < 5 ) | ( 1 < < 4 ) | ( 1 < < 3 ) | ( 1 < < 2 ) | ( 1 < < 1 ) ; //row18
self . bitboard [ empty ] [ i ] [ 4 ] | = ( 1 < < 15 ) | ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 12 ) | ( 1 < < 11 ) | ( 1 < < 10 ) | ( 1 < < 9 ) | ( 1 < < 8 ) | ( 1 < < 7 ) /* row4 */ | ( 1 < < 6 ) | ( 1 < < 5 ) | ( 1 < < 4 ) | ( 1 < < 3 ) | ( 1 < < 2 ) | ( 1 < < 1 ) ; //row19
self . bitboard [ empty ] [ i ] [ 5 ] | = ( 1 < < 15 ) | ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 12 ) | ( 1 < < 11 ) | ( 1 < < 10 ) | ( 1 < < 9 ) | ( 1 < < 8 ) | ( 1 < < 7 ) | ( 1 < < 6 ) /* row5 */ | ( 1 < < 5 ) | ( 1 < < 4 ) | ( 1 < < 3 ) | ( 1 < < 2 ) | ( 1 < < 1 ) ; //row20
self . bitboard [ empty ] [ i ] [ 6 ] | = ( 1 < < 15 ) | ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 12 ) | ( 1 < < 11 ) | ( 1 < < 10 ) | ( 1 < < 9 ) | ( 1 < < 8 ) | ( 1 < < 7 ) | ( 1 < < 6 ) | ( 1 < < 5 ) ; //row6
self . bitboard [ empty ] [ i ] [ 7 ] | = ( 1 < < 15 ) | ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 12 ) | ( 1 < < 11 ) | ( 1 < < 10 ) | ( 1 < < 9 ) | ( 1 < < 8 ) | ( 1 < < 7 ) | ( 1 < < 6 ) | ( 1 < < 5 ) | ( 1 < < 4 ) ; //row7
self . bitboard [ empty ] [ i ] [ 8 ] | = ( 1 < < 15 ) | ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 12 ) | ( 1 < < 11 ) | ( 1 < < 10 ) | ( 1 < < 9 ) | ( 1 < < 8 ) | ( 1 < < 7 ) | ( 1 < < 6 ) | ( 1 < < 5 ) | ( 1 < < 4 ) | ( 1 < < 3 ) ; //row8
self . bitboard [ empty ] [ i ] [ 9 ] | = ( 1 < < 15 ) | ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 12 ) | ( 1 < < 11 ) | ( 1 < < 10 ) | ( 1 < < 9 ) | ( 1 < < 8 ) | ( 1 < < 7 ) | ( 1 < < 6 ) | ( 1 < < 5 ) | ( 1 < < 4 ) | ( 1 < < 3 ) | ( 1 < < 2 ) ; //row9
self . bitboard [ empty ] [ i ] [ 10 ] | = ( 1 < < 15 ) | ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 12 ) | ( 1 < < 11 ) | ( 1 < < 10 ) | ( 1 < < 9 ) | ( 1 < < 8 ) | ( 1 < < 7 ) | ( 1 < < 6 ) | ( 1 < < 5 ) | ( 1 < < 4 ) | ( 1 < < 3 ) | ( 1 < < 2 ) | ( 1 < < 1 ) ; //row10
self . bitboard [ empty ] [ i ] [ 11 ] | = ( 1 < < 15 ) | ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 12 ) | ( 1 < < 11 ) | ( 1 < < 10 ) | ( 1 < < 9 ) | ( 1 < < 8 ) | ( 1 < < 7 ) | ( 1 < < 6 ) | ( 1 < < 5 ) | ( 1 < < 4 ) | ( 1 < < 3 ) | ( 1 < < 2 ) ; //row11
self . bitboard [ empty ] [ i ] [ 12 ] | = ( 1 < < 15 ) | ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 12 ) | ( 1 < < 11 ) | ( 1 < < 10 ) | ( 1 < < 9 ) | ( 1 < < 8 ) | ( 1 < < 7 ) | ( 1 < < 6 ) | ( 1 < < 5 ) | ( 1 < < 4 ) | ( 1 < < 3 ) ; //row12
self . bitboard [ empty ] [ i ] [ 13 ] | = ( 1 < < 15 ) | ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 12 ) | ( 1 < < 11 ) | ( 1 < < 10 ) | ( 1 < < 9 ) | ( 1 < < 8 ) | ( 1 < < 7 ) | ( 1 < < 6 ) | ( 1 < < 5 ) | ( 1 < < 4 ) ; //row13
self . bitboard [ empty ] [ i ] [ 14 ] | = ( 1 < < 15 ) | ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 12 ) | ( 1 < < 11 ) | ( 1 < < 10 ) | ( 1 < < 9 ) | ( 1 < < 8 ) | ( 1 < < 7 ) | ( 1 < < 6 ) | ( 1 < < 5 ) ; //row14
self . bitboard [ empty ] [ i ] [ 15 ] | = ( 1 < < 15 ) | ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 12 ) | ( 1 < < 11 ) | ( 1 < < 10 ) | ( 1 < < 9 ) | ( 1 < < 8 ) | ( 1 < < 7 ) | ( 1 < < 6 ) ; //row15
}
}
pub fn do_move ( & mut self , mv : Move ) {
let atk : Side = self . p_turn ;
let def : Side = side_opp ( atk ) ;
let mv = mv as usize ;
let black = Color ::Black as usize ;
let white = Color ::White as usize ;
let empty = Color ::Empty as usize ;
match self . p_turn {
Color ::Black = > {
self . state [ mv as usize ] = Color ::Black ;
// update black move and remove empty move in bitboard
self . bitboard [ black ] [ 0 ] [ MAPMOVEIDX [ 0 ] [ mv ] as usize ] | = MAPMOVEVALUE [ 0 ] [ mv ] ;
self . bitboard [ empty ] [ 0 ] [ MAPMOVEIDX [ 0 ] [ mv ] as usize ] ^ = MAPMOVEVALUE [ 0 ] [ mv ] ;
self . bitboard [ black ] [ 1 ] [ MAPMOVEIDX [ 1 ] [ mv ] as usize ] | = MAPMOVEVALUE [ 1 ] [ mv ] ;
self . bitboard [ empty ] [ 1 ] [ MAPMOVEIDX [ 1 ] [ mv ] as usize ] ^ = MAPMOVEVALUE [ 1 ] [ mv ] ;
self . bitboard [ black ] [ 0 ] [ MAPMOVEIDX [ 2 ] [ mv ] as usize ] | = MAPMOVEVALUE [ 2 ] [ mv ] ;
self . bitboard [ empty ] [ 0 ] [ MAPMOVEIDX [ 2 ] [ mv ] as usize ] ^ = MAPMOVEVALUE [ 2 ] [ mv ] ;
self . bitboard [ black ] [ 1 ] [ MAPMOVEIDX [ 3 ] [ mv ] as usize ] | = MAPMOVEVALUE [ 3 ] [ mv ] ;
self . bitboard [ empty ] [ 1 ] [ MAPMOVEIDX [ 3 ] [ mv ] as usize ] ^ = MAPMOVEVALUE [ 3 ] [ mv ] ;
}
Color ::White = > {
self . state [ mv as usize ] = Color ::White ;
// update white move and remove empty move in bitboard
self . bitboard [ white ] [ 0 ] [ MAPMOVEIDX [ 0 ] [ mv ] as usize ] | = MAPMOVEVALUE [ 0 ] [ mv ] ;
self . bitboard [ empty ] [ 0 ] [ MAPMOVEIDX [ 0 ] [ mv ] as usize ] ^ = MAPMOVEVALUE [ 0 ] [ mv ] ;
self . bitboard [ white ] [ 1 ] [ MAPMOVEIDX [ 1 ] [ mv ] as usize ] | = MAPMOVEVALUE [ 1 ] [ mv ] ;
self . bitboard [ empty ] [ 1 ] [ MAPMOVEIDX [ 1 ] [ mv ] as usize ] ^ = MAPMOVEVALUE [ 1 ] [ mv ] ;
self . bitboard [ white ] [ 0 ] [ MAPMOVEIDX [ 2 ] [ mv ] as usize ] | = MAPMOVEVALUE [ 2 ] [ mv ] ;
self . bitboard [ empty ] [ 0 ] [ MAPMOVEIDX [ 2 ] [ mv ] as usize ] ^ = MAPMOVEVALUE [ 2 ] [ mv ] ;
self . bitboard [ white ] [ 1 ] [ MAPMOVEIDX [ 3 ] [ mv ] as usize ] | = MAPMOVEVALUE [ 3 ] [ mv ] ;
self . bitboard [ empty ] [ 1 ] [ MAPMOVEIDX [ 3 ] [ mv ] as usize ] ^ = MAPMOVEVALUE [ 3 ] [ mv ] ;
}
_ = > panic! { } ,
}
self . p_turn = def ;
}
fn turn ( & self ) -> Side {
self . p_turn
}
pub fn can_play ( & self , from : Square ) -> bool {
if self . state [ from as usize ] = = Color ::Empty {
true
} else {
false
}
}
}
pub struct List {
// legal move list
p_move : [ Move ; ( FILE_SIZE * RANK_SIZE ) as usize ] ,
p_size : i32 ,
}
/// Use List to store legal moves.
impl List {
pub fn clear ( & mut self ) {
self . p_size = 0 ;
}
pub fn add ( & mut self , mv : Move ) {
self . p_move [ self . p_size as usize ] = mv ;
self . p_size + = 1 ;
}
pub fn size ( & self ) -> i32 {
self . p_size
}
pub fn shuffle ( & mut self ) {
let mut rng = thread_rng ( ) ;
let num = self . p_size ;
let mut new_move : Vec < Move > = vec! [ ] ;
for x in 0 .. ( num as usize ) {
new_move . push ( self . p_move [ x ] ) ;
}
new_move . shuffle ( & mut rng ) ;
for x in 0 .. ( self . p_size as usize ) {
self . p_move [ x ] = new_move [ x ] ;
}
}
}
// functions
fn square_make ( fl : i32 , rk : i32 ) -> Square {
rk * ( FILE_SIZE + 1 ) + fl
}
fn side_opp ( sd : Side ) -> Side {
match sd {
Side ::White = > Side ::Black ,
Side ::Black = > Side ::White ,
_ = > panic! ( " " ) ,
}
}
fn pos_is_winner ( pos : & Pos ) -> bool {
let current_side = side_opp ( pos . p_turn ) ;
check_pattern5 ( & pos , current_side )
}
fn pos_is_draw ( pos : & Pos ) -> bool {
let mut found : bool = true ;
for rk in 0 .. RANK_SIZE {
for fl in 0 .. FILE_SIZE {
let sq : Square = square_make ( fl , rk ) ;
if pos . can_play ( sq ) {
found = false ;
break ;
}
if found = = false {
break ;
}
}
}
let mut out : bool = false ;
if found = = true & & ! pos_is_winner ( pos ) {
out = true ;
}
out
}
#[ target_feature(enable = " avx512f,avx512bw " ) ]
#[ cfg(any(target_arch = " x86 " , target_arch = " x86_64 " )) ]
unsafe fn pos_is_draw_avx512 ( pos : & Pos ) -> bool {
let empty = Color ::Empty as usize ;
let board0org = _mm512_loadu_epi32 ( & pos . bitboard [ empty ] [ 0 ] [ 0 ] ) ;
let answer = _mm512_set1_epi32 ( 0 ) ;
// if all empty is 0, all board is filled.
let temp_mask = _mm512_mask_cmpneq_epi32_mask ( 0b11111111_11111111 , answer , board0org ) ;
if _popcnt32 ( temp_mask as i32 ) = = 0 & & ! pos_is_winner_avx512 ( pos ) {
return true ;
} else {
return false ;
}
}
fn pos_is_end ( pos : & Pos ) -> bool {
if pos_is_winner ( pos ) | | pos_is_draw ( pos ) {
true
} else {
false
}
}
fn pos_disp ( pos : & Pos ) {
for rk in 0 .. RANK_SIZE {
for fl in 0 .. FILE_SIZE {
let sq : Square = square_make ( fl , rk ) ;
match pos . state [ sq as usize ] {
Color ::Black = > print! ( " # " ) ,
Color ::White = > print! ( " O " ) ,
Color ::Empty = > print! ( " - " ) ,
Color ::Border = > print! ( " | " ) ,
}
}
println! ( " " ) ;
}
match pos . turn ( ) {
Color ::Black = > println! ( " black to play " ) ,
Color ::White = > println! ( " white to play " ) ,
_ = > panic! ( ) ,
}
}
fn gen_moves ( list : & mut List , pos : & Pos ) {
list . clear ( ) ;
for rk in 0 .. RANK_SIZE {
for fl in 0 .. FILE_SIZE {
let sq : Square = square_make ( fl , rk ) ;
if pos . can_play ( sq ) {
list . add ( sq ) ;
}
}
}
}
/// AI: use Minimax search with alpha-beta pruning
fn search ( pos : & Pos , alpha : i32 , beta : i32 , depth : i32 , _ply : i32 ) -> i32 {
assert! ( - EVAL_INF < = alpha & & alpha < beta & & beta < = EVAL_INF ) ;
// leaf?
#[ cfg(any(target_arch = " x86 " , target_arch = " x86_64 " )) ]
{
if is_x86_feature_detected! ( " avx512bw " ) {
unsafe {
if pos_is_winner_avx512 ( & pos ) {
return - EVAL_INF + _ply ;
}
if pos_is_draw_avx512 ( & pos ) {
return 0 ;
}
}
} else {
if pos_is_winner ( & pos ) {
return - EVAL_INF + _ply ;
}
if pos_is_draw ( & pos ) {
return 0 ;
}
}
}
#[ cfg(not(any(target_arch = " x86 " , target_arch = " x86_64 " ))) ]
{
if pos_is_winner ( & pos ) {
return - EVAL_INF + _ply ;
}
if pos_is_draw ( & pos ) {
return 0 ;
}
}
if depth = = 0 {
return eval ( & pos , _ply ) ;
}
let p_move_new : [ Move ; ( FILE_SIZE * RANK_SIZE ) as usize ] =
[ 0 ; ( FILE_SIZE * RANK_SIZE ) as usize ] ;
let mut list = List {
p_move : p_move_new ,
p_size : 0 ,
} ;
let mut bm : Move = MOVE_NONE ;
let mut bs : i32 = SCORE_NONE ;
gen_moves ( & mut list , & pos ) ;
// move loop
if _ply = = 0 {
list . shuffle ( ) ;
}
for i in 0 .. list . size ( ) {
if bs < beta {
let mv : Move = list . p_move [ i as usize ] ;
let mut new_pos = Pos {
state : pos . state ,
p_turn : pos . p_turn ,
bitboard : pos . bitboard ,
} ;
new_pos . do_move ( mv ) ;
let sc : i32 = - search ( & new_pos , - beta , - cmp ::max ( alpha , bs ) , depth - 1 , _ply + 1 ) ;
if sc > bs {
bm = mv ;
bs = sc ;
}
}
}
assert! ( bm ! = MOVE_NONE ) ;
assert! ( bs > = - EVAL_INF & & bs < = EVAL_INF ) ;
if _ply = = 0 {
bm
} else {
bs
} //best move at the root node, best score elsewhere
}
/// Evaluation function: give different scores to different patterns after a fixed depth.
fn eval ( pos : & Pos , _ply : i32 ) -> i32 {
let atk : Side = pos . turn ( ) ;
let def : Side = side_opp ( atk ) ;
// check if opp has live4 which will win playing next move
#[ cfg(any(target_arch = " x86 " , target_arch = " x86_64 " )) ]
{
if is_x86_feature_detected! ( " avx512bw " ) {
unsafe {
if check_patternlive4_avx512 ( & pos , def ) {
return - 4096 ;
}
}
} else {
if check_patternlive4 ( & pos , def ) {
return - 4096 ;
}
}
}
#[ cfg(not(any(target_arch = " x86 " , target_arch = " x86_64 " ))) ]
{
if check_patternlive4 ( & pos , def ) {
return - 4096 ;
}
}
// check if self has live4 which will win playing next move
#[ cfg(any(target_arch = " x86 " , target_arch = " x86_64 " )) ]
{
if is_x86_feature_detected! ( " avx512bw " ) {
unsafe {
if check_patternlive4_avx512 ( & pos , atk ) {
return 2560 ;
}
}
} else {
if check_patternlive4 ( & pos , atk ) {
return 2560 ;
}
}
}
#[ cfg(not(any(target_arch = " x86 " , target_arch = " x86_64 " ))) ]
{
if check_patternlive4 ( & pos , atk ) {
return 2560 ;
}
}
// check if self has dead4 which will win playing next move
#[ cfg(any(target_arch = " x86 " , target_arch = " x86_64 " )) ]
{
if is_x86_feature_detected! ( " avx512bw " ) {
unsafe {
if check_patterndead4_avx512 ( & pos , atk ) > 0 {
return 2560 ;
}
}
} else {
if check_patterndead4 ( & pos , atk ) > 0 {
return 2560 ;
}
}
}
#[ cfg(not(any(target_arch = " x86 " , target_arch = " x86_64 " ))) ]
{
if check_patterndead4 ( & pos , atk ) > 0 {
return 2560 ;
}
}
#[ cfg(any(target_arch = " x86 " , target_arch = " x86_64 " )) ]
{
if is_x86_feature_detected! ( " avx512bw " ) {
unsafe {
let n_c4 : i32 = check_patterndead4_avx512 ( & pos , def ) ;
let n_c3 : i32 = check_patternlive3_avx512 ( & pos , def ) ;
// check if opp has 2 dead4 which will win playing next move
if n_c4 > 1 {
return - 2048 ;
}
// check if opp has a dead 4 and live 3 which will win playing the next two move
if n_c4 = = 1 & & n_c3 > 0 {
return - 2048 ;
}
if check_patternlive3_avx512 ( & pos , atk ) > 1 {
return 2560 ;
}
// check if opp has 2 live3 which will win playing the next two move
if n_c3 > 1 {
return - 2048 ;
}
}
} else {
let n_c4 : i32 = check_patterndead4 ( & pos , def ) ;
let n_c3 : i32 = check_patternlive3 ( & pos , def ) ;
// check if opp has 2 dead4 which will win playing next move
if n_c4 > 1 {
return - 2048 ;
}
// check if opp has a dead 4 and live 3 which will win playing the next two move
if n_c4 = = 1 & & n_c3 > 0 {
return - 2048 ;
}
// check if self has 2 live3 which will win playing the next two move
if check_patternlive3 ( & pos , atk ) > 1 {
return 2560 ;
}
// check if opp has 2 live3 which will win playing the next two move
if n_c3 > 1 {
return - 2048 ;
}
}
}
#[ cfg(not(any(target_arch = " x86 " , target_arch = " x86_64 " ))) ]
{
let n_c4 : i32 = check_patterndead4 ( & pos , def ) ;
let n_c3 : i32 = check_patternlive3 ( & pos , def ) ;
// check if opp has 2 dead4 which will win playing next move
if n_c4 > 1 {
return - 2048 ;
}
// check if opp has a dead 4 and live 3 which will win playing the next two move
if n_c4 = = 1 & & n_c3 > 0 {
return - 2048 ;
}
// check if self has 2 live3 which will win playing the next two move
if check_patternlive3 ( & pos , atk ) > 1 {
return 2560 ;
}
// check if opp has 2 live3 which will win playing the next two move
if n_c3 > 1 {
return - 2048 ;
}
}
0
}
/// Check <b>OOOOO</b>
fn check_pattern5 ( pos : & Pos , sd : Side ) -> bool {
let mut n : i32 = 0 ;
for rk in 0 .. RANK_SIZE {
for fl in 0 .. FILE_SIZE {
let sq : Square = square_make ( fl , rk ) ;
for pat in 0 .. 4 {
let idx0 = sq ;
let idx1 = sq + DIRECTION [ pat ] [ 0 ] ;
let idx2 = sq + DIRECTION [ pat ] [ 1 ] ;
let idx3 = sq + DIRECTION [ pat ] [ 2 ] ;
let idx4 = sq + DIRECTION [ pat ] [ 3 ] ;
let val0 = pos . state [ idx0 as usize ] ;
let val1 = pos . state [ idx1 as usize ] ;
let val2 = pos . state [ idx2 as usize ] ;
let val3 = pos . state [ idx3 as usize ] ;
let val4 = pos . state [ idx4 as usize ] ;
#[ rustfmt::skip ]
if val0 = = sd & & val1 = = sd & & val2 = = sd & & val3 = = sd & & val4 = = sd { n + = 1 ; }
}
}
}
if n > 0 {
true
} else {
false
}
}
/// Check <b>-OOOO-</b>
fn check_patternlive4 ( pos : & Pos , sd : Side ) -> bool {
let mut n : i32 = 0 ;
for rk in 0 .. RANK_SIZE {
for fl in 0 .. FILE_SIZE {
let sq : Square = square_make ( fl , rk ) ;
for pat in 0 .. 4 {
let idx0 = sq ;
let idx1 = sq + DIRECTION [ pat ] [ 0 ] ;
let idx2 = sq + DIRECTION [ pat ] [ 1 ] ;
let idx3 = sq + DIRECTION [ pat ] [ 2 ] ;
let idx4 = sq + DIRECTION [ pat ] [ 3 ] ;
let idx5 = sq + DIRECTION [ pat ] [ 4 ] ;
let val0 = pos . state [ idx0 as usize ] ;
let val1 = pos . state [ idx1 as usize ] ;
let val2 = pos . state [ idx2 as usize ] ;
let val3 = pos . state [ idx3 as usize ] ;
let val4 = pos . state [ idx4 as usize ] ;
let val5 = pos . state [ idx5 as usize ] ;
#[ rustfmt::skip ]
if val0 = = Color ::Empty & & val1 = = sd & & val2 = = sd & & val3 = = sd & & val4 = = sd & & val5 = = Color ::Empty { n + = 1 ; }
}
}
}
if n > 0 {
true
} else {
false
}
}
/// Check <b>OOOO-, OOO-O, OO-OO, O-OOO, -OOOO</b>
fn check_patterndead4 ( pos : & Pos , sd : Side ) -> i32 {
let mut n : i32 = 0 ;
for rk in 0 .. RANK_SIZE {
for fl in 0 .. FILE_SIZE {
let sq : Square = square_make ( fl , rk ) ;
for dir in 0 .. 4 {
let idx0 = sq ;
let idx1 = sq + DIRECTION [ dir ] [ 0 ] ;
let idx2 = sq + DIRECTION [ dir ] [ 1 ] ;
let idx3 = sq + DIRECTION [ dir ] [ 2 ] ;
let idx4 = sq + DIRECTION [ dir ] [ 3 ] ;
let val0 = pos . state [ idx0 as usize ] ;
let val1 = pos . state [ idx1 as usize ] ;
let val2 = pos . state [ idx2 as usize ] ;
let val3 = pos . state [ idx3 as usize ] ;
let val4 = pos . state [ idx4 as usize ] ;
#[ rustfmt::skip ]
if val0 = = sd & & val1 = = sd & & val2 = = sd & & val3 = = sd & & val4 = = Color ::Empty { n + = 1 ; }
#[ rustfmt::skip ]
if val0 = = sd & & val1 = = sd & & val2 = = sd & & val3 = = Color ::Empty & & val4 = = sd { n + = 1 ; }
#[ rustfmt::skip ]
if val0 = = sd & & val1 = = sd & & val2 = = Color ::Empty & & val3 = = sd & & val4 = = sd { n + = 1 ; }
#[ rustfmt::skip ]
if val0 = = sd & & val1 = = Color ::Empty & & val2 = = sd & & val3 = = sd & & val4 = = sd { n + = 1 ; }
#[ rustfmt::skip ]
if val0 = = Color ::Empty & & val1 = = sd & & val2 = = sd & & val3 = = sd & & val4 = = sd { n + = 1 ; }
}
}
}
n
}
/// Check <b>-OOO-, -OO-O-, -O-OO-</br>
fn check_patternlive3 ( pos : & Pos , sd : Side ) -> i32 {
let mut n : i32 = 0 ;
for rk in 0 .. RANK_SIZE {
for fl in 0 .. FILE_SIZE {
let sq : Square = square_make ( fl , rk ) ;
for dir in 0 .. 4 {
let idx0 = sq ;
let idx1 = sq + DIRECTION [ dir ] [ 0 ] ;
let idx2 = sq + DIRECTION [ dir ] [ 1 ] ;
let idx3 = sq + DIRECTION [ dir ] [ 2 ] ;
let idx4 = sq + DIRECTION [ dir ] [ 3 ] ;
let idx5 = sq + DIRECTION [ dir ] [ 4 ] ;
let val0 = pos . state [ idx0 as usize ] ;
let val1 = pos . state [ idx1 as usize ] ;
let val2 = pos . state [ idx2 as usize ] ;
let val3 = pos . state [ idx3 as usize ] ;
let val4 = pos . state [ idx4 as usize ] ;
let val5 = pos . state [ idx5 as usize ] ;
#[ rustfmt::skip ]
if val0 = = Color ::Empty & & val1 = = sd & & val2 = = sd & & val3 = = sd & & val4 = = Color ::Empty { n + = 1 ; }
#[ rustfmt::skip ]
if val0 = = Color ::Empty & & val1 = = sd & & val2 = = sd & & val3 = = Color ::Empty & & val4 = = sd & & val5 = = Color ::Empty { n + = 1 ; }
#[ rustfmt::skip ]
if val0 = = Color ::Empty & & val1 = = sd & & val2 = = Color ::Empty & & val3 = = sd & & val4 = = sd & & val5 = = Color ::Empty { n + = 1 ; }
}
}
}
n
}
#[ target_feature(enable = " avx512f,avx512bw " ) ]
#[ cfg(any(target_arch = " x86 " , target_arch = " x86_64 " )) ]
unsafe fn pos_is_winner_avx512 ( pos : & Pos ) -> bool {
let current_side = side_opp ( pos . p_turn ) ;
let coloridx = current_side as usize ;
let board0org : [ __m512i ; 2 ] = [
_mm512_loadu_epi32 ( & pos . bitboard [ coloridx ] [ 0 ] [ 0 ] ) ,
_mm512_loadu_epi32 ( & pos . bitboard [ coloridx ] [ 1 ] [ 0 ] ) ,
] ; // load states from bitboard
#[ rustfmt::skip ]
let answer = _mm512_set1_epi16 ( ( 1 < < 15 ) | ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 12 ) | ( 1 < < 11 ) ) ; // an unbroken chain of five moves
// use Mask to filter out which data is not processed.
// 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
// 1 x x x x _ _ _ _ _ _ _ _ _ _ _ 0 x o x o x 0 0 0 0 0 0 0 0 0 0 0
// 2 x _ _ _ _ o _ x o _ _ _ _ _ _ 0 x o _ _ _ _ _| x x o o o x x _ _
// . ...
// . ...
// . ...
// 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 x o x o o o o o o o 0 0 0 0 0 0
//
// answer_mask[0]: 01_11..............: "0" is in row 16 and column 1-16.
// There is no data to match (x = black, o = white, _ = empty, 0 = no data).
//
//
// Then, shift one space left.
// 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
// 1 x x x _ _ _ _ _ _ _ _ _ _ _ 0 x o x o x 0 0 0 0 0 0 0 0 0 0 0 0
// . ...
// . ...
// . ...
// 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 x o x o o o o o o o 0 0 0 0 0 0 0
// answer_mask[1]: ................_10: "0" is in row 1 and column 17-32;
// There is no enough data to match (o x o x but we want to match o o o o o).
//
// answer_mask[2]: mix 2 data together (column 17-23 and column 24-32). Using Mask to make it match correctly.
// For example, column 23,24,25,26,27 is not a pattern and 24,25,26,27,28 is a pattern.
// That is why some mask bits are set to 0 from answer_mask[2] to answer_mask[10].
#[ rustfmt::skip ]
let answer_mask : [ __mmask32 ; 11 ] = [ 0b01_11_11_11_11_11_11_11_11_11_11_11_11_11_11_11 ,
0b01_11_11_11_11_11_11_11_11_11_11_11_11_11_11_10 ,
0b01_11_11_11_11_11_11_11_11_11_11_11_11_11_10_10 ,
0b01_11_11_11_11_11_11_11_11_11_11_11_11_10_10_10 ,
0b01_11_11_11_11_11_11_11_11_11_11_11_10_10_10_10 ,
0b01_11_11_11_11_11_11_11_11_11_11_10_10_10_10_10 ,
0b00_11_11_11_11_11_11_11_11_11_10_10_10_10_11_10 ,
0b00_10_11_11_11_11_11_11_11_10_10_10_10_11_11_10 ,
0b00_10_10_11_11_11_11_11_10_10_10_10_11_11_11_10 ,
0b00_10_10_10_11_11_11_10_10_10_10_11_11_11_11_10 ,
0b00_10_10_10_10_11_10_10_10_10_11_11_11_11_11_10 ] ;
let mut count_match : i32 = 0 ;
for dir in 0 .. 2 {
// direction 0 and 1
let mut board0 = board0org [ dir ] ;
let boardf = _mm512_and_si512 ( answer , board0 ) ;
let temp_mask = _mm512_mask_cmpeq_epi16_mask ( answer_mask [ 0 ] , answer , boardf ) ;
count_match + = _popcnt32 ( temp_mask as i32 ) ;
for i in 1 .. 11 {
// OOOOOOOOOOO----, the last 4 "-" cannot make an unbroken chain of five.
board0 = _mm512_slli_epi32 ( board0 , 1 ) ; // shift one space left
let boardf = _mm512_and_si512 ( answer , board0 ) ; // focus on the pattern
let temp_mask = _mm512_mask_cmpeq_epi16_mask ( answer_mask [ i ] , answer , boardf ) ; // see if it matches the pattern
count_match + = _popcnt32 ( temp_mask as i32 ) ;
}
}
if count_match > 0 {
return true ;
} else {
return false ;
}
}
#[ target_feature(enable = " avx512f,avx512bw " ) ]
#[ cfg(any(target_arch = " x86 " , target_arch = " x86_64 " )) ]
unsafe fn check_patternlive4_avx512 ( pos : & Pos , sd : Side ) -> bool {
let coloridx = sd as usize ;
let emptyidx = Color ::Empty as usize ;
#[ rustfmt::skip ]
let answer_color = _mm512_set1_epi16 ( ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 12 ) | ( 1 < < 11 ) ) ;
#[ rustfmt::skip ]
let answer_empty = _mm512_set1_epi16 ( ( 1 < < 15 ) | ( 1 < < 10 ) ) ;
#[ rustfmt::skip ]
let answer = _mm512_set1_epi16 ( ( 1 < < 15 ) | ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 12 ) | ( 1 < < 11 ) | ( 1 < < 10 ) ) ;
#[ rustfmt::skip ]
let answer_mask : [ __mmask32 ; 10 ] = [ 0b01_11_11_11_11_11_11_11_11_11_11_11_11_11_11_10 ,
0b01_11_11_11_11_11_11_11_11_11_11_11_11_11_10_10 ,
0b01_11_11_11_11_11_11_11_11_11_11_11_11_10_10_10 ,
0b01_11_11_11_11_11_11_11_11_11_11_11_10_10_10_10 ,
0b01_11_11_11_11_11_11_11_11_11_11_10_10_10_10_10 ,
0b00_11_11_11_11_11_11_11_11_11_10_10_10_10_10_10 ,
0b00_10_11_11_11_11_11_11_11_10_10_10_10_10_11_10 ,
0b00_10_10_11_11_11_11_11_10_10_10_10_10_11_11_10 ,
0b00_10_10_10_11_11_11_10_10_10_10_10_11_11_11_10 ,
0b00_10_10_10_10_11_10_10_10_10_10_11_11_11_11_10 ] ;
let board0org : [ __m512i ; 2 ] = [
_mm512_loadu_epi32 ( & pos . bitboard [ coloridx ] [ 0 ] [ 0 ] ) ,
_mm512_loadu_epi32 ( & pos . bitboard [ coloridx ] [ 1 ] [ 0 ] ) ,
] ;
let board1org : [ __m512i ; 2 ] = [
_mm512_loadu_epi32 ( & pos . bitboard [ emptyidx ] [ 0 ] [ 0 ] ) ,
_mm512_loadu_epi32 ( & pos . bitboard [ emptyidx ] [ 1 ] [ 0 ] ) ,
] ;
let mut count_match : i32 = 0 ;
for dir in 0 .. 2 {
let mut board0 = board0org [ dir ] ;
let mut board1 = board1org [ dir ] ;
let boardf1 = _mm512_and_si512 ( answer_color , board0 ) ;
let boardf2 = _mm512_and_si512 ( answer_empty , board1 ) ;
let boardf = _mm512_or_si512 ( boardf1 , boardf2 ) ;
let temp_mask = _mm512_mask_cmpeq_epi16_mask ( answer_mask [ 0 ] , answer , boardf ) ;
count_match + = _popcnt32 ( temp_mask as i32 ) ;
for i in 1 .. 10 {
board0 = _mm512_slli_epi32 ( board0 , 1 ) ;
board1 = _mm512_slli_epi32 ( board1 , 1 ) ;
let boardf1 = _mm512_and_si512 ( answer_color , board0 ) ;
let boardf2 = _mm512_and_si512 ( answer_empty , board1 ) ;
let boardf = _mm512_or_si512 ( boardf1 , boardf2 ) ;
let temp_mask = _mm512_mask_cmpeq_epi16_mask ( answer_mask [ i ] , answer , boardf ) ;
count_match + = _popcnt32 ( temp_mask as i32 ) ;
}
}
if count_match > 0 {
return true ;
} else {
return false ;
}
}
#[ target_feature(enable = " avx512f,avx512bw " ) ]
#[ cfg(any(target_arch = " x86 " , target_arch = " x86_64 " )) ]
unsafe fn check_patterndead4_avx512 ( pos : & Pos , sd : Side ) -> i32 {
let coloridx = sd as usize ;
let emptyidx = Color ::Empty as usize ;
#[ rustfmt::skip ]
let answer_color : [ __m512i ; 5 ] = [ _mm512_set1_epi16 ( ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 12 ) | ( 1 < < 11 ) ) ,
_mm512_set1_epi16 ( ( 1 < < 15 ) | ( 1 < < 13 ) | ( 1 < < 12 ) | ( 1 < < 11 ) ) ,
_mm512_set1_epi16 ( ( 1 < < 15 ) | ( 1 < < 14 ) | ( 1 < < 12 ) | ( 1 < < 11 ) ) ,
_mm512_set1_epi16 ( ( 1 < < 15 ) | ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 11 ) ) ,
_mm512_set1_epi16 ( ( 1 < < 15 ) | ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 12 ) ) ] ;
#[ rustfmt::skip ]
let answer_empty : [ __m512i ; 5 ] = [ _mm512_set1_epi16 ( 1 < < 15 ) ,
_mm512_set1_epi16 ( 1 < < 14 ) ,
_mm512_set1_epi16 ( 1 < < 13 ) ,
_mm512_set1_epi16 ( 1 < < 12 ) ,
_mm512_set1_epi16 ( 1 < < 11 ) ] ;
#[ rustfmt::skip ]
let answer = _mm512_set1_epi16 ( ( 1 < < 15 ) | ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 12 ) | ( 1 < < 11 ) ) ;
#[ rustfmt::skip ]
let answer_mask : [ __mmask32 ; 11 ] = [ 0b01_11_11_11_11_11_11_11_11_11_11_11_11_11_11_11 ,
0b01_11_11_11_11_11_11_11_11_11_11_11_11_11_11_10 ,
0b01_11_11_11_11_11_11_11_11_11_11_11_11_11_10_10 ,
0b01_11_11_11_11_11_11_11_11_11_11_11_11_10_10_10 ,
0b01_11_11_11_11_11_11_11_11_11_11_11_10_10_10_10 ,
0b01_11_11_11_11_11_11_11_11_11_11_10_10_10_10_10 ,
0b00_11_11_11_11_11_11_11_11_11_10_10_10_10_11_10 ,
0b00_10_11_11_11_11_11_11_11_10_10_10_10_11_11_10 ,
0b00_10_10_11_11_11_11_11_10_10_10_10_11_11_11_10 ,
0b00_10_10_10_11_11_11_10_10_10_10_11_11_11_11_10 ,
0b00_10_10_10_10_11_10_10_10_10_11_11_11_11_11_10 ] ;
let board0org : [ __m512i ; 2 ] = [
_mm512_loadu_epi32 ( & pos . bitboard [ coloridx ] [ 0 ] [ 0 ] ) ,
_mm512_loadu_epi32 ( & pos . bitboard [ coloridx ] [ 1 ] [ 0 ] ) ,
] ;
let board1org : [ __m512i ; 2 ] = [
_mm512_loadu_epi32 ( & pos . bitboard [ emptyidx ] [ 0 ] [ 0 ] ) ,
_mm512_loadu_epi32 ( & pos . bitboard [ emptyidx ] [ 1 ] [ 0 ] ) ,
] ;
let mut count_match : i32 = 0 ;
for pattern in 0 .. 5 {
for dir in 0 .. 2 {
let mut board0 = board0org [ dir ] ;
let mut board1 = board1org [ dir ] ;
let boardf1 = _mm512_and_si512 ( answer_color [ pattern ] , board0 ) ;
let boardf2 = _mm512_and_si512 ( answer_empty [ pattern ] , board1 ) ;
let boardf = _mm512_or_si512 ( boardf1 , boardf2 ) ;
let temp_mask = _mm512_mask_cmpeq_epi16_mask ( answer_mask [ 0 ] , answer , boardf ) ;
count_match + = _popcnt32 ( temp_mask as i32 ) ;
for i in 1 .. 11 {
board0 = _mm512_slli_epi32 ( board0 , 1 ) ;
board1 = _mm512_slli_epi32 ( board1 , 1 ) ;
let boardf1 = _mm512_and_si512 ( answer_color [ pattern ] , board0 ) ;
let boardf2 = _mm512_and_si512 ( answer_empty [ pattern ] , board1 ) ;
let boardf = _mm512_or_si512 ( boardf1 , boardf2 ) ;
let temp_mask = _mm512_mask_cmpeq_epi16_mask ( answer_mask [ i ] , answer , boardf ) ;
count_match + = _popcnt32 ( temp_mask as i32 ) ;
}
}
}
count_match
}
#[ target_feature(enable = " avx512f,avx512bw " ) ]
#[ cfg(any(target_arch = " x86 " , target_arch = " x86_64 " )) ]
unsafe fn check_patternlive3_avx512 ( pos : & Pos , sd : Side ) -> i32 {
let coloridx = sd as usize ;
let emptyidx = Color ::Empty as usize ;
#[ rustfmt::skip ]
let board0org : [ __m512i ; 2 ] = [ _mm512_loadu_epi32 ( & pos . bitboard [ coloridx ] [ 0 ] [ 0 ] ) , _mm512_loadu_epi32 ( & pos . bitboard [ coloridx ] [ 1 ] [ 0 ] ) ] ;
#[ rustfmt::skip ]
let board1org : [ __m512i ; 2 ] = [ _mm512_loadu_epi32 ( & pos . bitboard [ emptyidx ] [ 0 ] [ 0 ] ) , _mm512_loadu_epi32 ( & pos . bitboard [ emptyidx ] [ 1 ] [ 0 ] ) ] ;
#[ rustfmt::skip ]
let answer_color : [ __m512i ; 1 ] = [ _mm512_set1_epi16 ( ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 12 ) ) ] ;
#[ rustfmt::skip ]
let answer_empty : [ __m512i ; 1 ] = [ _mm512_set1_epi16 ( ( 1 < < 15 ) | ( 1 < < 11 ) ) ] ;
#[ rustfmt::skip ]
let answer : __m512i = _mm512_set1_epi16 ( ( 1 < < 15 ) | ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 12 ) | ( 1 < < 11 ) ) ;
let mut count_match : i32 = 0 ;
#[ rustfmt::skip ]
let answer_mask : [ __mmask32 ; 11 ] = [ 0b01_11_11_11_11_11_11_11_11_11_11_11_11_11_11_11 ,
0b01_11_11_11_11_11_11_11_11_11_11_11_11_11_11_10 ,
0b01_11_11_11_11_11_11_11_11_11_11_11_11_11_10_10 ,
0b01_11_11_11_11_11_11_11_11_11_11_11_11_10_10_10 ,
0b01_11_11_11_11_11_11_11_11_11_11_11_10_10_10_10 ,
0b01_11_11_11_11_11_11_11_11_11_11_10_10_10_10_10 ,
0b00_11_11_11_11_11_11_11_11_11_10_10_10_10_11_10 ,
0b00_10_11_11_11_11_11_11_11_10_10_10_10_11_11_10 ,
0b00_10_10_11_11_11_11_11_10_10_10_10_11_11_11_10 ,
0b00_10_10_10_11_11_11_10_10_10_10_11_11_11_11_10 ,
0b00_10_10_10_10_11_10_10_10_10_11_11_11_11_11_10 ] ;
for pattern in 0 .. 1 {
for dir in 0 .. 2 {
let mut board0 = board0org [ dir ] ;
let mut board1 = board1org [ dir ] ;
let boardf1 = _mm512_and_si512 ( answer_color [ pattern ] , board0 ) ;
let boardf2 = _mm512_and_si512 ( answer_empty [ pattern ] , board1 ) ;
let boardf = _mm512_or_si512 ( boardf1 , boardf2 ) ;
let temp_mask = _mm512_mask_cmpeq_epi16_mask ( answer_mask [ 0 ] , answer , boardf ) ;
count_match + = _popcnt32 ( temp_mask as i32 ) ;
for i in 1 .. 11 {
board0 = _mm512_slli_epi32 ( board0 , 1 ) ;
board1 = _mm512_slli_epi32 ( board1 , 1 ) ;
let boardf1 = _mm512_and_si512 ( answer_color [ pattern ] , board0 ) ;
let boardf2 = _mm512_and_si512 ( answer_empty [ pattern ] , board1 ) ;
let boardf = _mm512_or_si512 ( boardf1 , boardf2 ) ;
let temp_mask = _mm512_mask_cmpeq_epi16_mask ( answer_mask [ i ] , answer , boardf ) ;
count_match + = _popcnt32 ( temp_mask as i32 ) ;
}
}
}
#[ rustfmt::skip ]
let answer_color : [ __m512i ; 2 ] = [ _mm512_set1_epi16 ( ( 1 < < 14 ) | ( 1 < < 12 ) | ( 1 < < 11 ) ) ,
_mm512_set1_epi16 ( ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 11 ) ) ] ;
#[ rustfmt::skip ]
let answer_empty : [ __m512i ; 2 ] = [ _mm512_set1_epi16 ( ( 1 < < 15 ) | ( 1 < < 13 ) | ( 1 < < 10 ) ) ,
_mm512_set1_epi16 ( ( 1 < < 15 ) | ( 1 < < 12 ) | ( 1 < < 10 ) ) ] ;
#[ rustfmt::skip ]
let answer : __m512i = _mm512_set1_epi16 ( ( 1 < < 15 ) | ( 1 < < 14 ) | ( 1 < < 13 ) | ( 1 < < 12 ) | ( 1 < < 11 ) | ( 1 < < 10 ) ) ;
#[ rustfmt::skip ]
let answer_mask : [ __mmask32 ; 10 ] = [ 0b01_11_11_11_11_11_11_11_11_11_11_11_11_11_11_10 ,
0b01_11_11_11_11_11_11_11_11_11_11_11_11_11_10_10 ,
0b01_11_11_11_11_11_11_11_11_11_11_11_11_10_10_10 ,
0b01_11_11_11_11_11_11_11_11_11_11_11_10_10_10_10 ,
0b01_11_11_11_11_11_11_11_11_11_11_10_10_10_10_10 ,
0b00_11_11_11_11_11_11_11_11_11_10_10_10_10_10_10 ,
0b00_10_11_11_11_11_11_11_11_10_10_10_10_10_11_10 ,
0b00_10_10_11_11_11_11_11_10_10_10_10_10_11_11_10 ,
0b00_10_10_10_11_11_11_10_10_10_10_10_11_11_11_10 ,
0b00_10_10_10_10_11_10_10_10_10_10_11_11_11_11_10 ] ;
for pattern in 0 .. 2 {
for dir in 0 .. 2 {
let mut board0 = board0org [ dir ] ;
let mut board1 = board1org [ dir ] ;
let boardf1 = _mm512_and_si512 ( answer_color [ pattern ] , board0 ) ;
let boardf2 = _mm512_and_si512 ( answer_empty [ pattern ] , board1 ) ;
let boardf = _mm512_or_si512 ( boardf1 , boardf2 ) ;
let temp_mask = _mm512_mask_cmpeq_epi16_mask ( answer_mask [ 0 ] , answer , boardf ) ;
count_match + = _popcnt32 ( temp_mask as i32 ) ;
for i in 1 .. 10 {
board0 = _mm512_slli_epi32 ( board0 , 1 ) ;
board1 = _mm512_slli_epi32 ( board1 , 1 ) ;
let boardf1 = _mm512_and_si512 ( answer_color [ pattern ] , board0 ) ;
let boardf2 = _mm512_and_si512 ( answer_empty [ pattern ] , board1 ) ;
let boardf = _mm512_or_si512 ( boardf1 , boardf2 ) ;
let temp_mask = _mm512_mask_cmpeq_epi16_mask ( answer_mask [ i ] , answer , boardf ) ;
count_match + = _popcnt32 ( temp_mask as i32 ) ;
}
}
}
count_match
}
fn main ( ) {
#[ cfg(any(target_arch = " x86 " , target_arch = " x86_64 " )) ]
{
if is_x86_feature_detected! ( " avx512bw " ) {
println! ( " \n \n The program is running with avx512f and avx512bw intrinsics \n \n " ) ;
} else {
println! ( " \n \n The program is running with NO intrinsics. \n \n " ) ;
}
}
#[ cfg(not(any(target_arch = " x86 " , target_arch = " x86_64 " ))) ]
{
println! ( " \n \n The program is running with NO intrinsics. \n \n " ) ;
}
loop {
let start = Instant ::now ( ) ;
println! ( " Hello, this is Connect5 (Outer-Open Gomoku)! " ) ;
println! ( " Self-playing with search depth = 4 " ) ;
let test_state : [ Color ; SQUARE_SIZE as usize ] = [ Color ::Empty ; SQUARE_SIZE as usize ] ;
let test_bitboard : [ [ [ i32 ; 16 ] ; 2 ] ; 3 ] = [ [ [ 0 ; 16 ] ; 2 ] ; 3 ] ;
let mut test1 = Pos {
state : test_state ,
p_turn : Color ::Black ,
bitboard : test_bitboard ,
} ;
test1 . init ( ) ;
let mut count : i32 = 0 ;
for i in 0 .. ( FILE_SIZE * RANK_SIZE ) {
let mut next_move : Move = square_make ( 1 , 7 ) ; // set the first move is (1,7)
if i > 0 {
next_move = search ( & test1 , - EVAL_INF , EVAL_INF , 4 , 0 ) ;
} // search depth = 4
test1 . do_move ( next_move ) ;
pos_disp ( & test1 ) ;
if pos_is_end ( & test1 ) {
2022-10-25 15:17:23 -04:00
println! ( " Game over!!!!!! at Move {i} " ) ;
2020-12-25 18:42:42 -05:00
count = i + 1 ;
break ;
}
}
let duration = start . elapsed ( ) ;
println! (
" Average time for each move is: {:?} " ,
duration / count as u32
) ;
}
}