From: Luigi Pinca Date: Sun, 9 Feb 2014 14:26:39 +0000 (+0100) Subject: improved the matching system making it a little more tolerant X-Git-Url: https://git.saalbach.dev/?a=commitdiff_plain;h=41cf0059758334925c21ffaa9cf2f78cdf5d8ac7;p=binbsis50.git improved the matching system making it a little more tolerant --- diff --git a/config.json b/config.json index f02d082..c114617 100644 --- a/config.json +++ b/config.json @@ -1,5 +1,4 @@ { - "allowederrors": 2, "gameswithnorepeats": 3, "port": 8138, "rooms": [ diff --git a/lib/match.js b/lib/match.js index 7dddce4..914724b 100644 --- a/lib/match.js +++ b/lib/match.js @@ -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; + } } } diff --git a/package.json b/package.json index ec177ea..b6b5e29 100644 --- a/package.json +++ b/package.json @@ -30,5 +30,5 @@ "start": "node app.js" }, "subdomain": "binb", - "version": "0.4.2" + "version": "0.4.3" }