1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

フリーアドレスなのに同じ席に座りがちなので、自動席替えシステム作ってみた

Last updated at Posted at 2025-12-04

1. フリーアドレスでも同じ席座りがち

フリーアドレスでも皆なんとなく同じような席に座りがちじゃないですか?
これだとフリーアドレスの意味があまりないなと感じていました。

そこで、小学校のときに席替えがありワクワクしていたことを思い出し、毎日自動で席が割り当てられるシステムを作成しました。

2. できたもの!

GASを用いて、実行すると次の日の出欠表を見て座席表が更新されるようになってます。

※ ボタンを押して実行していますが、トリガーで毎日自動実行されるようにしています。

Videotogif (9).gif

機能は以下になります。

機能

  • 自動で翌日の出欠シートを見てランダムに出席者を座席表シートが更新される
  • 金曜は土日を飛ばして月曜の出欠を見る
  • ボタンを押しても実行できる

3. 実装

3.1. 全体コード

こちらが全体コードです
// 設定
const SEAT_SHEET_NAME = "今日の座席";
const ATTENDANCE_SHEET_NAME = "出欠";

// 座席の配置
const SEAT_CELLS = [
  "B2", "B3", "B4",
  "C2", "C3", "C4"
];

 // 席替えを実行するメイン関数
 // GASのトリガーで毎日実行することを想定 
function shuffleSeats() {
  const spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
  const seatSheet = spreadSheet.getSheetByName(SEAT_SHEET_NAME);
  const attendanceSheet = spreadSheet.getSheetByName(ATTENDANCE_SHEET_NAME);
  
  const today = new Date();
  const weekday = getWeekday(today);
  
  // 土日は実行しない
  if (weekday === "" || weekday === "") {
    console.log("土日のため、席替えをスキップします");
    return;
  }
  
  // 対象日を計算
  let targetDay = new Date(today.getTime() + 24 * 60 * 60 * 1000);
  
  // 金曜日の場合は月曜日の席を決める
  if (weekday === "") {
    targetDay = new Date(today.getTime() + 3 * 24 * 60 * 60 * 1000);
  }
  
  // 対象日に出席する人のリストを取得
  const attendees = getAttendees(attendanceSheet, targetDay);
  console.log("出席者:", attendees);
  
  if (attendees.length === 0) {
    console.log("出席者がいません");
    return;
  }
  
  console.log("席替え対象者:", shuffleTargets);
  
  // シャッフル
  const shuffledPersons = arrayShuffle(shuffleTargets);
  
  // 座席シートをクリア
  clearSeats(seatSheet);
  
  // 席を割り当て
  assignSeats(seatSheet, shuffledPersons, targetDay);
  
  console.log("席替え完了!");
}

// 出席者のリストを取得
function getAttendees(sheet, targetDate) {
  const data = sheet.getDataRange().getValues();
  const dateRow = data[0]; // 1行目:日付
  const dayRow = data[1];  // 2行目:曜日
  
  // 対象日の列を探す
  let targetColIndex = -1;
  for (let i = 1; i < dateRow.length; i++) {
    const cellDate = new Date(dateRow[i]);
    if (isSameDate(cellDate, targetDate)) {
      targetColIndex = i;
      break;
    }
  }
  
  if (targetColIndex === -1) {
    console.log("対象日が出欠シートに見つかりません:", targetDate);
    return [];
  }
  
  console.log("対象日の列:", targetColIndex + 1, "列目");
  
  // 出席者を収集(3行目以降)
  const attendees = [];
  for (let i = 2; i < data.length; i++) {
    const personName = data[i][0];
    const attendance = data[i][targetColIndex];
    
    // 「出」の人のみを対象(「テ」や「欠」は除外)
    if (personName && attendance === "") {
      attendees.push(personName);
    }
  }
  
  return attendees;
}

// 座席をクリア
function clearSeats(sheet) {
  // すべての座席セルをクリア
  SEAT_CELLS.forEach(cell => {
    sheet.getRange(cell).setValue("");
  });
}

// 席を割り当て
function assignSeats(sheet, persons, targetDate) {
  // 日付情報を設定
  sheet.getRange("A1").setValue(targetDate);
  sheet.getRange("B1").setValue(`(${getWeekday(targetDate)})の座席`);
  
  // 座席に人を割り当て
  const maxSeats = SEAT_CELLS.length;
  for (let i = 0; i < persons.length; i++) {
    if (i < maxSeats) {
      // 座席がある場合
      sheet.getRange(SEAT_CELLS[i]).setValue(persons[i]);
    } else {
      // 座席が足りない場合はS列に表示
      const overflowRow = i - maxSeats + 1;
      sheet.getRange(`S${overflowRow}`).setValue(persons[i]);
    }
  }
}

// 配列をシャッフル
function arrayShuffle(array) {
  const newArray = [...array]; // 元の配列を変更しないようにコピー
  for (let i = newArray.length - 1; i > 0; i--) {
    const r = Math.floor(Math.random() * (i + 1));
    [newArray[i], newArray[r]] = [newArray[r], newArray[i]];
  }
  return newArray;
}

// 曜日を取得
function getWeekday(date) {
  const weekdays = ["", "", "", "", "", "", ""];
  return weekdays[date.getDay()];
}

// 2つの日付が同じ日かどうかを判定
function isSameDate(date1, date2) {
  return date1.getFullYear() === date2.getFullYear() &&
         date1.getMonth() === date2.getMonth() &&
         date1.getDate() === date2.getDate();
}


// 毎日自動実行するためのトリガーを設定
// この関数を一度だけ手動で実行してトリガーを設定してください
function setupDailyTrigger() {
  // 既存のトリガーを削除
  const triggers = ScriptApp.getProjectTriggers();
  triggers.forEach(trigger => {
    if (trigger.getHandlerFunction() === 'shuffleSeats') {
      ScriptApp.deleteTrigger(trigger);
    }
  });
  
  // 毎日18時に実行するトリガーを作成
  ScriptApp.newTrigger('shuffleSeats')
    .timeBased()
    .everyDays(1)
    .atHour(18)
    .create();
  
  console.log("トリガーを設定しました。毎日18時に席替えが実行されます。");
}


// スプレッドシートのボタンから実行する関数
// ボタンにはこの関数を割り当ててください
function button() {
  shuffleSeats();
  SpreadsheetApp.getUi().alert('席替えが完了しました!');
}

3.2. 技術的ポイント

3.2.1. 必要なスプレッドシート

以下の2つのシートが必要です。

  • 今日の出欠:席の配置を表示するシート
  • 出欠:日付・曜日・各人の出欠状況(出/欠/テ)

座席のセルも配列として定義しています

const SEAT_SHEET_NAME = "今日の座席";
const ATTENDANCE_SHEET_NAME = "出欠";

const SEAT_CELLS = [
  "B2", "B3", "B4",
  "C2", "C3", "C4"
];

3.2.2. 席替え処理の流れ

席替え処理の流れは

  • スプレッドシートの取得
  • 今日の曜日をチェック
  • 土日は実行しない
  • 翌日の席を作成(金曜は月曜日の席)
  • 出欠シートから対象日の出席者を取得
  • ランダムにシャッフル
  • 座席シートをクリア
  • 割り当てを反映

という感じです。

function shuffleSeats() {
  const spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
  const seatSheet = spreadSheet.getSheetByName(SEAT_SHEET_NAME);
  const attendanceSheet = spreadSheet.getSheetByName(ATTENDANCE_SHEET_NAME);

  const today = new Date();
  const weekday = getWeekday(today);

  if (weekday === "" || weekday === "") {
    console.log("土日のため、席替えをスキップします");
    return;
  }

  let targetDay = new Date(today.getTime() + 24 * 60 * 60 * 1000);
  if (weekday === "") {
    targetDay = new Date(today.getTime() + 3 * 24 * 60 * 60 * 1000);
  }

  const attendees = getAttendees(attendanceSheet, targetDay);
  if (attendees.length === 0) return;

  const shuffledPersons = arrayShuffle(attendees);

  clearSeats(seatSheet);
  assignSeats(seatSheet, shuffledPersons, targetDay);

  console.log("席替え完了!");
}

3.2.3. 出席者リストを取得する

出欠シートから対象日の列を探し、「出」の人だけを抽出します。

function getAttendees(sheet, targetDate) {
  const data = sheet.getDataRange().getValues();
  const dateRow = data[0];
  const dayRow = data[1];

  let targetColIndex = -1;
  for (let i = 1; i < dateRow.length; i++) {
    const cellDate = new Date(dateRow[i]);
    if (isSameDate(cellDate, targetDate)) {
      targetColIndex = i;
      break;
    }
  }

  const attendees = [];
  for (let i = 2; i < data.length; i++) {
    if (data[i][targetColIndex] === "") {
      attendees.push(data[i][0]);
    }
  }

  return attendees;
}

3.2.4. シャッフル処理

配列をランダムに並び替える処理です。

function arrayShuffle(array) {
  const newArray = [...array];
  for (let i = newArray.length - 1; i > 0; i--) {
    const r = Math.floor(Math.random() * (i + 1));
    [newArray[i], newArray[r]] = [newArray[r], newArray[i]];
  }
  return newArray;
}

3.2.5. 自動で実行されるトリガー設定

GASトリガーを一度だけ実行すれば、自動で毎日座席表を更新してくれます。

function setupDailyTrigger() {
  const triggers = ScriptApp.getProjectTriggers();
  triggers.forEach(trigger => {
    if (trigger.getHandlerFunction() === 'shuffleSeats') {
      ScriptApp.deleteTrigger(trigger);
    }
  });

  ScriptApp.newTrigger('shuffleSeats')
    .timeBased()
    .everyDays(1)
    .atHour(18)
    .create();
}

3.2.6. スプレッドシートのボタンで実行

「席替えボタン」を作り、右上の3点からスクリプトの割り当てます。
これでボタンを押すだけでも実行できます。

スクリーンショット 2025-12-04 22.46.57.png

function button() {
  shuffleSeats();
  SpreadsheetApp.getUi().alert('席替えが完了しました!');
}

4. まとめ

今回はGASで自動席替えシステムを作ってみました。
良いか悪いかはさておき、これを用いれば同じ席に毎回座ることはないかなと思います。

また、GASはあまりやってこなかったので、色々試してみたいなと思います。

1
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?