public string Build(IList<MoveType> moves, out int score)
        {
            if(moves.Count == 0)
            {
                score = 0;
                return string.Empty;
            }

            var scores = new Score[moves.Count];
            var phrases = new string[moves.Count];
            for(int idx = 0; idx < moves.Count; idx++)
            {
                var items = PowerPhrases
                    .Where(phrase => EndsWithPhrase(moves, phrase, idx))
                    .Select(phrase => new {Phrase = phrase, Score = idx < phrase.Length ? new Score() : scores[idx - phrase.Length]});

                if(idx > 0)
                    items = items.Concat(new[] {new {Phrase = (string)null, Score = scores[idx - 1]}});

                var item = items
                    .MaxOrDefault(elem => elem.Score.CountNewScore(elem.Phrase));

                scores[idx] = item == null ? (idx == 0 ? new Score() : scores[idx - 1]) : item.Score.GetUpdatedScore(item.Phrase);
                phrases[idx] = item == null ? null : item.Phrase;
            }

            score = scores[moves.Count - 1].TotalScore;

            var result = new string[moves.Count];
            for(int idx = moves.Count - 1; idx >= 0;)
            {
                var phrase = phrases[idx];
                if(phrase != null)
                {
                    result[idx] = phrase;
                    idx -= phrase.Length;
                    continue;
                }
                result[idx] = SelectMove(moves[idx]).First().ToString();
                idx--;
            }

            return string.Join(null, result);
        }
        public Score GetUpdatedScore(string phrase)
        {
            var score = new Score
            {
                PhraseCounts = PhraseCounts == null ? new Dictionary<string, int>() : new Dictionary<string, int>(PhraseCounts),
                TotalScore = CountNewScore(phrase)
            };

            if(phrase != null)
            {
                if(!score.PhraseCounts.ContainsKey(phrase))
                    score.PhraseCounts[phrase] = 0;
                score.PhraseCounts[phrase]++;
            }

            return score;
        }