Search code examples
google-sheetsgoogle-apps-script

Google sheets behaving differently from script


I've been working towards getting a spreadsheet template for designing factions for a game, and started learning macros to do just this. All was smooth until I started getting some strange errors where the output present in the spreadsheet does not match the output in the code editor.

The input looks like this : 'C=>bd \\ C=>Bd'

The output in the code editor looks like this: V: 3.5, S: 0, P: 0

The output in the spreadsheet looks like this: V: NaN, S: NaN, P: NaN

Both of which are the product of this string interpolation:

V: ${sides.side2.value - sides.side1.value}, S: ${sides.side2.ships}, P: ${sides.side2.points}

When testing the function I copy the input from the cell verbatim and set my parameter equal to the copied cell content.

Does anybody know why these would be different?

Willing to post more details about the code if requested, but as it stands I'm not sure if its relevant.

EDIT: Adding the script + Input with expected output

CASE:

  • Input: C=>bd \\ C=>Bd
  • Expected Output: 'V: 3.5, S: 0, P: 0'
  • Actual Output: 'V: NaN, S: NaN, P: NaN'
let cubes = [
    // smalls
    { letter: 'b', value: 1},
    { letter: 'w', value: 1},
    { letter: 'g', value: 1},
    //larges
    { letter: 'K', value: 1.5},
    { letter: 'Y', value: 1.5},
    { letter: 'B', value: 1.5},
    // ultra
    { letter: 'U', value: 3},
  
    // wilds
    { letter: 'c', value: 1},
    { letter: 'C', value: 1.5},
    { letter: 'd', value: 2},
    { letter: 'D', value: 3},
  
    //non cubes
    { letter: 's', value: 1},
    { letter: '$', value: 1},
    { letter: '0', value: 0},
    { letter: '*', value: 0}, // faction specific token
  ]
  .map(x => x.letter === 's' ? {...x, isShip: true} : {...x, isShip: false})
  .map(x => x.letter === '$' ? {...x, isPoint: true} : {...x, isPoint:false})
  
  /**
   * Prints the converter delta as `{V: value, S: ships, P: points}`
   * @param {string} s Converter Equation.
   * @return {string} Converter Delta
   * @customfunction
   */
  function SC_PRINT(s) {
    let sides;
    if (s.includes(`\\`)) {
      let arr = s.split(`\\`).map(x => x.trim());
      sides = arr.reduce((prev, curr) => {
        let c =  getSides(curr);
        return {
          side1: {
            value: prev.side1.value + c.side1.value,
            ships: prev.side1.ships + c.side1.ships,
            points: prev.side1.points + c.side1.points,
          },
          side2: {
            value: prev.side2.value + c.side2.value,
            ships: prev.side2.ships + c.side2.ships,
            points: prev.side2.points + c.side2.points,
          }
        };
      }, {side1:{value: 0, ships: 0, points: 0}, side2:{value: 0, ships: 0, points: 0}})
    } else {
      sides = getSides(s)
    }
  
    if (!sides.side1 && !sides.side2) {
      return `V: 0, S: 0, P: 0`
    }
    return `V: ${sides.side2.value - sides.side1.value}, S: ${sides.side2.ships}, P: ${sides.side2.points}`;
  }
  
  /** 
   * Splits a converter string into two sides
   * @param {string} s Converter Equation
   * @return {object} The splitted converter
   */
  function getSides(s) {
    if (!s) {
      return {
        side1: '',
        side2: ''
      }
    }
  
    if (s.includes('-')) {
      sides = s.split('->')
    }
    if (s.includes('=')) {
      sides = s.split('=>')
    }
  
    let side1 = getValue(sides[0]);
    let side2 = getValue(sides[1]);
  
    return {
      side1: side1,
      side2: side2
    }
  }
  
  /**
   * Maps a string to an output
   * @param {string} side A side of a converter
   * @returns {object} Object representing the value, ships and points of a particular side
   */
  function getValue (side) {
    side = side
    return side.split('').reduce((prev, curr) => {
      let cube = cubes.filter(c => c.letter === curr)[0];
      if (cube.isShip) return {...prev, ships: prev.ships + 1}
      else if (cube.isPoint) return {...prev, points: prev.points + 1}
      else return {...prev, value: prev.value + cube.value}
    }, {value: 0, ships: 0, points: 0})
  

Solution

  • From @customfunction of your showing script, I guessed that you are using your function SC_PRINT as a custom function like =SC_PRINT("C=>bd \\ C=>Bd").

    In this case, I think that the inputted value of "C=>bd \\ C=>Bd" is given as "C=>bd \\\\ C=>Bd". By this, let arr = s.split(\).map(x => x.trim()); returns [ 'C=>bd', '', 'C=>Bd' ]. I guessed that this is the reason for your current issue of 'V: NaN, S: NaN, P: NaN'.

    In order to remove this issue, how about the following modification? In this modification, the function SC_PRINT is modified.

    From:

    let arr = s.split(`\\`).map(x => x.trim());
    

    To:

    let arr = s.split(/\\{1,}/g).map(x => x.trim());
    

    or

    let arr = s.split(`\\`).map(x => x.trim()).filter(String);
    

    Testing:

    When I tested this modification, the following result was obtained.

    enter image description here