Kaynağa Gözat

db is slow. do updates before waiting for user.

This makes it harder to even notice the db lag.
I tried preparing the statements before using them,
but that didn't make any difference.

I've added settings (in the yaml) to adjust the
display date format.  (Because, well, because
I can!)
Steve Thielemann 3 yıl önce
ebeveyn
işleme
9ed77a17b9
4 değiştirilmiş dosya ile 154 ekleme ve 39 silme
  1. 26 15
      db.cpp
  2. 2 0
      db.h
  3. 67 6
      main.cpp
  4. 59 18
      play.cpp

+ 26 - 15
db.cpp

@@ -5,9 +5,18 @@
 #include <iostream>
 #include <sstream>
 
+// configuration settings access
+#include "yaml-cpp/yaml.h"
+extern YAML::Node config;
+
 DBData::DBData(void)
     : db("space-data.db", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE) {
+
   init();
+  stmt_getSet = std::make_unique<SQLite::Statement>(
+      db, "SELECT value FROM settings WHERE username=? AND setting=?");
+  stmt_setSet = std::make_unique<SQLite::Statement>(
+      db, "REPLACE INTO settings(username, setting, value) VALUES(?,?,?);");
 }
 
 // DBData::DBData(void) : sql(std::string(DB_CONNECT_STRING)) {}
@@ -28,26 +37,22 @@ void DBData::setUser(std::string currentUser) { user = currentUser; }
 
 std::string DBData::getSetting(const std::string &setting,
                                std::string ifMissing) {
-  SQLite::Statement query(
-      db, "SELECT value FROM settings WHERE username=? AND setting=?");
-  query.reset();
-  query.bind(1, user);
-  query.bind(2, setting);
-  if (query.executeStep()) {
-    std::string value = query.getColumn(0);
+  stmt_getSet->reset();
+  stmt_getSet->bind(1, user);
+  stmt_getSet->bind(2, setting);
+  if (stmt_getSet->executeStep()) {
+    std::string value = stmt_getSet->getColumn(0);
     return value;
   };
   return ifMissing;
 }
 
 void DBData::setSetting(const std::string &setting, const std::string &value) {
-  SQLite::Statement stmt(
-      db, "REPLACE INTO settings(username, setting, value) VALUES(?,?,?);");
-  stmt.reset();
-  stmt.bind(1, user);
-  stmt.bind(2, setting);
-  stmt.bind(3, value);
-  stmt.exec();
+  stmt_setSet->reset();
+  stmt_setSet->bind(1, user);
+  stmt_setSet->bind(2, setting);
+  stmt_setSet->bind(3, value);
+  stmt_setSet->exec();
 }
 
 void DBData::save_score(time_t when, std::string date, int hand, int score) {
@@ -80,7 +85,13 @@ bool DBData::has_played_day(time_t day) {
 
 std::string make_date(time_t tt) {
   std::stringstream ss;
-  ss << std::put_time(std::localtime(&tt), "%Y/%0m/%0d");
+  if (config["date_score"]) {
+    std::string custom_format = config["date_score"].as<std::string>();
+    ss << std::put_time(std::localtime(&tt), custom_format.c_str());
+  } else {
+    ss << std::put_time(std::localtime(&tt), "%Y/%0m/%0d");
+  }
+
   std::string date = ss.str();
   return date;
 }

+ 2 - 0
db.h

@@ -7,6 +7,8 @@ class DBData {
   SQLite::Database db;
   void init(void);
   std::string user;
+  std::unique_ptr<SQLite::Statement> stmt_getSet;
+  std::unique_ptr<SQLite::Statement> stmt_setSet;
 
 public:
   DBData();

+ 67 - 6
main.cpp

@@ -1,5 +1,6 @@
 #include "door.h"
 #include "space.h"
+#include "yaml-cpp/yaml.h"
 #include <chrono>  // chrono::system_clock
 #include <ctime>   // localtime
 #include <iomanip> // put_time
@@ -13,6 +14,9 @@
 #include "version.h"
 #include <algorithm> // transform
 
+// configuration here -- access via extern
+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)
@@ -29,10 +33,21 @@ bool replace(std::string &str, const char *from, const char *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 from_string(std::string colorCode);
 
 std::function<std::ofstream &(void)> get_logger;
 
+/*
 unsigned long score = 0;
 int hand = 1;
 int total_hands = 3;
@@ -42,6 +57,7 @@ int best_streak = 0;
 int active_card = 23;
 
 std::chrono::_V2::system_clock::time_point play_day;
+*/
 
 /*
 
@@ -418,8 +434,15 @@ int opt_from_string(std::string colorCode) {
 int configure(door::Door &door, DBData &db) {
   auto menu = make_config_menu();
   int r = 0;
+  bool save_deckcolor = false;
+  const char *deckcolor = "DeckColor";
+  std::string newColor;
 
   while (r >= 0) {
+    if (save_deckcolor) {
+      db.setSetting(deckcolor, newColor);
+      save_deckcolor = false;
+    }
     r = menu.choose(door);
     if (r > 0) {
       door << door::reset << door::cls;
@@ -427,8 +450,8 @@ int configure(door::Door &door, DBData &db) {
       if (c == 'D') {
         // Ok, deck colors
         // get default
-        std::string key("DeckColor");
-        std::string currentDefault = db.getSetting(key, std::string("ALL"));
+
+        std::string currentDefault = db.getSetting(deckcolor, "ALL");
         int currentOpt = opt_from_string(currentDefault);
 
         door << door::reset << door::cls;
@@ -439,11 +462,12 @@ int configure(door::Door &door, DBData &db) {
 
         if (newOpt >= 0) {
           newOpt--;
-          std::string newColor = from_color_option(newOpt);
+          newColor = from_color_option(newOpt);
           if (newOpt != currentOpt) {
-            door.log() << key << " was " << currentDefault << ", " << currentOpt
-                       << ". Now " << newColor << ", " << newOpt << std::endl;
-            db.setSetting(key, newColor);
+            door.log() << deckcolor << " was " << currentDefault << ", "
+                       << currentOpt << ". Now " << newColor << ", " << newOpt
+                       << std::endl;
+            save_deckcolor = true;
           }
         }
       }
@@ -455,6 +479,7 @@ int configure(door::Door &door, DBData &db) {
   return r;
 }
 
+/*
 door::Panel make_score_panel(door::Door &door) {
   const int W = 25;
   door::Panel p(W);
@@ -518,6 +543,7 @@ door::Panel make_score_panel(door::Door &door) {
 
   return p;
 }
+*/
 
 door::Panel make_about(void) {
   const int W = 60;
@@ -665,6 +691,41 @@ int main(int argc, char *argv[]) {
   DBData spacedb;
   spacedb.setUser(door.username);
 
+  if (file_exists("space-ace.yaml")) {
+    config = YAML::LoadFile("space-ace.yaml");
+  }
+
+  bool update_config = false;
+
+  // populate with "good" defaults
+  if (!config["hands_per_day"]) {
+    config["hands_per_day"] = 3;
+    update_config = true;
+  }
+
+  if (!config["date_format"]) {
+    config["date_format"] = "%B %d";
+    update_config = true;
+  }
+
+  if (!config["date_score"]) {
+    config["date_score"] = "%m/%d/%Y"; // or "%Y/%0m/%0d";
+    update_config = true;
+  }
+
+  /*
+    if (config["hands_per_day"]) {
+      get_logger() << "hands_per_day: " << config["hands_per_day"].as<int>()
+                   << std::endl;
+    }
+  */
+
+  // save configuration -- something was updated
+  if (update_config) {
+    std::ofstream fout("space-ace.yaml");
+    fout << config << std::endl;
+  }
+
   // retrieve lastcall
   time_t last_call = std::stol(spacedb.getSetting("LastCall", "0"));
 

+ 59 - 18
play.cpp

@@ -6,6 +6,12 @@
 #include <iomanip> // put_time
 #include <sstream>
 
+// configuration settings access
+#include "yaml-cpp/yaml.h"
+extern YAML::Node config;
+
+#define CHEATER "CHEAT_YOUR_ASS_OFF"
+
 static std::function<std::ofstream &(void)> get_logger;
 
 static int press_a_key(door::Door &door) {
@@ -27,16 +33,18 @@ PlayCards::PlayCards(door::Door &d, DBData &dbd, std::mt19937 &r)
 
   init_values();
 
+  play_day = std::chrono::system_clock::now();
+
   spaceAceTriPeaks = make_tripeaks();
   score_panel = make_score_panel();
   streak_panel = make_streak_panel();
   left_panel = make_left_panel();
   cmd_panel = make_command_panel();
+  /*
+    int mx = door.width;
+    int my = door.height;
+  */
 
-  int mx = door.width;
-  int my = door.height;
-
-  play_day = std::chrono::system_clock::now();
   get_logger = [this]() -> ofstream & { return door.log(); };
 }
 
@@ -44,10 +52,17 @@ PlayCards::~PlayCards() { get_logger = nullptr; }
 
 void PlayCards::init_values(void) {
   hand = 1;
-  total_hands = 3;
+  if (config["hands_per_day"]) {
+    total_hands = config["hands_per_day"].as<int>();
+  } else
+    total_hands = 3;
+
   card_number = 28;
   current_streak = 0;
   best_streak = 0;
+  std::string best;
+  best = db.getSetting("best_streak", "0");
+  best_streak = std::stoi(best);
   active_card = 23;
   score = 0;
 }
@@ -79,7 +94,7 @@ int PlayCards::play_cards(void) {
 
   off_x = (mx - game_width) / 2;
   off_y = (my - game_height) / 2;
-  int true_off_y = off_y;
+  // int true_off_y = off_y;
 
   // we can now position things properly centered
 
@@ -91,6 +106,7 @@ next_hand:
   card_number = 28;
   active_card = 23;
   score = 0;
+  current_streak = 0;
 
   // Use play_day to seed the rng
   {
@@ -137,10 +153,19 @@ next_hand:
   door::Panel *c;
 
   bool in_game = true;
+  bool save_streak = false;
+
   while (in_game) {
     // time might have updated, so update score panel too.
     score_panel->update(door);
 
+    // do the save here -- try to hide the database lag
+    if (save_streak) {
+      save_streak = false;
+      std::string best = std::to_string(best_streak);
+      db.setSetting("best_streak", best);
+    }
+
     r = door.sleep_key(door.inactivity);
     if (r > 0) {
       // not a timeout or expire.
@@ -153,6 +178,9 @@ next_hand:
           current_streak = 0;
           streak_panel->update(door);
 
+          // update the cards left_panel
+          left_panel->update(door);
+
           // Ok, deal next card from the pile.
           int cx, cy, level;
 
@@ -167,15 +195,13 @@ next_hand:
           c = dp.card(deck.at(card_number));
           c->set(cx + off_x, cy + off_y);
           door << *c;
-          // update the cards left_panel
-          left_panel->update(door);
         }
         break;
       case 'R':
-        // now_what = false;
         redraw(false);
         break;
       case 'Q':
+        // possibly prompt here for [N]ext hand or [Q]uit ?
         in_game = false;
         break;
       case ' ':
@@ -193,16 +219,24 @@ next_hand:
                      << std::endl;
                      */
 
-        if (dp.can_play(deck.at(active_card), deck.at(card_number))) {
+        if (dp.can_play(deck.at(active_card), deck.at(card_number)) or
+            config[CHEATER]) {
           // if (true) {
           // yes we can.
           ++current_streak;
-          if (current_streak > best_streak)
+          if (current_streak > best_streak) {
             best_streak = current_streak;
+            if (!config[CHEATER]) {
+              save_streak = true;
+            }
+          }
           streak_panel->update(door);
           score += 10;
-          if (current_streak > 2)
-            score += 5;
+          if (current_streak > 1)
+            score += current_streak * 5;
+          score_panel->update(door);
+          if (get_logger)
+            get_logger() << "score_panel update : " << score << std::endl;
 
           // play card!
           state.at(active_card) = 2;
@@ -284,6 +318,7 @@ next_hand:
 
               score += 100;
               state.at(active_card) = 3; // handle this in the "redraw"
+              score_panel->update(door);
             }
 
             // Find new "number" for active_card to be.
@@ -297,10 +332,12 @@ next_hand:
                 active_card = new_active;
               } else {
                 get_logger() << "This looks like END OF GAME." << std::endl;
+                get_logger() << "SCORE: " << score << std::endl;
                 // bonus for cards left
                 press_a_key(door);
                 if (hand < total_hands) {
                   hand++;
+                  // current_streak = 0;
                   door << door::reset << door::cls;
                   goto next_hand;
                 }
@@ -554,10 +591,10 @@ std::unique_ptr<door::Panel> PlayCards::make_score_panel() {
       return text;
     };
     std::string scoreString = scoreUpdate();
-    door::Line score(scoreString, W);
-    score.setRender(svRender);
-    score.setUpdater(scoreUpdate);
-    p->addLine(std::make_unique<door::Line>(score));
+    door::Line scoreline(scoreString, W);
+    scoreline.setRender(svRender);
+    scoreline.setUpdater(scoreUpdate);
+    p->addLine(std::make_unique<door::Line>(scoreline));
   }
   {
     door::updateFunction timeUpdate = [this](void) -> std::string {
@@ -606,7 +643,11 @@ std::unique_ptr<door::Panel> PlayCards::make_streak_panel(void) {
     std::string text = "Playing: ";
     auto in_time_t = std::chrono::system_clock::to_time_t(play_day);
     std::stringstream ss;
-    ss << std::put_time(std::localtime(&in_time_t), "%B %d");
+    if (config["date_format"]) {
+      std::string fmt = config["date_format"].as<std::string>();
+      ss << std::put_time(std::localtime(&in_time_t), fmt.c_str());
+    } else
+      ss << std::put_time(std::localtime(&in_time_t), "%B %d");
     text.append(ss.str());
     door::Line current(text, W);
     current.setRender(svRender);