Excel VBAで実用ツール(座席表作成編)

2024-01-07

■宴会の座席決定を支援するツール

最近はコロナ禍で宴会を行う機会もなくなってしまいましたが、以前は数十人規模の宴会が年に何回も開催されていました。
ややフォーマルな宴会だったりすると、予め段取りや座席を決めておかなくてはいけない訳ですが、人数が多くなって来ると座席を決めるのも結構大変でした。

本稿では筆者が幹事の時に作成した、座席決定支援ツールを紹介します。
この宴会の出席者は30名強、広い和室に4つの島を準備しましたので、上座に主賓を座らせ、幹事3名を等間隔で配置することにしましたが、それぞれの島が均等に盛上るように残りのメンバーをバランス良く配置する必要がありました。
30人にもなると、頭の中で座席レイアウトを考えてもまとまらないので、Excelシートに貼付けた「シャッフル」ボタンで次項で紹介するツールを動かし、できあがった座席を眺めて今一だったら再度「シャッフル」するということを繰返した結果、なかなか良い感じの座席レイアウトができあがりました。

事前準備

「座席表」「work」というExcelシートを用意し、「座席表」シートには座席レイアウト、「work」シートにはシャッフルしたい座席数分の『座席番号』と『氏名』を入れたテーブルを作成します。

(「work」シートのイメージ)
A列を『座席番号』、B列を『氏名』とする以下のような表を用意し、『氏名』だけ手入力します。
⇒『座席番号』にはツールの実行結果が入りますので、入力は不要です。

座席番号 氏名
AAA
BBB
・・・

(「座席表」シートのイメージ)
座席レイアウトに近い形で枠を配置し、シャッフルした結果を埋めたいセルに「=IFERROR(VLOOKUP(n,work!$A$2:$B$xx,2,FALSE),"")」という式を埋めます。
ここでnは1から配置したい座席数までの連番、$B$xxは「work」シートに作成したテーブルの最後のセルです。
⇒座席を固定したい箇所は、『主賓』『幹事』のように値を入力します。

幹事 主賓 ・・・
・・・

サンプル・プログラム

行番号2~3で座席決定の範囲を指定し、行番号6で座席番号を格納する配列、行番号7で座席番号を格納したかどうかを示す配列(格納済の場合、True)を定義しています。

行番号12のRandomizeステートメントで乱数ジェネレータを初期化、行番号13~15で配列を初期化した後、行番号16~22の繰返し処理で乱数を基に座席番号を算出し、行番号23~25で「work」シートにセットしています。
行番号18ではRnd関数を使用して乱数を取得していますが、Rnd関数の戻り値は「0≦戻り値<1」のため、座席番号の範囲になるように「Int(MAX * Rnd + 1)」という計算を行っています。

  1. Option Base 1
  2. Const MIN = 1
  3. Const MAX = 28
  4. Dim sht As Worksheet
  5. Dim num As Integer
  6. Dim a_num(MIN To MAX) As Integer
  7. Dim flag(MIN To MAX) As Boolean
  8. Dim cnt As Integer
  9. Private Sub Sample1()
  10.     Set sht = Worksheets(“work")
  11.     Randomize
  12.     For cnt = MIN To MAX
  13.         flag(cnt) = False
  14.     Next cnt
  15.     For cnt = MIN To MAX
  16.         Do
  17.             num = Int(MAX * Rnd + 1)
  18.         Loop While flag(num)
  19.         a_num(cnt) = num
  20.         flag(num) = True
  21.     Next cnt
  22.     For cnt = MIN To MAX
  23.         sht.Cells(cnt + 1, 1) = a_num(cnt)
  24.     Next cnt
  25. End Sub

■会議の座席表を作成するツール

前項で紹介したツールとほぼ同様ですが、定例会議の座席を毎回変更していた時期があり、Excelツールで座席を決めていました。
この宴会の出席者は13名で、正方形に並べた16席(1辺に4席ずつ)に配置するだけですが、「部長の隣は空ける」「1辺に3名以上配置する」という条件を設定し、条件を満たさない場合は自動的に再シャッフルする仕様にしていました。

事前準備

前項のサンプル・プログラムと同様、「座席表」「work」というExcelシートを用意し、「座席表」シートには座席レイアウト、「work」シートにはシャッフルしたい座席数分の『座席番号』と『氏名』を入れたテーブルを作成します。

(「work」シートのイメージ)
A列を『座席番号』、B列を『氏名』とする以下のような表を用意し、『氏名』だけ手入力します。
⇒『座席番号』にはツールの実行結果が入りますので、入力は不要です。

座席番号 氏名
AAA
BBB
・・・

(「座席表」シートのイメージ)
座席レイアウトに近い形で枠を配置し、シャッフルした結果を埋めたいセルに「=IFERROR(VLOOKUP(n,work!$A$2:$B$xx,2,FALSE),"")」という式を埋めます。
ここでnは1から配置したい座席数までの連番、$B$xxは「work」シートに作成したテーブルの最後のセルです。
⇒下図の灰色のセルに数式を埋めます。

サンプル・プログラム

行番号2~3で座席決定の範囲を指定し、行番号6で座席番号を格納する配列、行番号7で座席番号を格納したかどうかを示す配列(格納済の場合、True)を定義しています。

行番号12のRandomizeステートメントで乱数ジェネレータを初期化、行番号13~27の処理を結果判定が"OK"になるまで繰返すこととし、その中の処理は前掲のサンプル・プログラムと同様で、行番号14~16で配列を初期化した後、行番号17~23の繰返し処理で乱数を基に座席番号を算出し、行番号24~26で「work」シートにセットしています。
行番号19ではRnd関数を使用して乱数を取得していますが、Rnd関数の戻り値は「0≦戻り値<1」のため、座席番号の範囲になるように「Int(MAX * Rnd + 1)」という計算を行っています。

行番号37~57の「結果判定」関数では、「部長の隣が空いていない」または「1辺の人数が3名未満」の時に"NG"を返しています。
また、行番号59~67の「氏名→座席変換」関数は「work」シートのテーブルを氏名で検索して座席番号を返し、行番号69~77の「座席→氏名変換」関数は逆に座席番号で検索して氏名を返しています。

  1. Option Base 1
  2. Const MIN = 1
  3. Const MAX = 16
  4. Dim sht As Worksheet
  5. Dim num As Integer
  6. Dim a_num(MIN To MAX) As Integer
  7. Dim flag(MIN To MAX) As Boolean
  8. Dim cnt As Integer
  9. Private Sub Sample2()
  10.     Set sht = Worksheets(“work")
  11.     Randomize
  12.     Do
  13.         For cnt = MIN To MAX
  14.             flag(cnt) = False
  15.         Next cnt
  16.         For cnt = MIN To MAX
  17.             Do
  18.                 num = Int(MAX * Rnd + 1)
  19.             Loop While flag(num)
  20.             a_num(cnt) = num
  21.             flag(num) = True
  22.         Next cnt
  23.         For cnt = MIN To MAX
  24.             sht.Cells(cnt + 1, 1) = a_num(cnt)
  25.         Next cnt
  26.     Loop Until 結果判定 = “OK"
  27. End Sub
  28. Private Function 結果判定() As String
  29.     Dim 部長, 左隣, 右隣, 人数, i, j As Integer
  30.     結果判定 = “OK"
  31.     部長 = 氏名→座席変換(“部長")
  32.     左隣 = 部長 – 1
  33.     If 部長 = MIN Then
  34.         左隣 = MAX
  35.     End If
  36.     右隣 = 部長 + 1
  37.     If 部長 = MAX Then
  38.         右隣 = 右隣 – MAX
  39.     End If
  40.     If (座席→氏名変換(左隣) <> “") Or (座席→氏名変換(右隣) <> “") Then
  41.         結果判定 = “NG"
  42.         Exit Function
  43.     End If
  44.     For i = 1 To 4
  45.         人数 = 0
  46.         For j = 1 To 4
  47.             If 座席→氏名変換(4 * (i – 1) + j) <> “" Then
  48.                 人数 = 人数 + 1
  49.             End If
  50.         Next j
  51.         If 人数 < 3 Then
  52.             結果判定 = “NG"
  53.         End If
  54.     Next i
  55. End Function
  56. Private Function 氏名→座席変換(ByVal 氏名 As String) As Integer
  57.     Dim i As Integer
  58.     氏名→座席変換 = 0
  59.     For i = 2 To sht.Cells(Rows.Count, 2).End(xlUp).Row
  60.         If 氏名 = sht.Cells(i, 2) Then
  61.             氏名→座席変換 = sht.Cells(i, 1)
  62.         End If
  63.     Next i
  64. End Function
  65. Private Function 座席→氏名変換(ByVal 座席 As Integer) As String
  66.     Dim i As Integer
  67.     座席→氏名変換 = “"
  68.     For i = 2 To sht.Cells(Rows.Count, 1).End(xlUp).Row
  69.         If 座席 = sht.Cells(i, 1) Then
  70.             座席→氏名変換 = sht.Cells(i, 2)
  71.         End If
  72.     Next i
  73. End Function

 

国本温子(著),緑川吉行(著),できるシリーズ編集部(著)
出版社:インプレス
発売日:2022/3/23
単行本(ソフトカバー):A5判/912ページ

大村あつし(著),古川順平(著)
出版社:技術評論社
発売日:2021/1/9
単行本(ソフトカバー):A5判/800ページ

高橋宣成(著)
出版社:技術評論社
発売日:2019/11/25
単行本(ソフトカバー):B5変形判/576ページ

実用ツール

Posted by hides