mirror of
https://git.proxmox.com/git/rustc
synced 2025-05-03 21:05:00 +00:00
1273 lines
57 KiB
Rust
1273 lines
57 KiB
Rust
//! <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.\
|
|
//! On Intel Tiger Lake i7-1165G7, the avx512 is around 11.11s <span>±</span> 1.31s.
|
|
//!
|
|
//! <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\nThe program is running with avx512f and avx512bw intrinsics\n\n");
|
|
} else {
|
|
println!("\n\nThe program is running with NO intrinsics.\n\n");
|
|
}
|
|
}
|
|
|
|
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
|
{
|
|
println!("\n\nThe 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) {
|
|
println!("Game over!!!!!! at Move {}", i);
|
|
count = i + 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
let duration = start.elapsed();
|
|
|
|
println!(
|
|
"Average time for each move is: {:?}",
|
|
duration / count as u32
|
|
);
|
|
}
|
|
}
|