better calories tracking

This commit is contained in:
Chris Danford
2004-02-22 23:29:13 +00:00
parent 9e6a952a41
commit 06c9073fcf
8 changed files with 246 additions and 59 deletions
-29
View File
@@ -28,35 +28,6 @@ static const CString COINS_DAT = "Data/Coins.dat";
const int COINS_DAT_VERSION = 1;
tm AddDays( tm start, int iDaysToMove )
{
start.tm_mday += iDaysToMove;
time_t seconds = mktime( &start );
ASSERT( seconds != (time_t)-1 );
tm time;
localtime_r( &seconds, &time );
return time;
}
tm GetYesterday( tm start )
{
return AddDays( start, -1 );
}
int GetDayOfWeek( tm time )
{
int iDayOfWeek = time.tm_wday;
ASSERT( iDayOfWeek < DAYS_IN_WEEK );
return iDayOfWeek;
}
tm GetNextSunday( tm start )
{
return AddDays( start, DAYS_IN_WEEK-GetDayOfWeek(start) );
}
Bookkeeper::Bookkeeper()
{
int i, j;
+76 -20
View File
@@ -95,7 +95,6 @@ void Profile::InitGeneralData()
m_iNumSongsPlayedByMeter[i] = 0;
ZERO( m_iNumSongsPassedByPlayMode );
ZERO( m_iNumSongsPassedByGrade );
ZERO( m_iCaloriesByDayForLastYear );
}
void Profile::InitSongScores()
@@ -120,6 +119,11 @@ void Profile::InitScreenshotData()
m_vScreenshots.clear();
}
void Profile::InitCalorieData()
{
m_mapDayToCaloriesBurned.clear();
}
CString Profile::GetDisplayName() const
{
if( !m_sDisplayName.empty() )
@@ -135,7 +139,7 @@ CString Profile::GetDisplayTotalCaloriesBurned() const
if( m_fWeightPounds == 0 ) // weight not entered
return "N/A";
else
return ssprintf("%0.3fCal",m_fTotalCaloriesBurned);
return ssprintf("%0.3f Cal",m_fTotalCaloriesBurned);
}
int Profile::GetTotalNumSongsPlayed() const
@@ -385,6 +389,7 @@ bool Profile::LoadAllFromDir( CString sDir )
LOAD_NODE( CourseScores );
LOAD_NODE( CategoryScores );
LOAD_NODE( ScreenshotData );
LOAD_NODE( CalorieData );
}
return true; // FIXME? Investigate what happens if we always return true.
@@ -408,6 +413,7 @@ bool Profile::SaveAllToDir( CString sDir ) const
xml.AppendChild( SaveCourseScoresCreateNode() );
xml.AppendChild( SaveCategoryScoresCreateNode() );
xml.AppendChild( SaveScreenshotDataCreateNode() );
xml.AppendChild( SaveCalorieDataCreateNode() );
bool bSaved = xml.SaveToFile(fn);
if( bSaved && PREFSMAN->m_bSignProfileData )
{
@@ -585,17 +591,6 @@ XNode* Profile::SaveGeneralDataCreateNode() const
}
}
{
XNode* pCaloriesByDayForLastYear = pGeneralDataNode->AppendChild("CaloriesByDayForLastYear");
for( int i=0; i<DAYS_IN_YEAR; i++ )
{
/* Don't save empty. */
if( m_iCaloriesByDayForLastYear[i]==0 )
continue;
pCaloriesByDayForLastYear->AppendChild( DayInYearToString(i), m_iCaloriesByDayForLastYear[i] );
}
}
return pGeneralDataNode;
}
@@ -727,13 +722,6 @@ void Profile::LoadGeneralDataFromNode( const XNode* pNode )
}
{
XNode* pCaloriesByDayForLastYear = pNode->GetChild("CaloriesByDayForLastYear");
if( pCaloriesByDayForLastYear )
for( int i=0; i<DAYS_IN_YEAR; i++ )
pCaloriesByDayForLastYear->GetChildValue( DayInYearToString(i), m_iCaloriesByDayForLastYear[i] );
}
}
void Profile::AddStepTotals( int iTotalTapsAndHolds, int iTotalJumps, int iTotalHolds, int iTotalMines, int iTotalHands )
@@ -753,6 +741,11 @@ void Profile::AddStepTotals( int iTotalTapsAndHolds, int iTotalJumps, int iTotal
SCALE( m_fWeightPounds, 100.f, 200.f, 0.000f, 0.000f ) * iTotalMines +
SCALE( m_fWeightPounds, 100.f, 200.f, 0.222f, 0.386f ) * iTotalHands;
m_fTotalCaloriesBurned += fCals;
time_t cur_time = time(NULL);
tm *cur_tm = localtime( &cur_time );
Day day = { cur_tm->tm_yday, cur_tm->tm_year+1900 };
m_mapDayToCaloriesBurned[day] += fCals;
}
}
@@ -1451,3 +1444,66 @@ XNode* Profile::SaveScreenshotDataCreateNode() const
return pNode;
}
void Profile::LoadCalorieDataFromNode( const XNode* pNode )
{
CHECKPOINT;
ASSERT( pNode->name == "CalorieData" );
for( XNodes::const_iterator pDay = pNode->childs.begin();
pDay != pNode->childs.end();
pDay++ )
{
if( (*pDay)->name != "Day" )
WARN_AND_CONTINUE;
Day day;
if( !(*pDay)->GetAttrValue("DayInYear",day.iDayInYear) )
WARN_AND_CONTINUE;
if( !(*pDay)->GetAttrValue("Year",day.iYear) )
WARN_AND_CONTINUE;
float fCaloriesBurned = 0;
if( !(*pDay)->GetChildValue("CaloriesBurned",fCaloriesBurned) )
WARN_AND_CONTINUE;
m_mapDayToCaloriesBurned[day] = fCaloriesBurned;
}
}
XNode* Profile::SaveCalorieDataCreateNode() const
{
CHECKPOINT;
const Profile* pProfile = this;
ASSERT( pProfile );
XNode* pNode = new XNode;
pNode->name = "CalorieData";
for( map<Day,float>::const_iterator i = m_mapDayToCaloriesBurned.begin();
i != m_mapDayToCaloriesBurned.end();
i++ )
{
XNode* pDay = pNode->AppendChild( "Day" );
pDay->AppendAttr( "DayInYear", i->first.iDayInYear );
pDay->AppendAttr( "Year", i->first.iYear );
pDay->AppendChild( "CaloriesBurned", i->second );
}
return pNode;
}
float Profile::GetCaloriesBurnedForDay( Day day ) const
{
map<Day,float>::const_iterator i = m_mapDayToCaloriesBurned.find( day );
if( i == m_mapDayToCaloriesBurned.end() )
return 0;
else
return i->second;
}
+33 -3
View File
@@ -72,6 +72,8 @@ public:
int GetTotalNumSongsPassed() const;
static CString GetProfileDisplayNameFromDir( CString sDir );
int GetSongNumTimesPlayed( const Song* pSong ) const;
void AddStepTotals( int iNumTapsAndHolds, int iNumJumps, int iNumHolds, int iNumMines, int iNumHands );
//
// Editable data
@@ -107,9 +109,6 @@ public:
int m_iNumSongsPlayedByMeter[MAX_METER+1];
int m_iNumSongsPassedByPlayMode[NUM_PLAY_MODES];
int m_iNumSongsPassedByGrade[NUM_GRADES];
int m_iCaloriesByDayForLastYear[DAYS_IN_YEAR];
void AddStepTotals( int iNumTapsAndHolds, int iNumJumps, int iNumHolds, int iNumMines, int iNumHands );
//
// Steps high scores
@@ -171,6 +170,33 @@ public:
void AddScreenshot( Screenshot screenshot );
int GetNextScreenshotIndex() { return m_vScreenshots.size(); }
//
// Calorie Data
//
// Why track calories in a map, and not in a static sized array like
// Bookkeeping? The machine's clock is not guaranteed to be set correctly.
// If calorie array is in a static sized array, playing on a machine with
// a mis-set clock could wipe out all your past data. With this scheme,
// the worst that could happen is that playing on a mis-set machine will
// insert some garbage entries into the map.
struct Day
{
int iDayInYear; // 0-365
int iYear; // e.g. 2004
bool operator==( const Day& other ) const { return iDayInYear==other.iDayInYear && iYear==other.iYear; }
bool operator<( const Day& other ) const
{
if(iYear<other.iYear)
return true;
if( iYear>other.iYear)
return false;
else
return iDayInYear<other.iDayInYear;
}
};
map<Day,float> m_mapDayToCaloriesBurned;
float GetCaloriesBurnedForDay( Day day ) const;
//
// Init'ing
@@ -183,6 +209,7 @@ public:
InitCourseScores();
InitCategoryScores();
InitScreenshotData();
InitCalorieData();
}
void InitEditableData();
void InitGeneralData();
@@ -190,6 +217,7 @@ public:
void InitCourseScores();
void InitCategoryScores();
void InitScreenshotData();
void InitCalorieData();
//
// Loading and saving
@@ -208,6 +236,7 @@ public:
void LoadCourseScoresFromNode( const XNode* pNode );
void LoadCategoryScoresFromNode( const XNode* pNode );
void LoadScreenshotDataFromNode( const XNode* pNode );
void LoadCalorieDataFromNode( const XNode* pNode );
void SaveEditableDataToDir( CString sDir ) const;
XNode* SaveGeneralDataCreateNode() const;
@@ -215,6 +244,7 @@ public:
XNode* SaveCourseScoresCreateNode() const;
XNode* SaveCategoryScoresCreateNode() const;
XNode* SaveScreenshotDataCreateNode() const;
XNode* SaveCalorieDataCreateNode() const;
void DeleteProfileDataFromDirSM390a12( CString sDir ) const;
void DeleteSongScoresFromDirSM390a12( CString sDir ) const;
+49 -7
View File
@@ -363,6 +363,7 @@ void PrintStatistics( RageFile &f, const Profile *pProfile, CString sTitle, vect
END_TABLE;
}
PRINT_CLOSE(f);
}
PRINT_CLOSE(f);
}
@@ -855,13 +856,7 @@ void PrintBookkeeping( RageFile &f, const Profile *pProfile, CString sTitle, vec
BEGIN_TABLE(4);
for( int i=0; i<NUM_LAST_WEEKS; i++ )
{
CString sWeek;
switch( i )
{
case 0: sWeek = "This week"; break;
case 1: sWeek = "Last week"; break;
default: sWeek = ssprintf("%d weeks ago",i); break;
}
CString sWeek = LastWeekToString( i );
TABLE_LINE2( sWeek, coins[i] );
}
END_TABLE;
@@ -972,6 +967,51 @@ void PrintScreenshots( RageFile &f, const Profile *pProfile, CString sTitle, CSt
PRINT_CLOSE(f);
}
void PrintCaloriesBurned( RageFile &f, const Profile *pProfile, CString sTitle, CString sProfileDir )
{
PRINT_OPEN(f, sTitle );
{
f.Write("<table>\n");
// header row
f.Write("<tr>");
f.Write("<td></td>");
{
for( int i=0; i<DAYS_IN_WEEK; i++ )
f.Write("<td>"+DayOfWeekToString(i)+"</td>");
}
f.Write("<td>Total</td>");
f.Write("</tr>");
// row for each week
time_t now = time( NULL );
tm when = *localtime( &now );
when = GetNextSunday( when );
when = AddDays( when, -DAYS_IN_WEEK );
{
for( int i=0; i<NUM_LAST_WEEKS; i++ )
{
float fWeekCals = 0;
f.Write("<tr>");
f.Write("<td>"+LastWeekToString(i)+"</td>");
for( int i=0; i<DAYS_IN_WEEK; i++ )
{
Profile::Day day = { when.tm_yday, when.tm_year+1900 };
float fDayCals = pProfile->GetCaloriesBurnedForDay( day );
fWeekCals += fDayCals;
f.Write("<td>"+ssprintf("%0.3f",fDayCals)+"</td>");
when = AddDays( when, +1 );
}
f.Write("<td>"+ssprintf("%0.3f",fWeekCals)+"</td>");
f.Write("</tr>");
when = AddDays( when, -DAYS_IN_WEEK*2 );
}
}
f.Write("</table>\n");
}
PRINT_CLOSE(f);
}
void SaveStatsWebPage(
CString sDir,
@@ -1124,6 +1164,7 @@ TITLE.c_str(), STYLE_CSS.c_str() ) );
PrintSongHighScores( f, pProfile, "My Song High Scores", vpSongs, vpAllSteps, vStepsTypesToShow, mapStepsToSong, vpCourses );
PrintCourseHighScores( f, pProfile, "My Course High Scores", vpSongs, vpAllSteps, vStepsTypesToShow, mapStepsToSong, vpCourses );
PrintScreenshots( f, pProfile, "My Screenshots", sDir );
PrintCaloriesBurned( f, pProfile, "My Calories Burned", sDir );
PrintGradeTable( f, pProfile, "My Grade Table", vpSongs, vpAllSteps, vStepsTypesToShow, mapStepsToSong, vpCourses );
PrintPopularity( f, pProfile, "Last Machine Popularity", vpSongs, vpAllSteps, vStepsTypesToShow, mapStepsToSong, vpCourses );
PrintSongHighScores( f, pProfile, "Last Machine High Scores", vpSongs, vpAllSteps, vStepsTypesToShow, mapStepsToSong, vpCourses );
@@ -1134,6 +1175,7 @@ TITLE.c_str(), STYLE_CSS.c_str() ) );
PrintSongHighScores( f, pProfile, "Song High Scores", vpSongs, vpAllSteps, vStepsTypesToShow, mapStepsToSong, vpCourses );
PrintCourseHighScores( f, pProfile, "Course High Scores", vpSongs, vpAllSteps, vStepsTypesToShow, mapStepsToSong, vpCourses );
PrintScreenshots( f, pProfile, "Screenshots", sDir );
PrintCaloriesBurned( f, pProfile, "Calories Burned", sDir );
PrintGradeTable( f, pProfile, "Grade Table", vpSongs, vpAllSteps, vStepsTypesToShow, mapStepsToSong, vpCourses );
PrintInventoryList( f, pProfile, "Song Information", vpSongs, vpAllSteps, vStepsTypesToShow, mapStepsToSong, vpCourses );
PrintBookkeeping( f, pProfile, "Bookkeeping", vpSongs, vpAllSteps, vStepsTypesToShow, mapStepsToSong, vpCourses );
+71
View File
@@ -63,3 +63,74 @@ CString HourInDayToString( int iHourInDayIndex )
return ssprintf("%02d:00", iHourInDayIndex);
}
static const CString MONTH_TO_NAME[MONTHS_IN_YEAR] =
{
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
};
CString MonthToString( int iMonthIndex )
{
return MONTH_TO_NAME[iMonthIndex];
}
CString LastWeekToString( int iLastWeekIndex )
{
switch( iLastWeekIndex )
{
case 0: return "This week"; break;
case 1: return "Last week"; break;
default: return ssprintf("%d weeks ago",iLastWeekIndex); break;
}
}
tm AddDays( tm start, int iDaysToMove )
{
start.tm_mday += iDaysToMove;
time_t seconds = mktime( &start );
ASSERT( seconds != (time_t)-1 );
tm time;
localtime_r( &seconds, &time );
return time;
}
tm GetYesterday( tm start )
{
return AddDays( start, -1 );
}
int GetDayOfWeek( tm time )
{
int iDayOfWeek = time.tm_wday;
ASSERT( iDayOfWeek < DAYS_IN_WEEK );
return iDayOfWeek;
}
tm GetNextSunday( tm start )
{
return AddDays( start, DAYS_IN_WEEK-GetDayOfWeek(start) );
}
tm GetDayInYearAndYear( int iDayInYearIndex, int iYear )
{
time_t now = time( NULL );
tm when = *localtime( &now );
when.tm_mday = iDayInYearIndex;
when.tm_year = iYear - 1900;
time_t then = mktime( &when );
when = *localtime( &then );
return when;
}
+12
View File
@@ -11,17 +11,29 @@
-----------------------------------------------------------------------------
*/
#include "time.h"
const int NUM_LAST_DAYS = 7;
const int NUM_LAST_WEEKS = 52;
const int DAYS_IN_YEAR = 365;
const int HOURS_IN_DAY = 24;
const int DAYS_IN_WEEK = 7;
const int MONTHS_IN_YEAR = 12;
CString DayInYearToString( int iDayInYearIndex );
CString LastDayToString( int iLastDayIndex );
CString DayOfWeekToString( int iDayOfWeekIndex );
CString HourInDayToString( int iHourIndex );
CString MonthToString( int iMonthIndex );
CString LastWeekToString( int iLastWeekIndex );
tm AddDays( tm start, int iDaysToMove );
tm GetYesterday( tm start );
int GetDayOfWeek( tm time );
tm GetNextSunday( tm start );
tm GetDayInYearAndYear( int iDayInYearIndex, int iYear );
#endif
+3
View File
@@ -1043,6 +1043,9 @@ LPXAttr _tagXMLNode::AppendAttr( LPCTSTR name /*= NULL*/, LPCTSTR value /*= NULL
return AppendAttr( CreateAttr( name, value ) );
}
LPXAttr _tagXMLNode::AppendAttr( LPCTSTR name, float value ){ return AppendAttr(name,ssprintf("%f",value)); }
LPXAttr _tagXMLNode::AppendAttr( LPCTSTR name, int value ) { return AppendAttr(name,ssprintf("%d",value)); }
//========================================================
// Name : DetachChild
// Desc : no delete object, just detach in list
+2
View File
@@ -186,6 +186,8 @@ typedef struct _tagXMLNode
XAttrs::iterator GetAttrIterator( LPXAttr node );
LPXAttr CreateAttr( LPCTSTR anem = NULL, LPCTSTR value = NULL );
LPXAttr AppendAttr( LPCTSTR name = NULL, LPCTSTR value = NULL );
LPXAttr AppendAttr( LPCTSTR name, float value );
LPXAttr AppendAttr( LPCTSTR name, int value );
LPXAttr AppendAttr( LPXAttr attr );
bool RemoveAttr( LPXAttr attr );
LPXAttr DetachAttr( LPXAttr attr );