Exemple #1
0
        public int CompareTo(object obj)
        {
            if (obj == null)
            {
                return(1);
            }

            TichuCard other = obj as TichuCard;

            if (Suit != other.Suit)
            {
                return(Suit > other.Suit ? 1 : -1);
            }

            if (Rank != other.Rank)
            {
                return(Rank > other.Rank ? 1 : -1);
            }

            if (Special != other.Special)
            {
                return(Special > other.Special ? 1 : -1);
            }

            return(0);
        }
Exemple #2
0
        public override string ToString()
        {
            // What state do we want to show?
            // - Current cards in each hand
            // - Current player turn
            // - Cards played in current trick
            // - Trick counts by player
            StringBuilder sb = new StringBuilder();

            for (int player = 0; player < 4; player++)
            {
                if (CurrentPlayerTurn == player)
                {
                    sb.Append($"[{player}] ");
                }
                else
                {
                    sb.Append($" {player}  ");
                }
                sb.AppendLine(TichuCard.PrintCardsSortedBySuit(Players[player].Cards));
            }

            sb.AppendLine(string.Join(" ", _currentTrick.Select(play => play.ToString())));
            sb.AppendLine(string.Join(" ", Evaluate()));
            return(sb.ToString());
        }
Exemple #3
0
        public static void Run(int numGames)
        {
            Random random = new Random();

            int[] cumulativeTrickCounts            = new int[4]; // [playerId]
            IPlayGenerator <Play>[] playGenerators = new IPlayGenerator <Play> [4];
            //playGenerators[0] = new MultiThreadedMcts<Play>(100000, 50, random, 8);
            playGenerators[0]  = new Mcts <Play>(10000, 50, random);
            playGenerators[1]  = new RandomPlayGenerator <Play>();
            playGenerators[2]  = new HighestCardPlayGenerator();
            playGenerators[3]  = new HighestCardPlayGenerator();
            Logger.Log.Enabled = true;
            for (int gameNumber = 0; gameNumber < numGames; gameNumber++)
            {
                var gameState = TichuGameRunHarness.SetupFourPlayerGame(random);

                if (true)
                {
                    Logger.Log.WriteLine("Starting cards:");
                    for (int i = 0; i < 4; i++)
                    {
                        Logger.Log.WriteLine($"Player {i} {TichuCard.PrintCardsSortedBySuit(gameState.Players[i].Cards)}");
                    }
                }
                while (true)
                {
                    gameState.SetPointOfViewPlayer(gameState.CurrentPlayerTurn);
                    Play play = playGenerators[gameState.CurrentPlayerTurn].FindPlay(gameState);
                    Logger.Log.WriteLine($"Player {play.Player} played {play.Cards[0].ToString()}");
                    gameState.CommitPlay(play);
                    if (gameState.GameOver())
                    {
                        break;
                    }

                    if (gameState.PlayedCards.Count % 4 == 0)
                    {
                        Logger.Log.WriteLine("----");
                    }
                }

                var scores = gameState.Evaluate();
                for (int i = 0; i < 4; i++)
                {
                    cumulativeTrickCounts[i] += (int)scores[i];
                }

                Console.WriteLine($"Tricks: {scores[0]} {scores[1]} {scores[2]} {scores[3]} ");
            }

            string header = string.Format("{0, 6}{1, 10}{2, 10}", "Player", "Tricks", "Average");

            Console.WriteLine(header);

            for (int i = 0; i < 4; i++)
            {
                string output = string.Format("{0, 6}{1, 10}{2, 10:N1}", i, cumulativeTrickCounts[i], (double)cumulativeTrickCounts[i] / numGames);
                Console.WriteLine(output);
            }
        }
Exemple #4
0
        public IList <Play> GetPlays()
        {
            // Any card that hasn't been played is a valid play
            List <Play> plays = new List <Play>();

            if (CurrentPlayerTurn == _pointOfViewPlayer)
            {
                if (_currentTrick.Count > 0)
                {
                    // Try and follow suit. If we have none of that suit, fall through into allowing all cards in our hand
                    var suitCards = TichuCard.GetCardsWithSuit(Players[CurrentPlayerTurn].Cards, _currentTrick[0].Cards[0].Suit);
                    if (suitCards != null)
                    {
                        foreach (var card in suitCards)
                        {
                            plays.Add(Play.PlayCards(CurrentPlayerTurn, new TichuCard[] { card }));
                        }
                    }
                }

                // If we didn't have to follow suit, any card is a valid play
                if (plays.Count == 0)
                {
                    // Make correct plays from our own hand
                    foreach (var card in Players[CurrentPlayerTurn].Cards)
                    {
                        plays.Add(Play.PlayCards(CurrentPlayerTurn, new TichuCard[] { card }));
                    }
                }
            }
            else
            {
                // For simulated players we choose a random card from those unused. Also exclude cards
                // from the point-of-view player's hand since from the AI agent's pov those cards are
                // determined (ie, we're not cheating by looking at their hand here).
                // We could use a more sophisticated selection policy here to guide the search.
                //foreach (var card in RemainingCards.Except(Players[_pointOfViewPlayer].Cards))
                foreach (var card in RemainingPlayoutCards)
                {
                    plays.Add(Play.PlayCards(CurrentPlayerTurn, new TichuCard[] { card }));
                }
            }

            return(plays);
        }
Exemple #5
0
        /// <summary>
        /// Creates a random deck of cards excluding dog, dragon, phoenix, mahjong
        /// </summary>
        public static TichuDeck CreateWithoutSpecials()
        {
            List <TichuCard> drawPool = new List <TichuCard>();

            for (int suit = 0; suit < 4; suit++)
            {
                for (int rank = 0; rank < 13; rank++)
                {
                    TichuCard c = new TichuCard((CardSuit)suit, (CardRank)rank);
                    drawPool.Add(c);
                }
            }
            TichuDeck deck   = new TichuDeck(drawPool);
            Random    random = new Random();

            for (int i = 0; i < 52; i++)
            {
                int randomCard = random.Next(drawPool.Count);
                deck._deck.Push(drawPool[randomCard]);
                drawPool.RemoveAt(randomCard);
            }

            return(deck);
        }
Exemple #6
0
        private static ParsedHand ParseHand(StreamReader reader, ParsedGame game)
        {
            ParsedHand hand = new ParsedHand();

            // Tichu cards
            string line = reader.ReadLine();

            if (line == null)
            {
                return(null);
            }

            if (line != @"---------------Gr.Tichukarten------------------")
            {
                throw new ParseException();
            }

            // Parse grand tichu cards (first 8 dealt)
            for (int i = 0; i < 4; i++)
            {
                line = reader.ReadLine();
                int playerNum = int.Parse(line.Substring(1, 1));

                string[] grandTichuCards = line.Substring(3).Split(" ");
                for (int cardIndex = 0; cardIndex < 8; cardIndex++)
                {
                    hand.GrandTichuCards[i][cardIndex] = GetCard(grandTichuCards[cardIndex + 1]);
                }
            }

            line = reader.ReadLine();
            if (line != @"---------------Startkarten------------------")
            {
                throw new ParseException();
            }

            // Parse starting hand (14 cards dealt pre-pass)
            for (int i = 0; i < 4; i++)
            {
                line = reader.ReadLine();
                int      playerNum     = int.Parse(line.Substring(1, 1));
                string[] startingCards = line.Substring(3).Split(" ");

                for (int cardIndex = 0; cardIndex < 14; cardIndex++)
                {
                    hand.StartingCards[i][cardIndex] = GetCard(startingCards[cardIndex + 1]);
                }
            }

            line = reader.ReadLine();

            while (line.StartsWith("Grosses Tichu: ") || line.StartsWith("Tichu: "))
            {
                if (line.StartsWith("Grosses Tichu: "))
                {
                    string[] grandPlayers = line.Substring(15).Split(" ", StringSplitOptions.RemoveEmptyEntries);
                    int      count        = 0;
                    foreach (string player in grandPlayers)
                    {
                        count++;
                        if (count > 1)
                        {
                            throw new Exception("Multi grand in one line");
                        }

                        hand.Plays.Add(Play.GrandTichu(int.Parse(player.Substring(1, 1))));
                    }
                }
                else
                {
                    string[] tichuPlayers = line.Substring(7).Split(" ", StringSplitOptions.RemoveEmptyEntries);
                    int      count        = 0;
                    foreach (string player in tichuPlayers)
                    {
                        count++;
                        if (count > 1)
                        {
                            throw new Exception("Multi tichu in one line");
                        }

                        hand.Plays.Add(Play.GrandTichu(IndexFromPlayerTag(player)));
                    }
                }
                line = reader.ReadLine();
            }

            if (line != "Schupfen:")
            {
                throw new ParseException();
            }

            // Parse card exchange
            for (int i = 0; i < 4; i++)
            {
                line = reader.ReadLine();
                string[] passes     = line.Substring(3).Split(" ", StringSplitOptions.RemoveEmptyEntries);
                string   playerName = passes[0];
                if (game.Players[i] == null)
                {
                    // Seed the set of players names the first time we parse them
                    game.Players[i] = playerName;
                }

                //Debug.Assert(game.Players[i] == playerName); // The names should be consistent between hands in a game


                hand.ExchangedCards[i][0] = GetCard(passes[3]);
                hand.ExchangedCards[i][1] = GetCard(passes[6]);
                hand.ExchangedCards[i][2] = GetCard(passes[9]);
            }

            line = reader.ReadLine();

            // If there are bombs, the players with them are listed here
            if (line.StartsWith("BOMBE: "))
            {
                string[] bombPlayers = line.Substring(7).Split(" ");
                foreach (string player in bombPlayers)
                {
                    if (string.IsNullOrEmpty(player))
                    {
                        continue;
                    }

                    hand.HasBomb[int.Parse(player.Substring(1, 1))] = true;
                }
                line = reader.ReadLine();
            }

            if (line != @"---------------Rundenverlauf------------------")
            {
                throw new ParseException();
            }

            // Remember who played the mahjong when we see the wish line
            int mahjongPlayer = 0;

            while (true)
            {
                // Parse plays until we see the scores indicating the end of the hand
                line = reader.ReadLine();

                // Scores line; we're done playing
                if (line.StartsWith("Ergebnis: "))
                {
                    break;
                }

                // Wish
                if (line.StartsWith("Wunsch:"))
                {
                    TichuCard wishCard = new TichuCard(default(CardSuit), RankFromParsedString(line.Substring(7)));
                    hand.Plays.Add(Play.Wish(mahjongPlayer, wishCard));
                }
                else if (line.StartsWith("Drache an: "))
                {
                    string dragonPlayer = line.Substring(11);
                    hand.Plays.Add(Play.GiveDragon(IndexFromPlayerTag(dragonPlayer)));
                }
                else if (line.StartsWith("Tichu: "))
                {
                    string tichuPlayer = line.Substring(7);
                    hand.Plays.Add(Play.Tichu(IndexFromPlayerTag(tichuPlayer)));
                }
                else if (line.StartsWith("("))
                {
                    // Options:
                    // - Playing cards
                    // - Passing

                    string[] playLine    = line.Split(" ", StringSplitOptions.RemoveEmptyEntries);
                    int      playerIndex = IndexFromPlayerTag(playLine[0]);
                    if (playLine[1] == "passt.")
                    {
                        // Pass
                        hand.Plays.Add(Play.Pass(playerIndex));
                    }
                    else
                    {
                        // Play some number of cards
                        List <TichuCard> cards = new List <TichuCard>();
                        foreach (var x in playLine.AsSpan(1))
                        {
                            cards.Add(GetCard(x));
                        }
                        Play.PlayCards(playerIndex, cards.ToArray());
                    }
                }
                else
                {
                    Debug.Assert(false, $"Unparsed line: {line}");
                }
            }

            Debug.Assert(line.StartsWith("Ergebnis: "));
            string[] scores = line.Substring(10).Split(" ", StringSplitOptions.RemoveEmptyEntries);

            hand.Scores[0] = int.Parse(scores[0]);
            hand.Scores[1] = int.Parse(scores[2]);

            Debug.Assert((hand.Scores[0] + hand.Scores[1]) % 100 == 0);
            return(hand);
        }