かずきち。の日記

サーバサイドエンジニアのつぶやき

オンライン飲み会でビンゴ大会をしたい!GoogleAppsScriptを利用してビンゴ大会を実装する!ビンゴ後の賞品発送まで!

オンラインでビンゴ大会がしたい

飲み会を盛り上げてくれるビンゴ大会。
結婚式や忘年会で催されることも多い。
しかしコロナが始まり、一時期話題になったリモート飲み会も普及しつつあります。
今回はビンゴ大会をオンラインでやる仕組みをさくっと構築していこうと思います。

スプレッドシートを利用してビンゴカードを作る

まずはスプレッドシートをビンゴカードに改造するためのメニューUIを作っていきます。
「ファイル」「編集」「表示」とある一番右に「ゲーム準備」というメニューバーが追加されていると思います。
こいつを押すと、ゲーム開始です。

押すと瞬時にこのようなビンゴカードが発行されます。
数字は自動で機械で割り振ります。
不正ができないように7列にカード発行日時のタイムスタンプを記録するので、不正にカードを再発行しても時間が記録され

とはいえ、時間を書き換えられると意味がないので…

セルの編集権限を自分だけにします。
これでビンゴカードを発行した時間は他人にはいじれなくなります。

あとは通常通りにビンゴ大会のビデオ会議をやっていきます。

「3」…「24」...「37」...

と続けて行くといつかビンゴが出ます。
自動でビンゴ判定のプログラムが走りますので、ビンゴ達成の人には商品発送リンクが表示されます。

他の人は別の番号のビンゴカードが割り振られているので、ゲーム続行です。
これで商品がなくなるまでビンゴを続けます。
そして当選者はビンゴの景品を受け取るリンクが発行されますので、

からビンゴ大会の景品やSNSアカウントを聞き出します。
あとはこちらで商品を用意して送付もしくはAmazonで他人あてに商品を払い出せばよいです。

こんな具合に賞品の到着を待ってもらいましょう。
これでGASを使って飲み会が盛り上がるツールが作れます。

最後にビンゴ大会を行うコードを記載しておきます。
/**
 * このスクリプトの説明、使い方はこちら。
 * https://myfunc.jp/items/00028/index.html
 */

function onOpen() {
  // スプレッドシートを開いたときに実行される関数
  const ui = SpreadsheetApp.getUi()

  // メニューの表示名
  const menu = ui.createMenu('ゲーム準備');

  // メニューに追加するボタン
  menu.addItem('ビンゴカードを生成', 'generate_bingo_card');

  // メニューを画面に追加する
  menu.addToUi();
}


function generate_bingo_card() {
  //A1を直接指定する場合
  SpreadsheetApp.getActiveSheet().getRange("A1").activate();

  // ビンゴに使用する数字をしまっておく配列
  let bingo_numbers = [];

  // ビンゴは左列から1-15/16-30/31-45/46-60/61-75の範囲の値が入る。
  // それぞれの値を用意しておく
  for (let i = 0; i < 5; i++) {

    bingo_numbers[i] = [];

    for (let j = 1; j <= 15; j++) {

      // ビンゴに使う数字は1列目なら0 * 15 + 1-15、2列目なら 1 * 15 + 1-15、3列目なら 2 * 15 + 1-15・・・
      bingo_numbers[i].push(i * 15 + j);

    }
  }

  // 結果書き込み用の配列
  let values = [];

  // ビンゴカードの数字を1行ずつ作成する
  for (let i = 0; i < 5; i++) {

    values[i] = [];

    // 1列ごとに1-15/16-30/31-45/46-60/61-75のいずれかが入る
    for (let j = 0; j < bingo_numbers.length; j++) {

      // 乱数をもとに配列のkeyを指定する
      // 最大値は残っている数字の数だけ
      let key = Math.floor(Math.random() * bingo_numbers[j].length);

      // 結果用配列に入れる
      if (i == 2 && j == 2) { // 中心部分はFREEとする
        values[i].push('FREE');

      } else {
        values[i].push(bingo_numbers[j][key]);
      }

      // 一度使った数字は使えないので削除する
      bingo_numbers[j].splice(key, 1);
    }
  }

  Logger.log(values);

  // スプレッドシートの取得
  const ss = SpreadsheetApp.getActiveSpreadsheet();

  // アクティブシートの取得
  const sheet = ss.getActiveSheet();

  // アクティブセルの取得
  const active_cell = sheet.getActiveCell();

  // アクティブセルの行番号を取得
  const active_row = active_cell.getRow();

  // アクティブセルの列番号を取得
  const active_col = active_cell.getColumn();

  // 書き込み範囲のrangeを取得。アクティブセルから5行と5列だがvaluesのlengthを取っている
  const range = sheet.getRange(active_row, active_col, values.length, values[0].length);

  // セルへ値書き込み
  range.setValues(values);

  // セルの幅を調整する
  for (let i = active_col; i < active_col + values[0].length; i++){
    sheet.setColumnWidth(i, 100);
  }

  // セルの高さを調整する
  for (let i = active_row; i < active_row + values.length; i++){
    sheet.setRowHeight(i, 100);
  }

  // テキストを調整する
  range.setFontSize(20); // フォントサイズを指定
  range.setHorizontalAlignment('center'); // 水平方向の位置を指定
  range.setVerticalAlignment('middle'); // 垂直方向の位置を指定
  range.setBackgroundRGB(255,255,255); // 背景色を指定
  range.setBorder(true,true,true,true,true,true,"RED", SpreadsheetApp.BorderStyle.SOLID_THICK); // 罫線の指定

  var start = sheet.getRange("C3");
  start.setBackground("red");

  var timerange = sheet.getRange('B7'); //書き込み先の範囲
  let date = new Date();
  timerange.setValue(Utilities.formatDate( date, 'Asia/Tokyo', 'yyyy/MM/dd HH:mm:ss')); // 引数の値をセルに入力
}

function bingoCheck(){
    var ss = SpreadsheetApp.getActiveSpreadsheet();
  
  //シート名は置き換えてください
  var sh = ss.getSheetByName("シート1");
  
  //A1セルの背景色を取得する
  var bgColorA1 = sh.getRange(1,1).getBackground();
  //B1セルの背景色を取得する
  var bgColorB1 = sh.getRange(1,2).getBackground();
  //C1セルの背景色を取得する
  var bgColorC1 = sh.getRange(1,3).getBackground();
  //D1セルの背景色を取得する
  var bgColorD1 = sh.getRange(1,4).getBackground();
  //E1セルの背景色を取得する
  var bgColorE1 = sh.getRange(1,5).getBackground();
  //A2セルの背景色を取得する
  var bgColorA2 = sh.getRange(2,1).getBackground();
  //B2セルの背景色を取得する
  var bgColorB2 = sh.getRange(2,2).getBackground();
  //B3セルの背景色を取得する
  var bgColorC2 = sh.getRange(2,3).getBackground();
  //B4セルの背景色を取得する
  var bgColorD2 = sh.getRange(2,4).getBackground();
  //B5セルの背景色を取得する
  var bgColorE2 = sh.getRange(2,5).getBackground();
  //C1セルの背景色を取得する
  var bgColorA3 = sh.getRange(3,1).getBackground();
  //C2セルの背景色を取得する
  var bgColorB3 = sh.getRange(3,2).getBackground();
  //C3セルの背景色を取得する
  var bgColorC3 = sh.getRange(3,3).getBackground();
  //C4セルの背景色を取得する
  var bgColorD3 = sh.getRange(3,4).getBackground();
  //C5セルの背景色を取得する
  var bgColorE3 = sh.getRange(3,5).getBackground();
  //D1セルの背景色を取得する
  var bgColorA4 = sh.getRange(4,1).getBackground();
  //D2セルの背景色を取得する
  var bgColorB4 = sh.getRange(4,2).getBackground();
  //D3セルの背景色を取得する
  var bgColorC4 = sh.getRange(4,3).getBackground();
  //D4セルの背景色を取得する
  var bgColorD4 = sh.getRange(4,4).getBackground();
  //D5セルの背景色を取得する
  var bgColorE4 = sh.getRange(4,5).getBackground();
  //E1セルの背景色を取得する
  var bgColorA5 = sh.getRange(5,1).getBackground();
  //E2セルの背景色を取得する
  var bgColorB5 = sh.getRange(5,2).getBackground();
  //E3セルの背景色を取得する
  var bgColorC5 = sh.getRange(5,3).getBackground();
  //E4セルの背景色を取得する
  var bgColorD5 = sh.getRange(5,4).getBackground();
  //E5セルの背景色を取得する
  var bgColorE5 = sh.getRange(5,5).getBackground();

  //ログを確認
  Logger.log(bgColorA3);

  //縦列ビンゴ判定
  if (bgColorA1 === "#ff0000" && bgColorA2 === "#ff0000" && bgColorA3 === "#ff0000" && bgColorA4 === "#ff0000" && bgColorA5 === "#ff0000"){
    SpreadsheetApp.getUi().alert('ビンゴおめでとうございます。\n景品発送手続きに入りますので、\n https://docs.google.com/forms/d/e/1FAIpQLSdd97i9-F6QU3LCMTMf0PU_xaq--eQ3eI32BRXuu5p9q_7TRQ/viewform?usp=sf_link\nにアクセスして、発送先を登録してください。1人につき、応募は1回のみです。');
  }

  if (bgColorB1 === "#ff0000" && bgColorB2 === "#ff0000" && bgColorB3 === "#ff0000" && bgColorB4 === "#ff0000" && bgColorB5 === "#ff0000"){
    SpreadsheetApp.getUi().alert('ビンゴおめでとうございます。\n景品発送手続きに入りますので、\n https://docs.google.com/forms/d/e/1FAIpQLSdd97i9-F6QU3LCMTMf0PU_xaq--eQ3eI32BRXuu5p9q_7TRQ/viewform?usp=sf_link\nにアクセスして、発送先を登録してください。1人につき、応募は1回のみです。');
  }

  if (bgColorC1 === "#ff0000" && bgColorC2 === "#ff0000" && bgColorC3 === "#ff0000" && bgColorC4 === "#ff0000" && bgColorC5 === "#ff0000"){
    SpreadsheetApp.getUi().alert('ビンゴおめでとうございます。\n景品発送手続きに入りますので、\n https://docs.google.com/forms/d/e/1FAIpQLSdd97i9-F6QU3LCMTMf0PU_xaq--eQ3eI32BRXuu5p9q_7TRQ/viewform?usp=sf_link\nにアクセスして、発送先を登録してください。1人につき、応募は1回のみです。');
  }

  if (bgColorD1 === "#ff0000" && bgColorD2 === "#ff0000" && bgColorD3 === "#ff0000" && bgColorD4 === "#ff0000" && bgColorD5 === "#ff0000"){
    SpreadsheetApp.getUi().alert('ビンゴおめでとうございます。\n景品発送手続きに入りますので、\n https://docs.google.com/forms/d/e/1FAIpQLSdd97i9-F6QU3LCMTMf0PU_xaq--eQ3eI32BRXuu5p9q_7TRQ/viewform?usp=sf_link\nにアクセスして、発送先を登録してください。1人につき、応募は1回のみです。');
  }

  if (bgColorE1 === "#ff0000" && bgColorE2 === "#ff0000" && bgColorE3 === "#ff0000" && bgColorE4 === "#ff0000" && bgColorE5 === "#ff0000"){
    SpreadsheetApp.getUi().alert('ビンゴおめでとうございます。\n景品発送手続きに入りますので、\n https://docs.google.com/forms/d/e/1FAIpQLSdd97i9-F6QU3LCMTMf0PU_xaq--eQ3eI32BRXuu5p9q_7TRQ/viewform?usp=sf_link\nにアクセスして、発送先を登録してください。1人につき、応募は1回のみです。');
  }
  
  //横列ビンゴ判定
  if (bgColorA1 === "#ff0000" && bgColorB1 === "#ff0000" && bgColorC1 === "#ff0000" && bgColorD1 === "#ff0000" && bgColorE1 === "#ff0000"){
    SpreadsheetApp.getUi().alert('ビンゴおめでとうございます。\n景品発送手続きに入りますので、\n https://docs.google.com/forms/d/e/1FAIpQLSdd97i9-F6QU3LCMTMf0PU_xaq--eQ3eI32BRXuu5p9q_7TRQ/viewform?usp=sf_link\nにアクセスして、発送先を登録してください。1人につき、応募は1回のみです。');
  }

  if (bgColorA2 === "#ff0000" && bgColorB2 === "#ff0000" && bgColorC2 === "#ff0000" && bgColorD2 === "#ff0000" && bgColorE2 === "#ff0000"){
    SpreadsheetApp.getUi().alert('ビンゴおめでとうございます。\n景品発送手続きに入りますので、\n https://docs.google.com/forms/d/e/1FAIpQLSdd97i9-F6QU3LCMTMf0PU_xaq--eQ3eI32BRXuu5p9q_7TRQ/viewform?usp=sf_link\nにアクセスして、発送先を登録してください。1人につき、応募は1回のみです。');
  }

  if (bgColorA3 === "#ff0000" && bgColorB3 === "#ff0000" && bgColorC3 === "#ff0000" && bgColorD3 === "#ff0000" && bgColorE3 === "#ff0000"){
    SpreadsheetApp.getUi().alert('ビンゴおめでとうございます。\n景品発送手続きに入りますので、\n https://docs.google.com/forms/d/e/1FAIpQLSdd97i9-F6QU3LCMTMf0PU_xaq--eQ3eI32BRXuu5p9q_7TRQ/viewform?usp=sf_link\nにアクセスして、発送先を登録してください。1人につき、応募は1回のみです。');
  }

  if (bgColorA4 === "#ff0000" && bgColorB4 === "#ff0000" && bgColorC4 === "#ff0000" && bgColorD4 === "#ff0000" && bgColorE4 === "#ff0000"){
    SpreadsheetApp.getUi().alert('ビンゴおめでとうございます。\n景品発送手続きに入りますので、\n https://docs.google.com/forms/d/e/1FAIpQLSdd97i9-F6QU3LCMTMf0PU_xaq--eQ3eI32BRXuu5p9q_7TRQ/viewform?usp=sf_link\nにアクセスして、発送先を登録してください。1人につき、応募は1回のみです。');
  }

  if (bgColorA5 === "#ff0000" && bgColorB5 === "#ff0000" && bgColorC5 === "#ff0000" && bgColorD5 === "#ff0000" && bgColorE5 === "#ff0000"){
    SpreadsheetApp.getUi().alert('ビンゴおめでとうございます。\n景品発送手続きに入りますので、\n https://docs.google.com/forms/d/e/1FAIpQLSdd97i9-F6QU3LCMTMf0PU_xaq--eQ3eI32BRXuu5p9q_7TRQ/viewform?usp=sf_link\nにアクセスして、発送先を登録してください。1人につき、応募は1回のみです。');
  }

  //斜め列ビンゴ判定
  if (bgColorA1 === "#ff0000" && bgColorB2 === "#ff0000" && bgColorC3 === "#ff0000" && bgColorD4 === "#ff0000" && bgColorE5 === "#ff0000"){
    SpreadsheetApp.getUi().alert('ビンゴおめでとうございます。\n景品発送手続きに入りますので、\n https://docs.google.com/forms/d/e/1FAIpQLSdd97i9-F6QU3LCMTMf0PU_xaq--eQ3eI32BRXuu5p9q_7TRQ/viewform?usp=sf_link\nにアクセスして、発送先を登録してください。1人につき、応募は1回のみです。');
  }

  if (bgColorE1 === "#ff0000" && bgColorD2 === "#ff0000" && bgColorC3 === "#ff0000" && bgColorB4 === "#ff0000" && bgColorA5 === "#ff0000"){
    SpreadsheetApp.getUi().alert('ビンゴおめでとうございます。\n景品発送手続きに入りますので、\n https://docs.google.com/forms/d/e/1FAIpQLSdd97i9-F6QU3LCMTMf0PU_xaq--eQ3eI32BRXuu5p9q_7TRQ/viewform?usp=sf_link\nにアクセスして、発送先を登録してください。1人につき、応募は1回のみです。');
  }
}

プログラムの序盤ではビンゴカードの発行。
終盤ではビンゴ判定が行われています。
興味ある人は是非オンラインビンゴ大会をやってみてください。