2
* Copyright (C) 2007 Jordi Mas i Hernàndez <jmas@softcatala.org>
4
* This program is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU General Public License as
6
* published by the Free Software Foundation; either version 2 of the
7
* License, or (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* General Public License for more details.
14
* You should have received a copy of the GNU General Public
15
* License along with this program; if not, write to the
16
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17
* Boston, MA 02111-1307, USA.
23
using System.ComponentModel;
25
using gbrainy.Core.Views;
26
using gbrainy.Core.Libraries;
28
namespace gbrainy.Core.Main
30
public class GameSession : IDrawable, IDrawRequest
38
CalculationTrainers = 8,
41
TrainersOnly = MemoryTrainers | CalculationTrainers,
42
AllGames = MemoryTrainers | CalculationTrainers | LogicPuzzles
45
private enum ScoresType
55
public enum SessionStatus
63
// Data kept for every game type in raw data (processed with a formula after)
64
public class Statistics
66
public int Played { get; set; }
67
public int Won { get; set; }
68
public int Scored { get; set; }
71
private TimeSpan game_time;
72
private int games_played;
73
private int games_won;
74
private Game current_game;
75
private GameManager game_manager;
76
private System.Timers.Timer timer;
78
private string current_time;
79
private TimeSpan one_sec = TimeSpan.FromSeconds (1);
80
private int total_score;
81
private bool scored_game;
82
private SessionStatus status;
83
private ViewsControler controler;
84
private ISynchronizeInvoke synchronize;
85
private PlayerHistory history;
86
private Statistics [] statistics;
89
public event EventHandler DrawRequest;
90
public event EventHandler <UpdateUIStateEventArgs> UpdateUIElement;
95
game_manager = new GameManager ();
96
game_time = TimeSpan.Zero;
98
timer = new System.Timers.Timer ();
99
timer.Elapsed += TimerUpdater;
100
timer.Interval = (1 * 1000); // 1 second
102
statistics = new Statistics [(int) ScoresType.Last];
104
for (int i = 0; i < (int) ScoresType.Last; i++)
105
statistics [i] = new Statistics ();
107
controler = new ViewsControler (this);
108
Status = SessionStatus.NotPlaying;
109
history = new PlayerHistory ();
116
public PlayerHistory PlayerHistory {
117
set { history = value; }
118
get { return history; }
121
public ISynchronizeInvoke SynchronizingObject {
122
set { synchronize = value; }
123
get { return synchronize; }
127
get {return game_manager.GameType; }
128
set {game_manager.GameType = value; }
131
public Game.Difficulty Difficulty {
132
get {return game_manager.Difficulty; }
133
set {game_manager.Difficulty = value; }
136
public TimeSpan GameTime {
137
get {return game_time; }
138
set {game_time = value; }
141
public int GamesPlayed {
142
get {return games_played; }
143
set { games_played = value;}
146
public int GamesWon {
147
get {return games_won; }
148
set {games_won = value; }
152
get {return paused; }
153
set {paused = value; }
156
public Game CurrentGame {
157
get {return current_game; }
159
current_game = value;
160
controler.Game = value;
164
public bool EnableTimer {
165
get {return timer.Enabled; }
166
set {timer.Enabled = value; }
169
public SessionStatus Status {
170
get {return status; }
173
controler.Status = value;
177
public GameManager GameManager {
178
get {return game_manager;}
181
public int TotalScore {
182
get {return total_score;}
185
public int LogicScore {
187
if (statistics [(int) ScoresType.LogicPuzzles].Played == 0)
190
return ScoreFormula (statistics [(int) ScoresType.LogicPuzzles]);
194
public int MemoryScore {
196
if (statistics [(int) ScoresType.MemoryTrainers].Played == 0)
199
return ScoreFormula (statistics [(int) ScoresType.MemoryTrainers]);
203
public int MathScore {
205
if (statistics [(int) ScoresType.CalculationTrainers].Played == 0)
208
return ScoreFormula (statistics [(int) ScoresType.CalculationTrainers]);
212
public int VerbalScore {
214
if (statistics [(int) ScoresType.VerbalAnalogies].Played == 0)
217
return ScoreFormula (statistics [(int) ScoresType.VerbalAnalogies]);
221
public string TimePlayed {
223
return (current_time == null) ? TimeSpanToStr (TimeSpan.FromSeconds (0)) : current_time;
227
public string TimePerGame {
231
average = (games_played > 0) ? TimeSpan.FromSeconds (game_time.TotalSeconds / games_played) : game_time;
232
return TimeSpanToStr (average);
236
public string StatusText {
238
if (Status == SessionStatus.NotPlaying)
242
text = String.Format (Catalog.GetString ("Games played: {0} ({1}% score)"),games_played, total_score);
243
text += String.Format (Catalog.GetString (" - Time: {0}"), current_time);
245
if (CurrentGame != null)
246
text += " " + String.Format (Catalog.GetString ("- Game: {0}"), CurrentGame.Name);
252
public void NewSession ()
255
if (Status != SessionStatus.NotPlaying)
258
current_time = TimeSpanToStr (game_time);
260
for (int i = 0; i < (int) ScoresType.Last; i++)
261
statistics [i] = new Statistics ();
266
game_time = TimeSpan.Zero;
267
timer.SynchronizingObject = SynchronizingObject;
271
public void EndSession ()
273
history.SaveGameSession (this);
275
if (CurrentGame != null)
276
CurrentGame.Finish ();
279
timer.SynchronizingObject = null;
283
Status = SessionStatus.Finished;
286
public void NextGame ()
288
if (CurrentGame != null)
289
CurrentGame.Finish ();
292
CurrentGame = game_manager.GetPuzzle ();
293
CurrentGame.SynchronizingObject = SynchronizingObject;
294
CurrentGame.DrawRequest += GameDrawRequest;
295
CurrentGame.UpdateUIElement += GameUpdateUIElement;
297
CurrentGame.Initialize ();
299
CurrentGame.GameTime = TimeSpan.Zero;
301
Status = SessionStatus.Playing;
308
current_time = Catalog.GetString ("Paused");
311
public void Resume ()
318
How the game session is scored
320
* Every game has a scoring algorithm that scores the player performance within the game.
321
This takes into account time used and tips (result is from 0 to 10)
322
* The results are added to the games and scores arrays where we store the results for
323
the different game types (verbal, logic, etc)
324
* We apply a ScoreFormula function that balances the total result with the number of
325
games played (is not the same 100% games won playing 2 than 10 games) and the difficulty
327
The final result is a number from 0 to 100
330
public bool ScoreGame (string answer)
336
if (CurrentGame == null || scored_game == true)
339
score = CurrentGame.Score (answer);
346
switch (CurrentGame.Type) {
347
case Game.Types.LogicPuzzle:
348
statistics [(int) ScoresType.LogicPuzzles].Scored += score;
349
statistics [(int) ScoresType.LogicPuzzles].Played++;
350
if (won) statistics [(int) ScoresType.LogicPuzzles].Won++;
352
case Game.Types.MemoryTrainer:
353
statistics [(int) ScoresType.MemoryTrainers].Scored += score;
354
statistics [(int) ScoresType.MemoryTrainers].Played++;
355
if (won) statistics [(int) ScoresType.MemoryTrainers].Won++;
357
case Game.Types.MathTrainer:
358
statistics [(int) ScoresType.CalculationTrainers].Scored += score;
359
statistics [(int) ScoresType.CalculationTrainers].Played++;
360
if (won) statistics [(int) ScoresType.CalculationTrainers].Won++;
362
case Game.Types.VerbalAnalogy:
363
statistics [(int) ScoresType.VerbalAnalogies].Scored += score;
364
statistics [(int) ScoresType.VerbalAnalogies].Played++;
365
if (won) statistics [(int) ScoresType.VerbalAnalogies].Won++;
373
// Updates total score taking only into account played game types
374
if (LogicScore >= 0) {
375
total_score += LogicScore;
379
if (MemoryScore >= 0) {
380
total_score += MemoryScore;
384
if (MathScore >= 0) {
385
total_score += MathScore;
389
if (VerbalScore >= 0) {
390
total_score += VerbalScore;
394
total_score = total_score / components;
401
// Applies scoring formula to the session
403
int ScoreFormula (Statistics stats)
406
double score, factor;
408
switch (Difficulty) {
409
case Game.Difficulty.Easy:
412
case Game.Difficulty.Medium:
415
case Game.Difficulty.Master:
419
throw new InvalidOperationException ("Invalid switch value");
422
// Simple percentage of games won vs played
423
score = stats.Scored > 0 ? stats.Scored / stats.Played * 10 : 0;
425
// Puts score of the game in prespective for the whole game
426
factor = Math.Log (stats.Won + 2, logbase); // +2 to avoid log 0
428
score = score * factor;
430
if (score > 100) score = 100;
435
private void TimerUpdater (object source, ElapsedEventArgs e)
438
if (CurrentGame == null)
441
game_time = game_time.Add (one_sec);
442
CurrentGame.GameTime = CurrentGame.GameTime + one_sec;
443
current_time = TimeSpanToStr (game_time);
446
if (UpdateUIElement == null)
449
UpdateUIElement (this, new UpdateUIStateEventArgs (UpdateUIStateEventArgs.EventUIType.Time, null));
452
static private string TimeSpanToStr (TimeSpan time)
454
string fmt = time.ToString ();
455
int i = fmt.IndexOf ('.');
456
if (i > 0 && fmt.Length - i > 2)
457
fmt = fmt.Substring (0, i);
462
public void GameUpdateUIElement (object obj, UpdateUIStateEventArgs args)
464
if (UpdateUIElement != null)
465
UpdateUIElement (this, args);
468
// A game has requested a redraw, scale the request to the object
469
// subscribed to GameSession.GameDrawRequest
470
public void GameDrawRequest (object o, EventArgs args)
472
if (DrawRequest != null)
473
DrawRequest (this, EventArgs.Empty);
476
public virtual void Draw (CairoContextEx gr, int width, int height, bool rtl)
478
controler.CurrentView.Draw (gr, width, height, rtl);