add 54 benchmarks, small performance improvement
This commit is contained in:
@@ -3,7 +3,25 @@ name = "euler54"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "poker"
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "euler54"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rstest = "*"
|
rstest = "*"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
criterion = "*"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
debug = true
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "benchmark"
|
||||||
|
harness = false
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
use std::io::BufRead;
|
||||||
|
use std::io::BufReader;
|
||||||
|
|
||||||
|
use criterion::{criterion_group, criterion_main, Criterion};
|
||||||
|
|
||||||
|
use poker::game::Game;
|
||||||
|
|
||||||
|
fn bench_game(c: &mut Criterion) {
|
||||||
|
c.bench_function("example game", |b| {
|
||||||
|
b.iter(|| Game::from("5H 5C 6S 7S KD 2C 3S 8S 8D TD"))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bench_all(c: &mut Criterion) {
|
||||||
|
c.bench_function("all games", |b| {
|
||||||
|
let content: Vec<_> = BufReader::new(std::fs::File::open("poker.txt").unwrap())
|
||||||
|
.lines()
|
||||||
|
.map(|l| l.unwrap())
|
||||||
|
.collect();
|
||||||
|
b.iter(|| {
|
||||||
|
for line in &content {
|
||||||
|
let _ = Game::from(line.as_ref());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
criterion_group!(benches, bench_game, bench_all);
|
||||||
|
criterion_main!(benches);
|
||||||
+64
-32
@@ -3,7 +3,13 @@ use crate::value::{Value, Values};
|
|||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
pub type Cards = [Card; 5];
|
pub struct Cards {
|
||||||
|
pub array: CardsArray,
|
||||||
|
pub suit_hashset: HashSet<Suit>,
|
||||||
|
pub value_hashmap: HashMap<Value, usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
type CardsArray = [Card; 5];
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Copy, Hash)]
|
#[derive(Debug, PartialEq, PartialOrd, Eq, Ord, Clone, Copy, Hash)]
|
||||||
pub struct Card {
|
pub struct Card {
|
||||||
@@ -21,48 +27,49 @@ impl From<&str> for Card {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Contains<T> {
|
impl From<&str> for Cards {
|
||||||
fn contains_value(&self, x: &T) -> bool;
|
fn from(s: &str) -> Self {
|
||||||
}
|
let cards_array: CardsArray = s
|
||||||
|
.split_whitespace()
|
||||||
impl Contains<Value> for &Cards {
|
.map(Card::from)
|
||||||
fn contains_value(&self, x: &Value) -> bool {
|
.collect::<Vec<_>>()
|
||||||
for card in self.iter() {
|
.try_into()
|
||||||
if card.value == *x {
|
.unwrap_or_else(|_| panic!());
|
||||||
return true;
|
Cards::new(cards_array)
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CardTrait {
|
impl Cards {
|
||||||
fn have_matching_suits(&self) -> bool;
|
fn new(cards: CardsArray) -> Self {
|
||||||
fn contain_all_values_of(&self, values: &Values) -> bool;
|
let suit_hashset = cards.to_suit_hashset();
|
||||||
fn get_highest_card(&self) -> Card;
|
let value_hashmap = cards.to_value_hashmap();
|
||||||
fn have_consecutive_values(&self) -> bool;
|
Self {
|
||||||
fn to_value_hashset(&self) -> HashSet<Value>;
|
array: cards,
|
||||||
fn to_value_hashmap(&self) -> HashMap<Value, usize>;
|
suit_hashset,
|
||||||
fn to_suit_hashset(&self) -> HashSet<Suit>;
|
value_hashmap,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CardTrait for Cards {
|
pub fn have_matching_suits(&self) -> bool {
|
||||||
fn have_matching_suits(&self) -> bool {
|
self.array[1..]
|
||||||
self[1..]
|
|
||||||
.iter()
|
.iter()
|
||||||
.zip(self[..4].iter())
|
.zip(self.array[..4].iter())
|
||||||
.all(|(c1, c2)| c1.suit == c2.suit)
|
.all(|(c1, c2)| c1.suit == c2.suit)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contain_all_values_of(&self, values: &Values) -> bool {
|
pub fn contain_all_values_of(&self, values: &Values) -> bool {
|
||||||
values.iter().all(|v| self.contains_value(v))
|
values.iter().all(|v| self.value_hashmap.contains_key(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_highest_card(&self) -> Card {
|
pub fn get_highest_card(&self) -> Card {
|
||||||
*self.iter().reduce(|accum, item| max(accum, item)).unwrap()
|
*self
|
||||||
|
.array
|
||||||
|
.iter()
|
||||||
|
.reduce(|accum, item| max(accum, item))
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn have_consecutive_values(&self) -> bool {
|
pub fn have_consecutive_values(&self) -> bool {
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
for value in Value::iterator() {
|
for value in Value::iterator() {
|
||||||
if self.contains_value(value) {
|
if self.contains_value(value) {
|
||||||
@@ -77,6 +84,33 @@ impl CardTrait for Cards {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn contains_value(&self, value: &Value) -> bool {
|
||||||
|
self.value_hashmap.contains_key(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Contains<T> {
|
||||||
|
fn contains_value(&self, x: &T) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Contains<Value> for &CardsArray {
|
||||||
|
fn contains_value(&self, x: &Value) -> bool {
|
||||||
|
for card in self.iter() {
|
||||||
|
if card.value == *x {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait CardTrait {
|
||||||
|
fn to_value_hashmap(&self) -> HashMap<Value, usize>;
|
||||||
|
fn to_suit_hashset(&self) -> HashSet<Suit>;
|
||||||
|
fn to_value_hashset(&self) -> HashSet<Value>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CardTrait for CardsArray {
|
||||||
fn to_suit_hashset(&self) -> HashSet<Suit> {
|
fn to_suit_hashset(&self) -> HashSet<Suit> {
|
||||||
self.iter().map(|c| c.suit).collect()
|
self.iter().map(|c| c.suit).collect()
|
||||||
}
|
}
|
||||||
@@ -102,8 +136,6 @@ mod test {
|
|||||||
// use super::Card;
|
// use super::Card;
|
||||||
use crate::hand::Hand;
|
use crate::hand::Hand;
|
||||||
|
|
||||||
use super::CardTrait;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_consecutive_values() {
|
fn test_consecutive_values() {
|
||||||
let hand = Hand::from("2H 3C 4D 5D 6S");
|
let hand = Hand::from("2H 3C 4D 5D 6S");
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::card::{CardTrait, Cards};
|
use crate::card::Cards;
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
|
|
||||||
impl From<&Cards> for Evaluation {
|
impl From<&Cards> for Evaluation {
|
||||||
@@ -46,7 +46,7 @@ impl Evaluation {
|
|||||||
|
|
||||||
fn is_four_of_a_kind(cards: &Cards) -> Option<Value> {
|
fn is_four_of_a_kind(cards: &Cards) -> Option<Value> {
|
||||||
cards
|
cards
|
||||||
.to_value_hashmap()
|
.value_hashmap
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, count)| **count == 4)
|
.filter(|(_, count)| **count == 4)
|
||||||
.map(|(value, _)| *value)
|
.map(|(value, _)| *value)
|
||||||
@@ -55,7 +55,7 @@ impl Evaluation {
|
|||||||
|
|
||||||
fn is_full_house(cards: &Cards) -> Option<Value> {
|
fn is_full_house(cards: &Cards) -> Option<Value> {
|
||||||
if cards
|
if cards
|
||||||
.to_value_hashmap()
|
.value_hashmap
|
||||||
.values()
|
.values()
|
||||||
.filter(|v| [2, 3].contains(v))
|
.filter(|v| [2, 3].contains(v))
|
||||||
.count()
|
.count()
|
||||||
@@ -85,7 +85,7 @@ impl Evaluation {
|
|||||||
|
|
||||||
fn is_three_of_a_kind(cards: &Cards) -> Option<Value> {
|
fn is_three_of_a_kind(cards: &Cards) -> Option<Value> {
|
||||||
cards
|
cards
|
||||||
.to_value_hashmap()
|
.value_hashmap
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, count)| **count == 3)
|
.filter(|(_, count)| **count == 3)
|
||||||
.map(|(value, _)| *value)
|
.map(|(value, _)| *value)
|
||||||
@@ -93,8 +93,8 @@ impl Evaluation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_two_pairs(cards: &Cards) -> Option<Value> {
|
fn is_two_pairs(cards: &Cards) -> Option<Value> {
|
||||||
let hm = cards.to_value_hashmap();
|
let values: Vec<_> = cards
|
||||||
let values: Vec<_> = hm
|
.value_hashmap
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, count)| **count == 2)
|
.filter(|(_, count)| **count == 2)
|
||||||
.map(|(value, _)| value)
|
.map(|(value, _)| value)
|
||||||
@@ -106,9 +106,10 @@ impl Evaluation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_one_pair(cards: &Cards) -> Option<Value> {
|
fn is_one_pair(cards: &Cards) -> Option<Value> {
|
||||||
let hm = cards.to_value_hashmap();
|
if cards.value_hashmap.len() == 4 {
|
||||||
if hm.len() == 4 {
|
cards
|
||||||
hm.iter()
|
.value_hashmap
|
||||||
|
.iter()
|
||||||
.filter(|(_, count)| **count == 2)
|
.filter(|(_, count)| **count == 2)
|
||||||
.map(|(value, _)| *value)
|
.map(|(value, _)| *value)
|
||||||
.next()
|
.next()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::{card::CardTrait, hand::Hand};
|
use crate::hand::Hand;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Player {
|
pub enum Player {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::card::{Card, Cards};
|
use crate::card::Cards;
|
||||||
use crate::evaluation::Evaluation;
|
use crate::evaluation::Evaluation;
|
||||||
|
|
||||||
pub struct Hand {
|
pub struct Hand {
|
||||||
@@ -9,8 +9,7 @@ pub struct Hand {
|
|||||||
impl From<&str> for Hand {
|
impl From<&str> for Hand {
|
||||||
fn from(line: &str) -> Self {
|
fn from(line: &str) -> Self {
|
||||||
assert_eq!(line.len(), 14);
|
assert_eq!(line.len(), 14);
|
||||||
let vec: Vec<_> = line.split_whitespace().map(Card::from).collect();
|
let cards = Cards::from(line);
|
||||||
let cards: [Card; 5] = vec.try_into().unwrap_or_else(|_| panic!());
|
|
||||||
let evaluation = Evaluation::from(&cards);
|
let evaluation = Evaluation::from(&cards);
|
||||||
Self { cards, evaluation }
|
Self { cards, evaluation }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
pub mod card;
|
||||||
|
pub mod evaluation;
|
||||||
|
pub mod game;
|
||||||
|
pub mod hand;
|
||||||
|
pub mod suit;
|
||||||
|
pub mod value;
|
||||||
@@ -1,13 +1,6 @@
|
|||||||
#![allow(dead_code)]
|
|
||||||
|
|
||||||
use std::io::{BufRead, BufReader};
|
use std::io::{BufRead, BufReader};
|
||||||
|
|
||||||
mod card;
|
use poker::game;
|
||||||
mod evaluation;
|
|
||||||
mod game;
|
|
||||||
mod hand;
|
|
||||||
mod suit;
|
|
||||||
mod value;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut p1_wins = 0;
|
let mut p1_wins = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user