0x0001F36D 5 yıl önce
ebeveyn
işleme
5216f00dba

+ 6 - 0
Yuuna.sln

@@ -6,10 +6,16 @@ MinimumVisualStudioVersion = 10.0.40219.1
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yuuna.Contracts", "src\Yuuna.Contracts\Yuuna.Contracts.csproj", "{9063A9AB-AD78-49F4-9B59-192CAC7A798A}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yuuna", "src\Yuuna\Yuuna.csproj", "{32DA3206-124F-4AB8-99E1-9B81066C9DDD}"
+	ProjectSection(ProjectDependencies) = postProject
+		{FCA784A1-546A-47E1-B5C1-3CF6A44FB3A7} = {FCA784A1-546A-47E1-B5C1-3CF6A44FB3A7}
+	EndProjectSection
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yuuna.Common", "src\Yuuna.Common\Yuuna.Common.csproj", "{FCA784A1-546A-47E1-B5C1-3CF6A44FB3A7}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yuuna.Faker", "src\Yuuna.Faker\Yuuna.Faker.csproj", "{B38575D1-8904-4358-921A-11F3ED6FEAA8}"
+	ProjectSection(ProjectDependencies) = postProject
+		{FCA784A1-546A-47E1-B5C1-3CF6A44FB3A7} = {FCA784A1-546A-47E1-B5C1-3CF6A44FB3A7}
+	EndProjectSection
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7AD85507-85E8-46E4-9A36-A9DFD2FC3513}"
 	ProjectSection(SolutionItems) = preProject

+ 2 - 3
src/Yuuna.Contracts/Optimization/IScore.cs

@@ -11,11 +11,10 @@ namespace Yuuna.Contracts.Optimization
 
     public interface IScore
     {
-        IPattern Contrast { get; }
-        double Coverage { get; }
+        IPattern Pattern { get; } 
         bool IsCompacted { get; }
         IImmutableList<IGroup> Missing { get; }
-        PluginBase Plugin { get; }
+        PluginBase Owner { get; }
         IImmutableList<IPair> SequentialMatches { get; }
     }
 }

+ 8 - 11
src/Yuuna.Contracts/Optimization/Score.cs

@@ -10,32 +10,29 @@ namespace Yuuna.Contracts.Optimization
     using Yuuna.Contracts.Plugins;
     using Yuuna.Contracts.Semantics;
 
-    internal struct Score : IScore
+    public struct Score : IScore
     {
         /// <summary>
         /// 比較的文法。
         /// </summary>
-        public IPattern Contrast { get; }
-
-        public double Coverage { get; }
+        public IPattern Pattern { get; } 
 
         public bool IsCompacted { get; }
 
         public IImmutableList<IGroup> Missing { get; }
 
-        public PluginBase Plugin { get; }
+        public PluginBase Owner { get; }
 
         public IImmutableList<IPair> SequentialMatches { get; }
 
-        internal Score(PluginBase owner, IImmutableList<IPair> matches, IPattern contrast)
+        public Score(IPattern pattern, IImmutableList<IPair> matches)
         {
-            this.Contrast = contrast;
-            this.Plugin = owner;
+            this.Pattern = pattern;
+            this.Owner = pattern.Owner;
             this.SequentialMatches = matches;
 
-            this.IsCompacted = contrast.Count == matches.Count;
-            this.Coverage = (double)matches.Count / contrast.Count;
-            this.Missing = contrast.ToImmutable().Except(matches.Select(x => x.Synonym.Owner)).ToImmutableArray();
+            this.IsCompacted = pattern.Count == matches.Count;
+            this.Missing = pattern.ToImmutable().Except(matches.Select(x => x.Synonym.Owner)).ToImmutableArray();
         }
     }
 }

+ 6 - 6
src/Yuuna.Contracts/Optimization/ScoreComparer.cs

@@ -15,23 +15,23 @@ namespace Yuuna.Contracts.Optimization
 
         public int Compare(IScore x, IScore y)
         {
-            var f1 = x.Contrast.SequentialKeys.Count == x.SequentialMatches.Count;
-            var f2 = y.Contrast.SequentialKeys.Count == y.SequentialMatches.Count;
+            var f1 = x.Pattern.SequentialKeys.Count == x.SequentialMatches.Count;
+            var f2 = y.Pattern.SequentialKeys.Count == y.SequentialMatches.Count;
             if (f1 & f2)
-                return x.Contrast.SequentialKeys.Count - y.Contrast.SequentialKeys.Count;
+                return x.Pattern.SequentialKeys.Count - y.Pattern.SequentialKeys.Count;
             else if (f1)
                 return 1;
             else if (f2)
                 return -1;
             else
             {
-                var v1 = x.Contrast.SequentialKeys.Count - x.SequentialMatches.Count;
-                var v2 = y.Contrast.SequentialKeys.Count - y.SequentialMatches.Count;
+                var v1 = x.Pattern.SequentialKeys.Count - x.SequentialMatches.Count;
+                var v2 = y.Pattern.SequentialKeys.Count - y.SequentialMatches.Count;
                 if (v1 > v2)
                     return -v2;
                 else if (v1 < v2)
                     return v1;
-                return x.Contrast.SequentialKeys.Count - y.Contrast.SequentialKeys.Count;
+                return x.Pattern.SequentialKeys.Count - y.Pattern.SequentialKeys.Count;
             }
         }
     }

+ 128 - 4
src/Yuuna.Contracts/Optimization/StrategyBase.cs

@@ -3,12 +3,127 @@
 
 namespace Yuuna.Contracts.Optimization
 {
+    using System;
     using System.Collections.Generic;
     using System.Collections.Immutable;
+    using System.Diagnostics.CodeAnalysis;
+    using System.Linq;
     using System.Runtime.CompilerServices;
 
     using Yuuna.Contracts.Patterns;
     using Yuuna.Contracts.Plugins;
+    using Yuuna.Contracts.Semantics;
+
+    public abstract class Plan
+    {
+        public Plan()
+        {
+
+        }
+
+        public void FindBest(IEnumerable<PluginBase> plugins, IImmutableList<string> feed)
+        {
+            var list = ImmutableArray.CreateBuilder<Match>();
+            foreach (var plugin in plugins)
+            {
+                foreach (var p in plugin.Patterns.ToImmutable())
+                {
+                    var score = this.CalculatePatternMatch(p, feed);
+                    if (score.HasValue)
+                        list.Add(score.Value);
+                }
+            }
+
+            var e = this.E(list.ToImmutable());
+        } 
+
+        protected virtual void E(IImmutableList<Match> matches)
+        {
+            var sta = new SortedList<Match, int>();
+            foreach (var j in matches)
+            {
+                if (!sta.ContainsKey(j))
+                    sta.Add(j, 1);
+                else
+                    sta[j]++;
+            }
+
+            var tuple = new List<Tuple<Match, double>>();
+            foreach (var s in sta)
+            {
+                var x = (s.Value) / (double)-(matches.Count * s.Key.SequentialMatches.Count);
+                var y = Math.Tanh(Math.Pow(Math.E, x));
+                tuple.Add(Tuple.Create(s.Key, y));
+            }
+
+            foreach (var s in tuple.OrderByDescending(x => x.Item2))
+            {
+                Console.WriteLine(s);
+            }
+        }
+
+        /// <summary>
+        /// 評估 <paramref name="pattern"/> 與 <paramref name="feed"/> 的符合程度並給予一個分數,並返回一個 <see cref="Match"/> 物件。
+        /// 若回傳 <see langword="null"/> 則此規則將不列入計算。
+        /// </summary>
+        /// <param name="pattern"></param>
+        /// <param name="feed"></param>
+        /// <returns></returns>
+        protected virtual Match? CalculatePatternMatch(IPattern pattern, IImmutableList<string> feed)
+        {
+            var matches = ImmutableArray.CreateBuilder<ISynonym>();
+
+            using (var iterator = pattern.ToImmutable().GetEnumerator())
+            {
+                iterator.MoveNext();
+                foreach (var word in feed)
+                {
+                    if (iterator.Current.TryGetSynonym(word, out var s))
+                    {
+                        matches.Add(s);
+                        if (!iterator.MoveNext())
+                            break;
+                    }
+                }
+            } 
+            return new Match(pattern, matches.ToImmutable());
+        }
+    } 
+
+    public struct Match : IEquatable<Match>
+    {
+        /// <summary>
+        /// 比較的文法。
+        /// </summary>
+        public IPattern Pattern { get; }
+
+        /// <summary>
+        /// 表示缺少的群組物件清單。
+        /// </summary>
+        public IImmutableList<IGroup> Missing { get; }
+
+        /// <summary> 
+        /// </summary>
+        public IImmutableList<ISynonym> SequentialMatches { get; }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="pattern">比對的目標</param>
+        /// <param name="matches">從頭逐一比對後符合的項目</param>
+        public Match(IPattern pattern, IImmutableList<ISynonym> matches)
+        {
+            this.Pattern = pattern; 
+            this.SequentialMatches = matches; 
+            this.Missing = pattern.ToImmutable().Except(matches.Select(x => x.Owner)).ToImmutableArray();
+        }
+
+        public bool Equals(Match other)
+        {
+            return this.Pattern.Equals(other.Pattern);
+        }
+    }
+
 
     public abstract class StrategyBase
     {
@@ -20,6 +135,13 @@ namespace Yuuna.Contracts.Optimization
         {
         }
 
+        /// <summary>
+        /// 評估 <paramref name="plugin"/> 中最佳的
+        /// </summary>
+        /// <param name="plugin"></param>
+        /// <param name="words"></param>
+        /// <param name="set"></param>
+        /// <returns></returns>
         internal IImmutableList<IScore> Assess(PluginBase plugin, IImmutableList<string> words, IPatternSet set)
         {
             var scores = new List<IScore>();
@@ -32,16 +154,18 @@ namespace Yuuna.Contracts.Optimization
             }
             scores.Sort(this.Comparer);
 
+
+
             return scores.ToImmutableArray();
         }
 
         /// <summary>
-        /// 評估
+        /// 評估 <paramref name="pattern"/> 與 <paramref name="words"/> 的符合程度,並返回評估後的分數物件
         /// </summary>
         /// <param name="words"></param>
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        private IScore Evaluate(PluginBase plugin, IImmutableList<string> words, IPattern pattern)
-        {
+        private IScore Evaluate(IImmutableList<string> words, IPattern pattern)
+        { 
             var matches = ImmutableArray.CreateBuilder<IPair>();
 
             using (var iterator = pattern.ToImmutable().GetEnumerator())
@@ -58,7 +182,7 @@ namespace Yuuna.Contracts.Optimization
                 }
             }
 
-            return new Score(plugin, matches.ToImmutable(), pattern);
+            return new Score(matches.ToImmutable(), pattern);
         }
     }
 }

+ 3 - 0
src/Yuuna.Contracts/Patterns/IPattern.cs

@@ -8,9 +8,12 @@ namespace Yuuna.Contracts.Patterns
 
     using Yuuna.Contracts.Semantics;
     using Yuuna.Common.Linq;
+    using Yuuna.Contracts.Plugins;
 
     public interface IPattern : IEquatable<IPattern>, IImmutable<IGroup>
     {
+        PluginBase Owner { get; }
+
         int Count { get; }
 
         IImmutableList<string> SequentialKeys { get; }

+ 10 - 9
src/Yuuna.Contracts/Patterns/Internal/PatternFactory.cs

@@ -9,15 +9,18 @@ namespace Yuuna.Contracts.Patterns
     using System.Collections.Immutable;
 
     using Yuuna.Common.Artisan.Cascade;
+    using Yuuna.Contracts.Plugins;
     using Yuuna.Contracts.Semantics;
 
     internal sealed class PatternFactory : Initial<InvokeBuilder, IPattern>, IPatternSet, IPatternBuilder
     {
         private readonly ConcurrentDictionary<IPattern, Bag> _list;
+        private readonly PluginBase _owner;
 
-        public PatternFactory()
+        internal PatternFactory(PluginBase owner)
         {
             this._list = new ConcurrentDictionary<IPattern, Bag>();
+            this._owner = owner;
         }
 
         public IInvokeBuilder Build(IGroup group, params IGroup[] rest)
@@ -25,7 +28,7 @@ namespace Yuuna.Contracts.Patterns
             if (group is null)
                 throw new ArgumentNullException(nameof(group));
 
-            var g = new Pattern();
+            var g = new Pattern(this._owner);
             g.Add(group);
             if (rest != null)
                 foreach (var item in rest)
@@ -37,12 +40,9 @@ namespace Yuuna.Contracts.Patterns
 
         public IImmutableList<IPattern> ToImmutable() => this._list.Keys.ToImmutableArray();
 
-        public bool TryGet(IPattern pattern, out Invoke invoke)
+        public bool TryGet(IPattern pattern, out Bag invoke)
         {
-            var b = this._list.TryGetValue(pattern, out var s);
-            System.Console.WriteLine(b);
-            invoke = s.Invoke;
-            return b;
+            return this._list.TryGetValue(pattern, out invoke);
         }
 
         protected override void OnCompleted(Queue<object> session)
@@ -53,7 +53,8 @@ namespace Yuuna.Contracts.Patterns
                 Invoke = session.Dequeue() as Invoke,
                 Incomplete = session.Dequeue() as Incomplete,
             };
-            System.Console.WriteLine(this._list.TryAdd(ge.Pattern, ge));
+            
+            this._list.TryAdd(ge.Pattern, ge);
         }
     }
-}
+};

+ 6 - 2
src/Yuuna.Contracts/Patterns/Pattern.cs

@@ -6,7 +6,7 @@ namespace Yuuna.Contracts.Patterns
     using System.Collections.Immutable;
     using System.Diagnostics;
     using System.Linq;
-
+    using Yuuna.Contracts.Plugins;
     using Yuuna.Contracts.Semantics;
 
     public sealed class Pattern : IPattern
@@ -26,10 +26,13 @@ namespace Yuuna.Contracts.Patterns
 
         public IImmutableList<string> SequentialKeys { get; private set; }
 
-        internal Pattern()
+        public PluginBase Owner { get; }
+
+        internal Pattern(PluginBase owner)
         {
             this._keyBuilder = ImmutableArray.CreateBuilder<string>();
             this._groupBuilder = ImmutableArray.CreateBuilder<IGroup>();
+            this.Owner = owner;
         }
 
         public bool Equals(IPattern other)
@@ -57,5 +60,6 @@ namespace Yuuna.Contracts.Patterns
             this.SequentialKeys = this._keyBuilder.ToImmutable();
             this._groups = this._groupBuilder.ToImmutable();
         }
+
     }
 }

+ 10 - 6
src/Yuuna.Contracts/PluginBase.cs → src/Yuuna.Contracts/Plugins/PluginBase.cs

@@ -10,21 +10,29 @@ namespace Yuuna.Contracts.Plugins
     using Yuuna.Contracts.Patterns;
     using Yuuna.Contracts.Semantics;
     using Yuuna.Contracts.TextSegmention;
-
+    
     public abstract class PluginBase
     {
         private readonly PatternFactory _patternfactory;
         private StrategyBase _strategy;
 
+        internal IPatternSet Patterns => this._patternfactory;
+
         public PluginBase()
         {
-            this._patternfactory = new PatternFactory();
+            this._patternfactory = new PatternFactory(this);
         }
 
+        [Obsolete]
         internal IImmutableList<IScore> Evaluate(IImmutableList<string> cutted)
         {
             return this._strategy.Assess(this, cutted, this._patternfactory);
         }
+        [Obsolete]
+        internal Invoke SelectBest(IScore score)
+        {
+            return this._patternfactory.TryGet(score.Pattern, out var b) ? b : null;
+        }
 
         internal bool Initialize(StrategyBase strategy, ITextSegmenter textSegmenter, IGroupManager groupManager)
         {
@@ -44,10 +52,6 @@ namespace Yuuna.Contracts.Plugins
             }
         }
 
-        internal Invoke SelectBest(IScore score)
-        {
-            return this._patternfactory.TryGet(score.Contrast, out var b) ? b : null;
-        }
 
         /// <summary>
         /// 在初始化後引發。

+ 43 - 16
src/Yuuna.Faker/Fake.cs

@@ -16,39 +16,66 @@ namespace TestPlugin
         protected override void BuildPatterns(IGroupManager g, IPatternBuilder p)
         {
             g.Define("open").AppendOrCreate(new[] { "打開", "開" });
-            g.Define("door").AppendOrCreate(new[] { "門", "房間門" });
+            g.Define("close").AppendOrCreate(new[] { "關上", "關" });
+            g.Define("door").AppendOrCreate(new[] { "門", "房間門", "房門" });
             g.Define("light").AppendOrCreate(new[] { "燈", "檯燈" });
 
             p.Build(g["open"], g["door"]).OnInvoke(score =>
             {
                 var DOOR = new { IS_OPENED = new[] { true, false, true, false }.RandomTakeOne() };
+                Console.WriteLine("門的狀態是: " + (DOOR.IS_OPENED ? "開著的" : "關著的" ));
                 // 開門
                 if (!DOOR.IS_OPENED)
                     return (Moods.Happy, "已經開好門囉 <3");
                 else
-                    return (Moods.Sad, "可是門本來就是開的欸 QAQ");
+                    return new Response[]
+                    {
+                        (Moods.Sad,  "可是門本來就是開的欸 QAQ"  ),
+                        (Moods.Normal,  "喔是喔,不過就是一扇門,早就開好了"  ),
+                        (Moods.Sad,  "可是門本來就是開的欸 QAQ"  ),
+                    }
+                    .RandomTakeOne();
             }).OnIncomplete(s => throw new NotImplementedException());
 
-            p.Build(g["open"], g["light"]).OnInvoke(score =>
+            p.Build(g["close"], g["door"]).OnInvoke(score =>
             {
-                var LIGHT = new { IS_OPENED = new[] { true, false, true, false }.RandomTakeOne() };
-                // 開燈
-                if (!LIGHT.IS_OPENED)
-                    return (Moods.Happy, "已經開好燈囉 <3");
+                var DOOR = new { IS_OPENED = new[] { true, false, true, false }.RandomTakeOne() };
+                Console.WriteLine("門的狀態是: " + (DOOR.IS_OPENED ? "開著的" : "關著的"));
+                // 開門
+                if (DOOR.IS_OPENED)
+                    return (Moods.Happy, "已經關好門囉 <3");
                 else
-                    return (Moods.Sad, "可是燈本來就是開的欸 QAQ");
+                    return new Response[]
+                    {
+                        (Moods.Sad,  "可是門本來就是關的欸 QAQ"  ),
+                        (Moods.Sad,  "門本來就是關著的,北七逆?"  ),
+                        (Moods.Sad,  "我不想動,因為本來就沒開過"  ),
+                    }
+                    .RandomTakeOne();
             }).OnIncomplete(s => throw new NotImplementedException());
 
-            //g.Define("browser").AppendOrCreate(new[] { "瀏覽器", "chrome" });
-            //p.Build(g["open"], g["browser"]).OnInvoke(score =>
+            //p.Build(g["open"], g["light"]).OnInvoke(score =>
+            //{
+            //    var LIGHT = new { IS_OPENED = new[] { true, false, true, false }.RandomTakeOne() };
+            //    Console.WriteLine("燈的狀態是: " + (LIGHT.IS_OPENED ? "開著的" : "關著的"));
+            //    // 開燈
+            //    if (!LIGHT.IS_OPENED)
+            //        return (Moods.Happy, "已經開好燈囉 <3");
+            //    else
+            //        return (Moods.Sad, "可是燈本來就是開的欸 QAQ");
+            //}).OnIncomplete(s => throw new NotImplementedException());
+
+            //p.Build(g["close"], g["light"]).OnInvoke(score =>
             //{
-            //    var DOOR = new { IS_OPENED = true };
-            //    // 開門
-            //    if (!DOOR.IS_OPENED)
-            //        return (Moods.Happy, "已經開好門囉 <3");
+            //    var LIGHT = new { IS_OPENED = new[] { true, false, true, false }.RandomTakeOne() };
+            //    Console.WriteLine("燈的狀態是: " + (LIGHT.IS_OPENED ? "開著的" : "關著的"));
+            //    // 開燈
+            //    if (!LIGHT.IS_OPENED)
+            //        return (Moods.Happy, "已經關好燈囉 <3");
             //    else
-            //        return (Moods.Sad, "可是門本來就是開的欸 QAQ");
-            //});
+            //        return (Moods.Sad, "可是燈本來就是關的欸 QAQ");
+            //}).OnIncomplete(s => throw new NotImplementedException());
+
         }
     }
 }

+ 27 - 12
src/Yuuna/EntryPoint.cs

@@ -18,6 +18,7 @@ namespace Yuuna
     using Yuuna.Semantics;
     using Yuuna.TextSegmention;
     using Yuuna.Common.Utilities;
+    using System.Threading.Tasks;
 
     internal class EntryPoint
     {
@@ -29,20 +30,33 @@ namespace Yuuna
                 var stt = SpeechRecognizer.Create("secret.json");
                 stt.RecognizeCompleted += a =>
                 {
-                    Console.WriteLine("From Google Cloud Speech: " + a[0].Transcript);
-                    Send(a[0].Transcript);
+                    if (a.Count > 0)
+                    {
+                        Console.WriteLine("## Google 語音: " + a[0].Transcript);
+                        Send(a[0].Transcript);
+                    }
                 };
-                using (stt.Recognize())
-                {
-                    Console.WriteLine("請說 [打開燈] 並按下 Enter 鍵");
-                    Console.ReadKey();
-                }
+
+                Console.WriteLine("## Proof of Concept Ver.");
+                Console.WriteLine("可以叫我開關燈或者開關門,其他的我還不會");
+
+                Console.WriteLine("按下 Enter 鍵開始錄音,任意鍵離開");
+                Loop:
+                if(Console.ReadKey().Key == ConsoleKey.Enter)
+                { 
+                    using (stt.Recognize())
+                    {
+                        Console.WriteLine("按下 Enter 停止錄音,任意鍵離開"); 
+                        if(Console.ReadKey().Key == ConsoleKey.Enter)
+                            goto Loop;
+                    }
+                } 
             }
             catch (Exception e)
             {
                 Console.WriteLine(e.Message);
-            }
-            Console.ReadKey();
+                Console.ReadKey();
+            } 
         }
 
         public static void Send(string text)
@@ -59,6 +73,7 @@ namespace Yuuna
             Console.WriteLine("我: " + text);
             var cutted = segmenter.Cut(text);
             Console.WriteLine($"來自分詞器 {segmenter.Name} 的分詞結果: [ {string.Join(", ", cutted)} ]");
+             
 
             var list = new List<IScore>();
             foreach (var p in allPlugins)
@@ -71,7 +86,7 @@ namespace Yuuna
                 sb.Append("我不懂你的意思");
             else if (best.IsCompacted)
             {
-                var resp = best.Plugin.SelectBest(best).Invoke(best);
+                var resp = best.Owner.SelectBest(best).Invoke(best);
                 Console.WriteLine(resp.Mood.ToString());
                 sb.Append(resp.Message);
             }
@@ -84,7 +99,7 @@ namespace Yuuna
                         {
                             Console.WriteLine("#1");
                             sb.Append("你" + new[] { "是想", "想要" }.RandomTakeOne() + " ");
-                            sb.Append(choices.Select(x => x.Contrast.ToImmutable().Aggregate(string.Empty, (s, g) => s += g.ToImmutable().RandomTakeOne().ToImmutable().RandomTakeOne())));
+                            sb.Append(choices.Select(x => x.Pattern.ToImmutable().Aggregate(string.Empty, (s, g) => s += g.ToImmutable().RandomTakeOne().ToImmutable().RandomTakeOne())));
                             sb.Append(" 嗎?");
                         }
                         break;
@@ -93,7 +108,7 @@ namespace Yuuna
                         {
                             Console.WriteLine("#2");
                             sb.Append("你" + new[] { "是想", "想要" }.RandomTakeOne() + " ");
-                            sb.AppendJoin(" 還是 ", choices.Select(x => x.Contrast.ToImmutable().Aggregate(string.Empty, (s, g) => s += g.ToImmutable().RandomTakeOne().ToImmutable().RandomTakeOne())));
+                            sb.AppendJoin(" 還是 ", choices.Select(x => x.Pattern.ToImmutable().Aggregate(string.Empty, (s, g) => s += g.ToImmutable().RandomTakeOne().ToImmutable().RandomTakeOne())));
                             sb.Append(" ?");
                         }
                         break;

+ 13 - 0
src/Yuuna/Strategy/Policy.cs

@@ -0,0 +1,13 @@
+
+namespace Yuuna
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Text;
+    using Yuuna.Common.Linq;
+
+    public interface IStrategy
+    {
+        void Evaluate(IImmutable<string> cutted);
+    }
+}

+ 8 - 3
src/Yuuna/TextSegmention/JiebaSegmenter.cs

@@ -28,18 +28,23 @@ namespace Yuuna.TextSegmention
 
             foreach (var name in manager.Keys)
             {
-                Console.WriteLine("name: " + name);
+                this.InternalLog("name: " + name);
                 foreach (var synonym in manager[name].ToImmutable())
                 {
-                    Console.WriteLine("  count: " + synonym.ToImmutable().Count);
+                    this.InternalLog("  count: " + synonym.ToImmutable().Count);
                     foreach (var w in synonym.ToImmutable())
                     {
-                        Console.WriteLine("  added: " + w);
+                        this.InternalLog("  added: " + w);
                         this._jieba.AddWord(w);
                     }
                 }
                 Console.WriteLine();
             }
         }
+
+        private void InternalLog(string v)
+        {
+            Console.WriteLine(v);
+        }
     }
 }

+ 1 - 6
src/Yuuna/Yuuna.csproj

@@ -7,18 +7,13 @@
 
   <ItemGroup>
     <ProjectReference Include="..\Yuuna.Contracts\Yuuna.Contracts.csproj" />
+    <ProjectReference Include="..\Yuuna.Faker\Yuuna.Faker.csproj" />
   </ItemGroup>
 
   <ItemGroup>
     <Folder Include="Properties\" />
   </ItemGroup>
 
-  <ItemGroup>
-    <Reference Include="Yuuna.Faker">
-      <HintPath>..\Yuuna.Faker\bin\Debug\netcoreapp3.0\Yuuna.Faker.dll</HintPath>
-    </Reference>
-  </ItemGroup>
-
   <ItemGroup>
     <None Update="secret.json">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>