initial commit

This commit is contained in:
Edward Tirado Jr 2025-05-23 00:44:18 -05:00
commit 94b1f06590
16 changed files with 631 additions and 0 deletions

8
src/main.rs Normal file
View file

@ -0,0 +1,8 @@
mod poker;
mod models;
mod tests;
fn main() {
poker::game()
}

41
src/models/deck.rs Normal file
View 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
View 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
View file

@ -0,0 +1,3 @@
pub mod deck;
pub mod hand;
pub mod player;

7
src/models/player.rs Normal file
View 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
View 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
View 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
View 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
View file

@ -0,0 +1,2 @@
mod deck_test;
mod hand_test;