Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Determining if two words share a letter

Any hints about how I'd tackle this in Twine Harlowe?

E.g. I'd want a positive result if the words were "eyes" and "smile" (both contain e and s), or a negative result if the words were "eyes" and "blink" (no letters in common).

Something to do with splitting a string into an array of substrings for starters, I guess

Thank you!

Comments

  • note: A more experienced Javascript coder may be able to supply a better solutions.

    You could use a combination of Javascript's String split() method, the new Array some() method and an inline function to do what you want. It would look something like the following.
    "eyes".split('').some(function(c){return "smile".indexOf(c) !== -1;})
    
    or (a slightly more readable version)
    
    "eyes".split('').some(
    	function(c) {
    		return "smile".indexOf(c) !== -1;
    	}
    );
    

    But there are two issues with the above:

    1. The Array some() method may not exist in older web-browsers, which you can solve by adding the following Polyfill from MDN to the start of your Story Javascript area.
    // Polyfill for Array some() method.
    // Production steps of ECMA-262, Edition 5, 15.4.4.17
    // Reference: http://es5.github.io/#x15.4.4.17
    if (!Array.prototype.some) {
      Array.prototype.some = function(fun/*, thisArg*/) {
        'use strict';
    
        if (this == null) {
          throw new TypeError('Array.prototype.some called on null or undefined');
        }
    
        if (typeof fun !== 'function') {
          throw new TypeError();
        }
    
        var t = Object(this);
        var len = t.length >>> 0;
    
        var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
        for (var i = 0; i < len; i++) {
          if (i in t && fun.call(thisArg, t[i], i, t)) {
            return true;
          }
        }
    
        return false;
      };
    }
    

    2. Harlowe has problems parsing the expression and throws a "Unexpected token" error for the following.
    result: (print: "eyes".split('').some(function(c){return "smile".indexOf(c) !== -1;}))
    

    You can get around this issue by creating a custom method and using that instead. There are two ways you can do this:

    a. Create a Custom Namespace to contain your new method.

    Add the following to your Story Javascript area, it creates a new My namespace and assigns a new containsCharacters method to that namespace. This code needs to appear later in the passage than the Array some() method Polyfill.
    if (typeof window.My == "undefined") {
      window.My = {};
    }
    Object.defineProperty(window.My, 'containsCharacters', {
    	value(str, searchValue) {
    		// Check if a valid str value was supplied.
    		if (typeof str !== 'string' || typeof searchValue !== 'string') {
    			return false;
    		}
    
    		return searchValue.split('').some(function(c){return str.indexOf(c) !== -1;})
    	}
    });
    
    ... to use the new method add the following to a passage, it creates three variables and then checks if the characters in two of them are contained within the third.
    (set: $wordA to "eyes")
    (set: $wordB to "smile")
    (set: $wordC to "blink")
    
    check 1: (print: My.containsCharacters($wordA, $wordB))
    check 2: (print: My.containsCharacters($wordA, $wordC))
    

    b. Extend the built-in Javascript String prototype.

    warning: This technique is consider bad by some (many?) because it can interfere with current (or future) Standard methods added by web-browser developers.

    Add the following to your Story Javascript area, it extends the built-in Sting prototype to include a new containsCharacters method. This code needs to appear later in the passage than the Array some() method Polyfill.
    Object.defineProperty(String.prototype, 'containsCharacters', {
    	value(searchValue) {
    		// Lazy equality for null.
    		if (this == null) {
    			throw new TypeError('String.prototype.containsCharacters called on null or undefined');
    		}
    
    		// Check if a valid searchValue was supplied.
    		if (typeof searchValue !== 'string') {
    			return false;
    		}
    
    		var str = this;
    		return searchValue.split('').some(function(c){return str.indexOf(c) !== -1;})
    	}
    });
    
    ... to use the new method add the following to a passage, it creates three variables and then checks if the characters in two of them are contained within the third.
    (set: $wordA to "eyes")
    (set: $wordB to "smile")
    (set: $wordC to "blink")
    
    check 1: (print: $wordA.containsCharacters($wordB))
    check 2: (print: $wordA.containsCharacters($wordC))
    
  • Oh my God, brilliant. Thanks so much. This will level me up once I get my head around it.
Sign In or Register to comment.