สร้างวงเล็บการแข่งขัน

ระดับการเขียนโค้ด: ระดับเริ่มต้น ระยะเวลา: 5 นาที ประเภทโปรเจ็กต์: ระบบอัตโนมัติที่มีเมนูที่กำหนดเอง

วัตถุประสงค์

  • ทำความเข้าใจสิ่งที่โซลูชันทำ
  • ทำความเข้าใจสิ่งที่บริการ Apps Script ทำภายในโซลูชัน
  • ตั้งค่าสคริปต์
  • เรียกใช้สคริปต์

เกี่ยวกับโซลูชันนี้

สร้างสายการแข่งขันสำหรับผู้เล่นหรือทีมได้สูงสุด 64 รายการ โซลูชันนี้จะสร้างแผนผังแบบต้นไม้ที่แสดงการแข่งขันแบบแพ้คัดออก

ตัวอย่างตารางการแข่งขันที่เสร็จสมบูรณ์

วิธีการทำงาน

สคริปต์จะวนซ้ำในรายการผู้เล่นและกำหนดจำนวนรอบที่จำเป็นในสายการแข่งขัน สคริปต์จะจัดรูปแบบชีตสายการแข่งขัน เพื่อสร้างแผนผังแบบต้นไม้และเพิ่มชื่อผู้เล่นในรอบแรก

บริการ Apps Script

โซลูชันนี้ใช้บริการต่อไปนี้

  • บริการสเปรดชีต: รับช่วงของผู้เล่นและสร้างแผนภาพแบบต้นไม้สำหรับการแข่งขัน

ข้อกำหนดเบื้องต้น

หากต้องการใช้ตัวอย่างนี้ คุณต้องมีข้อกำหนดเบื้องต้นต่อไปนี้

  • บัญชี Google (บัญชี Google Workspace อาจต้องได้รับการอนุมัติจากผู้ดูแลระบบ)
  • เว็บเบราว์เซอร์ที่เข้าถึงอินเทอร์เน็ตได้

ตั้งค่าสคริปต์

คลิกปุ่มต่อไปนี้เพื่อทำสำเนาสเปรดชีตตัวอย่างสร้างสายการแข่งขัน

ทำสำเนา

เรียกใช้สคริปต์

  1. ในสเปรดชีตที่คัดลอก ให้คลิกเครื่องมือสร้างสายการแข่งขัน > สร้างสายการแข่งขัน คุณอาจต้องรีเฟรชหน้าเพื่อให้เมนูที่กำหนดเองนี้ปรากฏขึ้น
  2. ให้สิทธิ์สคริปต์เมื่อได้รับข้อความแจ้ง <<../_snippets/oauth.md>>

  3. คลิกเครื่องมือสร้างสายการแข่งขัน > สร้างสายการแข่งขัน อีกครั้ง

  4. เปลี่ยนไปที่แท็บสายการแข่งขัน เพื่อดูสายการแข่งขัน

ตรวจสอบโค้ด

หากต้องการตรวจสอบโค้ด Apps Script สำหรับโซลูชันนี้ ให้คลิก ดูซอร์สโค้ด:

ดูซอร์สโค้ด

Code.gs

solutions/automations/bracket-maker/Code.js
// To learn how to use this script, refer to the documentation:
// https://developers.google.com/apps-script/samples/automations/bracket-maker

/*
Copyright 2022 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

const RANGE_PLAYER1 = "FirstPlayer";
const SHEET_PLAYERS = "Players";
const SHEET_BRACKET = "Bracket";
const CONNECTOR_WIDTH = 15;

/**
 * Adds a custom menu item to run the script.
 */
function onOpen() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  ss.addMenu("Bracket maker", [
    { name: "Create bracket", functionName: "createBracket" },
  ]);
}

/**
 * Creates the brackets based on the data provided on the players.
 */
function createBracket() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  let rangePlayers = ss.getRangeByName(RANGE_PLAYER1);
  const sheetControl = ss.getSheetByName(SHEET_PLAYERS);
  const sheetResults = ss.getSheetByName(SHEET_BRACKET);

  // Gets the players from column A.  Assumes the entire column is filled.
  rangePlayers = rangePlayers.offset(
    0,
    0,
    sheetControl.getMaxRows() - rangePlayers.getRowIndex() + 1,
    1,
  );
  let players = rangePlayers.getValues();

  // Figures out how many players there are by skipping the empty cells.
  let numPlayers = 0;
  for (let i = 0; i < players.length; i++) {
    if (!players[i][0] || players[i][0].length === 0) {
      break;
    }
    numPlayers++;
  }
  players = players.slice(0, numPlayers);

  // Provides some error checking in case there are too many or too few players/teams.
  if (numPlayers > 64) {
    Browser.msgBox(
      "Sorry, this script can only create brackets for 64 or fewer players.",
    );
    return; // Early exit
  }

  if (numPlayers < 3) {
    Browser.msgBox("Sorry, you must have at least 3 players.");
    return; // Early exit
  }

  // Clears the 'Bracket' sheet and all formatting.
  sheetResults.clear();

  let upperPower = Math.ceil(Math.log(numPlayers) / Math.log(2));

  // Calculates the number that is a power of 2 and lower than numPlayers.
  const countNodesUpperBound = 2 ** upperPower;

  // Calculates the number that is a power of 2 and higher than numPlayers.
  const countNodesLowerBound = countNodesUpperBound / 2;

  // Determines the number of nodes that will not show in the 1st level.
  const countNodesHidden = numPlayers - countNodesLowerBound;

  // Enters the players for the 1st round.
  const currentPlayer = 0;
  for (let i = 0; i < countNodesLowerBound; i++) {
    if (i < countNodesHidden) {
      // Must be on the first level
      const rng = sheetResults.getRange(i * 4 + 1, 1);
      setBracketItem_(rng, players);
      setBracketItem_(rng.offset(2, 0, 1, 1), players);
      setConnector_(sheetResults, rng.offset(0, 1, 3, 1));
      setBracketItem_(rng.offset(1, 2, 1, 1));
    } else {
      // This player gets a bye.
      setBracketItem_(sheetResults.getRange(i * 4 + 2, 3), players);
    }
  }

  // Fills in the rest of the bracket.
  upperPower--;
  for (let i = 0; i < upperPower; i++) {
    const pow1 = 2 ** (i + 1);
    const pow2 = 2 ** (i + 2);
    const pow3 = 2 ** (i + 3);
    for (let j = 0; j < 2 ** (upperPower - i - 1); j++) {
      setBracketItem_(sheetResults.getRange(j * pow3 + pow2, i * 2 + 5));
      setConnector_(
        sheetResults,
        sheetResults.getRange(j * pow3 + pow1, i * 2 + 4, pow2 + 1, 1),
      );
    }
  }
}

/**
 * Sets the value of an item in the bracket and the color.
 * @param {Range} rng The Spreadsheet Range.
 * @param {string[]} players The list of players.
 */
function setBracketItem_(rng, players) {
  if (players) {
    const rand = Math.ceil(Math.random() * players.length);
    rng.setValue(players.splice(rand - 1, 1)[0][0]);
  }
  rng.setBackgroundColor("yellow");
}

/**
 * Sets the color and width for connector cells.
 * @param {Sheet} sheet The spreadsheet to setup.
 * @param {Range} rng The spreadsheet range.
 */
function setConnector_(sheet, rng) {
  sheet.setColumnWidth(rng.getColumnIndex(), CONNECTOR_WIDTH);
  rng.setBackgroundColor("green");
}
</section>

ผู้ร่วมให้ข้อมูล

ตัวอย่างนี้ได้รับการดูแลโดย Google โดยได้รับความช่วยเหลือจาก Google Developer Experts

ขั้นตอนถัดไป