[gbrainy] Major work. Separates logically the functions in different assemblies, use namespaces and increase c



commit 508c381e0c29a0370f12e0c19c0d38f9f5f7353e
Author: Jordi Mas <jmas softcatala org>
Date:   Sat Nov 21 10:19:25 2009 +0100

    Major work. Separates logically the functions in different assemblies, use namespaces and increase cohesion

 ChangeLog                                          |   98 --
 autogen.sh                                         |    2 +-
 configure.in                                       |   11 +-
 data/ChangeLog                                     |   78 --
 docs/classes.dia                                   |  Bin 0 -> 3768 bytes
 platforms/ChangeLog                                |   24 -
 po/ChangeLog                                       |  661 ----------
 po/POTFILES.in                                     |  176 ++--
 sample_extensions/Calculation/CalculationSample.cs |    4 +-
 sample_extensions/Logic/PuzzleSample.cs            |    4 +-
 src/ArrayListIndicesRandom.cs                      |   60 -
 src/CairoContextEx.cs                              |  433 -------
 src/CalculationGames/CalculationArithmetical.cs    |  145 ---
 src/CalculationGames/CalculationAverage.cs         |  161 ---
 src/CalculationGames/CalculationCloserFraction.cs  |  160 ---
 src/CalculationGames/CalculationFractions.cs       |  212 ----
 src/CalculationGames/CalculationGreatestDivisor.cs |  232 ----
 src/CalculationGames/CalculationOperator.cs        |  144 ---
 src/CalculationGames/CalculationPrimes.cs          |  235 ----
 src/CalculationGames/CalculationProportions.cs     |  122 --
 src/CalculationGames/CalculationRatio.cs           |  135 --
 src/CalculationGames/CalculationTwoNumbers.cs      |  112 --
 src/ChangeLog                                      | 1282 --------------------
 src/{ => Clients/Classical}/AssemblyInfo.cs.in     |    0
 src/{ => Clients/Classical}/Defines.cs.in          |   18 +-
 src/Clients/Classical/Dialogs/AboutDialog.cs       |   85 ++
 src/Clients/Classical/Dialogs/CustomGameDialog.cs  |  212 ++++
 src/{ => Clients/Classical}/Dialogs/GtkDialog.cs   |   47 +-
 .../Classical/Dialogs/PlayerHistoryDialog.cs       |  298 +++++
 src/Clients/Classical/Dialogs/PreferencesDialog.cs |   88 ++
 .../Classical/GtkSynchronize.cs}                   |   71 +-
 src/Clients/Classical/Makefile.am                  |   67 +
 src/Clients/Classical/SimpleLabel.cs               |   96 ++
 src/{ => Clients/Classical}/gbrainy.addin.xml      |    0
 src/Clients/Classical/gbrainy.cs                   |  574 +++++++++
 src/{ => Clients/Classical}/gbrainy.glade          |    0
 .../Classical}/mono-addins-strings.xml             |    0
 src/ColorPalette.cs                                |  131 --
 src/Core/Libraries/CairoContextEx.cs               |  437 +++++++
 src/Core/Libraries/SVGImage.cs                     |  137 +++
 src/Core/Main/ArrayListIndicesRandom.cs            |   63 +
 src/Core/Main/ColorPalette.cs                      |  132 ++
 src/{ => Core/Main}/Defines.cs.in                  |   18 +-
 src/Core/Main/Game.cs                              |  345 ++++++
 src/Core/Main/GameManager.cs                       |  463 +++++++
 src/Core/Main/GameSession.cs                       |  360 ++++++
 src/Core/Main/GameTips.cs                          |   79 ++
 src/Core/Main/Memory.cs                            |  244 ++++
 src/Core/Main/PlayerHistory.cs                     |  126 ++
 src/Core/Main/Preferences.cs                       |  180 +++
 src/Core/Main/Verbal/Analogies.cs                  |  187 +++
 src/Core/Main/Verbal/AnalogiesFactory.cs           |  180 +++
 src/Core/Main/Verbal/AnalogiesMultipleOptions.cs   |  124 ++
 .../Main/Verbal/AnalogiesPairOfWordsCompare.cs     |  111 ++
 .../Main/Verbal/AnalogiesPairOfWordsOptions.cs     |  122 ++
 src/Core/Main/Verbal/AnalogiesQuestionAnswer.cs    |   70 ++
 .../Main/Verbal}/Analogy.cs                        |   66 +-
 src/Core/Platform/Unix.cs                          |  122 ++
 src/Core/Views/CountDownView.cs                    |  103 ++
 src/Core/Views/FinishView.cs                       |  169 +++
 src/{Defines.cs.in => Core/Views/IDrawRequest.cs}  |   24 +-
 .../Views/IDrawable.cs}                            |   19 +-
 src/Core/Views/ViewsControler.cs                   |   64 +
 src/Core/Views/WelcomeView.cs                      |   84 ++
 src/CountDown.cs                                   |   93 --
 src/Dialogs/AboutDialog.cs                         |   83 --
 src/Dialogs/CustomGameDialog.cs                    |  206 ----
 src/Dialogs/PlayerHistoryDialog.cs                 |  292 -----
 src/Dialogs/PreferencesDialog.cs                   |   84 --
 src/Game.cs                                        |  324 -----
 src/GameDrawingArea.cs                             |  311 -----
 src/GameManager.cs                                 |  474 --------
 src/GameSession.cs                                 |  337 -----
 src/GameTips.cs                                    |   60 -
 src/Games/Calculation/CalculationArithmetical.cs   |  149 +++
 src/Games/Calculation/CalculationAverage.cs        |  166 +++
 src/Games/Calculation/CalculationCloserFraction.cs |  164 +++
 src/Games/Calculation/CalculationFractions.cs      |  217 ++++
 .../Calculation/CalculationGreatestDivisor.cs      |  236 ++++
 src/Games/Calculation/CalculationOperator.cs       |  148 +++
 src/Games/Calculation/CalculationPrimes.cs         |  241 ++++
 src/Games/Calculation/CalculationProportions.cs    |  127 ++
 src/Games/Calculation/CalculationRatio.cs          |  140 +++
 src/Games/Calculation/CalculationTwoNumbers.cs     |  116 ++
 src/Games/GameList.cs                              |  127 ++
 src/Games/Logic/Puzzle3DCube.cs                    |  162 +++
 src/Games/Logic/PuzzleBalance.cs                   |  144 +++
 src/Games/Logic/PuzzleBuildTriangle.cs             |  233 ++++
 src/Games/Logic/PuzzleCirclesRectangle.cs          |  169 +++
 src/Games/Logic/PuzzleClocks.cs                    |  181 +++
 src/Games/Logic/PuzzleCountCircles.cs              |  106 ++
 src/Games/Logic/PuzzleCountSeries.cs               |   82 ++
 src/Games/Logic/PuzzleCounting.cs                  |  135 ++
 src/Games/Logic/PuzzleCoverPercentage.cs           |  174 +++
 src/Games/Logic/PuzzleCube.cs                      |   97 ++
 src/Games/Logic/PuzzleDivideCircle.cs              |  179 +++
 src/Games/Logic/PuzzleEquation.cs                  |   80 ++
 src/Games/Logic/PuzzleExtraCircle.cs               |  165 +++
 src/Games/Logic/PuzzleFigureLetter.cs              |  195 +++
 src/Games/Logic/PuzzleFigurePattern.cs             |  221 ++++
 src/Games/Logic/PuzzleFigures.cs                   |  169 +++
 src/Games/Logic/PuzzleFourSided.cs                 |  140 +++
 src/Games/Logic/PuzzleHandshakes.cs                |   76 ++
 src/Games/Logic/PuzzleLargerShape.cs               |  248 ++++
 src/Games/Logic/PuzzleLines.cs                     |  115 ++
 src/Games/Logic/PuzzleMatrixGroups.cs              |  140 +++
 src/Games/Logic/PuzzleMatrixNumbers.cs             |  158 +++
 src/Games/Logic/PuzzleMissingPiece.cs              |  163 +++
 src/Games/Logic/PuzzleMissingSlice.cs              |  202 +++
 src/Games/Logic/PuzzleMostInCommon.cs              |  301 +++++
 src/Games/Logic/PuzzleMoveFigure.cs                |  116 ++
 src/Games/Logic/PuzzleNextFigure.cs                |  157 +++
 src/Games/Logic/PuzzleNumericRelation.cs           |  133 ++
 src/Games/Logic/PuzzleNumericSequence.cs           |  107 ++
 src/Games/Logic/PuzzleOstracism.cs                 |   95 ++
 src/Games/Logic/PuzzlePencil.cs                    |  186 +++
 src/Games/Logic/PuzzlePeopleTable.cs               |  117 ++
 src/Games/Logic/PuzzlePercentage.cs                |  134 ++
 src/Games/Logic/PuzzleQuadrilaterals.cs            |  157 +++
 src/Games/Logic/PuzzleSquareDots.cs                |  198 +++
 src/Games/Logic/PuzzleSquareSheets.cs              |  109 ++
 src/Games/Logic/PuzzleSquares.cs                   |   96 ++
 src/Games/Logic/PuzzleSquaresAndLetters.cs         |  115 ++
 src/Games/Logic/PuzzleTetris.cs                    |  165 +++
 src/Games/Logic/PuzzleTimeNow.cs                   |   71 ++
 src/Games/Logic/PuzzleTriangles.cs                 |  123 ++
 src/Games/Logic/PuzzleTrianglesWithNumbers.cs      |  140 +++
 src/Games/Makefile.am                              |   98 ++
 src/Games/Memory/MemoryColouredFigures.cs          |  186 +++
 src/Games/Memory/MemoryColouredText.cs             |   96 ++
 src/Games/Memory/MemoryCountDots.cs                |  138 +++
 src/Games/Memory/MemoryFacts.cs                    |  176 +++
 src/Games/Memory/MemoryFigures.cs                  |  238 ++++
 src/Games/Memory/MemoryFiguresNumbers.cs           |  161 +++
 src/Games/Memory/MemoryIndications.cs              |  325 +++++
 src/Games/Memory/MemoryNumbers.cs                  |  181 +++
 src/Games/Memory/MemoryWords.cs                    |  169 +++
 src/Makefile.am                                    |  152 +---
 src/MemoryGames/Memory.cs                          |  207 ----
 src/MemoryGames/MemoryColouredFigures.cs           |  183 ---
 src/MemoryGames/MemoryColouredText.cs              |   91 --
 src/MemoryGames/MemoryCountDots.cs                 |  134 --
 src/MemoryGames/MemoryFacts.cs                     |  170 ---
 src/MemoryGames/MemoryFigures.cs                   |  234 ----
 src/MemoryGames/MemoryFiguresNumbers.cs            |  156 ---
 src/MemoryGames/MemoryIndications.cs               |  321 -----
 src/MemoryGames/MemoryNumbers.cs                   |  176 ---
 src/MemoryGames/MemoryWords.cs                     |  165 ---
 src/PlayerHistory.cs                               |  124 --
 src/Preferences.cs                                 |  179 ---
 src/PuzzleGames/Puzzle3DCube.cs                    |  157 ---
 src/PuzzleGames/PuzzleBalance.cs                   |  139 ---
 src/PuzzleGames/PuzzleBuildTriangle.cs             |  229 ----
 src/PuzzleGames/PuzzleCirclesRectangle.cs          |  163 ---
 src/PuzzleGames/PuzzleClocks.cs                    |  177 ---
 src/PuzzleGames/PuzzleCountCircles.cs              |  102 --
 src/PuzzleGames/PuzzleCountSeries.cs               |   78 --
 src/PuzzleGames/PuzzleCounting.cs                  |  129 --
 src/PuzzleGames/PuzzleCoverPercentage.cs           |  170 ---
 src/PuzzleGames/PuzzleCube.cs                      |   93 --
 src/PuzzleGames/PuzzleDivideCircle.cs              |  176 ---
 src/PuzzleGames/PuzzleEquation.cs                  |   74 --
 src/PuzzleGames/PuzzleExtraCircle.cs               |  160 ---
 src/PuzzleGames/PuzzleFigureLetter.cs              |  191 ---
 src/PuzzleGames/PuzzleFigurePattern.cs             |  217 ----
 src/PuzzleGames/PuzzleFigures.cs                   |  165 ---
 src/PuzzleGames/PuzzleFourSided.cs                 |  138 ---
 src/PuzzleGames/PuzzleHandshakes.cs                |   70 --
 src/PuzzleGames/PuzzleLargerShape.cs               |  242 ----
 src/PuzzleGames/PuzzleLines.cs                     |  111 --
 src/PuzzleGames/PuzzleMatrixGroups.cs              |  135 --
 src/PuzzleGames/PuzzleMatrixNumbers.cs             |  152 ---
 src/PuzzleGames/PuzzleMissingPiece.cs              |  159 ---
 src/PuzzleGames/PuzzleMissingSlice.cs              |  197 ---
 src/PuzzleGames/PuzzleMostInCommon.cs              |  296 -----
 src/PuzzleGames/PuzzleMoveFigure.cs                |  114 --
 src/PuzzleGames/PuzzleNextFigure.cs                |  153 ---
 src/PuzzleGames/PuzzleNumericRelation.cs           |  130 --
 src/PuzzleGames/PuzzleNumericSequence.cs           |  104 --
 src/PuzzleGames/PuzzleOstracism.cs                 |   91 --
 src/PuzzleGames/PuzzlePencil.cs                    |  182 ---
 src/PuzzleGames/PuzzlePeopleTable.cs               |  114 --
 src/PuzzleGames/PuzzlePercentage.cs                |  129 --
 src/PuzzleGames/PuzzleQuadrilaterals.cs            |  153 ---
 src/PuzzleGames/PuzzleSquareDots.cs                |  194 ---
 src/PuzzleGames/PuzzleSquareSheets.cs              |  105 --
 src/PuzzleGames/PuzzleSquares.cs                   |   93 --
 src/PuzzleGames/PuzzleSquaresAndLetters.cs         |  111 --
 src/PuzzleGames/PuzzleTetris.cs                    |  161 ---
 src/PuzzleGames/PuzzleTimeNow.cs                   |   65 -
 src/PuzzleGames/PuzzleTriangles.cs                 |  118 --
 src/PuzzleGames/PuzzleTrianglesWithNumbers.cs      |  137 ---
 src/SVGImage.cs                                    |  134 --
 src/SimpleLabel.cs                                 |   93 --
 src/Unix.cs                                        |  119 --
 src/VerbalAnalogies/Analogies.cs                   |  185 ---
 src/VerbalAnalogies/AnalogiesFactory.cs            |  178 ---
 src/VerbalAnalogies/AnalogiesMultipleOptions.cs    |  120 --
 src/VerbalAnalogies/AnalogiesPairOfWordsCompare.cs |  107 --
 src/VerbalAnalogies/AnalogiesPairOfWordsOptions.cs |  118 --
 src/VerbalAnalogies/AnalogiesQuestionAnswer.cs     |   67 -
 src/gbrainy.cs                                     |  551 ---------
 202 files changed, 15418 insertions(+), 16944 deletions(-)
---
diff --git a/autogen.sh b/autogen.sh
index 79872c2..9972011 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -8,7 +8,7 @@ ORIGDIR=`pwd`
 cd $srcdir
 PROJECT=gbrainy
 TEST_TYPE=-f
-FILE=src/gbrainy.glade
+FILE=src/Makefile.am
 
 DIE=0
 
diff --git a/configure.in b/configure.in
index b47b0a5..d902aed 100644
--- a/configure.in
+++ b/configure.in
@@ -1,5 +1,5 @@
 AC_INIT(gbrainy, 1.24)
-AC_CONFIG_SRCDIR(src/gbrainy.cs)
+AC_CONFIG_SRCDIR(src/Core/)
 
 AM_CONFIG_HEADER(config.h)
 
@@ -126,13 +126,18 @@ AC_SUBST(GNOME_ICON_THEME_PREFIX)
 
 
 AC_OUTPUT([
-src/Defines.cs
-src/AssemblyInfo.cs
+src/Core/Main/Defines.cs
+src/Clients/Classical/Defines.cs
+src/Clients/Classical/AssemblyInfo.cs
 Makefile
 po/Makefile.in
 src/Makefile
+src/Core/Makefile
+src/Games/Makefile
+src/Clients/Classical/Makefile
 data/Makefile
 ])
 
 echo "Support for older GTK:  ${enable_gtk_28}"
 echo "Mono-addins:            ${enable_addins_sharp}"
+
diff --git a/docs/classes.dia b/docs/classes.dia
new file mode 100644
index 0000000..d2c5c27
Binary files /dev/null and b/docs/classes.dia differ
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 0ccb96f..1343f01 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,83 +1,97 @@
 data/verbal_analogies.xml
 gbrainy.desktop.in
-src/CalculationGames/CalculationArithmetical.cs
-src/CalculationGames/CalculationAverage.cs
-src/CalculationGames/CalculationCloserFraction.cs
-src/CalculationGames/CalculationFractions.cs
-src/CalculationGames/CalculationGreatestDivisor.cs
-src/CalculationGames/CalculationOperator.cs
-src/CalculationGames/CalculationPrimes.cs
-src/CalculationGames/CalculationProportions.cs
-src/CalculationGames/CalculationRatio.cs
-src/CalculationGames/CalculationTwoNumbers.cs
-src/ColorPalette.cs
-src/CountDown.cs
-src/Dialogs/AboutDialog.cs
-src/Dialogs/CustomGameDialog.cs
-src/Dialogs/PlayerHistoryDialog.cs
-src/Game.cs
-src/GameDrawingArea.cs
-src/GameManager.cs
-src/GameSession.cs
-src/GameTips.cs
-src/gbrainy.cs
-src/gbrainy.glade
-src/MemoryGames/Memory.cs
-src/MemoryGames/MemoryColouredFigures.cs
-src/MemoryGames/MemoryColouredText.cs
-src/MemoryGames/MemoryCountDots.cs
-src/MemoryGames/MemoryFacts.cs
-src/MemoryGames/MemoryFigures.cs
-src/MemoryGames/MemoryFiguresNumbers.cs
-src/MemoryGames/MemoryIndications.cs
-src/MemoryGames/MemoryNumbers.cs
-src/MemoryGames/MemoryWords.cs
-src/mono-addins-strings.xml
-src/PuzzleGames/Puzzle3DCube.cs
-src/PuzzleGames/PuzzleBalance.cs
-src/PuzzleGames/PuzzleBuildTriangle.cs
-src/PuzzleGames/PuzzleCirclesRectangle.cs
-src/PuzzleGames/PuzzleClocks.cs
-src/PuzzleGames/PuzzleCountCircles.cs
-src/PuzzleGames/PuzzleCounting.cs
-src/PuzzleGames/PuzzleCountSeries.cs
-src/PuzzleGames/PuzzleCoverPercentage.cs
-src/PuzzleGames/PuzzleCube.cs
-src/PuzzleGames/PuzzleDivideCircle.cs
-src/PuzzleGames/PuzzleEquation.cs
-src/PuzzleGames/PuzzleExtraCircle.cs
-src/PuzzleGames/PuzzleFigureLetter.cs
-src/PuzzleGames/PuzzleFigurePattern.cs
-src/PuzzleGames/PuzzleFigures.cs
-src/PuzzleGames/PuzzleFourSided.cs
-src/PuzzleGames/PuzzleHandshakes.cs
-src/PuzzleGames/PuzzleLargerShape.cs
-src/PuzzleGames/PuzzleLines.cs
-src/PuzzleGames/PuzzleMatrixGroups.cs
-src/PuzzleGames/PuzzleMatrixNumbers.cs
-src/PuzzleGames/PuzzleMissingPiece.cs
-src/PuzzleGames/PuzzleMissingSlice.cs
-src/PuzzleGames/PuzzleMostInCommon.cs
-src/PuzzleGames/PuzzleMoveFigure.cs
-src/PuzzleGames/PuzzleNextFigure.cs
-src/PuzzleGames/PuzzleNumericRelation.cs
-src/PuzzleGames/PuzzleNumericSequence.cs
-src/PuzzleGames/PuzzleOstracism.cs
-src/PuzzleGames/PuzzlePencil.cs
-src/PuzzleGames/PuzzlePeopleTable.cs
-src/PuzzleGames/PuzzlePercentage.cs
-src/PuzzleGames/PuzzleQuadrilaterals.cs
-src/PuzzleGames/PuzzleSquareDots.cs
-src/PuzzleGames/PuzzleSquaresAndLetters.cs
-src/PuzzleGames/PuzzleSquares.cs
-src/PuzzleGames/PuzzleSquareSheets.cs
-src/PuzzleGames/PuzzleTetris.cs
-src/PuzzleGames/PuzzleTimeNow.cs
-src/PuzzleGames/PuzzleTriangles.cs
-src/PuzzleGames/PuzzleTrianglesWithNumbers.cs
-src/VerbalAnalogies/Analogies.cs
-src/VerbalAnalogies/AnalogiesFactory.cs
-src/VerbalAnalogies/AnalogiesMultipleOptions.cs
-src/VerbalAnalogies/AnalogiesPairOfWordsCompare.cs
-src/VerbalAnalogies/AnalogiesPairOfWordsOptions.cs
-src/VerbalAnalogies/AnalogiesQuestionAnswer.cs
+src/Core/Views/CountDownView.cs
+src/Core/Views/FinishView.cs
+src/Core/Views/IDrawable.cs
+src/Core/Views/IDrawRequest.cs
+src/Core/Views/ViewsControler.cs
+src/Core/Views/WelcomeView.cs
+src/Core/Libraries/SVGImage.cs
+src/Core/Libraries/CairoContextEx.cs
+src/Core/Platform/Unix.cs
+src/Core/Main/ArrayListIndicesRandom.cs
+src/Core/Main/ColorPalette.cs
+src/Core/Main/Game.cs
+src/Core/Main/GameManager.cs
+src/Core/Main/GameSession.cs
+src/Core/Main/GameTips.cs
+src/Core/Main/PlayerHistory.cs
+src/Core/Main/Preferences.cs
+src/Core/Main/Memory.cs
+src/Core/Main/Verbal/Analogies.cs
+src/Core/Main/Verbal/Analogy.cs
+src/Core/Main/Verbal/AnalogiesMultipleOptions.cs
+src/Core/Main/Verbal/AnalogiesPairOfWordsCompare.cs
+src/Core/Main/Verbal/AnalogiesPairOfWordsOptions.cs
+src/Core/Main/Verbal/AnalogiesQuestionAnswer.cs
+src/Core/Main/Verbal/AnalogiesFactory.cs
+src/Clients/Classical/gbrainy.cs
+src/Clients/Classical/Dialogs/AboutDialog.cs
+src/Clients/Classical/Dialogs/CustomGameDialog.cs
+src/Clients/Classical/Dialogs/GtkDialog.cs
+src/Clients/Classical/Dialogs/PlayerHistoryDialog.cs
+src/Clients/Classical/Dialogs/PreferencesDialog.cs
+src/Games/Logic/Puzzle3DCube.cs
+src/Games/Logic/PuzzleBalance.cs
+src/Games/Logic/PuzzleBuildTriangle.cs
+src/Games/Logic/PuzzleCirclesRectangle.cs
+src/Games/Logic/PuzzleClocks.cs
+src/Games/Logic/PuzzleCountCircles.cs
+src/Games/Logic/PuzzleCounting.cs
+src/Games/Logic/PuzzleCountSeries.cs
+src/Games/Logic/PuzzleCoverPercentage.cs
+src/Games/Logic/PuzzleCube.cs
+src/Games/Logic/PuzzleDivideCircle.cs
+src/Games/Logic/PuzzleEquation.cs
+src/Games/Logic/PuzzleExtraCircle.cs
+src/Games/Logic/PuzzleFigureLetter.cs
+src/Games/Logic/PuzzleFigurePattern.cs
+src/Games/Logic/PuzzleFigures.cs
+src/Games/Logic/PuzzleFourSided.cs
+src/Games/Logic/PuzzleHandshakes.cs
+src/Games/Logic/PuzzleLargerShape.cs
+src/Games/Logic/PuzzleLines.cs
+src/Games/Logic/PuzzleMatrixGroups.cs
+src/Games/Logic/PuzzleMatrixNumbers.cs
+src/Games/Logic/PuzzleMissingPiece.cs
+src/Games/Logic/PuzzleMissingSlice.cs
+src/Games/Logic/PuzzleMostInCommon.cs
+src/Games/Logic/PuzzleMoveFigure.cs
+src/Games/Logic/PuzzleNextFigure.cs
+src/Games/Logic/PuzzleNumericRelation.cs
+src/Games/Logic/PuzzleNumericSequence.cs
+src/Games/Logic/PuzzleOstracism.cs
+src/Games/Logic/PuzzlePencil.cs
+src/Games/Logic/PuzzlePeopleTable.cs
+src/Games/Logic/PuzzlePercentage.cs
+src/Games/Logic/PuzzleQuadrilaterals.cs
+src/Games/Logic/PuzzleSquareDots.cs
+src/Games/Logic/PuzzleSquaresAndLetters.cs
+src/Games/Logic/PuzzleSquares.cs
+src/Games/Logic/PuzzleSquareSheets.cs
+src/Games/Logic/PuzzleTetris.cs
+src/Games/Logic/PuzzleTimeNow.cs
+src/Games/Logic/PuzzleTriangles.cs
+src/Games/Logic/PuzzleTrianglesWithNumbers.cs
+src/Games/Memory/MemoryColouredFigures.cs
+src/Games/Memory/MemoryColouredText.cs
+src/Games/Memory/MemoryCountDots.cs
+src/Games/Memory/MemoryFacts.cs
+src/Games/Memory/MemoryFigures.cs
+src/Games/Memory/MemoryFiguresNumbers.cs
+src/Games/Memory/MemoryIndications.cs
+src/Games/Memory/MemoryNumbers.cs
+src/Games/Memory/MemoryWords.cs
+src/Games/Calculation/CalculationArithmetical.cs
+src/Games/Calculation/CalculationAverage.cs
+src/Games/Calculation/CalculationCloserFraction.cs
+src/Games/Calculation/CalculationFractions.cs
+src/Games/Calculation/CalculationGreatestDivisor.cs
+src/Games/Calculation/CalculationOperator.cs
+src/Games/Calculation/CalculationPrimes.cs
+src/Games/Calculation/CalculationProportions.cs
+src/Games/Calculation/CalculationRatio.cs
+src/Games/Calculation/CalculationTwoNumbers.cs
+src/Games/GameList.cs
+src/Clients/Classical/gbrainy.glade
+src/Clients/Classical/mono-addins-strings.xml
diff --git a/sample_extensions/Calculation/CalculationSample.cs b/sample_extensions/Calculation/CalculationSample.cs
index 573be6b..db71973 100644
--- a/sample_extensions/Calculation/CalculationSample.cs
+++ b/sample_extensions/Calculation/CalculationSample.cs
@@ -62,11 +62,11 @@ public class CalculationSample : Game
 		right_answer = String.Format ("{0} and {1}", number_a, number_b);
 	}
 
-	public override void Draw (CairoContextEx gr, int area_width, int area_height)
+	public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
 	{	
 		double x = DrawAreaX + 0.1;
 
-		base.Draw (gr, area_width, area_height);
+		base.Draw (gr, area_width, area_height, rtl);
 
 		gr.SetPangoLargeFontSize ();
 
diff --git a/sample_extensions/Logic/PuzzleSample.cs b/sample_extensions/Logic/PuzzleSample.cs
index 06eb21c..c8e1947 100644
--- a/sample_extensions/Logic/PuzzleSample.cs
+++ b/sample_extensions/Logic/PuzzleSample.cs
@@ -36,9 +36,9 @@ public class PuzzleSample : Game
 		right_answer = "8";
 	}
 
-	public override void Draw (CairoContextEx gr, int area_width, int area_height)
+	public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
 	{
-		base.Draw (gr, area_width, area_height);
+		base.Draw (gr, area_width, area_height, rtl);
 
 		gr.Color = new Color (0.4, 0.4, 0.4);
 		gr.DrawTextCentered (0.5, DrawAreaY, "This is an extension sample");
diff --git a/src/AssemblyInfo.cs.in b/src/Clients/Classical/AssemblyInfo.cs.in
similarity index 100%
copy from src/AssemblyInfo.cs.in
copy to src/Clients/Classical/AssemblyInfo.cs.in
diff --git a/src/Defines.cs.in b/src/Clients/Classical/Defines.cs.in
similarity index 68%
copy from src/Defines.cs.in
copy to src/Clients/Classical/Defines.cs.in
index a35eac1..e04324b 100644
--- a/src/Defines.cs.in
+++ b/src/Clients/Classical/Defines.cs.in
@@ -19,14 +19,14 @@
 
 using System;
 
-public class Defines
+namespace gbrainy.Clients.Classical
 {
-	public const string VERSION = "@VERSION@";
-	public const string GNOME_LOCALE_DIR = "@prefix@/share/locale";
-	public const string DATA_DIR = "@prefix@/share/games/gbrainy/";
-	public const string VERBAL_ANALOGIES = "verbal_analogies.xml";
-	public const string CONFIG_DIR = "gbrainy"; // like .config/gbrainy
+	public class Defines
+	{
+		public const string VERSION = "@VERSION@";
+		public const string GNOME_LOCALE_DIR = "@prefix@/share/locale";
+		public const string DATA_DIR = "@prefix@/share/games/gbrainy/";
+		public const string VERBAL_ANALOGIES = "verbal_analogies.xml";
+		public const string CONFIG_DIR = "gbrainy"; // like .config/gbrainy
+	}
 }
-
-
-
diff --git a/src/Clients/Classical/Dialogs/AboutDialog.cs b/src/Clients/Classical/Dialogs/AboutDialog.cs
new file mode 100644
index 0000000..184b6b0
--- /dev/null
+++ b/src/Clients/Classical/Dialogs/AboutDialog.cs
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2008-2009 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 Gtk;
+using Gdk;
+using Mono.Unix;
+using System.Text;
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+namespace gbrainy.Clients.Classical
+{
+	public class AboutDialog : Gtk.AboutDialog
+	{
+		public AboutDialog () : base ()
+		{
+			StringBuilder license = new StringBuilder (256);
+			string [] authors = new string [] {
+				"Jordi Mas i Hernandez <jmas softcatala org>",
+			};
+
+			string [] artists = new string [] {
+				"Anna Barberà Maré",
+				"Carme Cabal Sardà",
+				"Jordi Mas i Hernandez",
+				"Openclipart.org"
+			};
+
+			// Translators: Replace by the name of the people that translated the application
+			string translators = Catalog.GetString ("translator-credits");
+
+			if (translators == "translator-credits")
+				translators = null;
+
+			license.Append (Catalog.GetString ("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.\n\n"));
+			license.Append (Catalog.GetString ("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.\n\n"));
+			license.Append (Catalog.GetString ("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."));
+
+			Name = "gbrainy";
+			Version = Defines.VERSION;
+			Authors = authors;
+			Documenters = null;
+			Logo = LoadFromAssembly ("gbrainy.svg");
+
+			Copyright = "(c) 2007-2009 Jordi Mas i Hernandez\n";
+			Copyright += Catalog.GetString ("Based on ideas by Terry Stickels, MENSA books and Jordi Mas.");
+
+			Comments = Catalog.GetString ("A brain teaser game for fun and to keep your brain trained.");
+			Website = "http://live.gnome.org/gbrainy";;
+			WebsiteLabel = Catalog.GetString ("gbrainy web site");
+			TranslatorCredits = translators;
+			Artists = artists;
+			IconName = null;
+			License = license.ToString ();
+			WrapLicense = true;
+			Response += delegate (object o, Gtk.ResponseArgs e) {Destroy ();};
+		}
+
+		static Pixbuf LoadFromAssembly (string resource)
+		{
+			try {
+				return new Pixbuf (System.Reflection.Assembly.GetEntryAssembly (), resource);
+			} catch {
+				return null;
+			}
+		}
+	}
+}
diff --git a/src/Clients/Classical/Dialogs/CustomGameDialog.cs b/src/Clients/Classical/Dialogs/CustomGameDialog.cs
new file mode 100644
index 0000000..24b62e2
--- /dev/null
+++ b/src/Clients/Classical/Dialogs/CustomGameDialog.cs
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2007 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 Gtk;
+using Mono.Unix;
+using System.Collections;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Clients.Classical
+{
+	public class CustomGameDialog : GtkDialog
+	{
+		static ListStore games_store;
+		[Glade.Widget] Gtk.TreeView treeview;
+		[Glade.Widget] Box preview_vbox;
+		[Glade.Widget] Label preview_question;
+		CairoPreview drawing_area;
+		GameManager manager;
+		int ngames, npos;
+		Type [] custom_games;
+
+		const int COL_ENABLED = 2;
+		const int COL_OBJECT = 3;
+
+		public CustomGameDialog (GameManager manager) : base ("customgame")
+		{
+			Game game;
+			Type[] games;
+			GameManager gm;
+
+			this.manager = manager;
+			gm = new GameManager ();
+			gm.GameType = GameSession.Types.AllGames;
+			games = gm.CustomGames;
+
+			drawing_area = new CairoPreview ();
+			preview_vbox.Add (drawing_area);
+			drawing_area.Visible = true;
+
+			// Define columns
+			TreeViewColumn name_column = new TreeViewColumn (Catalog.GetString("Game Name"), 
+				new CellRendererText(), "text", 0);
+
+			name_column.Expand = true;
+			treeview.AppendColumn (name_column);
+
+			TreeViewColumn type_column = new TreeViewColumn (Catalog.GetString("Type"), 
+				new CellRendererText(), "text", 1);
+
+			type_column.Expand = true;
+			treeview.AppendColumn (type_column);
+
+			CellRendererToggle toggle_cell = new CellRendererToggle();
+			TreeViewColumn toggle_column = new TreeViewColumn(Catalog.GetString("Enabled"), 
+				toggle_cell, "active", COL_ENABLED);
+			toggle_cell.Activatable = true;
+			toggle_cell.Toggled += OnActiveToggled;
+			toggle_column.Expand = false;
+			treeview.CursorChanged += OnCursorChanged;
+			treeview.AppendColumn (toggle_column);
+
+			if (games_store == null) {
+				games_store = new ListStore (typeof(string), typeof (string), typeof(bool), typeof (Game));
+					 
+				// Data
+				string type;
+				for (int i = 0; i < games.Length; i++)
+				{	
+					game =  (Game) Activator.CreateInstance (games [i], true);
+					type = Game.GetGameTypeDescription (game.Type);
+					games_store.AppendValues (game.Name, type, true, game);
+				}
+			}
+
+			treeview.Model = games_store;
+			game =  (Game) Activator.CreateInstance (games [0], true);
+			game.Initialize ();
+			drawing_area.puzzle = game;
+			preview_question.Markup = game.Question;
+			treeview.ColumnsAutosize ();
+		}
+
+		public int NumOfGames {
+			get { return ngames;}
+		}
+
+		private void OnCursorChanged (object o, EventArgs args) 
+		{
+			TreeIter iter;
+		    
+		    	if (!treeview.Selection.GetSelected (out iter)) {
+				return;
+		    	}
+
+			Game game = games_store.GetValue (iter, COL_OBJECT) as Game;
+			game.Initialize ();
+			preview_question.Markup = game.Question;
+			drawing_area.puzzle = game;
+			drawing_area.QueueDraw ();
+		}
+
+		private void OnActiveToggled (object o, ToggledArgs args) 
+		{
+			TreeIter iter;
+
+			if (!games_store.GetIter (out iter, new TreePath (args.Path)))
+				return;
+
+			bool enabled = !(bool) games_store.GetValue (iter, COL_ENABLED);
+			games_store.SetValue (iter, COL_ENABLED, enabled);
+		}
+
+		void OnSelectAll (object sender, EventArgs args)
+		{
+			games_store.Foreach (delegate (TreeModel model, TreePath path, TreeIter iter)  {
+				games_store.SetValue (iter, COL_ENABLED, true);
+				return false;
+			});
+		}
+
+		void OnUnSelectAll (object sender, EventArgs args)
+		{
+			games_store.Foreach (delegate (TreeModel model, TreePath path, TreeIter iter)  {
+				games_store.SetValue (iter, COL_ENABLED, false);
+				return false;
+			});
+		}
+
+		void OnOK (object sender, EventArgs args)
+		{
+			ngames = 0;
+			npos = 0;
+
+			games_store.Foreach (delegate (TreeModel model, TreePath path, TreeIter iter)  {
+				if ((bool) games_store.GetValue (iter, COL_ENABLED) == true)
+					ngames++;
+
+				return false;
+			});
+
+			if (ngames == 0)
+				return;
+
+			custom_games = new Type [ngames];
+			games_store.Foreach (delegate (TreeModel model, TreePath path, TreeIter iter)  {
+				Game game = games_store.GetValue (iter, COL_OBJECT) as Game;
+				bool enabled = (bool) games_store.GetValue (iter, COL_ENABLED);
+
+				if (enabled == true) {
+					custom_games[npos] = game.GetType ();
+					npos++;
+				}
+				return false;
+			});
+
+	
+			manager.CustomGames = custom_games;
+		}
+
+		public class CairoPreview : DrawingArea 
+		{
+			public Game puzzle;
+
+			protected override bool OnExposeEvent (Gdk.EventExpose args)
+			{
+				if(!IsRealized)
+					return false;
+
+				int w, h, nw, nh;
+				double x = 0, y = 0;
+				Cairo.Context cc = Gdk.CairoHelper.Create (args.Window);
+				CairoContextEx cr = new CairoContextEx (cc.Handle, this);
+				args.Window.GetSize (out w, out h);
+
+				nh = nw = Math.Min (w, h);
+
+				if (nw < w) {
+					x = (w - nw) / 2;
+				}
+
+				if (nh < h) {
+					y = (h - nh) / 2;
+				}
+
+				cr.Translate (x, y);
+				puzzle.DrawPreview (cr, nw, nh, Direction == Gtk.TextDirection.Rtl);
+				((IDisposable)cc).Dispose();
+				((IDisposable)cr).Dispose();
+	   			return base.OnExposeEvent(args);
+			}
+		}	
+	}
+}
diff --git a/src/Dialogs/GtkDialog.cs b/src/Clients/Classical/Dialogs/GtkDialog.cs
similarity index 59%
rename from src/Dialogs/GtkDialog.cs
rename to src/Clients/Classical/Dialogs/GtkDialog.cs
index eb2dddb..c425a23 100644
--- a/src/Dialogs/GtkDialog.cs
+++ b/src/Clients/Classical/Dialogs/GtkDialog.cs
@@ -22,32 +22,35 @@ using Glade;
 using Gtk;
 using Mono.Unix;
 
-public class GtkDialog
+namespace gbrainy.Clients.Classical
 {
-	public Glade.XML xml;
-	public Gtk.Dialog dialog;
-	public string dialog_name;
-
-	public GtkDialog (string dialog_name)
+	public class GtkDialog
 	{
-		this.dialog_name = dialog_name;
-		xml = new Glade.XML (null, "gbrainy.glade", dialog_name, "gbrainy");
-		xml.Autoconnect (this);
-		Dialog.IconName = "gbrainy";
-		dialog = null;
-	}
+		public Glade.XML xml;
+		public Gtk.Dialog dialog;
+		public string dialog_name;
 
-	public ResponseType Run ()
-	{
-		return (ResponseType) Dialog.Run ();
-	}
+		public GtkDialog (string dialog_name)
+		{
+			this.dialog_name = dialog_name;
+			xml = new Glade.XML (null, "gbrainy.glade", dialog_name, "gbrainy");
+			xml.Autoconnect (this);
+			Dialog.IconName = "gbrainy";
+			dialog = null;
+		}
+
+		public ResponseType Run ()
+		{
+			return (ResponseType) Dialog.Run ();
+		}
 
-	public Gtk.Dialog Dialog {
-		get {
-			if (dialog == null)
-				dialog = (Gtk.Dialog) xml.GetWidget (dialog_name);
-				
-			return dialog;
+		public Gtk.Dialog Dialog {
+			get {
+				if (dialog == null)
+					dialog = (Gtk.Dialog) xml.GetWidget (dialog_name);
+			
+				return dialog;
+			}
 		}
 	}
 }
diff --git a/src/Clients/Classical/Dialogs/PlayerHistoryDialog.cs b/src/Clients/Classical/Dialogs/PlayerHistoryDialog.cs
new file mode 100644
index 0000000..0b4b732
--- /dev/null
+++ b/src/Clients/Classical/Dialogs/PlayerHistoryDialog.cs
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2008-2009 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 Gtk;
+using Mono.Unix;
+using System.Collections;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Clients.Classical
+{
+	public class PlayerHistoryDialog : GtkDialog
+	{
+		[Glade.Widget] Box history_preview;
+		[Glade.Widget] Label label_playerhistory;
+		[Glade.Widget] Gtk.CheckButton checkbutton_total;
+		[Glade.Widget] Gtk.CheckButton checkbutton_memory;
+		[Glade.Widget] Gtk.CheckButton checkbutton_logic;
+		[Glade.Widget] Gtk.CheckButton checkbutton_calculation;
+		[Glade.Widget] Gtk.CheckButton checkbutton_verbal;
+
+		CairoPreview drawing_area;
+
+		public PlayerHistoryDialog () : base ("playerhistory")
+		{
+			string label;
+
+			label = Catalog.GetString ("The graphic below shows the player's game score evolution. ");
+			label +=  Catalog.GetPluralString ("You need more than one game recorded to see the score evolution.",
+				"It is built using the results of {0} last recorded games.", 
+				GtkClient.history.Games.Count < 2 ? 1 : 2);
+
+			label_playerhistory.Text = String.Format (label, GtkClient.history.Games.Count);
+
+			drawing_area = new CairoPreview (this);
+			history_preview.Add (drawing_area);
+			drawing_area.Visible = true;
+
+	 		checkbutton_total.Label = Catalog.GetString ("Total");
+	 		checkbutton_logic.Label = Game.GetGameTypeDescription (Game.Types.LogicPuzzle);
+	 		checkbutton_calculation.Label = Game.GetGameTypeDescription (Game.Types.MathTrainer);
+	 		checkbutton_memory.Label = Game.GetGameTypeDescription (Game.Types.MemoryTrainer);
+	 		checkbutton_verbal.Label = Game.GetGameTypeDescription (Game.Types.VerbalAnalogy);
+
+	 		checkbutton_total.Active = checkbutton_memory.Active = checkbutton_logic.Active = checkbutton_calculation.Active = checkbutton_verbal.Active = true;
+		}
+
+		void OnTotalToggled (object sender, EventArgs args)
+		{
+			drawing_area.QueueDraw ();
+		}
+
+		void OnLogicToggled (object sender, EventArgs args)
+		{
+			drawing_area.QueueDraw ();
+		}
+
+		void OnMemoryToggled (object sender, EventArgs args)
+		{
+			drawing_area.QueueDraw ();
+		}
+
+		void OnCalculationToggled (object sender, EventArgs args)
+		{
+			drawing_area.QueueDraw ();
+		}
+
+		public class CairoPreview : DrawingArea 
+		{
+			const double area_h = 0.8, area_w = 0.9, point_size = 0.005 * 1.25;
+			Cairo.Color math_color = new Cairo.Color (0.56, 0.71, 0.20);    // 8fb735
+			Cairo.Color logic_color = new Cairo.Color (0.81, 0.54, 0.23);   // d18c3b
+			Cairo.Color memory_color = new Cairo.Color (0.73, 0.22, 0.51);  // bb3a84
+			Cairo.Color verbal_color = new Cairo.Color (0.68, 0.16, 0.17);  // af2b2c
+			Cairo.Color total_color = new Cairo.Color (0, 0, 0.6);
+			Cairo.Color text_color = new Cairo.Color (0, 0, 0);
+			Cairo.Color axis_color = new Cairo.Color (0.15, 0.15, 0.15);
+			PlayerHistoryDialog dlg;
+
+			public CairoPreview (PlayerHistoryDialog dlg)
+			{
+				this.dlg = dlg;
+			}
+
+			private void DrawLegend (CairoContextEx cr, double x, double y)
+			{
+				const double line_size = 0.05, offset_x = 0.01, second_row = 0.05, space_hor = 0.4;
+				double old_width;
+
+				old_width = cr.LineWidth;
+				cr.LineWidth = 0.01;
+		
+				cr.Color = total_color;
+				cr.MoveTo (x, y);
+				cr.LineTo (x + line_size, y);
+				cr.Stroke ();
+				cr.Color = text_color;
+				cr.MoveTo (x + line_size + offset_x, y - 0.01);
+				cr.ShowPangoText (Catalog.GetString ("Total"));
+				cr.Stroke ();
+
+				cr.Color = logic_color;
+				cr.MoveTo (x, y + second_row);
+				cr.LineTo (x + line_size, y + second_row);
+				cr.Stroke ();
+				cr.Color = text_color;
+				cr.MoveTo (x + line_size + offset_x, y - 0.01 + second_row);
+				cr.ShowPangoText (Game.GetGameTypeDescription (Game.Types.LogicPuzzle));
+				cr.Stroke ();
+
+				x += space_hor;
+				cr.Color = memory_color;
+				cr.MoveTo (x, y);
+				cr.LineTo (x + line_size, y);
+				cr.Stroke ();
+				cr.Color = text_color;
+				cr.MoveTo (x + line_size + offset_x, y - 0.01);
+				cr.ShowPangoText (Game.GetGameTypeDescription (Game.Types.MemoryTrainer));
+				cr.Stroke ();
+
+				cr.Color = math_color;
+				cr.MoveTo (x, y + second_row);
+				cr.LineTo (x + line_size, y + second_row);
+				cr.Stroke ();
+				cr.Color = text_color;
+				cr.MoveTo (x + line_size + offset_x, y - 0.01 + second_row);
+				cr.ShowPangoText (Game.GetGameTypeDescription (Game.Types.MathTrainer));
+				cr.Stroke ();
+
+				x += space_hor;
+				cr.Color = verbal_color;
+				cr.MoveTo (x, y);
+				cr.LineTo (x + line_size, y);
+				cr.Stroke ();
+				cr.Color = text_color;
+				cr.MoveTo (x + line_size + offset_x, y - 0.01);
+				cr.ShowPangoText (Game.GetGameTypeDescription (Game.Types.VerbalAnalogy));
+				cr.Stroke ();
+
+				cr.LineWidth = old_width;
+			}
+
+			private void DrawLines (CairoContextEx cr, double x, double y)
+			{
+				double px, py;
+				PlayerHistory history = GtkClient.history;
+				double ratio;
+
+				if (history.Games.Count == 0)
+					return;
+
+				ratio = area_w / (history.Games.Count - 1);
+		
+				if (dlg.checkbutton_logic.Active) { // Logic
+					cr.Color = logic_color;
+					cr.MoveTo (x, area_h - (area_h * history.Games[0].logic_score / 100));
+					for (int i = 1; i < history.Games.Count; i++)
+					{
+						px = x + (ratio * i);
+						py = y + area_h - (area_h * history.Games[i].logic_score / 100);
+						cr.LineTo (px, py);
+					}
+					cr.Stroke ();
+				}
+
+				if (dlg.checkbutton_calculation.Active) { // Math
+					cr.Color = math_color;
+					cr.MoveTo (x, area_h - (area_h * history.Games[0].math_score / 100));
+					for (int i = 1; i < history.Games.Count; i++)
+					{
+						px = x + (ratio * i);
+						py = y + area_h - (area_h * history.Games[i].math_score / 100);
+						cr.LineTo (px, py);
+					}
+					cr.Stroke ();
+				}
+
+				if (dlg.checkbutton_memory.Active) { // Memory
+					cr.Color = memory_color;
+					cr.MoveTo (x, area_h - (area_h * history.Games[0].memory_score / 100));
+					for (int i = 1; i < history.Games.Count; i++)
+					{
+						px = x + (ratio * i);
+						py = y + area_h - (area_h * history.Games[i].memory_score / 100);
+						cr.LineTo (px, py);
+					}
+					cr.Stroke ();
+				}
+
+				if (dlg.checkbutton_verbal.Active) { // Verbal
+					cr.Color = verbal_color;
+					cr.MoveTo (x, area_h - (area_h * history.Games[0].verbal_score / 100));
+					for (int i = 1; i < history.Games.Count; i++)
+					{
+						px = x + (ratio * i);
+						py = y + area_h - (area_h * history.Games[i].verbal_score / 100);
+						cr.LineTo (px, py);
+					}
+					cr.Stroke ();
+				}
+
+				if (dlg.checkbutton_total.Active) { // Total			
+					cr.Color = total_color;
+					cr.MoveTo (x, area_h - (area_h * history.Games[0].total_score / 100));
+					for (int i = 1; i < history.Games.Count; i++)
+					{
+						px = x + (ratio * i);
+						py = y + area_h - (area_h * history.Games[i].total_score / 100);
+						cr.LineTo (px, py);
+					}
+					cr.Stroke ();
+				}
+			}
+
+			private void DrawGrid (CairoContextEx cr, double x, double y)
+			{
+				// Draw Axis
+				cr.MoveTo (x, y);
+				cr.LineTo (x, y + area_h);
+				cr.LineTo (x + area_w, y + area_h);
+				cr.Stroke ();
+
+				cr.Color = new Cairo.Color (0.8, 0.8, 0.8);
+				cr.LineWidth = 0.001;
+				for (double line_y = y; line_y < area_h + y; line_y += area_h / 10) {
+					cr.MoveTo (x, line_y);
+					cr.LineTo (x + area_w, line_y);
+					cr.Stroke ();
+				}
+			}		
+	
+			protected override bool OnExposeEvent (Gdk.EventExpose args)
+			{
+				if(!IsRealized)
+					return false;
+
+				int w, h, nw, nh;
+				double x = 0, y = 0;
+
+				Cairo.Context cc = Gdk.CairoHelper.Create (args.Window);
+				CairoContextEx cr = new CairoContextEx (cc.Handle, this);
+				args.Window.GetSize (out w, out h);
+
+				nh = nw = Math.Min (w, h);
+
+				if (nw < w) {
+					x = (w - nw) / 2;
+				}
+
+				if (nh < h) {
+					y = (h - nh) / 2;
+				}
+	
+				cr.Translate (x, y);
+				cr.Scale (nw, nh);
+
+				// Background
+				cr.Color = new Cairo.Color (1, 1, 1);
+				cr.Paint ();
+				cr.Stroke ();
+
+				x = 0.05; 
+				y = 0.05;
+				cr.LineWidth = point_size;
+				cr.Color = axis_color;
+
+				cr.Rectangle (x, y, area_w, area_h);
+				cr.Clip ();
+				DrawLines (cr, x, y);
+				cr.ResetClip ();
+				DrawLegend (cr, x, y + area_h + 0.05);
+				DrawGrid (cr, x, y);
+
+				((IDisposable)cc).Dispose();
+				((IDisposable)cr).Dispose();
+	   			return base.OnExposeEvent(args);
+			}
+		}	
+	}
+}
diff --git a/src/Clients/Classical/Dialogs/PreferencesDialog.cs b/src/Clients/Classical/Dialogs/PreferencesDialog.cs
new file mode 100644
index 0000000..8e1ca2a
--- /dev/null
+++ b/src/Clients/Classical/Dialogs/PreferencesDialog.cs
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2007-2008 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 Gtk;
+using Mono.Unix;
+using System.Collections;
+
+using gbrainy.Core.Main;
+
+namespace gbrainy.Clients.Classical
+{
+	public class PreferencesDialog : GtkDialog
+	{
+		[Glade.Widget] Gtk.SpinButton prefspinbutton;
+		[Glade.Widget] Gtk.SpinButton maxstoredspinbutton;
+		[Glade.Widget] Gtk.SpinButton minplayedspinbutton;
+		[Glade.Widget] Gtk.CheckButton prefcheckbutton;
+		[Glade.Widget] Gtk.RadioButton rb_easy;
+		[Glade.Widget] Gtk.RadioButton rb_medium;
+		[Glade.Widget] Gtk.RadioButton rb_master;
+
+		public PreferencesDialog () : base ("preferences")
+		{
+			prefspinbutton.Value = Preferences.GetIntValue (Preferences.MemQuestionTimeKey);
+			prefcheckbutton.Active = Preferences.GetBoolValue (Preferences.MemQuestionWarnKey);
+			maxstoredspinbutton.Value = Preferences.GetIntValue (Preferences.MaxStoredGamesKey);
+			minplayedspinbutton.Value = Preferences.GetIntValue (Preferences.MinPlayedGamesKey);
+		
+			switch ((Game.Difficulty) Preferences.GetIntValue (Preferences.DifficultyKey)) {
+			case Game.Difficulty.Easy:
+				rb_easy.Active = rb_easy.HasFocus = true;
+				break;		
+			case Game.Difficulty.Medium:
+				rb_medium.Active = rb_medium.HasFocus = true;
+				break;
+			case Game.Difficulty.Master:
+				rb_master.Active = rb_master.HasFocus = true;
+				break;
+			}
+
+		}
+
+		private Game.Difficulty Difficulty {
+			get {
+				if (rb_easy.Active)
+					return Game.Difficulty.Easy;
+
+				if (rb_master.Active)
+					return Game.Difficulty.Master;
+
+				return Game.Difficulty.Medium;			
+			}
+		}
+
+
+		private void OnCleanHistory (object sender, EventArgs args)
+		{
+			GtkClient.history.Clean ();
+		}
+
+		private void OnOK (object sender, EventArgs args)
+		{
+			Preferences.SetIntValue (Preferences.MemQuestionTimeKey, (int) prefspinbutton.Value);
+			Preferences.SetBoolValue (Preferences.MemQuestionWarnKey, prefcheckbutton.Active);
+			Preferences.SetIntValue (Preferences.DifficultyKey, (int) Difficulty);
+			Preferences.SetIntValue (Preferences.MaxStoredGamesKey, (int) maxstoredspinbutton.Value);
+			Preferences.SetIntValue (Preferences.MinPlayedGamesKey, (int) minplayedspinbutton.Value);
+			Preferences.Save ();
+		}
+	}
+}
diff --git a/src/VerbalAnalogies/Analogy.cs b/src/Clients/Classical/GtkSynchronize.cs
similarity index 50%
copy from src/VerbalAnalogies/Analogy.cs
copy to src/Clients/Classical/GtkSynchronize.cs
index 7629e17..3ead549 100644
--- a/src/VerbalAnalogies/Analogy.cs
+++ b/src/Clients/Classical/GtkSynchronize.cs
@@ -18,55 +18,42 @@
  */
 
 using System;
-using System.Xml;
-using System.IO;
-using System.Collections.Generic;
-
-using Cairo;
-using Mono.Unix;
 using Gtk;
 
-public class Analogy
+namespace gbrainy.Clients.Classical
 {
-	public enum Type
+	public class GtkSynchronize :System.ComponentModel.ISynchronizeInvoke
 	{
-		QuestionAnswer = 0,
-		MultipleOptions,
-		PairOfWordsOptions,
-		PairOfWordsCompare,
-		Last
-	}
-
-	public string question;
-	public string [] answers;
-	public Type type;
-	public string tip;
-	public string rationale;
-	public int right;
+		public GtkSynchronize ()
+		{
 
-	public bool MultipleAnswers {
-		get {
-			string [] items = answers[right].Split (AnalogiesFactory.Separator);
-
-			return items.Length > 1;
 		}
-	}
-
-	public override string ToString ()
-	{
-		string str = string.Empty;
 	
-		str += String.Format ("Question: {0}\n", question);
-		str += String.Format ("Type: {0}\n", type);
-		str += String.Format ("Tip: {0}\n", tip);
-		str += String.Format ("Rational: {0}\n", rationale);
-		return str;
-	}
-
-	public Analogy ()
-	{
+		// true if the caller must call Invoke; otherwise, false.
+		public bool InvokeRequired {
+			get {
+				return true;
+			}
+		}
+	
+		public IAsyncResult BeginInvoke (Delegate method, object[] args)
+		{
+			Application.Invoke (delegate {
+				method.DynamicInvoke (args);
+			});
 
-	}
-}
+			return null;
+		}
 
+		public object EndInvoke (IAsyncResult result)
+		{
+			return null;
+		}
 
+		// Use Invoke when the control's main thread is different from the calling thread to marshal the call to the proper thread.
+		public object Invoke (Delegate method, object[] args)
+		{
+			return null;
+		}
+	}	
+}
diff --git a/src/Clients/Classical/Makefile.am b/src/Clients/Classical/Makefile.am
new file mode 100644
index 0000000..db54e99
--- /dev/null
+++ b/src/Clients/Classical/Makefile.am
@@ -0,0 +1,67 @@
+EXTRAFLAGS =  -nowarn:0169 $(CSC_DEFINES)
+
+WRAPPER = gbrainy
+
+GBRAINY_CSDISTFILES =					\
+	$(srcdir)/Defines.cs 				\
+	$(srcdir)/gbrainy.cs 				\
+	$(srcdir)/GtkSynchronize.cs 			\
+	$(srcdir)/SimpleLabel.cs			\
+	$(srcdir)/Dialogs/AboutDialog.cs		\
+	$(srcdir)/Dialogs/CustomGameDialog.cs		\
+	$(srcdir)/Dialogs/GtkDialog.cs			\
+	$(srcdir)/Dialogs/PlayerHistoryDialog.cs	\
+	$(srcdir)/Dialogs/PreferencesDialog.cs
+
+ASSEMBLIES = \
+	 $(GBRAINY_LIBS)    		\
+	 $(MONO_ADDINS_LIBS)    	\
+	-r:Mono.Cairo.dll		\
+	-r:../../gbrainy.Core.dll	\
+	-r:Mono.Posix
+
+RESOURCES =										\
+-resource:$(srcdir)/gbrainy.glade  \
+-resource:$(top_srcdir)/data/app-graphics/resume-32.png  \
+-resource:$(top_srcdir)/data/app-graphics/endgame-32.png  \
+-resource:$(top_srcdir)/data/app-graphics/pause-32.png  \
+-resource:$(top_srcdir)/data/app-graphics/allgames-32.png  \
+-resource:$(top_srcdir)/data/app-graphics/gbrainy.png  \
+-resource:$(top_srcdir)/data/app-graphics/logic-games-32.png  \
+-resource:$(top_srcdir)/data/app-graphics/math-games-32.png  \
+-resource:$(top_srcdir)/data/app-graphics/memory-games-32.png  \
+-resource:$(top_srcdir)/data/app-graphics/verbal-games.svg  \
+-resource:$(top_srcdir)/data/app-graphics/verbal-games-32.png  \
+-resource:$(top_srcdir)/data/app-graphics/gbrainy.svg  \
+-resource:$(srcdir)/gbrainy.addin.xml
+
+gbrainydir = $(libdir)/gbrainy
+gbrainy_SCRIPTS = ../../gbrainy.exe
+
+
+GBRAINY_CSFILES = $(GBRAINY_CSDISTFILES)	\
+	AssemblyInfo.cs
+
+
+../../gbrainy.exe: $(GBRAINY_CSFILES) 
+	$(CSC) -target:winexe -out:$@ $(EXTRAFLAGS) $(GBRAINY_CSFILES) $(ASSEMBLIES) $(RESOURCES)
+
+all: ../../gbrainy.exe
+
+EXTRA_DIST =					\
+	gbrainy.glade \
+	$(srcdir)/gbrainy.addin.xml \
+	$(srcdir)/mono-addins-strings.xml \
+	$(GBRAINY_CSDISTFILES)			
+
+
+CLEANFILES =					\
+	gbrainy.exe.config			\
+	gbrainy.exe.mdb				\
+	../../gbrainy.exe			\
+	gbrainy
+
+
+DISTCLEANFILES = 				\
+	Makefile
+
diff --git a/src/Clients/Classical/SimpleLabel.cs b/src/Clients/Classical/SimpleLabel.cs
new file mode 100644
index 0000000..cce2645
--- /dev/null
+++ b/src/Clients/Classical/SimpleLabel.cs
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2009 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 Gtk;
+
+namespace gbrainy.Clients.Classical
+{
+	//
+	// Simple Label control that draws a piece of text
+	//
+	public class SimpleLabel : DrawingArea
+	{
+		string text;
+		int width_margin, height_margin;
+
+		public SimpleLabel ()
+		{
+
+		}
+
+		public string Text {
+			get { return text;}
+			set {
+				if (text == value)
+					return;
+
+				text = value;
+				QueueDraw ();
+			}
+		}
+
+		public int WidthMargin {
+			set {
+				if (width_margin == value)
+					return;
+
+				width_margin = value;
+				QueueDraw ();
+			}
+		}
+
+		public int HeightMargin {
+			set {
+				if (height_margin == value)
+					return;
+
+				height_margin = value;
+				QueueDraw ();
+			}
+		}
+
+		protected override bool OnExposeEvent (Gdk.EventExpose args)
+		{
+			if (String.IsNullOrEmpty (text))
+				return base.OnExposeEvent (args);
+
+			using (Cairo.Context cr = Gdk.CairoHelper.Create (args.Window))
+			{
+				int winWidth, winHeight;
+				Gdk.GC light = Style.ForegroundGC (StateType.Normal);
+				args.Window.GetSize (out winWidth, out winHeight);
+
+				using (Pango.Layout layout = new Pango.Layout (this.PangoContext))
+				{
+					if (Direction == Gtk.TextDirection.Rtl)
+						layout.Alignment = Pango.Alignment.Right;					
+					else
+						layout.Alignment = Pango.Alignment.Left;
+			
+					layout.Width = (winWidth - width_margin * 2) * (int) Pango.Scale.PangoScale;
+					layout.SetMarkup (text);
+					args.Window.DrawLayout (light, width_margin, height_margin, layout);
+				}
+			}
+
+			return base.OnExposeEvent (args);
+		}
+	}
+}
diff --git a/src/gbrainy.addin.xml b/src/Clients/Classical/gbrainy.addin.xml
similarity index 100%
rename from src/gbrainy.addin.xml
rename to src/Clients/Classical/gbrainy.addin.xml
diff --git a/src/Clients/Classical/gbrainy.cs b/src/Clients/Classical/gbrainy.cs
new file mode 100644
index 0000000..6655a21
--- /dev/null
+++ b/src/Clients/Classical/gbrainy.cs
@@ -0,0 +1,574 @@
+/*
+ * Copyright (C) 2007-2009 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 System.Reflection;
+using System.Runtime.InteropServices;
+using Cairo;
+using Gtk;
+using Gdk;
+using Gnome;
+using Mono.Unix;
+using System.Text;
+using System.Globalization;
+using System.Threading;
+using System.Diagnostics;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+using gbrainy.Core.Platform;
+
+#if MONO_ADDINS
+using Mono.Addins;
+using Mono.Addins.Setup;
+#endif
+
+namespace gbrainy.Clients.Classical
+{
+	public class GtkClient: Program
+	{
+		[Glade.Widget("gbrainy")] Gtk.Window app_window;
+		[Glade.Widget ("toolbar_item")] Gtk.CheckMenuItem toolbar_menuitem;
+		[Glade.Widget] Box drawing_vbox;
+		[Glade.Widget] Gtk.VBox question_vbox;
+		[Glade.Widget] Gtk.VBox solution_vbox;
+		[Glade.Widget] Gtk.Entry answer_entry;
+		[Glade.Widget] Gtk.Button answer_button;
+		[Glade.Widget] Gtk.Button tip_button;
+		[Glade.Widget] Gtk.Button next_button;
+		[Glade.Widget] Gtk.Statusbar statusbar;
+		[Glade.Widget] Gtk.Toolbar toolbar;
+		[Glade.Widget] Gtk.Menu settings_menu;
+		[Glade.Widget] Gtk.Menu help_menu;
+		[Glade.Widget] Gtk.MenuItem pause_menuitem;
+		[Glade.Widget] Gtk.MenuItem finish_menuitem;
+		[Glade.Widget] Gtk.MenuItem newgame_menuitem;
+		DrawingArea drawing_area;
+		GameSession session;
+		ToolButton all_tbbutton, logic_tbbutton, calculation_tbbutton, memory_tbbutton, verbal_tbbutton, pause_tbbutton, finish_tbbutton;
+		bool low_res;
+		bool full_screen;
+		SimpleLabel question_label;
+		SimpleLabel solution_label;
+		bool margins = false;
+	
+		public static PlayerHistory history = null;
+
+		public GtkClient (string [] args, params object [] props)
+		: base ("gbrainy", Defines.VERSION, Modules.UI,  args, props)
+		{
+			Gtk.MenuItem item;
+
+			Catalog.Init ("gbrainy", Defines.GNOME_LOCALE_DIR);
+			Unix.FixLocaleInfo ();
+
+			Glade.XML gXML = new Glade.XML (null, "gbrainy.glade", "gbrainy", null);
+			gXML.Autoconnect (this);
+
+			BuildToolBar ();
+			session = new GameSession ();
+			session.DrawRequest += SessionDrawRequest;
+			session.SynchronizingObject = new GtkSynchronize ();
+
+			if (history == null)
+				history = new PlayerHistory ();
+
+			session.GameManager.Difficulty = (Game.Difficulty) Preferences.GetIntValue (Preferences.DifficultyKey);
+			drawing_area = new DrawingArea ();
+			drawing_area.ExposeEvent += OnDrawingAreaExposeEvent;
+			GameSensitiveUI ();
+
+			// For low resolutions, hide the toolbar and made the drawing area smaller
+			if (drawing_area.Screen.Width> 0 && drawing_area.Screen.Height > 0) {
+				if (drawing_area.Screen.Height < 700) {
+					drawing_vbox.HeightRequest = 300;
+					low_res = true;
+				}
+			}
+
+			question_label = new SimpleLabel ();
+			question_label.HeightMargin = 2;
+			question_vbox.Add (question_label);
+
+			solution_label = new SimpleLabel ();
+			solution_label.HeightMargin = 2;
+			solution_vbox.Add (solution_label);
+
+		#if MONO_ADDINS
+			item = new Gtk.MenuItem (Catalog.GetString ("Extensions"));
+			settings_menu.Append (item);
+			item.Activated += delegate (object sender, EventArgs ar) { Mono.Addins.Gui.AddinManagerWindow.Run (app_window);};
+		#endif
+
+			item = new Gtk.MenuItem (Catalog.GetString ("How to Extend gbrainy's Functionality"));
+			help_menu.Prepend (item);
+			item.Activated += delegate (object sender, EventArgs ar) { Process.Start ("http://live.gnome.org/gbrainy/Extending";);};
+
+			drawing_vbox.Add (drawing_area);
+			app_window.IconName = "gbrainy";
+			app_window.ShowAll ();
+
+			if (Preferences.GetBoolValue (Preferences.Toolbar) == false || low_res == true)
+				toolbar_menuitem.Active = false;
+
+			ActiveInputControls (false);
+		}
+
+		// Gamesession has requested a redraw of the drawingarea
+		public void SessionDrawRequest (object o, EventArgs args)
+		{
+			drawing_area.QueueDraw ();
+		}
+
+		void OnDrawingAreaExposeEvent (object o, ExposeEventArgs ar)
+		{
+			Gdk.EventExpose args = ar.Event;
+
+			int w, h, nw, nh;
+			double x = 0, y = 0;
+			args.Window.GetSize (out w, out h);
+
+			Cairo.Context cc = Gdk.CairoHelper.Create (args.Window);
+			CairoContextEx cr = new CairoContextEx (cc.Handle, drawing_area);
+
+			// We want a square drawing area for the puzzles then the figures are shown as designed. 
+			// For example, squares are squares. This also makes sure that proportions are kept when resizing
+			nh = nw = Math.Min (w, h);	
+
+			if (nw < w)
+				x = (w - nw) / 2;
+
+			if (nh < h)
+				y = (h - nh) / 2;
+
+			if (margins)
+				SetMargin ((int) x);
+			else
+				SetMargin (2);
+
+			cr.Translate (x, y);
+			session.Draw (cr, nw, nh, drawing_area.Direction == Gtk.TextDirection.Rtl);
+
+			((IDisposable)cc).Dispose();
+			((IDisposable)cr).Dispose();
+		}
+
+		public void UpdateStatusBar ()
+		{
+			statusbar.Push (0, session.StatusText);
+		}
+
+		public void ActiveInputControls (bool active)
+		{
+			bool answer, entry, next, tip;
+
+			answer = entry = next = tip = active;
+
+			if (active == true && session.CurrentGame != null && session.CurrentGame.ButtonsActive == true && String.IsNullOrEmpty (session.CurrentGame.Tip ) == false)
+				tip = true;
+			else
+				tip = false;
+	
+			Console.WriteLine ("ActiveInputControls {0}", session.Status);
+
+			switch (session.Status) {
+			case GameSession.SessionStatus.NotPlaying:
+			case GameSession.SessionStatus.Finished:
+				answer = false;
+				entry =  false;
+				next = false;
+				tip = false;
+				break;
+			case GameSession.SessionStatus.Playing:
+				break;
+			case GameSession.SessionStatus.Answered:
+				answer = false;
+				entry =  false;
+				tip = false;
+				break;
+			}
+
+			answer_button.Sensitive = answer;
+			answer_entry.Sensitive = entry;
+			next_button.Sensitive = next;
+			tip_button.Sensitive = tip;
+
+			if (entry == true)
+				answer_entry.GrabFocus ();
+		}
+
+		public void UpdateQuestion (string question)
+		{
+			question_label.Text = question;
+		}
+
+		public void QueueDraw ()
+		{
+			drawing_area.QueueDraw ();
+		}
+
+		public void SetMargin (int margin)
+		{
+			question_label.WidthMargin = margin;
+			solution_label.WidthMargin = margin;
+		}
+
+		void UpdateSolution (string solution)
+		{		
+			solution_label.Text = solution;
+		}
+
+		void BuildToolBar ()
+		{
+			IconFactory icon_factory = new IconFactory ();
+		        AddIcon (icon_factory, "logic-games", "logic-games-32.png");
+			AddIcon (icon_factory, "math-games", "math-games-32.png");
+			AddIcon (icon_factory, "memory-games", "memory-games-32.png");
+			AddIcon (icon_factory, "verbal-games", "verbal-games-32.png");
+			AddIcon (icon_factory, "pause", "pause-32.png");
+			AddIcon (icon_factory, "resume", "resume-32.png");
+			AddIcon (icon_factory, "endgame", "endgame-32.png");
+			AddIcon (icon_factory, "allgames", "allgames-32.png");
+			icon_factory.AddDefault ();
+
+			toolbar.IconSize = Gtk.IconSize.Dnd;
+			toolbar.ShowArrow = false;
+	
+			Tooltips tooltips = new Tooltips ();
+			all_tbbutton = new ToolButton ("allgames");
+			all_tbbutton.SetTooltip (tooltips, Catalog.GetString ("Play all the games"), null);
+			all_tbbutton.Label = Catalog.GetString ("All");
+			all_tbbutton.Clicked += OnAllGames;
+			toolbar.Insert (all_tbbutton, -1);
+
+			logic_tbbutton = new ToolButton ("logic-games");
+			logic_tbbutton.SetTooltip (tooltips, Catalog.GetString ("Play games that challenge your reasoning and thinking"), null);
+			logic_tbbutton.Label = Catalog.GetString ("Logic");
+			logic_tbbutton.Clicked += OnLogicOnly;
+			toolbar.Insert (logic_tbbutton, -1);
+
+			calculation_tbbutton = new ToolButton ("math-games");
+			calculation_tbbutton.Label = Catalog.GetString ("Calculation");
+			calculation_tbbutton.SetTooltip (tooltips, Catalog.GetString ("Play games that challenge your mental calculation skills"), null);
+			calculation_tbbutton.Clicked += OnMathOnly;
+			toolbar.Insert (calculation_tbbutton, -1);
+
+			memory_tbbutton = new ToolButton ("memory-games");
+			memory_tbbutton.Label = Catalog.GetString ("Memory");
+			memory_tbbutton.SetTooltip (tooltips, Catalog.GetString ("Play games that challenge your short term memory"), null);
+			memory_tbbutton.Clicked += OnMemoryOnly;
+			toolbar.Insert (memory_tbbutton, -1);
+
+			verbal_tbbutton = new ToolButton ("verbal-games");
+			verbal_tbbutton.Label = Catalog.GetString ("Verbal");
+			verbal_tbbutton.SetTooltip (tooltips, Catalog.GetString ("Play games that challenge your verbal aptitude"), null);
+			verbal_tbbutton.Clicked += OnVerbalOnly;
+			toolbar.Insert (verbal_tbbutton, -1);
+
+			pause_tbbutton = new ToolButton ("pause");
+			pause_tbbutton.Label = Catalog.GetString ("Pause");
+			pause_tbbutton.SetTooltip (tooltips, Catalog.GetString ("Pause or resume the game"), null);
+			pause_tbbutton.Clicked += OnPauseGame;
+			toolbar.Insert (pause_tbbutton, -1);
+
+			finish_tbbutton = new ToolButton ("endgame");
+			finish_tbbutton.SetTooltip (tooltips, Catalog.GetString ("End the game and show score"), null);
+			finish_tbbutton.Label = Catalog.GetString ("Finish");
+			finish_tbbutton.Clicked += OnEndGame;
+			toolbar.Insert (finish_tbbutton, -1);
+		}
+
+		void GameSensitiveUI () 
+		{
+			//Toolbar buttons and menu items that are sensitive when the user is playing
+			bool playing;
+
+			if (session.Status == GameSession.SessionStatus.Playing)
+				playing = true;
+			else
+				playing = false;
+	
+			finish_tbbutton.Sensitive = pause_tbbutton.Sensitive = playing;
+			all_tbbutton.Sensitive = calculation_tbbutton.Sensitive = memory_tbbutton.Sensitive = logic_tbbutton.Sensitive = verbal_tbbutton.Sensitive = !playing;
+			pause_menuitem.Sensitive = finish_menuitem.Sensitive = playing;
+			newgame_menuitem.Sensitive = !playing;
+		}
+
+		private void GetNextGame ()
+		{
+			UpdateSolution (String.Empty);
+			UpdateQuestion (String.Empty);
+			session.NextGame ();
+
+			ActiveInputControls (session.CurrentGame.ButtonsActive);
+			next_button.Sensitive = true;
+			UpdateQuestion (session.CurrentGame.Question);
+			answer_entry.Text = string.Empty;
+			UpdateStatusBar ();
+			session.CurrentGame.DrawAnswer = false;
+			drawing_area.QueueDraw ();
+		}
+	
+		void OnMenuAbout (object sender, EventArgs args)
+		{
+			AboutDialog about = new AboutDialog ();
+			about.Run ();
+		}	
+
+		void OnAnswerButtonClicked (object sender, EventArgs args)
+		{
+			string answer;
+
+			if (session.CurrentGame == null)
+				return;
+	
+			if (answer_button.Sensitive == true && session.CurrentGame.CheckAnswer (answer_entry.Text) == true) {
+				session.GamesWon++;
+				session.CurrentGame.Won = true;
+				answer = "<span color='#00A000'>" + Catalog.GetString ("Congratulations.") + "</span>";
+			} else
+				answer = Catalog.GetString ("Incorrect answer.");
+
+			session.ScoreGame ();
+			session.EnableTimer = false;
+			answer_entry.Text = String.Empty;
+			UpdateStatusBar ();
+			UpdateSolution (answer + " " + session.CurrentGame.Answer);
+
+			session.CurrentGame.DrawAnswer = true;
+			session.Status = GameSession.SessionStatus.Answered;
+			ActiveInputControls (true);
+			next_button.GrabFocus ();
+			drawing_area.QueueDraw ();
+		}		
+
+		void OnQuit (object sender, EventArgs args)
+		{
+			Quit ();	
+		}	
+
+		void OnDeleteWindow (object sender, DeleteEventArgs args)
+		{
+			Quit ();	
+		}	
+
+		void OnNextButtonClicked (object sender, EventArgs args)
+		{
+			if (answer_entry.Text.Length > 0) {
+				OnAnswerButtonClicked (sender, args);
+				return;
+			}
+
+			session.ScoreGame ();
+			GetNextGame ();
+			session.EnableTimer = true;
+		}
+
+		void OnTip (object sender, EventArgs args)
+		{
+			if (session.CurrentGame == null)
+				return;
+
+			UpdateSolution (session.CurrentGame.TipString);
+		}
+
+		void OnNewGame ()
+		{
+			session.NewSession ();
+			GetNextGame ();
+			GameSensitiveUI ();
+			UpdateSolution (Catalog.GetString ("Once you have an answer type it in the \"Answer:\" entry box and press the \"OK\" button."));
+			UpdateStatusBar ();
+		}
+
+		void OnMathOnly (object sender, EventArgs args)
+		{
+			session.Type = GameSession.Types.CalculationTrainers;
+			OnNewGame ();
+		}
+
+
+		void OnVerbalOnly (object sender, EventArgs args)
+		{
+			session.Type = GameSession.Types.VerbalAnalogies;
+			OnNewGame ();
+		}
+
+		void OnMemoryOnlyAfterCountDown (object source, EventArgs e)
+		{
+			OnNewGame ();
+		}
+
+		void OnMemoryOnly (object sender, EventArgs args)
+		{
+			session.Type = GameSession.Types.MemoryTrainers;
+			UpdateSolution (String.Empty);
+	 		UpdateQuestion (String.Empty);
+			OnNewGame ();
+		}
+
+		void OnPreferences (object sender, EventArgs args)
+		{
+			PreferencesDialog dialog;
+
+			dialog = new PreferencesDialog ();
+			if (dialog.Run () == ResponseType.Ok) {
+				session.GameManager.Difficulty = (Game.Difficulty) Preferences.GetIntValue (Preferences.DifficultyKey);
+			}
+			dialog.Dialog.Destroy ();
+		}
+
+		void OnCustomGame (object sender, EventArgs args)
+		{
+			ResponseType rslt;
+			CustomGameDialog dialog;
+
+			dialog = new CustomGameDialog (session.GameManager);		
+			rslt = dialog.Run ();
+			dialog.Dialog.Destroy ();
+
+			if (rslt == ResponseType.Ok && dialog.NumOfGames > 0) {
+				session.Type = GameSession.Types.Custom;
+				OnNewGame ();
+			}
+		}
+
+		void OnLogicOnly (object sender, EventArgs args)
+		{
+			session.Type = GameSession.Types.LogicPuzzles;
+			OnNewGame ();
+		}
+
+		void OnAllGames (object sender, EventArgs args)
+		{
+			session.Type = GameSession.Types.AllGames;
+			OnNewGame ();		
+		}
+
+		void OnTrainersOnly (object sender, EventArgs args)
+		{
+			session.Type = GameSession.Types.TrainersOnly;
+			OnNewGame ();		
+		}
+
+		void OnAnswerActivate (object sender, EventArgs args)
+		{
+			if (answer_entry.Text.Length > 0) {
+				OnAnswerButtonClicked (sender, args);
+				return;
+			}
+		}
+
+		void OnEndGame (object sender, EventArgs args)
+		{	
+			history.SaveGameSession (session);
+			session.EndSession ();
+	
+			UpdateSolution (String.Empty);
+			UpdateQuestion (String.Empty);
+			UpdateStatusBar ();
+			GameSensitiveUI ();
+			drawing_area.QueueDraw ();
+			ActiveInputControls (false);
+			SetPauseResumeButton (true);
+		}
+
+		void SetPauseResumeButton (bool pause)
+		{
+			if (pause) {
+				pause_tbbutton.StockId = "pause";
+				pause_tbbutton.Label = Catalog.GetString ("Pause");
+	 			session.Resume ();
+				ActiveInputControls (true);
+			} else {
+				pause_tbbutton.StockId = "resume";
+				pause_tbbutton.Label = Catalog.GetString ("Resume");
+				session.Pause ();
+				ActiveInputControls (false);
+			}
+			UpdateStatusBar ();
+		}
+
+		void OnPauseGame (object sender, EventArgs args)
+		{
+			SetPauseResumeButton (session.Paused);
+		}
+
+		private void OnToolbarActivate (object sender, System.EventArgs args)
+		{
+			int width, height;
+			Requisition requisition;
+
+			requisition =  toolbar.SizeRequest ();
+			app_window.GetSize (out width, out height);
+			toolbar.Visible = !toolbar.Visible;
+			Preferences.SetBoolValue (Preferences.Toolbar, toolbar.Visible);
+			Preferences.Save ();
+			app_window.Resize (width, height - requisition.Height);
+		}
+
+		void OnHistory (object sender, EventArgs args)
+		{
+			PlayerHistoryDialog dialog;
+
+			dialog = new PlayerHistoryDialog ();
+			dialog.Run ();
+			dialog.Dialog.Destroy ();	
+		}	
+
+		private void AddIcon (IconFactory stock, string stockid, string resource)
+		{
+			Gtk.IconSet iconset = stock.Lookup (stockid);
+		
+			if (iconset != null)
+				return;
+
+			iconset = new Gtk.IconSet ();
+			Gdk.Pixbuf img = Gdk.Pixbuf.LoadFromResource (resource);
+			IconSource source = new IconSource ();
+			source.Pixbuf = img;
+			iconset.AddSource (source);
+			stock.Add (stockid, iconset);		
+		}
+
+		void OnFullscreen (object sender, EventArgs args)
+		{
+			if (full_screen == false) {
+				margins = true;
+				app_window.Fullscreen ();
+			}
+			else {
+				margins = false;
+				app_window.Unfullscreen ();
+			}
+
+			full_screen = !full_screen;
+		}
+
+		public static void Main (string [] args) 
+		{
+			try {
+				Unix.SetProcessName ("gbrainy");
+			} catch {}
+
+			GtkClient gui = new GtkClient (args);
+			gui.Run ();	
+		}
+	}
+}
diff --git a/src/gbrainy.glade b/src/Clients/Classical/gbrainy.glade
similarity index 100%
rename from src/gbrainy.glade
rename to src/Clients/Classical/gbrainy.glade
diff --git a/src/mono-addins-strings.xml b/src/Clients/Classical/mono-addins-strings.xml
similarity index 100%
rename from src/mono-addins-strings.xml
rename to src/Clients/Classical/mono-addins-strings.xml
diff --git a/src/Core/Libraries/CairoContextEx.cs b/src/Core/Libraries/CairoContextEx.cs
new file mode 100644
index 0000000..5cc8708
--- /dev/null
+++ b/src/Core/Libraries/CairoContextEx.cs
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) 2007-2008 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 Cairo;
+using Mono.Unix;
+using System.Runtime.InteropServices;
+using Pango;
+
+using gbrainy.Core.Main;
+
+namespace gbrainy.Core.Libraries
+{
+	#if GTK_2_8 // For GTK < 2.10
+
+	public static class PangoCairoHelper
+	{
+		[DllImport ("libpangocairo-1.0.so.0")]
+		private static extern void pango_cairo_show_layout (IntPtr cr, IntPtr layout);
+
+		public static void ShowLayout (Cairo.Context cr, Pango.Layout layout)
+		{
+			pango_cairo_show_layout (cr == null ? IntPtr.Zero : cr.Handle,
+			layout == null ? IntPtr.Zero : layout.Handle);
+		}
+
+		[DllImport ("libpangocairo-1.0.so.0")]
+		private static extern IntPtr pango_cairo_create_layout (IntPtr cr);
+
+		public static Pango.Layout CreateLayout (Cairo.Context cr)
+		{
+			IntPtr raw_ret = pango_cairo_create_layout (cr == null ? IntPtr.Zero : cr.Handle);
+			return GLib.Object.GetObject (raw_ret) as Pango.Layout;
+		}
+
+		[DllImport ("libpangocairo-1.0.so.0")]
+		private static extern void pango_cairo_layout_path (IntPtr cr, IntPtr layout);
+
+		public static void LayoutPath (Cairo.Context cr, Pango.Layout layout,
+		bool iUnderstandThePerformanceImplications)
+		{
+			pango_cairo_layout_path (cr == null ? IntPtr.Zero : cr.Handle,
+			layout == null ? IntPtr.Zero : layout.Handle);
+		}
+
+		[DllImport ("libpangocairo-1.0.so.0")]
+		private static extern void pango_cairo_context_set_resolution (IntPtr pango_context, double dpi);
+
+		public static void ContextSetResolution (Pango.Context context, double dpi)
+		{
+			pango_cairo_context_set_resolution (context == null ? IntPtr.Zero : context.Handle, dpi);
+		}
+
+		[DllImport ("libpangocairo-1.0.so.0")]
+		private static extern IntPtr pango_layout_get_context (IntPtr layout);
+
+		public static Pango.Context LayoutGetContext (Pango.Layout layout)
+		{
+			IntPtr handle = pango_layout_get_context (layout.Handle);
+			return handle.Equals (IntPtr.Zero) ? null : GLib.Object.GetObject (handle) as Pango.Context;
+		}
+	}
+
+	#endif
+
+	public class CairoContextEx : Cairo.Context
+	{
+		Pango.Layout layout;
+		double font_size;
+		static SVGImage image = null;
+
+		const double line_space = 0.018;
+		const double width_margin = 0.04;
+
+		public CairoContextEx (IntPtr state, Gtk.Widget widget) : base (state)
+		{
+			CommonConstructor ();
+
+		#if GTK_2_8
+		#else
+			double resolution = widget.Screen.Resolution;
+			if (resolution != -1)  {
+				Pango.Context c = layout.Context;
+				Pango.CairoHelper.ContextSetResolution (c, resolution);
+				c.Dispose ();
+			}
+		#endif
+
+		}
+
+		// Used by GeneratePDF
+		public CairoContextEx (Cairo.Surface s) : base (s)
+		{
+			CommonConstructor ();
+		}
+
+		private void CommonConstructor ()
+		{
+	#if GTK_2_8
+			layout = PangoCairoHelper.CreateLayout (this);
+	#else
+			layout = Pango.CairoHelper.CreateLayout (this);
+	#endif
+			layout.FontDescription = FontDescription.FromString ("Sans");
+			SetPangoNormalFontSize ();
+		}
+
+		// No dispose of resources on this class
+		protected override void Dispose (bool disposing)
+		{
+			layout.Dispose ();
+		}
+
+		private void UpdateFontSize ()
+		{
+			layout.FontDescription.Size = (int) (font_size * Pango.Scale.PangoScale * Matrix.Xx);	
+		}
+
+		/*
+			Font drawing using Pango
+
+			* Pango does not work well with float numbers. We should work on 
+			the device unit space and then translate to our user space.
+
+			* Cairo Show.Text paints on the bottom-left of the coordinates
+			and Pango paints on the top-left of the coordinates
+		*/
+
+
+		// Shows a text from the current position. No Width defined then no RTL positioning
+		public void ShowPangoText (string str)
+		{
+			Cairo.Matrix old = Matrix;
+
+			UpdateFontSize ();
+			Matrix = new Cairo.Matrix ();		
+			layout.SetText (str);
+			layout.SingleParagraphMode = true;
+	#if GTK_2_8
+			PangoCairoHelper.ShowLayout (this, layout);
+	#else
+			Pango.CairoHelper.ShowLayout (this, layout);
+	#endif
+			Matrix = old;
+		}
+
+		// Shows a text from the current position. Defines all the line as text drawing box
+		public void ShowPangoText (string str, bool bold, double width, double rotation)
+		{
+			Pango.Alignment align = layout.Alignment;
+
+			if (bold) {
+				layout.FontDescription.Weight = Pango.Weight.Bold;
+			}
+
+			if (width == -1) { // Calculates maximum width in the user space
+				layout.Width = (int) (((1 - width_margin) * Matrix.Xx - (CurrentPoint.X * Matrix.Xx)) * Pango.Scale.PangoScale);
+			} else 
+				layout.Width = (int) (width * Matrix.Xx * Pango.Scale.PangoScale);
+
+			if (rotation != 0) {
+
+				Cairo.Matrix old = Matrix;
+
+				UpdateFontSize ();
+				Matrix = new Cairo.Matrix ();
+				Rotate (rotation);
+				layout.SetText (str);
+				layout.SingleParagraphMode = true;
+	#if GTK_2_8
+			PangoCairoHelper.ShowLayout  (this, layout);
+	#else
+			Pango.CairoHelper.ShowLayout (this, layout);
+	#endif
+				Matrix = old;
+			}
+			else
+				ShowPangoText (str);
+				
+			layout.FontDescription.Weight = Pango.Weight.Normal;
+			layout.Width = -1;
+			layout.Alignment = align;
+		}
+
+		public void SetPangoNormalFontSize ()
+		{
+			font_size = 0.022;
+		}
+
+		public void SetPangoLargeFontSize ()
+		{
+			font_size = 0.0325;
+		}
+
+		public void SetPangoFontSize (double size)
+		{
+			font_size = size;
+		}
+
+		/*
+			Draw text functions
+		*/		
+		
+		// Used for fractions that right align is needed
+		public void DrawTextAlignedRight (double x, double y, string str)
+		{
+			int w, h;
+			Cairo.Matrix old = Matrix;
+
+			UpdateFontSize ();
+			Matrix = new Cairo.Matrix ();
+
+			layout.SetText (str);
+			layout.SingleParagraphMode = true;
+			layout.Width = -1;
+			layout.GetPixelSize (out w, out h);
+			MoveTo ((old.X0 + x * old.Xx) - w, y * old.Xx);
+	#if GTK_2_8
+			PangoCairoHelper.ShowLayout (this, layout);
+	#else
+			Pango.CairoHelper.ShowLayout (this, layout);
+	#endif
+			Matrix = old;
+		}
+
+		// From a giving point centers the text into it
+		public void DrawTextCentered (double x, double y, string str)
+		{
+			int w, h;
+			Cairo.Matrix old = Matrix;
+
+			UpdateFontSize ();
+			Matrix = new Cairo.Matrix ();
+
+			layout.SetText (str);
+			layout.SingleParagraphMode = true;
+			layout.Width = -1;
+			layout.GetPixelSize (out w, out h);
+			MoveTo ((old.X0 + x * old.Xx) - w / 2, (y - font_size / 2) * old.Xx);
+	#if GTK_2_8
+			PangoCairoHelper.ShowLayout  (this, layout);
+	#else
+			Pango.CairoHelper.ShowLayout (this, layout);
+	#endif
+			Matrix = old;
+		}
+
+		public double DrawStringWithWrapping (double x, double y, string str)
+		{
+			return DrawStringWithWrapping (x, y, str, -1);
+		}
+
+		public double DrawStringWithWrapping (double x, double y, string str, double width)
+		{
+			int w, h;
+			Cairo.Matrix old = Matrix;
+
+			MoveTo (x, y);
+			UpdateFontSize ();
+			Matrix = new Cairo.Matrix ();
+
+			if (width == -1)
+				layout.Width = (int) ((1.0 - x -  width_margin) * old.Xx * Pango.Scale.PangoScale);
+			else	
+				layout.Width = (int) (width * old.Xx * Pango.Scale.PangoScale);
+
+			layout.Spacing = (int) (line_space * (old.Xx * Pango.Scale.PangoScale));
+			layout.SingleParagraphMode = false;
+			layout.SetText (str);
+	#if GTK_2_8
+			PangoCairoHelper.ShowLayout (this, layout);
+	#else
+			Pango.CairoHelper.ShowLayout (this, layout);
+	#endif
+			layout.GetPixelSize (out w, out h);
+			Matrix = old;
+			return y + h / old.Xx;
+		}
+
+		public void DrawEquilateralTriangle (double x, double y, double size)
+		{
+			MoveTo (x + (size / 2), y);
+			LineTo (x, y + size);
+			LineTo (x + size, y + size);
+			LineTo (x + (size / 2), y);
+			Stroke ();	
+		}
+
+		public void DrawDiamond (double x, double y, double size)
+		{
+			MoveTo (x + size / 2, y);
+			LineTo (x, y + size / 2);
+			LineTo (x + size / 2, y + size);
+			LineTo (x + size, y + size / 2);
+			LineTo (x + size / 2, y);
+			Stroke ();
+		}
+
+		public void FillGradient (double x, double y, double w, double h)
+		{
+			Save ();
+			LinearGradient shadow = new LinearGradient (x, y, x + w, y + h);
+			shadow.AddColorStop (0, new Cairo.Color (0, 0, 0, 0.3));
+			shadow.AddColorStop (0.5, new Cairo.Color (0, 0, 0, 0.1));
+			Source = shadow;
+			Fill ();
+			Restore ();
+			((IDisposable)shadow).Dispose ();
+		}
+
+		public void DrawClock (double x, double y, double size, int hand_short, int hand_large)
+		{
+			const double radian = Math.PI / 180;
+			double radius = size / 2;
+			double x0, y0;
+			int num, degrees;
+
+			Arc (x, y, radius, 0, 2 * Math.PI);
+			Stroke ();
+			for (degrees = 0; degrees < 360; degrees+= 30) {
+				x0 = radius * Math.Cos (degrees * radian);
+				y0 = radius * Math.Sin (degrees * radian);
+				 // Small lines
+				MoveTo (x + 0.9 * x0, y + 0.9 * y0);
+				LineTo (x + x0, y + y0);
+				Stroke ();
+				// Numbers
+				num = (degrees / 30) + 3;
+				if (num > 12) num = num - 12;
+
+				DrawTextCentered (x + x0 * 0.75,  y + y0 * 0.75, num.ToString ());
+				Stroke ();
+			}
+
+			if (hand_large >=1 && hand_large <= 12 ) {
+				// Hand Large
+				degrees = (hand_large - 3) * 30;
+				x0 = radius * Math.Cos (degrees * radian);
+				y0 = radius * Math.Sin (degrees * radian);
+				MoveTo (x, y);
+				LineTo (x + x0 * 0.55, y + y0 * 0.55);
+				Stroke ();
+			}
+
+			if (hand_short >=1 && hand_short <= 12) {
+				// Hand Short
+				degrees = (hand_short - 3) * 30;
+				x0 = radius * Math.Cos (degrees * radian);
+				y0 = radius * Math.Sin (degrees * radian);
+				MoveTo (x, y);
+				LineTo (x + x0 * 0.4, y + y0 * 0.4);
+				Stroke ();
+			}
+		}
+
+		public void FillGradient (double x, double y, double w, double h, Cairo.Color color)
+		{
+			Save ();
+			LinearGradient shadow = new LinearGradient (x, y, x + w, y + h);
+			shadow.AddColorStop (0, new Cairo.Color (color.R, color.G, color.B, color.A));
+			shadow.AddColorStop (0.5, new Cairo.Color (color.R, color.G, color.B, color.A * 0.7));
+			Source = shadow;
+			Fill ();
+			Restore ();
+			((IDisposable)shadow).Dispose ();
+		}
+
+		virtual public void DrawBackground ()
+		{
+			try {
+				if (image == null)
+					image = new SVGImage (Defines.DATA_DIR + "background.svg");
+
+				Save ();
+				Rectangle (0, 0, 1, 1);
+				Scale (0.999 / image.Width, 0.999 / image.Height);
+				image.RenderToCairo (Handle);
+				Restore ();
+
+			} catch {
+			}
+		}
+
+		public void DrawImageFromAssembly (string  resource, double x, double y, double width, double height)
+		{
+			try {
+				using (SVGImage image = new SVGImage (System.Reflection.Assembly.GetCallingAssembly (), resource))
+				{
+					DrawImage (image, x, y, width, height);
+				}
+			}
+			catch (Exception)
+			{
+				return;
+			}
+		}
+
+		public void DrawImageFromFile (string filename, double x, double y, double width, double height)
+		{
+			try {
+				using (SVGImage image = new SVGImage (filename))
+				{
+					DrawImage (image, x, y, width, height);
+				}
+			}
+			catch (Exception)
+			{
+				return;
+			}
+		}
+
+		void DrawImage (SVGImage image, double x, double y, double width, double height)
+		{		
+			Save ();
+			Translate (x, y);
+			Scale (width / image.Width, height / image.Height);
+			image.RenderToCairo (Handle);
+			Restore ();
+		}
+	}
+}
diff --git a/src/Core/Libraries/SVGImage.cs b/src/Core/Libraries/SVGImage.cs
new file mode 100644
index 0000000..31d4fde
--- /dev/null
+++ b/src/Core/Libraries/SVGImage.cs
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2008-2009 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 Mono.Unix;
+using System.IO;
+using System.Runtime.InteropServices;
+
+namespace gbrainy.Core.Libraries
+{
+	//
+	// SVG image class based on rsvg library
+	//
+	public class SVGImage : IDisposable
+	{
+		//lib rsvg2
+		[DllImport("rsvg-2")]
+		static extern void rsvg_handle_render_cairo (IntPtr Rsvghandle, IntPtr cairo_t);
+
+		[DllImport("rsvg-2")]
+		static extern IntPtr rsvg_handle_new_from_file (string file_name, out int error);
+
+		[DllImport("rsvg-2")]
+		static extern void rsvg_handle_free (IntPtr handle);
+
+		[DllImport("rsvg-2")]
+		static extern void rsvg_handle_get_dimensions (IntPtr handle, ref RsvgDimensionData dimension);
+
+		[DllImport("rsvg-2")]
+		static extern IntPtr rsvg_handle_new_from_data (byte[] data, int len, out int error);
+
+		[StructLayout(LayoutKind.Sequential)]
+		struct RsvgDimensionData
+		{
+		    	public int width;
+		    	public int height;
+		    	public double em;
+			public double ex;
+		}
+
+		RsvgDimensionData dimension;
+		IntPtr handle;
+
+		public SVGImage (System.Reflection.Assembly _assembly, string resource)
+		{
+			try {
+				byte[] array;
+				Stream stream;
+				int error = 0;
+
+				stream =  _assembly.GetManifestResourceStream (resource);
+				array = new byte [stream.Length];
+
+				stream.Read (array, 0, (int) stream.Length);
+			
+				handle = rsvg_handle_new_from_data (array, array.Length, out error);
+				rsvg_handle_get_dimensions (handle, ref dimension);
+			} 
+			finally
+			{
+				if (handle == IntPtr.Zero)
+					throw new System.IO.IOException ("Resource not found: " + resource);
+			}
+		}
+	
+		public SVGImage (string file)
+		{
+			int error = 0;
+			dimension = new RsvgDimensionData ();
+
+			try {
+				handle = rsvg_handle_new_from_file (file, out error);
+
+				if (handle != IntPtr.Zero)		
+					rsvg_handle_get_dimensions (handle, ref dimension);
+
+			}
+
+			finally
+			{
+				if (handle == IntPtr.Zero)
+					throw new System.IO.IOException ("File not found: " + file);
+
+			}
+		}
+
+		public int Width {
+			get { return dimension.width; }
+		}
+	
+		public int Height {
+			get { return dimension.height; }
+		}
+
+		~SVGImage ()
+		{
+			Dispose (false);
+		}
+
+		public void Dispose ()
+		{
+			Dispose (true);
+			System.GC.SuppressFinalize (this);
+		}
+
+		protected virtual void Dispose (bool disposing)
+		{
+			if (handle == IntPtr.Zero)
+				return;
+
+			rsvg_handle_free (handle);
+			handle = IntPtr.Zero;
+		}
+
+		public void RenderToCairo (IntPtr cairo_surface)
+		{
+			if (handle != IntPtr.Zero)
+				rsvg_handle_render_cairo (handle, cairo_surface);
+		}
+	}
+}
diff --git a/src/Core/Main/ArrayListIndicesRandom.cs b/src/Core/Main/ArrayListIndicesRandom.cs
new file mode 100644
index 0000000..7ea18f4
--- /dev/null
+++ b/src/Core/Main/ArrayListIndicesRandom.cs
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2007 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 System.Collections.Generic;
+
+namespace gbrainy.Core.Main
+{
+	//
+	// Returns a list of indexes in random order
+	//
+	public class ArrayListIndicesRandom : List <int>
+	{
+		Random random;
+
+		public ArrayListIndicesRandom (int capacity) : base (capacity)
+		{
+			random = new Random ();
+		}
+
+		public void Initialize ()
+		{
+			List <int> random_list = new List <int> (Capacity);
+			for (int i = 0; i < Capacity; i++) {
+				random_list.Add (i);
+			}
+			RandomizeFromArray (random_list);
+		}
+
+		public void RandomizeFromArray (List <int> ar)
+		{		
+			int left = Capacity;
+			int index;
+			int []array = ar.ToArray ();
+			Clear ();
+
+			// Generate a random number that can be as big as the maximum -1
+			// Add the random element picked up element in the list
+			// The element just randomized gets out of pending list and replaced by the maximum -1 element 
+			for (int i = 0; i < Capacity; i++, left--) {
+				index = random.Next (left);
+				Add (array[index]);
+				array[index] = array[left - 1];
+			}
+		}
+	}
+}
diff --git a/src/Core/Main/ColorPalette.cs b/src/Core/Main/ColorPalette.cs
new file mode 100644
index 0000000..25a6d6c
--- /dev/null
+++ b/src/Core/Main/ColorPalette.cs
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2007 Javier M Mora <javiermm gmail com>
+ *
+ * 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 Cairo;
+using Mono.Unix;
+
+namespace gbrainy.Core.Main
+{
+	//Utility class for color operations
+	public class ColorPalette
+	{
+		private ArrayListIndicesRandom color_order;
+
+		private double alpha;
+		public double Alpha {
+			set { alpha = value; }
+			get { return alpha; }
+		}
+
+		public int Count {
+			get { return color_order.Count; }
+		}
+
+		// Are defined "First", "PrimaryColors", "PrimarySecundaryColors", and "Last" to
+		// create iterators. So: 
+		//   for (Colors.Id it= Colors.Id.First; it<Colors.Id.PrimaryColors; it++);
+		//   for (Colors.Id it= Colors.Id.First; it<Colors.Id.PrimarySecundaryColors; it++);
+		//   for (Colors.Id it= Colors.Id.First; it<Colors.Id.Last; it++);
+		//
+
+		public enum Id
+		{
+			First=0,
+			Red=First,
+			Green,
+			Blue,
+			PrimaryColors,
+			Yellow=PrimaryColors, 
+			Magenta,
+			Orange,
+			PrimarySecundaryColors,
+			Black=PrimarySecundaryColors,
+			Last,
+			White=Last
+		};
+
+		private static readonly string[] ColorName= new string[] {
+			Catalog.GetString ("red"),
+			Catalog.GetString ("green"),
+			Catalog.GetString ("blue"),
+			Catalog.GetString ("yellow"),
+			Catalog.GetString ("magenta"),
+			Catalog.GetString ("orange"),
+			Catalog.GetString ("black"),
+			Catalog.GetString ("white")
+		};
+
+		private static Cairo.Color[] CairoColor = new Cairo.Color[] {
+			new Cairo.Color (0.81, 0.1, 0.13),
+			new Cairo.Color (0.54, 0.71, 0.24),
+			new Cairo.Color (0.17, 0.23 ,0.56),
+			new Cairo.Color (0.94, 0.93, 0.25),
+			new Cairo.Color (0.82, 0.25, 0.59),
+			new Cairo.Color (1, 0.54, 0),
+			new Cairo.Color (0, 0, 0),
+			new Cairo.Color (.9, .9, .9)
+		};
+
+		public ColorPalette (Id id)
+		{
+			color_order = new ArrayListIndicesRandom((int)id);
+			alpha=1;
+		}
+
+		public ColorPalette (int size)
+		{
+			color_order = new ArrayListIndicesRandom(size);
+			alpha=1;
+		}
+
+		public void Initialize()
+		{
+			color_order.Initialize();
+		}
+
+		public Cairo.Color Cairo (int index) 
+		{
+			return Cairo (CairoColor[(int)color_order[index]]);
+		}
+
+		public Cairo.Color Cairo (Id id) 
+		{
+			return Cairo (CairoColor[(int)id]);
+		}
+
+		public Cairo.Color Cairo(Cairo.Color color)
+		{
+			return new Cairo.Color(color.R, color.G, color.B, alpha);
+		}
+
+		public string Name(int index)
+		{
+			return ColorName[(int)color_order[index]];
+		}
+
+		public string Name(Id id)
+		{
+			return ColorName[(int)id];
+		}
+
+		public int Size()
+		{
+			return color_order.Count;
+		}
+	}
+}
diff --git a/src/Defines.cs.in b/src/Core/Main/Defines.cs.in
similarity index 68%
copy from src/Defines.cs.in
copy to src/Core/Main/Defines.cs.in
index a35eac1..2bfaf42 100644
--- a/src/Defines.cs.in
+++ b/src/Core/Main/Defines.cs.in
@@ -19,14 +19,14 @@
 
 using System;
 
-public class Defines
+namespace gbrainy.Core.Main
 {
-	public const string VERSION = "@VERSION@";
-	public const string GNOME_LOCALE_DIR = "@prefix@/share/locale";
-	public const string DATA_DIR = "@prefix@/share/games/gbrainy/";
-	public const string VERBAL_ANALOGIES = "verbal_analogies.xml";
-	public const string CONFIG_DIR = "gbrainy"; // like .config/gbrainy
+	public class Defines
+	{
+		public const string VERSION = "@VERSION@";
+		public const string GNOME_LOCALE_DIR = "@prefix@/share/locale";
+		public const string DATA_DIR = "@prefix@/share/games/gbrainy/";
+		public const string VERBAL_ANALOGIES = "verbal_analogies.xml";
+		public const string CONFIG_DIR = "gbrainy"; // like .config/gbrainy
+	}
 }
-
-
-
diff --git a/src/Core/Main/Game.cs b/src/Core/Main/Game.cs
new file mode 100644
index 0000000..bb18f17
--- /dev/null
+++ b/src/Core/Main/Game.cs
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2007 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 System.ComponentModel;
+using Mono.Unix;
+
+using gbrainy.Core.Views;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Core.Main
+{
+	abstract public class Game : Views.IDrawable, IDrawRequest
+	{
+		// See: GetGameTypeDescription
+		public enum Types
+		{	
+			None			= 0,
+			LogicPuzzle		= 2,
+			MemoryTrainer		= 4,
+			MathTrainer		= 8,
+			VerbalAnalogy		= 16,
+		}
+
+		public enum Difficulty
+		{
+			None			= 0,
+			Easy			= 2,
+			Medium			= 4,
+			Master			= 8,
+		}
+
+		private bool draw_answer;
+		private Cairo.Color default_color;
+		protected string right_answer;
+		protected Random random;
+		private TimeSpan game_time;
+		private bool won;
+		private bool tip_used;
+		private Difficulty difficulty;
+		private ISynchronizeInvoke synchronize;
+
+		public event EventHandler DrawRequest;
+
+		protected Game ()
+		{
+			random = new Random ();
+			draw_answer = false;
+			default_color = new Cairo.Color (0, 0, 0);
+			won = false;
+			tip_used = false;
+			difficulty = Difficulty.Medium;
+		}
+
+		// Used by games to request a redraw of the view
+		protected void OnDrawRequest ()
+		{
+			if (DrawRequest == null)
+				return;
+
+			DrawRequest (this, EventArgs.Empty);
+		}
+
+		public abstract string Question {
+			get;
+		}
+
+		public virtual string Answer {
+			get {
+				return String.Format (Catalog.GetString ("The correct answer is {0}."), right_answer);
+			}
+		}
+
+		public ISynchronizeInvoke SynchronizingObject { 
+			set { 
+				synchronize = value;
+				Console.WriteLine ("Game.SynchronizingObject (GtkSynchronize) {0} {1}", this, value);
+			}
+			get { return synchronize; }
+		}
+
+
+		// Stores how difficult the game is
+		public virtual Difficulty GameDifficulty {
+			get {
+				return Difficulty.Master | Difficulty.Medium | Difficulty.Easy;
+			}
+		}
+
+		// The level of difficulty selected for the current game
+		public virtual Difficulty CurrentDifficulty {
+			set {
+				difficulty = value;
+			}
+			get {
+				return difficulty;
+			}
+		}
+
+		public abstract string Name {
+			get;
+		}
+
+		public string TipString {
+			get { 
+				string tip = Tip;
+	
+				if (tip != string.Empty)
+					tip_used = true;
+
+				return tip;
+			}
+		}
+
+		public virtual string Tip {
+			get { return string.Empty;}
+		}
+	
+		public virtual bool ButtonsActive {
+			get { return true;}
+		}
+
+		public virtual Types Type {
+			get { return Types.LogicPuzzle;}
+		}
+
+		public bool DrawAnswer {
+			get { return draw_answer; }
+			set { draw_answer = value; }
+		}
+
+		// An initialized game cannot be playable (for example, missing external files)
+		public virtual bool IsPlayable {
+			get { return true;}
+		}
+
+		public virtual double DrawAreaX {
+			get {return 0.1;}
+		}
+
+		public virtual double DrawAreaY {
+			get {return 0.1;}
+		}
+
+		public virtual double DrawAreaWidth {
+			get {return 1 - DrawAreaX * 2;}
+		}
+
+		public virtual double DrawAreaHeight {
+			get {return 1 - DrawAreaY * 2;}
+		}
+
+		public virtual double LineWidth {
+			get {return 0.005; }
+		}
+
+		public virtual Cairo.Color DefaultDrawingColor {
+			get {return default_color; }
+		}
+
+		public TimeSpan GameTime {
+			get {return game_time; }
+			set {game_time = value; }
+		}
+
+		public bool Won {
+			get { return won; }
+			set { won = value; }
+		}
+
+		// Average time in seconds that a player is expected to complete this game
+		public int AverageTime {
+			get {
+				double factor;
+
+				switch (CurrentDifficulty) {
+				case Difficulty.Easy:
+					factor = 1.3;
+					break;
+				case Difficulty.Master:
+					factor = 0.7;
+					break;		
+				case Difficulty.Medium:
+				default:
+					factor = 1.0;
+					break;		
+				}
+				
+				switch (Type) {
+				case Types.MemoryTrainer:
+					return (int) (30 * factor);
+				case Types.MathTrainer:
+					return (int) (60 * factor);
+				}
+				return (int) (120 * factor); // Default for all games (logic)
+			}
+		}
+
+		//
+		// Score algorithm return a value between 0 and 10
+		//
+		public virtual int Score {
+			get {
+				double score;
+				double seconds = GameTime.TotalSeconds;
+
+				if (won == false) {
+					score = 0;
+				} else {		
+					score = 10;
+			
+					// Time
+					if (seconds > AverageTime * 3) {
+						score = score * 0.6;
+					}
+					else if (seconds > AverageTime * 2) {
+						score = score * 0.7;
+					} else if (seconds > AverageTime) {
+						score = score * 0.8;
+					}
+		
+					if (tip_used) {
+						score = score * 0.8;
+					}
+				}
+
+				return (int) score;
+			}
+		}
+	
+		public abstract void Initialize ();
+		public virtual void Finish () {}
+
+		static public string GetPossibleAnswer (int answer)
+		{
+			switch (answer) {
+				// Translators Note
+				// The following series of answers may need to be adapted
+				// in cultures with alphabets different to the Latin one.
+				// The idea is to enumerate a sequence of possible answers
+				// For languages represented with the Latin alphabet use 
+				// the same than English
+			case 0: // First possible answer for a series (e.g.: Figure A)
+				return Catalog.GetString ("A");
+			case 1: // Second possible answer for a series
+				return Catalog.GetString ("B");
+			case 2: // Third possible answer for a series
+				return Catalog.GetString ("C");
+			case 3: // Fourth possible answer for a series
+				return Catalog.GetString ("D");
+			case 4: // Fifth possible answer for a series
+				return Catalog.GetString ("E");
+			case 5: // Sixth possible answer for a series
+				return Catalog.GetString ("F");
+			case 6: // Seventh possible answer for a series
+				return Catalog.GetString ("G");
+			case 7: // Eighth possible answer for a series
+				return Catalog.GetString ("H");
+			default:
+				return string.Empty;
+			}
+		}
+
+		public string GetPossibleFigureAnswer (int answer)
+		{
+			return String.Format (Catalog.GetString ("Figure {0}"), GetPossibleAnswer (answer));
+		}
+
+		public virtual void Draw (CairoContextEx gr, int width, int height, bool rtl)
+		{
+			gr.Scale (width, height);
+			gr.DrawBackground ();
+			gr.Color = new Cairo.Color (0, 0, 0);
+			gr.LineWidth = LineWidth;
+		}
+
+		public virtual void DrawPreview (CairoContextEx gr, int width, int height, bool rtl)
+		{
+			Draw (gr, width, height, rtl);
+		}
+
+		public virtual bool CheckAnswer (string answer)
+		{
+			return (String.Compare (answer, right_answer, true) == 0);
+		}
+
+		// 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)
+		{
+			string str;
+
+			switch (type) 
+			{
+				case Game.Types.LogicPuzzle:
+					str = Catalog.GetString ("Logic");
+					break;
+				case Game.Types.MemoryTrainer:
+					str = Catalog.GetString ("Memory");
+					break;
+				case Game.Types.MathTrainer:
+					str = Catalog.GetString ("Mental Calculation");
+					break;
+				case Game.Types.VerbalAnalogy:
+					str = Catalog.GetString ("Verbal");
+					break;
+				default:
+					str = string.Empty;
+					break;
+			}
+			return str;
+		}
+	}
+}
diff --git a/src/Core/Main/GameManager.cs b/src/Core/Main/GameManager.cs
new file mode 100644
index 0000000..17716b1
--- /dev/null
+++ b/src/Core/Main/GameManager.cs
@@ -0,0 +1,463 @@
+/*
+ * Copyright (C) 2007-2009 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 System.IO;
+using System.Collections;
+using System.Collections.Generic;
+using System.Reflection;
+using Mono.Unix;
+
+#if MONO_ADDINS
+using Mono.Addins;
+using Mono.Addins.Setup;
+#endif
+
+using gbrainy.Core.Main.Verbal;
+
+namespace gbrainy.Core.Main
+{
+	public class GameManager
+	{
+		// Serves analogies as their container class is still not exhausted
+		// This is used to make sure that the analogies are not repeated within a game session
+		public class AnalogiesManager
+		{
+			List <Analogies> analogies;
+
+			public AnalogiesManager (Type [] types)
+			{
+				analogies = new List <Analogies> ();
+			
+				foreach (Type type in types)
+				{
+					Analogies analogy;
+
+					analogy = (Analogies) Activator.CreateInstance (type, true);
+					analogies.Add (analogy);
+				}
+			}
+
+			public void Initialize ()
+			{
+				foreach (Analogies analogy in analogies)
+					analogy.CurrentIndex = 0;
+			}
+
+			public bool IsExhausted {
+				get {
+					foreach (Analogies analogy in analogies)
+					{
+						if (analogy.IsExhausted == false)
+							return false;
+					}
+					return true;
+				}
+			}
+		}
+
+		static Type[] VerbalAnalogiesInternal = new Type[] 
+		{
+			typeof (AnalogiesQuestionAnswer),
+			typeof (AnalogiesMultipleOptions),
+			typeof (AnalogiesPairOfWordsOptions),
+			typeof (AnalogiesPairOfWordsCompare),
+		};
+
+		bool once;
+		GameSession.Types game_type;
+		ArrayListIndicesRandom list;
+		IEnumerator enumerator;
+		List <Type> games;
+		Game.Difficulty difficulty;
+		List <Type> LogicPuzzles;
+		List <Type> CalculationTrainers;
+		List <Type> MemoryTrainers;
+		List <Type> VerbalAnalogies;
+		AnalogiesManager analogies_manager;
+	
+		public GameManager ()
+		{
+			game_type = GameSession.Types.None;
+			difficulty = Game.Difficulty.Medium;
+			games = new List <Type> ();
+			VerbalAnalogies = new List <Type> (VerbalAnalogiesInternal);
+
+			LoadAssemblyGame ();
+
+			if (LogicPuzzles == null)
+				LogicPuzzles = new List <Type> ();
+
+			if (MemoryTrainers == null)
+				MemoryTrainers = new List <Type> ();
+
+			if (CalculationTrainers == null)
+				CalculationTrainers = new List <Type> ();
+
+			LoadPlugins ();
+
+			if (once == false) {
+				once = true;
+				Console.WriteLine (Catalog.GetString ("Games registered: {0}: {1} logic puzzles, {2} calculation trainers, {3} memory trainers, {4} verbal analogies"), 
+					LogicPuzzles.Count + CalculationTrainers.Count + MemoryTrainers.Count + VerbalAnalogies.Count,
+					LogicPuzzles.Count, CalculationTrainers.Count, MemoryTrainers.Count, VerbalAnalogies.Count);
+			}
+
+			analogies_manager = new AnalogiesManager (VerbalAnalogiesInternal);
+			//GeneratePDF ();
+		}
+
+		public GameSession.Types GameType {
+			get {return game_type; }
+			set {
+				if (game_type == value)
+					return;
+			
+				game_type = value;
+				BuildGameList ();
+			}
+		}
+
+		public Game.Difficulty Difficulty {
+			set {
+				difficulty = value;
+				BuildGameList ();
+			}
+			get {
+				return difficulty;
+			}
+		}
+
+		// Used from CustomGameDialog only
+		public Type[] CustomGames {
+			get { 
+				Type[] list = new Type [LogicPuzzles.Count + CalculationTrainers.Count + MemoryTrainers.Count + VerbalAnalogies.Count];
+				int idx = 0;
+
+				for (int i = 0; i < LogicPuzzles.Count; i++, idx++)
+					list[idx] = LogicPuzzles [i];
+
+				for (int i = 0; i < CalculationTrainers.Count; i++, idx++)
+					list[idx] = CalculationTrainers [i];
+
+				for (int i = 0; i < MemoryTrainers.Count; i++, idx++)
+					list[idx] = MemoryTrainers [i];
+
+				for (int i = 0; i < VerbalAnalogies.Count; i++, idx++)
+					list[idx] = VerbalAnalogies [i];
+
+				return list;
+			}
+			set {
+				games = new List <Type> (value.Length);
+				for (int i = 0; i < value.Length; i++)
+					games.Add (value[i]);
+
+				list = new ArrayListIndicesRandom (games.Count);
+				Initialize ();
+			}
+		}
+
+		// Dynamic load of the gbrainy.Games.Dll assembly
+		void LoadAssemblyGame ()
+		{
+			const string ASSEMBLY = "gbrainy.Games.dll";
+			const string CLASS = "gbrainy.Games.GameList";
+			const string LOGIC_METHOD = "LogicPuzzles";
+			const string CALCULATION_METHOD = "CalculationTrainers";
+			const string MEMORY_METHOD = "MemoryTrainers";
+
+			Assembly asem;
+			Type type = null;
+			PropertyInfo prop;
+			object obj;
+
+			try
+			{
+				// Expects the assembly to be in the same dir than this assembly
+				Assembly asm = Assembly.GetExecutingAssembly ();
+				string asm_dir = System.IO.Path.GetDirectoryName (asm.Location);
+
+				asem = Assembly.LoadFrom (Path.Combine (asm_dir, ASSEMBLY));
+
+				foreach (Type t in asem.GetTypes()) 
+				{
+					if (t.FullName == CLASS)
+					{
+						type = t;
+						break;
+					}
+				}
+
+				obj = Activator.CreateInstance (type);
+
+				prop = type.GetProperty (LOGIC_METHOD);
+				LogicPuzzles = new List <Type> ((Type []) prop.GetValue (obj, null));
+
+				prop = type.GetProperty (MEMORY_METHOD);
+				MemoryTrainers = new List <Type> ((Type []) prop.GetValue (obj, null));
+
+				prop = type.GetProperty (CALCULATION_METHOD);
+				CalculationTrainers = new List <Type> ((Type []) prop.GetValue (obj, null));
+			}
+
+			catch (Exception e)
+			{
+				Console.WriteLine ("GameManager.LoadAssemblyGame. Exception: {0}", e);
+			}
+		}
+
+		void LoadPlugins ()
+		{
+
+	#if MONO_ADDINS
+			try {
+				ExtensionNodeList addins;
+				Game game;
+				string dir = System.IO.Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData), "gbrainy");
+		
+				AddinManager.Initialize (dir);
+				Console.WriteLine ("Pluggin database:" + dir);
+				AddinManager.Registry.Update (null);
+				new SetupService (AddinManager.Registry);
+
+				addins = AddinManager.GetExtensionNodes ("/gbrainy/games/logic");
+				foreach (TypeExtensionNode node in addins) {
+					game = (Game) node.CreateInstance ();
+					Console.WriteLine ("Loading external logic game: {0}", game);
+					LogicPuzzles.Add (game.GetType ());
+				}
+		
+				addins = AddinManager.GetExtensionNodes ("/gbrainy/games/memory");
+				foreach (TypeExtensionNode node in addins) {
+					game = (Game) node.CreateInstance ();
+					Console.WriteLine ("Loading external memory game: {0}", game);
+					MemoryTrainers.Add (game.GetType ());
+				}
+
+				addins = AddinManager.GetExtensionNodes ("/gbrainy/games/calculation");
+				foreach (TypeExtensionNode node in addins) {
+					game = (Game) node.CreateInstance ();
+					Console.WriteLine ("Loading external calculation game: {0}", game);
+					CalculationTrainers.Add (game.GetType ());
+				}
+
+				addins = AddinManager.GetExtensionNodes ("/gbrainy/games/verbal");
+				foreach (TypeExtensionNode node in addins) {
+					game = (Game) node.CreateInstance ();
+					Console.WriteLine ("Loading external verbal analogy game: {0}", game);
+					VerbalAnalogies.Add (game.GetType ());
+				}
+			}
+			catch (Exception e)
+			{
+				Console.WriteLine (String.Format ("Exception {0} when loading the plugins", e));
+			}
+	#endif
+		}
+
+		void BuildGameList ()
+		{
+			analogies_manager.Initialize ();
+
+			if (GameType == GameSession.Types.Custom)
+				return;
+		
+			games.Clear ();
+			Random random = new Random ();
+
+			// For all games, 1/4 of the total are logic, 1/4 Memory, 1/4 calculation, 1/4 verbal analogies
+			if ((game_type & GameSession.Types.AllGames) == GameSession.Types.AllGames) {
+			
+				int idx_cal = 0, idx_mem = 0, idx_verb = 0;
+				ArrayListIndicesRandom idx_logic = new ArrayListIndicesRandom (LogicPuzzles.Count);
+				ArrayListIndicesRandom idx_memory = new ArrayListIndicesRandom (MemoryTrainers.Count);
+				ArrayListIndicesRandom idx_calculation = new ArrayListIndicesRandom (CalculationTrainers.Count);
+				ArrayListIndicesRandom idx_verbal = new ArrayListIndicesRandom (VerbalAnalogies.Count);
+
+				games.Clear ();
+				idx_memory.Initialize ();
+				idx_logic.Initialize ();
+				idx_calculation.Initialize ();
+				idx_verbal.Initialize ();
+
+				for (int i = 0; i < LogicPuzzles.Count; i++, idx_mem++, idx_cal++, idx_verb++) {
+
+					if (idx_cal == CalculationTrainers.Count) {
+						idx_cal = 0;
+						idx_calculation.Initialize ();
+					}
+
+					if (idx_mem == MemoryTrainers.Count) {
+						idx_mem = 0;
+						idx_memory.Initialize ();
+					}
+
+					if (idx_verb == VerbalAnalogies.Count) {
+						idx_verb = 0;
+						idx_verbal.Initialize ();
+					}
+
+					switch (random.Next (3)) {
+					case 0:
+						games.Add (CalculationTrainers [idx_calculation[idx_cal]]);
+						games.Add (LogicPuzzles [idx_logic[i]]);
+						games.Add (MemoryTrainers [idx_memory[idx_mem]]);
+						games.Add (VerbalAnalogies [idx_verbal[idx_verb]]);
+						break;
+					case 1:
+						games.Add (MemoryTrainers [idx_memory[idx_mem]]);
+						games.Add (CalculationTrainers [idx_calculation[idx_cal]]);
+						games.Add (VerbalAnalogies [idx_verbal[idx_verb]]);
+						games.Add (LogicPuzzles [idx_logic[i]]);
+						break;
+					case 2:
+						games.Add (CalculationTrainers [idx_calculation[idx_cal]]);
+						games.Add (VerbalAnalogies [idx_verbal[idx_verb]]);
+						games.Add (MemoryTrainers [idx_memory[idx_mem]]);
+						games.Add (LogicPuzzles [idx_logic[i]]);
+						break;
+					}
+				}
+			} else {
+
+				if ((game_type & GameSession.Types.LogicPuzzles) == GameSession.Types.LogicPuzzles) {
+					for (int i = 0; i < LogicPuzzles.Count; i++)
+						games.Add (LogicPuzzles [i]);
+				}
+
+				if ((game_type & GameSession.Types.CalculationTrainers) == GameSession.Types.CalculationTrainers) {
+					for (int i = 0; i < CalculationTrainers.Count; i++)
+						games.Add (CalculationTrainers [i]);
+				}
+
+				if ((game_type & GameSession.Types.MemoryTrainers) == GameSession.Types.MemoryTrainers) {
+					for (int i = 0; i < MemoryTrainers.Count; i++)
+						games.Add (MemoryTrainers [i]);
+				}
+
+				if ((game_type & GameSession.Types.VerbalAnalogies) == GameSession.Types.VerbalAnalogies) {
+					for (int i = 0; i < VerbalAnalogies.Count; i++)
+						games.Add (VerbalAnalogies [i]);
+				}
+
+			}
+
+			list = new ArrayListIndicesRandom (games.Count);
+			Initialize ();
+		}
+
+		void Initialize ()
+		{
+			if ((game_type & GameSession.Types.AllGames) == GameSession.Types.AllGames) { // The game list has been already randomized
+				list.Clear ();
+				for (int i = 0; i < games.Count; i++)
+					list.Add (i);
+			} else
+				list.Initialize ();
+
+			enumerator = list.GetEnumerator ();
+		}
+	
+		public Game GetPuzzle ()
+		{
+			Game puzzle, first = null;
+
+			while (true) {
+
+				if (enumerator.MoveNext () == false) { // All the games have been played, restart again 
+					Initialize ();
+					enumerator.MoveNext ();
+
+					if (analogies_manager.IsExhausted == true)
+						analogies_manager.Initialize ();
+				}
+				puzzle =  (Game) Activator.CreateInstance ((Type) games [(int) enumerator.Current], true);
+				//puzzle =  (Game) Activator.CreateInstance (LogicPuzzles [37], true);
+
+				if (first != null && first.GetType () == puzzle.GetType ())
+					break;
+
+				if (puzzle.IsPlayable == false)
+					continue;
+
+				Analogies analogy = puzzle as Analogies;
+				if (analogy != null && analogy.IsExhausted == true)
+					continue;
+				
+				if (first == null)
+					first = puzzle;
+
+				if ((puzzle.GameDifficulty & difficulty) == difficulty)
+					break;
+			}
+
+			puzzle.CurrentDifficulty = Difficulty;
+			return puzzle;
+		}
+
+	#if _PDF_
+		// Generates a single PDF document with all the puzzles contained in gbrainy (4 games per page)
+		public void GeneratePDF ()
+		{
+			int width = 400, height = 400, margin = 20, x, y, cnt, games_page = 4;
+			Game puzzle;
+			game_type = GameSession.Types.AllGames;
+			Type [] allgames = CustomGames;
+		
+			for (int i = 0; i < allgames.Length; i++)
+				games.Add (allgames [i]);
+
+			PdfSurface pdf = new PdfSurface ("games.pdf", (width + margin) * 2, (height + margin) * games_page / 2);
+			x = y = cnt = 0;
+			CairoContextEx cr = new CairoContextEx (pdf);
+			for (int game = 0; game < games.Count; game++)
+			{
+				puzzle =  (Game) Activator.CreateInstance ((Type) games [game], true);
+				puzzle.Initialize ();
+				cnt++;
+				cr.Save ();
+				cr.Translate (x, y);
+				cr.Rectangle (0, 0, width, height);;	
+				cr.Clip ();
+				cr.Save ();
+				puzzle.DrawPreview (cr, width, height);
+				x += width + margin;
+				if (x > width + margin) {
+					x = 0;
+					y += height + margin;
+				}
+				cr.Restore ();
+				cr.MoveTo (50,  height - 10);
+				cr.ShowText (String.Format ("Game: {0} / D:{1}", puzzle.Name, puzzle.GameDifficulty));
+				cr.Stroke ();
+				cr.Restore ();
+
+				if (cnt >= games_page) {
+					cr.ShowPage ();
+					cnt = x = y = 0;
+				}
+			}
+			pdf.Finish ();
+			((IDisposable)cr).Dispose();
+			return;
+		}
+	#endif
+	}
+}
diff --git a/src/Core/Main/GameSession.cs b/src/Core/Main/GameSession.cs
new file mode 100644
index 0000000..95fc618
--- /dev/null
+++ b/src/Core/Main/GameSession.cs
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2007 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 Mono.Unix;
+using System.Timers;
+using System.ComponentModel;
+
+using gbrainy.Core.Views;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Core.Main
+{
+	public class GameSession : IDrawable, IDrawRequest
+	{
+		[Flags]
+		public enum Types
+		{	
+			None			= 0,
+			LogicPuzzles		= 2,
+			MemoryTrainers		= 4,
+			CalculationTrainers	= 8,
+			VerbalAnalogies		= 16,
+			Custom			= 32,
+			TrainersOnly		= MemoryTrainers | CalculationTrainers,
+			AllGames		= MemoryTrainers | CalculationTrainers | LogicPuzzles
+		}
+
+		private enum ScoresType
+		{
+			None = 0,
+			LogicPuzzles,
+			MemoryTrainers,
+			CalculationTrainers,
+			VerbalAnalogies,
+			Last			
+		}
+
+		public enum SessionStatus
+		{
+			NotPlaying,
+			Playing,
+			Answered,
+			Finished,
+		}
+
+		private TimeSpan game_time;
+		private int games_played;
+		private int games_won;
+		private Game current_game;
+		private GameManager game_manager;
+		private System.Timers.Timer timer;
+		private bool paused;
+		private string current_time;
+		private TimeSpan one_sec = TimeSpan.FromSeconds (1);
+		private int [] scores;
+		private int [] games;
+		private int total_score;
+		private bool scored_game;
+		private SessionStatus status;
+		private ViewsControler controler;
+		private ISynchronizeInvoke synchronize;
+
+		public event EventHandler DrawRequest;
+	
+		public GameSession ()
+		{
+			game_manager = new GameManager ();
+			game_time = TimeSpan.Zero;
+
+			timer = new System.Timers.Timer ();
+			timer.Elapsed += TimerUpdater;
+			timer.Interval = (1 * 1000); // 1 second
+		
+			scores = new int [(int) ScoresType.Last];
+			games = new int [(int) ScoresType.Last];
+			controler = new ViewsControler (this);
+			Status = SessionStatus.NotPlaying;
+		}
+
+		public ISynchronizeInvoke SynchronizingObject { 
+			set { synchronize = value; }
+			get { return synchronize; }
+		}
+	
+		public Types Type {
+			get {return game_manager.GameType; }
+			set {game_manager.GameType = value; }
+		}
+
+		public Game.Difficulty Difficulty {
+			get {return game_manager.Difficulty; }
+			set {game_manager.Difficulty = value; }
+		}
+	
+		public TimeSpan GameTime {
+			get {return game_time; }
+			set {game_time = value; }
+		}
+
+		public int GamesPlayed {
+			get {return games_played; }
+			set { games_played = value;}
+		}
+		
+		public int GamesWon {
+			get {return games_won; }
+			set {games_won = value; }
+		}
+
+		public bool Paused {
+			get {return paused; }
+			set {paused = value; }
+		}
+
+		public Game CurrentGame {
+			get {return current_game; }
+			set {
+				current_game = value; 
+				controler.Game = value;
+			}
+		}
+
+		public bool EnableTimer {
+			get {return timer.Enabled; }
+			set {timer.Enabled = value; }
+		}
+
+		public SessionStatus Status {
+			get {return status; }
+			set {
+				status = value;
+				controler.Status = value;
+			}
+		}
+
+		public GameManager GameManager {
+			get {return  game_manager;}
+		}
+
+		public int TotalScore {
+			get {return total_score;}
+		}
+
+		public int LogicScore {
+			get {
+				if (games [(int) ScoresType.LogicPuzzles] == 0)
+					return 0;
+			
+				return scores [(int) ScoresType.LogicPuzzles] * 10 / games [(int) ScoresType.LogicPuzzles];
+			}
+		}
+
+		public int MemoryScore {
+			get {
+				if (games [(int) ScoresType.MemoryTrainers] == 0)
+					return 0;
+			
+				return scores [(int) ScoresType.MemoryTrainers] * 10 / games [(int) ScoresType.MemoryTrainers];
+			}
+		}
+
+		public int MathScore {
+			get {
+				if (games [(int) ScoresType.CalculationTrainers] == 0)
+					return 0;
+			
+				return scores [(int) ScoresType.CalculationTrainers] * 10 / games [(int) ScoresType.CalculationTrainers];
+			}
+		}
+
+		public int VerbalScore {
+			get {
+				if (games [(int) ScoresType.VerbalAnalogies] == 0)
+					return 0;
+			
+				return scores [(int) ScoresType.VerbalAnalogies] * 10 / games [(int) ScoresType.VerbalAnalogies];
+			}
+		}
+
+		public string TimePlayed {
+			get {
+				return (current_time == null) ? TimeSpanToStr (TimeSpan.FromSeconds (0)) : current_time;
+			}
+		}
+
+		public string TimePerGame {
+			get {
+				TimeSpan average;
+
+				average = (games_played > 0) ? TimeSpan.FromSeconds (game_time.TotalSeconds / games_played) : game_time;
+				return TimeSpanToStr (average);
+			}
+		}
+
+		public string StatusText {
+			get {
+				if (Status == SessionStatus.NotPlaying)
+					return string.Empty;
+
+				String text;
+				text = String.Format (Catalog.GetString ("Games played: {0} ({1}% score)"),games_played, total_score);
+				text += String.Format (Catalog.GetString (" - Time: {0}"), current_time);
+
+				if (CurrentGame != null)
+	 				text += " " + String.Format (Catalog.GetString ("- Game: {0}"), CurrentGame.Name);
+	
+				return text;
+			}
+		}
+	
+		public void NewSession ()
+		{
+			if (Status != SessionStatus.NotPlaying)
+				EndSession ();
+
+			games_played = 0;
+			games_won = 0;
+			game_time = TimeSpan.Zero;
+			timer.Enabled = true;
+		}
+
+		public void EndSession ()
+		{
+			if (CurrentGame != null)
+				CurrentGame.Finish ();
+
+			timer.Enabled = false;
+			paused = false;
+			CurrentGame = null;
+			games_played = 0;
+			games_won = 0;
+			game_time = TimeSpan.Zero;
+			current_time = TimeSpanToStr (game_time);
+			scores = new int [(int) ScoresType.Last];
+			games = new int [(int) ScoresType.Last];
+			total_score = 0;
+			scored_game = false;
+			Status = SessionStatus.Finished;
+		}
+
+		public void NextGame ()
+		{	
+			if (CurrentGame != null)
+				CurrentGame.Finish ();
+
+			games_played++;
+			CurrentGame = game_manager.GetPuzzle ();
+			CurrentGame.SynchronizingObject = SynchronizingObject;
+			CurrentGame.DrawRequest += GameDrawRequest;
+			CurrentGame.Initialize ();
+
+			CurrentGame.GameTime = TimeSpan.Zero;
+			scored_game = false;
+			Status = SessionStatus.Playing;
+		}
+
+		public void Pause ()
+		{
+			timer.Enabled = false;
+			paused = true;
+			current_time = Catalog.GetString ("Paused");
+		}
+
+		public void Resume ()
+		{
+			timer.Enabled = true;
+			paused = false;
+		}
+
+		public void ScoreGame ()
+		{
+			if (CurrentGame == null || scored_game == true)
+				return;
+
+			switch (CurrentGame.Type) {
+			case Game.Types.LogicPuzzle:
+				scores [(int) ScoresType.LogicPuzzles] += CurrentGame.Score;
+				games [(int) ScoresType.LogicPuzzles]++;
+				break;
+			case Game.Types.MemoryTrainer:
+				scores [(int) ScoresType.MemoryTrainers] += CurrentGame.Score;
+				games [(int) ScoresType.MemoryTrainers]++;
+				break;
+			case Game.Types.MathTrainer:
+				scores [(int) ScoresType.CalculationTrainers] += CurrentGame.Score;
+				games [(int) ScoresType.CalculationTrainers]++;
+				break;
+			case Game.Types.VerbalAnalogy:
+				scores [(int) ScoresType.VerbalAnalogies] += CurrentGame.Score;
+				games [(int) ScoresType.VerbalAnalogies]++;
+				break;
+			default:
+				break;
+			}
+		
+			total_score = 0;
+			for (int i = 0; i < (int) ScoresType.Last; i++) {
+				total_score += scores [i];
+			}
+
+			total_score = total_score * 10 / games_played;
+			scored_game = true;
+		}	
+
+
+		private void TimerUpdater (object source, ElapsedEventArgs e)
+		{
+			lock (this) {
+				game_time = game_time.Add (one_sec);
+				CurrentGame.GameTime = CurrentGame.GameTime + one_sec;
+				current_time = TimeSpanToStr (game_time);
+			}
+
+			//Application.Invoke (delegate {	app.UpdateStatusBar (); } );
+		}
+
+		static private string TimeSpanToStr (TimeSpan time)
+		{
+			string fmt = time.ToString ();
+			int i = fmt.IndexOf ('.');
+			if (i > 0 && fmt.Length - i > 2)
+				fmt = fmt.Substring (0, i);
+
+			return fmt;
+		}
+
+		// A game has requested a redraw, scale the request to the object
+		// subscribed to GameSession.GameDrawRequest
+		public void GameDrawRequest (object o, EventArgs args)
+		{
+			//Console.WriteLine ("GameSession.GameRequestRedraw {0}", o); 
+			if (DrawRequest != null)
+				DrawRequest (this, EventArgs.Empty);
+		}
+
+		public virtual void Draw (CairoContextEx gr, int width, int height, bool rtl)
+		{
+			//Console.WriteLine ("GameSession.Draw");
+			controler.CurrentView.Draw (gr, width, height, rtl);
+		}
+
+	}
+}
diff --git a/src/Core/Main/GameTips.cs b/src/Core/Main/GameTips.cs
new file mode 100644
index 0000000..0c29c4e
--- /dev/null
+++ b/src/Core/Main/GameTips.cs
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2007-2008 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 Mono.Unix;
+
+namespace gbrainy.Core.Main
+{
+	static class GameTips
+	{
+		static ArrayListIndicesRandom random_indices;
+		static int idx = 0;
+	
+		static public int Count {
+			get { return 11; }
+		}
+
+		// Gets a random tip from the list
+		static public string Tip {
+			get {
+				if (idx + 1 >= Count || random_indices == null) {
+					random_indices = new ArrayListIndicesRandom (Count);
+					random_indices.Initialize ();
+					idx = 0;
+				}
+
+				return GetTip (idx++); 
+			}
+
+		}
+
+		static public string GetTip (int tip)
+		{
+			switch (tip) {
+			case 0:
+				return Catalog.GetString ("Read the instructions carefully and identify the data and given clues.");
+			case 1:
+				return Catalog.GetString ("To score the player gbrainy uses the time and tips needed to complete each game.");
+			case 2:
+				return Catalog.GetString ("In logic games, elements that may seem irrelevant can be very important.");
+			case 3:
+				return Catalog.GetString ("Break the mental blocks and look into the boundaries of problems.");
+			case 4:
+				return Catalog.GetString ("Enjoy making mistakes, they are part of the learning process.");
+			case 5:
+				return Catalog.GetString ("Do all the problems, even the difficult ones. Improvement comes from practising.");
+			case 6:
+				return Catalog.GetString ("Play on a daily basis, you will notice progress soon.");
+			case 7: // Translators: Custom Game Selection is a menu option
+				return Catalog.GetString ("Use the 'Custom Game Selection' to choose exactly which games you want to play.");
+			case 8:
+				return Catalog.GetString ("Use the Settings to adjust the difficulty level of the game.");
+			case 9:
+				return Catalog.GetString ("Association of elements is a common technique for remembering things.");
+			case 10:
+				return Catalog.GetString ("Grouping elements into categories is a common technique for remembering things.");
+			}
+
+			return string.Empty;
+		}
+	}
+}
diff --git a/src/Core/Main/Memory.cs b/src/Core/Main/Memory.cs
new file mode 100644
index 0000000..77e779c
--- /dev/null
+++ b/src/Core/Main/Memory.cs
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using Mono.Unix;
+using System.Timers;
+
+using gbrainy.Core.Views;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Core.Main
+{
+	public abstract class Memory : Game
+	{
+		protected int time_left;
+		protected int total_time;
+		protected System.Timers.Timer timer;
+		private bool request_answer = false;
+		private bool buttons_active;
+		protected bool shade = false;
+		protected const int shading_time = 15;
+		private LinearGradient gradient = null;
+		protected double alpha;
+		private bool draw_timer;
+		CountDownView downview;
+
+		//public event EventHandler RequestRedraw;
+
+		public override bool ButtonsActive {
+			get { return buttons_active;}
+		}
+
+		public abstract string MemoryQuestion {
+			get;
+		}
+
+		public override string Question {
+			get {
+				return Catalog.GetString ("Memorize the objects below in the given time");
+			}
+		}
+
+		public override Types Type {
+			get { return Game.Types.MemoryTrainer;}
+		}
+
+		public int TotalTime {
+			get { return total_time;}
+			set { 
+				total_time = value;
+				time_left = value;
+			}
+		}
+
+		public override void Initialize ()
+		{
+			if (Preferences.GetBoolValue (Preferences.MemQuestionWarnKey) == false) {
+				InitializeGame ();
+				return;
+			}
+
+			downview = new CountDownView (OnCountDownFinish);
+			downview.RequestRedraw += OnCountDownRedraw;
+		}
+
+		public void OnCountDownRedraw (object o, EventArgs args)
+		{
+			OnDrawRequest ();
+		}
+
+		void OnCountDownFinish (object source, EventArgs e)
+		{
+			downview.EndDrawCountDown ();
+			InitializeGame ();
+			downview = null;
+		}
+
+		void InitializeGame ()
+		{
+			timer = new System.Timers.Timer ();
+			timer.SynchronizingObject = SynchronizingObject;
+			timer.Elapsed += TimerUpdater;
+			timer.Interval = (1 * 100); // 0.1 seconds
+			buttons_active = false;
+			timer.Enabled = false;
+			Console.WriteLine ("Memory.InitializeGame (GtkSynchronize) is null {0}", SynchronizingObject == null);
+			alpha = 1;
+			draw_timer = false;
+
+			time_left = total_time = Preferences.GetIntValue (Preferences.MemQuestionTimeKey) * 10; // Seconds
+
+			StartTimer ();
+		}
+
+		public void StartTimer ()
+		{
+			Console.WriteLine ("Memory.StartTimer {0}", SynchronizingObject);
+			timer.Enabled = true;
+			draw_timer = true;
+		}
+
+		private void TimerUpdater (object source, ElapsedEventArgs e)
+		{
+			if (shade == false && time_left == 0) {
+				lock (this) {
+					time_left = shading_time;
+					shade = true;
+					draw_timer = false;
+				}
+				return;	
+			}	
+
+			if (time_left == 0) {
+				lock (this) {
+					shade = false;
+					timer.Enabled = false;
+					request_answer = true;
+					buttons_active = true;
+				}
+				/*if (App != null) {
+					Application.Invoke (delegate {
+						//App.UpdateQuestion (MemoryQuestion);
+						//App.ActiveInputControls (buttons_active);
+					});
+				}*/
+			} else {
+				lock (this) {
+					time_left--;
+				}
+			}
+	
+			OnDrawRequest ();
+		}
+
+		public override void Finish ()
+		{
+			timer.Enabled = false;
+		}		
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			if (downview != null) {
+				downview.Draw (gr, area_width, area_height, rtl);
+				return;
+			}
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			if (shade) {
+				if (alpha > 0)
+					alpha -= (1 / (double) shading_time);
+
+				gr.Color = new Color (DefaultDrawingColor.R, DefaultDrawingColor.G, DefaultDrawingColor.B, alpha);
+				DrawObjectToMemorize (gr, area_width, area_height);
+				return;
+			}
+		
+			alpha = 1;
+			gr.Color = new Color (DefaultDrawingColor.R, DefaultDrawingColor.G, DefaultDrawingColor.B, alpha);
+			if (request_answer && DrawAnswer == false) {
+				DrawPossibleAnswers (gr, area_width, area_height);
+			} else {
+				DrawObjectToMemorize (gr, area_width, area_height);			
+			}		
+		}
+
+		public override void DrawPreview (CairoContextEx gr, int width, int height, bool rtl)
+		{
+			gr.Scale (width, height);
+			gr.DrawBackground ();
+			gr.Color = new Cairo.Color (0, 0, 0);
+			gr.LineWidth = LineWidth;
+			DrawObjectToMemorize (gr, width, height);
+		}
+
+		public virtual void DrawPossibleAnswers (CairoContextEx gr, int area_width, int area_height) {}
+
+		public virtual void DrawObjectToMemorize (CairoContextEx gr, int area_width, int area_height)
+		{
+			double percentage;
+
+			if (draw_timer == false)
+				return;
+
+			percentage = 100 - ((time_left * 100) / total_time);
+			DrawTimeBar (gr, 0.1, 0.2, percentage);
+		}
+
+		public void DrawTimeBar (CairoContextEx gr, double x, double y, double percentage)
+		{
+			double width = 0.04, height = 0.6;
+			const double w = 0.003, h = 0.003;
+
+			gr.Save ();
+			gr.Color = new Color (0, 0, 0);	
+			gr.MoveTo (x, y);
+			gr.LineTo (x, y + height);
+			gr.LineTo (x + width, y + height);
+			gr.LineTo (x + width, y);
+			gr.LineTo (x, y);
+			gr.Stroke ();
+
+			x+= w;
+			y+= h;
+			width -= w * 2;
+			height -= h * 2;
+			y += height * (100 - percentage) / 100;
+			height *= percentage / 100;
+
+			if (gradient == null) {
+				gradient = new LinearGradient (x, y, x + width, y + height);
+				gradient.AddColorStop (0, new Color (1, 0, 0, 1));
+				gradient.AddColorStop (1, new Color (0.2, 0, 0, 1));
+			}
+
+			gr.Source = gradient;			
+			gr.MoveTo (x, y);
+			gr.LineTo (x, y + height);
+			gr.LineTo (x + width, y + height);
+			gr.LineTo (x + width, y);
+			gr.LineTo (x, y);
+			gr.FillPreserve ();
+			gr.Stroke ();
+			gr.Restore ();
+		}
+	}
+}
diff --git a/src/Core/Main/PlayerHistory.cs b/src/Core/Main/PlayerHistory.cs
new file mode 100644
index 0000000..7da06ae
--- /dev/null
+++ b/src/Core/Main/PlayerHistory.cs
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2008-2009 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 System.Collections.Generic;
+using System.IO;
+using System.Xml;
+using System.Xml.Serialization;
+
+namespace gbrainy.Core.Main
+{
+	public class PlayerHistory
+	{
+		private string file, config_path;
+		private List <GameHistory> games;
+
+		[Serializable]
+		public class GameHistory
+		{
+			public int games_played;
+			public int games_won;
+			public int total_score;
+			public int math_score;
+			public int logic_score;
+			public int memory_score;
+			public int verbal_score;
+		}
+
+		public PlayerHistory ()
+		{
+			config_path = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData);
+			config_path = Path.Combine (config_path, Defines.CONFIG_DIR);
+			file = Path.Combine (config_path, "PlayerHistory.xml");
+		}
+
+		public List <GameHistory> Games {
+			get {
+				if (games == null)
+				{
+					Load ();
+					if (games == null) 
+						games = new List <GameHistory> ();
+				}
+				return games; 
+			}
+		}
+
+		public void Clean ()
+		{
+			Games.Clear ();
+			Save ();
+		}
+
+		public void SaveGameSession (GameSession session)
+		{
+			if (session.GamesPlayed < Preferences.GetIntValue (Preferences.MinPlayedGamesKey))
+				return;
+
+			GameHistory history = new GameHistory ();
+	
+			history.games_played = session.GamesPlayed;
+			history.games_won = session.GamesWon;
+			history.math_score = session.MathScore;
+			history.logic_score = session.LogicScore;
+			history.memory_score = session.MemoryScore;
+			history.total_score = session.TotalScore;
+			history.verbal_score = session.VerbalScore;
+
+			if (Games.Count >= Preferences.GetIntValue (Preferences.MaxStoredGamesKey))
+				Games.RemoveAt (0);
+
+			Games.Add (history);
+			Save ();
+		}
+
+		private void Save ()
+		{
+			try {
+
+				if (!Directory.Exists (config_path))
+					Directory.CreateDirectory (config_path);
+
+				using (FileStream str = File.Create (file))
+				{
+					XmlSerializer bf = new XmlSerializer (typeof (List <GameHistory>));
+					bf.Serialize (str, Games);
+				}
+			}
+		
+			catch (Exception)
+			{
+			}
+		}
+
+		private void Load ()
+		{
+			try {
+				using (FileStream str = File.OpenRead (file))
+				{
+					XmlSerializer bf = new XmlSerializer (typeof (List <GameHistory>));
+				    	games = (List <GameHistory>) bf.Deserialize(str);
+				}
+			}
+			catch (Exception)
+			{
+			}
+		}
+	
+	}
+}
diff --git a/src/Core/Main/Preferences.cs b/src/Core/Main/Preferences.cs
new file mode 100644
index 0000000..b4e981d
--- /dev/null
+++ b/src/Core/Main/Preferences.cs
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2008 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 System.Collections.Generic;
+using System.IO;
+using System.Xml;
+using System.Xml.Serialization;
+using System.Text;
+
+namespace gbrainy.Core.Main
+{
+	public static class Preferences
+	{
+		static string file, config_path;
+		static SerializableDictionary <string, string > properties;
+
+		public const string MemQuestionWarnKey = "MemQuestionWarn";
+		public const string MemQuestionTimeKey = "MemQuestionTime";
+		public const string DifficultyKey = "Difficulty";
+		public const string MinPlayedGamesKey = "MinPlayedGames";
+		public const string MaxStoredGamesKey = "MaxStoredGamesKey";
+		public const string Toolbar = "Toolbar";
+
+		const string element_item = "item";
+		const string element_key = "key";
+		const string element_value = "value";
+		const string element_collection = "collection";
+
+	    	public class SerializableDictionary <TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
+		{
+			public System.Xml.Schema.XmlSchema GetSchema ()
+			{
+				return null;
+			}
+
+			public void ReadXml (System.Xml.XmlReader reader)
+			{
+				XmlSerializer key_serializer = new XmlSerializer (typeof (TKey));
+				XmlSerializer value_serializer = new XmlSerializer (typeof (TValue));
+		 		bool wasEmpty = reader.IsEmptyElement;
+
+			    	reader.Read ();
+
+				if (wasEmpty)
+					return;
+			
+				reader.ReadStartElement (element_collection);
+				while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
+				{
+					reader.ReadStartElement (element_item);
+
+					reader.ReadStartElement (element_key);
+					TKey key = (TKey) key_serializer.Deserialize (reader);
+					reader.ReadEndElement ();
+
+					reader.ReadStartElement (element_value);
+					TValue value = (TValue) value_serializer.Deserialize (reader);
+					reader.ReadEndElement();
+
+					this[key] = value; // already created in DefaultValues
+					reader.ReadEndElement();
+
+					reader.MoveToContent();
+				}
+				reader.ReadEndElement();
+			}
+
+			public void WriteXml (System.Xml.XmlWriter writer)
+			{
+				XmlSerializer key_serializer = new XmlSerializer (typeof(TKey));
+				XmlSerializer value_serializer = new XmlSerializer (typeof(TValue));
+
+				writer.WriteStartElement (element_collection);
+				foreach (TKey key in this.Keys)
+				{
+					writer.WriteStartElement (element_item);
+					writer.WriteStartElement (element_key);
+
+					key_serializer.Serialize (writer, key);
+					writer.WriteEndElement ();
+					writer.WriteStartElement (element_value);
+
+					TValue value = this[key];
+					value_serializer.Serialize (writer, value);
+					writer.WriteEndElement ();
+					writer.WriteEndElement ();
+				}
+				writer.WriteEndElement ();
+			}
+
+	    	}
+
+		static Preferences ()
+		{
+			properties = new SerializableDictionary <string, string> ();
+			config_path = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData);
+			config_path = Path.Combine (config_path, Defines.CONFIG_DIR);
+			file = Path.Combine (config_path, "Preferences.xml");
+			Load ();
+		}
+
+		public static void Save ()
+		{
+			try {
+				if (!Directory.Exists (config_path))
+					Directory.CreateDirectory (config_path);
+
+				XmlTextWriter writer = new XmlTextWriter (file, Encoding.UTF8);
+				writer.Formatting = Formatting.Indented;
+
+				properties.WriteXml (writer);
+				writer.Close ();
+			}		
+			catch (Exception)
+			{
+			}
+		}
+	
+		public static int GetIntValue (string key)
+		{
+			return Int32.Parse (properties [key]);
+		}
+
+		public static bool GetBoolValue (string key)
+		{
+			return Boolean.Parse (properties [key]);
+		}
+
+		public static void SetIntValue (string key, int value)
+		{
+			properties[key] = value.ToString ();
+		}
+
+		public static void SetBoolValue (string key, bool value)
+		{
+			properties [key] = value.ToString ();
+		}
+
+		static void LoadDefaultValues ()
+		{
+			properties.Add (MemQuestionWarnKey, true.ToString ());
+			properties.Add (MemQuestionTimeKey, "4");
+			properties.Add (DifficultyKey, ((int)(Game.Difficulty.Medium)).ToString ());
+			properties.Add (MinPlayedGamesKey, "5");
+			properties.Add (MaxStoredGamesKey, "20");
+			properties.Add (Toolbar, true.ToString ());
+		}
+
+		static void Load ()
+		{
+			try {
+				LoadDefaultValues ();
+				XmlTextReader reader = new XmlTextReader (file);
+				properties.ReadXml (reader);
+				reader.Close ();
+			}
+			catch (Exception)
+			{
+			}
+		}
+	
+	}
+}
diff --git a/src/Core/Main/Verbal/Analogies.cs b/src/Core/Main/Verbal/Analogies.cs
new file mode 100644
index 0000000..7790144
--- /dev/null
+++ b/src/Core/Main/Verbal/Analogies.cs
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2009 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 System.Collections.Generic;
+
+using Mono.Unix;
+
+namespace gbrainy.Core.Main.Verbal
+{
+	public abstract class Analogies : Game
+	{
+		protected Analogy current;
+
+		public override string Name {
+			get { return Catalog.GetString ("Verbal analogies"); }
+		}
+
+		public override string Question {
+			get {
+				if (current == null)
+					return string.Empty;
+
+				return current.question;
+			}
+		}
+
+		public override string Tip {
+			get {
+				if (current == null)
+					return null;
+				else
+					return current.tip;
+			}
+		}
+
+		public override bool IsPlayable {
+			get { return List.Count > 0;}
+		}
+
+		public override string Answer {
+			get {
+				if (current == null)
+					return string.Empty;
+
+				if (current.MultipleAnswers == true) 
+				{
+					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 = 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;
+			}
+		}
+
+		public override Types Type {
+			get { return Game.Types.VerbalAnalogy;}
+		}
+
+		public abstract ArrayListIndicesRandom Indices {
+			get;
+			set;
+		}
+
+		public abstract int CurrentIndex {
+			get;
+			set;
+		}
+
+		// Returns true when this game manager has no more games to server
+		public bool IsExhausted {
+			get { return CurrentIndex + 1 >= List.Count;}
+		}
+
+		public abstract Dictionary <int, Analogy> List {
+			get;
+		}
+
+		public Analogy GetNext ()
+		{
+			int idx;
+			Analogy analogy;
+
+			if (List.Count == 0)
+				return null;
+
+			if (Indices == null || CurrentIndex + 1 >= List.Count) {
+				Indices = new ArrayListIndicesRandom (List.Count);
+				Indices.Initialize ();
+			}
+			else
+				CurrentIndex++;
+
+			idx = Indices [CurrentIndex];
+		
+			try
+			{
+				List.TryGetValue (idx, out analogy);
+			}
+
+			catch (KeyNotFoundException)
+			{
+				analogy = null;
+			}
+
+			if (analogy != null && analogy.answers != null) { // Randomize answers order
+
+				ArrayListIndicesRandom indices;
+				string [] answers;
+				int new_right = 0;
+
+				indices = new ArrayListIndicesRandom (analogy.answers.Length);
+				answers = new string [analogy.answers.Length];
+
+				indices.Initialize ();
+
+				for (int i = 0; i < indices.Count; i++)
+				{
+					answers [i] = Catalog.GetString (analogy.answers [indices[i]]);
+					if (indices[i] == analogy.right)
+						new_right = i;
+				}
+				analogy.right = new_right;
+				analogy.answers = answers;
+			}
+
+			analogy.question = Catalog.GetString (analogy.question);
+
+			if (String.IsNullOrEmpty (analogy.tip) == false)
+				analogy.tip = Catalog.GetString (analogy.tip);
+
+			if (String.IsNullOrEmpty (analogy.rationale) == false)
+				analogy.rationale = Catalog.GetString (analogy.rationale);
+
+			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/Core/Main/Verbal/AnalogiesFactory.cs b/src/Core/Main/Verbal/AnalogiesFactory.cs
new file mode 100644
index 0000000..bdd9d1f
--- /dev/null
+++ b/src/Core/Main/Verbal/AnalogiesFactory.cs
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2009 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 System.Xml;
+using System.IO;
+using System.Collections.Generic;
+
+using Cairo;
+using Mono.Unix;
+
+namespace gbrainy.Core.Main.Verbal
+{
+	static public class AnalogiesFactory
+	{
+		static Dictionary <int, Analogy> [] analogies_arrays;
+		static bool read = false;
+	
+		public const char Separator = '|';
+
+		static AnalogiesFactory ()
+		{
+			analogies_arrays = new Dictionary <int, Analogy> [(int) Analogy.Type.Last];
+
+			for (int i = 0; i < (int) Analogy.Type.Last; i++)
+				analogies_arrays[i] = new Dictionary <int, Analogy> ();
+		}
+
+		static public Dictionary <int, Analogy> Get (Analogy.Type type)
+		{
+			if (read == false)
+				Read ();
+
+			return analogies_arrays [(int) type];
+		}
+
+		static public void Read ()
+		{
+			Analogy analogy;
+			string name;
+			List <string> answers;
+
+			try 
+			{
+				StreamReader myStream = new StreamReader (Defines.DATA_DIR + Defines.VERBAL_ANALOGIES);
+				XmlTextReader reader = new XmlTextReader (myStream);
+				answers = new List <string> ();
+
+				analogy = new Analogy ();
+				while (reader.Read ())
+				{
+					name = reader.Name.ToLower ();
+					switch (name) {
+					case "analogy":
+						if (reader.NodeType == XmlNodeType.Element) {
+							analogy = new Analogy ();
+							answers.Clear ();
+						}
+						else {
+							if (reader.NodeType == XmlNodeType.EndElement) {
+								analogy.answers = answers.ToArray ();
+								analogies_arrays [(int) analogy.type].Add (analogies_arrays [(int) analogy.type].Count, analogy);
+							}
+						}
+						break;
+					case "_question":
+						if (reader.NodeType != XmlNodeType.Element)
+							return;
+
+						string type;
+
+						type = reader.GetAttribute ("type");
+		
+						if (String.IsNullOrEmpty (type) == false) {
+							switch (type.ToLower ()) {
+							case "multipleoptions":
+								analogy.type = Analogy.Type.MultipleOptions;
+								break;
+							case "pairofwordsoptions":
+								analogy.type = Analogy.Type.PairOfWordsOptions;
+								break;
+							case "pairofwordscompare":
+								analogy.type = Analogy.Type.PairOfWordsCompare;
+								break;
+							default:
+								analogy.type = Analogy.Type.QuestionAnswer;
+								break;
+							}
+						}
+						analogy.question = reader.ReadElementString ();
+						break;
+					case "_tip":
+						if (reader.NodeType == XmlNodeType.Element)
+							analogy.tip = reader.ReadElementString ();
+
+						break;
+					case "_rationale":
+						if (reader.NodeType == XmlNodeType.Element)
+							analogy.rationale = reader.ReadElementString ();
+
+						break;
+					case "_answer":
+						if (reader.NodeType != XmlNodeType.Element)
+							break;
+	
+						string right;
+
+						right = reader.GetAttribute ("correct");
+		
+						if (String.IsNullOrEmpty (right) == false)
+							if (right.ToLower () == "yes")
+								analogy.right = answers.Count;
+					
+						answers.Add (reader.ReadElementString ());
+						break;
+					}
+				}
+
+				read = true;
+
+				int cnt = 0;	
+				for (int i = 0; i < (int) Analogy.Type.Last; i++) 
+				{
+					cnt += analogies_arrays[i].Count;
+
+					if (analogies_arrays[i].Count > 0) {
+						Console.WriteLine (Catalog.GetString ("Read {0} verbal analogies of type {1}"), analogies_arrays[i].Count, 
+							analogies_arrays[i][0].type.ToString ());
+					}
+				}
+			
+				Console.WriteLine (Catalog.GetString ("Read a total of {0} verbal analogies"), cnt);
+			}
+
+			catch (Exception e)
+			{
+				Console.WriteLine ("Error loading {0}. Exception {1}", Defines.DATA_DIR + Defines.VERBAL_ANALOGIES, e.Message);
+			}
+
+			finally
+			{
+				CheckEmpty ();
+			}
+		}
+
+		static void CheckEmpty ()
+		{
+			Analogy empty = new Analogy ();
+			empty.question = Catalog.GetString ("There are no verbal analogies available.");
+			bool all_empty = true;
+
+			for (int i = 0; i < (int) Analogy.Type.Last; i++)
+			{
+				if (analogies_arrays[i].Count > 0) {
+					all_empty = false;
+					break;	
+				}
+			}
+
+			if (all_empty == true)
+				analogies_arrays[0].Add (0, empty);
+		}
+	}
+}
diff --git a/src/Core/Main/Verbal/AnalogiesMultipleOptions.cs b/src/Core/Main/Verbal/AnalogiesMultipleOptions.cs
new file mode 100644
index 0000000..42ff5ca
--- /dev/null
+++ b/src/Core/Main/Verbal/AnalogiesMultipleOptions.cs
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2009 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 System.IO;
+using System.Collections.Generic;
+
+using Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Core.Main.Verbal
+{
+	public class AnalogiesMultipleOptions : Analogies
+	{
+		static protected Dictionary <int, Analogy> analogies;
+		static protected ArrayListIndicesRandom analogies_indices;
+		static protected int analogies_index = 0;
+
+		public AnalogiesMultipleOptions ()
+		{
+			if (analogies == null)
+				analogies = AnalogiesFactory. Get (Analogy.Type.MultipleOptions);
+		}
+
+		public override string Name {
+			get { return Catalog.GetString ("Multiple options");}
+		}
+
+		public override string Question {
+			get {
+				string str = string.Empty;
+
+				if (current == null)
+					return string.Empty;
+
+				if (current.answers == null)
+					return current.question;
+
+				for (int n = 0; n < current.answers.Length; n++)
+				{
+					str+= GetPossibleAnswer (n);
+
+					if (n +1 < current.answers.Length) {
+						// Translators: this the separator used when concatenating possible options for answering verbal analogies
+						// For example: "Possible correct answers are: a, b, c, d."						
+						str += Catalog.GetString (", ");
+					}
+				}
+
+				// Translators: {0} is replaced by a question and {1} by the suggestions on how to answer
+				// E.g: What is the correct option? Answer A, B, C.
+				return String.Format (Catalog.GetString ("{0} Answer {1}."),
+					current.question,
+					str);
+			}
+		}
+
+		public override ArrayListIndicesRandom Indices {
+			get { return analogies_indices; }
+			set { analogies_indices = value; }
+		}
+
+		public override int CurrentIndex {
+			get { return analogies_index; }
+			set { analogies_index = value; }
+		}
+
+		public override Dictionary <int, Analogy> List {
+			get { return analogies; }
+		}
+
+		public override void Initialize ()
+		{
+			current = GetNext ();
+
+			if (current == null || current.answers == null)
+				return;
+
+			right_answer = GetPossibleAnswer (current.right);
+		}
+	
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double x = DrawAreaX, y = DrawAreaY + 0.1;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			if (current == null || current.answers == null)
+				return;
+
+			gr.SetPangoLargeFontSize ();
+			gr.MoveTo (0.1, y);
+			gr.ShowPangoText (Catalog.GetString ("Possible answers are:"));
+
+			y += 0.12;
+			x += 0.05;
+			for (int n = 0; n < current.answers.Length; n++)
+			{
+				gr.MoveTo (x, y);
+				gr.ShowPangoText (String.Format ("{0}) {1}", GetPossibleAnswer (n), current.answers[n].ToString ()));
+				gr.Stroke ();
+				y += 0.15;
+			}
+		}
+	}
+}
diff --git a/src/Core/Main/Verbal/AnalogiesPairOfWordsCompare.cs b/src/Core/Main/Verbal/AnalogiesPairOfWordsCompare.cs
new file mode 100644
index 0000000..2953c79
--- /dev/null
+++ b/src/Core/Main/Verbal/AnalogiesPairOfWordsCompare.cs
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2009 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 System.IO;
+using System.Collections.Generic;
+
+using Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Core.Main.Verbal
+{
+	public class AnalogiesPairOfWordsCompare : Analogies
+	{
+		static protected Dictionary <int, Analogy> analogies;
+		static protected ArrayListIndicesRandom analogies_indices;
+		static protected int analogies_index = 0;
+
+		string samples, sample;
+
+		public AnalogiesPairOfWordsCompare ()
+		{
+			if (analogies == null)
+				analogies = AnalogiesFactory. Get (Analogy.Type.PairOfWordsCompare);
+		}
+
+		public override string Name {
+			get { return Catalog.GetString ("Pair of words compare");}
+		}
+
+		public override ArrayListIndicesRandom Indices {
+			get { return analogies_indices; }
+			set { analogies_indices = value; }
+		}
+
+		public override int CurrentIndex {
+			get { return analogies_index; }
+			set { analogies_index = value; }
+		}
+
+		public override Dictionary <int, Analogy> List {
+			get { return analogies; }
+		}
+
+		public override string Question {
+			get {
+				if (current == null)
+					return string.Empty;
+
+				if (current.answers == null)
+					return current.question;
+
+				return String.Format (Catalog.GetString (
+					"Given the pair of words below, which word has the closest relationship to '{0}'?"),
+					sample);
+			}
+		}
+
+		public override void Initialize ()
+		{
+			current = GetNext ();
+
+			if (current == null || current.answers == null)
+				return;
+
+			string [] items;
+
+			items = current.question.Split (AnalogiesFactory.Separator);
+
+			if (items.Length == 2)
+				sample = items [1].Trim ();
+			else
+				sample = string.Empty;
+
+			samples = items [0].Trim ();
+			right_answer = current.answers [current.right];
+		}
+	
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double y = DrawAreaY + 0.1;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			if (current == null || current.answers == null)
+				return;
+
+			gr.SetPangoLargeFontSize ();
+			gr.DrawTextCentered (0.5, y + 0.25,
+				String.Format (Catalog.GetString ("Words: {0}"), samples));
+		}
+	}
+}
diff --git a/src/Core/Main/Verbal/AnalogiesPairOfWordsOptions.cs b/src/Core/Main/Verbal/AnalogiesPairOfWordsOptions.cs
new file mode 100644
index 0000000..9d30a8c
--- /dev/null
+++ b/src/Core/Main/Verbal/AnalogiesPairOfWordsOptions.cs
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2009 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 System.IO;
+using System.Collections.Generic;
+
+using Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Core.Main.Verbal
+{
+	public class AnalogiesPairOfWordsOptions : Analogies
+	{
+		static protected Dictionary <int, Analogy> analogies;
+		static protected ArrayListIndicesRandom analogies_indices;
+		static protected int analogies_index = 0;
+
+		public AnalogiesPairOfWordsOptions ()
+		{
+			if (analogies == null)
+				analogies = AnalogiesFactory. Get (Analogy.Type.PairOfWordsOptions);
+		}
+
+		public override string Name {
+			get { return Catalog.GetString ("Pair of words");}
+		}
+
+		public override ArrayListIndicesRandom Indices {
+			get { return analogies_indices; }
+			set { analogies_indices = value; }
+		}
+
+		public override int CurrentIndex {
+			get { return analogies_index; }
+			set { analogies_index = value; }
+		}
+
+		public override Dictionary <int, Analogy> List {
+			get { return analogies; }
+		}
+
+		public override string Question {
+			get {
+				string str = string.Empty;
+	
+				if (current == null)
+					return string.Empty;
+
+				if (current.answers == null)
+					return current.question;
+
+				for (int n = 0; n < current.answers.Length; n++)
+				{
+					str+= GetPossibleAnswer (n);
+
+					if (n +1 < current.answers.Length) {
+						// Translators: this the separator used when concatenating possible options for answering verbal analogies
+						// For example: "Possible correct answers are: a, b, c, d."						
+						str += Catalog.GetString (", ");
+					}
+				}
+
+				return String.Format (Catalog.GetString (
+					"Given the pair of words '{0}', which of the possible answers has the closest in relationship to the given pair? Answer {1}."),
+					current.question,
+					str);
+			}
+		}
+
+		public override void Initialize ()
+		{
+			current = GetNext ();
+
+			if (current == null || current.answers == null)
+				return;
+
+			right_answer = GetPossibleAnswer (current.right);
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double x = DrawAreaX, y = DrawAreaY + 0.1;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			if (current == null || current.answers == null || current.answers.Length <= 1)
+				return;
+
+			gr.SetPangoLargeFontSize ();
+			gr.MoveTo (0.1, y);
+			gr.ShowPangoText (Catalog.GetString ("Possible answers are:"));
+			y += 0.12;
+			x += 0.05;
+			for (int n = 0; n < current.answers.Length; n++)
+			{
+				gr.MoveTo (x, y);
+				gr.ShowPangoText (String.Format ("{0}) {1}", GetPossibleAnswer (n), current.answers[n].ToString ()));
+				gr.Stroke ();
+				y += 0.15;
+			}
+		}
+	}
+}
diff --git a/src/Core/Main/Verbal/AnalogiesQuestionAnswer.cs b/src/Core/Main/Verbal/AnalogiesQuestionAnswer.cs
new file mode 100644
index 0000000..963cf36
--- /dev/null
+++ b/src/Core/Main/Verbal/AnalogiesQuestionAnswer.cs
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2009 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 System.IO;
+using System.Collections.Generic;
+
+using Mono.Unix;
+using Cairo;
+
+namespace gbrainy.Core.Main.Verbal
+{
+	public class AnalogiesQuestionAnswer : Analogies
+	{
+		static protected Dictionary <int, Analogy> analogies;
+		static protected ArrayListIndicesRandom analogies_indices;
+		static protected int analogies_index = 0;
+
+		public AnalogiesQuestionAnswer ()
+		{
+			if (analogies == null)
+				analogies = AnalogiesFactory.Get (Analogy.Type.QuestionAnswer);
+		}
+
+		public override string Name {
+			get { return Catalog.GetString ("Question and answer");}
+		}
+
+		public override ArrayListIndicesRandom Indices {
+			get { return analogies_indices; }
+			set { analogies_indices = value; }
+		}
+
+		public override int CurrentIndex {
+			get { return analogies_index; }
+			set { analogies_index = value; }
+		}
+
+		public override Dictionary <int, Analogy> List {
+			get { return analogies; }
+		}
+
+		public override void Initialize ()
+		{
+			current = GetNext ();
+
+			if (current == null)
+				return;
+
+			if (current.answers != null) 
+				right_answer = current.answers [current.right];
+		}
+	}
+}
diff --git a/src/VerbalAnalogies/Analogy.cs b/src/Core/Main/Verbal/Analogy.cs
similarity index 54%
rename from src/VerbalAnalogies/Analogy.cs
rename to src/Core/Main/Verbal/Analogy.cs
index 7629e17..dabf7b1 100644
--- a/src/VerbalAnalogies/Analogy.cs
+++ b/src/Core/Main/Verbal/Analogy.cs
@@ -24,49 +24,49 @@ using System.Collections.Generic;
 
 using Cairo;
 using Mono.Unix;
-using Gtk;
 
-public class Analogy
+namespace gbrainy.Core.Main.Verbal
 {
-	public enum Type
+	public class Analogy
 	{
-		QuestionAnswer = 0,
-		MultipleOptions,
-		PairOfWordsOptions,
-		PairOfWordsCompare,
-		Last
-	}
+		public enum Type
+		{
+			QuestionAnswer = 0,
+			MultipleOptions,
+			PairOfWordsOptions,
+			PairOfWordsCompare,
+			Last
+		}
 
-	public string question;
-	public string [] answers;
-	public Type type;
-	public string tip;
-	public string rationale;
-	public int right;
+		public string question;
+		public string [] answers;
+		public Type type;
+		public string tip;
+		public string rationale;
+		public int right;
 
-	public bool MultipleAnswers {
-		get {
-			string [] items = answers[right].Split (AnalogiesFactory.Separator);
+		public bool MultipleAnswers {
+			get {
+				string [] items = answers[right].Split (AnalogiesFactory.Separator);
 
-			return items.Length > 1;
+				return items.Length > 1;
+			}
 		}
-	}
 
-	public override string ToString ()
-	{
-		string str = string.Empty;
+		public override string ToString ()
+		{
+			string str = string.Empty;
 	
-		str += String.Format ("Question: {0}\n", question);
-		str += String.Format ("Type: {0}\n", type);
-		str += String.Format ("Tip: {0}\n", tip);
-		str += String.Format ("Rational: {0}\n", rationale);
-		return str;
-	}
+			str += String.Format ("Question: {0}\n", question);
+			str += String.Format ("Type: {0}\n", type);
+			str += String.Format ("Tip: {0}\n", tip);
+			str += String.Format ("Rational: {0}\n", rationale);
+			return str;
+		}
 
-	public Analogy ()
-	{
+		public Analogy ()
+		{
 
+		}
 	}
 }
-
-
diff --git a/src/Core/Platform/Unix.cs b/src/Core/Platform/Unix.cs
new file mode 100644
index 0000000..fc26723
--- /dev/null
+++ b/src/Core/Platform/Unix.cs
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2007-2009 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 System.Runtime.InteropServices;
+using System.Text;
+using System.Globalization;
+using System.Threading;
+
+namespace gbrainy.Core.Platform
+{
+	//
+	// Unix system calls
+	//
+	static public class Unix
+	{
+		[DllImport("libc")]
+		static extern IntPtr localeconv ();
+
+		[DllImport ("libc")] // Linux
+		static extern int prctl (int option, byte [] arg2, IntPtr arg3, IntPtr arg4, IntPtr arg5);
+
+		[DllImport ("libc")] // BSD
+		static extern void setproctitle (byte [] fmt, byte [] str_arg);
+	 
+	
+		/* Taken from locale.h  */
+		[StructLayout (LayoutKind.Sequential)]
+		struct lconv
+		{
+			public string decimal_point;
+			public string thousands_sep;		
+			public string grouping;
+			public string int_curr_symbol;
+			public string currency_symbol;
+			public string mon_decimal_point;
+			public string mon_thousands_sep;
+			public string mon_grouping;
+			public string positive_sign;
+			public string negative_sign;
+			char int_frac_digits;
+			char frac_digits;
+			char p_cs_precedes;
+			char p_sep_by_space;
+			char n_cs_precedes;
+			char n_sep_by_space;
+			char p_sign_posn;
+			char n_sign_posn;
+			char int_p_cs_precedes;
+			char int_p_sep_by_space;
+			char int_n_cs_precedes;
+			char int_n_sep_by_space;
+			char int_p_sign_posn;
+			char int_n_sign_posn;
+		}
+
+		// Mono supports less locales that Unix systems
+		// To overcome this limitation we setup the right locale parameters
+		// when the Mono locale is InvariantCulture, that is, when the user's locale
+		// has not been identified and the default Mono locale is used
+		//
+		// See: https://bugzilla.novell.com/show_bug.cgi?id=420468
+		// 
+		static public void FixLocaleInfo ()
+		{
+			IntPtr st = IntPtr.Zero;
+			lconv lv;
+			int platform = (int) Environment.OSVersion.Platform;
+		
+			if (platform != 4 && platform != 128) // Only in Unix based systems
+				return;
+
+			if (CultureInfo.CurrentCulture != CultureInfo.InvariantCulture) // Culture well supported
+				return;
+
+			try {
+				st = localeconv ();
+				if (st == IntPtr.Zero) return;
+
+				lv = (lconv) Marshal.PtrToStructure (st, typeof (lconv));
+				CultureInfo culture =  (CultureInfo) CultureInfo.CurrentCulture.Clone ();
+				culture.NumberFormat.NumberDecimalSeparator = lv.decimal_point;
+				Thread.CurrentThread.CurrentCulture = culture;
+			}
+			catch (Exception) {}
+		}
+
+		public static void SetProcessName (string name)
+		{
+			int platform = (int) Environment.OSVersion.Platform;		
+			if (platform != 4 && platform != 128)
+				return;
+
+			try {
+				if (prctl (15 /* PR_SET_NAME */, Encoding.ASCII.GetBytes (name + "\0"),
+					IntPtr.Zero, IntPtr.Zero, IntPtr.Zero) != 0) {
+					throw new ApplicationException ("Error setting process name: " + 
+						Mono.Unix.Native.Stdlib.GetLastError ());
+				}
+			} catch (EntryPointNotFoundException) {
+				setproctitle (Encoding.ASCII.GetBytes ("%s\0"), 
+					Encoding.ASCII.GetBytes (name + "\0"));
+			}
+		}
+	}
+}
diff --git a/src/Core/Views/CountDownView.cs b/src/Core/Views/CountDownView.cs
new file mode 100644
index 0000000..c1bdb2f
--- /dev/null
+++ b/src/Core/Views/CountDownView.cs
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2007-2009 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 Cairo;
+using Mono.Unix;
+using System.Timers;
+
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Core.Views
+{
+	public class CountDownView : IDrawable
+	{
+		static int countdown_time;
+		System.Timers.Timer timer;
+		EventHandler finish;
+		public event EventHandler RequestRedraw; // Not used in this view
+
+		public CountDownView (EventHandler OnFinish)
+		{
+			timer = new System.Timers.Timer ();
+			timer.Elapsed += TimerUpdater;
+			timer.Interval = (1 * 1000); // 1 second
+			finish = OnFinish;
+			Start ();
+		}
+
+		public void Start ()
+		{
+			countdown_time = 3;
+			timer.Enabled = true;
+		}
+
+		public void EndDrawCountDown ()
+		{
+			if (timer == null)
+				return;
+
+			timer.Enabled = false;
+			timer.Dispose ();
+			timer = null;
+		}
+
+		public void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			gr.Scale (area_width, area_height);
+
+			gr.Color = new Cairo.Color (0.8, 0.8, 0.8);
+			gr.Paint ();
+
+			gr.LineWidth = 0.01;
+			gr.Color = new Cairo.Color (0, 0, 0, 1);
+
+			gr.SetPangoLargeFontSize ();
+			gr.DrawTextCentered (0.5, 0.1, Catalog.GetString ("Get ready to memorize the next objects..."));
+			gr.Stroke ();
+
+			gr.SetPangoFontSize (0.35);
+			gr.MoveTo (0.37, 0.22);
+			gr.ShowPangoText (countdown_time.ToString ());
+			gr.Stroke ();
+
+			gr.Arc (0.5, 0.5, 0.25, 0, 2 * Math.PI);
+			gr.Stroke ();
+			gr.Arc (0.5, 0.5, 0.28, 0, 2 * Math.PI);
+			gr.Stroke ();
+		}
+
+		// It is executed in another thread
+		void TimerUpdater (object source, ElapsedEventArgs e)
+		{
+			lock (this) {
+
+				if (countdown_time == 1) {
+					EndDrawCountDown ();
+					finish (this, EventArgs.Empty);
+				
+				}
+				countdown_time--;
+				if (RequestRedraw != null)
+					RequestRedraw (this, EventArgs.Empty);
+			}
+		}
+	}
+}
diff --git a/src/Core/Views/FinishView.cs b/src/Core/Views/FinishView.cs
new file mode 100644
index 0000000..1da1412
--- /dev/null
+++ b/src/Core/Views/FinishView.cs
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2007-2009 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Core.Views
+{
+	public class FinishView : IDrawable
+	{
+		GameSession session;
+		const int tips_shown = 4;
+
+		public event EventHandler RequestRedraw; // Not used in this view
+
+		public FinishView (GameSession session)
+		{
+			this.session = session;
+		}
+
+		static void DrawBand (CairoContextEx gr, double x, double y)
+		{
+			gr.Save ();
+			gr.Rectangle (x, y, 1 - 0.06, 0.06);
+			gr.Color = new Cairo.Color (0, 0, 0.2, 0.2);
+			gr.Fill ();
+			gr.Restore ();		
+		}
+
+		static void DrawBar (CairoContextEx gr, double x, double y, double w, double h, double percentage)
+		{
+			double per = percentage / 100;
+	
+			gr.Rectangle (x, y - h * per, w, h * per);
+			gr.FillGradient (x, y - h * per, w, h * per, new Cairo.Color (0, 0, 1));
+			gr.MoveTo (x, (y - 0.04) - h * per);
+			gr.ShowPangoText (String.Format ("{0}%", percentage));
+			gr.Stroke ();
+
+			gr.Save ();
+			gr.Color = new Cairo.Color (0, 0, 0);	
+			gr.MoveTo (x, y);
+			gr.LineTo (x, y - h * per);
+			gr.LineTo (x + w, y - h * per);
+			gr.LineTo (x + w, y);
+			gr.LineTo (x, y);
+			gr.Stroke ();
+			gr.Restore ();
+		}
+
+		void DrawGraphicBar (CairoContextEx gr, double x, double y)
+		{
+			const double area_w = 0.9, area_h = 0.28;
+			const double bar_w = 0.05, bar_h = area_h - 0.02;
+			const double space_x = 0.09;
+		
+			gr.LineWidth = 0.005;
+
+			// Axis
+			gr.MoveTo (x, y);
+			gr.LineTo (x, y + area_h);
+			gr.LineTo (x + area_w, y + area_h);
+			gr.Stroke ();
+
+			x = x + space_x;
+			DrawBar (gr, x, y + area_h, bar_w, bar_h, session.TotalScore);
+			gr.DrawTextCentered (x + bar_w / 2, y + area_h + 0.03, Catalog.GetString ("Total"));
+
+			x = x + space_x * 2;
+			DrawBar (gr, x, y + area_h, bar_w, bar_h, session.LogicScore);
+			gr.DrawTextCentered (x + bar_w / 2, y + area_h + 0.03, 	Catalog.GetString ("Logic")); 
+
+			x = x + space_x * 2;
+			DrawBar (gr, x, y + area_h, bar_w, bar_h, session.MathScore);
+			gr.DrawTextCentered (x + bar_w / 2, y + area_h + 0.03, Catalog.GetString ("Calculation"));
+
+			x = x + space_x * 2;
+			DrawBar (gr, x, y + area_h, bar_w, bar_h, session.MemoryScore);
+			gr.DrawTextCentered (x + bar_w / 2, y + area_h + 0.03, Catalog.GetString ("Memory"));
+
+			x = x + space_x * 2;
+			DrawBar (gr, x, y + area_h, bar_w, bar_h, session.VerbalScore);
+			gr.DrawTextCentered (x + bar_w / 2, y + area_h + 0.03, Catalog.GetString ("Verbal"));
+		}
+
+		public void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double y = 0.04, x = 0.05;
+			const double space_small = 0.02;
+			string s;
+
+			gr.Scale (area_width, area_height);
+			gr.DrawBackground ();
+			gr.Color = new Cairo.Color (0, 0, 0, 1);
+
+			gr.MoveTo (x, y);
+			gr.ShowPangoText (Catalog.GetString ("Score"), false, -1, 0);
+			DrawBand (gr, 0.03, y - 0.01);
+
+			y += 0.08;
+			gr.MoveTo (x, y);
+
+			if (session.GamesPlayed >= 10) {
+				if (session.TotalScore >= 90)
+					s = String.Format (Catalog.GetString ("Outstanding results"));
+				else if (session.TotalScore >= 80) 
+					s = String.Format (Catalog.GetString ("Excellent results"));
+				else if (session.TotalScore >= 50) 
+					s = String.Format (Catalog.GetString ("Good results"));
+				else if (session.TotalScore >= 30) 
+					s = String.Format (Catalog.GetString ("Poor results"));
+				else s = String.Format (Catalog.GetString ("Disappointing results"));
+			} else 
+				s = String.Empty;
+
+			gr.MoveTo (x, y);
+
+			if (s == String.Empty)
+				gr.ShowPangoText (String.Format (Catalog.GetString ("Games won: {0} ({1} played)"), session.GamesWon, session.GamesPlayed));	
+			else 
+				gr.ShowPangoText (String.Format (Catalog.GetString ("{0}. Games won: {1} ({2} played)"), s, session.GamesWon, session.GamesPlayed));	
+
+			y += 0.06;
+			gr.MoveTo (x, y);
+			gr.ShowPangoText (String.Format (Catalog.GetString ("Time played {0} (average per game {1})"), session.GameTime, session.TimePerGame));
+		
+			y += 0.1;
+			DrawGraphicBar (gr, x, y);
+			y += 0.4;
+
+			gr.MoveTo (x, y);
+			gr.ShowPangoText (Catalog.GetString ("Tips for your next games"), false, -1, 0);
+			DrawBand (gr, 0.03, y - 0.01);
+
+			y += 0.08;
+
+			for (int i = 0; i < tips_shown; i++)
+			{
+				y = gr.DrawStringWithWrapping (x, y,  "- " + GameTips.Tip);
+				if (y > 0.88)
+					break;
+
+				y += space_small;
+			}
+
+			gr.Stroke ();
+		}
+	}
+}
diff --git a/src/Defines.cs.in b/src/Core/Views/IDrawRequest.cs
similarity index 59%
rename from src/Defines.cs.in
rename to src/Core/Views/IDrawRequest.cs
index a35eac1..e2e420d 100644
--- a/src/Defines.cs.in
+++ b/src/Core/Views/IDrawRequest.cs
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 Jordi Mas i Hernàndez <jmas softcatala org>
+ * Copyright (C) 2009 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
@@ -18,15 +18,19 @@
  */
 
 using System;
+using System.ComponentModel;
 
-public class Defines
-{
-	public const string VERSION = "@VERSION@";
-	public const string GNOME_LOCALE_DIR = "@prefix@/share/locale";
-	public const string DATA_DIR = "@prefix@/share/games/gbrainy/";
-	public const string VERBAL_ANALOGIES = "verbal_analogies.xml";
-	public const string CONFIG_DIR = "gbrainy"; // like .config/gbrainy
-}
-
+using gbrainy.Core.Libraries;
 
+namespace gbrainy.Core.Views
+{
+	// Used by any class that can draw and due to logic requirements may need to request a redraw
+	public interface IDrawRequest
+	{
+		// Used to synchronize threads of the application with UI thread 
+		ISynchronizeInvoke SynchronizingObject { get; set;}
 
+		// Any element that draws on request may need to request a redraw
+		event EventHandler DrawRequest;
+	}
+}
diff --git a/src/AssemblyInfo.cs.in b/src/Core/Views/IDrawable.cs
similarity index 68%
rename from src/AssemblyInfo.cs.in
rename to src/Core/Views/IDrawable.cs
index ea8b88e..f4cdd02 100644
--- a/src/AssemblyInfo.cs.in
+++ b/src/Core/Views/IDrawable.cs
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007-2009 Jordi Mas i Hernàndez <jmas softcatala org>
+ * Copyright (C) 2009 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
@@ -17,11 +17,16 @@
  * Boston, MA 02111-1307, USA.
  */
 
-using System.Reflection;
-
-[assembly: AssemblyVersion("@VERSION@")]
-[assembly: AssemblyTitle ("gbrainy")]
-[assembly: AssemblyCopyright ("(c)2007-2009 Jordi Mas")]
-[assembly: AssemblyDescription ("A brain teaser game for fun and to keep your brain trained")]
+using System;
+using System.ComponentModel;
 
+using gbrainy.Core.Libraries;
 
+namespace gbrainy.Core.Views
+{
+	// Used by any class that can draw in drawing context
+	public interface IDrawable
+	{
+		void Draw (CairoContextEx gr, int width, int height, bool rtl);
+	}
+}
diff --git a/src/Core/Views/ViewsControler.cs b/src/Core/Views/ViewsControler.cs
new file mode 100644
index 0000000..648aa63
--- /dev/null
+++ b/src/Core/Views/ViewsControler.cs
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2009 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 gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Core.Views
+{
+	public class ViewsControler
+	{
+		GameSession.SessionStatus status;
+		WelcomeView welcome;
+		FinishView finish;
+		Game game;
+
+		public ViewsControler (GameSession session)
+		{
+			welcome = new WelcomeView ();
+			finish = new FinishView (session);
+		}
+
+		public GameSession.SessionStatus Status {
+			set { status = value;}
+		}
+
+		public Game Game {
+			set { game = value;}
+		}
+
+		public IDrawable CurrentView {
+			get {
+				switch (status) {
+				case GameSession.SessionStatus.NotPlaying:
+					return welcome;
+				case GameSession.SessionStatus.Playing:
+				case GameSession.SessionStatus.Answered:
+					return game;
+				case GameSession.SessionStatus.Finished:
+					return finish;
+				default:
+					throw new InvalidOperationException ("Invalid status");
+				}
+			}
+		}
+	}
+}
diff --git a/src/Core/Views/WelcomeView.cs b/src/Core/Views/WelcomeView.cs
new file mode 100644
index 0000000..ea1f7f2
--- /dev/null
+++ b/src/Core/Views/WelcomeView.cs
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2007-2008 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Core.Views
+{
+	public class WelcomeView : IDrawable
+	{
+		public event EventHandler RequestRedraw; // Not used in this view
+
+		public WelcomeView ()
+		{
+
+		}
+
+		public void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double y = 0.03;
+			const double space = 0.17;
+			const double image_size = 0.14;
+
+			gr.Scale (area_width, area_height);
+			gr.DrawBackground ();
+			//gr.SetPangoNormalFontSize ();
+			gr.Color = new Cairo.Color (0, 0, 0, 1);
+
+			gr.MoveTo (0.05, y);
+			gr.ShowPangoText (String.Format (Catalog.GetString ("Welcome to gbrainy {0}"), Defines.VERSION), true, -1, 0);
+			gr.Stroke ();
+
+			gr.DrawStringWithWrapping (0.05, y + 0.07, Catalog.GetString ("gbrainy is a brain teaser game and trainer to have fun and to keep your brain trained. It includes:"));
+
+			y = 0.22;
+			gr.DrawImageFromFile (Defines.DATA_DIR + "logic-games.svg", rtl ? 0.75 : 0.05, y, image_size, image_size);
+			gr.DrawStringWithWrapping (rtl ? 0.05 : 0.23, y + 0.01, 
+				Catalog.GetString ("Logic puzzles. Challenge your reasoning and thinking skills."), 
+				rtl ? 0.65 : -1);
+
+			y += space;
+			gr.DrawImageFromFile (Defines.DATA_DIR + "math-games.svg", rtl ? 0.75 : 0.05, y, image_size, image_size);
+			gr.DrawStringWithWrapping (rtl ? 0.05 : 0.23, y + 0.01, 
+				Catalog.GetString ("Mental calculation. Arithmetical operations that test your mental calculation abilities."),
+				rtl ? 0.65 : -1);
+
+			y += space;
+			gr.DrawImageFromFile (Defines.DATA_DIR + "memory-games.svg", rtl ? 0.75 : 0.05, y, image_size, image_size);
+			gr.DrawStringWithWrapping (rtl ? 0.05 : 0.23, y + 0.01, 
+				Catalog.GetString ("Memory trainers. To prove your short term memory."),
+				rtl ? 0.65 : -1);
+
+			y += space;
+			gr.DrawImageFromFile (Defines.DATA_DIR + "verbal-games.svg", rtl ? 0.75 : 0.05, y, image_size, image_size);
+			gr.DrawStringWithWrapping (rtl ? 0.05 : 0.23, y + 0.01, 
+				Catalog.GetString ("Verbal analogies. Challenge your verbal aptitude."),
+				rtl ? 0.65 : -1);
+
+			gr.DrawStringWithWrapping (0.05, y + 0.17,  Catalog.GetString ("Use the Settings to adjust the difficulty level of the game."));
+			gr.Stroke ();
+		}
+	}
+}
diff --git a/src/Games/Calculation/CalculationArithmetical.cs b/src/Games/Calculation/CalculationArithmetical.cs
new file mode 100644
index 0000000..184b48f
--- /dev/null
+++ b/src/Games/Calculation/CalculationArithmetical.cs
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2007-2008 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Calculation
+{
+	public class CalculationArithmetical : Game
+	{
+		public enum Operation
+		{
+			Addition = 0,	
+			Subtraction,	
+			Multiplication,
+			LastOperation
+		}
+
+		private int []operands;
+		private Operation operation;
+		private int max_operand;
+		private int max_operations;
+
+		public override string Name {
+			get {return Catalog.GetString ("Arithmetical");}
+		}
+
+		public override Types Type {
+			get { return Game.Types.MathTrainer;}
+		}
+
+		public override string Question {
+			get {return Catalog.GetString ("What is the result of the arithmetical operation?");} 
+		}
+
+		public override void Initialize ()
+		{
+			int result = 0, operations = 0;
+			operation = (Operation) random.Next ((int) Operation.LastOperation);
+
+			switch (CurrentDifficulty) {
+			case Difficulty.Easy:
+				max_operations = 2;
+				max_operand = 50;
+				break;
+			case Difficulty.Medium:
+				max_operations = 3;
+				max_operand = 100;
+				break;
+			case Difficulty.Master:
+				max_operations = 5;
+				max_operand = 500;
+				break;
+			}
+
+			switch (operation) {
+			case Operation.Addition:
+			case Operation.Subtraction:
+				operations = 2 + random.Next (max_operations);
+					break;
+			case Operation.Multiplication:
+				operations = 2 + random.Next (1);
+				break;
+			}
+
+			operands = new int [operations];
+
+			result = operands[0] = 10 + random.Next (max_operand);
+			for (int i = 1; i < operands.Length; i ++)
+			{
+				operands[i] = 10 + random.Next (max_operand);
+				switch (operation) {
+				case Operation.Addition:
+					result += operands[i];
+					break;	
+				case Operation.Subtraction:
+					result -= operands[i];
+					break;
+				case Operation.Multiplication:
+					result *= operands[i];
+					break;
+				}
+			}
+			right_answer = result.ToString ();
+		}
+	
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{	
+			double operand_y = DrawAreaY + 0.2;
+			const double operand_space = 0.1;
+			const double aligned_pos = 0.58;
+
+			base.Draw (gr, area_width, area_height, rtl);
+	
+			gr.SetPangoLargeFontSize ();
+			for (int i = 0; i < operands.Length - 1; i++)
+			{
+				gr.DrawTextAlignedRight (aligned_pos, operand_y, operands[i].ToString ());
+				gr.MoveTo (DrawAreaX + 0.2, operand_y + 0.03);	
+
+				switch (operation) {
+				case Operation.Addition:
+					gr.ShowPangoText ("+");
+					break;	
+				case Operation.Subtraction:
+					gr.ShowPangoText ("-");
+					break;
+				case Operation.Multiplication:
+					gr.ShowPangoText ("*");
+					break;
+				}
+
+				operand_y += operand_space;
+			}
+
+			gr.DrawTextAlignedRight (aligned_pos, operand_y, operands[operands.Length - 1].ToString ());
+
+			operand_y += 0.08;
+			gr.MoveTo (DrawAreaX + 0.2, operand_y);
+			gr.LineTo (DrawAreaX + 0.5, operand_y);
+			gr.Stroke ();
+
+			if (DrawAnswer) {
+				gr.DrawTextAlignedRight (aligned_pos, operand_y + 0.03, right_answer);
+			}
+		}
+
+	}
+}
diff --git a/src/Games/Calculation/CalculationAverage.cs b/src/Games/Calculation/CalculationAverage.cs
new file mode 100644
index 0000000..fa3c3c7
--- /dev/null
+++ b/src/Games/Calculation/CalculationAverage.cs
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2009 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Calculation
+{
+	public class CalculationAverage : Game
+	{
+		const int options_cnt = 4;
+		const int correct_pos = 0;
+		int []numbers;
+		double []options;
+		ArrayListIndicesRandom random_indices;
+		int correct;
+
+		public override string Name {
+			get {return Catalog.GetString ("Average");}
+		}
+
+		public override Types Type {
+			get { return Game.Types.MathTrainer;}
+		}
+
+		public override string Question {
+			get {
+				string nums = string.Empty;
+	
+				for (int i = 0; i < numbers.Length - 1; i++)
+					nums += numbers[i] + ", ";
+
+				nums += numbers [numbers.Length - 1];
+
+				return String.Format (
+					Catalog.GetString ("Given the numbers: {0}. Which of the following numbers is the nearest to the average? Answer {1}, {2}, {3} or {4}."), nums,
+					GetPossibleAnswer (0), GetPossibleAnswer (1), GetPossibleAnswer (2), GetPossibleAnswer (3));}
+		}
+
+		public override string Answer {
+			get { 
+				string answer = base.Answer + " ";
+
+				answer += String.Format (Catalog.GetString ("The result of the operation is {0:##0.###}"), 
+					correct);
+				return answer;
+			}
+		}
+
+		public override void Initialize ()
+		{
+			bool duplicated;
+			int nums, options_next, dist, num_size, which = 0;
+
+			switch (CurrentDifficulty) {
+			case Difficulty.Easy:
+				nums = 3;
+				dist = nums * 3;
+				num_size = 50;
+				break;
+			default:
+			case Difficulty.Medium:
+				nums = 5;
+				dist = nums * 3;
+				num_size = 150;
+				break;
+			case Difficulty.Master:
+				nums = 7;
+				dist = nums * 3;
+				num_size = 500;
+				break;
+			}
+
+			numbers = new int [nums];
+			options = new double [options_cnt];
+
+			// Random set of numbers
+			correct = 0;
+			for (int i = 0; i < nums; i++)
+			{
+				numbers [i] = 10 + random.Next (num_size) + dist;
+				correct += numbers [i];
+			}
+
+			correct = correct / nums;
+
+			options [correct_pos] = correct;
+			options_next = correct_pos + 1;
+
+			while (options_next < options_cnt) {
+				double ans;
+
+				ans = correct + random.Next (dist);
+				duplicated = false;	
+
+				// No repeated answers
+				for (int num = 0; num < options_next; num++)
+				{
+					// Due to decimal precission
+					if (options [num] == ans || options [num] == ans + 1 || options [num] == ans - 1) {
+						duplicated = true;
+						break;
+					}
+				}
+
+				if (duplicated)
+					continue;
+			
+				options [options_next] = ans;
+				options_next++;
+			}
+
+			random_indices = new ArrayListIndicesRandom (options_cnt);
+			random_indices.Initialize ();
+		
+			for (int i = 0; i < options_cnt; i++)
+			{
+				if (random_indices [i] == correct_pos) {
+					which = i;
+					break;
+				}
+			}
+
+			right_answer += GetPossibleAnswer (which);
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{	
+			double x = DrawAreaX + 0.25, y = DrawAreaY + 0.16;
+			int indx;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			gr.SetPangoLargeFontSize ();
+
+			for (int i = 0; i < options_cnt; i++)
+			{
+				gr.MoveTo (x, y);
+				indx = random_indices[i];
+				gr.ShowPangoText (String.Format ("{0}) {1:##0.###}", GetPossibleAnswer (i) , options [indx]));
+
+				y = y + 0.15;
+			}
+		}
+	}
+}
diff --git a/src/Games/Calculation/CalculationCloserFraction.cs b/src/Games/Calculation/CalculationCloserFraction.cs
new file mode 100644
index 0000000..1de7577
--- /dev/null
+++ b/src/Games/Calculation/CalculationCloserFraction.cs
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Calculation
+{
+	public class CalculationCloserFraction : Game
+	{
+		private double question_num;
+		private const int options_cnt = 4;
+		private double []options;
+		private ArrayListIndicesRandom random_indices;
+		private int which;
+
+		public override string Name {
+			get {return Catalog.GetString ("Closer fraction");}
+		}
+
+		public override Types Type {
+			get { return Game.Types.MathTrainer;}
+		}
+
+		public override string Question {
+			get {return String.Format (
+				Catalog.GetString ("Which of the following numbers is closer to {0:##0.###}? Answer {1}, {2}, {3} or {4}."), question_num,
+				GetPossibleAnswer (0), GetPossibleAnswer (1), GetPossibleAnswer (2), GetPossibleAnswer (3));}
+		}
+
+		public override string Answer {
+			get { 
+				string answer = base.Answer + " ";
+				int ans_idx = random_indices[which];
+
+				answer += 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;
+			}
+		}
+
+		public override void Initialize ()
+		{	
+			options = new double [options_cnt * 2];
+			bool duplicated;
+			bool done = false;
+			int i, ans_idx, basenum, randnum;
+
+			switch (CurrentDifficulty) {
+			case Difficulty.Easy:
+				basenum = 5;
+				randnum = 10;
+				break;
+			default:
+			case Difficulty.Medium:
+				basenum = 5;
+				randnum = 30;
+				break;
+			case Difficulty.Master:
+				basenum = 9;
+				randnum = 60;
+				break;
+			}
+
+
+			while (done == false) {
+				duplicated = false;
+				options[0 + 0] = basenum + random.Next (randnum);
+				options[0 + 1] = basenum + random.Next (randnum);
+				
+				options[2 + 0] = options[0 + 0] + random.Next (2);
+				options[2 + 1] = options[0 + 1] + random.Next (2);
+
+				options[(2 * 2) + 0] = options[0 + 0] - random.Next (5);
+				options[(2 * 2) + 1] = options[0 + 1] - random.Next (5);
+		
+				options[(3 * 2) + 0] = options[0 + 0] +  random.Next (5);
+				options[(3 * 2) + 1] = options[0 + 1] +  random.Next (5);
+
+				// No repeated answers
+				for (int num = 0; num < options_cnt; num++)
+				{
+					for (int n = 0; n < options_cnt; n++)
+					{
+						if (n == num) continue;
+
+						if (options [(num * 2) + 0] / options [(num * 2) + 1] ==
+							options [(n * 2) + 0] / options [(n * 2) + 1]) {
+							duplicated = true;
+							break;
+						}
+					}
+				}
+
+				if (duplicated)
+					continue;
+			
+				// No numerator = denominator (1 value)
+				if (options [0 + 0] == options [0 + 1]) continue;
+				if (options [(1 * 2) + 0] == options [(1 * 2) + 1]) continue;
+				if (options [(2 * 2) + 0] == options [(2 * 2) + 1]) continue;
+				if (options [(3 * 2) + 0] == options [(3 * 2) + 1]) continue;
+
+				// No < 2
+				for (i = 0; i < options_cnt * 2; i++) {
+					if (options [i] < 2)
+						break;
+				}
+
+				if (i < options_cnt * 2)
+					continue;
+							
+				done = true;
+			}
+
+			random_indices = new ArrayListIndicesRandom (4);
+			random_indices.Initialize ();
+		
+			which = random.Next (options_cnt);
+			ans_idx = random_indices[which];
+			question_num = options[ans_idx * 2] / options[(ans_idx * 2) + 1];
+			right_answer += GetPossibleAnswer (which);
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{	
+			double x = DrawAreaX + 0.25, y = DrawAreaY + 0.16;
+			int indx;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			gr.SetPangoLargeFontSize ();
+
+			for (int i = 0; i < options_cnt; i++)
+			{
+				gr.MoveTo (x, y);
+				indx = random_indices[i];
+				gr.ShowPangoText (String.Format ("{0}) {1}", GetPossibleAnswer (i) , options [indx * 2] +  " / " + options [(indx  * 2) +1]));
+			
+				y = y + 0.15;
+			}
+		}
+	}
+}
diff --git a/src/Games/Calculation/CalculationFractions.cs b/src/Games/Calculation/CalculationFractions.cs
new file mode 100644
index 0000000..6fc7b19
--- /dev/null
+++ b/src/Games/Calculation/CalculationFractions.cs
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2008 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Calculation
+{
+	public class CalculationFractions : Game
+	{
+		public enum Operation
+		{
+			Addition,	
+			Subtraction,
+			LastOperation
+		}
+
+		class FormulaFraction
+		{
+			public int numerator, denominator;
+			public Operation operation;
+
+			public FormulaFraction (int numerator, int denominator, Operation operation)
+			{
+				this.numerator = numerator;
+				this.denominator = denominator;
+				this.operation = operation;
+			}
+		
+			public double Result {
+				get {
+					return (double) numerator / (double) denominator; 
+				}	
+			}
+		}
+
+		private int fractions_num, demominator_max, factor_max;
+		private FormulaFraction[] fractions;
+		private const string format_string = "{0:##0.###}";
+
+		public override string Name {
+			get {return Catalog.GetString ("Fractions");}
+		}
+
+		public override Types Type {
+			get { return Game.Types.MathTrainer;}
+		}
+
+		public override string Question {
+			get {return String.Format (Catalog.GetString ("What is the result of the given operation? Answer using either a fraction or a number."));} 
+		}
+
+		private int Factor {
+			get {
+				switch (random.Next (factor_max)) {
+				case 0:
+				default:
+					return 2;
+				case 1:
+					return 3;
+				case 2:
+					return 5;
+				case 3: 
+					return 7;
+				}
+			}
+		}
+
+		public override void Initialize ()
+		{
+			double rslt = 0;
+			int factor = Factor;
+
+			switch (CurrentDifficulty) {
+			case Difficulty.Easy:
+				fractions_num = 2;
+				demominator_max = 5;
+				factor_max = 2;
+				break;
+			default:
+			case Difficulty.Medium:
+				fractions_num = 4;
+				demominator_max = 3;
+				factor_max = 3;
+				break;
+			case Difficulty.Master:
+				fractions_num = 4;
+				demominator_max = 5;
+				factor_max = 4;
+				break;
+			}
+
+			fractions = new FormulaFraction [fractions_num];
+			for (int i = 0; i < fractions_num; i++) {
+				fractions[i] = new FormulaFraction (1 + random.Next (10), (1 + random.Next (demominator_max)) * factor,
+					(Operation) random.Next ((int) Operation.LastOperation));
+
+				if (i == 0)
+					fractions[0].operation = Operation.LastOperation; // No operation
+
+				switch (fractions[i].operation) {
+				case Operation.Addition:
+					rslt += fractions[i].Result;
+					break;
+				case Operation.Subtraction:
+					rslt -= fractions[i].Result;
+					break;
+				default:
+					rslt = fractions[i].Result;
+					break;
+				}			
+			}
+
+			right_answer = String.Format (format_string, rslt);
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{	
+			const double fraction_size = 0.17;
+			double x =  0.5  - (fractions_num * fraction_size / 2), y = DrawAreaY + 0.3;
+			const double offset_x = 0.12;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			gr.SetPangoLargeFontSize ();
+
+			for (int i = 0; i < fractions_num; i++) 
+			{
+				// Numerator
+				gr.DrawTextAlignedRight (x + offset_x, y, fractions[i].numerator.ToString ());
+
+				// Sign
+				gr.MoveTo (x, y + 0.04);
+				switch (fractions[i].operation) {
+				case Operation.Addition:
+					gr.ShowPangoText ("+");
+					break;	
+				case Operation.Subtraction:
+					gr.ShowPangoText ("-");
+					break;
+				}
+				gr.Stroke ();
+
+				// Line
+				gr.MoveTo (x + 0.05, y + 0.08);
+				gr.LineTo (x + offset_x + 0.02,  y + 0.08);
+				gr.Stroke ();
+
+				// Denominator
+				gr.DrawTextAlignedRight (x + offset_x, y + 0.1, fractions[i].denominator.ToString ());
+
+				x += fraction_size;
+			}	
+		}
+
+		public override bool CheckAnswer (string answer)
+		{	
+			string num_a = string.Empty;
+			string num_b = string.Empty;
+			double a, b;
+			double rslt;
+			bool first = true;		
+
+			for (int c = 0; c < answer.Length; c++)
+			{
+				if (answer[c] < '0' || answer[c] > '9') {
+					if (answer[c] != '-' && answer[c] != '.' && answer[c] != ',') {
+						first = false;
+						continue;
+					}
+				}
+			
+				if (first == true)
+					num_a += answer[c];
+				else
+					num_b += answer[c];
+			}
+
+			try {
+
+				if (num_b != string.Empty) {
+					a = Double.Parse (num_a);
+					b = Double.Parse (num_b);
+					rslt = (double) a / (double) b;
+				} else {
+					rslt = Double.Parse (num_a);
+				}
+
+			}
+
+			catch (FormatException) {
+				return false;
+			}
+			return right_answer.Equals (String.Format (format_string, rslt));
+		}
+	}
+}
diff --git a/src/Games/Calculation/CalculationGreatestDivisor.cs b/src/Games/Calculation/CalculationGreatestDivisor.cs
new file mode 100644
index 0000000..477e332
--- /dev/null
+++ b/src/Games/Calculation/CalculationGreatestDivisor.cs
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2007-2008 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Calculation
+{
+	public class CalculationGreatestDivisor : Game
+	{
+		private int []numbers;
+		private int []answers;
+		private int max_num;
+		private int num_answ_ques;
+
+		public override string Name {
+			get {return Catalog.GetString ("Greatest divisor");}
+		}
+
+		public override Types Type {
+			get { return Game.Types.MathTrainer;}
+		}
+
+		public override string Question {
+			get {return Catalog.GetString ("Which of the possible divisors is the greatest that divides all numbers?");} 
+		}
+
+		public override void Initialize ()
+		{	
+			bool found;
+			int n, m;
+			int []mult = new int [3];
+
+			switch (CurrentDifficulty) {
+			case Difficulty.Easy:
+				max_num = 999;
+				num_answ_ques = 3;
+				break;
+			case Difficulty.Medium:
+				max_num = 999;
+				num_answ_ques = 4;
+				break;
+			case Difficulty.Master:
+				max_num = 9999;
+				num_answ_ques = 5;
+				break;
+			}
+
+			numbers = new int [num_answ_ques];
+			answers = new int [num_answ_ques];
+
+			// Common multiplayers for all numbers
+			for (m = 0; m < mult.Length; m++) {
+				mult[m] = GetMultiplier (mult);
+			}
+		
+			n = 0;
+			while (n < numbers.Length) {
+				numbers [n] = 4 + random.Next (5);
+				for (int i = 1; i < 5; i++) {
+					numbers [n] =  numbers [n]  * (1 + random.Next (10));
+				}
+		
+				for (m = 0; m < mult.Length; m++) {
+					numbers[n] = numbers [n] * mult[m];
+				}
+			
+				if (numbers[n] > max_num || numbers[n] < 50) 
+					continue;
+
+				found = false;
+				for (int i = 0; i < n; i++) {
+					if (numbers[i]  == numbers [n]) {
+						found = true;
+						break;
+					}				
+				}
+				if (found == false)
+					n++;
+			}
+
+			for (n = 0; n < answers.Length; n++) {
+				answers[n] = GetUniqueAnswer (mult, answers);
+			}
+
+			n = 0;
+			int answer = 0;
+			for (int a = 0; a < answers.Length; a++)
+			{
+				for (n = 0; n < answers.Length; n++)
+				{
+					if ((double)numbers[n] / (double)answers[a] !=  Math.Abs (numbers[n] / answers[a]))
+						break;								
+				}
+			
+				if (n == answers.Length && answers[a] > answer)
+					answer = answers[a];
+			}
+
+			right_answer = answer.ToString ();
+		}
+
+		private int GetUniqueAnswer (int []mult, int []answers)
+		{
+			int answer = 0;
+			bool found = false;
+			int n;
+
+			while (found == false) {
+				switch (random.Next (7)) {
+				case 0:
+					answer = mult[0];
+					break;
+				case 1:
+					answer = mult[0] * mult[1];
+					break;
+				case 2:	
+					answer = mult[0] * mult[2];
+					break;
+				case 3:
+					answer = mult[0] * 7;
+					break;
+				case 4:
+					answer = mult[0] * 13;
+					break;
+				case 5:
+					answer = mult[0] * mult[1] * mult[2];
+					break;
+				case 6:
+					answer = mult[0] * 19;
+					break;
+				}
+
+				for (n = 0; n < answers.Length; n++) {
+					if (answers [n] == answer)
+						break;
+				}
+
+				if (n == answers.Length)
+					found = true;
+			}
+	
+			return answer;
+		}
+
+		private int GetMultiplier (int []nums)
+		{
+			int rslt = 1;
+			bool found = false;
+			int n;
+
+			while (found == false) {
+				switch (random.Next (4)) {
+				case 0:
+					rslt = 2;
+					break;
+				case 1:
+					rslt = 3;
+					break;
+				case 2:
+					rslt = 5;
+					break;
+				case 3:
+					rslt = 7;
+					break;
+
+				}
+				for (n = 0; n < nums.Length; n++) {
+					if (nums[n] == rslt) 
+						break;
+				}
+
+				if (n == nums.Length)
+					found = true;
+			}
+
+			return rslt;
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{	
+			double x = DrawAreaX, y = DrawAreaY + 0.1;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			gr.SetPangoLargeFontSize ();
+
+			gr.MoveTo (0.05, y);
+			gr.ShowPangoText (Catalog.GetString ("Numbers"));
+			y += 0.12;
+
+			for (int n = 0; n < numbers.Length; n++)
+			{
+				gr.MoveTo (x, y);
+				gr.ShowPangoText (numbers[n].ToString ());
+				gr.Stroke ();
+				x += 0.17;
+			}
+		
+			x = DrawAreaX;
+			y += 0.3;
+
+			gr.MoveTo (0.05, y);
+			gr.ShowPangoText (Catalog.GetString ("Possible divisors"));
+			y += 0.12;
+
+			for (int n = 0; n < answers.Length; n++)
+			{
+				gr.MoveTo (x, y);
+				gr.ShowPangoText (answers[n].ToString ());
+				gr.Stroke ();
+				x += 0.17;
+			}
+		}
+	}
+}
diff --git a/src/Games/Calculation/CalculationOperator.cs b/src/Games/Calculation/CalculationOperator.cs
new file mode 100644
index 0000000..1940955
--- /dev/null
+++ b/src/Games/Calculation/CalculationOperator.cs
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2007-2008 Brandon Perry <bperry volatile gmail com>
+ * Copyright (C) 2007-2008 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Calculation
+{
+	public class CalculationOperator : Game
+	{
+		private double number_a, number_b, number_c, total;
+		private char[] opers = {'*', '+', '-', '/'};
+		private char oper1, oper2;
+	
+		public override string Name {
+			get {return Catalog.GetString ("Operator");}
+		}
+	
+		public override string Tip {
+			get {return String.Format( Catalog.GetString ("The first operator is {0}."), oper1);}
+		}
+
+		public override Types Type {
+			get { return Game.Types.MathTrainer;}
+		}
+
+		public override string Question {
+			get {return String.Format (Catalog.GetString ("Which operators make {0}, {1}, and {2} equal {3}? Answer using '+-/*'."), number_a, number_b, number_c, total);} 
+		}
+
+		private double ProcessOperation (double total, double number, char op)
+		{
+			switch (op) {
+			case '-':
+				return total - number;
+			case '*':
+				return total * number;
+			case '/':
+				return total / number;
+			case '+':
+			default:
+				return total + number;
+			}
+		}
+
+		public override void Initialize ()
+		{
+			bool done = false;
+			while (done == false) {
+				number_a = 5 + random.Next (1000);
+				number_b = 3 + random.Next (1000);
+				number_c = 7 + random.Next (1000);
+
+				oper1 = opers[random.Next(4)];
+				oper2 = opers[random.Next(4)];
+
+				total = ProcessOperation (number_a, number_b, oper1);
+				total = ProcessOperation (total, number_c, oper2);
+
+				if (total < 20000 && total > -20000 && total != 0 && total == (int) total)
+					done = true;
+			}
+
+			right_answer = String.Format (Catalog.GetString ("{0} and {1}"), oper1, oper2);
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{	
+			const double aligned_pos = 0.58;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			gr.SetPangoLargeFontSize ();
+			gr.DrawTextAlignedRight (aligned_pos, DrawAreaY + 0.2, number_a.ToString ());
+			gr.DrawTextAlignedRight (aligned_pos, DrawAreaY + 0.3, number_b.ToString ());
+			gr.DrawTextAlignedRight (aligned_pos, DrawAreaY + 0.4, number_c.ToString ());
+
+			gr.MoveTo (DrawAreaX + 0.2, DrawAreaY + 0.5);
+			gr.LineTo (DrawAreaX + 0.5, DrawAreaY + 0.5);
+			gr.Stroke ();
+
+			gr.DrawTextAlignedRight (aligned_pos, DrawAreaY + 0.55, total.ToString ());
+
+			gr.MoveTo (DrawAreaX + 0.2, DrawAreaY + 0.25);
+			gr.ShowPangoText ((DrawAnswer == true) ? oper1.ToString () : "?");
+
+			gr.MoveTo (DrawAreaX + 0.2, DrawAreaY + 0.35);
+			gr.ShowPangoText ((DrawAnswer == true) ?  oper2.ToString () : "?");
+
+		}
+
+		private bool IndexOf (char c, char [] chars)
+		{
+			for (int i = 0; i < chars.Length; i++)
+				if (c == chars [i]) return true;
+
+			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/CalculationPrimes.cs b/src/Games/Calculation/CalculationPrimes.cs
new file mode 100644
index 0000000..a4ac7a3
--- /dev/null
+++ b/src/Games/Calculation/CalculationPrimes.cs
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2009 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Calculation
+{
+	public class CalculationPrimes : Game
+	{
+		const int total_primes = 1129;
+		const int total_nums = 5;
+		int max;
+		bool div3;	
+		int []numbers;
+		int []primes = new int []	
+		{
+			2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 
+			37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 
+			83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 
+			139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 
+			197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 
+			263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 
+			331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 
+			397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 
+			461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 
+			541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 
+			607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 
+			673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 
+			751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 
+			827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 
+			907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 
+			983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 
+			1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 
+			1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 
+			1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 
+			1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 
+			1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 
+			1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 
+			1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 
+			1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 
+			1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 
+			1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 
+			1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 
+			1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 
+			2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 
+			2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 
+			2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, 
+			2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 
+			2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 
+			2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 
+			2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 
+			2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 
+			2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 
+			2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 
+			2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 
+			2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 
+			3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 
+			3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 
+			3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 
+			3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 
+			3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 
+			3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 
+			3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 
+			3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 
+			3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 
+			3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 
+			4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 
+			4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 
+			4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 
+			4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 
+			4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, 
+			4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 
+			4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 
+			4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 
+			4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 
+			4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 
+			4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 
+			5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 
+			5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 
+			5227, 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 
+			5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417, 
+			5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 
+			5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 
+			5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 
+			5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 
+			5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, 
+			5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 
+			5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 
+			6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 
+			6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 
+			6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 
+			6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 
+			6449, 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 
+			6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 
+			6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 
+			6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 
+			6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 
+			6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 
+			7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, 
+			7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 
+			7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 
+			7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 
+			7481, 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 
+			7549, 7559, 7561, 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 
+			7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 
+			7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 
+			7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927, 
+			7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053, 
+			8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111, 8117, 8123, 8147, 
+			8161, 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 8237, 
+			8243, 8263, 8269, 8273, 8287, 8291, 8293, 8297, 8311, 8317, 8329, 
+			8353, 8363, 8369, 8377, 8387, 8389, 8419, 8423, 8429, 8431, 8443, 
+			8447, 8461, 8467, 8501, 8513, 8521, 8527, 8537, 8539, 8543, 8563, 
+			8573, 8581, 8597, 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 
+			8669, 8677, 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 
+			8741, 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, 
+			8837, 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, 8929, 8933, 
+			8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, 9013, 9029, 
+			9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, 9127, 9133, 9137, 
+			9151, 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227, 
+			9239, 9241, 9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337, 
+			9341, 9343, 9349, 9371, 9377, 9391, 9397, 9403, 9413, 9419, 9421, 
+			9431, 9433, 9437, 9439, 9461, 9463, 9467, 9473, 9479, 9491, 9497, 
+			9511, 9521, 9533, 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, 
+			9629, 9631, 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 
+			9733, 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, 
+			9817, 9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887, 9901, 
+			9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973
+		};
+
+		public override string Name {
+			get {return Catalog.GetString ("Primes");}
+		}
+
+		public override Types Type {
+			get { return Game.Types.MathTrainer;}
+		}
+
+		public override string Question {
+			get {return Catalog.GetString ("In the set of numbers below, which of the following numbers is a prime? A prime number is a positive integer that has exactly two different positive divisors, 1 and itself.");}
+		}
+
+		public override string Tip {
+			get { return Catalog.GetString ("If the sum of all digits in a given number is divisible by 3, then so is the number. For example 15 = 1 + 5 = 6, which is divisible by 3.");}
+		}
+
+		public override void Initialize ()
+		{	
+			int answer;
+			int max_primeidx;
+
+			switch (CurrentDifficulty) {
+			case Difficulty.Easy:
+				max = 500;
+				div3 = true;
+				max_primeidx = 94;
+				break;
+			case Difficulty.Master:
+				max = 10000;
+				div3 = false;
+				max_primeidx = total_primes;
+				break;		
+			case Difficulty.Medium:
+			default:
+				max = 1000;
+				div3 = true;
+				max_primeidx = 167;
+				break;		
+			}
+
+			numbers = new int [total_nums];
+
+			for (int i = 0; i < numbers.Length; i++)
+			 	numbers [i] = GenerateNonPrime ();
+		
+			answer = primes [random.Next (max_primeidx + 1)];
+			numbers [random.Next (numbers.Length)] = answer;
+			right_answer = answer.ToString ();
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{	
+			double x = DrawAreaX, y = DrawAreaY + 0.1;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			gr.SetPangoLargeFontSize ();
+
+			gr.MoveTo (0.05, y);
+			gr.ShowPangoText (Catalog.GetString ("Numbers"));
+			y += 0.12;
+
+			for (int n = 0; n < numbers.Length; n++)
+			{
+				gr.MoveTo (x, y);
+				gr.ShowPangoText (numbers[n].ToString ());
+				gr.Stroke ();
+				x += 0.17;
+			}
+		}
+	
+		int GenerateNonPrime ()
+		{
+			int num;
+			while (true) {
+				num = 100 + random.Next (max - 100);
+
+				if (num % 2 == 0)
+					continue;
+
+				if (div3 == false && num % 3 == 0)
+					continue;
+
+				if (Array.BinarySearch (primes, num) < 0)
+					break;
+			}
+			return num;
+		}
+	}
+}
diff --git a/src/Games/Calculation/CalculationProportions.cs b/src/Games/Calculation/CalculationProportions.cs
new file mode 100644
index 0000000..20110c4
--- /dev/null
+++ b/src/Games/Calculation/CalculationProportions.cs
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2009 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Calculation
+{
+	public class CalculationProportions : Game
+	{
+		const int options_cnt = 4;
+		const int correct_pos = 0;
+		double []options;
+		ArrayListIndicesRandom random_indices;
+		double num, den, percentage, correct;
+
+		public override string Name {
+			get {return Catalog.GetString ("Proportions");}
+		}
+
+		public override Types Type {
+			get { return Game.Types.MathTrainer;}
+		}
+
+		public override string Question {
+			get {
+				return String.Format (
+					Catalog.GetString ("A {0}/{1} of 'number A' is {2}% of a 'number B'. 'number A' divided by a 'number B' is? Answer {3}, {4}, {5} or {6}."), 
+					num, den, percentage, GetPossibleAnswer (0), GetPossibleAnswer (1), GetPossibleAnswer (2), GetPossibleAnswer (3));}
+		}
+
+		public override string Answer {
+			get { 
+				string answer = base.Answer + " ";
+
+				answer += String.Format (Catalog.GetString ("The result of the operation is {0:##0.###}. You have to divide {1}/100 by {2}/{3}."), 
+					correct, percentage, num, den);
+				return answer;
+			}
+		}
+
+		public override void Initialize ()
+		{
+			int options_next, random_max, which = 0;
+		
+			switch (CurrentDifficulty) {
+			case Difficulty.Easy:
+				random_max = 10;
+				break;
+			default:
+			case Difficulty.Medium:
+				random_max = 15;
+				break;
+			case Difficulty.Master:
+				random_max = 25;
+				break;
+			}
+
+			do {
+				// Fraction
+				num = 15 + random.Next (random_max) * 2;
+				den = 1 + random.Next (random_max);
+				percentage = 50 + random.Next (random_max);
+			} while (num / den == 1); 	
+
+			options = new double [options_cnt];
+
+			options_next = 0;
+			options [options_next++] = correct = percentage / 100 / (num / den);
+			options [options_next++] = percentage / 50 * (num / den);
+			options [options_next++] = percentage / 100 / (den / num);
+			options [options_next++] = percentage / 150 * (den / num);
+
+			random_indices = new ArrayListIndicesRandom (options_cnt);
+			random_indices.Initialize ();
+		
+			for (int i = 0; i < options_cnt; i++)
+			{
+				if (random_indices [i] == correct_pos) {
+					which = i;
+					break;
+				}
+			}
+
+			right_answer += GetPossibleAnswer (which);
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{	
+			double x = DrawAreaX + 0.25, y = DrawAreaY + 0.16;
+			int indx;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			gr.SetPangoLargeFontSize ();
+
+			for (int i = 0; i < options_cnt; i++)
+			{
+				gr.MoveTo (x, y);
+				indx = random_indices[i];
+				gr.ShowPangoText (String.Format ("{0}) {1:##0.###}", GetPossibleAnswer (i) , options [indx]));
+
+				y = y + 0.15;
+			}
+		}
+	}
+}
diff --git a/src/Games/Calculation/CalculationRatio.cs b/src/Games/Calculation/CalculationRatio.cs
new file mode 100644
index 0000000..f9e99a3
--- /dev/null
+++ b/src/Games/Calculation/CalculationRatio.cs
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2009 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Calculation
+{
+	public class CalculationRatio : Game
+	{
+		int number_a, number_b, ratio_a, ratio_b;
+
+		public override string Name {
+			get {return Catalog.GetString ("Ratio");}
+		}
+
+		public override Types Type {
+			get { return Game.Types.MathTrainer;}
+		}
+
+		public override string Question {
+			get {
+				return String.Format (
+					Catalog.GetString ("Two numbers that sum {0} have a ratio of {1} to {2}. Which are these numbers?"), 
+					number_a + number_b, ratio_a, ratio_b);
+			}
+		}
+
+
+		public override string Answer {
+			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}."),
+					ratio_a, ratio_b);
+				return answer;
+			}
+		}
+
+		public override string Tip {
+			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 void Initialize ()
+		{
+			int random_max;
+		
+			switch (CurrentDifficulty) {
+			case Difficulty.Easy:
+				random_max = 5;
+				break;
+			default:
+			case Difficulty.Medium:
+				random_max = 8;
+				break;
+			case Difficulty.Master:
+				random_max = 15;
+				break;
+			}
+
+			number_a = 10 + random.Next (random_max);
+
+			if (number_a % 2 !=0)
+				number_a++;
+		
+			ratio_a = 2;
+			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);
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{	
+			double x = DrawAreaX + 0.1;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			gr.SetPangoLargeFontSize ();
+
+			gr.MoveTo (x, DrawAreaY + 0.22);
+			gr.ShowPangoText (String.Format (Catalog.GetString ("number1 + number2 = {0}"), number_a + number_b));
+		
+			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
new file mode 100644
index 0000000..3ed7905
--- /dev/null
+++ b/src/Games/Calculation/CalculationTwoNumbers.cs
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2007-2008 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Calculation
+{
+	public class CalculationTwoNumbers : Game
+	{
+		private int number_a, number_b;
+		private int op1, op2, max_operand;
+
+		public override string Name {
+			get {return Catalog.GetString ("Two numbers");}
+		}
+
+		public override Types Type {
+			get { return Game.Types.MathTrainer;}
+		}
+
+		public override string Question {
+			get {return String.Format (Catalog.GetString ("Which two numbers when added are {0} and when multiplied are {1}?"), op1, op2);} 
+		}
+
+		public override void Initialize ()
+		{	
+			switch (CurrentDifficulty) {
+			case Difficulty.Easy:
+				max_operand = 8;
+				break;
+			case Difficulty.Medium:
+				max_operand = 10;
+				break;
+			case Difficulty.Master:
+				max_operand = 15;
+				break;
+			}
+
+			number_a = 5 + random.Next (max_operand);
+			number_b = 3 + random.Next (max_operand);
+
+			op1 = number_a + number_b;
+			op2 = number_a * number_b;
+
+			right_answer = String.Format (Catalog.GetString ("{0} and {1}"), number_a, number_b);
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{	
+			double x = DrawAreaX + 0.1;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			gr.SetPangoLargeFontSize ();
+
+			gr.MoveTo (x, DrawAreaY + 0.22);
+			gr.ShowPangoText (String.Format (Catalog.GetString ("number1 + number2 = {0}"), op1));
+		
+			gr.MoveTo (x, DrawAreaY + 0.44);
+			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/GameList.cs b/src/Games/GameList.cs
new file mode 100644
index 0000000..4fcc613
--- /dev/null
+++ b/src/Games/GameList.cs
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2007-2009 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 System.Collections;
+using System.Collections.Generic;
+using Mono.Unix;
+
+using gbrainy.Games.Calculation;
+using gbrainy.Games.Logic;
+using gbrainy.Games.Memory;
+
+namespace gbrainy.Games
+{
+	public class GameList
+	{
+		static Type[] LogicPuzzlesInternal = new Type[] 
+		{
+			typeof (PuzzleMatrixNumbers),
+			typeof (PuzzleSquares),
+			typeof (PuzzleFigures),
+			typeof (PuzzleMoveFigure),
+			typeof (PuzzleCirclesRectangle),
+			typeof (PuzzlePencil),
+			typeof (PuzzleTriangles),
+			typeof (PuzzleCoverPercentage),
+			typeof (PuzzleNumericSequence),
+			typeof (PuzzleSquaresAndLetters),
+			typeof (PuzzleSquareDots),
+			typeof (PuzzleNumericRelation),
+			typeof (PuzzleNextFigure),
+			typeof (PuzzleSquareSheets),
+			typeof (PuzzleCube),
+			typeof (PuzzleFigureLetter),
+			typeof (PuzzleDivideCircle),
+			typeof (PuzzleMatrixGroups),
+			typeof (PuzzleBalance),
+			typeof (PuzzleTrianglesWithNumbers),
+			typeof (PuzzleOstracism),
+			typeof (PuzzleFigurePattern),
+			typeof (PuzzlePeopleTable),
+			typeof (PuzzleMissingSlice),
+			typeof (PuzzleLines),
+			typeof (PuzzleTetris),
+			typeof (PuzzleMissingPiece),
+			typeof (PuzzleMostInCommon),
+			typeof (PuzzleBuildTriangle),
+			typeof (PuzzleClocks),
+			typeof (PuzzleCountCircles),
+			typeof (PuzzleEquation),
+			typeof (PuzzleQuadrilaterals),
+			typeof (PuzzleExtraCircle),
+			typeof (PuzzleCountSeries),
+			typeof (PuzzleFourSided),
+			typeof (PuzzleLargerShape),
+			typeof (PuzzleHandshakes),
+			typeof (PuzzleCounting),
+			typeof (PuzzlePercentage),
+			typeof (PuzzleTimeNow),
+			typeof (Puzzle3DCube),
+		};
+
+		static Type[] CalculationTrainersInternal = new Type[] 
+		{
+			typeof (CalculationArithmetical),
+			typeof (CalculationGreatestDivisor),
+			typeof (CalculationTwoNumbers),
+			typeof (CalculationCloserFraction),
+			typeof (CalculationOperator),
+			typeof (CalculationFractions),
+			typeof (CalculationPrimes),
+			typeof (CalculationAverage),
+			typeof (CalculationProportions),
+			typeof (CalculationRatio),
+		};
+
+		static Type[] MemoryTrainersInternal = new Type[] 
+		{
+			typeof (MemoryColouredFigures),
+			typeof (MemoryFiguresNumbers),
+			typeof (MemoryColouredText),
+			typeof (MemoryWords),
+			typeof (MemoryCountDots),
+			typeof (MemoryFigures),
+			typeof (MemoryIndications),
+			typeof (MemoryNumbers),
+			typeof (MemoryFacts),
+		};
+
+		public static Type [] LogicPuzzles
+		{
+			get {
+				return LogicPuzzlesInternal;
+			}
+		}
+
+		public static Type [] CalculationTrainers
+		{
+			get {
+				return CalculationTrainersInternal;
+			}
+		}
+
+		public static Type [] MemoryTrainers
+		{
+			get {
+				return MemoryTrainersInternal;
+			}
+		}
+	}
+}
diff --git a/src/Games/Logic/Puzzle3DCube.cs b/src/Games/Logic/Puzzle3DCube.cs
new file mode 100644
index 0000000..79a2025
--- /dev/null
+++ b/src/Games/Logic/Puzzle3DCube.cs
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2009 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 Cairo;
+using Mono.Unix;
+using System;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class Puzzle3DCube : Game
+	{
+		int rows, columns, deepth;
+
+		public override string Name {
+			get {return Catalog.GetString ("Cube");}
+		}
+
+		public override string Question {
+			get {return String.Format (Catalog.GetString ("How many cubes do you count in the figure below? (not counting the figure) Answer using a number."));} 
+		}
+
+		public override string Tip {
+			get { return Catalog.GetString ("A cube is a regular solid object having six congruent square faces.");}
+		}
+
+		public override void Initialize ()
+		{
+			int ans, max_random;
+
+			switch (CurrentDifficulty) {
+			case Difficulty.Easy:
+				max_random = 1;
+				break;
+			case Difficulty.Master:
+				max_random = 5;
+				break;
+			case Difficulty.Medium:
+			default:
+				max_random = 3;
+				break;		
+			}
+
+			rows = columns = deepth = 4 + random.Next (max_random);
+			ans = rows * columns * deepth;
+			right_answer += ans.ToString ();	
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			const double size = 0.05;
+			const double radian = Math.PI / 180;
+			const int degrees = -45;
+			const double radius = 0.035;
+			const double size_y = 0.025;
+
+			double x = DrawAreaX + 0.1;
+			double y = DrawAreaY + 0.3;
+			double x0, y0, offset_y;
+			double offset_x = 0;
+		
+			base.Draw (gr, area_width, area_height, rtl);
+
+			x = 1 - (2 * DrawAreaX) - (columns * size * 1.5);
+			x = DrawAreaX + x /2;
+
+			// Front face
+			for (int pos_y = 0; pos_y < rows; pos_y++)
+			{
+				//  |
+				//  |
+				//
+				gr.MoveTo (x, y + (pos_y * size));
+				gr.LineTo (x, y + ((pos_y + 1) * size));
+				gr.Stroke ();
+
+				for (int pos_x = 0; pos_x < columns; pos_x++)
+				{
+					//  ---|
+					//     |
+					//
+					gr.MoveTo (x + (size * pos_x) , y + (pos_y * size));
+					gr.LineTo (x + (size * (pos_x + 1)), y + (pos_y * size));
+					gr.LineTo (x + (size * (pos_x + 1)), y + (pos_y + 1) * size);
+					gr.Stroke ();
+				}
+			}
+
+			gr.MoveTo (x , y + (rows * size));
+			gr.LineTo (x + (columns * size) , y + (rows * size));
+			gr.Stroke ();
+
+			// Back face
+			for (int pos_y = 0; pos_y < rows; pos_y++)
+			{
+				offset_x = (0.025 * pos_y);
+
+				//  |
+				//  |
+				//
+				gr.MoveTo (x + offset_x, y - (pos_y * size_y));
+				gr.LineTo (x + offset_x + 0.025, y - ((pos_y + 1)  * size_y));
+				gr.Stroke ();
+
+				for (int pos_x = 0; pos_x < columns; pos_x++)
+				{
+					gr.MoveTo (x + offset_x + (size * pos_x) , y - (pos_y * size_y));
+					gr.LineTo (x + offset_x + (size * (pos_x + 1)), y - (pos_y * size_y));
+					gr.LineTo (x + offset_x +  0.025 + (size * (pos_x + 1)), y - (pos_y + 1) * size_y);
+					gr.Stroke ();
+				}
+			}
+
+			offset_x = (0.025 * columns);
+			gr.MoveTo (x + offset_x, y - (rows * size_y));
+			gr.LineTo (x + offset_x + (size * columns) , y - (rows * size_y));
+			gr.Stroke ();
+
+			// Lateral face
+			for (int pos_y = 0; pos_y < rows; pos_y++)
+			{
+				for (int pos_x = 0; pos_x < columns; pos_x++)
+				{
+					offset_x = (size * columns) + (0.025 * pos_x);
+					offset_y = size_y * pos_x;
+		
+					gr.MoveTo (x + offset_x, y - offset_y + (pos_y * size));
+					gr.LineTo (x + offset_x, y - offset_y + (pos_y + 1) * size);
+					x0 = radius * Math.Cos (degrees * radian);
+					y0 = radius * Math.Sin (degrees * radian);
+
+					gr.LineTo (x + offset_x + x0, y - offset_y + y0 +  (pos_y + 1) * size);
+					gr.Stroke ();
+				}
+			}
+
+			offset_x = (size * columns) + (0.025 * columns);
+			offset_y = size_y * rows;	
+			gr.MoveTo (x + offset_x, y - offset_y);
+			gr.LineTo (x + offset_x, y - offset_y + (rows * size));
+			gr.Stroke ();
+		}
+	}	
+}
diff --git a/src/Games/Logic/PuzzleBalance.cs b/src/Games/Logic/PuzzleBalance.cs
new file mode 100644
index 0000000..067664f
--- /dev/null
+++ b/src/Games/Logic/PuzzleBalance.cs
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleBalance : Game
+	{
+		private const int elements = 5;
+		private int group;
+		private int [] balances = new int []
+		{
+			2,3,2,0,0,	1,3,1,1,1,
+			3,3,1,0,0,	2,2,2,1,0,
+			3,2,2,0,0,	0,0,0,0,0,
+
+			2,2,3,0,0,	3,2,1,1,0,
+			1,2,2,0,0,	3,1,1,0,0,
+			3,3,1,0,0,	0,0,0,0,0,
+
+			2,2,0,0,0,	2,1,1,0,0,
+			3,2,0,0,0,	1,1,1,2,0,
+			2,2,3,0,0,	0,0,0,0,0,
+		};
+
+		private const double figure_width = 0.1, figure_height = 0.1, space_width = 0.05, space_height = 0;
+
+		public override string Name {
+			get {return Catalog.GetString ("Balance");}
+		}
+
+		public override string Question {
+			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 Tip {
+			get { return Catalog.GetString ("Every diamond counts as two triangles.");}
+		}
+
+		public override void Initialize ()
+		{
+			int ans = 0;
+			group = random.Next (3);
+
+			for (int i = 0; i < elements; i++)	
+				ans += balances [(group * elements * 6) + (4 * elements) + i];
+
+			right_answer = ans.ToString ();
+		}
+
+		public void DrawBalance (CairoContextEx gr, double x, double y, int index, bool full)
+		{
+			const double width = 0.5;
+			double fig_x = x + 0.1, fig_y = y - 0.11;
+			int total = (full == true) ? (elements * 2) : elements; 
+
+			gr.Rectangle (x + 0.05, y - 0.12, 0.38, 0.08);
+			gr.Stroke ();
+
+			gr.Rectangle (x + 0.5, y - 0.12, 0.38, 0.08);
+			gr.Stroke ();
+
+			for (int i = 0; i < total; i++) {
+				switch (balances[i + index]) {
+				case 1:
+					gr.DrawEquilateralTriangle (fig_x, fig_y, 0.05);
+					break;
+				case 2:
+					gr.DrawDiamond (fig_x, fig_y, 0.05);
+					break;
+				case 3:
+					gr.Rectangle (fig_x, fig_y + 0.005, 0.045, 0.045);
+					break;
+				}
+			
+				if (i == elements - 1)
+					fig_x = x + 0.54;
+				else
+					fig_x += 0.07;
+			}
+
+			x += 0.2;
+			y += 0.01;
+			gr.MoveTo (x, y);
+			gr.LineTo (x + width, y);
+			gr.LineTo (x + width, y - 0.05);
+			gr.Stroke ();
+		
+			gr.MoveTo (x , y);
+			gr.LineTo (x , y - 0.05);
+			gr.Stroke ();
+		
+			gr.DrawEquilateralTriangle (x + (width / 2) - 0.04, y, 0.08);
+			gr.Stroke ();
+
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{		
+			double x = 0.05, y = DrawAreaY + 0.1;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			DrawBalance (gr, x, y, group * elements * 6, true);
+			y += 0.3;
+		
+			DrawBalance (gr, x, y, (group * elements * 6) + 1 * elements * 2, true);
+			y += 0.3;
+
+			DrawBalance (gr, x, y, (group * elements * 6) + 2 * elements * 2, false);
+		}
+
+	}
+}
diff --git a/src/Games/Logic/PuzzleBuildTriangle.cs b/src/Games/Logic/PuzzleBuildTriangle.cs
new file mode 100644
index 0000000..fdcc91b
--- /dev/null
+++ b/src/Games/Logic/PuzzleBuildTriangle.cs
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2008 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleBuildTriangle : Game
+	{
+		public enum Figures
+		{
+			TriangleA,
+			TriangleB,
+			TriangleC,
+			Square,
+			Diamon,
+			LongRectangle,
+			LongRectangleUp,
+			TriangleD,
+		}
+
+		private const double figure_size = 0.1;
+		private ArrayListIndicesRandom random_indices_answers;
+		private string [] answers;
+		private const int answer_num = 3;
+		private int total_figures;
+		private double space_figures;
+		private double radian = Math.PI / 180;
+
+		public override string Name {
+			get {return Catalog.GetString ("Build a triangle");}
+		}
+
+		public override string Question {
+			get {return String.Format (
+				Catalog.GetString ("Which three pieces can you use together to build a triangle? Answer using the three figure names, e.g.: {0}{1}{2}."),
+					GetPossibleAnswer (0), GetPossibleAnswer (1), GetPossibleAnswer (2));}
+		}
+
+		public override string Tip {
+			get { return Catalog.GetString ("The resulting triangle is isosceles.");}
+		}
+
+		public override void Initialize ()
+		{
+			switch (CurrentDifficulty) {
+			case Difficulty.Easy:
+				total_figures = 6;
+				space_figures = 0.26;
+				break;
+			case Difficulty.Medium:
+			case Difficulty.Master:
+				total_figures = 8;
+				space_figures = 0.2;
+				break;
+			}
+
+			random_indices_answers = new ArrayListIndicesRandom (total_figures);
+			random_indices_answers.Initialize ();
+			answers = new string[answer_num];
+
+			for (int i = 0; i < random_indices_answers.Count; i++)
+			{
+				switch ((Figures) random_indices_answers[i]) {
+				case Figures.TriangleB:
+					answers[0] =  GetPossibleAnswer (i);
+					break;
+				case Figures.TriangleC:
+					answers[1] =  GetPossibleAnswer (i);
+					break;
+				case Figures.Square:
+					answers[2] =  GetPossibleAnswer (i);
+					break;
+				}
+			}
+
+			right_answer = answers[0] + answers[1] + answers[2];
+		}
+
+		private static void DrawFigure (CairoContextEx gr, double x, double y, Figures figure)
+		{
+			switch (figure) {
+			case Figures.TriangleA:
+				gr.DrawEquilateralTriangle (x, y, figure_size);
+				break;
+			case Figures.TriangleB:
+				gr.MoveTo (x, y);
+				gr.LineTo (x, y + figure_size);
+				gr.LineTo (x + figure_size, y);
+				gr.LineTo (x, y);
+				gr.Stroke ();
+				break;
+			case Figures.TriangleC:
+				gr.MoveTo (x, y);
+				gr.LineTo (x, y + figure_size);
+				gr.LineTo (x + figure_size, y + figure_size);
+				gr.LineTo (x, y);
+				gr.Stroke ();
+				break;
+			case Figures.Square:
+				gr.Rectangle (x, y, figure_size, figure_size);
+				gr.Stroke ();
+				break;
+			case Figures.LongRectangle:
+				gr.Rectangle (x, y + figure_size / 2, figure_size, figure_size / 2);
+				gr.Stroke ();
+				break;
+			case Figures.LongRectangleUp:
+				gr.Rectangle (x, y, figure_size, figure_size / 2);
+				gr.Stroke ();
+				break;
+			case Figures.Diamon:
+				gr.DrawDiamond (x, y, figure_size);
+				break;
+			case Figures.TriangleD:
+				gr.MoveTo (x, y);
+				gr.LineTo (x, y + figure_size * 0.7);
+				gr.LineTo (x + figure_size * 0.7, y + figure_size * 0.7);
+				gr.LineTo (x, y);
+				gr.Stroke ();
+				break;
+			}
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double x = DrawAreaX + 0.05, y = DrawAreaY + 0.1;
+			double degrees, x1, x2, dist;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			for (int i = 0; i < random_indices_answers.Count; i++)	
+			{
+				DrawFigure (gr, x, y, (Figures) random_indices_answers[i]);
+				gr.MoveTo (x, y + 0.13);
+				gr.ShowPangoText (GetPossibleFigureAnswer (i));
+
+				if (i  == (total_figures / 2) - 1) {
+					y+= 0.30;
+					x= DrawAreaX + 0.05;
+				}
+				else
+					x+= space_figures;
+			}
+
+			if (DrawAnswer == false)
+				return;
+
+			gr.MoveTo (DrawAreaX, y + 0.28);
+			gr.ShowPangoText (Catalog.GetString ("The triangle is:"));
+			gr.Stroke ();
+		
+			x = DrawAreaX + 0.35;
+			y += 0.35;
+
+			degrees = radian * 45;	// First triangle
+			gr.MoveTo (x, y);
+			x1 = x + figure_size * Math.Cos (degrees);
+			gr.LineTo (x1, y + figure_size * Math.Sin (degrees));
+
+			degrees = radian * (135);
+			x2 = x + figure_size * Math.Cos (degrees);
+			gr.MoveTo (x, y);
+			gr.LineTo (x2, y + figure_size * Math.Sin (degrees));
+			gr.LineTo (x1, y + figure_size * Math.Sin (degrees));
+			dist = (x1 - x2);
+			x += dist;
+
+			degrees = radian * 45; // Second triangle
+			gr.MoveTo (x, y);
+			x1 = x + figure_size * Math.Cos (degrees);
+			gr.LineTo (x1, y + figure_size * Math.Sin (degrees));
+
+			degrees = radian * (135);
+			x2 = x + figure_size * Math.Cos (degrees);
+			gr.MoveTo (x, y);
+			gr.LineTo (x2, y + figure_size * Math.Sin (degrees));
+			gr.LineTo (x1, y + figure_size * Math.Sin (degrees));
+
+			degrees = radian * (-45); // Bottom
+			x =  DrawAreaX + 0.35;
+			gr.MoveTo (x, y);
+			gr.LineTo (x + figure_size * Math.Cos (degrees), y + figure_size * Math.Sin (degrees));
+
+			x += dist;
+			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;
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleCirclesRectangle.cs b/src/Games/Logic/PuzzleCirclesRectangle.cs
new file mode 100644
index 0000000..0baa99a
--- /dev/null
+++ b/src/Games/Logic/PuzzleCirclesRectangle.cs
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleCirclesRectangle : Game
+	{
+		public override string Name {
+			get {return Catalog.GetString ("Circles in a rectangle");}
+		}
+
+		public override string Question {
+			get {return Catalog.GetString ("What is the maximum number of circles (as shown) that fit in the square below?");} 
+		}
+
+		public override string Tip {
+			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 void Initialize ()
+		{
+			right_answer = "68";
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double first_x = DrawAreaX + 0.05;
+			double first_y = DrawAreaY + 0.1;
+			const double space_fromrect = 0.02, space_fromcircle = 0.01;
+			int circles = 8;
+			const double unit = 0.0625;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			gr.Rectangle (first_x, first_y, unit * 8, unit * 8);
+			gr.Stroke ();
+
+			// |-------|
+			gr.MoveTo (first_x, first_y - 0.04 - space_fromrect);
+			gr.LineTo (first_x, first_y - space_fromrect);
+			gr.Stroke ();
+			gr.MoveTo (first_x, first_y - 0.02 - space_fromrect);
+			gr.LineTo (first_x + 0.5, first_y - 0.02 - space_fromrect);
+			gr.Stroke ();
+			gr.MoveTo (first_x + 0.5, first_y - 0.04 - space_fromrect);
+			gr.LineTo (first_x + 0.5, first_y - space_fromrect);
+			gr.Stroke ();
+
+			gr.MoveTo (first_x + 0.2, first_y - 0.06 - space_fromrect);
+			gr.ShowPangoText (Catalog.GetString ("8 units"));
+			gr.Stroke ();
+
+
+
+			//  ---
+			//	 |
+			//	 |
+			//	 |
+			//  ---
+			gr.MoveTo (first_x  - space_fromrect, first_y);
+			gr.LineTo (first_x  - space_fromrect - 0.04, first_y);
+			gr.Stroke ();
+			gr.MoveTo (first_x - space_fromrect - 0.02, first_y);
+			gr.LineTo (first_x - space_fromrect - 0.02, first_y + 0.5);
+			gr.Stroke ();
+			gr.MoveTo (first_x - space_fromrect, first_y + 0.5);
+			gr.LineTo (first_x - space_fromrect - 0.04, first_y + 0.5);
+			gr.Stroke ();
+
+			gr.MoveTo (first_x - space_fromrect - 0.07, first_y + 0.3);
+			gr.ShowPangoText (Catalog.GetString ("8 units"), false, -1, 270 * Math.PI/180);
+			gr.Stroke ();
+
+			// Sample circle
+			gr.Arc (first_x + 0.7, first_y + 0.1, unit / 2, 0, 2 * Math.PI);
+			gr.Stroke ();
+
+			// |-------|
+			gr.MoveTo (first_x + 0.65, first_y + 0.05 - 0.04 - space_fromcircle);
+			gr.LineTo (first_x + 0.65, first_y + 0.05 - space_fromcircle);
+			gr.Stroke ();
+			gr.MoveTo (first_x + 0.65, first_y + 0.05 - 0.02 - space_fromcircle);
+			gr.LineTo (first_x + 0.65 + 0.1, first_y + 0.05 - 0.02 - space_fromcircle);
+			gr.Stroke ();
+			gr.MoveTo (first_x + 0.65 + 0.1, first_y + 0.05 - 0.04 - space_fromcircle);
+			gr.LineTo (first_x + 0.65 + 0.1, first_y + 0.05 - space_fromcircle);
+			gr.Stroke ();
+
+			gr.MoveTo (first_x + 0.65, first_y - 0.04 - space_fromcircle);
+			gr.ShowPangoText (Catalog.GetString ("1 unit"));
+			gr.Stroke ();
+
+			//  ---
+			//	 |
+			//	 |
+			//	 |
+			//  ---
+			gr.MoveTo (first_x + 0.65  - space_fromcircle, first_y + 0.05);
+			gr.LineTo (first_x + 0.65  - space_fromcircle - 0.04, first_y + 0.05);
+			gr.Stroke ();
+			gr.MoveTo (first_x + 0.65 - space_fromcircle - 0.02, first_y + 0.05);
+			gr.LineTo (first_x + 0.65 - space_fromcircle - 0.02, first_y  + 0.05 + 0.1);
+			gr.Stroke ();
+			gr.MoveTo (first_x + 0.65 - space_fromcircle, first_y + 0.1 + 0.05);
+			gr.LineTo (first_x + 0.65 - space_fromcircle - 0.04, first_y + 0.1 + 0.05);
+			gr.Stroke ();
+
+			gr.MoveTo (first_x + 0.65 - space_fromcircle - 0.08, first_y + 0.15);
+			gr.ShowPangoText (Catalog.GetString ("1 unit"), false, -1, 270 * Math.PI/180);
+			gr.Stroke ();
+
+			if (DrawAnswer == false)
+				return;
+
+			double x;
+			for (int line = 0; line < 9; line++)
+			{
+				for (int circle = 0; circle < circles; circle++) 
+				{
+					x = first_x + (unit / 2) + (circle * unit);
+				
+					if (circles == 7)
+						x+= unit / 2;
+
+					gr.Arc (x, (unit / 2) + first_y + (unit * line) - (unit / 8) * line, 
+							(unit / 2), 0, 2 * Math.PI);
+					gr.Stroke ();
+				}
+
+				if (circles ==8)
+					circles = 7;
+				else
+					circles = 8;
+			}
+
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleClocks.cs b/src/Games/Logic/PuzzleClocks.cs
new file mode 100644
index 0000000..6799065
--- /dev/null
+++ b/src/Games/Logic/PuzzleClocks.cs
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2008 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 Cairo;
+using Mono.Unix;
+using System;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleClocks : Game
+	{
+		private const double figure_size = 0.3;
+		private const double radian = Math.PI / 180;
+		private int addition;
+		private int []handles;
+		private const int clocks = 4;
+		private const int handle_num = 2;
+
+		public override string Name {
+			get {return Catalog.GetString ("Clocks");}
+		}
+
+		public override string Question {
+			get {return (String.Format (
+				Catalog.GetString ("To what number should the large handle of the '{0}' clock point? Answer using numbers."),
+				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 Tip {
+			get { return Catalog.GetString ("The clocks do not follow the time logic.");}
+		}
+
+		public override void Initialize ()
+		{
+			int position;
+
+			// In all these cases the clock logic clearly do not work since the small hand is in the next hour
+			switch (random.Next (3)) {
+			case 0:
+				position = 48;
+				addition = 5;
+				break;
+			case 1:
+				position = 38;
+				addition = 15;
+				break;
+			case 2:
+			default:
+				position = 24;
+				addition = 5;
+				break;
+			}
+
+			handles = new int [clocks * handle_num];
+
+			for (int i = 0; i < handles.Length; i++, i++)
+			{
+				handles [i] = position / 10;
+				handles [i + 1] = position - ((position / 10) * 10);
+				position += addition;
+			}
+		
+			right_answer = handles[7].ToString ();
+
+			/*DateTime dt1 = new DateTime (2008, 2, 20, handles[0], handles[1] * 5, 0);
+			DateTime dt2 = new DateTime (2008, 2, 20, handles[2], handles[3] * 5, 0);
+			Console.WriteLine ("t1 {0}", dt1);
+			Console.WriteLine ("t2 {0}", dt2);
+			Console.WriteLine ("Time diff {0} from 1st to 2nd", dt2-dt1);
+
+			dt1 = new DateTime (2008, 2, 20, handles[2], handles[3] * 5, 0);
+			dt2 = new DateTime (2008, 2, 20, handles[4], handles[5] * 5, 0);
+			Console.WriteLine ("t1 {0}", dt1);
+			Console.WriteLine ("t2 {0}", dt2);
+			Console.WriteLine ("Time diff {0} from 1st to 2nd", dt2-dt1);
+
+			dt1 = new DateTime (2008, 2, 20, handles[4], handles[5] * 5, 0);
+			dt2 = new DateTime (2008, 2, 20, handles[6], handles[7] * 5, 0);
+			Console.WriteLine ("t1 {0}", dt1);
+			Console.WriteLine ("t2 {0}", dt2);
+			Console.WriteLine ("Time diff {0} from 1st to 2nd", dt2-dt1);*/
+
+		}	
+
+		static void DrawClock (CairoContextEx gr, double x, double y, int hand_short, int hand_large, bool draw_large)
+		{
+			const double radius = figure_size / 2;
+			double x0, y0;
+			int num, degrees;
+
+			gr.Arc (x, y, radius, 0, 2 * Math.PI);
+			gr.Stroke ();
+			for (degrees = 0; degrees < 360; degrees+= 30) {
+				x0 = radius * Math.Cos (degrees * radian);
+				y0 = radius * Math.Sin (degrees * radian);
+				 // Small lines
+				gr.MoveTo (x + 0.9 * x0, y + 0.9 * y0);
+				gr.LineTo (x + x0, y + y0);
+				gr.Stroke ();
+				// Numbers
+				num = (degrees / 30) + 3;
+				if (num > 12) num = num - 12;
+
+				gr.DrawTextCentered (x + x0 * 0.75,  y + y0 * 0.75, num.ToString ());
+				gr.Stroke ();
+			}
+
+			if (draw_large) {
+				// Hand Large
+				degrees = (hand_large - 3) * 30; 
+				x0 = radius * Math.Cos (degrees * radian);
+				y0 = radius * Math.Sin (degrees * radian);
+				gr.MoveTo (x, y);
+				gr.LineTo (x + x0 * 0.55, y + y0 * 0.55);
+				gr.Stroke ();
+			}
+			// Hand Short
+			degrees = (hand_short - 3) * 30; 
+			x0 = radius * Math.Cos (degrees * radian);
+			y0 = radius * Math.Sin (degrees * radian);
+			gr.MoveTo (x, y);
+			gr.LineTo (x + x0 * 0.4, y + y0 * 0.4);
+			gr.Stroke ();
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double x = DrawAreaX + 0.1, y = DrawAreaY + 0.05;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			DrawClock (gr, x + 0.1, y + 0.1, handles[0], handles[1], true);
+			gr.MoveTo (x + 0.03, y + 0.29);
+			gr.ShowPangoText (GetPossibleFigureAnswer (0));
+			gr.Stroke ();
+	
+			DrawClock (gr, x + 0.5, y + 0.1, handles[2], handles[3], true);
+			gr.MoveTo (x + 0.43, y + 0.29);
+			gr.ShowPangoText (GetPossibleFigureAnswer (1));
+			gr.Stroke ();
+
+			DrawClock (gr, x + 0.1, y + 0.52, handles[4], handles[5], true);
+			gr.MoveTo (x + 0.03, y + 0.71);
+			gr.ShowPangoText (GetPossibleFigureAnswer (2));
+			gr.Stroke ();
+
+			DrawClock (gr, x + 0.5, y + 0.52, handles[6], handles[7], DrawAnswer == true);
+			gr.MoveTo (x + 0.43, y + 0.71);
+			gr.ShowPangoText (GetPossibleFigureAnswer (3));
+			gr.Stroke ();
+
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleCountCircles.cs b/src/Games/Logic/PuzzleCountCircles.cs
new file mode 100644
index 0000000..c4dadc7
--- /dev/null
+++ b/src/Games/Logic/PuzzleCountCircles.cs
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2008 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 Cairo;
+using Mono.Unix;
+using System;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleCountCircles : Game
+	{
+		private const double figure_size = 0.3;
+		private const double radian = Math.PI / 180;
+		private int n_circles;
+
+		class ItemCircle
+		{
+			public double x, y, rad;
+
+			public ItemCircle (double x, double y, double rad)
+			{
+				this.x = x;
+				this.y = y;
+				this.rad = rad;
+			}
+		}
+
+		ItemCircle[] circles;
+
+		public override string Name {
+			get {return Catalog.GetString ("Count circles");}
+		}
+
+		public override string Question {
+			get {return Catalog.GetString ("How many circles do you count?");} 
+		}
+
+		public override string Tip {
+			get { return Catalog.GetString ("It is an easy exercise if you systematically count the circles.");}
+		}
+
+		public override void Initialize ()
+		{
+			double x, y, rad;
+
+			switch (CurrentDifficulty) {
+			case Difficulty.Easy:
+				n_circles = 7;
+				break;
+			case Difficulty.Master:
+				n_circles = 14;
+				break;		
+			case Difficulty.Medium:
+			default:
+				n_circles = 10;
+				break;		
+			}
+
+			n_circles += random.Next (5);
+			circles = new ItemCircle [n_circles];
+			for (int i = 0; i < circles.Length; i++)
+			{
+				x = random.Next (500) / 1000d;
+				y = random.Next (500) / 1000d;
+				rad = 0.03 +  random.Next (500) / 3200d;
+
+				circles[i] = new ItemCircle (x, y, rad);
+			}
+
+			right_answer = n_circles.ToString ();
+		}	
+
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double x = DrawAreaX + 0.1, y = DrawAreaY + 0.05;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			for (int i = 0; i < circles.Length; i++)
+			{
+				gr.Arc (x + circles[i].x + 0.1, y + circles[i].y + 0.1, circles[i].rad, 0, 2 * Math.PI);
+				gr.Stroke ();
+			}
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleCountSeries.cs b/src/Games/Logic/PuzzleCountSeries.cs
new file mode 100644
index 0000000..2ed0ef9
--- /dev/null
+++ b/src/Games/Logic/PuzzleCountSeries.cs
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2008 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleCountSeries : Game
+	{
+		enum GameType
+		{
+			HowManyNines,
+			HowManySmallerDigits,
+			HowManyBiggerDigits,
+			Length		
+		}
+
+		private string question;
+
+		public override string Name {
+			get {return Catalog.GetString ("Count series");}
+		}
+
+		public override string Question {
+			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))
+			{
+				case GameType.HowManyNines:
+					question = Catalog.GetString ("How many numbers \"9\" are required to represent the numbers between 10 to 100?");
+					right_answer = "19";
+					break;
+
+				case GameType.HowManyBiggerDigits:
+					question = Catalog.GetString ("How many two digit numbers occur where the first digit is larger than the second (e.g.: 20 and 21)?");
+					right_answer = "45";
+					break;
+
+				case GameType.HowManySmallerDigits:
+					question = Catalog.GetString ("How many two digit numbers occur where the first digit is smaller than the second (e.g.: 12 and 13)?");
+					right_answer = "36";
+					break;
+			}
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			base.Draw (gr, area_width, area_height, rtl);
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleCounting.cs b/src/Games/Logic/PuzzleCounting.cs
new file mode 100644
index 0000000..b5029d2
--- /dev/null
+++ b/src/Games/Logic/PuzzleCounting.cs
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2009 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 Cairo;
+using Mono.Unix;
+using System;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleCounting : Game
+	{
+		enum GameType
+		{
+			Machine,
+			Fence,
+			Present,
+			Total
+		}
+
+		string question, answer;
+		GameType gametype;
+
+		public override string Name {
+			get {return Catalog.GetString ("Counting");}
+		}
+
+		public override string Question {
+			get {return question; }
+		}
+
+		public override string Answer {
+			get { return base.Answer + " " + answer;}
+		}
+
+		public override void Initialize ()
+		{
+			int ans, var, total;
+
+			gametype = (GameType) random.Next ((int) GameType.Total);
+
+			switch ((int) gametype)
+			{
+			case (int) GameType.Machine:
+				var = 2 + random.Next (5);
+				total = 50 + random.Next (100);
+				question = String.Format (
+					// Translators: {0} and {1} are always numbers greater than 1
+					Catalog.GetString ("We have a {0} meters piece of fabric. Machine A takes {1} seconds to cut 1 meter of this fabric. How many seconds does Machine A take to cut the entire piece of fabric into 1 meter pieces?"),
+					total, var);
+				answer = String.Format (
+					// Translators: {0} is always a number greater than 1
+					Catalog.GetString ("With the {0} cut, Machine A creates two 1 meter pieces."), (total - 1));
+	
+				ans = (total - 1) * var;
+				break;
+
+			case (int) GameType.Fence:
+				total = 20 + random.Next (20);
+				ans = 4 * total - 4;
+				question = String.Format (
+					// Translators: {0} is always a number greater than 20
+					Catalog.GetString ("A fence is built to enclose a square shaped region. {0} fence poles are used in each side of the square. How many fence poles are used in total?"),
+					total);
+					// Translators: {0} is always a number greater than 20
+				answer = String.Format (
+					Catalog.GetString ("There are {0} fence poles since the poles on the corners of the square are shared."), ans);
+				break;
+
+			case (int) GameType.Present:
+				int present = 5 + random.Next (20);
+				total = present + 2;
+				ans = total;
+				question = String.Format (
+					// Translators: {0} is always a number greater than 5
+					Catalog.GetString ("Wrapping an anniversary present costs one euro. The anniversary present costs {0} euros more than the cost to wrap it. How much does it cost to both purchase and wrap the present?"),
+					present);
+				answer = String.Format (
+					Catalog.GetString ("Individually, the present costs one euro more to purchase than to wrap."));
+				break;
+			default:
+				throw new Exception ("Unexpected value");
+			}
+
+			right_answer = (ans).ToString ();
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			base.Draw (gr, area_width, area_height, rtl);
+
+			if (gametype == GameType.Present) {
+				gr.DrawImageFromAssembly ("present.svg", 0.2, 0.4, 0.6, 0.2);
+			} else {
+				if (gametype == GameType.Fence)
+				{
+					double x105, y105;
+					const double x = 0.35, y = 0.2;
+					const double figure_size = 0.4;
+
+					x105 = figure_size * Math.Cos (105 * Math.PI / 180);
+					y105 = figure_size * Math.Sin (105 * Math.PI / 180);
+					gr.MoveTo (x, y);
+					gr.LineTo (x + x105, y + y105);
+					gr.LineTo (x + x105 + figure_size, y + y105);
+					gr.Stroke ();
+					gr.MoveTo (x + figure_size, y);
+					gr.LineTo (x + figure_size + x105, y + y105);
+					gr.Stroke ();
+					gr.MoveTo (x, y);
+					gr.LineTo (x + figure_size, y);
+					gr.Stroke ();
+				}
+			}
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleCoverPercentage.cs b/src/Games/Logic/PuzzleCoverPercentage.cs
new file mode 100644
index 0000000..a5426df
--- /dev/null
+++ b/src/Games/Logic/PuzzleCoverPercentage.cs
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2007-2008 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleCoverPercentage : Game
+	{
+		private bool cover_zone1, cover_zone2, cover_zone3, cover_zone4;
+		private int partial_zone, partial_zones;
+		private const double width = 0.5, height = 0.5;
+		private const double line_width = 0.001;
+
+		public override string Name {
+			get {return Catalog.GetString ("Cover percentage");}
+		}
+
+		public override string Question {
+			get {return Catalog.GetString ("What percentage of the figure is colored?");} 
+		}
+
+		public override void Initialize ()
+		{
+			int total = 0;
+
+			cover_zone1 = random.Next (3) == 0;
+			cover_zone2 = random.Next (3) == 0;
+			cover_zone3 = random.Next (3) == 0;
+			cover_zone4 = random.Next (3) == 0;
+
+			if (cover_zone1 && cover_zone2 && cover_zone3)
+				cover_zone4 = false;
+
+			if (cover_zone1) total+= 25;
+			if (cover_zone2) total+= 25;
+			if (cover_zone3) total+= 25;
+			if (cover_zone4) total+= 25;
+
+			if (cover_zone1 == false)
+				partial_zone = 1;
+			else
+				if (cover_zone2 == false)
+					partial_zone = 2;
+				else
+					if (cover_zone3 == false)
+						partial_zone = 3;
+					else
+						if (cover_zone4 == false)
+							partial_zone = 4;
+
+			partial_zones = random.Next (2) + 1;
+			total += partial_zones * 5;
+			right_answer = total.ToString ();
+		}
+
+		private static void Fill (CairoContextEx gr, double x, double y, double w, double h)
+		{
+			gr.Rectangle (x, y, w, h);
+			gr.FillGradient (x, y, w, h);
+		}
+
+		private void DrawSection (CairoContextEx gr, double x, double y)
+		{
+			double w =  width / 2, h = height / 2;
+			double pos_x = x, pos_y = y;
+			for (int i = 0; i < 5; i++) {
+				gr.MoveTo (pos_x, pos_y + h / 5);
+				gr.LineTo (pos_x + w, pos_y + h / 5);
+				gr.Stroke ();
+				pos_y += h / 5;
+			}
+	
+			gr.MoveTo (x + w / 2, y);
+			gr.LineTo (x + w / 2, y + h);
+			gr.Stroke ();
+
+			gr.Save ();
+			gr.Color = new Cairo.Color (0.90, 0.90, 0.90);
+			for (int i = 0; i < partial_zones; i++) {
+				Fill (gr, x + line_width, line_width + y, 
+					(w / 2) - (line_width * 2) , (h / 5) - (line_width * 2));
+				Fill (gr, x + (w / 2) + line_width * 2, line_width + y, 
+					(w / 2) - (line_width * 4) , (h / 5) - (line_width * 2));
+				y += h / 5;
+			}
+			gr.Restore ();
+		}
+
+		private void CoverZone (CairoContextEx gr, double x, double y)
+		{
+			Fill (gr, x + line_width, y + line_width , (width / 2) - (line_width * 2), (height / 2) - (line_width * 2));
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double x = 0.25, y = 0.25;
+
+			base.Draw (gr, area_width, area_height, rtl);
+		
+			gr.Rectangle (x, y, width, height);
+			gr.Stroke ();
+
+			gr.MoveTo (x, y + height / 2);
+			gr.LineTo (x + width, y + height / 2);
+			gr.Stroke ();
+
+			gr.MoveTo (x + width / 2, y);
+			gr.LineTo (x + width / 2, y + height);
+			gr.Stroke ();
+
+			if (cover_zone1) 
+				CoverZone (gr, x, y);
+
+			if (cover_zone2) 
+				CoverZone (gr, x + width / 2, y);
+
+			if (cover_zone3) 
+				CoverZone (gr, x, y + height / 2);
+		
+			if (cover_zone4) 
+				CoverZone (gr, x + width / 2, y + height / 2);
+
+			switch (partial_zone) {
+				case 1:
+					break;
+				case 2:
+					x += width / 2;
+					break;
+				case 3:
+					y += height / 2;
+					break;
+				case 4:
+					y += height / 2;
+					x += width / 2;
+					break;
+			}
+
+			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/PuzzleCube.cs b/src/Games/Logic/PuzzleCube.cs
new file mode 100755
index 0000000..d5443ab
--- /dev/null
+++ b/src/Games/Logic/PuzzleCube.cs
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using Mono.Unix;
+using System;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleCube : Game
+	{
+		private char question;
+		const int pairs = 4;
+
+		private int[] question_answer = 
+		{
+			1, 4,
+			6, 2,
+			4, 1,
+			2, 6,
+		};
+
+		public override string Name {
+			get {return Catalog.GetString ("Cube");}
+		}
+
+		public override string Question {
+			get {return String.Format (Catalog.GetString ("When folded as a cube, which face on the figure is opposite the face with a {0} drawn on it? Answer the number written on face."), question);} 
+		}
+
+		public override void Initialize ()
+		{
+			int pair = random.Next (pairs);
+			question = (char) (48 + question_answer[pair * 2]);
+			right_answer += (char) (48 + question_answer[(pair * 2) + 1]);
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double x = DrawAreaX + 0.1;
+			double y = DrawAreaY + 0.1;
+			const double txtoff_x = 0.04;
+			const double txtoff_y = 0.03;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			gr.Rectangle (x + 0.1, y, 0.1, 0.1);
+			gr.Stroke ();
+			gr.MoveTo (x + 0.1 + txtoff_x, y + txtoff_y);
+			gr.ShowPangoText ("1");
+
+			gr.Rectangle (x + 0.2, y, 0.1, 0.1);
+			gr.Stroke ();
+			gr.MoveTo (x + 0.2 + txtoff_x, y + txtoff_y);
+			gr.ShowPangoText ("2");
+
+			gr.Rectangle (x + 0.2, y + 0.1, 0.1, 0.1);
+			gr.Stroke ();
+			gr.MoveTo (x + 0.2 + txtoff_x, y + 0.1 + txtoff_y);
+			gr.ShowPangoText ("3");
+
+			gr.Rectangle (x + 0.3, y + 0.1, 0.1, 0.1);
+			gr.Stroke ();
+			gr.MoveTo (x + 0.3 + txtoff_x, y + 0.1 + txtoff_y);
+			gr.ShowPangoText ("4");
+
+			gr.Rectangle (x + 0.4, y + 0.1, 0.1, 0.1);
+			gr.Stroke ();
+			gr.MoveTo (x + 0.4 + txtoff_x, y + 0.1 + txtoff_y);
+			gr.ShowPangoText ("5");
+
+			gr.Rectangle (x + 0.4, y + 0.2, 0.1, 0.1);
+			gr.Stroke ();
+			gr.MoveTo (x + 0.4 + txtoff_x, y + 0.2 + txtoff_y);
+			gr.ShowPangoText ("6");
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleDivideCircle.cs b/src/Games/Logic/PuzzleDivideCircle.cs
new file mode 100644
index 0000000..d68a4f2
--- /dev/null
+++ b/src/Games/Logic/PuzzleDivideCircle.cs
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleDivideCircle : Game
+	{
+		private const double figure_size = 0.15;
+		private int dots;
+	
+		private class Circle
+		{	
+			public double x;
+			public double y;
+
+			public Circle (double x, double y) 
+			{
+				this.x = x;
+				this.y = y;
+			}
+		}
+
+		public override string Name {
+			get {return Catalog.GetString ("Divide circles");}
+		}
+
+		public override string Question {
+			get {return Catalog.GetString ("In the last figure, in how many regions is the circle divided into when all dots are connected?");} 
+		}
+
+		public override void Initialize ()
+		{
+			if (CurrentDifficulty==Difficulty.Easy)
+				dots = 5;
+			else
+				dots = 5 + random.Next (2);
+
+			switch (dots) {
+			case 5:
+				right_answer = "16";
+				break;
+			case 6:
+				right_answer = "30";
+				break;
+			}			
+		}
+
+		static private void DrawAndConnectPoints (CairoContextEx gr, double x, double y, Circle[] circles, bool connect)
+		{
+			const double point_size = 0.01;
+			for (int i = 0; i < circles.Length; i++) {
+				gr.Arc (x + point_size + circles[i].x, y + point_size + circles[i].y, point_size, 0, 2 * Math.PI);
+				gr.Fill ();
+				gr.Stroke ();
+			}
+
+			if (connect == false)
+				return;
+		
+			gr.Save ();
+			gr.LineWidth = 0.003;
+			double offset = point_size;
+			for (int from = 0; from < circles.Length; from++) {
+				for (int to = 0; to < circles.Length; to++) {
+					gr.MoveTo (x + circles[from].x+ offset, y + circles[from].y + offset);
+					gr.LineTo (x + circles[to].x + offset, y + circles[to].y + offset);
+					gr.Stroke ();
+				}
+			}
+			gr.Restore ();
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double x = DrawAreaX + 0.05, y = DrawAreaY;
+			double pos_x = x;
+			double pos_y = y;
+			Circle[] circles = null;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			// First circle
+			gr.Arc (pos_x + figure_size, y + figure_size, figure_size, 0, 2 * Math.PI);
+			gr.Stroke ();
+			DrawAndConnectPoints (gr, pos_x, pos_y, 
+				new Circle [] {
+					new Circle (0.14, 0),
+					new Circle (0.14, 0.29),
+				}, true);
+
+			gr.MoveTo (pos_x, pos_y + figure_size * 2 + 0.05);
+			gr.ShowPangoText (String.Format (Catalog.GetString ("Has {0} regions"), 2));
+			gr.Stroke ();
+
+			// Second circle
+			pos_x += 0.4;
+			gr.Arc (pos_x + figure_size, pos_y + figure_size, figure_size, 0, 2 * Math.PI);
+			gr.Stroke ();		
+			DrawAndConnectPoints (gr, pos_x, pos_y,
+				new Circle [] {
+					new Circle (0.01, 0.06),
+					new Circle (0.27, 0.06),
+					new Circle (0.14, 0.29),
+				}, true);
+
+			gr.MoveTo (pos_x, pos_y + figure_size * 2 + 0.05);
+			gr.ShowPangoText (String.Format (Catalog.GetString ("Has {0} regions"), 4));
+			gr.Stroke ();
+
+			// Third circle
+			pos_x = x;
+			pos_y += 0.45;
+			gr.Arc (pos_x + figure_size, pos_y + figure_size, figure_size, 0, 2 * Math.PI);
+			gr.Stroke ();		
+			DrawAndConnectPoints (gr, pos_x, pos_y,
+				new Circle [] {
+					new Circle (0.01, 0.06),
+					new Circle (0.27, 0.06),
+					new Circle (0.01, 0.21),
+					new Circle (0.27, 0.21),
+				}, true);
+
+			gr.MoveTo (pos_x, pos_y + figure_size * 2 + 0.05);
+			gr.ShowPangoText (String.Format (Catalog.GetString ("Has {0} regions"), 8));
+			gr.Stroke ();
+
+			switch (dots) {
+			case 5:
+				circles =  new Circle [] {
+					new Circle (0.01, 0.06),
+					new Circle (0.27, 0.06),
+					new Circle (0.01, 0.21),
+					new Circle (0.27, 0.21),
+					new Circle (0.14, 0),
+				};
+				break;
+			case 6:
+				circles =  new Circle [] {
+					new Circle (0.01, 0.06),
+					new Circle (0.27, 0.06),
+					new Circle (0.01, 0.21),
+					new Circle (0.27, 0.21),
+					new Circle (0.14, 0),
+					new Circle (0.14, 0.29)
+				};
+				break;
+			}
+
+			// Forth circle
+			pos_x += 0.4;
+			gr.Arc (pos_x + figure_size, pos_y + figure_size, figure_size, 0, 2 * Math.PI);
+			gr.Stroke ();		
+			DrawAndConnectPoints (gr, pos_x, pos_y, circles, DrawAnswer);
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleEquation.cs b/src/Games/Logic/PuzzleEquation.cs
new file mode 100644
index 0000000..ada87bb
--- /dev/null
+++ b/src/Games/Logic/PuzzleEquation.cs
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2008 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 Cairo;
+using Mono.Unix;
+using System;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleEquation : Game
+	{
+		private int num_a, num_b, num_c, num_d, num_e;
+		private string formula;
+
+		public override string Name {
+			get {return Catalog.GetString ("Equation");}
+		}
+
+		public override string Question {
+			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 void Initialize ()
+		{
+			bool found  = false;
+			int order = 0, sequential;
+
+			while (found == false) {
+				num_a = 2 + random.Next (5);
+				num_b = 2 + random.Next (5);
+				num_c = 2 + random.Next (5);
+				num_d = 2 + random.Next (5);
+				num_e = 2 + random.Next (5);
+				order = num_a * num_b + num_c *  num_d - num_e;
+				sequential = ((num_a * num_b + num_c) * num_d) - num_e;
+
+				if (order != sequential)
+					found = true;
+			}
+
+			formula = String.Format ("{0} * {1} + {2} * {3} - {4} = ?", num_a, num_b, num_c, num_d, num_e);
+			right_answer = (order).ToString ();
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			base.Draw (gr, area_width, area_height, rtl);
+
+			gr.SetPangoLargeFontSize ();
+			gr.DrawTextCentered (0.5, DrawAreaY + 0.3, formula);
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleExtraCircle.cs b/src/Games/Logic/PuzzleExtraCircle.cs
new file mode 100644
index 0000000..ed6d1d4
--- /dev/null
+++ b/src/Games/Logic/PuzzleExtraCircle.cs
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2008 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleExtraCircle : Game
+	{
+		private const int total_slices = 6;
+		private const int circles = 4;
+		private const double radius = 0.1;
+		private const double radian = Math.PI / 180;
+		private int ans_pos;
+		private Color[] cercle_colors;
+		private Color[] badcercle_colors;
+		private int[] start_indices;
+		private ColorPalette cp;
+
+		public override string Name {
+			get {return Catalog.GetString ("Extra circle");}
+		}
+
+		public override string Question {
+			get {return String.Format (
+				Catalog.GetString ("Which circle does not belong to the group? It is not a sequence of elements. Answer {0}, {1}, {2} or {3}."),
+					GetPossibleAnswer (0), GetPossibleAnswer (1), GetPossibleAnswer (2), GetPossibleAnswer (3));}
+		}
+
+		public override string Tip {
+			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 void Initialize ()
+		{
+			ArrayListIndicesRandom random_indices = new ArrayListIndicesRandom (total_slices);
+			Color clr;
+
+			cp = new ColorPalette (ColorPalette.Id.Last);
+			cp.Initialize ();
+
+			cercle_colors = new Color [total_slices];
+			badcercle_colors =  new Color [total_slices];
+			for (int i = 0; i < total_slices; i++) {
+				cercle_colors [i] = cp.Cairo (i);
+				badcercle_colors [i] = cp.Cairo (i);
+			}
+		
+			// Correct answer
+			random_indices.Initialize ();
+			clr = badcercle_colors [random_indices[0]];
+			badcercle_colors [random_indices[0]] =  badcercle_colors [random_indices[1]];
+			badcercle_colors [random_indices[1]] = clr;
+
+			// Indices
+			start_indices = new int [circles];
+			for (int i = 0; i < circles; i++)
+				start_indices[i] = (random_indices[i]);
+
+			ans_pos = random.Next (circles);
+			right_answer = GetPossibleAnswer (ans_pos);
+		}
+
+		static private void DrawSlice (CairoContextEx gr, double x, double y, double dg, Color color)
+		{
+			double x1, y1, smallest_x, smallest_y, degrees;
+
+			smallest_x = x;
+			smallest_y = y;
+			degrees = radian * (60 + dg);
+			gr.MoveTo (x, y);
+			x1 = x + radius * Math.Cos (degrees);
+			y1 = y + radius * Math.Sin (degrees);
+			gr.LineTo (x1, y1);
+			if (x1 < smallest_x) smallest_x = x1;
+			if (y1 < smallest_y) smallest_y = y1;
+		
+			degrees = dg * radian;
+			gr.MoveTo (x, y);
+			x1 = x + radius * Math.Cos (degrees);
+			y1 = y + radius * Math.Sin (degrees);
+			gr.LineTo (x1, y1);
+			if (x1 < smallest_x) smallest_x = x1;
+			if (y1 < smallest_y) smallest_y = y1;
+
+			gr.Arc (x, y, radius, dg * radian, radian * (60 + dg));
+			gr.FillGradient (smallest_x, smallest_y, radius, radius, color);
+			gr.Stroke ();
+		}
+
+		private void DrawCircle (CairoContextEx gr, double x, double y, Color[] colors, int color_indice)
+		{		
+			double dg;
+			gr.Arc (x, y, radius, 0, 2 * Math.PI);
+			gr.Stroke ();
+		
+			gr.Save ();
+			for (int slice = 0; slice < total_slices; slice++) 
+			{	
+				dg = slice * (360 / total_slices);
+				DrawSlice (gr, x, y, dg, colors [color_indice]);
+			
+				color_indice++;
+				if (color_indice >= colors.Length)
+					color_indice = 0;
+			
+			}
+			gr.Restore ();
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{		
+			double x = DrawAreaX, y = DrawAreaY;
+			Color [] colors;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			x+= radius / 2;
+			y+= radius / 2;
+
+			for (int i = 0; i < circles; i++)
+			{
+				if (ans_pos == i)
+					colors = badcercle_colors;
+				else
+					colors = cercle_colors;
+
+				DrawCircle (gr, x + i * 0.23, y + 0.2, colors, start_indices[i]);
+
+				gr.MoveTo (x - 0.07 + i * 0.22, y + 0.36);
+				gr.ShowPangoText (GetPossibleFigureAnswer (i));
+				gr.Stroke ();
+			}
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleFigureLetter.cs b/src/Games/Logic/PuzzleFigureLetter.cs
new file mode 100644
index 0000000..a46e96e
--- /dev/null
+++ b/src/Games/Logic/PuzzleFigureLetter.cs
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using Mono.Unix;
+using System;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleFigureLetter : Game
+	{
+		private QuestionType question;
+	
+		enum QuestionType
+		{
+			TwoRectangles	= 0,
+			TwoCercles,
+			ThreeCercles,
+			Length		
+		}
+
+		public override string Name {
+			get {return Catalog.GetString ("Figures and text");}
+		}
+
+		public override string Question {
+			get {return Catalog.GetString ("The figures and the text are related. What text should go under the last figure?");} 
+		}
+
+		public override string Tip {
+			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 void Initialize ()
+		{
+			question = (QuestionType) random.Next ((int) QuestionType.Length);
+
+			switch (question) {
+			case QuestionType.TwoRectangles:
+				right_answer = "ABF";
+				break;
+			case QuestionType.TwoCercles:
+				right_answer = "CDF";
+				break;
+			case QuestionType.ThreeCercles:
+				right_answer = "ACE";
+				break;
+			}
+		}
+
+		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;
+			double y = DrawAreaY + 0.1;
+
+			base.Draw (gr, area_width, area_height, rtl);
+		
+			// Three circles
+			gr.Arc (x + 0.06, y, 0.05, 0, 2 * Math.PI);
+			gr.Stroke ();
+			gr.Arc (x, y + 0.1, 0.05, 0, 2 * Math.PI);
+			gr.Stroke ();
+			gr.Arc (x + 0.11, y + 0.1, 0.05, 0, 2 * Math.PI);
+			gr.Stroke ();
+			gr.MoveTo (x + 0.02, y + 0.18);
+			gr.ShowPangoText ("CDE");
+			gr.Stroke ();
+
+			// Two linked circles
+			gr.Arc (x + 0.3, y, 0.05, 0, 2 * Math.PI);
+			gr.Stroke ();
+			gr.Arc (x + 0.3 + 0.06, y + 0.05, 0.05, 0, 2 * Math.PI);
+			gr.Stroke ();
+			gr.MoveTo (x + 0.30, y + 0.18);
+			gr.ShowPangoText ("ACF");
+			gr.Stroke ();
+
+			// Two rectangles
+			gr.Rectangle (x + 0.5, y, 0.1, 0.1);
+			gr.Rectangle (x + 0.62, y, 0.1, 0.1);
+			gr.Stroke ();
+			gr.MoveTo (x + 0.58, y + 0.18);
+			gr.ShowPangoText ("BDF");
+			gr.Stroke ();
+
+	
+			// Tree rectangles
+			gr.Rectangle (x - 0.05, y + 0.35, 0.1, 0.1);
+			gr.Rectangle (x + 0.06 - 0.05, y + 0.37, 0.1, 0.1);
+			gr.Rectangle (x + 0.12 - 0.05, y + 0.39, 0.1, 0.1);
+			gr.Stroke ();
+			gr.MoveTo (x + 0.04, y + 0.53);
+			gr.ShowPangoText ("ABE");
+			gr.Stroke ();
+
+			x += 0.25;
+			y += 0.35;
+
+			switch (question) {
+			case QuestionType.TwoRectangles:
+				gr.Rectangle (x, y, 0.1, 0.1);
+				gr.Rectangle (x + 0.05, y + 0.03, 0.1, 0.1);
+				gr.Stroke ();
+				gr.MoveTo (x + 0.05, y + 0.18);
+				break;
+			case QuestionType.TwoCercles:
+				gr.Arc (x + 0.05, y + 0.05, 0.05, 0, 2 * Math.PI);
+				gr.Stroke ();
+				gr.Arc (x + 0.12 + 0.05, y + 0.05, 0.05, 0, 2 * Math.PI);
+				gr.Stroke ();
+				gr.MoveTo (x + 0.1, y + 0.18);
+				break;
+			case QuestionType.ThreeCercles:
+				gr.Arc (x + 0.05 + 0.06, y + 0.04, 0.05, 0, 2 * Math.PI);
+				gr.Stroke ();
+				gr.Arc (x + 0.05, y + 0.06 + 0.04, 0.05, 0, 2 * Math.PI);
+				gr.Stroke ();
+				gr.Arc (x + 0.05  + 0.11, y + 0.06 + 0.04, 0.05, 0, 2 * Math.PI);
+				gr.Stroke ();
+				gr.MoveTo (x + 0.1, y + 0.18);
+				break;
+			}
+
+			gr.ShowPangoText ("?");
+			gr.Stroke ();		
+		}
+
+	}
+}
diff --git a/src/Games/Logic/PuzzleFigurePattern.cs b/src/Games/Logic/PuzzleFigurePattern.cs
new file mode 100644
index 0000000..7daee12
--- /dev/null
+++ b/src/Games/Logic/PuzzleFigurePattern.cs
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleFigurePattern : Game
+	{
+		private ArrayListIndicesRandom random_indices;
+
+		enum Figures
+		{
+			TwoLines = 0,
+			Cross,
+			RotatedCross,
+			Last
+		};
+
+		public override string Name {
+			get {return Catalog.GetString ("Figure pattern");}
+		}
+
+		public override string Question {
+			get {return String.Format (
+				Catalog.GetString ("What figure should replace the question mark? Answer {0}, {1} or {2}."),
+				GetPossibleAnswer (0), GetPossibleAnswer (1), GetPossibleAnswer (2));}
+		}
+
+		public override string Tip {
+			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 void Initialize ()
+		{
+			random_indices = new ArrayListIndicesRandom ((int) Figures.Last);
+			random_indices.Initialize ();
+
+			for (int i = 0; i < (int) Figures.Last; i++)
+			{
+				if ((int) random_indices[i] == (int) Figures.Cross) {
+					right_answer = GetPossibleAnswer (i);
+					break;
+				}
+			}
+		}
+
+		private void DrawRotatedCross (CairoContextEx gr, double x, double y, double size)
+		{
+			gr.MoveTo (x, y);
+			gr.LineTo (x + size, y + size);
+			gr.MoveTo (x + size, y);
+			gr.LineTo (x, y + size);
+			gr.Stroke ();
+		}
+
+		static void DrawTwoLines (CairoContextEx gr, double x, double y, double size)
+		{
+			gr.MoveTo (x, y);
+			gr.LineTo (x + size, y);
+			gr.MoveTo (x, y + size);
+			gr.LineTo (x + size, y + size);
+			gr.Stroke ();
+		}
+
+		static void DrawCross (CairoContextEx gr, double x, double y, double size)
+		{
+			gr.MoveTo (x + size / 2, y);
+			gr.LineTo (x + size / 2, y + size);
+			gr.MoveTo (x, y + size / 2);
+			gr.LineTo (x + size, y + size / 2);
+			gr.Stroke ();
+		}
+	
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double org_x = DrawAreaX + 0.1;
+			double x = org_x, y = 0.08;
+			const double figure_size = 0.13, space_x = 0.1, space_y = 0.2;
+			double x45, y45, x135, y135, offset;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			// First pattern
+			gr.Rectangle (x, y, figure_size, figure_size);
+			gr.MoveTo (x, y);
+			gr.LineTo (x + figure_size, y + figure_size);
+			gr.MoveTo (x + figure_size, y);
+			gr.LineTo (x, y + figure_size);
+			gr.MoveTo (x + figure_size / 2, y);
+			gr.LineTo (x + figure_size / 2, y + figure_size);
+			gr.MoveTo (x, y + figure_size / 2);
+			gr.LineTo (x + figure_size, y + figure_size / 2);
+			gr.Stroke ();
+
+			x += figure_size + space_x;
+			gr.Rectangle (x, y, figure_size, figure_size);
+			gr.MoveTo (x + figure_size / 2, y);
+			gr.LineTo (x + figure_size / 2, y + figure_size);
+			gr.MoveTo (x, y + figure_size / 2);
+			gr.LineTo (x + figure_size, y + figure_size / 2);
+			gr.Stroke ();
+
+			x += figure_size + space_x;
+			DrawCross (gr, x, y, figure_size);
+
+			y += space_y;
+			x = org_x;
+			// Second pattern
+			gr.Rectangle (x, y, figure_size, figure_size);
+			gr.MoveTo (x, y);
+			gr.LineTo (x + figure_size, y + figure_size);
+			gr.MoveTo (x + figure_size, y);
+			gr.LineTo (x, y + figure_size);
+			gr.Stroke ();
+
+			x += figure_size + space_x;
+			DrawRotatedCross (gr, x, y, figure_size);
+
+			// Rotated rectangle
+			x += figure_size + space_x;
+			x45 = figure_size * Math.Cos (45 * Math.PI / 180);
+			y45 = figure_size * Math.Sin (45 * Math.PI / 180);
+			x135 = figure_size * Math.Cos (135 * Math.PI / 180);
+			y135 = figure_size * Math.Sin (135 * Math.PI / 180);
+			offset = - 0.03;
+			// Down-right
+			gr.MoveTo (x + figure_size / 2, y + offset);
+			gr.LineTo (x + figure_size / 2 + x45, y + offset + y45);
+			// Up right
+			gr.LineTo ((x + figure_size / 2 + x45) + x135, (y + offset +  y45) + y135);
+			gr.Stroke ();
+			// Down left
+			gr.MoveTo (x + figure_size / 2, y + offset);
+			gr.LineTo (x + figure_size / 2 + x135, y + offset + y135);
+			// Up left
+			gr.LineTo (x + figure_size / 2 + x135 + x45, y + offset + y135 + y45);
+			gr.Stroke ();
+
+			y += space_y;
+			x = org_x;
+
+			// Third pattern
+			gr.MoveTo (x, y);
+			gr.LineTo (x + figure_size, y);
+			gr.LineTo (x, y + figure_size);
+			gr.LineTo (x + figure_size, y  + figure_size);
+			gr.Stroke ();
+
+			x += figure_size + space_x;
+			gr.MoveTo (x + figure_size, y);
+			gr.LineTo (x, y);
+			gr.LineTo (x + figure_size, y + figure_size);
+			gr.LineTo (x, y  + figure_size);
+			gr.Stroke ();
+		
+			x += figure_size + space_x;
+			gr.MoveTo (x + 0.03, y - 0.02);
+			gr.SetPangoFontSize (figure_size);
+			gr.ShowPangoText ("?");
+			gr.SetPangoNormalFontSize ();
+			gr.Stroke ();
+	
+			gr.MoveTo (0.05, y - 0.01 + space_y);
+			gr.ShowPangoText (Catalog.GetString ("Possible answers are:"));
+
+			// Answers
+			x = org_x;
+			y += space_y + 0.07;
+
+			for (int i = 0; i < (int) Figures.Last; i++)
+			{
+			 	switch ((Figures) random_indices[i]) {
+				case Figures.TwoLines:
+					DrawTwoLines (gr, x, y, figure_size);
+					break;
+				case Figures.Cross:
+					DrawCross (gr, x, y, figure_size);
+					break;
+				case Figures.RotatedCross:
+					DrawRotatedCross (gr, x, y, figure_size);
+					break;
+				}
+			
+				gr.MoveTo (x, y + 0.18);
+				gr.ShowPangoText (GetPossibleFigureAnswer (i));
+
+				x += figure_size + space_x;			
+			}
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleFigures.cs b/src/Games/Logic/PuzzleFigures.cs
new file mode 100644
index 0000000..4405399
--- /dev/null
+++ b/src/Games/Logic/PuzzleFigures.cs
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using System.Text;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleFigures : Game
+	{
+		private int [] figures  = new int []
+		{
+			0, 0, 1, 1, 2, 2,
+			1, 2, 2, 0, 1, 0,
+			2, 1, 0, 2, 0, 1
+		};
+
+		private ArrayListIndicesRandom random_indices;
+		private const double figure_width = 0.1, figure_height = 0.1, space_width = 0.05, space_height = 0;
+
+		public override string Name {
+			get {return Catalog.GetString ("Figures");}
+		}
+
+		public override string Question {
+			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 void Initialize ()
+		{
+			random_indices = new ArrayListIndicesRandom (6);
+			random_indices.Initialize ();
+
+			StringBuilder sb = new StringBuilder (3);
+	
+			sb.Append (GetPossibleAnswer (figures[random_indices [5]]));
+			sb.Append (GetPossibleAnswer (figures[6 + random_indices [5]]));
+			sb.Append (GetPossibleAnswer (figures[(2 * 6) + random_indices [5]]));
+
+			right_answer = sb.ToString ();
+		}
+
+		private void AnswerCoding (CairoContextEx gr, double x, double y)
+		{
+			double pos_x = x;
+
+			gr.MoveTo (pos_x, y - 0.01);
+			y += 0.05;
+			gr.ShowPangoText (Catalog.GetString ("Convention when giving the answer is:"));
+
+			gr.MoveTo (pos_x, y + 0.05);
+			gr.ShowPangoText (String.Format (Catalog.GetString ("{0} ->"), GetPossibleAnswer (0)));
+			gr.Stroke ();
+			gr.DrawDiamond (x + 0.1, y, 0.1);
+			gr.Stroke ();
+	
+			pos_x += 0.3;
+			gr.MoveTo (pos_x, y + 0.05);
+			gr.ShowPangoText (String.Format (Catalog.GetString ("{0} ->"), GetPossibleAnswer (1)));
+			gr.Stroke ();
+			pos_x += 0.1;
+			gr.Arc (pos_x + 0.05, y + 0.05, 0.05, 0, 2 * Math.PI);	
+			gr.Stroke ();
+
+			pos_x += 0.2;
+			gr.MoveTo (pos_x, y + 0.05);
+			gr.ShowPangoText (String.Format (Catalog.GetString ("{0} ->"), GetPossibleAnswer (2)));
+			gr.Stroke ();
+			pos_x += 0.1;
+			gr.DrawEquilateralTriangle (pos_x, y, 0.1);
+			gr.Stroke ();
+
+			y += 0.16;
+			gr.MoveTo (x, y);		
+			gr.ShowPangoText (String.Format (Catalog.GetString ("E.g: {0}{1}{2} (diamond, triangle, circle)"),
+				GetPossibleAnswer (0), GetPossibleAnswer (2), GetPossibleAnswer (1)));
+
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{		
+			int element;
+			const double figure_width = 0.1, figure_height = 0.1, space_width = 0.05, space_height = 0.1;
+			double x = DrawAreaX, y = DrawAreaY;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			for (int i = 0; i < (DrawAnswer ? 6 : 5) ; i++)
+			{
+				element = random_indices [i];
+				y = DrawAreaY;
+				for (int n = 0; n < 3; n++) 
+				{
+					switch ((int) figures[(n * 6) + element])
+					{
+						case 0:
+							gr.DrawDiamond (x, y, 0.1);
+							break;
+						case 1:
+							gr.Arc (x + 0.05, y + 0.05, 0.05, 0, 2 * Math.PI);	
+							break;
+						case 2:
+							gr.DrawEquilateralTriangle (x, y, 0.1);
+							break;
+						default:
+							break;
+					}
+					gr.Stroke ();
+					y+= figure_height + space_height;		
+				}
+				x+= figure_width + space_width;
+			}
+
+			if (DrawAnswer == false) {
+				y = DrawAreaY;
+				gr.Save ();
+				gr.SetPangoFontSize (0.1);
+				for (int n = 0; n < 3; n++) {
+					gr.MoveTo (x, y - 0.02);
+					gr.ShowPangoText ("?");
+					gr.Stroke ();
+					y+= figure_height + space_height;
+				}
+				gr.SetPangoNormalFontSize ();
+				gr.Restore ();	
+			}
+
+			AnswerCoding (gr, DrawAreaX, y);
+		}
+
+		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
new file mode 100644
index 0000000..c270d81
--- /dev/null
+++ b/src/Games/Logic/PuzzleFourSided.cs
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2008 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleFourSided : Game
+	{
+		int type;
+		public override string Name {
+			get {return Catalog.GetString ("Four sided");}
+		}
+
+		public override string Question {
+			get {return Catalog.GetString ("How many four sided figures do you count in the figure below?");} 
+		}
+
+		public override string Tip {
+			get { return Catalog.GetString ("A four sided figure can be embedded inside another figure.");}
+		}
+
+		public override string Answer {
+			get { 
+				string answer = base.Answer + " ";
+
+				answer += 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;
+			}
+		}
+
+		public override void Initialize ()
+		{
+			if (CurrentDifficulty==Difficulty.Easy)
+				type = 0;
+			else
+				type = random.Next (2);
+
+		
+			if (type == 0)	
+				right_answer = "13";
+			else
+				right_answer = "17";
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double x = DrawAreaX + 0.1, y = DrawAreaY + 0.1, w = 0.6, h = 0.6;
+
+			base.Draw (gr, area_width, area_height, rtl);
+		
+			gr.Rectangle (x, y, w, h);
+			gr.Stroke ();
+
+			// Lines
+			gr.MoveTo (x + w /2, y);
+			gr.LineTo (x + w /2, y + h);
+			gr.Stroke ();
+			gr.MoveTo (x, y + h /2);
+			gr.LineTo (x + w, y + h / 2);
+			gr.Stroke ();
+
+			// Diagonals
+			gr.MoveTo (x, y);
+			gr.LineTo (x + w, y + h);
+			gr.Stroke ();
+
+			if (type == 1) {
+				gr.MoveTo (x + w, y);
+				gr.LineTo (x, y + h);
+				gr.Stroke ();
+			}
+
+			if (DrawAnswer == false)
+				return;
+
+			// References
+			gr.MoveTo (x - 0.04, y - 0.02);
+			gr.ShowPangoText ("a");
+			gr.Stroke ();
+
+			gr.MoveTo (x + w / 2 - 0.02, y - 0.02);
+			gr.ShowPangoText ("b");
+			gr.Stroke ();
+
+			gr.MoveTo (x + w + 0.02, y - 0.02);
+			gr.ShowPangoText ("c");
+			gr.Stroke ();
+
+			gr.MoveTo (x - 0.04, y + h /2 - 0.02);
+			gr.ShowPangoText ("d");
+			gr.Stroke ();
+
+			gr.MoveTo (x + w / 2 - 0.04, y  + h /2 - 0.04);
+			gr.ShowPangoText ("e");
+			gr.Stroke ();
+
+			gr.MoveTo (x + w + 0.02, y  + h /2 - 0.02);
+			gr.ShowPangoText ("f");
+			gr.Stroke ();
+
+			gr.MoveTo (x - 0.04, y + h + 0.04);
+			gr.ShowPangoText ("g");
+			gr.Stroke ();
+
+			gr.MoveTo (x + w / 2 - 0.02, y + h + 0.04);
+			gr.ShowPangoText ("h");
+			gr.Stroke ();
+
+			gr.MoveTo (x + w + 0.02, y + h + 0.04);
+			gr.ShowPangoText ("i");
+			gr.Stroke ();
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleHandshakes.cs b/src/Games/Logic/PuzzleHandshakes.cs
new file mode 100644
index 0000000..b3ef802
--- /dev/null
+++ b/src/Games/Logic/PuzzleHandshakes.cs
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2008 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 Cairo;
+using Mono.Unix;
+using System;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleHandshakes : Game
+	{
+		int people, handshakes;
+
+		public override string Name {
+			get {return Catalog.GetString ("Handshakes");}
+		}
+
+		public override string Question {
+			get {return String.Format (
+				Catalog.GetString ("All attendees to a party are introduced to one another. {0} handshakes are made in total. How many people are attending the party?"), 				handshakes);
+			}
+		}
+
+		public override string Tip {
+			get { return Catalog.GetString ("Try to imagine a situation in which you are meeting a small number of people.");}
+		}
+
+		public override void Initialize ()
+		{
+			handshakes = 0;
+
+			switch (CurrentDifficulty) {
+			case Difficulty.Easy:
+				people = 4 + random.Next (4);
+				break;
+			case Difficulty.Master:
+				people = 5 + random.Next (8);
+				break;		
+			case Difficulty.Medium:
+			default:
+				people = 5 + random.Next (4);
+				break;		
+			}
+		
+			for (int i = 1; i < people; i++)
+				handshakes += i;
+		
+			right_answer = people.ToString ();
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			base.Draw (gr, area_width, area_height, rtl);
+			gr.DrawImageFromAssembly ("handshake.svg", 0.2, 0.6, 0.6, 0.3);
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleLargerShape.cs b/src/Games/Logic/PuzzleLargerShape.cs
new file mode 100644
index 0000000..85bddd8
--- /dev/null
+++ b/src/Games/Logic/PuzzleLargerShape.cs
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2008 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 Cairo;
+using Mono.Unix;
+using System;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleLargerShape : Game
+	{
+		private const double rect_witdh = 0.04, rect_height = 0.04, space_figures = 0.22;
+		private ArrayListIndicesRandom random_indices;
+		private const int answers = 4;
+		private char[] quest1, quest2, answer;
+		private int ranswer;
+		private ColorPalette palette;
+
+		private static char A = 'A';
+		private static char B = 'B';
+		private static char X = 'X'; // Transparent
+
+		/* Game 1 */
+		private int g1rightanswer = 0;
+		private char [] g1question_A  = new char []
+		{
+			A, B,
+			X, X,
+		};
+
+		private char [] g1question_B  = new char []
+		{
+			B, A, X,
+			A, X, X,
+			X, X, X,
+		};
+
+		private char [] g1answer  = new char []
+		{
+			// Figure A
+			B, A, X,
+			A, X, X,
+			X, B, A,
+			// Figure B
+			A, X, X,
+			X, B, A,
+			X, A, B,
+			// Figure C
+			A, B, X,
+			B, X, X,
+			X, B, A,
+			// Figure D
+			X, X, X,
+			B, B, A,
+			X, A, B,
+		};
+
+		/* Game 2 */	
+		private int g2rightanswer = 0;
+		private char [] g2question_A  = new char []
+		{
+			B, A,
+			A, B,
+		};
+
+		private char [] g2question_B  = new char []
+		{
+			A, A, X,
+			A, X, X,
+			X, X, X,
+		};
+
+		private char [] g2answer  = new char []
+		{
+			// Figure A
+			A, A, X,
+			A, A, B,
+			X, B, A,
+			// Figure B
+			A, X, X,
+			X, B, A,
+			X, A, A,
+			// Figure C
+			A, B, X,
+			B, A, B,
+			X, B, A,
+			// Figure D
+			X, X, X,
+			A, A, A,
+			X, A, B,
+		};
+
+		public override string Name {
+			get {return Catalog.GetString ("Larger shape");}
+		}
+
+		public override string Question {
+			get {return String.Format (
+				Catalog.GetString ("Which larger shape can you make combining the first two figures? Answer {0}, {1}, {2} or {3}."),
+				GetPossibleAnswer (0), GetPossibleAnswer (1), GetPossibleAnswer (2), GetPossibleAnswer (3));}
+		}
+
+		public override void Initialize ()
+		{
+			palette = new ColorPalette (ColorPalette.Id.PrimaryColors);
+			palette.Initialize ();
+
+			switch (random.Next (2)) {
+			case 0:
+				quest1 = g1question_A;
+				quest2 = g1question_B;
+				answer = g1answer;
+				ranswer = g1rightanswer;
+				break;
+			case 1:
+				quest1 = g2question_A;
+				quest2 = g2question_B;
+				answer = g2answer;
+				ranswer = g2rightanswer;
+				break;
+			}
+
+			random_indices = new ArrayListIndicesRandom (answers);
+			random_indices.Initialize ();
+
+			for (int i = 0; i < answers; i++)
+			{
+				if ((int) random_indices[i] == ranswer) {
+					right_answer = GetPossibleAnswer (i);
+					break;
+				}
+			}
+		}
+
+		private Color ColorForPortion (char portion)
+		{
+			if (portion == A)
+				return palette.Cairo (1);
+
+			return palette.Cairo (0);
+		}
+
+		private void DrawSquare (CairoContextEx gr, double x, double y)
+		{
+			// XX
+			// XX
+			for (int i = 0; i < 2; i++) {
+				if (quest1 [i] != X) {
+					gr.Rectangle (x + i * rect_witdh, y, rect_witdh, rect_height);	
+					gr.FillGradient (x + i * rect_witdh, y, rect_witdh, rect_height, ColorForPortion (quest1 [i]));
+				}
+				gr.Rectangle (x + i * rect_witdh, y, rect_witdh, rect_height);
+				gr.Stroke ();
+
+				if (quest1 [i + 2] != X) {
+					gr.Rectangle (x + i * rect_witdh, y + rect_height, rect_witdh, rect_height);
+					gr.FillGradient (x + i * rect_witdh, y + rect_height, rect_witdh, rect_height, ColorForPortion (quest1 [i + 2]));
+				}
+				gr.Rectangle (x + i * rect_witdh, y + rect_height, rect_witdh, rect_height);
+				gr.Stroke ();
+			}
+		}
+
+		private void DrawLShape (CairoContextEx gr, double x, double y)
+		{
+			// XXX  
+			// X
+			// X
+			for (int i = 0; i < 3; i++) { // XXXX
+				if (quest2 [i] != X) {
+					gr.Rectangle (x + i * rect_witdh, y, rect_witdh, rect_height);	
+					gr.FillGradient (x + i * rect_witdh, y, rect_witdh, rect_height, ColorForPortion (quest2 [i]));
+				}
+				gr.Rectangle (x + i * rect_witdh, y, rect_witdh, rect_height);
+				gr.Stroke ();
+			}
+
+			for (int i = 0; i < 2; i++) {
+				if (quest2 [(i + 1) * 3] != X) {
+					gr.Rectangle (x, y + rect_height * (i + 1), rect_witdh, rect_height);
+					gr.FillGradient (x, y + rect_height * (i + 1), rect_witdh, rect_height, ColorForPortion (quest2 [(i + 1) * 3]));
+				}
+				gr.Rectangle (x, y + rect_height * (i + 1), rect_witdh, rect_height);
+				gr.Stroke ();
+			}
+		}
+
+		private void DrawPossibleAnswer (CairoContextEx gr, double x, double y, char [] portions, int figure, int seq)
+		{
+			const int columns = 3, rows = 3;
+			const double rect_w = 0.05, rect_h = 0.05;
+			int index = figure * columns * rows;
+
+			for (int row = 0; row < rows; row++) {
+				for (int column = 0; column < columns; column++) {
+					if (portions [index + column + (3 * row)] != X) {
+						gr.Rectangle (x + column * rect_w, y + row * rect_h, rect_w, rect_h);
+						gr.FillGradient (x + column * rect_w, y + row * rect_h, rect_w, rect_h, ColorForPortion (portions [index + column + (3 * row)]));
+					}
+					gr.Rectangle (x + column * rect_w, y + row * rect_h, rect_w, rect_h);
+					gr.Stroke ();
+				}
+			}
+
+			gr.MoveTo (x, y + 0.18);
+			gr.ShowPangoText (GetPossibleFigureAnswer (seq));
+			gr.Stroke ();
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double x = DrawAreaX + 0.1, y = DrawAreaY;
+
+			base.Draw (gr, area_width, area_height, rtl);
+	
+			DrawSquare (gr, x, y);
+			DrawLShape (gr, x + 0.4, y);
+
+			gr.MoveTo (0.1, 0.3);
+			gr.ShowPangoText (Catalog.GetString ("Possible answers are:"));
+			gr.Stroke ();
+		
+			DrawPossibleAnswer (gr, x, y + 0.32, answer, random_indices [0], 0);
+			DrawPossibleAnswer (gr, x + 0.4, y + 0.32, answer, random_indices [1], 1);
+			DrawPossibleAnswer (gr, x, y + 0.6, answer, random_indices [2], 2);
+			DrawPossibleAnswer (gr, x + 0.4, y + 0.6, answer, random_indices [3], 3);
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleLines.cs b/src/Games/Logic/PuzzleLines.cs
new file mode 100644
index 0000000..816bd71
--- /dev/null
+++ b/src/Games/Logic/PuzzleLines.cs
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using Mono.Unix;
+using System;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleLines : Game
+	{
+		private const int max_types = 3;
+		private int type;
+		private int fig1, fig2;
+
+		public override string Name {
+			get {return Catalog.GetString ("Lines");}
+		}
+
+		public override string Question {
+			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 Tip {
+			get { return Catalog.GetString ("It is an easy exercise if you systematically count the lines.");}
+		}
+
+		public override void Initialize ()
+		{
+			if (CurrentDifficulty==Difficulty.Easy)
+				type = 0;
+			else
+				type = random.Next (max_types);		
+
+			switch (type) {
+			case 0:
+				fig1 = 15;
+				fig2 = 21;
+				break;
+			case 1:
+				fig1 = 33;
+				fig2 = 39;
+				break;
+			case 2:
+				fig1 = 15;
+				fig2 = 39;
+				break;
+			}
+
+			right_answer = (fig1 + fig2).ToString ();
+		}
+
+		static private void DrawLine (CairoContextEx gr, double x, double y, double w, double h)
+		{
+			gr.MoveTo (x, y);
+			gr.LineTo (x + w, y + h);
+			gr.Stroke ();
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			base.Draw (gr, area_width, area_height, rtl);
+	
+			DrawLine (gr, 0.1, 0.2, 0.4, 0.38);
+			DrawLine (gr, 0.1, 0.3, 0.4, 0.3);
+			DrawLine (gr, 0.1, 0.4, 0.4, 0.25);
+
+			if (type == 1)  {
+				DrawLine (gr, 0.6, 0.3, -0.2, 0.35);
+				DrawLine (gr, 0.5, 0.25, -0.2, 0.35);		
+			}
+
+			DrawLine (gr, 0.1, 0.25, 0.6, 0.1);
+			DrawLine (gr, 0.25, 0.2, 0, 0.4);
+
+			if (type == 2 || type == 1)  {
+				DrawLine (gr, 0.85, 0.25, -0.2, 0.4);
+				DrawLine (gr, 0.88, 0.25, -0.2, 0.4);
+			}
+
+			DrawLine (gr, 0.91, 0.25, -0.2, 0.4);
+			DrawLine (gr, 0.8, 0.2, 0, 0.4);
+			DrawLine (gr, 0.82, 0.2, 0, 0.4);
+			DrawLine (gr, 0.6, 0.50, 0.25, 0);
+			DrawLine (gr, 0.6, 0.53, 0.25, 0);
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleMatrixGroups.cs b/src/Games/Logic/PuzzleMatrixGroups.cs
new file mode 100644
index 0000000..1f8477c
--- /dev/null
+++ b/src/Games/Logic/PuzzleMatrixGroups.cs
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2007-2008 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleMatrixGroups : Game
+	{
+		private int [] numbers;
+		private int good_pos;
+		private const int rows = 4, columns = 4;
+		private int divisor;
+
+		public override string Name {
+			get {return Catalog.GetString ("Matrix groups");}
+		}
+
+		public override string Question {
+			get {return Catalog.GetString ("One of numbers in the matrix must be circled. Which one?");}
+		}
+
+		public override string Tip {
+			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 void Initialize ()
+		{
+			numbers = new int [rows * columns];
+			bool completed = false;
+			int count;
+			int good = 1 + random.Next (5);
+
+			switch (random.Next (2)) {
+			case 0:
+				divisor = 2;
+				break;
+			case 1:
+				divisor = 3;
+				break;
+			}
+		
+			while (completed == false) {
+				count = 0;
+				for (int n = 0; n < rows; n++) {
+					for (int i = 0; i < columns; i++) {
+						numbers[(n*rows) + i] = GetUnique ((n*rows) + i);
+						if (numbers[(n*rows) + i] % divisor == 0) {
+							count++;
+							if  (count == good) {
+								good_pos =  (n*rows) + i;
+							}
+						}
+					}
+				}
+			
+				if (count > 5 && count < 10)
+					completed = true;
+			}
+			right_answer = numbers[good_pos].ToString ();
+		}
+
+		private int GetUnique (int max)
+		{
+			int unique = 0, i;
+			bool found = false;
+
+			while (found == false)
+			{
+				unique = 1 + random.Next (100);
+				for (i = 0; i < max; i++) {
+					if (unique == numbers [i]) {
+						break;
+					}
+				}
+				if (i == max)
+					found = true;
+			}
+			return unique;
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double rect_w = DrawAreaWidth / rows;
+			double rect_h = DrawAreaHeight / columns;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			for (int column = 0; column < columns; column++) {
+				for (int row = 0; row < rows; row++) {
+				
+					gr.Color = DefaultDrawingColor;
+					gr.Rectangle (DrawAreaX + row * rect_w, DrawAreaY + column * rect_h, rect_w, rect_h);
+					gr.Stroke ();
+
+					gr.DrawTextCentered (DrawAreaX + (rect_w / 2) + column * rect_w, (rect_h / 2) + DrawAreaY + row * rect_h, 
+						(numbers[column + (row * 4)]).ToString() );
+
+					if (numbers[column + (row * 4)] % divisor == 0 && good_pos != column + (row * 4)) {
+						gr.Arc (DrawAreaX + (rect_w / 2) + column * rect_w, (rect_h / 2) + DrawAreaY + row * rect_h,
+							0.05, 0, 2 * Math.PI);
+						gr.FillGradient (DrawAreaX + (rect_w / 2) + column * rect_w, (rect_h / 2) + DrawAreaY + row * rect_h,
+							0.05, 0.05);
+
+					}		
+					gr.Stroke ();
+				}
+			}
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleMatrixNumbers.cs b/src/Games/Logic/PuzzleMatrixNumbers.cs
new file mode 100644
index 0000000..84faa1a
--- /dev/null
+++ b/src/Games/Logic/PuzzleMatrixNumbers.cs
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2007 Jordi Mas i Hernàndez <jmas softcatala org>
+ * Copyright (C) 2007 Javier Mª Mora Merchán <jamarier gmail com>
+ *
+ * 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleMatrixNumbers : Game
+	{
+		public enum Operation
+		{
+			MultiplyAndAdd = 0,	// Multiplies two elements and adds a third
+			MutilplyAndSubs,	// Multiplies two elements and substracts a third
+			AddAndSubs,		// Adds two elements and  substracts a third 
+			LastOperation
+		}
+
+		private int [] numbers;
+		private Operation operation;
+		private bool orientation;
+		private const int rows = 4, columns = 4;
+
+		public override string Name {
+			get {return Catalog.GetString ("Matrix numbers");}
+		}
+
+		public override string Question {
+			get {return Catalog.GetString ("The numbers in the matrix follow a logic. Which is the number that should replace the question mark?");}
+		}
+
+		public override string Tip {
+			get { 
+				if (orientation) 
+					return Catalog.GetString ("The logic is arithmetical and works vertically.");
+				else 
+					return Catalog.GetString ("The logic is arithmetical and works horizontally.");
+			}
+		}
+
+		public override string Answer {
+			get { 
+				string answer = base.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."));
+					} else {
+						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."));
+					} else {
+						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."));
+					} else {
+						answer += String.Format(Catalog.GetString("The fourth column is calculated by adding the first two columns and subtracting the third."));
+					}
+					break;
+				}
+				return answer;
+			}
+		}
+
+		public override void Initialize ()
+		{
+			operation = (Operation) random.Next ((int) Operation.LastOperation);
+			orientation = (random.Next ((int) 2) == 0) ? true : false;
+			numbers = new int [4 * 4];
+
+			int coordinateA, coordinateB;
+
+			if (orientation) {
+				coordinateA=4; 
+				coordinateB=1;
+			}
+			else {
+				coordinateA=1;
+				coordinateB=4;
+			}
+
+		
+			for (int n = 0; n < 3; n++)
+				for (int i = 0; i < 4; i++) 
+					numbers[n*coordinateA + i*coordinateB] = random.Next (10) + random.Next (5);
+
+			for (int i = 0; i < 4; i++) {
+				switch (operation) {
+				case Operation.MultiplyAndAdd:
+					numbers[3*coordinateA + i*coordinateB] = (numbers [0*coordinateA + i*coordinateB ] * numbers[1*coordinateA + i*coordinateB]) + numbers[2*coordinateA + i*coordinateB];
+					break;
+				case Operation.MutilplyAndSubs:
+					numbers[3*coordinateA + i*coordinateB] = (numbers [0*coordinateA + i*coordinateB ] * numbers[1*coordinateA + i*coordinateB]) - numbers[2*coordinateA + i*coordinateB];
+					break;
+				case Operation.AddAndSubs:
+					numbers[3*coordinateA + i*coordinateB] = (numbers [0*coordinateA + i*coordinateB ] + numbers[1*coordinateA + i*coordinateB]) - numbers[2*coordinateA + i*coordinateB];
+					break;
+				default:
+					break;
+				}			
+			}
+
+			right_answer = numbers[3*coordinateA + 3*coordinateB].ToString ();
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double rect_w = DrawAreaWidth / rows;
+			double rect_h = DrawAreaHeight / columns;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			for (int column = 0; column < columns; column++) {
+				for (int row = 0; row < rows; row++) {
+					gr.Rectangle (DrawAreaX + row * rect_w, DrawAreaY + column * rect_h, rect_w, rect_h);
+
+					if (row != 3  || column != 3) {
+						gr.MoveTo (0.04 + DrawAreaX + column * rect_w, (rect_h / 2) + DrawAreaY + row * rect_h);
+						gr.ShowPangoText ( (numbers[column + (row * 4)]).ToString() );
+					}
+				}
+			}
+
+			gr.MoveTo (0.04 + DrawAreaX + 3 * rect_w, (rect_h / 2) + DrawAreaY + 3 * rect_h);
+			gr.ShowPangoText ("?");
+			gr.Stroke ();
+		}
+
+	}
+}
diff --git a/src/Games/Logic/PuzzleMissingPiece.cs b/src/Games/Logic/PuzzleMissingPiece.cs
new file mode 100644
index 0000000..b42ffd9
--- /dev/null
+++ b/src/Games/Logic/PuzzleMissingPiece.cs
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleMissingPiece : Game
+	{
+		private ArrayListIndicesRandom random_indices;
+		private const double sub_figure = 0.15;
+
+		public override string Name {
+			get {return Catalog.GetString ("Missing piece");}
+		}
+
+		public override string Question {
+			get {return String.Format (
+				Catalog.GetString ("Which square completes the figure below? Answer {0}, {1} or {2}."),
+				GetPossibleAnswer (0), GetPossibleAnswer (1), GetPossibleAnswer (2));}
+		}
+
+		public override string Tip {
+			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 void Initialize ()
+		{
+			random_indices = new ArrayListIndicesRandom (3);
+			random_indices.Initialize ();
+
+			for (int i = 0; i < random_indices.Count; i++) {
+				if (random_indices [i] == 0) {
+					right_answer = GetPossibleAnswer (i);
+					break;
+				}
+			}
+		}
+
+		private void DrawFigureSequence (CairoContextEx gr, double x, double y, int sequence, bool last_block)
+		{
+			gr.Rectangle (x, y, sub_figure, sub_figure);
+			gr.Rectangle (x + sub_figure, y, sub_figure, sub_figure);
+
+			if (last_block)
+				gr.Rectangle (x + sub_figure * 2, y, sub_figure, sub_figure);
+
+			switch (sequence) {
+			case 0:
+				gr.MoveTo (x, y + sub_figure);
+				gr.LineTo (x + sub_figure, y);
+				gr.MoveTo (x, y);
+				gr.LineTo (x + sub_figure, y + sub_figure);
+				x+= sub_figure;
+				gr.MoveTo (x, y);
+				gr.LineTo (x + sub_figure, y  + sub_figure);
+				x+= sub_figure;
+				gr.MoveTo (x, y + sub_figure);
+				gr.LineTo (x + sub_figure, y);
+				break;
+			case 1:
+				gr.MoveTo (x + sub_figure, y);
+				gr.LineTo (x, y + sub_figure);
+				gr.MoveTo (x + sub_figure / 2, y + sub_figure);
+				gr.LineTo (x + sub_figure, y + sub_figure / 2);
+				x+= sub_figure;
+				gr.MoveTo (x, y + sub_figure / 2);
+				gr.LineTo (x + sub_figure / 2, y + sub_figure);
+				x+= sub_figure;
+				gr.MoveTo (x, y);
+				gr.LineTo (x + sub_figure, y + sub_figure);
+				break;
+			case 2:
+				gr.MoveTo (x + sub_figure / 2, y);
+				gr.LineTo (x + sub_figure, y + sub_figure / 2);
+				gr.MoveTo (x, y + sub_figure);
+				gr.LineTo (x + sub_figure / 2, y + sub_figure / 2);
+				gr.LineTo (x + sub_figure, y + sub_figure);
+				x+= sub_figure;
+				gr.MoveTo (x, y + sub_figure / 2);
+				gr.LineTo (x + sub_figure / 2, y);
+				break;
+			}
+
+			gr.Stroke ();
+		}
+
+		private void DrawAnswerFigures (CairoContextEx gr, double x, double y, int figure)
+		{
+			gr.Rectangle (x, y, sub_figure, sub_figure);
+
+			switch (figure) {
+			case 0:
+				gr.MoveTo (x, y + sub_figure);
+				gr.LineTo (x + sub_figure / 2, y + sub_figure / 2);
+				gr.LineTo (x + sub_figure, y + sub_figure);
+				break;
+			case 1:
+				gr.MoveTo (x, y + sub_figure);
+				gr.LineTo (x + sub_figure, y);
+				break;
+			case 2:
+				gr.MoveTo (x, y);
+				gr.LineTo (x + sub_figure, y + sub_figure);
+				break;
+			}
+			gr.Stroke ();
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double x = DrawAreaX + 0.15, y = DrawAreaY;
+			int figure;
+
+			base.Draw (gr, area_width, area_height, rtl);
+		
+			for (int i = 0; i < 2; i++)
+				DrawFigureSequence (gr, x, y + sub_figure * i , i, true);
+
+			DrawFigureSequence (gr, x, y + sub_figure * 2 , 2, false);
+
+			gr.MoveTo (0.1, 0.62);
+			gr.ShowPangoText (Catalog.GetString ("Possible answers are:"));
+
+			x = DrawAreaX + 0.1;
+			for (int i = 0; i < random_indices.Count; i++) {
+				figure = random_indices [i];
+				DrawAnswerFigures (gr, x + (0.08 + sub_figure) * i, 0.70, figure);
+				gr.MoveTo (x + (0.08 + sub_figure) * i, 0.9);
+				gr.ShowPangoText (GetPossibleFigureAnswer (i));
+			}
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleMissingSlice.cs b/src/Games/Logic/PuzzleMissingSlice.cs
new file mode 100644
index 0000000..e8620f9
--- /dev/null
+++ b/src/Games/Logic/PuzzleMissingSlice.cs
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleMissingSlice : Game
+	{
+		private const int total_slices = 6;
+		private const int half_slices = total_slices / 2;
+		private const int items_per_slice = 3;
+		private const double radius = 0.22;
+		private const double radian = Math.PI / 180;
+		private const double arc_centerx = 0.2, arc_centery = 0.2;
+		private const int possible_answers = 3;
+		private ArrayListIndicesRandom random_indices;
+		private int ans_pos;
+		private int[] bad_answers;
+		private int sum_offset;
+
+		private int [] slices = new int []
+		{
+			2, 4, 3,
+			2, 3, 6,
+			1, 3, 4,
+			3, 7, 1,
+			6, 3, 2,
+		};
+
+		private int [] slices_opposite = new int []
+		{
+			6, 4, 5,
+			6, 5, 2,
+			7, 5, 4,
+			5, 1, 7,
+			2, 5, 6,
+		};
+
+		public override string Name {
+			get {return Catalog.GetString ("Missing slice");}
+		}
+
+		public override string Question {
+			get {return String.Format (
+				Catalog.GetString ("Some slices have a common property. Which is the missing slice in the circle below? Answer {0}, {1} or {2}."),
+				GetPossibleAnswer (0), GetPossibleAnswer (1), GetPossibleAnswer (2));}
+		}
+
+		public override string Tip {
+			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 void Initialize ()
+		{
+			sum_offset = random.Next (3);
+			random_indices = new ArrayListIndicesRandom (slices.Length / items_per_slice);
+			random_indices.Initialize ();
+			ans_pos = random.Next (possible_answers);
+			right_answer = GetPossibleAnswer (ans_pos);
+		
+			bad_answers = new int [possible_answers * items_per_slice];
+			for (int i = 0; i < bad_answers.Length; i++) {
+				bad_answers[i] = 1 + random.Next (9);
+			}
+		}
+
+		private static void DrawSlice (CairoContextEx gr, double x, double y)
+		{
+			double degrees, x1, y1;
+		
+			degrees = 0;
+			gr.MoveTo (x, y);
+			x1 = x + radius * Math.Cos (degrees);
+			y1 = y + radius * Math.Sin (degrees);
+			gr.LineTo (x1, y1);
+			gr.Stroke ();
+
+			degrees = radian * 60;
+			gr.MoveTo (x, y);
+			x1 = x + radius * Math.Cos (degrees);
+			y1 = y + radius * Math.Sin (degrees);
+			gr.LineTo (x1, y1);
+			gr.Stroke ();
+
+			gr.Arc (x, y, radius, 0, radian * 60);
+			gr.Stroke ();
+		}
+
+		private void DrawSliceText (CairoContextEx gr, double x, double y, int slice, string str1, string str2, string str3)
+		{	
+			double x0, y0, degrees;
+
+			// Number more near to the center;
+			degrees = radian * (slice * ((360 / total_slices)) + (360 / 12));
+			x0 = 0.35 * radius * Math.Cos (degrees);
+			y0 = 0.35 * radius * Math.Sin (degrees);
+			gr.DrawTextCentered (x + x0, y + y0, str1);
+	
+			// Number opposite to the center and at the top
+			degrees = radian * (slice * ((360 / total_slices)) + (360 / 24));
+			x0 = 0.8 * radius * Math.Cos (degrees);
+			y0 = 0.8 * radius * Math.Sin (degrees);
+			gr.DrawTextCentered (x + x0, y + y0, str2);
+	
+			// Number opposite to the center and at the bottom
+			degrees = radian * (slice * ((360 / total_slices)) + (360 / 8));			
+			x0 = 0.8 * radius * Math.Cos (degrees);
+			y0 = 0.8 * radius * Math.Sin (degrees);
+			gr.DrawTextCentered (x + x0, y + y0, str3);
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{		
+			double x = DrawAreaX + 0.2, y = DrawAreaY;
+			double x0, y0, degrees;
+			int pos;
+
+			base.Draw (gr, area_width, area_height, rtl);
+			
+			gr.Arc (x + arc_centerx, y + arc_centery, radius, 0, 2 * Math.PI);
+			gr.Stroke ();
+
+			for (int slice = 0; slice < total_slices; slice++) 
+			{
+				degrees = radian * slice * (360 / total_slices);
+				gr.MoveTo (x + arc_centerx, y + arc_centery);
+				gr.LineTo (x + arc_centerx + (radius * Math.Cos (degrees)), y + arc_centery + (radius * Math.Sin (degrees)));
+	
+				if (slice > total_slices - 1) continue;
+
+				if (slice == 0) {
+					degrees = radian * (slice * ((360 / total_slices)) + (360 / 12));
+					x0 = 0.5 * radius * Math.Cos (degrees);
+					y0 = 0.5 * radius * Math.Sin (degrees);
+					gr.DrawTextCentered (x + arc_centerx + x0, y + arc_centery + y0, "?");
+					continue;
+				}
+			
+				if (slice < half_slices) {
+					pos = random_indices [slice];
+					DrawSliceText (gr, x + arc_centerx, y + arc_centery, slice, (sum_offset + slices [pos * items_per_slice]).ToString (),
+						 (sum_offset + slices [1 + (pos * items_per_slice)]).ToString (), (sum_offset + slices [2 + (pos * items_per_slice)]).ToString ());
+				}
+				else {
+					pos = random_indices [slice - half_slices];
+					DrawSliceText (gr, x + arc_centerx, y + arc_centery, slice, slices_opposite [pos * items_per_slice].ToString (),
+						 slices_opposite [2 + (pos * items_per_slice)].ToString (), slices_opposite [1 + (pos * items_per_slice)].ToString ());
+				}
+			}
+
+			gr.MoveTo (0.1, 0.61);
+			gr.ShowPangoText (Catalog.GetString ("Possible answers are:"));
+
+			y = 0.68;
+	 		for (int i = 0; i < possible_answers; i++) 
+			{
+				DrawSlice (gr, 0.10 + i * 0.28, y);
+				if (i == ans_pos) {
+					pos = random_indices [0];
+					DrawSliceText (gr, 0.10 + i * 0.28, y, 0, (sum_offset + slices [pos * items_per_slice]).ToString (),
+						 (sum_offset + slices [1 + (pos * items_per_slice)]).ToString (), (sum_offset + slices [2 + (pos * items_per_slice)]).ToString ());
+				} else {
+					DrawSliceText (gr, 0.10 + i * 0.28, y, 0, bad_answers [i * items_per_slice].ToString (),
+						 bad_answers [1 + (i * items_per_slice)].ToString (), bad_answers [2 + (i * items_per_slice)].ToString ());
+				}
+			
+				gr.MoveTo (0.10  + i * 0.28, y + 0.25);
+				gr.ShowPangoText (GetPossibleFigureAnswer (i));
+			}
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleMostInCommon.cs b/src/Games/Logic/PuzzleMostInCommon.cs
new file mode 100644
index 0000000..b4e4846
--- /dev/null
+++ b/src/Games/Logic/PuzzleMostInCommon.cs
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2008 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 Cairo;
+using Mono.Unix;
+using System.Collections;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleMostInCommon : Game
+	{
+		public enum Element
+		{
+			SmallCircle,
+			MediumCircleWithChild,
+			MediumCircle,
+			LargeCircle,
+		}
+
+		struct FigureElement
+		{
+			public double x;
+			public double y;
+			public Element element;
+
+			public FigureElement (double _x, double _y, Element _element)
+			{
+				x = _x;
+				y = _y;
+				element = _element;
+			}
+		}
+	
+		private double small_size = 0.01;
+		private double medium_size = 0.02;
+	  	private ArrayList questions;
+	  	private ArrayList answers;
+		private ArrayListIndicesRandom random_indices_answers;
+		private const double pos1_x = 0.03;
+		private const double pos2_x = 0.06;
+		private const double pos3_x = 0.09;
+		private const double pos4_x = 0.07;
+		private const double pos5_x = 0.10;
+		private const double pos6_x = 0.02;
+		private const double pos7_x = 0.05;
+		private const double pos1_y = 0.03;
+		private const double pos2_y = 0.06;
+		private const double pos3_y = 0.09;
+		private const double pos4_y = 0.02;
+		private const double pos5_y = 0.05;
+		private const double pos6_y = 0.07;
+		private const double pos7_y = 0.11;
+
+		public override string Name {
+			get {return Catalog.GetString ("Most in common");}
+		}
+
+		public override string Question {
+			get {return String.Format (
+				Catalog.GetString ("Which of the possible answers have the most in common with the four given figures? Answer {0}, {1}, {2} or {3}."),
+					GetPossibleAnswer (0), GetPossibleAnswer (1), GetPossibleAnswer (2), GetPossibleAnswer (3));}
+		}
+
+		public override string Tip {
+			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 + " ";
+
+				if (CurrentDifficulty ==  Difficulty.Easy) 
+					answer += 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;
+			}
+		}
+
+		public override void Initialize ()
+		{
+			// Question
+			ArrayList array_good = new ArrayList ();
+			array_good.AddRange (new Element [] {Element.SmallCircle, Element.SmallCircle, Element.SmallCircle, 
+				Element.MediumCircle,Element.MediumCircle, Element.MediumCircleWithChild, Element.MediumCircleWithChild});
+
+			// Four random samples with equal elements
+			questions = new ArrayList ();
+			for (int i = 0; i < 4; i++) {
+				questions.Add (BuildFigure (array_good, questions));
+			}
+
+			ArrayList array = new ArrayList ();
+			answers = new ArrayList ();
+			random_indices_answers = new ArrayListIndicesRandom (4);
+			random_indices_answers.Initialize ();
+
+			for (int i = 0; i < random_indices_answers.Count; i++) {
+				if ((int) random_indices_answers [i] == 0) {
+					right_answer = GetPossibleAnswer (i);
+					break;
+				}
+			}
+
+			if (CurrentDifficulty ==  Difficulty.Easy) {
+				// Answer 1 (good)
+				array.AddRange (new Element [] {Element.SmallCircle, Element.SmallCircle, Element.SmallCircle, 
+				Element.MediumCircle,Element.MediumCircle, Element.MediumCircleWithChild, Element.MediumCircleWithChild});
+				answers.Add (BuildFigure (array, answers));
+
+				// Answer 2
+				array.Clear ();
+				array.AddRange (new Element [] {Element.SmallCircle, Element.SmallCircle, Element.MediumCircle, 
+				Element.MediumCircle,Element.MediumCircle, Element.MediumCircleWithChild, Element.MediumCircleWithChild});
+				answers.Add (BuildFigure (array, answers));
+
+				// Answer 3
+				array.Clear ();
+				array.AddRange (new Element [] {Element.SmallCircle, Element.SmallCircle, Element.MediumCircle, 
+				Element.MediumCircle,Element.MediumCircle, Element.MediumCircleWithChild, Element.MediumCircleWithChild});
+				answers.Add (BuildFigure (array, answers));
+
+				// Answer 4
+				array.Clear ();
+				array.AddRange (new Element [] {Element.SmallCircle, Element.SmallCircle, Element.MediumCircle, 
+				Element.MediumCircle,Element.MediumCircle, Element.MediumCircleWithChild, Element.MediumCircleWithChild});
+				answers.Add (BuildFigure (array, answers));
+				return;
+			}
+
+			// Medium or Master
+
+			// Answer 1 (good)
+			array.AddRange (new Element [] {Element.SmallCircle, Element.SmallCircle, Element.MediumCircleWithChild, 
+				Element.MediumCircle,Element.MediumCircle, Element.MediumCircleWithChild, Element.MediumCircleWithChild});
+			answers.Add (BuildFigure (array, answers));
+
+			// Answer 2
+			array.Clear ();
+			array.AddRange (new Element [] {Element.SmallCircle, Element.MediumCircle, Element.MediumCircle, 
+				Element.MediumCircle,Element.MediumCircle, Element.MediumCircleWithChild, Element.MediumCircleWithChild});
+			answers.Add (BuildFigure (array, answers));
+
+			// Answer 3
+			array.Clear ();
+			array.AddRange (new Element [] {Element.SmallCircle, Element.MediumCircleWithChild, Element.MediumCircleWithChild, 
+				Element.MediumCircle,Element.MediumCircle, Element.MediumCircleWithChild, Element.MediumCircleWithChild});
+			answers.Add (BuildFigure (array, answers));
+
+			// Answer 4
+			array.Clear ();
+			array.AddRange (new Element [] {Element.MediumCircle, Element.MediumCircleWithChild, Element.MediumCircleWithChild, 
+				Element.MediumCircle,Element.MediumCircle, Element.MediumCircleWithChild, Element.MediumCircleWithChild});
+			answers.Add (BuildFigure (array, answers));
+		}
+
+		private ArrayListIndicesRandom RandomizeFromArray (ArrayList ar)
+		{		
+			int index;
+			object []array = (object []) ar.ToArray (typeof (object));
+			ArrayListIndicesRandom elements = new ArrayListIndicesRandom (ar.Count);
+			int left = ar.Count;
+			elements.Clear ();
+
+			// Generate a random number that can be as big as the maximum -1
+			// Add the random element picked up element in the list
+			// The element just randomized gets out of pending list and replaced by the maximum -1 element 
+			for (int i = 0; i < ar.Count; i++, left--) {
+				index = random.Next (left);
+				elements.Add ((int) array[index]);
+				array[index] = array[left - 1];
+			}
+			return elements;
+		}
+
+		// Generates a new figure that was not generated before
+		private FigureElement [] BuildFigure (ArrayList array, ArrayList figures)
+		{
+			bool done = false;
+			FigureElement [] element = null;
+			ArrayListIndicesRandom elements = new ArrayListIndicesRandom (array.Count);
+			bool element_exists = false;
+
+			while (done == false) {
+
+				elements = RandomizeFromArray (array);
+				element = new FigureElement []
+				{
+					new FigureElement (pos1_x, pos1_y, (Element) elements[0]),
+					new FigureElement (pos2_x, pos2_y, (Element) elements[1]),
+					new FigureElement (pos3_x, pos3_y, (Element) elements[2]),
+					new FigureElement (pos4_x, pos4_y, (Element) elements[3]),
+					new FigureElement (pos5_x, pos5_y, (Element) elements[4]),
+					new FigureElement (pos6_x, pos6_y, (Element) elements[5]),
+					new FigureElement (pos7_x, pos7_y, (Element) elements[6]),
+				};
+	
+				for (int i = 0; i < figures.Count; i++) {
+					FigureElement [] element2 = (FigureElement []) figures[i];
+
+					if (element.Length != element2.Length)
+						continue;
+
+					element_exists = true;
+					for (int n = 0; n < element.Length; n++) {
+						if (element[n].element != element2[n].element) {
+							element_exists = false;
+							break;
+						}
+					}
+					if (element_exists == true)
+						break;
+				}
+
+				if (element_exists == false)
+					done = true;
+			}
+
+			return element;
+		}
+
+		private void DrawFigureElement (CairoContextEx gr, double x, double y, FigureElement figure)
+		{
+			switch (figure.element) {
+			case Element.SmallCircle:
+				gr.Arc (x + figure.x + small_size / 2, y + figure.y + small_size / 2, small_size, 0, 2 * Math.PI);
+				break;
+			case Element.MediumCircle:
+				gr.Arc (x + figure.x + medium_size / 2, y + figure.y + medium_size / 2, medium_size, 0, 2 * Math.PI);
+				break;
+			case Element.MediumCircleWithChild:
+				gr.Arc (x + figure.x + medium_size / 2, y + figure.y + medium_size / 2, medium_size, 0, 2 * Math.PI);
+				gr.Stroke ();
+				gr.Arc (x + figure.x + medium_size / 2, y + figure.y + medium_size / 2, small_size, 0, 2 * Math.PI);
+				break;
+			}
+			gr.Stroke ();
+		}
+
+		private void DrawFigure (CairoContextEx gr, double x, double y, FigureElement[] figure)
+		{
+			const double cercle_size = 0.15;
+			gr.Stroke ();
+			gr.Arc (x + cercle_size / 2, y + cercle_size / 2, cercle_size / 2, 0, 2 * Math.PI);
+			gr.Stroke ();
+
+			for (int i = 0; i < figure.Length; i++)
+				DrawFigureElement (gr, x, y,  figure[i]);			
+
+			gr.Stroke ();
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double x = DrawAreaX, y = DrawAreaY + 0.1;
+
+			base.Draw (gr, area_width, area_height, rtl);
+		
+			for (int i = 0; i < questions.Count; i++) {
+				DrawFigure (gr, x, y, (FigureElement []) questions[i]);
+				 x+= 0.22;
+			}
+
+			y += 0.28;
+			x = DrawAreaX;
+			gr.MoveTo (x - 0.06, y);
+			gr.ShowPangoText (Catalog.GetString ("Possible answers are:"));
+			gr.Stroke ();
+	
+			y += 0.08;
+			for (int i = 0; i < random_indices_answers.Count; i++) {
+				DrawFigure (gr, x, y, (FigureElement []) answers[(int)random_indices_answers[i]]);
+				gr.MoveTo (x, y + 0.2);
+				x+= 0.22;
+				gr.ShowPangoText (GetPossibleFigureAnswer (i));
+			}
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleMoveFigure.cs b/src/Games/Logic/PuzzleMoveFigure.cs
new file mode 100644
index 0000000..2597281
--- /dev/null
+++ b/src/Games/Logic/PuzzleMoveFigure.cs
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleMoveFigure: Game
+	{
+		private int lines;
+		private int type;
+
+		public override string Name {
+			get {return Catalog.GetString ("Move figure");}
+		}
+
+		public override string Question {
+			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 + " ";
+
+				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;
+				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 answer;
+			}
+		}
+
+		public override void Initialize ()
+		{	
+			type = random.Next (2);
+			lines = 4 + type;
+		
+			switch (type)
+			{
+				case 0:
+					right_answer = "3";
+					break;
+				case 1:
+					right_answer = "5";
+					break;
+			}
+		
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double first_x, x, y;
+			double figure_size = 0.07 + (0.01 * (5 - lines));
+			double margin = 0;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			// Figure 1
+			margin = ((1.0 - (figure_size * lines * 2)) / 2);
+
+			x = first_x = margin + (figure_size * lines / 2) + figure_size / 2;
+			y = DrawAreaY + 0.2;
+			for (int line = 0; line < lines + 1; line++)
+			{
+				for (int circles = 0; circles < line; circles++)
+				{
+					gr.Arc (x, y, figure_size / 2, 0, 2 * Math.PI);	
+					gr.Stroke ();
+					x += figure_size;
+				}
+				x = first_x = first_x - (figure_size / 2);
+				y += figure_size;			
+			}
+
+			// Figure 2
+			first_x = margin + (figure_size * lines);
+			y = DrawAreaY + 0.2 + figure_size;
+			for (int line = 0; line < lines; line++)
+			{
+				x = first_x = first_x + (figure_size / 2);
+				for (int circles = 0; circles < lines - line; circles++)
+				{
+					gr.Arc (x, y, figure_size / 2, 0, 2 * Math.PI);	
+					gr.Stroke ();
+					x += figure_size;
+				}
+				y += figure_size;			
+			}
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleNextFigure.cs b/src/Games/Logic/PuzzleNextFigure.cs
new file mode 100644
index 0000000..bd04243
--- /dev/null
+++ b/src/Games/Logic/PuzzleNextFigure.cs
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using Mono.Unix;
+using System;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleNextFigure : Game
+	{
+		private const double figure_size = 0.2;
+		private ArrayListIndicesRandom random_indices;
+
+		public enum CerclePosition 
+		{
+			None		= 0,
+			Top		= 2,
+			Right		= 4,
+			Bottom		= 8,
+			Left		= 16,
+		}
+
+		enum Figures
+		{
+			First,
+			Second,
+			Third,
+			Last
+		};
+
+		public override string Name {
+			get {return Catalog.GetString ("Next figure");}
+		}
+
+		public override string Question {
+			get {return String.Format (
+				Catalog.GetString ("Which is the next logical figure in the sequence? Answer {0}, {1} or {2}."),
+				GetPossibleAnswer (0), GetPossibleAnswer (1), GetPossibleAnswer (2));} 
+		}
+
+
+		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 void Initialize ()
+		{
+			random_indices = new ArrayListIndicesRandom ((int) Figures.Last);
+			random_indices.Initialize ();
+
+			for (int i = 0; i < (int) Figures.Last; i++)
+			{
+				if ((int) random_indices[i] == (int) Figures.Third) {
+					right_answer = GetPossibleAnswer (i);
+					break;
+				}
+			}
+		}
+
+		static private void DrawDiamon (CairoContextEx gr, double x, double y, CerclePosition cercles)
+		{	
+			double distance = 0.04;
+
+			gr.MoveTo (x + figure_size / 2, y);
+			gr.LineTo (x, y + figure_size / 2);
+			gr.LineTo (x + figure_size / 2, y + figure_size);
+			gr.LineTo (x + figure_size, y + figure_size / 2);
+			gr.LineTo (x + figure_size / 2, y);
+			gr.Stroke ();
+
+			if ((cercles & CerclePosition.Top) == CerclePosition.Top) {
+				gr.Arc (x + figure_size / 2, y + distance, 0.01, 0, 2 * Math.PI);	
+				gr.Stroke ();
+			}
+
+			if ((cercles & CerclePosition.Right) == CerclePosition.Right) {
+				gr.Arc (x + figure_size - distance, y + figure_size / 2, 0.01, 0, 2 * Math.PI);	
+				gr.Stroke ();
+			}
+
+			if ((cercles & CerclePosition.Bottom) == CerclePosition.Bottom) {
+				gr.Arc (x + figure_size / 2, y + figure_size - distance, 0.01, 0, 2 * Math.PI);	
+				gr.Stroke ();
+			}
+
+			if ((cercles & CerclePosition.Left) == CerclePosition.Left) {
+				gr.Arc (x + distance, y + figure_size / 2, 0.01, 0, 2 * Math.PI);
+				gr.Stroke ();
+			}
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double x = DrawAreaX;
+			double y = DrawAreaY;
+			double space_figures = figure_size + 0.1;
+		
+			base.Draw (gr, area_width, area_height, rtl);
+
+			DrawDiamon (gr, x, y, CerclePosition.Top | CerclePosition.Left);
+			DrawDiamon (gr, x + space_figures , y, CerclePosition.Bottom);
+			DrawDiamon (gr, x + space_figures * 2, y, CerclePosition.Top | CerclePosition.Right);
+		
+			y += figure_size + 0.06;
+			gr.MoveTo (x, y);
+			gr.ShowPangoText (Catalog.GetString ("Possible answers are:"));
+			gr.Stroke ();
+			y += 0.10;
+
+			for (int i = 0; i < (int) Figures.Last; i++)
+			{
+			 	switch ((Figures) random_indices[i]) {
+				case Figures.First:
+					DrawDiamon (gr, x, y, CerclePosition.Right | CerclePosition.Left);
+					break;
+				case Figures.Second:
+					DrawDiamon (gr, x, y, CerclePosition.Top | CerclePosition.Right);
+					break;
+				case Figures.Third:
+					DrawDiamon (gr, x, y, CerclePosition.Bottom | CerclePosition.Top);
+					break;
+				}
+			
+				gr.MoveTo (x + 0.02, y + 0.25);
+				gr.ShowPangoText (GetPossibleFigureAnswer (i));
+				x += space_figures;			
+			}
+
+			gr.Stroke ();
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleNumericRelation.cs b/src/Games/Logic/PuzzleNumericRelation.cs
new file mode 100644
index 0000000..cd47121
--- /dev/null
+++ b/src/Games/Logic/PuzzleNumericRelation.cs
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using System.Text;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleNumericRelation : Game
+	{
+		private const int group_size = 3;
+		private int sum_value;
+		private int question;
+		private int[] numbers;
+		private int formula;
+		private const int max_num = 9;
+
+		public override string Name {
+			get {return Catalog.GetString ("Numeric relation");}
+		}
+
+		public override string Question {
+			get {return Catalog.GetString ("What number should replace the question mark?");} 
+		}
+
+		public override string Tip {
+			get { return Catalog.GetString ("The numbers are related arithmetically.");}
+		}
+
+		public override string Answer {
+			get { 
+				string answer = base.Answer + " ";
+
+				switch (formula) {
+				case 0:
+					answer += String.Format (Catalog.GetString ("Every group of {0} numbers sums exactly {1}."), group_size, sum_value);
+					break;
+				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;
+
+				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 answer;
+			}
+		}
+
+		public override void Initialize ()
+		{
+			int group = 0, inc = 0;
+
+			if (CurrentDifficulty == Difficulty.Easy) {
+				sum_value = 10 + random.Next (10);
+				inc = 5;
+			}
+			else {
+				sum_value = 30 + random.Next (10);
+				inc = 12;
+			}
+
+			question = 1 + random.Next (max_num - 2);
+			formula = random.Next (3);
+			numbers =  new int [max_num];
+		
+			for (int i = 0; i < max_num; i++) {
+				if (group == group_size - 1) {	
+					switch (formula) {
+					case 0:
+						numbers[i] = sum_value - numbers[i - 1] - numbers[i - 2];
+						break;
+					case 1:
+						numbers[i] = numbers[i - 1] * numbers[i - 2];
+						break;
+					case 2:
+						numbers[i] = numbers[i - 2] - numbers[i - 1];
+						break;
+					}
+					group = 0;
+					continue;
+				}
+				numbers[i] = 1 + random.Next (inc);
+				group++;
+			}
+
+			right_answer = numbers[question].ToString ();
+		}
+
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			StringBuilder sequence = new StringBuilder (64);
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			gr.SetPangoLargeFontSize ();
+
+			for (int num = 0; num < max_num - 1; num++)
+			{
+				if (num == question) {
+					sequence.Append ("?, ");
+				} else {
+					sequence.Append (numbers[num]);
+					sequence.Append (", ");
+				}
+			}
+			sequence.Append (numbers[max_num - 1]);
+			gr.DrawTextCentered (0.5, DrawAreaY + 0.3, sequence.ToString ());
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleNumericSequence.cs b/src/Games/Logic/PuzzleNumericSequence.cs
new file mode 100644
index 0000000..5a5f83f
--- /dev/null
+++ b/src/Games/Logic/PuzzleNumericSequence.cs
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using System.Text;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleNumericSequence : Game
+	{
+		private const int max_num = 6;
+		private int[] numbers;
+		private int formula;
+
+		public override string Name {
+			get {return Catalog.GetString ("Numeric sequence");}
+		}
+
+		public override string Question {
+			get {return Catalog.GetString ("The next sequence follows a logic. What number should replace the question mark?");} 
+		}
+
+		public override string Tip {
+			get { return Catalog.GetString ("Every number in the sequence is related to the previous one.");}
+		}
+
+		public override string Answer {
+			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;
+				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;
+				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 answer;
+			}
+		}
+
+		public override void Initialize ()
+		{
+			formula = random.Next (CurrentDifficulty == Difficulty.Easy ? 2 : 3);
+			numbers =  new int [max_num];
+			numbers[0] = 3 + random.Next (3);
+			for (int i = 1; i < max_num; i++) {
+				switch (formula) {
+				case 0:
+					numbers[i] = (numbers[i - 1] - 1) * 2;
+					break;
+				case 1:
+					numbers[i] = (numbers[i - 1] + 1) * 3;
+					break;
+				case 2:
+					numbers[i] = (numbers[i -1] - 2) * (-2);
+					break;
+				}				
+			}
+
+			right_answer = numbers[max_num-1].ToString ();
+		}
+
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			StringBuilder sequence = new StringBuilder (64);
+
+			base.Draw (gr, area_width, area_height, rtl);
+			gr.SetPangoLargeFontSize ();
+
+			for (int num = 0; num < max_num - 1; num++)
+			{
+				sequence.Append (numbers[num]);
+				sequence.Append (", ");
+			}
+			sequence.Append ("?");
+
+			gr.DrawTextCentered (0.5, DrawAreaY + 0.3, sequence.ToString ());
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleOstracism.cs b/src/Games/Logic/PuzzleOstracism.cs
new file mode 100644
index 0000000..a475166
--- /dev/null
+++ b/src/Games/Logic/PuzzleOstracism.cs
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleOstracism : Game
+	{
+		private ArrayListIndicesRandom random_indices;
+		private const int wrong_answer = 2;
+		private string [] equations = new string []
+		{
+			"21 x 60 = 1260",
+			"15 x 93 = 1395",
+			"70 x 16 = 1120",
+			"43 x 51 = 1453",
+			"80 x 16 = 1806",
+		};
+
+		public override string Name {
+			get {return Catalog.GetString ("Ostracism");}
+		}
+
+		public override string Question {
+			get {return String.Format (
+				Catalog.GetString ("Which equation does not belong to the group? Answer {0}, {1}, {2}, {3} or {4}."),
+				GetPossibleAnswer (0), GetPossibleAnswer (1), GetPossibleAnswer (2), GetPossibleAnswer (3), GetPossibleAnswer (4));}
+		}
+
+
+		public override string Tip {
+			get { return Catalog.GetString ("The criteria for deciding if an equation belongs to the group is not arithmetical.");}
+		}
+
+		public override string Answer {
+			get { 
+				string answer = base.Answer + " ";
+				answer += Catalog.GetString ("In all equations the digits from the left side should also appear in the right side.");
+				return answer;
+			}
+		}
+
+		public override void Initialize ()
+		{
+			random_indices = new ArrayListIndicesRandom (equations.Length);
+			random_indices.Initialize ();
+			right_answer = string.Empty;
+
+			for (int i = 0; i < random_indices.Count; i++)
+			{
+				if (random_indices[i] == wrong_answer) {
+					right_answer = GetPossibleAnswer (i);
+					break;
+				}
+			}
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double x = DrawAreaX + 0.15, y = DrawAreaY + 0.2;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			gr.SetPangoLargeFontSize ();		
+			for (int i = 0; i < random_indices.Count; i++)
+			{
+				gr.MoveTo (x, y);
+				gr.ShowPangoText (String.Format ("{0}) {1}", GetPossibleAnswer (i), equations [random_indices[i]]));
+				y += 0.1;
+			}
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzlePencil.cs b/src/Games/Logic/PuzzlePencil.cs
new file mode 100644
index 0000000..be16cb8
--- /dev/null
+++ b/src/Games/Logic/PuzzlePencil.cs
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzlePencil : Game
+	{
+		private ArrayListIndicesRandom random_indices;
+		private const double figure_width = 0.1, figure_height = 0.1, space_width = 0.1, space_height = 0.15;
+		private const double figure_size = 0.2;
+		private const int figures = 5;
+		private const int answer_index = 4;
+
+		public override string Name {
+			get {return Catalog.GetString ("Pencil");}
+		}
+
+		public override string Question {
+			get {return String.Format ( Catalog.GetString 
+				("Which of the following figures cannot be drawn without crossing any previous lines nor lifting the pencil? Answer {0}, {1}, {2}, {3} or {4}."),
+				GetPossibleAnswer (0), GetPossibleAnswer (1), GetPossibleAnswer (2), GetPossibleAnswer (3), GetPossibleAnswer (4));} 
+		}
+
+		public override void Initialize ()
+		{
+			random_indices = new ArrayListIndicesRandom (figures);
+			random_indices.Initialize ();
+			right_answer = string.Empty;
+
+			for (int i = 0; i < random_indices.Count; i++) {
+				if (random_indices[i] != answer_index)
+					continue;
+			
+				right_answer = GetPossibleAnswer (i);
+				break;
+			}	
+		}
+
+		static private void DrawTriangle (CairoContextEx gr, double x, double y)
+		{
+			gr.MoveTo (x + (figure_size / 2), y);
+			gr.LineTo (x, y + figure_size);
+			gr.LineTo (x + figure_size, y + figure_size);
+			gr.LineTo (x + (figure_size / 2), y);
+			gr.LineTo (x + (figure_size / 2), y + figure_size);
+			gr.Stroke ();	
+		}
+
+		static private void DrawDiamon (CairoContextEx gr, double x, double y)
+		{
+			gr.MoveTo (x, y);
+			gr.LineTo (x - (figure_size / 2), y + (figure_size / 2));
+			gr.LineTo (x, y + figure_size);
+			gr.LineTo (x + figure_size / 2, y + (figure_size / 2));
+			gr.LineTo (x, y);
+			gr.LineTo (x, y + figure_size);
+			gr.Stroke ();
+		}
+
+		static private void DrawRectangleWithTriangles (CairoContextEx gr, double x, double y)
+		{
+			gr.Rectangle (x, y, figure_size, figure_size);
+			gr.Stroke ();	
+	
+			gr.MoveTo (x, y + figure_size);
+			gr.LineTo (x + figure_size / 4, y);
+			gr.LineTo (x + figure_size / 2, y + figure_size);
+
+			gr.Stroke ();		
+	
+			gr.MoveTo (x + figure_size / 2, y + figure_size);
+			gr.LineTo (x + figure_size / 4 * 3, y);
+			gr.LineTo (x + figure_size, y + figure_size);
+
+			gr.Stroke ();
+		}
+
+		static private void DrawThreeTriangles (CairoContextEx gr, double x, double y)
+		{
+			gr.MoveTo (x, y);
+			gr.LineTo (x, y + figure_size);
+			gr.LineTo (x + figure_size, y);
+			gr.LineTo (x, y);
+			gr.LineTo (x + figure_size, y + figure_size);
+			gr.LineTo (x + figure_size, y);
+
+			gr.Stroke ();
+		
+		}
+
+	/*	private void DrawHouse (CairoContextEx gr, double x, double y)
+		{
+			gr.MoveTo (x, y + figure_size);
+			gr.LineTo (x, y + figure_size / 2);
+			gr.LineTo (x + figure_size / 2, y);
+			gr.LineTo (x + figure_size, y + figure_size / 2);
+			gr.LineTo (x, y + figure_size / 2);
+			gr.LineTo (x + figure_size, y + figure_size);
+			gr.LineTo (x + figure_size, y + figure_size / 2);
+			gr.LineTo (x, y + figure_size);
+			gr.LineTo (x + figure_size, y + figure_size);
+			gr.Stroke ();		
+		}*/
+
+		static private void DrawRectangleWithCross (CairoContextEx gr, double x, double y)
+		{
+			gr.Rectangle (x, y, figure_size, figure_size);
+
+			gr.MoveTo (x, y);
+			gr.LineTo (x + figure_size, y + figure_size);
+			gr.Stroke ();
+
+			gr.MoveTo (x + figure_size, y);
+			gr.LineTo (x, y + figure_size);
+			gr.Stroke ();
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double x = DrawAreaX, y = DrawAreaY;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			for (int figure = 0; figure < figures; figure++)
+			{
+				switch (random_indices[figure]) {
+				case 0:
+					DrawTriangle (gr, x, y);
+					break;
+				case 1:
+					DrawDiamon (gr, x + 0.1, y);
+					break;
+				//case 2:
+				//	DrawHouse (gr, x, y);				
+				//	break;
+				case 2:
+					DrawRectangleWithTriangles (gr, x, y);
+					break;
+				case 3:
+					DrawThreeTriangles (gr, x, y);
+					break;
+				case answer_index:
+					DrawRectangleWithCross (gr, x, y);
+					break;
+			
+				}			
+						
+				gr.MoveTo (x, y + figure_size + 0.05);
+				gr.ShowPangoText (GetPossibleFigureAnswer (figure));
+
+				if (figure == 2) {
+					x = DrawAreaX;
+					y += figure_size + space_height;
+
+				} else {						
+					x += figure_size + space_width;		
+				}
+			}
+
+		}
+
+	}
+}
diff --git a/src/Games/Logic/PuzzlePeopleTable.cs b/src/Games/Logic/PuzzlePeopleTable.cs
new file mode 100644
index 0000000..02a46e1
--- /dev/null
+++ b/src/Games/Logic/PuzzlePeopleTable.cs
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzlePeopleTable : Game
+	{
+		private const double figure_size = 0.15;
+		private string ques1, ques2;
+	
+		private class Circle
+		{	
+			public double x;
+			public double y;
+
+			public Circle (double x, double y) 
+			{
+				this.x = x;
+				this.y = y;
+			}
+		}
+
+		public override string Name {
+			get {return Catalog.GetString ("People at a table");}
+		}
+
+		public override string Question {
+			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 void Initialize ()
+		{
+			switch (random.Next (3)) {
+			case 0:
+				ques1 = Catalog.GetString ("5th");
+				ques2 = Catalog.GetString ("19th");
+				right_answer = "28";
+				break;
+			case 1:
+				ques1 = Catalog.GetString ("4th");
+				ques2 = Catalog.GetString ("12th");
+				right_answer = "16";
+				break;
+			case 2:
+				ques1 = Catalog.GetString ("9th");
+				ques2 = Catalog.GetString ("22nd");
+				right_answer = "26";
+				break;
+			}			
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double x = DrawAreaX + 0.22, y = DrawAreaY + 0.2;
+			double pos_x = x;
+			double pos_y = y;
+			Circle[] circles = null;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			circles =  new Circle [] {
+				new Circle (0.01, 0.06),
+				new Circle (0.27, 0.06),
+				new Circle (0.01, 0.21),
+				new Circle (0.27, 0.21),
+				new Circle (0.14, 0),
+				new Circle (0.14, 0.29)
+			};
+
+			// Circle
+			gr.Arc (pos_x + figure_size, pos_y + figure_size, figure_size, 0, 2 * Math.PI);
+			gr.Stroke ();		
+
+			const double point_size = 0.01;
+			for (int i = 0; i < circles.Length; i++) {
+				gr.Arc (x + point_size + circles[i].x, y + point_size + circles[i].y, point_size, 0, 2 * Math.PI);
+				gr.Fill ();
+				gr.Stroke ();
+			}
+
+			gr.MoveTo (x + circles[2].x + 0.01, y + circles[2].y + 0.01);
+			gr.LineTo (x + circles[1].x + 0.01, y + circles[1].y + 0.01);
+			gr.Stroke ();
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzlePercentage.cs b/src/Games/Logic/PuzzlePercentage.cs
new file mode 100644
index 0000000..9150705
--- /dev/null
+++ b/src/Games/Logic/PuzzlePercentage.cs
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2009 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 Cairo;
+using Mono.Unix;
+using System;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzlePercentage : Game
+	{
+		enum GameType
+		{
+			Discount,
+			Sales,
+			Water,
+			Total
+		}
+
+		string question, answer;
+		GameType gametype;
+
+		public override string Name {
+			get {return Catalog.GetString ("Percentage");}
+		}
+
+		public override string Question {
+			get {return question; }
+		}
+
+		public override string Answer {
+			get {
+
+				if (String.IsNullOrEmpty (answer) == true)
+					return base.Answer;
+
+				return base.Answer + " " + answer;
+			}
+		}
+
+		public override void Initialize ()
+		{
+			int ans;
+
+			gametype = (GameType) random.Next ((int) GameType.Total);
+
+			switch ((int) gametype)
+			{
+			case (int) GameType.Discount:
+				int price, discount, paid;
+
+				discount = 10 + random.Next (30);
+				price = 100 + random.Next (100);
+				paid = price - (price * discount / 100);
+			
+				question = String.Format (
+					Catalog.GetString ("After getting {0}% discount you have paid {1} monetary units for a TV set. What was the original price of the TV set?"),
+					discount, paid);
+				ans = price;
+				break;
+			case (int) GameType.Sales:
+				int sales, increase, previous;
+
+				previous = 10 + random.Next (90);
+				increase = 10 + random.Next (20);
+				sales = previous + (previous * increase / 100);
+			
+				question = String.Format (
+					Catalog.GetString ("John's shop had sales of {0} monetary units. This was an increase of {1}% over last month. What were last month sales?"),
+					sales, increase);
+				ans = previous;
+				break;
+			case (int) GameType.Water:
+				double decrease, percentage;
+
+				do
+				{
+					decrease = (1 + random.Next (70));
+					percentage = decrease / (100 - decrease) * 100;
+
+				} while (percentage != Math.Truncate (percentage));
+			
+				question = String.Format (
+					Catalog.GetString ("The amount of water in a bucket decreases by {0}%. By what percentage must the amount of water increase to reach its original value?"),
+					decrease);
+
+				answer = Catalog.GetString ("The objective is to obtain the same total amount");
+				ans = (int) percentage;
+				break;
+			default:
+				throw new Exception ("Unexpected value");
+			}
+
+			right_answer = (ans).ToString ();
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			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/PuzzleQuadrilaterals.cs b/src/Games/Logic/PuzzleQuadrilaterals.cs
new file mode 100644
index 0000000..eceab38
--- /dev/null
+++ b/src/Games/Logic/PuzzleQuadrilaterals.cs
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2008 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleQuadrilaterals : Game
+	{
+		enum Figures
+		{
+			FigureA,
+			FigureB,
+			FigureC,
+			FigureD,
+			FigureE,
+			FigureF,
+			Last
+		};
+
+		private ArrayListIndicesRandom random_indices;
+		private const double figure_size = 0.15;
+
+		public override string Name {
+			get {return Catalog.GetString ("Quadrilaterals");}
+		}
+
+		public override string Question {
+			get {return String.Format (
+				Catalog.GetString ("Which of the following figures does not belong to the group? Answer {0}, {1}, {2}, {3}, {4} or {5}."),
+					GetPossibleAnswer (0), GetPossibleAnswer (1), GetPossibleAnswer (2), GetPossibleAnswer (3), GetPossibleAnswer (4), 
+					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 void Initialize ()
+		{
+			random_indices = new ArrayListIndicesRandom ((int) Figures.Last);
+			random_indices.Initialize ();
+
+			for (int i = 0; i < (int) Figures.Last; i++)
+			{
+				if ((Figures) random_indices[i] == Figures.FigureA) {
+					right_answer = GetPossibleAnswer (i);
+					break;
+				}
+			}
+		}
+
+		static void DrawFigure (CairoContextEx gr, double x, double y, Figures figure)
+		{
+			switch (figure) {
+			case Figures.FigureA:
+				double x105, y105;
+
+				x105 = figure_size * Math.Cos (105 * Math.PI / 180);
+				y105 = figure_size * Math.Sin (105 * Math.PI / 180);
+				gr.MoveTo (x, y);
+				gr.LineTo (x + x105, y + y105);
+				gr.LineTo (x + x105 + figure_size, y + y105);
+				gr.Stroke ();
+				gr.MoveTo (x + figure_size, y);
+				gr.LineTo (x + figure_size + x105, y + y105);
+				gr.Stroke ();
+				gr.MoveTo (x, y);
+				gr.LineTo (x + figure_size, y);
+				break;
+
+			case Figures.FigureB:
+				gr.Rectangle (x, y, figure_size * 0.8, figure_size * 1.2);
+				break;
+
+			case Figures.FigureC:
+				gr.MoveTo (x, y);
+				gr.LineTo (x + figure_size * 1.3, y);
+				gr.LineTo (x + figure_size * 1.3, y + figure_size);
+				gr.LineTo (x , y + figure_size);
+				gr.LineTo (x, y);
+				break;
+
+			case Figures.FigureD:
+				gr.MoveTo (x + 0.03, y);
+				gr.LineTo (x + figure_size - 0.03, y);
+				gr.LineTo (x + figure_size, y + figure_size);
+				gr.LineTo (x , y + figure_size);
+				gr.LineTo (x + 0.03, y);
+				break;
+
+			case Figures.FigureE:
+				gr.MoveTo (x + 0.03, y);
+				gr.LineTo (x + figure_size - 0.04, y);
+				gr.LineTo (x + figure_size - 0.04, y + figure_size * 1.2);
+				gr.LineTo (x , y + figure_size  * 1.2);
+				gr.LineTo (x + 0.03, y);;
+				break;
+
+			case Figures.FigureF:
+				gr.MoveTo (x, y);
+				gr.LineTo (x, y + figure_size);
+				gr.LineTo (x + figure_size, y + figure_size);
+				gr.LineTo (x + figure_size - 0.02, y);
+				gr.LineTo (x, y);
+				break;
+			}
+
+			gr.Stroke ();
+
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double x = DrawAreaX, y = DrawAreaY, space_x = 0.15;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			for (int i = 0; i < random_indices.Count; i++) {
+				DrawFigure (gr, x, y, (Figures) random_indices[i]);
+				gr.MoveTo (x, y - 0.02 + figure_size * 1.6);
+				gr.ShowPangoText (GetPossibleFigureAnswer (i));
+
+				if (i == 2) {
+					x = DrawAreaX;
+					y += figure_size * 3;
+				} else 
+					x += figure_size + space_x;
+			}
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleSquareDots.cs b/src/Games/Logic/PuzzleSquareDots.cs
new file mode 100644
index 0000000..e8bc7fb
--- /dev/null
+++ b/src/Games/Logic/PuzzleSquareDots.cs
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleSquareDots : Game
+	{
+		private const double figure_size = 0.25; 
+		private const int lines = 6;
+		private const int columns = 6;
+		private const int figures = 6;
+		private static bool X = true;
+		private static bool O = false;
+		private const double space_figures = 0.05;
+		private ArrayListIndicesRandom possible_answers;
+
+		private bool [] puzzle_A  = new bool []
+		{
+			// Figure A
+			O, O, O, O, O, O,
+			O, O, O, O, O, O, 	
+			O, O, X, X, O, O,	// Down, Diagonal down left
+			O, O, X, X, O, O,	// Up, Diagonal up left
+			O, O, O, O, O, O,
+			O, O, O, O, O, O,
+		
+			// Figure B
+			O, O, O, O, O, O,
+			O, O, O, O, O, O,
+			O, O, X, O, O, O,
+			O, O, X, O, O, O,
+			O, O, O, O, O, O,
+			O, O, O, O, O, O,
+
+			// Figure C
+			O, O, O, O, O, O,
+			O, X, X, O, O, O,
+			O, O, O, O, O, O,
+			O, O, O, O, O, O,
+			O, X, X, O, O, O,
+			O, O, O, O, O, O,
+
+			// Wrong answer 1
+			O, X, X, O, O, O,
+			O, O, O, O, O, O,
+			O, O, O, O, O, O,
+			O, O, O, O, O, O,
+			O, O, O, O, O, O,
+			O, X, X, O, O, O,
+
+			// Correct Answer
+			X, O, X, O, O, O,
+			O, O, O, O, O, O,
+			O, O, O, O, O, O,
+			O, O, O, O, O, O,
+			O, O, O, O, O, O,
+			X, O, X, O, O, O,
+
+			// Wrong answer 2
+			O, O, O, O, O, O,
+			O, X, X, O, O, O,
+			O, O, O, O, O, O,
+			O, O, O, O, O, O,
+			O, O, O, O, O, O,
+			O, X, X, O, O, O,
+		};
+
+		public override string Name {
+			get {return Catalog.GetString ("Square with dots");}
+		}
+
+		public override string Question {
+			get {return (String.Format (
+				Catalog.GetString ("What is the letter of the figure that represents the next logical figure in the sequence? Answer {0}, {1} or {2}."),
+				GetPossibleAnswer (0), GetPossibleAnswer (1), GetPossibleAnswer (2)));} 
+		}
+
+		public override void Initialize ()
+		{
+			possible_answers = new ArrayListIndicesRandom (3);
+			possible_answers.Initialize ();
+
+			for (int i = 0; i < possible_answers.Count; i++) {
+				if (possible_answers[i] == 0) {
+					right_answer = GetPossibleAnswer (i);
+					break;
+				}
+			}
+		}
+
+		public void DrawFigure (CairoContextEx gr, double x, double y, bool [] puzzle, int index)
+		{
+			double pos_x = x, pos_y = y;
+			double square_size = figure_size / lines;
+			double center_square = square_size / 2;
+			double radius_square = (square_size - (LineWidth *2)) / 2;
+
+			gr.Rectangle (pos_x, pos_y, figure_size, figure_size);
+			gr.Stroke ();
+
+			for (int line = 0; line < lines - 1; line++) // Horizontal
+			{
+				pos_y += square_size;
+				gr.MoveTo (pos_x, pos_y);
+				gr.LineTo (pos_x + figure_size, pos_y);
+				gr.Stroke ();
+			}
+
+			pos_y = y;
+			for (int column = 0; column < columns - 1; column++) // Vertical
+			{
+				pos_x += square_size;
+				gr.MoveTo (pos_x, pos_y);
+				gr.LineTo (pos_x, pos_y + figure_size);
+				gr.Stroke ();
+			}
+
+			pos_y = y + center_square;
+			pos_x = x + center_square;
+		
+			for (int line = 0; line < lines; line++) // Circles
+			{	
+				for (int column = 0; column < columns; column++)
+				{
+					if (puzzle[index + (columns * line) + column] == false)
+						continue;
+
+					gr.Arc (pos_x + (square_size * column), pos_y, radius_square, 0, 2 * Math.PI);
+					gr.Stroke ();
+				}
+				pos_y += square_size;
+			}
+		}
+
+		public void DrawPossibleAnswer (CairoContextEx gr, double x, double y, int figure)
+		{
+			switch (figure) {
+			case 0: // Good answer
+				DrawFigure (gr, x, y, puzzle_A, columns * lines * 4);
+				break;
+			case 1:
+				DrawFigure (gr, x, y, puzzle_A,  columns * lines * 3);
+				break;
+			case 2:
+				DrawFigure (gr, x, y, puzzle_A, columns * lines * 5);
+				break;
+			}
+		}
+	
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double x = DrawAreaX, y = DrawAreaY;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			DrawFigure (gr, x, y, puzzle_A, 0);
+			DrawFigure (gr, x + figure_size + space_figures, y, puzzle_A, columns * lines);
+			DrawFigure (gr, x + (figure_size + space_figures) * 2, y, puzzle_A, columns * lines * 2);
+	
+			y += figure_size + 0.10;
+			gr.MoveTo (x, y - 0.02);
+			gr.ShowPangoText (Catalog.GetString ("Possible answers are:"));
+			gr.Stroke ();
+			y += 0.05;
+
+			for (int i = 0; i < possible_answers.Count; i++) {
+				DrawPossibleAnswer (gr, x, y, possible_answers[i]);
+				gr.MoveTo (x, y + figure_size + 0.05);
+				gr.ShowPangoText (GetPossibleFigureAnswer (i));
+				gr.Stroke ();
+				x+= figure_size + space_figures;
+			}
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleSquareSheets.cs b/src/Games/Logic/PuzzleSquareSheets.cs
new file mode 100644
index 0000000..b204653
--- /dev/null
+++ b/src/Games/Logic/PuzzleSquareSheets.cs
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using Mono.Unix;
+using System;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleSquareSheets : Game
+	{
+		public override string Name {
+			get {return Catalog.GetString ("Squares sheets");}
+		}
+
+		public override string Question {
+			get {return Catalog.GetString ("What is the minimum number of square sheets of paper of any size required to create the figure? Lines indicate frontiers between different sheets.");} 
+		}
+
+		public override string Tip {
+			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 void Initialize ()
+		{
+			right_answer = "5";
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double x = DrawAreaX + 0.2, y = DrawAreaY + 0.2, width = 0.4, height = 0.4;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			gr.Rectangle (x, y, width, height);
+			gr.Stroke ();
+		
+			gr.MoveTo (x, y + 0.1);
+			gr.LineTo (x + width, y + 0.1);  // First horizontal
+			gr.Stroke ();
+
+			gr.MoveTo (x, y + 0.3);
+			gr.LineTo (x + width - 0.1, y + 0.3); // Second horizontal
+			gr.Stroke ();
+
+			gr.MoveTo (x + 0.1, y);
+			gr.LineTo (x + 0.1, y + height);  // First vertical
+			gr.Stroke ();
+
+			gr.MoveTo (x + 0.3, y);
+			gr.LineTo (x + 0.3, y + height - 0.1);  // Second vertical
+			gr.Stroke ();
+
+			if (DrawAnswer == false)
+				return;
+
+			gr.LineTo (x + 0.04, y + 0.06);
+			gr.ShowPangoText ("1");
+
+			gr.LineTo (x + 0.18, y + 0.06);
+			gr.ShowPangoText ("2");
+
+			gr.LineTo (x + 0.34, y + 0.06);
+			gr.ShowPangoText ("3");
+		
+			gr.LineTo (x + 0.04, y + 0.2);
+			gr.ShowPangoText ("2");
+
+			gr.LineTo (x + 0.18, y + 0.2);
+			gr.ShowPangoText ("4");
+
+			gr.LineTo (x + 0.34, y + 0.2);
+			gr.ShowPangoText ("5");
+
+			gr.LineTo (x + 0.04, y + 0.36);
+			gr.ShowPangoText ("3");
+
+		}
+	}
+}
+
+
diff --git a/src/Games/Logic/PuzzleSquares.cs b/src/Games/Logic/PuzzleSquares.cs
new file mode 100644
index 0000000..34e61c6
--- /dev/null
+++ b/src/Games/Logic/PuzzleSquares.cs
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleSquares : Game
+	{
+		private double rows, columns;
+		private int type;
+
+		public override string Name {
+			get {return Catalog.GetString ("Squares");}
+		}
+
+		public override string Question {
+			get {return Catalog.GetString ("How many squares of any size do you count in the figure below?");} 
+		}
+
+		public override string Tip {
+			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 + " ";
+
+				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;
+				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 answer;
+			}
+		}
+
+		public override void Initialize ()
+		{
+			if (CurrentDifficulty==Difficulty.Easy)
+				type = 0;
+			else
+				type = random.Next (2);
+
+			rows = 3;
+			columns = 3;		
+
+			if (type == 0) {
+				rows++;
+				columns++;
+				right_answer = "30";
+			} else {
+				right_answer = "14";
+			}
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double rect_w = DrawAreaWidth / rows;
+			double rect_h = DrawAreaHeight / columns;
+
+			base.Draw (gr, area_width, area_height, rtl);
+
+			for (int column = 0; column < columns; column++) {
+				for (int row = 0; row < rows; row++) {
+					gr.Rectangle (DrawAreaX + row * rect_w, DrawAreaY + column * rect_h, rect_w, rect_h);
+				}
+			}
+
+			gr.Stroke ();
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleSquaresAndLetters.cs b/src/Games/Logic/PuzzleSquaresAndLetters.cs
new file mode 100644
index 0000000..6fec6bb
--- /dev/null
+++ b/src/Games/Logic/PuzzleSquaresAndLetters.cs
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleSquaresAndLetters : Game
+	{
+		private char[] characters;
+		private int step;
+		private const double figure_size = 0.2;
+		private const int figures = 3;
+
+		public override string Name {
+			get {return Catalog.GetString ("Squares and letters");}
+		}
+
+		public override string Question {
+			get {return Catalog.GetString ("The letters around the squares follow a logic. 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 void Initialize ()
+		{
+			int first_letter;
+			ArrayListIndicesRandom first_letters;
+
+			first_letters = new ArrayListIndicesRandom (figures); // Make sure that the first letter is never the same
+			first_letters.Initialize ();
+			step = random.Next (3) + 3;
+
+			characters = new char [(1 + figures) * 4]; 
+			for (int figure = 0; figure < figures; figure++) {
+				first_letter = first_letters [figure];
+				for (int letter = 0; letter < 4; letter++) {
+					characters[(figure * 4) + letter] = (char) (65 + first_letter + (step * letter));
+				}				
+			}
+
+			right_answer = ToStr (characters[((figures - 1) * 4) + 3]);
+			characters[((figures - 1) * 4) + 3] = '?';
+		}
+
+		static string ToStr (char ch)
+		{
+			string s = string.Empty;
+			s+= ch;
+			return s;
+		}
+
+		private void DrawRectangleWithText (CairoContextEx gr, double x, double y, int index)
+		{
+			gr.Rectangle (x, y, figure_size, figure_size);
+
+			gr.MoveTo (x - 0.04, y);
+			gr.ShowPangoText (ToStr (characters [index]));
+			gr.Stroke ();
+
+			gr.MoveTo (x + 0.01 + figure_size, y);
+			gr.ShowPangoText (ToStr (characters [index + 1]));
+			gr.Stroke ();
+
+			gr.MoveTo (x - 0.04, y + figure_size);
+			gr.ShowPangoText (ToStr (characters [index + 2]));
+			gr.Stroke ();
+
+			gr.MoveTo (x + 0.01 + figure_size, y + figure_size);
+			gr.ShowPangoText (ToStr (characters [index + 3]));
+			gr.Stroke ();
+		}
+
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double x = DrawAreaX + 0.05, y = DrawAreaY + 0.1;
+
+			base.Draw (gr, area_width, area_height, rtl);
+		
+			DrawRectangleWithText (gr, x, y, 0);
+			DrawRectangleWithText (gr, x + figure_size + 0.2, y, 4);
+			DrawRectangleWithText (gr, x + figure_size + 0.05, y + 0.2 + figure_size, 8);
+			
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleTetris.cs b/src/Games/Logic/PuzzleTetris.cs
new file mode 100644
index 0000000..fcf096c
--- /dev/null
+++ b/src/Games/Logic/PuzzleTetris.cs
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using Mono.Unix;
+using System;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleTetris : Game
+	{
+		private ArrayListIndicesRandom random_indices_questions;
+		private ArrayListIndicesRandom random_indices_answers;
+		private const double rect_witdh = 0.04, rect_height = 0.04, space_figures = 0.22;
+
+		public override string Name {
+			get {return Catalog.GetString ("Tetris");}
+		}
+
+		public override string Question {
+			get {return String.Format (
+				Catalog.GetString ("What figure completes the sequence below? Answer {0}, {1} or {2}."),
+				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 void Initialize ()
+		{
+			random_indices_questions = new ArrayListIndicesRandom (4);
+			random_indices_questions.Initialize ();
+
+			random_indices_answers = new ArrayListIndicesRandom (3);
+			random_indices_answers.Initialize ();
+
+			for (int i = 0; i < random_indices_answers.Count; i++) {
+				if ((int) random_indices_answers [i] == 0) {
+					right_answer = GetPossibleAnswer (i);
+					break;
+				}
+			}
+		}
+
+		private static void DrawQuestionFigures (CairoContextEx gr, double x, double y, int figure)
+		{
+			switch (figure) {
+			case 0:
+				// XX
+				// XX
+				for (int i = 0; i < 2; i++) {
+					gr.Rectangle (x + i * rect_witdh, y, rect_witdh, rect_height);
+					gr.Rectangle (x + i * rect_witdh, y - rect_height, rect_witdh, rect_height);
+				}
+				gr.Stroke ();
+				break;
+			case 1:
+				//  X
+				// XXX
+				for (int i = 0; i < 3; i++) {
+					gr.Rectangle (x + i * rect_witdh, y, rect_witdh, rect_height);
+				}
+				gr.Rectangle (x + 1 * rect_witdh, y - rect_height, rect_witdh, rect_height);
+				gr.Stroke ();
+				break;
+			case 2:
+				//   X
+				// XXX
+				for (int i = 0; i < 3; i++) {
+					gr.Rectangle (x + i * rect_witdh, y, rect_witdh, rect_height);
+				}
+				gr.Rectangle (x + 2 * rect_witdh, y - rect_height, rect_witdh, rect_height);
+				gr.Stroke ();
+				break;
+			case 3:
+				// XXXX
+				for (int i = 0; i < 4; i++) {
+					gr.Rectangle (x + i * rect_witdh, y, rect_witdh, rect_height);
+				}
+				gr.Stroke ();
+				break;
+			}
+		}
+
+		private static void DrawAnswerFigures (CairoContextEx gr, double x, double y, int figure)
+		{
+			switch (figure) {
+			case 0:
+				//  XX
+				// XX
+				for (int i = 0; i < 2; i++) {
+					gr.Rectangle (x + i * rect_witdh, y, rect_witdh, rect_height);
+					gr.Rectangle (x + rect_witdh + i * rect_witdh, y -  rect_height, rect_witdh, rect_height);
+				}
+				break;
+			case 1:
+				// X
+				// X
+				// X
+				// X
+				for (int i = 0; i < 4; i++) {
+					gr.Rectangle (x, y -  rect_height * i, rect_witdh, rect_height);
+				}
+				break;
+			case 2:
+				// XXX
+				//  X
+				for (int i = 0; i < 3; i++) {
+					gr.Rectangle (x + i * rect_witdh, y - rect_height, rect_witdh, rect_height);
+				}
+				gr.Rectangle (x + rect_witdh, y, rect_witdh, rect_height);
+				break;
+			}
+			gr.Stroke ();
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double x = DrawAreaX, y = DrawAreaY + 0.1;
+
+			base.Draw (gr, area_width, area_height, rtl);
+		
+			for (int i = 0; i < 4; i++) {
+				DrawQuestionFigures (gr, x, y, random_indices_questions [i]);
+				x += space_figures;
+			}
+
+			gr.MoveTo (0.1, 0.4 - 0.02);
+			gr.ShowPangoText (Catalog.GetString ("Possible answers are:"));
+
+			x = 0.2;
+			y = 0.6;
+			for (int i = 0; i < 3; i++) {
+				DrawAnswerFigures (gr, x, y, random_indices_answers [i]);
+				gr.MoveTo (x, y + 0.13);
+				gr.ShowPangoText (GetPossibleFigureAnswer (i));
+				x += space_figures;
+			}
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleTimeNow.cs b/src/Games/Logic/PuzzleTimeNow.cs
new file mode 100644
index 0000000..d0e7802
--- /dev/null
+++ b/src/Games/Logic/PuzzleTimeNow.cs
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2009 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 Cairo;
+using Mono.Unix;
+using System;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleTimeNow : Game
+	{
+		const double figure_size = 0.3;
+		int after, position_a, position_b, ans;
+
+		public override string Name {
+			get {return Catalog.GetString ("Time now");}
+		}
+
+		public override string Question {
+			get {return (String.Format (
+				// Translators: {1} and {2} are replaced by hours
+				Catalog.GetString ("{0} hours ago it was as long after {1} as it was before {2} on the same day. What is the time now?"),
+				after, position_a, position_b));}
+		}
+
+		public override void Initialize ()
+		{
+			after = 4 + random.Next (3);
+			position_a = 2 + random.Next (3);
+			position_b = position_a + 6;
+
+			ans = after + position_b;
+
+			if (ans > 12)
+				ans = ans - 12;  
+
+			right_answer = ans.ToString ();
+		}	
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			base.Draw (gr, area_width, area_height, rtl);
+			gr.DrawClock (DrawAreaX + 0.4, DrawAreaY + 0.4, figure_size, 
+				0, 0 /* No hands */);
+
+			gr.MoveTo (DrawAreaX + 0.3, DrawAreaY + 0.3 + figure_size);
+			gr.ShowPangoText (Catalog.GetString ("Sample clock"));
+			gr.Stroke ();
+
+		}
+	}
+}
diff --git a/src/Games/Logic/PuzzleTriangles.cs b/src/Games/Logic/PuzzleTriangles.cs
new file mode 100644
index 0000000..a28364b
--- /dev/null
+++ b/src/Games/Logic/PuzzleTriangles.cs
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleTriangles : Game
+	{
+		int type;
+		public override string Name {
+			get {return Catalog.GetString ("Triangles");}
+		}
+
+		public override string Question {
+			get {return Catalog.GetString ("How many triangles of any size do you count in the figure below?");} 
+		}
+
+		public override string Tip {
+			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}"),
+					(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;
+			}
+		}
+
+		public override void Initialize ()
+		{
+			if (CurrentDifficulty==Difficulty.Easy)
+				type = 1;
+			else
+				type = random.Next (2);
+
+			if (type == 0)	
+				right_answer = "16";
+			else
+				right_answer = "8";
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double x = DrawAreaX + 0.1, y = DrawAreaY + 0.2;
+			const double witdh = 0.6, height = 0.5;
+
+			base.Draw (gr, area_width, area_height, rtl);
+		
+			gr.MoveTo (x, y);
+			gr.LineTo (x + witdh, y);		
+			gr.LineTo (x + witdh / 2, y + height / 2);
+			gr.LineTo (x, y);
+			gr.LineTo (x + 0.45, y + height /4);
+			gr.Stroke ();
+	
+			if (type == 0) {
+				gr.MoveTo (x + witdh / 2, y);
+				gr.LineTo (x + witdh / 2, y + height / 2);
+				gr.Stroke ();
+			}
+
+			gr.MoveTo (x + 0.152, y + 0.125);
+			gr.LineTo (x + witdh, y);
+			gr.Stroke ();
+
+			if (DrawAnswer == false)
+				return;
+
+			// References
+			gr.MoveTo (x - 0.02, y);
+			gr.ShowPangoText ("a");
+
+			gr.MoveTo (x + witdh /2  - 0.02, y);
+			gr.ShowPangoText ("b");
+
+			gr.MoveTo (x + witdh, y);
+			gr.ShowPangoText ("c");
+
+			gr.MoveTo (x + witdh /2  - 0.03, y + 0.07 - 0.02);
+			gr.ShowPangoText ("d");
+
+			gr.MoveTo (x + 0.11, y + 0.16);
+			gr.ShowPangoText ("e");
+
+			gr.MoveTo (x + 0.47, y + 0.16);
+			gr.ShowPangoText ("f");
+
+			gr.MoveTo (x + (witdh /2) - 0.01, y + 0.26);
+			gr.ShowPangoText ("g");
+
+		}
+	}
+}
+
+
diff --git a/src/Games/Logic/PuzzleTrianglesWithNumbers.cs b/src/Games/Logic/PuzzleTrianglesWithNumbers.cs
new file mode 100644
index 0000000..2863297
--- /dev/null
+++ b/src/Games/Logic/PuzzleTrianglesWithNumbers.cs
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2007 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Logic
+{
+	public class PuzzleTrianglesWithNumbers : Game
+	{
+		private const double figure_size = 0.2;
+		private const int elements_group = 12;
+		private int group;
+		private string answer_number;
+		private int [] numbers = new int []
+		{
+			15, 14,	// 210
+			35, 6,
+			70, 3,
+			42, 5,
+			7, 30,
+			21, 10,		
+		
+			8, 20,	// 160
+			5, 32,
+			40, 4,
+			2, 80,
+			10, 16,
+			1, 160,
+
+			6, 20,  // 120
+			40, 3,
+			4, 30,
+			15, 8,
+			24, 5,
+			2, 60,
+		};
+
+		public override string Name {
+			get {return Catalog.GetString ("Triangles with numbers");}
+		}
+
+		public override string Question {
+			get {return Catalog.GetString ("Which number should replace the question mark below?");} 
+		}
+
+
+		public override string Tip {
+			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 void Initialize ()
+		{
+			group = random.Next (3);
+			switch (group) {
+			case 0:
+				right_answer = "10";
+				answer_number = "210";
+				break;
+			case 1:
+				right_answer = "160";
+				answer_number = "160";
+				break;
+			case 2:
+				right_answer = "60";
+				answer_number = "120";
+				break;
+			}
+		}
+
+
+		private void DrawTriangle (CairoContextEx gr, double x, double y, int index, bool question)
+		{
+			gr.MoveTo (x + figure_size / 2, y);
+			gr.LineTo (x, y + figure_size);
+			gr.LineTo (x + figure_size, y + figure_size);
+			gr.LineTo (x + figure_size / 2, y);
+			gr.LineTo (x + figure_size / 2, y + figure_size);
+			gr.Stroke ();
+
+			gr.MoveTo (x + 0.04, y + 0.15);
+			gr.ShowPangoText (numbers [(elements_group * group) + index * 2].ToString ());	
+			gr.MoveTo (x + 0.12, y + 0.15);
+
+			if (question == true)
+				gr.ShowPangoText ("?");	
+			else
+				gr.ShowPangoText (numbers [(elements_group * group) + (index * 2) + 1].ToString ());	
+		}
+
+		public override void Draw (CairoContextEx gr, int area_width, int area_height, bool rtl)
+		{
+			double x = DrawAreaX, y = DrawAreaY + 0.1;
+
+			base.Draw (gr, area_width, area_height, rtl);
+		
+			DrawTriangle (gr, x, y, 0, false);
+			x += 0.3;
+			DrawTriangle (gr, x, y, 1, false);
+			x += 0.3;
+			DrawTriangle (gr, x, y, 2, false);
+
+			y += 0.3;
+			x = DrawAreaX;	
+			DrawTriangle (gr, x, y, 3, false);
+			x += 0.3;
+			DrawTriangle (gr, x, y, 4, false);
+			x += 0.3;
+			DrawTriangle (gr, x, y, 5, true);
+		}
+	}
+}
diff --git a/src/Games/Makefile.am b/src/Games/Makefile.am
new file mode 100644
index 0000000..d2ff965
--- /dev/null
+++ b/src/Games/Makefile.am
@@ -0,0 +1,98 @@
+CSFLAGS = -target:library 
+
+TARGET = ../gbrainy.Games.dll
+
+CSFILES =  \
+		GameList.cs					\
+		Logic/Puzzle3DCube.cs				\
+		Logic/PuzzleBalance.cs				\
+		Logic/PuzzleBuildTriangle.cs			\
+		Logic/PuzzleCirclesRectangle.cs			\
+		Logic/PuzzleClocks.cs				\
+		Logic/PuzzleCountCircles.cs			\
+		Logic/PuzzleCounting.cs				\
+		Logic/PuzzleCountSeries.cs			\
+		Logic/PuzzleCoverPercentage.cs			\
+		Logic/PuzzleCube.cs				\
+		Logic/PuzzleDivideCircle.cs			\
+		Logic/PuzzleEquation.cs				\
+		Logic/PuzzleExtraCircle.cs			\
+		Logic/PuzzleFigureLetter.cs			\
+		Logic/PuzzleFigurePattern.cs			\
+		Logic/PuzzleFigures.cs				\
+		Logic/PuzzleFourSided.cs			\
+		Logic/PuzzleHandshakes.cs			\
+		Logic/PuzzleLargerShape.cs			\
+		Logic/PuzzleLines.cs				\
+		Logic/PuzzleMatrixGroups.cs			\
+		Logic/PuzzleMatrixNumbers.cs			\
+		Logic/PuzzleMissingPiece.cs			\
+		Logic/PuzzleMissingSlice.cs			\
+		Logic/PuzzleMostInCommon.cs			\
+		Logic/PuzzleMoveFigure.cs			\
+		Logic/PuzzleNextFigure.cs			\
+		Logic/PuzzleNumericRelation.cs			\
+		Logic/PuzzleNumericSequence.cs			\
+		Logic/PuzzleOstracism.cs			\
+		Logic/PuzzlePencil.cs				\
+		Logic/PuzzlePeopleTable.cs			\
+		Logic/PuzzlePercentage.cs			\
+		Logic/PuzzleQuadrilaterals.cs			\
+		Logic/PuzzleSquareDots.cs			\
+		Logic/PuzzleSquaresAndLetters.cs		\
+		Logic/PuzzleSquares.cs				\
+		Logic/PuzzleSquareSheets.cs			\
+		Logic/PuzzleTetris.cs				\
+		Logic/PuzzleTimeNow.cs				\
+		Logic/PuzzleTriangles.cs			\
+		Logic/PuzzleTrianglesWithNumbers.cs		\
+		Memory/MemoryColouredFigures.cs			\
+		Memory/MemoryColouredText.cs			\
+		Memory/MemoryCountDots.cs			\
+		Memory/MemoryFacts.cs				\
+		Memory/MemoryFigures.cs				\
+		Memory/MemoryFiguresNumbers.cs			\
+		Memory/MemoryIndications.cs			\
+		Memory/MemoryNumbers.cs				\
+		Memory/MemoryWords.cs				\
+		Calculation/CalculationArithmetical.cs		\
+		Calculation/CalculationAverage.cs		\
+		Calculation/CalculationCloserFraction.cs 	\
+		Calculation/CalculationFractions.cs		\
+		Calculation/CalculationGreatestDivisor.cs 	\
+		Calculation/CalculationOperator.cs		\
+		Calculation/CalculationPrimes.cs		\
+		Calculation/CalculationProportions.cs		\
+		Calculation/CalculationRatio.cs			\
+		Calculation/CalculationTwoNumbers.cs
+
+RES = 
+REFS =  \
+	-r:System \
+	-r:Mono.Cairo.dll		\
+	-r:Mono.Posix			\
+	-r:.././gbrainy.Core.dll
+
+SRCDIR_CSFILES = $(CSFILES:%=$(srcdir)/%)
+RES_CSFLAGS = $(foreach res, $(RES), -resource:$(res))
+
+$(TARGET): $(SRCDIR_CSFILES) $(RES)
+	echo $(RES_FILES)
+	$(CSC) -out:$@ $(CSFLAGS) $(REFS) $(RES_CSFLAGS) $(SRCDIR_CSFILES)
+
+all: $(TARGET)
+
+install-data-local: $(TARGET)
+	$(mkinstalldirs) $(DESTDIR)$(pkglibdir)
+	$(INSTALL_DATA) $(TARGET) $(DESTDIR)$(pkglibdir)
+
+uninstall-local:
+	cd $(DESTDIR)$(pkglibdir) && rm -f gbrainy.Games.dll
+
+EXTRA_DIST = 			\
+	$(CSFILES) $(RES)
+
+CLEANFILES =			\
+	$(TARGET)		\
+	$(TARGET).mdb
+
diff --git a/src/Games/Memory/MemoryColouredFigures.cs b/src/Games/Memory/MemoryColouredFigures.cs
new file mode 100644
index 0000000..bc73c8c
--- /dev/null
+++ b/src/Games/Memory/MemoryColouredFigures.cs
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2007-2008 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Memory
+{
+	public class MemoryColouredFigures : Core.Main.Memory
+	{
+		enum SquareColor
+		{
+			Color1 = 0,
+			Color2,
+			Color3,
+			Length
+		}
+
+		private int columns, rows;
+		private int squares;
+		private double rect_w;
+		private double rect_h;
+		private SquareColor []squares_colours;
+		private ArrayListIndicesRandom answers_order;
+		private const int answers = 4;
+		private ColorPalette palette;
+		private int color_sheme;
+		private const double block_space = 0.35;
+
+		public override string Name {
+			get {return Catalog.GetString ("Colored figures");}
+		}
+
+		public override string MemoryQuestion {
+			get { return String.Format (
+				Catalog.GetString ("Which of these figures was previously shown? Answer {0}, {1}, {2} or {3}."),
+				GetPossibleAnswer (0), GetPossibleAnswer (1), GetPossibleAnswer (2), GetPossibleAnswer (3));}
+		}
+
+		public override void Initialize ()
+		{
+			switch (CurrentDifficulty) {
+			case Difficulty.Easy:
+				columns = rows = 5;
+				break;
+			case Difficulty.Medium:
+				columns = rows = 6;
+				break;
+			case Difficulty.Master:
+				columns = rows = 7;
+				break;
+			}
+
+			squares = columns * rows;
+			rect_w = 0.3 / rows;
+			rect_h = 0.3 / columns;
+			squares_colours = new SquareColor [squares * answers];
+			color_sheme = random.Next (2);
+			palette = new ColorPalette(ColorPalette.Id.PrimarySecundaryColors);
+			palette.Initialize();
+
+			for (int i = 0; i < squares; i++)	
+				squares_colours[i] = (SquareColor) random.Next ((int) SquareColor.Length);
+		
+			Randomize (squares_colours, 0, squares);
+			Randomize (squares_colours, 0, squares * 2);
+			Randomize (squares_colours, 0, squares * 3);
+
+			answers_order = new ArrayListIndicesRandom (answers);
+			answers_order.Initialize ();
+
+			for (int i = 0; i < answers_order.Count; i++) {
+				if (answers_order[i] == 0) {
+					right_answer += GetPossibleAnswer (i);
+					break;
+				}
+			}
+
+			base.Initialize ();
+		}
+
+		private void Randomize (SquareColor []colours, int source, int target)
+		{	
+			int elements = 4 + random.Next (2);
+			bool done = false;
+
+			while (done == false) {
+				for (int i = 0; i < squares; i++) {
+					colours[i + target] = colours[i + source];
+				}
+
+				for (int i = 0; i < elements; i++) {
+					colours[target + random.Next (squares)] = (SquareColor) random.Next ((int) SquareColor.Length);
+				}
+
+				// Is not valid if it is already present
+				bool equals = true;
+				for (int answer = 0; answer < answers; answer++) {
+					if (answer * squares == target)
+						continue;
+
+					equals = true;
+					for (int i = 0; i < squares; i++) {
+						if (colours[i + target] != colours[i + (answer * squares)]) {
+							equals = false;
+							break;
+						}
+					}
+
+					if (equals == true)
+						break;
+				}
+
+				if (equals == false)
+					done = true;
+			}
+		}
+
+		public override void DrawPossibleAnswers (CairoContextEx gr, int area_width, int area_height)
+		{
+			double x = DrawAreaX, y = DrawAreaY;
+	
+			palette.Alpha = alpha;
+		
+			for (int i = 0; i < answers_order.Count; i++) {
+				if (i == 2) {
+					y += 0.45;
+					x = DrawAreaX;
+				}
+				DrawSquare (gr, x, y, squares_colours, squares * answers_order[i]);
+				gr.MoveTo (x, y + block_space - 0.02);
+				gr.ShowPangoText (GetPossibleFigureAnswer (i));
+				gr.Stroke ();
+				x += block_space + 0.08;
+			}
+		}
+
+		public override void DrawObjectToMemorize (CairoContextEx gr, int area_width, int area_height)
+		{
+			base.DrawObjectToMemorize (gr, area_width, area_height);
+			palette.Alpha = alpha; 
+			DrawSquare (gr, DrawAreaX + 0.3, DrawAreaY + 0.1, squares_colours, 0);
+		}
+
+		private void DrawSquare (CairoContextEx gr, double x, double y, SquareColor []colours, int index)
+		{
+			gr.Save ();
+			for (int column = 0; column < columns; column++) {
+				for (int row = 0; row < rows; row++) {
+
+					// if you want 2 schemes (primary or secundary colors)
+					Color c = palette.Cairo(ColorPalette.Id.First+ color_sheme*3 + (int)colours[index+(columns * row) + column]);
+					gr.Rectangle (x + row * rect_w, y + column * rect_h, rect_w, rect_h);
+					gr.FillGradient (x + row * rect_w, y + column * rect_h, rect_w, rect_h, c);
+				}
+			}
+			gr.Restore ();
+			for (int column = 0; column < columns; column++) {
+				for (int row = 0; row < rows; row++) {
+					gr.Rectangle (x + row * rect_w, y + column * rect_h, rect_w, rect_h);
+					gr.Stroke ();			
+				}
+			}
+		}
+	}
+}
diff --git a/src/Games/Memory/MemoryColouredText.cs b/src/Games/Memory/MemoryColouredText.cs
new file mode 100644
index 0000000..1212993
--- /dev/null
+++ b/src/Games/Memory/MemoryColouredText.cs
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2007 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 Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Memory
+{
+	public class MemoryColouredText : Core.Main.Memory
+	{
+		private ColorPalette palette;
+		private int question;
+		private string question_colorname;
+		private int colors_shown;
+
+		public override string Name {
+			get {return Catalog.GetString ("Colored text");}
+		}
+
+		public override string MemoryQuestion {
+			get { 
+				return String.Format (Catalog.GetString ("What was the color of the text that said '{0}'?"), question_colorname);}
+		}
+
+		public override void Initialize ()
+		{
+			switch (CurrentDifficulty) {
+			case Difficulty.Easy:
+				colors_shown = 3;
+				break;
+			case Difficulty.Medium:
+				colors_shown = 4;
+				break;
+			case Difficulty.Master:
+				colors_shown = 6;
+				break;
+			}
+
+			palette = new ColorPalette (colors_shown);
+			palette.Initialize ();
+		
+			question = random.Next (palette.Count);
+			right_answer = palette.Name (question);
+			question_colorname = palette.Name ((ColorPalette.Id) question);
+		
+			base.Initialize ();
+		}
+	
+		public override void DrawObjectToMemorize (CairoContextEx gr, int area_width, int area_height)
+		{
+			base.DrawObjectToMemorize (gr, area_width, area_height);
+			DrawObject (gr);
+		}
+
+		private void DrawObject (CairoContextEx gr)
+		{
+			palette.Alpha=alpha;
+
+			double x= DrawAreaX + 0.125, y = DrawAreaY + 0.2;
+
+			for (int i = 0; i < palette.Count ; i++)
+			{
+				gr.Color = palette.Cairo(i);
+				gr.MoveTo (x, y);
+				gr.ShowPangoText ( palette.Name((ColorPalette.Id)i) );
+				gr.Stroke ();
+			
+				if (i == 2) {
+					y += 0.2;
+					x = DrawAreaX + 0.125;
+				} else {
+					x+= 0.25;
+				}
+			}
+		}
+	}
+}
diff --git a/src/Games/Memory/MemoryCountDots.cs b/src/Games/Memory/MemoryCountDots.cs
new file mode 100644
index 0000000..ca7d809
--- /dev/null
+++ b/src/Games/Memory/MemoryCountDots.cs
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2007 Javier M Mora <javiermm gmail com>
+ *
+ * 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Memory
+{
+	public class MemoryCountDots : Core.Main.Memory
+	{
+		private const int NUMCOLUMNS = 7;
+		private const int MINDOTS = 1;
+		private const int MAXDOTS = 25;
+		private int maxdotscolor;
+
+		private ArrayListIndicesRandom location_order;
+		private ColorPalette palette;
+
+		private int [] dotsPerColor;
+
+		public override string Name {
+			get {return Catalog.GetString ("Counting dots");}
+		}
+
+		public override string MemoryQuestion {
+			get { return String.Format(Catalog.GetString ("How many {0} dots were in the previous image? Answer using numbers."),
+							palette.Name(0)); }
+		}
+
+		public override void Initialize ()
+		{
+			switch (CurrentDifficulty) {
+			case Difficulty.Easy:
+				maxdotscolor = 2;
+				break;
+			case Difficulty.Medium:
+				maxdotscolor = 5;
+				break;
+			case Difficulty.Master:
+				maxdotscolor = 8;
+				break;
+			}
+
+			location_order = new ArrayListIndicesRandom (NUMCOLUMNS*NUMCOLUMNS);
+			location_order.Initialize();
+
+			palette = new ColorPalette(ColorPalette.Id.Last);
+			palette.Initialize();
+
+			// dotsPerColor is compared with iterator of dots. (this iterator is 0 based, so I
+			// have to substract 1 to make dotsPerColor contents 0 based.
+			dotsPerColor = new int [palette.Count];
+			for (int i=0,before=-1; i< palette.Count; i++) {
+				dotsPerColor[i] = before + MINDOTS + random.Next(maxdotscolor-MINDOTS+1);
+				before = dotsPerColor[i];
+			}
+
+			right_answer = (dotsPerColor[0]+1).ToString ();
+		
+			base.Initialize ();
+		}
+
+		public override void DrawObjectToMemorize (CairoContextEx gr, int area_width, int area_height)
+		{
+			base.DrawObjectToMemorize (gr, area_width, area_height);
+			DrawObject (gr, area_width, area_height);
+		}
+
+		private void DrawObject (CairoContextEx gr, int area_width, int area_height)
+		{
+			palette.Alpha = alpha;
+			double x = DrawAreaX + 0.15, y = DrawAreaY + 0.1;
+
+			gr.Color = palette.Cairo(ColorPalette.Id.Black);
+			double pos_x = x, pos_y = y;
+			const double figure_size = 0.6;
+			const double square_size = figure_size / NUMCOLUMNS ;
+			const double center_square = square_size / 2;
+			double radius_square = .8 * (square_size - (LineWidth *2)) / 2;
+
+			gr.Rectangle (pos_x, pos_y, figure_size, figure_size);
+			gr.Stroke ();
+
+			for (int line = 0; line < NUMCOLUMNS - 1; line++) // Horizontal
+			{
+				pos_y += square_size;
+				gr.MoveTo (pos_x, pos_y);
+				gr.LineTo (pos_x + figure_size, pos_y);
+				gr.Stroke ();
+			}
+
+			pos_y = y;
+			for (int column = 0; column < NUMCOLUMNS - 1; column++) // Vertical
+			{
+				pos_x += square_size;
+				gr.MoveTo (pos_x, pos_y);
+				gr.LineTo (pos_x, pos_y + figure_size);
+				gr.Stroke ();
+			}
+
+			pos_y = y + center_square;
+			pos_x = x + center_square;
+
+			for (int i = 0,itcolor=0; i < MAXDOTS && itcolor<palette.Count; i++)
+			{
+				int dx,dy;
+				Color color = palette.Cairo(itcolor);
+				dx = (location_order[i]) % NUMCOLUMNS;
+				dy = (location_order[i]) / NUMCOLUMNS;
+
+				gr.Arc (pos_x+square_size*dx, pos_y+square_size*dy,radius_square,0,2*Math.PI);
+				gr.FillGradient (pos_x+square_size*dx, pos_y+square_size*dy, radius_square, radius_square, color);
+
+				if (i==dotsPerColor[itcolor]) itcolor++;
+			}
+		}
+	}
+}
diff --git a/src/Games/Memory/MemoryFacts.cs b/src/Games/Memory/MemoryFacts.cs
new file mode 100644
index 0000000..a1f6997
--- /dev/null
+++ b/src/Games/Memory/MemoryFacts.cs
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2009 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 Cairo;
+using Mono.Unix;
+using System.Collections.Generic;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Memory
+{
+	public class MemoryFacts : Core.Main.Memory
+	{
+		const int total_questions = 4;
+		string question;
+		Fact[] facts;
+
+		struct Fact
+		{
+			public string fact;
+			public string[] questions;
+			public int[] answers;
+			public int Length;
+	
+			public void Initialize (int items)
+			{
+				questions = new string [items];
+				answers = new int [items];
+				Length = items;
+			}
+		}
+
+		public override string Name {
+			get {return Catalog.GetString ("Memorize facts");}
+		}
+
+		public override string MemoryQuestion {
+			get { return question;}
+		}
+
+		public override void Initialize ()
+		{
+			int fact_idx, quest_idx, questions;
+			ArrayListIndicesRandom indices;
+
+			switch (CurrentDifficulty) {
+			case Difficulty.Easy:
+				questions = 1;
+				break;
+			default:
+			case Difficulty.Medium:
+				questions = 2;
+				break;
+			case Difficulty.Master:
+				questions = 3;
+				break;
+			}
+
+			indices = new ArrayListIndicesRandom (total_questions);
+			indices.Initialize ();
+
+			facts = new Fact [questions];
+			base.Initialize ();
+
+			for (int i = 0; i < facts.Length; i++)
+				facts[i] = GetFact (indices[i]);
+
+			fact_idx = random.Next (questions);
+			quest_idx = random.Next (facts [fact_idx].Length);
+			question = facts [fact_idx].questions [quest_idx];
+			right_answer = (facts [fact_idx].answers [quest_idx]).ToString ();
+
+			// Since this particular test requires to read and understand text
+			// lets give the user twice time to be able to understand the text properly
+			TotalTime = TotalTime * 2;
+		}
+
+		Fact GetFact (int index)
+		{
+			Fact fact = new Fact ();
+
+			switch (index) {
+			case 0:
+				fact.Initialize (2);
+				fact.answers [0] = 2 + random.Next (14);
+				fact.answers [1] = 1914 + random.Next (50);
+				fact.fact = String.Format (
+					// Translators: {0} is replaced by a number, {1} by a year (like 1940)
+					Catalog.GetString ("Shiny Cars had already announced a {0} days production halt next month, but before that it had not cut production since {1}."),
+					fact.answers [0], fact.answers [1]);
+				fact.questions [0] = Catalog.GetString ("For how many days did Shiny Cars halt its production?");
+				fact.questions [1] = Catalog.GetString ("In what year did Shiny Cars last halt its production?");
+				break;
+			case 1:
+				fact.Initialize (2);
+				fact.answers [0] = 10 + random.Next (30);
+				fact.answers [1] = 1914 + random.Next (50);
+				fact.fact = String.Format (
+					// Translators: {0} is replaced by a number, {1} by a year (like 1940)
+					Catalog.GetString ("Shiny Cars sales fell {0}% this past December, the worse decline since {1}."),
+					fact.answers [0], fact.answers [1]);
+				fact.questions [0] = Catalog.GetString ("By how much did company sales fall last December?");
+				fact.questions [1] = Catalog.GetString ("In what year did Shiny Cars record a sales total lower than that of last December?");
+				break;
+			case 2:
+				fact.Initialize (1);
+				fact.answers [0] = 10 + random.Next (30);
+				fact.fact = String.Format (Catalog.GetString ("About {0}% of Shiny Cars produced worldwide are sold in Europe"),
+					fact.answers [0]);
+				fact.questions [0] = Catalog.GetString ("What percentage of all Shiny Cars produced worldwide are sold in Europe?");
+				break;
+			case 3:
+				fact.Initialize (2);
+				fact.answers [0] = 10 + random.Next (30);
+				fact.answers [1] = 100 - (1 + random.Next (10)) - fact.answers [0];
+				fact.fact = String.Format (Catalog.GetString ("About {0}% of Shiny Cars use diesel, {1}% use gasoline and the remainder use electric."),
+					fact.answers [0], fact.answers [1]);
+				fact.questions [0] = Catalog.GetString ("What percentage of Shiny Cars use diesel?");
+				fact.questions [1] = Catalog.GetString ("What percentage of Shiny Cars use gasoline?");
+				break;
+			default:
+				throw new Exception ("Invalid index value");
+			}
+
+			return fact;
+		}
+
+		public override void DrawPossibleAnswers (CairoContextEx gr, int area_width, int area_height)
+		{
+
+		}
+	
+		public override void DrawObjectToMemorize (CairoContextEx gr, int area_width, int area_height)
+		{
+			string text = string.Empty;
+
+			base.DrawObjectToMemorize (gr, area_width, area_height);
+	
+			for (int i = 0; i < facts.Length; i++)
+			{
+				text += facts[i].fact;
+				text += "\n\n";
+			}
+			gr.DrawStringWithWrapping (0.3, DrawAreaY + 0.2, text);
+		}
+
+		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/Memory/MemoryFigures.cs b/src/Games/Memory/MemoryFigures.cs
new file mode 100644
index 0000000..3313608
--- /dev/null
+++ b/src/Games/Memory/MemoryFigures.cs
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2007-2008 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Memory
+{
+	public class MemoryFigures : Core.Main.Memory
+	{
+		private ArrayListIndicesRandom figures;
+		private int rows;
+		private int columns;
+		private const double start_x_ques = 0.25;
+		private const double start_x_ans = 0.25;
+		private const double start_y = 0.15;
+		private const double figure_size = 0.08;
+		private double rect_w, rect_h;
+		private int question_pos, question_answer;
+		private int figures_active;
+
+		public enum FigureType
+		{
+			Triangle,
+			Rectangle,
+			Diamond,
+			Cercle,
+			TriangleWithLine,
+			RectangleWithLine,
+			DiamondWithLine,
+			CercleWithLine,
+		}
+
+		public override string Name {
+			get {return Catalog.GetString ("Memory figures");}
+		}
+
+		public override string MemoryQuestion {
+			get { 
+				return Catalog.GetString ("In which cell is the other figure like the one shown below? Answer the cell number." );}
+		}
+
+		public override void Initialize ()
+		{
+			int fig1, fig2;
+
+			switch (CurrentDifficulty) {
+			case Difficulty.Easy:
+				figures_active = 4;
+				rows = columns = 3;
+				break;
+			case Difficulty.Medium:
+				figures_active = 6;
+				rows = 3;
+				columns = 4;			
+				break;
+			case Difficulty.Master:
+				figures_active = 8;
+				columns = rows = 4;
+				break;
+			}
+
+			rect_w = 0.65 / columns;
+			rect_h = 0.65 / rows;
+			figures = new ArrayListIndicesRandom (figures_active * 2);
+			figures.Initialize ();
+			question_pos = random.Next (figures_active * 2);
+
+			for (int figure = 0; figure < figures_active * 2; figure++)
+			{	
+				if (figure == question_pos)
+					continue;
+	
+				fig1 = figures[figure];
+				fig2 = figures[question_pos];
+
+				if (fig1 >= figures_active) fig1 -= figures_active;
+				if (fig2 >= figures_active) fig2 -= figures_active;
+
+				if (fig1 == fig2) {
+					question_answer = figure + 1;
+					break;
+				}
+			}
+			right_answer = question_answer.ToString ();
+			base.Initialize ();
+		}
+
+		public override void DrawPossibleAnswers (CairoContextEx gr, int area_width, int area_height)
+		{
+			int col = 1, fig;
+			double x = start_x_ans, y = start_y;
+			gr.Color = new Color (DefaultDrawingColor.R, DefaultDrawingColor.G, DefaultDrawingColor.B, 1);
+
+			if (DrawAnswer ==  true) {
+				DrawAllFigures (gr, start_x_ans, start_y, area_width, area_height);
+				return;
+			}
+
+			gr.SetPangoLargeFontSize ();
+			DrawGrid (gr, x, y, area_width, area_height);
+			for (int figure = 0; figure < figures.Count; figure++, col++)
+			{
+				fig = (int)figures[figure];
+				if (fig >= figures_active) fig -= figures_active;
+
+				if (figure == question_pos)
+					DrawFigure (gr, x, y, (FigureType) fig);
+				else {
+					gr.DrawTextCentered (x + rect_w / 2, y + rect_h / 2, (figure + 1).ToString ());
+					gr.Stroke ();
+				}
+
+				if (col >= columns) {
+					col = 0;
+					y += rect_h;
+					x = start_x_ans;
+				} else {
+					x += rect_w;
+				}
+			}
+		}
+
+		public override void DrawObjectToMemorize (CairoContextEx gr, int area_width, int area_height)
+		{
+			base.DrawObjectToMemorize (gr, area_width, area_height);
+			DrawAllFigures (gr, start_x_ques, start_y, area_width, area_height);
+		}
+
+		private void DrawAllFigures (CairoContextEx gr, double x, double y, int area_width, int area_height)
+		{
+			int col = 1, fig;
+			double org_x = x;
+
+			DrawGrid (gr, x, y, area_width, area_height);
+			gr.Color = new Color (DefaultDrawingColor.R, DefaultDrawingColor.G, DefaultDrawingColor.B, alpha);
+			for (int figure = 0; figure < figures.Count; figure++, col++)
+			{
+				fig = (int)figures[figure];
+				if (fig >= figures_active) 
+					fig -= figures_active;
+
+				DrawFigure (gr, x, y, (FigureType) fig);
+
+				if (col >= columns) {
+					col = 0;
+					y += rect_h;
+					x = org_x;
+				} else {
+					x += rect_w;
+				}
+			}
+		}
+
+		private void DrawFigure (CairoContextEx gr, double x, double y, FigureType fig)
+		{
+			double space_x, space_y;
+
+			space_x = (rect_w - figure_size) / 2;
+			space_y = (rect_h - figure_size) / 2;
+
+			switch (fig) {
+			case FigureType.Triangle:
+				gr.DrawEquilateralTriangle (x + space_x, y + space_y, figure_size);
+				break;
+			case FigureType.Rectangle:
+				gr.Rectangle (x + space_x, y + space_y, figure_size, figure_size);
+				gr.Stroke ();
+				break;
+			case FigureType.Diamond:
+				gr.DrawDiamond (x + space_x, y + space_y, figure_size);
+				break;
+			case FigureType.Cercle:
+				gr.Arc (x + space_x + figure_size / 2, y + space_y + figure_size / 2, figure_size / 2, 0, 2 * Math.PI);	
+				gr.Stroke ();
+				break;
+			case FigureType.TriangleWithLine:
+				gr.DrawEquilateralTriangle (x + space_x, y + space_y, figure_size);
+				gr.MoveTo (x + space_x + figure_size / 2, y + space_y);
+				gr.LineTo (x + space_x + figure_size / 2, y + space_y + figure_size);
+				gr.Stroke ();
+				break;
+			case FigureType.RectangleWithLine:
+				gr.Rectangle (x + space_x, y + space_y, figure_size, figure_size);
+				gr.MoveTo (x + space_x, y + space_y);
+				gr.LineTo (x + space_x + figure_size, y + space_y + figure_size);
+				gr.MoveTo (x + space_x + figure_size, y + space_y);
+				gr.LineTo (x + space_x, y + space_y + figure_size);
+				gr.Stroke ();
+				break;
+			case FigureType.DiamondWithLine:
+				gr.DrawDiamond (x + space_x, y + space_y, figure_size);
+				gr.MoveTo (x + space_x + figure_size / 2, y + space_y);
+				gr.LineTo (x + space_x + figure_size / 2, y + space_y + figure_size);
+				gr.Stroke ();
+				break;
+			case FigureType.CercleWithLine:
+				gr.Arc (x + space_x + figure_size / 2, y + space_y + figure_size / 2, figure_size / 2, 0, 2 * Math.PI);
+				gr.Stroke ();
+				gr.MoveTo (x + space_x + figure_size / 2, y + space_y);
+				gr.LineTo (x + space_x + figure_size / 2, y + space_y + figure_size);
+				gr.Stroke ();
+				break;
+			}
+		}
+
+		private void DrawGrid (CairoContextEx gr, double x, double y, int area_width, int area_height)
+		{
+			gr.Color = new Color (DefaultDrawingColor.R, DefaultDrawingColor.G, DefaultDrawingColor.B, alpha);
+			for (int column = 0; column < columns; column++) {
+				for (int row = 0; row < rows; row++) {
+					gr.Rectangle (x + column * rect_w, y + row * rect_h, rect_w, rect_h);
+				}
+			}
+			gr.Stroke ();
+		}
+	}
+}
diff --git a/src/Games/Memory/MemoryFiguresNumbers.cs b/src/Games/Memory/MemoryFiguresNumbers.cs
new file mode 100644
index 0000000..05b10de
--- /dev/null
+++ b/src/Games/Memory/MemoryFiguresNumbers.cs
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2007-2008 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Memory
+{
+	public class MemoryFiguresNumbers : Core.Main.Memory
+	{
+		private int [] numbers;
+		private int rows, columns, squares;
+		private double rect_w, rect_h;
+		private ArrayListIndicesRandom answers_order;
+		private const int answers = 4;
+		private const double block_space = 0.35;
+
+		public override string Name {
+			get {return Catalog.GetString ("Figures with numbers");}
+		}
+
+		public override string MemoryQuestion {
+			get { return String.Format (
+				Catalog.GetString ("Which one of these squares was previously shown? Answer {0}, {1}, {2} or {3}."),
+				GetPossibleAnswer (0), GetPossibleAnswer (1), GetPossibleAnswer (2), GetPossibleAnswer (3));}
+		}
+
+		public override void Initialize ()
+		{
+			switch (CurrentDifficulty) {
+			case Difficulty.Easy:
+				columns = rows = 2;
+				break;
+			case Difficulty.Medium:
+				columns = rows = 3;
+				break;
+			case Difficulty.Master:
+				columns = rows = 4;
+				break;
+			}
+
+			rect_w = 0.3 / rows;
+			rect_h = 0.3 / columns;
+			squares = rows * columns;
+			numbers = new int [squares * 4];
+		
+			for (int n = 0; n < rows; n++)
+				for (int i = 0; i < columns; i++)
+					numbers[(n*columns) + i] = random.Next (10) + random.Next (5);
+
+			Randomize (numbers, 0, squares);
+			Randomize (numbers, 0, squares * 2);
+			Randomize (numbers, 0, squares * 3);
+
+			answers_order = new ArrayListIndicesRandom (answers);
+			answers_order.Initialize ();
+
+			for (int i = 0; i < answers_order.Count; i++) {
+				if ((int) answers_order[i] == 0) {
+					right_answer = GetPossibleAnswer (i);
+					break;
+				}
+			}
+
+			base.Initialize ();
+		}
+
+		private void Randomize (int []nums, int source, int target)
+		{	
+			int elements = 4 + random.Next (2);
+			bool done = false;
+
+			while (done == false) {
+				for (int i = 0; i < squares; i++) {
+					nums[i + target] = nums[i + source];
+				}
+
+				for (int i = 0; i < elements; i++) {
+					nums[target + random.Next (squares)] = random.Next (10) + random.Next (5);
+				}
+
+				// Is not valid if it is already present
+				bool equals = true;
+				for (int answer = 0; answer < answers; answer++) {
+					if (answer * squares == target)
+						continue;
+
+					equals = true;
+					for (int i = 0; i < squares; i++) {
+						if (nums[i + target] != nums[i + (answer * squares)]) {
+							equals = false;
+							break;
+						}
+					}
+
+					if (equals == true)
+						break;
+				}
+
+				if (equals == false)
+					done = true;
+			}
+		}
+	
+
+		public override void DrawPossibleAnswers (CairoContextEx gr, int area_width, int area_height)
+		{
+			double x = DrawAreaX , y = DrawAreaY;
+			gr.Color = DefaultDrawingColor;
+			for (int i = 0; i < answers_order.Count; i++) {
+				if (i == 2) {
+					y += 0.45;
+					x = DrawAreaX;
+				}
+				DrawSquare (gr, x, y, numbers, squares * (int) answers_order[i]);
+				gr.MoveTo (x, y + block_space);
+				gr.ShowPangoText (GetPossibleFigureAnswer (i));
+				gr.Stroke ();
+				x += block_space + 0.08;
+			}
+		}
+
+		public override void DrawObjectToMemorize (CairoContextEx gr, int area_width, int area_height)
+		{
+			base.DrawObjectToMemorize (gr, area_width, area_height);
+			DrawSquare (gr, 0.3 + DrawAreaX, DrawAreaY + 0.1, numbers, 0);
+		}
+
+		private void DrawSquare (CairoContextEx gr, double x, double y, int[] nums, int index)
+		{
+			for (int column = 0; column < columns; column++) {
+				for (int row = 0; row < rows; row++) {
+					gr.Rectangle (x + row * rect_w, y + column * rect_h, rect_w, rect_h);
+					gr.DrawTextCentered (x + (rect_w / 2) + column * rect_w, y + (rect_h / 2) + row * rect_h, 
+						(nums[index + column + (row * columns)]).ToString ());
+				}
+			}
+			gr.Stroke ();
+		}
+	}
+}
diff --git a/src/Games/Memory/MemoryIndications.cs b/src/Games/Memory/MemoryIndications.cs
new file mode 100644
index 0000000..46b979e
--- /dev/null
+++ b/src/Games/Memory/MemoryIndications.cs
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2008 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 Cairo;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Memory
+{
+	public class MemoryIndications : Core.Main.Memory
+	{
+		class Indication 
+		{
+			public Type type;
+			public object obj;
+
+			public Indication (Type type, object obj)
+			{
+				this.type = type;
+				this.obj = obj;
+			}
+
+			public enum Type
+			{
+				Start,
+				Turn,
+				End,
+			}
+
+			public enum TurnDirection
+			{
+				Right,
+				Left,
+				Down,
+				Up
+			}
+
+			public void Draw (CairoContextEx gr, ref double x, ref double y, Indication next_prev)
+			{
+				const double line_length = 0.050;
+				const double points = 0.050;
+
+				if (type == Type.Start) {
+					gr.Rectangle (x, y, points, points);
+					gr.DrawTextCentered (x + points /2 , y + points /2, ((int)obj).ToString ());
+					switch ((TurnDirection) next_prev.obj) {
+					case TurnDirection.Right:
+						x += points;
+						y += points / 2;
+						break;
+					case TurnDirection.Left:
+						y += points / 2;
+						break;
+					case TurnDirection.Down:
+						y += points;
+						x += points / 2;
+						break;
+					case TurnDirection.Up:
+						x += points / 2;
+						break;
+					}
+
+					gr.Stroke ();
+			
+				} else if (type == Type.Turn) {
+					gr.MoveTo (x, y);
+					switch ((TurnDirection) obj) {
+					case TurnDirection.Right:
+						x += line_length;
+						break;
+					case TurnDirection.Left:
+						x -= line_length;
+						break;
+					case TurnDirection.Up:
+						y -= line_length;
+						break;
+					case TurnDirection.Down:
+						y += line_length;
+						break;
+					}
+
+					gr.LineTo (x, y);
+					gr.Stroke ();
+				} else if (type == Type.End) {
+					switch ((TurnDirection) next_prev.obj) {
+					case TurnDirection.Right:
+						y -= points / 2; 
+						break;
+					case TurnDirection.Left:
+						x -= points;
+						y -= points / 2;
+						break;
+					case TurnDirection.Down:
+						x -= points / 2; 
+						break;
+					case TurnDirection.Up:
+						x -= points / 2; 
+						y -= points;
+						break;
+					}
+					gr.Rectangle (x, y, points, points);
+					gr.Stroke ();
+					gr.DrawTextCentered (x + points /2 , y + points /2, ((int)obj).ToString ());
+				}
+			}	
+	
+			public override string ToString ()
+			{
+				switch (type) {
+				case Type.Start:
+					return String.Format (Catalog.GetString ("Start at point number {0}"), (int) obj);
+				case Type.Turn: {
+					switch ((TurnDirection) obj) {
+					case TurnDirection.Right:
+						return Catalog.GetString ("Turn right");
+					case TurnDirection.Left:
+						return Catalog.GetString ("Turn left");
+					case TurnDirection.Up:
+						return Catalog.GetString ("Go up");
+					case TurnDirection.Down:
+						return Catalog.GetString ("Go down");
+					}
+					break;
+				}
+				case Type.End:
+					return String.Format (Catalog.GetString ("End at point {0}"), obj);
+				}
+				return null;
+			}
+		}
+
+		private Indication[] indications;
+		private Indication[] indications_wrongA;
+		private Indication[] indications_wrongB;
+		private Indication[] indications_wrongC;
+		private ArrayListIndicesRandom answers;
+		private int ans;
+
+		public override string Name {
+			get {return Catalog.GetString ("Memorize indications");}
+		}
+
+		public override string MemoryQuestion {
+			get { 
+				return String.Format (
+					Catalog.GetString ("Which of the following graphics represent the indications previously given? Answer {0}, {1}, {2} or {3}."),
+					GetPossibleAnswer (0), GetPossibleAnswer (1), GetPossibleAnswer (2), GetPossibleAnswer (3));}
+		}
+
+		public override void Initialize ()
+		{
+			indications = new Indication [CurrentDifficulty == Difficulty.Easy ? 5 : 7];
+			Indication.TurnDirection second_turn = (Indication.TurnDirection) 2 +  random.Next (2);
+		
+			indications[0] = new Indication (Indication.Type.Start, 0);
+			indications[1] = new Indication (Indication.Type.Turn, random.Next (2)); // right or left
+			indications[2] = new Indication (Indication.Type.Turn, second_turn); // up or down
+			indications[3] = new Indication (Indication.Type.Turn, random.Next (2)); // right or left
+
+			if (CurrentDifficulty==Difficulty.Easy) {
+				indications[4] = new Indication (Indication.Type.End, 1);		
+			} else {
+				if (second_turn == Indication.TurnDirection.Up)
+					indications[4] = new Indication (Indication.Type.Turn, Indication.TurnDirection.Up);
+				else
+					indications[4] = new Indication (Indication.Type.Turn, Indication.TurnDirection.Down);
+
+				indications[5] = new Indication (Indication.Type.Turn, random.Next (2)); // right or left
+				indications[6] = new Indication (Indication.Type.End, 1);
+			}
+		
+			indications_wrongA = CopyAnswer ();
+			indications_wrongB = CopyAnswer ();
+			indications_wrongC = CopyAnswer ();
+
+			if ((Indication.TurnDirection) indications[3].obj == Indication.TurnDirection.Right) {
+				indications_wrongA[3] = new Indication (Indication.Type.Turn, Indication.TurnDirection.Left);
+			}
+			else {
+				indications_wrongA[3] = new Indication (Indication.Type.Turn, Indication.TurnDirection.Right);
+			}
+
+			if (CurrentDifficulty == Difficulty.Easy) {
+				if ((Indication.TurnDirection) indications[2].obj == Indication.TurnDirection.Up) {
+					indications_wrongB[2] = new Indication (Indication.Type.Turn, Indication.TurnDirection.Down);
+				}
+				else {
+					indications_wrongB[2] = new Indication (Indication.Type.Turn, Indication.TurnDirection.Up);
+				}
+			} else {
+				if ((Indication.TurnDirection) indications[5].obj == Indication.TurnDirection.Right) {
+					indications_wrongB[5] = new Indication (Indication.Type.Turn, Indication.TurnDirection.Left);
+				}
+				else {
+					indications_wrongB[5] = new Indication (Indication.Type.Turn, Indication.TurnDirection.Right);
+				}
+			}
+
+			if ((Indication.TurnDirection) indications[1].obj == Indication.TurnDirection.Right) {
+				indications_wrongC[1] = new Indication (Indication.Type.Turn, Indication.TurnDirection.Left);
+			}
+			else {
+				indications_wrongC[1] = new Indication (Indication.Type.Turn, Indication.TurnDirection.Right);
+			}
+		
+			base.Initialize ();
+
+			answers = new ArrayListIndicesRandom (4);
+			answers.Initialize ();
+
+			for (int i = 0; i < answers.Count; i++) {
+				if (answers [i] == 0) {
+					right_answer = GetPossibleAnswer (i);
+					ans = i;
+					break;
+				}
+			}
+
+			//for (int i = 0; i < indications.Length; i++)
+			//	Console.WriteLine ("{0}",  indications[i].ToString ());
+		}
+
+		private Indication[] CopyAnswer ()
+		{
+			Indication[] answer = new Indication [indications.Length];
+			for (int i = 0; i < indications.Length; i++)
+				answer[i] = new Indication (indications[i].type, indications[i].obj);
+
+			return answer;
+		}
+
+		private static void DrawPossibleAnswers (CairoContextEx gr, double x, double y, Indication[] indications)
+		{		
+			for (int i = 0; i < indications.Length - 1; i++)
+				indications[i].Draw (gr, ref x, ref y, indications[i + 1]);
+
+			indications[indications.Length - 1].Draw (gr, ref x, ref y, indications[indications.Length - 2]);
+		}
+
+		private Indication[] WhichAnswer (object answer)
+		{
+			switch ((int) answer) {
+			case 0:
+				return indications;
+			case 1:
+				return indications_wrongA;
+			case 2:
+				return indications_wrongB;
+			case 3:
+				return indications_wrongC;
+			}
+
+			return null;
+		}
+
+		public override void DrawPossibleAnswers (CairoContextEx gr, int area_width, int area_height)
+		{
+			double x, y;
+
+			x = 0.22; y = 0.3;
+			DrawPossibleAnswers (gr, x, y, WhichAnswer (answers[0]));
+			gr.MoveTo (x, y + 0.2);
+			gr.ShowPangoText (GetPossibleFigureAnswer (0));
+
+			x = 0.7; y = 0.3;
+			DrawPossibleAnswers (gr, x, y, WhichAnswer (answers[1]));
+			gr.MoveTo (x, y + 0.2);
+			gr.ShowPangoText (GetPossibleFigureAnswer (1));
+
+			x = 0.22; y = 0.7;
+			DrawPossibleAnswers (gr, x, y, WhichAnswer (answers[2]));
+			gr.MoveTo (x, y + 0.2);
+			gr.ShowPangoText (GetPossibleFigureAnswer (2));
+
+			x = 0.7; y = 0.7;
+			DrawPossibleAnswers (gr, x, y, WhichAnswer (answers[3]));
+			gr.MoveTo (x, y + 0.2);
+			gr.ShowPangoText (GetPossibleFigureAnswer (3));
+		}
+	
+		public override void DrawObjectToMemorize (CairoContextEx gr, int area_width, int area_height)
+		{
+			base.DrawObjectToMemorize (gr, area_width, area_height);
+
+			if (DrawAnswer == false) {
+				for (int i = 0; i < indications.Length; i++)
+				{
+					gr.MoveTo (0.3, 0.2 + i * 0.08);
+					gr.ShowPangoText (indications[i].ToString ());
+					gr.Stroke ();
+				}
+			} else {
+					for (int i = 0; i < indications.Length; i++)
+					{
+						gr.MoveTo (0.1, 0.2 + i * 0.08);
+						gr.ShowPangoText (indications[i].ToString ());
+						gr.Stroke ();
+					}
+					DrawPossibleAnswers (gr, 0.7, 0.3, WhichAnswer (answers[ans]));
+					gr.MoveTo (0.7, 0.5);
+					gr.ShowPangoText (GetPossibleFigureAnswer (ans));
+					gr.Stroke ();
+			}
+		}
+	}
+}
diff --git a/src/Games/Memory/MemoryNumbers.cs b/src/Games/Memory/MemoryNumbers.cs
new file mode 100644
index 0000000..5682919
--- /dev/null
+++ b/src/Games/Memory/MemoryNumbers.cs
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2008 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 Cairo;
+using System.Text;
+using Mono.Unix;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Memory
+{
+	public class MemoryNumbers : Core.Main.Memory
+	{
+		private Challenge current_game;
+		private const int num_games = 3;
+
+		public class Challenge
+		{
+			protected static int [] numbers;
+
+			public Challenge () {}
+		
+			public static int[] Numbers {
+				set { numbers = value;}
+				get { return numbers;}
+			}
+
+			virtual public string Question {
+				get {return string.Empty; }
+			}	
+
+			virtual public string Answer {
+				get {return string.Empty; }
+			}	
+		}
+
+		public class ChallengeOdds : Challenge
+		{
+			public override string Question {
+				get {
+					return Catalog.GetString ("How many odd numbers were in the previous image? Answer using numbers.");
+				}
+			}		
+
+			public override string Answer {
+				get {
+					int odds = 0;
+					for (int i = 0; i < numbers.Length; i++) {
+						if (numbers[i] % 2 != 0)
+							odds++;
+					}
+					return odds.ToString ();
+				}
+			}
+		}
+
+		public class ChallengeEvens : Challenge
+		{
+			public override string Question {
+				get {
+					return Catalog.GetString ("How many even numbers were in the previous image? Answer using numbers.");
+				}
+			}		
+
+			public override string Answer {
+				get {
+					int evens = 0;
+					for (int i = 0; i < numbers.Length; i++) {
+						if (numbers[i] % 2 == 0)
+							evens++;
+					}
+					return evens.ToString ();
+				}
+			}
+		}
+
+		public class ChallengeTwoDigits : Challenge
+		{
+			public override string Question {
+				get {
+					return Catalog.GetString ("How many numbers with more than one digit were in the previous image? Answer using numbers.");
+				}
+			}		
+
+			public override string Answer {
+				get {
+					int digits = 0;
+					for (int i = 0; i < numbers.Length; i++) {
+						if (numbers[i] > 9)
+							digits++;
+					}
+					return digits.ToString ();
+				}
+			}
+		}
+
+		public override string Name {
+			get {return Catalog.GetString  ("Memorize numbers");}
+		}
+
+		public override string MemoryQuestion {
+			get { return current_game.Question; }
+		}
+
+		public override void Initialize ()
+		{
+			base.Initialize ();
+			int total;
+	
+			switch (CurrentDifficulty) {
+			case Difficulty.Easy:
+				total = 5;
+				break;
+			case Difficulty.Medium:
+			default:
+				total = 7;
+				break;
+			case Difficulty.Master:
+				total = 9;
+				break;
+			}
+
+			int[] nums = new int [total];
+
+			for (int i = 0; i < nums.Length; i++)
+				nums[i] = 1 + random.Next (15);
+
+			switch (random.Next (num_games)) {
+			case 0: 
+				current_game = new ChallengeOdds ();
+				break;
+			case 1:
+				current_game = new ChallengeEvens ();
+				break;
+			case 2:
+				current_game = new ChallengeTwoDigits ();
+				break;
+			}
+		
+			Challenge.Numbers = nums;
+			right_answer = current_game.Answer;
+		}
+
+		public override void DrawObjectToMemorize (CairoContextEx gr, int area_width, int area_height)
+		{
+
+			StringBuilder sequence = new StringBuilder (64);
+
+			base.DrawObjectToMemorize (gr, area_width, area_height);
+			gr.SetPangoLargeFontSize ();
+
+			for (int num = 0; num < Challenge.Numbers.Length - 1; num++)
+			{
+				sequence.Append (Challenge.Numbers [num]);
+				sequence.Append (", ");
+			}
+			sequence.Append (Challenge.Numbers [Challenge.Numbers.Length - 1]);
+
+			gr.DrawTextCentered (0.5, DrawAreaY + 0.3, sequence.ToString ());
+
+		}
+	}
+}
diff --git a/src/Games/Memory/MemoryWords.cs b/src/Games/Memory/MemoryWords.cs
new file mode 100644
index 0000000..5165be0
--- /dev/null
+++ b/src/Games/Memory/MemoryWords.cs
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2007-2008 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 Cairo;
+using Mono.Unix;
+using System.Collections.Generic;
+
+using gbrainy.Core.Main;
+using gbrainy.Core.Libraries;
+
+namespace gbrainy.Games.Memory
+{
+	public class MemoryWords : Core.Main.Memory
+	{
+		private ArrayListIndicesRandom words_order;
+		private List <string> words;
+		private const int total_words = 35;
+		private int showed;
+		private int answer;
+
+		public override string Name {
+			get {return Catalog.GetString ("Memorize words");}
+		}
+
+		public override string MemoryQuestion {
+			get { 
+				return String.Format (Catalog.GetString ("There is a missing word from the previous list. Which one is the missing word?"));}
+		}
+
+		public override void Initialize ()
+		{
+			int tmp;
+			words = new List <string> (total_words);
+
+			// Body parts
+			words.Add (Catalog.GetString ("wrist"));
+			words.Add (Catalog.GetString ("elbow"));
+			words.Add (Catalog.GetString ("armpit"));
+			words.Add (Catalog.GetString ("hand"));
+			words.Add (Catalog.GetString ("chest"));
+			
+			//Fishes
+			words.Add (Catalog.GetString ("sardine"));
+			words.Add (Catalog.GetString ("trout"));
+			words.Add (Catalog.GetString ("monkfish"));
+			words.Add (Catalog.GetString ("cod"));
+			words.Add (Catalog.GetString ("salmon"));
+
+			// Vegetables
+			words.Add (Catalog.GetString ("potato"));
+			words.Add (Catalog.GetString ("ginger"));			
+			words.Add (Catalog.GetString ("pepper"));
+			words.Add (Catalog.GetString ("garlic"));
+			words.Add (Catalog.GetString ("pumpkin"));
+
+			// Bicycle
+			words.Add (Catalog.GetString ("brake"));
+			words.Add (Catalog.GetString ("pedal"));
+			words.Add (Catalog.GetString ("chain"));			
+			words.Add (Catalog.GetString ("wheel"));
+			words.Add (Catalog.GetString ("handlebar"));
+
+			// Music
+			words.Add (Catalog.GetString ("drummer"));
+			words.Add (Catalog.GetString ("speaker"));
+			words.Add (Catalog.GetString ("lyrics"));
+			words.Add (Catalog.GetString ("beat"));			
+			words.Add (Catalog.GetString ("song"));
+
+			// Weather
+			words.Add (Catalog.GetString ("cloud"));
+			words.Add (Catalog.GetString ("rain"));
+			words.Add (Catalog.GetString ("storm"));
+			words.Add (Catalog.GetString ("fog"));
+			words.Add (Catalog.GetString ("rainbow"));
+
+			// Animals
+			words.Add (Catalog.GetString ("rabbit"));
+			words.Add (Catalog.GetString ("mouse"));
+			words.Add (Catalog.GetString ("monkey"));
+			words.Add (Catalog.GetString ("bear"));
+			words.Add (Catalog.GetString ("wolf"));
+
+			switch (CurrentDifficulty) {
+			case Difficulty.Easy:
+				showed = 6;
+				break;
+			case Difficulty.Medium:
+				showed = 9;
+				break;
+			case Difficulty.Master:
+				showed = 12;
+				break;
+			}
+
+			words_order = new ArrayListIndicesRandom (total_words);
+			words_order.Initialize ();
+			answer = random.Next (showed);
+			tmp = words_order [answer];
+			right_answer = words [tmp];
+			base.Initialize ();
+		}
+	
+		public override void DrawPossibleAnswers (CairoContextEx gr, int area_width, int area_height)
+		{
+			double x= DrawAreaX + 0.125, y = DrawAreaY + 0.1;
+			int cnt = 0;
+
+			for (int i = 0; i < showed; i++)
+			{
+				if (i == answer)
+					continue;
+
+				gr.MoveTo (x, y);
+				gr.ShowPangoText (words[words_order[i]]);
+				gr.Stroke ();
+
+				if ((cnt + 1) % 3 == 0) {
+					y += 0.2;
+					x = DrawAreaX + 0.125;
+				} else {
+					x+= 0.25;
+				}
+				cnt++;
+			}
+		}
+	
+		public override void DrawObjectToMemorize (CairoContextEx gr, int area_width, int area_height)
+		{
+			base.DrawObjectToMemorize (gr, area_width, area_height);
+			DrawObject (gr, area_width, area_height);
+		}
+	
+		private void DrawObject (CairoContextEx gr, int area_width, int area_height)
+		{
+			double x= DrawAreaX + 0.125, y = DrawAreaY + 0.1;
+			for (int i = 0; i < showed; i++)
+			{
+				gr.MoveTo (x, y);
+				gr.ShowPangoText (words[words_order[i]]);
+				gr.Stroke ();
+			
+				if ((i + 1) % 3 == 0) {
+					y += 0.2;
+					x = DrawAreaX + 0.125;
+				} else {
+					x+= 0.25;
+				}
+			}
+		}
+	}
+}
diff --git a/src/Makefile.am b/src/Makefile.am
index 08daabb..6b3e6a1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,149 +1,5 @@
-EXTRAFLAGS =  -nowarn:0169 $(CSC_DEFINES)
-
-WRAPPER = gbrainy
-
-GBRAINY_CSDISTFILES =				\
-	$(srcdir)/ArrayListIndicesRandom.cs	\
-	$(srcdir)/GameManager.cs		\
-	$(srcdir)/PuzzleGames/PuzzleCirclesRectangle.cs	\
-	$(srcdir)/Game.cs			\
-	$(srcdir)/PuzzleGames/PuzzleFigures.cs		\
-	$(srcdir)/PuzzleGames/PuzzleMatrixNumbers.cs	\
-	$(srcdir)/PuzzleGames/PuzzleMoveFigure.cs		\
-	$(srcdir)/PuzzleGames/PuzzlePencil.cs		\
-	$(srcdir)/PuzzleGames/PuzzleSquares.cs		\
-	$(srcdir)/PuzzleGames/PuzzleTriangles.cs		\
-	$(srcdir)/PuzzleGames/PuzzleCoverPercentage.cs	\
-	$(srcdir)/PuzzleGames/PuzzleNumericSequence.cs	\
-	$(srcdir)/PuzzleGames/PuzzleSquaresAndLetters.cs	\
-	$(srcdir)/PuzzleGames/PuzzleSquareDots.cs		\
-	$(srcdir)/PuzzleGames/PuzzleNumericRelation.cs	\
-	$(srcdir)/PuzzleGames/PuzzleNextFigure.cs		\
-	$(srcdir)/PuzzleGames/PuzzleSquareSheets.cs		\
-	$(srcdir)/CalculationGames/CalculationArithmetical.cs	\
-	$(srcdir)/MemoryGames/MemoryColouredFigures.cs	\
-	$(srcdir)/GameSession.cs		\
-	$(srcdir)/MemoryGames/MemoryFiguresNumbers.cs		\
-	$(srcdir)/MemoryGames/Memory.cs			\
-	$(srcdir)/MemoryGames/MemoryColouredText.cs		\
-	$(srcdir)/PuzzleGames/PuzzleCube.cs			\
-	$(srcdir)/MemoryGames/MemoryWords.cs		\
-	$(srcdir)/PuzzleGames/PuzzleFigureLetter.cs		\
-	$(srcdir)/Dialogs/CustomGameDialog.cs		\
-	$(srcdir)/PuzzleGames/PuzzleDivideCircle.cs		\
-	$(srcdir)/CalculationGames/CalculationGreatestDivisor.cs	\
-	$(srcdir)/CalculationGames/CalculationTwoNumbers.cs	\
-	$(srcdir)/CalculationGames/CalculationCloserFraction.cs	\
-	$(srcdir)/PuzzleGames/PuzzleMatrixGroups.cs		\
-	$(srcdir)/PuzzleGames/PuzzleBalance.cs		\
-	$(srcdir)/PuzzleGames/PuzzleTrianglesWithNumbers.cs	\
-	$(srcdir)/PuzzleGames/PuzzleOstracism.cs		\
-	$(srcdir)/MemoryGames/MemoryCountDots.cs		\
-	$(srcdir)/CalculationGames/CalculationOperator.cs	\
-	$(srcdir)/PuzzleGames/PuzzleFigurePattern.cs	\
-	$(srcdir)/ColorPalette.cs		\
-	$(srcdir)/PuzzleGames/PuzzlePeopleTable.cs		\
-	$(srcdir)/GameDrawingArea.cs		\
-	$(srcdir)/MemoryGames/MemoryFigures.cs		\
-	$(srcdir)/PuzzleGames/PuzzleMissingSlice.cs		\
-	$(srcdir)/PuzzleGames/PuzzleLines.cs		\
-	$(srcdir)/PuzzleGames/PuzzleTetris.cs		\
-	$(srcdir)/Dialogs/PreferencesDialog.cs		\
-	$(srcdir)/PuzzleGames/PuzzleMissingPiece.cs		\
-	$(srcdir)/MemoryGames/MemoryIndications.cs		\
-	$(srcdir)/PuzzleGames/PuzzleMostInCommon.cs		\
-	$(srcdir)/PuzzleGames/PuzzleBuildTriangle.cs	\
-	$(srcdir)/CairoContextEx.cs		\
-	$(srcdir)/PuzzleGames/PuzzleClocks.cs		\
-	$(srcdir)/PuzzleGames/PuzzleCountCircles.cs		\
-	$(srcdir)/PuzzleGames/PuzzleEquation.cs		\
-	$(srcdir)/PuzzleGames/PuzzleQuadrilaterals.cs	\
-	$(srcdir)/CalculationGames/CalculationFractions.cs	\
-	$(srcdir)/PuzzleGames/PuzzleExtraCircle.cs		\
-	$(srcdir)/PuzzleGames/PuzzleCountSeries.cs		\
-	$(srcdir)/PlayerHistory.cs		\
-	$(srcdir)/Dialogs/PlayerHistoryDialog.cs	\
-	$(srcdir)/Dialogs/GtkDialog.cs			\
-	$(srcdir)/Preferences.cs		\
-	$(srcdir)/PuzzleGames/PuzzleFourSided.cs		\
-	$(srcdir)/PuzzleGames/PuzzleLargerShape.cs		\
-	$(srcdir)/SVGImage.cs			\
-	$(srcdir)/MemoryGames/MemoryNumbers.cs		\
-	$(srcdir)/Dialogs/AboutDialog.cs	\
-	$(srcdir)/PuzzleGames/PuzzleHandshakes.cs	\
-	$(srcdir)/CalculationGames/CalculationPrimes.cs	\
-	$(srcdir)/MemoryGames/MemoryFacts.cs		\
-	$(srcdir)/PuzzleGames/PuzzleCounting.cs	\
-	$(srcdir)/VerbalAnalogies/Analogy.cs \
-	$(srcdir)/VerbalAnalogies/AnalogiesFactory.cs \
-	$(srcdir)/VerbalAnalogies/Analogies.cs \
-	$(srcdir)/VerbalAnalogies/AnalogiesQuestionAnswer.cs \
-	$(srcdir)/VerbalAnalogies/AnalogiesMultipleOptions.cs \
-	$(srcdir)/VerbalAnalogies/AnalogiesPairOfWordsOptions.cs \
-	$(srcdir)/VerbalAnalogies/AnalogiesPairOfWordsCompare.cs \
-	$(srcdir)/CalculationGames/CalculationAverage.cs \
-	$(srcdir)/CalculationGames/CalculationProportions.cs \
-	$(srcdir)/CalculationGames/CalculationRatio.cs \
-	$(srcdir)/PuzzleGames/PuzzlePercentage.cs	\
-	$(srcdir)/PuzzleGames/PuzzleTimeNow.cs	\
-	$(srcdir)/PuzzleGames/Puzzle3DCube.cs	\
-	$(srcdir)/SimpleLabel.cs	\
-	$(srcdir)/Unix.cs	\
-	$(srcdir)/GameTips.cs	\
-	$(srcdir)/CountDown.cs	\
-	$(srcdir)/gbrainy.cs			
-
-
-ASSEMBLIES = \
-	 $(GBRAINY_LIBS)    		\
-	 $(MONO_ADDINS_LIBS)    	\
-	-r:Mono.Cairo.dll		\
-	-r:Mono.Posix
-
-RESOURCES =										\
--resource:$(srcdir)/gbrainy.glade  \
--resource:$(top_srcdir)/data/app-graphics/resume-32.png  \
--resource:$(top_srcdir)/data/app-graphics/endgame-32.png  \
--resource:$(top_srcdir)/data/app-graphics/pause-32.png  \
--resource:$(top_srcdir)/data/app-graphics/allgames-32.png  \
--resource:$(top_srcdir)/data/app-graphics/gbrainy.png  \
--resource:$(top_srcdir)/data/app-graphics/logic-games-32.png  \
--resource:$(top_srcdir)/data/app-graphics/math-games-32.png  \
--resource:$(top_srcdir)/data/app-graphics/memory-games-32.png  \
--resource:$(top_srcdir)/data/app-graphics/verbal-games.svg  \
--resource:$(top_srcdir)/data/app-graphics/verbal-games-32.png  \
--resource:$(top_srcdir)/data/app-graphics/gbrainy.svg  \
--resource:$(top_srcdir)/data/game-graphics/present.svg  \
--resource:$(top_srcdir)/data/game-graphics/handshake.svg  \
--resource:$(srcdir)/gbrainy.addin.xml
-
-gbrainydir = $(libdir)/gbrainy
-gbrainy_SCRIPTS = gbrainy.exe ../data/gbrainy.exe.config
-bin_SCRIPTS = gbrainy
-
-GBRAINY_CSFILES = $(GBRAINY_CSDISTFILES)	\
-	Defines.cs \
-	AssemblyInfo.cs
-
-gbrainy.exe: $(GBRAINY_CSFILES) 
-	$(CSC) -target:winexe -out:$@ $(EXTRAFLAGS) $(GBRAINY_CSFILES) $(ASSEMBLIES) $(RESOURCES)
-
-all: gbrainy.exe
-
-EXTRA_DIST =					\
-	gbrainy.glade \
-	$(srcdir)/gbrainy.addin.xml \
-	$(srcdir)/mono-addins-strings.xml \
-	$(GBRAINY_CSDISTFILES)			
-
-
-CLEANFILES =					\
-	gbrainy.exe.config			\
-	gbrainy.exe.mdb				\
-	gbrainy.exe				\
-	gbrainy
-
-
-DISTCLEANFILES = 				\
-	Makefile
+SUBDIRS = 		\
+	Core		\
+	Games		\
+	Clients/Classical
 



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