use chess::{Board, Piece, Square};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StrategicMotif {
pub id: u64,
pub pattern_hash: u64,
pub motif_type: MotifType,
pub evaluation: f32,
pub context: StrategicContext,
pub confidence: f32,
pub master_games: Vec<GameReference>,
pub description: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum MotifType {
PawnStructure(PawnPattern),
PieceCoordination(CoordinationPattern),
KingSafety(SafetyPattern),
Initiative(InitiativePattern),
Endgame(EndgamePattern),
Opening(OpeningPattern),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum PawnPattern {
IsolatedPawn {
file_index: u8,
is_white: bool,
weakness_value: f32,
},
DoubledPawns {
file_index: u8,
is_white: bool,
count: u8,
},
PassedPawn {
square_index: u8,
is_white: bool,
advancement: f32,
},
PawnChain {
base_square_index: u8,
length: u8,
is_white: bool,
},
HangingPawns {
file1_index: u8,
file2_index: u8,
is_white: bool,
},
BackwardPawn { square_index: u8, is_white: bool },
PawnMajority {
kingside: bool,
is_white: bool,
advantage: f32,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum CoordinationPattern {
KnightOutpost {
square_index: u8,
is_white: bool,
strength: f32,
},
BishopPair { is_white: bool, open_diagonals: u8 },
RookLift {
from_rank_index: u8,
to_rank_index: u8,
is_white: bool,
},
QueenKnightAttack {
target_area: KingArea,
is_white: bool,
},
PositionalSacrifice { piece_type: u8, compensation: f32 }, ActivityAdvantage {
is_white: bool,
activity_differential: f32,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SafetyPattern {
CastlingStructure {
side: CastlingSide,
is_white: bool,
safety_value: f32,
},
PawnShield {
king_square_index: u8,
shield_pattern: u8,
},
KingExposure {
square_index: u8,
is_white: bool,
danger_level: f32,
},
OppositeCastling {
attacker_is_white: bool,
attack_potential: f32,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum InitiativePattern {
SpaceAdvantage {
area: BoardArea,
is_white: bool,
space_value: f32,
},
DevelopmentLead { is_white: bool, tempo_count: u8 },
PressurePoints {
square_indices: Vec<u8>,
is_white: bool,
},
PawnBreak {
break_square_index: u8,
is_white: bool,
timing: f32,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum EndgamePattern {
BishopEndgame { is_white: bool, bishop_quality: f32 },
RookEndgame {
pattern: RookPattern,
advantage: f32,
},
KingActivity {
square_index: u8,
is_white: bool,
activity: f32,
},
PawnRace { is_white: bool, race_advantage: f32 },
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum OpeningPattern {
CentralControl {
square_indices: Vec<u8>,
is_white: bool,
control_value: f32,
},
DevelopmentPrinciple {
piece_type: u8,
target_square_index: u8,
value: f32,
},
OpeningBreak {
break_move: String,
is_white: bool,
strategic_value: f32,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StrategicContext {
pub game_phase: GamePhase,
pub material_context: MaterialContext,
pub min_ply: u16,
pub max_ply: Option<u16>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum GamePhase {
Opening,
Middlegame,
Endgame,
Any,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum MaterialContext {
Equal,
Advantage(bool),
Compensation(bool),
Any,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum CastlingSide {
Kingside,
Queenside,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum BoardArea {
Center,
Kingside,
Queenside,
Rank(u8), File(u8), }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum KingArea {
Kingside,
Queenside,
Center,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum RookPattern {
ActiveRook,
PassiveRook,
RookBehindPasser,
SeventhRank,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GameReference {
pub game_id: String,
pub white: String,
pub black: String,
pub result: String,
pub ply: u16,
pub rating: Option<u16>,
}
#[derive(Debug, Clone)]
pub struct MotifMatch {
pub motif: StrategicMotif,
pub relevance: f32,
pub matching_squares: Vec<Square>,
}
pub struct StrategicDatabase {
motifs: HashMap<u64, StrategicMotif>,
pawn_matcher: PawnPatternMatcher,
piece_matcher: PiecePatternMatcher,
king_matcher: KingPatternMatcher,
evaluation_cache: lru::LruCache<u64, f32>,
total_motifs: usize,
}
impl StrategicDatabase {
pub fn new() -> Self {
Self {
motifs: HashMap::new(),
pawn_matcher: PawnPatternMatcher::new(),
piece_matcher: PiecePatternMatcher::new(),
king_matcher: KingPatternMatcher::new(),
evaluation_cache: lru::LruCache::new(std::num::NonZeroUsize::new(10000).unwrap()),
total_motifs: 0,
}
}
pub fn load_from_binary<P: AsRef<std::path::Path>>(
path: P,
) -> Result<Self, Box<dyn std::error::Error>> {
use std::fs::File;
use std::io::BufReader;
let file = File::open(path)?;
let reader = BufReader::new(file);
let motifs: Vec<StrategicMotif> = bincode::deserialize_from(reader)?;
let mut database = Self::new();
for motif in motifs {
database.add_motif(motif);
}
println!("📚 Loaded {} strategic motifs", database.total_motifs);
Ok(database)
}
pub fn save_to_binary<P: AsRef<std::path::Path>>(
&self,
path: P,
) -> Result<(), Box<dyn std::error::Error>> {
use std::fs::File;
use std::io::BufWriter;
let motifs: Vec<&StrategicMotif> = self.motifs.values().collect();
let file = File::create(path)?;
let writer = BufWriter::new(file);
bincode::serialize_into(writer, &motifs)?;
Ok(())
}
pub fn add_motif(&mut self, motif: StrategicMotif) {
self.motifs.insert(motif.pattern_hash, motif.clone());
match &motif.motif_type {
MotifType::PawnStructure(_) => self.pawn_matcher.add_pattern(&motif),
MotifType::PieceCoordination(_) => self.piece_matcher.add_pattern(&motif),
MotifType::KingSafety(_) => self.king_matcher.add_pattern(&motif),
_ => {} }
self.total_motifs += 1;
}
pub fn find_motifs(&mut self, board: &Board) -> Vec<MotifMatch> {
let board_hash = board.get_hash();
if let Some(&_cached_eval) = self.evaluation_cache.get(&board_hash) {
return vec![];
}
let mut matches = Vec::new();
matches.extend(self.pawn_matcher.find_matches(board));
matches.extend(self.piece_matcher.find_matches(board));
matches.extend(self.king_matcher.find_matches(board));
let total_eval = self.evaluate_motifs(&matches);
self.evaluation_cache.put(board_hash, total_eval);
matches
}
pub fn evaluate_motifs(&self, matches: &[MotifMatch]) -> f32 {
if matches.is_empty() {
return 0.0;
}
let weighted_sum: f32 = matches
.iter()
.map(|m| m.motif.evaluation * m.relevance * m.motif.confidence)
.sum();
let total_weight: f32 = matches
.iter()
.map(|m| m.relevance * m.motif.confidence)
.sum();
if total_weight > 0.0 {
weighted_sum / total_weight
} else {
0.0
}
}
pub fn get_strategic_evaluation(&mut self, board: &Board) -> f32 {
let matches = self.find_motifs(board);
self.evaluate_motifs(&matches)
}
pub fn stats(&self) -> StrategicDatabaseStats {
StrategicDatabaseStats {
total_motifs: self.total_motifs,
cache_size: self.evaluation_cache.len(),
cache_hit_rate: 0.0, }
}
}
#[derive(Debug)]
pub struct StrategicDatabaseStats {
pub total_motifs: usize,
pub cache_size: usize,
pub cache_hit_rate: f32,
}
pub struct PawnPatternMatcher {
patterns: Vec<StrategicMotif>,
}
impl PawnPatternMatcher {
pub fn new() -> Self {
Self {
patterns: Vec::new(),
}
}
pub fn add_pattern(&mut self, motif: &StrategicMotif) {
self.patterns.push(motif.clone());
}
pub fn find_matches(&self, board: &Board) -> Vec<MotifMatch> {
let mut matches = Vec::new();
for pattern in &self.patterns {
if let Some(motif_match) = self.match_pawn_pattern(board, pattern) {
matches.push(motif_match);
}
}
matches
}
fn match_pawn_pattern(&self, _board: &Board, _motif: &StrategicMotif) -> Option<MotifMatch> {
None
}
}
pub struct PiecePatternMatcher {
patterns: Vec<StrategicMotif>,
}
impl PiecePatternMatcher {
pub fn new() -> Self {
Self {
patterns: Vec::new(),
}
}
pub fn add_pattern(&mut self, motif: &StrategicMotif) {
self.patterns.push(motif.clone());
}
pub fn find_matches(&self, _board: &Board) -> Vec<MotifMatch> {
Vec::new()
}
}
pub struct KingPatternMatcher {
patterns: Vec<StrategicMotif>,
}
impl KingPatternMatcher {
pub fn new() -> Self {
Self {
patterns: Vec::new(),
}
}
pub fn add_pattern(&mut self, motif: &StrategicMotif) {
self.patterns.push(motif.clone());
}
pub fn find_matches(&self, _board: &Board) -> Vec<MotifMatch> {
Vec::new()
}
}
pub mod pattern_utils {
use super::*;
pub fn generate_pattern_hash(board: &Board) -> u64 {
let mut hash = 0u64;
hash ^= hash_pawn_structure(board);
hash ^= hash_piece_patterns(board);
hash ^= hash_king_positions(board);
hash
}
fn hash_pawn_structure(_board: &Board) -> u64 {
0
}
fn hash_piece_patterns(_board: &Board) -> u64 {
0
}
fn hash_king_positions(_board: &Board) -> u64 {
0
}
pub fn determine_game_phase(board: &Board) -> GamePhase {
let material_count = count_material(board);
if material_count > 60 {
GamePhase::Opening
} else if material_count > 20 {
GamePhase::Middlegame
} else {
GamePhase::Endgame
}
}
fn count_material(board: &Board) -> u32 {
let mut total = 0u32;
for square in chess::ALL_SQUARES {
if let Some(piece) = board.piece_on(square) {
match piece {
Piece::Queen => total += 9,
Piece::Rook => total += 5,
Piece::Bishop => total += 3,
Piece::Knight => total += 3,
_ => {}
}
}
}
total
}
}