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

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

8
.idea/.gitignore generated vendored Normal file
View file

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

11
.idea/CardGames.iml generated Normal file
View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="EMPTY_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

8
.idea/modules.xml generated Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/CardGames.iml" filepath="$PROJECT_DIR$/.idea/CardGames.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

157
Cargo.lock generated Normal file
View file

@ -0,0 +1,157 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "CardGames"
version = "0.1.0"
dependencies = [
"rand",
]
[[package]]
name = "bitflags"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "getrandom"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
dependencies = [
"cfg-if",
"libc",
"r-efi",
"wasi",
]
[[package]]
name = "libc"
version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]]
name = "ppv-lite86"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
dependencies = [
"zerocopy",
]
[[package]]
name = "proc-macro2"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "r-efi"
version = "5.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
[[package]]
name = "rand"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
dependencies = [
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
dependencies = [
"getrandom",
]
[[package]]
name = "syn"
version = "2.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "wasi"
version = "0.14.2+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
dependencies = [
"wit-bindgen-rt",
]
[[package]]
name = "wit-bindgen-rt"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
dependencies = [
"bitflags",
]
[[package]]
name = "zerocopy"
version = "0.8.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

7
Cargo.toml Normal file
View file

@ -0,0 +1,7 @@
[package]
name = "CardGames"
version = "0.1.0"
edition = "2024"
[dependencies]
rand = "0.9.1"

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;