developmaunt #5
15
Mau/Card.cs
15
Mau/Card.cs
@@ -48,6 +48,21 @@ public static class CardExtensions
|
|||||||
|| playedCard.IsSameCardValue(currentCard)
|
|| playedCard.IsSameCardValue(currentCard)
|
||||||
|| playedCard.CardType == CardType.JOKER;
|
|| playedCard.CardType == CardType.JOKER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsSpecialCard(this Card card)
|
||||||
|
{
|
||||||
|
return card.IsMauCard() || card.CardValue is
|
||||||
|
CardValue.SEVEN or
|
||||||
|
CardValue.EIGHT or
|
||||||
|
CardValue.JACK or
|
||||||
|
CardValue.KING or
|
||||||
|
CardValue.ACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsMauCard(this Card card)
|
||||||
|
{
|
||||||
|
return card.CardType == CardType.JOKER || card.CardValue is CardValue.TWO;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum CardType
|
public enum CardType
|
||||||
|
|||||||
68
Mau/Deck.cs
68
Mau/Deck.cs
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
public class Deck
|
public class Deck
|
||||||
{
|
{
|
||||||
private List<Card> _unusedDeck = new();
|
private readonly List<Card> _unusedDeck = new();
|
||||||
private List<Card> _usedDeck = new();
|
private readonly List<Card> _usedDeck = new();
|
||||||
public Card CurrentCard;
|
public Card CurrentCard { get; private set; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <summary>
|
* <summary>
|
||||||
@@ -15,23 +15,20 @@ public class Deck
|
|||||||
{
|
{
|
||||||
CreateSet();
|
CreateSet();
|
||||||
ShuffleDeck();
|
ShuffleDeck();
|
||||||
CurrentCard = DrawCard();
|
var initialCard = DrawCard();
|
||||||
_usedDeck.Add(CurrentCard);
|
CurrentCard = initialCard;
|
||||||
|
|
||||||
if (CurrentCard.CardType != CardType.JOKER) return;
|
|
||||||
CurrentCard = DrawCard();
|
|
||||||
_usedDeck.Add(CurrentCard);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <summary>
|
* <summary>
|
||||||
* Adds the given card to the used cards deck.
|
* Adds the given card to the used cards deck and sets the current card to the given card.
|
||||||
* </summary>
|
* </summary>
|
||||||
* <param name="card">The card to add to the used cards deck.</param>
|
* <param name="card">The card to add to the used cards deck.</param>
|
||||||
*/
|
*/
|
||||||
public void AddCardToUsedDeck(Card card)
|
public void AddCardToUsedDeck(Card card)
|
||||||
{
|
{
|
||||||
_usedDeck.Add(card);
|
_usedDeck.Add(card);
|
||||||
|
CurrentCard = card;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,29 +42,6 @@ public class Deck
|
|||||||
_usedDeck.AddRange(cards);
|
_usedDeck.AddRange(cards);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <summary>
|
|
||||||
* Creates a new deck of cards and adds them to the unused deck.
|
|
||||||
* </summary>
|
|
||||||
*/
|
|
||||||
private void CreateSet()
|
|
||||||
{
|
|
||||||
foreach (CardType cardType in Enum.GetValues(typeof(CardType)))
|
|
||||||
{
|
|
||||||
if (cardType == CardType.JOKER)
|
|
||||||
{
|
|
||||||
_unusedDeck.Add(new Card(cardType, CardValue.RED));
|
|
||||||
_unusedDeck.Add(new Card(cardType, CardValue.BLACK));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
foreach (CardValue cardValue in Enum.GetValues(typeof(CardValue)))
|
|
||||||
{
|
|
||||||
if (cardValue is CardValue.RED or CardValue.BLACK) continue;
|
|
||||||
_unusedDeck.Add(new Card(cardType, cardValue));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <summary>
|
* <summary>
|
||||||
* Draws a card from the deck.
|
* Draws a card from the deck.
|
||||||
@@ -98,6 +72,29 @@ public class Deck
|
|||||||
return cards;
|
return cards;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <summary>
|
||||||
|
* Creates a new deck of cards and adds them to the unused deck.
|
||||||
|
* </summary>
|
||||||
|
*/
|
||||||
|
private void CreateSet()
|
||||||
|
{
|
||||||
|
foreach (CardType cardType in Enum.GetValues(typeof(CardType)))
|
||||||
|
{
|
||||||
|
if (cardType == CardType.JOKER)
|
||||||
|
{
|
||||||
|
_unusedDeck.Add(new Card(cardType, CardValue.RED));
|
||||||
|
_unusedDeck.Add(new Card(cardType, CardValue.BLACK));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach (CardValue cardValue in Enum.GetValues(typeof(CardValue)))
|
||||||
|
{
|
||||||
|
if (cardValue is CardValue.RED or CardValue.BLACK) continue;
|
||||||
|
_unusedDeck.Add(new Card(cardType, cardValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <summary>
|
* <summary>
|
||||||
* Moves all the used cards back to the unused deck and shuffles it.
|
* Moves all the used cards back to the unused deck and shuffles it.
|
||||||
@@ -124,6 +121,9 @@ public class Deck
|
|||||||
*/
|
*/
|
||||||
private void ShuffleDeck()
|
private void ShuffleDeck()
|
||||||
{
|
{
|
||||||
_unusedDeck = _unusedDeck.OrderBy(x => Guid.NewGuid()).ToList();
|
var unusedDeckCopy = new List<Card>(_unusedDeck);
|
||||||
|
_unusedDeck.Clear();
|
||||||
|
unusedDeckCopy = unusedDeckCopy.OrderBy(x => Guid.NewGuid()).ToList();
|
||||||
|
_unusedDeck.AddRange(unusedDeckCopy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
107
Mau/Game.cs
107
Mau/Game.cs
@@ -9,19 +9,38 @@ namespace MauMau_Server.Mau;
|
|||||||
|
|
||||||
public class Game : RoomType
|
public class Game : RoomType
|
||||||
{
|
{
|
||||||
|
// Helpers
|
||||||
private readonly Deck _deck = new();
|
private readonly Deck _deck = new();
|
||||||
private readonly TurnManager _turnManager = new();
|
private readonly TurnManager _turnManager = new();
|
||||||
public readonly List<Card> MauCardBuffer = new();
|
|
||||||
public CardType? NextAllowedCardType { get; set; }
|
// Game state
|
||||||
|
private readonly List<Card> _mauCardBuffer = new();
|
||||||
|
private CardType? NextAllowedCardType { get; set; }
|
||||||
|
|
||||||
|
// Variables
|
||||||
|
private const int NumberOfFaultcards = 5;
|
||||||
|
private const int NumberOfStartCards = 8;
|
||||||
|
|
||||||
public Game(Room.Room room, IEnumerable<ConnectionInstance> connections) : base(room)
|
public Game(Room.Room room, IEnumerable<ConnectionInstance> connections) : base(room)
|
||||||
{
|
{
|
||||||
|
// If the current card is a joker, set the next allowed card type to a random card type
|
||||||
|
if (_deck.CurrentCard.CardType == CardType.JOKER)
|
||||||
|
{
|
||||||
|
// In the case the random card type is a joker, try again until it is not
|
||||||
|
do
|
||||||
|
{
|
||||||
|
var cardTypes = Enum.GetValues(typeof(CardType));
|
||||||
|
var randomIndex = new Random().Next(cardTypes.Length);
|
||||||
|
NextAllowedCardType = (CardType?)cardTypes.GetValue(randomIndex) ?? CardType.SPADES;
|
||||||
|
} while (NextAllowedCardType == CardType.JOKER);
|
||||||
|
}
|
||||||
|
|
||||||
// Convert all the connections to players
|
// Convert all the connections to players
|
||||||
List<Player> players = new();
|
List<Player> players = new();
|
||||||
foreach (var player in connections.Select(connection => new Player(connection)))
|
foreach (var player in connections.Select(connection => new Player(connection)))
|
||||||
{
|
{
|
||||||
// Give the new player a hand of cards
|
// Give the new player a hand of cards
|
||||||
var initialHand = _deck.DrawCards(8);
|
var initialHand = _deck.DrawCards(NumberOfStartCards);
|
||||||
player.GiveCards(initialHand);
|
player.GiveCards(initialHand);
|
||||||
players.Add(player);
|
players.Add(player);
|
||||||
}
|
}
|
||||||
@@ -155,7 +174,7 @@ public class Game : RoomType
|
|||||||
{
|
{
|
||||||
// If there are cards in the MauCardBuffer, this means there are multiple cards that need to be drawn
|
// If there are cards in the MauCardBuffer, this means there are multiple cards that need to be drawn
|
||||||
// Otherwise, just draw a single card
|
// Otherwise, just draw a single card
|
||||||
if (MauCardBuffer.Count > 0)
|
if (_mauCardBuffer.Count > 0)
|
||||||
{
|
{
|
||||||
// Count the amount of cards that need to be drawn
|
// Count the amount of cards that need to be drawn
|
||||||
var totalCards = CountMauCardBuffer();
|
var totalCards = CountMauCardBuffer();
|
||||||
@@ -178,7 +197,7 @@ public class Game : RoomType
|
|||||||
player.GiveCard(drawnCard);
|
player.GiveCard(drawnCard);
|
||||||
|
|
||||||
// Change the player if the drawn card cannot be played
|
// Change the player if the drawn card cannot be played
|
||||||
if (!drawnCard.CanBePlayedOn(_deck.CurrentCard))
|
if (!CardCanBePlayed(drawnCard))
|
||||||
{
|
{
|
||||||
_turnManager.ChangeTurnTo();
|
_turnManager.ChangeTurnTo();
|
||||||
}
|
}
|
||||||
@@ -218,42 +237,25 @@ public class Game : RoomType
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if there is a specific card type that is allowed to be played
|
if (!CardCanBePlayed(playerCard)) return;
|
||||||
if (NextAllowedCardType != null)
|
|
||||||
{
|
|
||||||
// If the card is not the allowed card type, not the same value or a joker, ignore the message
|
|
||||||
if (playerCard.CardType != NextAllowedCardType && playerCard.CardType != CardType.JOKER && playerCard.CardValue != _deck.CurrentCard.CardValue)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Reset the allowed card type, so the next player has the normal same type and same value rules
|
|
||||||
NextAllowedCardType = null;
|
|
||||||
} else if (MauCardBuffer.Count > 0)
|
|
||||||
{
|
|
||||||
// If there are queued mau cards, the player can only another mau card (or draw)
|
|
||||||
if (playerCard.CardType != CardType.JOKER && playerCard.CardValue != CardValue.TWO)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Check if the card can be played on the current card, if not, ignore the message
|
|
||||||
if (!playerCard.CanBePlayedOn(_deck.CurrentCard))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the card from the player's hand
|
// Remove the card from the player's hand
|
||||||
player.Hand.Remove(playerCard);
|
player.Hand.Remove(playerCard);
|
||||||
|
|
||||||
|
// If the player's last played card is a special card, give the player 5 fault cards
|
||||||
|
if (player.Hand.Count < 1 && playerCard.IsSpecialCard())
|
||||||
|
{
|
||||||
|
var faultCards = _deck.DrawCards(NumberOfFaultcards);
|
||||||
|
player.GiveCards(faultCards);
|
||||||
|
}
|
||||||
|
|
||||||
// Add the card to the used deck
|
// Add the card to the used deck
|
||||||
_deck.AddCardToUsedDeck(playerCard);
|
_deck.AddCardToUsedDeck(playerCard);
|
||||||
|
|
||||||
// Set the new current card
|
// Reset the allowed card type, so the next player has the normal same type and same value rules
|
||||||
_deck.CurrentCard = playerCard;
|
NextAllowedCardType = null;
|
||||||
|
|
||||||
|
// If the player has no cards left, end the game with player as winner
|
||||||
if (player.Hand.Count == 0)
|
if (player.Hand.Count == 0)
|
||||||
{
|
{
|
||||||
EndGame(player);
|
EndGame(player);
|
||||||
@@ -280,13 +282,13 @@ public class Game : RoomType
|
|||||||
case CardValue.RED:
|
case CardValue.RED:
|
||||||
case CardValue.BLACK:
|
case CardValue.BLACK:
|
||||||
{
|
{
|
||||||
MauCardBuffer.Add(card);
|
_mauCardBuffer.Add(card);
|
||||||
_turnManager.CurrentPlayer.State = PlayerState.CHOOSE;
|
_turnManager.CurrentPlayer.State = PlayerState.CHOOSE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CardValue.TWO:
|
case CardValue.TWO:
|
||||||
{
|
{
|
||||||
MauCardBuffer.Add(card);
|
_mauCardBuffer.Add(card);
|
||||||
_turnManager.ChangeTurnTo();
|
_turnManager.ChangeTurnTo();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -319,6 +321,37 @@ public class Game : RoomType
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <summary>
|
||||||
|
* Check if the card can be played with the current game state.
|
||||||
|
* <list type="bullet">
|
||||||
|
* <item>The player can only play a mau card if there are pending mau cards (or draw)</item>
|
||||||
|
* <item>If there is a next allowed card type, the player can only play that card type, a joker or a card with the same value as the current card</item>
|
||||||
|
* <item>Otherwise, the player can play a card that has the same type, same value or is a joker</item>
|
||||||
|
* </list>
|
||||||
|
* </summary>
|
||||||
|
* <returns>True if the given card could be played</returns>
|
||||||
|
*/
|
||||||
|
private bool CardCanBePlayed(Card card)
|
||||||
|
{
|
||||||
|
// Check if there are pending mau cards played
|
||||||
|
if (_mauCardBuffer.Count > 0)
|
||||||
|
{
|
||||||
|
// If so, the card must be a mau card
|
||||||
|
return card.IsMauCard();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if there is a next allowed card type
|
||||||
|
if (NextAllowedCardType != null)
|
||||||
|
{
|
||||||
|
// If so, the card must be the allowed card type, a joker or the same value as the current card
|
||||||
|
return card.CardType == NextAllowedCardType || card.CardType == CardType.JOKER || card.CardValue == _deck.CurrentCard.CardValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, use the normal rules
|
||||||
|
return card.CanBePlayedOn(_deck.CurrentCard);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <summary>
|
* <summary>
|
||||||
* Count the amount of cards that need to be drawn from the MauCardBuffer. This method also clears the buffer.
|
* Count the amount of cards that need to be drawn from the MauCardBuffer. This method also clears the buffer.
|
||||||
@@ -328,7 +361,7 @@ public class Game : RoomType
|
|||||||
private int CountMauCardBuffer()
|
private int CountMauCardBuffer()
|
||||||
{
|
{
|
||||||
var totalCards = 0;
|
var totalCards = 0;
|
||||||
foreach (var card in MauCardBuffer)
|
foreach (var card in _mauCardBuffer)
|
||||||
{
|
{
|
||||||
if (card.CardType == CardType.JOKER)
|
if (card.CardType == CardType.JOKER)
|
||||||
{
|
{
|
||||||
@@ -342,7 +375,7 @@ public class Game : RoomType
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MauCardBuffer.Clear();
|
_mauCardBuffer.Clear();
|
||||||
return totalCards;
|
return totalCards;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user