[gnome-tetravex] Use double for saving game duration.



commit d990d04848d0af0054a52042c174d6e94516c73d
Author: Arnaud Bonatti <arnaud bonatti gmail com>
Date:   Tue Sep 24 17:57:16 2019 +0200

    Use double for saving game duration.

 src/gnome-tetravex.vala |   5 +--
 src/history.vala        | 104 ++++++++++++++++++++++++++++++++++--------------
 src/score-dialog.vala   |  11 ++---
 src/score-overlay.vala  |  24 +++++------
 4 files changed, 92 insertions(+), 52 deletions(-)
---
diff --git a/src/gnome-tetravex.vala b/src/gnome-tetravex.vala
index 7d958f4..1e268a3 100644
--- a/src/gnome-tetravex.vala
+++ b/src/gnome-tetravex.vala
@@ -416,7 +416,7 @@ private class Tetravex : Gtk.Application
     {
         int elapsed = 0;
         if (puzzle_init_done)
-            elapsed = (int) (puzzle.elapsed + 0.5);
+            elapsed = (int) puzzle.elapsed; // felt better when + 0.5, but as the clock is still displayed 
while the score-overlay displays the exact time, that is regularly feeling odd
         int hours = elapsed / 3600;
         int minutes = (elapsed - hours * 3600) / 60;
         int seconds = elapsed - hours * 3600 - minutes * 60;
@@ -457,8 +457,7 @@ private class Tetravex : Gtk.Application
     private void show_end_game_cb (Puzzle puzzle)
     {
         DateTime date = new DateTime.now_local ();
-        uint duration = (uint) (puzzle.elapsed + 0.5);
-        last_history_entry = new HistoryEntry (date, puzzle.size, duration);
+        last_history_entry = new HistoryEntry (date, puzzle.size, puzzle.elapsed, /* old history format */ 
false);
 
         if (!puzzle_is_finished) // Ctrl-n has been hit before the animation finished
             return;
diff --git a/src/history.vala b/src/history.vala
index 157c054..13547c7 100644
--- a/src/history.vala
+++ b/src/history.vala
@@ -26,7 +26,7 @@ private class History : Object
                          out HistoryEntry?  other_entry_1,
                          out HistoryEntry?  other_entry_2)
     {
-        entries.insert_sorted (entry, HistoryEntry.compare_entries);
+        entries.insert_sorted (entry, compare_entries);
         entry_added (entry);
         save ();
 
@@ -146,15 +146,18 @@ private class History : Object
                 continue;
             uint8 size = (uint8) test;
 
-            if (!uint64.try_parse (tokens [2], out test))
+            double duration;
+            bool int_duration;
+            if (uint64.try_parse (tokens [2], out duration))
+                int_duration = true;
+            else if (double.try_parse (tokens [2], out duration))
+                int_duration = false;
+            else
                 continue;
-            if (test > uint.MAX)
-                continue;
-            uint duration = (uint) test;
 
-            entries.prepend (new HistoryEntry ((!) date, size, duration));
+            entries.prepend (new HistoryEntry ((!) date, size, duration, int_duration));
         }
-        entries.sort (HistoryEntry.compare_entries);
+        entries.sort (compare_entries);
     }
 
     /*\
@@ -167,7 +170,11 @@ private class History : Object
 
         foreach (HistoryEntry entry in entries)
         {
-            string line = "%s %hu %u\n".printf (entry.date.to_string (), entry.size, entry.duration);
+            string line;
+            if (entry.int_duration)
+                line = "%s %hu %u\n".printf (entry.date.to_string (), entry.size, (uint) entry.duration);
+            else
+                line = "%s %hu %s\n".printf (entry.date.to_string (), entry.size, entry.duration.to_string 
());
             contents += line;
         }
 
@@ -181,45 +188,84 @@ private class History : Object
             warning ("Failed to save history: %s", e.message);
         }
     }
+
+    /*\
+    * * comparing
+    \*/
+
+    private static int compare_entries (HistoryEntry a, HistoryEntry b)
+    {
+        /* in size order, 2 first */
+        if (a.size != b.size)
+            return (int) a.size - (int) b.size;
+
+        /* not in the same second, easy */
+        if ((uint) a.duration < (uint) b.duration)
+            return -1;
+        if ((uint) a.duration > (uint) b.duration)
+            return 1;
+
+        /* old history format after, to renew a bit the challenge (it might logically be more at duration - 
0.5) */
+        if (a.int_duration && !b.int_duration)
+            return 1;
+        if (b.int_duration && !a.int_duration)
+            return -1;
+
+        /* compare duration */
+        if (a.duration < b.duration)
+            return -1;
+        if (a.duration > b.duration)
+            return 1;
+
+        /* newer on the top */
+        return -1 * a.date.compare (b.date);
+    }
 }
 
 private class HistoryEntry : Object // TODO make struct? needs using HistoryEntry? for the List...
 {
-    [CCode (notify = false)] public DateTime date { internal get; protected construct; }
-    [CCode (notify = false)] public uint8 size    { internal get; protected construct; }
-    [CCode (notify = false)] public uint duration { internal get; protected construct; }
+    [CCode (notify = false)] public DateTime date       { internal get; protected construct; }
+    [CCode (notify = false)] public uint8 size          { internal get; protected construct; }
+    [CCode (notify = false)] public double duration     { internal get; protected construct; }
+    [CCode (notify = false)] public bool int_duration   { internal get; protected construct; }
 
-    internal HistoryEntry (DateTime date, uint8 size, uint duration)
+    internal HistoryEntry (DateTime date, uint8 size, double duration, bool int_duration)
     {
-        Object (date: date, size: size, duration: duration);
+        Object (date: date, size: size, duration: duration, int_duration: int_duration);
     }
 
     /*\
     * * utilities
     \*/
 
-    internal static string get_duration_string (uint duration)
+    internal static string get_duration_string (HistoryEntry entry)
     {
-        if (duration >= 3600)
+        if (entry.duration >= 3600.0)
             /* Translators: that is the duration of a game, as seen in the Scores dialog, if game has taken 
one hour or more; the %u are replaced by the hours (h), minutes (m) and seconds (s); as an example, you might 
want to use "%u:%.2u:%.2u", that is quite international (the ".2" meaning "two digits, padding with 0") */
-            return _("%uh %um %us").printf (duration / 3600, (duration / 60) % 60, duration % 60);
+            return _("%uh %um %us").printf ((uint) entry.duration / 3600, ((uint) entry.duration / 60) % 60, 
(uint) entry.duration % 60);
 
-        if (duration >= 60)
+        if (entry.duration >= 60.0)
             /* Translators: that is the duration of a game, as seen in the Scores dialog, if game has taken 
between one minute and one hour; the %u are replaced by the minutes (m) and seconds (s); as an example, you 
might want to use "%.2u:%.2u", that is quite international (the ".2" meaning "two digits, padding with 0") */
-            return _("%um %us").printf (duration / 60, duration % 60);
+            return _("%um %us").printf ((uint) entry.duration / 60, (uint) entry.duration % 60);
 
-        else
-            /* Translators: that is the duration of a game, as seen in the Scores dialog, if game has taken 
less than one minute; the %u is replaced by the number of seconds (s) it has taken; as an example, you might 
want to use "00:%.2u", that is quite international (the ".2" meaning "two digits, padding with 0") */
-            return _("%us").printf (duration);
-    }
+        else if (entry.int_duration)
+            /* Translators: that is the duration of a game, as seen in the Scores dialog, if game has taken 
less than one minute; the %u is replaced by the number of seconds (s) it has taken */
+            return _("%us").printf ((uint) entry.duration);
+
+        else if (entry.duration >= 20.0)
+            /* Translators: that is the duration of a game, as seen in the Scores dialog, if game has taken 
less than one minute; the %.0f is replaced by the number of seconds (s) it has taken */
+            return _("%.0fs").printf (Math.floor (entry.duration));
+
+        else if (entry.duration >= 10.0)
+            /* Translators: that is the duration of a game, as seen in the Scores dialog, if game has taken 
less than one minute; the %.1f is replaced by the number of seconds (s) it has taken, including deciseconds 
(1 digits after comma, so the .1) */
+            return _("%.1fs").printf (Math.floor (entry.duration * 10.0) / 10.0);
+
+        else if (entry.duration >= 5.0)
+            /* Translators: that is the duration of a game, as seen in the Scores dialog, if game has taken 
less than one minute; the %.2f is replaced by the number of seconds (s) it has taken, including centiseconds 
(2 digits after comma, so the .2) */
+            return _("%.2fs").printf (Math.floor (entry.duration * 100.0) / 100.0);
 
-    internal static int compare_entries (HistoryEntry a, HistoryEntry b)
-    {
-        if (a.size != b.size)
-            return (int) a.size - (int) b.size;
-        if (a.duration != b.duration)
-            return (int) a.duration - (int) b.duration;
         else
-            return a.date.compare (b.date);
+            /* Translators: that is the duration of a game, as seen in the Scores dialog, if game has taken 
less than one minute; the %.3f is replaced by the number of seconds (s) it has taken, including milliseconds 
(3 digits after comma, so the .3) */
+            return _("%.3fs").printf (Math.floor (entry.duration * 1000.0) / 1000.0);
     }
 }
diff --git a/src/score-dialog.vala b/src/score-dialog.vala
index 49560ae..ebfa756 100644
--- a/src/score-dialog.vala
+++ b/src/score-dialog.vala
@@ -75,9 +75,7 @@ private class ScoreDialog : Dialog
         scores.show ();
         scroll.add (scores);
 
-        List<unowned HistoryEntry> entries = history.entries.copy ();
-        entries.sort (HistoryEntry.compare_entries);
-        foreach (HistoryEntry entry in entries)
+        foreach (HistoryEntry entry in history.entries)
             entry_added_cb (entry);
 
         TreeIter iter;
@@ -89,10 +87,7 @@ private class ScoreDialog : Dialog
     {
         score_model.clear ();
 
-        List<unowned HistoryEntry> entries = history.entries.copy ();
-        entries.sort (HistoryEntry.compare_entries);
-
-        foreach (HistoryEntry entry in entries)
+        foreach (HistoryEntry entry in history.entries)
         {
             if (entry.size != size)
                 continue;
@@ -100,7 +95,7 @@ private class ScoreDialog : Dialog
             /* "the preferred date representation for the current locale without the time" */
             string date_label = entry.date.format ("%x");
 
-            string time_label = HistoryEntry.get_duration_string (entry.duration);
+            string time_label = HistoryEntry.get_duration_string (entry);
 
             int weight = Pango.Weight.NORMAL;
             if (entry == selected_entry)
diff --git a/src/score-overlay.vala b/src/score-overlay.vala
index 27e2ccc..398b406 100644
--- a/src/score-overlay.vala
+++ b/src/score-overlay.vala
@@ -46,26 +46,26 @@ private class ScoreOverlay : Grid
             case 1:
                 /* Translators: text of the score overlay, displayed after a puzzle is complete; appears if 
the player has been the fastest for a puzzle of this size; introduces the game time */
                 score_0.set_place_label (_("New best time!"));
-                score_0.set_value_label (HistoryEntry.get_duration_string (entry.duration), true);
+                score_0.set_value_label (HistoryEntry.get_duration_string (entry), true);
 
                 /* Translators: text of the score overlay, displayed after a puzzle is complete; appears if 
the player has been the fastest for a puzzle of this size; introduces the old best time */
                 score_1.set_place_label (_("Second:"));
                 if (other_entry_0 != null)
-                    score_1.set_value_label (HistoryEntry.get_duration_string (((!) 
other_entry_0).duration));
+                    score_1.set_value_label (HistoryEntry.get_duration_string ((!) other_entry_0));
                 else
                     score_1.set_value_label (null);
 
                 /* Translators: text of the score overlay, displayed after a puzzle is complete; appears if 
the player has been the fastest for a puzzle of this size; introduces the old second best time */
                 score_2.set_place_label (_("Third:"));
                 if (other_entry_1 != null)
-                    score_2.set_value_label (HistoryEntry.get_duration_string (((!) 
other_entry_1).duration));
+                    score_2.set_value_label (HistoryEntry.get_duration_string ((!) other_entry_1));
                 else
                     score_2.set_value_label (null);
 
                 /* Translators: text of the score overlay, displayed after a puzzle is complete; appears if 
the player has been the fastest for a puzzle of this size; introduces the old third best time */
                 score_3.set_place_label (_("Out of podium:"));
                 if (other_entry_2 != null)
-                    score_3.set_value_label (HistoryEntry.get_duration_string (((!) 
other_entry_2).duration));
+                    score_3.set_value_label (HistoryEntry.get_duration_string ((!) other_entry_2));
                 else
                     score_3.set_value_label (null);
                 break;
@@ -75,23 +75,23 @@ private class ScoreOverlay : Grid
                     assert_not_reached ();
                 /* Translators: text of the score overlay, displayed after a puzzle is complete; appears if 
the player has made the second best time for a puzzle of this size; introduces the best time ever */
                 score_0.set_place_label (_("Best time:"));
-                score_0.set_value_label (HistoryEntry.get_duration_string (((!) other_entry_0).duration));
+                score_0.set_value_label (HistoryEntry.get_duration_string ((!) other_entry_0));
 
                 /* Translators: text of the score overlay, displayed after a puzzle is complete; appears if 
the player has made the second best time for a puzzle of this size; introduces the game time */
                 score_1.set_place_label (_("Your time:"));
-                score_1.set_value_label (HistoryEntry.get_duration_string (entry.duration), true);
+                score_1.set_value_label (HistoryEntry.get_duration_string (entry), true);
 
                 /* Translators: text of the score overlay, displayed after a puzzle is complete; appears if 
the player has made the second best time for a puzzle of this size; introduces the old second best time */
                 score_2.set_place_label (_("Third:"));
                 if (other_entry_1 != null)
-                    score_2.set_value_label (HistoryEntry.get_duration_string (((!) 
other_entry_1).duration));
+                    score_2.set_value_label (HistoryEntry.get_duration_string ((!) other_entry_1));
                 else
                     score_2.set_value_label (null);
 
                 /* Translators: text of the score overlay, displayed after a puzzle is complete; appears if 
the player has made the second best time for a puzzle of this size; introduces the old third best time */
                 score_3.set_place_label (_("Out of podium:"));
                 if (other_entry_2 != null)
-                    score_3.set_value_label (HistoryEntry.get_duration_string (((!) 
other_entry_2).duration));
+                    score_3.set_value_label (HistoryEntry.get_duration_string ((!) other_entry_2));
                 else
                     score_3.set_value_label (null);
                 break;
@@ -101,7 +101,7 @@ private class ScoreOverlay : Grid
                     assert_not_reached ();
                 /* Translators: text of the score overlay, displayed after a puzzle is complete; appears if 
the player has not made the first or second best time for a puzzle of this size; introduces the best time 
ever */
                 score_0.set_place_label (_("Best time:"));
-                score_0.set_value_label (HistoryEntry.get_duration_string (((!) other_entry_0).duration));
+                score_0.set_value_label (HistoryEntry.get_duration_string ((!) other_entry_0));
 
                 if (position == 3)
                 /* Translators: text of the score overlay, displayed after a puzzle is complete; appears if 
the player has not made the first or second best time for a puzzle of this size; introduces the second best 
time */
@@ -114,16 +114,16 @@ private class ScoreOverlay : Grid
                 else
                 /* Translators: text of the score overlay, displayed after a puzzle is complete; appears if 
the player has not made the first or second best time for a puzzle of this size; the %u is replaced by the 
rank before the one of the game played */
                     score_1.set_place_label (_("Place %u:").printf (position - 1));
-                score_1.set_value_label (HistoryEntry.get_duration_string (((!) other_entry_1).duration));
+                score_1.set_value_label (HistoryEntry.get_duration_string ((!) other_entry_1));
 
                 /* Translators: text of the score overlay, displayed after a puzzle is complete; appears if 
the player has not made the first or second best time for a puzzle of this size; introduces the game time */
                 score_2.set_place_label (_("Your time:"));
-                score_2.set_value_label (HistoryEntry.get_duration_string (entry.duration), true);
+                score_2.set_value_label (HistoryEntry.get_duration_string (entry), true);
 
                 /* Translators: text of the score overlay, displayed after a puzzle is complete; appears if 
the player has not made the first or second best time for a puzzle of this size; the %u is replaced by the 
rank after the one of the game played */
                 score_3.set_place_label (_("Place %u:").printf (position + 1));
                 if (other_entry_2 != null)
-                    score_3.set_value_label (HistoryEntry.get_duration_string (((!) 
other_entry_2).duration));
+                    score_3.set_value_label (HistoryEntry.get_duration_string ((!) other_entry_2));
                 else
                     score_3.set_value_label (null);
                 break;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]