Skip to content

Commit

Permalink
bug(pgn): fixed variation pointer calculation
Browse files Browse the repository at this point in the history
  • Loading branch information
datawater committed Oct 11, 2024
1 parent 42caf20 commit 8af81d0
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 9 deletions.
3 changes: 2 additions & 1 deletion libcmbr/src/cmbr/pgntocmbr.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::{CmbrFile, SanToCmbrMvConvertor};
use crate::cmbr::CmbrGame;
use crate::cmbr::CmbrVariation;
use crate::pgn::VariationPointerT;
use crate::pgn::{PgnGame, PgnToken};
use pgn_lexer::parser::Token;

Expand Down Expand Up @@ -143,7 +144,7 @@ impl CmbrFile {
let variations = &game.variations;
let variations_iter = variations.iter();

let mut variation_pointers: HashMap<u16, u16> = HashMap::with_capacity(1);
let mut variation_pointers: HashMap<VariationPointerT, VariationPointerT> = HashMap::with_capacity(1);
variation_pointers.insert(0, 0);

for (id, variation) in variations_iter {
Expand Down
4 changes: 2 additions & 2 deletions libcmbr/src/cmbr/structs.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::collections::HashMap;

use super::u24;
use crate::utils::def_enum;
use crate::{pgn::VariationPointerT, utils::def_enum};
use litemap::LiteMap;

def_enum! (
Expand Down Expand Up @@ -73,7 +73,7 @@ pub struct CmbrGame {
/// 'u': Undefined.
pub result: char,
/// Variation pointer (main variation is 0)
pub variations: LiteMap<u16, CmbrVariation>,
pub variations: LiteMap<VariationPointerT, CmbrVariation>,
pub encountered_positions: HashMap<u32, u32>,
}

Expand Down
12 changes: 8 additions & 4 deletions libcmbr/src/pgn/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ use litemap::LiteMap;
use pgn_lexer::parser::Token;
use std::collections::VecDeque;

use crate::utils::nth_prime_number;

pub type VariationPointerT = u32;

/// An enumeration representing different types of PGN tokens.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub enum PgnToken<'a> {
/// Represents a token specific to the game, such as a move, header, or result.
Token(Token<'a>),
/// Represents a pointer to a variation.
VariationPointer(u16),
VariationPointer(VariationPointerT),
/// Represents no token. This is the default variant.
#[default]
None,
Expand All @@ -26,7 +30,7 @@ pub struct PgnVariation<'a>(pub Vec<PgnToken<'a>>);
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct PgnGame<'a> {
pub global_tokens: Vec<Token<'a>>,
pub variations: LiteMap<u16, PgnVariation<'a>>,
pub variations: LiteMap<VariationPointerT, PgnVariation<'a>>,
}

/// Builds an ast (represented as `a Vec<PgnGame>`) from the inputted Token list
Expand Down Expand Up @@ -76,7 +80,7 @@ fn next_token<'a>(
tokens: &mut VecDeque<Token<'a>>,
tree: &mut Vec<PgnGame<'a>>,
game_number: &mut u32,
variation_depth: u16,
variation_depth: VariationPointerT,
amount_of_encountered_variations: &mut u16,
) {
// NOTE: I don't know if this is slow. (Like this whole approach) I'm just gonna pretend it isn't until it causes problems
Expand Down Expand Up @@ -120,7 +124,7 @@ fn next_token<'a>(
}
}
Token::StartVariation(_) => {
let new_variation_depth = *amount_of_encountered_variations * (variation_depth + 1);
let new_variation_depth = nth_prime_number::<u32>(*amount_of_encountered_variations as u32) * (variation_depth + 1);

*amount_of_encountered_variations += 1;

Expand Down
2 changes: 1 addition & 1 deletion libcmbr/src/pgn/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ mod pgn_tests {

let ast = crate::pgn::parse_pgn(&mut mmap);

let ast_expected = "[PgnGame { global_tokens: [TagSymbol([69]), TagString([69]), TagSymbol([83]), TagString([83]), Result([42])], variations: LiteMap { values: [(0, PgnVariation([Token(MoveNumber(1, false)), Token(Move([101, 52])), VariationPointer(1), VariationPointer(2), Token(MoveNumber(1, true)), Token(Move([101, 53])), Token(MoveNumber(2, false)), Token(Move([78, 102, 51])), VariationPointer(3), VariationPointer(5), Token(MoveNumber(2, true)), Token(Move([78, 99, 54])), Token(MoveNumber(3, false)), Token(Move([66, 99, 52])), Token(Move([66, 99, 53])), Token(MoveNumber(4, false)), Token(Move([79, 45, 79]))])), (1, PgnVariation([Token(MoveNumber(1, false)), Token(Move([100, 52]))])), (2, PgnVariation([Token(MoveNumber(1, false)), Token(Move([99, 52]))])), (3, PgnVariation([Token(MoveNumber(2, false)), Token(Move([78, 99, 51])), Token(Move([100, 53])), VariationPointer(16)])), (5, PgnVariation([Token(MoveNumber(2, false)), Token(Move([100, 51]))])), (16, PgnVariation([Token(MoveNumber(2, true)), Token(Move([100, 54]))]))], _key_type: PhantomData<u16>, _value_type: PhantomData<libcmbr::pgn::ast::PgnVariation> } }, PgnGame { global_tokens: [TagSymbol([69]), TagString([69]), TagSymbol([83]), TagString([83]), Result([42])], variations: LiteMap { values: [(0, PgnVariation([Token(MoveNumber(1, false)), Token(Move([101, 52])), VariationPointer(1), VariationPointer(2), Token(MoveNumber(1, true)), Token(Move([101, 53])), Token(MoveNumber(2, false)), Token(Move([78, 102, 51])), VariationPointer(3), VariationPointer(5), Token(Commentary([32, 67, 111, 109, 109, 101, 110, 116, 32]))])), (1, PgnVariation([Token(MoveNumber(1, false)), Token(Move([100, 52]))])), (2, PgnVariation([Token(MoveNumber(1, false)), Token(Move([99, 52]))])), (3, PgnVariation([Token(MoveNumber(2, false)), Token(Move([78, 99, 51])), Token(Move([100, 53])), VariationPointer(16)])), (5, PgnVariation([Token(MoveNumber(2, false)), Token(Move([100, 51]))])), (16, PgnVariation([Token(MoveNumber(2, true)), Token(Move([100, 54]))]))], _key_type: PhantomData<u16>, _value_type: PhantomData<libcmbr::pgn::ast::PgnVariation> } }]";
let ast_expected = "[PgnGame { global_tokens: [TagSymbol([69]), TagString([69]), TagSymbol([83]), TagString([83]), Result([42])], variations: LiteMap { values: [(0, PgnVariation([Token(MoveNumber(1, false)), Token(Move([101, 52])), VariationPointer(2), VariationPointer(3), Token(MoveNumber(1, true)), Token(Move([101, 53])), Token(MoveNumber(2, false)), Token(Move([78, 102, 51])), VariationPointer(5), VariationPointer(11), Token(MoveNumber(2, true)), Token(Move([78, 99, 54])), Token(MoveNumber(3, false)), Token(Move([66, 99, 52])), Token(Move([66, 99, 53])), Token(MoveNumber(4, false)), Token(Move([79, 45, 79]))])), (2, PgnVariation([Token(MoveNumber(1, false)), Token(Move([100, 52]))])), (3, PgnVariation([Token(MoveNumber(1, false)), Token(Move([99, 52]))])), (5, PgnVariation([Token(MoveNumber(2, false)), Token(Move([78, 99, 51])), Token(Move([100, 53])), VariationPointer(42)])), (11, PgnVariation([Token(MoveNumber(2, false)), Token(Move([100, 51]))])), (42, PgnVariation([Token(MoveNumber(2, true)), Token(Move([100, 54]))]))], _key_type: PhantomData<u32>, _value_type: PhantomData<libcmbr::pgn::ast::PgnVariation> } }, PgnGame { global_tokens: [TagSymbol([69]), TagString([69]), TagSymbol([83]), TagString([83]), Result([42])], variations: LiteMap { values: [(0, PgnVariation([Token(MoveNumber(1, false)), Token(Move([101, 52])), VariationPointer(2), VariationPointer(3), Token(MoveNumber(1, true)), Token(Move([101, 53])), Token(MoveNumber(2, false)), Token(Move([78, 102, 51])), VariationPointer(5), VariationPointer(11), Token(Commentary([32, 67, 111, 109, 109, 101, 110, 116, 32]))])), (2, PgnVariation([Token(MoveNumber(1, false)), Token(Move([100, 52]))])), (3, PgnVariation([Token(MoveNumber(1, false)), Token(Move([99, 52]))])), (5, PgnVariation([Token(MoveNumber(2, false)), Token(Move([78, 99, 51])), Token(Move([100, 53])), VariationPointer(42)])), (11, PgnVariation([Token(MoveNumber(2, false)), Token(Move([100, 51]))])), (42, PgnVariation([Token(MoveNumber(2, true)), Token(Move([100, 54]))]))], _key_type: PhantomData<u32>, _value_type: PhantomData<libcmbr::pgn::ast::PgnVariation> } }]";

assert_eq!(format!("{:?}", ast), ast_expected);
}
Expand Down
44 changes: 43 additions & 1 deletion libcmbr/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::ops::{BitAnd, Shl, Shr, Sub};
use std::{collections::{BTreeSet, VecDeque}, ops::{BitAnd, Shl, Shr, Sub}};

// Macro stolen from https://stackoverflow.com/a/62759540
macro_rules! def_enum {
Expand Down Expand Up @@ -34,3 +34,45 @@ where
let mask = (T::from(1u8) << num_bits) - T::from(1u8);
return (number >> start_position) & mask;
}

pub(crate) fn nth_prime_number<T>(n: u32) -> T
where T: std::cmp::Ord + std::clone::Clone + std::convert::From<u32>
{
const PRIMES_LOOKUP: &[u32] = &[
1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83,
89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179,
181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277,
281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389,
397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499,
503, 509, 521, 523, 541,
];

if n <= 100 {
return T::from(PRIMES_LOOKUP[n as usize]);
}

let limit = if n < 6 {
15 // Small value for small n
} else {
let log_n = (n as f64).ln();
(n as f64 * (log_n + log_n.ln())).ceil() as usize
};

let mut isprime = VecDeque::from(vec![true; limit]);
let mut prime = BTreeSet::new();

isprime[0] = false;
isprime[1] = false;

for i in 2..limit {
if isprime[i] {
prime.insert(T::from(i as u32));

for j in (i * i..limit).step_by(i) {
isprime[j] = false;
}
}
}

prime.iter().nth(n as usize - 1).cloned().unwrap()
}

0 comments on commit 8af81d0

Please sign in to comment.