initial commit
This commit is contained in:
commit
94b1f06590
16 changed files with 631 additions and 0 deletions
8
src/main.rs
Normal file
8
src/main.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
mod poker;
|
||||
|
||||
mod models;
|
||||
mod tests;
|
||||
|
||||
fn main() {
|
||||
poker::game()
|
||||
}
|
41
src/models/deck.rs
Normal file
41
src/models/deck.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
use rand::seq::SliceRandom;
|
||||
|
||||
const VALUES: [u8; 13] = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
|
||||
const RANKS: [&str; 13] = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"];
|
||||
const SUITS: [&str; 4] = ["♣", "◆", "♠", "♥"];
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Card {
|
||||
pub rank: String,
|
||||
pub value: u8,
|
||||
pub suit: String,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Deck {
|
||||
pub cards: Vec<Card>,
|
||||
}
|
||||
|
||||
impl Deck {
|
||||
pub fn new() -> Deck {
|
||||
let mut cards = Vec::new();
|
||||
for suit in SUITS.iter() {
|
||||
for rank in RANKS.iter() {
|
||||
cards.push(Card {
|
||||
rank: rank.to_string(),
|
||||
suit: suit.to_string(),
|
||||
value: VALUES[RANKS.iter().position(|r| r == rank).unwrap()],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Deck {
|
||||
cards,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shuffle(&mut self) {
|
||||
self.cards.shuffle(&mut rand::rng());
|
||||
}
|
||||
}
|
167
src/models/hand.rs
Normal file
167
src/models/hand.rs
Normal file
|
@ -0,0 +1,167 @@
|
|||
use crate::models::deck::{Card, Deck};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum HandSort {
|
||||
None,
|
||||
Value,
|
||||
Rank,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Hand {
|
||||
pub cards: Vec<Card>,
|
||||
pub card_sort: HandSort,
|
||||
}
|
||||
|
||||
impl Hand {
|
||||
pub fn new() -> Hand {
|
||||
Hand {
|
||||
cards: Vec::new(),
|
||||
card_sort: HandSort::None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw(&mut self, count: u8, deck: &mut Deck) {
|
||||
for _ in 0..count {
|
||||
let card = deck.cards.pop().unwrap();
|
||||
self.cards.push(card);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sort(&mut self, hand_sort: HandSort) {
|
||||
match hand_sort {
|
||||
HandSort::Value => self.sort_by_value(),
|
||||
HandSort::Rank => self.sort_by_rank(),
|
||||
HandSort::None => (),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sort_by_value(&mut self) {
|
||||
self.cards.sort_by(|a, b| a.value.cmp(&b.value));
|
||||
self.card_sort = HandSort::Value;
|
||||
}
|
||||
|
||||
pub fn sort_by_rank(&mut self) {
|
||||
//self.cards.sort_by(|a, b| a.rank.cmp(&b.rank));
|
||||
self.card_sort = HandSort::Rank;
|
||||
}
|
||||
|
||||
fn pair_count(&self) -> u8 {
|
||||
let mut pairs = 0;
|
||||
|
||||
let mut value_counts: HashMap<u8, u8> = HashMap::new();
|
||||
for card in self.cards.iter() {
|
||||
value_counts.insert(card.value, value_counts.get(&card.value).unwrap_or(&0) + 1);
|
||||
}
|
||||
|
||||
for i in value_counts.values() {
|
||||
if i > &1 {
|
||||
pairs = pairs + 1;
|
||||
}
|
||||
}
|
||||
|
||||
pairs
|
||||
}
|
||||
|
||||
pub fn has_single_pair(&mut self) -> bool {
|
||||
if !matches!(self.card_sort, HandSort::Value) {
|
||||
self.sort(HandSort::Value);
|
||||
}
|
||||
|
||||
if self.pair_count() == 1 {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn has_two_pair(&mut self) -> bool {
|
||||
if !matches!(self.card_sort, HandSort::Value) {
|
||||
self.sort(HandSort::Value);
|
||||
}
|
||||
|
||||
if self.pair_count() == 2 {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn has_three_of_a_kind(&mut self) -> bool {
|
||||
if !matches!(self.card_sort, HandSort::Value) {
|
||||
self.sort(HandSort::Value);
|
||||
}
|
||||
for i in 2..self.cards.len() {
|
||||
if self.cards[i].rank == self.cards[i - 1].rank && self.cards[i].rank == self.cards[i - 2].rank {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn has_straight(&mut self) -> bool {
|
||||
if !matches!(self.card_sort, HandSort::Value) {
|
||||
self.sort(HandSort::Value);
|
||||
}
|
||||
|
||||
let hand_size = self.cards.len();
|
||||
|
||||
// Handle Ace low straight
|
||||
if self.cards[0].value == 2 && self.cards[hand_size - 1].value == 14 {
|
||||
self.cards[hand_size - 1].value = 1;
|
||||
self.cards.rotate_right(1)
|
||||
}
|
||||
|
||||
for i in 1..self.cards.len() {
|
||||
if self.cards[i].value != self.cards[i - 1].value + 1 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
pub fn has_flush(&self) -> bool {
|
||||
for i in 1..self.cards.len() {
|
||||
if self.cards[i].suit != self.cards[i - 1].suit {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
pub fn has_full_house(&mut self) -> bool {
|
||||
if self.has_three_of_a_kind() && self.has_two_pair() {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn has_four_of_a_kind(&mut self) -> bool {
|
||||
if !matches!(self.card_sort, HandSort::Value) {
|
||||
self.sort(HandSort::Value);
|
||||
}
|
||||
for i in 3..self.cards.len() {
|
||||
if self.cards[i].rank == self.cards[i - 1].rank &&
|
||||
self.cards[i].rank == self.cards[i - 2].rank &&
|
||||
self.cards[i].rank == self.cards[i - 3].rank
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn has_straight_flush(&mut self) -> bool {
|
||||
self.has_straight() && self.has_flush()
|
||||
}
|
||||
|
||||
pub fn has_royal_flush(&mut self) -> bool {
|
||||
self.has_flush() && self.has_straight() && self.cards[0].value == 10
|
||||
}
|
||||
}
|
3
src/models/mod.rs
Normal file
3
src/models/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
pub mod deck;
|
||||
pub mod hand;
|
||||
pub mod player;
|
7
src/models/player.rs
Normal file
7
src/models/player.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
use crate::models::hand::Hand;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Player {
|
||||
pub name: String,
|
||||
pub hand: Hand,
|
||||
}
|
35
src/poker.rs
Normal file
35
src/poker.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
use crate::models::deck::{Card, Deck};
|
||||
use crate::models::hand::Hand;
|
||||
use crate::models::player::Player;
|
||||
use std::io;
|
||||
|
||||
struct Game {
|
||||
name: String,
|
||||
deck: Vec<Card>,
|
||||
}
|
||||
|
||||
pub fn game() {
|
||||
let mut deck = Deck::new();
|
||||
deck.shuffle();
|
||||
|
||||
let mut players: Vec<Player> = Vec::new();
|
||||
let mut player_count: String = String::new();
|
||||
|
||||
println!("Welcome to Poker! How many players? (1-4)");
|
||||
io::stdin().read_line(&mut player_count).expect("Failed to read line");
|
||||
let player_count: usize = player_count.trim().parse().expect("Failed to parse player count");
|
||||
|
||||
for index in 0..player_count {
|
||||
players.push(Player {
|
||||
name: String::from(format!("Player {}", index + 1)),
|
||||
hand: Hand::new(),
|
||||
});
|
||||
|
||||
players[index].hand.draw(5, &mut deck);
|
||||
players[index].hand.sort_by_value();
|
||||
}
|
||||
|
||||
for player in players.iter_mut() {
|
||||
println!("{:?}\n", player.name);
|
||||
}
|
||||
}
|
10
src/tests/deck_test.rs
Normal file
10
src/tests/deck_test.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::models::deck::Deck;
|
||||
|
||||
#[test]
|
||||
fn test_new_deck_has_52_cards() {
|
||||
let deck = Deck::new();
|
||||
assert_eq!(deck.cards.len(), 52);
|
||||
}
|
||||
}
|
160
src/tests/hand_test.rs
Normal file
160
src/tests/hand_test.rs
Normal file
|
@ -0,0 +1,160 @@
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::models::deck::{Card, Deck};
|
||||
use crate::models::hand::Hand;
|
||||
use crate::models::player::Player;
|
||||
|
||||
#[test]
|
||||
fn test_hand_has_correct_amount_of_cards_after_drawing() {
|
||||
let mut deck = Deck::new();
|
||||
let mut player = Player {
|
||||
name: String::from("Testy McTestFace"),
|
||||
hand: Hand::new(),
|
||||
};
|
||||
|
||||
player.hand.draw(5, &mut deck);
|
||||
assert_eq!(player.hand.cards.len(), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hand_adds_cards_to_exhasting_hand() {
|
||||
let mut deck = Deck::new();
|
||||
let mut player = Player {
|
||||
name: String::from("Testy McTestFace"),
|
||||
hand: Hand::new(),
|
||||
};
|
||||
|
||||
player.hand.draw(5, &mut deck);
|
||||
player.hand.draw(3, &mut deck);
|
||||
assert_eq!(player.hand.cards.len(), 8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_has_single_pair() {
|
||||
let mut hand = Hand::new();
|
||||
|
||||
hand.cards.push(Card { rank: "A".to_string(), value: 14, suit: "♥".to_string() });
|
||||
hand.cards.push(Card { rank: "2".to_string(), value: 2, suit: "♠".to_string() });
|
||||
hand.cards.push(Card { rank: "4".to_string(), value: 4, suit: "♥".to_string() });
|
||||
hand.cards.push(Card { rank: "A".to_string(), value: 14, suit: "◆".to_string() });
|
||||
hand.cards.push(Card { rank: "5".to_string(), value: 5, suit: "♣".to_string() });
|
||||
|
||||
assert_eq!(hand.has_single_pair(), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_has_two_pair() {
|
||||
let mut hand = Hand::new();
|
||||
|
||||
hand.cards.push(Card { rank: "A".to_string(), value: 14, suit: "♥".to_string() });
|
||||
hand.cards.push(Card { rank: "2".to_string(), value: 2, suit: "♠".to_string() });
|
||||
hand.cards.push(Card { rank: "2".to_string(), value: 2, suit: "♥".to_string() });
|
||||
hand.cards.push(Card { rank: "A".to_string(), value: 14, suit: "◆".to_string() });
|
||||
hand.cards.push(Card { rank: "5".to_string(), value: 5, suit: "♣".to_string() });
|
||||
|
||||
assert_eq!(hand.has_two_pair(), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_has_three_of_a_kind() {
|
||||
let mut hand = Hand::new();
|
||||
|
||||
hand.cards.push(Card { rank: "A".to_string(), value: 14, suit: "♥".to_string() });
|
||||
hand.cards.push(Card { rank: "2".to_string(), value: 2, suit: "♠".to_string() });
|
||||
hand.cards.push(Card { rank: "2".to_string(), value: 4, suit: "♥".to_string() });
|
||||
hand.cards.push(Card { rank: "5".to_string(), value: 14, suit: "◆".to_string() });
|
||||
hand.cards.push(Card { rank: "2".to_string(), value: 5, suit: "♣".to_string() });
|
||||
|
||||
assert_eq!(hand.has_three_of_a_kind(), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_has_four_of_a_kind() {
|
||||
let mut hand = Hand::new();
|
||||
|
||||
hand.cards.push(Card { rank: "2".to_string(), value: 14, suit: "♥".to_string() });
|
||||
hand.cards.push(Card { rank: "2".to_string(), value: 2, suit: "♠".to_string() });
|
||||
hand.cards.push(Card { rank: "2".to_string(), value: 4, suit: "◆".to_string() });
|
||||
hand.cards.push(Card { rank: "5".to_string(), value: 14, suit: "◆".to_string() });
|
||||
hand.cards.push(Card { rank: "2".to_string(), value: 5, suit: "♣".to_string() });
|
||||
|
||||
assert_eq!(hand.has_four_of_a_kind(), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_has_straight() {
|
||||
let mut hand = Hand::new();
|
||||
hand.cards.push(Card { rank: "9".to_string(), value: 9, suit: "◆".to_string() });
|
||||
hand.cards.push(Card { rank: "7".to_string(), value: 7, suit: "♥".to_string() });
|
||||
hand.cards.push(Card { rank: "J".to_string(), value: 11, suit: "♣".to_string() });
|
||||
hand.cards.push(Card { rank: "8".to_string(), value: 8, suit: "♠".to_string() });
|
||||
hand.cards.push(Card { rank: "10".to_string(), value: 10, suit: "◆".to_string() });
|
||||
|
||||
assert_eq!(hand.has_straight(), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_has_straight_ace_low() {
|
||||
let mut hand = Hand::new();
|
||||
|
||||
hand.cards.push(Card { rank: "2".to_string(), value: 2, suit: "♥".to_string() });
|
||||
hand.cards.push(Card { rank: "4".to_string(), value: 4, suit: "◆".to_string() });
|
||||
hand.cards.push(Card { rank: "A".to_string(), value: 14, suit: "♣".to_string() });
|
||||
hand.cards.push(Card { rank: "5".to_string(), value: 5, suit: "◆".to_string() });
|
||||
hand.cards.push(Card { rank: "3".to_string(), value: 3, suit: "♠".to_string() });
|
||||
|
||||
assert_eq!(hand.has_straight(), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_has_flush() {
|
||||
let mut hand = Hand::new();
|
||||
|
||||
hand.cards.push(Card { rank: "2".to_string(), value: 2, suit: "♥".to_string() });
|
||||
hand.cards.push(Card { rank: "4".to_string(), value: 4, suit: "♥".to_string() });
|
||||
hand.cards.push(Card { rank: "9".to_string(), value: 9, suit: "♥".to_string() });
|
||||
hand.cards.push(Card { rank: "5".to_string(), value: 5, suit: "♥".to_string() });
|
||||
hand.cards.push(Card { rank: "8".to_string(), value: 8, suit: "♥".to_string() });
|
||||
|
||||
assert_eq!(hand.has_flush(), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_has_full_house() {
|
||||
let mut hand = Hand::new();
|
||||
|
||||
hand.cards.push(Card { rank: "2".to_string(), value: 2, suit: "♥".to_string() });
|
||||
hand.cards.push(Card { rank: "5".to_string(), value: 5, suit: "♠".to_string() });
|
||||
hand.cards.push(Card { rank: "2".to_string(), value: 2, suit: "♣".to_string() });
|
||||
hand.cards.push(Card { rank: "5".to_string(), value: 5, suit: "◆".to_string() });
|
||||
hand.cards.push(Card { rank: "2".to_string(), value: 2, suit: "◆".to_string() });
|
||||
|
||||
assert_eq!(hand.has_full_house(), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_has_straight_flush() {
|
||||
let mut hand = Hand::new();
|
||||
|
||||
hand.cards.push(Card { rank: "2".to_string(), value: 2, suit: "♥".to_string() });
|
||||
hand.cards.push(Card { rank: "3".to_string(), value: 3, suit: "♥".to_string() });
|
||||
hand.cards.push(Card { rank: "4".to_string(), value: 4, suit: "♥".to_string() });
|
||||
hand.cards.push(Card { rank: "5".to_string(), value: 5, suit: "♥".to_string() });
|
||||
hand.cards.push(Card { rank: "6".to_string(), value: 6, suit: "♥".to_string() });
|
||||
|
||||
assert_eq!(hand.has_straight_flush(), true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_has_royal_flush() {
|
||||
let mut hand = Hand::new();
|
||||
|
||||
hand.cards.push(Card { rank: "10".to_string(), value: 10, suit: "♥".to_string() });
|
||||
hand.cards.push(Card { rank: "J".to_string(), value: 11, suit: "♥".to_string() });
|
||||
hand.cards.push(Card { rank: "Q".to_string(), value: 12, suit: "♥".to_string() });
|
||||
hand.cards.push(Card { rank: "K".to_string(), value: 13, suit: "♥".to_string() });
|
||||
hand.cards.push(Card { rank: "A".to_string(), value: 14, suit: "♥".to_string() });
|
||||
|
||||
assert_eq!(hand.has_royal_flush(), true)
|
||||
}
|
||||
}
|
2
src/tests/mod.rs
Normal file
2
src/tests/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
mod deck_test;
|
||||
mod hand_test;
|
Loading…
Add table
Add a link
Reference in a new issue