/// <summary> /// 對指定運算符實例化 /// </summary> /// <param name="sign">運算符</param> /// <returns>運算符實例</returns> public IArithmetic GetFormulaOperator(SignOfOperation sign) { // 返回緩衝區中的運算符對象 Lazy <ArithmeticBase, IArithmeticMetaDataView> lazyArithmetic = ArithmeticCache.GetOrAdd(sign, (c) => { // 從MEF容器中注入本類的屬性信息(注入運算符屬性) _composer.Compose(this); LogUtil.LogDebug(MessageUtil.GetMessage(() => MsgResources.I0001L)); // 指定運算符并獲取處理類型 IEnumerable <Lazy <ArithmeticBase, IArithmeticMetaDataView> > arithmetics = Arithmetics.Where(d => { return(d.Metadata.Sign == sign); }); if (!arithmetics.Any()) { // 指定的題型參數對象未找到 throw new ArithmeticNotFoundException(MessageUtil.GetMessage(() => MsgResources.E0020L, sign.ToString())); } LogUtil.LogDebug(MessageUtil.GetMessage(() => MsgResources.I0002L, sign.ToString())); return(arithmetics.First()); }); ArithmeticBase arithmetic = lazyArithmetic.Value; // 內部部件組合 _composer.Compose(arithmetic); // 返回該運算符處理類型的實例 return(arithmetic); }
/// <summary> /// /// </summary> /// <param name="operation"></param> /// <returns></returns> public static string ToOperationString(this SignOfOperation operation) { var flag = string.Empty; switch (operation) { case SignOfOperation.Plus: flag = "+"; break; case SignOfOperation.Subtraction: flag = "-"; break; case SignOfOperation.Division: flag = "÷"; break; case SignOfOperation.Multiple: flag = "×"; break; case SignOfOperation.Before: flag = "之前"; break; case SignOfOperation.Later: flag = "之後"; break; default: break; } return(flag); }
/// <summary> /// 獲取運算符對應的簡寫ID /// </summary> /// <param name="operation">運算符</param> /// <returns>簡寫ID</returns> public static string OperationToID(this SignOfOperation operation) { var flag = string.Empty; switch (operation) { case SignOfOperation.Plus: flag = "P"; break; case SignOfOperation.Subtraction: flag = "S"; break; case SignOfOperation.Division: flag = "D"; break; case SignOfOperation.Multiple: flag = "M"; break; default: break; } return(flag); }
/// <summary> /// 算式作成 /// </summary> /// <param name="p">題型參數</param> /// <param name="signFunc">運算符取得用的表達式</param> private void MarkFormulaList(TimeCalculationParameter p, Func <SignOfOperation> signFunc) { // 按照指定數量作成相應的數學計算式 for (var i = 0; i < p.NumberOfQuestions; i++) { // 結束時間 TimeType endTime; SignOfOperation sign = signFunc(); // 對指定運算符實例化(時間計算:之前和之後) IArithmetic strategy = CalculateManager(sign); Formula formula = strategy.CreateFormula(new ArithmeticParameter() { // 開始時間 MaximumLimit = GetStartTime(p, out TimeType startTime), // 結束時間 MinimumLimit = GetElapsedTime(p, out TimeType elapsedTime) });
/// <summary> /// 經過時間計算式 /// </summary> /// <param name="elapsedTime">時間計算式</param> /// <param name="gap">填空項目</param> /// <param name="sign">運算符(之前\之後)</param> /// <param name="index">控件索引ID</param> /// <returns>HTML模板信息</returns> private string GetElapsedTimeHtml(TimeType elapsedTime, GapFilling gap, SignOfOperation sign, int index) { var html = string.Empty; html += string.Format(SPAN_TIME_NUM_HTML_FORMAT, "在"); // 如果是填空項目 if (gap == GapFilling.Right) { // 小時 html += string.Format(INPUT_HTML_FORMAT, index.ToString().PadLeft(2, '0'), "0"); html += string.Format(SPAN_TIME_NUM_HTML_FORMAT, Consts.HOUR_UNIT); // 分鐘 html += string.Format(INPUT_HTML_FORMAT, index.ToString().PadLeft(2, '0'), "1"); html += string.Format(SPAN_TIME_NUM_HTML_FORMAT, Consts.MINUTE_UNIT); // 秒 html += string.Format(INPUT_HTML_FORMAT, index.ToString().PadLeft(2, '0'), "2"); html += string.Format(SPAN_TIME_NUM_HTML_FORMAT, Consts.SEC_UNIT); // 題型答案 html += string.Format(INPUT_ANSWER_HTML_FORMAT, index.ToString().PadLeft(2, '0'), Base64.EncodeBase64(elapsedTime.HMSValue)); } else { // 時間顯示(eg: 9小時23分鐘3秒) // 小時 if (elapsedTime.Hours.Value != 0) { html += string.Format(SPAN_TIME_CN_HTML_FORMAT, elapsedTime.Hours, Consts.HOUR_UNIT); } // 分鐘 if (elapsedTime.Minutes.Value != 0) { html += string.Format(SPAN_TIME_CN_HTML_FORMAT, elapsedTime.Minutes, Consts.MINUTE_UNIT); } // 秒 if (elapsedTime.Seconds.Value != 0) { html += string.Format(SPAN_TIME_CN_HTML_FORMAT, elapsedTime.Seconds, Consts.SEC_UNIT); } } html += string.Format(SPAN_TIME_NUM_HTML_FORMAT, sign.ToOperationUnicode()); return(html); }
/// <summary> /// 運算符轉換為對應的字符編碼 /// </summary> /// <param name="operation">運算符(加減乘除)</param> /// <returns>字符編碼</returns> public static string ToOperationString(this SignOfOperation operation) { var flag = string.Empty; switch (operation) { // + case SignOfOperation.Plus: flag = "+"; break; // − case SignOfOperation.Subtraction: flag = "-"; break; // ÷ case SignOfOperation.Division: flag = "/"; break; // × case SignOfOperation.Multiple: flag = "*"; break; // 之前 case SignOfOperation.Before: flag = "之前"; break; // 之后 case SignOfOperation.Later: flag = "之后"; break; default: break; } return(flag); }
/// <summary> /// 運算符轉換為對應的字符編碼 /// </summary> /// <param name="operation">運算符(加減乘除)</param> /// <returns>字符編碼</returns> public static string ToOperationUnicode(this SignOfOperation operation) { var flag = string.Empty; switch (operation) { // + case SignOfOperation.Plus: flag = "+"; break; // − case SignOfOperation.Subtraction: flag = "−"; break; // ÷ case SignOfOperation.Division: flag = "÷"; break; // × case SignOfOperation.Multiple: flag = "×"; break; // 之前 case SignOfOperation.Before: flag = "之前"; break; // 之后 case SignOfOperation.Later: flag = "之后"; break; default: break; } return(flag); }
/// <summary> /// 算式作成 /// </summary> /// <param name="p">題型參數</param> /// <param name="signFunc">運算符取得用的表達式</param> private void MarkFormulaList(MathWordProblemsParameter p, Func <SignOfOperation> signFunc) { // 當前反推判定次數(一次推算內次數累加) int defeated = 0; // 按照指定數量作成相應的數學計算式 for (var i = 0; i < p.NumberOfQuestions; i++) { SignOfOperation sign = signFunc(); List <Problems> signProblems = GetProblemsBySign(sign, p.Levels); // 題庫中的數量比指定的出題數少的情況 if (signProblems.Count == 0) { continue; } // 計算式作成 MarkFormulas(p, signProblems); // 判定是否需要反推并重新作成計算式 if (CheckIsNeedInverseMethod(p.Formulas.Last())) { p.Formulas.Remove(p.Formulas.Last()); defeated++; // 如果大於兩次則認為此題無法作成繼續下一題 if (defeated == INVERSE_NUMBER) { // 當前反推判定次數復原 defeated = 0; continue; } i--; continue; } } }
/// <summary> /// 對指定運算符實例化 /// </summary> /// <param name="sign">運算符</param> /// <returns>運算符實例</returns> public IArithmetic CreateArithmeticInstance(SignOfOperation sign) { // 運算符工廠實例化 return(arithmeticFactory.GetFormulaOperator(sign)); }
/// <summary> /// 對指定運算符實例化 /// </summary> /// <param name="sign">運算符</param> /// <returns>運算符實例</returns> protected IArithmetic CalculateManager(SignOfOperation sign) { return(Helper.CreateArithmeticInstance(sign)); }
/// <summary> /// 加減算式作成 /// </summary> /// <param name="p">題型參數</param> public override void MarkFormulaList(CurrencyOperationParameter p) { // 標準題型(指定單個運算符) if (p.FourOperationsType == FourOperationsType.Standard) { // 考虑乘除法接龙答题结果会超出限制,所以只随机加减法策略 if (p.Signs[0] == SignOfOperation.Division || p.Signs[0] == SignOfOperation.Multiple) { p.Signs[0] = SignOfOperation.Plus; } // 指定單個運算符實例 IArithmetic strategy = CalculateManager(p.Signs[0]); // 按照指定數量作成相應的數學計算式 for (var i = 0; i < p.NumberOfQuestions; i++) { Formula formula = strategy.CreateFormula(new ArithmeticParameter() { MaximumLimit = p.MaximumLimit, QuestionType = p.QuestionType, MinimumLimit = 0 }); if (CheckIsNeedInverseMethod(p.Formulas, formula)) { i--; continue; } // 計算式作成 p.Formulas.Add(new CurrencyOperationFormula { // 貨幣運算方程式 CurrencyArithmetic = formula, // 等式值是不是出現在右邊 AnswerIsRight = IsRight }); } } else { // 按照指定數量作成相應的數學計算式 for (var i = 0; i < p.NumberOfQuestions; i++) { // 混合題型(加減運算符實例隨機抽取) SignOfOperation sign = CommonUtil.GetRandomNumber(SignOfOperation.Plus, SignOfOperation.Subtraction); // 對運算符實例進行cache管理 IArithmetic strategy = CalculateManager(sign); var formula = strategy.CreateFormula(new ArithmeticParameter() { MaximumLimit = p.MaximumLimit, QuestionType = p.QuestionType, MinimumLimit = 0 }); if (CheckIsNeedInverseMethod(p.Formulas, formula)) { i--; continue; } // 計算式作成 p.Formulas.Add(new CurrencyOperationFormula { // 貨幣運算方程式 CurrencyArithmetic = formula, // 等式值是不是出現在右邊 AnswerIsRight = IsRight }); } } }
/// <summary> /// 獲取指定運算符出題資料庫 /// </summary> /// <param name="sign">運算符</param> /// <param name="levels">等級選擇</param> /// <returns>出題資料庫</returns> private List <Problems> GetProblemsBySign(SignOfOperation sign, int[] levels) { return(_allProblems.Where(d => d.Sign == (int)sign && Array.IndexOf(levels, d.Level) >= 0).ToList()); }
/// <summary> /// 綜合題型巧算(合併) /// </summary> /// <param name="formulas">計算式作成</param> protected virtual void CleverWithSyntheticCombine(IList <CleverCalculationFormula> formulas) { // 當前反推判定次數(一次推算內次數累加) int defeated = 0; CleverCalculationFormula cleverCalculation = new CleverCalculationFormula { Type = (int)Synthetic.Combine, ConfixFormulas = new List <Formula>(), Answer = new List <int>() }; while (1 == 1) { // 如果大於三次則認為此題無法作成繼續下一題 if (defeated == INVERSE_NUMBER) { cleverCalculation = null; break; } cleverCalculation.ConfixFormulas.Clear(); cleverCalculation.Answer.Clear(); var answer = 0; // 獲取一個10以內的共有因數 int factorShare = CommonUtil.GetRandomNumber(3, 9); // 合併方法(加法或者减法) SignOfOperation combine = CommonUtil.GetRandomNumber(SignOfOperation.Plus, SignOfOperation.Subtraction); StringBuilder express = new StringBuilder(); // 加法合併 if (combine == SignOfOperation.Plus) { int factor1 = CommonUtil.GetRandomNumber(1, 9); // 加法合併的兩種情況: // 1.相加之和是整十數 int factor2 = CommonUtil.GetRandomNumber(1, 50, condition: _ => (_ % 10 == 0 || _ + factor1 <= 10) && _ != factor1, getDefault: () => 30); // 2.相加之和是十 if (factor2 > 10) { factor2 -= factor1; } // 隨機排列計算式各參數(打亂參數位置) SetNewGuidFactors(out List <int> factors1, factorShare, factor1); SetNewGuidFactors(out List <int> factors2, factorShare, factor2); // eg: 8 * 5 + 2 * 5 = (8 + 2) * 5 = 10 * 5 express.AppendFormat(CultureInfo.CurrentCulture, "{0}*{1}+{2}*{3}", factors1[0], factors1[1], factors2[0], factors2[1]); answer = (factor1 + factor2) * factorShare; cleverCalculation.ConfixFormulas.Add(new Formula(factor1 + factor2, factorShare, answer, SignOfOperation.Multiple)); cleverCalculation.Answer.Add(answer); } // 減法合併 else { int factor1 = CommonUtil.GetRandomNumber(11, 19); int factor2 = CommonUtil.GetRandomNumber(5, 9, condition: _ => factor1 - _ <= 10, getDefault: () => 5); // 隨機排列計算式各參數(打亂參數位置) SetNewGuidFactors(out List <int> factors1, factorShare, factor1); SetNewGuidFactors(out List <int> factors2, factorShare, factor2); // eg: 18 * 5 - 9 * 5 = (18 - 9) * 5 = 20 express.AppendFormat(CultureInfo.CurrentCulture, "{0}*{1}-{2}*{3}", factors1[0], factors1[1], factors2[0], factors2[1]); answer = (factor1 - factor2) * factorShare; cleverCalculation.ConfixFormulas.Add(new Formula(factor1 - factor2, factorShare, answer, SignOfOperation.Multiple)); cleverCalculation.Answer.Add(answer); } // 計算式推導 var calc = new ExpressArithmeticUtil(); if (!calc.IsResult(express.ToString(), out int result)) { defeated++; continue; } if (result != answer) { defeated++; continue; } // 加入推導出計算式集合 calc.Formulas.ToList().ForEach(f => cleverCalculation.ConfixFormulas.Add(f)); defeated = 0; break; } if (cleverCalculation != null) { formulas.Add(cleverCalculation); } }
/// <summary> /// /// </summary> /// <param name="sign"></param> public ArithmeticAttribute(SignOfOperation sign) : base(typeof(ArithmeticBase)) { Sign = sign; }