Exemple #1
0
        private bool Expected(string message)
        {
            string loweredMessage = message.ToLowerInvariant();

            if (loweredMessage.StartsWith("unexpected "))
            {
                throw new InvalidOperationException(string.Format("Table Manager tells me I screwed up: '{0}'", message));
            }

            if (loweredMessage.StartsWith("disconnect"))
            {
                this.state = TableManagerProtocolState.WaitForDisconnect;
                return(true);
            }

            for (int a = 0; a < this.tableManagerExpectedResponse.Length; a++)
            {
                if (loweredMessage.StartsWith(this.tableManagerExpectedResponse[a].ToLowerInvariant()))
                {
                    return(true);
                }
            }

            if (message.StartsWith("Teams"))
            {
                return(true);                                           // bug in BridgeMoniteur
            }
            Log.Trace(0, "Unexpected response by {3}: '{0}' in state {2}; expected '{1}'", message, this.tableManagerExpectedResponse[0], this.state, this.seat);
            throw new InvalidOperationException(string.Format("Unexpected response by {2} '{0}'; expected '{1}'", message, this.tableManagerExpectedResponse[0], this.seat));
        }
Exemple #2
0
 public override void HandleTournamentStopped()
 {
     base.HandleTournamentStopped();
     this.moreBoards = false;
     this.state      = TableManagerProtocolState.Finished;
     this.HandleSessionEnd();
     this.Stop();
 }
Exemple #3
0
        private void ChangeState(TableManagerProtocolState newState, bool waitForSync, bool waitForMoreStateChanges, string[] expectedAnswers, string message, params object[] args)
        {
            message = string.Format(message, args);
            var stateChange = new StateChange()
            {
                Message = message, NewState = newState, ExpectedResponses = expectedAnswers, WaitForSync = waitForSync, WaitForStateChanges = waitForMoreStateChanges
            };

            lock (this.stateChanges) this.stateChanges.Enqueue(stateChange);
#if syncTrace
            //Log.Trace("Client {0} queued state change {1} ({2} states on the q)", this.seat, newState, this.stateChanges.Count);
#endif
        }
Exemple #4
0
        private async Task ProcessStateChanges()
        {
            const int minimumWait       = 0;
            var       waitForNewMessage = minimumWait;

            do
            {
                waitForNewMessage = 5;

                while (this.stateChanges.Count > 0 && !this.WaitForProtocolSync)
                {
                    waitForNewMessage = minimumWait;
                    StateChange stateChange;
                    lock (this.stateChanges) stateChange = this.stateChanges.Dequeue();
                    //if (this.state != stateChange.NewState)
                    {
                        this.state = stateChange.NewState;
#if syncTrace
                        Log.Trace(2, "Client {0} new state {1} message='{2}' expects='{3}'", this.seat, this.state, stateChange.Message, stateChange.ExpectedResponses[0]);
#endif
                    }

                    this.tableManagerExpectedResponse = stateChange.ExpectedResponses;
                    if (stateChange.Message.Length > 0)
                    {
                        await this.WriteProtocolMessageToRemoteMachine(stateChange.Message);
                    }

                    this.WaitForProtocolSync = stateChange.WaitForSync;        // e.g. must wait for 'to lead' message
                    this.WaitForBridgeEvents = stateChange.WaitForStateChanges;
                }

                if (waitForNewMessage > minimumWait)
                {
                    await Task.Delay(waitForNewMessage);
                }
            } while (this.moreBoards);
        }
Exemple #5
0
        private void ProcessMessage(string message)
        {
#if syncTrace
            Log.Trace(2, "Client {1} processing '{0}'", message, seat);
#endif

            if (message == "End of session" ||
                message.StartsWith("NS:")               // something new from Bridge Moniteur: session ends with
                )
            {
                this.EventBus.HandleTournamentStopped();
                return;
            }

            if (Expected(message))
            {
                try
                {
                    switch (this.state)
                    {
                    case TableManagerProtocolState.WaitForSeated:
                        this.HandleSeated();
                        this.ChangeState(TableManagerProtocolState.WaitForTeams, false, false, new string[] { "Teams" }, "{0} ready for teams", this.seat);
                        break;

                    case TableManagerProtocolState.WaitForTeams:
                        this.teamNS = message.Substring(message.IndexOf("N/S : \"") + 7);
                        this.teamNS = teamNS.Substring(0, teamNS.IndexOf("\""));
                        this.teamEW = message.Substring(message.IndexOf("E/W : \"") + 7);
                        this.teamEW = teamEW.Substring(0, teamEW.IndexOf("\""));
                        if (this.team != (this.seat.IsSameDirection(Seats.North) ? this.teamNS : this.teamEW))
                        {
                            throw new ArgumentOutOfRangeException("team", "Seated in another team");
                        }

                        this.HandleTeams(teamNS, teamEW);
                        this.ChangeState(TableManagerProtocolState.WaitForStartOfBoard, false, false, new string[] { "Start of board", "End of session" }, "{0} ready to start", this.seat);
                        break;

                    case TableManagerProtocolState.WaitForStartOfBoard:
                        if (message.StartsWith("Teams"))
                        {               // bug in BridgeMoniteur when tournament is restarted
                        }
                        else if (message.StartsWith("Timing"))
                        {
                            // Timing - N/S : this board [minutes:seconds], total [hours:minutes:seconds]. E/W : this board [minutes:seconds], total [hours:minutes:seconds]".
                            // Bridge Moniteur does not send the '.' at the end of the message
                            // Timing - N/S : this board  01:36,  total  0:01:36.  E/W : this board  01:34,  total  0:01:34
                            if (!message.EndsWith("."))
                            {
                                message += ".";
                            }
                            string[] timing  = message.Split('.');
                            string[] parts   = timing[0].Split(',');
                            string   boardNS = "00:" + parts[0].Substring(parts[0].IndexOf("board") + 6).Trim();
                            string   totalNS = parts[1].Substring(parts[1].IndexOf("total") + 6).Trim();
                            parts = timing[1].Split(',');
                            string boardEW = "00:" + parts[0].Substring(parts[0].IndexOf("board") + 6).Trim();
                            string totalEW = parts[1].Substring(parts[1].IndexOf("total") + 6).Trim();

                            TimeSpan _boardNS = ParseTimeUsed(boardNS);
                            TimeSpan _totalNS = ParseTimeUsed(totalNS);
                            TimeSpan _boardEW = ParseTimeUsed(boardEW);
                            TimeSpan _totalEW = ParseTimeUsed(totalEW);
                            this.EventBus.HandleTimeUsed(_boardNS, _totalNS, _boardEW, _totalEW);
                        }
                        else
                        {
                            this.ChangeState(TableManagerProtocolState.WaitForBoardInfo, false, false, new string[] { "Board number" }, "{0} ready for deal", this.seat);
                        }
                        break;

                    case TableManagerProtocolState.WaitForBoardInfo:
                        // "Board number 1. Dealer North. Neither vulnerable."
                        string[] dealInfoParts = message.Split('.');
                        int      boardNumber   = Convert.ToInt32(dealInfoParts[0].Substring(13));
                        this.theDealer = SeatsExtensions.FromXML(dealInfoParts[1].Substring(8));
                        Vulnerable vulnerability = Vulnerable.Neither;
                        switch (dealInfoParts[2].Substring(1))
                        {
                        case "Both vulnerable":
                            vulnerability = Vulnerable.Both; break;

                        case "N/S vulnerable":
                            vulnerability = Vulnerable.NS; break;

                        case "E/W vulnerable":
                            vulnerability = Vulnerable.EW; break;
                        }

                        var board = new Board2(this.theDealer, vulnerability, new Distribution());
                        this.CurrentResult = new TMBoardResult(this, board, new SeatCollection <string>(new string[] { this.teamNS, this.teamEW, this.teamNS, this.teamEW }));

                        this.EventBus.HandleBoardStarted(boardNumber, this.theDealer, vulnerability);
                        this.ChangeState(TableManagerProtocolState.WaitForMyCards, false, false, new string[] { this.seat + "'s cards : " }, "{0} ready for cards", this.seat);
                        break;

                    case TableManagerProtocolState.WaitForMyCards:
                        // "North's cards : S J 8 5.H A K T 8.D 7 6.C A K T 3."
                        // "North's cards : S J 8 5.H A K T 8.D.C A K T 7 6 3."
                        // "North's cards : S -.H A K T 8 4 3 2.D.C A K T 7 6 3."
                        string   cardInfo = message.Substring(2 + message.IndexOf(":"));
                        string[] suitInfo = cardInfo.Split('.');
                        for (int s1 = 0; s1 < 4; s1++)
                        {
                            suitInfo[s1] = suitInfo[s1].Trim();
                            Suits s = SuitHelper.FromXML(suitInfo[s1].Substring(0, 1));
                            if (suitInfo[s1].Length > 2)
                            {
                                string cardsInSuit = suitInfo[s1].Substring(2) + " ";
                                if (cardsInSuit.Substring(0, 1) != "-")
                                {
                                    while (cardsInSuit.Length > 1)
                                    {
                                        Ranks rank = Rank.From(cardsInSuit.Substring(0, 1));
                                        this.EventBus.HandleCardPosition(this.seat, s, rank);
                                        cardsInSuit = cardsInSuit.Substring(2);
                                    }
                                }
                            }
                        }

                        //this.EventBus.WaitForEventCompletion();
                        // TM is now expecting a response: either a bid or a 'ready for bid'
                        this.EventBus.HandleCardDealingEnded();

                        break;

                    case TableManagerProtocolState.WaitForOtherBid:
                        if (message.StartsWith("Explain "))
                        {
                            message = message.Substring(8);
                            string[] answer = message.Split(' ');
                            Seats    bidder = SeatsExtensions.FromXML(answer[0]);
                            var      bid    = new Bid(answer[answer.Length - 1], "");

                            this.EventBus.HandleExplanationNeeded(bidder, bid);
                        }
                        else
                        {
                            this.WaitForBridgeEvents = true;
                            ProtocolHelper.HandleProtocolBid(message, this.EventBus);
                        }

                        break;

                    case TableManagerProtocolState.WaitForDummiesCards:
                        //Log.Trace("Client {1} processing dummies cards", message, seat);
                        string   dummiesCards = message.Substring(2 + message.IndexOf(":"));
                        string[] suitInfo2    = dummiesCards.Split('.');
                        for (Suits s = Suits.Spades; s >= Suits.Clubs; s--)
                        {
                            int suit = 3 - (int)s;
                            suitInfo2[suit] = suitInfo2[suit].Trim();
                            if (suitInfo2[suit].Length > 2)
                            {
                                string cardsInSuit = suitInfo2[suit].Substring(2) + " ";
                                if (cardsInSuit.Substring(0, 1) != "-")
                                {
                                    while (cardsInSuit.Length > 1)
                                    {
                                        Ranks rank = Rank.From(cardsInSuit.Substring(0, 1));
                                        this.EventBus.HandleCardPosition(this.CurrentResult.Play.Dummy, s, rank);
                                        cardsInSuit = cardsInSuit.Substring(2);
                                    }
                                }
                            }
                        }

                        this.WaitForProtocolSync = false;
                        this.EventBus.HandleShowDummy(this.CurrentResult.Play.Dummy);
                        break;

                    case TableManagerProtocolState.WaitForLead:
                        this.WaitForProtocolSync = false;
                        break;

                    case TableManagerProtocolState.WaitForCardPlay:
                        if (message.Contains("to lead"))
                        {
                            /// This indicates a timing issue: TM sent a '... to lead' message before TD sent its HandleTrickFinished event
                            /// Wait until I receveive the HandleTrickFinished event
                            Log.Trace(1, "TableManagerClient.ProcessMessage {0}: received 'to lead' before HandleTrickFinished", this.seat);
                            //Debugger.Break();
                        }
                        else
                        {
                            string[] cardPlay = message.Split(' ');
                            Seats    player   = SeatsExtensions.FromXML(cardPlay[0]);
                            Card     card     = new Card(SuitHelper.FromXML(cardPlay[2].Substring(1, 1)), Rank.From(cardPlay[2].Substring(0, 1)));
                            if (player != this.CurrentResult.Play.Dummy)
                            {
                                this.EventBus.HandleCardPosition(player, card.Suit, card.Rank);
                            }
                            this.WaitForBridgeEvents = true;
                            this.EventBus.HandleCardPlayed(player, card.Suit, card.Rank);
                        }

                        break;

                    case TableManagerProtocolState.WaitForDisconnect:
                        this.state = TableManagerProtocolState.Finished;
                        this.EventBus.HandleTournamentStopped();
                        break;
                    }
                }
                catch (Exception ex)
                {
                    Log.Trace(0, "Error while processing message '{0}' in state {1}: {2}", message, state, ex.ToString());
                    throw;
                }
            }
            else
            {           // unexpected message
            }
        }
        private void ChangeState(string message, string expected, TableManagerProtocolState newState, Seats seat)
        {
            var exp = expected.Split(';');

            if (message.ToLowerInvariant().Replace("  ", " ").StartsWith(exp[0].ToLowerInvariant()) || (exp.Length >= 2 && message.ToLowerInvariant().Replace("  ", " ").StartsWith(exp[1].ToLowerInvariant())))
            {
                this.clients[seat].state = newState;
                var allReady = true;
                for (Seats s = Seats.North; s <= Seats.West; s++)
                {
                    if (this.clients[s] == null || this.clients[s].state != newState)
                    {
                        allReady = false; break;
                    }
                }
                if (allReady)
                {
#if syncTrace
                    Log.Trace(2, "{1} ChangeState {0}", newState, this.Name);
#endif
                    switch (newState)
                    {
                    case TableManagerProtocolState.Initial:
                        break;

                    case TableManagerProtocolState.WaitForSeated:
                        break;

                    case TableManagerProtocolState.WaitForTeams:
                        this.BroadCast("Teams : N/S : \"" + this.clients[Seats.North].teamName + "\" E/W : \"" + this.clients[Seats.East].teamName + "\"");
                        this.OnHostEvent(this, HostEvents.ReadyForTeams, null);
                        break;

                    case TableManagerProtocolState.WaitForStartOfBoard:
                        this.c.StartNextBoard().Wait();
                        break;

                    case TableManagerProtocolState.WaitForBoardInfo:
                        this.BroadCast("Board number {0}. Dealer {1}. {2} vulnerable.", this.c.currentBoard.BoardNumber, this.c.currentBoard.Dealer.ToXMLFull(), ProtocolHelper.Translate(this.c.currentBoard.Vulnerable));
                        break;

                    case TableManagerProtocolState.WaitForMyCards:
                        this.clients[Seats.North].WriteData(ProtocolHelper.Translate(Seats.North, this.c.currentBoard.Distribution));
                        this.clients[Seats.East].WriteData(ProtocolHelper.Translate(Seats.East, this.c.currentBoard.Distribution));
                        this.clients[Seats.South].WriteData(ProtocolHelper.Translate(Seats.South, this.c.currentBoard.Distribution));
                        this.clients[Seats.West].WriteData(ProtocolHelper.Translate(Seats.West, this.c.currentBoard.Distribution));
                        break;

                    case TableManagerProtocolState.WaitForCardPlay:
                        break;

                    case TableManagerProtocolState.WaitForOtherBid:
                        for (Seats s = Seats.North; s <= Seats.West; s++)
                        {
                            this.clients[s].state = TableManagerProtocolState.WaitForCardPlay;
                        }
                        ProtocolHelper.HandleProtocolBid(this.lastRelevantMessage, this.EventBus);
                        break;

                    case TableManagerProtocolState.WaitForOtherCardPlay:
                        ProtocolHelper.HandleProtocolPlay(this.lastRelevantMessage, this.EventBus);
                        break;

                    case TableManagerProtocolState.WaitForOwnCardPlay:
                        break;

                    case TableManagerProtocolState.WaitForDummiesCardPlay:
                        break;

                    case TableManagerProtocolState.GiveDummiesCards:
                        var cards = ProtocolHelper.Translate(this.CurrentResult.Play.Dummy, this.c.currentBoard.Distribution).Replace(this.CurrentResult.Play.Dummy.ToXMLFull(), "Dummy");
                        for (Seats s = Seats.North; s <= Seats.West; s++)
                        {
                            if (s != this.CurrentResult.Play.Dummy)
                            {
                                this.clients[s].WriteData(cards);
                            }
                        }
                        for (Seats s = Seats.North; s <= Seats.West; s++)
                        {
                            this.clients[s].state = (s == this.CurrentResult.Auction.Declarer ? TableManagerProtocolState.WaitForOwnCardPlay : TableManagerProtocolState.WaitForCardPlay);
                            lock (this.clients) this.clients[s].Pause = false;
                        }
                        break;

                    case TableManagerProtocolState.WaitForDisconnect:
                        break;

                    case TableManagerProtocolState.WaitForLead:
                        break;

                    case TableManagerProtocolState.Finished:
                        break;

                    default:
                        break;
                    }
                }
            }
            else
            {
#if syncTrace
                Log.Trace(0, "{1} expected '{0}'", expected, this.Name);
                this.DumpQueue();
#endif
                this.clients[seat].Refuse("Expected '{0}'", expected);
                throw new InvalidOperationException(string.Format("Expected '{0}'", expected));
            }
        }