Exemplo n.º 1
0
        static void Main()
        {
            var(codeFactory, rounds) = StartGame();

            var random        = new Random();
            var humanScore    = 0;
            var computerScore = 0;

            for (var round = 1; round <= rounds; ++round)
            {
                View.ShowStartOfRound(round);

                if (!HumanTakesTurn())
                {
                    return;
                }

                while (!ComputerTakesTurn())
                {
                    View.ShowInconsistentInformation();
                }
            }

            View.ShowScores(humanScore, computerScore, isFinal: true);

            /// <summary>
            /// Gets the game start parameters from the user.
            /// </summary>
            (CodeFactory codeFactory, int rounds) StartGame()
            {
                View.ShowBanner();

                var colors    = Controller.GetNumberOfColors();
                var positions = Controller.GetNumberOfPositions();
                var rounds    = Controller.GetNumberOfRounds();

                var codeFactory = new CodeFactory(positions, colors);

                View.ShowTotalPossibilities(codeFactory.Possibilities);
                View.ShowColorTable(codeFactory.Colors);

                return(codeFactory, rounds);
            }

            /// <summary>
            /// Executes the human's turn.
            /// </summary>
            /// <returns>
            /// True if thue human completed his or her turn and false if
            /// he or she quit the game.
            /// </returns>
            bool HumanTakesTurn()
            {
                // Store a history of the human's guesses (used for the show
                // board command below).
                var history     = new List <TurnResult>();
                var code        = codeFactory.Create(random);
                var guessNumber = default(int);

                for (guessNumber = 1; guessNumber <= MaximumGuesses; ++guessNumber)
                {
                    var guess = default(Code);

                    while (guess is null)
                    {
                        switch (Controller.GetCommand(guessNumber, codeFactory.Positions, codeFactory.Colors))
                        {
                        case (Command.MakeGuess, Code input):
                            guess = input;
                            break;

                        case (Command.ShowBoard, _):
                            View.ShowBoard(history);
                            break;

                        case (Command.Quit, _):
                            View.ShowQuitGame(code);
                            return(false);
                        }
                    }

                    var(blacks, whites) = code.Compare(guess);
                    if (blacks == codeFactory.Positions)
                    {
                        break;
                    }

                    View.ShowResults(blacks, whites);

                    history.Add(new TurnResult(guess, blacks, whites));
                }

                if (guessNumber <= MaximumGuesses)
                {
                    View.ShowHumanGuessedCode(guessNumber);
                }
                else
                {
                    View.ShowHumanFailedToGuessCode(code);
                }

                humanScore += guessNumber;

                View.ShowScores(humanScore, computerScore, isFinal: false);
                return(true);
            }

            /// <summary>
            /// Executes the computers turn.
            /// </summary>
            /// <returns>
            /// True if the computer completes its turn successfully and false
            /// if it does not (due to human error).
            /// </returns>
            bool ComputerTakesTurn()
            {
                var isCandidate = new bool[codeFactory.Possibilities];
                var guessNumber = default(int);

                Array.Fill(isCandidate, true);

                View.ShowComputerStartTurn();
                Controller.WaitUntilReady();

                for (guessNumber = 1; guessNumber <= MaximumGuesses; ++guessNumber)
                {
                    // Starting with a random code, cycle through codes until
                    // we find one that is still a candidate solution.  If
                    // there are no remaining candidates, then it implies that
                    // the user made an error in one or more responses.
                    var codeNumber = EnumerableExtensions.Cycle(random.Next(codeFactory.Possibilities), codeFactory.Possibilities)
                                     .FirstOrDefault(i => isCandidate[i], -1);

                    if (codeNumber < 0)
                    {
                        return(false);
                    }

                    var guess = codeFactory.Create(codeNumber);

                    var(blacks, whites) = Controller.GetBlacksWhites(guess);
                    if (blacks == codeFactory.Positions)
                    {
                        break;
                    }

                    // Mark codes which are no longer potential solutions.  We
                    // know that the current guess yields the above number of
                    // blacks and whites when compared to the solution, so any
                    // code that yields a different number of blacks or whites
                    // can't be the answer.
                    foreach (var(candidate, index) in codeFactory.EnumerateCodes().Select((candidate, index) => (candidate, index)))
                    {
                        if (isCandidate[index])
                        {
                            var(candidateBlacks, candidateWhites) = guess.Compare(candidate);
                            if (blacks != candidateBlacks || whites != candidateWhites)
                            {
                                isCandidate[index] = false;
                            }
                        }
                    }
                }

                if (guessNumber <= MaximumGuesses)
                {
                    View.ShowComputerGuessedCode(guessNumber);
                }
                else
                {
                    View.ShowComputerFailedToGuessCode();
                }

                computerScore += guessNumber;
                View.ShowScores(humanScore, computerScore, isFinal: false);

                return(true);
            }
        }