[gbrainy/gbrainy_15x] Use regular expressions & attributes to check answers
- From: Jordi Mas <jmas src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gbrainy/gbrainy_15x] Use regular expressions & attributes to check answers
- Date: Fri, 21 May 2010 02:01:27 +0000 (UTC)
commit 036a7a00139ef8441fbd38b48e117d00c0b421fb
Author: Jordi Mas <jmas softcatala org>
Date: Fri May 21 04:02:06 2010 +0200
Use regular expressions & attributes to check answers
src/Core/Main/Game.cs | 100 +++++++++++-
src/Core/Main/Verbal/Analogies.cs | 15 --
src/Games/Calculation/CalculationRatio.cs | 43 +----
src/Games/Calculation/CalculationTwoNumbers.cs | 42 +----
src/Games/Logic/PuzzleTimeNow.cs | 28 +---
tests/Core/GameManagerTest.cs | 2 +-
tests/Core/GameTest.cs | 216 ++++++++++++++++++++++++
tests/Core/PlayerPersonalRecordTest.cs | 2 -
tests/Makefile.am | 3 +-
9 files changed, 341 insertions(+), 110 deletions(-)
---
diff --git a/src/Core/Main/Game.cs b/src/Core/Main/Game.cs
index f7e7b36..583d9f3 100644
--- a/src/Core/Main/Game.cs
+++ b/src/Core/Main/Game.cs
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Jordi Mas i Hernà ndez <jmas softcatala org>
+ * Copyright (C) 2007-2010 Jordi Mas i Hernà ndez <jmas softcatala org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -20,6 +20,7 @@
using System;
using System.ComponentModel;
using System.Collections.Generic;
+using System.Text.RegularExpressions;
using Mono.Unix;
using gbrainy.Core.Views;
@@ -48,6 +49,18 @@ namespace gbrainy.Core.Main
Master = 8,
}
+ [Flags]
+ public enum AnswerCheckAttributes
+ {
+ None = 0,
+ Trim = 2,
+ IgnoreCase = 4,
+ IgnoreSpaces = 8,
+ MatchAll = 16,
+ }
+
+ public const char AnswerSeparator = '|';
+
public class AnswerEventArgs : EventArgs
{
public AnswerEventArgs (string answer)
@@ -139,6 +152,15 @@ namespace gbrainy.Core.Main
}
}
+ // How to check the answer
+ public virtual AnswerCheckAttributes CheckAttributes {
+ get { return AnswerCheckAttributes.Trim | AnswerCheckAttributes.IgnoreCase; }
+ }
+
+ public virtual string AnswerCheckExpression {
+ get { return ".+"; }
+ }
+
public abstract string Name {
get;
}
@@ -362,7 +384,81 @@ namespace gbrainy.Core.Main
public virtual bool CheckAnswer (string answer)
{
- return (String.Compare (answer, right_answer, true) == 0);
+ Regex regex;
+ Match match;
+ AnswerCheckAttributes type;
+ bool ignore_case, ignore_spaces;
+
+ if (String.IsNullOrEmpty (answer))
+ return false;
+
+ ignore_case = (CheckAttributes & AnswerCheckAttributes.IgnoreCase) == AnswerCheckAttributes.IgnoreCase;
+ ignore_spaces = (CheckAttributes & AnswerCheckAttributes.IgnoreSpaces) == AnswerCheckAttributes.IgnoreSpaces;
+ regex = new Regex (AnswerCheckExpression);
+
+ string [] right_answers = right_answer.Split (AnswerSeparator);
+
+ for (int i = 0; i < right_answers.Length; i++)
+ {
+ right_answers [i] = right_answers[i].Trim ();
+
+ if (ignore_spaces)
+ right_answers [i] = RemoveWhiteSpace (right_answers [i]);
+ }
+
+ if ((CheckAttributes & AnswerCheckAttributes.Trim) == AnswerCheckAttributes.Trim)
+ answer = answer.Trim ();
+
+ if (ignore_spaces)
+ 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)
+ {
+ match = regex.Match (answer);
+ while (String.IsNullOrEmpty (match.Value) == false)
+ {
+ for (int i = 0; i < right_answers.Length; i++)
+ {
+ if (String.Compare (match.Value, right_answers[i], ignore_case) == 0)
+ {
+ right_answers[i] = null;
+ break;
+ }
+ }
+ match = match.NextMatch ();
+ }
+
+ // Have all the expected answers been matched?
+ for (int i = 0; i < right_answers.Length; i++)
+ {
+ if (right_answers[i] != null)
+ return false;
+ }
+
+ return true;
+ }
+ else // Any string from the list of possible answers (answer1 | answer2) present in the answer will do it
+ {
+ foreach (string s in right_answers)
+ {
+ match = regex.Match (answer);
+ if (String.Compare (match.Value, s, ignore_case) == 0)
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static string RemoveWhiteSpace (string source)
+ {
+ string str = string.Empty;
+ for (int n = 0; n < source.Length; n++)
+ {
+ if (char.IsWhiteSpace (source [n]) == false)
+ str += source [n];
+ }
+ return str;
}
// When asking for a list of figures people trends to use spaces or commas
diff --git a/src/Core/Main/Verbal/Analogies.cs b/src/Core/Main/Verbal/Analogies.cs
index f773923..25180dd 100644
--- a/src/Core/Main/Verbal/Analogies.cs
+++ b/src/Core/Main/Verbal/Analogies.cs
@@ -198,20 +198,5 @@ namespace gbrainy.Core.Main.Verbal
return analogy;
}
-
- public override bool CheckAnswer (string answer)
- {
- string [] items = right_answer.Split (AnalogiesFactory.Separator);
-
- foreach (string ans in items)
- {
- string str = ans.Trim ();
-
- if (String.Compare (str, answer, true) == 0)
- return true;
- }
-
- return base.CheckAnswer (answer);
- }
}
}
diff --git a/src/Games/Calculation/CalculationRatio.cs b/src/Games/Calculation/CalculationRatio.cs
index 68a2662..6c12618 100644
--- a/src/Games/Calculation/CalculationRatio.cs
+++ b/src/Games/Calculation/CalculationRatio.cs
@@ -60,6 +60,14 @@ namespace gbrainy.Games.Calculation
get { return Catalog.GetString ("A ratio specifies a proportion between two numbers. A ratio a:b means that for every 'a' parts you have 'b' parts.");}
}
+ public override AnswerCheckAttributes CheckAttributes {
+ get { return AnswerCheckAttributes.Trim | AnswerCheckAttributes.MatchAll; }
+ }
+
+ public override string AnswerCheckExpression {
+ get { return "[0-9]+"; }
+ }
+
public override void Initialize ()
{
int random_max;
@@ -86,7 +94,8 @@ namespace gbrainy.Games.Calculation
ratio_b = 3 + random.Next (random_max);
number_b = number_a / ratio_a * ratio_b;
- right_answer = String.Format (Catalog.GetString ("{0} and {1}"), 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);
}
public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
@@ -103,37 +112,5 @@ namespace gbrainy.Games.Calculation
gr.MoveTo (x, DrawAreaY + 0.44);
gr.ShowPangoText (String.Format (Catalog.GetString ("have a ratio of {0}:{1}"), ratio_a, ratio_b));
}
-
- public override bool CheckAnswer (string answer)
- {
- string num_a = string.Empty;
- string num_b = string.Empty;
- bool first = true;
-
- for (int c = 0; c < answer.Length; c++)
- {
- if (answer[c] < '0' || answer[c] > '9') {
- first = false;
- continue;
- }
-
- if (first == true)
- num_a += answer[c];
- else
- num_b += answer[c];
- }
-
- try {
- if (Int32.Parse (num_a) == number_a && Int32.Parse (num_b) == number_b ||
- Int32.Parse (num_b) == number_a && Int32.Parse (num_a) == number_b)
- return true;
- }
-
- catch (FormatException) {
- return false;
- }
-
- return false;
- }
}
}
diff --git a/src/Games/Calculation/CalculationTwoNumbers.cs b/src/Games/Calculation/CalculationTwoNumbers.cs
index 1489ade..db85d4e 100644
--- a/src/Games/Calculation/CalculationTwoNumbers.cs
+++ b/src/Games/Calculation/CalculationTwoNumbers.cs
@@ -61,6 +61,14 @@ namespace gbrainy.Games.Calculation
}
}
+ public override AnswerCheckAttributes CheckAttributes {
+ get { return AnswerCheckAttributes.Trim | AnswerCheckAttributes.MatchAll; }
+ }
+
+ public override string AnswerCheckExpression {
+ get { return "[0-9]+"; }
+ }
+
public override void Initialize ()
{
type = (GameTypes) random.Next ((int) GameTypes.Length);
@@ -99,7 +107,8 @@ namespace gbrainy.Games.Calculation
op2 = number_a * number_b;
- right_answer = String.Format (Catalog.GetString ("{0} and {1}"), 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);
}
public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
@@ -127,36 +136,5 @@ namespace gbrainy.Games.Calculation
gr.ShowPangoText (String.Format (Catalog.GetString ("number1 * number2 = {0}"), op2));
}
- public override bool CheckAnswer (string answer)
- {
- string num_a = string.Empty;
- string num_b = string.Empty;
- bool first = true;
-
- for (int c = 0; c < answer.Length; c++)
- {
- if (answer[c] < '0' || answer[c] > '9') {
- first = false;
- continue;
- }
-
- if (first == true)
- num_a += answer[c];
- else
- num_b += answer[c];
- }
-
- try {
- if (Int32.Parse (num_a) == number_a && Int32.Parse (num_b) == number_b ||
- Int32.Parse (num_b) == number_a && Int32.Parse (num_a) == number_b)
- return true;
- }
-
- catch (FormatException) {
- return false;
- }
-
- return false;
- }
}
}
diff --git a/src/Games/Logic/PuzzleTimeNow.cs b/src/Games/Logic/PuzzleTimeNow.cs
index adf8667..7cc62dc 100644
--- a/src/Games/Logic/PuzzleTimeNow.cs
+++ b/src/Games/Logic/PuzzleTimeNow.cs
@@ -47,7 +47,6 @@ namespace gbrainy.Games.Logic
after, position_a, position_b, position_b));}
}
-
public override string Answer {
get {
string answer = base.Answer + " ";
@@ -56,6 +55,10 @@ namespace gbrainy.Games.Logic
}
}
+ public override AnswerCheckAttributes CheckAttributes {
+ get { return AnswerCheckAttributes.Trim | AnswerCheckAttributes.IgnoreCase | AnswerCheckAttributes.IgnoreSpaces; }
+ }
+
public override void Initialize ()
{
int hour;
@@ -85,28 +88,5 @@ namespace gbrainy.Games.Logic
gr.DrawTextCentered (0.5, DrawAreaY + 0.3 + figure_size, Catalog.GetString ("Sample clock"));
}
-
- public override bool CheckAnswer (string answer)
- {
- string ans = string.Empty;
- string user = string.Empty;
-
- if (base.CheckAnswer (answer))
- return true;
-
- // Compare ignoring spaces then '1PM' is as valid as '1 PM'
- for (int c = 0; c < answer.Length; c++)
- {
- if (Char.IsWhiteSpace (answer[c]) == false)
- ans += answer[c];
- }
-
- for (int c = 0; c < right_answer.Length; c++)
- {
- if (Char.IsWhiteSpace (right_answer[c]) == false)
- user += right_answer[c];
- }
- return (String.Compare (user, ans, true) == 0);
- }
}
}
diff --git a/tests/Core/GameManagerTest.cs b/tests/Core/GameManagerTest.cs
index b227e9b..1f7d246 100644
--- a/tests/Core/GameManagerTest.cs
+++ b/tests/Core/GameManagerTest.cs
@@ -31,7 +31,7 @@ namespace gbrainyTest
[TestFixtureSetUp]
public void Construct ()
{
- Console.WriteLine ("GameManagerTest constructor");
+
}
//Lists the games without tip
diff --git a/tests/Core/GameTest.cs b/tests/Core/GameTest.cs
new file mode 100644
index 0000000..f2a5209
--- /dev/null
+++ b/tests/Core/GameTest.cs
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2010 Jordi Mas i Hernà ndez <jmas softcatala org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+using System;
+using NUnit.Framework;
+
+using gbrainy.Core.Main;
+
+namespace gbrainyTest
+{
+ public class TestGame : Game
+ {
+ public string Expression { get; set; }
+ public Game.AnswerCheckAttributes Attributes { get; set; }
+
+ public TestGame ()
+ {
+ Attributes = base.CheckAttributes;
+ }
+
+ public override string Question {
+ get { return "Question"; }
+ }
+
+ public override string Name {
+ get { return "TestGame"; }
+ }
+
+ public string RightAnswer {
+ set { right_answer = value; }
+ }
+
+ public override string AnswerCheckExpression {
+ get {
+ if (String.IsNullOrEmpty (Expression))
+ return base.AnswerCheckExpression;
+
+ return Expression;
+ }
+ }
+
+ public override AnswerCheckAttributes CheckAttributes {
+ get { return Attributes; }
+ }
+
+ public override void Initialize () {}
+ }
+
+ [TestFixture]
+ public class GameTest
+ {
+ [TestFixtureSetUp]
+ public void Construct ()
+ {
+
+ }
+
+ // Test individual attributes
+ [Test]
+ public void Trim ()
+ {
+ TestGame game = new TestGame ();
+
+ game.Attributes = Game.AnswerCheckAttributes.None;
+ game.RightAnswer = "icon";
+ Assert.AreEqual (true, game.CheckAnswer ("icon"));
+ Assert.AreEqual (false, game.CheckAnswer (" icon "));
+
+ game.Attributes = Game.AnswerCheckAttributes.Trim;
+ Assert.AreEqual (true, game.CheckAnswer ("icon"));
+ Assert.AreEqual (true, game.CheckAnswer (" icon "));
+
+ game.Attributes = Game.AnswerCheckAttributes.MatchAll;
+ Assert.AreEqual (true, game.CheckAnswer ("icon"));
+ Assert.AreEqual (false, game.CheckAnswer (" icon "));
+
+ game.Attributes = Game.AnswerCheckAttributes.Trim | Game.AnswerCheckAttributes.MatchAll;
+ Assert.AreEqual (true, game.CheckAnswer ("icon"));
+ Assert.AreEqual (true, game.CheckAnswer (" icon "));
+ }
+
+ [Test]
+ public void IgnoreCase ()
+ {
+ TestGame game = new TestGame ();
+
+ game.Attributes = Game.AnswerCheckAttributes.None;
+ game.RightAnswer = "icon";
+ Assert.AreEqual (true, game.CheckAnswer ("icon"));
+ Assert.AreEqual (false, game.CheckAnswer ("ICON"));
+
+ game.Attributes = Game.AnswerCheckAttributes.IgnoreCase;
+ Assert.AreEqual (true, game.CheckAnswer ("icon"));
+ Assert.AreEqual (true, game.CheckAnswer ("ICON"));
+
+ game.Attributes = Game.AnswerCheckAttributes.MatchAll;
+ Assert.AreEqual (true, game.CheckAnswer ("icon"));
+ Assert.AreEqual (false, game.CheckAnswer ("ICON"));
+
+ game.Attributes = Game.AnswerCheckAttributes.IgnoreCase | Game.AnswerCheckAttributes.MatchAll;
+ Assert.AreEqual (true, game.CheckAnswer ("icon"));
+ Assert.AreEqual (true, game.CheckAnswer ("ICON"));
+ }
+
+ [Test]
+ public void IgnoreSpaces ()
+ {
+ TestGame game = new TestGame ();
+
+ game.Attributes = Game.AnswerCheckAttributes.None;
+ game.RightAnswer = "10 pm";
+ Assert.AreEqual (true, game.CheckAnswer ("10 pm"));
+ Assert.AreEqual (false, game.CheckAnswer ("10pm"));
+
+ game.Attributes = Game.AnswerCheckAttributes.IgnoreSpaces;
+ Assert.AreEqual (true, game.CheckAnswer ("10 pm"));
+ Assert.AreEqual (true, game.CheckAnswer ("10pm"));
+
+ game.Attributes = Game.AnswerCheckAttributes.MatchAll;
+ Assert.AreEqual (true, game.CheckAnswer ("10 pm"));
+ Assert.AreEqual (false, game.CheckAnswer ("10pm"));
+
+ game.Attributes = Game.AnswerCheckAttributes.IgnoreSpaces | Game.AnswerCheckAttributes.MatchAll;
+ Assert.AreEqual (true, game.CheckAnswer ("10 pm"));
+ Assert.AreEqual (true, game.CheckAnswer ("10pm"));
+ }
+
+ // Test attributes as used in real games
+
+ [Test]
+ public void DefaultAnswer ()
+ {
+ TestGame game = new TestGame ();
+
+ game.RightAnswer = "icon";
+ Assert.AreEqual (true, game.CheckAnswer ("icon"));
+
+ game.RightAnswer = "icona";
+ Assert.AreEqual (true, game.CheckAnswer ("icona"));
+ }
+
+ [Test]
+ public void DefaultAnswerOptions ()
+ {
+ TestGame game = new TestGame ();
+
+ game.RightAnswer = "option1 | option2";
+ Assert.AreEqual (true, game.CheckAnswer ("option1"));
+ Assert.AreEqual (true, game.CheckAnswer ("option2"));
+ Assert.AreEqual (true, game.CheckAnswer (" option2 "));
+
+ Assert.AreEqual (false, game.CheckAnswer ("option3"));
+ }
+
+ [Test]
+ public void CheckPuzzleTimeNowAnswer ()
+ {
+ TestGame game = new TestGame ();
+ game.RightAnswer = "10 PM";
+ game.Attributes = Game.AnswerCheckAttributes.Trim | Game.AnswerCheckAttributes.IgnoreCase | Game.AnswerCheckAttributes.IgnoreSpaces;
+
+ Assert.AreEqual (true, game.CheckAnswer ("10 PM"));
+ Assert.AreEqual (true, game.CheckAnswer ("10 pm"));
+ Assert.AreEqual (true, game.CheckAnswer ("10pm"));
+ Assert.AreEqual (true, game.CheckAnswer ("10Pm"));
+ Assert.AreEqual (true, game.CheckAnswer (" 10Pm "));
+
+ Assert.AreEqual (false, game.CheckAnswer ("10 P"));
+ Assert.AreEqual (false, game.CheckAnswer ("10"));
+ }
+
+ [Test]
+ public void TwoNumbersAnswer ()
+ {
+ TestGame game = new TestGame ();
+ game.RightAnswer = "10 | 20";
+ game.Expression = "[0-9]+";
+ game.Attributes = Game.AnswerCheckAttributes.Trim | Game.AnswerCheckAttributes.MatchAll;
+
+ // Right answers
+ Assert.AreEqual (true, game.CheckAnswer ("10 and 20"));
+ Assert.AreEqual (true, game.CheckAnswer ("10 i 20"));
+ Assert.AreEqual (true, game.CheckAnswer ("10 y 20"));
+ Assert.AreEqual (true, game.CheckAnswer ("10 20"));
+ Assert.AreEqual (true, game.CheckAnswer (" 10 20 "));
+
+ Assert.AreEqual (true, game.CheckAnswer ("20 and 10"));
+ Assert.AreEqual (true, game.CheckAnswer ("20 i 10"));
+ Assert.AreEqual (true, game.CheckAnswer ("20 y 10"));
+ Assert.AreEqual (true, game.CheckAnswer ("20 10"));
+ Assert.AreEqual (true, game.CheckAnswer (" 20 10 "));
+
+ // Invalid answers
+ Assert.AreEqual (false, game.CheckAnswer (" 10 30 "));
+ Assert.AreEqual (false, game.CheckAnswer ("10"));
+ Assert.AreEqual (false, game.CheckAnswer ("20"));
+ Assert.AreEqual (false, game.CheckAnswer ("10 2"));
+ }
+ }
+}
diff --git a/tests/Core/PlayerPersonalRecordTest.cs b/tests/Core/PlayerPersonalRecordTest.cs
index 2720d11..c9ebf93 100644
--- a/tests/Core/PlayerPersonalRecordTest.cs
+++ b/tests/Core/PlayerPersonalRecordTest.cs
@@ -28,8 +28,6 @@ namespace gbrainyTest
[TestFixture]
public class PlayerPersonalRecordTest
{
- PlayerHistory history;
-
[TestFixtureSetUp]
public void Construct ()
{
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 3695e8e..93fefdb 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -10,7 +10,8 @@ CSFILES = \
$(srcdir)/Core/PlayerHistoryTest.cs \
$(srcdir)/Core/PlayerPersonalRecordTest.cs \
$(srcdir)/Core/GameSessionTest.cs \
- $(srcdir)/Core/GameManagerTest.cs
+ $(srcdir)/Core/GameManagerTest.cs \
+ $(srcdir)/Core/GameTest.cs
ASSEMBLIES = \
$(NUNIT_LIBS) \
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]