[gbrainy/refactoring] Extract playlist functionality from GameManager



commit 80bdeea64f7bafcd9d122a3fba286d391cca654f
Author: Jordi Mas <jmas softcatala org>
Date:   Sat Jul 30 14:03:12 2011 +0200

    Extract playlist functionality from GameManager

 src/Clients/Classical/CommandLine.cs              |    9 +-
 src/Clients/Classical/Dialogs/CustomGameDialog.cs |   12 +-
 src/Clients/Classical/Dialogs/PdfExportDialog.cs  |   18 +-
 src/Clients/Classical/gbrainy.cs                  |   12 +-
 src/Clients/WebForms/AllGames.aspx.cs             |    2 +-
 src/Clients/WebForms/Game.aspx.cs                 |    9 +-
 src/Core/Core.csproj                              |    8 +-
 src/Core/Main/GameLocator.cs                      |   39 ++++
 src/Core/Main/GameManager.cs                      |  230 +-------------------
 src/Core/Main/GameSession.cs                      |   23 ++-
 src/Core/Main/GameSessionPlayList.cs              |  243 +++++++++++++++++++++
 src/Core/Makefile.am                              |    2 +
 tests/Clients/Classical/CommandLineTest.cs        |    2 +-
 tests/Core/GameManagerTest.cs                     |   73 +------
 tests/Core/GameSessionPlayListTest.cs             |  113 ++++++++++
 tests/Makefile.am                                 |    3 +-
 16 files changed, 468 insertions(+), 330 deletions(-)
---
diff --git a/src/Clients/Classical/CommandLine.cs b/src/Clients/Classical/CommandLine.cs
index 537047e..6056c0b 100644
--- a/src/Clients/Classical/CommandLine.cs
+++ b/src/Clients/Classical/CommandLine.cs
@@ -108,11 +108,10 @@ namespace gbrainy.Clients.Classical
 
 		static void GameList ()
 		{
-			GameManager.GameLocator [] games;
+			GameLocator [] games;
 			GameManager gm = new GameManager ();
 
 			GtkClient.GameManagerPreload (gm);
-			gm.GameType = GameSession.Types.AllGames;
 			games = gm.AvailableGames;
 
 			Console.WriteLine (Catalog.GetString ("List of available games"));
@@ -131,7 +130,7 @@ namespace gbrainy.Clients.Classical
 		void BuildPlayList (string [] names)
 		{
 			Dictionary <string, int> dictionary;
-			GameManager.GameLocator [] games;
+			GameLocator [] games;
 			GameManager gm = new GameManager ();
 			GtkClient.GameManagerPreload (gm);
 			games = gm.AvailableGames;
@@ -152,7 +151,7 @@ namespace gbrainy.Clients.Classical
 				}
 				catch (Exception e)
 				{
-					Console.WriteLine ("gbrainy. Error adding {0} {1}", game.Name, e.Message);
+					Console.WriteLine ("CommandLine.BuildPlayList. Error adding {0} {1}", game.Name, e.Message);
 				}
 			}
 
@@ -166,7 +165,7 @@ namespace gbrainy.Clients.Classical
 				}
 				catch (KeyNotFoundException)
 				{
-					Console.WriteLine ("gbrainy. Game [{0}] not found", names [i]);
+					Console.WriteLine ("CommandLine.BuildPlayList. Game [{0}] not found", names [i]);
 				}
 			}
 
diff --git a/src/Clients/Classical/Dialogs/CustomGameDialog.cs b/src/Clients/Classical/Dialogs/CustomGameDialog.cs
index 001059f..0b2627f 100644
--- a/src/Clients/Classical/Dialogs/CustomGameDialog.cs
+++ b/src/Clients/Classical/Dialogs/CustomGameDialog.cs
@@ -34,8 +34,8 @@ namespace gbrainy.Clients.Classical.Dialogs
 		[GtkBeans.Builder.Object] Gtk.TreeView treeview;
 		[GtkBeans.Builder.Object] Box preview_vbox;
 		GameDrawingArea drawing_area;
-		GameManager manager;
-		GameManager.GameLocator [] games;
+		GameSession session;
+		GameLocator [] games;
 		bool selection_done;
 
 		const int COL_NAME = 0;
@@ -44,13 +44,13 @@ namespace gbrainy.Clients.Classical.Dialogs
 		const int COL_OBJECT = 3;
 		const int COL_INDEX = 4;
 
-		public CustomGameDialog (GameManager manager) : base ("CustomGameDialog.ui", "customgame")
+		public CustomGameDialog (GameSession session) : base ("CustomGameDialog.ui", "customgame")
 		{
 			Game game;
 
 			selection_done = false;
-			this.manager = manager;
-			games = manager.AvailableGames;
+			this.session = session;
+			games = session.GameManager.AvailableGames;
 
 			drawing_area = new GameDrawingArea ();
 			drawing_area.UseSolutionArea = false;
@@ -233,7 +233,7 @@ namespace gbrainy.Clients.Classical.Dialogs
 			});
 
 			if (selection_done == true)
-				manager.PlayList = play_list.ToArray ();
+				session.PlayList.PlayList = play_list.ToArray ();
 		}
 	}
 }
diff --git a/src/Clients/Classical/Dialogs/PdfExportDialog.cs b/src/Clients/Classical/Dialogs/PdfExportDialog.cs
index b78d113..a76025c 100644
--- a/src/Clients/Classical/Dialogs/PdfExportDialog.cs
+++ b/src/Clients/Classical/Dialogs/PdfExportDialog.cs
@@ -41,11 +41,13 @@ namespace gbrainy.Clients.Classical.Dialogs
 		[GtkBeans.Builder.Object] Gtk.ComboBox layout_combo;
 
 		BrowseFile file;
+		GameManager manager;
 		const int COLUMN_VALUE = 1;
 		const int DEF_SIDEVALUE = 4;
 
-		public PdfExportDialog () : base ("PdfExportDialog.ui", "pdfexportbox")
+		public PdfExportDialog (GameManager manager) : base ("PdfExportDialog.ui", "pdfexportbox")
 		{
+			this.manager = manager;
 			games_spinbutton.Value = 10;
 			checkbox_logic.Active = checkbox_calculation.Active = checkbox_verbal.Active = true;
 
@@ -147,20 +149,20 @@ namespace gbrainy.Clients.Classical.Dialogs
 		void GeneratePdf (GameSession.Types types, int num_games, int gamespage, GameDifficulty difficulty, bool colorblind, string filename)
 		{
 			Game [] games;
-			GameManager gm;
+			GameSession session;
 			string msg;
 			MessageType msg_type;
 
 			games = new Game [num_games];
-			gm = new GameManager ();
-			gm.ColorBlind = colorblind;
-			gm.Difficulty = difficulty;
-			GtkClient.GameManagerPreload (gm);
-			gm.GameType = types;
+			session = new GameSession ();
+			session.GameManager = manager;
+			session.PlayList.ColorBlind = colorblind;
+			session.PlayList.Difficulty = difficulty;
+			session.PlayList.GameType = types;
 
 			for (int n = 0; n < num_games; n++)
 			{
-				 games [n] = gm.GetPuzzle ();
+				 games [n] = session.PlayList.GetPuzzle ();
 			}
 
 			if (PdfExporter.GeneratePdf (games, gamespage, filename) == true) {
diff --git a/src/Clients/Classical/gbrainy.cs b/src/Clients/Classical/gbrainy.cs
index 6cb8efa..8128214 100644
--- a/src/Clients/Classical/gbrainy.cs
+++ b/src/Clients/Classical/gbrainy.cs
@@ -99,7 +99,7 @@ namespace gbrainy.Clients.Classical
 			GameManagerPreload (session.GameManager);
 			Console.WriteLine (session.GameManager.GetGamesSummary ());
 
-			session.GameManager.ColorBlind = Preferences.Get <bool> (Preferences.ColorBlindKey);
+			session.PlayList.ColorBlind = Preferences.Get <bool> (Preferences.ColorBlindKey);
 			session.DrawRequest += SessionDrawRequest;
 			session.UpdateUIElement += SessionUpdateUIElement;
 			session.SynchronizingObject = new GtkSynchronize ();
@@ -535,7 +535,7 @@ namespace gbrainy.Clients.Classical
 		{
 			PdfExportDialog pdf;
 
-			pdf = new PdfExportDialog ();
+			pdf = new PdfExportDialog (session.GameManager);
 			pdf.Run ();
 			pdf.Destroy ();
 		}
@@ -547,7 +547,7 @@ namespace gbrainy.Clients.Classical
 			dialog = new PreferencesDialog (session.PlayerHistory);
 			if ((Gtk.ResponseType) dialog.Run () == ResponseType.Ok) {
 				session.Difficulty = (GameDifficulty) Preferences.Get <int> (Preferences.DifficultyKey);
-				session.GameManager.ColorBlind = Preferences.Get <bool> (Preferences.ColorBlindKey);
+				session.PlayList.ColorBlind = Preferences.Get <bool> (Preferences.ColorBlindKey);
 
 				if (dialog.NewThemeSet == true)
 					drawing_area.ReloadBackground ();
@@ -559,7 +559,7 @@ namespace gbrainy.Clients.Classical
 		{
 			CustomGameDialog dialog;
 
-			dialog = new CustomGameDialog (session.GameManager);
+			dialog = new CustomGameDialog (session);
 			dialog.Run ();
 			dialog.Destroy ();
 
@@ -748,9 +748,9 @@ namespace gbrainy.Clients.Classical
 
 			app.Initialize ();
 			// Set RandomOrder before setting the custom list then it has effect of custom games
-			app.Session.GameManager.RandomOrder = line.RandomOrder;
+			app.Session.PlayList.RandomOrder = line.RandomOrder;
 			if (line.PlayList.Length > 0) {
-				app.Session.GameManager.PlayList = line.PlayList;
+				app.Session.PlayList.PlayList = line.PlayList;
 				app.InitialSessionType = GameSession.Types.Custom;
 			}
 			app.ProcessDefaults ();
diff --git a/src/Clients/WebForms/AllGames.aspx.cs b/src/Clients/WebForms/AllGames.aspx.cs
index f1c9c28..98a84e3 100644
--- a/src/Clients/WebForms/AllGames.aspx.cs
+++ b/src/Clients/WebForms/AllGames.aspx.cs
@@ -110,7 +110,7 @@ namespace gbrainy.Clients.WebForms
 			manager = Game.CreateManager ();
 			GameImage.CreateDirectory (images_dir);	
 			
-			GameManager.GameLocator [] games;
+			GameLocator [] games;
 			gbrainy.Core.Main.Game game;
 			
 			games = manager.AvailableGames;
diff --git a/src/Clients/WebForms/Game.aspx.cs b/src/Clients/WebForms/Game.aspx.cs
index 9ca33c5..ac1a7b2 100644
--- a/src/Clients/WebForms/Game.aspx.cs
+++ b/src/Clients/WebForms/Game.aspx.cs
@@ -47,10 +47,6 @@ namespace gbrainy.Clients.WebForms
 			manager.LoadVerbalAnalogies (System.IO.Path.Combine ("data/", Defines.VERBAL_ANALOGIES));
 			manager.LoadGamesFromXml (System.IO.Path.Combine ("data/", "games.xml"));
 
-			manager.Difficulty = gbrainy.Core.Main.GameDifficulty.Medium;
-			manager.GameType = gbrainy.Core.Main.GameSession.Types.LogicPuzzles |
-				 gbrainy.Core.Main.GameSession.Types.Calculation |
-				gbrainy.Core.Main.GameSession.Types.VerbalAnalogies;
 			return manager;
 		}
 
@@ -117,6 +113,11 @@ namespace gbrainy.Clients.WebForms
 				Logger.Debug ("Game.Page_Load creating new session");
 				session = new gbrainy.Core.Main.GameSession ();
 				session.GameManager = CreateManager ();
+			 	session.PlayList.Difficulty = gbrainy.Core.Main.GameDifficulty.Medium;
+				session.PlayList.GameType = gbrainy.Core.Main.GameSession.Types.LogicPuzzles |
+					gbrainy.Core.Main.GameSession.Types.Calculation |
+					gbrainy.Core.Main.GameSession.Types.VerbalAnalogies;
+
 				session.New ();
 				WebSession.GameState = session;
 				Global.TotalGamesSessions++;
diff --git a/src/Core/Core.csproj b/src/Core/Core.csproj
index 556b8f0..81fc733 100644
--- a/src/Core/Core.csproj
+++ b/src/Core/Core.csproj
@@ -35,16 +35,14 @@
     <Reference Include="Mono.Posix" />
     <Reference Include="System.Xml" />
     <Reference Include="pango-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
-      <Package>gtk-sharp-2.0</Package>
     </Reference>
     <Reference Include="gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
-      <Package>gtk-sharp-2.0</Package>
     </Reference>
     <Reference Include="gdk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f">
-      <Package>gtk-sharp-2.0</Package>
     </Reference>
     <Reference Include="Mono.CSharp" />
-    <Reference Include="Mono.Cairo, Version=2.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756" />
+    <Reference Include="Mono.Cairo" />
+    <Reference Include="System.Core" />
   </ItemGroup>
   <ItemGroup>
     <Compile Include="Main\ArrayListIndicesRandom.cs" />
@@ -118,6 +116,8 @@
     <Compile Include="Services\DefaultServices.cs" />
     <Compile Include="Services\ICSharpCompiler.cs" />
     <Compile Include="Main\PreferencesStorage.cs" />
+    <Compile Include="Main\GameSessionPlayList.cs" />
+    <Compile Include="Main\GameLocator.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ProjectExtensions>
diff --git a/src/Core/Main/GameLocator.cs b/src/Core/Main/GameLocator.cs
new file mode 100644
index 0000000..733968d
--- /dev/null
+++ b/src/Core/Main/GameLocator.cs
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2007-2010 Jordi Mas i HernÃndez <jmas softcatala org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * 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;
+
+namespace gbrainy.Core.Main
+{
+	public class GameLocator
+	{
+		public Type TypeOf { get; set; }
+		public int Variant { get; set; }
+		public GameTypes GameType { get; set; }
+		public bool IsGame { get; set; }
+
+		public GameLocator (Type type, int variant, GameTypes game_type, bool isGame)
+		{
+			TypeOf = type;
+			Variant = variant;
+			GameType = game_type;
+			IsGame = isGame;
+		}
+	}
+}
diff --git a/src/Core/Main/GameManager.cs b/src/Core/Main/GameManager.cs
index 68aef7a..02cc152 100644
--- a/src/Core/Main/GameManager.cs
+++ b/src/Core/Main/GameManager.cs
@@ -33,6 +33,7 @@ using gbrainy.Core.Main.Xml;
 
 namespace gbrainy.Core.Main
 {
+	// Manages all the games available on the system
 	public class GameManager
 	{
 		static Type[] VerbalAnalogiesInternal = new Type[]
@@ -43,39 +44,14 @@ namespace gbrainy.Core.Main
 			typeof (AnalogiesPairOfWordsCompare),
 		};
 
-		public class GameLocator
-		{
-			public Type TypeOf { get; set; }
-			public int Variant { get; set; }
-			public GameTypes GameType { get; set; }
-			public bool IsGame { get; set; }
-
-			public GameLocator (Type type, int variant, GameTypes game_type, bool isGame)
-			{
-				TypeOf = type;
-				Variant = variant;
-				GameType = game_type;
-				IsGame = isGame;
-			}
-		}
-
-		GameSession.Types game_type;
-		IEnumerator <int> enumerator;
-		GameDifficulty difficulty;
-		bool color_blind;
-
 		List <GameLocator> available_games; 	// List of all available games in the system
-		List <int> play_list;  		// Play list for the Selected difficulty, game types
 		int cnt_logic, cnt_memory, cnt_calculation, cnt_verbal;
+		static bool domain_load;
 
 		public GameManager ()
 		{
-			game_type = GameSession.Types.None;
-			difficulty = GameDifficulty.Medium;
 			available_games = new List <GameLocator> ();
-			play_list = new List <int> ();
 			cnt_logic = cnt_memory = cnt_calculation = cnt_verbal = 0;
-			RandomOrder = true;
 		}
 
 		public GameTypes AvailableGameTypes {
@@ -98,80 +74,19 @@ namespace gbrainy.Core.Main
 			}
 		}
 
-		public GameSession.Types GameType {
-			get {return game_type; }
-			set {
-				if (game_type == value)
-					return;
-
-				game_type = value;
-
-				if ((game_type & GameSession.Types.Custom) != GameSession.Types.Custom)
-					BuildPlayList (available_games);
-			}
-		}
-
-		public GameDifficulty Difficulty {
-			set {
-				if (difficulty == value)
-					return;
-
-				difficulty = value;
-
-				if ((game_type & GameSession.Types.Custom) != GameSession.Types.Custom)
-					BuildPlayList (available_games);
-			}
-			get { return difficulty; }
-		}
-
-		// Establish the PlayList (the indices of the array to available games)
-		public int [] PlayList {
-			get { return play_list.ToArray ();}
-			set {
-				play_list = new List <int> (value);
-
-				if (RandomOrder == true)
-				{
-					ArrayListIndicesRandom random = new ArrayListIndicesRandom (play_list.Count);
-					random.RandomizeFromArray (play_list);
-					enumerator = random.GetEnumerator ();
-				}
-				else
-					enumerator = play_list.GetEnumerator ();
-			}
-		}
-
-		// Indicates if the PlayList for CustomGames is delivered in RandomOrder
- 		public bool RandomOrder { get; set; }
-
-		public bool ColorBlind { 
-			get { return color_blind;} 
-			set {
-				if (color_blind == value)
-					return;
-
-				color_blind = value;
-
-				if ((game_type & GameSession.Types.Custom) != GameSession.Types.Custom)
-					BuildPlayList (available_games);	
-			}
-		}
-
 		// Returns all the games available for playing
 		public GameLocator [] AvailableGames {
 			get { return available_games.ToArray (); }
 		}
-		
+
 		// Gives the Assembly.Load used in GameManager the right path to load the application assemblies
 		static Assembly ResolveAssemblyLoad (object sender, ResolveEventArgs args)
 		{
-			IConfiguration config = ServiceLocator.Instance.GetService <IConfiguration> ();	
+			IConfiguration config = ServiceLocator.Instance.GetService <IConfiguration> ();
 			string asm_dir = config.Get <string> (ConfigurationKeys.AssembliesDir);
         		string full_name = System.IO.Path.Combine (asm_dir, args.Name);
 			return Assembly.LoadFile (full_name);
    		}
-		
-		static bool domain_load;
 
 		// Dynamic load of the gbrainy.Games.Dll assembly
 		public void LoadAssemblyGames (string file)
@@ -191,11 +106,11 @@ namespace gbrainy.Core.Main
 				if (domain_load == false)
 				{
 					AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler (ResolveAssemblyLoad);
-					domain_load = true;					
+					domain_load = true;
 				}
-				
+
 				asem = Assembly.Load (file);
-				
+
 				foreach (Type t in asem.GetTypes())
 				{
 					if (t.FullName == CLASS)
@@ -240,10 +155,10 @@ namespace gbrainy.Core.Main
 
 			foreach (GameXmlDefinition game in xml_games.Definitions)
 			{
-				// If the game has variants the game definition is used as reference 
+				// If the game has variants the game definition is used as reference
 				// but only the variants are playable. The first variant is used as game (IsGame = true)
 				available_games.Add (new GameLocator (type, cnt++, game.Type, true));
-				
+
 				switch (game.Type) {
 				case GameTypes.LogicPuzzle:
 					cnt_logic++;
@@ -254,7 +169,7 @@ namespace gbrainy.Core.Main
 				default:
 					break;
 				}
-					
+
 				for (int i = 1; i < game.Variants.Count; i++)
 				{
 					available_games.Add (new GameLocator (type, cnt++, game.Type, false));
@@ -333,7 +248,7 @@ namespace gbrainy.Core.Main
 		{
 			String s = string.Empty;
 	#if MONO_ADDINS
-			s += ServiceLocator.Instance.GetService <ITranslations> ().GetString ("Extensions database:") + " " + 
+			s += ServiceLocator.Instance.GetService <ITranslations> ().GetString ("Extensions database:") + " " +
 					System.IO.Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData), "gbrainy");
 
 			s += Environment.NewLine;
@@ -381,128 +296,5 @@ namespace gbrainy.Core.Main
 			}
 			return cnt;
 		}
-
-
-		// Taking a GameLocator list builds the play_list
-		void BuildPlayList (List <GameLocator> all_games)
-		{
-			if ((game_type & GameSession.Types.Custom) == GameSession.Types.Custom)
-				throw new InvalidOperationException ();
-
-			play_list.Clear ();
-
-			ArrayListIndicesRandom indices = new ArrayListIndicesRandom (all_games.Count);
-			indices.Initialize ();
-
-			List <int> logic_indices = new List <int> (cnt_logic);
-			List <int> calculation_indices = new List <int> (cnt_calculation);
-			List <int> memory_indices = new List <int> (cnt_memory);
-			List <int> verbal_indices = new List <int> (cnt_verbal);
-			bool logic, memory, calculation, verbal;
-
-			// Decide which game_types are part of the game
-			if ((game_type & GameSession.Types.AllGames) == GameSession.Types.AllGames)
-			{
-				logic = memory = calculation = verbal = true;
-			}
-			else
-			{
-				logic = (game_type & GameSession.Types.LogicPuzzles) == GameSession.Types.LogicPuzzles;
-				calculation = (game_type & GameSession.Types.Calculation) == GameSession.Types.Calculation;
-				memory = (game_type & GameSession.Types.Memory) == GameSession.Types.Memory;
-				verbal = (game_type & GameSession.Types.VerbalAnalogies) == GameSession.Types.VerbalAnalogies;
-			}
-
-			// Create arrays by game type
-			for (int n = 0; n < all_games.Count; n++)
-			{
-				switch (all_games [indices [n]].GameType) {
-				case GameTypes.LogicPuzzle:
-					if (logic)
-						logic_indices.Add (indices [n]);
-					break;
-				case GameTypes.Memory:
-					if (memory)
-						memory_indices.Add (indices [n]);
-					break;
-				case GameTypes.Calculation:
-					if (calculation)
-						calculation_indices.Add (indices [n]);
-					break;
-				case GameTypes.VerbalAnalogy:
-					if (verbal)
-						verbal_indices.Add (indices [n]);
-					break;
-				default:
-					throw new InvalidOperationException ("Unknown value");
-				}
-			}
-
-			int total = logic_indices.Count + memory_indices.Count + calculation_indices.Count + verbal_indices.Count;
-			int pos_logic, pos_memory, pos_calculation, pos_verbal;
-			Random random = new Random ();
-
-			pos_logic = pos_memory = pos_calculation = pos_verbal = 0;
-
-			while (play_list.Count < total)
-			{
-				switch (random.Next (3)) {
-				case 0:
-					if (pos_calculation < calculation_indices.Count) play_list.Add (calculation_indices[pos_calculation++]);
-					if (pos_logic < logic_indices.Count) play_list.Add (logic_indices[pos_logic++]);
-					if (pos_memory < memory_indices.Count) play_list.Add (memory_indices[pos_memory++]);
-					if (pos_verbal < verbal_indices.Count) play_list.Add (verbal_indices[pos_verbal++]);
-					break;
-				case 1:
-					if (pos_memory < memory_indices.Count) play_list.Add (memory_indices[pos_memory++]);
-					if (pos_calculation < calculation_indices.Count) play_list.Add (calculation_indices[pos_calculation++]);
-					if (pos_verbal < verbal_indices.Count) play_list.Add (verbal_indices[pos_verbal++]);
-					if (pos_logic < logic_indices.Count) play_list.Add (logic_indices[pos_logic++]);
-					break;
-				case 2:
-					if (pos_calculation < calculation_indices.Count) play_list.Add (calculation_indices[pos_calculation++]);
-					if (pos_verbal < verbal_indices.Count) play_list.Add (verbal_indices[pos_verbal++]);
-					if (pos_memory < memory_indices.Count) play_list.Add (memory_indices[pos_memory++]);
-					if (pos_logic < logic_indices.Count) play_list.Add (logic_indices[pos_logic++]);
-					break;
-				}
-			}
-			enumerator = play_list.GetEnumerator ();
-		}
-
-		public Game GetPuzzle ()
-		{
-			Game puzzle, first = null;
-
-			while (true) {
-
-				if (enumerator.MoveNext () == false) { // All the games have been played, restart again
-					enumerator = play_list.GetEnumerator ();
-					enumerator.MoveNext ();
-				}
-
-				puzzle =  (Game) Activator.CreateInstance ((Type) available_games [enumerator.Current].TypeOf, true);
-
-				puzzle.Variant = available_games [enumerator.Current].Variant;
-
-				if (first != null && first.GetType () == puzzle.GetType ())
-					break;
-
-				if (puzzle.IsPlayable == false)
-					continue;
-
-				if (ColorBlind == true && puzzle.UsesColors == true)
-					continue;
-
-				if (first == null)
-					first = puzzle;
-
-				if ((puzzle.Difficulty & difficulty) == difficulty)
-					break;
-			}
-
-			puzzle.CurrentDifficulty = Difficulty;
-			return puzzle;
-		}
 	}
 }
diff --git a/src/Core/Main/GameSession.cs b/src/Core/Main/GameSession.cs
index f059b29..70b17bf 100644
--- a/src/Core/Main/GameSession.cs
+++ b/src/Core/Main/GameSession.cs
@@ -60,6 +60,7 @@ namespace gbrainy.Core.Main
 		private PlayerHistory player_history;
 		private int id;
 		private GameSessionHistoryExtended history;
+		private GameSessionPlayList play_list;
 
 		public event EventHandler DrawRequest;
 		public event EventHandler <UpdateUIStateEventArgs> UpdateUIElement;
@@ -68,6 +69,7 @@ namespace gbrainy.Core.Main
 		{
 			id = 0;
 			game_manager = new GameManager ();
+			play_list = new GameSessionPlayList (game_manager);
 			game_time = TimeSpan.Zero;
 
 			timer = new System.Timers.Timer ();
@@ -103,13 +105,13 @@ namespace gbrainy.Core.Main
 		}
 	
 		public Types Type {
-			get {return game_manager.GameType; }
-			set {game_manager.GameType = value; }
+			get { return play_list.GameType; }
+			set { play_list.GameType = value; }
 		}
 
 		public GameDifficulty Difficulty {
-			get {return game_manager.Difficulty; }
-			set {game_manager.Difficulty = value; }
+			get { return play_list.Difficulty; }
+			set { play_list.Difficulty = value; }
 		}
 	
 		public string GameTime {
@@ -121,6 +123,11 @@ namespace gbrainy.Core.Main
 			set {paused = value; }
 		}
 
+		public GameSessionPlayList PlayList {
+			get { return play_list; }
+			set { play_list = value; }
+		}
+
 		public Game CurrentGame {
 			get {return current_game; }
 			set {
@@ -147,7 +154,10 @@ namespace gbrainy.Core.Main
 
 		public GameManager GameManager {
 			get { return game_manager;}
-			set { game_manager = value;}
+			set {
+				game_manager = value;
+				play_list.GameManager = value;
+			}
 		}
 
 		public string TimePerGame {
@@ -181,7 +191,6 @@ namespace gbrainy.Core.Main
 				}	
 			}
 		}
-
 	
 		public void New ()
 		{
@@ -228,7 +237,7 @@ namespace gbrainy.Core.Main
 				}
 
 				history.GamesPlayed++;
-				CurrentGame = game_manager.GetPuzzle ();
+				CurrentGame = play_list.GetPuzzle ();
 				CurrentGame.SynchronizingObject = SynchronizingObject;
 				CurrentGame.DrawRequest += GameDrawRequest;
 				CurrentGame.UpdateUIElement += GameUpdateUIElement;
diff --git a/src/Core/Main/GameSessionPlayList.cs b/src/Core/Main/GameSessionPlayList.cs
new file mode 100644
index 0000000..e27c768
--- /dev/null
+++ b/src/Core/Main/GameSessionPlayList.cs
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2007-2011 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.Linq;
+using System.Collections.Generic;
+
+namespace gbrainy.Core.Main
+{
+	// Manages a list of games to played within a session based on difficulty, game types and other parameters
+	public class GameSessionPlayList
+	{
+		IEnumerator <int> enumerator;
+		List <int> play_list; // Play list for the Selected difficulty, game types
+		GameDifficulty difficulty;
+		bool color_blind;
+		bool dirty;
+		GameSession.Types game_type;
+		GameManager manager;
+
+		public GameSessionPlayList (GameManager manager)
+		{
+			this.manager = manager;
+			play_list = new List <int> ();
+			game_type = GameSession.Types.AllGames;
+			difficulty = GameDifficulty.Medium;
+			RandomOrder = true;
+			dirty = true;
+		}
+
+		public bool ColorBlind {
+			get { return color_blind;}
+			set {
+				if (color_blind == value)
+					return;
+
+				color_blind = value;
+				dirty = true;
+			}
+		}
+
+		public GameDifficulty Difficulty {
+			set {
+				if (difficulty == value)
+					return;
+
+				difficulty = value;
+				dirty = true;
+			}
+			get { return difficulty; }
+		}
+
+		public GameManager GameManager {
+			get { return manager;}
+			set {
+				if (manager == value)
+					return;
+
+				manager = value;
+				dirty = true;
+			}
+		}
+
+		public GameSession.Types GameType {
+			get {return game_type; }
+			set {
+				if (game_type == value)
+					return;
+
+				game_type = value;
+				dirty = true;
+			}
+		}
+
+		// Indicates if the PlayList for CustomGames is delivered in RandomOrder
+ 		public bool RandomOrder { get; set; }
+
+		// Establish the PlayList (the indices of the array to available games)
+		public int [] PlayList {
+			get { return play_list.ToArray ();}
+			set {
+				play_list = new List <int> (value);
+				dirty = false;
+				UpdateEnumerator ();
+			}
+		}
+
+		void BuildListIfIsDirty ()
+		{
+			if (dirty == false)
+				return;
+
+			if ((game_type & GameSession.Types.Custom) != GameSession.Types.Custom)
+				BuildPlayList (manager.AvailableGames);
+
+			dirty = false;
+		}
+
+		// Taking a GameLocator list builds the play_list
+		void BuildPlayList (GameLocator [] all_games)
+		{
+			if ((game_type & GameSession.Types.Custom) == GameSession.Types.Custom)
+				throw new InvalidOperationException ();
+
+			ArrayListIndicesRandom indices = new ArrayListIndicesRandom (all_games.Length);
+			indices.Initialize ();
+			play_list.Clear ();
+
+			// Decide which game types are part of the list
+			bool logic, memory, calculation, verbal;
+			if ((game_type & GameSession.Types.AllGames) == GameSession.Types.AllGames)
+			{
+				logic = memory = calculation = verbal = true;
+			}
+			else
+			{
+				logic = (game_type & GameSession.Types.LogicPuzzles) == GameSession.Types.LogicPuzzles;
+				calculation = (game_type & GameSession.Types.Calculation) == GameSession.Types.Calculation;
+				memory = (game_type & GameSession.Types.Memory) == GameSession.Types.Memory;
+				verbal = (game_type & GameSession.Types.VerbalAnalogies) == GameSession.Types.VerbalAnalogies;
+			}
+
+			// Create item arrays for games types
+			List <int> logic_indices = new List <int> ();
+			List <int> calculation_indices = new List <int> ();
+			List <int> memory_indices = new List <int> ();
+			List <int> verbal_indices = new List <int> ();
+
+			if (logic)
+				logic_indices.AddRange (indices.Where (a => all_games[a].GameType == GameTypes.LogicPuzzle));
+
+			if (memory)
+				memory_indices.AddRange (indices.Where (a => all_games[a].GameType == GameTypes.Memory));
+
+			if (calculation)
+				calculation_indices.AddRange (indices.Where (a => all_games[a].GameType == GameTypes.Calculation));
+
+			if (verbal)
+				verbal_indices.AddRange (indices.Where (a => all_games[a].GameType == GameTypes.VerbalAnalogy));
+
+			CreateListWithDistributedGameTypes (logic_indices, calculation_indices, memory_indices, verbal_indices);
+			UpdateEnumerator ();
+		}
+
+		void CreateListWithDistributedGameTypes (List <int> logic_indices, List <int> calculation_indices, List <int> memory_indices,
+			List <int> verbal_indices)
+		{
+			int total = logic_indices.Count + memory_indices.Count + calculation_indices.Count + verbal_indices.Count;
+			int pos_logic, pos_memory, pos_calculation, pos_verbal;
+			Random random = new Random ();
+
+			pos_logic = pos_memory = pos_calculation = pos_verbal = 0;
+
+			while (play_list.Count < total)
+			{
+				switch (random.Next (3)) {
+				case 0:
+					if (pos_calculation < calculation_indices.Count) play_list.Add (calculation_indices[pos_calculation++]);
+					if (pos_logic < logic_indices.Count) play_list.Add (logic_indices[pos_logic++]);
+					if (pos_memory < memory_indices.Count) play_list.Add (memory_indices[pos_memory++]);
+					if (pos_verbal < verbal_indices.Count) play_list.Add (verbal_indices[pos_verbal++]);
+					break;
+				case 1:
+					if (pos_memory < memory_indices.Count) play_list.Add (memory_indices[pos_memory++]);
+					if (pos_calculation < calculation_indices.Count) play_list.Add (calculation_indices[pos_calculation++]);
+					if (pos_verbal < verbal_indices.Count) play_list.Add (verbal_indices[pos_verbal++]);
+					if (pos_logic < logic_indices.Count) play_list.Add (logic_indices[pos_logic++]);
+					break;
+				case 2:
+					if (pos_calculation < calculation_indices.Count) play_list.Add (calculation_indices[pos_calculation++]);
+					if (pos_verbal < verbal_indices.Count) play_list.Add (verbal_indices[pos_verbal++]);
+					if (pos_memory < memory_indices.Count) play_list.Add (memory_indices[pos_memory++]);
+					if (pos_logic < logic_indices.Count) play_list.Add (logic_indices[pos_logic++]);
+					break;
+				}
+			}
+		}
+
+		void UpdateEnumerator ()
+		{
+			if (RandomOrder == true)
+			{
+				ArrayListIndicesRandom random = new ArrayListIndicesRandom (play_list.Count);
+				random.RandomizeFromArray (play_list);
+				enumerator = random.GetEnumerator ();
+			}
+			else
+				enumerator = play_list.GetEnumerator ();
+		}
+
+		public Game GetPuzzle ()
+		{
+			Game puzzle, first = null;
+
+			BuildListIfIsDirty ();
+
+			while (true) {
+
+				if (enumerator.MoveNext () == false) { // All the games have been played, restart again
+					enumerator = play_list.GetEnumerator ();
+					enumerator.MoveNext ();
+				}
+
+				puzzle = (Game) Activator.CreateInstance ((Type) manager.AvailableGames [enumerator.Current].TypeOf, true);
+				puzzle.Variant = manager.AvailableGames [enumerator.Current].Variant;
+
+				if (first != null && first.GetType () == puzzle.GetType ())
+					break;
+
+				if (puzzle.IsPlayable == false)
+					continue;
+
+				if (ColorBlind == true && puzzle.UsesColors == true)
+					continue;
+
+				if (first == null)
+					first = puzzle;
+
+				if ((puzzle.Difficulty & difficulty) == difficulty)
+					break;
+			}
+
+			puzzle.CurrentDifficulty = Difficulty;
+			return puzzle;
+		}
+	}
+}
diff --git a/src/Core/Makefile.am b/src/Core/Makefile.am
index fb0cb29..4a58c4f 100644
--- a/src/Core/Makefile.am
+++ b/src/Core/Makefile.am
@@ -16,10 +16,12 @@ CSDISTFILES =  \
 		$(srcdir)/Main/GameAnswerCheckAttributes.cs \
 		$(srcdir)/Main/GameAnswerEventArgs.cs	\
 		$(srcdir)/Main/GameDifficulty.cs 	\
+		$(srcdir)/Main/GameLocator.cs		\
 		$(srcdir)/Main/GameManager.cs		\
 		$(srcdir)/Main/GameSession.cs		\
 		$(srcdir)/Main/GameSessionHistory.cs	\
 		$(srcdir)/Main/GameSessionHistoryExtended.cs \
+		$(srcdir)/Main/GameSessionPlayList.cs	\
 		$(srcdir)/Main/GameTypes.cs		\
 		$(srcdir)/Main/GameTips.cs		\
 		$(srcdir)/Main/Xml/DrawingObject.cs	\
diff --git a/tests/Clients/Classical/CommandLineTest.cs b/tests/Clients/Classical/CommandLineTest.cs
index 725d8ad..39593aa 100644
--- a/tests/Clients/Classical/CommandLineTest.cs
+++ b/tests/Clients/Classical/CommandLineTest.cs
@@ -57,7 +57,7 @@ namespace gbrainy.Test.Clients.Classical
 			const int game_cnt = 5; // number of games to pass as parameters
 			CommandLine line;
 			string [] args;
-			GameManager.GameLocator [] games;
+			GameLocator [] games;
 			GameManager gm = new GameManager ();
 			StringBuilder game_list = new StringBuilder ();
 			int [] candidates; // Stores the indexes of the games passed as parameters
diff --git a/tests/Core/GameManagerTest.cs b/tests/Core/GameManagerTest.cs
index bf8e16c..b8cef95 100644
--- a/tests/Core/GameManagerTest.cs
+++ b/tests/Core/GameManagerTest.cs
@@ -41,9 +41,9 @@ namespace gbrainy.Test.Core
 		public void GamesWithNoTip ()
 		{
 			int notip = 0;
-			GameManager.GameLocator [] games = manager.AvailableGames;
+			GameLocator [] games = manager.AvailableGames;
 
-			foreach (GameManager.GameLocator locator in games)
+			foreach (GameLocator locator in games)
 			{
 				Game game = (Game) Activator.CreateInstance (locator.TypeOf, true);
 				game.Variant = locator.Variant;
@@ -60,10 +60,10 @@ namespace gbrainy.Test.Core
 		public void GamesNoDuplicatedName ()
 		{
 			Dictionary <string, bool> dictionary;
-			GameManager.GameLocator [] games = manager.AvailableGames;
+			GameLocator [] games = manager.AvailableGames;
 			dictionary = new Dictionary <string, bool> (games.Length);
 
-			foreach (GameManager.GameLocator locator in games)
+			foreach (GameLocator locator in games)
 			{
 				if (locator.IsGame == false)
 					continue;
@@ -78,73 +78,11 @@ namespace gbrainy.Test.Core
 			}
 		}
 
-		[Test]
-		public void CustomGamesRandomOrder ()
-		{
-			Dictionary <int, string> dictionary;
-			GameManager.GameLocator [] games;
-
-			List <int> list = new List <int> ();
-			games = manager.AvailableGames;
-
-			// Create a hash to map from game name to locator
-			dictionary = new Dictionary <int, string> (games.Length);
-			for (int i = 0; i < games.Length; i++)
-			{
-				if (games[i].IsGame == false)
-					continue;
-
-				Game game = (Game) Activator.CreateInstance (games[i].TypeOf, true);
-				game.Variant = games[i].Variant;
-				dictionary.Add (i, game.Name);
-				list.Add (dictionary.Count - 1);
-			}
-
-			Game current;
-			string name;
-
-			manager.RandomOrder = false;
-			manager.PlayList = list.ToArray ();
-
-			for (int i = 0; i < list.Count; i++)
-			{
-				current = manager.GetPuzzle ();
-
-				try
-				{
-					name = dictionary [i];
-					Assert.AreEqual (true, name == current.Name);
-				}
-				catch (KeyNotFoundException)
-				{
-
-				}
-			}
-		}
-
-		[Test]
-		public void ColorBlind ()
-		{
-			Game game;
-			GameManager.GameLocator [] games;
-
-			GameManager manager = new GameManager ();
-			manager.GameType = GameSession.Types.AllGames;
-			manager.ColorBlind = true;
-			games = manager.AvailableGames;
-
-			for (int i = 0; i < games.Length; i++)
-			{
-				game = (Game) manager.GetPuzzle ();
-				Assert.AreEqual (false, game.UsesColors);
-			}
-		}
 
 		[Test]
 		public void ResetAvailableGames ()
 		{
 			GameManager manager = new GameManager ();
-			manager.GameType = GameSession.Types.AllGames;
 			manager.LoadAssemblyGames ("gbrainy.Games.dll");
 			Assert.AreNotEqual (0, manager.AvailableGames.Length);
 
@@ -156,14 +94,13 @@ namespace gbrainy.Test.Core
 		public void XmlGames ()
 		{
 			GameManager manager = new GameManager ();
-			manager.GameType = GameSession.Types.AllGames;
 			manager.LoadGamesFromXml ("test_games.xml");
 
 			Assert.AreEqual (3, manager.AvailableGames.Length);
 			int logic_variants = 0;
 			int logic_games = 0;
 
-			foreach (GameManager.GameLocator locator in manager.AvailableGames)
+			foreach (GameLocator locator in manager.AvailableGames)
 			{
 				if (locator.GameType != GameTypes.LogicPuzzle)
 					continue;
diff --git a/tests/Core/GameSessionPlayListTest.cs b/tests/Core/GameSessionPlayListTest.cs
new file mode 100644
index 0000000..fe1e7db
--- /dev/null
+++ b/tests/Core/GameSessionPlayListTest.cs
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2010 Jordi Mas i HernÃndez <jmas softcatala org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+using System;
+using System.Collections.Generic;
+using NUnit.Framework;
+
+using gbrainy.Core.Main;
+
+namespace gbrainy.Test.Core
+{
+	[TestFixture]
+	public class GameSessionPlayListTest : UnitTestSupport
+	{
+		GameManager manager;
+
+		[TestFixtureSetUp]
+		public void Construct ()
+		{
+			RegisterDefaultServices ();
+			manager = new GameManager ();
+		}
+
+		[Test]
+		public void CustomGamesNoRandomOrder ()
+		{
+			Dictionary <int, string> dictionary;
+			GameLocator [] games;
+			GameSessionPlayList play_list = new GameSessionPlayList (manager);
+
+			List <int> list = new List <int> ();
+			games = manager.AvailableGames;
+
+			// Create a hash to map from game name to locator
+			dictionary = new Dictionary <int, string> (games.Length);
+			for (int i = 0; i < games.Length; i++)
+			{
+				if (games[i].IsGame == false)
+					continue;
+
+				Game game = (Game) Activator.CreateInstance (games[i].TypeOf, true);
+				game.Variant = games[i].Variant;
+				dictionary.Add (i, game.Name);
+				list.Add (dictionary.Count - 1);
+			}
+
+			Game current;
+			string name;
+
+			play_list.RandomOrder = false;
+			play_list.PlayList = list.ToArray ();
+
+			for (int i = 0; i < list.Count; i++)
+			{
+				current = play_list.GetPuzzle ();
+
+				try
+				{
+					name = dictionary [i];
+					Assert.AreEqual (true, name == current.Name);
+				}
+				catch (KeyNotFoundException)
+				{
+
+				}
+			}
+		}
+
+		[Test]
+		public void ColorBlind ()
+		{
+			Game game;
+			GameSessionPlayList play_list = new GameSessionPlayList (manager);
+
+			play_list.ColorBlind = true;
+			for (int i = 0; i < play_list.PlayList.Length; i++)
+			{
+				game = play_list.GetPuzzle ();
+				Assert.AreEqual (false, game.UsesColors);
+			}
+		}
+
+		[Test]
+		public void Difficulty ()
+		{
+			Game game;
+			GameSessionPlayList play_list = new GameSessionPlayList (manager);
+
+			play_list.Difficulty = GameDifficulty.Easy;
+			for (int i = 0; i < play_list.PlayList.Length; i++)
+			{
+				game = play_list.GetPuzzle ();
+				Assert.AreEqual (GameDifficulty.Easy, game.Difficulty);
+			}
+		}
+	}
+}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 52defa9..6bc2c73 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -16,7 +16,8 @@ CSFILES_CORE =					\
 	$(srcdir)/Core/GameManagerTest.cs \
 	$(srcdir)/Core/GameAnswerTest.cs \
 	$(srcdir)/Core/GameXmlFactoryTest.cs \
-	$(srcdir)/Core/PreferencesTest.cs
+	$(srcdir)/Core/PreferencesTest.cs \
+	$(srcdir)/Core/GameSessionPlayListTest.cs
 
 CSFILES_CLASSICAL =					\
 	$(srcdir)/TestSupport/UnitTestSupport.cs \



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