[gbrainy/gbrainy_15x] More work on using regular expressions for answers



commit 4aeb61773d3803d4237329de92de35bce005bfda
Author: Jordi Mas <jmas softcatala org>
Date:   Fri May 21 20:32:11 2010 +0200

    More work on using regular expressions for answers

 src/Core/Main/Game.cs                              |   85 ++++++++++++++------
 src/Core/Main/Verbal/Analogies.cs                  |   57 ++++++++-----
 src/Games/Calculation/CalculationAverage.cs        |    9 +--
 src/Games/Calculation/CalculationCloserFraction.cs |    8 +-
 src/Games/Calculation/CalculationOperator.cs       |   45 ++++-------
 src/Games/Calculation/CalculationRatio.cs          |   12 ++--
 src/Games/Calculation/CalculationTwoNumbers.cs     |    6 +-
 src/Games/Logic/PuzzleBalance.cs                   |    8 +-
 src/Games/Logic/PuzzleBuildTriangle.cs             |   35 +++-----
 src/Games/Logic/PuzzleCirclesRectangle.cs          |    8 +-
 src/Games/Logic/PuzzleClocks.cs                    |    8 +-
 src/Games/Logic/PuzzleCountSeries.cs               |    7 --
 src/Games/Logic/PuzzleCounting.cs                  |    4 +-
 src/Games/Logic/PuzzleCoverPercentage.cs           |   15 +---
 src/Games/Logic/PuzzleDice.cs                      |    4 +-
 src/Games/Logic/PuzzleEquation.cs                  |    8 +-
 src/Games/Logic/PuzzleExtraCircle.cs               |    8 +-
 src/Games/Logic/PuzzleFigureLetter.cs              |   79 +++++++-----------
 src/Games/Logic/PuzzleFigurePattern.cs             |    8 +-
 src/Games/Logic/PuzzleFigures.cs                   |   16 +---
 src/Games/Logic/PuzzleFourSided.cs                 |    8 +--
 src/Games/Logic/PuzzleLines.cs                     |    8 +-
 src/Games/Logic/PuzzleMatrixGroups.cs              |    8 +-
 src/Games/Logic/PuzzleMatrixNumbers.cs             |   20 +++--
 src/Games/Logic/PuzzleMissingPiece.cs              |    8 +-
 src/Games/Logic/PuzzleMissingSlice.cs              |    8 +-
 src/Games/Logic/PuzzleMostInCommon.cs              |   12 +--
 src/Games/Logic/PuzzleMoveFigure.cs                |   15 ++--
 src/Games/Logic/PuzzleNextFigure.cs                |    9 +--
 src/Games/Logic/PuzzleNumericRelation.cs           |   19 ++---
 src/Games/Logic/PuzzleNumericSequence.cs           |   16 ++--
 src/Games/Logic/PuzzleOstracism.cs                 |   14 +--
 src/Games/Logic/PuzzlePeopleTable.cs               |    8 +-
 src/Games/Logic/PuzzlePercentage.cs                |   25 ++----
 src/Games/Logic/PuzzlePredicateLogic.cs            |    7 --
 src/Games/Logic/PuzzleQuadrilaterals.cs            |    8 +-
 src/Games/Logic/PuzzleSquareSheets.cs              |    8 +-
 src/Games/Logic/PuzzleSquares.cs                   |   15 ++--
 src/Games/Logic/PuzzleSquaresAndLetters.cs         |    9 +--
 src/Games/Logic/PuzzleTetris.cs                    |    8 +-
 src/Games/Logic/PuzzleTimeNow.cs                   |    6 +-
 src/Games/Logic/PuzzleTrains.cs                    |    4 +-
 src/Games/Logic/PuzzleTriangles.cs                 |   10 +--
 src/Games/Logic/PuzzleTrianglesWithNumbers.cs      |    8 +-
 src/Games/Memory/MemoryFacts.cs                    |   15 +---
 tests/Core/GameTest.cs                             |   87 +++++++++++++++++++-
 46 files changed, 384 insertions(+), 409 deletions(-)
---
diff --git a/src/Core/Main/Game.cs b/src/Core/Main/Game.cs
index 583d9f3..439fd25 100644
--- a/src/Core/Main/Game.cs
+++ b/src/Core/Main/Game.cs
@@ -21,6 +21,7 @@ using System;
 using System.ComponentModel;
 using System.Collections.Generic;
 using System.Text.RegularExpressions;
+using System.Text;
 using Mono.Unix;
 
 using gbrainy.Core.Views;
@@ -57,9 +58,11 @@ namespace gbrainy.Core.Main
 			IgnoreCase		= 4,
 			IgnoreSpaces		= 8,
 			MatchAll		= 16,
+			MatchAllInOrder		= 32,
 		}
 
 		public const char AnswerSeparator = '|';
+		const int MAX_POSSIBLE_ANSWER = 7;
 
 		public class AnswerEventArgs : EventArgs
 		{
@@ -113,16 +116,36 @@ namespace gbrainy.Core.Main
 				question));
 		}
 
+		// The question text shown to the user
 		public abstract string Question {
 			get;
 		}
 
+		// Builds a text answer for the puzzle
 		public virtual string Answer {
 			get {
-				return String.Format (Catalog.GetString ("The correct answer is {0}."), right_answer);
+				string str;
+		
+				str = String.Format (Catalog.GetString ("The correct answer is {0}."), AnswerValue);
+
+				if (String.IsNullOrEmpty (Rationale))
+					return str;
+
+				return str += " " + Rationale;				
 			}
 		}
 
+		// Text that explains why the right answer is valid
+		public virtual string Rationale {
+			get { return string.Empty; }
+		}
+
+		// Right answer as shown to the user. Usually equals to right_answer, can be different
+		// when the answer contains multiple options (e.g. 1 | 2 shown as 1 and 2).
+		public virtual string AnswerValue {
+			get { return right_answer; }
+		}
+
 		public ISynchronizeInvoke SynchronizingObject { 
 			set { 
 				synchronize = value;
@@ -326,6 +349,17 @@ namespace gbrainy.Core.Main
 		public abstract void Initialize ();
 		public virtual void Finish () {}
 
+		protected string GetPossibleAnswersExpression ()
+		{
+			StringBuilder str = new StringBuilder ();
+			str.Append ("[");
+			for (int i = 0; i < MAX_POSSIBLE_ANSWER; i++)
+				str.Append (GetPossibleAnswer (i));
+
+			str.Append ("]");
+			return str.ToString ();
+		}
+
 		static public string GetPossibleAnswer (int answer)
 		{
 			switch (answer) {
@@ -352,7 +386,7 @@ namespace gbrainy.Core.Main
 			case 7: // Eighth possible answer for a series
 				return Catalog.GetString ("H");
 			default:
-				return string.Empty;
+				throw new ArgumentOutOfRangeException ("Do not have an option for this answer");
 			}
 		}
 
@@ -386,7 +420,6 @@ namespace gbrainy.Core.Main
 		{
 			Regex regex;
 			Match match;
-			AnswerCheckAttributes type;
 			bool ignore_case, ignore_spaces;
 
 			if (String.IsNullOrEmpty (answer))
@@ -394,7 +427,11 @@ namespace gbrainy.Core.Main
 
 			ignore_case = (CheckAttributes & AnswerCheckAttributes.IgnoreCase) == AnswerCheckAttributes.IgnoreCase;
 			ignore_spaces = (CheckAttributes & AnswerCheckAttributes.IgnoreSpaces) == AnswerCheckAttributes.IgnoreSpaces;
-			regex = new Regex (AnswerCheckExpression);
+
+			if (ignore_case == true) // This necessary to make pattern selection (e.g. [a-z]) case insensitive
+				regex = new Regex (AnswerCheckExpression, RegexOptions.IgnoreCase);
+			else
+				regex = new Regex (AnswerCheckExpression);
 
 			string [] right_answers = right_answer.Split (AnswerSeparator);
 
@@ -413,22 +450,36 @@ namespace gbrainy.Core.Main
 				answer = RemoveWhiteSpace (answer);
 
 			// All strings from the list of expected answers (two numbers: 22 | 44) must present in the answer
-			if ((CheckAttributes & AnswerCheckAttributes.MatchAll) == AnswerCheckAttributes.MatchAll)
+			if ((CheckAttributes & AnswerCheckAttributes.MatchAll) == AnswerCheckAttributes.MatchAll ||
+				(CheckAttributes & AnswerCheckAttributes.MatchAllInOrder) == AnswerCheckAttributes.MatchAllInOrder)
 			{
+				int pos = 0;
 				match = regex.Match (answer);
 				while (String.IsNullOrEmpty (match.Value) == false)
 				{
-					for (int i = 0; i < right_answers.Length; i++)
+					if ((CheckAttributes & AnswerCheckAttributes.MatchAll) == AnswerCheckAttributes.MatchAll)
 					{
-						if (String.Compare (match.Value, right_answers[i], ignore_case) == 0)
+						for (int i = 0; i < right_answers.Length; i++)
 						{
-							right_answers[i] = null;
-							break;
+							if (String.Compare (match.Value, right_answers[i], ignore_case) == 0)
+							{
+								right_answers[i] = null;
+								break;
+							}
 						}
+					} 
+					else //MatchAllInOrder
+					{
+						if (String.Compare (match.Value, right_answers[pos++], ignore_case) != 0)
+							return false;
+
 					}
 					match = match.NextMatch ();
 				}
 
+				if ((CheckAttributes & AnswerCheckAttributes.MatchAllInOrder) == AnswerCheckAttributes.MatchAllInOrder)
+					return true;
+
 				// Have all the expected answers been matched?
 				for (int i = 0; i < right_answers.Length; i++)
 				{
@@ -461,22 +512,6 @@ namespace gbrainy.Core.Main
 			return str;
 		}
 
-		// When asking for a list of figures people trends to use spaces or commas
-		// to separate the elements
-		static public string TrimAnswer (string answer)
-		{
-			string rslt = string.Empty;
-
-			for (int i = 0; i < answer.Length; i++)
-			{
-				if (answer[i]==' ' || answer[i] == ',')
-					continue;
-
-				rslt += answer[i];
-			}
-			return rslt;
-		}
-
 		// Type enum to string representation
 		static public string GetGameTypeDescription (Types type)
 		{
diff --git a/src/Core/Main/Verbal/Analogies.cs b/src/Core/Main/Verbal/Analogies.cs
index 25180dd..62518c3 100644
--- a/src/Core/Main/Verbal/Analogies.cs
+++ b/src/Core/Main/Verbal/Analogies.cs
@@ -57,33 +57,48 @@ namespace gbrainy.Core.Main.Verbal
 
 		public override string Answer {
 			get {
+				string str;
+				if (current == null || current.MultipleAnswers == false)
+					return base.Answer;
+
+				str = String.Format (Catalog.GetString ("Possible correct answers are: {0}."), AnswerValue);
+
+				if (String.IsNullOrEmpty (Rationale))
+					return str;
+
+				return str += " " + Rationale;
+			}
+		}
+
+		public override string Rationale {
+			get {
 				if (current == null)
 					return string.Empty;
+				
+				return current.rationale;
+			}
+		}
+
+		public override string AnswerValue {
+			get { 
+				if (current == null || current.MultipleAnswers == false)
+					return right_answer;
+
+				string [] items;
+				string str = string.Empty;
 
-				if (current.MultipleAnswers == true) 
+				items = right_answer.Split (AnalogiesFactory.Separator);
+
+				for (int i = 0 ; i < items.Length; i++)
 				{
-					string [] items;
-					string str = string.Empty;
-	
-					items = right_answer.Split (AnalogiesFactory.Separator);
-
-					for (int i = 0 ; i < items.Length; i++)
-					{
-						str += items [i].Trim ();
-						if (i + 1 < items.Length) {
-							// Translators: this the separator used when concatenating multiple possible answers for verbal analogies
-							// For example: "Possible correct answers are: sleep, rest."
-							str += Catalog.GetString (", ");
-						}
+					str += items [i].Trim ();
+					if (i + 1 < items.Length) {
+						// Translators: this the separator used when concatenating multiple possible answers for verbal analogies
+						// For example: "Possible correct answers are: sleep, rest."
+						str += Catalog.GetString (", ");
 					}
-					str = String.Format (Catalog.GetString ("Possible correct answers are: {0}."), str);
-					return str;
 				}
-
-				if (String.IsNullOrEmpty (current.rationale) == false)
-					return base.Answer + " " + current.rationale;
-
-				return base.Answer;
+				return str;
 			}
 		}
 
diff --git a/src/Games/Calculation/CalculationAverage.cs b/src/Games/Calculation/CalculationAverage.cs
index bdbb1ab..e7f4d41 100644
--- a/src/Games/Calculation/CalculationAverage.cs
+++ b/src/Games/Calculation/CalculationAverage.cs
@@ -62,13 +62,10 @@ namespace gbrainy.Games.Calculation
 			get { return Catalog.GetString ("The average of a list of numbers is the sum of all of the numbers divided by the number of items in the list.");}
 		}
 
-		public override string Answer {
+		public override string Rationale {
 			get { 
-				string answer = base.Answer + " ";
-
-				answer += String.Format (Catalog.GetString ("The result of the operation is {0:##0.###}."), 
-					correct);
-				return answer;
+				return String.Format (Catalog.GetString ("The result of the operation is {0:##0.###}."), 
+					correct);				
 			}
 		}
 
diff --git a/src/Games/Calculation/CalculationCloserFraction.cs b/src/Games/Calculation/CalculationCloserFraction.cs
index 765ec69..41b1171 100644
--- a/src/Games/Calculation/CalculationCloserFraction.cs
+++ b/src/Games/Calculation/CalculationCloserFraction.cs
@@ -49,14 +49,12 @@ namespace gbrainy.Games.Calculation
 				GetPossibleAnswer (0), GetPossibleAnswer (1), GetPossibleAnswer (2), GetPossibleAnswer (3));}
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
+		public override string Rationale {
+			get {
 				int ans_idx = random_indices[which];
 
-				answer += String.Format (Catalog.GetString ("The result of the operation {0} / {1} is {2:##0.###}"), 
+				return String.Format (Catalog.GetString ("The result of the operation {0} / {1} is {2:##0.###}"), 
 					options[ans_idx * 2], options[(ans_idx * 2) + 1], question_num);
-				return answer;
 			}
 		}
 
diff --git a/src/Games/Calculation/CalculationOperator.cs b/src/Games/Calculation/CalculationOperator.cs
index 156978e..1aa8aee 100644
--- a/src/Games/Calculation/CalculationOperator.cs
+++ b/src/Games/Calculation/CalculationOperator.cs
@@ -30,11 +30,11 @@ namespace gbrainy.Games.Calculation
 	public class CalculationOperator : Game
 	{
 		private double number_a, number_b, number_c, total;
-		private char[] opers = {'*', '+', '-', '/'};
+		private readonly char[] opers = {'*', '+', '-', '/'};
 		private char oper1, oper2;
 
 		public override string Name {
-			get {return Catalog.GetString ("Operator");}
+			get {return Catalog.GetString ("Operators");}
 		}
 
 		public override string Tip {
@@ -49,6 +49,18 @@ namespace gbrainy.Games.Calculation
 			get {return String.Format (Catalog.GetString ("Which operators make {0}, {1}, and {2} equal {3}? Answer using '+-/*'."), number_a, number_b, number_c, total);}
 		}
 
+		public override string AnswerCheckExpression {
+			get { return "[+*-/]+"; }
+		}
+
+		public override AnswerCheckAttributes CheckAttributes {
+			get { return AnswerCheckAttributes.Trim | AnswerCheckAttributes.MatchAll; }
+		}
+
+		public override string AnswerValue {
+			get { return String.Format (Catalog.GetString ("{0} and {1}"), oper1, oper2); }
+		}
+
 		private double ProcessOperation (double total, double number, char op)
 		{
 			switch (op) {
@@ -106,7 +118,7 @@ namespace gbrainy.Games.Calculation
 					break;
 			}
 
-			right_answer = String.Format (Catalog.GetString ("{0} and {1}"), oper1, oper2);
+			right_answer = String.Format ("{0} | {1}", oper1, oper2);
 		}
 
 		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
@@ -141,32 +153,5 @@ namespace gbrainy.Games.Calculation
 
 			return false;
 		}
-
-		public override bool CheckAnswer (string answer)
-		{
-			char op1 = '\0', op2 = '\0';
-			int c = 0;
-
-			for (c = 0; c < answer.Length; c++)
-			{
-				if (IndexOf (answer[c], opers)) {
-					op1 = answer[c];
-					break;
-				}
-			}
-
-			for (c++; c < answer.Length; c++)
-			{
-				if (IndexOf (answer[c], opers)) {
-					op2 = answer[c];
-					break;
-				}
-			}
-
-			if (oper1 == op1 && oper2 == op2)
-				return true;
-
-			return false;
-		}
 	}
 }
diff --git a/src/Games/Calculation/CalculationRatio.cs b/src/Games/Calculation/CalculationRatio.cs
index 6c12618..cdb3177 100644
--- a/src/Games/Calculation/CalculationRatio.cs
+++ b/src/Games/Calculation/CalculationRatio.cs
@@ -46,13 +46,10 @@ namespace gbrainy.Games.Calculation
 			}
 		}
 
-		public override string Answer {
+		public override string Rationale {
 			get {
-				string answer = base.Answer + " ";
-
-				answer += String.Format (Catalog.GetString ("The second number is calculated by multiplying the first by {0} and dividing it by {1}."),
+				return String.Format (Catalog.GetString ("The second number is calculated by multiplying the first by {0} and dividing it by {1}."),
 					ratio_a, ratio_b);
-				return answer;
 			}
 		}
 
@@ -68,6 +65,10 @@ namespace gbrainy.Games.Calculation
 			get { return "[0-9]+"; }
 		}
 
+		public override string AnswerValue {
+			get { return String.Format (Catalog.GetString ("{0} and {1}"), number_a, number_b); }
+		}
+
 		public override void Initialize ()
 		{
 			int random_max;
@@ -94,7 +95,6 @@ namespace gbrainy.Games.Calculation
 			ratio_b = 3 + random.Next (random_max);
 			number_b = number_a / ratio_a * ratio_b;
 
-			//TODO: right_answer = String.Format (Catalog.GetString ("{0} and {1}"), number_a, number_b);
 			right_answer = String.Format ("{0} | {1}", number_a, number_b);
 		}
 
diff --git a/src/Games/Calculation/CalculationTwoNumbers.cs b/src/Games/Calculation/CalculationTwoNumbers.cs
index db85d4e..3096f74 100644
--- a/src/Games/Calculation/CalculationTwoNumbers.cs
+++ b/src/Games/Calculation/CalculationTwoNumbers.cs
@@ -69,6 +69,10 @@ namespace gbrainy.Games.Calculation
 			get { return "[0-9]+"; }
 		}
 
+		public override string AnswerValue {
+			get { return String.Format (Catalog.GetString ("{0} and {1}"), number_a, number_b); }
+		}
+
 		public override void Initialize ()
 		{
 			type = (GameTypes) random.Next ((int) GameTypes.Length);
@@ -106,8 +110,6 @@ namespace gbrainy.Games.Calculation
 			}
 
 			op2 = number_a * number_b;
-
-			//TODO: right_answer = String.Format (Catalog.GetString ("{0} and {1}"), number_a, number_b);
 			right_answer = String.Format ("{0} | {1}", number_a, number_b);
 		}
 
diff --git a/src/Games/Logic/PuzzleBalance.cs b/src/Games/Logic/PuzzleBalance.cs
index 067664f..f54af88 100644
--- a/src/Games/Logic/PuzzleBalance.cs
+++ b/src/Games/Logic/PuzzleBalance.cs
@@ -55,11 +55,9 @@ namespace gbrainy.Games.Logic
 			get {return Catalog.GetString ("How many triangles are needed in the right part of the last figure to keep it balanced?");} 
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-				answer += Catalog.GetString ("Every triangle counts as 1, each diamond as 2 and each square as 3.");
-				return answer;
+		public override string Rationale {
+			get {
+				return Catalog.GetString ("Every triangle counts as 1, each diamond as 2 and each square as 3.");
 			}
 		}
 
diff --git a/src/Games/Logic/PuzzleBuildTriangle.cs b/src/Games/Logic/PuzzleBuildTriangle.cs
index fdcc91b..cdffbb2 100644
--- a/src/Games/Logic/PuzzleBuildTriangle.cs
+++ b/src/Games/Logic/PuzzleBuildTriangle.cs
@@ -63,6 +63,18 @@ namespace gbrainy.Games.Logic
 			get { return Catalog.GetString ("The resulting triangle is isosceles.");}
 		}
 
+		public override AnswerCheckAttributes CheckAttributes {
+			get { return AnswerCheckAttributes.Trim | AnswerCheckAttributes.IgnoreCase | AnswerCheckAttributes.MatchAll; }
+		}
+
+		public override string AnswerCheckExpression {
+			get { return GetPossibleAnswersExpression ();}
+		}
+
+		public override string AnswerValue {
+			get { return answers[0] + answers[1] + answers[2]; }
+		}
+
 		public override void Initialize ()
 		{
 			switch (CurrentDifficulty) {
@@ -96,7 +108,7 @@ namespace gbrainy.Games.Logic
 				}
 			}
 
-			right_answer = answers[0] + answers[1] + answers[2];
+			right_answer = answers[0] + " | " + answers[1] + " | " + answers[2];
 		}
 
 		private static void DrawFigure (CairoContextEx gr, double x, double y, Figures figure)
@@ -208,26 +220,7 @@ namespace gbrainy.Games.Logic
 			degrees = radian * (-135);
 			gr.MoveTo (x, y);
 			gr.LineTo (x + figure_size * Math.Cos (degrees), y + figure_size * Math.Sin (degrees));
-			gr.Stroke ();	
-		}
-
-		public override bool CheckAnswer (string a)
-		{	
-			int matches = 0;
-
-			a = TrimAnswer (a.ToUpper ());
-
-			for (int i = 0; i < answer_num; i++) {
-				answers [i] = answers [i].ToUpper ();
-	
-				if (a.Contains (answers[i]))
-					matches++;
-			}
-
-			if (matches == answer_num)
-				return true;
-
-			return false;
+			gr.Stroke ();
 		}
 	}
 }
diff --git a/src/Games/Logic/PuzzleCirclesRectangle.cs b/src/Games/Logic/PuzzleCirclesRectangle.cs
index 0baa99a..a3ed3f2 100644
--- a/src/Games/Logic/PuzzleCirclesRectangle.cs
+++ b/src/Games/Logic/PuzzleCirclesRectangle.cs
@@ -40,11 +40,9 @@ namespace gbrainy.Games.Logic
 			get { return Catalog.GetString ("You can fit more than 64 circles.");}
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-				answer += String.Format (Catalog.GetString ("In the layout shown {0} units of height are gained in each row. This allows using an additional row."), 0.1340);
-				return answer;
+		public override string Rationale {
+			get {
+				return String.Format (Catalog.GetString ("In the layout shown {0} units of height are gained in each row. This allows using an additional row."), 0.1340);
 			}
 		}
 
diff --git a/src/Games/Logic/PuzzleClocks.cs b/src/Games/Logic/PuzzleClocks.cs
index a9e1d88..895f9a5 100644
--- a/src/Games/Logic/PuzzleClocks.cs
+++ b/src/Games/Logic/PuzzleClocks.cs
@@ -47,11 +47,9 @@ namespace gbrainy.Games.Logic
 				GetPossibleFigureAnswer (3)));}
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-				answer += String.Format (Catalog.GetString ("Starting from the first clock sum {0} to the value indicated by the hands."), addition);
-				return answer;
+		public override string Rationale {
+			get {
+				return String.Format (Catalog.GetString ("Starting from the first clock sum {0} to the value indicated by the hands."), addition);
 			}
 		}
 
diff --git a/src/Games/Logic/PuzzleCountSeries.cs b/src/Games/Logic/PuzzleCountSeries.cs
index abd2d2d..1e41fbc 100644
--- a/src/Games/Logic/PuzzleCountSeries.cs
+++ b/src/Games/Logic/PuzzleCountSeries.cs
@@ -46,13 +46,6 @@ namespace gbrainy.Games.Logic
 			get {return question;} 
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-				return answer;
-			}
-		}
-
 		public override void Initialize ()
 		{
 			switch ((GameType) random.Next ((int) GameType.Length))
diff --git a/src/Games/Logic/PuzzleCounting.cs b/src/Games/Logic/PuzzleCounting.cs
index 573df7a..39a470e 100644
--- a/src/Games/Logic/PuzzleCounting.cs
+++ b/src/Games/Logic/PuzzleCounting.cs
@@ -47,8 +47,8 @@ namespace gbrainy.Games.Logic
 			get {return question; }
 		}
 
-		public override string Answer {
-			get { return base.Answer + " " + answer;}
+		public override string Rationale {
+			get { return answer;}
 		}
 
 		public override void Initialize ()
diff --git a/src/Games/Logic/PuzzleCoverPercentage.cs b/src/Games/Logic/PuzzleCoverPercentage.cs
index a5426df..09b0b03 100644
--- a/src/Games/Logic/PuzzleCoverPercentage.cs
+++ b/src/Games/Logic/PuzzleCoverPercentage.cs
@@ -41,6 +41,10 @@ namespace gbrainy.Games.Logic
 			get {return Catalog.GetString ("What percentage of the figure is colored?");} 
 		}
 
+		public override string AnswerCheckExpression {
+			get { return "[0-9]+";}
+		}
+
 		public override void Initialize ()
 		{
 			int total = 0;
@@ -159,16 +163,5 @@ namespace gbrainy.Games.Logic
 
 			DrawSection (gr, x, y);
 		}
-
-		public override bool CheckAnswer (string answer)
-		{	
-			if (String.Compare (answer, right_answer, true) == 0) 
-				return true;
-
-			if (String.Compare (answer, right_answer + "%", true) == 0) 
-				return true;
-
-			return false;
-		}
 	}
 }
diff --git a/src/Games/Logic/PuzzleDice.cs b/src/Games/Logic/PuzzleDice.cs
index 99ef10f..6db616c 100644
--- a/src/Games/Logic/PuzzleDice.cs
+++ b/src/Games/Logic/PuzzleDice.cs
@@ -74,8 +74,8 @@ namespace gbrainy.Games.Logic
 			get { return problems[problem].question;}
 		}
 
-		public override string Answer {
-			get { return base.Answer + " " + problems[problem].rationale; }
+		public override string Rationale {
+			get { return problems[problem].rationale; }
 		}
 
 		public override void Initialize ()
diff --git a/src/Games/Logic/PuzzleEquation.cs b/src/Games/Logic/PuzzleEquation.cs
index ada87bb..4badbc8 100644
--- a/src/Games/Logic/PuzzleEquation.cs
+++ b/src/Games/Logic/PuzzleEquation.cs
@@ -39,11 +39,9 @@ namespace gbrainy.Games.Logic
 			get {return Catalog.GetString ("What is the result of the equation below?");} 
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-				answer += Catalog.GetString ("The order of arithmetical operations is always as follows: exponents and roots, multiplication and division, addition and subtraction.");
-				return answer;
+		public override string Rationale {
+			get {
+				return Catalog.GetString ("The order of arithmetical operations is always as follows: exponents and roots, multiplication and division, addition and subtraction.");
 			}
 		}
 
diff --git a/src/Games/Logic/PuzzleExtraCircle.cs b/src/Games/Logic/PuzzleExtraCircle.cs
index ddfafd3..a450bf6 100644
--- a/src/Games/Logic/PuzzleExtraCircle.cs
+++ b/src/Games/Logic/PuzzleExtraCircle.cs
@@ -56,11 +56,9 @@ namespace gbrainy.Games.Logic
 			get { return Catalog.GetString ("All circles share a common property except for one.");}
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-				answer += String.Format (Catalog.GetString ("In all circles the color slices follow the same order except for this one."));
-				return answer;
+		public override string Rationale {
+			get {
+				return String.Format (Catalog.GetString ("In all circles the color slices follow the same order except for this one."));
 			}
 		}
 
diff --git a/src/Games/Logic/PuzzleFigureLetter.cs b/src/Games/Logic/PuzzleFigureLetter.cs
index a46e96e..7bf7cb1 100644
--- a/src/Games/Logic/PuzzleFigureLetter.cs
+++ b/src/Games/Logic/PuzzleFigureLetter.cs
@@ -50,11 +50,32 @@ namespace gbrainy.Games.Logic
 			get { return Catalog.GetString ("Every character of the text represents a property of the figure.");}
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-				answer += Catalog.GetString ("'A' indicates that the figures overlap, 'B' that are rectangles, 'C' that are circles, 'D' that the figures are separated, 'E' that there are three figures and 'F' that there are two figures.");
-				return answer;
+		public override string Rationale {
+			get {
+				return Catalog.GetString ("'A' indicates that the figures overlap, 'B' that are rectangles, 'C' that are circles, 'D' that the figures are separated, 'E' that there are three figures and 'F' that there are two figures.");
+			}
+		}
+
+		public override AnswerCheckAttributes CheckAttributes {
+			get { return AnswerCheckAttributes.Trim | AnswerCheckAttributes.IgnoreCase | AnswerCheckAttributes.MatchAll; }
+		}
+
+		public override string AnswerCheckExpression {
+			get { return GetPossibleAnswersExpression ();}
+		}
+
+		public override string AnswerValue {
+			get {
+				switch (question) {
+				case QuestionType.TwoRectangles:
+					return "ABF";
+				case QuestionType.TwoCercles:
+					return "CDF";
+				case QuestionType.ThreeCercles:
+					return "ACE";
+				default:
+					throw new InvalidOperationException ();
+				}
 			}
 		}
 
@@ -64,56 +85,19 @@ namespace gbrainy.Games.Logic
 
 			switch (question) {
 			case QuestionType.TwoRectangles:
-				right_answer = "ABF";
+				right_answer = "A | B | F";
 				break;
 			case QuestionType.TwoCercles:
-				right_answer = "CDF";
+				right_answer = "C | D | F";
 				break;
 			case QuestionType.ThreeCercles:
-				right_answer = "ACE";
+				right_answer = "A | C | E";
 				break;
+			default:
+				throw new InvalidOperationException ();
 			}
 		}
 
-		public override bool CheckAnswer (string answer)
-		{	
-			answer = TrimAnswer (answer);
-			switch (question) {
-			case QuestionType.TwoRectangles:		
-				if ((String.Compare (answer, "ABF", true) == 0) 
-					|| (String.Compare (answer, "AFB", true) == 0)
-					|| (String.Compare (answer, "BAF", true) == 0)
-					|| (String.Compare (answer, "BFA", true) == 0)
-					|| (String.Compare (answer, "FBA", true) == 0)
-					|| (String.Compare (answer, "FAB", true) == 0)) {
-					return true;
-				}
-				break;
-			case QuestionType.TwoCercles:		
-				if ((String.Compare (answer, "CDF", true) == 0)
-					|| (String.Compare (answer, "CFD", true) == 0)
-					|| (String.Compare (answer, "DCF", true) == 0)
-					|| (String.Compare (answer, "DFC", true) == 0)
-					|| (String.Compare (answer, "FCD", true) == 0)
-					|| (String.Compare (answer, "FDC", true) == 0)) {
-					return true;
-				}
-				break;
-			case QuestionType.ThreeCercles:		
-				if ((String.Compare (answer, "ACE", true) == 0)
-					|| (String.Compare (answer, "AEC", true) == 0)
-					|| (String.Compare (answer, "CAE", true) == 0)
-					|| (String.Compare (answer, "CEA", true) == 0)
-					|| (String.Compare (answer, "EAC", true) == 0)
-					|| (String.Compare (answer, "ECA", true) == 0)) {
-					return true;
-				}
-				break;
-			}
-				
-			return false;
-		}
-
 		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
 		{
 			double x = DrawAreaX + 0.05;
@@ -190,6 +174,5 @@ namespace gbrainy.Games.Logic
 			gr.ShowPangoText ("?");
 			gr.Stroke ();		
 		}
-
 	}
 }
diff --git a/src/Games/Logic/PuzzleFigurePattern.cs b/src/Games/Logic/PuzzleFigurePattern.cs
index 7f9f77b..4f61236 100644
--- a/src/Games/Logic/PuzzleFigurePattern.cs
+++ b/src/Games/Logic/PuzzleFigurePattern.cs
@@ -52,11 +52,9 @@ namespace gbrainy.Games.Logic
 			get { return Catalog.GetString ("The third figure of every row involves somehow combining the first two figures.");}
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-				answer += Catalog.GetString ("Superpose the first and second figures and remove the lines that they have in common, then rotate the resulting figure 45 degrees.");
-				return answer;
+		public override string Rationale {
+			get {
+				return Catalog.GetString ("Superpose the first and second figures and remove the lines that they have in common, then rotate the resulting figure 45 degrees.");
 			}
 		}
 
diff --git a/src/Games/Logic/PuzzleFigures.cs b/src/Games/Logic/PuzzleFigures.cs
index 702bb29..96ba1a8 100644
--- a/src/Games/Logic/PuzzleFigures.cs
+++ b/src/Games/Logic/PuzzleFigures.cs
@@ -48,13 +48,9 @@ namespace gbrainy.Games.Logic
 			get {return Catalog.GetString ("What is the next logical sequence of objects in the last column? See below the convention when giving the answer.");} 
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-
-				answer += Catalog.GetString ("It is the only combination that you can build with the given elements without repeating them.");
-
-				return answer;
+		public override string Rationale {
+			get {
+				return Catalog.GetString ("It is the only combination that you can build with the given elements without repeating them.");
 			}
 		}
 
@@ -169,11 +165,5 @@ namespace gbrainy.Games.Logic
 			gr.ShowPangoText (String.Format (Catalog.GetString ("E.g: {0}{1}{2} (diamond, triangle, circle)"),
 				GetPossibleAnswer (0), GetPossibleAnswer (2), GetPossibleAnswer (1)));
 		}
-
-		public override bool CheckAnswer (string answer)
-		{
-			answer = TrimAnswer (answer);
-			return base.CheckAnswer (answer);
-		}
 	}
 }
diff --git a/src/Games/Logic/PuzzleFourSided.cs b/src/Games/Logic/PuzzleFourSided.cs
index c270d81..f74097d 100644
--- a/src/Games/Logic/PuzzleFourSided.cs
+++ b/src/Games/Logic/PuzzleFourSided.cs
@@ -42,15 +42,11 @@ namespace gbrainy.Games.Logic
 			get { return Catalog.GetString ("A four sided figure can be embedded inside another figure.");}
 		}
 
-		public override string Answer {
+		public override string Rationale {
 			get { 
-				string answer = base.Answer + " ";
-
-				answer += String.Format (Catalog.GetString ("The four sided figures are made by connecting the following points: {0}"),
+				return String.Format (Catalog.GetString ("The four sided figures are made by connecting the following points: {0}"),
 					(type == 0) ? "abde, degh, bcef, efhi, acdf, dfgi, abhg, bcih, acig, aghe, aefc, deig, bcie." : 
 					"abde, degh, bcef, efhi, acdf, dfgi, abhg, bcih, acig, aghe, aefc, deig, bcie, acde, cehi, abeg, egif.");
-
-				return answer;
 			}
 		}
 
diff --git a/src/Games/Logic/PuzzleLines.cs b/src/Games/Logic/PuzzleLines.cs
index 816bd71..e3b7671 100644
--- a/src/Games/Logic/PuzzleLines.cs
+++ b/src/Games/Logic/PuzzleLines.cs
@@ -40,11 +40,9 @@ namespace gbrainy.Games.Logic
 			get {return Catalog.GetString ("How many line segments in total are in the figures below? A line segment is a line between two points with no crossing lines.");}
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-				answer += String.Format (Catalog.GetString ("There are {0} lines in the figure to the left and {1} in the figure to the right."), fig1, fig2);
-				return answer;
+		public override string Rationale {
+			get {
+				return String.Format (Catalog.GetString ("There are {0} lines in the figure to the left and {1} in the figure to the right."), fig1, fig2);
 			}
 		}
 
diff --git a/src/Games/Logic/PuzzleMatrixGroups.cs b/src/Games/Logic/PuzzleMatrixGroups.cs
index 1f8477c..170f2d4 100644
--- a/src/Games/Logic/PuzzleMatrixGroups.cs
+++ b/src/Games/Logic/PuzzleMatrixGroups.cs
@@ -45,11 +45,9 @@ namespace gbrainy.Games.Logic
 			get { return Catalog.GetString ("All circled numbers share an arithmetical property.");}
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-				answer += String.Format (Catalog.GetString ("Every circled number can be divided by {0}."), divisor);
-				return answer;
+		public override string Rationale {
+			get {
+				return String.Format (Catalog.GetString ("Every circled number can be divided by {0}."), divisor);
 			}
 		}
 
diff --git a/src/Games/Logic/PuzzleMatrixNumbers.cs b/src/Games/Logic/PuzzleMatrixNumbers.cs
index 380fc78..c8dcde1 100644
--- a/src/Games/Logic/PuzzleMatrixNumbers.cs
+++ b/src/Games/Logic/PuzzleMatrixNumbers.cs
@@ -59,33 +59,37 @@ namespace gbrainy.Games.Logic
 			}
 		}
 
-		public override string Answer {
+		public override string Rationale {
 			get { 
-				string answer = base.Answer + " ";
+				string answer;
 
 				switch (operation) {
 				case Operation.MultiplyAndAdd:
 					if (orientation) {
-						answer += String.Format(Catalog.GetString("The fourth row is calculated by multiplying the first two rows and adding the third."));
+						answer = String.Format(Catalog.GetString("The fourth row is calculated by multiplying the first two rows and adding the third."));
 					} else {
-						answer += String.Format(Catalog.GetString("The fourth column is calculated by multiplying the first two columns and adding the third."));
+						answer = String.Format(Catalog.GetString("The fourth column is calculated by multiplying the first two columns and adding the third."));
 					}
 					break;
 				case Operation.MutilplyAndSubs:
 					if (orientation) {
-						answer += String.Format(Catalog.GetString("The fourth row is calculated by multiplying the first two rows and subtracting the third."));
+						answer = String.Format(Catalog.GetString("The fourth row is calculated by multiplying the first two rows and subtracting the third."));
 					} else {
-						answer += String.Format(Catalog.GetString("The fourth column is calculated by multiplying the first two columns and subtracting the third."));
+						answer = String.Format(Catalog.GetString("The fourth column is calculated by multiplying the first two columns and subtracting the third."));
 					}
 					break;
 				case Operation.AddAndSubs:
 					if (orientation) {
-						answer += String.Format(Catalog.GetString("The fourth row is calculated by adding the first two rows and subtracting the third."));
+						answer = String.Format(Catalog.GetString("The fourth row is calculated by adding the first two rows and subtracting the third."));
 					} else {
-						answer += String.Format(Catalog.GetString("The fourth column is calculated by adding the first two columns and subtracting the third."));
+						answer = String.Format(Catalog.GetString("The fourth column is calculated by adding the first two columns and subtracting the third."));
 					}
 					break;
+				default:
+					answer = string.Empty;
+					break;
 				}
+
 				return answer;
 			}
 		}
diff --git a/src/Games/Logic/PuzzleMissingPiece.cs b/src/Games/Logic/PuzzleMissingPiece.cs
index a7d2f20..1e5f3f3 100644
--- a/src/Games/Logic/PuzzleMissingPiece.cs
+++ b/src/Games/Logic/PuzzleMissingPiece.cs
@@ -46,11 +46,9 @@ namespace gbrainy.Games.Logic
 			get { return Catalog.GetString ("The logic works at row level.");}
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-				answer += Catalog.GetString ("In every row the third square is made by flipping the first square and superimposing it on the second square, followed by removing the matching lines.");
-				return answer;
+		public override string Rationale {
+			get {
+				return Catalog.GetString ("In every row the third square is made by flipping the first square and superimposing it on the second square, followed by removing the matching lines.");
 			}
 		}
 
diff --git a/src/Games/Logic/PuzzleMissingSlice.cs b/src/Games/Logic/PuzzleMissingSlice.cs
index 16a728f..1bf2a24 100644
--- a/src/Games/Logic/PuzzleMissingSlice.cs
+++ b/src/Games/Logic/PuzzleMissingSlice.cs
@@ -73,11 +73,9 @@ namespace gbrainy.Games.Logic
 			get { return Catalog.GetString ("Each slice is related to the opposite one.");}
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-				answer += String.Format (Catalog.GetString ("All numbers of each slice, when added to the ones of the opposite slice, add always {0}."), sum_offset + 8);
-				return answer;
+		public override string Rationale {
+			get {
+				return String.Format (Catalog.GetString ("All numbers of each slice, when added to the ones of the opposite slice, add always {0}."), sum_offset + 8);
 			}
 		}
 
diff --git a/src/Games/Logic/PuzzleMostInCommon.cs b/src/Games/Logic/PuzzleMostInCommon.cs
index a2ad804..bd0ae1f 100644
--- a/src/Games/Logic/PuzzleMostInCommon.cs
+++ b/src/Games/Logic/PuzzleMostInCommon.cs
@@ -87,16 +87,12 @@ namespace gbrainy.Games.Logic
 			get { return Catalog.GetString ("Think of the common elements that the given figures have inside them.");}
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-
+		public override string Rationale {
+			get {
 				if (CurrentDifficulty ==  Difficulty.Easy) 
-					answer += Catalog.GetString ("It has the same number of elements inside the figure as the given figures.");
+					return Catalog.GetString ("It has the same number of elements inside the figure as the given figures.");
 				else
-					answer += Catalog.GetString ("It is the figure with the most elements in common compared to the given figures.");
-			
-				return answer;
+					return Catalog.GetString ("It is the figure with the most elements in common compared to the given figures.");
 			}
 		}
 
diff --git a/src/Games/Logic/PuzzleMoveFigure.cs b/src/Games/Logic/PuzzleMoveFigure.cs
index 2597281..80f7a95 100644
--- a/src/Games/Logic/PuzzleMoveFigure.cs
+++ b/src/Games/Logic/PuzzleMoveFigure.cs
@@ -39,19 +39,16 @@ namespace gbrainy.Games.Logic
 			get {return Catalog.GetString ("What is the minimum number of circles to be moved in order to convert the left figure into the right figure?");} 
 		}
 	
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-
+		public override string Rationale {
+			get {
 				switch (type) {
 				case 0:
-					answer += Catalog.GetString ("Move the circle from the first line to the second and move two circles from the fourth line to the second and the fifth lines.");
-					break;
+					return Catalog.GetString ("Move the circle from the first line to the second and move two circles from the fourth line to the second and the fifth lines.");
 				case 1:
-					answer += Catalog.GetString ("Move the first line to the seventh; move the two circles of the second line to third; and move first and last circles of the fifth line to the sixth.");
-					break;
+					return Catalog.GetString ("Move the first line to the seventh; move the two circles of the second line to third; and move first and last circles of the fifth line to the sixth.");
+				default:	
+					return string.Empty;
 				}
-				return answer;
 			}
 		}
 
diff --git a/src/Games/Logic/PuzzleNextFigure.cs b/src/Games/Logic/PuzzleNextFigure.cs
index 64b3714..21ce4dd 100644
--- a/src/Games/Logic/PuzzleNextFigure.cs
+++ b/src/Games/Logic/PuzzleNextFigure.cs
@@ -61,12 +61,9 @@ namespace gbrainy.Games.Logic
 		}
 
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-
-				answer += String.Format (Catalog.GetString ("From first figure, the top circle advances by two positions clockwise, while the left circle goes backwards one position."));
-				return answer;
+		public override string Rationale {
+			get {
+				return String.Format (Catalog.GetString ("From first figure, the top circle advances by two positions clockwise, while the left circle goes backwards one position."));
 			}
 		}
 
diff --git a/src/Games/Logic/PuzzleNumericRelation.cs b/src/Games/Logic/PuzzleNumericRelation.cs
index cd47121..6d79b5d 100644
--- a/src/Games/Logic/PuzzleNumericRelation.cs
+++ b/src/Games/Logic/PuzzleNumericRelation.cs
@@ -48,23 +48,18 @@ namespace gbrainy.Games.Logic
 			get { return Catalog.GetString ("The numbers are related arithmetically.");}
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-
+		public override string Rationale {
+			get {
 				switch (formula) {
 				case 0:
-					answer += String.Format (Catalog.GetString ("Every group of {0} numbers sums exactly {1}."), group_size, sum_value);
-					break;
+					return String.Format (Catalog.GetString ("Every group of {0} numbers sums exactly {1}."), group_size, sum_value);
 				case 1:
-					answer += Catalog.GetString ("Divide the sequence in groups of three numbers. Every third number is calculated by multiplying by the two previous ones.");
-					break;
-
+					return Catalog.GetString ("Divide the sequence in groups of three numbers. Every third number is calculated by multiplying by the two previous ones.");
 				case 2:
-					answer += Catalog.GetString ("Divide the sequence in groups of three numbers. Every third number is calculated by subtracting the second number from the first.");
-					break;
+					return Catalog.GetString ("Divide the sequence in groups of three numbers. Every third number is calculated by subtracting the second number from the first.");
+				default:
+					return String.Empty;
 				}
-				return answer;
 			}
 		}
 
diff --git a/src/Games/Logic/PuzzleNumericSequence.cs b/src/Games/Logic/PuzzleNumericSequence.cs
index e4bb104..1522d85 100644
--- a/src/Games/Logic/PuzzleNumericSequence.cs
+++ b/src/Games/Logic/PuzzleNumericSequence.cs
@@ -45,22 +45,18 @@ namespace gbrainy.Games.Logic
 			get { return Catalog.GetString ("Every number in the sequence is related to the previous one.");}
 		}
 
-		public override string Answer {
+		public override string Rationale {
 			get { 
-				string answer = base.Answer + " ";
-
 				switch (formula) {
 				case 0:
-					answer += Catalog.GetString ("Every number in the sequence is the result of subtracting 1 from the previous number and multiplying it by 2.");
-					break;
+					return Catalog.GetString ("Every number in the sequence is the result of subtracting 1 from the previous number and multiplying it by 2.");
 				case 1:
-					answer += Catalog.GetString ("Every number in the sequence is the result of adding 1 to the previous number and multiplying it by 3.");
-					break;
+					return Catalog.GetString ("Every number in the sequence is the result of adding 1 to the previous number and multiplying it by 3.");
 				case 2:
-					answer += Catalog.GetString ("Every number in the sequence is the result of subtracting 2 from the previous number and multiplying it by -2.");
-					break;
+					return Catalog.GetString ("Every number in the sequence is the result of subtracting 2 from the previous number and multiplying it by -2.");
+				default:
+					return string.Empty;
 				}
-				return answer;
 			}
 		}
 
diff --git a/src/Games/Logic/PuzzleOstracism.cs b/src/Games/Logic/PuzzleOstracism.cs
index 8cd9714..1b9b65e 100644
--- a/src/Games/Logic/PuzzleOstracism.cs
+++ b/src/Games/Logic/PuzzleOstracism.cs
@@ -74,22 +74,16 @@ namespace gbrainy.Games.Logic
 			}	
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-
+		public override string Rationale {
+			get {
 				switch (gametype) {
 				case GameType.Equations:
-					answer += Catalog.GetString ("In all the other equations the digits from the left side appear also in the right side.");
-					break;
+					return Catalog.GetString ("In all the other equations the digits from the left side appear also in the right side.");
 				case GameType.Numbers:
-					answer += Catalog.GetString ("In all the other numbers the last three digits are the square of the first two digits.");
-					break;
+					return Catalog.GetString ("In all the other numbers the last three digits are the square of the first two digits.");
 				default:
 					throw new InvalidOperationException ();
 				}
-
-				return answer;
 			}
 		}
 
diff --git a/src/Games/Logic/PuzzlePeopleTable.cs b/src/Games/Logic/PuzzlePeopleTable.cs
index d232f26..56de712 100644
--- a/src/Games/Logic/PuzzlePeopleTable.cs
+++ b/src/Games/Logic/PuzzlePeopleTable.cs
@@ -51,11 +51,9 @@ namespace gbrainy.Games.Logic
 			get {return String.Format (Catalog.GetString ("A group of people are sitting at round table, evenly spaced out. How many people are there if the {0} person is across from the {1}?"), ques1, ques2);} 
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-				answer += Catalog.GetString ("Subtracting the two positions you find out how many people are seated half way around the table. Doubling this number leaves you with the total amount of people.");
-				return answer;
+		public override string Rationale {
+			get {
+				return Catalog.GetString ("Subtracting the two positions you find out how many people are seated half way around the table. Doubling this number leaves you with the total amount of people.");
 			}
 		}
 
diff --git a/src/Games/Logic/PuzzlePercentage.cs b/src/Games/Logic/PuzzlePercentage.cs
index 7153a90..99a92d4 100644
--- a/src/Games/Logic/PuzzlePercentage.cs
+++ b/src/Games/Logic/PuzzlePercentage.cs
@@ -47,16 +47,16 @@ namespace gbrainy.Games.Logic
 			get {return question; }
 		}
 
-		public override string Answer {
+		public override string Rationale {
 			get {
-
-				if (String.IsNullOrEmpty (answer) == true)
-					return base.Answer;
-
-				return base.Answer + " " + answer;
+				return answer;
 			}
 		}
 
+		public override string AnswerCheckExpression {
+			get { return "[0-9]+";}
+		}
+
 		public override void Initialize ()
 		{
 			int ans;
@@ -126,18 +126,5 @@ namespace gbrainy.Games.Logic
 		{
 			base.Draw (gr, area_width, area_height, rtl);
 		}
-
-		public override bool CheckAnswer (string answer)
-		{	
-			if (gametype == GameType.Water) {
-				if (String.Compare (answer, right_answer + "%", true) == 0) 
-					return true;
-			}
-
-			if (String.Compare (answer, right_answer, true) == 0) 
-				return true;
-
-			return false;
-		}
 	}
 }
diff --git a/src/Games/Logic/PuzzlePredicateLogic.cs b/src/Games/Logic/PuzzlePredicateLogic.cs
index 8afbdd8..4b0d04c 100644
--- a/src/Games/Logic/PuzzlePredicateLogic.cs
+++ b/src/Games/Logic/PuzzlePredicateLogic.cs
@@ -96,13 +96,6 @@ namespace gbrainy.Games.Logic
 			get {return predicates[question].question;} 
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-				return answer;
-			}
-		}
-
 		public override void Initialize ()
 		{
 			int answers;
diff --git a/src/Games/Logic/PuzzleQuadrilaterals.cs b/src/Games/Logic/PuzzleQuadrilaterals.cs
index eceab38..8b48afc 100644
--- a/src/Games/Logic/PuzzleQuadrilaterals.cs
+++ b/src/Games/Logic/PuzzleQuadrilaterals.cs
@@ -53,11 +53,9 @@ namespace gbrainy.Games.Logic
 					GetPossibleAnswer (5));}
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-				answer += Catalog.GetString ("It is the only figure with all lines of equal length.");
-				return answer;
+		public override string Rationale {
+			get {
+				return Catalog.GetString ("It is the only figure with all lines of equal length.");
 			}
 		}
 
diff --git a/src/Games/Logic/PuzzleSquareSheets.cs b/src/Games/Logic/PuzzleSquareSheets.cs
index 272eda9..d1e17d5 100644
--- a/src/Games/Logic/PuzzleSquareSheets.cs
+++ b/src/Games/Logic/PuzzleSquareSheets.cs
@@ -40,11 +40,9 @@ namespace gbrainy.Games.Logic
 			get { return Catalog.GetString ("The sheets should overlap.");}
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-				answer += Catalog.GetString ("The numbers in the figure reflect the different areas covered by each one of the sheets.");
-				return answer;
+		public override string Rationale {
+			get {
+				return Catalog.GetString ("The numbers in the figure reflect the different areas covered by each one of the sheets.");
 			}
 		}
 
diff --git a/src/Games/Logic/PuzzleSquares.cs b/src/Games/Logic/PuzzleSquares.cs
index 34e61c6..2147db0 100644
--- a/src/Games/Logic/PuzzleSquares.cs
+++ b/src/Games/Logic/PuzzleSquares.cs
@@ -42,19 +42,16 @@ namespace gbrainy.Games.Logic
 			get { return Catalog.GetString ("A square is a rectangle with sides of equal length. A square can also be built from other squares.");}
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-
+		public override string Rationale {
+			get {
 				switch (type) {
 				case 0:
-					answer += Catalog.GetString ("There are 16 single squares, 9 squares made by 4 single squares, 4 squares made by 9 single squares and 1 square made by 16 single squares.");
-					break;
+					return Catalog.GetString ("There are 16 single squares, 9 squares made by 4 single squares, 4 squares made by 9 single squares and 1 square made by 16 single squares.");
 				case 1:
-					answer += Catalog.GetString ("There are 9 single squares, 4 squares made by 4 single squares and 1 square made by 9 single squares.");
-					break;
+					return Catalog.GetString ("There are 9 single squares, 4 squares made by 4 single squares and 1 square made by 9 single squares.");
+				default:
+					return string.Empty;
 				}
-				return answer;
 			}
 		}
 
diff --git a/src/Games/Logic/PuzzleSquaresAndLetters.cs b/src/Games/Logic/PuzzleSquaresAndLetters.cs
index f7e7949..00f97bf 100644
--- a/src/Games/Logic/PuzzleSquaresAndLetters.cs
+++ b/src/Games/Logic/PuzzleSquaresAndLetters.cs
@@ -41,12 +41,9 @@ namespace gbrainy.Games.Logic
 			get {return Catalog.GetString ("The letters around the squares follow a pattern. Which letter should replace the question mark in the last square?");} 
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-				answer += String.Format (Catalog.GetString ("Every letter is calculated by taking the alphabetical position of the previous character and adding {0} to it in order to get the position of the new letter."), step);
-
-				return answer;
+		public override string Rationale {
+			get {
+				return String.Format (Catalog.GetString ("Every letter is calculated by taking the alphabetical position of the previous character and adding {0} to it in order to get the position of the new letter."), step);
 			}
 		}
 
diff --git a/src/Games/Logic/PuzzleTetris.cs b/src/Games/Logic/PuzzleTetris.cs
index 7cf6ca6..8ebf988 100644
--- a/src/Games/Logic/PuzzleTetris.cs
+++ b/src/Games/Logic/PuzzleTetris.cs
@@ -43,11 +43,9 @@ namespace gbrainy.Games.Logic
 				GetPossibleAnswer (0), GetPossibleAnswer (1), GetPossibleAnswer (2));}
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-				answer += Catalog.GetString ("It is the figure that completes all possible combinations with four blocks without taking into account rotations.");
-				return answer;
+		public override string Rationale {
+			get {
+				return Catalog.GetString ("It is the figure that completes all possible combinations with four blocks without taking into account rotations.");
 			}
 		}
 
diff --git a/src/Games/Logic/PuzzleTimeNow.cs b/src/Games/Logic/PuzzleTimeNow.cs
index 7cc62dc..d3e8a13 100644
--- a/src/Games/Logic/PuzzleTimeNow.cs
+++ b/src/Games/Logic/PuzzleTimeNow.cs
@@ -47,11 +47,9 @@ namespace gbrainy.Games.Logic
 				after, position_a, position_b, position_b));}
 		}
 
-		public override string Answer {
+		public override string Rationale {
 			get {
-				string answer = base.Answer + " ";
-				answer += String.Format (Catalog.GetString ("You have to calculate the hour from which the distance is the same for the given times, and then add the {0} hours to convert it to present time."), after);
-				return answer;
+				return String.Format (Catalog.GetString ("You have to calculate the hour from which the distance is the same for the given times, and then add the {0} hours to convert it to present time."), after);
 			}
 		}
 
diff --git a/src/Games/Logic/PuzzleTrains.cs b/src/Games/Logic/PuzzleTrains.cs
index 2802a35..e42a2a9 100644
--- a/src/Games/Logic/PuzzleTrains.cs
+++ b/src/Games/Logic/PuzzleTrains.cs
@@ -47,8 +47,8 @@ namespace gbrainy.Games.Logic
 			get {return question; }
 		}
 
-		public override string Answer {
-			get { return base.Answer + " " + answer;}
+		public override string Rationale {
+			get { return answer;}
 		}
 
 		public override string Tip {
diff --git a/src/Games/Logic/PuzzleTriangles.cs b/src/Games/Logic/PuzzleTriangles.cs
index a28364b..54312ff 100644
--- a/src/Games/Logic/PuzzleTriangles.cs
+++ b/src/Games/Logic/PuzzleTriangles.cs
@@ -42,15 +42,11 @@ namespace gbrainy.Games.Logic
 			get { return Catalog.GetString ("A triangle can be embedded inside another triangle.");}
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-
-				answer += String.Format (Catalog.GetString ("The triangles are made by connecting the following points: {0}"),
+		public override string Rationale {
+			get {
+				return String.Format (Catalog.GetString ("The triangles are made by connecting the following points: {0}"),
 					(type == 0) ? "bdc, dcf, dfg, abd, ade, edg, acg, abg, bcg, afg, ecg, acd, acf, ace, adg, cdg." : 
 					"dcf, ade, acg, afg, ecg, acd, acf, ace.");
-
-				return answer;
 			}
 		}
 
diff --git a/src/Games/Logic/PuzzleTrianglesWithNumbers.cs b/src/Games/Logic/PuzzleTrianglesWithNumbers.cs
index 2863297..b43b016 100644
--- a/src/Games/Logic/PuzzleTrianglesWithNumbers.cs
+++ b/src/Games/Logic/PuzzleTrianglesWithNumbers.cs
@@ -69,11 +69,9 @@ namespace gbrainy.Games.Logic
 			get { return Catalog.GetString ("All the triangles share a property and are independent of the rest.");}
 		}
 
-		public override string Answer {
-			get { 
-				string answer = base.Answer + " ";
-				answer += String.Format (Catalog.GetString ("The result of multiplying the two numbers inside every triangle is {0}."), answer_number);
-				return answer;
+		public override string Rationale {
+			get {
+				return String.Format (Catalog.GetString ("The result of multiplying the two numbers inside every triangle is {0}."), answer_number);
 			}
 		}
 
diff --git a/src/Games/Memory/MemoryFacts.cs b/src/Games/Memory/MemoryFacts.cs
index 9c7c41b..b47f83f 100644
--- a/src/Games/Memory/MemoryFacts.cs
+++ b/src/Games/Memory/MemoryFacts.cs
@@ -56,6 +56,10 @@ namespace gbrainy.Games.Memory
 			get { return question;}
 		}
 
+		public override string AnswerCheckExpression {
+			get { return "[0-9]+";}
+		}
+
 		public override void Initialize ()
 		{
 			int fact_idx, quest_idx, questions;
@@ -161,16 +165,5 @@ namespace gbrainy.Games.Memory
 			}
 			gr.DrawStringWithWrapping (0.3, DrawAreaY + 0.2, text, 0.95 - 0.3);
 		}
-
-		public override bool CheckAnswer (string answer)
-		{	
-			if (String.Compare (answer, right_answer, true) == 0) 
-				return true;
-
-			if (String.Compare (answer, right_answer + "%", true) == 0) 
-				return true;
-
-			return false;
-		}
 	}
 }
diff --git a/tests/Core/GameTest.cs b/tests/Core/GameTest.cs
index f2a5209..1bfe544 100644
--- a/tests/Core/GameTest.cs
+++ b/tests/Core/GameTest.cs
@@ -42,6 +42,10 @@ namespace gbrainyTest
 			get { return "TestGame"; }
 		}
 
+		public string PossibleAnswersExpression {
+			get { return GetPossibleAnswersExpression (); }
+		}
+
 		public string RightAnswer {
 			set { right_answer = value; }
 		}
@@ -60,6 +64,7 @@ namespace gbrainyTest
 		}
 
 		public override void Initialize () {}
+		
 	}
 
 	[TestFixture]
@@ -71,7 +76,7 @@ namespace gbrainyTest
 
 		}
 
-		// Test individual attributes
+		// Test individual attributes (MatchAll follows a different logic path)
 		[Test]
 		public void Trim ()
 		{
@@ -141,6 +146,31 @@ namespace gbrainyTest
 			Assert.AreEqual (true, game.CheckAnswer ("10pm"));
 		}
 
+		[Test]
+		public void MatchAllInOder ()
+		{
+			TestGame game = new TestGame ();
+
+			game.Attributes = Game.AnswerCheckAttributes.MatchAllInOrder;
+			game.Expression = "[0-9]+";
+			game.RightAnswer = "10 | 20 | 30";
+
+			Assert.AreEqual (true, game.CheckAnswer ("10 20 30"));
+			Assert.AreEqual (false, game.CheckAnswer ("30 20 10"));
+		}
+
+		[Test]
+		public void MatchAll ()
+		{
+			TestGame game = new TestGame ();
+
+			game.Attributes = Game.AnswerCheckAttributes.MatchAll;
+			game.Expression = "[0-9]+";
+			game.RightAnswer = "10 | 20 | 30";
+			Assert.AreEqual (true, game.CheckAnswer ("10 20 30"));
+			Assert.AreEqual (true, game.CheckAnswer ("30 20 10"));
+		}
+
 		// Test attributes as used in real games
 
 		[Test]
@@ -186,6 +216,61 @@ namespace gbrainyTest
 		}
 
 		[Test]
+		public void CheckCalculationOperator ()
+		{
+			TestGame game = new TestGame ();
+			game.RightAnswer = "+ | -";
+			game.Expression = "[+*-/]+";
+			game.Attributes = Game.AnswerCheckAttributes.Trim | Game.AnswerCheckAttributes.MatchAllInOrder;
+
+			Assert.AreEqual (true, game.CheckAnswer ("+ i -"));
+			Assert.AreEqual (true, game.CheckAnswer ("+ and -"));
+			Assert.AreEqual (true, game.CheckAnswer ("+ -"));
+
+			Assert.AreEqual (false, game.CheckAnswer ("- +"));
+		}
+
+		[Test]
+		public void CheckPuzzleBuildTriangle ()
+		{
+			TestGame game = new TestGame ();
+	
+			game.RightAnswer = "A | B | C";
+			game.Expression = "[ABCDF]";
+			game.Attributes = Game.AnswerCheckAttributes.Trim | Game.AnswerCheckAttributes.IgnoreCase | Game.AnswerCheckAttributes.MatchAll;
+
+			Assert.AreEqual (true, game.CheckAnswer ("A B C"));
+			Assert.AreEqual (true, game.CheckAnswer ("C B A"));
+			Assert.AreEqual (true, game.CheckAnswer ("B C A"));
+			Assert.AreEqual (true, game.CheckAnswer ("A B C"));
+			Assert.AreEqual (true, game.CheckAnswer ("C A B"));
+			Assert.AreEqual (true, game.CheckAnswer ("a b c"));
+
+			Assert.AreEqual (false, game.CheckAnswer ("B C C"));
+			Assert.AreEqual (false, game.CheckAnswer ("B C"));
+			Assert.AreEqual (false, game.CheckAnswer ("BC"));
+		}
+
+
+		[Test]
+		public void CheckPuzzlePercentage ()
+		{
+			TestGame game = new TestGame ();
+	
+			game.RightAnswer = "10";
+			game.Expression = "[0-9]+";
+
+			Assert.AreEqual (true, game.CheckAnswer ("10%"));
+			Assert.AreEqual (true, game.CheckAnswer ("10 %"));
+			Assert.AreEqual (true, game.CheckAnswer ("10"));
+
+			game.RightAnswer = "9";
+			Assert.AreEqual (true, game.CheckAnswer ("9%"));
+			Assert.AreEqual (true, game.CheckAnswer ("9 %"));
+			Assert.AreEqual (true, game.CheckAnswer ("9"));
+		}
+
+		[Test]
 		public void TwoNumbersAnswer ()
 		{
 			TestGame game = new TestGame ();



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]