2017-07-17 19:42:36 +00:00
using System ;
2016-03-25 11:48:22 +00:00
using System.Collections.Generic ;
2015-12-05 10:27:00 +00:00
using System.Linq ;
2017-07-17 19:42:36 +00:00
using NadekoBot.Common ;
using NadekoBot.Extensions ;
2015-12-05 10:27:00 +00:00
2017-07-17 19:42:36 +00:00
namespace NadekoBot.Modules.Gambling.Common
2016-03-25 11:48:22 +00:00
{
public class Cards
{
2016-03-15 22:47:10 +00:00
private static readonly Dictionary < int , string > cardNames = new Dictionary < int , string > ( ) {
2015-12-05 10:27:00 +00:00
{ 1 , "Ace" } ,
{ 2 , "Two" } ,
{ 3 , "Three" } ,
{ 4 , "Four" } ,
{ 5 , "Five" } ,
{ 6 , "Six" } ,
{ 7 , "Seven" } ,
{ 8 , "Eight" } ,
{ 9 , "Nine" } ,
{ 10 , "Ten" } ,
{ 11 , "Jack" } ,
{ 12 , "Queen" } ,
2016-03-02 05:00:44 +00:00
{ 13 , "King" }
2015-12-05 10:27:00 +00:00
} ;
2016-03-15 22:47:10 +00:00
private static Dictionary < string , Func < List < Card > , bool > > handValues ;
2015-12-05 10:27:00 +00:00
2015-12-10 20:35:34 +00:00
2016-03-25 11:48:22 +00:00
public enum CardSuit
{
2016-03-15 22:47:10 +00:00
Spades = 1 ,
Hearts = 2 ,
Diamonds = 3 ,
Clubs = 4
}
2015-12-10 20:35:34 +00:00
2016-03-25 11:48:22 +00:00
public class Card : IComparable
{
2016-03-15 22:47:10 +00:00
public CardSuit Suit { get ; }
public int Number { get ; }
2016-03-02 05:00:44 +00:00
2016-03-25 11:48:22 +00:00
public string Name
{
get
{
2016-03-15 22:47:10 +00:00
var str = "" ;
2015-12-05 10:27:00 +00:00
2016-03-25 11:48:22 +00:00
if ( Number < = 10 & & Number > 1 )
{
2016-03-15 22:47:10 +00:00
str + = "_" + Number ;
2016-03-25 11:48:22 +00:00
}
else {
2016-03-15 22:47:10 +00:00
str + = GetName ( ) . ToLower ( ) ;
}
return str + "_of_" + Suit . ToString ( ) . ToLower ( ) ;
2015-12-05 10:27:00 +00:00
}
}
2016-03-25 11:48:22 +00:00
public Card ( CardSuit s , int cardNum )
{
2016-03-15 22:47:10 +00:00
this . Suit = s ;
this . Number = cardNum ;
}
2015-12-05 10:27:00 +00:00
2016-03-15 22:47:10 +00:00
public string GetName ( ) = > cardNames [ Number ] ;
2015-12-12 22:39:58 +00:00
2016-03-15 22:47:10 +00:00
public override string ToString ( ) = > cardNames [ Number ] + " Of " + Suit ;
2015-12-10 20:35:34 +00:00
2016-03-25 11:48:22 +00:00
public int CompareTo ( object obj )
{
2016-03-15 22:47:10 +00:00
if ( ! ( obj is Card ) ) return 0 ;
var c = ( Card ) obj ;
return this . Number - c . Number ;
}
2015-12-10 20:35:34 +00:00
}
2015-12-05 10:27:00 +00:00
2016-03-15 22:47:10 +00:00
private List < Card > cardPool ;
2016-03-25 11:48:22 +00:00
public List < Card > CardPool
{
2016-03-15 22:47:10 +00:00
get { return cardPool ; }
set { cardPool = value ; }
}
2015-12-05 10:27:00 +00:00
2016-03-15 22:47:10 +00:00
/// <summary>
/// Creates a new instance of the BlackJackGame, this allows you to create multiple games running at one time.
/// </summary>
2016-03-25 11:48:22 +00:00
public Cards ( )
{
2016-03-15 22:47:10 +00:00
cardPool = new List < Card > ( 52 ) ;
RefillPool ( ) ;
InitHandValues ( ) ;
}
/// <summary>
/// Restart the game of blackjack. It will only refill the pool for now. Probably wont be used, unless you want to have only 1 bjg running at one time,
/// then you will restart the same game every time.
/// </summary>
public void Restart ( ) = > RefillPool ( ) ;
/// <summary>
/// Removes all cards from the pool and refills the pool with all of the possible cards. NOTE: I think this is too expensive.
/// We should probably make it so it copies another premade list with all the cards, or something.
/// </summary>
2016-03-25 11:48:22 +00:00
private void RefillPool ( )
{
2016-03-15 22:47:10 +00:00
cardPool . Clear ( ) ;
//foreach suit
2016-03-25 11:48:22 +00:00
for ( var j = 1 ; j < 14 ; j + + )
{
2016-03-15 22:47:10 +00:00
// and number
2016-03-25 11:48:22 +00:00
for ( var i = 1 ; i < 5 ; i + + )
{
2016-03-15 22:47:10 +00:00
//generate a card of that suit and number and add it to the pool
// the pool will go from ace of spades,hears,diamonds,clubs all the way to the king of spades. hearts, ...
cardPool . Add ( new Card ( ( CardSuit ) i , j ) ) ;
}
2015-12-05 10:27:00 +00:00
}
}
2016-09-10 19:40:25 +00:00
private Random r = new NadekoRandom ( ) ;
2016-03-15 22:47:10 +00:00
/// <summary>
/// Take a card from the pool, you either take it from the top if the deck is shuffled, or from a random place if the deck is in the default order.
/// </summary>
/// <returns>A card from the pool</returns>
2016-03-25 11:48:22 +00:00
public Card DrawACard ( )
{
2016-03-15 22:47:10 +00:00
if ( CardPool . Count = = 0 )
Restart ( ) ;
//you can either do this if your deck is not shuffled
var num = r . Next ( 0 , cardPool . Count ) ;
var c = cardPool [ num ] ;
cardPool . RemoveAt ( num ) ;
return c ;
// if you want to shuffle when you fill, then take the first one
/ *
Card c = cardPool [ 0 ] ;
cardPool . RemoveAt ( 0 ) ;
return c ;
* /
}
/// <summary>
/// Shuffles the deck. Use this if you want to take cards from the top of the deck, instead of randomly. See DrawACard method.
/// </summary>
2016-03-25 11:48:22 +00:00
private void Shuffle ( )
{
2016-03-15 22:47:10 +00:00
if ( cardPool . Count < = 1 ) return ;
2016-09-10 19:40:25 +00:00
var orderedPool = cardPool . Shuffle ( ) ;
2016-03-15 22:47:10 +00:00
cardPool = cardPool as List < Card > ? ? orderedPool . ToList ( ) ;
}
2016-07-21 10:57:57 +00:00
public override string ToString ( ) = > string . Concat ( cardPool . Select ( c = > c . ToString ( ) ) ) + Environment . NewLine ;
2016-03-15 22:47:10 +00:00
2016-03-25 11:48:22 +00:00
private static void InitHandValues ( )
{
2016-03-15 22:47:10 +00:00
Func < List < Card > , bool > hasPair =
cards = > cards . GroupBy ( card = > card . Number )
. Count ( group = > group . Count ( ) = = 2 ) = = 1 ;
Func < List < Card > , bool > isPair =
cards = > cards . GroupBy ( card = > card . Number )
. Count ( group = > group . Count ( ) = = 3 ) = = 0
& & hasPair ( cards ) ;
Func < List < Card > , bool > isTwoPair =
cards = > cards . GroupBy ( card = > card . Number )
. Count ( group = > group . Count ( ) = = 2 ) = = 2 ;
Func < List < Card > , bool > isStraight =
2016-03-25 11:48:22 +00:00
cards = >
{
2016-03-15 22:47:10 +00:00
if ( cards . GroupBy ( card = > card . Number ) . Count ( ) ! = cards . Count ( ) )
return false ;
var toReturn = ( cards . Max ( card = > ( int ) card . Number )
- cards . Min ( card = > ( int ) card . Number ) = = 4 ) ;
if ( toReturn | | cards . All ( c = > c . Number ! = 1 ) ) return toReturn ;
var newCards = cards . Select ( c = > c . Number = = 1 ? new Card ( c . Suit , 14 ) : c ) ;
return ( newCards . Max ( card = > ( int ) card . Number )
- newCards . Min ( card = > ( int ) card . Number ) = = 4 ) ;
} ;
Func < List < Card > , bool > hasThreeOfKind =
cards = > cards . GroupBy ( card = > card . Number )
. Any ( group = > group . Count ( ) = = 3 ) ;
Func < List < Card > , bool > isThreeOfKind =
cards = > hasThreeOfKind ( cards ) & & ! hasPair ( cards ) ;
Func < List < Card > , bool > isFlush =
cards = > cards . GroupBy ( card = > card . Suit ) . Count ( ) = = 1 ;
Func < List < Card > , bool > isFourOfKind =
cards = > cards . GroupBy ( card = > card . Number )
. Any ( group = > group . Count ( ) = = 4 ) ;
Func < List < Card > , bool > isFullHouse =
cards = > hasPair ( cards ) & & hasThreeOfKind ( cards ) ;
Func < List < Card > , bool > hasStraightFlush =
cards = > isFlush ( cards ) & & isStraight ( cards ) ;
Func < List < Card > , bool > isRoyalFlush =
cards = > cards . Min ( card = > card . Number ) = = 1 & &
cards . Max ( card = > card . Number ) = = 13
& & hasStraightFlush ( cards ) ;
Func < List < Card > , bool > isStraightFlush =
cards = > hasStraightFlush ( cards ) & & ! isRoyalFlush ( cards ) ;
handValues = new Dictionary < string , Func < List < Card > , bool > >
{
{ "Royal Flush" , isRoyalFlush } ,
{ "Straight Flush" , isStraightFlush } ,
{ "Four Of A Kind" , isFourOfKind } ,
{ "Full House" , isFullHouse } ,
{ "Flush" , isFlush } ,
{ "Straight" , isStraight } ,
{ "Three Of A Kind" , isThreeOfKind } ,
{ "Two Pairs" , isTwoPair } ,
{ "A Pair" , isPair }
} ;
}
2015-12-10 20:35:34 +00:00
2016-03-25 11:48:22 +00:00
public static string GetHandValue ( List < Card > cards )
{
2016-03-15 22:47:10 +00:00
if ( handValues = = null )
InitHandValues ( ) ;
2016-03-25 11:48:22 +00:00
foreach ( var kvp in handValues . Where ( x = > x . Value ( cards ) ) )
{
2016-03-15 22:47:10 +00:00
return kvp . Key ;
}
2016-07-20 20:58:41 +00:00
return "High card " + ( cards . FirstOrDefault ( c = > c . Number = = 1 ) ? . GetName ( ) ? ? cards . Max ( ) . GetName ( ) ) ;
2015-12-10 20:35:34 +00:00
}
}
2015-12-05 10:27:00 +00:00
}