토너먼트 대괄호 만들기

코딩 수준: 초급
시간: 5분
프로젝트 유형: 맞춤 메뉴를 사용한 자동화

목표

  • 솔루션의 기능을 이해합니다.
  • 솔루션 내에서 Apps Script 서비스의 기능을 이해합니다.
  • 스크립트를 설정합니다.
  • 스크립트를 실행합니다.

이 솔루션 정보

최대 64명의 인원이나 팀이 참여하는 토너먼트 대진표를 만드세요. 이 솔루션은 싱글 엘리미네이션 토너먼트를 나타내는 트리 다이어그램을 만듭니다.

토너먼트 대진표의 스크린샷

사용 방법

스크립트는 플레이어 목록을 반복하고 대괄호 안에 필요한 라운드 수를 결정합니다. 스크립트는 대괄호 시트 형식을 지정하여 트리 다이어그램을 만들고 플레이어의 이름을 1라운드에 추가합니다.

Apps Script 서비스

이 솔루션은 다음 서비스를 사용합니다.

스프레드시트 서비스–플레이어 범위를 가져오고 토너먼트의 트리 다이어그램을 만듭니다.

기본 요건

이 샘플을 사용하려면 다음과 같은 기본 요건이 필요합니다.

  • Google 계정 (Google Workspace 계정은 관리자 승인이 필요할 수 있음)
  • 인터넷 액세스가 가능한 웹브라우저

스크립트 설정

다음 버튼을 클릭하여 토너먼트 대진표 만들기 샘플 스프레드시트의 사본을 만드세요.
사본 만들기

스크립트 실행

  1. 복사한 스프레드시트에서 괄호 만들기 > 대괄호 만들기를 클릭합니다. 이 맞춤 메뉴를 표시하려면 페이지를 새로고침해야 할 수 있습니다.
  2. 메시지가 표시되면 스크립트를 승인합니다. OAuth 동의 화면에 확인되지 않은 앱입니다라는 경고가 표시되면 고급 > {프로젝트 이름}(으)로 이동(안전하지 않음)을 선택하여 계속 진행합니다.

  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() {
  let 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() {
  let ss = SpreadsheetApp.getActiveSpreadsheet();
  let rangePlayers = ss.getRangeByName(RANGE_PLAYER1);
  let sheetControl = ss.getSheetByName(SHEET_PLAYERS);
  let 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.
  let countNodesUpperBound = Math.pow(2, upperPower);

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

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

  // Enters the players for the 1st round.
  let currentPlayer = 0;
  for (let i = 0; i < countNodesLowerBound; i++) {
    if (i < countNodesHidden) {
      // Must be on the first level
      let 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++) {
    let pow1 = Math.pow(2, i + 1);
    let pow2 = Math.pow(2, i + 2);
    let pow3 = Math.pow(2, i + 3);
    for (let j = 0; j < Math.pow(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) {
    let 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');
}

참여자

이 샘플은 Google Developer Experts의 도움으로 Google에서 관리합니다.

다음 단계