Pre-release
AdventureJS Docs Downloads Devlog
Score: 0 Moves: 0
// parseNumeric.js

(function () {
  /* global AdventureJS A */

  var p = AdventureJS.Parser.prototype;

  /**
   * Look for numbers written as text and convert to number.
   * <br><br>
   * Example:<br>
   * type 10 on keyboard<br>
   * Becomes:<br>
   * type global_number on keyboard<br>
   * @memberOf AdventureJS.Parser
   * @method AdventureJS.Parser#parseNumeric
   * @param {String} input Player input.
   * @returns {String}
   */
  p.parseNumeric = function Parser_parseNumeric(input) {
    this.game.log(
      "L1571",
      "log",
      "high",
      `[parseNumeric.js] parseNumeric() receive: ${input}`,
      "Parser"
    );

    const ONES = [
      "and",
      "zero",
      "one",
      "two",
      "three",
      "four",
      "five",
      "six",
      "seven",
      "eight",
      "nine",
      "ten",
      "eleven",
      "twelve",
      "thirteen",
      "fourteen",
      "fifteen",
      "sixteen",
      "seventeen",
      "eighteen",
      "nineteen",
    ];

    const TENS = [
      "twenty",
      "thirty",
      "forty",
      "fifty",
      "sixty",
      "seventy",
      "eighty",
      "ninety",
      "hundred",
    ];

    const THOUSANDS = ["thousand", "million", "billion", "trillion"];

    const VALUES = {
      zero: 0,
      one: 1,
      two: 2,
      three: 3,
      four: 4,
      five: 5,
      six: 6,
      seven: 7,
      eight: 8,
      nine: 9,
      ten: 10,
      eleven: 11,
      twelve: 12,
      thirteen: 13,
      fourteen: 14,
      fifteen: 15,
      sixteen: 16,
      seventeen: 17,
      eighteen: 18,
      nineteen: 19,
      twenty: 20,
      thirty: 30,
      forty: 40,
      fifty: 50,
      sixty: 60,
      seventy: 70,
      eighty: 80,
      ninety: 90,
    };

    const SCALES = {
      hundred: 100,
      thousand: 1000,
      million: 1000000,
      billion: 1000000000,
    };

    function wordsToNumber(numeric) {
      console.warn(`wordsToNumber`, numeric);
      let total = 0;
      let current = 0;

      for (const word of numeric.toLowerCase().split(/\s+/)) {
        if (!word) continue;

        if (word === "and") {
          continue;
        }

        if (word in VALUES) {
          current += VALUES[word];
        } else if (word === "hundred") {
          current *= 100;
        } else if (word in SCALES) {
          total += current * SCALES[word];
          current = 0;
        } else {
          throw new Error(`Unknown number word: ${word}`);
        }
      }

      return `${total + current} `;
    }

    const split_input = input.split(" ");

    let numeric = "";
    for (let i = 0; i < split_input.length; i++) {
      let word = split_input[i];
      if (
        ONES.includes(word) ||
        TENS.includes(word) ||
        THOUSANDS.includes(word)
      ) {
        numeric += `${word} `;
      } else if (numeric) {
        numeric.trim();
        if (numeric.endsWith(" and")) numeric.replace(" and", "");
        input = input.replace(numeric, wordsToNumber(numeric));
        numeric = "";
      }
    }

    this.game.log(
      "L1692",
      "log",
      "high",
      `[parseNumeric.js] parseNumeric() return:\n${input}`,
      "Parser"
    );
    return input;
  };
})();