Worked on premature optimizations

This commit is contained in:
Lukas Wölfer
2025-07-26 15:53:26 +02:00
parent e23e0b8cde
commit a273ad0752
2 changed files with 114 additions and 13 deletions

View File

@@ -1,4 +1,6 @@
#![allow(dead_code)] #![allow(dead_code)]
use std::default;
use crate::objective::Objective; use crate::objective::Objective;
mod card; mod card;
@@ -15,7 +17,7 @@ struct Shop {
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Icon { pub enum Icon {
Circle, Circle,
Square, Square,
Triangle, Triangle,
@@ -47,9 +49,34 @@ struct Board {
objectives: [CriteriaCard; 4], objectives: [CriteriaCard; 4],
} }
#[derive(Debug, Clone, Copy, Default)]
struct PointThresholds(u32);
impl PointThresholds {
const BITFIELD_SIZE: usize = 4;
pub fn len(&self) -> usize {
(self.0.ilog2() as usize).div_ceil(Self::BITFIELD_SIZE)
}
pub fn new(points: &[u8]) -> Self {
let mut result = Self(0);
for (index, p) in points.iter().enumerate() {
result.set(index, *p);
}
result
}
fn set(&mut self, index: usize, value: u8) {
debug_assert!(value < (1 << Self::BITFIELD_SIZE));
self.0 |= u32::from(value) << (index * Self::BITFIELD_SIZE);
}
pub fn get(&self, index: usize) -> u8 {
let bitmask = (1u8 << Self::BITFIELD_SIZE) - 1;
(self.0 >> (index * Self::BITFIELD_SIZE)) as u8 & bitmask
}
}
#[derive(Debug)] #[derive(Debug)]
struct CriteriaCard { struct CriteriaCard {
objective: Objective, objective: Objective,
// Points depending on how often the criteria was met // Points depending on how often the criteria was met
points: Vec<u8>, points: PointThresholds,
} }

View File

@@ -5,9 +5,9 @@ use crate::{Icon, Painting, icon_bitfield::IconBitfield};
pub enum Objective { pub enum Objective {
AllFields, AllFields,
/// Must use every icon in the vector at least once /// Must use every icon in the vector at least once
IconsUsed(Vec<Icon>), IconsUsed(IconSet),
/// The count of all icons in the vec `.0` combined is exactly `.1` /// The count of all icons in the vec `.0` combined is exactly `.1`
ExactlyNIcons((Vec<Icon>, u8)), ExactlyNIcons((IconSet, u8)),
/// These icons are in fields exactly next to each other /// These icons are in fields exactly next to each other
/// One icon can only be the neighbor of one other icon /// One icon can only be the neighbor of one other icon
Neighbors(Vec<(Icon, Icon)>), Neighbors(Vec<(Icon, Icon)>),
@@ -15,6 +15,58 @@ pub enum Objective {
DistantNeighbors(Vec<(Icon, Icon)>), DistantNeighbors(Vec<(Icon, Icon)>),
NInARow(Icon, u8), NInARow(Icon, u8),
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct IconSet(u8);
const ICON_SET_ORDER: [Icon; 4] = [Icon::Circle, Icon::Triangle, Icon::Square, Icon::Color];
pub struct IconSetIterator {
icon_set: IconSet,
index: u8,
}
impl From<&[Icon]> for IconSet {
fn from(value: &[Icon]) -> Self {
let v = value
.iter()
.map(|x| 1 << ICON_SET_ORDER.iter().position(|v| x == v).unwrap())
.fold(0, |a, b| a | b);
Self(v)
}
}
impl IconSet {
pub fn len(&self) -> usize {
self.0.count_ones() as usize
}
}
impl Iterator for IconSetIterator {
type Item = Icon;
fn next(&mut self) -> Option<Self::Item> {
while self.index < 4 {
let old_index = self.index;
self.index += 1;
if self.icon_set.0 & (1 << old_index) != 0 {
return Some(*ICON_SET_ORDER.get(old_index as usize).unwrap());
}
}
None
}
}
impl IntoIterator for IconSet {
type Item = Icon;
type IntoIter = IconSetIterator;
fn into_iter(self) -> Self::IntoIter {
IconSetIterator {
icon_set: self,
index: 0,
}
}
}
impl Objective { impl Objective {
pub fn count_matches(&self, painting: &Painting) -> u8 { pub fn count_matches(&self, painting: &Painting) -> u8 {
@@ -28,7 +80,7 @@ impl Objective {
} }
Objective::IconsUsed(icons) => { Objective::IconsUsed(icons) => {
let bits = IconBitfield::from_painting(painting); let bits = IconBitfield::from_painting(painting);
if icons.iter().all(|i| bits.get_icon_bits(*i) > 0) { if icons.into_iter().all(|i| bits.get_icon_bits(i) > 0) {
1 1
} else { } else {
0 0
@@ -38,8 +90,8 @@ impl Objective {
let bits = IconBitfield::from_painting(painting); let bits = IconBitfield::from_painting(painting);
if icons if icons
.iter() .into_iter()
.map(|i| bits.get_icon_bits(*i).count_ones()) .map(|i| bits.get_icon_bits(i).count_ones())
.sum::<u32>() as u8 .sum::<u32>() as u8
== *count == *count
{ {
@@ -70,7 +122,10 @@ impl Objective {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{Card, Painting, objective::Objective}; use crate::{
Card, Icon, Painting,
objective::{IconSet, Objective},
};
#[test] #[test]
fn test_all_fields() { fn test_all_fields() {
@@ -89,18 +144,37 @@ mod tests {
Card::from_dbg_string("ll..."), Card::from_dbg_string("ll..."),
Card::from_dbg_string("..t.."), Card::from_dbg_string("..t.."),
]; ];
assert_eq!( assert_eq!(Objective::NInARow(Icon::Color, 2).count_matches(&v), 2);
Objective::NInARow(crate::Icon::Color, 2).count_matches(&v),
2
);
let tricky_two: Painting = [ let tricky_two: Painting = [
Card::from_dbg_string("...ll"), Card::from_dbg_string("...ll"),
Card::from_dbg_string("tl..."), Card::from_dbg_string("tl..."),
Card::from_dbg_string("..lc."), Card::from_dbg_string("..lc."),
]; ];
assert_eq!( assert_eq!(
Objective::NInARow(crate::Icon::Color, 2).count_matches(&tricky_two), Objective::NInARow(Icon::Color, 2).count_matches(&tricky_two),
2 2
); );
} }
#[test]
fn test_icons_used() {
let v: Painting = [
Card::from_dbg_string("...ll"),
Card::from_dbg_string("ll..."),
Card::from_dbg_string("..t.."),
];
assert_eq!(
Objective::IconsUsed(IconSet::from([Icon::Color].as_slice())).count_matches(&v),
1
);
assert_eq!(
Objective::IconsUsed(IconSet::from([Icon::Triangle].as_slice())).count_matches(&v),
1
);
assert_eq!(
Objective::IconsUsed(IconSet::from([Icon::Circle].as_slice())).count_matches(&v),
0
);
}
} }