use mino::Mat; mod basic; mod downstacking; pub use basic::{i_deps, max_height, row_trans}; pub use downstacking::mystery_mdse; #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub struct Features(pub usize, pub [i32; 4]); /// Computes the feature vector for the given matrix. These are the underlying values /// used to calculate the heuristic rating. pub fn features(mat: &Mat, pcnt: usize) -> Features { Features( pcnt, [ max_height(mat), i_deps(mat), row_trans(mat), mystery_mdse(mat), ], ) } #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub struct Weights(pub [i32; 4]); impl Weights { /// Default weights (determined experimentally). pub const DEFAULT: Self = Self([ 512, // max_height 1024, // i_deps 0, // FIXME: row_trans 1024, // mdse ]); /// Constant penalty given to the number of pieces placed. Each element of the weight /// vector is effectively a ratio to this constant, i.e. if this were to be doubled, /// then all of the weights should be doubled as well to produce an identical /// heuristic. pub const PER_PIECE: i32 = 1024; } impl Default for Weights { fn default() -> Self { Self::DEFAULT } } impl Features { /// Applies the given weights vector to the features. Returns the heuristic score. #[inline] pub fn evaluate(&self, weights: &Weights) -> i32 { let pcnt = self.0 as i32; let ft = &self.1; let wt = &weights.0; let mut score = Weights::PER_PIECE * pcnt; score += wt[0] * ft[0]; score += wt[1] * ft[1]; score += wt[2] * ft[2]; score += wt[3] * ft[3]; // TODO(?) quadratic weights, e.g. score += wt[i] * f[j]^2 score } }