Worked on premature optimizations
This commit is contained in:
@@ -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,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user