Пересчет ячейки листа Google - PullRequest
0 голосов
/ 04 декабря 2018

Я создаю настольную игру, и я решил выбрать для этой цели листы Google.Я свел свою проблему к минимальному примеру, состоящему из одного листа и одного сценария.


Ситуация

Следующие пункты относятся к моему листу игры в кости:

  • Клетки B2: C5 содержат в наличии кубики .Первый столбец содержит спрайты игральных костей, вторые числа граней, разделенные запятыми.
    • Перспектива игрового дизайна : художник может изменять изображения костей.Дизайнер может изменить номера граней игральных костей.Оба типа изменений будут автоматически распространяться на ячейки, которые ссылаются на кости.
  • Клетки E2: I2 и E10: I10 содержат особые * 1027 бросок *.В каждом броске от 1 до 5 ссылок на кубики в столбце B . Перспектива игрового дизайна : Существует множество различных игровых предметов, каждый из которых может иметь разные кубики для определения результата действия.Разработчик может добавлять или удалять ссылки на кубики, и он будет запускать автоматический пересчет в определенных ячейках (в нашем случае это K2 и K10 ).
Ячейки, начинающиеся с K2 и K10 , содержат результат функции DICEFACES, примененной к диапазонам E2: I2 и E10: I10 .
  • Перспектива игрового дизайна : Матрица граней игральных костей будет в дальнейшем использоваться для расчета вероятностей игральных костей.Для простоты моего примера я рассматриваю саму матрицу как конечный результат.

DICEFACES - это пользовательская функция, которую я создал в редакторе скриптов в файле Code.gsсвязанный с таблицей стилей.Возвращает матрицу граней кубиков, соответствующих кубикам в указанном диапазоне.Его тело выглядит следующим образом:

function DICEFACES(unused_ref_to_range_containing_dices)
{
  var app  = SpreadsheetApp;
  var spr  = app.getActiveSheet();

  // In the end this array will hold the dice faces. For example two
  // 1d6 dices would result in [[1,2,3,4,5,6],[1,2,3,4,5,6]].
  //
  var Dices = [];

  // The the formula inside the active cell (i.e. the cell on which
  // we are calling this function). This is a string like:
  //
  // "=DICEFACES(E2:I2)"
  //
  var active_formula = spr.getActiveRange().getFormula();

  // Set item_range to the one pointed to by the formula. This could
  // be a range like E2:I2.
  //
  var item_range = spr.getRange(active_formula.match(/=\w+\((.*)\)/i)[1]);

  // Loop over dice cells in the item_range.
  //
  for (var i = 1; i <= item_range.getNumColumns(); i++)
  {
    // "=B2", "=B3", ...
    //
    var dice_formula = item_range.getCell(1, i).getFormula();

    // As soon as we encounter an empty formula, we skip (i.e. there are
    // no more dices).
    //
    if (dice_formula == "")
    {
      break;
    }

    // A reference to the cell containing the dice image. We don't really
    // need the image, the dice faces are of greater importance to us.
    //
    var dice_cell = spr.getRange(dice_formula.substr(1));

    // Move one column to the right prior to the dice_cell and retreive
    // the value of the cell. This is a string like "1,2,3,4,5,6".
    //
    var dice_csv = dice_cell.offset(0, 1).getValue();

    // Convert the CSV string to a javascript array like [1,2,3,4,5,6]
    // and push it to Dices.
    //
    Dices.push(dice_csv.split(",").map(Number));
  }
  return Dices;
}

Проблема

Проблема заключается в том, что при изменении граней кубиков в столбце C ,DICEFACE формулы не пересчитываются.Непосредственно перед созданием снимка экрана я добавил ,4 суффикс к ячейке C2 , и, как вы можете видеть, в ячейке N2 нет 4.Однако, если я или повторно сохраню файл сценария Code.gs или и изменим кубики в E2: I2 , пересчет произойдет немедленно.

Я почти уверен, что знаю, в чем проблема: поскольку я пересекаю ячейки в скрипте, само приложение листа не видит ссылочную связь между ячейками в столбце C и формуламив К2 и К10 .Глядя на мой лист, ссылка на ячейку, вероятно, выглядит примерно так:

K4  <-- E2:I2   <-- B2, B3 (C is not here)
K10 <-- E10:I10 <-- B4, B5 (C is not here)

Значение моей записи A <-- B равно If there's a change in range B, update cell A.


Вопрос

Что я должен изменить, чтобы автоматический пересчет произошел сразу после изменения граней костей?И если это невозможно, как лучше всего выполнить мою задачу?

1 Ответ

0 голосов
/ 05 декабря 2018

Проблема в том, что при изменении граней костей в столбце C формулы DICEFACE не пересчитываются.

DIFACE - это пользовательская функция, и пользовательские функции пересчитываются при открытии электронной таблицы и изменении значений аргументов пользовательской функции.

С учетом вышеизложенного, чтобы свести к минимуму изменения в вашей пользовательской функцииФункция добавляет второй аргумент для работы в качестве триггера.

Измените регулярное выражение

/=\w+\((.*)\)/i

на

/=\w+\((.*),.*\)/i

Затем вызовите пользовательскую функцию следующим образом

=DICEFACES(E2:I2,C2)

или

=DICEFACES(E2:I2,C2:C5)


Я использовал запятую, предполагая, что используется разделитель аргументов Google Sheets, но некоторые таблицы вместо этого могут использовать точку с запятой.

Модифицированная версия пользовательской функции OP

/**
 * Returns a matrix of dice faces corresponding to the dices in the provided range.
 *
 * @param {Array} unused_ref_to_range_containing_dices Reference to range. i.e. E2:I2
 * @param {String|Number|Date|Array} ref_as_trigger Reference to a range used as trigger. i.e. C2 or C2:C5
 * @return array
 * @customfunction
 */
function DICEFACES(unused_ref_to_range_containing_dices,ref_as_trigger)
{
  var app  = SpreadsheetApp;
  var spr  = app.getActiveSheet();

  // In the end this array will hold the dice faces. For example two
  // 1d6 dices would result in [[1,2,3,4,5,6],[1,2,3,4,5,6]].
  //
  var Dices = [];

  // The the formula inside the active cell (i.e. the cell on which
  // we are calling this function). This is a string like:
  //
  // "=DICEFACES(E2:I2)"
  //
  var active_formula = spr.getActiveRange().getFormula();

  // Set item_range to the one pointed to by the formula. This could
  // be a range like E2:I2.
  //
  var item_range = spr.getRange(active_formula.match(/=\w+\((.*),.*\)/i)[1]); // CHANGED

  // Loop over dice cells in the item_range.
  //
  for (var i = 1; i <= item_range.getNumColumns(); i++)
  {
    // "=B2", "=B3", ...
    //
    var dice_formula = item_range.getCell(1, i).getFormula();

    // As soon as we encounter an empty formula, we skip (i.e. there are
    // no more dices).
    //
    if (dice_formula == "")
    {
      break;
    }

    // A reference to the cell containing the dice image. We don't really
    // need the image, the dice faces are of greater importance to us.
    //
    var dice_cell = spr.getRange(dice_formula.substr(1));

    // Move one column to the right prior to the dice_cell and retreive
    // the value of the cell. This is a string like "1,2,3,4,5,6".
    //
    var dice_csv = dice_cell.offset(0, 1).getValue();

    // Convert the CSV string to a javascript array like [1,2,3,4,5,6]
    // and push it to Dices.
    //
    Dices.push(dice_csv.split(",").map(Number));
  }
  return Dices;
}
...