パソコン用ヘッダー画像
Googleサービス PR

雨の日・猛暑の日はおうちでボウリング大会!~GASでスコア自動計算~

GASでボウリングスコア表を自動計算
記事内に商品プロモーションを含む場合があります

夏休み、子供たちと過ごす時間は宝物。でも、連日の雨や猛暑で、外遊びもままならない…。そんな時こそ、おうち時間を最大限に活用しませんか?今回は、Google Apps Script(GAS)を使って、なんとボウリングのスコア自動計算表を作る方法をご紹介します!

GASでボウリングスコア自動計算表を作ろう!

スプレッドシートで作成したボウリングスコア表

Google Apps Script(GAS)とは何か、その基本的な使い方を解説します。
さらに、ボウリングのスコアを自動計算するスプレッドシートの作成手順をわかりやすく説明します。GAS初心者でも安心して取り組めるように、1つ1つのステップを丁寧に解説します。

ボウリングのスコア計算は意外と複雑

スペア、ストライク、ボウリングのルールはシンプル。でも、スコアの計算を自動でおこなうとなると、意外と奥深い!

今回は、そんな計算をGASをつかって、自動で計算してくれるようなスクリプトを作ってみたので紹介します。

作成手順をステップごとに解説

  • STEP1
    スプレッドシートの準備
    ボウリングのスコアを記録するためのスプレッドシートを作成
  • STEP2
    GASエディタを開く
    スプレッドシートのメニューバーから「拡張機能」→「Apps Script」を選択
  • STEP3
    コードを書く
    ボウリングのスコアを計算するためのコード作成。ボウリングのスコア計算ルールに基づいて、各フレームのスコアや合計スコアを計算するロジックを記述
  • STEP4
    コードを実行
    コードを書き終えたら、GASエディタのツールバーにある実行ボタンを押してコードを実行
  • STEP5
    トリガー設定
    スプレッドシートに編集があったら、スクリプトが実行されるようにトリガー設定

ボウリングスコア自動計算スクリプト解説

GAS作成の手順

このGoogle Apps Script (GAS)は、ボウリングのスコア表を自動計算するためのものです。「スコア表」シートに入力された各フレームの投球結果をもとに、各プレイヤーのスコアをリアルタイムで更新します。

function onEdit(e) {
  if (!e || !e.range) return; 
  const sheet = e.range.getSheet();
  if (sheet.getName() !== "スコア表") return;

  const editedRow = e.range.getRow();
  const editedColumn = e.range.getColumn();

  if (editedRow >= 3 && editedColumn >= 2 && editedColumn <= sheet.getLastColumn()) {
    calculateScore();
  }
}

function calculateScore() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("スコア表");
  const lastColumn = sheet.getLastColumn();
  const lastPlayer = (lastColumn - 1) / 4;

  for (let player = 1; player <= lastPlayer; player++) {
    let totalScore = 0;

    for (let frame = 1; frame <= 10; frame++) {
      const row = frame + 2;
      const col = (player - 1) * 4 + 2;

      const firstThrow = sheet.getRange(row, col).getValue();
      const secondThrow = sheet.getRange(row, col + 1).getValue();
      const thirdThrow = frame === 10 ? sheet.getRange(row, col + 2).getValue() : "";

      const firstThrowValue = parseThrow(firstThrow);
      const secondThrowValue = parseThrow(secondThrow, firstThrowValue);
      const thirdThrowValue = parseThrow(thirdThrow);

      if (isNaN(firstThrowValue) || (secondThrow !== "" && isNaN(secondThrowValue)) || (thirdThrow !== "" && isNaN(thirdThrowValue))) {
        sheet.getRange(row, col + 3).clearContent();
        continue;
      }

      let frameScore = firstThrowValue + (secondThrow !== "" ? secondThrowValue : 0);

      if (frame < 10) { 
        if (firstThrow === "X") { 
          const nextFirstThrow = sheet.getRange(row + 1, col).getValue();
          const nextSecondThrow = sheet.getRange(row + 1, col + 1).getValue();
          const nextFirstThrowValue = parseThrow(nextFirstThrow);
          const nextSecondThrowValue = parseThrow(nextSecondThrow, nextFirstThrowValue);

          if (nextFirstThrow === "X" && frame < 9) {
            const nextNextFirstThrow = sheet.getRange(row + 2, col).getValue();
            const nextNextFirstThrowValue = parseThrow(nextNextFirstThrow);
            frameScore += nextFirstThrowValue + nextNextFirstThrowValue;
          } else {
            frameScore += nextFirstThrowValue + nextSecondThrowValue;
          }
        } else if (secondThrow === "/") { 
          const nextFirstThrow = sheet.getRange(row + 1, col).getValue();
          const nextFirstThrowValue = parseThrow(nextFirstThrow);
          frameScore += nextFirstThrowValue;
        }
      } else { 
        if (firstThrow === "X") {
          // 10フレーム目のストライクの計算を確認
          frameScore = 10 + secondThrowValue + thirdThrowValue;
        } else if (secondThrow === "/") {
          // 10フレーム目のスペアの計算を確認
          frameScore = firstThrowValue + 10 - firstThrowValue + thirdThrowValue;
        } else {
          // 通常の計算
          frameScore = firstThrowValue + secondThrowValue;
        }
      }

      totalScore += frameScore;
      sheet.getRange(row, col + 3).setValue(isNaN(totalScore) ? "" : totalScore);
    }
  }
}

function parseThrow(throwValue, firstThrowValue = 0) {
  if (throwValue === "X") return 10;
  if (throwValue === "/") return 10 - firstThrowValue;
  if (throwValue === "-") return 0;
  return parseInt(throwValue, 10);
}

onEdit(e)関数:

  • スコア表が編集されたときに実行
  • 編集されたセルがスコア表の対象範囲内(3行目以降、2列目以降)にある場合のみ、calculateScore関数を呼び出す

calculateScore()関数:

  • スコア計算の中心となる関数
  • スコア表の最終列から、何人プレイしているかを計算
  • 各プレイヤーごとに以下の処理
  • 各フレーム(1〜10フレーム)のスコアを計算
    • 1投目、2投目(10フレーム目は3投目も)の値を取得し、parseThrow関数で数値に変換
    • ストライク (X) やスペア (/) の場合は、次のフレームの投球結果も考慮してスコアを計算
    • 各フレームのスコアを合計し、その時点でのトータルスコアをセルに表示

parseThrow(throwValue, firstThrowValue)関数:

  • 投球結果の文字列(”X”, “/”, “-“, 数字など)を数値に変換する補助関数
  • ストライクは10点、スペアは(10 – 1投目の点数)、ガターは0点

おうち遊びにもボウリングは最適!

子どもと遊ぶ家ボウリング

家ボウリングの最大の魅力は、天候に左右されずにいつでも楽しめることです。雨で外遊びができない日や、夏の暑い日でも、エアコンの効いた快適な室内で体を動かすことができます。

ボウリングは、ピンを倒す爽快感や、スコアを競い合う楽しさを味わえるだけでなく、全身運動にもなるので、子供たちの運動不足解消にも役立ちます。

GASで広がる!おうち遊びの可能性

GASの活用方法として、タブレット学習やオリジナルゲームの作成など、家遊びをさらに充実させるアイデアを紹介します。GASの可能性は無限大!あなたのアイデア次第で、様々な楽しみ方ができます。

デジタル×アナログで楽しむ家ボウリング

我が家では、Pixelタブレットを活用して、家ボウリングを楽しんでいます。子供たちは、自分のデバイスでスコアを確認しながら、より楽しくボウリングをすることができます。

紙とペンでスコアを記録するアナログな方法と組み合わせることで、デジタルとアナログの両方を楽しめるのも魅力。

GASで家ボウリングを楽しもう!

この記事では、GASを使ったボウリングスコア自動計算表の作成方法と、家ボウリングの魅力、アレンジアイデアを紹介しました。

GASを活用することで、家遊びがもっと楽しく、学びのあるものになることをお伝えしました。ぜひ、この記事を参考に、あなたもGASでオリジナルのボウリング大会を開催し、子供たちと一緒に素敵な思い出を作ってください。


Fatal error: Uncaught JSMin_UnterminatedRegExpException: JSMin: Unterminated RegExp at byte 47225: /.source + in /home/c1448553/public_html/one-walker.net/wp-content/plugins/autoptimize/classes/external/php/jsmin.php:264 Stack trace: #0 /home/c1448553/public_html/one-walker.net/wp-content/plugins/autoptimize/classes/external/php/jsmin.php(150): JSMin->action(1) #1 /home/c1448553/public_html/one-walker.net/wp-content/plugins/autoptimize/classes/external/php/jsmin.php(84): JSMin->min() #2 /home/c1448553/public_html/one-walker.net/wp-content/plugins/autoptimize/classes/autoptimizeSpeedupper.php(38): JSMin::minify('/* PrismJS 1.29...') #3 /home/c1448553/public_html/one-walker.net/wp-includes/class-wp-hook.php(324): autoptimizeSpeedupper->js_snippetcacher('/* PrismJS 1.29...', '/home/c1448553/...') #4 /home/c1448553/public_html/one-walker.net/wp-includes/plugin.php(205): WP_Hook->apply_filters('/* PrismJS 1.29...', Array) #5 /home/c1448553/public_html/one-walker.net/wp-content/plugins/autoptimize/classes/autoptimizeScripts.ph in /home/c1448553/public_html/one-walker.net/wp-content/plugins/autoptimize/classes/external/php/jsmin.php on line 264