MENU

【VB】ペントミノ3Dパズルを解く(4)棚クラスを作る

今回は棚クラスです。棚は全部で12作り、1つの棚に1種類の部品を登録します。登録する部品は回転や裏返しをしたものをあらかじめ用意しておきます。例えば部品"T"の棚には向きの違う12個の部品"T"を登録します。


部品"F"の場合は部品の形状が非対称なので登録されるのは24個になります。


こうして登録した各部品棚の部品数はこのようになります。

F I L N P T U V W X Y Z
部品数 24 1 16 16 24 12 12 12 12 3 16 12

ただし部品"P"については24個のうち6個を登録します。ペントミノ2Dソルバーのときと同じように180度回転と反転で重なるものはあらかじめ除外します(図の濃い色の部品のみを登録します)。


・クラス宣言

クラスの名前は "Shelf" です

Public Class Shelf

・プロパティ:名前 Name

棚の名前です。中に入れる部品の名前をそのまま使います。解の表示で使用します

ReadOnly Property Name As String

・プロパティ:表示色 Color

解の表示で背景色として使用します

ReadOnly Property Color As Color

・プロパティ:部品集 Pieces

部品コレクション。前述のとおり回転や裏返しをしたものをあらかじめ入れておきます

ReadOnly Property Pieces As List(Of Piece)

・プロパティ:部品を箱に置いたとき

部品集から部品を選択して箱に置いたときの部品と置いた座標。選択していないときはともにNothing

Property PlacedPiece As Piece
Property PlacedCoord As Coord

・初期化

4つの引数のうち name と color はそのままプロパティにしたあと、expression の文字列をもとに部品集(Pieces)をつくっていきます。またBoxはそのサイズを参照するためのものです。
※Boxクラスは「ペントミノ3Dパズルを解く(5)箱クラスを作る」を参照

Sub New(name As String, color As Color, expression As String, box As Box)
   _Name = name
   _Color = color
   _Pieces = New List(Of Piece)
   _PlacedPiece = Nothing
   _PlacedCoord = Nothing
   Dim piece As New Piece(expression)

   For a = 0 To 3
      For b = 0 To 3
         For c = 0 To 3

            '元の部品を各軸の回りに回転させる
            Dim p = piece.Clone()
            p.RotateXY(a)
            p.RotateXZ(b)
            p.RotateYZ(c)
            p.ShiftToOrigin()

            '部品の向きが箱に収まらなければ除外
            If p.LenX > box.LenX OrElse
               p.LenY > box.LenY OrElse
               p.LenZ > box.LenZ Then
               Continue For
            End If

            '回転シノニムを除外(DEF.SynonymJudgePieceName="P")
            If name = DEF.SynonymJudgePieceName Then
               If IsRotateSynonym(p) Then
                  Continue For
               End If
            End If

            'リストに無ければ追加
            If Pieces.Any(Function(s) s = p) = False Then
               Pieces.Add(p)
            End If

         Next
      Next
   Next
End Sub

・回転シノニム判定

前述の部品"P"で180度回転させるとぴったり重なるもの(シノニム)を除外するときに使用します。引数の部品を様々な方向に180度回転させて部品集に登録済みかどうかを判定します。

Private Function IsRotateSynonym(pc As Piece) As Boolean
   For Each plane In {"X", "Y", "Z", "XY", "YZ", "ZX", "XYZ"}
      Dim p = pc.Clone
      If plane.Contains("X") Then
         p.RotateYZ(2)
      End If
      If plane.Contains("Y") Then
         p.RotateXZ(2)
      End If
      If plane.Contains("Z") Then
         p.RotateXY(2)
      End If
      p.ShiftToOrigin()
      If Pieces.Any(Function(s) s = p) = True Then
         Return True
      End If
   Next
   '回転シノニムではない
   Return False
End Function


以上が「棚クラス」です。クラス全体のソースは以下のとおりです。

Public Class Shelf
   '**********************************************
   '*            Shelf  (部品棚クラス) 
   '**********************************************
   ReadOnly Property Name As String             '名前
   ReadOnly Property Color As Color             '表示色 
   ReadOnly Property Pieces As List(Of Piece)   '部品コレクション

   Property PlacedPiece As Piece    'ボードに配置した部品(Pieces内の1個),配置してないときはNothing
   Property PlacedCoord As Coord    'PlacedPieceを配置した場所,配置してないときはNothing

   Sub New(name As String, color As Color, expression As String, board As Board)
      _Name = name
      _Color = color
      _Pieces = New List(Of Piece)
      _PlacedPiece = Nothing
      _PlacedCoord = Nothing
      Dim piece As New Piece(expression)

      For a = 0 To 3
         For b = 0 To 3
            For c = 0 To 3

               '元の部品を各軸の回りに回転させる
               Dim p = piece.Clone()
               p.RotateXY(a)
               p.RotateXZ(b)
               p.RotateYZ(c)
               p.ShiftToOrigin()

               '部品の向きが箱に収まらなければ除外
               If p.LenX > board.LenX OrElse
                  p.LenY > board.LenY OrElse
                  p.LenZ > board.LenZ Then
                  Continue For
               End If

               '回転シノニムを除外
               If name = DEF.SynonymJudgePieceName Then
                  If IsRotateSynonym(p) Then
                     Continue For
                  End If
               End If

               'リストに無ければ追加
               If Pieces.Any(Function(s) s = p) = False Then
                  Pieces.Add(p)
               End If

            Next
         Next
      Next
   End Sub

   '回転シノニム判定(True=180度回転で重複する)
   Private Function IsRotateSynonym(pc As Piece) As Boolean
      For Each plane In {"X", "Y", "Z", "XY", "YZ", "ZX", "XYZ"}
         Dim p = pc.Clone
         If plane.Contains("X") Then
            p.RotateYZ(2)
         End If
         If plane.Contains("Y") Then
            p.RotateXZ(2)
         End If
         If plane.Contains("Z") Then
            p.RotateXY(2)
         End If
         p.ShiftToOrigin()
         If Pieces.Any(Function(s) s = p) = True Then
            Return True
         End If
      Next
      '回転シノニムではない
      Return False
   End Function

End Class

次は「箱クラス」です。