changeset 456:c81b38ec7bd2 release-2.1

Fix #644: fix word list and selection Reuse the same list across successive hangman invocations. Task: #644 Errata: 20170727
author David Demelier <markand@malikania.fr>
date Thu, 27 Jul 2017 21:54:30 +0200
parents 8b615d37d303
children c3f46ad1ece6
files plugins/hangman/hangman.js tests/plugin-hangman/CMakeLists.txt tests/plugin-hangman/main.cpp tests/plugin-hangman/wordlist_fix_644.conf
diffstat 4 files changed, 75 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/plugins/hangman/hangman.js	Tue Jul 25 17:08:19 2017 +0200
+++ b/plugins/hangman/hangman.js	Thu Jul 27 21:54:30 2017 +0200
@@ -62,9 +62,12 @@
 Hangman.map = {};
 
 /**
- * List of words
+ * List of words.
  */
-Hangman.words = [];
+Hangman.words = {
+    all: [],        //!< All words,
+    registry: {}    //!< Words list per server/channel.
+};
 
 /**
  * Search for an existing game.
@@ -139,15 +142,15 @@
 
         while ((line = file.readline()) !== undefined)
             if (Hangman.isWord(line))
-                Hangman.words.push(line);
+                Hangman.words.all.push(line);
     } catch (e) {
         throw new Error("could not open '" + path + "'");
     }
 
-    if (Hangman.words.length === 0)
+    if (Hangman.words.all.length === 0)
         throw new Error("empty word database");
 
-    Logger.info("number of words in database: " + Hangman.words.length);
+    Logger.info("number of words in database: " + Hangman.words.all.length);
 }
 
 /**
@@ -182,14 +185,18 @@
  */
 Hangman.prototype.select = function ()
 {
+    var id = this.server.toString() + "@" + this.channel;
+
     // Reload the words if empty.
-    if (!this.words || this.words.length === 0)
-        this.words = Hangman.words.slice(0);
+    if (!Hangman.words.registry[id] || Hangman.words.registry[id].length === 0)
+        Hangman.words.registry[id] = Hangman.words.all.slice(0);
 
-    var i = Math.floor(Math.random() * this.words.length);
+    var i = Math.floor(Math.random() * Hangman.words.registry[id].length);
 
-    this.word = this.words[i];
-    this.words.splice(i, 1);
+    this.word = Hangman.words.registry[id][i];
+
+    // Erase words from the registry.
+    Hangman.words.registry[id].splice(i, 1);
 
     // Fill table.
     this.table = {};
--- a/tests/plugin-hangman/CMakeLists.txt	Tue Jul 25 17:08:19 2017 +0200
+++ b/tests/plugin-hangman/CMakeLists.txt	Thu Jul 27 21:54:30 2017 +0200
@@ -18,7 +18,7 @@
 
 irccd_define_test(
     NAME plugin-hangman
-    SOURCES main.cpp
+    SOURCES main.cpp words.conf wordlist_fix_644.conf
     LIBRARIES libirccd
     FLAGS PLUGINDIR=\"${IRCCD_FAKEROOTDIR}/${WITH_PLUGINDIR}\"
 )
--- a/tests/plugin-hangman/main.cpp	Tue Jul 25 17:08:19 2017 +0200
+++ b/tests/plugin-hangman/main.cpp	Thu Jul 27 21:54:30 2017 +0200
@@ -16,6 +16,9 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <unordered_map>
+#include <unordered_set>
+
 #include <gtest/gtest.h>
 
 #include <irccd/irccd.hpp>
@@ -226,6 +229,57 @@
     ASSERT_EQ("jean:win=hangman:!hangman:test:jean:jean!jean@localhost:jean:sky", m_server->last());
 }
 
+TEST_F(HangmanTest, wordlist_fix_644)
+{
+    /*
+     * To be sure that the selection use the same list, we create a list of
+     * three words that has different size to determine which one was selected.
+     *
+     * Then we run 3 games and verify that the old selection is not the same
+     * as the current.
+     *
+     * This is not very accurate but it's better than nothing.
+     */
+    load({{ "file", SOURCEDIR "/wordlist_fix_644.conf" }});
+
+    std::unordered_map<unsigned, std::string> words{
+        { 14, "abc"     },
+        { 16, "abcd"    },
+        { 18, "abcde"   }
+    };
+    std::unordered_set<unsigned> found;
+
+    m_plugin->setFormats({
+        { "start", "#{word}" }
+    });
+
+    unsigned last, current;
+
+    // 1. Initial game + finish.
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
+    last = m_server->last().length();
+    found.insert(last);
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", words[last]});
+
+    // 2. Current must not be the last one.
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
+    current = m_server->last().length();
+
+    ASSERT_NE(last, current);
+    ASSERT_EQ(0U, found.count(current));
+
+    found.insert(current);
+    last = current;
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", words[current]});
+
+    // 3. Last word must be the one that is kept into the map.
+    m_plugin->onCommand(m_irccd, MessageEvent{m_server, "jean!jean@localhost", "#hangman", ""});
+    current = m_server->last().length();
+
+    ASSERT_NE(last, current);
+    ASSERT_EQ(0U, found.count(current));
+}
+
 int main(int argc, char **argv)
 {
     path::setApplicationPath(argv[0]);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/plugin-hangman/wordlist_fix_644.conf	Thu Jul 27 21:54:30 2017 +0200
@@ -0,0 +1,3 @@
+abc
+abcd
+abcde