diff --git a/src/Ellie.Econ/Deck/Deck.cs b/src/Ellie.Econ/Deck/Deck.cs new file mode 100644 index 0000000..78f5dd0 --- /dev/null +++ b/src/Ellie.Econ/Deck/Deck.cs @@ -0,0 +1,309 @@ +#nullable disable +namespace Ellie.Econ; + +public class Deck +{ + public enum CardSuit + { + Spades = 1, + Hearts = 2, + Diamonds = 3, + Clubs = 4 + } + + private static readonly Dictionary _cardNames = new() + { + { 1, "Ace" }, + { 2, "Two" }, + { 3, "Three" }, + { 4, "Four" }, + { 5, "Five" }, + { 6, "Six" }, + { 7, "Seven" }, + { 8, "Eight" }, + { 9, "Nine" }, + { 10, "Ten" }, + { 11, "Jack" }, + { 12, "Queen" }, + { 13, "King" } + }; + + private static Dictionary, bool>> handValues; + + public List CardPool { get; set; } + private readonly Random _r = new EllieRandom(); + + static Deck() + => InitHandValues(); + + /// + /// Creates a new instance of the BlackJackGame, this allows you to create multiple games running at one time. + /// + public Deck() + => RefillPool(); + + /// + /// 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. + /// + public void Restart() + => RefillPool(); + + /// + /// 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. + /// + protected virtual void RefillPool() + { + CardPool = new(52); + //foreach suit + for (var j = 1; j < 14; j++) + // and number + for (var i = 1; i < 5; i++) + //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((CardSuit)i, j)); + } + + /// + /// 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. + /// + /// A card from the pool + public Card Draw() + { + 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; + */ + } + + /// + /// Shuffles the deck. Use this if you want to take cards from the top of the deck, instead of randomly. See DrawACard + /// method. + /// + private void Shuffle() + { + if (CardPool.Count <= 1) + return; + var orderedPool = CardPool.Shuffle(); + CardPool ??= orderedPool.ToList(); + } + + public override string ToString() + => string.Concat(CardPool.Select(c => c.ToString())) + Environment.NewLine; + + private static void InitHandValues() + { + bool HasPair(List cards) + { + return cards.GroupBy(card => card.Number).Count(group => group.Count() == 2) == 1; + } + + bool IsPair(List cards) + { + return cards.GroupBy(card => card.Number).Count(group => group.Count() == 3) == 0 && HasPair(cards); + } + + bool IsTwoPair(List cards) + { + return cards.GroupBy(card => card.Number).Count(group => group.Count() == 2) == 2; + } + + bool IsStraight(List cards) + { + if (cards.GroupBy(card => card.Number).Count() != cards.Count()) + return false; + var toReturn = cards.Max(card => card.Number) - cards.Min(card => card.Number) == 4; + if (toReturn || cards.All(c => c.Number != 1)) + return toReturn; + + var newCards = cards.Select(c => c.Number == 1 ? new(c.Suit, 14) : c).ToArray(); + return newCards.Max(card => card.Number) - newCards.Min(card => card.Number) == 4; + } + + bool HasThreeOfKind(List cards) + { + return cards.GroupBy(card => card.Number).Any(group => group.Count() == 3); + } + + bool IsThreeOfKind(List cards) + { + return HasThreeOfKind(cards) && !HasPair(cards); + } + + bool IsFlush(List cards) + { + return cards.GroupBy(card => card.Suit).Count() == 1; + } + + bool IsFourOfKind(List cards) + { + return cards.GroupBy(card => card.Number).Any(group => group.Count() == 4); + } + + bool IsFullHouse(List cards) + { + return HasPair(cards) && HasThreeOfKind(cards); + } + + bool HasStraightFlush(List cards) + { + return IsFlush(cards) && IsStraight(cards); + } + + bool IsRoyalFlush(List cards) + { + return cards.Min(card => card.Number) == 1 + && cards.Max(card => card.Number) == 13 + && HasStraightFlush(cards); + } + + bool IsStraightFlush(List cards) + { + return HasStraightFlush(cards) && !IsRoyalFlush(cards); + } + + handValues = new() + { + { "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 } + }; + } + + public static string GetHandValue(List cards) + { + if (handValues is null) + InitHandValues(); + + foreach (var kvp in handValues.Where(x => x.Value(cards))) + return kvp.Key; + return "High card " + (cards.FirstOrDefault(c => c.Number == 1)?.GetValueText() ?? cards.Max().GetValueText()); + } + + public class Card : IComparable + { + private static readonly IReadOnlyDictionary _suitToSuitChar = new Dictionary + { + { CardSuit.Diamonds, "♦" }, + { CardSuit.Clubs, "♣" }, + { CardSuit.Spades, "♠" }, + { CardSuit.Hearts, "♥" } + }; + + private static readonly IReadOnlyDictionary _suitCharToSuit = new Dictionary + { + { "♦", CardSuit.Diamonds }, + { "d", CardSuit.Diamonds }, + { "♣", CardSuit.Clubs }, + { "c", CardSuit.Clubs }, + { "♠", CardSuit.Spades }, + { "s", CardSuit.Spades }, + { "♥", CardSuit.Hearts }, + { "h", CardSuit.Hearts } + }; + + private static readonly IReadOnlyDictionary _numberCharToNumber = new Dictionary + { + { 'a', 1 }, + { '2', 2 }, + { '3', 3 }, + { '4', 4 }, + { '5', 5 }, + { '6', 6 }, + { '7', 7 }, + { '8', 8 }, + { '9', 9 }, + { 't', 10 }, + { 'j', 11 }, + { 'q', 12 }, + { 'k', 13 } + }; + + public CardSuit Suit { get; } + public int Number { get; } + + public string FullName + { + get + { + var str = string.Empty; + + if (Number is <= 10 and > 1) + str += "_" + Number; + else + str += GetValueText().ToLowerInvariant(); + return str + "_of_" + Suit.ToString().ToLowerInvariant(); + } + } + + private readonly string[] _regIndicators = + { + "🇦", ":two:", ":three:", ":four:", ":five:", ":six:", ":seven:", ":eight:", ":nine:", ":keycap_ten:", + "🇯", "🇶", "🇰" + }; + + public Card(CardSuit s, int cardNum) + { + Suit = s; + Number = cardNum; + } + + public string GetValueText() + => _cardNames[Number]; + + public override string ToString() + => _cardNames[Number] + " Of " + Suit; + + public int CompareTo(object obj) + { + if (obj is not Card card) + return 0; + return Number - card.Number; + } + + public static Card Parse(string input) + { + if (string.IsNullOrWhiteSpace(input)) + throw new ArgumentNullException(nameof(input)); + + if (input.Length != 2 + || !_numberCharToNumber.TryGetValue(input[0], out var n) + || !_suitCharToSuit.TryGetValue(input[1].ToString(), out var s)) + throw new ArgumentException("Invalid input", nameof(input)); + + return new(s, n); + } + + public string GetEmojiString() + { + var str = string.Empty; + + str += _regIndicators[Number - 1]; + str += _suitToSuitChar[Suit]; + + return str; + } + } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Deck/NewCard.cs b/src/Ellie.Econ/Deck/NewCard.cs new file mode 100644 index 0000000..4a091a4 --- /dev/null +++ b/src/Ellie.Econ/Deck/NewCard.cs @@ -0,0 +1,5 @@ +namespace Ellie.Econ; + +public abstract record class NewCard(TSuit Suit, TValue Value) + where TSuit : struct, Enum + where TValue : struct, Enum; \ No newline at end of file diff --git a/src/Ellie.Econ/Deck/NewDeck.cs b/src/Ellie.Econ/Deck/NewDeck.cs new file mode 100644 index 0000000..a71406c --- /dev/null +++ b/src/Ellie.Econ/Deck/NewDeck.cs @@ -0,0 +1,54 @@ +namespace Ellie.Econ; + +public abstract class NewDeck + where TCard: NewCard + where TSuit : struct, Enum + where TValue : struct, Enum +{ + protected static readonly TSuit[] _suits = Enum.GetValues(); + protected static readonly TValue[] _values = Enum.GetValues(); + + public virtual int CurrentCount + => _cards.Count; + + public virtual int TotalCount { get; } + + protected readonly LinkedList _cards = new(); + public NewDeck() + { + TotalCount = _suits.Length * _values.Length; + } + + public virtual TCard? Draw() + { + var first = _cards.First; + if (first is not null) + { + _cards.RemoveFirst(); + return first.Value; + } + + return null; + } + + public virtual TCard? Peek(int x = 0) + { + var card = _cards.First; + for (var i = 0; i < x; i++) + { + card = card?.Next; + } + + return card?.Value; + } + + public virtual void Shuffle() + { + var cards = _cards.ToList(); + var newCards = cards.Shuffle(); + + _cards.Clear(); + foreach (var card in newCards) + _cards.AddFirst(card); + } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Deck/Regular/MultipleRegularDeck/MultipleRegularDeck.cs b/src/Ellie.Econ/Deck/Regular/MultipleRegularDeck/MultipleRegularDeck.cs new file mode 100644 index 0000000..2a7e7df --- /dev/null +++ b/src/Ellie.Econ/Deck/Regular/MultipleRegularDeck/MultipleRegularDeck.cs @@ -0,0 +1,28 @@ +namespace Ellie.Econ; + +public class MultipleRegularDeck : NewDeck +{ + private int Decks { get; } + + public override int TotalCount { get; } + + public MultipleRegularDeck(int decks = 1) + { + if (decks < 1) + throw new ArgumentOutOfRangeException(nameof(decks), "Has to be more than 0"); + + Decks = decks; + TotalCount = base.TotalCount * decks; + + for (var i = 0; i < Decks; i++) + { + foreach (var suit in _suits) + { + foreach (var val in _values) + { + _cards.AddLast((RegularCard)Activator.CreateInstance(typeof(RegularCard), suit, val)!); + } + } + } + } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Deck/Regular/RegularCard.cs b/src/Ellie.Econ/Deck/Regular/RegularCard.cs new file mode 100644 index 0000000..337a1ff --- /dev/null +++ b/src/Ellie.Econ/Deck/Regular/RegularCard.cs @@ -0,0 +1,4 @@ +namespace Ellie.Econ; + +public sealed record class RegularCard(RegularSuit Suit, RegularValue Value) + : NewCard(Suit, Value); \ No newline at end of file diff --git a/src/Ellie.Econ/Deck/Regular/RegularDeck.cs b/src/Ellie.Econ/Deck/Regular/RegularDeck.cs new file mode 100644 index 0000000..6997623 --- /dev/null +++ b/src/Ellie.Econ/Deck/Regular/RegularDeck.cs @@ -0,0 +1,15 @@ +namespace Ellie.Econ; + +public sealed class RegularDeck : NewDeck +{ + public RegularDeck() + { + foreach (var suit in _suits) + { + foreach (var val in _values) + { + _cards.AddLast((RegularCard)Activator.CreateInstance(typeof(RegularCard), suit, val)!); + } + } + } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Deck/Regular/RegularDeckExtensions.cs b/src/Ellie.Econ/Deck/Regular/RegularDeckExtensions.cs new file mode 100644 index 0000000..98c880c --- /dev/null +++ b/src/Ellie.Econ/Deck/Regular/RegularDeckExtensions.cs @@ -0,0 +1,56 @@ +namespace Ellie.Econ; + +public static class RegularDeckExtensions +{ + public static string GetEmoji(this RegularSuit suit) + => suit switch + { + RegularSuit.Hearts => "♥️", + RegularSuit.Spades => "♠️", + RegularSuit.Diamonds => "♦️", + _ => "♣️", + }; + + public static string GetEmoji(this RegularValue value) + => value switch + { + RegularValue.Ace => "🇦", + RegularValue.Two => "2️⃣", + RegularValue.Three => "3️⃣", + RegularValue.Four => "4️⃣", + RegularValue.Five => "5️⃣", + RegularValue.Six => "6️⃣", + RegularValue.Seven => "7️⃣", + RegularValue.Eight => "8️⃣", + RegularValue.Nine => "9️⃣", + RegularValue.Ten => "🔟", + RegularValue.Jack => "🇯", + RegularValue.Queen => "🇶", + _ => "🇰", + }; + + public static string GetEmoji(this RegularCard card) + => $"{card.Value.GetEmoji()} {card.Suit.GetEmoji()}"; + + public static string GetName(this RegularValue value) + => value.ToString(); + + public static string GetName(this RegularSuit suit) + => suit.ToString(); + + public static string GetName(this RegularCard card) + => $"{card.Value.ToString()} of {card.Suit.GetName()}"; +} + + + + + + + + + + + + + diff --git a/src/Ellie.Econ/Deck/Regular/RegularSuit.cs b/src/Ellie.Econ/Deck/Regular/RegularSuit.cs new file mode 100644 index 0000000..dc4167b --- /dev/null +++ b/src/Ellie.Econ/Deck/Regular/RegularSuit.cs @@ -0,0 +1,9 @@ +namespace Ellie.Econ; + +public enum RegularSuit +{ + Hearts, + Diamonds, + Clubs, + Spades +} \ No newline at end of file diff --git a/src/Ellie.Econ/Deck/Regular/RegularValue.cs b/src/Ellie.Econ/Deck/Regular/RegularValue.cs new file mode 100644 index 0000000..8aa9171 --- /dev/null +++ b/src/Ellie.Econ/Deck/Regular/RegularValue.cs @@ -0,0 +1,18 @@ +namespace Ellie.Econ; + +public enum RegularValue +{ + Ace = 1, + Two = 2, + Three = 3, + Four = 4, + Five = 5, + Six = 6, + Seven = 7, + Eight = 8, + Nine = 9, + Ten = 10, + Jack = 12, + Queen = 13, + King = 14, +} \ No newline at end of file diff --git a/src/Ellie.Econ/Ellie.Econ.csproj b/src/Ellie.Econ/Ellie.Econ.csproj new file mode 100644 index 0000000..038763e --- /dev/null +++ b/src/Ellie.Econ/Ellie.Econ.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + diff --git a/src/Ellie.Econ/Gambling/Betdraw/BetdrawColorGuess.cs b/src/Ellie.Econ/Gambling/Betdraw/BetdrawColorGuess.cs new file mode 100644 index 0000000..7ecd3bd --- /dev/null +++ b/src/Ellie.Econ/Gambling/Betdraw/BetdrawColorGuess.cs @@ -0,0 +1,7 @@ +namespace Ellie.Econ.Gambling.Betdraw; + +public enum BetdrawColorGuess +{ + Red, + Black +} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Betdraw/BetdrawGame.cs b/src/Ellie.Econ/Gambling/Betdraw/BetdrawGame.cs new file mode 100644 index 0000000..d52ae43 --- /dev/null +++ b/src/Ellie.Econ/Gambling/Betdraw/BetdrawGame.cs @@ -0,0 +1,86 @@ +using Serilog; + +namespace Ellie.Econ.Gambling.Betdraw; + +public sealed class BetdrawGame +{ + private static readonly EllieRandom _rng = new(); + private readonly RegularDeck _deck; + + private const decimal SINGLE_GUESS_MULTI = 2.075M; + private const decimal DOUBLE_GUESS_MULTI = 4.15M; + + public BetdrawGame() + { + _deck = new RegularDeck(); + } + + public BetdrawResult Draw(BetdrawValueGuess? val, BetdrawColorGuess? col, decimal amount) + { + if (val is null && col is null) + throw new ArgumentNullException(nameof(val)); + + var card = _deck.Peek(_rng.Next(0, 52))!; + + var realVal = (int)card.Value < 7 + ? BetdrawValueGuess.Low + : BetdrawValueGuess.High; + + var realCol = card.Suit is RegularSuit.Diamonds or RegularSuit.Hearts + ? BetdrawColorGuess.Red + : BetdrawColorGuess.Black; + + // if card is 7, autoloss + if (card.Value == RegularValue.Seven) + { + return new() + { + Won = 0M, + Multiplier = 0M, + ResultType = BetdrawResultType.Lose, + Card = card, + }; + } + + byte win = 0; + if (val is BetdrawValueGuess valGuess) + { + if (realVal != valGuess) + return new() + { + Won = 0M, + Multiplier = 0M, + ResultType = BetdrawResultType.Lose, + Card = card + }; + + ++win; + } + + if (col is BetdrawColorGuess colGuess) + { + if (realCol != colGuess) + return new() + { + Won = 0M, + Multiplier = 0M, + ResultType = BetdrawResultType.Lose, + Card = card + }; + + ++win; + } + + var multi = win == 1 + ? SINGLE_GUESS_MULTI + : DOUBLE_GUESS_MULTI; + + return new() + { + Won = amount * multi, + Multiplier = multi, + ResultType = BetdrawResultType.Win, + Card = card + }; + } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Betdraw/BetdrawResult.cs b/src/Ellie.Econ/Gambling/Betdraw/BetdrawResult.cs new file mode 100644 index 0000000..82661ac --- /dev/null +++ b/src/Ellie.Econ/Gambling/Betdraw/BetdrawResult.cs @@ -0,0 +1,9 @@ +namespace Ellie.Econ.Gambling.Betdraw; + +public readonly struct BetdrawResult +{ + public decimal Won { get; init; } + public decimal Multiplier { get; init; } + public BetdrawResultType ResultType { get; init; } + public RegularCard Card { get; init; } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Betdraw/BetdrawResultType.cs b/src/Ellie.Econ/Gambling/Betdraw/BetdrawResultType.cs new file mode 100644 index 0000000..371b8fa --- /dev/null +++ b/src/Ellie.Econ/Gambling/Betdraw/BetdrawResultType.cs @@ -0,0 +1,7 @@ +namespace Ellie.Econ.Gambling.Betdraw; + +public enum BetdrawResultType +{ + Win, + Lose +} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Betdraw/BetdrawValueGuess.cs b/src/Ellie.Econ/Gambling/Betdraw/BetdrawValueGuess.cs new file mode 100644 index 0000000..caf2a14 --- /dev/null +++ b/src/Ellie.Econ/Gambling/Betdraw/BetdrawValueGuess.cs @@ -0,0 +1,7 @@ +namespace Ellie.Econ.Gambling.Betdraw; + +public enum BetdrawValueGuess +{ + High, + Low, +} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Betflip/BetflipGame.cs b/src/Ellie.Econ/Gambling/Betflip/BetflipGame.cs new file mode 100644 index 0000000..d6d26aa --- /dev/null +++ b/src/Ellie.Econ/Gambling/Betflip/BetflipGame.cs @@ -0,0 +1,33 @@ +namespace Ellie.Econ.Gambling; + +public sealed class BetflipGame +{ + private readonly decimal _winMulti; + private static readonly EllieRandom _rng = new EllieRandom(); + + public BetflipGame(decimal winMulti) + { + _winMulti = winMulti; + } + + public BetflipResult Flip(byte guess, decimal amount) + { + var side = (byte)_rng.Next(0, 2); + if (side == guess) + { + return new BetflipResult() + { + Side = side, + Won = amount * _winMulti, + Multiplier = _winMulti + }; + } + + return new BetflipResult() + { + Side = side, + Won = 0, + Multiplier = 0, + }; + } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Betflip/BetflipResult.cs b/src/Ellie.Econ/Gambling/Betflip/BetflipResult.cs new file mode 100644 index 0000000..8763f50 --- /dev/null +++ b/src/Ellie.Econ/Gambling/Betflip/BetflipResult.cs @@ -0,0 +1,8 @@ +namespace Ellie.Econ.Gambling; + +public readonly struct BetflipResult +{ + public decimal Won { get; init; } + public byte Side { get; init; } + public decimal Multiplier { get; init; } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Betroll/BetrollGame.cs b/src/Ellie.Econ/Gambling/Betroll/BetrollGame.cs new file mode 100644 index 0000000..5938957 --- /dev/null +++ b/src/Ellie.Econ/Gambling/Betroll/BetrollGame.cs @@ -0,0 +1,42 @@ +namespace Ellie.Econ.Gambling; + +public sealed class BetrollGame +{ + private readonly (int WhenAbove, decimal MultiplyBy)[] _thresholdPairs; + private readonly EllieRandom _rng; + + public BetrollGame(IReadOnlyList<(int WhenAbove, decimal MultiplyBy)> pairs) + { + _thresholdPairs = pairs.OrderByDescending(x => x.WhenAbove).ToArray(); + _rng = new(); + } + + public BetrollResult Roll(decimal amount = 0) + { + var roll = _rng.Next(1, 101); + + for (var i = 0; i < _thresholdPairs.Length; i++) + { + ref var pair = ref _thresholdPairs[i]; + + if (pair.WhenAbove < roll) + { + return new() + { + Multiplier = pair.MultiplyBy, + Roll = roll, + Threshold = pair.WhenAbove, + Won = amount * pair.MultiplyBy + }; + } + } + + return new() + { + Multiplier = 0, + Roll = roll, + Threshold = -1, + Won = 0, + }; + } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Betroll/BetrollResult.cs b/src/Ellie.Econ/Gambling/Betroll/BetrollResult.cs new file mode 100644 index 0000000..ddafa5c --- /dev/null +++ b/src/Ellie.Econ/Gambling/Betroll/BetrollResult.cs @@ -0,0 +1,9 @@ +namespace Ellie.Econ.Gambling; + +public readonly struct BetrollResult +{ + public int Roll { get; init; } + public decimal Multiplier { get; init; } + public decimal Threshold { get; init; } + public decimal Won { get; init; } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Rps/RpsGame.cs b/src/Ellie.Econ/Gambling/Rps/RpsGame.cs new file mode 100644 index 0000000..8d3c623 --- /dev/null +++ b/src/Ellie.Econ/Gambling/Rps/RpsGame.cs @@ -0,0 +1,75 @@ +namespace Ellie.Econ.Gambling.Rps; + +public sealed class RpsGame +{ + private static readonly EllieRandom _rng = new EllieRandom(); + + const decimal WIN_MULTI = 1.95m; + const decimal DRAW_MULTI = 1m; + const decimal LOSE_MULTI = 0m; + + public RpsGame() + { + + } + + public RpsResult Play(RpsPick pick, decimal amount) + { + var compPick = (RpsPick)_rng.Next(0, 3); + if (compPick == pick) + { + return new() + { + Won = amount * DRAW_MULTI, + Multiplier = DRAW_MULTI, + ComputerPick = compPick, + Result = RpsResultType.Draw, + }; + } + + if ((compPick == RpsPick.Paper && pick == RpsPick.Rock) + || (compPick == RpsPick.Rock && pick == RpsPick.Scissors) + || (compPick == RpsPick.Scissors && pick == RpsPick.Paper)) + { + return new() + { + Won = amount * LOSE_MULTI, + Multiplier = LOSE_MULTI, + Result = RpsResultType.Lose, + ComputerPick = compPick, + }; + } + + return new() + { + Won = amount * WIN_MULTI, + Multiplier = WIN_MULTI, + Result = RpsResultType.Win, + ComputerPick = compPick, + }; + } +} + +public enum RpsPick : byte +{ + Rock = 0, + Paper = 1, + Scissors = 2, +} + +public enum RpsResultType : byte +{ + Win, + Draw, + Lose +} + + + +public readonly struct RpsResult +{ + public decimal Won { get; init; } + public decimal Multiplier { get; init; } + public RpsResultType Result { get; init; } + public RpsPick ComputerPick { get; init; } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Slot/SlotGame.cs b/src/Ellie.Econ/Gambling/Slot/SlotGame.cs new file mode 100644 index 0000000..f6cddb9 --- /dev/null +++ b/src/Ellie.Econ/Gambling/Slot/SlotGame.cs @@ -0,0 +1,116 @@ +namespace Ellie.Econ.Gambling; + +//here is a payout chart +//https://lh6.googleusercontent.com/-i1hjAJy_kN4/UswKxmhrbPI/AAAAAAAAB1U/82wq_4ZZc-Y/DE6B0895-6FC1-48BE-AC4F-14D1B91AB75B.jpg +//thanks to judge for helping me with this +public class SlotGame +{ + private static readonly EllieRandom _rng = new EllieRandom(); + + public SlotResult Spin(decimal bet) + { + var rolls = new[] + { + (byte)_rng.Next(0, 6), + (byte)_rng.Next(0, 6), + (byte)_rng.Next(0, 6) + }; + + ref var a = ref rolls[0]; + ref var b = ref rolls[1]; + ref var c = ref rolls[2]; + + var multi = 0; + var winType = SlotWinType.None; + if (a == b && b == c) + { + if (a == 5) + { + winType = SlotWinType.TrippleJoker; + multi = 30; + } + else + { + winType = SlotWinType.TrippleNormal; + multi = 10; + } + } + else if (a == 5 && (b == 5 || c == 5) + || (b == 5 && c == 5)) + { + winType = SlotWinType.DoubleJoker; + multi = 4; + } + else if (a == 5 || b == 5 || c == 5) + { + winType = SlotWinType.SingleJoker; + multi = 1; + } + + return new() + { + Won = bet * multi, + WinType = winType, + Multiplier = multi, + Rolls = rolls, + }; + } +} + +public enum SlotWinType : byte +{ + None, + SingleJoker, + DoubleJoker, + TrippleNormal, + TrippleJoker, +} + +/* +var rolls = new[] + { + _rng.Next(default(byte), 6), + _rng.Next(default(byte), 6), + _rng.Next(default(byte), 6) + }; + + var multi = 0; + var winType = SlotWinType.None; + + ref var a = ref rolls[0]; + ref var b = ref rolls[1]; + ref var c = ref rolls[2]; + if (a == b && b == c) + { + if (a == 5) + { + winType = SlotWinType.TrippleJoker; + multi = 30; + } + else + { + winType = SlotWinType.TrippleNormal; + multi = 10; + } + } + else if (a == 5 && (b == 5 || c == 5) + || (b == 5 && c == 5)) + { + winType = SlotWinType.DoubleJoker; + multi = 4; + } + else if (rolls.Any(x => x == 5)) + { + winType = SlotWinType.SingleJoker; + multi = 1; + } + + return new() + { + Won = bet * multi, + WinType = winType, + Multiplier = multi, + Rolls = rolls, + }; + } +*/ \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Slot/SlotResult.cs b/src/Ellie.Econ/Gambling/Slot/SlotResult.cs new file mode 100644 index 0000000..42d3630 --- /dev/null +++ b/src/Ellie.Econ/Gambling/Slot/SlotResult.cs @@ -0,0 +1,9 @@ +namespace Ellie.Econ.Gambling; + +public readonly struct SlotResult +{ + public decimal Multiplier { get; init; } + public byte[] Rolls { get; init; } + public decimal Won { get; init; } + public SlotWinType WinType { get; init; } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Wof/LuLaResult.cs b/src/Ellie.Econ/Gambling/Wof/LuLaResult.cs new file mode 100644 index 0000000..0f98e1a --- /dev/null +++ b/src/Ellie.Econ/Gambling/Wof/LuLaResult.cs @@ -0,0 +1,9 @@ +namespace Ellie.Econ.Gambling; + +public readonly struct LuLaResult +{ + public int Index { get; init; } + public decimal Multiplier { get; init; } + public decimal Won { get; init; } + public IReadOnlyList Multipliers { get; init; } +} \ No newline at end of file diff --git a/src/Ellie.Econ/Gambling/Wof/WofGame.cs b/src/Ellie.Econ/Gambling/Wof/WofGame.cs new file mode 100644 index 0000000..d76a215 --- /dev/null +++ b/src/Ellie.Econ/Gambling/Wof/WofGame.cs @@ -0,0 +1,34 @@ +namespace Ellie.Econ.Gambling; + +public sealed class LulaGame +{ + private static readonly IReadOnlyList DEFAULT_MULTIPLIERS = new[] { 1.7M, 1.5M, 0.2M, 0.1M, 0.3M, 0.5M, 1.2M, 2.4M }; + + private readonly IReadOnlyList _multipliers; + private static readonly EllieRandom _rng = new(); + + public LulaGame(IReadOnlyList multipliers) + { + _multipliers = multipliers; + } + + public LulaGame() : this(DEFAULT_MULTIPLIERS) + { + } + + public LuLaResult Spin(long bet) + { + var result = _rng.Next(0, _multipliers.Count); + + var multi = _multipliers[result]; + var amount = bet * multi; + + return new() + { + Index = result, + Multiplier = multi, + Won = amount, + Multipliers = _multipliers.ToArray(), + }; + } +} \ No newline at end of file diff --git a/src/Ellie.Econ/GlobalUsings.cs b/src/Ellie.Econ/GlobalUsings.cs new file mode 100644 index 0000000..a197f0b --- /dev/null +++ b/src/Ellie.Econ/GlobalUsings.cs @@ -0,0 +1 @@ +global using Ellie.Common; \ No newline at end of file