Browse Source

Updated: I score the wins in the table as well.

I should probably just have sqlite total up
the scores for the day (and sort descending
for me).

Broke out common functions into utils file.
Added get_logger() // global logging access.
Added config // global configuration access.
Steve Thielemann 4 years ago
parent
commit
6b27759eee
9 changed files with 238 additions and 68 deletions
  1. 1 1
      CMakeLists.txt
  2. 84 15
      db.cpp
  3. 18 1
      db.h
  4. 10 12
      deck.cpp
  5. 0 2
      deck.h
  6. 33 28
      main.cpp
  7. 35 9
      play.cpp
  8. 33 0
      utils.cpp
  9. 24 0
      utils.h

+ 1 - 1
CMakeLists.txt

@@ -65,6 +65,6 @@ endif()
 
 
 add_subdirectory(yaml-cpp)
 add_subdirectory(yaml-cpp)
 
 
-add_executable(space-ace main.cpp deck.cpp db.h db.cpp play.h play.cpp images.h)
+add_executable(space-ace main.cpp deck.cpp db.h db.cpp play.h play.cpp utils.h utils.cpp images.h)
 target_link_libraries(space-ace door++ pthread SQLiteCpp sqlite3 dl yaml-cpp)
 target_link_libraries(space-ace door++ pthread SQLiteCpp sqlite3 dl yaml-cpp)
 
 

+ 84 - 15
db.cpp

@@ -1,4 +1,5 @@
 #include "db.h"
 #include "db.h"
+#include "utils.h"
 
 
 #include <SQLiteCpp/VariadicBind.h>
 #include <SQLiteCpp/VariadicBind.h>
 
 
@@ -6,14 +7,6 @@
 #include <iostream>
 #include <iostream>
 #include <sstream>
 #include <sstream>
 
 
-// configuration settings access
-#include "yaml-cpp/yaml.h"
-extern YAML::Node config;
-
-#include <fstream>
-#include <functional>
-extern std::function<std::ofstream &(void)> get_logger;
-
 /*
 /*
 The database access is slow.
 The database access is slow.
 
 
@@ -47,7 +40,7 @@ settings(username TEXT, setting TEXT, value TEXT, \
 PRIMARY KEY(username, setting));");
 PRIMARY KEY(username, setting));");
     db.exec("CREATE TABLE IF NOT EXISTS \
     db.exec("CREATE TABLE IF NOT EXISTS \
 scores ( \"username\" TEXT, \"when\" INTEGER, \
 scores ( \"username\" TEXT, \"when\" INTEGER, \
-\"date\" INTEGER, \"hand\" INTEGER, \"score\" INTEGER, \
+\"date\" INTEGER, \"hand\" INTEGER, \"won\" INTEGER, \"score\" INTEGER, \
 PRIMARY KEY(\"username\", \"date\", \"hand\"));");
 PRIMARY KEY(\"username\", \"date\", \"hand\"));");
   } catch (std::exception &e) {
   } catch (std::exception &e) {
     if (get_logger) {
     if (get_logger) {
@@ -119,23 +112,25 @@ void DBData::setSetting(const std::string &setting, const std::string &value) {
  * @param when now()
  * @param when now()
  * @param date what day they played
  * @param date what day they played
  * @param hand which hand they played
  * @param hand which hand they played
+ * @param won did they win? 1/0
  * @param score
  * @param score
  */
  */
-void DBData::saveScore(time_t when, time_t date, int hand, int score) {
+void DBData::saveScore(time_t when, time_t date, int hand, int won, int score) {
   try {
   try {
-    SQLite::Statement stmt(db,
-                           "INSERT INTO scores( \"username\", \"when\", "
-                           "\"date\", \"hand\", \"score\") VALUES(?,?,?,?,?);");
+    SQLite::Statement stmt(
+        db, "INSERT INTO scores( \"username\", \"when\", "
+            "\"date\", \"hand\", \"won\", \"score\") VALUES(?,?,?,?,?,?);");
     stmt.bind(1, user);
     stmt.bind(1, user);
     stmt.bind(2, when);
     stmt.bind(2, when);
     stmt.bind(3, date);
     stmt.bind(3, date);
     stmt.bind(4, hand);
     stmt.bind(4, hand);
-    stmt.bind(5, score);
+    stmt.bind(5, won);
+    stmt.bind(6, score);
     stmt.exec();
     stmt.exec();
   } catch (std::exception &e) {
   } catch (std::exception &e) {
     if (get_logger) {
     if (get_logger) {
       get_logger() << "saveScore( " << when << "," << date << "," << hand << ","
       get_logger() << "saveScore( " << when << "," << date << "," << hand << ","
-                   << score << " ): " << user << std::endl;
+                   << won << "," << score << " ): " << user << std::endl;
       get_logger() << "SQLite exception: " << e.what() << std::endl;
       get_logger() << "SQLite exception: " << e.what() << std::endl;
     }
     }
   }
   }
@@ -169,6 +164,80 @@ int DBData::handsPlayedOnDay(time_t day) {
   return 0;
   return 0;
 }
 }
 
 
+std::vector<scores_data> DBData::getScoresOnDay(time_t date) {
+  std::vector<scores_data> scores;
+  try {
+    // \"when\",
+    SQLite::Statement stmt(db, "SELECT \"username\", \"date\", \"hand\", "
+                               "\"won\", \"score\" FROM SCORES WHERE "
+                               "\"date\"=? ORDER BY \"username\", \"hand\";");
+    stmt.bind(1, date);
+    while (stmt.executeStep()) {
+      scores_data sd;
+      sd.user = (const char *)stmt.getColumn(0);
+      sd.date = stmt.getColumn(1);
+      sd.hand = stmt.getColumn(2);
+      sd.won = stmt.getColumn(3);
+      sd.score = stmt.getColumn(4);
+      scores.push_back(sd);
+    }
+  } catch (std::exception &e) {
+    if (get_logger) {
+      get_logger() << "getScoresOnDay( " << date << " ): " << std::endl;
+      get_logger() << "SQLite exception: " << e.what() << std::endl;
+    }
+    scores.clear();
+  }
+  return scores;
+}
+
+std::map<time_t, std::vector<scores_data>> DBData::getScores(void) {
+  std::map<time_t, std::vector<scores_data>> scores;
+  try {
+    SQLite::Statement stmt(db, "SELECT \"username\", \"date\", \"hand\", "
+                               "\"won\", \"score\" FROM SCORES "
+                               "ORDER BY \"date\", \"username\", \"hand\";");
+    time_t current = 0;
+    std::vector<scores_data> vsd;
+
+    while (stmt.executeStep()) {
+      time_t the_date = stmt.getColumn(1);
+
+      if (current == 0) {
+        // ok, we've got the first one!
+        current = the_date;
+      } else {
+        // Ok, are we on another date now?
+        if (the_date != current) {
+          scores[current] = std::move(vsd);
+          vsd.clear();
+          current = the_date;
+        }
+      }
+      scores_data sd;
+      sd.user = (const char *)stmt.getColumn(0);
+      sd.date = the_date; // stmt.getColumn(1);
+      sd.hand = stmt.getColumn(2);
+      sd.won = stmt.getColumn(3);
+      sd.score = stmt.getColumn(4);
+      vsd.push_back(sd);
+    }
+    if (!vsd.empty()) {
+      scores[current] = std::move(vsd);
+    }
+    vsd.clear();
+  } catch (std::exception &e) {
+    if (get_logger) {
+      get_logger() << "getScores(): " << std::endl;
+      get_logger() << "SQLite exception: " << e.what() << std::endl;
+    }
+    scores.clear();
+  }
+  return scores;
+}
+
+void DBData::expireScores(void) {}
+
 /**
 /**
  * @brief Format date to string.
  * @brief Format date to string.
  *
  *

+ 18 - 1
db.h

@@ -3,6 +3,18 @@
 
 
 #include <SQLiteCpp/SQLiteCpp.h>
 #include <SQLiteCpp/SQLiteCpp.h>
 
 
+#include <map>
+#include <string>
+#include <vector>
+
+typedef struct {
+  time_t date;
+  std::string user;
+  int hand;
+  int score;
+  int won;
+} scores_data;
+
 class DBData {
 class DBData {
   SQLite::Database db;
   SQLite::Database db;
   void create_tables(void);
   void create_tables(void);
@@ -24,7 +36,12 @@ public:
   void clearUser(void) { user.clear(); };
   void clearUser(void) { user.clear(); };
   std::string getSetting(const std::string &setting, std::string ifMissing);
   std::string getSetting(const std::string &setting, std::string ifMissing);
   void setSetting(const std::string &setting, const std::string &value);
   void setSetting(const std::string &setting, const std::string &value);
-  void saveScore(time_t when, time_t date, int hand, int score);
+  void saveScore(time_t when, time_t date, int hand, int won, int score);
+
+  std::vector<scores_data> getScoresOnDay(time_t date);
+  std::map<time_t, std::vector<scores_data>> getScores(void);
+  void expireScores(void);
+
   int handsPlayedOnDay(time_t day);
   int handsPlayedOnDay(time_t day);
 };
 };
 
 

+ 10 - 12
deck.cpp

@@ -1,5 +1,6 @@
 #include "deck.h"
 #include "deck.h"
 
 
+#include "utils.h"
 #include <algorithm>
 #include <algorithm>
 #include <map>
 #include <map>
 #include <sstream>
 #include <sstream>
@@ -264,15 +265,15 @@ shared_panel Deck::card(int c) { return cards[c]; }
 /**
 /**
  * @brief Return panel for back of card.
  * @brief Return panel for back of card.
  *
  *
- * 0 = Blank
- * 1 = level 1 (furthest/darkest)
- * 2 = level 2
- * 3 = level 3
- * 4 = level 4 (closest/lightest)
+ * - 0 = Blank
+ * - 1 = level 1 (furthest/darkest)
+ * - 2 = level 2
+ * - 3 = level 3
+ * - 4 = level 4 (closest/lightest)
  *
  *
- * 5 = left (fills with left corner in place)
- * 6 = right (fills right corner)
- * 7 = both (fills both corners)
+ * - 5 = left (fills with left corner in place)
+ * - 6 = right (fills right corner)
+ * - 7 = both (fills both corners)
  *
  *
  * @param level
  * @param level
  * @return door::Panel*
  * @return door::Panel*
@@ -290,7 +291,7 @@ const std::array<std::pair<int, int>, 18> Deck::blocks = {
 };
 };
 
 
 /**
 /**
- * @brief Which card (if any) is unblocked by this card
+ * @brief Which card(s) are unblocked by this card?
  *
  *
  * @param card
  * @param card
  * @return * int
  * @return * int
@@ -974,6 +975,3 @@ door::ANSIColor stringToANSIColor(std::string colorCode) {
 }
 }
 
 
 std::string stringFromColorOptions(int opt) { return deck_colors[opt]; }
 std::string stringFromColorOptions(int opt) { return deck_colors[opt]; }
-void string_toupper(std::string &str) {
-  std::transform(str.begin(), str.end(), str.begin(), ::toupper);
-}

+ 0 - 2
deck.h

@@ -140,6 +140,4 @@ door::renderFunction makeColorRender(door::ANSIColor c1, door::ANSIColor c2,
 door::ANSIColor stringToANSIColor(std::string colorCode);
 door::ANSIColor stringToANSIColor(std::string colorCode);
 std::string stringFromColorOptions(int opt);
 std::string stringFromColorOptions(int opt);
 
 
-void string_toupper(std::string &str);
-
 #endif
 #endif

+ 33 - 28
main.cpp

@@ -11,38 +11,13 @@
 #include "db.h"
 #include "db.h"
 #include "deck.h"
 #include "deck.h"
 #include "play.h"
 #include "play.h"
+#include "utils.h"
 #include "version.h"
 #include "version.h"
 #include <algorithm> // transform
 #include <algorithm> // transform
 
 
 // configuration here -- access via extern
 // configuration here -- access via extern
 YAML::Node config;
 YAML::Node config;
 
 
-bool replace(std::string &str, const std::string &from, const std::string &to) {
-  size_t start_pos = str.find(from);
-  if (start_pos == std::string::npos)
-    return false;
-  str.replace(start_pos, from.length(), to);
-  return true;
-}
-
-bool replace(std::string &str, const char *from, const char *to) {
-  size_t start_pos = str.find(from);
-  if (start_pos == std::string::npos)
-    return false;
-  str.replace(start_pos, strlen(from), to);
-  return true;
-}
-
-bool file_exists(const std::string &name) {
-  ifstream f(name.c_str());
-  return f.good();
-}
-
-bool file_exists(const char *name) {
-  ifstream f(name);
-  return f.good();
-}
-
 door::ANSIColor stringToANSIColor(std::string colorCode);
 door::ANSIColor stringToANSIColor(std::string colorCode);
 
 
 std::function<std::ofstream &(void)> get_logger;
 std::function<std::ofstream &(void)> get_logger;
@@ -706,7 +681,7 @@ int main(int argc, char *argv[]) {
   }
   }
 
 
   if (!config["date_format"]) {
   if (!config["date_format"]) {
-    config["date_format"] = "%B %d";
+    config["date_format"] = "%B %d"; // Month day or "%b %d,%Y" Mon,d YYYY
     update_config = true;
     update_config = true;
   }
   }
 
 
@@ -837,7 +812,37 @@ int main(int argc, char *argv[]) {
     }; break;
     }; break;
 
 
     case 2: // view scores
     case 2: // view scores
-      door << "Show scores goes here!" << door::nl;
+    {
+      door << door::cls;
+      auto all_scores = spacedb.getScores();
+      for (auto it : all_scores) {
+        time_t on_this_date = it.first;
+        std::string nice_date = convertDateToDateScoreFormat(on_this_date);
+        door << "  *** " << nice_date << " ***" << door::nl;
+        scores_data merge;
+
+        for (auto sd : it.second) {
+          if (merge.user.empty())
+            merge = sd;
+          else {
+            if (merge.user == sd.user) {
+              // merge in the information
+              merge.hand = sd.hand;
+              merge.won += sd.won;
+              merge.score += sd.score;
+            } else {
+              // Ok, output the merged data and reset
+              door << setw(15) << merge.user << " " << merge.hand << " "
+                   << merge.won << " " << sd.score << door::nl;
+              merge = sd;
+            }
+          }
+        }
+        door << setw(15) << merge.user << " " << merge.hand << " " << merge.won
+             << " " << merge.score << door::nl;
+      }
+      door << "====================" << door::nl;
+    }
       r = press_a_key(door);
       r = press_a_key(door);
       break;
       break;
 
 

+ 35 - 9
play.cpp

@@ -1,25 +1,24 @@
 #include "play.h"
 #include "play.h"
 #include "db.h"
 #include "db.h"
 #include "deck.h"
 #include "deck.h"
+#include "utils.h"
 #include "version.h"
 #include "version.h"
 
 
 #include <iomanip> // put_time
 #include <iomanip> // put_time
 #include <sstream>
 #include <sstream>
 
 
-// configuration settings access
-#include "yaml-cpp/yaml.h"
-extern YAML::Node config;
-
 #define CHEATER "CHEAT_YOUR_ASS_OFF"
 #define CHEATER "CHEAT_YOUR_ASS_OFF"
 
 
-static std::function<std::ofstream &(void)> get_logger;
+// static std::function<std::ofstream &(void)> get_logger;
 
 
+/*
 static int press_a_key(door::Door &door) {
 static int press_a_key(door::Door &door) {
   door << door::reset << "Press a key to continue...";
   door << door::reset << "Press a key to continue...";
   int r = door.sleep_key(door.inactivity);
   int r = door.sleep_key(door.inactivity);
   door << door::nl;
   door << door::nl;
   return r;
   return r;
 }
 }
+*/
 
 
 /*
 /*
 In the future, this will probably check to see if they can play today or not, as
 In the future, this will probably check to see if they can play today or not, as
@@ -33,20 +32,32 @@ PlayCards::PlayCards(door::Door &d, DBData &dbd) : door{d}, db{dbd} {
   init_values();
   init_values();
 
 
   play_day = std::chrono::system_clock::now();
   play_day = std::chrono::system_clock::now();
+
   // adjustment
   // adjustment
   time_t time_play_day = std::chrono::system_clock::to_time_t(play_day);
   time_t time_play_day = std::chrono::system_clock::to_time_t(play_day);
+  /*
   if (get_logger) {
   if (get_logger) {
     get_logger() << "before: "
     get_logger() << "before: "
                  << std::put_time(std::localtime(&time_play_day), "%F %R")
                  << std::put_time(std::localtime(&time_play_day), "%F %R")
                  << std::endl;
                  << std::endl;
   };
   };
+  */
   normalizeDate(time_play_day);
   normalizeDate(time_play_day);
   play_day = std::chrono::system_clock::from_time_t(time_play_day);
   play_day = std::chrono::system_clock::from_time_t(time_play_day);
+  /*
   if (get_logger) {
   if (get_logger) {
     get_logger() << "after: "
     get_logger() << "after: "
                  << std::put_time(std::localtime(&time_play_day), "%F %R")
                  << std::put_time(std::localtime(&time_play_day), "%F %R")
                  << std::endl;
                  << std::endl;
   };
   };
+  */
+
+  /*
+   * TODO:  Check the date with the db.  Have they already played up today?  If
+   * so, display calendar and find a day they can play.  Or, play missed hands
+   * for today.
+   */
+
   spaceAceTriPeaks = make_tripeaks();
   spaceAceTriPeaks = make_tripeaks();
   score_panel = make_score_panel();
   score_panel = make_score_panel();
   streak_panel = make_streak_panel();
   streak_panel = make_streak_panel();
@@ -63,7 +74,9 @@ PlayCards::PlayCards(door::Door &d, DBData &dbd) : door{d}, db{dbd} {
 PlayCards::~PlayCards() { get_logger = nullptr; }
 PlayCards::~PlayCards() { get_logger = nullptr; }
 
 
 void PlayCards::init_values(void) {
 void PlayCards::init_values(void) {
+  // beware of hand=1 !  We might not be playing the first hand here!
   hand = 1;
   hand = 1;
+
   if (config["hands_per_day"]) {
   if (config["hands_per_day"]) {
     total_hands = config["hands_per_day"].as<int>();
     total_hands = config["hands_per_day"].as<int>();
   } else
   } else
@@ -79,6 +92,10 @@ void PlayCards::init_values(void) {
   score = 0;
   score = 0;
 }
 }
 
 
+/**
+ * @brief Display the bonus text, when you remove a peak.
+ *
+ */
 void PlayCards::bonus(void) {
 void PlayCards::bonus(void) {
   door << door::ANSIColor(door::COLOR::YELLOW, door::ATTR::BOLD) << "BONUS";
   door << door::ANSIColor(door::COLOR::YELLOW, door::ATTR::BOLD) << "BONUS";
 }
 }
@@ -150,7 +167,7 @@ next_hand:
     streak_panel->set(right_panel_x + off_x, off_yp);
     streak_panel->set(right_panel_x + off_x, off_yp);
     cmd_panel->set(left_panel_x + off_x, off_yp + 5);
     cmd_panel->set(left_panel_x + off_x, off_yp + 5);
 
 
-    // next panel position
+    // next panel position (top = card 10, centered)
     cardPos(10, cx, cy);
     cardPos(10, cx, cy);
     int next_off_x = (mx - next_quit_panel->getWidth()) / 2;
     int next_off_x = (mx - next_quit_panel->getWidth()) / 2;
     next_quit_panel->set(next_off_x, cy + off_y);
     next_quit_panel->set(next_off_x, cy + off_y);
@@ -240,7 +257,7 @@ next_hand:
                 std::chrono::system_clock::now());
                 std::chrono::system_clock::now());
             db.saveScore(right_now,
             db.saveScore(right_now,
                          std::chrono::system_clock::to_time_t(play_day), hand,
                          std::chrono::system_clock::to_time_t(play_day), hand,
-                         score);
+                         0, score);
           }
           }
           in_game = false;
           in_game = false;
           r = 'Q';
           r = 'Q';
@@ -251,7 +268,7 @@ next_hand:
           time_t right_now = std::chrono::system_clock::to_time_t(
           time_t right_now = std::chrono::system_clock::to_time_t(
               std::chrono::system_clock::now());
               std::chrono::system_clock::now());
           db.saveScore(right_now,
           db.saveScore(right_now,
-                       std::chrono::system_clock::to_time_t(play_day), hand,
+                       std::chrono::system_clock::to_time_t(play_day), hand, 0,
                        score);
                        score);
           hand++;
           hand++;
           goto next_hand;
           goto next_hand;
@@ -405,7 +422,7 @@ next_hand:
                     std::chrono::system_clock::now());
                     std::chrono::system_clock::now());
                 db.saveScore(right_now,
                 db.saveScore(right_now,
                              std::chrono::system_clock::to_time_t(play_day),
                              std::chrono::system_clock::to_time_t(play_day),
-                             hand, score);
+                             hand, 1, score);
                 //}
                 //}
                 next_quit_panel->update();
                 next_quit_panel->update();
                 door << *next_quit_panel;
                 door << *next_quit_panel;
@@ -512,6 +529,15 @@ next_hand:
   return r;
   return r;
 }
 }
 
 
+/**
+ * @brief Redraw the entire play cards screen.
+ *
+ * If dealing then show delays when displaying cards, or turning them over.
+ *
+ * Otherwise, the user has requested a redraw -- and don't delay.
+ *
+ * @param dealing
+ */
 void PlayCards::redraw(bool dealing) {
 void PlayCards::redraw(bool dealing) {
   shared_panel c;
   shared_panel c;
 
 

+ 33 - 0
utils.cpp

@@ -0,0 +1,33 @@
+#include "utils.h"
+
+#include <algorithm>
+
+bool replace(std::string &str, const std::string &from, const std::string &to) {
+  size_t start_pos = str.find(from);
+  if (start_pos == std::string::npos)
+    return false;
+  str.replace(start_pos, from.length(), to);
+  return true;
+}
+
+bool replace(std::string &str, const char *from, const char *to) {
+  size_t start_pos = str.find(from);
+  if (start_pos == std::string::npos)
+    return false;
+  str.replace(start_pos, strlen(from), to);
+  return true;
+}
+
+bool file_exists(const std::string &name) {
+  std::ifstream f(name.c_str());
+  return f.good();
+}
+
+bool file_exists(const char *name) {
+  std::ifstream f(name);
+  return f.good();
+}
+
+void string_toupper(std::string &str) {
+  std::transform(str.begin(), str.end(), str.begin(), ::toupper);
+}

+ 24 - 0
utils.h

@@ -0,0 +1,24 @@
+#ifndef UTILS_H
+#define UTILS_H
+
+#include <fstream>
+#include <functional>
+#include <string.h>
+#include <string>
+
+// utility functions go here
+
+bool replace(std::string &str, const std::string &from, const std::string &to);
+bool replace(std::string &str, const char *from, const char *to);
+bool file_exists(const std::string &name);
+bool file_exists(const char *name);
+void string_toupper(std::string &str);
+
+// logger access
+extern std::function<std::ofstream &(void)> get_logger;
+
+// configuration settings access
+#include "yaml-cpp/yaml.h"
+extern YAML::Node config;
+
+#endif