]> git.example.dev Git - binbsis50.git/commitdiff
improved the matching system making it a little more tolerant
authorLuigi Pinca <luigipinca@gmail.com>
Sun, 9 Feb 2014 14:26:39 +0000 (15:26 +0100)
committerLuigi Pinca <luigipinca@gmail.com>
Sun, 9 Feb 2014 14:26:39 +0000 (15:26 +0100)
config.json
lib/match.js
package.json

index f02d0822238d62a0ccd7ae707da64d14d41f3441..c114617d36e464a2528fb774ab451c62f042aca2 100644 (file)
@@ -1,5 +1,4 @@
 {
-  "allowederrors": 2,
   "gameswithnorepeats": 3,
   "port": 8138,
   "rooms": [
index 7dddce4786fb2cbe8f840caa1337b85457e16ca1..914724bd5fd9af7bdcb3798dc4bf676a8e839dcb 100644 (file)
@@ -1,53 +1,57 @@
 /**
- * Module dependencies.
- */
-
-var threshold = require('../config').allowederrors;
-
-/**
- * Check if the edit distance between two strings is smaller than a threshold k.
- * We dont need to trace back the optimal alignment, so we can run the Levenshtein distance 
- * algorithm in better than O(n*m).
- * We use only a diagonal stripe of width 2k+1 in the matrix.
- * See Algorithms on strings, trees, and sequences: computer science and computational biology.
+ * Check if the edit distance between two strings is smaller than a threshold
+ * `k` defined as the natural logarithm of the length of the first string
+ * rounded to the nearest integer.
+ * We dont need to trace back the optimal alignment, so we can run the
+ * Levenshtein distance algorithm in better than `O(n * m)`.
+ * We use only a diagonal stripe of width `2k + 1` in the matrix.
+ * See Algorithms on strings, trees, and sequences: computer science and
+ * computational biology.
  * Cambridge, UK: Cambridge University Press. pp 263-264. ISBN 0-521-58519-8.
  */
 
-var checkDistance = function(s1, s2, k) {
+var checkDistance = function(s1, s2) {
+  var k = Math.log(s1.length);
+  k = Math.round(k);
+
   if (k === 0) {
     return s1 === s2;
   }
   if (Math.abs(s1.length - s2.length) > k) {
     return false;
   }
-  var d = [];
-  for (var i=0; i <= s1.length; i++) {
+
+  var d = []
+    , i, j, l, m;
+
+  for (i = 0; i <= s1.length; i++) {
     d[i] = []; // Now d is a matrix with s1.length + 1 rows
     d[i][0] = i;
   }
-  for (var j=1; j <= s2.length; j++) {
+  for (j = 1; j <= s2.length; j++) {
     d[0][j] = j;
   }
-  for (i=1; i <= s1.length; i++) {
-    var l = ((i-k) < 1) ? 1 : i-k;
-    var m = ((i+k) > s2.length) ? s2.length : i+k;
-    for (j=l; j<=m; j++) {
+
+  for (i = 1; i <= s1.length; i++) {
+    l = ((i - k) < 1) ? 1 : i - k;
+    m = ((i + k) > s2.length) ? s2.length : i + k;
+    for (j = l; j <= m; j++) {
       if (s1.charAt(i-1) === s2.charAt(j-1)) {
         d[i][j] = d[i-1][j-1];
+        continue;
       }
-      else {
-        if ((j === l) && (d[i][j-1] === undefined)) {
-          d[i][j] = Math.min(d[i-1][j-1]+1, d[i-1][j]+1);
-        }
-        else if ((j === m) && (d[i-1][j] === undefined)) {
-          d[i][j] = Math.min(d[i][j-1]+1, d[i-1][j-1]+1);
-        }
-        else {
-          d[i][j] = Math.min(d[i][j-1]+1, d[i-1][j-1]+1, d[i-1][j]+1);
-        }
+      if (j === l && d[i][j-1] === undefined) {
+        d[i][j] = Math.min(d[i-1][j-1] + 1, d[i-1][j] + 1);
+        continue;
+      }
+      if (j === m && d[i-1][j] === undefined) {
+        d[i][j] = Math.min(d[i][j-1] + 1, d[i-1][j-1] + 1);
+        continue;
       }
+      d[i][j] = Math.min(d[i][j-1] + 1, d[i-1][j-1] + 1, d[i-1][j] + 1);
     }
   }
+
   return d[s1.length][s2.length] <= k;
 };
 
@@ -55,60 +59,77 @@ var checkDistance = function(s1, s2, k) {
  * Expose a function to check if the user answer is acceptable.
  */
 
-module.exports = function(subject, guess, enableartistrules) {
-  if (checkDistance(subject, guess, threshold)) {
+module.exports = function(pattern, guess, enableartistrules) {
+  if (checkDistance(pattern, guess)) {
     return true;
   }
 
-  // Ignore dots
-  if (/\./.test(subject) && 
-    checkDistance(subject.replace(/\./g, ''), guess, threshold)) {
-    return true;
+  var _pattern;
+
+  if (~pattern.indexOf('.')) {
+    // Ignore dots
+    _pattern = pattern.replace(/\./g, '');
+    if (checkDistance(_pattern, guess)) {
+      return true;
+    }
   }
-  // Ignore dashes
-  if (/\-/.test(subject) && 
-    checkDistance(subject.replace(/\-/g, ''), guess, threshold)) {
-    return true;
+  if (~pattern.indexOf('-')) {
+    // Ignore dashes
+    _pattern = pattern.replace(/\-/g, '');
+    if (checkDistance(_pattern, guess)) {
+      return true;
+    }
   }
-  // Allow to write "and" in place of "+"
-  if (/\+/.test(subject) && 
-    checkDistance(subject.replace(/\+/, 'and'), guess, threshold)) {
-    return true;
+  if (~pattern.indexOf('+')) {
+    // Allow to write "and" in place of "+"
+    _pattern = pattern.replace(/\+/, 'and');
+    if (checkDistance(_pattern, guess)) {
+      return true;
+    }
   }
-  // Allow to write "and" in place of " & "
-  if (/ & /.test(subject) && !/\(/.test(subject) &&
-    checkDistance(subject.replace(/ & /, ' and '), guess, threshold)) {
-    return true;
+  if (~pattern.indexOf(' & ') && !~pattern.indexOf('(')) {
+    // Allow to write "and" in place of " & "
+    _pattern = pattern.replace(/ & /, ' and ');
+    if (checkDistance(_pattern, guess)) {
+      return true;
+    }
   }
 
   if (enableartistrules) {
-    // Split artist name on " & " and ", " (artist name can be composed by more names)
-    var splits = subject.split(/ & |, /)
+    // Split artist name on " & " and ", " (it can be composed by more names)
+    var splits = pattern.split(/ & |, /)
       , multipleartists = splits.length !== 1;
+
     for (var i = 0; i < splits.length; i++) {
       var artist = splits[i];
       if (multipleartists) {
-        if (checkDistance(artist, guess, threshold)) {
+        if (checkDistance(artist, guess)) {
           return true;
         }
-        if (/\./.test(artist) &&
-          checkDistance(artist.replace(/\./g, ''), guess, threshold)) {
-          return true;
+        if (~artist.indexOf('.')) {
+          _pattern = artist.replace(/\./g, '');
+          if (checkDistance(_pattern, guess)) {
+            return true;
+          }
         }
       }
-      // Ignore "the" at the beginning of artist name
-      if (/^the /.test(artist)) {
+      if (artist.indexOf('the ') === 0) {
+        // Ignore "the" at the beginning of artist name
         var nothe = artist.replace(/^the /, '');
-        if (checkDistance(nothe, guess, threshold)) {
+        if (checkDistance(nothe, guess)) {
           return true;
         }
-        if (/\./.test(nothe) &&
-          checkDistance(nothe.replace(/\./g, ''), guess, threshold)) {
-          return true;
+        if (~nothe.indexOf('.')) {
+          _pattern = nothe.replace(/\./g, '');
+          if (checkDistance(_pattern, guess)) {
+            return true;
+          }
         }
-        if (/jimi hendrix experience/.test(nothe) &&
-          checkDistance(nothe.replace(/ experience/, ''), guess, threshold)) {
-          return true;
+        if (nothe === 'jimi hendrix experience') {
+          _pattern = nothe.replace(' experience', '');
+          if (checkDistance(_pattern, guess)) {
+            return true;
+          }
         }
       }
       if (guess === 'ccr' && artist === 'creedence clearwater revival') {
@@ -123,25 +144,31 @@ module.exports = function(subject, guess, enableartistrules) {
     }
   }
   else {
-    // Ignore commas
-    if (/,/.test(subject) && 
-      checkDistance(subject.replace(/,/g, ''), guess, threshold)) {
-      return true;
-    }
-    // Ignore additional info e.g. "(Love Theme from Titanic)"
-    if (/\(.+\)\??(?: \[.+\])?/.test(subject)) {
-      var normalized = subject.replace(/\(.+\)\??(?: \[.+\])?/, '').trim();
-      if (checkDistance(normalized, guess, threshold)) {
+    if (~pattern.indexOf(',')) {
+      // Ignore commas
+      _pattern = pattern.replace(/,/g, '');
+      if (checkDistance(_pattern, guess)) {
         return true;
       }
-      if (/ & /.test(normalized) && 
-        checkDistance(normalized.replace(/ & /, ' and '), guess, threshold)) {
+    }
+    if (/\(.+\)\??(?: \[.+\])?/.test(pattern)) {
+      // Ignore additional info e.g. "(Love Theme from Titanic)"
+      var normalized = pattern.replace(/\(.+\)\??(?: \[.+\])?/, '').trim();
+      if (checkDistance(normalized, guess)) {
         return true;
       }
+      if (~normalized.indexOf(' & ')) {
+        _pattern = normalized.replace(/ & /, ' and ');
+        if (checkDistance(_pattern, guess)) {
+          return true;
+        }
+      }
     }
-    if (/, [pP]t\. [0-9]$/.test(subject) && 
-      checkDistance(subject.replace(/, [pP]t\. [0-9]$/, ''), guess, threshold)) {
-      return true;
+    if (/, [pP]t\. [0-9]$/.test(pattern)) {
+      _pattern = pattern.replace(/, [pP]t\. [0-9]$/, '');
+      if (checkDistance(_pattern, guess)) {
+        return true;
+      }
     }
   }
 
index ec177eabc58ab777e8a4cdb0ffef31c675fc2a84..b6b5e29b66c7e27adbf61ac9c550e82e35744aed 100644 (file)
@@ -30,5 +30,5 @@
     "start": "node app.js"
   },
   "subdomain": "binb",
-  "version": "0.4.2"
+  "version": "0.4.3"
 }