Click here to Skip to main content
15,896,557 members
Articles / Desktop Programming / WTL

The Psychology of a WTL Project: Lowercase Cause (a typing program)

Rate me:
Please Sign up or sign in to vote.
4.99/5 (32 votes)
20 Apr 200524 min read 64K   2.7K   25  
A psychological journey into a project crafted from start to finish.
#pragma once
#include "stdafx.h"

class phrase_list;

// ------------------------------------------------------------[constants]---
//

// used to compare if a time has a null time, you can't really check for 0
// because local time settings will change it when you pass it to the 
// constructor
const CTime NULL_TIME = CTime(1984, 4, 13, 0, 0, 0);

// id for our timer
const UINT GAME_SESSION_TIMER = 201;

// our difficulty logic constants 
const int DIFFICULTY_LEVELS = 8;
const int WPM_INCREASE_FACTOR = 10;
const int TIMED_START_WINDOWS = 5;
const int TIMED_START_LIVES = 5000;

// how points are calculated
const int POINTS_FOR_GOOD_CHARACTERS = 1;
const int POINTS_FOR_BAD_CHARACTERS = -2;
const int POINTS_FOR_CLOSED_WINDOWS = 10;

const int STARTING_LIVES = 4;

// our color table for the fade color
const int COLORS_COUNT = 1;
const COLORREF COLORS[COLORS_COUNT] = 
	{ RGB(128, 0, 255) };

// our game modes or types
enum game_type { SURVIVAL, TIMED };

// default high score filename, zoo because it holds high scores which are
// metaphorical to animals. i made that up
const std::string HIGH_SCORE_FILENAME = _T("high_scores.zoo");

// the delimiter to use for our high scores, i used | because you can't
// have that in filenames
const TCHAR DELIMITER = _T('|');

//
// -----------------------------------------------------------[/constants]---
// ---------------------------------------------------------[game_session]---
// 

// all settings necessary for a customized new game
class game_session
{
public:
	game_session() : _difficulty(1) { reset(); }

	void init(HWND hwnd); // we need a hwnd associated for our timer
	void reset(); // initialize everything to 0

	void increment_valid_characters();
	void increment_invalid_characters();
	void increment_closed_windows();

	// statistics on what characters have been typed
	int get_total_characters() const { return _total_characters; }
	int get_correct_characters() const { return _correct_characters; }
	int get_closed_windows() const { return _closed_windows; }

	// time functions
	// --------------
	game_type get_game_type() const;
	CTimeSpan get_running_time() const;
	CTimeSpan get_time_left() const;

	void set_timer(int timer);
	void start(); // start timer
	void end(); 

	bool is_timed() const { return _timer != 0; }
	long get_timer() const { return _timer; }

	bool has_started() const; // whether or not the game has starter
	bool is_over() const; // whether or not the game is over

	// statistics derived from characters typed
	int get_wpm() const;
	int get_awpm() const;
	int get_accuracy() const;
	int get_points() const;

	void set_lives(int lives) { _lives = lives; }
	void decrement_lives() { _lives--; }
	int get_lives() const { return _lives; }

	void set_difficulty(int difficulty) 
		{ _difficulty = difficulty; set_lives(get_starting_lives()); }
	int get_difficulty() const { return _difficulty; }

	// returns the number of windows we should display initially
	// based on the difficulty 
	int get_starting_windows() const;

	// return the number of lives based on the difficulty
	int get_starting_lives() const;

	// get the number of seconds that a window should be displayed
	// based on the difficulty and WPM_INCREATE_FACTOR
	int get_window_life(const std::string& s) const;
	int get_seconds_to_type_length(int length) const;

	// returns the wpm expected at the current difficulty if 
	// difficulty is -1 or the target wpm at difficulty
	int get_target_wpm(int difficulty = -1) const;

	void set_average_phrase_length(int average_length)
	{ _average_phrase_length = average_length; }
	int get_average_phrase_length() const { return _average_phrase_length; }

	BEGIN_MSG_MAP(game_session)
		MESSAGE_HANDLER(WM_TIMER, OnTimer)
	END_MSG_MAP()

	LRESULT OnTimer(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);

private:
	int _lives;
	int _difficulty;

	// math used for calculating both wpm and awpm
	int _get_wpm(int characters) const;

	// window handle required to be associated with it for our timer
	HWND _hwnd;

	// characters typed, falling into 2 categories. good and bad
	int _total_characters;
	int _correct_characters;

	// windows successfully typed away
	int _closed_windows;

	// used to calculate wpm and awpm. marks the start of when the typing
	// session begins
	CTime _start_time;

	// sets the end time when finished so that our wpm and awpm calculations
	// don't decay
	CTime _end_time;

	// used for timed games, 0 if not timed
	long _timer;

	// used for calculating our get_window_life
	int _average_phrase_length;
};

//
// --------------------------------------------------------[/game_session]---
// ----------------------------------------------------------[phrase_list]---
//

// class which manages our phrases for a list
typedef std::list<std::string> string_list_t;
string_list_t get_phrase_files();

class phrase_list
{
public:
	typedef std::vector<std::string> phrase_list_t;
	void load_phrase_list(const std::string& path);
	std::string get_random_phrase() const;
	std::string get_file_name() const { return _file_name; }
	size_t get_count() const { return _list.size(); }
	int get_average_length() const;

private:
	void _process_line(const std::string& line);
	phrase_list_t _list;
	std::string _file_name;
};

//
// ---------------------------------------------------------[/phrase_list]---
// -----------------------------------------------------------[high_score]---
//

// provides a way of handling high scores
class high_score
{
public:
	high_score() : _points(0) {}
	high_score(const game_session& gs, const std::string& phrase_list);

	bool is_null() const { return _points == 0; }

	void set_name(const std::string& name) { _name = name; }
	void set_phrase_list(const std::string& pl) { _phrase_list = pl; }
	void set_difficulty(int difficulty) { _difficulty = difficulty; }
	void set_points(int points) { _points = points; }
	void set_time(long time) { _time = time; }
	void set_type(game_type type) { _type = type; }
	void set_awpm(int awpm) { _awpm = awpm; }
	void set_wpm(int wpm) { _wpm = wpm; }
	
	std::string get_name() const { return _name; }
	std::string get_phrase_list() const { return _phrase_list; }
	int get_difficulty() const { return _difficulty; }
	int get_points() const { return _points; }
	long get_time() const { return _time; }
	game_type get_type() const { return _type; }
	int get_awpm() const { return _awpm; }
	int get_wpm() const { return _wpm; }

	std::string get_string() const;
	std::string get_type_string() const;

private:
	std::string _name;
	std::string _phrase_list;
	game_type _type;
	int _difficulty;
	int _points;
	long _time;
	int _wpm;
	int _awpm;
};

//
// ----------------------------------------------------------[/high_score]---
// ---------------------------------------------------[high_score_manager]---
//

// singleton for accessing a container of high scores
class high_score_manager
{
public:
	typedef std::vector<high_score> high_score_list_t;

	// returns the high score in the manager associated with the passed 
	// high_score
	static high_score get_current_high_score(const high_score& hs);

	// will compare the passed high_score with the current high_score and 
	// return true if the passed is higher
	static bool is_high_score(const high_score& hs);

	// add a new high_score (will replace the old if any)
	static void add(high_score hs);

	static void save();
	static void load();

	// return the list of our high scores
	static high_score_list_t& get_list() { return _list; }

private:
	static high_score_list_t::iterator 
		_get_current_high_score(const high_score& hs);

	// parsing helpers
	static size_t _get_next_token_as_string(std::string& s, 
		const std::string& buffer, size_t index, TCHAR delimiter = DELIMITER);
	static size_t _get_next_token_as_long(long& l, const std::string& buffer, 
		size_t index, TCHAR delimiter = DELIMITER);

	static high_score_list_t _list;
};

//
// --------------------------------------------------[/high_score_manager]---

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions