MENU

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

箱クラスは箱内の空いているセルに部品が置けるかどうかを判定したり、現在おいている部品と座標位置を登録して完成判断に使用します。

・クラス宣言

クラスの名前は "Box" です。

Public Class Box

・プロパティ:LenX, LenY, LenZ

箱の大きさ。初期化時に退避します。

ReadOnly Property LenX As Integer     'X軸方向
ReadOnly Property LenY As Integer     'Y軸方向
ReadOnly Property LenZ As Integer     'Z軸方向

・プロパティ:Cells( , , )

箱内のセル(値は Boolean)です。見た目(Cells)は3次元ですが処理速度の関係で実体(_Cells)は1次元にしています。サイズは初期化で確保します。

Private _Cells As Boolean()    'セル実体:1次元配列
Property Cells(x As Integer, y As Integer, z As Integer) As Boolean
   Get
      Return _Cells(x + (y + z * LenY) * LenX)
   End Get
   Set(value As Boolean)
      _Cells(x + (y + z * LenY) * LenX) = value
   End Set
End Property

・プロパティ:解判定関係

解の判定に使用するプロパティです。PlacedPieceCountが部品の種類(=12)に等しくなったときが正解です。PlacedFirstPieceは最初に置いた部品でプログレスバーの表示計算に使います。

Property PlacedPieceCount As Integer = 0
Property PlacedFirstPiece As Piece = Nothing

・初期化

引数にボードの横と縦のサイズを指定します。

Sub New(width As Integer, depth As Integer, height As Integer)
   _LenX = width
   _LenY = depth
   _LenZ = height
   ReDim _Cells(width * depth * height - 1)
   PlacedPieceCount = 0
   PlacedFirstPiece = Nothing
End Sub

・関数 FitInBox

指定した座標が箱の中にあるかどうかを判定します(箱の中にあれば True)。

Public Function FitInBox(x As Integer, y As Integer, z As Integer) As Boolean
   If x >= 0 AndAlso x <= LenX - 1 AndAlso
      y >= 0 AndAlso y <= LenY - 1 AndAlso
      z >= 0 AndAlso z <= LenZ - 1 Then
      Return True
   Else
      Return False
   End If
End Function

・関数:NextBlankCell

指定した座標から空(False)セルを検索して、空セルがあればその座標を返します。検索方向はZ→Y→X座標の順です。空セルがなければ Nothing を返します。

Public Function NextBlankCell(c As Coord) As Coord
   Dim x = c.X
   Dim y = c.Y
   Dim z = c.Z
   Do Until Cells(x, y, z) = False
      Select Case True
         Case z < LenZ - 1
            z += 1
         Case y < LenY - 1
            y += 1
            z = 0
         Case x < LenX - 1
            x += 1
            y = 0
            z = 0
         Case Else
            Return Nothing
      End Select
   Loop
   Return New Coord(x, y, z)
End Function

・関数:CanPlace

箱内の指定した位置に部品が置けるかどうかを返します(部品を置くことができれば True)。部品の5個の座標に対応するセルがすべて空であれば True、1つでもセルが埋まっていれば False を返します。

Public Function CanPlace(piece As Piece, c As Coord) As Boolean
   For Each p In piece.Coords
      Dim x = c.X + p.X
      Dim y = c.Y + p.Y
      Dim z = c.Z + p.Z
      If FitInBox(x, y, z) = False OrElse Cells(x, y, z) = True Then
         Return False
      End If
   Next
   Return True
End Function

・メソッド:PlacePiece

箱内の指定した位置に部品を置きます

Public Sub PlacePiece(shelf As Shelf)
   With shelf.PlacedCoord
      For Each p In shelf.PlacedPiece.Coords
         Cells(.X + p.X, .Y + p.Y, .Z + p.Z) = True
      Next
   End With
   PlacedPieceCount += 1          '解判定のためのカウンターを増加
   If PlacedPieceCount = 1 Then
      PlacedFirstPiece = shelf.PlacedPiece    'プログレスバー表示用
   End If
End Sub

・メソッド:RemovePiece

ボードの指定した位置の部品を取り除きます

Public Sub RemovePiece(shelf As Shelf)
   With shelf.PlacedCoord
      For Each p In shelf.PlacedPiece.Coords
         Cells(.X + p.X, .Y + p.Y, .Z + p.Z) = False
      Next
   End With
   PlacedPieceCount -= 1          '解判定のためのカウンターを減少
End Sub


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

Public Class Box
   '**********************************************
   '*              Box  (箱クラス) 
   '**********************************************
   ReadOnly Property LenX As Integer     'X軸方向
   ReadOnly Property LenY As Integer     'Y軸方向
   ReadOnly Property LenZ As Integer     'Z軸方向

   Private _Cells As Boolean()    'セル実体:1次元配列
   Property Cells(x As Integer, y As Integer, z As Integer) As Boolean
      Get
         Return _Cells(x + (y + z * LenY) * LenX)
      End Get
      Set(value As Boolean)
         _Cells(x + (y + z * LenY) * LenX) = value
      End Set
   End Property

   Property PlacedPieceCount As Integer = 0
   Property PlacedFirstPiece As Piece = Nothing

   '** 初期化
   Sub New(width As Integer, depth As Integer, height As Integer)
      _LenX = width
      _LenY = depth
      _LenZ = height
      ReDim _Cells(width * depth * height - 1)
      PlacedPieceCount = 0
      PlacedFirstPiece = Nothing
   End Sub

   '** FitInBox
   Public Function FitInBox(x As Integer, y As Integer, z As Integer) As Boolean
      If x >= 0 AndAlso x <= LenX - 1 AndAlso
         y >= 0 AndAlso y <= LenY - 1 AndAlso
         z >= 0 AndAlso z <= LenZ - 1 Then
         Return True
      Else
         Return False
      End If
   End Function

   '** NextBlankCell
   Public Function NextBlankCell(c As Coord) As Coord
      Dim x = c.X
      Dim y = c.Y
      Dim z = c.Z
      Do Until Cells(x, y, z) = False
         Select Case True
            Case z < LenZ - 1
               z += 1
            Case y < LenY - 1
               y += 1
               z = 0
            Case x < LenX - 1
               x += 1
               y = 0
               z = 0
            Case Else
               Return Nothing
         End Select
      Loop
      Return New Coord(x, y, z)
   End Function

   '** CanPlace
   Public Function CanPlace(piece As Piece, c As Coord) As Boolean
      For Each p In piece.Coords
         Dim x = c.X + p.X
         Dim y = c.Y + p.Y
         Dim z = c.Z + p.Z
         If FitInBox(x, y, z) = False OrElse Cells(x, y, z) = True Then
            Return False
         End If
      Next
      Return True
   End Function

   '** PlacePiece
   Public Sub PlacePiece(shelf As Shelf)
      With shelf.PlacedCoord
         For Each p In shelf.PlacedPiece.Coords
            Cells(.X + p.X, .Y + p.Y, .Z + p.Z) = True
         Next
      End With
      PlacedPieceCount += 1
      If PlacedPieceCount = 1 Then
         PlacedFirstPiece = shelf.PlacedPiece
      End If
   End Sub

   '** RemovePiece
   Public Sub RemovePiece(shelf As Shelf)
      With shelf.PlacedCoord
         For Each p In shelf.PlacedPiece.Coords
            Cells(.X + p.X, .Y + p.Y, .Z + p.Z) = False
         Next
      End With
      PlacedPieceCount -= 1
   End Sub

End Class

以上でプログラムで使用する4つのクラス(Coord, Piece, Shelf, Box)が揃いました。次回はプログラムの鑑「DEFクラス」です。プログラム諸元や共有で使用する定数や関数などをまとめて記述しておくクラスです。