LoginSignup
1
0
記事投稿キャンペーン 「2024年!初アウトプットをしよう」

GASで「情シスビンゴ」を作ってみた!

Last updated at Posted at 2024-01-13

Why & What|はじめに

「作ったきかっけ」と「どんなものができたか」については、下記のnoteにまとめました。
先にご確認いただけると嬉しいです!

How|スクリプトの内容

GitHub

特に学びとなった部分の振り返り

メニューの作成

ui.gs
// サンプルコード
// スプレッドシートが開かれたら自動的に実行される関数
function onOpen() {
  let ui = SpreadsheetApp.getUi();
  ui.createMenu('[GAS]')
    .addItem('実行する処理の名前', 'function名')
    .addSeparator()
    .addSubMenu(
      ui.createMenu("設定")
        .addItem('実行する処理の名前', 'function名')
        .addItem('実行する処理の名前', 'function名'))
    .addToUi();
  • 過去、挿入した図形にスクリプトを割り当て「GAS実行ボタン」を作ったりしていましたが、Uiクラスからメニューを作成する方がスッキリしますね。
  • 階層構造も作ることができて、とても便利。

配列から要素をランダムに選択する(Math.random)

sample-getRandomValue.gs
function getRandomValue(array, key) {
  // [0以上 array.length 未満]のランダムな整数を生成
  let randomIndex = Math.floor(Math.random() * array.length);
  // [ランダムに選択されたインデックス]に対応する配列の要素を取得
  let selectedElement = array[randomIndex];
  // インデックスを指定して値を取り出す
  let selectedValue = selectedElement[key];

  // [選択された要素]と[そのプロパティの値]をオブジェクトとして返す
  return { element: selectedElement, value: selectedValue };
}

// サンプル
const sampleArray = [
  { id: 1, value: "A" },
  { id: 2, value: "B" },
  { id: 3, value: "C" },
  { id: 4, value: "D" },
  { id: 5, value: "E" }
];

const result = getRandomValue(sampleArray, "value");

console.log("Selected Element:", result.element);
console.log("Selected Value:", result.value);
  • Math.floor()
    • 引数として与えられた数値以下で、最大の整数に切り捨てられた値を返す
  • Math.random()*array.length
    • Math.random()
      • 「0~1」間の数字をランダムに生成する(「0.37654」などなど)
    • array.length
      • 配列の要素数

こちらの記事が分かりやすかったです。

[ garagarapon.gs ]では、ランダムに取り出した値(ビンゴ文字/' item ')を書き込みなどに利用していますね。

garagarapon.gs
  // ランダムに要素を1つ選択
  let randomIndex = Math.floor(Math.random() * remainingItems.length);
  let selectedItem = remainingItems[randomIndex];
  let item = selectedItem[1];

配列全体をランダムに並べ替える(Fisher–Yates のシャッフル)

createBingoCards.gs
function fisherYatesShuffle(array) {
  // 変数を宣言する時に同時に値を代入して初期化(array.length)
  let currentIndex = array.length, temporaryValue, randomIndex;

    // currentIndex : 配列内の現在の要素の位置を示す変数
    // temporaryValue : 要素の交換時に一時的に値を保存するための変数
    // randomIndex : ランダムに選択されたインデックスを保存する変数

  // currentIndex が 0 になるまで繰り返す
  while (currentIndex !== 0) {
    // 配列の中からランダムにインデックスを選択
    randomIndex = Math.floor(Math.random() * currentIndex);
    // currentIndex をデクリメント(数値を1ずつ減少させる)
    currentIndex -= 1;

    // 現在の要素をtmp変数に保存
    temporaryValue = array[currentIndex];
    // 現在の要素とランダムに選択した要素を交換
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
  }

  // シャッフルされた配列を返す
  return array;
}
// サンプル
let sampleArray = [1, 2, 3, 4, 5];
let shuffledArray = fisherYatesShuffle(sampleArray);

console.log(shuffledArray);
  • 1つの配列のなかで、「入れ替え前」と「入れ替え後」の領域に分割して考える
    • 1回目:元の配列から1つをランダムに選択し、配列の末尾の要素と入れ替える
    • 2回目:末尾の要素は「入れ替え後」の領域なので、末尾-1の範囲から1つをランダム選択し、「入れ替え前」領域の末尾の要素と入れ替える
    • 3回目:「入れ替え後」領域に2つの要素があるので、「入れ替え前」領域は元の配列の末尾-2の部分
  • 「入れ替え前」領域が無くなるまで繰り返す

こちらの記事がとても分かりやすかったです。

抽選された要素を探し「済フラグ」を入れる

setDoneStatus.gs
function setDoneStatus(sheet, columnName, targetValue, setStatus) {
  // シート上のすべての値を取得
  let data = sheet.getDataRange().getValues();

  // 列名が格納された最初の行を取得
  let headerRow = data[0];

  // columnNameに指定された列のインデックスを取得
  let columnIndex = headerRow.indexOf(columnName);

  // columnNameが見つからない場合はエラーを出力して終了
  if (columnIndex === -1) {
    console.error(`Column '${columnName}' not found.`);
    return;
  }

  // データの行を走査( [iの初期値=1]なので2行目から処理を開始)
  for (let i = 1; i < data.length; i++) {
    // 対象の値が見つかったらステータスを設定してループ終了(break)
    if (data[i][columnIndex] === targetValue) {
      sheet.getRange(i + 1, columnIndex + 1).setValue(setStatus);
      break;
    }
  }
}

// サンプル
// function setDoneStatus(sheet, columnName, targetValue, setStatus)
setDoneStatus(all_item_sheet, "name", item, "");

  • 要素をランダムに選択する処理と合わせて、事後処理として汎用性が高い。

サンプルコードとほぼ同じですが、[ garagarapon.gs ]では「要素シート」上のすべての値を取得して、各行の2番目の要素が、引数として渡された name と一致するかを確認しています。

garagarapon.gs
// 選ばれた要素に済フラグを入れる関数
function set_done(num_item_sheet, name) {
  // num_item_sheet(要素シート)上のすべての値を取得
  let num_item_data = num_item_sheet.getDataRange().getValues();
  for (let i = 1; i < num_item_data.length; i++) {
    // 各行の2番目の要素(num_item_data[i][1])が、引数として渡された name と一致するか確認
    if (num_item_data[i][1] == name) {
      // 一致した行の3番目の要素(num_item_data[i][2])に '済' を設定し、 break でループ終了
      num_item_sheet.getRange(i + 1, 3).setValue('');
      break;
    }
  }
}

余談ですが、要素に数字を入れて実行してみると、シャッフルされているのが分かりやすいですね。

image.png

image.png


以上です!

参考記事

「情シスビンゴ」GAS作成の参考

スクリプト振り返りの参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0