部屋割りマクロ(Excel)
部屋割りをサクッと済ませるマクロ
部屋割りマクロ
部屋の定員数に応じて、部屋割りをサクッとやってくれるマクロを作ってみた。
同じ定員数の部屋ばっかりだと、単純にmod演算子を使ったループで一発なんだけれど、定員数に凸凹があるときに、定員数順に前もってソートしておくとか、メンドウなので、定員数に凸凹があっても対応できるように考えてみた。
部屋割りマクロのコード
リスト1 標準モジュール
Public Function assignOfRooms(ByVal targetRange As Range, _ ByVal roomData As Range, _ Optional ByVal hasHeader As Boolean = True) As Boolean On Error GoTo errorHandler '2列以上選択していたらFalseを返す。' If targetRange.Columns.Count <> 1 Then assignOfRooms = False Exit Function End If '部屋定員表が2列の表でなかったらFalseを返す。' If roomData.Columns.Count <> 2 Then assignOfRooms = False Exit Function End If '部屋定員表の項目ラベルがあるときは、項目ラベルを表から除く。' With roomData If hasHeader Then Set roomData = .Offset(1, 0).Resize(.Rows.Count - 1, .Columns.Count) End With '部屋定員表を2次元配列化する。' Dim roomDataArray As Variant roomDataArray = roomData.Value '配列添字が1始まりになるので注意!' Dim rowCount As Integer rowCount = UBound(roomDataArray, 1) '振り番対象のセルの数が、収容人数オーバーだったらFalseを返す。' Dim capacityOfAllRooms As Integer Dim i As Integer For i = 1 To rowCount capacityOfAllRooms = capacityOfAllRooms + roomDataArray(i, 2) Next If capacityOfAllRooms < targetRange.Count Then assignOfRooms = False Exit Function End If targetRange.ClearContents '振り番処理' Dim getFromArrayCount As Integer '配列にアクセスした回数を記録する変数' getFromArrayCount = 1 Dim loopOfArray As Integer For i = 1 To targetRange.Count '配列からの値取得が何周目かを計算する。' loopOfArray = (getFromArrayCount - 1) \ rowCount + 1 With targetRange.Cells(i, 1) If loopOfArray > roomDataArray(((getFromArrayCount - 1) Mod rowCount + 1), 2) Then '振り番しようとする部屋が定員に達していたら次の部屋に進める' Do getFromArrayCount = getFromArrayCount + 1 loopOfArray = (getFromArrayCount - 1) \ rowCount + 1 Loop Until loopOfArray <= roomDataArray(((getFromArrayCount - 1) Mod rowCount + 1), 2) End If .Value = roomDataArray(((getFromArrayCount - 1) Mod rowCount + 1), 1) getFromArrayCount = getFromArrayCount + 1 End With Next assignOfRooms = True Exit Function errorHandler: assignOfRooms = False End Function
コードの解説は、いづれ改めて書きます。ひとまず、コード中のコメントでご容赦を。
第1引数で、振り番したいセル範囲を、
第2引数で、部屋の定員表を表す n 行2列のセル範囲を受け取る。
省略可能な第3引数は、部屋の定員表のセル範囲が、項目ラベルを含んでいるかどうかを表す。
部屋割りが成功したらTrue、失敗したらFalseを返すFunctionにしている。
失敗にもいろいろなパターンがあるので、クラスモジュールにした方がいいかも知れない。
実験
シート上に、
こんなふうにデータを用意し、次のコードで実験してみた。
リスト2 標準モジュール
Public Sub testassignOfRooms() If assignOfRooms(targetRange:=Selection, _ roomData:=ActiveSheet.Range("A1").CurrentRegion, _ hasHeader:=True) Then MsgBox "部屋割り完了!" Else MsgBox "部屋割り失敗!" End If End Sub
こんなふうに範囲を選択して実行。
できた。
右端の表には、COUNTIFを使って部屋割り結果を計算するようにしているが、ピッタリ定員通りに部屋割りができた。
おわりに
急ぎ足でとりあえず書いたコードなので、可読性が低い。
時間があるときにゆっくりとリファクタリングする。